Roundcube ist der weltweit am häufigsten eingesetzte Open-Source-Webmail-Client. Wir haben kürzlich eine gefährliche Sicherheitslücke in der Anwendung entdeckt! Es handelt sich um einen „Stored XSS“, der in Verbindung mit einer Cookie-Tossing-Technik einem Angreifer vollständigen Zugriff auf den Posteingang des Opfers und von dort aus auf jedes Konto gewährt, das diese E-Mail-Adresse zur Authentifizierung oder Passwortwiederherstellung verwendet.
Wir haben dies durch die Durchführung unserer KI-Penetrationstests Agenten gegen eine lokale Roundcube-Instanz laufen ließen. Alle Ergebnisse wurden verantwortungsbewusst über HackerOne an Nextcloud, die Betreuer von Roundcube, gemeldet (XSS unter #3594137 offengelegt) und in Version 1.6.14 behoben.
In diesem Beitrag werden wir erläutern, was wir getan haben, wie unsere Mitarbeiter die Sicherheitslücke entdeckt haben und wie eine einfache HTML-Injektion den Posteingang eines Nutzers vollständig kompromittieren konnte.
Die Injektionsstelle
Jeder Angriff hat einen Ausgangspunkt. Schauen wir uns einen an, den einer unserer Mitarbeiter zur Überprüfung aufgegriffen hat.
Roundcube behandelt benutzergesteuerte Inhalte auf verschiedene Weise. E-Mail-Texte werden am strengsten geprüft. Diese werden umfassend bereinigt, da sie direkt in der Anwendung angezeigt werden.
HTML-Anhänge werden über einen separaten Endpunkt in mail/get.php dargestellt, wobei die Content Security Policy auf „script-src 'none'“ gesetzt ist, um die Ausführung von JavaScript zu blockieren.
Ein dritter, eher versteckter Endpunkt verarbeitet Inline-Anhänge, die noch nicht versendet wurden und während des Verfassens einer E-Mail vorübergehend angezeigt werden können. Dies ist der Endpunkt, mit dem wir uns befassen werden. Die Aktion „display-attachment“ verarbeitet diese Art von Anfragen:
class rcmail_action_mail_attachment_display extends rcmail_action_mail_attachment_upload {
...
public function run($args = []) {
self::init();
$rcmail = rcmail::get_instance();
$file = $rcmail->get_uploaded_file(self::$file_id);
self::display_uploaded_file($file);
Die Funktion self::display_uploaded_file() dort geschieht das Wunderbare. Denn rcube_uploads.php Wie sich zeigt, werden solche Anhänge direkt mit ihrem ursprünglichen Inhaltstyp und Textkörper zurückgegeben, ohne dass eine Bereinigung, Sandboxing oder die Anwendung einer Content Security Policy erfolgt.
header('Content-Type: ' . $file['mimetype']);
header('Content-Length: ' . $file['size']);
if (isset($file['data']) && is_string($file['data'])) {
echo $file['data'];
} elseif (!empty($file['path'])) {
readfile($file['path']);
}
Sie fragen sich vielleicht, wie wir dieses Ziel erreichen? Wenn Sie in Roundcube eine neue E-Mail verfassen, können Sie der temporären E-Mail eine Datei anhängen, genauer gesagt eine HTML-Datei. Wir versehen diese mit schädlichem Inhalt:
<script>alert(origin)</script>
Nach dem Hochladen öffnet sich beim Klicken auf den Anhang ein Popup-Fenster, in dem dieser mithilfe der „get“-Aktion dargestellt wird, geschützt durch eine strenge CSP. Das ist der sichere Weg. Interessant ist jedoch, was passiert, wenn man swap _action=get gegen _action=Anhang anzeigen:

Nimm die ursprüngliche URL für diese Anzeige:
/?_task=mail&_frame=1&_file=rcmfile21774532162043767100&_id=193102765369c53621200f8&_action=get&_extwin=1Tauschen _action=get gegen _action=Anhang anzeigen und wenn man einige überflüssige Parameter weglässt, erhält man:
/?_task=mail&_file=rcmfile21774532162043767100&_id=193102765369c53621200f8&_action=display-attachmentDiese URL zeigt denselben Inhalt an, jedoch ohne die CSP! Daher wird das JavaScript in unserem HTML-Code ausgeführt, wodurch die aktuelle Herkunft angezeigt und XSS bestätigt wird:

Das ist zwar ein interessanter Fall von Self-XSS, aber ist das wirklich ein Problem? Wenn wir realistisch bleiben, wird ein normaler Nutzer unsere XSS-Payload nicht von sich aus hochladen und sie dann auf diese besondere Weise anzeigen…
Ein Blick auf attachment_upload.php, wirst du feststellen, dass ein Daten_erstellen_ Für Ihren aktuellen Benutzer muss ein Sitzungsschlüssel festgelegt sein, und nur dieser Benutzer kann den Anhang abrufen.
public static function init()
{
self::$COMPOSE_ID = rcube_utils::get_input_string('_id', rcube_utils::INPUT_GPC);
self::$COMPOSE = null;
self::$SESSION_KEY = 'compose_data_' . self::$COMPOSE_ID;
if (self::$COMPOSE_ID && !empty($_SESSION[self::$SESSION_KEY])) {
self::$COMPOSE = &$_SESSION[self::$SESSION_KEY];
}
if (!self::$COMPOSE) {
exit('Invalid session var!');Da es sich hierbei um eine temporäre Verbindung handelt, die ausschließlich an Ihre aktuelle Sitzung gebunden ist, gibt es keine Möglichkeit, eine Schadcode-Nutzung vorzubereiten und das Opfer dazu zu bringen, diese durch die Anmeldung im Konto des Angreifers auszulösen, wie wir es bei Mailcow. Der gesamte roundcube_sessid Das Cookie müsste auf das Gerät des Opfers kopiert werden. Eine weitere Aufgabe, die unmöglich klingt.
Ausnutzen von Self-XSS durch Cookie-Tossing
Das von uns entdeckte Self-XSS-Loch scheint auf den ersten Blick nicht ausnutzbar zu sein. Der Anhang ist an die Sitzung gebunden, sodass es keine Möglichkeit gibt, eine Payload für ein Opfer vorzubereiten, ohne ihm gleichzeitig das Sitzungs-Cookie des Angreifers zu übergeben. Doch damit ist das Problem noch nicht gelöst. Hier kommt das sogenannte „Cookie Tossing“ ins Spiel.
In Browsern weisen Cookies einige interessante Eigenheiten auf, darunter die Domäne=Attribut.
> Als Wert kann nur die aktuelle Domain oder eine übergeordnete Domain festgelegt werden, es sei denn, es handelt sich um ein öffentliches Suffix. Durch die Festlegung der Domain wird das Cookie sowohl für diese als auch für alle ihre Subdomains verfügbar.
Cookies können nicht nur für die aktuelle Domain, sondern auch für eine übergeordnete Domain gesetzt werden. Ein Cookie, das von sub.example.com mit Domain=example.com wird für jede Subdomain unter example.com, darunter solche wie other.example.com das hatte nichts mit der Einstellung zu tun. Diese Art von Angriff wird als Kekswerfen, wobei eine Subdomain Cookies setzt, die von einer anderen Subdomain gelesen werden.
Das bedeutet, dass wir zur Ausnutzung unserer Schwachstelle lediglich Folgendes benötigen: Kontrolle über eine Subdomain auf derselben Domain wie die Roundcube-Zieldomain. Von dort aus führt eine separate XSS-Sicherheitslücke auf einer Seite wie xss.target.local kann die document.cookie Eigenschaft zum Schreiben von Cookies mit der Domain=target.local Attribut. Sobald diese Cookies gesetzt sind, sendet der Browser des Opfers sie an mail.target.local weiter, wo Roundcube die Sitzung des Angreifers anstelle derjenigen des Opfers lädt.
In dieser Sitzung steht der schädliche HTML-Anhang bereits bereit. Wird das Opfer auf die URL des Anhangs weitergeleitet, wird die XSS-Payload innerhalb der Roundcube-Domäne im Browser des Opfers ausgelöst, ohne dass eine weitere Interaktion erforderlich ist.
Zusammenfassend lässt sich sagen, dass ein Angreifer Folgendes tun muss, um diese Schwachstelle auszunutzen:
- sich in ihr eigenes Konto einloggen, eine neue E-Mail erstellen und eine schädliche HTML-Datei anhängen
- Kopiere den Link, um den Anhang und die Cookies anzuzeigen (zu laden)
- Legen Sie die Cookie-Werte über eine für XSS anfällige Subdomain fest, indem Sie
document.cookiemit demDomäne=Attribut, das auf die Zieldomäne verweist. - Leite das Opfer auf den Link zum Anhang weiter. Der XSS-Angriff wird im Roundcube-Ursprungsserver ausgelöst.
So sieht die XSS-Nutzlast für die Subdomain in der Praxis aus: Dabei werden die Sitzungscookies gesetzt und das Opfer auf die URL des Anhangs weitergeleitet
Dokument.cookie='roundcube_sessid=1798cbb4c1d7c7f9ca26069b52aac1aa; Domain=target.local'
document.cookie='roundcube_sessauth=GfNmiyX5brPm4l814QUx62l5gsJKBXfU-1773063000; Domain=target.local'
location.href = 'http://mail.target.local/?_task=mail&_action=display-attachment&_id=183727919869aecb6499f76&_file=rcmfile11773063013009066400';Abgesehen von der Subdomain XSS erfordert der weitere Ablauf des Roundcube-Exploits keine weitere Benutzerinteraktion. Die gesamte Sicherheit von Roundcube hängt nun von jeder Subdomain derselben Website ab.

Voller Zugriff
Das Warn-Popup im obigen Screenshot bestätigt, dass auf dem Ursprungsserver von Roundcube ein XSS-Angriff ausgeführt wird, zeigt jedoch für sich genommen keine konkreten Auswirkungen. Es gibt also immer noch ein Problem. Zu diesem Zeitpunkt haben wir die Sitzung des Angreifers in den Browser des Opfers geladen, sodass alle durchgeführten Aktionen über das Konto des Angreifers und nicht über das des Opfers erfolgen. Das ist ideal, um unsere Payload zu übermitteln, aber nicht so ideal, um auf Dinge zuzugreifen, auf die wir normalerweise keinen Zugriff hätten.
Wenn man sich den Browser ansieht, werden Cookies eigentlich gar nicht ersetzt wenn wir eine andere Domäne=. Beide sind verschickt!
Cookie: roundcube_sessauth=OPFER; roundcube_sessauth=ANGREIFER
Wenn beide Cookies vorhanden sind, wählt der Server das des Angreifers aus, da es im Header an letzter Stelle steht. Bei der XSS-Payload möchten wir, dass die Cookies des Angreifers ausgewählt werden, während wir bei allen nachfolgenden Endpunkten die Cookies des Opfers wünschen. Glücklicherweise verfügen Cookies über ein weiteres Attribut, das dieses Problem perfekt löst: Pfad=.
Indem Sie einen eindeutigen Pfad festlegen, wie zum Beispiel Pfad=/index.php/xss, die weiterhin auf die Startseite verweist, werden die Cookies nur versendet werden wenn dieser Pfad mit dem Ziel der Anfrage übereinstimmt. Für unsere Anfragen gilt also:
/index.php/xsssendetroundcube_sessauth=OPFER; roundcube_sessauth=ANGREIFER-> Die Nutzlast des Angreifers wird zurückgegeben- / sendet
roundcube_sessauth=OPFER-> Die E-Mails des Opfers werden zurückgeschickt
Wir müssen lediglich den JavaScript-Exploit so anpassen, dass dieses neue Attribut gesetzt wird, und dann zu /index.php/xss Anschließend muss sichergestellt werden, dass die Cookies des Angreifers in dieser Anfrage für unsere Nutzlast mitgesendet werden; danach hat unser XSS jedoch freien Zugriff auf das Konto des Opfers.
Dokument.cookie='roundcube_sessid=1798cbb4c1d7c7f9ca26069b52aac1aa; Domain=target.local; Path=/index.php/xss'
document.cookie='roundcube_sessauth=GfNmiyX5brPm4l814QUx62l5gsJKBXfU-1773063000; Domain=target.local; Path=/index.php/xss'
location.href = 'http://mail.target.local/index.php/xss?_task=mail&_action=display-attachment&_id=183727919869aecb6499f76&_file=rcmfile11773063013009066400';In den DevTools können wir sehen, wie die doppelten Cookies nun eingerichtet sind:

Zwar sind die Voraussetzungen für einen erfolgreichen Angriff (Konto bei Roundcube + XSS in einer Subdomain) etwas knifflig, doch die potenziellen Folgen eines erfolgreichen Angriffs sind enorm.
E-Mails sind die am meisten genutzte und vertrauenswürdigste Form der Authentifizierung, da viele Websites für die Anmeldung oder die Passwortwiederherstellung auf „magische Links“ zurückgreifen. Wenn ein Angreifer Zugriff auf Ihre E-Mails hat, kann er solche Passwortzurücksetzungen auf allen Websites auslösen, bei denen diese E-Mail-Adresse hinterlegt ist. Anschließend kann er die Bestätigungs-E-Mail lesen, die der jeweilige Dienst versendet, und so Zugriff auf viele weitere Konten erlangen.
Behebung
Aktualisieren Sie Roundcube auf Version 1.6.14 oder höher (1.6.x) bzw. auf 1.5.14 oder höher (1.5.x LTS). Alle gemeldeten Sicherheitslücken wurden in dieser Version behoben. Wenn Sie Aikido verwenden, werden anfällige Roundcube-Instanzen in Ihrem Surface-Monitoring-Feed automatisch als „mittlerer Befund“ gekennzeichnet.

Aikido nicht bei Aikido registriert? Erstelle ein kostenloses Konto, um loszulegen – keine Kreditkarte erforderlich.
Fazit
Obwohl es zunächst wie eine harmlose XSS-Sicherheitslücke aussah, erforderte deren Ausnutzung etwas mehr Wissen über Cookies und Sitzungen. Subdomains derselben Website erhalten vom Browser oft etwas mehr Berechtigungen als völlig separate Websites – ein weiterer Grund, dafür zu sorgen, dass alle Ihre Ressourcen sicher sind.
Das ist eine schwierige Aufgabe, aber wie hier gezeigt, kann Aikido Webanwendungen selbstständig auf Sicherheitslücken überprüfen, um solche Schwachstellen in Ihrer gesamten Infrastruktur aufzuspüren.
Die Betreuer von Roundcube hat diese Sicherheitslücke behoben in Version 1.6.14 durch Hinzufügen eines script-src 'none' Die Content Security Policy, genau wie bei den übrigen Anhängen bereits der Fall. Dadurch wird die Ausführung von JavaScript bei der Rückgabe von beliebigem HTML verhindert.
Bonus: IMAP-CRLF-Injektion über CSRF
Im Rahmen desselben Penetrationstests entdeckte ein anderer Tester eine zweite Schwachstelle, die wir besonders interessant fanden. Nach der Meldung stellte sich heraus, dass es sich um einen Doppelbefund handelte, den auch das Martila Security Research Team entdeckt hatte. Dennoch hielten wir es für interessant genug, die Details dieser Schwachstelle hier kurz zu erläutern.
Der /?_task=mail&_action=search endpoint übergibt die vom Client bereitgestellten _filter Parameter direkt in den IMAP SUCHEN Befehl in rcube_imap_generic.php:
if (!empty($criteria)) {
$params .= ($params ? ' ' : '') . $criteria;
} else {
$params .= 'ALL';
}
[$code, $response] = $this->execute($return_uid ? 'UID SEARCH' : 'SEARCH', [$params]);Obwohl die Funktion den Befehl scheinbar von seinen Argumenten trennt, die Umsetzung von execute() fügt sie einfach ohne Bereinigung aneinander:
foreach ($arguments as $arg) {
$query .= ' ' . self::r_implode($arg);
}
Durch Einfügen eines Wagenrücklaufs und Zeilenvorschubs (CRLF, %0D%0A) Zeichen kann ein Angreifer die SEARCH-Parameter umgehen und zusätzliche IMAP-Befehle in die IMAP-Sitzung des authentifizierten Benutzers einschleusen.
Damit können Sie nicht nur E-Mails suchen, sondern auch Ordner hinzufügen, E-Mails verschieben oder den gesamten Posteingang löschen, da es sich hierbei um reine IMAP-Befehle handelt.
Nachfolgend finden Sie ein Beispiel für einen Filter, der auf ALL%0D%0AX007%20CREATE%20EvilFolder:
Beim Aufruf werden die folgenden Daten an IMAP gesendet, zusammen mit dem eingefügten CREATE-Befehl, der nach der Suche ausgeführt wird:
X006 ALLES SUCHEN
X007 EvilFolder ERSTELLENDie Auswirkungen davon sind dann in der Roundcube-Benutzeroberfläche zu sehen:

Da es sich um eine einfache GET-Anfrage handelt, reicht ein Besuch des oben genannten Links aus, um die Befehle auszuführen. Damit könnten durch einen einzigen Klick auf einen Link alle E-Mails dauerhaft gelöscht werden (X001 UID-Speicher 1:* Flags \Gelöscht gefolgt von X002 LÖSCHEN), was zu einem erheblichen Datenverlust führte.
Diese Sicherheitslücke ist nun gepatcht durch Entfernen \r\n Zeichen aus Suchanfragen.

