Posts Tagged ‘python’

Discord Discriminator Farming

30 Apr 2018

This post outlines how I got the Discord discriminator that I wanted.

This process is old and is no longer required as Discord now allow you to change your discriminator via Discord Nitro.

What are discriminators?

Discord is a free modern voice and text chat application. Discord uses usernames to identify its users. However, instead of a username becoming unavailable after just 1 person uses it, Discord allows 9999 people to share the same username. It does this by using the combination of a name (unicode string) and a discriminator (4 digits) as a Discord tag.  SomeUserName#1234 is an example of a Discord tag. This is a great idea (and more services should use it) as it allows many extra people to use their first name or a common alias as their username.

Each Discord account still has an underlying Discord user ID (i.e. 356005924638224307 ) that can is echo’d if you type in  \@SomeUserName#1234 into any text channel. This is typically hidden from most users and used by developers when making plugins and bots.

Why do discriminators matter?

They don’t but just like usernames, discriminators are visible and thus can be considered to be a cosmetic name tag attached to your account. This is why people want specific Discord discriminators. Because it looks nice! User#0001  or User#1337  look a lot nicer than User#6519. For a long time, Discord has been strictly against scripts/bots which were designed to change a users Discriminator. This is because they believed the aesthetics of discriminators did not matter and their only purpose was to allow more people to share the same usernames. This statement was somewhat unfair given that almost all Discord devs had manually changed their discriminators!

Writing a Discord Discriminator Farmer

Back in mid 2017, I decided I wanted a new fancy Discord discriminator to replace my randomly generated one of 8471.

There is only one way to change your discriminator. Discord offer a name change feature in which you can change your username but not your discriminator. However, what happens if the username you want is already taken by someone with the same discriminator as you? Two users can’t have the same Discord tag. In this case, Discord changes your username (assuming all 9999 discriminator for that username aren’t taken) and then randomly generates a new discriminator for you!

This is the key behaviour that I used to write some python scripts to farm Discord discriminators.

Step 1: Gathering a list of usernames and discriminators

