pwn中常使用的工具
前言
pwn作为CTF比赛中的重要一部分,用到的工具不及其他部分的多,但是工具相对来说也比较难用。主要用的工具有:pwntools、checksec、ROPgadget、one_gadget、gdb+pwndbg、IDA pro等等。
0x1 pwntools
pwntools是一个用Python编写的CTF框架和开发库,旨在快速构建原型和开发,并旨在使编写利用脚本尽可能简单。
通过以下命令用来安装python3下的pwntools包:
$ sudo apt-get update
$ sudo apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
$ python3 -m pip --default-timeout=100 install --upgrade pip
$ python3 -m pip --default-timeout=100 install --upgrade pwntools
以上命令执行完毕后进入python3输入 from pwn import *
,如下图显示则安装成功。
0x2 checksec
checksec是一个脚本软件,在安装pwntools后被顺带安装,可以用来查看可执行文件的程序架构信息和保护信息。如下图使用:
0x3 ROPgadget
ROPgadget这个工具允许你在二进制文件中搜索代码gadget片段,以方便ROP的利用。ROPgadget支持x86、x64、ARM、ARM64、PowerPC、SPARC和MIPS架构上的ELF/PE/Mach-O格式。在安装pwntools后被顺带安装。以下是常用的ROPgadget指令:
# 查找可存储寄存器的代码
$ ROPgadget --binary rop --only 'pop|ret'
# 查找字符串
$ ROPgadget --binary rop --string "/bin/sh"
# 查找有int 0x80的地址
$ ROPgadget --binary rop --only 'int'
0x4 one_gadget
one-gadget 是glibc里调用execve(’/bin/sh’, NULL, NULL)的一段非常有用的gadget。在我们能够控制ip(也就是pc)的时候,用one-gadget来做RCE(远程代码执行)非常方便,比如有时候我们能够做一个任意函数执行,但是做不到控制第一个参数,这样就没办法调用system(“sh”),这个时候one-gadget就可以搞定了。如果你想知道one-gadget原理,click here!
通过以下命令安装one_gadget:
# 先安装ruby
$ sudo add-apt-repository ppa:brightbox/ruby-ng
$ sudo apt-get update
$ sudo apt-get remove ruby
$ sudo apt-get install ruby2.6 ruby2.6-dev
# 再安装one_gadget
$ sudo gem install one_gadget
one-gadget 的使用非常简单,比如说希望在某个libc中找到某段启动shell的gadget,只需键入以下命令:$ one_gadget libc-2.23.so
可见输出结果不仅仅给出了gadget对应的libc偏移,还给出了约束,这样只需要控制程序在满足约束的前提下跳转到对应的地址执行gadget便可以获得shell。
0x5 libc database search
在进行libc基址泄露的时候,常常不知道远程服务器用的是什么版本的libc,此时便可以通过libc database search这个网站来查询所用的libc版本,只需要将泄露的函数名和泄露的函数绝对地址或绝对地址的后12位填入表单中,点击查找则可以找到可能的libc版本。其原理是由于内存分配是以页为单位,而一个页是4K个字节,也就是需要用12位二进制来存储,所以libc在加载到内存中,低12位地址是固定不变的。
如下所示:
找到的libc有:
同时会提供下载接口和一些常用函数的偏移:
0x6 GDB+pwndbg
GDB 全称“GNU symbolic debugger”,从名称上不难看出,它诞生于 GNU 计划,是 Linux 下常用的程序调试器。发展至今,GDB 已经迭代了诸多个版本,当下的 GDB 支持调试多种编程语言编写的程序,包括 C、C++、Go、Objective-C、OpenCL、Ada 等。实际场景中,GDB 更常用来调试 C 和 C++ 程序。而pwndbg (/poʊndbæg/)是一个GDB插件,它使得用GDB进行调试变得不那么麻烦,且更加专注于底层软件开发人员、硬件黑客、反向工程师和开发人员所需的特性。而pwndbg是GDB上的一种插件,可以使得调试功能更强大。
GDB一般在安装C/C++编译套件的时候会被自动安装到系统中,在没有给它装插件的情况下,GDB的运行如下:
可以使用如下命令安装pwndbg插件:
$ git clone https://github.com/pwndbg/pwndbg
$ cd pwndbg
$ ./setup.sh
在安装好pwndbg后,打开GDB如下:
gdb+pwndbg的常用基本指令:
-
r
:开始运行程序 -
b [funcname/*addr]
:在某个函数起始处或某个指令地址处下断点 -
c
:继续执行程序 -
ni
:单步步过 -
s
:单步步入 -
stop
:停止执行 -
q
:退出gdb -
stack [num]
:查看栈帧 -
info b
:查看断点详细信息 -
delete
:删除所有断点 -
delete [break point num]
: 根据断点号删除指定的断点,用空格隔开可以删除多个断点 -
vmmap
:查看程序内存结构 -
aslr on/off
:打开/关闭aslr -
got
:查看got表信息 -
plt
:查看plt表信息 -
x/[n/f/u] [addr]
:查看任意内存位置的值
n:是正整数,表示需要显示的内存单元的个数,即从当前地址向后显示n个内存单元的内容,一个内存单元的大小由第三个参数u定义。f:表示addr指向的内存内容的输出格式,s对应输出字符串,此处需特别注意输出整型数据的格式:
x 按十六进制格式显示变量.
d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。u:就是指以多少个字节作为一个内存单元unit,默认为4。u还可以用被一些字符表示:
如b=1 byte, h=2 bytes,w=4 bytes,g=8 bytes.addr:表示内存地址。
演示如:x/22dw 0x0804A220
参考资料:《CTF 竞赛入门指南》、CTF Wiki