BSides Badge 2025
Popis toho, jak jsem postupoval při analýze BSides Badge, zejména se pak jedná o své začátečnické poznámky a seznamování se s nástrojem Ghidra.
BSides Prague 2025
Upozornění: Článek je průběžně upravován.
Jedná se o druhou konferenci pořádanou v Praze, jejíž zaměření je kyber-bezpečnost.
Hlavní téma tohoto článku je ale elektronická badge, kterou bylo možno zakoupit při koupi vstupenky, kdy měli návštěvníci tak možnost získat i elektronickou badge, která byla sama o sobě zajímavá. Toho jsem následně využil. Zejména pak k rozšíření si technických znalostí, se kterými bych se s vámi rád podělil.
Jak to celé fungovalo
Ve zkratce se jednalo o tři důležité komponenty
ESP32-C3,X, token Vaším úkolem bylo připojit říkejme tomu třeba hw token do svojí badge, tím se zařízení spustilo. Hlavní myšlenkou bylo sbírat klíče ostatních účastníků a sbírat tak XP body, čím více lidí tím více XP. HW Token zároveň sloužil i jako vstupní bod k CTF, čemuž jsem bohužel nevěnoval tolik času, kolik bych rád. Dalším problémem bylo, že 3xAAA baterie, které byli dodány, byli nedostatečné a zařízení tak často končilo v nekonečné smyčce boot sekvence. Zařízení se připojovalo k Wi-Fibsidesprg25s heslemherewegoagaina ověřovalo se tak vůči serveru nahttps://apixp.bsides.cz
Stranou teď vše ostatní, mě zajímá ESP32.
Specifikace
1
2
3
4
CPU: ESP32-C3-MINI-1U
Display: 1.28inch 240x240 IPS
Frequency 160Mhz, 400KB SRAM, 384KB ROM
Flash size 4MB
Analýza a identifikace
Při připojení k PC přes USB-C jsem potřeboval zjistit, jak se samotné zařízení tváří pro OS.:
1
2
3
4
5
6
7
8
9
10
sudo dmesg
[ 1062.048138] usb 3-7: new full-speed USB device number 10 using xhci_hcd
[ 1062.173487] usb 3-7: New USB device found, idVendor=303a, idProduct=1001, bcdDevice= 1.01
[ 1062.173497] usb 3-7: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 1062.173501] usb 3-7: Product: USB JTAG/serial debug unit
[ 1062.173504] usb 3-7: Manufacturer: Espressif
[ 1062.173506] usb 3-7: SerialNumber: 98:XX:XX:XX:XX:XX
[ 1062.204015] cdc_acm 3-7:1.0: ttyACM0: USB ACM device
[ 1062.204059] usbcore: registered new interface driver cdc_acm
[ 1062.204062] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
Informace o čipu
Pro stažení firmware je potřeba mít esptool.py a pro zjištění základních informací o čipu.:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
esptool.py --port /dev/ttyACM0 flash_id
esptool.py v4.8.1
Serial port /dev/ttyACM0
Connecting...
Detecting chip type... ESP32-C3
Chip is ESP32-C3 (QFN32) (revision v0.4)
Features: WiFi, BLE, Embedded Flash 4MB (XMC)
Crystal is 40MHz
MAC: 98:XX:XX:XX:XX:XX
Uploading stub...
Running stub...
Stub running...
Manufacturer: 20
Device: 4016
Detected flash size: 4MB
Hard resetting via RTS pin...
Stažení firmware
Pro to, abychom si dále mohli se stávajícím firmware hrát jsem si stáhl jeho image pomocí.:
1
esptool.py --chip esp32c3 --port /dev/ttyACM0 read_flash 0x000000 0x400000 esp32c3_dump_4mb.bin
- Proč
0x000000? Protože to je začátek paměti - Prox
0X400000? Protože to je konec paměti v hexadecimálním formátu. ->4 x 1024 x 1024 = 4 194 304 bajtů = 4MB - tzn. že čteme celou paměť od
0-4 MB
Kontrola, zda je firmware nějakým způsobem šifrovaný.:
1
espefuse.py --chip esp32c3 --port /dev/ttyACM0 summary
SECURE_BOOT_EN <- jestli je aktivní secure boot DIS_DOWNLOAD_MANUAL_ENCRYPT <- Zakazuje čtení přes UART po zapnutí šifrování
Soubor esp32c3_dump_4mb.bin si raději rozkopíruji, ať si jej omylem nepřepíšu.
1
2
md5sum esp32c3_dump_4mb.bin
c418f0f71a50554739367c5ba012b1d8 esp32c3_dump_4mb.bin
- Pokud by jste si chtěli též s dumpem pohrát tak je možné jej stáhnout zde.: GitHub
Extrakce souborů pomocí binwalk
Pomocí binwalk jsme schopni vyextrahovat další zajímavé soubory.:
1
binwalk -e esp32c3_dump_4mb.bin
- Tím získáme několik obrázků
.png
Identifikace partitions
Ruční metoda
1
esptool.py --chip esp32c3 --port /dev/ttyACM0 read_flash 0x8000 0x1000 partitions.bin
esp32 partitions začíná na offsetu 0x8000 a končí na 0x1000
1
2
3
4
5
6
strings partitions.bin
otadata
app0
spiffs
coredump
Metoda pomocí nástroje
Používám nástroj GitHub
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
python3 esp32_image_parser.py show_partitions ../esp32c3_dump_4mb.bin
reading partition table...
entry 0:
label : nvs
offset : 0x9000
length : 20480
type : 1 [DATA]
sub type : 2 [WIFI]
entry 1:
label : otadata
offset : 0xe000
length : 8192
type : 1 [DATA]
sub type : 0 [OTA]
entry 2:
label : app0
offset : 0x10000
length : 3145728
type : 0 [APP]
sub type : 16 [ota_0]
entry 3:
label : spiffs
offset : 0x310000
length : 917504
type : 1 [DATA]
sub type : 130 [unknown]
entry 4:
label : coredump
offset : 0x3f0000
length : 65536
type : 1 [DATA]
sub type : 3 [unknown]
MD5sum:
98f492a471b542a1572d58e33e614dc8
Done
NVS Partition
Jedná se o non-volatile-storage partition, kde jsou většinou uloženy přístupové údaje, wi-fi údaje, uživatelské data, ale i historické, občas nejsou správně promazány.
- Jak ji získat?
- Použijeme nástroj
esp32_image_parserGitHub - Doufal jsem, že tady najdeme potřebný certifikát, díky kterému badge mohla komunikovat s backendem šifrovaně…
1
python3 esp32_image_parser.py dump_nvs ../../esp32c3_dump_4mb.bin -partition nvs -nvs_output_type json
Wi-Fi SSID
1
2
3
4
5
6
7
8
9
10
11
12
{
"entry_state": "Written",
"entry_ns_index": 2,
"entry_ns": "nvs.net80211",
"entry_type": "BLOB_DATA",
"entry_span": 3,
"entry_chunk_index": 0,
"entry_key": "sta.ssid",
"entry_data_type": "BLOB_DATA",
"entry_data_size": 36,
"entry_data": "CwAAAGJzaWRlc3ByZzI1AAAAAAAAAAAAAAAAAAAAAAAAAAAA"
}
1
2
echo "CwAAAGJzaWRlc3ByZzI1AAAAAAAAAAAAAAAAAAAAAAAAAAAA" | base64 -d
bsideprg25
Wi-Fi PASS
1
2
3
4
5
6
7
8
9
10
11
12
{
"entry_state": "Written",
"entry_ns_index": 2,
"entry_ns": "nvs.net80211",
"entry_type": "BLOB_DATA",
"entry_span": 4,
"entry_chunk_index": 0,
"entry_key": "sta.pswd",
"entry_data_type": "BLOB_DATA",
"entry_data_size": 65,
"entry_data": "aGVyZXdlZ29hZ2FpbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
}
1
2
echo "aGVyZXdlZ29hZ2FpbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" | base64 -d
herewegoagain
SPIFFS partition
Bohužel certifikát jsme stále nenašli, tak půjdeme dál …
SPIFFS (Serial Peripheral Interface Flash File System) je zkrátka uložiště, které zůstává i po odpojení napájení u ESP32. Může být použito pro logy, ukládání souborů, nebo uživatelských konfigurací. Třeba se zde může uchovávat i aktualizace pro ESP32, které bylo aktualizováno pomocí OTA.
Potřebujeme vyextrahovat partition spiffs:
1
python3 esp32_image_parser.py dump_partition ../../esp32c3_dump_4mb.bin -partition spiffs -output esp32c3_spiff_filesystem
- Nástroj na čtení SPIFFS GitHub
pokus č.1 Po úspěšné kompilaci nástroje mkspiffs jsem zkusil.:
1
2
3
4
5
6
7
8
9
./mkspiffs -u output ../../esp32_image_parser/esp32c3_spiff_filesystem
/bid.txt > ./output/bid.txt size: 18 Bytes
/kid.txt > ./output/kid.txt size: 18 Bytes
/badgename.txt > ./output/badgename.txt size: 9 Bytes
/uid.txt > ./output/uid.txt size: 10 Bytes
/flags.txt > ./output/flags.txt size: 3 Bytes
/totps.txt > ./output/totps.txt size: 48 Bytes
/avatar.png > ./output/avatar.png size: 20692 Bytes
/paired.txt > ./output/paired.txt size: 3 Bytes
- Bohužel, žádný ze souborů nenabídl zajímavé data, jen pár hexadecimálních znaků,
avatar.pngrozhodně neobsahoval magic bytes obrázku PNG apod. - I přesto, že je tam pár náznaků, tak se mi nepovedlo obrázek zrekonstruovat…
OTADATA
Tady by se měli uchovávat nové firmware provedené via OTA když si vzpomeneme na partition map:
1
2
3
4
5
6
entry 1:
label : otadata
offset : 0xe000
length : 8192
type : 1 [DATA]
sub type : 0 [OTA]
Tak pomocí hexdump dojdeme k závěru, že na badge neproběhla žádná OTA aktualizace, protože 0x00-0x03 obsahuje první sekvenci 01 00 00 00 a další sekvence nejsou zaplněny. ff ff ff ff
1
2
3
4
hexdump -C -n 32 -s 0xe000 esp32c3_dump_4mb.bin
0000e000 01 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff |................|
0000e010 ff ff ff ff ff ff ff ff ff ff ff ff 9a 98 43 47 |..............CG|
0000e020
Ghidra
Záleží co zde chceme analyzovat, sám jsem zatím nevyřešil vnitřní otázku, zda je lepší analyzovat celý dump
esp32c3_dump_4mb.bina nebo až vyextrahovanou partitionapp0.
- Tak pokud používáme doplněk pro ghidru viz. níže tak můžeme použít celý dump, jinak je lepší analyzovat konkrétní partition
app0protože se pak vyhneme složitému mapování paměti.
- Doplněk pro Ghidru k importování ESP32 flash images GitHub
Bez tohoto doplňku jsem měl problém s tím namapovat správně paměť. Analýza takového firmware pak dostala úplně nový rozměr.
Dekompilace
První myšlenkou bylo, že se zkusím něco nového přiučit s Ghidrou a třeba se mi podaří pochopit i to, jak ESP32-C3 formuluje dotazy na backend. Díky tomu se mi podařilo zjistit bohužel jen pár střípků.
- Dotaz bude určitě na
apixp.bsides.cz - zařízení ESP32 má v sobě uložen PUBLIC RSA KEY, ten mi k ničemu moc není, zejména pokud by byla komunikace šifrovaná…
- Dotaz bude s klíčem
cmda hodnota klíče by měla být"getinfo" - Bude zde taky klíč
kidkterý bude pro každou badge unikátní, a je pravděpodobně načítána pávě z hardwarového klíče, který se do badge vloží. - Badge bude očekávat v JSON odpovědi
badgename,uid,flags,score.
Super, to bychom měli, ale jak si to doopravdy potvrdit a hlavně jak zjistit onen
kid, protože ze samotného hardwarového klíče tuto hodnotu zatím nevím jak zjistit.Mohl bych se tedy vrátit k myšlence Man-In-The-Middle útoku, resp odposlechu pomocí Access point a třeba se něco dozvím …
Evil AP
Myšlenka je taková, že vytvořím AP, které bude nastaveno dle toho, co očekává badge. tedy.:
1
2
BSSID: bsidesprg25
Password: herewegoagain
Kvůli své lenivosti jsem vytáhl PineApple Mark VII, ale byl bych to schopný udělat i s obyčejným Wi-Fi donglem a síťovým připojením pomocí nástroje
EvilTwinBudu poslouchat provoz a zjistím přesnou strukturu HTTP požadavků, které ze zařízení odchází.
Tuto metodu jsem nakonec použil s připojením k internetu, abych rovnou získal i případnou odpověď, a taky hlavně proto, protože se mi v offline režimu nepodařilo ESP32 donutit k dotazu na
apixp.bsides.cz.Ač jsem se této metodě bránil, protože jsem žil v domnění, že bude využito HTTPS. Já bych tak viděl stejně jen dotaz na DNS a pak navázání spojení a tím by to pro mě končilo… Tak jsem se konečně odhodlal zvolit tuto metodu, a zjistil jsem, že komunikace probíhá jen pomocí HTTP a žádné šifrování zde není … HURÁ! XoXo
- Následně jsem si pak zopakoval akci v BurpSuite, s tím že zkusím zjistit, zda neexistuje více
cmdpříkazů, bohužel jsem další možný nenašel.
HTTP REQUEST
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
GET /?cmd=getinfo&kid=CDAB356475BC77CC HTTP/2
Host: apixp.bsides.cz
Sec-Ch-Ua: "Not:A-Brand";v="24", "Chromium";v="134"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Linux"
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Priority: u=0, i
Content-Length: 2
HTTP REPLY
1
2
3
4
5
6
7
8
9
10
11
12
HTTP/2 200 OK
Date: Fri, 11 Apr 2025 11:28:39 GMT
Server: ATS
Vary: User-Agent,Accept-Encoding
Cache-Control: max-age=0, no-cache, no-store, must-revalidate
Expires: Sat, 1 Jan 2000 01:00:00 GMT
Pragma: no-cache
Content-Length: 95
Content-Type: application/json
Age: 0
{"status":"success","badgename":"Charlie","uid":"22235234","flags":0,"score":{"*":60,"cea":60}}





