Page 3 of 5

Re: New crash exploit part III (17.11.2012)

Posted: Sun Dec 09, 2012 1:10 am
by dierighty
Nice job, Grabbi on capturing those packets.
From observing the wireshark the server normally updates the clients(@ 33Hz?)
with a data packet of 212 bytes.
In Grabbi's packet log, the server sends its last data packet, No. 5593, at time 10.119069.
So I assume after this time the server has hung, and is no longer updating clients
with data. Thus the hacker(50.117.78.136) probably did something bad somewhere around
time 10.119069 that is causing the problem.

battlefield42 data packets follow this general format:
[7 bytes] header
[2 bytes] size of data contents
[... bytes] data contents (of a number of bytes specified by the 2 byte field above)

So looking around server packet no. 5593, this packet sent by the hacker, looks fishy
because the 2 byte field that holds the size of the data contents is 0:
No. Time Source Destination Protocol Length Info
5597 10.120369 50.117.78.136 h1345257.stratoserver.net UDP 99 Source port: ansyslmd Destination port: 14567

Frame 5597: 99 bytes on wire (792 bits), 99 bytes captured (792 bits)
Ethernet II, Src: Cisco_a2:9c:00 (00:16:9c:a2:9c:00), Dst: TyanComp_65:10:65 (00:e0:81:65:10:65)
Internet Protocol Version 4, Src: 50.117.78.136 (50.117.78.136), Dst: h1345257.stratoserver.net (85.214.86.156)
User Datagram Protocol, Src Port: ansyslmd (1055), Dst Port: 14567 (14567)
Data (57 bytes)

0000 0c 85 fa ff ff ff ff [00 00] c3 00 00 00 00 fc df ................
0010 ff fd df ff fd df ff 01 00 00 00 fc df ff fd df ................
0020 ff fd df ff 01 00 00 00 fc df ff fd df ff fd df ................
0030 ff 01 00 00 00 04 ad b1 89 .........

;I put []'s around the word that is supposed to hold the size of the data contents,
notice how its 0! :/

From the backtrace that you posted wq_Compf, it shows that an infinite loop
is somewhere in those functions:
(gdb) bt
#0 0x0843c12b in dice::ref2::io::SWConnection::getPacketFromRecvQueue(unsigned char*, unsigned int*) ()
#1 0x0843867a in dice::ref2::io::NetServer::getRecvdPacket(int*, unsignedchar*, unsigned int*) ()
#2 0x08137913 in dice::bf::GameServer::receive(int*) ()
#3 0x08137be2 in dice::bf::GameServer::processReceivedPackets() ()
#4 0x08132995 in dice::bf::GameServer::update(int, float) ()
#5 0x080bc366 in dice::bf::Setup::mainLoop() ()
#6 0x080bb71c in dice::bf::Setup::start(std::string const&) ()
#7 0x08050775 in main ()

So I began to look at how a data packet with its size field set to 00 would affect these functions.
The problem looks to ultimately begin in dice::ref2::io::SWConnection::getPacketFromRecvQueue(
where these 2 bytes are read:
0x0843c147 <+71>: mov ax,WORD PTR [eax+edx*1] ;get the size field in the data packet
0x0843c14b <+75>: test ax,ax
0x0843c14e <+78>: jne 0x843c157 ;jump if size != 0
0x0843c150 <+80>: mov eax,0x9 ;set the return variable to 0x9
0x0843c155 <+85>: jmp 0x843c11a ;jump to ret
Normally, getPacketFromRecvQueue() would have popped this packet from the Receive Queue but because
of the 0 data field it has returned early, leaving the bad packet still in its queue.
From this point on, functions return and processing ends up back in GameServer::processReceivedPackets().
Now, GameServer::processReceivedPackets() checks the value returned by GameServer::receive(), which is
in the eax register:
0x08137bdd <+61>: call 0x81378d0 <dice::bf::GameServer::receive(int*)>
0x08137be2 <+66>: add esp,0x10
0x08137be5 <+69>: mov edi,eax ;retval, eax = 9 set in SWConnection::getPacketFromRecvQueue
0x08137be7 <+71>: cmp eax,0x1
0x08137bea <+74>: je 0x81382f0
0x08137bf0 <+80>: cmp eax,0x1
0x08137bf3 <+83>: jle 0x8137f80
0x08137bf9 <+89>: cmp eax,0xa
0x08137bfc <+92>: je 0x8137f10
0x08137c02 <+98>: cmp eax,0xd
0x08137c05 <+101>: je 0x8137e90
0x08137c0b <+107>: cmp edi,0x8
0x08137c0e <+110>: jne 0x8137bd0 ;a retval of 0x9 loops back, and the bad packet remains!
This shows that with a return value of 0x9 the jne @ 0x08137c0e gets
executed looping back causing the infinite loop.

To check this using a bf42 server process, I used GDB. At instruction 0x843c147 in SWConnection::getPacketFromRecvQueue,
I set the data field of any of battlefield data packet to 00:
//$hobo is just a variable name i made up
(gdb) x/i $eip
=> 0x843c147 <_ZN4dice4ref22io12SWConnection22getPacketFromRecvQueueEPhPj+71>:mov ax,WORD PTR [eax+edx*1]
(gdb) x/x $eax+$edx
0xb08d6ff: 0x58c1002d
(gdb) set variable $hobo=0xb08d6ff
(gdb) p/x $hobo
$9 = 0xb08d6ff
(gdb) set *(char*)$hobo=0x0
(gdb) x/x $eax+$edx
0xb08d6ff: 0x58c10000
(gdb) continue

I noticed that the server no longer responds, but I change the data field
back to what it was (normally it is 0x2d), the server starts working again
because it can start handling packets out of its recv queue again.

I am not sure how this is all effected if the bad client sends good
packets again, if the server just pops & processes those and then hangs
on the bad packet.

I hope that with the ability to re-create the problem in GDB, tuia, s[sk] and other
talented individuals can help get this patched :)

