In Python, the .get() method returns None for missing keys instead of raising an exception, unlike square bracket access which raises KeyError. This behavior can create authentication bypass vulnerabilities when code uses .get() to access dictionary values for credential validation, as None == None evaluates to True, allowing attackers to bypass authentication by sending malformed requests with missing password fields.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Whatever .get()'s you the flag
Added:Everyone, I hope you're doing great.
So, a month ago I had the opportunity to visit Area 41 conference here in Zurich, Switzerland. And it was absolutely amazing. So, there were like so many things to do at that conference. First of all, you got a really cool hackable badge. This one. It's It looks amazing.
It is amazing. And you can hack it. So, what else to ask for? Apart from that, there were like talks, villages, lots of people to meet. And actually quite a lot of CTFs as well. I had some time before my talk, so I decided to play one of the sponsored CTFs. It's like, you know, a CTF at the sponsor's booth. And I've chosen the Infoguard one. Shout out to the Infoguard crew for organizing it.
Because it was just four challenges and they were actually seemed pretty interesting. So, I decided to him, let's let's try it.
One of the challenges I actually solved in an unintended way, and I do have to admit I solved it accidentally. From time to time, not too often, you happen to solve a challenge accidentally. Like you're not meaning to solve a challenge, but you do something and because of bugs well, things happen and you get the flag. And this is what happened with this challenge.
So, what I wanted to talk about today is basically this challenge and what happened there, how did I get the flag.
So, a simplified version of a challenge looks like this. There are basically two endpoints which matter. And again, this is the simplified version, meaning that on the actual CTF the task was a little bit more complicated, but we actually never got it as players who found the unintended solution. We only saw ever a website with a login form where we had to provide the credentials, the username and the password. And that website actually used JSON protocol to login.
And yeah, from my perspective, this CTF task was all about what's on the screen right now.
Basically, the authentication and the information endpoint. The authentication endpoint is for authentication. You have to send it the username and the password, and the info is where the magic happens.
Or rather, where if you're logged in, you get the flag. Let's try sending a request to that info endpoint. So, I already have a script ready, which does curl on this info endpoint. And if we run it, we get status login required, but no flag. Well, this is fine. This is working as expected. So, we do have to login. Now, the problem is that we don't really know what is there username and the password.
Let's analyze the source code. The actual challenge was black box. We didn't see it, but to actually admire the beauty of this simple unintended solution, it's better that we look at the source code.
What's happening here is that we are getting a dictionary, a JSON-encoded dictionary. We decode it to a data variable, and then if it's empty, we actually say invalid JSON format.
Otherwise, we try to get from this dictionary a username and a password.
Now, there is this global dictionary called users, which is a plain text dictionary where the key is the username, and the password is, well, yeah, the password, just plain text password. So, for example, John and John's password.
So, we fetch the user from that dictionary. For example, if we provide username John, then John's password is being fetched here, and we compare it to whatever the user provided as a password during authentication. If it matches, hey, great. We set the username for the session, and we reply with status okay.
Otherwise, we reply with error message invalid credentials. So, the way I actually walked you through it is slightly misleading, because this is showcasing how it works in the perfect scenario, where the user gets to login.
But, let's try a couple of things. So, first of all, let's try to send the username and the Well, we don't know the password, so I'm just going to send ASDF, and let's see what happens.
We are sending content type application JSON, [clears throat] and then we actually send the JSON-encoded dictionary with username and password here. Okay, let's send it.
And we are getting 401 unauthorized message invalid credentials status error.
Okay. Yeah, this apparently isn't going to work. So, what I actually did at the CTF was I was going step by step. I was thinking of Okay, let's just get the first part of the protocol right. Let's see if there is any error if the password field is missing. If there are any errors, you can usually determine by what error is there, whether this is this framework or that framework, this library, or maybe something else. So, this kind of gives you an idea of a technological stack which is being used.
So, let's remove the password field, and let's go with username John, and let's see what happens, and we get invalid credentials. But, what I did on the CTF, I actually put here 1 2 3 as a number, and let's see what happens now. And hey, I actually got status okay with a cookie.
Is this an actual session cookie? No, it cannot be. Or is it? So, let's try to send like add this cookie, send this cookie basically to the info endpoint, and see what happens. I'm going to comment this out.
And we get the flag. And this is basically how I solved the challenge.
Now, what happened is the interesting question. So, let's walk through it again from this function, but now let's keep in mind the packet which we sent, which is username is actually an integer. This doesn't matter that it's an integer, but I sent an integer, and there's no password field at all.
Okay, so we get the JSON here, and it gets decoded correctly. It's a correct JSON. It's not an empty dictionary at all, so this isn't met.
We get the username and the username is 123 as an integer. And the password, well, there is no password. Now, there's an important difference in Python between the notation data.get password and an alternative notation which would be data and then square brackets password.
The square brackets, if the key password does not exist, actually raises raises an exception like throws an exception.
But the get method does not. Rather than that, it by default returns none.
Or you can actually like put a second parameter here and it would return the second parameter otherwise, but well, it it does actually return none if the second argument is not specified. So, we get a none here. We got username 123, password none.
Okay, so now we get this fetch from the users global dictionary and we try to fetch the 123 user.
Oh, there is no 123 user in this dictionary at all.
But we are using get here, so this will not raise an exception as discussed in a second ago. This will return none. So, we suddenly have none on the left side and we have none on the right side. And hey, in Python, none is equal to none, which makes a lot of sense. So, we are logged in. Amazing and we get the flag and we got a solution. So, this was a pretty fun task and like because of again the quirks in how the code was exactly made, it allowed us to bypass the challenge altogether. In the end, I actually managed to complete all the challenges. First, I got a rubber ducky for it. Thank you very much.
I was first, but I was actually tied with two other people because of the conference rules which were applied to the CTF which disregarded the when you submitted the last flag, which is fine.
Like it's a conference, right? Like people aren't don't have time all the time to play the CTF. They will go to talks and so on.
Now, if you enjoy this kind of Python quirks and would like to learn more about it, check out my Python cyber summer camp on hacker kernel.com. I'm going to leave the link in the description. It's going to start in two weeks basically and it's going to contain a lot of weird Python stuff, a lot of quirks, a lot of things which surprise programmers and we will also go pretty in depth. If you enjoy Python, check it out.
That's it for today. Thank you for watching. I hope you enjoyed it.
Leave a comment if you did. Leave a comment also, what is the most surprising thing in Python which caught you off guard?
Maybe something like this, maybe something a little bit more complicated.
With that, signing off. Take care.
Cheers.
Related Videos

