漏洞描述
Apache ZooKeeper是一个开源的分布式协调服务,它用于维护配置信息、命名、提供分布式同步以及提供组服务。AdminServer是其中一个特性,提供了HTTP接口来供用户通过API访问ZooKeeper的相关命令。2024年11月,官方披露其在使用 IPAuthenticationProvider 时使用IP白名单进行认证的情况下,攻击者可伪造X-Forwarded-For头绕过相关验证。
环境搭建
git clone https://github.com/apache/zookeeper.git
较新版本的zookeeper直接maven导入包即可
idea设置:
过程中还要在org.apache.zookeeper.server下新建version.Info接口,不然运行中报错:
运行成功后在web端提供一个http接口用于执行一些命令:
执行某些命令需要提供凭证:
漏洞分析
看到阿里云漏洞的通报,自己下了代码就试着分析了,通过关键字直接搜索,命令执行的接口调用在org.apache.zookeeper.server.admin.JettyAdminServer.CommandServlet类中实现,这是一个JettyAdminServer的内部类,在入口下断调试:
269行调用org.apache.zookeeper.server.admin.Commands#runGetCommand,继续调用org.apache.zookeeper.server.admin.Commands#runCommand:
这里跟进org.apache.zookeeper.server.admin.Commands#getCommand
这里实际上zookeeper把每个要执行的命令封装成一个类,然后存入到commands中,然后再根据url中的值去取关键类,在具体的类初始化过程中,定义了是否要鉴权的部分:
org.apache.zookeeper.server.admin.CommandBase
构造函数的authRequest在后面执行中,担任了鉴权的标志位,这里也能看到,不同的命令封装类,对应的构造函数参数是不同的:
未设置鉴权
设置鉴权
了解到上述逻辑后,继续跟进org.apache.zookeeper.server.admin.Commands#runCommand
这里判断了鉴权,有的话进入if,没有则直接根据get或者post执行命令。
具体看下if逻辑里的代码
首先得传入authInfo,这个authInfo是根据header传入的,默认是取Authorization传入的值,然后进入关键代码org.apache.zookeeper.server.admin.Commands#handleAuthentication和org.apache.zookeeper.server.admin.Commands#handleAuthorization:
在org.apache.zookeeper.server.admin.Commands#handleAuthentication中,会根据我们从http中传入的schema去调用不用的鉴权模块,若是传入ip的话,则调用org.apache.zookeeper.server.auth.IPAuthenticationProvider,进一步执行其handleAuthentication函数
其getClientIPAddress则可以通过X_FORWARDED_FOR_HEADER_NAME去获取ip地址,这就给了可以伪造ip的机会:
接着往下看,函数执行完后直接return了ids,又带入了org.apache.zookeeper.server.admin.Commands#handleAuthorization中,最后调用org.apache.zookeeper.server.ZooKeeperServer#checkACL检查权限:
默认是world anyone权限,如果这里自己做了ip规则的话,就存在伪造本地ip绕过的风险
修补
参考
https://avd.aliyun.com/detail?id=AVD-2024-51504
https://lists.apache.org/thread/b3qrmpkto5r6989qr61fw9y2x646kqlh