cursedCTF 2024 - cursed writeup
🎉🎉 Cursed CTF run for the second year 🎉🎉
During HITCON CTF Final, I met some of the admins for cursedCTF, and joined the admin team. In the end, I posted 6 challenges. I hope that everyone enjoyed the cursedness of this competition.
I always love the idea of a troll competition during April Fools. When I used to be an active competitive programming player, some friends would host these April Fools competitions, each with different gimmicks. That transfers to CTFs as well. I played XMAS-GTF in 2020 and the first cursedCTF last year, and I truly enjoy those experiences.
Last year I met some of the admins at HITCON CTF final and got to join the admin team! This is the first time being able to contribute to this event and I certainly enjoy my time.
Some (cursed) statistics
- 11058 teams that scored at least 1 flag
- 101 total challenges
- 1 challenge with 9606 solves
- 2 often used flag formats
- 2 challenges with no flag format
- 2+ leaked flags
- 4+ flags traded with contestants
- 1 admin playing as a contestant
- 2 players banned
- 4 challenges require real money
- 2 challenges reused
-
Competition ended 3 times
(I’ll add more as I gather more information)
My challenges
Well, I guess I should post writeups of my own challenge. I’ll order it roughly by my own perceived cursedness
forensic - fetusstego
1
another easy stego
This one is probably the most normal ctf challenge I created. The only cursed part is merely that it’s a stego. There isn’t really any twist to it, just guessed how the image is created.
So the image is created by 36 images, each with a single word. The pixels are then “zipped” together such that each 6 by 6 megapixel contains the pixel from each image in order. The solution is simply to extract the 36 images back out, which each contains a letter from the flag.
osint - Geogusser-Extreme 2
1
2
3
4
5
6
7
Guess the coordinate from the description
```
cursed.free.flag
```
the flag format is cursedctf{12.456789,-123.340000}
This challenge is created to check the “Solvable by dcode.fr” bingo block in mind. I totally missed the part where the bingo said “Crypto challenge”. I thought: How can I pick a dcode functionality that isn’t obvious, so it’s technically solvable by dcode.fr but it’s actually a bit harder than that. Then in the geography section, I found the what3word option, and decided Yeah this is what I want. Hence this challenge.
The solution is obviously just going to dcode.fr, and put the description in, then you’ll get the flag.
Wrap it in flag format and you’ll get cursedctf{65.826986,-113.171834}
osint - Geogusser-Extreme
1
2
3
4
5
6
7
Guess the coordinate from the description
```
```
the flag format is cursedctf{123.456789,12.340000}
Before I started to create any challenge, Emma1 already created all the geogusser challenges, but there seems to still be a lack of geogusser challenges (yeah there’s never enough geogusser!).
So I think? What is the simplest geogusser? Or else, what’s the minimal hint needed to guess a location?
I then remember the null island.
That’s obviously a good place to guess!
With an empty description, people would be able to get that it’s the null island and guess the all zero coordinate!
And this challenge is born, the flag is obviously cursedctf{0.000000,0.000000}
crypto - crypto curses
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
You've stumbled upon a strange website where everything seems to be encrypted. There's a message written on the homepage:
```
Cursed Cryptography Challenge:
Can you break the curse and find the hidden flag?
Remember, the flag format is cursed{\w+}
```
Your task is to decrypt the following ciphertext to reveal the flag:
```
Ciphertext:
Uijt jt b tfdsfu nvdi. Ju't b dpnjoh bddftt, cvu ju't tqfoejoh ijn xjui b xfflt."
```
This challenge is created by chatgpt™️.
Jokes aside, I was originally hoping that chatgpt could create a cohesive challenge, with a reasonable flag.
It ended up being a lot less stable when it comes to encrypting and decrypting things.
Let’s take this exact challenge, the ciphertext is supposedly a Caeser cipher of the plaintext This is a secret message. It's a coming after, but it's spending him with a weird.
.
If you tried to decrypt the ciphertext yourself, however, you’ll quickly find out it is the encryption of This is a secret much. It's a coming access, but it's spending him with a weeks."
.
Not to mention that chatgpt end up stating that the flag should be cursed{secret}
with totally no logic.
Well obviously cause chatgpt doesn’t have logic, it’s just a transformer* guessing the next token based on previous sentences
So the original idea of just posting the challenge description would utterly fail, as no one would probably guessed it correctly. The next idea is to use some sort of pixelation on the code block, and intended for people to use tools such as Depix to recover the content. This would have been a cool idea actually, but I can’t find a good pixelation app that I’m confident to be “solvable” (I guess challenges don’t really have to be solvable in cursedctf anyway)
In the end, I decided that maybe if the original chat log is leaked in some form.
People can just look at the correct flag, and there will be less confusion.
I cropped the chat such that the shareable link is shown in the navigation bar, with just 1 character cropped out.
I can maybe crop out a lot more characters, but I’m afraid that it’ll end up becoming a DDOS attack toward chatgpt.
Though in hindsight, two or even three characters (so 4096 possible urls) should be fine.
Link to the chat
Here some trials I made before settling with the above conversation
I was hoping that an odd request message could somehow force chatgpt to include it in the flag somehow in a somewhat more reasonable manner.
Seems like I can’t show multiple options chosen during the conversation…
forensic - babystego
1
2
3
Wow I make a image with the flag in powerpoint =D
hint - replace the flag format to `cursedctf{.*}` when you found the flag
As the description suggested, this challenge is indeed made with PowerPoint.
There are two cursedness in this challenge.
The original idea is to create a stego challenge where the flag is right in front of you the whole time, but people wouldn’t believe it.
So the simple way to do this is just to put the flag right in the middle of the image, but add various rabbit holes around the image.
What I totally missed is that I wrote cursed{I~AM~FLAG}
in the image, while I set up the challenge to accept cursedctf{I~AM~FLAG}
.
I didn’t notice this until the last day of the competition, and released the hint to fix that, as this was not the intended difficulty of this challenge.
It’s very funny though, I did spend some time deciding if I want to keep it as is since like 20 people already guessed it.
misc - check-sanity
1
`cursedctf{cursedctf{cursedctf{cursedctf{cursedctf{cursedctf{flag}}}}}}`
For this challenge, the idea is that normally you always submit flags according to the description.
So then the cursed thing is the reverse, to submit the description according to the flag?
Obviously, you’ll need a flag that almost everyone would have gotten, which would be sanity-check
.
Now if you look at sanity-check, the description said haha i claimed the best challenge
and then the flag.
So, the flag for check-sanity is haha i claimed the best challenge
.
I did make the arbitrary decision of truncating out the flag part.
I hope that this doesn’t hinder anyone with the right idea but ends up not getting the flag.
Halfway through the competition I thought that this challenge shouldn’t be that hard, but no one is getting it. I then saw that we had a #leaked-flags channel, and think: Huhhh it’ll be funny if the leaked flags channel actually contains a real flag. Since the flag for this challenge doesn’t have the flag format, it’s the perfect candidate as people wouldn’t notice that it’s a valid flag. I then posted a lot of fake flags along with it and announced the “One Piece” in the leaked-flags channel.
rev - git madness
1
2
JDSL... but in git????
ps - it only took 4 minute on my machine to check the flag =D that's blazingly fast
This is the challenge that drives me to contribute to this year’s cursedCTF. I was watching YouTube and saw The Most Amazing Software Ever Created, which is a reaction video to The inner json effect. The only thought I have after this is.
This is sooooo cooool, what if this is a CTF challenge?
Some parts obviously need to change. I’m more familiar with git, so I think I’ll build a similar system with git. Also, this might not be suitable for a normal CTF. (I’m creating challenges for b01lersCTF as well!! Stay Tune!!) Oh, cursedctf is around the corner and I did join the admin team, I should just put it there.
All of that happened like 1 week before the competition, and I didn’t have much time, so I quickly brew up a prototype and made this schematic.
Yeah that seems cool, we can use the git head and the git commits as states and pointers. Now we can implement a finite state machine using git! Some possible things I could add to the challenge are
- Randomize branch name
- Randomize commit name
- Randomize commit time
- Randomize tree layout
- Multiple languages
- Obfuscated Constants in different languages
- … maybe more ideas
Due to the time constraints, I can only implement the checking part as basic as I can while still abusing git’s state machine.
I use shellscript as the main language and call git directly to manipulate the state.
The idea is that each branch head acts like an anchor, while git checkout HEAD^
or git checkout HEAD~x
serves as the way to move the pointer around.
Due to the limitation of git, you can only move the pointer in one direction, namely toward the parent.
For the flag format part, I checked each character one by one. Then I have a section that does a “matrix multiplication”, which is just adding some position values together and verifying if they match the target sum value. I achieve summation check by having the target number of commits on the branch, and for each character input, you move that many commits toward the parent. After a certain number of jumps, if we land on the correct commit (state), then the check passes. The rest of the flag is checked through several modulo checks. Having git go to parents several times with one final commit going back to the branch head, we can have some sort of modulo operation, and hard code the result commit.
Let’s admire the glory of the final product.
I would hope that I can implement all the “features” and integrate more interesting ways to move on this “state machine”, but run out of time.
Also, I think this challenge is cursed enough as is.
jospeh fan club
is the only team that ends up solving it.
I’d hope that more people attempted it, but having a solve is already more than what I expected.
Conclusion
I hope that everyone who participated in this event has a fun time. I truly enjoyed the whole process, and would look forward to next year (or finals!). That’ll be a wrap for cursedCTF 2024 qual!
*: I’m not sure if chatgpt is using transformer under the hood, I’ll probably need more research into it to find out