Exercices d'ISI - Expérimental
Attaques web
Trouver le type de faille, pourquoi ça marche et indiquer le type de correction à apporter pour la résoudre.
Code 1
function getUserByLastname($lastname)
{
try {
$dbh = getPDO();
$query = "SELECT * FROM users WHERE lastname = '" . $lastname . "';";
$statment = $dbh->prepare($query);
$statment->execute();
// ...
}
Comment exploiter cette faille pour récupérer l'utilisateur avec id 2 sans connaitre son lastname ?
Solution
Injection SQL.
' OR id=2;--->SELECT * FROM filmmakers WHERE lastname = '' OR id=2;--';- without
;--trick:' OR id=2 AND '1'='1->SELECT * FROM filmmakers WHERE lastname = '' OR id=2 AND '1'='1';
Code 2
$id = $request['id'];
$id = escape($id); // remplace les " par \" et les ' par \'
$query = "SELECT * from users where id = $id;";
Solution
Solution:
Injection SQL à nouveau: l'échappement pas d'impact ici. pour supprimer tous les users: 2; DELETE from users
Code 3
<h1>Classement en groupes d'élèves selon leur moyenne</h1>
...
<?php
$indexGroup = 0;
for ($i = 1; $i <= 5.5; $i = $i + 0.5) {
echo "<ul>";
foreach ($students as $student) {
if ($student['moyenne'] > $i && $student['moyenne'] <= $i + 0.5) { //between min not inclusive and max inclusive.
echo "<li>" . round($student['moyenne'], 10) . ": " . $student['firstname'] . " " . $student['lastname'] . " </li > ";
}
}
echo "</ul > ";
}
?>
Solution
XSS dans firstname ou lastname: si le lastname vaut <script>alert(document.cookie)</script> -> alors l'HTML généré sera <li> 6: Samuel <script>alert(document.cookie)</script> </li >
Code 4
<label>Enter your new username</label>
<input id="newUsername" />
...
<script>
// ...
const username = document.getElementById("username");
username.innerHTML = document.getElementById("newUsername").value;
</script>
Solution
Solution: XSS
- Si on entre
<script>alert(document.cookie)</script>, l'attaque ne fonctionne pas car innerHTML bloque volontairement les balises<script>. - Par contre, une balise script est de loin la seule chose qui peut s'exécuter:
<img src='x' onerror="alert(document.cookie)" />fonctionne.
-> utiliser innertText ou textContent pour résoudre le problème, qui échappe les caractères propres à l'HTML
Quelle CWE ou nom de faille ?
Voir la liste ici https://cwe.mitre.org/top25/archive/2024/2024_cwe_top25.html
Code 1
<?php
// Un serveur web qui lance la commande `ls` dans le dossier donné en query parameter
// Si la fin de l'URL est /?path=src -> lancera "ls -la src"
echo "LS on demand\n";
$folder = $GET['path'];
echo shell_exec("ls -la " . $path);
Solution
CWE-78 (Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection'))
Corrections:
-> utiliser une fonction dédiée pour lire les éléments d'un dossier
-> ou utiliser le processus ls plutot qu'un shell qui lance ls
attention au path traversal, on ne voudrait pas pouvoir lister le contenu de tous les dossiers du serveur.
Code 2
char firstname[100];
char lastname[100];
char fullname[200];
puts("Votre prénom: ");
gets(firstname);
// ...
strcpy(fullname, firstname);
strcat(fullname, " ");
strcat(fullname, lastname);
Solution
CWE-787 Out-of-bounds Write
Pas de vérifications de la taille sur gets et strcpy, écriture au delà de
buffer overflow -> strncpy, fgets
Code 3
<form method="post" action="monentreprise.ch/delete_user?id=3">
<button type="submit">WIN IPHONE !</button>
</form>
Solution
CWE-352 Cross-Site Request Forgery (CSRF)
Correction: utiliser un token anti-CSRF
Code 4
#include <string.h>
#include <stdlib.h>
void print(char *message) {
printf("message = %s\n", message);
free(message);
}
int main() {
char *message = malloc(100);
message[0] = 'a';
print(message);
printf("message length is %d\n", strlen(message));
}
Solution
CWE-416 Use After Free
Usage du pointeur message après le free strlen(message), on accède ainsi à une zone désallouée ou allouée pour autre chose.
Correction: free plus tard ou ne pas réutiliser message une fois libéré.
Code 5
const newMessage = fetchLatestMessage()
const message = document.getElementById("message")
message.innerHTML = newMessage.content;
Solution
CWE-79 XSS (Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'))
Correction: Utiliser innerText ou textContent
Code 6
char firstname[100];
scanf("%s", firstname);
Solution
buffer overflow
Code 7
#include <stdio.h>
int main(int argc, char *argv[]) {
const int secret = 1234;
const int grades[18] = {5, 5, 6, 4, /*...this is filled with grades */};
int choice;
printf("Donner l'index de la note à afficher: ");
scanf("%d", &choice);
printf("Note choisie: %d\n", grades[choice]);
return 0;
}
Solution
buffer overflow -> accès arbitraire à la mémoire puisque l'index permet de lire n'importe quelle groupe de 4 bytes
comment afficher le secret ??
Solution
Possible de lire le secret en rentrant 19. En pointant juste après le tableau, là où secret est alloué, on accède donc à la valeur de secret.
Code 8
// ExpressJS web server, req.params contains the query parameters
app.get("/hello", (req, res) => {
res.send("Hello " + req.params.firstname);
})
Solution
XSS
Exploitations mémoires
Le chocolat c'est bon mais c'est cher
Comment peut-on exploiter ce code pour ne pas devoir payer (ou même payer un prix négatif)? Quel est la faille ?
#include "stdio.h"
#include "stdlib.h"
#define MAX 10
int main(void) {
printf("Combien de chocolats ? \n");
char buffer[MAX + 1];
fgets(buffer, MAX, stdin);
int price = 100 * atoi(buffer);
printf("Le prix à payer (c'est cher 100.- le carré) est de %d\n", price);
}
Solution
integer overflow -> donner un nombre N où 100*N > 2^31-1 et le int va overflow.
Le compte de Jamy
Comment arriver à se connecter avec le compte de Jamy (et ainsi voir le message Welcome Jamy) sans connaître son mot de passe et sans pouvoir accéder au fichier pwd.txt ?
#include <stdio.h>
#include <string.h>
#define SIZE 10
// Quick and dirty way to read the password of Jamy, assume the file exist and is valid
void read_pwd_from_file(char *secret_dest) {
FILE *file = fopen("pwd.txt", "r");
fscanf(file, "%s", secret_dest);
secret_dest[SIZE] = '\0';
fclose(file);
}
int main(int argc, char *argv[]) {
char secret[SIZE];
read_pwd_from_file(secret);
char password[SIZE];
printf("Enter the password of Jamy to login: ");
fflush(stdout);
scanf("%s", password);
if (strncmp(secret, password, SIZE) == 0) {
printf("Welcome Jamy, you are in.\n");
} else {
printf("Wrong password\n");
}
return 0;
}
Démo:
Enter the password of Jamy to login: je sais pas
Wrong password
Solution
Il se trouve que le compilateur GCC alloue ici sur la stack, la variable password puis secret. Comme il y a un buffer overflow sur le scanf qui n'a pas de limite de nombre de bytes lus, on peut ainsi écrire dans password et aussi dans secret, dès qu'on dépasse 9 caractères.
Pour que les 2 valeurs soient égales et que le strncmp (qui ne compare que les 10 bytes) retourne 0 pour indiquer l'égalité, on peut par exemple rentrer 20 lettres identiques pour que password = aaaaaaaaaa et secret également.
Enter the password of Jamy to login: aaaaaaaaaaaaaaaaaaaaa
Welcome Jamy, you are in.
Note: avec strcmp il aurait fallu faire un peu autrement parce que la première chaine password serait étendu de taille (valant aaaaaaaaaaaaaaaaaaaaa) alors que secret vaudrait aaaaaaaaaa, ce qui n'est pas égal. Nous aurions donc du rentrer 9 caractères égal, puis un null byte, puis à nouveau 9 caractères égal.
Il est possible de taper des null bytes dans son terminal, mais cela n'est pas évident. Il est plus simple d'utiliser un outil dédié, par exemple générer la séquence de caractères avec perl.
> perl -e 'print("a" x 9, "\0", "a" x 9)' | ./build/main
Enter the password of Jamy to login: Welcome Jamy, you are in.
Questions random de drill
Pas de solution sorry.
- Combien existe-t-il de mots de passe alphanumériques de longueur 10, avec toutes les lettres différentes ?
- Combien existe-t-il de mots de passe composé de 5 lettres minuscules ou moins ?
- Combien existe-t-il de mots de passe composé d'un mot du dictionnaire (10000 mots) avec avant ou après 3 chiffres formant un nombre entre
[100;300]? - Quel outil permet de casser des hash de mdp non salés très rapidement une fois la préparation terminée ?
- Comment peut-on jouer à pile ou face au téléphone ? Quels sont les enjeux de triche des 2 parties ?
- Qu'est-ce qu'une 0-day ?
- Qu'est-ce qu'un DDOS ? et un DOS ? et un botnet ?
- Comment envoyer un message authentique et confidentielle de Alice à Bob avec du chiffrement asymétrique ?
- Pourquoi l'authenticité des clés est importante ?
- Qu'est-ce qu'un shellcode ?
- Qu'est-ce qu'un buffer overflow ? D'où vient le problème ?
- Qu'est-ce que le stack smashing ?
- Quelles sécurités existent contre le stack smashing ?