pwntools是一个ctf框架和漏洞利用开发库,用Python开发,由rapid设计,旨在让使用者简单快速的编写exploit。
安装:
pwntools对Ubuntu 12.04和14.04的支持最好,但是绝大多数的功能也支持Debian, Arch, FreeBSD, OSX, 等等,确保安装以下系统库。
Binutils
Ubuntu
Mac OS X
Alternate OSes
Capstone
Ubuntu
Mac OS X
Python Development Headers
Ubuntu
Mac OS X
获得发行版本
$ apt-get install python2.7 python2.7-dev python-pip
$ pip install pwntools
获得最新版本
$ git clone https://github.com/Gallopsled/pwntools
$ cd pwntools
$ pip install -e .
模块索引
pwnlib.asm — Assembler functions
pwnlib.atexception — Callbacks on unhandled exception
pwnlib.atexit — Replacement for atexit
pwnlib.constants — Easy access to header file constants
pwnlib.context — Setting runtime variables
pwnlib.dynelf — Resolving remote functions using leaks
pwnlib.elf — Working with ELF binaries
pwnlib.exception — Pwnlib exceptions
pwnlib.gdb — Working with GDB
pwnlib.log and — Logging stuff
pwnlib.memleak — Helper class for leaking memory
pwnlib.replacements — Replacements for various functions
pwnlib.rop — Return Oriented Programming
pwnlib.shellcraft — Shellcode generation
pwnlib.term — Terminal handling
pwnlib.timeout — Timeout handling
pwnlib.tubes — Talking to the World!
pwnlib.ui — Functions for user interaction
pwnlib.useragents — A database of useragent strings
pwnlib.util.crc — Calculating CRC-sums
pwnlib.util.cyclic — Generation of unique sequences
pwnlib.util.fiddling — Utilities bit fiddling
pwnlib.util.hashes — Hashing functions
pwnlib.util.iters — Extension of standard module itertools
pwnlib.util.lists — Operations on lists
pwnlib.util.misc — We could not fit it any other place
pwnlib.util.net — Networking interfaces
pwnlib.util.packing — Packing and unpacking of strings
pwnlib.util.proc — Working with /proc/
pwnlib.util.safeeval — Safe evaluation of python code
pwnlib.util.web — Utilities for working with the WWW
1 context 设置运行时变量
context.log_level = 'debug'
2 remote,listen,ssh,process
支持常见操作recvline, recvuntil, clean 可以通过.interactive()直接与程序交互
3 p32 and u32
前者将数字转化为字符串,后者反之
4 log
输出消息
log.info('Hello, world!')
p = log.progress('Working')
p.status('Reticulating splines')
time.sleep(1)
p.success('Got a shell!')
5 cyclic and cyclic_find 对于直接的缓冲区溢出,可以很方便的确认再偏移多少可以控制eip
cyclic(20)
cyclic_find('aafb')
6 asm and disasm 快速的汇编和反汇编代码
asm('mov eax, 0')
asm(shellcraft.sh())
disasm('\xb8\x0b\x00\x00\x00')
7 shellcraft 提供了很多现成shellcode
8 ELF 用来操作ELF文件的工具
elf = ELF('pwn')
hex(elf.address)
hex(elf.symbols['write'])
hex(elf.got['write'])
hex(elf.plt['write'])
9 DynELF 通过信息泄露获得远程函数地址
可以没有程序
p = process('./pwnme')
def leak(address):
data = p.read(address, 4)
return data
main = 0xfeedf4ce
d = DynELF(leak, main)
d.lookup('system', 'libc')
如果有程序,速度会更快
d = DynELF(leak, main, elf=ELF('./pwnme'))
10 ROP 简化产生ROP链的操作
11 gdb.debug 和 gdb.attach
1 用gdb启动程序,并弹出新窗口与其交互
2 附加到一个程序上,pid/pwnlibs.tubes/socket都可以
12 args 快速访问所有的命令行参数
python foo.py REMOTE=1
args['REMOTE'] == '1'
13 一些实用工具
b64d('dGVzdA==')
b64e("test")
bits(511, zero = "+", one = "-") 把参数转换为位
bits_str(511) 得到'0000000111111111'
enhex("test") 得到'74657374'
isprint(c) 判断一个字符是否可打印
randoms(10) 返回'evafjilupm'
rol('abcdefg', 2) 得到'cdefgab'
unhex("74657374") 得到'test'
urldecode("test%20%41")
urlencode
14 net 查询网络接口
15 proc 查询进程
16 pause
17 safeeval 执行python代码,但不会产生副作用
18 其他
hexdump
read and write
enhex and unhex
more
group
align and align_down
urlencode and urldecode
which
wget
————————————–
与pwnlib.tubes的常见交互方式
recv()
recvuntil()
recvline()读取到'\n'
recvlines(n)
recvall() 读取到EOF
send()
sendline()会自动加换行符
——————————-
>>> 'b800000000'.decode('hex')
'\xb8\x00\x00\x00\x00'
>>> '\xb8\x00\x00\x00\x00'.encode('hex')
'b800000000'
转自:http://www.91ri.org/14382.html
现在的exploit是越来越难,一般起手题都得是NX开启的,ROP这种以前都能出400分题的技术现在也就出50-100分题了非常惨,也许跟这个工具简化了ROP过程有关系?
先简单回顾一下ROP的原理,由于NX开启不能在栈上执行shellcode,我们可以在栈上布置一系列的返回地址与参数,这样可以进行多次的函数调用,通过函数尾部的ret语句控制程序的流程,而用程序中的一些pop/ret的代码块(称之为gadget)来平衡堆栈。其完成的事情无非就是放上/bin/sh,覆盖程序中某个函数的GOT为system的,然后ret到那个函数的plt就可以触发system('/bin/sh')。由于是利用ret指令的exploit,所以叫Return-Oriented Programming。(如果没有开启ASLR,可以直接使用ret2libc技术)
好,这样来看,这种技术的难点自然就是如何在栈上布置返回地址以及函数参数了。而ROP模块的作用,就是自动地寻找程序里的gadget,自动在栈上部署对应的参数。
elf = ELF('ropasaurusrex')
rop = ROP(elf)
rop.read(0, elf.bss(0x80))
rop.dump()
# ['0x0000: 0x80482fc (read)',
# '0x0004: 0xdeadbeef',
# '0x0008: 0x0',
# '0x000c: 0x80496a8']
str(rop)
# '\xfc\x82\x04\x08\xef\xbe\xad\xde\x00\x00\x00\x00\xa8\x96\x04\x08'
使用ROP(elf)来产生一个rop的对象,这时rop链还是空的,需要在其中添加函数。
因为ROP对象实现了__getattr__的功能,可以直接通过func call的形式来添加函数,rop.read(0, elf.bss(0x80))实际相当于rop.call('read', (0, elf.bss(0x80)))。
通过多次添加函数调用,最后使用str将整个rop chain dump出来就可以了。
call(resolvable, arguments=()) : 添加一个调用,resolvable可以是一个符号,也可以是一个int型地址,注意后面的参数必须是元组否则会报错,即使只有一个参数也要写成元组的形式(在后面加上一个逗号)
chain() : 返回当前的字节序列,即payload
dump() : 直观地展示出当前的rop chain
raw() : 在rop chain中加上一个整数或字符串
search(move=0, regs=None, order=’size’) : 按特定条件搜索gadget,没仔细研究过
unresolve(value) : 给出一个地址,反解析出符号