TOP 15 Data compression Interview Questions and Answers 2019 Part-2 | Data compression | Wisdom jobs
wisdomjobs
281 views•2019-06-28

CTS 158: 802.11w Management Frame Protection
ClearToSend
4K views•2019-02-04

NDSS 2019 Send Hardest Problems My Way: Probabilistic Path Prioritization for Hybrid Fuzzing
NDSSSymposium
496 views•2019-04-02

How realistic is Cities: Skylines?
CityBeautiful
159K views•2019-02-14

GUIs & TUIs: Choosing a User Interface for Your Python Project | Real Python Podcast
realpython
2K views•2025-04-04

The OSI Model - Explained by Example
hnasr
225K views•2019-05-12

Cloud Computing - Introduction
elithecomputerguy
98K views•2019-10-07

From Traveler's Dilemma to Dynamic Routing | Demystifying Networking
IITBombayJuly
5K views•2019-08-04
Trending

WOW! Judge TURNS THE TABLES on Trump in His OWN $10B LAWSUIT!!!
MeidasTouch
197K views•2026-07-23

Playstation NO DISC/NO BUY Fight Is Over...
DavidJaffeGames
4K views•2026-07-23

Steam and Xbox Just Dropped The Hammer On PlayStation
OhNoItsAlexx
9K views•2026-07-23

Americans Confused in Australia for 17 Minutes Straight
IWrocker
17K views•2026-07-23