Hydrabus, for rule them all ?!
RetourÉ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
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.
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.
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
donne0x78
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.
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).
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 :
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 :
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 :
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.
Retour