UnSHc : déchiffrer des scripts SH compilés et chiffrés par SHc – Partie 2/2

3.4 Extraction des arguments de arc4()

Maintenant que nous disposons de toutes les tailles et adresses de localisation des 14 arguments de la fonction arc4, il est possible d’en extraire les valeurs à partir du dump STRINGFILE.

Cette extraction porte sur le tout premier appel de la fonction arc4, ainsi la valeur sous forme de chaîne hexadécimale résultante correspond à la variable msg1.

Cette opération est à répéter pour l’ensemble des 14 autres variables dont nous avons les offsets et sizes.

3.5 Récupération du pswd et de sa taille

La variable pswd, dernière donnée à récupérer composant le bloc data en amont du script *.sh.x.c est une donnée (offset + size) qui n’est pas exploitée par la fonction arc4(). C’est pourquoi elle ne fait pas partie des 14 autres valeurs précédemment extraites.

Si l’on se réfère au code source *.sh.x.c, on remarque que cette donnée est passée en argument à la fonction key(), qui est l’instruction précédant le tout premier appel de la fonction arc4() (voir figure 3).

Ainsi, si l’on grep le premier appel de la fonction arc4() sur le code désassemblé, et que l’on prend les N lignes précédentes (N dépendant de l’architecture), l’instruction call qui précèdera correspondra à notre offset de fonction key() :

3.6 Synthèse des extractions

Nous avons extrait à ce stade tous les offsets, sizes (depuis OBJFILE) et valeurs (depuis STRINGFILE) des arguments passés aux 14 call de la fonction arc4, le tout ordonné. Ainsi que l’offset, la taille et la valeur de l’argument pswd de la fonction key().

On peut donc déduire :

  • msg1 : offset 0x602149 (size 0x2a)
  • date : offset 0x60228c (size 0x1)
  • shll : offset 0x6022a4 (size 0xa)
  • inlo : offset 0x6022b0 (size 0x3)
  • xecc : offset 0x602290 (size 0xf)
  • lsto : offset 0x6022b3 (size 0x1)
  • tst1 : offset 0x6022d3 (size 0x16)
  • chk1 : offset 0x602179 (size 0x16)
  • msg2 : offset 0x6022b8 (size 0x13)
  • rlax : offset 0x6022cd (size 0x1)
  • opts : offset 0x6022ed (size 0x1)
  • text : offset 0x6021c4 (size 0xc1)
  • tst2 : offset 0x602194 (size 0x13)
  • chk2 : offset 0x6022f1 (size 0x13)
  • pswd : offset 0x60233b (size 0x100)

Pour ces 15 parties composant le bloc data originel de la source en C, nous avons leurs valeurs respectives au format \x??\x??.

Il est par conséquent possible de régénérer une source en C avec ces données, dans l’objectif d’obtenir le code source *.sh en clair originel.

4. Création d’une source C personnalisée

L’idée consiste à s’inspirer d’une source *.sh.x.c produite légitimement par SHc, pour procéder à la reconstruction de notre *.sh (plutôt qu’à son exécution).

4.1 Déclaration des valeurs extraites

L’ensemble des 15 valeurs de variables nous étant à présent connu, ce code source C peut démarrer ainsi :

Remplacer chaque $VAR_*_Z par les tailles respectives de chaque variable et chaque $VAR_* par leur valeur au format \x??\x??.

Les 14 appels de arc4() du code source C devront être alignés pour utiliser ces nouvelles déclarations.

4.2 Afficher le code source sur stdout

Enfin, interrompre l’exécution normale de la fonction xsh() pour ne pas exécuter via execvp() le code déchiffré, mais plutôt l’afficher sur la sortie standard (voir figure 5).

Fig. 5 : Affichage de la source sur stdout plutôt que l’exécuter.

5. Compilation et récupération de la source déchiffrée

La nouvelle source définie, il suffit de la compiler :

Exécuter ce nouveau binaire et rediriger la sortie standard dans un fichier *.sh :

Visualisation du code source déchiffré en clair :

La source originelle, accompagnée des commentaires est à présent disponible en clair.

Conclusion

SHc permet de chiffrer des fichiers SH destinés à des environnements de production. Seulement, en désossant la version chiffrée, il est possible de récupérer le code source originel. Ce présent article détaille la démarche manuelle que réalise l’outil UnSHc qui automatise cette récupération.

Embarquer tout le matériel cryptographique (clé, chiffré, aléas) dans un même binaire n’est pas jugé sécurisé. Les scripts *.sh.x chiffrés par SHc peuvent être recouvrés aisément.

D’autres solutions de protection de scripts SH existent, notamment obfsh [5] ou encore shellcrypt [6]. Mais ne remettez pas toute la sécurité de votre système uniquement à ces outils.

UnSHc [4] est disponible sous GitHub [3]. Celui-ci est compatible x86 et x64. D’autres supports d’architectures sont prévus (notamment ARM). Toute contribution est la bienvenue ! 🙂

Yann CAM
Security Researcher @ASafety / Security Consultant @SYNETIS

Remerciements

Je retire mon chapeau à Francisco Javier Rosales Garcia pour son outil SHc, que je continue de conseiller malgré l’existence de UnSHc. Salutations également à toute l’équipe de SYNETIS pour son intérêt, ses conseils et sa motivation sur de tels sujets !

Références

[1] Francisco Javier Rosales García, SHc, http://www.datsi.fi.upm.es/~frosal/
[2] Karsten Günther, « SHC Shell Compiler », Linux Magazine, http://www.linux-magazine.com/Online/Features/SHC-Shell-Compiler
[3] UnSHc on GitHub, https://github.com/yanncam/UnSHc
[4] UnSHc project on ASafety, https://www.asafety.fr/unshc-the-shc-decrypter/
[5] obfsh, « shell script obfuscator », http://www.comp.eonworks.com/scripts/obfuscate_shell_script-20011012.html
[6] ShellCrypt, « shellcrypt shell obfuscation », https://sourceforge.net/projects/shellcrypt/

Retrouvez cet article (et bien d’autres) dans MISC n°89, disponible sur la boutique et sur la plateforme de lecture en ligne Connect !