Common Injections
Injection is a vulnerability where an attempt is made to parameterize a protocol, but the data intended as a parameter instead breaks out of its parameter position and becomes part of the protocol structure.
URL Injection
URL injection is a simple example of this. When an application constructs URL addresses, for example, to make a call to another (internal) background system, and adds a path or parameter from user input to the constructed URL address, there is a risk of URL injection if the input is not properly encoded.
Example
The following image represents a situation where URL injections may be located.
In the above picture, the webpage is making an HTTP request to a background service using the user-provided credential as part of the URL path.
url = "/busy/" + user_given_syote
This seems completely safe and innocent, but what happens if the user provides a value instead of a username that redefines the final location of the query made by the website? If the website does not construct URLs securely, this can allow the use of the ../ string in the input, which can sometimes be used to travel backwards in the URL path.
In the above query, the user input ../kayttajat, which modified the final location of the query made by the website, causing the application to make an internal HTTP request to a different path than intended by the developer.
Exercise
Start the exercise below and continue reading.
URL injection exercise
Find and identify URL injection vulnerability and exploit it.
Source codes used in the task:
import os
import flask
import requests
from urllib.parse import urlparse
from modules.database import Database
from flask import Flask, render_template, request, flash, abort, jsonify
database = Database()
app = Flask(__name__)
### INTERFACES FOR INTERNAL QUESTIONS ONLY ###
# Interface to help development
@app.route("/api/users", methods=['GET'])
def users_api():
ip_address = flask.request.remote_addr
if ip_address not in ('127.0.0.1', '::1', 'localhost'):
abort(404)
users = database.get_users()
return jsonify({ 'Users': users })
# Let's check if the e-mail is already in stock
@app.route("/api/user/<user_mail>")
def user_api(user_mail):
ip_address = flask.request.remote_addr
if ip_address not in ('127.0.0.1', '::1', 'localhost'):
abort(404)
user_mail = request.view_args["user_mail"]
ret_user = database.get_user(user_mail)
return jsonify({ 'User': ret_user })
# EXTERNAL INTERFACES
@app.route("/verify", methods=['POST'])
def verify():
mail = request.form.get("mail")
response = requests.get("http://127.0.0.1:5000/api/user/"+sposti)
return jsonify(response.json())
@app.route("/", methods=["GET"])
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug=False, host='0.0.0.0')
Exercises
Flag
Find the flag from the lab environment and enter it below.
We start by performing the registration that is available in the application. We check the HTTP request resulting from this in the Burp Suite program.
We notice that registration causes an HTTP request to the interface /verify. Let's verify the interface's functionality from the source code.
@app.route("/verify", methods=['POST'])
def verify():
mail = request.form.get("mail")
response = requests.get("http://127.0.0.1:5000/api/user/"+sposti)
return jsonify(response.json())
The code used by the interface shows that the application accepts a given email address and performs a new query to the interface /api/user/ + email. We can also see from the source code that the application does not perform any kind of formatting on the given email address, which means that the application is vulnerable to URL injection attacks.
If we examine the code of the interface in question, we notice that it is not possible to execute queries on the interface itself, as the interface verifies that queries arrive from the address 127.0.0.1.
@app.route("/api/user/<user_mail>")
def user_api(user_mail):
ip_address = flask.request.remote_addr
if ip_address not in ('127.0.0.1', '::1', 'localhost'):
...
By examining the source code further, we can see that there is another internal API in the application that performs IP address verification.
@app.route("/api/users", methods=['GET'])
def users_api():
ip_address = flask.request.remote_addr
if ip_address not in ('127.0.0.1', '::1', 'localhost'):
abort(404)
users = database.get_users()
return jsonify({ 'Users': users })
The interface in question simply returns all the application users from the database. A found URL injection vulnerability is utilized to redirect the query made by the interface to the /verify endpoint mentioned above, to the /api/users interface.
Voila! - We succeeded in making an HTTP request, redirecting the server's HTTP request to another API, and this returned us the Flag:.
The most important thing is to remember that we do not want the user to be able to redefine the structure of the HTTP request made in the application. For this purpose, URL encoding can be used, for which there are various libraries available, depending on what solutions you use. For example, in Node.js applications, you can use the encodeURIComponent function, to which you input the data received from the user before setting it to the final URL address.
//Vulnerable:
var url = "http://taustapalvelu.com/api/esim/" + ID;
//Not vulnerable
var url = "http://taustapalvelu.com/api/esim/" + encodeURIComponent(id);
This must also be remembered when using user-provided information in parameters so that the attacker cannot manipulate the parameters used in queries.
//Vulnerable
var url = "http://taustapalvelu.com/api/tunnus?nimi=" + name;
// name parameter contains "bob&delete=true"
//Not vulnerable
var url = "http://taustapalvelu.com/api/tunnus?nimi="+ encodeURIComponent(name);
Ready to become an ethical hacker?
Start today.
As a member of Hakatemia you get unlimited access to Hakatemia modules, exercises and tools, and you get access to the Hakatemia Discord channel where you can ask for help from both instructors and other Hakatemia members.