ARCHIVE FILE
Injection attacks
The idea behind injection attacks is to find a way to add or embed untrusted data into a command or query and run that on the user's system or the web server.
SQL injection
SQL injection is a security problem that is normally caused by these issues:
- Trusting user generated input
- Setting up the database with an insecure configuration
- Using an insecure transport layer
With that in mind, let's focus on inputs and how we create our queries.
A typical login query looks like this:
select * from users
where username = "username"
and pwd like "password";
The database is asked for a row where both the name and the password match. If those two strings are glued in from a form, the password is not a value — it is more SQL. Send this fragment as the password: 1' OR '1=1. The parser sees pwd like "1' OR '1=1", the OR '1=1' is always true, and you are logged in without knowing anyone's password.
An SQL injection is a way to send user data into the SQL query string, which is then interpreted by the database.
Succesful injections can lead to one or more of these things:
- Privilege escalation
- Modification of data (including deleting all data)
- Extraction of data
Countermeasures
- Priniciple of least privilege for web application access
(in other words, don't run your web server as root)
- Prepared statements with paramaterized queries
SQL statements that acts as a template, and input parameters are always treated as data
- Stored procedures
These are generated and can be stored in your database. This allows you to use static SQL. However, to avoid SQL injection you need to avoid dynamically generating SQL in your stored procedure.
- Query whitelisting
Input validation.
- Escaping user input
Used as last resort
Prepared statements
This is an example of concatenation of a query in JavaScript. name is dropped into the SQL string. Whatever is in name becomes syntax.
mysqlConnection.query(
"SELECT name from user WHERE name =" + name + "),
(err, rows) => {
if(err) return err;
return rows
})
Turning this into a prepared statement where don't concatenate the user string means writing it like this.
mysqlConnection.query(
"SELECT name from user WHERE name = ?),
[username], (err, rows) => {
if(err) return err;
return rows
})
Here we use a question mark as input and pass the input parameter in an array, which treats the input as a data field. The driver sends the SQL and the value separately. 1' OR '1=1 is then just a weird username, not a clause.
Stored procedures
Stored procedures are way to generate a SQL query and have it be stored in your backend database.
It works much in the same way as prepared statements, but you need to generate them up front.
Here's how to generate one in MySQL. DELIMITER $ lets the procedure body contain ; without ending the CREATE. IN name is an argument, not a concatenated string.
DELIMITER $
CREATE PROCEDURE getUser(IN name VARCHAR(20))
BEGIN
SELECT * FROM users WHERE username LIKE name;
END$
And then you call it in your user code, again with a placeholder so the name stays data:
mysqlConnection.query(
"CALL getUser(?)),
[username], (err, rows) => {
if(err) return err;
return rows
})
Whitelisting
Validating that user controlled data adheres to a known specification. Table names cannot be bound as parameters in most drivers, so you must not concatenate them from the request. Map the input onto a known identifier; anything else throws.
var tableName;
switch(inputParam){
case "value1": {
tableName = "users";
}
default: {
throw new Error("invalid table name");
}
}
The tableName can then be directly appended to the SQL query since it is now known to be one of the legal and expected values for a table name in this query.
NoSQL Databases
While document-based databases such as MongoDB aren't susceptible to SQL attacks, they are not immune to injection attacks. In fact, because these injections may execute within a procedural languagage, the potential impacts are greater than SQL injections.
If the user input is not sanitized, running arbitrary JavaScript code is possible in MongoDB in certain cases. In this example documented on the Open Web Application Security Project's Wiki (https://www.owasp.org/index.php/Testing_for_NoSQL_injection), $where runs a JavaScript function per document. $userInput is spliced into that function:
db.myCollection.find( { active: true, $where: function() { return obj.credits - obj.debits < $userInput; } } );
By passing this input as $userInput, the MongoDB instance will execute at 100% database usage for 10 seconds, leading to temporary denial of service. The payload is a tight loop that does nothing else:
(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<10000); return Math.max();})()
$where treats that as code, not as a number. Ten seconds of Date calls per document is enough to stall the instance.
Command injection
Inject OS command into command string
Command injection happens when a web app takes some user controlled data and uses it as input into a command.
When sucessful, the attack can run code on the server side with the privilege of the web application's user. If the web server is running as root, this attack can compromise the entire web server.
You can mitigate against these attack by sanitizing user input, and disallow any shell redirection character, like the pipe character. A good idea is to use whitelisting to constrain valid data input to alphanumeric, and use API calls that supports the ability to run commands.
For instance, in Java, the following API calls are dangerous:
- Runtime.exec() & getRuntime.exec()
- getParameter
- ProcessBuilder.start()
- setAttribute, putValue, getValue
- FileReader fileInputStream
In Node the same class of bug is child_process.exec (and friends) with a string built from the request. exec runs a shell. A filename of foo; rm -rf / is then two commands. Prefer execFile / spawn with an argument array, the same idea as the SQL placeholder: the binary is one value, the arguments are data.
Cross site scripting
Cross-site scripting allows malicious users to do a number of nasty things, such as:
- Impersonate as the victim user.
- Carry out actions on behalf of the victim
- Read any data that the victim is able to access.
- Capture the vitim's credentials.
- Perform virtual defacement of the web site.
- Inject trojan functionality into the web site.
Three types of cross-site scripting
- Reflected XSS
Where the malicious script comes from the current HTTP request.
- Stored XSS
Where the malicious script comes from the website's database.
- DOM-based XSS
Where the vulnerability exists in client-side code rather than server-side code.
Reflected XSS
This scripting attack can happen when an application receives data in an HTTP request and includes that data within the immediate response in an unsafe way.
Let's say you have a web service that accepts data from HTTP parameters without sanitizing them. A polite greeting is echoed into the page:
https://www.example.shop/?status=Good+Morning
// <div>Good Morning</div>
Since the status field is not sanitized, a crafty link like this: https://www.example.shop/?status=<script>/+Exploit+code+/</script> will run this script inside the above-mentioned div, allowing the attacker to carry out actions, sending data etc. on behalf of the user who followed the link. The browser does not see a status string. It sees a <script> node.
Stored XSS
This scripting attack can happen when an application receives data from an untrusted source and passes this on in later HTTP responses.
For instance, comments on message boards or blogs, contact details on customer orders etc.
Let's say a message board lets users submit messages which are displayed to other users, without sanitizing the input. A malicious user can easily send a crafty <script>Bad+exploit</script> inside an innocent answer, and then other users will be at risk. The payload sits in the database and runs for everyone who loads the thread, not only for the person who clicked a link.
Dom-based XSS
DOM-based XSS can happen when an application contains some client-side JavaScript that processes data from an untrusted source in an unsafe way. The source can for instance be query parameters, such as input to search. The attack needs to be delivered to a sink within DOM, so that it's executed on the victim's browser.