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(22.214.171.124) 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 126.96.36.199 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: 188.8.131.52 (184.108.40.206), Dst: h1345257.stratoserver.net (220.127.116.11)
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:
#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
(gdb) set variable $hobo=0xb08d6ff
(gdb) p/x $hobo
$9 = 0xb08d6ff
(gdb) set *(char*)$hobo=0x0
(gdb) x/x $eax+$edx
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.