每日一pwn[pwn1_sctf_2016]
每日一pwn[pwn1_sctf_2016]
前言
在寒假玩了太久后的第一次刷题,直接来个每日一pwn,就当恢复训练了
分析
代码简单分析了一下
总的来说就是一个C++的逆向分析,总的来说不算难,但是对于没有接触过C++的来说,还是有点难以理解的。后面会简单介绍一下关于这段代码的。
1 | printf("Tell me something about yourself: "); |
这段代码就是打印提示语句,然后从edata这个流获取输入,和C语言里面没区别
1 | std::string::operator=((int)&input, (int)s); |
这段代码就很有C++的特性了,因为C++里面出现了一个新的方式那就命名空间的说法,其实可以理解为就是调用库的形式。这段代码就可以理解为从标准库的string模块调用operator这个函数,于是我们搜索的时候,便可以搜索std::string::operator()
函数的作用,或者看汇编代码默认识别的函数格式
于是我们知道这个函数其实就是将s的数据转换为C++格式的string类型那种格式
1 | std::allocator<char>::allocator(&v6); |
这段代码看着很复杂,其实很简单,首先就是通过allocator去申请一个V6的空间,然后通过string函数进行转换,类似于c语言的
1 | char v6="you"; |
然后就是一个自己写的函数了
1 | replace((std::string *)v4, (std::string *)&input, (std::string *)v7); |
看着很复杂,其实看懂几个关键的函数就行了,我们发现存在一个函数是find函数,以我们c语言的知识可以知道这个是查找字符的函数,百度搜索这个函数发现确实是的,于是我们可以发现,该函数在我们输入的字符串里面寻找"I"这个字符串
,并且我们动态调试后发现实现了将I替换为you这个功能。
接下来的代码就是一下赋值和销毁数据的代码了
1 | std::string::operator=(&input, v5, v2, v3); |
所有的函数前面有~
的都是用于销毁数据的。
1 | v0 = (const char *)std::string::c_str((std::string *)&input); |
c_str
函数返回一个指针,并将数据复制到s里面去,我们可以知道s只有32个字节,经过转换复制后的v0可以超过32字节,赋值回去后便会溢出
漏洞点
赋值回去后会存在溢出,并且函数存在后门函数
于是直接打一个栈溢出就行
s在栈上的位置为0x3c于是我们想办法将其覆盖就行0x3c/3=20,于是只需要20个“I”经过扩容后,就能覆盖到ebp,再覆盖一个ebp,最后就能覆盖返回地址了
payload=”I”*20+”AAAA”+p64(get_flag_addr)即可
exp
1 | from pwn import * |