Bypass admin login with SQL Injections (sqlmap)

Christophe Limpalair
9 min readOct 6, 2021

--

I originally posted this video on YouTube, but they ended up banning it from their platform. This was my most popular video at the time, so I wanted to share it here :)

Without further ado…the hacking video YouTube didn’t want you to see:

So you have a website with a login form, and you want to figure out how you can use SQL injection to successfully log in without even knowing a valid username or password. That’s exactly what I’ll show you how to do in this post.

Quick disclaimer: don’t do this against applications unless you have permission. This is meant to teach you these techniques so that you can perform them against your own application(s) that you have permissions for, which is not only completely legal but also highly recommended. If there are vulnerabilities in your applications, you want to find them before a malicious actor does. So doing this against applications you don’t own or have permissions for is a no-no, but doing this against your own applications or apps you have permissions to do it on, like for bug bounty programs, pentests, etc…is a big yes-yes.

Using automation

There’s a crazy powerful tool called sqlmap that I’ll use. This tool was literally built as a penetration testing tool to automate the process of finding and exploiting SQL injection vulnerabilities, and then actually taking over databases and servers. So if you’ve never used sqlmap before, definitely stick around so I can show you how it can help automate finding SQL injections.

Keep in mind, though, that you don’t have to use a tool — you could also do it manually.

If you’re interested in seeing a demo like this being done manually instead of using an automated tool like sqlmap, let me know in the comments below! I’ve actually already demonstrated that in my Injections Attacks: The Free Guide course, but I’d be happy to share it on here & YouTube as well if there’s enough interest.

Our example target application

For the example website that we’ll be attacking, I’m going to use an app called the OWASP Juice Shop. If you’ve never used it before or if you want to follow along, check out my quick tutorial that shows you exactly how to set it up just like I have it for this article.

The Juice Shop is a modern application that uses Angular.js and SQLite as its database, so that actually makes things a little bit more interesting than if we were dealing with a legacy app.

Let’s start by submitting just a generic request. I’ve got ZAP, my proxy tool of choice, but you could also use Burp for this of course. You don’t even technically need a proxy tool, but it can certainly make things easier.

