Canary绕过总结
1.有循环时,32或者64位程序下都可以逐字节爆破绕过。
2.可通过printf字符串漏洞来泄露(%p.%p.%p….)。
3.通过打印栈上数据的打印函数栈溢出连上canary泄露出来。
4.当程序直接读取flag进入内存时,利用函数__stack_chk_fail,加上足够长度的栈溢出覆盖argv[0]为程序中保存flag的地址。这样当__stack_chk_fail运行时就会打印出argv[0]中地址上对应的内容,也就是flag。有时候需要设置远程环境变量LIBC_FATAL_STDERR_=1,将flag打印在本地。
5.由pthread出来的线程函数中如果有足够长度的栈溢出,可以直接覆盖canary来源tcbhead_t结构体中的canary和栈中的canary为同一数值,这样检查仍旧通过。
(64位中为fs:[28h],32位中为gs:[14h])
▲查找方法:
(1)pwndbg>catch syscall 158
(2)查看rsi寄存器,里面存的内容就是tcbhead_t结构体的首地址。
(3)之后就可以查看canary的值:
但是这个方法好像不怎么顶用了,libc2.23及以下都行,但是libc2.27就会出现无法访问的错误,具体的原因好像是libc升级之后添加了什么东西设置了不可访问:
32位下没有arch_prctl这个系统调用了,需要看canary的生成函数调用了什么系统调用,方法类似,下断点之后查出来。
★IDA中远程调试也可以查出来,利用程序开头的fs:28,找到地址,然后减去libc基地址就可以得到偏移。但是需要libc一致,偏移才会一致。而且这个偏移并不是在libc数据段上,只是程序初始化时放在后面的,所以不同的程序不同的libc都会导致偏移不一样,需要具体调试。
▲长度一般为rbp+2000左右,不同的Libc版本都不太一样,需要调试才能知道。原因是通过pthread出来的线程函数栈会被安置到与TLS相差约2000字节的距离处:
这里可以看到,第一个是main函数栈,第二个是在main函数中通过pthread进程创建并且调用的函数栈,两者相差将近0x700000000这么远,完全不是正常的函数调用相差的栈距离。同时在该函数中rbp指向的始终是0000(全是),该函数结束后会先跳转到libc中的libpthread来恢复栈。
1 | #注释头 |