I also wonder if this is the only trick the hacker is using, or if there are bad
things in the packet log.

Re: New crash exploit part III (17.11.2012)

Posted: Sun Dec 09, 2012 4:31 am
by s[sk]
first of all, great analysis, we're not worthy! ;-)
dierighty wrote: So looking around server packet no. 5593, this packet sent by the hacker, looks fishy
because the 2 byte field that holds the size of the data contents is 0:
i've tested it by injecting udp packet with that size being 0 into client-server communication, it does hang the server
0x0843c147 <+71>: mov ax,WORD PTR [eax+edx*1] ;get the size field in the data packet
0x0843c14b <+75>: test ax,ax
0x0843c14e <+78>: jne 0x843c157 ;jump if size != 0
0x0843c150 <+80>: mov eax,0x9 ;set the return variable to 0x9
0x0843c155 <+85>: jmp 0x843c11a ;jump to ret
the first thing that was screaming "try me!" was

mov ebx, 0x9
jmp 0x0843C195

to pop that message out of the queue and still return 9

quick and limited test showed that now it disconnects that client and doesn't hang, can't test it on a populated server right now so no idea whether there are any side effects


bf1942_lnxded.static:
003F4150: B8 -> BB
003F4156: C3 -> 3E

let me know what you think

Re: New crash exploit part III (17.11.2012)

Posted: Sun Dec 09, 2012 9:11 am
by freddy
You can test on my server if you like, its getting crashed alot anyway so if it can help solve the problem just go ahead and do whatever it takes.

Re: New crash exploit part III (17.11.2012)

Posted: Sun Dec 09, 2012 1:04 pm
by Grabbi
without having much clue of these datas I thought already, that the attacker now has found an effective way to stall a server without leaving an exception message behind which easily could lead to a fix, and it could be the search for a needle in the haystack.

dierighty wrote:Nice job, Grabbi on capturing those packets.
well I think the nice job is on your side dierighty analyzing the captured data protocol with such a precision.

respect !

Hope you guys will find the needle :)

Greetings


Grabbi

Re: New crash exploit part III (17.11.2012)

Posted: Sun Dec 09, 2012 1:05 pm
by tuia
Very good analysis dierighty!
s[sk], your fix seems fine to me, pop from the queue the "bad" packet with data size 0 and return the same value 9 to the caller function, so it doesn't get processed.

Re: New crash exploit part III (17.11.2012)

Posted: Sun Dec 09, 2012 2:17 pm
by s[sk]
i've looked into windows binary, i can't easily test it so i just tried to blindpatch it, it's 50:50 i got it right, anyway someone will correct me if i'm wrong

1f75eb8b55ab5bb4d6782dd6f3be2e45 BF1942_w32ded.exe

001B360F: 5E B8 -> 90 BB
001B3615: 5B 59 -> EB E8

edit: fixed that extra pop

Re: New crash exploit part III (17.11.2012)

Posted: Sun Dec 09, 2012 5:09 pm
by tuia
It's there, but there is a previous pop esi instruction which should be nop'd, because the stack pointer will be changed. Or it can be modified to:
001B360F: 6A 09 5B EB EB
This is for BF1942_w32ded.exe v1.61.

I've tested s[sk] fixes on both Linux and Windows BF1942 servers and they seem to patch it correctly.

Re: New crash exploit part III (17.11.2012)

Posted: Sun Dec 09, 2012 10:19 pm
by s[sk]
tuia wrote:It's there, but there is a previous pop esi instruction which should be nop'd, because the stack pointer will be changed.
yes, of course, i'm blind
thanks ;-)

Re: New crash exploit part III (17.11.2012)

Posted: Mon Dec 10, 2012 2:47 pm
by Viral
I would test this as well on my server I just need to know how to patch the Linux server files. I am using the 1.62 patched version. I don't need a guide just give me a kick in the right direction and a link to the needed tools :P

Re: New crash exploit part III (17.11.2012)

Posted: Mon Dec 10, 2012 3:04 pm
by s[sk]
Viral wrote:I would test this as well on my server I just need to know how to patch the Linux server files. I am using the 1.62 patched version. I don't need a guide just give me a kick in the right direction and a link to the needed tools :P
i suggest using vbindiff for hexediting in linux
just be sure you are not editing a binary that's in use (running)