P0pR0cK5's Blog

Pentest, Challenges, Tests and more ...

View on GitHub

Hydrabus, for rule them all ?!

Retour

cover.jpg

Étant en quête d’un outil universel pour travailler sur du hacking hardware, je suis tombé sur une première carte que je possède maintenant depuis 3 ans, le Bus Pirate de chez dangerous prototype.

La carte est certes bien conçue mais elle n’apporte pas autant de fonctionnalités que je l’aurais souhaité avec quelques limitations techniques en prime.

L’objectif ici est d’avoir une carte tout en un, permettant de tester toutes sortes de protocoles tel que l’I2C et le SPI

En cherchant un peu j’ai découvert deux nouvelles cartes: le greatFET et l’Hydrabus. Ces cartes offrent un panel de fonctionnalités important et complètement différent du Bus Pirate.

Le greatFET offre un gros panel de fonctions coté USB en permettant notamment d’émuler des périphériques HID ou bien simplement du stockage à partir d’un image disque. Néanmoins, les protocoles plus classiques ne sont pas documenté les mettant en retrait du reste.

L’Hydrabus par contre n’offre pas de fonctions USB mais un large panel de protocole plus classique et largement plus utile a mon goût. Les développeurs sont également d’un aide précieuse et très réactifs.

J’ai donc choisi l’Hydrabus car il répond mieux a mes besoins.

Le Hardware

hydrabus

La carte est livrée avec une coque en plastique transparent laissant apparaître la sérigraphie de cette dernière. Du point de vue qualité globale, pour 75 euros livré, la carte repose sur un STM32F415 qui est proche des puces équipant les cartes de développement micropython.

Bien entendus le hardware seul ne justifie pas le prix de vente, mais bien le travail exceptionnel réalisé sur le firmware.

Il existe également un portage de micropython sur cette carte

HydraFW

Le software installé sur la machine est construit autour de l’OS temps réel Chibios.

La carte se branche donc en USB et est accessible depuis une console série qui offre un support pour les options suivantes :

Available commands
   help           Available commands
   history        Command history
   clear          Clear screen
   show           Show information
   logging        Turn logging on or off
   sd             SD card management
   adc            Read analog values
   dac            Write analog values
   pwm            Write PWM
   frequency      Read frequency
   gpio           Get or set GPIO pins
   spi            SPI mode
   i2c            I2C mode
   1-wire         1-wire mode
   2-wire         2-wire mode
   3-wire         3-wire mode
   uart           UART mode
   nfc            NFC mode
   can            CAN mode
   sump           SUMP mode
   jtag           JTAG mode
   random         Random number
   flash          NAND flash mode
   wiegand        Wiegand mode
   lin            LIN mode
   debug          Debug mode

La partie NFC n’est disponible que sur l’hydranfc

Il est possible s’interfacer directement depuis ces menus aux protocoles les plus communs tel que SPI, UART, i2c ou encore OneWire.

L’Hydrabus peu également s’utiliser comme analyseur logique 16 canaux @ 2MHz avec Sigrok (le monde SUMP). C’est moins efficace que les analyseurs logiques Salae mais ça montre la polyvalence de l’outil.

Enfin, il est possible de scripter l’utilisation de la carte par le biais du mode binary ou grâce à pyHydrabus (qui repose sur le mode Binary).

i2c où est tu ?

Pour ce test, je vais utiliser un écran OLED basé sur le contrôleur SSD1306.

hooked

Je vais donc interfacer l’Hydrabus avec cet écran en utilisant des pointes de touches spécifiques sur les pins suivants :

> i2c
GPIO resistor: pull-up
Frequency: 100khz (50khz, 400khz, 1mhz)
i2c1> show pin
SCL: PB6
SDA: PB7

Les commandes utilisables sont les suivantes :

i2c1> help
Show pins used in this mode
   show           Show I2C parameters
   trigger        Setup I2C trigger
   pull           GPIO pull (up/down/floating)
   frequency      Bus frequency
   scan           Scan for connected devices
   start          Start
   stop           Stop
   read           Read byte (repeat with :<num>)
   hd             Read byte (repeat with :<num>) and print hexdump
   write          Write byte (repeat with :<num>)
   <integer>      Write byte (repeat with :<num>)
   <string>       Write string
   [              Alias for "start"
   ]              Alias for "stop"
   &              Delay 1 usec (repeat with :<num>)
   %              Delay 1 msec (repeat with :<num>)
   ~              Write a random byte (repeat with :<num>)
   exit           Exit I2C mode

Maintenant, la partie importante est de décortiquer le datasheet de l’écran.

Pour l’initialiser, nous devons utiliser la suite d’octets suivants :

\x78\x00\x10\x40\x81\x7F\xA1\xA6\xA8\x0F\xD3\x00\xD5\xF0\xD9\x22\xDA\x02\xDB\x49\x8D\x14\xAF

