2.4.1 pwntools
Pwntools 是一个 CTF 框架和漏洞利用开发库,用 Python 开发,由 rapid 设计,旨在让使用者简单快速的编写 exp 脚本。包含了本地执行、远程连接读写、shellcode 生成、ROP 链的构建、ELF 解析、符号泄露众多强大功能。
安装
安装binutils:
git clone https://github.com/Gallopsled/pwntools-binutils sudo apt-get install software-properties-common sudo apt-add-repository ppa:pwntools/binutils sudo apt-get update sudo apt-get install binutils-arm-linux-gnu安装capstone:
git clone https://github.com/aquynh/capstone cd capstone make sudo make install安装pwntools:
sudo apt-get install libssl-dev sudo pip install pwntools
如果你在使用 Arch Linux,则可以通过 AUR 直接安装,这个包目前是由我维护的,如果有什么问题,欢迎与我交流:
但是由于 Arch 没有 PPA 源,如果想要支持更多的体系结构(如 arm, aarch64 等),只能手动编译安装相应的 binutils,使用下面的脚本,注意将变量 V 和 ARCH 换成你需要的。binutils源码
测试安装是否成功:
模块简介
Pwntools 分为两个模块,一个是 pwn,简单地使用 from pwn import * 即可将所有子模块和一些常用的系统库导入到当前命名空间中,是专门针对 CTF 比赛的;而另一个模块是 pwnlib,它更推荐你仅仅导入需要的子模块,常用于基于 pwntools 的开发。
下面是 pwnlib 的一些子模块(常用模块和函数加粗显示):
adb:安卓调试桥args:命令行魔法参数asm:汇编和反汇编,支持 i386/i686/amd64/thumb 等constants:对不同架构和操作系统的常量的快速访问config:配置文件context:设置运行时变量dynelf:用于远程函数泄露encoders:对 shellcode 进行编码elf:用于操作 ELF 可执行文件和库flag:提交 flag 到服务器fmtstr:格式化字符串利用工具gdb:与 gdb 配合使用libcdb:libc 数据库log:日志记录memleak:用于内存泄露rop:ROP 利用模块,包括 rop 和 sroprunner:运行 shellcodeshellcraft:shellcode 生成器term:终端处理timeout:超时处理tubes:能与 sockets, processes, ssh 等进行连接ui:与用户交互useragents:useragent 字符串数据库util:一些实用小工具
使用 Pwntools
下面我们对常用模块和函数做详细的介绍。
tubes
在一次漏洞利用中,首先当然要与二进制文件或者目标服务器进行交互,这就要用到 tubes 模块。
主要函数在 pwnlib.tubes.tube 中实现,子模块只实现某管道特殊的地方。四种管道和相对应的子模块如下:
pwnlib.tubes.process:进程>>> p = process('/bin/sh')
pwnlib.tubes.serialtube:串口pwnlib.tubes.sock:套接字>>> r = remote('127.0.0.1', 1080)>>> l = listen(1080)
pwnlib.tubes.ssh:SSH>>> s = ssh(host='example.com, user='name', password='passwd')`
pwnlib.tubes.tube 中的主要函数:
interactive():可同时读写管道,相当于回到 shell 模式进行交互,在取得 shell 之后调用recv(numb=1096, timeout=default):接收指定字节数的数据recvall():接收数据直到 EOFrecvline(keepends=True):接收一行,可选择是否保留行尾的recvrepeat(timeout=default):接收数据直到 EOF 或 timeoutrecvuntil(delims, timeout=default):接收数据直到 delims 出现send(data):发送数据sendline(data):发送一行,默认在行尾加close():关闭管道
下面是一个例子,先使用 listen 开启一个本地的监听端口,然后使用 remote 开启一个套接字管道与之交互:
下面是一个与进程交互的例子:
shellcraft
使用 shellcraft 模块可以生成对应架构和 shellcode 代码,直接使用链式调用的方法就可以得到,首先指定体系结构,再指定操作系统:
asm
该模块用于汇编和反汇编代码。
体系结构,端序和字长需要在 asm() 和 disasm() 中设置,但为了避免重复,运行时变量最好使用 pwnlib.context 来设置。
汇编:(pwnlib.asm.asm)
请注意,这里我们生成了 i386 和 arm 两种不同体系结构的 nop,当你使用不同与本机平台的汇编时,需要安装该平台的 binutils,方法在上面已经介绍过了。
反汇编:(pwnlib.asm.disasm)
构建具有指定二进制数据的 ELF 文件:(pwnlib.asm.make_elf)
这里我们生成了 amd64,即 64 位 /bin/sh 的 shellcode,配合上 asm 函数,即可通过 make_elf 得到 ELF 文件。
另一个函数 pwnlib.asm.make_elf_from_assembly 允许你构建具有指定汇编代码的 ELF 文件:
与上一个函数不同的是,make_elf_from_assembly 直接从汇编生成 ELF 文件,并且保留了所有的符号,例如标签和局部变量等。
elf
该模块用于 ELF 二进制文件的操作,包括符号查找、虚拟内存、文件偏移,以及修改和保存二进制文件等功能。(pwnlib.elf.elf.ELF)
上面的代码分别获得了 ELF 文件装载的基地址、函数地址、GOT 表地址和 PLT 表地址。
我们常常用它打开一个 libc.so,从而得到 system 函数的位置,这在 CTF 中是非常有用的:
我们甚至可以修改 ELF 文件的代码:
下面是一些常用函数:
asm(address, assembly):汇编指定指令并插入到 ELF 的指定地址处,需要使用 ELF.save() 保存bss(offset):返回.bss段加上offset后的地址checksec():打印出文件使用的安全保护disable_nx():关闭 NXdisasm(address, n_bytes):返回对指定虚拟地址进行反汇编后的字符串offset_to_vaddr(offset):将指定偏移转换为虚拟地址vaddr_to_offset(address):将指定虚拟地址转换为文件偏移read(address, count):从指定虚拟地址读取count个字节的数据write(address, data):在指定虚拟地址处写入datasection(name):获取name段的数据debug():使用gdb.debug()进行调试
最后还要注意一下 pwnlib.elf.corefile,它用于处理核心转储文件(Core Dump),当我们在写利用代码时,核心转储文件是非常有用的,关于它更详细的内容已经在前面 Linux基础一章中讲过,这里我们还是使用那一章中的示例代码,但使用 pwntools 来操作。
dynelf
pwnlib.dynelf.DynELF
该模块是专门用来应对无 libc 情况下的漏洞利用。它首先找到 glibc 的基地址,然后使用符号表和字符串表对所有符号进行解析,直到找到我们需要的函数的符号。这是一个有趣的话题,我们会专门开一个章节去讲解它。详见 4.4 使用 DynELF 泄露函数地址
fmtstr
pwnlib.fmtstr.FmtStr,pwnlib.fmtstr.fmtstr_payload
该模块用于格式化字符串漏洞的利用,格式化字符串漏洞是 CTF 中一种常见的题型,我们会在后面的章节中详细讲述,关于该模块的使用也会留到那儿。详见 3.3.1 格式化字符串漏洞
gdb
pwnlib.gdb
在写漏洞利用的时候,常常需要使用 gdb 动态调试,该模块就提供了这方面的支持。
两个常用函数:
gdb.attach(target, gdbscript=None):在一个新终端打开 gdb 并 attach 到指定 PID 的进程,或是一个pwnlib.tubes对象。gdb.debug(args, gdbscript=None):在新终端中使用 gdb 加载一个二进制文件。
上面两种方法都可以在开启的时候传递一个脚本到 gdb,可以很方便地做一些操作,如自动设置断点。
memleak
pwnlib.memleak
该模块用于内存泄露的利用。可用作装饰器。它会将泄露的内存缓存起来,在漏洞利用过程中可能会用到。
rop
util
pwnlib.util.packing, pwnlib.util.cyclic
util 其实是一些模块的集合,包含了一些实用的小工具。这里主要介绍两个,packing 和 cyclic。
packing 模块用于将整数打包和解包,它简化了标准库中的 struct.pack 和 struct.unpack 函数,同时增加了对任意宽度整数的支持。
使用 p32, p64, u32, u64 函数分别对 32 位和 64 位整数打包和解包,也可以使用 pack() 自己定义长度,另外添加参数 endian 和 signed 设置端序和是否带符号。
cyclic 模块在缓冲区溢出中很有用,它帮助生成模式字符串,然后查找偏移,以确定返回地址。
Pwntools 在 CTF 中的运用
可以在下面的仓库中找到大量使用 pwntools 的 write-up: pwntools-write-ups
参考资料
Last updated
Was this helpful?