PwnTools使用技巧
PwnTools使用技巧
一. 通过上下文设置目标平台
二. 本地进程对象的创建
语法如下:
通过声明的二进制文件路径可在本地创建新的进程并与其进行交互在上面创建的进程中,stdin默认使用的是管道。可以通过stdin=PTY来更改默认的设置,这样就能够以交互的方式进行操作。管道是一个单向的数据通道,数据只能从一端写入,从另一端读出。要实现双向的进程间交互,往往需要两个管道。stdout默认使用的是虚拟终端,这样共享库所提供的缓冲功能便失效。Linux进程的标准输入和输出如图3.4所示。
用这个可以实现本地的交互,查看本地是否可以实现相应功能。
三. 远程进程对象的创建
四. ELF模块
用户可以通过ELF模块获取程序基地址、函数地址(基于符号)、函数.got表地址、函数.plt表地址等。
常用的ELF模块API如下:
symbols['a_function']:用于获取函数a_function()的偏移地址。
got['a_function']:用于获取函数a_function()在.got表中的地址。
plt['a_function']:用于获取函数a_function()在.plt表中的地址。next(e.search(“some_characters”)):用于获取包含some_characters的字符串、汇编代码或者某个数值的地址。
五. search方法
六. cyclic命令的功能
cyclic命令的功能跟PEDA中的pattern_create和pattern_offset的功能类似,分别用于字符串的生成和子串偏移量的查找。执行cyclic命令的方式有两种,分别是命令行工具的方式和通过Python脚本文件调用函数的方式。
(1)字符串的生成
①通过命令行工具方式实现字符串的生成。使用pwn cyclic count命令或者cyclic count命令可以直接在shell命令提示符下生成字符串,例如:
②通过Python脚本文件调用函数cyclic(count)实现字符串的生成。例如:
这样就可以直接生成字符串,不需要手动输入。
(2)子串偏移量的查找
①命令行工具方式实现子串偏移量的查找。使用pwn cyclic-l substr命令可以直接在shell命令提示符下查找子串偏移量,例如:[插图]第一个子串偏移量为0,若没有找到子串则返回-1。
②通过Python脚本文件调用函数cyclic_find(subpattern)实现子串偏移量的查找。例如,通过调用下面的函数可以查找subpattern在pattern中的偏移量。[插图]通过cyclic命令可以获取缓冲区溢出攻击中保存的返回地址(通过pop命令弹出到IP/PC)在缓冲区中对应的偏移量。例如,在栈溢出时,可以创建cyclic(0x100)或者更长的pattern并输入数据,若在输入数据后PC/EIP的值变成0x61616161,那么就可以通过cyclic_find(0x61616161)获知会从哪一个字节开始时控制PC/EIP寄存器,可以避免很多没必要的计算。
七. 数据转化
Pwntools可以依据上下文中的字节次序对数据进行打包和解包,实现字符串和整数之间的转换。对于整数的打包与解包,可以使用p32()、p64()、u32()、u64()等函数,分别对应着32位和64位的整数的打包与解包。通过p32()函数可以将整数类型转换为小端格式的字节类型,但存在的问题是在Python 2中与在Python 3中的格式是不一样的。在Python 3中,字节类型跟字符串类型不一样,是一个独立的类型;而在Python 2中,字符串类型和字节类型可以通用。
八. shellcraft模块
shellcraft模块是漏洞代码(shellcode)的生成器,主要的命令如下:
shellcraft-l:显示Pwntools自带的shellcode。
shellcraft-l|grep i386.linux.sh:显示Pwntools自带的32位系统的Shellcode。
shellcraft-f a i386.linux.sh:以汇编的格式显示Pwntools自带的32位系统的shell-code。
32位代码如下:
运行结果如下:
分为:指令,汇编代码,机器码三部分
与在32位系统中生成shellcode类似,在64位系统中需要将context.update(arch='i386',os='linux')改为context.update(arch='amd64',os='linux',bits=64)。
九. ROP模块
ROP模块的作用是自动寻找程序里的gadget,在进行ROP攻击时自动在栈上部署对应的参数。(在gadget要应用的时候再查找有关资料)
十. GDB模块
Pwntools中的GDB模块提供了一些可用于动态调试ELF文件的API,其中最常用的是attach()函数,在指定进程之后可以使用attach()函数来调试该进程,配合Proc模块就可以得到对应进程的PID。attach()函数需要开启一个新的终端,该终端的类型必须由环境变量或者上下文对象来指定。具体示例如下
上述代码首先通过proc.pidof(p)[0]取出进程的PID,然后使用attach()函数进行调试。context.terminal指定的是终端类型和参数,这里用的是gnome-terminal,运行后会自动打开一个新的gnome-terminal,在里面启动GDB模块并自动断下来,这样就可以调试了。另外,也可以在使用attach()函数时指定GDB脚本文件,这样可以在希望的地方停下来。在使用attach()函数时可不需要通过proc.pidof()来获取进程的PID,可以直接传入进程来调用attach()函数,同时也可以通过GDB脚本文件传入一个文件对象,如way 4所示。
(这种看看别人的EXP再慢慢学习一下即可,都是可以直接照搬的模板)
十一. 数据交互
(1)数据发送的常用函数如下:
send(payload):发送payload。
sendline(payload):发送payload,并进行换行(末尾加\n)。sendafter(some_string,payload):接收到some_string后,发送payload。
(2)数据接收的常用函数如下:
recv(numb=字节大小,timeout=default):接收指定字节数。
recvall():一直接收直到达到文件末尾(EOF)。
recvline(keepends=True):接收一行,keepends用于设置是否保留行尾的\n。
recvuntil(delims,drop=False):一直读到delims的pattern出现为止。
recvrepeat(timeout=default):持续接收直到文件末尾或timeout。