gdb disas main

Flux RSS


Derniers billets blog


























Version 3.0beta4-tuxfamily

"Mais en fait, non !"

Vous pouvez me contacter directement à sylvain.sarmejeanne.ml AT gmail.com

Blog Logo RSS

News [browser] Opera garni

Généralement, les gens sont plutôt étonnés lorsque je leur dis que mon browser n'est pas Firefox mais Opera. La question qui revient le plus souvent : "Bah pourquoi ?".

Je ne me souviens plus exactement à quel moment j'ai fait le switch, mais ça devait certainement être pas longtemps après le 500e crash de Firefox pour cause de mémoire insuffisante (version 2 j'avoue, il parait que ça s'est amélioré depuis). Opera est rapide, fiable, mature, peu gourmand. L'archétype du produit bien sous tout rapport, qui juste marche, mais qui n'a pas connu le succès mérité sans qu'on sache vraiment pourquoi (un peu comme la Dreamcast quoi). Pourtant, ça m'a fait à peu près le même effet de passer de Firefox à Opera que de Debian à Gentoo, c'est vous dire le gouffre.

Et la sécurité dans tout ça ? Chaque release de Firefox corrige sont petit lot de "crashes with evidence of memory corruptions" (vous noterez le sens de l'euphémisme de la fondation Mozilla). Tout le monde s'en fout. Dans Internet Explorer, deux 0-days et c'est la panique. Sur le fond, je suis assez d'accord : il est plus sécurisé de surfer avec FF qu'avec IE, puisque dans la mesure où IE a le plus de parts de marchés, les codes d'exploit présents dans les kits le cibleront en priorité. Aucune raison technique, simple question de rentabilité. Donc encore mieux avec Opera. En résumé : personne n'utilise Opera, donc tout le monde aurait intérêt à l'utiliser (je suis fan de ce genre de paradoxe :) Opera contient peut-être des vulnérabilités énormes, mais il n'en demeure pas moins qu'il est moins risqué de surfer avec lui que FF ou IE. Point. Bien sûr qu'il y a des 0-days dans Opera, mais certainement moins que dans les autres browsers. Et qu'on ne me parle pas de Chrome.

Pendant qu'on y est, j'ai découvert une vuln hier (le concept est pourtant pas neuf, mais j'étais passé complètement à côté). Laissez-moi vous présenter le DNS prefetching. Quand vous ouvrez une page avec FF 3.5, il résout automatiquement les domaines des liens présents dans la page, même si vous n'avez cliqué nulle part. Démonstration :

<html>
<body>
<a href="http://mon.superdomaine.fr">gé mm pa cliké !!!</a>
</body>
</html>

La simple ouverture dans FF provoque la résolution du domaine :

dns prefetching

Bien pratique pour remplacer les vieillissantes notifications mail (NB : ne marche plus sur GMail en raison du récent passage à HTTPS).

La simple ouverture dans Opera provoque... bah rien. CQFD.

Posté par sylv1 le 04/02/2010 à 23:33:12
3 commentaires

News [quick] QEMU et réseau VDE

Avant avec QEMU, la mise en réseau de VM entre elles, ça n'était pas simple, contrairement à VMWare qui gère ça nativement. Mais depuis la version 0.10, QEMU supporte nativement VDE (Virtual Distributed Ethernet), rendant ainsi l'opération très facile (avant il fallait passer par le wrapper vdeqemu, qui marchait plus ou moins bien). Sous Gentoo, le USE flag vde est disponible pour les paquets app-emulation/qemu et app-emulation/kvm (versions ~x86), correspondant à l'option de compilation --enable-vde.

On commence par configurer les tap :

# tunctl -u sylv1
Set 'tap0' persistent and owned by uid 42
# tunctl -u sylv1
Set 'tap1' persistent and owned by uid 42

# ifconfig tap0 192.168.0.1
# ifconfig tap1 192.168.0.2

On crée ensuite le switch virtuel (NDS : chez moi, l'option -m 777 est nécessaire sinon QEMU ne démarre pas en raison de mauvaises permissions) :

# vde_switch -d -F -m 777 -t tap0,tap1

Ne reste plus qu'à lancer chaque VM :

$ qemu -loadvm 1 -m 128 -net nic,macaddr=52:54:00:12:34:56 -net tap,ifname=tap0,script=no -net vde malware.qcow2

$ qemu -loadvm 1 -m 128 -net nic,macaddr=52:54:00:12:34:57 -net tap,ifname=tap1,script=no -net vde malware.qcow2

Lors de la configuration réseau, Windows devrait vous dire que le nom de machine existe en double :)

Posté par sylv1 le 31/07/2009 à 20:41:38
1 commentaire

News [crypto] Mettez un sha dans votre moteur

L'info n'est ni neuve ni révolutionnaire mais j'avoue que j'étais passé à côté jusqu'à aujourd'hui : les distribs GNU/Linux sont en train de migrer vers l'utilisation de SHA-512 dans /etc/shadow. Sous Gentoo stable x86, c'est par exemple le cas depuis le 08/03/2009 (22/03/2009 sur hardened) ; dans /usr/portage/sys-auth/pambase, voir le ChangeLog et le nouveau USE flag sha512 dans metadata.xml. D'après ce que j'ai pu lire, Ubuntu 8.10 et Fedora 9 sont aussi passés à SHA-512 par défaut. Remarquez l'option sha512 sur la ligne pam_unix.so dans /etc/pam.d/system-auth.

Désormais, si vous changez votre mot de passe, il sera condensé avec SHA-512 (préfixe $6$) au lieu de MD5 (préfixe $1$). NDS : il existe aussi le préfixe $5$ pour SHA-256.

Vous pouvez générer manuellement le hash qui sera mis dans /etc/shadow via la ligne Python suivante : (utile car un bug dans mkpasswd empêche de spécifier un salt de seulement 8 caractères) :

python -c "import crypt; print crypt.crypt('monpass', '\$6\$mon-salt')"

Une fois tous les mots de passe mis à jour vers SHA-512, reste maintenant à tester l'ami John :

# john /etc/shadow
No password hashes loaded

Tiens :)

Posté par sylv1 le 25/06/2009 à 23:21:04
1 commentaire

News [sstic] Le SSTIC 2009 en images

Pour un résumé des talks, je suppose que vous savez où aller :)

