pwntools

pwntools是一个CTF框架和漏洞利用开发库,用Python开发,旨在让使用者简单快速的编写exploit。

用法汇总

导入与环境设置

1
2
3
4
5
6
7
from pwn import *   #导入包

#os设置系统为linux系统
#arch设置架构为32/64位
#log_level设置日志输出的等级为debug(会将完整的io过程都打印下来,方便出现问题时排查错误)
context(os='linux', arch='i386', log_level='debug')
context(os='linux', arch='amd64', log_level='debug')

连接

1
2
3
4
5
6
# 第一种连接方式,通过ip和port去连接
conn = remote('127.0.0.1', 8888)
# 第二种连接方式,通过ssh连接
shell = ssh(host='192.168.14.144', user='root', port=2222, password='123456')
# 第三种连接方式,打开程序,开启进程
p = process('./reverse0')

打包函数

p32/p64: 打包一个整数,分别打包为32位或64位
u32/u64: 解包一个字符串,得到整数

1
2
3
# 比如将0xdeadbeef进行32位的打包,将会得到'\xef\xbe\xad\xde'(小端序)
payload = p32(0xdeadbeef) #pack 32 bits number
payload = p64(0xdeadbeef) #pack 64 bits number

发送和接收数据

1
2
3
4
5
6
7
8
conn.send(data) #发送数据
conn.sendline(data) #发送一行数据,相当于在数据后面加\n
conn.recv(numb = 2048, timeout = default) #接收数据,numb制定接收的字节,timeout指定超时
conn.recvline(keepends=True) #接受一行数据,keepends为是否保留行尾的\n
conn.recvuntil("Hello,World\n",drop=false) #接受数据直到我们设置的标志出现
conn.recvall() #一直接收直到 EOF
conn.recvrepeat(timeout = default) #持续接受直到EOF或timeout
conn.interactive() #直接进行交互,相当于回到shell的模式,在取得shell之后使用

ELF模块

用于获取ELF文件的信息,首先使用ELF()获取这个文件的句柄,然后使用这个句柄调用函数,和IO模块很相似。

1
2
3
4
5
e = ELF('/bin/cat')
print(hex(e.address)) # 获取文件装载的基地址
print(hex(e.symbols['write'])) # 获取函数地址(基于符号)
print(hex(e.got['write'])) # 获取函数got表的地址
print(hex(e.plt['write'])) # 获取函数plt表的地址

汇编与反汇编

1
2
asm('mov eax, 0')   #汇编
disasm('\xb8\x0b\x00\x00\x00') #反汇编

生成shellcode

先通过context设置架构,然后生成shellcode。

1
2
context(arch='i386', os='linux')  #设置环境
shellcode = asm(shellcraft.sh()) #打印出汇编后的shellcode

调用gdb调试

在python文件中直接设置断点,当运行到该位置之后就会断下。

1
2
3
from pwn import *
p = process('./c')
gdb.attach(p)

Cyclic Pattern

使用pwntools生成一个pattern,pattern指一个字符串,可以通过其中的一部分数据去定位到其在一个字符串中的位置。

如,在栈溢出的时候,首先构造cyclic(0x100),或者更长长度的pattern,进行输入,输入后pc的值变为0x61616161,那么再通过cyclic_find(0x61616161)就可以得到从哪一个字节开始会控制PC寄存器了,避免了很多没必要的计算。

1
2
3
cyclic(0x100) # 生成一个0x100大小的pattern,即一个特殊的字符串
cyclic_find(0x61616161) # 找到该数据在pattern中的位置
cyclic_find('aaaa') # 查找位置也可以使用字符串去定位

常用脚本

  • SHA / MD5 认证

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from pwn import *
    from parse import *
    from pwnlib.util.iters import bruteforce
    import string
    from hashlib import sha256

    def brute_force(prefix,s):
    return bruteforce(lambda x:sha256(x+prefix).hexdigest()==s,string.ascii_letters+string.digits,length=4,method='fixed')

    r = remote("34.74.30.191",1337)
    data = r.recvline()
    prefix, s = parse("sha256(XXXX+{}) == {}",data)
    r.recvline()
    r.sendline(brute_force(prefix,s))