The first step in the process was to write a script ( to store a large number of Discord usernames and discriminators belonging to existing users. Recall that we needed to change our username to a new username that already had a user with our current discriminator. For example, if our Discord username was  SomeUserName#6513 and a user existed called  Tony#6513, we could change our username to Tony and because  Tony#6513 already exists, Discord would generate a new random Discriminator for us.

Overall, this script was fairly simple to make. We simply made a new Discord account and joined a lot of guilds (aka servers) with very high member counts. We then uses the Discord API to return a list of all members in the guild that were currently online. By joining a few massive guilds like /r/Overwatch and /r/PUBATTLEGROUNDS, we had access to over 60000+ Discord tags which meant we had an existing username for 99% of discriminators. Our script stored the results as a dict which was dumped as a pickle so our second script could use it. This file was regenerated every 15 minutes to ensure we wouldn’t get stuck (in the rare case where our dump contained no matching usernames for a particular discriminator).

Step 2: Farming them Discriminators

The second script ( would authenticate with Discord, load in our pickle from our first script and begin changing usernames. However, there was a problem. Discord initially allowed you to change your username as many times as you wanted. Then they restricted username changes to once per hour. Then once per two hours. Then once per day which is what the “secret” time window was when I was testing. This was to combat people doing exactly what I did. Now, given that I wanted a very small subset of target discriminators (22 total) out of a possible 9999, this would not do. As there was no way to get around this username change time limit I was forced to use multiple accounts and change each of their usernames daily.

This worked well initially before I ran into another issue. IP rate limiting. Discord would rate limit my servers IP address causing a lot of the username change API requests to fail. I overcame this quite easily by spanning out my name changes throughout the day rather than making them all at once.

Another issue was the fact that each account needed an Authorization Token to authenticate with the API. I ended up manually fetching and storing the authorization tokens for all the accounts I used by logging into each account, filling in a captcha if one was presented and then retrieving the authorization token from the browsers local storage. As long as you did not log out, the authorization token remained valid indefinitely (this is why you can stay signed into the same Discord account forever on the same machine/browser).

Finally I was able to run my script successfully with about ~150 accounts at once. Meaning I had 150 new discriminators generated over a 24 hour period. Again, this isn’t a huge amount but it was enough to make bruteforcing feasible.

Discord Account List

Once a name changed resulted in a new random discriminator that was in my target list, that thread would end and an entry would be written to my log file to alert me.

Step 3: One final name change

Over 2 weeks later running my scripts 24/7, I finally had 1 alert letting me know that a target discriminator was found. I really liked the result so I decided I would keep it and turn off my scripts. However, the account with the final discriminator did not have the username I wanted.

The final step involved changing the username to the username that I wanted to use. This part is important, you had to ensure the username you were changing your name to DID NOT have a discriminator that matched your new discriminator. Otherwise, Discord would just give you a randomly generated discriminator. This was easy enough, all you had to do was try to add a user via the friend system and see if the friend request was send successfully indicating the account existed or not indicating the account did not exist and it was safe to proceed. For example, if my final account with my target discriminator was  RandomUserName#1337  and I wanted my tag to be  MyName#1337, I would send a friend request to  MyName#1337 to see if that tag existed. If it did not, I could proceed and get it for myself! Otherwise, you would unfortunately be out of luck.

Changes to Date

After I stopped running my scripts, Discord eventually increased the username change time window and enforced harsher IP rate limiting. Finally, they allowed users to change their discriminator via Discord Nitro although most of the good ones are probably taken by now.

Source Code

The source code for this project is available here:

No Comments

Posted in Programming


HACKvent 2015: Day 15

15 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 15 December 2015



Straight away this looks like a logic solver problem. I intend to use Z3 theorem solver (link) as I am most familiar with it out of all the available solvers out there.

First step is to understand the problem. Each letter corresponds to a single digit 0-9. The q  digit cannot be 0. Each digit is represented by exactly 2 letters. In the grid of equations, a series of letters like bytwycju means 8 digits. Ie if b  was 2 and y  was 8, it would be a number starting with 28XXXXXX. The operations used in the equations are   & ^ | + - ==. C-like operator precedence is also used but this will match up nicely with python operator precedence.

Looking at the secret message, is it 38 pairs of letters. If each letter is a single digit then each pair must correspond to a ASCII  capital letters/numbers/spaces…etc. So I am going to assume the secret message is a 38 character length string.

Every letter from the alphabet is present in the challenge description and equations except for: aekmpr
This works out nicely as excluding those 6 letters leaves 20 letters total which leaves exactly 2 letters per digit, perfect!

So I start writing a new python script and add in all the rules I need. I use a BitVec of 32 bits because some operations become large. I could use a BitVec of 4 bits but then certain bitwise operations would overflow which is not what I want.

For each equation I need to generate a list of long constraints to add to the Z3 solver object. To do this I use a short python script written by OS-Freeze from Germany (thanks!) which was slightly modified by myself:

The above script would produce:

I simply change the equation for each equation in the challenge description until I have all of the constraints I need.

Now I can construct my actual solver script:

This is really a simple script. I use a dictionary called ZV to keep track of all my letters. I add in every letter as 32 bit BitVec’s. Next I add the constraint that ensures each letter is in [0,9]. I add the q != 0 contraint which eliminates the trivial all zero solution. Finally I add all the rules I generated above and run the script!

The following solution is found after 20 seconds or so:

I write a short script to decode the original message using the above solution (or key).
I end up with:

I run the script and the following message is printed:


I enter this into the ball-0-matic, get the daily QR code and the daily flag!


Day 15 Solution Ball

Flag:  HV15-U3bA-BKhc-gNqN-Hit6-C1fK

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 11

11 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 11 December 2015


The following image is provided:

HV15 Day 11 Punch Card


I had to spend some time researching the above image but I soon discover that it is a punch card.
It turns out to be a IBM 96 Column Punchcard. Unfortunately there isn’t much information online on how to decode them.

A reverse image search comes up with the following image:
IBM 96 Punchcard

This is what the challenge organiser used to make the above challenge!
The first thing I do is open the image in Photoshop and apply a black background so I can see the data (black dots) more easily.

I get:
HV15 Punchcard Black Dots

Another important piece of information was this image I found online:
Zorch its a system 3

I used the above image to determine how I decoded the data. The above image encodes the data ZORCH IT’S A SYSTEM 3.

You have to look at each column in the punch card and generate a number.
For example, in the first column above we have _A__81 or in binary 011001.
This corresponds to the letter (more on this later).

Thus each block can have a total of 32 bit characters. The total card can therefore contain a total of 96 (32*3) characters.

Now, going back to our message, I first write out all the bits in one big block, I get:

At this stage all I need to figure out is the language, I don’t find much on this online but I eventually come up with a 64 length partially working language (it begins with a space):

So in the example I discussed, 011001 is Z because 011001 is 25 in decimal and Z is at index 25 in the string array above.

Note: This language was created using trial and error and so I didn’t determine many characters initially (which I have just left as a ? ). Later on I discovered an image (link) which allowed me to determine every character! (some special characters were still left as a ? )

At this stage I can write a nice short python script to read the data and convert it to the language.

I put the bit data into a file called input.txt and run my script.
The following message is printed out:

Great! The clue is quite simple, we simply need to alternate the case of each of the 6 blocks in the nugget (as separated with | ). We know the nugget begins with the uppercase  HV15 so we know the pattern straight away.

Flag:  HV15-m3hn-BG5H-lufe-8WPM-kzfk

No Comments

Posted in Hackvent 2015


HACKvent 2015: Day 10

10 Dec 2015
CTF: Hackvent 2015
Link to challenge:
Date Completed: 10 December 2015


The following zip file was also provided: Download ZIP File


We notice that the zip file contains one zip file called, that contains one zip file called and so on. I also know that the file zile will keep getting lower and lower in file size the more we extract (due to ZIP headers and padding). Furthermore, opening the file in HxD (the hex editor) allows us to see the names of all embedded zip files. We see the number among many others so we know there are a lot of files here!

We write a quick python script to recursively extract each zip file.

Finally we reach the zip file: which is different from all of the other files.
This zip file contains one file called worst.500 and is password protected.

We use the glorious Accent Zip Password Recovery to crack the password in milliseconds.

The password for the zip file is: love

We extract the file, look inside and find the flag!

Flag:  HV15-iQYf-adNg-o4S9-JHc7-vfWu

No Comments

Posted in Hackvent 2015