Prêts à attaquer le SSTIC 2009 :)
Prêts à attaquer le SSTIC 2009 :)

La keynote sur la sûreté dans les avions
La keynote sur la sûreté dans les avions

Injection de code malicieux dans une Java Card
Injection de code malicieux dans une Java Card


Conférence de Florent sur le data tainting appliqué aux malware

Désobfuscation automatique de binaire
Désobfuscation automatique de binaire


Projet WOMBAT
Projet WOMBAT




ACPI et SMI
ACPI et SMI



Démo de la rootkit
Démo de la rootkit

Compromission via le bus PCI
Compromission via le bus PCI

Solution du challenge SSTIC 2009
Solution du challenge SSTIC 2009

Remise des prix du challenge
Remise des prix du challenge

Fuzzgrind
Fuzzgrind

La GUI de Fuzzgrind
La GUI de Fuzzgrind

Crackme résolu :)
Crackme résolu :)


Convergence fixe mobile
Convergence fixe mobile


Démo d'un fuzzer IKE
Démo d'un fuzzer IKE

Sécurité des smartphones
Sécurité des smartphones

Exemple de logiciel espion
Exemple de logiciel espion


Traçage de traîtres en multimédia
Traçage de traîtres en multimédia



La Barbie Hacker de Marie Barel
La Barbie Hacker de Marie Barel

Security failed
Security failed




Virtualisation matérielle pour protéger le noyau
Virtualisation matérielle pour protéger le noyau

