| Conférences

Baptiste, pentesteur dans la Bu Sécurité Offensive & Défensive, a eu l’occasion de participer aux conférences d’Insomni’Hack, qui se sont tenues à Genève en mars dernier, il nous livre son point de vue :


Une des conférence de cette année **Redesigning Open Source Ransomware**  par Raul Alvarez (Fortinet) a été remplacée par une conférence sur la sécurité des vélos connectés du parc de Zurich.

Celle-ci est nommée **On the security of bike sharing services** par Antoine Neuenschwander – @ant0inet (les slides sont présents à cette adresse https://www.slideshare.net/AntoineNeuenschwande/on-the-security-of-dockless-bike-sharing-services) et a déjà été présentée à la a41con de 2018.


La conférence a débuté par une courte introduction sur les différents systèmes de vélos connectés présent au cours des dernières années :

– Smide apparu en octobre 2016
– OBike en juillet 2017
– LimeBike début 2018
– PubliBike en mail 2018

Tous ces vélos connectés ont pour but d’être loués via smartphone (ou via une borne d’accès), de faciliter le déplacement des utilisateurs ainsi que favoriser l’utilisation des moyens de transports non polluants.

Néanmoins, lors de la mise en place d’un tel système, plusieurs questions se posent :

N’y a-t-il pas de problème de sécurités dans le moyen de paiement ?
– Est-ce qu’un utilisateur du service ne peut pas agir sur le compte d’un utilisateur ?
– Peut-on bloquer un vélo en cours d’utilisation (soulève des problèmes de sécurités encore plus importants)
– L’accès aux données est-il sécurisé ? (RGPD)

En plus de tous les risques de sécurité s’ajoutent d’autres problèmes annexes : que faire si un vélo disparaît / amende RGPD / perte de réputation…


**Smide**

Suite à cette introduction, on commence par une démonstration d’une vulnérabilité sur le système le plus ancien : **Smide**.

Celui-ci propose un système de pause : si l’utilisateur du vélo s’arrête, par exemple pour faire ses courses, il peut verrouiller le vélo tout en gardant le lien entre l’utilisateur et le vélo. Il peut ainsi déverrouiller et repartir avec le vélo sans avoir à en trouver un autre.

L’appel à l’api de Smide pour verrouiller un vélo fonctionne de la manière suivante :

Notez ici que la requête inclue l’utilisation d’un token JWT authentifiant l’utilisateur.

Maintenant, voici un exemple de requête sur le même vélo mais avec un token JWT différent ne possédant pas le vélo :

On remarque que l’api nous renvoie un code 200 indiquant que le verrouillage c’est bien déroulé.
On peut donc verrouiller tous les vélos du parc sans vérification de la part de l’api distante !

A partir de là, on peut soit réaliser un bruteforce sur tous les id ou bien récupérer les id des vélos autours de nous à l’aide de l’api :

En bonus, Antoine Neuenschwander nous confie qu’il a touché un bounty de 100 minutes gratuites sur l’application : une affaire !


**oBike**

On passe maintenant à **oBike**, celui-ci fonctionne en Bluetooth entre le smartphone de l’utilisateur et le vélo.
Voici le schéma présent dans les slides de la présentation afin de mieux comprendre les différentes interactions entre l’api, le smartphone et le vélo :

Ici, c’est le tracking des vélos qui va poser problème. En effet, ce sont les utilisateurs qui donnent la position de leur vélo et comme le montre l’image suivante, un utilisateur peut donner la position d’un vélo à l’api et celle-ci va l’enregistrer en tant que position actuelle ! Ce qui mène à des comportements assez absurdes :

On voit que le vélo à été “déplacé” à Singapour, ce qui à pour effet de renvoyer une réponse dans une autre langue que celle de l’utilisateur. On peut bien sûr faire cette requête sur n’importe quel vélo (possédé ou non) et déplacer tout le parc de vélo en Antarctique !

Il décide ensuite de nous présenter une vulnérabilité encore plus intéressante sur le système **oBike**.
Celui-ci fonctionnant en BLE, il nécessite une puce Bluetooth ainsi qu’un microcontrôleur. La clé de chiffrement utilisée dans l’api est une clé AES et, est donc présente dans le microcontrôleur.
AES étant un chiffrement symétrique, il est donc possible de déchiffrer les requêtes, de les modifier et de les réinjecter (tout ce système fonctionne à distance).

Lors d’une liquidation d’équipement oBike, Antoine Neuenschwander achète un des verrous et code son propre système d’interaction avec le verrou du oBike. S’ensuit alors une démonstration sur scène du déverrouillage du oBike (verrou qu’il avait apporté spécialement pour l’occasion) qui fonctionne à merveille !

Pour finir, une dernière vulnérabilité plus marginale mais néanmoins intéressante :

Le schéma ci-dessus représente le système de verrouillage du vélo, on voit ici que si la dernière requête n’est pas effectuée le vélo est déverrouillé mais l’utilisateur ne sera pas facturé.
Malheureusement, le requête n’ayant pas abouti, le vélo se verrouille de nouveau et il est mis dans un état “need to be fix”, on peut donc DoS tous les vélos du parc !

Antoine Neuenschwander conclue sur des recommandations générales sur les équipements connectés :

– Think about what could go wrong. Which risk are you willing to accept ?
– Perform a security audits. get rid of the low hanging fruits
– Flaws will be found, keys will be leaked… make the devices fixable


Mon conseil : Avec ces nouveaux moyens de transports connectés tel que les vélos ou les trottinettes que l’on voit de plus en plus dans les grandes villes, faites attention ! Si le même genre de vulnérabilités est présente, vous risquez de vous faire voler votre compte ou même de vous faire bloquer votre moyen de transport à distance !


CTF phuck3

Ce challenge n’a été résolu par aucune équipe pendant le CTF mais j’ai continué à travailler dessus car il me semblait intéressant .

Le challenge se présente de la manière suivante :

On remarque qu’on peux exécuter du code via le paramètre “eval”.
On peux alors vérifier l’environnement dans lequel on se trouve : phuck3/?eval=phpinfo();

Hum, un PHP 7… Quelles sont les fonctions non-autorisées ?

Outch ! Toutes les fonctions d’exécution de script sont désactivées…
On peut noter que les fonctions mail() et imap_open() sont désactivées.
En effet, la fonction mail est connue pour permettre d’exécuter du code via un LD_PRELOAD et la fonction imap_open est aussi vulnérable comme le montre ce blog post récent (décembre 2018) https://www.netsparker.com/blog/web-security/bypass-disabled-system-functions/

Il semblerai donc que nous ayons à faire à un nouveau bypass de disable_functions !
En regardant la liste, on s’aperçoit que file_get_content() est disponible, on peut donc tenter de faire directement un file_get_content(‘/flag’).

N’oublions pas le stripslashes() présent dans le script, celui-ci ne nous permet pas de mettre des ‘ ou des “, nous allons donc devoir trouver un autre moyen.

La fonction base64_decode() vient à notre rescousse et on fini avec notre payload :
phuck3/?eval=print_r(file_get_contents(base64_decode(L2ZsYWc)));

Et la… rien. Le script ne retourne rien… On active les erreurs et … :
“`
eval=ini_set(display_errors, 1);
ini_set(display_startup_errors, 1);
error_reporting(E_ALL);
print_r(file_get_contents(base64_decode(L2ZsYWc)));
“`

Malheurs ! La directive open_basedir est en place sur le répertoire  “/var/www/html”.

A partir d’ici, j’ai testé pas mal de fonctions différentes pour obtenir un shell mais sans succès.

A la fin du CTF, j’ai discuté avec une personne d’une autre équipe qui avait passé tout le CTF sur ce challenge sans succès non plus et il m’a indiqué que le créateur du challenge lui avait parlé d’un bypass d’open_basedir().

Curieux, je me suis donc rapproché du créateur sur Twitter et il m’a appris que la fonction open_basedir() avait un souci : on peut la redéfinir tant que l’on n’est pas moins restrictif que le chemin de base

Quel est l’intérêt d’augmenter encore plus la restriction mise en place ?

Il y a un cas qui n’est pas vérifié par PHP, on peut tenter de se déplacer dans un répertoire plus bas et de définir open_basedir au répertoire du dessus : on respecte alors bien la règle qui stipule que le chemin ne doit pas être moins restrictif que la valeur actuelle.
Ce qui donne :
?eval=chdir(‘img’);open_basedir(‘..’)

On tente et la : aucune erreur.
Nous avons bien réussi à remplacer la valeur d’open_basedir par ‘..’ !
A partir de la, il suffit juste de chdir(‘..’) jusqu’à la racine et de file_get_content(flag) :
“`
?eval=ini_set(display_errors, 1);
ini_set(display_startup_errors, 1);
error_reporting(E_ALL);
chdir(base64_decode(aW1n));
ini_set(open_basedir, base64_decode(Li4));
chdir(base64_decode(Li4));
chdir(base64_decode(Li4));
chdir(base64_decode(Li4));
chdir(base64_decode(Li4));
ini_set(open_basedir, base64_decode(Lw));
print_r(getcwd());
print_r(file_get_contents(flag));
“`


Et voilà !