Des trucs qu'on fait au boulot ... ou pas :-D

Aller au contenu | Aller au menu | Aller à la recherche

3 mars 2014

Développeur d'applications mobiles - iOS vs Android

Ca fait maintenant près de trois ans que je m'intéresse à la programmation sur mobile. J'ai commencé avec mon iPhone et je viens de migrer vers Androïd. Les deux plateformes ont chacune à leurs particularités et leurs atouts qui font que j'aurais du mal de dire avec laquelle je préfère travailler ...

Lire la suite...

9 février 2014

Implémenter un visitor

J'ai récemment dû implémenter un (web) service de consultation où l'utilisateur pouvait spécifier un filtre d'affichage en combinant des critères pas forcément connus lors de l'écriture du code. Il me fallait donc une grammaire pour représenter textuellement ce filtre, et un mécanisme pour l'exploiter (i.e. savoir si une donnée doit ou non être affichée lorsque ce filtre est utilisé). Après quelques recherches, je me suis décidé pour une version maison du langage de requête ldap (facile à écrire ou à générer et surtout facile à analyser). J'ai définit quelque classes, écrit un parseur qui me construit un arbre constitué de deux types de noeuds: les tests (=, <, >) et les relations (&, |, !) mais comment j'exploite tout çà pour filtrer? J'utilise un design pattern bien sûr!

Lire la suite...

21 janvier 2014

Mon nouveau téléphone

Après 3 ans de bons et loyaux services, mon iPhone 4 a commencé à montrer ses limites face à l'IOS 7 (même si la release 7.0.4 a redonné une bouffée d'oxygène grâce notamment à la modification des animations de lancement et de passage en arrière-plan des applications). Il était donc temps de changer. Deux possibilités s'offraient alors à moi: la voie du coeur, avec l'iPhone 5S, ce qui me permettait de conserver mes paramétrages (contacts, ...) ainsi que mes applications (surtout celles que j'ai achetées!) et la voie de la raison, le Nexus 5 de Google, qui poutre tous les autres mobiles android du marché par son rapport qualité/prix (je ne sais d'ailleurs même pas comment il peut encore y avoir une quelconque concurrence sur ce marché ?!?) Il est bien évidemment incohérent de comparer deux modèles ayant presque 4 ans d'écart, je vais donc me contenter de présenter de manière (plus ou moins ^^) objective mon nouveau bigo et dresser un bilan après une dizaine de jours d'utilisation.

Lire la suite...

30 octobre 2013

Les inconvénients du closed-source

L'objective-c possède un écosystème restreint et une syntaxe très particulière, ce qui le rend moins accessible que les autres langages objets populaires (java, c++, ...), mais une fois qu'on s'y est mis pour de vrai, c'est un langage vraiment sympa. Il a cependant un défaut de taille quand on est habitué à travailler avec des produits open-source ... c'est justement l'absence des sources! Le sdk est bien documenté mais quand on est confronté à un bug ou à une chelouserie d'implémentation, c'est la galère. Exemple!

Lire la suite...

21 octobre 2013

Activer la compression chez 1and1

En vérifiant le performances de mon blog (détail ici), j'ai constaté qu'un des gros problèmes était la non compression des ressources (js, css, ...). Ca augmente la bande passante et donc le temps de chargement depuis le serveur. Le problème c'est que le module deflate n'est pas dispo en hébergement mutualisé. En bidouillant un peu, on peu cependant contourner le problème d'au moins 2 façons: la mauvaise et la mienne :-p

Lire la suite...

24 septembre 2013

Lister les modules Apache de son hébérgeur

L'hébérgement mutualisé est pratique, peu onéreux (à partir d'une trentaine d'euros par an) et facile d'utilisation pour le n00b. Par contre, pour les personnes plus expérimentées, il montre vite ses limites: pas d'accès ssh, espace disque limité, un seul accès ftp, ... et au niveau configuration, on n'a pas énormément de moyens pour agir (même si 1&1 permet de personnaliser en grande partie le php.ini). Quoique ...

Lire la suite...

6 août 2013

Optimisation du blog

