0x01 简介
pwntools是一个CTF Pwn漏洞利用开发库,用于编写各种与Pwn题目进行交互和攻击利用的脚本。其由Python开发,由rapid设计,旨在让使用者简单快速的编写exploit。
0x02 安装
安装:pip install pwntools
当然只是在Linux环境适用,建议安装在Ubuntu环境而非Kali,Kali上会有很多问题。其中对Ubuntu 12.04和14.04的支持最好,但是绝大多数的功能也支持Debian、Arch、FreeBSD、OSX等等。
0x03 各个模块
通常在py文件头部写上from pwn import *即可导入所有需要的pwntools工具。
连接方式
1 2 3
| sh = porcess("./test") sh = remote("127.0.0.1",10001) sh.close()
|
IO模块
1 2 3 4 5 6 7 8
| sh.send(data) sh.sendline(data) sh.recv(numb = 2048, timeout = dufault) sh.recvline(keepends=True) sh.recvuntil("Hello,World\n",drop=fasle) sh.recvall() sh.recvrepeat(timeout = default) sh.interactive()
|
ELF文件操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| >>> e = ELF('/bin/cat') >>> print hex(e.address) 0x400000 >>> print hex(e.symbols['write']) 0x401680 >>> print hex(e.got['write']) 0x60b070 >>> print hex(e.plt['write']) 0x401680 >>> print hex(e.search('/bin/sh').next())
libc = e.libc libc.address = libc_start_main_addr - libc.symbols['__libc_start_main'] libc.symbols['system'] next(libc.search('/bin/sh'))
|
整数pack与数据unpack
pack:p32,p64
unpack:u32,u64
汇编和反汇编
汇编:
1 2 3 4
| >>> asm('nop') '\x90' >>> asm('nop', arch='arm') '\x00\xf0 \xe3'
|
可以使用context来指定cpu类型以及操作系统:
1 2 3 4
| >>> context.arch = 'i386' >>> context.os = 'linux' >>> context.endian = 'little' >>> context.word_size = 32
|
使用disasm进行反汇编:
1 2 3 4 5
| >>> print disasm('6a0258cd80ebf9'.decode('hex')) 0: 6a 02 push 0x2 2: 58 pop eax 3: cd 80 int 0x80 5: eb f9 jmp 0x0
|
注意,asm需要binutils中的as工具辅助,如果是不同于本机平台的其他平台的汇编,例如在我的x86机器上进行mips的汇编就会出现as工具未找到的情况,这时候需要安装其他平台的cross-binutils。
Shellcode生成器
1 2 3 4 5 6 7 8
| >>> print shellcraft.i386.nop().strip('\n') nop >>> print shellcraft.i386.linux.sh() /* push '/bin///sh\x00' */ push 0x68 push 0x732f2f2f push 0x6e69622f ...
|
结合asm可以可以得到最终的pyaload:
1 2 3 4 5 6 7 8
| from pwn import * context(os='linux',arch='amd64') shellcode = asm(shellcraft.sh())
或者
from pwn import * shellcode = asm(shellcraft.amd64.linux.sh())
|
除了直接执行sh之外,还可以进行其它的一些常用操作例如提权、反向连接等等。
ROP链生成器
1 2 3 4 5 6 7 8 9 10
| elf = ELF('ropasaurusrex') rop = ROP(elf) rop.read(0, elf.bss(0x80)) rop.dump()
str(rop)
|
使用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) : 给出一个地址,反解析出符号
GDB调试
当在运行py时添加参数M,则会将进程attach到GDB上调试:
1 2
| if args.M: gdb.attach(p)
|
DEBUG日志
当 context.log_level被设置为 “DEBUG” , 我们的输入和服务器的输出会被直接输出:
1
| context.log_level = 'DEBUG'
|
0x04 参考
pwntools使用