Aktualisiert am: 2023-12-06
SQL Injection
Enumeration
-
Im Quellcode finden wir einen Kommentar, der uns auf die Beschaffenheit der Tabelle
usershinweist. Dabei werden auch die Feldlängen definiert/* CREATE TABLE `users` ( `username` varchar(64) DEFAULT NULL, `password` varchar(64) DEFAULT NULL ); */ -
Jegliche SQL-Abfragen gehen durch
mysql_real_escape_string, um SQL Injection zu verhindern -
Jeglicher Output wird durch
htmlentitiesgeschickt, um XSS zu verhindern. Das ist aber ohnehin nicht unser Ziel -
Wenn der User existiert, werden bei korrektem Kennwort die Zugangsdaten ausgegeben. Wenn der User nicht existiert, wird er erstellt
if(validUser($link,$_REQUEST["username"])) { //user exists, check creds if(checkCredentials($link,$_REQUEST["username"],$_REQUEST["password"])){ echo "Welcome " . htmlentities($_REQUEST["username"]) . "!<br>"; echo "Here is your data:<br>"; $data=dumpData($link,$_REQUEST["username"]); print htmlentities($data); } else{ echo "Wrong password for user: " . htmlentities($_REQUEST["username"]) . "<br>"; } } else { //user doesn't exist if(createUser($link,$_REQUEST["username"],$_REQUEST["password"])){ echo "User " . htmlentities($_REQUEST["username"]) . " was created!"; } }
Exploitation
- Die Funktion
mysql_real_escape_stringwar (ist?) unzuverlässig bei fehlerhafter Konfiguration des Encodings. Dieser Artikel von 2006 geht auf das Ausnutzen der Schwachstelle mittels Multibyte Encoding ein. Es wird dort auch darauf hingeweisen, dass man besser Prepared Statements verwendet, was der OWASP-Empfehlung entspricht.
-
Wie ich gelernt habe, definiert SQL im Standard ein unerwartetes Verhalten bei der Überprüfung auf Gleichheit (
=) von Strings- Trailing Spaces werden bei einem
SELECTStatement abgeschnitten - Trailing Spaces werden bei einem
INSERTStatement berücksichtigt,- soweit dies die Feldlänge zulässt
- Trailing Spaces werden bei einem
-
SQL bietet uns hier einen Angriffsvektor, der sich mit einem besonders langen Benutzernamen ausnutzen lässt. Beachtet den Punkt am Ende – das kann auch ein anderes Zeichen wie ein Buchstabe oder eine Ziffer sein
kali@kali:~$ python3 -c "print('natas28' + ' ' * 64 + '.')" natas28 .- Der Punkt (
.) am Ende sorgt dafür, dass invalidUserdieSELECT-Abfrage fehlschlägt, gleichwohl der Benutzernatas28bereits existiert. Entsprechend wirdcreateUseraufgerufen - Die 64 Spaces (
) nach dem Benutzernamen sprengen die Feldlänge beimINSERT. Der Punkt am Ende wird abgeschnitten - Ab nun geben
SELECT-Abfragen aufnatas28mehrere Ergebnisse zurück
- Der Punkt (
-
Mit dem überlangen Benutzernamen können wir uns einen Benutzer mit beliebigem Kennwort erstellen und uns damit als
natas28Anmelden, um die (bzw. alle) Zugangsdaten zu erhaltenJWwR438wkgTsNKBbcJoowyysdM82YjeF
Best Practices
- Definiere identifizierende Felder mit einem
UNIQUEConstraint, um dadurch keine weiterenINSERTStatements zuzulassen, die sich bloss in der Anzahl an Trailing Spaces unterscheiden
Links
- Lösungsbeschreibung einer anderen Challenge mit ähnlicher Problemstellung