TMUCTF 2021 Writeup (English)

I mainly worked on Reversing challenge (by solo). There were lots of exciting challenges.

Thanks to all of the TMUCTF 2021 organizers for opening this awesome CTF competition!!!

Pwn

Because of somehow reason, I have worked on one pwn challenge. I wonder why.

Warmup

Just a basic buffer overflow challenge.

$ nc 194.5.207.56 7000
=================================================================
=     ____ _    _    ____ ____ ____   ____ ____ ____    __      =
=     |_ _\|\/\ || \ | __\|_ _\|  _\  |   \|   ||   \  / |      =
=       || |   \||_|\| \__  || | _\   '-'_/| \ |'-'_/ /_ |      =
=       |/ |/v\/|___/|___/  |/ |/     |___]|___||___]   \|      =
=                                                               =
=================================================================
Welcome to TMUCTF 2021! Let us know your name:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Thanks!

TMUCTF{n0w_y0u_4r3_w4rm3d_up}

Flag: TMUCTF{n0w_y0u_4r3_w4rm3d_up}

Rev

UnBIOSed

Running the distributed program returns error message that indicates this program is written by Python. By using pyinstxtractor.py and Uncompyle6, I was able to reverse executable to Python script. FYI, decompile will fail if we run tools using newer or older version Python that challenge excepts (3.7).

> python .\pyinstxtractor.py .\Unbiosed.exe
[+] Processing .\Unbiosed.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 37
[+] Length of package: 18531925 bytes
[+] Found 44 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: pyi_rth_pkgres.pyc
[+] Possible entry point: pyi_rth_multiprocessing.pyc
[+] Possible entry point: Unbiosed.pyc
[+] Found 439 files in PYZ archive
[+] Successfully extracted pyinstaller archive: .\Unbiosed.exe

You can now use a python decompiler on the pyc files within the extracted directory

> uncompyle6.exe .\Unbiosed.exe_extracted\Unbiosed.pyc
# uncompyle6 version 3.7.5.dev0
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:58:18) [MSC v.1900 64 bit (AMD64)]
# Embedded file name: Unbiosed.py
import numpy as np, random
a = np.empty([10, 10])
b = np.empty([10, 10])
c = np.dot(a, b)
if random.uniform(0, 5) <= 2:
    print('The Bios is Corrupted!')
    exit()
d = input('Please Enter the Recovery Key:')
e = list(d)
g = 0
h = [84, 77, 85, 67, 84, 70, 123, 77, 52, 121, 95, 52, 108, 108, 95, 89, 48, 117, 114, 95, 68, 51, 99, 49, 53, 49, 48, 110, 53, 95, 98, 51, 95, 85, 110, 98, 49, 48, 53, 51, 100, 33, 125]
for f in range(len(h)):
    if ord(e[f]) != h[f]:
        g = g + 1

if g > 0:
    print('Your Bios Data Cannot be Recovered with This Key.')
    exit()
print("Congratulations! You Have The Flag, But I'll Print it Out Again For You:")
print(d)
# okay decompiling .\Unbiosed.exe_extracted\Unbiosed.pyc

By writing stuffs like below, I got the flag for this challenge.

>>> h = [84, 77, 85, 67, 84, 70, 123, 77, 52, 121, 95, 52, 108, 108, 95, 89, 48, 117, 114, 95, 68, 51, 99, 49, 53, 49, 48, 110, 53, 95, 98, 51, 95, 85, 110, 98, 49, 48, 53, 51, 100, 33, 125]
>>> for hch in h:
...     print(chr(hch),end='')
...
TMUCTF{M4y_4ll_Y0ur_D3c1510n5_b3_Unb1053d!}

Flag: TMUCTF{M4y_4ll_Y0ur_D3c1510n5_b3_Unb1053d!}

findkey

I have used angr for this challenge because decompiled code generated by Ghidra seems to be to hard to read for me.