Je me suis récemment intéréssé au SEO et la première étape d'un bon référencement, c'est un site conforme aux standard et optimisé. J'ai donc passé mon blog dans YSlow et Page Speed. Les résultats ne sont pas mauvais mais y'a moyen de corriger facilement un grand nombre des "problèmes" relevés ...

Lire la suite...

31 juillet 2013

Tableau postgres et Hibernate

J'ai eu récemment à travailler sur l'optimisation d'une grosse requête hql qui effectuait de nombreuses jointures pour récupérer toutes les infos requises. Du coup, le nombre de lignes renvoyées au niveau de la base de données explosait porvoquant de sérieux problèmes de performance. J'entends déjà venir au galop l'inévitable « c'est un problème de conception ». Sans doutes mais ne pouvant tout refactorer, j'ai dû trouver une solution rapide et efficace.

Lire la suite...

24 juillet 2013

Installer un SSD dans son MacBook Pro

Je n'ai pas pu avoir la version SSD lors de l'achat ... mais il n'est jamais trop tard pour bien faire :-). Ayant fait l'acquisition d'un Crucial M4 qui semble être LA référence qualité-prix, j'ai dû démonter pour la première fois mon MacBook ... en voici un résumé en image.

Lire la suite...

18 juillet 2013

Implémenter un Singleton

J'ai eu ma période Singleton. J'en utilisait un peu partout, pas forcément toujours à bon escient (singleton = globale et les globales, c'est le mal). Ça m'est passé (en particulier à cause de l'utilisation fréquente de l'IOC dans mes projets) mais j'ai encore ponctuellement besoin d'en implémenter. C'est là que j'ai découvert que mon implémentation était toute moisie ...

Lire la suite...

15 juillet 2013

Implémenter une Factory

Le design pattern factory n'est pas très compliqué mais quand on n'en a jamais écrit une implémentation, ca peut être un poil compliqué de savoir comment démarrer. Je vais vous proposer plusieurs recettes pour passer d'une version basique (donc dangereuse) à une version toute "automatique" ...

Lire la suite...

11 juillet 2013

Debug sous Eclipse d'une webapp sur un Tomcat distant

Tout est dans le titre ^^

Lire la suite...

10 juillet 2013

Apache sous MacOS

Apache est livré en standard sous MacOS mais quand j'ai voulu l'utiliser pour mes dév locaux, galère! Après quelques recherches et moultes tentatives, j'ai quand même réussi à m'en sortir ^^ J'ai commencé mon billet en 10.7 (Lion) et je l'ai fini en 10.8 (Mountain Lion), j'ai donc détaillés les différences.

Lire la suite...

8 juillet 2013

Programmation dynamique

En faisant un peu de veille techno sur html5, je suis tombé sur EaselJS, un framework pour développer des animations autour des canvas. C'est la librairie qui a été choisie par Adobe pour exporter du flash en html5. Du coup, j'ai étudié un peu le source et je suis tombé sur quelque chose d'intéressant ...

Lire la suite...

29 juin 2013

LessCss

C'est l'été, j'ai décidé de changer de thème de blog \0/. L'ancien était un peu tristounet et surtout s'affichait assez mal sur les tablettes du fait de sa taille fixe. Après avoir fait (en vain) quelques recherches pour un thème sympa et original, et ne voulant pas payer pour un habillage, je me suis décidé à en faire un moi-même ....

Lire la suite...

19 juin 2013

The message loop

Un développeur web de mon équipe, peu habitué à la programmation « client lourd » m'a récemment demandé pourquoi son application java swt se lançait, affichait sa fenêtre et se terminait aussitôt apparemment sans erreur. Tout lui semblait correct, ca compilait sans erreur ni warning alors pourquoi ?!? Tout simplement parce qu'il manquait le coeur de système: la boucle de traitement des messages.

Lire la suite...

28 février 2013

Brute force

Pour cracker un mot de passe, la technique la plus simple (et généralement celle de la dernière chance ^^), c'est la force brute: essayer toutes les possibilités, une par une. Mais pour cela il faut pouvoir générer ces possibilités :-) Un outil comme hashcat sait le faire alors pourquoi pas nous ;-)

Lire la suite...

30 novembre 2012

Rooter sa Nexus 7

Avouons-le, la dernière tablette de Google déchire, tant par son prix que par ses fonctionnalités. Mais en bon possesseur d'iPhone jailbreaké, je me suis vite trouvé limité dans les fonctionnalités de personnalisation, par exemple dans les fonctions de nettoyage (suppression des stock applications, ...). J'ai donc fait des recherches sur la technique qu'on appelle rooting.

Il y a deux méthodes pour rooter la tablette de Google, le one-click avec interface graphique (windows only :-@) et le mode ligne de commande pour le bidouilleur averti et/ou l'heureux possesseur d'un mac. Va pour la seconde méthode ;-)