We’re on the login page (http://localhost:3000/#/login if you’re following along) and we’ll go ahead and submit fake credentials so we can see how this application behaves:

Obviously, we’re not authenticated since these aren’t valid credentials, but if we pull up ZAP and find our login request, we’ll get to see what endpoint we want to provide to sqlmap and how we’ll want to format our data.

We can see that a POST request is being made to this endpoint: http://localhost:3000/rest/user/login

And the data is being formatted like this: {"email":"test@test.com","password":"test"}

So even though the web page endpoint is https://localhost:3000/#/login, when we submit our login request, the client-side code is sending our request to this endpoint: http://localhost:3000/rest/user/login. So if we tried testing the /login endpoint with sqlmap, we would not find any SQL injection vulnerabilities. That is not the endpoint processing login requests.

Crafting our sqlmap attack

With this information, we have enough to start crafting our sqlmap command.

If you’re using Kali or Parrot OS, you should already have an instance of sqlmap installed. If you’re not or if you want to use the latest version, you can type this command:

git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev

I’ll navigate to where I downloaded the latest sqlmap version from GitHub:

cd ~/Documents/sqlmap-dev

And I’ll use python3 to make my request:

python3 sqlmap.py -u 'http://localhost:3000/rest/user/login' --data="email=test@test.com&password=test" --level 5 --risk 3 -f --banner --ignore-code 401 --dbms='sqlite' --technique=B
  • -u is the option that lets us dictate what endpoint we want sqlmap to target
  • --data is the option used to specify our POST data format separated by the & separator
  • --level 5 and --risk 3 are options the determine the types of payloads and techniques that sqlmap uses against the target. The higher the level, the more requests and the more detailed testing you will get. That has pros and cons, and you can check out my cheat sheets for more information on that
  • -f and --banner are fingerprinting options used to enumerate our target and try to gather useful data
  • --ignore-code 401 is used because when sqlmap sends requests with sqli payloads to the target, it will inevitably use invalid credentials which will result in an HTTP 401 response (401 being Unauthorized) from the target application...the problem is that sqlmap will stop sending requests at the first sign of 401 responses unless we provide this flag. We already know the requests will result in 401s, so we don't care and we want to ignore those
  • --dbms='sqlite' if you already know without a doubt that your target application is using a certain database management system, like how we know here that the juice shop uses sqlite, (you can usually figure this out with a little bit of upfront research) we can specify it which will help sqlmap cut back on the number of requests it has to send out and it will speed up our testing. If you don't know what the back-end DBMS is, then you can leave this off and sqlmap will figure it out
  • --technique=B is to tell sqlmap to only use boolean-based blind payloads for testing instead of including all of its other techniques. The only reason I'm doing this is to speed things up since I already know that this application is susceptible to this technique. Otherwise, you can just let sqlmap use all of its available techniques to increase your odds of finding something

I’m going quickly through these options for the sake of time, but my course goes into a lot of depth and explains all of sqlmap’s options inside & out if you’re interested in more.

We submit this request and we wait to see what happens

After a while, sqlmap will find a successful payload, and because we passed in the fingerprint and banner options, sqlmap enumerated back-end DBMS information and figured out that the target app is running:

  • SQLite 3.34.0

We can use this information to search for vulnerabilities, especially if it’s not the latest version, which is something else we could include in our report at the end.

I won’t do that here, but again, let me know if this is a video or article you’d like to see.

The successful SQLi payload

One more thing I’ll do before we wrap up is to look at the successful SQLi payload that sqlmap found:

Parameter: email (POST)
Type: boolean-based blind
Title: OR boolean-based blind - WHERE or HAVING clause (NOT)
Payload: email=test@test.com' OR NOT 1120=1120-- BGqV&password=test

The vulnerable parameter is the email param, the successful injection type is OR boolean-based blind, and the payload is this:

' OR NOT 1120=1120-- BGqV

What’s interesting about this though is that technically this payload itself doesn’t work, but there’s a reason why sqlmap is showing it to you. Let me demonstrate.

We can test this payload out manually via both the web page and via ZAP.

On the login page, if we try to submit this as the username:

test@test.com' OR NOT 1120=1120-- BGqV

We don’t get a successful login. So what’s going on? Why is sqlmap saying that it’s a successful payload?

There’s a reason that I teach you how to review sqlmap’s codebase in my course, and it’s because we can find the answer there.

If we go to /data/xml/payloads/boolean_blind.xml in sqlmap’s codebase, and search for the title of the payload (OR boolean-based blind - WHERE or HAVING clause (NOT)), we'll see that this payload gets compared to the response from a second payload:

<request>
<payload>OR NOT [RANDNUM]=[RANDNUM]</payload>
</request>
<response>
<comparison>OR NOT [RANDNUM]=[RANDNUM1]</comparison>
</response>

What this means is that the first payload — the one sqlmap is showing:

' OR NOT 1120=1120-- tGvo

Is actually being compared with the results from this slightly modified payload:

' OR NOT 1120=-1120-- tGvo

(Notice the negative number in the second payload)

Because sqlmap is getting different results from the application/database when it compares these two results, it knows that the different payloads are triggering a different response from the database, which means it’s vulnerable to SQL injections! We shouldn’t be able to manipulate SQL queries in the way that the payload is if this database isn’t vulnerable to SQLi.

So our successful payload is actually the comparison one, but that’s not the one sqlmap shows us.

If we use that comparison payload, we will successfully login via the application.

Again, we can also run this through ZAP.

test@test.com' OR NOT 1120=-1120-- tGvo

We get a successful login even though these are not valid credentials — it’s because we’ve found a successful SQL injection payload that tricks the database into thinking we are a valid user.

Understanding how this works at the SQL query level

We can also check out how this is working at the SQL statement level if we create a fake replica of the Juice Shop database in SQL Fiddle:

CREATE TABLE Users(
id INT PRIMARY KEY,
email VARCHAR(100) NOT NULL,
password VARCHAR(200),
deletedAt VARCHAR(100)
);
INSERT INTO Users
VALUES (1, 'admin@test.com', '098f6bcd4621d373cade4e832627b4f6', '' );

This is what we might expect the Users table to look like. Then, we execute the statement that the application is running when we login:

SELECT * FROM Users WHERE email = 'test@test.com' OR NOT 1120=-1120-- tGvo' AND password = '098f6bcd4621d373cade4e832627b4f6' AND deletedAt IS NULL

We can see that this query returns all records from the database, while the positive number one doesn’t return any results:

SELECT * FROM Users WHERE email = 'test@test.com' OR NOT 1120=1120-- tGvo' AND password = '098f6bcd4621d373cade4e832627b4f6' AND deletedAt IS NULL

If the database and application weren’t vulnerable to SQLi, then the query would look like this as it gets executed:

SELECT * FROM Users WHERE email = 'test@test.com\' OR NOT 1120=-1120-- tGvo' AND password = '098f6bcd4621d373cade4e832627b4f6' AND deletedAt IS NULL

The test@test.com\' OR NOT 1120=-1120-- tGvo would get treated as a simple string since the ' wouldn’t close the first single quote.

Conclusion

So we’ve found a vulnerable input field, we’ve found a vulnerable endpoint, we’ve successfully fingerprinted the back-end DBMS, and we’ve successfully crafted an sqlmap command against the OWASP Juice Shop.

As I said, I went quickly through a lot of concepts and topics in this article to show you how it’s done, but I’m happy to post more videos or articles going into further detail if you would find that helpful. You can also learn a lot more by checking out my free courses called Injection Attacks: The Free Guide, The Beginner’s Guide to sqlmap, or my premium course called The Practical Guide to sqlmap for SQL Injections. This is the most in-depth sqlmap course you will find on the Internet.

I also post a lot more articles like this over on our blog.

Thanks for reading, and see you next time!

--

--

Christophe Limpalair

Helped build 2 startups to acquisition in 5 years: ScaleYourCode (Founder) and Linux Academy. Now building Cybr, an online cybersecurity training platform