Do Secure-By-Design Pledges Come With Stickers? - Ivanti Connect Secure RCE (CVE-2025-0282)

Do Secure-By-Design Pledges Come With Stickers? - Ivanti Connect Secure RCE (CVE-2025-0282)

Did you have a good break? Have you had a chance to breathe? Wake up.

It’s 2025, and the chaos continues.

Haha, see what we did? We wrote the exact same thing in 2024 because 2024 was exactly the same.

As an industry, we are on GroundHog day - but let’s call it GroundHog Year, and pretend this isn’t just incredibly depressing.

Like clockwork, though, we have vulnerabilities in Ivanti Connect Secure that have all the hallmarks of APT using a zero-day against a mission-critical appliance.

The similarity and resemblance to the issues and drama that circulated Ivanti products in January 2024 is—frankly—incredible, and we were hoping that Ivanti would have learnt from that experience regarding effective response.

We mean, they signed a pledge and had an amazing photo opportunity, and we do not believe that any company who builds appliances whose foundational purpose is some sort of security function, would’ve been allowed to sign a non-binding pledge by their army of corporate lawyers for fun.

Luckily though, this allows for images like:

This time, in fairness, Ivanti Connect Secure users have a patch available a little earlier (for those who have traumatic flashbacks of the patching saga last year - stop reading here), but once again - users of other affected appliances like Ivanti's Policy Secure and Neurons for ZTA gateways are left waiting until Jan 21st 2025 for a patch.

Same drill - we have active exploitation, seemingly by the same threat actor - but technical details about the vulnerability themselves are thin on the ground. Something about making sure the attackers that are already using the vulnerability, can’t reproduce it and keep using it? Spielberg would be proud of the level of theatre we as an industry go through sometimes, truly.

Editor: For many reasons, the amount of work, effort and pure talent that regularly goes into our research is not accurately portrayed here. Skill is not shown in how complex and overwhelming a topic can be made while explaining it, but how understandable and accessibly a process or topic can be walked through.

All we know from the advisory is that Ivanti Connect Secure versions < 22.7r2.5 is vulnerable to two separate stack-based buffer overflow vulnerabilities, one allowing code execution as root with no authentication, and the other requiring authentication.

Memory corruption in 2025, what next? Some other random Ivanti products are apparently affected, which is of course absolutely shocking.

CVE-2025-0282 stands out - pre-authentication, RCE. We're cooking.

Give Us The Spoils

Through magic, the art of the deal, and just Internetting, we rapidly acquired the patched version 22.7R2.5 (referred to as R2.5 for brevity), and the previous 22.7R2.4 (referred to as R2.4 for brevity).

Our previously-documented //bin/bash bypass no longer works (funny because we saw it appear across half the Internet after publishing), so we did something else which enabled us to examine the contents of the root filesystem as normal (Ivanti, please focus on more important things).

We diffed the entire root filesystem- groupA-home on our systems - and were initially overwhelmed by a lot of small changes. However, many transpired to be unimportant - for example, each and every perl CGI file had the version number in a comment at the top of the file, causing naive tooling to detect it as an updated file. A few quick sed commands later, though, and these were removed, leaving us with a pile of binaries.

Almost all of these, though, are of an identical size pre- and post-patch, and again contained only insignificant changes such as version string updates. The notable exception to this was the file named root\\home\\bin\\web, which had grown in the patched version by some 4KB.

A quick peek at the file revealed this to be a compiled binary, written in C++, and so we started up Diaphora, a tool to detect changes in compiled binaries, and set it running.

As always, things don’t happen instantly - we actually had to wait a few minutes for this comparison to run which is circa 20x the length of our favourite TikTok video, and so, while bored, we decided to run strings against the two binaries (patched, and unpatched).

There are only a handful of changes visible from the output, and as always most are junk - but, we spotted a smoking gun:

--- r2.4\\groupA-home\\root\\home\\bin\\web.strings
+++ r2.5\\groupA-home\\root\\home\\bin\\web.strings
 Client Connection Instance not present. Can't Pause Input from %s user session, svcId : %d
 Client Connection Instance not present. Can't Resume Input from %s user session, svcId : %d
+Client IP value exceeds %d size limit
 Client Session Type: %d, Real Host detail not present
 Client TCP Source port is %d
+Client capabilities exceeds %d size limit
 Client cert is not required
 Client certificate required, verify mode=[%d] .
+Client hostname exceeds %d size limit
 Client wants %d <= version <= %d pref ver %d; server version is %d
 Client wants %d <= version <= %d; server version is %d

Do you see what we see? A number of new error messages telling us that values ‘exceed a size limit’. That sounds kinda overflow-y to us. Could this be related to one of the stack overflows we’re hunting?

Anyway, back to TikTok while we waited for Diaphora to finish, before diving into working out if these really were clues.

Fortunately, the code contains a fair amount of debug strings, and we noticed the embedded string Too late for IFT_PREAUTH_INIT.

It’s 2l8, b4by.

This is promising - it suggests, somewhat weakly, that we’re in code that’s running before authentication - and it gives us a valuable clue as to where in the codebase we are.

Although sophisticated research techniques (Google) give us no results for the constant IFT_PREAUTH_INIT, we soon found out that IFT (or rather, IF-T) is an open standard for VPN interoperability. Also known as IFTTLS, it runs over TLS, providing an alternate means to connect to the VPN.

Thanks to Mandiant’s how-to guide on reproducing this vulnerability, we can see that threat actors are removing a log file pertaining to IF-T - more material to support our suspicion that this is CVE-2025-0282.

Our hearts sank - does this mean we’d now be forced to install more software, namely Ivanti’s VPN client, to figure this out? Thankfully, due to IF-T being an open standard, we didn’t have to as this protocol is supported by OpenConnect, the open-source VPN client.

