Etape 1 : reconnaissance du terrain.
Il s’agit d’un challenge portant sur un PCAP entre 2 équipements à base de ESP32. L’énoncé indique que ce trafic sera du protocole ESP-NOW. D’où le titre du challenge.
Ce n’est pas mon domaine du tout. Je cherche donc de la documentation sur Internet comme d’habitude.
Avec un PCAP, le mieux serait de trouver un dissector WIRESHARK pour ESP-NOW. Je n’en trouverai pas au final. Par contre, je sais que cela existe car un document en évoque un et un hacker bulgare semble travailler sur un tel dissecteur depuis plusieurs années.
Le document qui me donne en gros la solution du challenge est un PDF disponible à cette adressse web :
La vraie adresse est néanmoins https://www.nozominetworks.com/resources/esp-now-protocol-analysis-and-vulnerability-research
(C’est ce PDF qui évoque un dissecteur LUA pour ESP-NOW mais je n’en ai pas trouvé trace, il n’est peut-être pas open sourcé ?)
Etape 2 : Analyse du PCAP.
Le PCAP commence par des paquets de broadcast qui ne semblent pas intéressants. Vraisemblablement le second ESP32 n’a pas encore démarré sa couche ESP-NOW jusqu’à présent.
On comprend néanmoins au vu de l’ensemble des frames du PCAP
que l’ESP32 de macaddr se terminant en d2:9c:d8 parle en premier et que
l’autre ESP32 de macaddr se terminant en d3:36:30 lui répond ensuite.
Par la suite, je comprendrai qu’en gros le premier ESP32 émet un char et
l’autre ESP32 lui fait écho.
Page 7 du PDF, on voit le schéma du paquet WIFI :
MAC Header ............... 24 bytes
Category Code ............ 1 byte --------+
Organization Identifier .. 3 bytes | Partie Wireless Management
Random values ............ 4 bytes |
Vendor Specific Content .. 7-257 bytes ---+
FCS ...................... 4 bytes
Page 7 du PDF, on comprend :
MAC Header ............... 24 bytes
Category Code ............ 1 byte ......... 0x7f
Organization Identifier .. 3 bytes ........ 0x18fe34
Random values ............ 4 bytes ........ 4 bytes aléatoires anti rejeu
Vendor Specific Content .. 7-257 bytes .... on trouvera ici toujours 13 bytes
FCS ...................... 4 bytes
Page 8 du PDF, on voit le schéma de la partie Vendor Specific Content :
Element ID ............... 1 bytes
Length ................... 1 byte
Organization Identifier .. 3 bytes
Type ..................... 1 byte
Version .................. 1 byte
Body ..................... 0-250 bytes
Page 8 du PDF, on comprend donc :
Element ID ............... 1 bytes ...... 0xdd
Length ................... 1 byte ....... 0x07
Organization Identifier .. 3 bytes ...... 0x18fe34
Type ..................... 1 byte ....... 0x04
Version .................. 1 byte ....... 0x02
Body ..................... 0-250 bytes .. taille 7 - 3 - 1 - 1 = 2
Avec tout cela, on s’y retrouve facilement dans les frames.
En gros chaque trame intéressante transporte donc un payload de 2 bytes. Sur le principe que cela transportera le flag au final, on va trouver au mieux 2 chars du flag par paquet. Ce sera un char au final.
Si je dumpe le payload de 2 bytes par frame de type Action, on voit :
- Le premier byte du payload vaut 0x02 ou 0x03 selon qui parle.
- Le premier byte du payload est un char et on trouve successivement
FCSC{...}.
On trouve presque le flag car en effet, il manque parfois des frames. Mais on peut facilement deviner ce qui manque :
Frame 18 [d8-30 SN=18] : 02 46 F
Frame 20 [30-d8 SN=01] : 03 46 F
Frame 21 [d8-30 SN=19] : 02 43 C
Frame 23 [30-d8 SN=02] : 03 43 C
Frame 24 [d8-30 SN=20] : 02 53 S
Frame 26 [30-d8 SN=03] : 03 53 S
Frame 27 [d8-30 SN=21] : 02 43 C
Frame 29 [30-d8 SN=04] : 03 43 C
Frame 30 [d8-30 SN=22] : 02 7b {
Frame 32 [30-d8 SN=05] : 03 7b {
Frame 33 [d8-30 SN=23] : 02 57 W
Frame 35 [30-d8 SN=06] : 03 57 W
>>> manque la frame d8-30 SN=24 => 1
Frame 37 [30-d8 SN=07] : 03 31 1
Frame 38 [d8-30 SN=25] : 02 66 f
Frame 40 [30-d8 SN=08] : 03 66 f
Frame 41 [d8-30 SN=26] : 02 49 I
>>> manque la frame 30-d8 SN=09 => I
>>> manque la frame 30-d8 SN=27 => _
Frame 44 [30-d8 SN=10] : 03 5f _
Frame 45 [d8-30 SN=28] : 02 34 4
Frame 47 [30-d8 SN=11] : 03 34 4
Frame 48 [d8-30 SN=29] : 02 63 c
Frame 50 [30-d8 SN=12] : 03 63 c
Frame 51 [d8-30 SN=30] : 02 54 T
Frame 53 [30-d8 SN=13] : 03 54 T
Frame 54 [d8-30 SN=31] : 02 69 i
Frame 56 [30-d8 SN=14] : 03 69 i
Frame 57 [d8-30 SN=32] : 02 30 0
Frame 59 [30-d8 SN=15] : 03 30 0
Frame 60 [d8-30 SN=33] : 02 6e n
Frame 62 [30-d8 SN=16] : 03 6e n
Frame 63 [d8-30 SN=34] : 02 5f _
Frame 65 [30-d8 SN=17] : 03 5f _
Frame 66 [d8-30 SN=35] : 02 46 F
Frame 68 [30-d8 SN=18] : 03 46 F
Frame 69 [d8-30 SN=36] : 02 72 r
Frame 71 [30-d8 SN=19] : 03 72 r
Frame 72 [d8-30 SN=37] : 02 34 4
Frame 74 [30-d8 SN=20] : 03 34 4
Frame 75 [d8-30 SN=38] : 02 4d M
Frame 77 [30-d8 SN=21] : 03 4d M
Frame 78 [d8-30 SN=39] : 02 65 e
Frame 80 [30-d8 SN=22] : 03 65 e
Frame 81 [d8-30 SN=40] : 02 53 S
Frame 83 [30-d8 SN=23] : 03 53 S
Frame 84 [d8-30 SN=41] : 02 5f _
Frame 86 [30-d8 SN=24] : 03 5f _
Frame 87 [d8-30 SN=42] : 02 38 8
Frame 89 [30-d8 SN=25] : 03 38 8
Frame 90 [d8-30 SN=43] : 02 33 3
Frame 92 [30-d8 SN=26] : 03 33 3
Frame 93 [d8-30 SN=44] : 02 66 f
Frame 95 [30-d8 SN=27] : 03 66 f
Frame 96 [d8-30 SN=45] : 02 30 0
>>> manque la frame 30-d8 SN=28 => 0
Frame 98 [d8-30 SN=46] : 02 64 d
Frame 100 [30-d8 SN=29] : 03 64 d
Frame 101 [d8-30 SN=47] : 02 65 e
Frame 103 [30-d8 SN=30] : 03 65 e
>>> manque la frame d8-30 SN=48 => f
Frame 105 [30-d8 SN=31] : 03 66 f
Frame 106 [d8-30 SN=49] : 02 35 5
Frame 108 [30-d8 SN=32] : 03 35 5
Frame 109 [d8-30 SN=50] : 02 39 9
>>> manque la frame 30-d8 SN=33 => 9
Frame 111 [d8-30 SN=51] : 02 31 1
Frame 113 [30-d8 SN=34] : 03 31 1
Frame 114 [d8-30 SN=52] : 02 66 f
Frame 116 [30-d8 SN=35] : 03 66 f
Frame 117 [d8-30 SN=53] : 02 63 c
Frame 119 [30-d8 SN=36] : 03 63 c
Frame 120 [d8-30 SN=54] : 02 63 c
Frame 122 [30-d8 SN=37] : 03 63 c
Frame 123 [d8-30 SN=55] : 02 65 e
Frame 125 [30-d8 SN=38] : 03 65 e
>>> manque la frame d8-30 SN=56 => e
Frame 127 [30-d8 SN=39] : 03 65 e
Frame 128 [d8-30 SN=57] : 02 61 a
Frame 130 [30-d8 SN=40] : 03 61 a
Frame 131 [d8-30 SN=58] : 02 7d }
Frame 133 [30-d8 SN=41] : 03 7d }
Donc en gros :
- soit on a le dialogue echo - reply et on un char du flag en double
- soit on a le echo mais pas le reply mais le echo donne le char du flag
- soit on a le reply mais pas le echo mais le reply donne le char du flag
En réassemblant, le flag doit donc être :
FCSC{W1fI_4cTi0n_Fr4MeS_83f0def591fcceea}
Bingo. Le flag se valide.
A noter que le challenge est possible car ici le trafic en ESP-NOW est en mode non chiffré. Le PDF explique qu’il existe ce mode en clair et deux modes chiffrés.
QED.
🐒