Lire la suite...

3 septembre 2012

Stripe CTF - Level 4

Ce niveau propose un système d'échange de points de karma. Chaque utilisateur du système peut transférer des points à n'importe quel autre utilisateur, lui révelant ainsi son mot de passe. Le but est donc de force l'utilisateur karma_fountain à nous faire un virement « à l'insu de son plein gré » afin d'obtenir son mot de passe et donc l'accès au niveau 5.

Analyse

De mieux en mieux, après python, on a droit à du ruby. Heureusement, là encore, pas besoin d'ue connaissance approfondie du langage pour comprendre le code ... en espérant que la faille ne vienne pas du code justement ^^.

Cette fois, les requêtes sql sont générées par une api, peu de chances donc de trouver une injection sql :'( mais comme le niveau précédent, aucune vérification ni de contenu, ni de longueur, n'est effectuée sur le nom d'utilisateur ou le mot de passe, ce dernier étant affiché sur la page des transferts. Donc si j'envoie du karma à l'utilisateur karma_fountain, je vais lui dévoiler mon mot de passe et provoquer son "affichage" lorsqu'il va se connecter. L'explication du niveau dit d'ailleurs que karma_fountain est « très actif ».

Solution

Le mot de passe étant libre, on peut donc y mettre ce qu'on veut, y compris du code javascript. Quand le navigateur affiche la page des transferts, le script contenu dans le mot de passe est alors exécuté! C'est du Cross-site request forgery, du code exécuté par d'autres utilisateurs (et donc au sein de leur session) mais à leur insu. J'avais déjà lu pas mal de trucs sur le sujet mais je n'ai jamais mis en oeuvre ce type d'attaque.

Première tentative

J'ai fait une première tentative en créant deux utilisateurs: bob et alice. Pour alice, j'utilise le mot de passe suivant:

<script type="text/javascript">alert('pwned!');</script>

Je me connecte en tant qu'alice, et j'envoie du karma à bob. Je me reconnecte ensuite en tant que bob, et quand j'affiche les transferts, le mot de passe d'alice « s'affiche » mais comme c'est du code javascript, il s'exécute et j'obtiens une boîte de dialogue qui m'affiche 'pwned'.

Maintenant, il faut trouver un moyen pour que karma_fountain nous donne du karma.

Deuxième tentative

En regardant le template layout.erb, on s'aperçoit que la page embarque la librairie jQuery \0/ Or pour faire un transfert, il suffit d'envoyer une requête post avec comme arguments le login de l'utilisateur de destination et le montant du karma à transferer.

Je vais donc créer un utilisateur charlie avec le mot de passe:

<script type="text/javascript">$.post("/user-tehgzcujoc/transfer",{to:"charlie",amount:"42"});</script>

Je me connecte en tant que charlie, j'envoie du karma à karma_fountain et j'attends ... quelques F5 plus tard, je reçois un transfert de karma_fountain et donc son mdp :-)

31 août 2012

Stripe CTF - Level 3

Ce niveau est une amélioration du coffre-fort du niveau 0. Cette fois, il est unbreakable ... ou presque ^^ Il suffit en fait faire croire au système que l'on est bob (en s'authentifiant comme tel) pour obtenir son secret (le mot de passe du niveau 4).

Analyse

Le niveau est écrit en python, langage à la syntaxe très particulière pour les c-istes ou les java-istes (dont je fais partie), mais assez explicite pour être facilement compris par eux.

Le code de traitement de la requête /login, puisque c'est le plus intéressant, est assez standard: recherche de l'utilisateur par son username, hashage du mot de passe fourni (pour éviter de conserver des mdp en clair) et comparaison à la valeur stockée en base. Le hash est calculé avec du SHA256.

