For the complete documentation index, see llms.txt. This page is also available as Markdown.

2.4.1 pwntools

Pwntools 是一个 CTF 框架和漏洞利用开发库,用 Python 开发,由 rapid 设计,旨在让使用者简单快速的编写 exp 脚本。包含了本地执行、远程连接读写、shellcode 生成、ROP 链的构建、ELF 解析、符号泄露众多强大功能。

安装

  1. 安装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
  2. 安装capstone:

    git clone https://github.com/aquynh/capstone
    cd capstone
    make
    sudo make install
  3. 安装pwntools:

    sudo apt-get install libssl-dev
    sudo pip install pwntools

如果你在使用 Arch Linux,则可以通过 AUR 直接安装,这个包目前是由我维护的,如果有什么问题,欢迎与我交流:

但是由于 Arch 没有 PPA 源,如果想要支持更多的体系结构(如 arm, aarch64 等),只能手动编译安装相应的 binutils,使用下面的脚本,注意将变量 VARCH 换成你需要的。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 和 srop

  • runner:运行 shellcode

  • shellcraft: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():接收数据直到 EOF

  • recvline(keepends=True):接收一行,可选择是否保留行尾的

  • recvrepeat(timeout=default):接收数据直到 EOF 或 timeout

  • recvuntil(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():关闭 NX

  • disasm(address, n_bytes):返回对指定虚拟地址进行反汇编后的字符串

  • offset_to_vaddr(offset):将指定偏移转换为虚拟地址

  • vaddr_to_offset(address):将指定虚拟地址转换为文件偏移

  • read(address, count):从指定虚拟地址读取 count 个字节的数据

  • write(address, data):在指定虚拟地址处写入 data

  • section(name):获取 name 段的数据

  • debug():使用 gdb.debug() 进行调试

最后还要注意一下 pwnlib.elf.corefile,它用于处理核心转储文件(Core Dump),当我们在写利用代码时,核心转储文件是非常有用的,关于它更详细的内容已经在前面 Linux基础一章中讲过,这里我们还是使用那一章中的示例代码,但使用 pwntools 来操作。

dynelf

pwnlib.dynelf.DynELF

该模块是专门用来应对无 libc 情况下的漏洞利用。它首先找到 glibc 的基地址,然后使用符号表和字符串表对所有符号进行解析,直到找到我们需要的函数的符号。这是一个有趣的话题,我们会专门开一个章节去讲解它。详见 4.4 使用 DynELF 泄露函数地址

fmtstr

pwnlib.fmtstr.FmtStrpwnlib.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.packstruct.unpack 函数,同时增加了对任意宽度整数的支持。

使用 p32, p64, u32, u64 函数分别对 32 位和 64 位整数打包和解包,也可以使用 pack() 自己定义长度,另外添加参数 endiansigned 设置端序和是否带符号。

cyclic 模块在缓冲区溢出中很有用,它帮助生成模式字符串,然后查找偏移,以确定返回地址。

Pwntools 在 CTF 中的运用

可以在下面的仓库中找到大量使用 pwntools 的 write-up: pwntools-write-ups

参考资料

Last updated