Bug Weekly #3: Injection

Block Audit
4 min readApr 26, 2018

--

Injection attack can manifest themselves in many different ways within your application. You’ve probably heard stories of SQL injection, a far too common issue in web applications or RCE (Remote Code Execution), which actually refers to memory corruption and executing arbitrary code, but often is used generically to mean “execution of arbitrary stuff, either code or commands” and is often the result of Command injection. Wherever there’s an opportunity to mix input into a query, command, of otherwise statement for a particular format or protocol, along with something to gain from changing the processes intended behavior, there’s risk of injection.

So how does any sort of injection happen in the first place? It’s the result of not having a strict separation between the intended code or format thereof and the combined parameters or otherwise data.

Again let’s take the example in SQL injection, where the straightforward thought of “how do I make a statement to execute” leads folks to consider doing a simple concatenation as found here.

String query = "SELECT account_balance FROM user_data WHERE user_name = "
+ request.getParameter("customerName");

try {
Statement statement = connection.createStatement( … );
ResultSet results = statement.executeQuery( query );
}

The code is taking a parameter from the request and appending it to the query. This *works* as long as the customerName doesn’t contain anything other than the usual alpha or alphanumeric characters one would expect.

But the moment it contains other characters that would change the query into something else, things change. It becomes an exploitable vulnerability as anyone can transform your intended query to simply grab the account balance for a user to anything they choose to do, such as insert other records, grab password hashes or even execute commands on the database server in some environments.

How does one make sure this doesn’t happen?

The first principle to is do input sanitization and/or data validation. This proactive measure ensures the input you get is scrubbed and is in the format you expect for the lifetime of the variable as long as it’s not tainted further by the user. Do it once as soon as you get the data from the user, reject the data if it’s not in the correct format or sanitize it by stripping all characters other than the ones you’ve explicitly allowed (eg. only letters and numbers and _’s) so that goes from untrusted input to verified input such as they’ve done here.

$_POST[‘lic’] = preg_replace(‘/[^a-zA-Z0-9]/’,”,$_POST[‘lic’]);

Or, if you know the values should only one of those in a set, validate the data with a whitelist approach as shown here.

$act = “static_value”; // or $lic = “static_value”;
$valid_acounts = array fetched from server

if(!in_array($act, $valid_accounts))
{
die();
}
// Proceed

Next, specifically to mitigate SQL injection vulnerabilities, just don’t concatenate. Parameterize queries, or use prepared statements.

String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";

PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );

The OWASP wiki has a ton of more context and examples available here as well. So first step, sanitize the input and validate the data. It doesn’t cost many extra cycles to check the data before you operate on it, so any extra performance hit incurred by these simple checks is worth it and should be built into the requirements of the application.

Don’t trust, verify. All data coming from the outside is untrusted data, should be assumed to be malformed and malicious and should not be used without explicitly checking it first. Do not reply on the the frameworks you may be using to do this stuff — it’s better to have extra checks than none at all.

Since you should be familiar with injection at this point via the SQL example, let’s briefly touch on Command injection. While SQL injection is serious, injecting commands is even more so. This type of issue provides a straightforward path for an attacker to completely compromise the server or machine that the vulnerable application is running on.

print("Please specify the name of the file to delete");
print("<p>");
$file=$_GET['filename'];
system("rm $file");

Seems simple, right? Give it a file and it will delete it. Maybe you caught the “arbitrary file deletion” bug, which is there as well, as a web application should restrict the files one can delete to a subset available, especially when dealing with the filesystem, unless some the user is administrator and some other arrangement is made. But the main issue here is there’s no sanitization on the filename parameter.

What if someone passed the url…

https://server/delete.php?filename=abc;ls%20/

The app would attempt to delete the file abc in the local directory (we should also be checking the return value here as well), but more importantly the ; character tells the shell to end the first sequence of commands and start executing a new one right after, in this case the ls / command which will list the filesystem on a Linux machine.

That may seem innocent, although privacy related, but that’s just an example. One can tell the shell to open up a remote shell on the box for one to access without authentication and run any commands they like. Again, this is a simple fix: just ensure filename can only even be alphanumeric. No injection characters, no problem. Make sure if your app is using any of these dangerous APIs, you heavily sanitize data before they ever get passed to them.

From there, the webserver is likely running as an lower privileged account like the nobody user, but there’s plenty of local privilege escalation bugs out there for unpatched systems (and unknown issues affecting patched ones) where an attacker can squirrel their way to root and complete server compromise.

So, sanitize those inputs and validate that data, your user’s trust and your and there servers depend upon a codebase free of issues like we’ve described here today. Don’t trust any data coming from the outside, verify.

/BA Team

--

--