Smuggler's Cove
Smuggler's Cove was a pwn challenge based on LuaJIT based lua interpreter + pointer corruption to disalign jitted function
Files
Source code
Corrupt function pointer
As we can see from the initial lua state, only two functions are exposed to the lua environment:
We can execute cargo and print, whose respective callbacks are debug_jit and print.
The print function only prints a lua variable as string, nothing special. But, the cargo function (debug_jit) is very very interesting as it adds a user provided offset to the pointer of a jitted function of choice:
We can use the cargo function to add an offset to the pointer of a jitted function of choice, but we can't just point it anywhere since the offset that we can add is limited to the mcode block it is in.
The best we can do is skip or disalign some instructions adding small offsets:
After function f is jitted, we should be able to add an offset to it. If we add an offset that would disalign the instructions of function f, we should see a segfault:
Arbitrary Code Execution
Now that we are able to disalign the jitted code we can try to reflect some controlled bytes and maybe get those to be executed as instructions. One way of doing this is using numeric constants like this:
In this format the print inside the if block is only there to make sure the compiler won't ignore this comparison since it does nothing. Here is what this function compiles to:

The if statment translate to moving 0xdeadbeefcafebabe into a register to later use it in a comparison, so we can expect to see 0xdeadbeeefcafebabe reflected in memory.

Now it's just a matter of calculating the offset from the starting of the jitted function to the start of our numeric constant, which is 0xd.
In this case the function pointer will be offset 0xd from the start of the jitted function, which means, the bytes 0xdeadbeefcafebabe will be executed as instructions.
But we can't fit any shellcode in just 8 bytes, so we need to split our shellcode in multiple parts and connect them using relative jmps.
Shellcode
In this challenge we don't have access to stdin over network. All we can do is submit our exploit to be ran on the remote server and then the output is sent to us, so we can't simply pop a shell and read the flag. Instead, we are meant to execute a binary with 111 permitions (exec only) called dig_up_the_loot, that will show us the flag:
In order for this to work we need argc to be 5 and argv to be ["./dig_up_the_loot","x","marks","the","spot"] . We also need rdi to hold a pointer to the ./dig_up_the_loot string and finally exec the execve syscall.
Notice that our lua file can't be larger than 433:
So pushing all the strings onto the stack then push the pointers to get the char *arg[] pointer array is not a good idea. Instead I abused the fact that at the beggining of the execution of the jitted function, the rcx register points to a memory area that seems to carry lua variables and other data related to the lua state:

This offset is deterministic but it's determined by our jitted function so keep in mind that we'll need to calculate this offset after the rest of the shellcode is done. All we need to do is increment the rcx register and push it onto the stack multiple times. I wrote a python script to generate the shellcode in the desired format:
Finally, notice that the JIT compiler doesn't move the numeric constants to the registers in order so I had to manually check in gdb what order it was using and manually adapt my exploit.
Final Exploit
Last updated
Was this helpful?