![记录第一道Pwn题 | My "Hello-World" for Pwn!](/images/article_images/myfirstpwn/cover.png)
记录第一道Pwn题 | My "Hello-World" for Pwn!
![](/images/avatar.jpg)
[Pwn入门] 我的第一道Pwn题
即使它很简单,这也是我新的开始。纯菜,仅做记录 →题目”rip”←
1. 程序文件查看
首先下载下来附件”pwn1”,然后checksec
一下:
发现没有保护。有保护我能做出来吗
直接扔进IDA,发现有两个函数,”main”与”fun”,进去看一下代码。
反编译一下得到:
1 | //mian |
2. 分析
很明显main的gets函数没有检查,这里存在缓冲区溢出可以利用。看一下mian的函数栈:
这里-0x01到-0x0F是字符串*s的空间(byte*15),+0x00是上个栈的rbp地址(64bit address),+0x08的r(64bit adress)是main函数的返回地址。我们的目标就是通过未检测用户输入长度的gets()
篡改r使main在return的时候转跳至fun来,继而获取shell。这里注意,因为对齐问题,我们要返回两次。 原因见文末
因此我们需要做的很简单:
- 输入长(0x08+0x0F)的垃圾字节填满上个栈的rbp与*s。
- 继续输入,覆盖main堆栈中的返回值r为mian的汇编码中
retn
的地址。(本题为0x401185,详见上图汇编代码) - 继续输入,覆盖后面64位为fun函数的起始地址。(本题为0x401186)
3. 编写exp/流程详解
依上文思路构建exp如下:
1 | from pwn import * |
终端运行python3 exp.py
,可以看到已经返回shell。ls
发现根目录有flag文件,cat flag
读出即可。
下面我们详细看下攻击的执行流程。(对比main最后几行汇编代码食用)
这是我们已经溢出过的栈:
leave过后即将执行retn时,rsp指向0x08,此时执行retn,执行后将会使rip指向0x401185,即还是这句retn,并使rsp-8,指向0x10。这一次retn执行后的栈:
(注意1:此时PC指向retn,程序下一句还是retn)
(注意2:此时栈并未对齐0x10,无法直接执行system()
)
然后继续执行,还是retn,这时由于rsp指向的是fun,这会导致rip指向fun的入口,进而执行fun的内容。且这次retn后栈已对齐0x10,可以正常执行system()函数,进而返回shell
4. 关于栈的对齐
又开了篇文章,详见本博客《栈对齐》
- 标题: 记录第一道Pwn题 | My "Hello-World" for Pwn!
- 作者: Atomic
- 创建于 : 2024-07-27 10:00:00
- 更新于 : 2024-09-12 08:49:52
- 链接: https://blog.atom1c.icu/2024/07/27/myfirstpwn/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。