Reading OpenConnect’s comments on the protocol fills us with a sense of dread:

Some Pulse VPNs may request a client certificate but not actually require one. If you are trying to authenticate to such a VPN, and running into strange errors about unrecognized packet types, then mimicking a very old version of the official Pulse client software may help resolve the issue:

This.. this is possibly the worst ‘code smell’ we have encountered yet.

IF-T[his then hax]

Let’s pretend we didn’t see that because the attacker probably didn’t see this opensource, freely available code on the Internet as well, and instead pretend to be the laser-focussed security researchers we aspire to be (and not the oh-look-a-shiny-thing bounce-from-one-project-to-another hackers we actually are).

Back in the room, back to IF-T.

As you’ll recall, the patched version of the Ivanti Connect Secure firmware brought with it a new error message, warning about ”over-sized client capabilities”. Come on…..

Looking for ‘capabilities’ in the OpenConnect client doesn’t show anything particularly helpful, so it must be something that OpenConnect doesn’t support (but our exploit does).

Fortunately, the pulse.c file, which handles IF-T, is pretty easy to extend. It’s pretty obvious how the IF-T packet is constructed - here’s an excerpt:

buf_append_ift_hdr(reqbuf, VENDOR_JUNIPER, 0x88);
buf_append(reqbuf, "clientHostName=%s", vpninfo->localname);
bytes = <code to get local IP address omitted>;
if (bytes[0])
        buf_append(reqbuf, " clientIp=%s", bytes);
buf_append(reqbuf, "\\n%c", 0);
ret = send_ift_packet(vpninfo, reqbuf);

We can see the packet is ASCII-based, and has some key-value pairs, with key and value separated by an =. We can also see that there are multiple pairs in a packet, separated by a space (here, the clientHostName and the clientIp).

Should we try adding a clientCapabilities key with a really long value, and see what happens?

Play along at home - do you reckon we should?

Let’s add a little bit of mischief to the pulse.c file and rebuild.

	if (bytes[0])
        buf_append(reqbuf, " clientIp=%s", bytes);
+ buf_append(reqbuf, " clientCapabilities=%s", bytes);
+ for(unsigned int n=0; n<100; n++)
+       buf_append(reqbuf, "AAAAAAAAAAAAAAAA");
	buf_append(reqbuf, "\\n%c", 0);
	ret = send_ift_packet(vpninfo, reqbuf);

What happens on the security-purposed Ivanti Connect Secure appliance?

Sir, I would like a refund.

Indeed, looking at the code, we find a nasty little misstep by someone (we’ve edited this snippet heavily for brevity):

    char dest[256];

    clientCapabilities = getKey(req, "clientCapabilities");
    if ( clientCapabilities != NULL )
    {
      clientCapabilitiesLength = strlen(clientCapabilities);
      if ( clientCapabilitiesLength != 0 )
	      connInfo->clientCapabilities = clientCapabilities;
      }
    }
    memset(dest, 0, sizeof(dest));
    strncpy(dest, connInfo->clientCapabilities, clientCapabilitiesLength);

Oof! The developer has (rightly) used strncpy, instead of the unsafe strcpy, but has mistakenly passed in the size of the input string - not the size of the destination buffer - as the size limit.

This means that if an attacker sends a clientCapabilities block with more than 256 bytes, they’ll spill over into other stack variables (omitted above for clarity), and eventually into the return address, where RCE awaits.

Exploitation is somewhat “complicated” by two factors:

  • Firstly, the ASLR and PIE mitigations are enabled (meaning that it is difficult to know which addresses to overflow the buffer with),
  • Secondly, there are a number of other function calls (not shown above) after the call to strncpy which depend on the state of other stack variables, which are inevitably corrupted, and so any exploit must be careful to avoid crashing.

For avoidance of doubt, we decided this was the time to take some advice. As always, we looked to watchTowr team members who have given us steady advice - our dogs.

“Should we release the exploit for this new vulnerability, so that defenders are on the same playing field as attackers, given it’s already exploited in-the-wild?”
“No, that's absolutely insane. Imagine what the mob would say in the Tweet replies about arming the criminals that are already armed - let’s keep everything secret and live in a world of mystery."

Well, there we have it. Our canine counsellors have advised us to hold off on the Detection Artifact Generator for now. Maybe in a week (timer starts now, go).

Summary

Well, it looks like this one is the Real Deal - a legit pre-authentication stack-based buffer overflow, present in the default configuration.

Exploit mitigations are in place, which is nice (read: ‘things are slightly less bad than they could have been’). This probably slowed down the APT groups exploiting this vulnerability slightly, but obviously, it did not prevent it and is irrelevant today.

We are glad things have improved since Ivanti's Secure-By-Design pledge. We also point out that we’ve only reviewed for one of the two vulnerabilities - the more severe (interesting), unauthenticated vulnerability.

We urge everyone to please take this seriously. Throw your vulnerability SLAs into the proverbial wind in situations like this, they are no longer relevant and the difference between a rapid response, and a response in hours, could be the difference between your organization calling your cyber insurer or not.

While we are quick to point out and walk through the vulnerability, we have tried to do our part - including working again with The Shadowserver Foundation to share the mechanism we have been using across our client base to identify, safely, vulnerable appliances. We believe this will allow the foundation to begin notifying certs, who can then speak to their cohorts to push patching.

At watchTowr, we passionately believe that continuous security testing is the future and that rapid reaction to emerging threats single-handedly prevents inevitable breaches.

With the watchTowr Platform, we deliver this capability to our clients every single day - it is our job to understand how emerging threats, vulnerabilities, and TTPs could impact their organizations, with precision.

If you'd like to learn more about the watchTowr Platform, our Attack Surface Management and Continuous Automated Red Teaming solution, please get in touch.