Projet SEC&SI de création d'un OS sécurisé pour Mme Michu
Projet SEC&SI de création d'un OS sécurisé pour Mme Michu




Security failed en live...
Security failed en live...

Social event
Social event

Programme des rump sessions
Programme des rump sessions




Aurélien Bordes et CredSSP
Aurélien Bordes et CredSSP

Une conf marrante sur les attaques via LaTeX
Une conf marrante sur les attaques via LaTeX

Un module PAM ethylomètre :)
Un module PAM ethylomètre :)

Il faut souffler...
Il faut souffler...

La box dont on ne doit pas prononcer le nom...
La box dont on ne doit pas prononcer le nom...

A quand une conf sur la compromission physique des équipements d'hôtels ?
A quand une prez sur la compromission physique des équipements d'hôtels ?


Macaron, une backdoor JavaEE
Macaron, une backdoor JavaEE


IpMorph, unification de la mystification de prise d'empreinte
IpMorph, unification de la mystification de prise d'empreinte


Kolumbo : analyse dynamique depuis le noyau
Kolumbo : analyse dynamique depuis le noyau

Calcul sur cartes grahiques
Calcul sur cartes grahiques

Emanations compromettantes électromagnétiques (une conf remarquable sur le fond comme sur la forme)
Emanations compromettantes électromagnétiques

Pour finir...


Posté par sylv1 le 05/06/2009 à 22:54:08
3 commentaires

News [linux] Même pas CAP

Je n'avais encore jamais joué avec les capabilities sous Linux. Il n'est jamais trop tard pour bien faire :)

Sur une distro GNU/Linux de base, un plus ou moins grand nombre de binaires setuid root sont présents. Par exemple, sur mon système, j'avais (cherchez l'intrus :)

# find / -type f -perm -004000
/usr/libexec/lockspool
/usr/libexec/dbus-daemon-launch-helper
/usr/lib/misc/ssh-keysign
/usr/lib/misc/xscreensaver/sonar
/usr/lib/misc/glibc/pt_chown
/usr/bin/smbumount
/usr/bin/Xorg
/usr/bin/rsh
/usr/bin/chage
/usr/bin/rcp
/usr/bin/tshark
/usr/bin/chsh
/usr/bin/newgrp
/usr/bin/expiry
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/sudo
/usr/bin/smbmnt
/usr/bin/lppasswd
/usr/bin/rlogin
/usr/bin/sudoedit
/usr/bin/dumpcap
/usr/kde/3.5/bin/kgrantpty
/usr/kde/3.5/bin/fileshareset
/usr/kde/3.5/bin/start_kdeinit
/sbin/unix_chkpwd
/bin/mount
/bin/passwd
/bin/su
/bin/umount
/bin/ping
/bin/.backdoor

La plupart des gens considèrent le bit suid sur un binaire appartant à root comme le Mal. Ce n'est pas toujours le cas. Par exemple, depuis la version 0.99.7, Wireshark vous permet de sniffer sur eth0 en tant que simple utilisateur, à partir du moment où vous faites partie du groupe wireshark. En fait, tout le code demandant des privilèges élevés est simplement passé dans dumpcap qui est setuid root, groupe wireshark seulement :

$ l `which dumpcap`
-r-sr-s--- 1 root wireshark 55K avril 13 23:47 /usr/bin/dumpcap

Cela vous évite donc de lancer la GUI Wireshark et ses 1.5 millions de lignes de code en root (NDS : tout cela est indiqué sous Gentoo lorsque vous installez le paquet). Le bit suid a donc augmenté la sécurité de votre système.

Mais il est aussi vrai qu'il suffit d'une vuln dans un binaire setuid et c'est game over ; on cherche donc à avoir le plus petit nombre possible de tels binaires. On peut même n'en avoir aucun, et c'est là où les capabilities entrent en jeu.