Il faut maintenant trouver l’adresse de l’écran sur le bus i2c grâce à la fonction scan :

i2c1> scan
Device found at address 0x3c

Cool, maintenant essayons d’envoyer un octet a notre écran :

i2c1> [ \x3c\x00 ]
I2C START
WRITE: 0x3C NACK 0x00 NACK
I2C STOP

Etant donné le nombre de NACK retourné, la transmission à échoué. En fait, l’adresse retournée par le scan est fausse car codé sur 8 bits là ou les adresses i2c sont codé sur 7 bits.

i2c_addr

Ainsi, pour obtenir la bonne adresse, il faut faire un décalage d’un bit a gauche ou simplement multiplier la valeur par 2.

Dans notre cas 0x3c donne 0x78

Maintenant essayons depuis l’hydrabus :

i2c1> [ \x78\x00 ]
I2C START
WRITE: 0x78 ACK 0x00 ACK
I2C STOP

Parfait, envoyons la séquence d’initialisation :

i2c1> [ \x78\x00\x10\x40\x81\x7F\xA1\xA6\xA8\x0F\xD3\x00\xD5\xF0\xD9\x22\xDA\x02\xDB\x49\x8D\x14\xAF ]
I2C START
WRITE: 0x78 ACK 0x00 ACK 0x10 ACK 0x40 ACK 0x81 ACK 0x7F ACK 0xA1 ACK 0xA6 ACK 0xA8 ACK 0x0F ACK 0xD3 ACK 0x00 ACK 0xD5 ACK 0xF0 ACK 0xD9 ACK 0x22 ACK 0xDA ACK 0x02 ACK 0xDB ACK 0x49 ACK 0x8D ACK 0x14 ACK 0xAF ACK
I2C STOP

L’écran s’allume avec des points afficher aléatoirement. C’est en fait un résidu du contenus de la RAM interne au contrôleur.

screen_on

Maintenant essayons d’envoyer des données aléatoires dans l’écran :

i2c1> [ \x78\x00\x40\x00\xff\xff\xff\xff\xff\xff ]
I2C START
WRITE: 0x78 ACK 0x00 ACK 0x40 ACK 0x00 ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK 0xFF ACK
I2C STOP

Explication :

  • Le premier octet représente l’adresse de l’écran 0x78

  • Le deuxième dois toujours être ` 0x00`

  • Le troisième indique que nous allons écrire dans la RAM : 0x40

  • Les autres octets représentent les données.

Note : N’ayant pas encore étudié en profondeur le fonctionnement du contrôleur, je n’irais pas plus loin dans l’utilisation du mode manuel.

Scriptons mes amis !

Comme je l’expliquais, il est possible d’utiliser pyHydrabus pour s’interfacer avec la carte depuis un script python, essayons avec le bus i2c :

import pyHydrabus

i=pyHydrabus.I2C('/dev/ttyACM1')

results = []
i.start()

for y in range(1,128):
	addr = (y<<1).to_bytes(1, byteorder='big')
	if i.write_read(addr,1) is not None:
		print("Found someone at 0x{}".format(addr.hex()))

i.stop()

Ce script permet entre autre de scanner le bus i2c pour trouver les adresses qui répondent. Il existe une fonction scan mais elle semble bloquer dès lors que le périphérique i2c retourne autre chose que ACK.

Une fois lancé, j’obtiens ceci :

jugu@WORKSTATION:~/Documents/hydrabus$ python3 scan.py
Found someone at 0x78

Allons plus loin avec un script qui écrit dans la RAM pour allumer tout l’écran :

import pyHydrabus
import time

i=pyHydrabus.I2C('/dev/ttyACM0')

def select (pageNumber):
	pagecode = [ b'\xb1', b'\xb0' ]
	i.write_read(b'\x78\x00\x00\x10' + pagecode[pageNumber])

def writeBlock (inp):
	for row in inp:
		i.write_read(b'\x78\x40' + row)

def initialize():
	i.start()
	i.write_read(b'\x78\x00\x10\x40\x81\x7F\xA1\xA6\xA8\x0F\xD3\x00\xD5\xF0\xD9\x22\xDA\x02\xDB\x49\x8D\x14\xAF',1)

	select(0)
	for x in range(0, 127):
		i.write_read(b'\x78\x40\xff',1)

	select(1)

	for x in range(0, 127):
		i.write_read(b'\x78\x40\xff',1)

i.start()
initialize()

Note : seul la fonction write_read fonctionne avec cet écran.

UART 1/2 : mise en application technique

L’objectif ici est de mettre dans la peau d’un hacker souhaitant s’interfacer avec l’UART d’un matériel inconnu. Pour simplifier ceci je vais me servir de mon Arduino dans lequel je vais envoyer un programme simple affichant la table ASCII :

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ;
  }
  Serial.println("ASCII Table ~ Character Map");
}

int thisByte = 33;