La requête de recherche ne souffre pas du même problème qu'au niveau 0 mais en y regardant de plus près, le remplacement de {0} par le nom d'utilisateur est effectué avec un simple format, qui après vérification n'effectue aucun traitement sur la donnée (protection des quotes par exemple). Voilà donc un point d'entrée potentiel, une injection sql!

Solution

Je me suis donc attelé à trouver un moyen de détourner la requête initiale:

SELECT id, password_hash, salt FROM users WHERE username = '{0}' LIMIT 1

La partie ennuyeuse est l'utilisation de LIMIT 1 dans la requête, et de la méthode fetchOne pour récupérer le résultat. Ansi seul l'enregistrement correspondant au username utilisé dans la clause WHERE est retourné. Mais comme le contenu du username saisi n'est pas vérifié et qu'il est injecté directement, une valeur telle que "bob' --" donnerait la requête:

SELECT id, password_hash, salt FROM users WHERE username = 'bob' -- LIMIT 1

L'utilisation du commentaire sql (--) a neutralisé la clause de limitation \0/. Maintenant on va modifier la requête pour qu'elle retourne les valeurs qui nous intéressent.

Il faut que le hash stocké en base corresponde au hash du couple mot de passe, [sel] lui aussi stocké en base (et inconnu de nous):

calculated_hash = hashlib.sha256(password + salt)
if calculated_hash.hexdigest() != password_hash:
    return "That's not the password for {0}!\n".format(username)

Choisissons un mot de passe: password fera l'affaire. Si on arrive à "prédire" la valeur du sel, on peut alors calculer le hash du mot de passe comme le ferait le serveur. Et si on arrive à lui donner cette valeur pour effectuer la comparaison, on a réussi!

On calcule le hash256 de 'password' + 'salt' (valeur arbitraire choisie comme sel), on utilise pour cela un shell python:

hashlib.sha256("password"+"salt").hexdigest();
# -> 7a37b85c8918eac19a9089c0fa5a2ab4dce3f90528dcdeec108b23ddf3607b99

Ensuite, on modifie le résultat de la requête sql avec une union pour ajouter nos données et une clause order by pour modifier l'ordre de retour. Pour l'id, on fait un peu de divination et/ou de brute force (en commencant à 1). Ça nous donne (le formatage du code d'injection ne servant qu'à la mise en page):

bob' UNION SELECT 1,
'7a37b85c8918eac19a9089c0fa5a2ab4dce3f90528dcdeec108b23ddf3607b99',
'salt' ORDER BY id ASC; --

et la requête complète:

SELECT id, password_hash, salt FROM users WHERE username = 'bob'
UNION
SELECT 1, '7a37b85c89[...]07b99', 'salt'
ORDER BY id ASC;
--  LIMIT 1

Ainsi, on récupère deux résultats mais l'order by les remet dans le bon ordre (le notre en premier). La fonction fetchOne ne va récupérer que le premier, donc celui avec les valeurs qui vont bien. Il ne reste qu'à nous connecter avec l'injection sql comme username et password en mot de passe ... et paf, l'authentification réussi mais avec le mauvais compte. Normal, on avait une incertitude sur l'id de bob. Un second essai avec l'id 2 nous donne le sésame.

Pour éviter ce problème de devinage d'id, on utilise une sous-requête

SELECT id, password_hash, salt FROM users WHERE username = 'bob'
UNION
SELECT (SELECT id FROM users WHERE username = 'bob'), '7a37b85c89[...]07b99', 'salt'
ORDER BY id ASC;
--  LIMIT 1

En lisant d'autres solutions sur le net, je suis tombé sur ce blog qui proposait:

' and 1=0 union all select (select id from users where username='bob'),
'd74ff0ee8da3b9806b18c877dbf29bbde50b5bd8e4dad7a3a725000feb82e8f1',
'' -- enter this as username and "pass" as password

Cette solution est plus élégante puisqu'elle élimine complètement le premier résultat (avec le test 0=1) pour ne laisser que les données qui vont bien pour l'authent.

Next Level!

- page 1 de 5