Hack'n Fix

 Hack two web apps.

Then fix the vulnerabilites.

Use of penetration testing techniques requires legal and ethical considerations. To safely use these tools, tactics and procedures, you might need to obtain contracts and permissions; and posses adequate technical skills. Check your local laws.

How to play

  1. Run the app. I recommend you start with 010-staff-only.
  2. Try hacking the app trough the web only, like a hacker would.
  3. Fix the vulnerability. Test that it's fixed.

If you run out of approaches and get stuck, don't worry. You can make it easier for yourself by peeking the source to help hacking. And I have two sets of tips.

Hacking Goals

TaskHacking goal
010-staff-onlyReveal admin password. It contains the string "SUPERADMIN"
020-your-eyes-onlyAccess adminsitrative console. The page contains text "you've found the secret page"

Reporting Tips

For the report, explain

  • Environment
    • OS, browser, hardware, network
    • Any precautions taken
      • For example: if using automated crawlers and fuzzers you're not familiar yet, disconnecting Internet when running the tools.
  • Hack
    • What methods you used for testing the applications (successfull and unsuccesfull).
    • What the vulnerability is?
    • How to exploit the vulnerability and how each part of your exploit work.
    • Refer all documentation and sources you used
  • Fix
    • Which area of code has the mistake
    • What the mistake is? Do you have a guess how programmer has made this mistake?
    • How does your fix work?
    • Does your fix have any downsides? Any areas that should be checked or explored in the future?
    • Refer all documentation and sources you used
  • Reflect
    • What kind of targets could have this type of vulnerability?
    • Is this likely to be common or realistic scennario?
    • How could this vulnerability be avoided?
    • Any other lessons learned.

Install requirements and download

Examples have been tested on Debian 12-Bookworm. The probably work with minor adaptations on other Debian-based distro's, too. And I think I saw someone run them on Arch, BTW.

$ sudo apt-get update
$ sudo apt-get -y install wget unzip micro

Download teros-challenges.zip and uncompress it.

$ wget https://terokarvinen.com/hack-n-fix/teros-challenges.zip
$ unzip teros-challenges.zip

010 - Staff Only

Running first challenge, "Staff Only"

$ cd challenges/010-staff-only/
$ python3 staff-only.py
from flask import Flask, render_template, request # sudo apt-get install python3-flask
ModuleNotFoundError: No module named 'flask'

Install the package mentioned in the comment and run again. And the same for the next package...

$ sudo apt-get -y install python3-flask python3-flask-sqlalchemy

$ python3 staff-only.py
WARNING: Purposefully VULNERABLE APP!
 * Serving Flask app 'staff-only'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit

Now surf to the given address and hack

Your hacking goal: Reveal admin password. It contains the string "SUPERADMIN". Find the vulnerability trough the web interface, without looking at the source code.

Once you've hacked it, fix the vulnerability in code.

Happy hacking!


020 - Your Eyes Only

Can you access the adminsitrative console? The page contains text "you've found the secret page".

This is a Django app. Django is my favourite web framework.

Navigate to 020-your-eyes-only. For example

$ cd
$ cd challenges/020-your-eyes-only/

Create virtual environment. It keeps everything tidy when installing Python packages from Pip, outside package management.

$ sudo apt-get -y install virtualenv

$ virtualenv virtualenv/ -p python3 --system-site-packages

Activate the virtualenv, which adds the text "(virtualenv)" or similar to your prompt. Django will only work when virtualenv is active.

$ source virtualenv/bin/activate

You can check 'which pip' to see that your pip command is running from inside your virtualenv ("...virtualenv/bin/pip").

WARNING: This literally downloads code from the Internet. If you make a typo in the package name, you could download malware. Attackers can use typosquatting, such as registering similar looking names djnago, Django, djangoo...

$ cat requirements.txt
django==4.2.*
$ pip install -r requirements.txt
Successfully installed django-4.2.16

You can test that correct version is installed with "django-admin --version", which prints "4.2.16" (last number can be bigger).

Navigate to the folder containing manage.py.

$ cd logtin/

Update the database.

$ ./manage.py makemigrations; ./manage.py migrate

Run test server. Development server must not be exposed to the Internet. (Advanced tip: if you're accessing it from another machine inside your hacking lab internal network, you can use './manage.py runserver 0.0.0.0:5000' to allow answering to non-localhost clients).

$ ./manage.py runserver
Django version 4.2.16, using settings 'logtin.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Surf to given page.

Your hacking goal: Access adminstrative console. The page contains text "you've found the secret page" the vulnerability through the web interface, without looking at the source code.

Once you've hacked it, fix the vulnerability in code.

Happy hacking!

Ps. How did you like the challenges? Comment below.

Tips

Tips for 010 Staff only

Minor spoilers ahead. But also, if you get stuck, if you run out of things to try => use the hints. That's what they are for.

Tips for 010 - Staff only (click to show)
  • Never trust the client.
    • Any client side validation (JavaScript, form input field type...) are just for client convience.
    • You can bypass those with Firefox F12, Inspector. Use Ctrl-Shift-C element picker, then modify your local DOM Tree.
    • You can also copy the form and save a modified version as local HTML (with some caveats)
    • For more advanced cases, man-in-the-middle proxy is nice. Like OWASP ZAP or MitmProxy.
  • SQL injection
    • Unlike real software, you can see below how user input is concatenated to SQL
    • Maybe something like "authenication bypass"
    • LIMIT shows you just part of SELECT matches.
  • Fixing it
    • Identify the programming library used
    • Use it correctly, likely explained in the very beginning of how to query a database

Here is even more help (but still not a walkrough):

Almost spoilers for 010 - Staff only (click to show)
  • SQL injection
    • "SELECT * FROM foo WHERE true", matches each line where WHERE is true.
    • Often used as "authentication bypass" or "login bypass", you can add "OR 1=1", a clause that's always true. And "false or true" is still true.
    • To get rid of the end of SQL query, you can use comment "-- " or write query to have the correct strings etc. open or close.
    • Often only the first row of results is shown. Use "LIMIT offset, count" to get second, third etc result. For example, "LIMIT 2,1" shows results starting from 2, show 1 result.
    • Use database library facilities to combine user data with SQL. This is often called "prepared queries" or "parametrized queries"
    • This code uses SQLAlchemy for the database library

Tips for 020 Your Eyes Only

Minor spoilers ahead. You should read them if you get stuck.

Tips for 020 - Staff only (click to show)
  • Some pages are not linked anywhere
  • Use a fuzzer to find unlinked pages
  • Ffuf is the leading fuzzer. There are others too, like dirbuster or gobuster.
  • Only fuzz you own practice target inside your own computer. If needed, disconnect the Internet when working.
  • Development server is pretty slow. You might need to limit the rate of your requests. (ffuf --help)
  • Some views are available to all. Some are available to logged in users. Some only for admin.

Here is even more help (but still not a walkrough):

Almost spoilers for 020 - Your Eyes Only (click to show)

Fixing it

  • View permissions are checked in views.py
  • In Django CBGV (class based generic views), permissions checking is often done in with UserPassesTestMixin, in test_func().