�
0x00_learning_the_ROPes
�glem
__ _ _ _ _ ______ � / /| || | | || |____ |� ___ ___ / /_| || |_| || |_ / / � / __/ __| '_ \__ _|__ _|/ / � | (__\__ \ (_) | | | | | / / � \___|___/\___/ |_| |_|/_/ � � ��
# summary
# before we start
# talk x86_64 to me..
RAX
EAX
AH
AL
AX
64 bits
32 bits
16 bits
16 bits
8 bits
8 bits
# x86_32 cdecl
> SYSCALLS
> FUNCTION CALLS
# x86_32 function calls?
> FUNCTION STACK FRAME HAS
> FUNCTION CALL STEPS
EBP ->
ESP ->
SAVED EBP
RET ADDR
ARG 1
ARG 2
LOCAL VAR 1
LOCAL VAR 2
LOCAL VAR N
0xFFFFFFFF
0x00000000
EBP-4
EBP-8
EBP+4
EBP+8
EBP+12
JUNK
JUNK
JUNK
# x86_64 fastcall
> SYSCALLS
> FUNCTION CALLS
# x86_64 function calls?
> FUNCTION STACK FRAME HAS
> FUNCTION CALL STEPS
RBP ->
RSP ->
SAVED RBP
RET ADDR
ARG N-1
ARG N
LOCAL VAR 1
LOCAL VAR 2
LOCAL VAR N
0xFFFFFFFFFFFFFFFF
0x0000000000000000
RBP-8
RBP-16
RBP+8
RBP+16
RBP+24
JUNK
JUNK
JUNK
# that virtual memory thing
# address space
$ cat /proc/`pidof sh`/maps
08048000-080ef000 r-xp /bin/sh
080ef000-080f1000 rwxp /bin/sh
080f1000-080f3000 rwxp
089a2000-089c4000 rwxp [heap]
f778a000-f778b000 rwxp /lib/x86_64-linux-gnu/libc-2.23.so
f887e000-f889c000 r-xp [vdso]
ffe09000-ffe2a000 rwxp [stack]
^^ addresses ^^ ^^ perms ^^ what’s inside
.text
.rodata
.data
.bss
~~ heap ~~
~~ stack ~~
mmap’d area (libs)
# quick history of sploit’n bins
> 1995 - Mudge, “How to write buffer overflows”� > 1996 - Aleph One, “Smashing the stack for fun and profit”� < We’ll stop executing things you can write to!� > 1997 - Solar Designer, “Getting around non-executable stack”� > 2001 - Nergal, “Advanced return-into-lib(c) exploits”� < We’ll make it so you don’t know where things are!� > 2002 - Tyler Durden, “Bypassing PaX ASLR protection”� > 2005 - Sebastian Krahmer, “Borrowed code chunks technique”� < We’ll... umm, alright I don’t really know.
(@ceyxiest)�
# good old exploitation
> reason things suck:
# so what now?
.text
.rodata
.data
.bss
~~ heap ~~
~~ stack ~~
mapped libraries
# but why?
~~~ THE SOLUTION ~~~�
# chain what? chain where? chain who?
void func1(char * s) {� char buf[80];� strcpy(buf, s);�}�
# go-go-gadget RET!
Gadget: 0x00000000004008f5�0x00000000004008f5: sub esp, 8�0x00000000004008f8: add rsp, 8�0x00000000004008fc: ret
Gadget: 0x00000000004008e1�0x00000000004008e1: pop rsi�0x00000000004008e2: pop r15�0x00000000004008e4: ret�
# go-go-gadget RET!
0x400235:
syscall
0x4009e5:
pop rdi
ret
0x40073f:
mov al, 0x3b
xor rsi, rsi
ret
0x4003f9:
xor rax, rax
xor rdx, rdx
ret
pop rdi
xor rax, rax
xor rdx, rdx
mov al, 0x3b
xor rsi, rsi
syscall
RET addr ->
0x400235
WHO CARES
WHO CARES
...
AAAAAAAAAAAAAAAA
buf ->
saved RBP ->
AAAAAAAAAAAAAAAA
0x4009e5
0xb0010f
0x4003f9
0x40073f
0xb0010f:
“/bin/sh”
# ideal chain
RET addr ->
JUNK / exit()
...
AAAAAAAAAAAAAAAA
buf ->
saved RBP ->
AAAAAAAAAAAAAAAA
0x4009e5
0x7fcc67a1d5e9a
WHO CARES
...
/bin/sh ptr ->
system() addr ->
0x7fcc93f1e7d1f
system() RET addr ->
# auto-win
void MLG_360_noscope() in libc (64 bit):
# got a leak?
# okay so ROP is neat
# tooling
> notable:
# click clack auto ROP goodness
In [1]: import angr�In [2]: import angrop�In [3]: p = angr.Project("./bin")�In [4]: rop = p.analyses.ROP()�In [5]: rop.find_gadgets()�In [6]: chain = rop.set_regs(rdi=0x1337)�In [7]: chain.print_payload_code()�chain = ""�chain += p64(0x3973ca3) # pop rdi; ret �chain += p64(0x1337)�
rop.set_regs(rax=0x1337, rbx=0x56565656)
rop.write_to_mem(0x61b100, "/bin/sh\0")
rop.func_call("read", [0, 0x804f000, 0x100])
rop.add_to_mem(0x804f124, 0x41414141)
# other types of rop?
# more practice
# references
# thanks & hack responsibly