void loop() {

  Serial.write(thisByte);

  Serial.print(", dec: ");
  Serial.print(thisByte);
  Serial.print(", hex: ");
  Serial.print(thisByte, HEX);
  Serial.print(", oct: ");
  Serial.print(thisByte, OCT);
  Serial.print(", bin: ");
  Serial.println(thisByte, BIN);

  if (thisByte == 126) {
    while (true) {
      continue;
    }
  }
  thisByte++;
}

Trouver le Baudrate

Nous partons du principe que nous ne connaissons pas le baudrate pour le déterminer grâce à un oscilloscope (ici le DS203).

scope_hook

L’idée ici est de prendre l’un des fronts montants le plus court et d’en mesurer la durée avant d’en calculer la vitesse en baud :

scope

Ici la durée indiquée est de 100 µs soit (1/100)*10⁶ ce qui donne 10000 bps ou plus simplement 9600 baud . Voici un tableau qui résume les durées mesurées avec les valeurs en baud :

Durée Baud Rate
3333µs (3.3ms) 300
833µs 1200
416µs 2400
208µs 4800
104µs (0.100ms) 9600
69µs 14400
52µs 19200
34µs 28800
26µs 38400
17.3µs 57600
8µs 115200
4.34µs 230400

Recevoir des données

Maintenant que nous connaissons la vitesse de transmission, essayons de communiquer avec l’Arduino depuis l’hydrabus :

uart1> show pin
TX: PA9
RX: PA10
uart1> show
Device: UART1
Speed: 115200 bps
Parity: none
Stop bits: 1
uart1> speed 9600
Final speed: 9600 bps(0.00% err)
uart1> bridge
Interrupt by pressing user button.

ASCII Table ~ Character Map
!, dec: 33, hex: 21, oct: 41, bin: 100001
", dec: 34, hex: 22, oct: 42, bin: 100010
#, dec: 35, hex: 23, oct: 43, bin: 100011
$, dec: 36, hex: 24, oct: 44, bin: 100100
%, dec: 37, hex: 25, oct: 45, bin: 100101
&, dec: 38, hex: 26, oct: 46, bin: 100110
', dec: 39, hex: 27, oct: 47, bin: 100111
(, dec: 40, hex: 28, oct: 50, bin: 101000
), dec: 41, hex: 29, oct: 51, bin: 101001
*, dec: 42, hex: 2A, oct: 52, bin: 101010
+, dec: 43, hex: 2B, oct: 53, bin: 101011
,, dec: 44, hex: 2C, oct: 54, bin: 101100
-, dec: 45, hex: 2D, oct: 55, bin: 101101
., dec: 46, hex: 2E, oct: 56, bin: 101110
/, dec: 47, hex: 2F, oct: 57, bin: 101111
0, dec: 48, hex: 30, oct: 60, bin: 110000
1, dec: 49, hex: 31, oct: 61, bin: 110001
2, dec: 50, hex: 32, oct: 62, bin: 110010
3, dec: 51, hex: 33, oct: 63, bin: 110011

La communication fonctionne !

UART 2/2 : test avec sigrok

Dans cette partie nous allons utiliser le protocole SUMP avec le logiciel Sigrok pour analyser ce qu’envoie la carte Arduino.

Voici un exemple de l’interface PulseView :

sigrok

Le décodeur fonctionne correctement dans le cas de l’UART, mais gardez en tête que cela ne remplace pas un véritable analyseur logique tel qu’un Salae dont voici un screenshoot :

salae

En fait le problème dans mon cadre de test c’est que l’Arduino attend que le port série soit disponible avant de lancer la séquence d’écriture. Comme il contient un bootloader, il se passe quelques secondes durant lesquelles le port série attend qu’un programme lui soit téléversé.

Aucun problème dans le cas du Salae car il écrit directement dans la RAM de mon PC permettant un capture de longue durée (15s ici).

Ce que L’Hydrabus ne peut pas faire même avec un Trigger. J’ai donc réussi à récupérer un morceau de la séquence en jouant avec les timings de capture.

Conclusion

L’Hydrabus est un outil tout terrain qui vous permettra de travailler directement avec du hardware, même si ce dernier est inconnu.

Il offre un panel large de fonctions, de protocole et d’interface pour dialoguer avec tout et n’importe quoi.

De plus la documentation est complète et en perpétuelle évolution. J’ai par exemple signalé la problématique rencontré avec les adresses i2c et les développeurs ont directement mis à jour la documentation en tenant compte de mes remarques.

Néanmoins pour le moment la carte n’offre pas de fonctions particulières en USB ce qui aurais était intéressant dé lors que cette dernière en possède deux. Mais nous verrons bien dans les prochaines versions de HydraFW.

J’oubliais le dernier point : Hydrabus est Open Source, il est donc possible de fabriquer vous-même la carte. Pensez à soutenir les personnes qui travaillent dessus en achetant la carte qu’ils vendent.


Written on August 25, 2019 by


Retour