-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: SQL Injection checkpoint (#113)
Most of the SQL injection docs done, they were done earlier and I thought I opened a pull request but I guess it didn't go through The docs are not completely finished, I need to edit it and add one or two more things, especially around the end. But for now they should be sufficient
- Loading branch information
1 parent
d389df1
commit a402c9c
Showing
6 changed files
with
216 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
--- | ||
title: SQL Injection | ||
description: Simple introduction to injecting SQL into a website | ||
--- | ||
|
||
SQL injection is one of the most common web vulnerabilities. | ||
It's one of the easiest attack vectors for a website, and it's even easier to prevent. | ||
|
||
In essence SQL injection is when a user uses a place that accepts user input that searches a database, and then gets something they weren't meant to. | ||
|
||
In 2017 the Open Web Application Security Project ([OWASP](https://owasp.org/)) [rated Injection as the most common web application vulnerability](https://owasp.org/www-project-top-ten/), and third most common in 2021. SQL injection is a large portion of injection. | ||
|
||
## What is SQL? | ||
|
||
SQL, or Structured Query Language, often pronounced like sequel, is a language used to interact with databases. | ||
It's used to create, modify, and retrieve data in the database. | ||
|
||
SQL is a very simple language to pick up, and it's very easy to learn the basics. | ||
Take this example: | ||
|
||
```sql | ||
SELECT * FROM users WHERE username = 'admin' AND password = 'password'; | ||
``` | ||
|
||
- `SELECT *` is used to select everything from a table. | ||
- `FROM users` is used to select the table `users` from the database. | ||
|
||
So `SELECT * FROM users` selects everything from the users table. | ||
|
||
`WHERE` is used to filter the results to only include the conditions following `WHERE`. | ||
In this case the conditions are the username must be `admin` and the password must be `password` | ||
|
||
Altogether this will get all of the users with the username `admin`, and the password `password`. And since it's a login page, it'll likely only return one user. | ||
|
||
### Simple injection | ||
|
||
The simplest way to perform SQL injection is to use a single quote ' in a field that accepts user input. | ||
In an example like the one before, instead of putting `admin` as the username, we're putting `'`, which would make the query look like this: | ||
|
||
```sql | ||
SELECT * FROM users WHERE username = ''' AND password = 'password'; | ||
``` | ||
This is an incorrect query since there are three single quotes, it'll likely throw an error at the user. | ||
|
||
We can use this to our advantage though, if we put `' OR 1=1--` as the username, the query would look like this: | ||
|
||
```sql | ||
SELECT * FROM users WHERE username = '' OR 1=1--' AND password = 'password'; | ||
``` | ||
|
||
Unlike `'`, this is a valid query. | ||
The `--` is used to comment out the rest of the query, so the `AND password = 'password'` is ignored. | ||
|
||
When SQL goes to the database, then goes to the users table, then gets all of the users with the conditions after `WHERE` it'll get all of the users wgeb the following condition is true: the username is `''`, or when `1=1`. Since 1 is always equal to 1, and only it has to be correct due to the OR, it'll always return true for the query from users. | ||
|
||
So, depending on how the surrounding code is setup, it'll either return all of the users or the first user, which is often the admin. | ||
Juice Shop is a website designed to be hacked. If we try this on [the demo Juice Shop login page](https://demo.owasp-juice.shop/#/login) by placing `' OR 1=1--` into the username field, we get signed into the admin account. | ||
|
||
In case you don't understand try [this hacksplaining exercise on SQL injection](https://www.hacksplaining.com/exercises/sql-injection). | ||
## Sqlmap | ||
There are many, many more injections to try than `' OR 1=1--`, and there are many different types of databases each with their own vulnerabilities. | ||
Which is where sqlmap comes in, to automate finding the type of database, and testing of different injections. | ||
|
||
### Installation | ||
|
||
Sqlmap is a python script, so it requires python to run. | ||
[Download the latest version of python here](https://www.python.org/downloads/), and install it. | ||
|
||
Sqlmap is available through pip and can be installed using the command python3 -m pip install sqlmap in your operating system's terminal. | ||
Alturnatively, you can download it [from sqlmap.org](https://sqlmap.org/). | ||
If you do this you'll need to extract the file and navigate to it with `cd`. Run it with `python sqlmap.py` or `python3 sqlmap.py` instead of `sqlmap`. | ||
|
||
### Usage | ||
|
||
Sqlmap is a command line tool, so it's used in the terminal. | ||
To use sqlmap, you need to know the URL of the website you're testing and the field that accepts user input. | ||
|
||
The simplest way to run sqlmap is to use `sqlmap -u <URL> --data=<input values>`. | ||
|
||
#### Juice Shop login page | ||
|
||
This will not work on the demo Juice Shop login page. You need to run your own Juice Shop instance. | ||
[Follow the setup instructions and then return.](https://github.com/juice-shop/juice-shop#setup) | ||
|
||
Go to the Juice Shop login page, and open your browser's developer tools. Most browsers use F12 or Ctrl+Shift+I to open the developer tools. | ||
Go to the network tab in the developer tools, and try to login with some random word as the email and password, it doesn't matter. | ||
|
||
Here is what the login request looks like in Firefox-based browser LibreWolf: | ||
![Juice Shop login request](../../../../assets/sql-injection/LoginHeader.png) | ||
Here we can see the real request is being made to `http://localhost:3000/rest/user/login` and not `http://localhost:3000/#/login`. | ||
|
||
If we go to the Request tab on Firefox-based broswers and toggle Raw, or the Payload tab on Chromium-based browsers and press view source, we can see the important data: | ||
![Juice Shop login request payload where the email is Tūhura and the password is Tech!](../../../../assets/sql-injection/LoginPayload.png) | ||
Here we can see the data is being sent as `{"email":"<email>","password":"<password>"}`. | ||
|
||
Sqlmap only needs the names of the data and an example of valid input, and it seperates values with `&`, so `--data` should be `[email protected]&password=test`. | ||
|
||
Now we can run sqlmap with the URL and data: | ||
|
||
```bash | ||
sqlmap -u "http://localhost:3000/rest/user/login" --data="[email protected]&password=test" | ||
``` | ||
|
||
There's a problem with this. Sqlmap will exit as soon as it gets the 401 error resonse from the site, similar to the one we got when we tried to login with a random email and password. Let sqlmap know to ignore this with `--ignore-code 401`: | ||
```bash | ||
sqlmap -u "http://localhost:3000/rest/user/login" --data="[email protected]&password=test" --ignore-code 401 | ||
``` | ||
Go ahead and just press enter whenever sqlmap asks a question, it'll use the default option which is good enough. | ||
|
||
It won't find anything. | ||
This is because we aren't going deep enough with the injection. To become more invasive use `--level 5` and `--risk 3` option. Level's max is 5, and risk's max is 3. | ||
|
||
While we're at it let's add --batch to just automatically accept the default options. | ||
|
||
```bash | ||
sqlmap -u "http://localhost:3000/rest/user/login" --data="[email protected]&password=test" --ignore-code 401 --level 5 --risk 3 --batch | ||
``` | ||
|
||
Now it'll find something. First it finds the DBMS (database management system), SQLite. In the future use `--dbms SQLite` with Juice Shop to skip this step since we already know the DBMS. | ||
Near the end it'll find the HTTP request with successful injection, which should look something similar to: | ||
|
||
```text | ||
--- | ||
Parameter: email (POST) | ||
Type: boolean-based blind | ||
Title: OR boolean-based blind - WHERE or HAVING clause (NOT) | ||
Payload: [email protected]' OR NOT 6173=6173-- QuXO&password=test | ||
--- | ||
``` | ||
|
||
The important part of this is the payload. For [an interesting reason](https://medium.com/@christophelimpalair/bypass-admin-login-with-sql-injections-sqlmap-bb60d447a1e2) it's using OR NOT instead of OR, so remove the NOT to make it valid and suddenly it found almost the exact same query as `' OR 1=1--`. | ||
|
||
This isn't very useful, we already knew to try `' OR 1=1--`. So let's try it on something more useful. | ||
|
||
#### Search | ||
|
||
Open up your local version of Juice Shop in a new tab, and then search something. It might not show in the network tab if you use the same tab. | ||
|
||
Here's what the search request looks like in LibreWolf: | ||
![Juice Shop search request](../../../../assets/sql-injection/SearchHeader.png) | ||
This time it's a GET request, which makes this whole process so much easier. | ||
|
||
First just check out what's at `http://localhost:3000/rest/products/search?q=test` in your browser. It's just a JSON array of products with the word test in them. | ||
|
||
Here's what it looks like in LibreWolf: | ||
![Juice Shop search request](../../../../assets/sql-injection/SearchJSON.png) | ||
All in all, this isn't very useful. We could have just searched "" and gotten this all on the regular page. | ||
|
||
Let's try getting the database schema. | ||
### Schema | ||
The schema is the structure of the database, including its tables, columns, and relationships. | ||
It is how you know of all of the different types of data in the database. | ||
To get the schema, use `--schema` with sqlmap. | ||
It's very slow to get the schema so it's best to use `--threads` and then the amount of threads you want to use to speed it up. | ||
```bash | ||
sqlmap -u "http://localhost:3000/rest/products/search?q=test" --level 5 --risk 3 --schema --threads 3 --dbms SQLite --batch | ||
``` | ||
This is going to take a while, so go make a hot chocolate or something. | ||
When it's done, it'll tell you where in your file system it saved the schema. | ||
Here's what I got: | ||
|
||
```text | ||
back-end DBMS: SQLite | ||
Database: <current> | ||
Table: Memories | ||
[6 columns] | ||
+-----------+----------+ | ||
| Column | Type | | ||
+-----------+----------+ | ||
| caption | VARCHAR | | ||
| createdAt | DATETIME | | ||
| id | INTEGER | | ||
| imagePath | VARCHAR | | ||
| updatedAt | DATETIME | | ||
| UserId | INTEGER | | ||
+-----------+----------+ | ||
``` | ||
|
||
Let's go back and try this on the login page this time! Actually, this time let's try to dump all the data from the database with `--dump-all`. | ||
|
||
```bash | ||
sqlmap -u "http://localhost:3000/rest/user/login" --data="[email protected]&password=test" --ignore-code 401 --level 5 --risk 3 --batch --dbms SQLite --threads 6 --dump-all | ||
``` | ||
|
||
This will take a while, so go get some marshmallows to go with your hot chocolate. | ||
|
||
When it's done, it'll tell you where in your file system it saved the data. | ||
|
||
... | ||
|
||
Okay this is taking too long. | ||
|
||
I left this going with 10 threads for 8 hours and it didn't finish. Even using just --dump instead of --dump-all didn't work. | ||
|
||
These are the challenges with enumerating through a database. It's very slow, and it's very easy to get blocked by the website. Use `sqlmap -hh` to see all the enumeration commands so you can narrow it down to exactly what you need. |