mardi 28 août 2012

Java CVE-2012-4681

Le dernier 0day à la mode touche toutes les versions 7 de java. Ce bug a une histoire intéressante. Je propose une analyse rapide de celui-ci.

UPDATE: un patch officiel est finalement sorti http://www.oracle.com/technetwork/topics/security/alert-cve-2012-4681-1835715.html

1/ La découverte
J'ai pris connaissance de ce bug via le blog de fireeye et un mail sur full-disclosure. Il est fait mention d'une attaque touchant tous les OS, tous les navigateurs supportant la version 7 de java, ce qui semble intéressant en soi.

2/ Un peu de technique
L'article de fireeye aidé d'un autre blog m'ont permis de remonter à la source de l'infection. Il s'agit d'une page web  http://ok.aa24.net/meeting/index.html (le nom résoud aujourd'hui vers 127.0.0.1).
La page web est constitué d'un script unique, sans aucune autre balise HTML laissant entendre que l'attaque est le fait d'un XSS, et est très obscurci:
La partie surlignée indique l'usage de Dadong JSXX 0.44. Il n'existe que peu d'informations sur cette lib de camouflage.
On trouve également plusieurs calculs mathématiques, meSjBJF7=Math.PI;sRjYnQL3=Math.tan; qui paraît il donnent du mal aux analyseurs antivirus car ils embarquent un moteur javascript, mais qui sont généralement incomplet, surtout sur les aspects mathématiques. Est-ce une méthode de protection supplémentaire?

Pour Dadong, il est à peu près impossible de décoder facilement le script. Un chercheur donne des pistes dans un article de blog. Pour pouvoir remplacer la fonction eval() par alert() il est obligatoire d'intuiter le chiffrement ce qui ne se fait pas sans effort.

Après décorticage, le but de ce script consiste à télécharger un binaire windows et une applet java, nommée avec un certain esprit d'à-propos "applet.jar". Le binaire windows est un simple dropper de RAT, je laisse ce point de côté (surtout que c'est le point le plus discuté sur les différents sites traitant du sujet). L'applet elle, est plus intéressant:
$ file applet.jar
applet.jar: Zip archive data, at least v1.0 to extract
$ unzip applet.jar
cve2012xxxx/
cve2012xxxx/Gondvv.class
cve2012xxxx/Gondzz.class

La présence de l'année 2012 dans le jar pourrait signifier d'une part que l'exploit date de cette année, et d'autre part que l'auteur savait qu'il serait découvert et référencé dans la base CVE avant la fin de l'année!

3/ La faille
En lisant différents codes d'exploit comme par exemple celui de pastie, on découvre la faille. Une fonction appelée judicieusement disableSecurity permet d'exécuter du code natif sans aucune restriction!
Comme lu sur un blog, cela ressemble à du code java standard, car ... c'est du code java standard! Et on comprend mieux l'étendue du désastre: toute machine sachant faire fonctionner est de facto vulnérable à cette faille, aussi bien linux, que mac, que Chrome ou Firefox. Ce n'est pas une histoire d'implémentation, ce n'est pas un bug, c'est une feature! (feature involontaire, mais feature tout de même)


Pour résumer: l'applet crée un contexte avec fullprivilege, sans SecurityManager (surprenant, mais rien d'anormal à ce niveau) et l'appelle. Logiquement java devrait réagir en l'interdisant (ce qui est le cas de java6) mais java7 l'autorise! Apparemment, un problème lors de la vérification des droits existe ce qui permet cette opération. L'auteur de la faille se retrouve donc directement dans un java sans aucune restriction et peut donc exécuter du code natif (le PoC donné sur pastie.org lance la calculatrice windows [1]).

EDIT 29/08: une très bonne explication sur le site d'immunity: http://immunityproducts.blogspot.fr/2012/08/java-0day-analysis-cve-2012-4681.html

4/ La déférlante
Le lendemain de la première publication (le 27 Août), metasploit a décidé de sortir un module fonctionnel. Et rapidement pour ceux qui doutaient encore on a eu la confirmation qu'il s'agit bien d'un bug java, toutes versions d'OS/navigateurs confondus puisque des confirmations de succès ont été lues. La démo en est très simple, cf ce post de blog.
Un second problème concerne la politique de mise à jour d'Oracle pour Java. On peut lire que le prochain cycle de patch ne sera pas lancé avant mi-octobre (!). Certains bloggeurs estiment qu'on aura droit pour une fois à un patch out-of-band.