>>> import angr
>>> p = angr.Project("./findkey")
WARNING | 2021-09-09 10:21:26,843 | cle.loader | The main binary is a position-independent executable. It is being loaded with a base address of 0x400000.
>>> e = p.factory.entry_state()
>>> simgr = p.factory.simulation_manager(e)
>>> s = simgr.explore(find=0x400000+0x11bc)
>>> s
<SimulationManager with 4 active, 2 deadended, 1 found>
>>> s.found[0].posix.dumps(0)
b"R3v\xbf3n9_By_\xf4g\xfc\xe0/\x00'\x00\x06\x01C\x11\xa9\x00\x08\xf4\x01\xc5\x00\x10\xb1\x06+z'H\x003:\x12\x01fk\x03\x00\x00\x07\xd0*A\xd83S\x11r\x00\x13\x00\x01"

Check.

$ echo -e "R3v\xbf3n9_By_\xf4g\xfc\xe0/" | ./findkey
Please enter the key: Well Done! TMUCTF{R3v�3n9_By_�g��/}

I knew that length of key is 0x10 from really quick static analysis, so I have bruteforced (using subprocess and string.printable on Python) for some characters that seems to be wrong on the result. As a result, I knew that partial part of key is R3v_3n9_By_4 . For the rest 4 characters, I have just guessed by the information (like angr.c in defined string of executable) and solved the challenge. I think there is much better solution for this part. :^(

$ ./findkey
Please enter the key: R3v_3n9_By_4N9r!
Well Done! TMUCTF{R3v_3n9_By_4N9r!}

Flag: TMUCTF{R3v_3n9_By_4N9r!}

Crack House

It is GUI application built using .NET framework, so I have used DotPeek to analyze it statically. Its not doing much complicated stuffs inside, so I have almost C&P whole if statements around validation, and just fixed a little to move it on Python.

Solver:

from pwn import *

import string

conn = remote('185.235.41.70', 6000)

def gen_key(username):
    index1 = 0
    numArray = [ord(uch) for uch in username]
    key = [0] * 16
    for i in range(16):
        if i % 2 == 0 and numArray[i] >= 65 and numArray[i] < 78:
            key[i] = numArray[i] + i
        elif i % 2 == 0 and numArray[i] >= 78 and numArray[i] < 91:
            key[i] = numArray[i] + i - 4
        elif i % 2 == 0 and numArray[i] >= 97 and numArray[i] < 110:
            key[i] = numArray[i] + i + 8
        elif i % 2 == 0 and numArray[i] >= 110 and numArray[i] < 123:
            key[i] = numArray[i] + i - 5
        elif i % 3 == 0 and numArray[i] >= 65 and numArray[i] < 78:
            key[i] = numArray[i] + i + 1
        elif i % 3 == 0 and numArray[i] >= 78 and numArray[i] < 91:
            key[i] = numArray[i] + i - 7
        elif i % 3 == 0 and numArray[i] >= 97 and numArray[i] < 110:
            key[i] = numArray[i] + i + 6
        elif i % 3 == 0 and numArray[i] >= 110 and numArray[i] < 123:
            key[i] = numArray[i] + i - 11
        elif i % 5 == 0 and numArray[i] >= 65 and numArray[i] < 78:
            key[i] = numArray[i] + i - 2
        elif i % 5 == 0 and numArray[i] >= 78 and numArray[i] < 91:
            key[i] = numArray[i] + i - 9
        elif i % 5 == 0 and numArray[i] >= 97 and numArray[i] < 110:
            key[i] = numArray[i] + i + 3
        elif i % 5 == 0 and numArray[i] >= 110 and numArray[i] < 123:
            key[i] = numArray[i] + i - 15
        elif i % 7 == 0 and numArray[i] >= 65 and numArray[i] < 78:
            key[i] = numArray[i] + i - 5
        elif i % 7 == 0 and numArray[i] >= 78 and numArray[i] < 91:
            key[i] = numArray[i] + i - 14
        elif i % 7 == 0 and numArray[i] >= 97 and numArray[i] < 110:
            key[i] = numArray[i] + i + 4
        elif i % 7 == 0 and numArray[i] >= 110 and numArray[i] < 123:
            key[i] = numArray[i] + i - 25
        elif i % 11 == 0 and numArray[i] >= 65 and numArray[i] < 78:
            key[i] = numArray[i] + i - 10
        elif i % 11 == 0 and numArray[i] >= 78 and numArray[i] < 91:
            key[i] = numArray[i] + i + 2
        elif i % 11 == 0 and numArray[i] >= 97 and numArray[i] < 110:
            key[i] = numArray[i] + i + 8
        elif i % 11 == 0 and numArray[i] >= 110 and numArray[i] < 123:
            key[i] = numArray[i] + i - 5
        elif i % 13 == 0 and numArray[i] >= 65 and numArray[i] < 78:
            key[i] = numArray[i] + i + 1
        elif i % 13 == 0 and numArray[i] >= 78 and numArray[i] < 91:
            key[i] = numArray[i] + i - 10
        elif i % 13 == 0 and numArray[i] >= 97 and numArray[i] < 110:
            key[i] = numArray[i] + i + 6
        elif i % 13 == 0 and numArray[i] >= 110 and numArray[i] < 123:
            key[i] = numArray[i] + i - 22
        elif i % 2 == 1 and numArray[i] >= 65 and numArray[i] < 78:
            key[i] = numArray[i] + i + 3
        elif i % 2 == 1 and numArray[i] >= 78 and numArray[i] < 91:
            key[i] = numArray[i] + i - 3
        elif i % 2 == 1 and numArray[i] >= 97 and numArray[i] < 110:
            key[i] = numArray[i] + i + 5
        elif i % 2 == 1 and numArray[i] >= 110 and numArray[i] < 123:
            key[i] = numArray[i] + i - 2
    final = ''
    for kch in key:
        final += chr(kch)
    return final

for _ in range(8): conn.recvuntil(b'\n')
for uch in string.ascii_uppercase[:-1]:
    unm = uch * 16
    key = gen_key(unm)
    print('[*] Sending pair of username and license key to remote (' + unm + ':' + key + ')')
    conn.sendlineafter(b':\n', unm.encode())
    conn.sendlineafter(b':\n', key.encode())

conn.interactive()

Output:

> python .\test.py
[x] Opening connection to 185.235.41.70 on port 6000
[x] Opening connection to 185.235.41.70 on port 6000: Trying 185.235.41.70
[+] Opening connection to 185.235.41.70 on port 6000: Done
[*] Sending pair of username and license key to remote (AAAAAAAAAAAAAAAA:AECEEDGCIKKBMOOQ)
[*] Sending pair of username and license key to remote (BBBBBBBBBBBBBBBB:BFDFFEHDJLLCNPPR)
[*] Sending pair of username and license key to remote (CCCCCCCCCCCCCCCC:CGEGGFIEKMMDOQQS)
[*] Sending pair of username and license key to remote (DDDDDDDDDDDDDDDD:DHFHHGJFLNNEPRRT)
[*] Sending pair of username and license key to remote (EEEEEEEEEEEEEEEE:EIGIIHKGMOOFQSSU)
[*] Sending pair of username and license key to remote (FFFFFFFFFFFFFFFF:FJHJJILHNPPGRTTV)
[*] Sending pair of username and license key to remote (GGGGGGGGGGGGGGGG:GKIKKJMIOQQHSUUW)
[*] Sending pair of username and license key to remote (HHHHHHHHHHHHHHHH:HLJLLKNJPRRITVVX)
[*] Sending pair of username and license key to remote (IIIIIIIIIIIIIIII:IMKMMLOKQSSJUWWY)
[*] Sending pair of username and license key to remote (JJJJJJJJJJJJJJJJ:JNLNNMPLRTTKVXXZ)
[*] Sending pair of username and license key to remote (KKKKKKKKKKKKKKKK:KOMOONQMSUULWYY[)
[*] Sending pair of username and license key to remote (LLLLLLLLLLLLLLLL:LPNPPORNTVVMXZZ\)
[*] Sending pair of username and license key to remote (MMMMMMMMMMMMMMMM:MQOQQPSOUWWNY[[])
[*] Sending pair of username and license key to remote (NNNNNNNNNNNNNNNN:JLLJNJPGRPT[VQXV)
[*] Sending pair of username and license key to remote (OOOOOOOOOOOOOOOO:KMMKOKQHSQU\WRYW)
[*] Sending pair of username and license key to remote (PPPPPPPPPPPPPPPP:LNNLPLRITRV]XSZX)
[*] Sending pair of username and license key to remote (QQQQQQQQQQQQQQQQ:MOOMQMSJUSW^YT[Y)
[*] Sending pair of username and license key to remote (RRRRRRRRRRRRRRRR:NPPNRNTKVTX_ZU\Z)
[*] Sending pair of username and license key to remote (SSSSSSSSSSSSSSSS:OQQOSOULWUY`[V][)
[*] Sending pair of username and license key to remote (TTTTTTTTTTTTTTTT:PRRPTPVMXVZa\W^\)
[*] Sending pair of username and license key to remote (UUUUUUUUUUUUUUUU:QSSQUQWNYW[b]X_])
[*] Sending pair of username and license key to remote (VVVVVVVVVVVVVVVV:RTTRVRXOZX\c^Y`^)
[*] Sending pair of username and license key to remote (WWWWWWWWWWWWWWWW:SUUSWSYP[Y]d_Za_)
[*] Sending pair of username and license key to remote (XXXXXXXXXXXXXXXX:TVVTXTZQ\Z^e`[b`)
[*] Sending pair of username and license key to remote (YYYYYYYYYYYYYYYY:UWWUYU[R][_fa\ca)
[*] Switching to interactive mode
License is valid!
Congratulations! Here is the flag:
TMUCTF{W0w_Y0u_Cr4ck3d_7h3_H0u53_L1k3_4_Ch4mp}

Flag: TMUCTF{W0w_Y0u_Cr4ck3d_7h3_H0u53_L1k3_4_Ch4mp}

Adimeht

By opening the executable using Ghidra, we can estimate that executable is packed. I have used pe-sieve to extract unpacked binary.

> .\pe-sieve32.exe /pid 8860
PID: 8860
Output filter: no filter: dump everything (default)
Dump mode: autodetect (default)
.
.
.
[+] Report dumped to: process_8860
[!] Failed reading Image at: 8a0000 img size: a70000
[!] Image size at: 8a0000 undetermined, using calculated size: a6f000
[*] This is a .NET payload and may require Enty Point correction. Current EP: 29ca
[*] Found possible Entry Point: 29ca
[*] Dumped module to: C:\Users\IEUser\Downloads\\process_8860\8a0000.Adimeht.exe as UNMAPPED

Unpacked binary is just a simple .NET application, so I have used DotPeek to Analyze it.

>>> flag = [33,128,119,373,33,70,174,72,308,153,126,338,151,35,384,65,35,8,384,81,153,384,202,8,214,35,65,56,153,151,384,153,35,19,338,142,104,40]
>>> for fch in enc_flag:
...     num2 = 1
...     for i in range(pkey):
...             num2 = fch * num2 % n
...     print(chr(num2), end='')
...
TMUCTF{7h3m1d4_c4n_b3_unp4ck3d_3451ly}

Flag: TMUCTF{7h3m1d4_c4n_b3_unp4ck3d_3451ly}

Welcome

Welcome

C&P (from Slack).

Flag: TMUCTF{W3lc0m3_70_7muc7f_2021_7h15_15_4_U}

Warmup

Flag image can be generated using stegsolve.jar 's Image Combiner in XOR mode.

f:id:m0pisec:20210909092105j:plain
output

Flag: TMUCTF{W3_h0p3_y0u_3nj0y_7h15_c0mp371710n_4nd_7h4nk_y0u!}