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:

  1. BurpSuite
  2. OWASP ZAP
  3. Fiddler
  4. Charles Proxy

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.