PatriotCTF 2024 Writeup by ICEDTEA

team: ICEDTEA
rk. 33/1360
image
官方Writeup

我終於在跟冰茶的比賽中有貢獻了
然後我太晚才有空寫write,比賽平台已經關了,很多沒截到圖,所以可能有的看不太懂

Misc

RTL_Warmup

給一個檔案 flag.vcd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$timescale 1 ps $end
$scope module uut $end
$var wire 1 ! clock $end
$var wire 8 " dout $end
$var wire 8 # din $end
$upscope $end
$enddefinitions $end
$dumpvars
0!
b01010000 "
b01010000 #
$end
#50000000
1!
#50000000
#100000000
0!
#100000000
b01000011 "
b01000011 #
#150000000
1!
#150000000
#200000000
0!
#200000000
(中略)
b01111101 "
b01111101 #
#2750000000
1!
#2750000000
#2800000000
0!
#2800000000

我看不懂RTL code,但根據chatGPT可知其中包含模擬的輸出數值,那些二進制數值對應於信號" dout# din的變化
用chatGPT將那些二進制轉 ASCII 就是flag

1
2
3
b01010000 "
b01010000 #
=> ASCII P

以此類推

EmojiStack

題目大致如下
👉: Move the stack pointer one cell to the right
👈: Move the stack pointer one cell to the lef
👍: Increment the current cell by one, bounded by 255
👎: Decrement the current cell by one, bounded by 0
💬: Print the ASCII value of the current cell
🔁##: Repeat the previous instruction 0x## times
The Emoji Stack is 256 cells long, with each cell supporting a value between 0 - 255.
給輸出flag的emoji

1
👉👉👉👉👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👉🔁08👍🔁34👈👈👈👈👈👈👈👈👈👈👍🔁48👉🔁15👍🔁5e👈🔁07👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👉🔁02👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👍🔁42👉🔁02👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👉🔁17👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👈🔁14👍🔁20👉🔁06👍🔁51👉🔁0c👍🔁34👉👉👍🔁46👈🔁14👍🔁4d👈🔁01👍🔁51👉🔁04👍🔁20👉🔁03👍🔁2f👉👉👉👉👉👉👉👉👍🔁4d👈🔁17👍🔁42👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👍🔁7c👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👉🔁0c👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👉👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👈👈👈👈👈👈👈👈👈👈👈👈👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👉🔁0c👍🔁32👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👉🔁04👍🔁5e👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👍🔁47👈🔁0f👍🔁46👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👉👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👈🔁03👍🔁20👈🔁08👍🔁5e👉🔁10👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👈🔁1d👍🔁40👉🔁10👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👉👉👉👉👍🔁5e👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈👈💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬👉💬

總之,問就是工人智慧
就不說我還看錯,🔁##是先執行一次前面指令,再重複0x##次,我都只重複0x##次害我多工人智慧兩次

making-baking-pancakes

忘記截圖連線畫面
連remote解決challenge一千次,每次challenge接收一串被base64 encode n+1次的字串,decode一次後字串末尾會有數字n表示要再decode n 次。
exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from pwn import *
import base64


r = remote('chal.pctf.competitivecyber.club', 9001)


def decode_challenge(challenge, iterations):
decoded = challenge
for _ in range(iterations):
decoded = base64.b64decode(decoded).decode()
return decoded

r.recvlines(10)


for i in range(1, 1001):

challenge = r.recvline().strip().decode().split(': ')[1]
challenge = base64.b64decode(challenge).decode()
n = int(challenge.split('|')[1])


decoded = decode_challenge(challenge, n)


response = ""
response += decoded
response += '|'
response += str(i)


r.sendline(response.encode())
print(response)
r.interactive()

r.close()

Reverse

password_protector

給一個 passwordProtector.pyc
https://pylingual.io/ 成功反編譯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import os
import secrets
from base64 import *

