Existe-t-il un moyen de sortir de la chaîne et d'injecter SQL sans utiliser un seul guillemet dans Oracle?

12

Je teste une application basée sur Oracle et j'ai trouvé le code suivant:

Requête = "CHOISIR le nom parmi les employés OERE id = '" + PKID + "';"

c'est-à-dire que la chaîne de requête contient des guillemets autour de la valeur PKID qui est obtenue directement à partir de l'URL.

De toute évidence, il s'agit d'une injection SQL classique en attente de se produire ... sauf que l'application est derrière CA SiteMinder qui empêche toute URL avec un seul devis (sous quelque forme) d'être transmise à l'application.

Existe-t-il un moyen de sortir de la chaîne et d'injecter SQL sans utiliser un seul guillemet?

Edit: Désolé, j'aurais dû être plus clair - je comprends comment cela devrait être écrit, mais je dois persuader les gens que c'est un problème exploitable. Pour le moment, car il est derrière siteminder qui bloque les guillemets simples, ce sera donc une correction de faible priorité.

jdsnape
la source
1
avez-vous essayé d'utiliser une variable de liaison?
JHFB
Ce que @JHFB a dit. La liaison des variables est une pratique standard.
Philᵀᴹ

Réponses:

9

Oui, il est possible d'effectuer une attaque par injection SQL sans fournir de guillemets dans le paramètre.

La façon de le faire est d'exploiter la façon dont les nombres et / ou les dates sont traités. Vous pouvez spécifier au niveau de la session le format d'une date ou d'un nombre. En manipulant cela, vous pouvez ensuite injecter avec n'importe quel personnage.

Par défaut au Royaume-Uni et aux États-Unis, une virgule est utilisée pour indiquer le séparateur des milliers en chiffres et un point pour le point décimal. Vous pouvez modifier ces valeurs par défaut en exécutant:

alter session set nls_numeric_characters = 'PZ';

Cela signifie que "P" est maintenant le point décimal et "Z" est le séparateur des milliers. Donc:

0P01

Est le nombre 0,01. Cependant, si vous créez une fonction P01, la référence d'objet sera récupérée avant la conversion des nombres. Cela vous permet d'exécuter des fonctions sur la base de données en vous donnant des pouvoirs croissants, comme suit:

Créez une fonction de base "get by id":

create procedure get_obj ( i in number ) as
begin
  execute immediate 'select object_name from all_objects where object_id = ' || i;
end;
/

Créez également une fonction P01 qui fait quelque chose de indésirable (dans ce cas, il suffit de créer une table, mais vous avez l'idée):

create function p01 return number as
  pragma autonomous_transaction;
begin
  execute immediate 'create table t (x integer)';
  return 1;
end;
/

Et nous sommes prêts à partir:

alter session set nls_numeric_characters = 'PZ';

SELECT * FROM t;

SQL Error: ORA-00942: table or view does not exist

exec get_obj(p01);

anonymous block completed

SELECT * FROM t;

no rows selected

Aucune citation nulle part, mais nous avons quand même réussi à exécuter la fonction "cachée" P01 et à créer la table t!

Bien que cela puisse être difficile à faire dans la pratique (et peut nécessiter une certaine connaissance / aide interne), cela montre que vous pouvez injecter du SQL sans avoir à avoir des guillemets. Modifier le nls_date_formatpeut permettre de faire des choses similaires.

Les résultats originaux pour les chiffres ont été par David Litchfield et vous pouvez lire son article ici . Vous pouvez trouver la discussion de Tom Kyte sur la façon dont les dates peuvent être exploitées ici .

Chris Saxon
la source
4

Vous pourriez probablement surcharger le type de données que vous utilisez, provoquant l'échec de cette instruction. Ensuite, ce qui vient après pourrait potentiellement être exécuté.

Peut-être que l'envoyer en tant que tableau d'octets Unicode ferait l'affaire et vous sortirait de cette instruction pour une autre.

S'il y a un trou ouvert, il en sera abusé. Et bloquer toutes les chaînes avec un seul devis n'est pas une bonne idée car les personnes portant le nom de famille "O'Brian" ne peuvent pas être vos clients (entre autres).

mrdenny
la source
Je suppose que vous voulez dire "trou" et non "entier".
ypercubeᵀᴹ
1

Essayez d'utiliser une variable de liaison. Vous pouvez le déclarer sous forme de nombre et cela devrait empêcher une injection SQL dommageable.

ADDITION: les variables de liaison augmentent également les performances et l'évolutivité car le plan de requête est compilé et stocké pour être réutilisé. Juste quelque chose d'autre à ajouter à votre argument. :)

JHFB
la source
1
Il ne demande pas comment prévenir l'injection mais comment en abuser .
Jeff
1
@jeff L'OP demande également des raisons de ne pas utiliser ce type de code. Ne pas utiliser de variables de liaison détruit les performances, c'est donc une bonne raison de toujours les utiliser.
Vincent Malgrat
@Vincent Malgrat: "Ne pas utiliser de variables de liaison détruit les performances" est faux. Il est vrai que la recompilation d'une instruction peut être évitée en utilisant des variables de liaison. De plus, le pool partagé sera inondé par de nombreuses instructions similaires si vous n'utilisez pas de variables de liaison. Néanmoins, l'optimiseur a moins d'informations pour construire un plan si l'on utilise des variables de liaison au lieu de valeurs littérales. Il existe des situations dans lesquelles il convient de sélectionner différents plans en fonction des valeurs des variables de liaison (ou des valeurs littérales).
miracle173
@ miracle173 Bien sûr, il y aura des exceptions, mais pas pour une recherche de clé primaire donnée par l'OP, jamais =)
Vincent Malgrat