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

SQL-Injection in Oracle



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



  • [Einleitung]


    Kürzlich, als ich verschiedene Webprojekte zu Schwachstellen erforschte, stieß ich auf eine SQL-Injektion in Oracle. Obwohl es derzeit selten ist, dieses DBMS in der Webprogrammierung zu verwenden, passiert es dennoch. Die ganze Forschung endete mit einer einfachen Erkennung von Fehlern, was noch zu tun war, war unverständlich. Bei der Suche nach einem Artikel, der die praktischen Aspekte der Ausnutzung dieser Sicherheitsanfälligkeit in Oracle beschreibt, wie zum Beispiel die Artikel "Geld und Spion", die Injektionen in MSSQL und PostgreSQL beschreiben, wurde dies nicht gefunden.
    Als Ergebnis der Suche wurde nur eine Reihe von Artikeln k00p3r gefunden, die vollständig aus externen Quellen kopiert wurden und eine einfache Übersetzung waren, deren Ablesung keine klare Vorstellung davon gab, Wangenknochen in Oracle zu halten, weil Artikel haben tatsächlich ein großes Volumen, sind theoretischer Natur und enthalten zum größten Teil Wasser.
    Am Ende musste ich mich an die institutionellen Fähigkeiten der Zusammenarbeit mit Oracle erinnern und eine Reihe verstreuter Informationen im Internet erneut lesen. In diesem Artikel möchte ich Ihnen mitteilen, dass ich es geschafft habe, die Implementierung von SQL-Injection in Oracle auszuloten und zu kombinieren.
    Nun, versuchen Sie, die Lücke zu füllen, und fügen Sie eine Reihe von Artikeln Bargeld und Spionage.

    [Funktionen von Oracle]


    Zuerst gebe ich einige Eigenschaften, die beim Einspritzen in Oracle berücksichtigt werden müssen. Ich möchte sofort reservieren, dass im Artikel die Injektionen in der SELECT-Anweisung berücksichtigt werden. Auch die Einspeisung in INSERT-, UPDATE- und DELETE-Operatoren ist möglich.
    Genauso wichtig ist die Tatsache, dass der Artikel sich mit Einspritzungsproblemen in den SQL-Abfragen von Oracle und nicht mit den PL / SQL-Prozeduren von Oracle befasst. Ein signifikanter Unterschied zwischen Einspritzungen in PL / SQL-Prozeduren besteht in der Möglichkeit, das Query Separator zu verwenden - ein Semikolon ";" - Zeichen. Aber darüber ist es notwendig, einen gesonderten Artikel mit einer Beschreibung aller Konsequenzen zu schreiben. Darüber hinaus glaubt der Autor, dass bei Webanwendungen Injektionen am häufigsten in SQL-Abfragen vorkommen (zumindest habe ich nur solche gefunden).
    In Oracle sowie in MySQL und PostgreSQL wird eine Injektion unter Verwendung des UNION-Operators durchgeführt, d. H. mit der Zusammensetzung der Kombination von zwei Abfragen (im folgenden wird der Begriff Unterabfrage zur Vereinfachung des Verständnisses verwendet). Neben der Übereinstimmung der Anzahl der Spalten in der Hauptabfrage und der Unterabfrage sollte jedoch beachtet werden, dass Oracle Typen nicht automatisch in eine Unterabfrage schreibt. Bei der Auswahl von Spalten müssen Sie im Gegensatz dazu beispielsweise Null aus MySQL ersetzen.
    Eine sehr wichtige Eigenschaft ist auch, dass alle SELECT-Abfragen aus einer Tabelle gemacht werden müssen, d.h. Die Abfragesyntax muss immer das Wort FROM und den Namen der Tabelle enthalten. Für einfache arithmetische Berechnungen oder andere Operationen, die keine echte Tabelle benötigen, gibt es eine Pseudo-SYS.DUAL-Tabelle in Oracle.
    Ein wichtiges Merkmal ist das Fehlen des LIMIT-Operators.
    Um die Abfrage zu kürzen, werden die Kommentarzeichen "-" (zwei Bindestriche) und "/ *" (ein rechter Schrägstrich und ein Stern) in Oracle SQL verwendet. Die erste Art von Kommentar ist einzeilig. Der zweite Typ ist mehrzeilig.
    Im Gegensatz zu PL / SQL-Routinen besteht keine Möglichkeit, mehrere SQL-Abfragen mit dem Trennzeichen ";" zu verwenden.
    Wenn ein Fehler erkannt wird, können Sie Oracle durch das Vorhandensein des Wortes ORA im Text der Fehlermeldung eindeutig identifizieren:

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

    Das Wort Oracle ist nicht immer im Text des Fehlers, zum Beispiel

    Warning: OCIStmtExecute: ORA-01722: invalid number in

    [Spaltenauswahl]


    Lassen Sie den Fehler im ID-Parameter vorhanden sein:

    www.site.com/view.php?id=1'
    Die Definition der Anzahl der Spalten, die in der Hauptabfrage vorhanden sind, ist die gleiche 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 der Spalten gibt es 2 bekannte Methoden und im Artikel Spyder gut beschrieben. Aber ich bringe sie wieder, damit der Leser nicht um die Artikel rennt:

    1. Eine einfache Suche.
    Machen Sie die folgende Abfrage

    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. Machen Sie die folgende Abfrage

    www.site.com/view.php?id=-1+order+by+1--
    wenn kein Fehler vorliegt, 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. In ähnlicher Weise schränken wir die Grenzen des ausgewählten Intervalls nach links und rechts ein und bestimmen letztlich die tatsächliche Anzahl der Spalten in der Hauptabfrage.

    [Definition druckbarer 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. Normalerweise nehmen Spalten mit Datentypen int, char und data an der Ausgabe teil. Wir werden genügend druckbare Spalten mit den Typen int und char haben, und wir werden nach ihnen suchen.
    Wie bereits erwähnt, werden von Oracle keine Typen automatisch in eine Unterabfrage umgewandelt. Wenn wir versuchen, in Spalten für Werte eines ungeeigneten Typs zu substituieren, erhalten wir daher den folgenden Typenfehlanpassungsfehler

    ORA-XXXXX: expression must have same datatype as corresponding expression
    Als nächstes beginnen wir mit der Erstellung von Abfragen, wobei jede Spalte abwechselnd durch eine beliebige Zahl ersetzt wird

    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 vom Typ int. In diesem Fall 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--
    Hier ist die Syntax der Funktion to_char ():
    to_char (Wert, [format_mask], [nls_Sprache])

    [Informationen erhalten]


    Nachdem wir die Anzahl der Spalten kennen gelernt haben und welche von ihnen druckbar sind, können wir sicher die erforderlichen Informationen aus der Datenbank holen. Nun, wenn wir bestimmte Tabellen in der Datenbank und die Spalten in ihnen kennen, ist es nicht schwierig, Informationen zu erhalten. 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 zur Bequemlichkeit der Anzeige und Überwindung verschiedener Probleme mit Codierungen möglich, die Funktionen concat (), to_char () zu verwenden.
    Um das Filtern von Anführungszeichen oder anderen notwendigen Zeichen zu überwinden, gibt es eine Funktion chr ().

    [Tabellen und Spalten]


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

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

    Von großem Interesse sind die Tabellen SYS.USER_TABLES und SYS.USER_TAB_COLUMNS, die alle Tabellen und ihre Spalten für den Benutzer 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--
    Meiner Meinung nach sind in der Tabelle SYS.USER_TABLES neben tabellenname die folgenden Spalten von Interesse: tablespace_name, num_rows, freelist_groups.
    Aber leider führen die obigen Anfragen nur zu einer - der ersten Aufzeichnung aus der gesamten Tabelle. Es besteht ein unwiderstehlicher Wunsch, den LIMIT-Operator entweder in MySQL oder PostgreSQL zu verwenden. Zur großen allgemeinen Enttäuschung wird dieser Operator in Oracle nicht unterstützt und hat darüber hinaus kein würdiges Äquivalent in Form eines anderen Betreibers.
    "Alles war verloren !!!" - Sie werden sagen.
    "NEIN !!!" - Ich werde dir antworten.
    Nachdem ich so ziemlich google gefoltert hatte, fand ich immer noch die Möglichkeit, eine komplexe Abfrage zu erstellen, obwohl ich irgendwie die semantische Last des LIMIT-Operators realisierte. 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 das Scannen einer anderen Anzahl von Datensätzen in der Stichprobe können wir also alle Namen der Tabellen nacheinander anzeigen. 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_ - alle für den Benutzer verfügbar (der Eigentümer darf nicht sein),
    USER_ - Objekte, deren Besitzer dieser Benutzer ist.
    Daher können wir die Aufgabe vereinfachen und die Namen nur 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
    Die 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 Hashes aller Datenbankbenutzer erhalten.
    Der Hauptort der Speicherung der Faltung des Passworts (Hash) ist die Tabelle des Wörterbuchverzeichnisses SYS.USER $. Über dieser Tabelle ist die Ableitung als Basis, SYS.DBA_USERS, konstruiert. Wenn PASSWORD_REUSE_TIME im Benutzerprofil aktiviert ist, wird die Passwortfaltung auch in SYS.USER_HISTORY $ gespeichert. Sie können Hash- 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 präsentieren, für den Fall, dass vielleicht jemand nützlich sein wird:
    1. Der Text des Passworts wird an den Benutzernamen auf der rechten Seite geklebt.
    2. In der resultierenden Zeile werden die Buchstaben erhöht.
    3. Die Zeichenketten werden in ein Zwei-Byte-Format konvertiert, indem der Nullwert 0x00 (für ASCII-Zeichen) nach links hinzugefügt und die Zeile rechts von Nullbytes auf eine Gesamtlänge von 80 angehängt wird.
    4. Die resultierende Zeichenfolge wird vom DES-Algorithmus im Modus der Kopplung von Chiffretext-Blö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 Bit) 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 als Endergebnis-Faltung deklariert.