def promptGen():
flipFlops = lambda x: chr(ord(x) + 1)
with open('topsneaky.txt', 'rb') as f:
first = f.read()
bittys = secrets.token_bytes(len(first))
onePointFive = int.from_bytes(first) ^ int.from_bytes(bittys)
second = onePointFive.to_bytes(len(first))
third = b64encode(second).decode('utf-8')
bittysEnc = b64encode(bittys).decode('utf-8')
fourth = ''
for each in third:
fourth += flipFlops(each)
fifth = f"Mwahahaha you will n{fourth[0:10]}ever crack into my pass{fourth[10:]}word, i'll even give you the key and the executable:::: {bittysEnc}"
return fifth

def main():
print(promptGen())
if __name__ == '__main__':
main()

可知題目上的亂碼可得出fifth、fourth,再依序解出third、second、first
exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bittysEnc = "Zfo5ibyl6t7WYtr2voUEZ0nSAJeWMcN3Qe3/+MLXoKL/p59K3jgV"
fourth = "Ocmu{9gtufMmQg8G0eCXWi3MY9QfZ0NjCrXhzJEj50fumttU0ymp"
fifth = f"Mwahahaha you will n{fourth[0:10]}ever crack into my pass{fourth[10:]}word, i'll even give you the key and the executable:::: {bittysEnc}"
third = ""
for i in fourth:
third += chr(ord(i)-1)
third = "Nbltz8fsteLlPf7F/dBWVh2LX8PeY/MiBqWgyIDi4/etlssT/xlo"
from base64 import *
bitty = b64decode(bittysEnc)
second = b64decode(third)
onePointFive = int.from_bytes(second)
from Crypto.Util.number import long_to_bytes
first = long_to_bytes(onePointFive ^ int.from_bytes(bitty))

print(first)

puzzle_room

三百多行python,執行起來在是走一個迷宮
image
從以下關鍵程式碼,得知走過的每個單字連在一起是key,如果走正確的路徑就可以AES解密出flag

1
2
3
4
5
key = "".join([try_get_tile(x)[0] for x in path.path_history])
enc_flag = b"FFxxg1OK5sykNlpDI+YF2cqF/tDem3LuWEZRR1bKmfVwzHsOkm+0O4wDxaM8MGFxUsiR7QOv/p904UiSBgyVkhD126VNlNqc8zNjSxgoOgs="
obj = AESCipher(key)
dec_flag = obj.decrypt(enc_flag)
if "pctf" in dec_flag:

從code review得知走的路徑有很多限制、規則,整理之後發現路徑會是 vulture 開頭,經過4~7個單字到達Shrine,暴破這4~7個單字找到正確的路徑
exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import itertools
from Crypto.Cipher import AES
import base64
import hashlib

class AESCipher(object):
def __init__(self, key):
self.bs = AES.block_size
self.key = hashlib.sha256(key.encode()).digest()

def decrypt(self, enc):
enc = base64.b64decode(enc)
iv = enc[: AES.block_size]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return AESCipher._unpad(cipher.decrypt(enc[AES.block_size :])).decode("utf-8")

@staticmethod
def _unpad(s):
return s[: -ord(s[len(s) - 1 :])]

# Known part of the key and encrypted flag
prefix = "vulture"
suffix = "Shrine"
words = ["urn", "arch", "snake", "bug", "plant", "staff", "foot"]
enc_flag = b"FFxxg1OK5sykNlpDI+YF2cqF/tDem3LuWEZRR1bKmfVwzHsOkm+0O4wDxaM8MGFxUsiR7QOv/p904UiSBgyVkhD126VNlNqc8zNjSxgoOgs="

# Brute force all possible combinations of 4 to 7 words in between
for length in range(4, 8):
for combo in itertools.permutations(words, length):
key = prefix + ''.join(combo) + suffix
obj = AESCipher(key)
try:
dec_flag = obj.decrypt(enc_flag)
if "pctf" in dec_flag:
print("Key found:", key)
print("Flag:", dec_flag)
break
except:
continue