Blind SQL Injection
Identifying the Vulnerability
Note: You can start the VM found in the question at the end of the next section for the module's practice web apps.
Scenario
We have been contracted by Aunt Maria's Donuts to conduct a vulnerability assessment of their business website. We were not given any user credentials, as they wish for the test to simulate an external attacker as closely as possible.
After taking a quick tour of the home page, we move to the registration page to see if creating a user will gain us any additional access.
After entering a username we notice the text The username 'moody' is available pop up underneath the field. This suggests that the database might've been queried to check if the username entered already exists or not, so this is worth checking out.
Investigating the 'Username Availability' Check
Taking a look at the source code of signup.php, we can see that usernameInput calls checkUsername() on the onfocusout event, which occurs when the user shifts focus away from the username field.
A bit further down in the source code we can see a reference to static/js/signup.js.
Taking a closer look at this script, we can see the definition of the checkUsername() function.
function checkUsername() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var json = JSON.parse(xhr.responseText);
var username = document.getElementById("usernameInput").value;
username = username.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
var usernameHelp = document.getElementById("usernameHelp");
if (json['status'] === 'available') {
usernameHelp.innerHTML = "<span style='color:green'>The username '" + username + "' is <b>available</b></span>";
} else {
usernameHelp.innerHTML = "<span style='color:red'>The username '" + username + "' is <b>taken</b>, please use a different one</span>";
}
}
};
xhr.open("GET", "/api/check-username.php?u=" + document.getElementById("usernameInput").value, true);
xhr.send();
}
What it does is:
- Sends a GET request to
/api/check-username.php?u=<username> - Updates the
usernameHelpelement to inform the user if the given username is available or taken, depending on the response from/api/check-username.php.
Using BurpSuite we can try a few various usernames out. For example admin and maria both return status: taken. More interesting, however, is that when we supply a single quote as the username the server returns an Error 500: Internal Server Error.

Confirming the SQL Injection Vulnerability
This suggests the presence of an SQL injection vulnerability. The query that is evaluated on the back-end most likely looks something like this:
SELECT Username FROM Users WHERE Username = '<u>'
By this logic, injecting ' or '1'='1 should make the query return something and in turn make the server think this 'username' is already taken. We can confirm this theory by sending the following request in Burp:

In this case, we have found a boolean-based SQL injection. We can inject whatever we want, but the server will only respond with status:taken or status:available meaning we will have to rely on using "Yes/No" questions to infer the data we want to extract from the database.
Table of Contents
Introduction
Introduction to MSSQL/SQL Server Introduction to Blind SQL InjectionBoolean-based SQLi
Identifying the Vulnerability Designing the Oracle Extracting Data OptimizingTime-based SQLi
Identifying the Vulnerability Oracle Design Data Extraction Out-of-Band DNSMSSQL-specific Attacks
Remote Code Execution Leaking NetNTLM Hashes File ReadTools of the Trade
Tools of the TradePreventing SQL Injection Vulnerabilities
Defending against SQL InjectionSkills Assessment
Skills AssessmentMy Workstation
OFFLINE
/ 1 spawns left