web-dev-qa-db-fra.com

L'injection SQL est-elle possible avec LIMIT?

Un de mes amis a créé une application Web que je teste pour le plaisir. J'ai remarqué qu'il permet à un utilisateur de définir la limite d'une certaine requête, et cette limite n'est pas filtrée.

Par exemple, je peux choisir n'importe quel nombre ou chaîne que j'aime comme limite. Je me rends compte que c'est injection SQL , et je peux facilement injecter des commandes SQL, mais est-il vraiment possible d'extraire des données ou de faire des dégâts avec un LIMIT?

Exemple de requête:

SELECT * FROM messages WHERE unread = 1 LIMIT **USER INPUT HERE**

Je comprends que si l'injection était dans la clause WHERE, j'aurais pu facilement faire un UNION SELECT pour extraire des informations, mais est-ce vraiment possible si l'entrée utilisateur était après la limite?

Pour plus d'informations, mon ami utilise le SGBD MySQL , vous ne pouvez donc pas vraiment exécuter deux requêtes telles que:

SELECT * FROM messages WHERE unread = 1 LIMIT 10;DROP TABLE messages-- 

Ce n'est pas possible.

38
Ali

Vous pouvez créer un UNION SELECT ici. Le seul problème est de faire correspondre les colonnes des messages, mais vous pouvez les deviner en ajoutant des colonnes jusqu'à ce qu'elles correspondent:

SELECT * FROM messages WHERE unread = 1 LIMIT 
    1 UNION SELECT mail,password,1,1,1 FROM users

Continuez à ajouter ,1 jusqu'à ce que vous obteniez le nombre de colonnes correct. En outre, vous devez faire correspondre le type de colonne. Essayez null au lieu de 1.

Si vous pouvez voir des erreurs MySQL, cela aiderait beaucoup de temps ici. Sinon, vous avez beaucoup essayé.

Voir également Test d'injection SQL sur owasp.org pour plus de détails.

74
PiTheNumber

Soit il n'y a presque pas de contraintes, et vous pouvez le faire de la manière habituelle (UNION ou '; XXX ---')

Parfois, ce n'est pas possible, et vous devrez vous replier sur la mise d'une expression booléenne dans LIMIT. C'est une injection SQL aveugle, et cela vous permettra de vider la base de données entière un bit à la fois.

4
Dillinur

MySQL prend en charge plusieurs instructions et a depuis au moins 4.1 il y a dix ans. Par exemple, vous pouvez activer ceci dans le module Perl mysql en utilisant mysql_multi_statements .

Bien que la bibliothèque cliente ne puisse pas prendre en charge plusieurs instructions pour le moment, vous n'êtes qu'une mise à niveau ou un changement de configuration loin d'un trou de sécurité.

3
Schwern

C'est un bon moment pour utiliser les instructions préparées par PDO et bindParam cette variable comme une entrée entière uniquement. Cela devrait annuler toute tentative de ce que vous essayez de faire en injectant du SQL.

J'envisagerais également de laisser l'utilisateur choisir parmi une liste prédéfinie de nombres dans une liste déroulante. À moins que la page de résultats ne soit définie pour paginer, vous pouvez potentiellement avoir un joli gâchis entre les mains en essayant de charger 100 000 enregistrements sur une page.

1
Rick

La requête de votre ami ne serait pas très utile aujourd'hui, mais elle pourrait l'être plus tard, mais à mesure que les technologies évoluent et que le SGBD MySQL est en constante amélioration comme de nombreuses autres technologies, votre ami doit assainir l'entrée dans le cas du LIMIT L'instruction serait modifiée afin qu'il soit possible d'utiliser UNION juste après. Votre ami peut également envisager le cas où l'architecture du SGBD MySQL serait modifiée de manière à ce qu'il soit possible d'exécuter plusieurs instructions SQL contrairement à ce qu'elle est maintenant.

Ce que je veux dire, c'est que votre ami doit aseptiser l'entrée: c'est la meilleure pratique: vous ne voyez peut-être pas cela trop important aujourd'hui, mais à l'avenir vous ne le savez jamais, et rappelez-vous qu'il y a toujours des gens qui peuvent être plus expérimentés que ton ami.

1
user45139

Définition d'une limite de 1 UNION SELECT ... permettra à l'attaquant d'extraire des informations de toute autre table, tant que les colonnes ont (ou peuvent être CAST avoir) le même nombre et le même type que les colonnes de la première SELECT. La définition d'une limite comme valeur produite à partir d'un sous -SELECT permettra à l'attaquant de lire toute autre information dans la base de données à partir du nombre de lignes retournées. Par exemple, le hachage de mot de passe d'un autre utilisateur peut être extrait 4 bits à la fois en effectuant à plusieurs reprises une sous-requête renvoyant un nombre compris entre 0 et 15 à différents décalages de sous-chaîne, puis en comptant les lignes dans chaque résultat.

Mais ces deux attaques peuvent être déjouées. De nombreux pilotes de base de données autorisent un paramétré LIMIT . Si un pilote particulier interfère avec un LIMIT paramétré, vous pouvez purifier l'entrée en convertissant l'entrée en un entier avant de le remplacer par une chaîne dans la requête. Cela vous aidera également à vous assurer de ne pas renvoyer plus d'enregistrements que votre application ne peut gérer à partir d'une seule requête (telle que LIMIT 12345678). En PHP, cela pourrait ressembler à ceci:

<?php
//...
$limit = intval($_REQUEST['numresults']);
$limit = min(max($limit, 10), 100);
$stmt = $dbh->prepare("SELECT ... FROM ... WHERE ... LIMIT $limit");
1
Damian Yerrick