Actuellement, un correctif toutà fait officieux est disponible sur le site de http://www.deependresearch.org/2012/08/java-7-0-day-vulnerability-information.html . Ce patch n'est toutefois pas librement téléchargeable (uniquement sur demande motivée par mail). Ils ne sont pas diffuseurs java et ne veulent prendre aucun risque sur l'usage de ce correctif.
Leur correctif (assez court) patche java/com/sun/beans/finder, en modifiant plusieurs fois:
return Class.forName(name, false, loader);
en
return checkAccess(Class.forName(name, false, loader));
et cette fonction checkAccess contient le commentaire suivant:
/**
* Check if the class may be accessed from the current access control
* context. If not, throw a {@link SecurityException}.
*
* @param clazz
*            Class to check
* @return the checked class
*/
Ce qui semble donner le comportement voulu.

5/ Et maintenant
Nous avons donc aujourd'hui un 0day dans la nature, très très facilement exploitable via metasploit sans autre solution que de désactiver java en attendant le bon vouloir d'Oracle pour produire un patch.

[1] comme lu sur un site web: "The PoC you sent me doesn't work, it only launch calc.exe" :-)

jeudi 23 août 2012

Sécurisé? Eh bien non.

Je lisais sur une mailing list qu'un gros problème en crypto, c'est qu'en cas de problème, cela fonctionne tout de même! C'est juste non sécurisé, mais personne ne s'en rend compte...

Étudiant en ce moment le chiffrement de disque sous linux, je propose un petit exercice pour s'en rendre compte. Sous linux, on utilise le frontend cryptsetup pour gérer la couche crypto:

# cryptsetup luksOpen /dev/sdb1 ciphered_sdb1
et la commande demande un mot de passe. S'il est correct, alors la clé maître de chiffrement du volume est libérée, permettant la lecture des données.

La documentation précise que l'on peut passer ce mot de passe via un pipe | unix, comme par exemple:
# echo $MDP | cryptsetup luksOpen /dev/sdb1 ciphered_sdb1
ou bien
# cat randomfile | cryptsetup luksOpen /dev/sdb1 ciphered_sdb1

Imaginons donc un setup qui va extraire un certain nombre d'octets depuis /dev/random et qui va s'en servir comme clé de chiffrement.

Ce setup n'offre qu'une faible garantie contre une attaque bruteforce!

La raison en est simple et est précisée dans la fin du man cryptsetup. En effet, le passage de données via un pipe s'arrête dès le premier \n rencontré. Ce qui signifie que si dans les premiers caractères du fichier un \n est présent, alors la force de la clé est simplement équivalente au nombre de caractères précédent le \n! Démonstration:

Tout d'abord génération d'un fichier aléatoire tiré depuis /dev/random et utilisation de celui-ci pour formater une partition luks:
root@slack:~# dd if=/dev/random of=rnd bs=16 count=1
0+1 enregistrements lus
0+1 enregistrements écrits
16 octets (16 B) copiés, 0,00016936 s, 94,5 kB/s
root@slack:~# cat rnd | cryptsetup luksFormat /dev/loop0
root@slack:~# cat rnd | cryptsetup luksOpen /dev/loop0 ciphered
root@slack:~# cryptsetup luksClose /dev/mapper/ciphered

A première vue, le setup semble correct: tout d'abord, la clé est tirée depuis un générateur de hasard correct. Ensuite, la clé fait 16 octets ce qui est suffisant pour contrer les bruteforce. On a vérifié que tout fonctionne, le volume peut s'ouvrir si on dispose bien du fichier de clé.

Mais il se trouve que la force de la clé est beaucoup plus faible que 16 octets! (et dû également à un certain nombre d'essai successifs de ma part pour obtenir un rnd voulu :) )

root@slack:~# hexdump rnd
00000000  ca 41 71 0a 51 ba 56 55  f7 13 fb d9 94 0e 5c 2f
00000010
root@slack:~# printf '\xca\x41\x71' > loose
root@slack:~# cat loose | cryptsetup luksOpen /dev/loop0 ciphered
root@slack:~# ls -l /dev/mapper/ciphered
lrwxrwxrwx 1 root root 7 août  23 21:19 /dev/mapper/ciphered -> ../dm-0
root@slack:~#

On constate que le fichier contient un 0a en 4e position, et que le volume s'ouvre uniquement avec la connaissance des trois précédents. Le système n'est donc absolument pas sécurisé malgré ce qu'il laissait imaginer puisqu'il est vulnérable à une attaque bruteforce. Pour éviter ce problème il faudrait s'assurer de ne jamais avoir de \n dans son fichier (ou d'utiliser l'option --key-file qui n'a pas ce problème, se référer à la page man partie: NOTES ON PASSWORD PROCESSING).

Comme indiqué en introduction il ne s'agit pas d'une attaque ou d'un scoop particulier, le but de cet article est simplement de montrer qu'un setup crypto qui fonctionne et qui paraît fiable ne l'est pas du tout.