从滥用HTTP hop by hop请求头看CVE-2022-1388

警告
本文最后更新于 2022-05-13,文中内容可能已过时。

# 前言

最近爆出来的bigip的CVE-2022-1388漏洞,涉及到一个知识点就是hop by hop,对这个东西没了解过,所以有了此文。

# 回顾CVE-2021-22986

CVE-2021-22986原理是因为apache和jetty之间的鉴权不当导致的权限绕过。

当不存在Authorization basic认证头时,由apache做权限校验,判断basic认证头是否存在,此时response中的server头为apache

image.png

当给一个错误的basic认证头时仍返回apache的401认证,注意这里给的是一个admin:空密码的admin用户。

image.png

当给一个空的X-F5-Auth-Token认证头时,由jetty处理返回401,报错信息为Authorization failed: no user authentication header or token detected.

image.png

当两个请求头都存在时,绕过了权限校验,rce。

image.png

由此得出结论,当存在X-F5-Auth-Token头时apache不检查basic认证头,而jetty只会判断用户名,而不判断密码是否正确。

思考为什么权限校验不起作用?

查看apache的配置文件/config/httpd/conf/httpd.conf发现

image.png

/mgmt/请求被转发到8100端口,并且启用了AuthPAM_Enabled,启用auth会调用/usr/lib/httpd/modules/mod_auth_pam.so判断鉴权,在这个so中

image.png

判断是否存在X-F5-Auth-Token头

image.png

然后接着拿一些其他的请求头

image.png

最终逻辑就是如果存在转发给jetty处理。

而在jetty中 f5.rest.jar

com.f5.rest.workers.authz.AuthzHelper#decodeBasicAuth

image.png

从header中拿到basic认证的用户名和密码,在com.f5.rest.common.RestOperationIdentifier#setIdentityFromBasicAuth中设置用户身份

image.png

因为basic不为空,所以进入com.f5.rest.common.RestOperation#setIdentityData

image.png

因为 userName!=null && userReference==null,所以处理完之后用户的身份变为

1
2
3
identityData.userName = 'admin';
identityData.userReference = 'http://localhost/mgmt/shared/authz/users/admin'
identityData.groupReference = null;

接着在鉴权的地方 com.f5.rest.workers.EvaluatePermissions#completeEvaluatePermission

image.png

setBasicAuthFromIdentity之后拿到userRef,此时userRef即上文处理完之后的用户身份。在判断AuthzHelper.isDefaultAdminRef(userRef)

image.png

先拿到默认的AdminReference和当前用户身份匹配,在getDefaultAdminReference()中拿到admin用户的身份new一个RestReference

image.png

UrlHelper.buildPublicUri(UrlHelper.buildUriPath(new String[]{WellKnownPorts.AUTHZ_USERS_WORKER_URI_PATH, DEFAULT_ADMIN_NAME}))最终构建出来的url还是http://localhost/mgmt/shared/authz/users/admin

所以此时我们在basic中将用户名设置为admin则可以满足defaultReference != null && defaultReference.equals(userReference)至此绕过权限认证。

然后就是找一个命令执行的点

image.png

对应的就是util下的路由功能点

image.png

调用bash执行命令即可

image.png

另外此处文档中也有提到

https://f5-sdk.readthedocs.io/en/latest/_modules/f5/bigip/tm/util/bash.html

# CVE-2021-22986的修复

在上文中,我们传递了一个X-F5-Auth-Token为空的header头,所以completeEvaluatePermission函数会赋给我们一个默认的用户身份。而修复补丁在mod_auth_pam.so判断当X-F5-Auth-Token为空直接返回401

image.png

所以我们无法传递给jetty一个空的X-F5-Auth-Token请求头。

那么CVE-2022-1388就是对其的绕过,这里引申出本文的重点hop by hop。

# hop by hop

先解释下这是什么东西。根据RFC 2612,HTTP/1.1 规范默认将以下标头视为逐跳:Keep-Alive、Transfer-Encoding、TE、Connection、Trailer、Upgrade、Proxy-Authorization和Proxy-Authenticate。当在请求中遇到这些标头时,代理服务器会处理这些标头,并且不会将其转发到下一个节点。

以推特@jinonehk的一张图来看

image.png

第一次尝试导出用户时返回403,因为不是环路ip,而当加上Connection: close, X-Real-IP时,导出用户成功,说明此时后端服务获取不到X-Real-IP请求头,认为是本地请求所以可以导出用户。

更具体一点,我在这里找到了一个ctf的题目 https://github.com/ritsec/RITSEC-CTF-2019/tree/master/Web/hop-by-hop

在verify函数中尝试获取xff头,如果获取不到则默认为direct。

image.png

而前置服务为apache,根据逐跳原则,当Connection中加了其他标头X-Forwarded-For,那么在apache转发给下一跳时,会移除X-Forwarded-For头,导致在verify函数中request.headers['X-Forwarded-For']抛出异常,由此拿到flag。

image.png

可以自己本地搭一个反代试试,我这有一个springboot的项目,只有一个controller

image.png

apache 80端口反代springboot 9091端口

先开启反代功能

1
LoadModule proxy_module modules/mod_proxy.so

配置virtualhost

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<VirtualHost *:80>
    ProxyRequests Off
    ProxyPreserveHost On
    <Proxy>
        Order deny,allow
        Allow from all
    </Proxy>
    ProxyPass /  http://localhost:9091
    ProxyPassReverse /  http://localhost:9091
</VirtualHost>

正常传token,springboot可以获取到token头

image.png

当connection加上Token时,springboot获取的token为null

image.png

由此可见CVE-2022-1388

# CVE-2022-1388

在CVE-2022-1388中使用Connection加上X-F5-Auth-Token让jetty接收到的X-F5-Auth-Token为null以此来绕过权限认证。

image.png

另外需要注意的一个地方为host赋值为localhost,不然host为ip时报错

image.png

因为CVE-2021-22986之后,在com.f5.rest.common.RestOperationIdentifier#setIdentityFromBasicAuth

image.png

当host为localhost或者127.0.0.1时,会赋予用户身份。另外这里还可以赋值host为127.4.2.1然后basic用户名为f5hubblelcdadmin,或者通过Connection加上X-Forwarded-Host也可以rce,就不截图了。

# hop by hop的适用面

我本地测试了apache、nginx、openresty、HAProxy,其中只有apache会消费掉Connection中的请求头,其他的要单独测试了。

# 参考链接

看了太多资料了,用到了但是没贴上来的请原作者见谅。

  1. 漏洞百出
  2. https://twitter.com/jinonehk/status/1420413477521301507
  3. https://nathandavison.com/blog/abusing-http-hop-by-hop-request-headers
  4. RFC 2616
  5. https://y4y.space/2021/03/19/cve-2021-22986-f5-rest-unauthenticated-rce-analysis/
  6. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection
  7. https://nosec.org/home/detail/4722.html

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。