A Web Application Interceptor is a interceptor tool which intercepts and analyzes web traffic between a client (such as a web browser) and a web server. These interceptors are commonly used for various purposes, including but not limited to: Security Testing, Debugging, Traffic Analysis etc.
The following are some of the popular web application interceptors:
A web interceptor is sometimes also known as a interceptor proxy.
Question
But, Wait a second! Why do we exactly need a web application interceptor?
Why a web application interceptor is used?
A sample application is demonstrated to explain the importance of the web application interceptor or proxy.
For the sample application to work, your system should have docker installed. The guide to install the same can be found on Docker Installation.
Run the projectasuras/webinterceptor
application using docker
(the application runs on port 5000
):
docker run --rm -p5000:5000 --name webinterceptor projectasuras/webinterceptor
Note: Docker image version shown in the guide is v1.0.0
.
Now navigate to http://127.0.0.1:5000
to access the application’s web portal. Try to input some characters on the page.
Tried???
Encountered a problem, right? The page is not allowing you enter more than a single character, but we are in dire need to enter our full name projectasuras
on the same.
Question
How can we provide our name projectasuras to be shown on the webpage ?
There are multiple ways to a provide our name projectasuras
as input, one way is to intercept the request and changing the provided input on the fly to provide our name projectasuras
.
There are many web interceptor/proxy in the market but the most common ones are BurpSuite and OWASP ZAP.
To provide a basic insights on how web intercepting works, we are going to use BurpSuite for the rest of this tutorial.
Web Interception using BurpSuite
Before proceeding further, you need to have BurpSuite installed on your OS. The configuration and installation process can be found at 2.
Note
Before proceeding further in the tutorial, make sure that BurpSuite is configured properly.
Now let’s deep dive into our first web request interception, by changing the input of a
to projectasuras
. But before, BurpSuite can intercept the request, make sure that the Interception is On
within BurpSuite, verify that by navigating to Proxy
tab then Intercept
tab and check whether it shows Intercept is on
.
You are good to go! Now, open the intercepting browser and open http://127.0.0.1:5000
.
Note
Your web page may not open as the requests will be intercepted by BurpSuite, so hit Forward
to allow the request to pass through).
We need to intercept the appropriate request, which contains our user input. So, enter you input (in our case it is a
) and hit Submit
. Switch back to BurpSuite application to check the HTTP Request sent by the browser onto the server.
The request have been intercepted by BurpSuite, is a POST
request to /
endpoint with Host
being 127.0.0.1:5000
and the data field of POST
request consisting of a user_input
parameter with a value containing a
.
We have found our request, now let’s modify the value of a
to projectasuras
.
Now click Forward
to send this modified request to web server.
See we have successfully intercepted and injected projectasuras
name onto web server.
You may wonder, why the server has accepted the input containing more than 1 character.
The answer lies in the source code of the application.
Source Code Evaluation
The HTML source code of the application is as follows:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Simple Flask App</title>
<script>
function validateInput(event) {
const inputField = document.getElementById('user_input');
const errorMsg = document.getElementById('error_msg');
if (inputField.value.length > 1) {
errorMsg.textContent = "Please enter exactly one character.";
event.preventDefault(); // Prevent form submission
} else {
errorMsg.textContent = ""; // Clear error message
}
}
</script>
</head>
<body>
<h1>Give Me Multiple Input</h1>
<form method="post" onsubmit="validateInput(event)">
<input type="text" id="user_input" name="user_input" placeholder="Type a character" maxlength="1" required>
<input type="submit" value="Submit">
</form>
<p id="error_msg" style="color: red;"></p>
</body>
</html>
Notice, the <input>
tag consisting of a maxlength="1"
parameter which is preventing us to enter more than 1 character from the browser. Similarly, a Javascript code (validateInput()
) is also preventing user from inputting the input of length greater than 1.
function validateInput(event) {
const inputField = document.getElementById('user_input');
const errorMsg = document.getElementById('error_msg');
if (inputField.value.length > 1) {
errorMsg.textContent = "Please enter exactly one character.";
event.preventDefault(); // Prevent form submission
} else {
errorMsg.textContent = ""; // Clear error message
}
}
When the length of inputField
is greater than 1
then the code is nullifying the event.
Now let’s try to see the back-end code which is serving this request:
@app.route('/', methods=['GET', 'POST'])
def index():
user_input = None
if request.method == 'POST':
user_input = request.form.get('user_input')
return render_template_string(template, user_input=user_input)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=False)
Bug
The developer forgot to validate the length of the
user_input
field on the back-end code.
Due to non-validation of the user_input
field in the POST
request, the user can input any string and the same will be processed by the back-end.
@app.route('/', methods=['GET', 'POST'])
def index():
user_input = None
if request.method == 'POST':
user_input = request.form.get('user_input')
return render_template_string(template, user_input=user_input)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=False)
We can easily fix, by making a check before rendering the user_input
as follows:
@app.route('/', methods=['GET', 'POST'])
def index():
user_input = None
if request.method == 'POST':
user_input = request.form.get('user_input')
if len(user_input) > 1:
abort(404)
return render_template_string(template, user_input=user_input)
In the above, code segment we have validated the length of the user_input
and thrown 404
error, therefore preventing the injection of arbitrary length input.
Todo
Can you find an alternate way to send any random string on the web-server?
Hint
Override the JavaScript
validateInput
function.