Pour que ça marche, il vous faut :

  • côte noyau : CONFIG_SECURITY_FILE_CAPABILITIES et CONFIG_EXT{2,3}_FS_XATTR (je crois que c'est tout)
  • côte userland : la libcap (je n'ai pas dit libpcap :)

On va prendre l'exemple hyper bateau du binaire ping. L'envoi d'un paquet ICMP nécessite l'ouverture d'une socket en mode RAW, opération privilégiée sous Linux. Pour que tout le monde puisse quand même utiliser ping, le binaire est donc setuid root :

$ l `which ping`
-rws--x--x 1 root root 36K août 31  2008 /bin/ping

On supprime le bit suid, le ping n'est plus possible :

# chmod -s `which ping`

$ ping www.free.fr
ping: icmp open socket: Operation not permitted

Un strace nous indique là où ça coince :

$ strace ping www.free.fr 2>&1 | grep EPERM
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = -1 EPERM (Operation not permitted)

Ne reste plus qu'à regarder à quelle capability ça correspond :

$ egrep -i "socket|raw" /usr/include/linux/capability.h
[...]
/* Allow use of RAW sockets */
#define CAP_NET_RAW          13
[...]

On modifie maintenant les attributs du fichier pour lui rajouter la capability CAP_NET_RAW. Le ping remarche bien :

# setcap CAP_NET_RAW=ep `which ping`

$ ping www.free.fr
PING www.free.fr (212.27.48.10) 56(84) bytes of data.
64 bytes from www.free.fr (212.27.48.10): icmp_seq=1 ttl=120 time=33.2 ms
[...]

Les flags ep correspondent à "Effective" et "Permitted" (cf la doc pour les détails).

A ce point, on a juste remplacé le bit suid par la capability. On aimerait aller plus loin, en attribuant par exemple la capability en fonction de l'utilisateur. C'est possible en appelant setcap avec les flags ei ("Effective" et "Inheritable") au lieu de ep :

# setcap CAP_NET_RAW=ei `which ping`

Il faut ensuite ajouter la ligne suivante dans /etc/pam.d/login :

auth       required     pam_cap.so

Enfin, il faut modifier le fichier /etc/security/capability.conf pour indiquer quel user se verra attribuer la capability :

$ grep sylv1 /etc/security/capability.conf 
cap_net_raw sylv1

Le ping marchera ainsi pour le user sylv1, mais pas pour les autres. En répétant la manip pour les autres binaires, vous obtiendrez ainsi un système sans binaire setuid root. A noter que l'utilisation des capabilities est un domaine d'actualité, par exemple Gentoo devrait par exemple travailler dessus lors du prochain Google Summer of Code.

On vient de voir que les capabilities peuvent être utilisées afin de restreindre les privilèges. Ils peuvent aussi être utilisés pour les augmenter ; si cela est fait intelligemment, cela peut aussi contribuer à améliorer la sécurité du système. Exemple : pour modifier votre conf réseau, vous ouvrez un shell root et lancez ifconfig ou route. Si vous laissez ce shell ouvert sans verrouiller votre session, c'est fini. Alors que vous auriez pu mettre la bonne capability, en l'occurence CAP_NET_ADMIN, et rester dans votre shell standard (évidemment, cela n'est applicable que si vous êtes seul sur le système). A méditer...

Mais ce n'est pas tout. Vous vous souvenez peut-être du MISC 13 (mai-juin 2004, et oui ça remonte :) où la page 50 parlait des capabilities. C'était pour introduire la notion de capability bounding set, un masque où chaque bit représente une capability : si un bit est à 0, la capability associée n'est disponible pour aucun processus. Vous pouvez donc utiliser /proc/sys/kernel/cap-bound (liée à la variable cap_bset du noyau) pour diminuer les capabilities de façon non-réversible (jusqu'au prochain reboot quoi). Problème : si vous oubliez aussi de désactiver CAP_SYS_RAWIO en plus de CAP_SYS_MODULE (chargement de module noyau), un attaquant peut accéder en dur à /dev/mem et écrire la valeur qu'il souhaite dans cap_bset. L'attaque ne date vraiment pas d'hier puisque l'article de MISC semble lui-même tiré d'un article datant de 2000.

De nos jours, c'est-à-dire depuis Linux 2.6.25, /proc/sys/kernel/cap-bound n'existe plus ; ce n'est plus un attribut global mais par thread, qui se transmet par fork/exec. Autrement dit, si vous voulez supprimer une capability pour tout le système, il faudra restreindre dès init. Regardons dans /usr/src/linux/include/linux/init_task.h :

#define INIT_TASK(tsk)	\
{
[...]
    .cap_bset = CAP_INIT_BSET,
[...]

Un peu plus haut :

#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
# define CAP_INIT_BSET  CAP_FULL_SET
#else
# define CAP_INIT_BSET  CAP_INIT_EFF_SET
#endif

Donc il faut modifier CAP_FULL_SET, défini dans /usr/src/linux/include/linux/capability.h :

# define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }})

Par défaut, le cap_bset vaut donc 0xffffffff (toutes les capabilities activées). Si on veut par exemple désactiver le chargement des modules pour tous, même root, on peut donc y rajouter CAP_SYS_MODULE (oui, je sais, c'est moins idiot de désactiver les modules dans la conf du noyau, c'est juste pour l'exemple :) :

# define CAP_FULL_SET ((kernel_cap_t){{ ~CAP_TO_MASK(CAP_SYS_MODULE), ~0 }})

N'oubliez pas aussi de désactiver CAP_SYS_RAWIO :)

Références :

Posté par sylv1 le 25/05/2009 à 23:45:00
2 commentaires

News [fun] Aix (pas IBM)

Petit souvenir d'un week-end à Aix-en-Provence :

Forum des cardeurs

Wikipedia : "Un cardeur est un ouvrier qui carde, c'est-à-dire qui démêle des fibres textiles et les peigne à l'aide d'une carde."

Quoi, vous aviez pensé à autre chose :)

Posté par sylv1 le 11/05/2009 à 23:08:49
0 commentaire

News [malware] Conficker : in security WehnTrust

Conficker, c'est un peu le Security Failed à lui tout seul. Des millions de machines infectées partout dans le monde. Pour éviter la propagation du ver à tout un parc de machines en une demi-journée, il suffisait pourtant :

  • d'avoir une politique "correcte" d'application des correctifs. Le MS08-067 est sorti fin octobre, ce qui laisse quand même le temps ; il était de plus sorti hors-cycle et tout le monde savait que c'était la faille de l'année à patcher
  • d'avoir supprimé les partages administratifs, particulièrement sur les postes de travail

Ces deux points font partie de tous les guides de sécurisation Windows depuis 10 ans. Que Mme Michu se fasse infecter sa clé USB, passe encore, mais il y a d'autres contextes dans lesquels on comprend moins... Bonne chance avec la variante C.

On va mainteanant tester notre ami Conficker sous XP avec WehnTrust. On l'installe, on reboote, on lance la bête. Résultat :

WehnTrust

On passe un coup de MSRT pour être sûr :

MSRT

Pas si compliqué que ça la sécurité finalement...

Posté par sylv1 le 14/03/2009 à 16:18:02
2 commentaires

News [fun] Stickers F-Secure

Youhou :)

Stickers F-Secure
Posté par sylv1 le 19/02/2009 à 20:19:10
2 commentaires

News [malware] TLS strikes back

S'il vous arrive d'analyser du malware de temps à autres, il vous est peut-être déjà arrivé de faire ceci :

  • 1. On recupère le binaire :
wget_ie http://site/vx.exe
  • 2. On fait un file pour voir vite fait de quoi il s'agit :
file vx.exe
vx.exe: MS-DOS executable PE  for MS Windows (console) Intel 80386 32-bit, UPX compressed
  • 3. "Tiens, il est compressé en UPX, on tente de le décompresser direct, on sait jamais :"
upx -d vx.exe
[...]
Unpacked 1 file.
  • 4. "Youhou, comment dépacker un malware en 2 secondes ! Le gars qui a fait ça est vraiment naze. Je vais maintenant travailler directement sur la version unpackée."

Oui, mais en fait non. Le raisonnement ci-dessus part du principe suivant : si upx -d marche, alors il s'agissait bien d'un binaire compressé avec UPX et le binaire unpacké aura le même comportement que le binaire packé. Sauf que qu'est-ce qui vous dit que le binaire UPX n'a pas été bidouillé ? Par exemple en ajoutant du code qui s'exécute avant le point d'entrée pour modifier des octets en mémoire juste avant que l'algorithme de décompression ne passe par là ? Par exemple en ajoutant un callback TLS ?

L'idée de ce billet blog m'est venue lorsque j'ai travaillé sur le level 2 du Khallenge 2008 et que je me suis rendu compte que le callback TLS du binaire original (celui qui pose les bases d'une détection de debugger réalisée un peu plus bas dans le code) n'était pas conservé par la décompression UPX. Plutôt marrant.

Bon, je ne vais pas m'étendre outre mesure sur le mécanisme de Thread Local Storage sous Windows. Il s'agit d'une fonctionnalité du loader permettant d'exécuter du code avant le point d'entrée défini dans l'en-tête PE. C'est par exemple utilisé par les malware pour déchiffrer le code situé à l'entry point (cf analyse de PE GRUM par N. Brulez dans MISC 31). Les structures sont les suivantes :

  • dans l'en-tête optionnelle PE, structure IMAGE_DIRECTORY_ENTRY_TLS non vide
  • son champ VirtualAddress contient la VA d'une structure IMAGE_TLS_DIRECTORY
  • elle-même contient un champ AddressOfCallBacks contenant la VA vers un tableau de pointeurs de fonction

Un bon schéma valant mieux qu'on long discours :

IMAGE_DIRECTORY_ENTRY_TLS, IMAGE_TLS_DIRECTORY

On peut ajouter un callback TLS à un binaire UPX pour par exemple :

  • exécuter du code malicieux dans la version compressée mais qui ne sera pas exécuté dans la version décompressée (classique)
  • exécuter du code pour modifier certains octets en mémoire afin de changer le comportement entre les 2 versions (plus rigolo, c'est ce qu'on va faire ici).

On part d'un programme très simple qui affiche une message box :

#include <windows.h>

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MessageBox(NULL, "good", "tls", MB_OK);
    return 0;
}

