So, how to use SROP to get a shell? Lets think reversely.
In the end, we want to get a shell, so we must use syscall(59,'/bin/sh',0,0). But '/bin/sh' is not in the memory. So, we need to write '/bin/sh' into the memory.
We can simply write '/bin/sh' on the stack, however, there is no way we are able to know the stack address. (In this case, rdi never gonna be 1, so we can't use write(1,addr,0x7df) to get stack address)
Here is another method, first, we do a mprotect to make a memory page writable using sigreturn. After sigreturn, rsp (stack pointer) will set to the address now is writable.
Then we return to main function and write '/bin/sh' and signal frame for calling syscall(59,'/bin/sh',0,0) there. In that case, we know the address of '/bin/sh'.
Now, how to trigger sigreturn? thats pretty straightforward, Since we have a write syscall in main, we just write 15 bytes to the stack and return to syscall gadget. That will set rax to 15 and trigger sigreturn.
There one more thing. Since we are using the gadget syscall; ret. After we execute mprotect, the program will ret to a address in the rsp.
Its okay if we end after one sigreturn. But in this case, we need to do two sigreturn, so it is important to return back to main. Therefore, we need find some where in the memory that contains an pointer to main, so that when ret is called, it will go back to main and we can do another SROP there.
Luckily, in 0x004020b8, there is pointer that point to main. So we can happily make whole 0x00402000-0x00403000 page writable and use this address as our new rsp.
write signal frame to the stack with rax=10 (mprotect), rdi = 0x00402000, rsi = 0x1000, rdx = 7 (rwx), rsp = 0x004020b8, rip = syscall addr. Then return to main
write 15 bytes to trigger sigreturn
return to main, write signal frame for calling execve. Then return to main
def start_remote(argv=, *a, **kw): '''Connect to the process on the remote host''' io = remote("tamuctf.com", 443, ssl=True, sni="void") if args.GDB: gdb.attach(io, gdbscript=gdbscript) return io
def start(argv=, *a, **kw): '''Start the exploit against the target.''' if args.LOCAL: return start_local(argv, *a, **kw) else: return start_remote(argv, *a, **kw)
# =========================================================== # EXPLOIT GOES HERE # =========================================================== # Arch: amd64-64-little # RELRO: No RELRO # Stack: No canary found # NX: NX enabled # PIE: No PIE (0x400000)