Rewrite mit QSA ermöglicht Umgehung Authorization Basic Passwortschutz
Der Path von URI's wird auf Parameter abgebildet (Parametrisierung). Parameter werden in einer RewriteRule an einen Indexer angehängt (QSA). Zum Parsen der Parameter wird serverseitig PHP eingesetzt.
Kategorie: Unsichere Konstrukte.
Auswirkung: Umgehung Passwortschutz Authorization Basic. Möglichkeit der Umgehung auch weiterer auf den Path bezogener Mechanismen infolge Vortäuschen eines Path und Rekonstruktion eines anderen Path mit angehängten Parametern.
Natürlich ist das folgende Beispiel konstruiert: Damit das Problem verständlich nachvollzogen werden kann. Es sei bereits hier notiert, dass Perl nicht die Lösung ist, jedoch gibt es wesentliche Unterschiede zwischen Perl und PHP, was das Parsen von Parametern betrifft, von daher der Vergleich.
Egal wie kompliziert eine RewriteRule
in der Praxis ist, der Artikel mit dem Beispiel verdeutlicht das Prinzip eines unsicheren Konstrukts, wobei das Problem in dem Moment sofort auftritt, wenn der Path
auf Parameter abgebildet, nur über die Parameter geroutet, das Parsen der Parameter mit PHP erfolgt und eine Authorization Basic gemacht werden soll. Dementsprechend gestaltet sich auch die Lösung, beschrieben am Ende des Artikels. Doch nun zur Sache:
Eine Eigenheit von PHP besteht darin, dass aus gleichnamigen HTTP-Parametern kein Array für die Werte gebildet wird wie das die HTTP-Spezifikation vorsieht, so sollte ein Array entstehen, wie folgt:
# GET Parameter, Query-String page=user&page=admin # Perl # ['user', 'admin'] # PHP $_GET['page'] hat nur einen Wert: 'admin'
Mit dem Parser CGI.pm
, der gewöhnlich in Perl eingesezt wird, um GET- oder POST-Parameter auszulesen, erfolgt die Array-Bildung wie oben beschrieben, auf den Schlüssel page
gäbe es also zwei dazugehörige Werte user und admin.
PHP jedoch bildet nicht das Array, sondern überschreibt die vorherigen bzw. alle vorherigen Werte, so haben wir mit obenstehendem QUERY-String lediglich den Wert admin in $GET_['page']
.
Betrachten Sie nun untenstehende Serverkonfiguration in einer .htaccess
-Datei:
RewriteEngine On <Files ~ "admin.html"> AuthUserFile d:/home/spoof/html/.htpasswd AuthName "Secret Realm" AuthType Basic order deny,allow require valid-user SetEnv Realm Secret </Files> RewriteRule ^(.*).html /index.php?page=$1 [QSA,L]
Ziele dieser Konfiguration sind:
index.php
übergeben bzw. angehängt,Diese Konfiguration funktioniert wie gewünscht, index.php
wird aufgerufen und liefert die Inhalte aus entsprechend des angeforderten URL. Der Passwortschutz für URL admin.html funktioniert ebenfalls.
Mit Kenntnis der RewriteRule
und dem Wissen, wie der Parser arbeitet, lässt sich das Passwort umgehen, der Angreifer ruft folgende URL's im Browser auf:
http://example.com/user.html # Seite user.html wird ausgeliefert http://example.com/user.html?page=admin # Seite admin.html wird ausgeliefert
Beim Aufruf der URL user.html wird, wie beabsichtigt, kein Passwort verlangt, die Seite wird über index.php
ausgeliefert. Der angehängte Parameter page=admin veranlasst jedoch index.php
dazu, nun auch die designierte Seite admin.html auszuliefern ohne dass der Passwortschutz mit .htaccess
greift. Denn im PHP-Script kommt aufgrund der Überschreibung nur ein Parameter an und der hat den Wert admin.
Aber auch dann, wenn PHP dazu veranlasst wird, ein Array zu bilden, ist es direkt manipulierbar:
RewriteRule ^(.*).html /index.php?page[]=$1 [QSA,L] # /user.html?page[0]=admin RewriteRule ^(.*).html /index.php?page[secret]=$1 [QSA,L] # /user.html?page[secret]=admin RewriteRule ^(.*).html /index.php?page[secret][strong]=$1 [QSA,L] # /user.html?page[secret][strong]=admin
Das heißt, dass sich am Verhalten des in PHP eingesetzten Parsers auch dann nichts ändert, wenn eine Array-Bildung angestrebt wird (Hinweis: page[secret][strong] ist als Parameter kein Array sondern ein String!). Egal wieviele scheinbare Indizies in der RewriteRule
vorgegeben werden, sie werden stets überschrieben, wenn ein gleichnamiger Parameter angehängt wird. Das Array $_GET
ist komplett manipulierbar, selbst wenn Sie einen Schlüssel sonstwotief verstecken und denken, mit der Abfrage $id = $_GET['strong']['secret']['index']['foo']['bar']['id']
sind Sie auf der sicheren Seite, mit dem Parameter strong[secret][index][foo][bar][id]=4712 kriegt jeder Angreifer jede id dahin, wo sie soll, vorausgesetzt, er kennt die id und den dazugehörigen Parameternamen.
Sie werden sich nun fragen, welche Prüfungen in der index.php
möglich sind, um das Problem aus der Welt zu schaffen. Hier ist die Anwort: Sie können prüfen, was Sie wollen, es wird das Problem nicht lösen. Selbst wenn Sie aus einem URL:
http://example.com/123/de/index.html
einen Parameter machen, z.B. id=123 und im Script index.php wird aufgrund der id der Seiteninhalt aus irgendeiner beliebigen Datenquelle geladen (egal ob MySQL oder Dateisystem), Sie können allenfalls prüfen, ob unter der id=123 die Inhalte vorliegen. Die Manipulierbarkeit des Parameter ist mit:
http://example.com/foo.html?id=12345
weiterhin gegeben, dann wird index.php
eben die Seite mit der id=12345
laden. Und wenn Sie in der .htaccess
bspw. den URL /shopmanager.html mit einem Passwort versehen, der Server weiß nichts davon, dass dem URL die id=12345
zugeordnet ist und wird gar nicht nach einem Passwort fragen: Der Besucher bekommt die Seiteninhalte für Seite mit id=12345, denn index.php
weiß andererseits nicht, was Sie in der Serverkonfiguration beabsichtigen.
Das Problem: Ist die Parametrisierung von URLs verbunden mit einer Authorization Basic: Mit Query-String-Append (QSA) werden aus dem URL erzeugte Parameter an den Indexer angehängt. Der Indexer kennt nicht die Vereinbarungen in der Serverkonfiguration (AuthType Basic, bezieht sich auf den Path des URI). Und der Server kennt nicht die Parameter (id, page usw.), welche der Indexer zum Ausliefern von Inhalten braucht.
Es ist ein systematischer Fehler, der mit einer Parametrisierung von URLs begangen wird und als Fehler nicht einmal dann erkennbar, wenn darauf aufbauende Anwendungen infolge URL-Manipulation kompromittiert wurden.
Statistische Erhebungen belegen, dass Angreifer auch aus den eigenen Reihen kommen. Ein Insider braucht nur wenige Informationen um durch URL-Manipulationen einen Super-GAU zu verursachen: Von jedem beliebigen Ort aus. Es genügt die Kenntnis der fürs Routing relevanten Parameternamen, der dazugehörigen Werte und die Kenntnis der RewriteRule.
Infolge dessen, dass der Parser von PHP jeden einzelnen Parameter überschreibt, kann der Angreifer mit Parametern jeden Path rekonstruieren und einen anderen Path vortäuschen. Sämtliche Mechanismen, die sich auf den Path beziehen, wie z.B. Authorization Basic, können dadurch ausgehebelt werden.
Wenn Authorization Basic im Spiel ist, führt das Routen über die Parameter zu Inkonsistenzen und dies wiederum zu der hier beschriebenen Sicherheitslücke in Verbindung mit PHP. Nutzen Sie statt Parameter (QSA) den Path für das Routing über Mod-Rewrite, der Path (z.B. /foo.html ohne QUERY_STRING) eines URI ist eindeutig.
Konkret: Nutzen Sie für das Routing per RewriteRule den vollständigen Path eines URI und nicht nur einen Teil davon, wenn Sie gleichzeitig Authorization Basic einsetzen und bilden Sie den Path NICHT auf Parameter ab.
Beachten Sie, dass HTTP-Parameter grundsätzlich Strings sind, daran ändert auch eine Schreibweise page[foo][bar] nichts, das sieht zwar aus wie ein PHP-Array aber es ist und bleibt ein String der manipulierbar ist. Beachten Sie daher auch, dass PHP aus gleichnamigen Parametern:
page[foo][bar]=1&...&page[foo][bar]=2
kein Array ('page[foo][bar]' => 1, 'page[foo][bar]' => 2)
bildet sondern vielmehr nur den Wert '2' in $_GET['page']['foo']['bar']
behält, weil sich gleichnamige Parameter aufgrund der Arbeitsweise des Parsers überschreiben.
Überprüfen Sie selbst Ihre Webanwendungen!
http://example.com:8078/foo/bar.html?name=boo;vname=dog#nose \__/ \______________/\___________/ \________________/ \__/ | | | | | Scheme Authority Path Query-String Fragment
Betrachten Sie untenstehende Regel:
RewriteRule !\.(css|jpg|jpeg|js|gif|ico|txt|pdf)$ /index.php [L]
Die Liste der von der Regel ausgenommenen Dateierweiterungen ist individuell und ggf. erweiterbar. Geroutet wird unabhängig von Parametern auf den Path bezogen und dieser geht als Kriterium für eine Authorization Basic dadurch nicht verloren. GET-Parameter sind, genauso wie POST-Parameter der jeweiligen Anwendung vorbehalten und spielen in der RewriteRule
überhaupt keine Rolle. Für das Ausliefern parametergesteuerter Inhalte ist eine Parameter-Kontrollstruktur
zuständig, welche in der Anwendung angesiedelt ist und nicht in der Serverkonfiguration.
Auf diese Art und Weise gibt es auch keine für alle Anwendungen reservierten Parameter und damit verbundene Abhängigkeiten, die bei komplexen Anwendungen schwer zu überschauen sind. Parameter sind und bleiben dadurch anwendungsspezifisch und effektiv nur für einen bestimmten URL. Das Routing über den Path benötigt eine Routing-Table
mit dem Path als Primärschlüssel.
Datenschutzerklärung: Diese Seite dient rein privaten Zwecken. Auf den für diese Domäne installierten Seiten werden grundsätzlich keine personenbezogenen Daten erhoben. Das Loggen der Zugriffe mit Ihrer Remote Adresse erfolgt beim Provider soweit das technisch erforderlich ist. sos@rolfrost.de.