On compile et on compresse en UPX. Toute la suite se fait dans un éditeur hexa. Première étape : trouver un endroit où stocker nos différentes structures. En parcourant vite fait le binaire, on trouve de la place à l'offset cf0 :

TLS callbacks

On y place notre structure IMAGE_TLS_DIRECTORY :

  • cf0 : StartAddressOfRawData = cf0 (offset) -> 4080f0 (VA)
  • cf4 : EndAddressOfRawData = cf0 (offset) -> 4080f0 (VA)
  • cf8 : AddressOfIndex pointe vers NULL à d00 (offset) -> 408100 (VA)
  • cfc : AddressOfCallBacks = d08 (offset) -> 408108 (VA)
  • d00 : SizeOfZeroFill = 0
  • d04 : Characteristics = 0

Le champ AddressOfCallBacks pointe vers l'offset d08 où on place maintenant notre tableau de pointeurs vers callbacks. On n'en a besoin que d'un seul :

  • d08 : pointeur vers notre callback = d10 (offset) -> 408110 (VA)

Que voulons-nous faire dans ce callback ? On va prendre l'exemple très simple de la modification de la chaine "good" qui se situe à l'offset 7ae, soit à l'adresse virtuelle 4075AE. Un simple MOV sur le contenu présent à cette adresse suffit (oui, je sais c'est particulièrement peu élégant comme méthode, mais c'est juste pour l'exemple...) :

