File Uploads are the most common way of getting documented data from the users. Such functionality can be commonly found on Blogging Sites, Chat bots, and Image/Document sharing websites.
Now, the thought arises about how these files could be vulnerable? An attacker may upload a malicious file that can be a spyware or a reverse/bind shell used to gain system access. Most of time, the contents or file type is not validated which results in any type of file getting uploaded that may pose a threat to the site.
Eg., you are able to upload a PHP or HTML file in a blogging site which is expecting you to upload images only.
Here in this lab, we are asked to upload a file. So, I upload a test php file to check if I am able to do so or not.
But I got an error, "Try Harder", means there are some filters being used. I tried to bypass the extension filter but it didn't worked. So this time, I made changes in the Hex Data of the file.
kali@kali:~/BugBounty$ xxd hex_edit.php 00000000: ffd8 ff68 7020 7068 7069 6e66 6f28 2920 ...hp phpinfo() 00000010: 3f3e 0a ?>.
I uploaded the file now and I got the success message.
Vulnerable Code:
elif session['level'] == 2: binary = uploaded_file.read(3) if uploaded_file.filename == '': result = "No file selected!" return render_template('vulnerabilities/insecure-file-upload.html', msg=result) elif (b'ffd8ff' or b'89504e') in binascii.hexlify(binary): full_filename = os.path.join(app.config['UPLOAD_FOLDER'], uploaded_file.filename) uploaded_file.save(full_filename) result = "File uploaded successfully!" else: result = "Try Harder!"
Once you are done with all methods of authentication bypass, the only method left is to perform a Brute Force Attack. In a brute-force attack, we try to pass all possible combinations of a username and password in order to find the correct one.
In this lab, we are already given the username and asked to find the password. What I did here was I intercepted the request using Burp Suite and forwarded the same to Intruder to perform a Brute Force attack.
Also, I noticed that only 2 requests are allowed per second so we need to configure our BurpSuite settings the same way. For this, you need to configure the Throttle option. I set the value to "1000"
And I got the successful login here with password as 12345qwert
.
Vulnerable Code:
# Brute Force Hard @app.route('/brute-force-hard', methods=['POST', 'GET']) @is_logged @limiter.limit("2/second") def brute_force_hard(): username = request.args.get('username') password = request.args.get('password') bf = BruteForce result = bf.brute_force_low(username=username, password=password)
As we know, an application is being served by a server running on an operating system and this application might be serving some content directly from the system files. For example, images or some text files are directly being displayed or read from the directory configured in the server.
At times, the server serves the content which is out of the configured directory, if and only if the given path is correct. The method of reading the content outside the directory is known as directory traversal attack or Dot Dot Slash attack as we go one step back into a directory by entering "../".
Here in this lab, we are asked to read the contents of a file which is stored in the secret folder. Assuming that this folder is inside the server directory, I entered the following path as input.
./secret/secrets.enc
But this gives an error, "Try Harder" means we have either "." or "/" blocked. To bypass this, I'll be URL encoding the input.
%2e%2f%73%65%63%72%65%74%2f%73%65%63%72%65%74%73%2e%65%6e%63
And I was able to read the file contents. With the same concept, I used the following URL encoded input to read the passwd file.
%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%65%74%63%2f%70%61%73%73%77%64
Vulnerable Code:
lif session['level'] == 2: if image_name in ["cat", "dog", "monkey"]: image_name = image_name + ".jpg" path = os.path.join("/Images", image_name) return render_template("vulnerabilities/directory-traversal.html", user_image=path) elif '%' in image_name: try: url = parse.unquote(image_name) f = open(url, 'r') result = f.read() except error: result = "Try Harder" else: result = "Try Harder"
Cross-Site Request Forgery or CSRF is a vulnerability that allows an attack to trick users to perform unintended actions and making them seem to be legitimate as these actions could only be performed if they are authenticated.
Such an attack is usually done by modifying the web request or by creating an overlay form.
Currently, there is no CSRF lab at level. Once it will be built, it will be updated.Server Side Request Forgery, commonly known as SSRF is a web vulnerability which allows an attacker to trick the application's server to send requests to arbitrary domains or read internal files.
SSRF is commonly used to enumerate and exploit the internal network of the application. It can also be used to deliver a backdoor or exploit which could give a direct shell access to the server. This vulnerability is usually found in applications making internal/external API calls.
Here in this lab, we are provided with an application which checks the stock of a particular product. I intercepted the request and found that there is a parameter product, which on forwarding sends a GET request to /api/stock/product. This time, the application has an hidden field named as source and it has a value of external. So, all you need this time is to change the value to "internal" and then pass the product name appended with "@target"
product=food@https://www.google.com&source=internal
As a result, I got the 200 OK
Status Code.
Vulnerable Code:
elif session['level'] == 2: if "internal" in source: requests.get('https://0.0.0.0:5001/api/stock/product?product=' + product, verify=False) else: return render_template('vulnerabilities/ssrf.html', product=product, stock="NULL") def check_stock(): if len(request.args) < 1: return redirect(url_for('ssrf')) else: product = request.args.get('product') if session['level'] == 1 or session['level'] == 2: if len(product.split("@")) > 1: product = product.split("@")[1] try: data = requests.get(product).content return data except requests.RequestException: pass if product != 'none': stock = randint(10, 50) else: stock = 'Invalid' return redirect(url_for('ssrf', product=product, stock=stock))
These days template engines are widely used by applications to display dynamic data which is being generated by the backend server. This dynamic data is passed to the frontend with the template itself and is directly pasted into the HTML file.
There are scenarios when this dynamic data is not sanitized or verified at the backend which results in arbitrary data getting processed by the template engine.
Currently, there is no SSTI lab at level. Once it will be built, it will be updated.I have solved all the labs of TIWAP above with High Level of Difficulty. These labs are solved using basic exploits or some vulnerability identifier exploits only. On that note, I suggest you to escalate these vulnerabilities and try to chain them with each other in order to gain a reverse shell on the target.
Git Repository: https://github.com/tombstoneghost/TIWAP
Other Contributers:
Special Mention for Reviewing the blog Anikait Sabharwal
Best of Luck! Happy Hacking :)