Gallopsled/pwntools — pull request #44 by zachriggle (2014-08-01 10:32:49+00:00)
Title: V2 rop

**Note** This changeset includes the changes in my `v2-elf` branch. Ignore `elf.py`, just look at `rop.py`.

Re-implement ROP for pwnv2 using Jon Salwan's [ROPgadget v5](https://github.com/JonathanSalwan/ROPgadget) (and by extension, [capstone](https://github.com/aquynh/capstone)). Also gain the ability to do 64-bit ROP for free.

Also added a `.dump` routine to dump out the ROP stack in an intelligible manner. Also enabled searching gadgets by which registers they pop, and how far the stack moves.

Still to-do: Add blacklisting functionality for the bytes that comprise gadget addresses.

```
>>> from pwn import *
>>> r = ROP([ELF('/bin/bash')])
[+] Started program '/bin/bash'
[*] Recieving all data...
[*] Program '/bin/bash' stopped with exit code 0
[+] Recieving all data: OK
[+] Binary loaded
[+] Loading gadgets, please wait...
[+] Gadgets loaded !
>>> r.call(0xf000baad)
>>> r.call(0xdeadcafe,())
>>> r.dump()
['adba00f0 0xf000baad ', 'fecaadde 0xdeadcafe ']
>>> r.call('read',(1,0xb00b5,0x1000))
>>> r.dump()
['adba00f0 0xf000baad ',
'fecaadde 0xdeadcafe ',
'b0da4100 0x41dab0 read',
'efbeadde 0xdeadbeef ', # <== dummy slot at end of ROP
'01000000 0x1 ',
'b5000b00 0xb00b5 ',
'00100000 0x1000 ']
>>> r.call(0xd0d0d0d0)
>>> r.dump()
['adba00f0 0xf000baad ',
'fecaadde 0xdeadcafe ',
'b0da4100 0x41dab0 read',
'd0d0d0d0 0xd0d0d0d0 ', # <== inserted in slot
'01000000 0x1 ',
'b5000b00 0xb00b5 ',
'00100000 0x1000 ']
>>> r.call(0xbeefbabe)
>>> r.dump()
['adba00f0 0xf000baad ',
'fecaadde 0xdeadcafe ',
'b0da4100 0x41dab0 read',
'6ae54100 0x41e56a pop rsp; pop r13; pop r14; ret', # <== updated to fix stack
'01000000 0x1 ',
'b5000b00 0xb00b5 ',
'00100000 0x1000 ',
'd0d0d0d0 0xd0d0d0d0 ', # <== moved
'bebaefbe 0xbeefbabe ']
>>> print repr(r)

>>> print repr(str(r))
'\xad\xba\x00\xf0\xfe\xca\xad\xde\xb0\xdaA\x00j\xe5A\x00\x01\x00\x00\x00\xb5\x00\x0b\x00\x00\x10\x00\x00\xd0\xd0\xd0\xd0\xbe\xba\xef\xbe'
>>> next((hex(addr),info) for addr,info in r.gadgets.items() if {'r12','r13'} & set(info['regs']))
('0x4aaa7eL', {'insns': ['add esp, 0x38', 'pop rbx', 'pop rbp', 'pop r12', 'pop r13', 'ret'], 'move': 76, 'regs': ['rbx', 'rbp', 'r12', 'r13']})
```

Additionally, support for using multiple ELF files was added.

```
>>> from pwn import *
>>> bash=ELF('/bin/bash')
>>> r = ROP([bash])
>>> r.call('system',[0xcafebabe])
Exception: Could not resolve 'system'
>>> bash.libs
{'/lib/x86_64-linux-gnu/libc.so.6': 140602609119232,
'/lib/x86_64-linux-gnu/libdl.so.2': 140602613075968,
'/lib/x86_64-linux-gnu/libtinfo.so.5': 140602615189504}
>>> libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
>>> r=ROP([bash,libc])
>>> r.call('system',[0xcafebabe])
>>> r.dump()
['b0d862f7ff7f0000 0x7ffff762d8f0 __libc_system',
'efbeadde00000000 0xdeadbeef ',
'bebafeca00000000 0xcafebabe ']
```

And for reference:

```
(gdb) p/x &__libc_system
$2 = 0x7ffff762d8f0
```