55                         PUSH EBP
89 E5                      MOV EBP, ESP
36 C705 AE754000 6576696C  MOV DWORD PTR SS:[004075AE], 6C697665
b8 0000 0000               MOV EAX, 0
C9                         LEAVE
C3                         RET

En résumé, on obtient ceci :

TLS callbacks

On peut ainsi modifier tout octet dans la version UPXée du binaire (attention, pour patcher certaines zones, il faut aussi patcher le checksum UPX), de façon à obtenir un binaire décompressé en mémoire différent de celui décompressé en statique avec upx -d.

Tout est en place, il ne reste plus qu'à modifier l'en-tête optionnelle PE pour rendre la structure IMAGE_DIRECTORY_ENTRY_TLS non nulle et la faire pointer sur la structure définie plus haut :

  • 140 : VirtualAddress = cf0 (offset) -> 4080F0 (VA)
  • 144 : Size = 18
IMAGE_DIRECTORY_TLS

On obtient ainsi le binaire à télécharger en annexe. Si on va un peu vite à l'analyse et qu'on exécute la version décompressée avec upx -d, il affiche le message défini dans le source, à savoir "good" :

En revanche, quand on exécute le binaire UPX lui-même sous XP, surprise :

Archive : sylv1_tls.zip

Posté par sylv1 le 04/10/2008 à 17:52:07
3 commentaires

