]> git.somenet.org - pub/jan/ctf-seminar.git/blob - writeups/mli/hxp-36c3-ctf.md
fix links
[pub/jan/ctf-seminar.git] / writeups / mli / hxp-36c3-ctf.md
1 # 36c3 hxp ctf
2
3 ## Time spent
4
5 In total I spent 7+9+1(challenges)+3+4+11 hours on this ctf __Total 35 hours__
6
7 3 hours writing this writeup
8
9 4 hours reading challenge writeups after the ctf was over
10
11 for preparation: a full workday reading and experimenting with writeups from last years 35c3 ctf + about 3 hours for the junior 35c3 ctf (ethereum challenges "entrance" and "future") = 11 hours
12
13 ## peerreviewed (ZAJ CRY BBY)
14
15 Description:
16
17 Because AES is so hard to understand, we went looking for something that is a little easier to follow. This paper (DOI: 10.1109/CCNC.2007.64, PDF) introduces an encrypted protocol that “prevents an attacker from recovering the transmitted information through operations on the encrypted vectors exchanged during the transmission procedure” - in fact, the paper even assures us that “the only identified way one can compromise the protocol security is by applying brute force attacks”. Since this is a peer-reviewed paper (by subject-matter experts, no less) we can be sure that our data is safe! My colleagues are still a bit concerned, though, so I am running this little test in order to prove that the protocol is secure.
18
19 Download:
20
21 * peerreviewed-320d68ba23764d17.tar.xz
22   * crypto.sage
23   * intercepted.txt
24
25 ### Time spent
26
27 For this challenge, I spent 6 hours during the ctf and 1 hour afterwards reading the writeup.
28
29 ### Overview
30
31 * I first downloaded/installed sagemath (+pycryptodome)
32 * We apparently have 3 instances of message communication inside of intercepted.txt
33   * block 1
34     * `A -> B: yA = (5.8537179772742871378006829317359804640034149162093776176771e75, 2.0260990893806965307943860314007373888732002921518840941414e76)`
35     * `B -> A: yB = (4.0652782673020986683538918237010543408982543019306057179496e95, -5.0285426513783822097670201376390415563936061484095492229894e94)`
36     * `A -> B: yC = (4.3083595977562861674637990303350994431503203162436044206961e76, -3.1928247205608247346546681530367209122491766171698701927922e76)`
37   * block 2
38     * `A -> B: yA = (3.9886651421460868244883042163468164077791762065632163641999e76, -1.2487387183806776412156661578750877275468860853692530589115e77)`
39     * `B -> A: yB = (2.5644531171906756537679808003501733255703504126650573479133e95, -1.6570541229598112699074962433815055733294177769576178678896e96)`
40     * `A -> B: yC = (4.5893614625576224795913782492661186902913334535507951850089e76, 6.8611881934867127810471276550294069221078140676008042683634e76)`
41   * block 3
42     * `A -> B: yA = (-6.5089227887140404010136240391818701730482514213358150433451e75, 5.5620733870042242270647223203879530885369669489378834804472e76)`
43     * `B -> A: yB = (1.0017374772520318947002755790705886607122203555146923369286e95, 1.2876407911288161811207561236370324382394428286338064237471e96)`
44     * `A -> B: yC = (1.1418280384822587553925695577555385627605037374102719431688e77, -1.9966984339634055590175475802847306340483261373340080568330e76)`
45 * The intercepted.txt was probably generated by the "Self-test"-lines of `crypto.sage` inside `if __name__ == '__main__'`
46   * The plaintext message is split into blocks of 192 bytes
47 * The output blocks look independed to each other (regarding encryption)
48 * My goal was to make an equation to see what I need in order to recompute the plaintext
49
50 according to the code in the test procedure of the original crypto.sage sourcecode
51
52 key 1: `O1, Oc1, A1, Ac1`
53
54 key 2: `O2, Oc2, A2, Ac2`
55
56 transmission 1->2: `b * O1 * A1` = yA
57 transmission 2->1: `yA * O2 * A2` = yB
58 transmission 1->2: `yB * Oc1 * Ac1` = yC
59
60 So, yA, yB, yC are public. We can also compute `O2 * A2` by `yB/yA` and `Oc1 * Ac1` by `yC/yB`.
61 I wrote this on some paper and tried to make sense of it for some time. I looked at the generate_key() function and thought how this could work in a matrix context.
62
63 I skimmed through the paper to look whether there was some information about a possible exploit when all transmission content is listened to, but they just wrote that you cannot break this crypto except using "brute-force". Hmm, must be something else then (which the peerreviewers ;) did not get - matches the description at least).
64
65 ### Solution/Exploit
66
67 I did not manage to solve the challenge before end of ctf.
68
69 There are two writeups (<https://balsn.tw/ctf_writeup/20191228-hxp36c3ctf/#peerreviewed> and <https://github.com/epicleet/write-ups/blob/master/2019/hxp_36c3/peerreviewed/README.md>), the second one explains the problem pretty well.
70
71 The absolute value b can be computed by `yC*yA / yB` (because `Oc1*Ac1` are basically inverses of `O1*A1` which all 4 get canceled out so that `yC*yA / yB = yB*b / yB = b`). b itself consists of the plaintext. The flag was `hxp{p33r_r3v13w3d_m4y_n0t_b3_1337_r3v13w3d}`.
72
73 ## catch-the-flag (MSC)
74
75 Description: "Just catch me."
76
77 Download:
78
79 * catch the flag-9573fd8e2bb91485.tar.xz
80   * client.py
81   * Dockerfile
82   * flag_char.py
83   * game.py
84   * world_generator.py
85   * ...
86
87 ### Time spent
88
89 I invested 9 hours into this challenge, most of it walking around manually and also changing my script each time after I found out a new aspect of the game (which I should have looked at beforehand yes, the `game.py` and other files were here for a reason.
90
91 ### Overview
92
93 This challenge was about a console-based game, I imagined that it was similar to the old Nokia game Snake where the flag is the snake and I have to walk around and read the flag. The problem is that there are holes (pits) in the ground and when I fall into one I have to start over.
94
95 * The game will print only 'i' when we stand on nothing special.
96 * 'iw' means that we are standing against a wall
97 * 'breeze' means there is a pit nearby
98 * 'smell' means there is the flag nearby
99
100 I decided that I track my current position and paint a map from the responses I get because the pits don't seem to change (while the flag does run around the map). I wanted to first run around manually to find out as much as possible about the game.
101
102 I kept track of the map using an array and printed it on each move):
103
104 ```json
105 [['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'B', 'i', 'B', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i',
106  ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'B', ' ', 'B', ' ', 'B', ' ', ' ', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i',
107  ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', ' ', 'B', 'i', 'i', 'i', 'B', 'd', 'B', 'i', 'B', 'B', ' ', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i',
108  ['i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'B',
109  ['B', 'd', 'B', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'd', 'B', 'i', 'i', 'i', 'i', 'B', ' ',
110  ['i', 'B', 'd', 'B', 'i', 'i', 'i', 'B', ' ', 'B', 'i', 'i', 'B', 'i', 'B', ' ', 'B', 'i', 'i', 'B', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'B', ' ',
111  ['B', ' ', 'B', 'i', 'i', 'i', 'i', 'B', ' ', 'i', 'i', 'B', 'd', 'B', 'd', 'B', 'i', 'i', 'B', ' ', 'B', 'i', 'B', 'd', 'B', 'B', 'i', 'i', 'i', 'B', 'd', ' ',
112  ['i', 'B', 'd', 'B', 'i', 'i', 'B', ' ', 'B', 'i', 'i', 'B', 'd', ' ', 'B', 'i', 'i', 'i', ' ', 'B', 'i', 'i', 'i', 'B', 'B', 'i', 'i', 'i', 'B', ' ', ' ', 'B',
113  ['i', 'i', 'B', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'B', 'B', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'B', 'd', 'i', 'i', 'i', 'i', 'i', 'B', 'B', 'i',  ['i', 'i', 'i', 'i', 'i', 'i', 'B', 'd', 'B', 'B', 'i', 'B', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'B', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i',
114  ['i', 'i', 'i', 'i', 'i', 'B', 'd', 'B', 'B', ' ', 'B', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'B', ' ', 'B', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i',
115  ['i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'd', 'B', ' ', 'B', 'B', 'i', 'B', 'i', 'B', ' ', 'B',
116  ['i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'B', 'B', 'd', 'B', ' ', 'B', ' ', 'B', 'i',
117  ['i', 'i', 'i', 'i', 'B', 'd', 'B', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', ' ', ' ', ' ', ' ', 'B', 'i',
118  ['i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'B', 'd', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', ' ', ' ', ' ', 'B', 'i',
119  ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'd', 'B', 'i', 'i',
120  ['i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'd', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'B', ' ', 'B', 'i', 'i', 'B',  ['i', 'B', 'd', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'B', ' ', ' ', ' ', ' ', 'B', 'B', ' ',
121  ['i', 'i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'B', 'i', ' ', ' ', ' ', ' ', ' ', 'B',
122  ['i', 'i', 'B', 'i', 'B', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'B', 'i', 'B', '?O, 'i', 'i', 'smell', 'i', 'i', 'i', 'B', '
123  ['i', 'B', 'd', 'B', ' ', ' ', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'd', ' ', ' ', ' ', ' ', 'i', 'i', 'i', 'i', '4', 'smell', 'i', 'i', '
124  ['B', ' ', 'B', ' ', ' ', ' ', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', ' ', ' ', 'B', 'i', ' ', ' ', 'i', 'i', 'i', 'i', 'i', ' ', ' ', ' ',
125  ['i', 'B', 'i', 'B', 'd', ' ', 'i', 'B', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', ' ', 'iO, 'BO, 'smell', 'i', 't', 'smell', 'i', 'smell', 'i', ' ', ' '
126  ['i', 'i', 'i', 'i', 'B', 'B', 'i', 'd', 'B', 'i', 'i', 'i', 'i', 'i', 'B', 'd', ' ', 'i', ' ', 'i', 'B', 'i', 'B', 'i', 'smell', 'smell', 'i', ' ', ' ', ' ', 'B
127  ['i', 'i', 'i', 'i', 'i', 'i', 'B', 'n', 'B', 'a', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'B', 'smell', 'i', 'i', 'i', 'i', 'iO, 'B', 'd', 'd', ' ', ' ', ' ', ' ', '
128  ['i', 'i', 'B', 'i', 'B', 'i', 'i', 'B', 'i', 'i', 'i', 'B', 'i', 'B', 'i', 'i', 'iO, 'smell', 'i', 'smell', 'smell', 'smell', 't', 'NoneO, 'B', 'i', 'smell', 's
129  ['i', 'i', ' ', ' ', ' ', 'i', ' ', 'i', 'i', 'n', 'smell', 'wO, 'BO, 'i', '?OO, '?OO, ' ', ' ', ' ', ' ', ' ', ' ', ' ', '?O, '?O, '?O, 'i', 'i', 'i', 'i', 'i',
130  ['i', 'B', 'i', 'B', 'i', 'i', 'i', 'B', 'i', 'smell', 'x', 'BO, 'd']
131  ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B', 'i', 'i', 'NoneO, 'B']
132  ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'smell', 'i', 'i', 'i', 'B', ' ', ' ', '?O, 'B', ' ', 'B']
133  ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'n', 'smell', '_', 'i', 'B', 'i', 'B', 'NoneO, 'BO, 'B', 'B', 'B', 'd']
134  ['i', 'B', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B']
135  ['B', ' ', 'i', ' ', 'i', 'NoneO, 'B', 'i', 'B', 'd']
136  ['B', 'B', 'i', 'i', 'i', 'B', ' ', 'B', 'i', 'B', 'B']
137  ['d', 'B', 'i', 'i', 'i', 'BO, 'B', 'i', 'i', 'i', 'i', 'B']
138  ['B', 'i', 'i', 'i', 'B', 'BO, 'd', 'B', 'i', 'i', 'i', 'B']
139  ['i', 'i', 'i', 'B', 'd', 'B', 'B', 'i', 'i', 'i', 'B']
140  ['i', 'i', 'i', 'i', 'B', 'i', 'i', 'i', 'i', 'B']
141  ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B']
142  ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B']
143  ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'B']
144  ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'B']
145  ['i', 'i', 'i', 'i', 'i', 'i', 'B']
146  ['B', 'i', 'i', 'i', 'i', 'B']
147  ['d', 'B', 'B', 'i', 'i', 'B']
148  ['d', 'B', 'd', 'B', 'B', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'i', 'i', 'i']
149  ['B', 'B']
150  ['B']
151  ['i', 'B']
152  ['i', 'i', 'B']
153  ['|]
154 ```
155
156 ### Solution/Exploit
157
158 Code which I used to connect/walk around/store state locally see [exploit.py](hxp-36c3-ctf/exploit.py)
159
160 I wrote all characters of the flag (well all which I encountered) to this file: [flagchars.txt](hxp-36c3-ctf/flagchars.txt), for example the output from one run was `[['f', 'h'], ['f', 'x'], ['f', 'n'], ['f', 'p'], ['f', 'n'], ['f', 'w']]` (we can see some of the characters of the actual flag `hxp{and_n0w_try_t0_c4tch_m3_w1th0ut_dy1ng}`). Unfortunately I did not manage to find out the order of the flag characters.
161
162 I did not find out the whole flag. This is a good writeup: <https://flagbot.ch/posts/catch-the-flag/> - this guy was more intelligent than me and dumped the map automatically using an A* path algorithm (to find all the pits). He used the algorithm also to walk to a tile he wanted to go after having the pits he had to avoid. It was then easy to find out that there are 42 flag characters running around in the map (count until `Congrats, you caught the whole flag.`). The writeup author also found out that the seed which fed the randomness determing the flag characters is time.time() - and ran the same game locally feeding this seed as input to find out the actual character positions. The flag turned out to be `hxp{and_n0w_try_t0_c4tch_m3_w1th0ut_dy1ng}`.
163
164 ## tetres2019 (REV)
165
166 Description:
167
168 * We made a tetris game but we’re not sure whether it’s actually winnable. Can you please check?
169 * If you execute on hardware that sucks (i.e. not GT740M, GTX970, GTX1080, RTX2060, UHD 620, UHD 630, or any AMD) or software that sucks (i.e. not OpenGL version 4.6) the program might complain that some GL function was not loaded. This is not necessarily a hard error. It’s a hard error if it crashes. :)
170 * But even hard errors are, unfortunately, totally your problem.
171 * Good luck.
172
173 Download:
174
175 * tetres2019-ed197a2f816f57ea.tar.xz
176   * tetris.exe
177
178 ### Time spent
179
180 1 hour
181
182 ### Overview
183
184 I could not start the game (`The driver doesn't support some functions and the game might crash.`) but tried to analyze it.
185
186 * File `tetris.exe` returned: `tetris.exe: PE32 executable (console) Intel 80386, for MS Windows`
187
188 But ghidra only can load some lines of assembler core. Accidentially I opened it using 7-Zip and could extract a file `peippo`. As Ch4s3r in Mattermost wrote, this looks like a packed binary. Unfortunately I also could not load this `peippo` file in Ghidra although trying different formats.
189
190 * File `peippo` returned: `peippo: data`
191
192 Binwalk does not return results. The first bytes of this file are
193
194 ```xxd
195 00000000: fcbe 6001 3000 bf16 d430 00b9 a000 0000  ..`.0....0......
196 00000010: f3a4 ba38 1330 00b9 b110 3000 e838 0100  ...8.0....0..8..
197 00000020: 00ff 3581 1030 00ff 357d 1030 0068 d0af  ..5..0..5}.0.h..
198 00000030: 4100 6800 0040 00e8 ad05 0000 83c4 10e9  A.h..@..........
199 00000040: 0fc4 1000 4b45 524e 454c 3332 2e44 4c4c  ....KERNEL32.DLL
200 00000050: 0000 004c 6f61 644c 6962 7261 7279 4100  ...LoadLibraryA.
201 00000060: 0000 4765 7450 726f 6341 6464 7265 7373  ..GetProcAddress
202 00000070: 0051 1000 0060 1000 0000 0000 0051 1000  .Q...`.......Q..
203 00000080: 0060 1000 0000 0000 0071 1000 0000 0000  .`.......q......
204 ```
205
206 ### Solution
207
208 I did not solve it.
209
210 Writeup: <https://martinradev.github.io/jekyll/update/2019/12/29/tetris-re.html>, the challenge could be solved by using a graphics debugger (<https://renderdoc.org/> was used in this case) to trace the OpenGL calls. Apparently the player had to score 1337 points for the flag to be rendered. Flag: `hxp{300$_GPU_For_7etr1s_1n_2019}`