News [crypto] Goût de LUKS

Ayant acquis il y a quelques temps un nouveau laptop, je m'étais empressé de le chiffrer avec du DM-Crypt/LUKS et j'avais voulu jouer un peu avec ce système de (dé)chiffrement de disque à la volée et la technique de cold boot. NDS : la plupart des infos qui suivent sont plus ou moins obsolètes depuis la publication des sources du cold boot original ; c'est donc plus pour garder une trace de ce que j'avais fait à l'époque.

La première étape consiste à récupérer un dump de la RAM. J'avais utilisé MsRamDump qui fait très bien l'affaire. Dans ce dump on trouve tout un tas de choses très intéressantes comme le mot de passe root utilisé pour redémarrer le système, à tel point que je n'ai pas pu m'empêcher de grepper sur ma passphrase pour voir si elle s'y trouvait en clair : c'était bien sûr très naïf (ou pas...). La vraie question est donc : "comment récupérer ma clé de chiffrement AES dans ce dump ?", ce qui ramène à la question "mais au fait, elle ressemble à quoi ma clé de chiffrement ?".

Petit tour très rapide dans le monde DM-Crypt/LUKS. A chaque démarrage de l'OS (j'ai bien dit "OS", il ne s'agit pas d'un chiffrement pré-boot au sens strict comme TrueCrypt), un prompt "Enter LUKS passphrase:" me demande ma passphrase pour déchiffrer ma partition root. cryptsetup est l'outil de gestion des clés LUKS. Regardons ses sources de plus près :

$ grep "Enter LUKS passphrase:" -R cryptsetup-1.0.5
cryptsetup-1.0.5/lib/setup.c

La chaîne est présente deux fois, dont une pour __crypt_luks_open() (l'autre pour __crypt_luks_format()) qui semble être la bonne piste. Nous voyons immédiatement que notre chère master key se trouve dans la variable struct luks_masterkey *mk. Pour info :

struct luks_masterkey {
	size_t keyLength;
	char key[];
};

La fonction __crypt_luks_open() fait appel à LUKS_open_any_key() (dans luks/keymanage.c) qui se charge d'énumérer les slots de clé associés à une partition (il est possible de stocker LUKS_NUMKEYS = 8 versions chiffrées avec une passphrase de la clé sur chaque partition) et de débloquer la master key le cas échéant (son checksum étant stocké dans l'en-tête de la partition, cf specs pour les détails). Elle passe ensuite la main à son backend DM-Crypt qui se chargera d'effectuer les opérations de chiffrement de façon transparente.

Bref, pour récupérer la clé, il suffit de poser un printf dans __crypt_luks_open() entre LUKS_open_any_key() et LUKS_dealloc_masterkey(mk). On note au passage l'appel à safe_free(password) pointant vers un rassurant memset(data, 0, n) qui explique le pourquoi du paragraphe 2 :) Une fois la main passée à DM-Crypt, la clé est elle aussi shredée de la mémoire par la fonction LUKS_dealloc_masterkey(). Ce qu'on va trouver dans le dump c'est donc la clé stockée par le composant DM-Crypt du noyau :

$ find /usr/src/linux -name '*dm-crypt*'
/usr/src/drivers/md/dm-crypt.c
$ cat /usr/src/drivers/md/dm-crypt.c
[...]
struct crypt_config {
[...]
u8 key[0];
[...]

OK donc maintenant j'ai la master key de la partition qui s'affiche au démarrage :

Dump LUKS master key

On va donc pouvoir regarder comment la récupérer dans le dump. Déjà, notre mk étant connue, on peut écrire un petit prog pour parcourir un fichier de dump et voir à peu près où elle se trouve en mémoire, histoire de faire connaissance :

$ ./searchknownluksmk ramdump
[sylv1] Found LUKS key at offset 922802228
[sylv1] Found LUKS key at offset 922802692
[sylv1] Found LUKS key at offset 923103124
[sylv1] Found LUKS key at offset 923138452
[sylv1] Found LUKS key at offset 923608116
[sylv1] Found LUKS key at offset 923608580

Surprise, la clé est présente à plusieurs endroits :) Raisonnons maintenant dans le "bon" sens et cherchons à déterminer une signature dans le dump permettant de retrouver la clé. Bon, là j'avoue que je me suis pas cassé la tête : j'ai juste remarqué que la clé était présente à l'offset 0x8c après la signature "aes\x00aes)". Je n'ai aucune idée si c'est générique ou spécifique à mon système (si quelqu'un peut tester, je suis preneur, surtout que ça ne correspond pas exactement à ce que d'autres ont trouvé avant moi) :

Signature to LUKS key

En tout cas, cela nous donne le petit programme fourni en annexe pour retrouver une master key AES-256 (pour être plus générique sur la taille, on peut aller chercher les infos dans l'en-tête LUKS de la partition, mais là j'ai pas le temps :).

$ ./searchluksmk ramdump
[sylv1] Found sig at 0xa56f08, LUKS master key is:
0123ABCD...

Une fois la clé connue, il suffit de modifier la source de cryptsetup pour forcer l'utilisation de cette master key lors de l'ouverture du périphérique (toujours dans __crypt_luks_open()) :

A partir du dump mémoire, on récupère ainsi la main sur le filesystem sans connaître la passphrase :

# cryptsetup luksOpen /dev/sda8 ineednopass
Enter LUKS passphrase: *simple appui sur entree*
[sylv1] Forcing master key to 0123ABCD....
Command successful.
# mount /dev/mapper/ineednopass /mnt/test
# ls /mnt/test
bin   dev  home  lost+found  mnt  proc  sbin  tmp  var
boot  etc  lib   media       opt  root  sys   usr
# echo gagné :)
gagné :)

Petite remarque au passage : si vous n'utilisez pas le mode "clé chiffrée en gpg sur périphérique usb avec passphrase", votre partition /boot reste en clair, ce qui permet donc à votre voisin de rooter votre bécane en patchant le noyau et/ou votre initramfs pendant que vous avez le dos tourné.

Source : searchluksmk.c

Posté par sylv1 le 10/09/2008 à 00:11:22
2 commentaires

Le contenu du blog est publié sous la licence CC-BY-SA.

[ Site créé par Sylvain Sarméjeanne ]
Cette page a été générée par mes scripts en 0.048 secondes :)
[Valid XHTML 1.1!] [Valid CSS!] [[Valid RSS]]