การแฮ็กอุปกรณ์สมาร์ตโฮม (2024)
(jmswrnr.com)- เพื่อควบคุมเครื่องฟอกอากาศที่ใช้ ESP32 ซึ่งถูกผูกกับแอปของผู้ผลิตและคลาวด์โดยตรงจาก Home Assistant จึงทำการวิศวกรรมย้อนกลับเส้นทางการควบคุมระยะไกลและแทนที่ด้วยเซิร์ฟเวอร์ภายในเครื่อง
- จากการวิเคราะห์แอป, การหลบเลี่ยง DNS และการดักจับด้วย Wireshark พบว่าอุปกรณ์ส่ง แพ็กเก็ต UDP ไปยัง
smartdeviceep.---.com:41014และใช้โปรโตคอลเฉพาะของตัวเองแทน DTLS มาตรฐาน - ผ่านการเชื่อมต่อ UART และการดัมพ์แฟลช 4MB จึงดึง
dev_key.key, ใบรับรอง, การตั้งค่าเซิร์ฟเวอร์ และการตั้งค่า WiFi ออกมาได้ แล้ววิเคราะห์โครงสร้างเฟิร์มแวร์ด้วย Ghidra และ esp32knife - แพ็กเก็ตประกอบด้วยเฮดเดอร์ 13 ไบต์และ CRC-16 ใน 2 ไบต์สุดท้าย พร้อมการสร้างคีย์แบบ ECDH/HKDF,
AES-128-CBCและการซีเรียลไลซ์แบบ MessagePack โดยสามารถถอดรหัสได้สำเร็จหลังแพตช์เฟิร์มแวร์ให้พิมพ์ shared secret ออกทาง serial log - โครงสร้างสุดท้ายเชื่อมต่อกันเป็น MITM proxy, local server และ MQTT bridge ที่ใช้ Mosquitto ทำให้ควบคุมการเปิดปิดและความเร็วพัดลมผ่าน MQTT Fan ของ Home Assistant ได้อย่างเสถียรเป็นเวลาหลายสัปดาห์
เปลี่ยนเครื่องฟอกอากาศที่พึ่งพาคลาวด์ให้ควบคุมแบบโลคัลได้
- เป้าหมายคือควบคุมเครื่องฟอกอากาศที่เชื่อมต่อได้เฉพาะผ่านแอปมือถือของผู้ผลิตและบัญชีคลาวด์ด้วย Home Assistant
- จากการสลับเปิดปิด Bluetooth, WiFi และ 5G บนโทรศัพท์ พบว่าแอปควบคุมอุปกรณ์ได้ผ่าน การเชื่อมต่ออินเทอร์เน็ต เท่านั้น ไม่ใช่ Bluetooth หรือ WiFi ภายในเครือข่าย
- เนื่องจากค่าควบคุมอย่างความเร็วพัดลมวิ่งอยู่ระหว่างอุปกรณ์กับเซิร์ฟเวอร์คลาวด์ ช่วงเครือข่ายนี้จึงเป็นจุดโจมตีสำคัญ
- หากดักทราฟฟิกและเปลี่ยนค่าได้ ก็จะควบคุมอุปกรณ์ได้
- หากจำลองการตอบกลับของเซิร์ฟเวอร์ได้ ก็จะทำให้อุปกรณ์ทำงานได้โดยไม่ต้องพึ่งอินเทอร์เน็ตและคลาวด์ของผู้ผลิต
- เนื้อหาการวิศวกรรมย้อนกลับมีไว้เพื่อการศึกษา และข้อมูลอ่อนไหวเฉพาะผลิตภัณฑ์ เช่น private key, โดเมน และ API endpoint ถูกทำให้คลุมเครือหรือลบออกแล้ว
- การดัดแปลงอุปกรณ์อาจทำให้การรับประกันสิ้นสุดลงหรือทำให้อุปกรณ์เสียหายถาวรได้
การวิเคราะห์แอปและการดักจับทราฟฟิก UDP
- ดึงไฟล์
.apkของ Android ออกมา แล้วเปิดclasses.dexด้วย dex2jar และ jd-gui เพื่อตรวจสอบภายใน - ใน
MainActivity.classยืนยันได้ว่าแอปพัฒนาด้วย React Native และพบการเชื่อมต่อ WebSocket แบบปลอดภัยในassets/index.android.bundle- โค้ดตัวอย่างมีการเชื่อมต่อไปยัง
wss://smartdeviceapi.---.com
- โค้ดตัวอย่างมีการเชื่อมต่อไปยัง
- ใช้ฟังก์ชันดู DNS query ของ Pi-hole เพื่อตรวจสอบโดเมนเซิร์ฟเวอร์คลาวด์ที่อุปกรณ์เชื่อมต่อ
- ใช้ฟังก์ชัน
Local DNSของ Pi-hole ส่งโดเมนนั้นไปยังเวิร์กสเตชันภายใน192.168.0.10แล้วกรองทราฟฟิกของ IP อุปกรณ์192.168.0.61ใน Wireshark - อุปกรณ์กำลังส่ง แพ็กเก็ต UDP ไปยังพอร์ต
41014ของเวิร์กสเตชัน
การตั้งค่ารีเลย์และร่องรอยของโปรโตคอลเฉพาะ
- เนื่องจาก Local DNS ถูกตั้งให้ resolve โดเมนคลาวด์ไปยังเวิร์กสเตชัน จึงใช้ Cloudflare DNS resolver
1.1.1.1เพื่อค้นหา IP จริงของเซิร์ฟเวอร์ - ใช้ node-udp-forwarder ให้เวิร์กสเตชันทำหน้าที่เป็น UDP relay ระหว่างอุปกรณ์กับเซิร์ฟเวอร์คลาวด์
- จับแพ็กเก็ตแรกตอนบูตและการตอบกลับจากเซิร์ฟเวอร์ได้ แต่ข้อมูลดูเหมือนเป็นไบต์สุ่มโดยไม่มีสตริงที่อ่านออก จึงมีความเป็นไปได้ว่าเข้ารหัสอยู่
- Wireshark ไม่รู้จักแพ็กเก็ตเป็น DTLS และรูปแบบเฮดเดอร์ตามสเปก DTLS ก็ไม่ตรงกับแพ็กเก็ตที่จับได้
- เนื่องจากดูไม่ใช่โปรโตคอลมาตรฐาน จึงต้องวิศวกรรมย้อนกลับโครงสร้างแพ็กเก็ตและวิธีเข้ารหัสด้วยตัวเอง
แกะ ESP32 และเข้าถึง serial
- เมื่อแกะอุปกรณ์ออก พบแผงวงจรหลัก, พอร์ตเชื่อมต่อพัดลม และสายแพของแผงควบคุมด้านหน้า
- คอนโทรลเลอร์หลักมีสกรีนว่า
ESP32-WROOM-32Dซึ่งเป็นไมโครคอนโทรลเลอร์ตระกูล ESP32 ที่รองรับ WiFi และ Bluetooth - อ้างอิงข้อมูลด้านการวิศวกรรมย้อนกลับ ESP32 จากรีโพซิทอรี ESP32-reversing
- ตรวจสอบพิน
TXD0และRXD0จาก datasheet ของ ESP32 แล้วไล่ตามลายวงจรที่เชื่อมกับรูพินสำหรับดีบักบน PCB เพื่อหาจุดเชื่อมต่อ serial - ใช้
USB-UART Bridgeของ Flipper Zero เพื่อตั้งค่าการเชื่อมต่อ UARTTXของ Flipper Zero เชื่อมกับRXของ ESP32RXของ Flipper Zero เชื่อมกับTXของ ESP32GNDเชื่อมกับGND
- เมื่อเชื่อมต่อผ่าน Putty ที่
COM7ความเร็ว115200ก็มี boot log แสดงออกมา
ไฟล์และการตั้งค่าเซิร์ฟเวอร์ที่เผยออกมาใน boot log
- serial log แสดงว่า ESP32 เป็นชิปที่มี CPU 2 คอร์, WiFi/BT/BLE และแฟลชภายนอกขนาด 4MB
- แอปพลิเคชันกำลังทำงานจากพาร์ทิชัน
factory - มีการเมานต์ไฟล์ซิสเต็ม FAT และแสดงพื้นที่รวม
122 KiBกับพื้นที่ว่าง0 KiB - แอปพลิเคชันกำลังอ่านไฟล์ต่อไปนี้
serialdev_key.keySmartDevice-root-ca.crtSmartDevice-signer-ca.crtserver_config
- การตั้งค่าเซิร์ฟเวอร์มี
smartdeviceep.---.com:41014อยู่ด้วย
การดัมพ์แฟลชและโครงสร้างพาร์ทิชัน
- เพื่อบูต ESP32 เข้าสู่โหมด
Download Bootได้มีการเชื่อมพินIO0เข้ากับGNDขณะเปิดเครื่อง - ใช้ esptool ดัมพ์แฟลช 4MB ทั้งหมด
- คำสั่งคือ
esptool -p COM7 -b 115200 read_flash 0 0x400000 flash.bin
- คำสั่งคือ
- ทำการดัมพ์หลายครั้งเพื่อยืนยันว่าอ่านได้ถูกต้อง และเก็บสำรองไว้เผื่อจำเป็นต้องแฟลชกลับเมื่อเกิดปัญหา
- วิเคราะห์ดัมพ์ด้วย esp32knife เพื่อให้ได้
partitions.csv - โครงสร้างพาร์ทิชันมีรายการดังนี้
nvs: ที่เก็บคีย์-ค่า 16Kotadata: ข้อมูล OTA 8Kphy_init: ข้อมูล PHY 4Kfactory: พาร์ทิชันแอป 768Kota_0,ota_1: พาร์ทิชันแอป OTA ขนาด 768K อย่างละหนึ่งชุดstorage: พาร์ทิชันข้อมูล FAT 1M
- ตามข้อมูลจากผู้อ่าน การดัมพ์แฟลชนี้อาจถูกป้องกันได้หากเปิดใช้ flash encryption แต่ในอุปกรณ์นี้ไม่ได้เปิดใช้
คีย์และใบรับรองที่พบใน storage
- สถานะล่าสุดของพาร์ทิชัน
nvsมี SSID และรหัสผ่าน WiFi และในประวัติบันทึกยังเห็นข้อมูลรับรอง WiFi ที่เคยใช้งานก่อนหน้านี้ด้วย - พาร์ทิชัน FAT
storageถูกเมานต์เป็นดิสก์เสมือนด้วย OSFMount เพื่อตรวจสอบ - ภายใน storage มีไฟล์ต่อไปนี้
dev_infodev_key.keyserialserver_configSmartDevice-root-ca.crtSmartDevice-signer-ca.crtwifi_config
dev_key.keyขึ้นต้นด้วย-----BEGIN EC PRIVATE KEY-----ซึ่งเป็น Elliptic Curve private key และยืนยันได้ด้วยopenssl ec -in dev_key.key -text -noout- ไฟล์
.crtทั้งสองขึ้นต้นด้วย-----BEGIN CERTIFICATE-----ซึ่งเป็นใบรับรอง และยืนยันได้ด้วยopenssl x509 - เมื่อมีทั้งใบรับรองและคีย์ของอุปกรณ์เก็บอยู่ในตัวเครื่อง จึงมีความเป็นไปได้สูงว่าจะถูกใช้สำหรับเข้ารหัสข้อมูลในแพ็กเก็ต UDP
การตั้งค่าสภาพแวดล้อมการวิเคราะห์ Ghidra
- เปิดอิมเมจพาร์ทิชัน
factoryที่กำลังรันอยู่ใน CodeBrowser ของ Ghidra เพื่อวิเคราะห์ - เนื่องจาก ESP32 ใช้ชุดคำสั่ง Xtensa จึงเลือกภาษา
Tensilica Xtensa 32-bit little-endian - เนื่องจากอิมเมจพาร์ทิชันแบบดิบสะท้อนการแมปหน่วยความจำเสมือนได้ไม่ถูกต้อง จึงสร้าง
part.3.factory.elfด้วย esp32knife แล้วนำเข้ามาใหม่ - เผยแพร่คอมมิตที่แก้ไข esp32knife ให้รองรับเซกเมนต์
RTC_DATAด้วย - โหลดโครงสร้างอุปกรณ์ต่อพ่วงและแผนที่หน่วยความจำของ ESP32 ด้วย SVD-Loader-Ghidra
- ใช้
SymbolImportScriptของ Ghidra เพื่อนำเข้าป้ายกำกับฟังก์ชัน ROM ของ ESP32 ทำให้ระบุฟังก์ชัน ROM ทั่วไปอย่างprintfได้ง่ายขึ้น
เบาะแสการเข้ารหัสที่พบจากสตริง
- ติดตามสตริงที่เห็นใน serial log และสตริงรอบข้างจาก
Defined Stringsของ Ghidra - ในสตริงรอบข้างพบเบาะแสดังต่อไปนี้
Message CRC errorSeed ErrorPRNG failECDH setup failedmbedtls_ecdh_gen_public failedmbedtls_ecdh_compute_shared failedMBED HKDF failedWrite ECC conn packet
- mbedtls เป็นไลบรารีโอเพนซอร์สที่ทำงานด้าน cryptographic primitives, การจัดการใบรับรอง X509 และการใช้งาน SSL/TLS กับ DTLS
- จากการที่มีการใช้ฟังก์ชัน ECDH และ HKDF โดยตรง และไม่ได้ใช้ DTLS จึงวิเคราะห์ได้ว่าได้มีการทำ key exchange และ key derivation ภายในโปรโตคอลที่พัฒนาขึ้นเอง
- สตริง
ECC conn packetแสดงให้เห็นว่าแพ็กเก็ตเชื่อมต่อแรกเกี่ยวข้องกับกระบวนการแลกเปลี่ยนกุญแจ ECDH
แพตช์เฟิร์มแวร์เพื่อตัดการพึ่งพาแผงควบคุม
- การวิเคราะห์ขณะเชื่อม PCB กับพัดลมและแผงควบคุมนั้นไม่สะดวก จึงถอดแผงควบคุมออก แต่ระหว่างบูตเกิด panic พร้อม log
No Cap device found! - ฟังก์ชันรอบสตริง
No Cap device found!พิมพ์CapSense Initออกมาด้วย จึงสรุปได้ว่าเป็นลอจิกเริ่มต้นอินพุตแบบ capacitive ของแผงด้านหน้า - ใน Ghidra ตั้งชื่อฟังก์ชันนั้นว่า
InitCapSenseและตั้งชื่อ service ที่เรียกมันว่าStartCapSenseService - เปลี่ยนคำสั่งเรียก
StartCapSenseServiceเป็นnopเพื่อตัดการเริ่ม service ของแผงควบคุมออก - แก้ไขไบต์ในอิมเมจ
part.3.factoryแบบดิบแล้วแฟลชกลับที่ออฟเซ็ต0x10000แต่บูตไม่ขึ้นเพราะ checksum ของอิมเมจ ESP32 ผิดพลาด - เพิ่มสคริปต์สำหรับซ่อม checksum ของ app partition โดยอ้างอิงลอจิกภายในของ esptool
- เมื่อนำอิมเมจที่ซ่อม checksum แล้วไปแฟลช อุปกรณ์ก็ทำงานได้ตามปกติแม้ไม่มีแผงควบคุม และการแก้ไขเฟิร์มแวร์ก็สำเร็จ
โครงสร้างส่วนหัวแพ็กเก็ตและ CRC
- จากการเปรียบเทียบแพ็กเก็ตระหว่างการบูตหลายครั้ง พบว่า 13 ไบต์แรกคล้ายกัน ส่วนที่เหลือดูเหมือนถูกเข้ารหัส
- รูปแบบส่วนหัวแพ็กเก็ตเป็นดังนี้
55: magic byte สำหรับระบุโปรโตคอล00 31: ความยาวแพ็กเก็ต02: ตัวระบุข้อความ01 23 45 67 89 AB CD EF FF: serial ของอุปกรณ์ 9 ไบต์
- แพตเทิร์นของ message ID มีดังนี้
0x02: แพ็กเก็ตแรกที่อุปกรณ์สมาร์ตส่งออก0x82: การตอบกลับแรกที่ cloud server ส่งมา0x01: แพ็กเก็ตถัดมาที่อุปกรณ์สมาร์ตส่งออก0x81: การตอบกลับถัดมาที่ server ส่งมา
- บิตบนใช้แยก client request กับ server response และบิตล่างใช้แยกการแลกเปลี่ยนครั้งแรกกับแพ็กเก็ตถัดไป
- ไล่ตามฟังก์ชันที่อ้างอิงสตริง
Message CRC errorเพื่อยืนยันลอจิกตรวจสอบ CRC - 2 ไบต์สุดท้ายเป็น checksum แบบ CRC-16 ของแพ็กเก็ตที่เหลือทั้งหมด
- พหุนามคือ
0x1021 - ค่าเริ่มต้นคือ
0xFFFF - ยืนยันด้วยวิธีเดียวกันจากหลายแพ็กเก็ตที่ดักจับได้
- พหุนามคือ
โฟลว์การสร้างกุญแจ ECDH/HKDF
- ในแพ็กเก็ตที่ดูเหมือนเป็นการแลกเปลี่ยนกุญแจครั้งแรก ข้อมูลที่ตัดส่วนหัว 13 ไบต์และ CRC 2 ไบต์ออกแล้วมีขนาด 32 ไบต์ ซึ่งตรงกับขนาด public key 256 บิต
- ใน client request มี
00 01นำหน้าอยู่ และค่าดังกล่าวไม่เปลี่ยนไปในแต่ละการบูต จึงถือว่าเป็นตัวบรรยายข้อมูล - ใน Ghidra ไล่ตามสตริง error เพื่อหาฟังก์ชันสร้างกุญแจ แล้วเทียบกับซอร์สของ mbedtls เพื่อสรุปในระดับ pseudocode
- ฟังก์ชันสร้างกุญแจทำงานดังนี้
- สร้างคู่กุญแจ ECDH ด้วย
mbedtls_ecdh_gen_public - พบลักษณะการเขียนทับกุญแจที่สร้างขึ้นด้วยกุญแจอีกชุดหนึ่งในหน่วยความจำ
- โหลด public key อีกตัวหนึ่ง
- คำนวณ shared secret ด้วย
mbedtls_ecdh_compute_shared - สร้างค่ารandom 32 ไบต์ด้วย
mbedtls_ctr_drbg_random - อนุมานกุญแจสุดท้ายด้วย
mbedtls_hkdf
- สร้างคู่กุญแจ ECDH ด้วย
- การตั้งค่า HKDF เป็นดังนี้
- แฮช:
SHA-256 salt: shared secret ของ ECDHinput: ค่าสุ่ม 32 ไบต์ที่อุปกรณ์สร้างขึ้นinfo: serial ของอุปกรณ์ 9 ไบต์- ขนาดกุญแจผลลัพธ์:
0x10หรือ 16 ไบต์
- แฮช:
- ฟังก์ชันที่ถูกเรียกได้ส่งข้อมูลขนาด
0x22ไบต์ โดยนำค่าสุ่ม 32 ไบต์ไปต่อท้าย00 01ซึ่งตรงกับรูปแบบแพ็กเก็ตแลกเปลี่ยนกุญแจแรกที่ดักจับได้
การพิมพ์ shared secret และการถอดรหัส AES
- การคำนวณกุญแจสำหรับถอดรหัสขั้นสุดท้ายจำเป็นต้องใช้ shared secret ของ ECDH
- แทนที่จะดีบักผ่าน JTAG ได้ทำการแพตช์เฟิร์มแวร์โดยเขียนทับตำแหน่งลอจิก CapSense ที่ปิดใช้งานไปแล้วด้วยฟังก์ชันแบบกำหนดเอง เพื่อพิมพ์ shared secret ออกทาง serial
- แทรกการเรียกฟังก์ชันทันทีหลังจากสร้าง shared secret ใน
GenerateNetworkKeyและใช้ key pointer ในรีจิสเตอร์เพื่อพิมพ์ข้อมูล 32 ไบต์ - ตอนบูต shared secret ถูกพิมพ์เป็นเลขฐานสิบหกหลัง
Write ECC conn packetและแม้รีบูตหลายครั้งค่าก็ไม่เปลี่ยน - ยืนยันกุญแจผลลัพธ์จาก HKDF ได้ด้วยแพตช์อีกตัว และสามารถทำซ้ำลอจิกสร้างกุญแจเดียวกันจากแพ็กเก็ตที่ดักจับได้
- ภายในฟังก์ชันเข้ารหัสพบตารางคงที่ที่ขึ้นต้นด้วย
63 7C 77 7B F2 6B 6F C5ซึ่งตรงกับ AES Forward S-Box ของ mbedtls - รูปแบบการเข้ารหัสสุดท้ายคือ AES-128-CBC และค่าสุ่ม 16 ไบต์ในแพ็กเก็ตถูกใช้เป็น IV
- ในแพ็กเก็ตที่ถอดรหัสแล้วพบค่าที่อ่านได้ เช่น
mirror_data_get,FAN_SPEED,BOOST,FILTER1,FILTER2
การทำ MITM proxy
- ได้ private key ของอุปกรณ์และลอจิกการอนุมานกุญแจแล้ว อีกทั้งข้อมูลไดนามิกที่จำเป็นก็เปิดเผยอยู่บนเครือข่าย จึงสามารถเขียน MITM proxy ได้โดยไม่ต้องแพตช์เฟิร์มแวร์
- สคริปต์ Node.js สร้าง local UDP socket และ UDP socket สำหรับ cloud server แล้วส่งต่อแพ็กเก็ตได้สองทาง
- แพ็กเก็ตที่รับจากอุปกรณ์สมาร์ตจะถูกบันทึก log แล้วส่งต่อไปยัง cloud server และแพ็กเก็ตที่รับจาก cloud server ก็จะถูกบันทึก log แล้วส่งต่อไปยังอุปกรณ์สมาร์ต
- มองแพ็กเก็ตที่
messageIdเป็น2ว่าเป็นแพ็กเก็ตแลกเปลี่ยนกุญแจ และใช้ค่าสุ่มภายในนั้นในการคำนวณกุญแจ AES สำหรับแพ็กเก็ตถัดไป - ระหว่างควบคุมอุปกรณ์ด้วยแอปมือถือ ได้สะสม log จาก MITM เพื่อยืนยันรูปแบบ request และ response ที่จำเป็นต่อการพัฒนา local server
โครงสร้างข้อความ MessagePack
- ข้อมูลที่ถอดรหัสแล้วยังคงอยู่ในรูปแบบการซีเรียลไลซ์แบบไบนารี
- เฮดเดอร์ข้อมูลภายในดูเหมือนจะเป็น ID และความยาวแบบ little-endian
01 00: packet ID64 00: transaction ID29 00: ความยาวข้อมูลที่ซีเรียลไลซ์
- เดิมมีการย้อนวิศวกรรมรูปแบบการซีเรียลไลซ์ด้วยตัวเองบางส่วน แต่เมื่อตรวจสอบแล้วพบว่าเป็น MessagePack
- หากใช้ implementation อย่าง
msgpackrก็สามารถแปลงข้อมูลไบนารีออกมาเป็นรูปแบบ JSON ได้ง่าย - ข้อความหลักที่ยืนยันได้มีดังนี้
- การแลกเปลี่ยนคีย์: อุปกรณ์ส่งไบต์สุ่มที่ใช้กับ HKDF ไปยังเซิร์ฟเวอร์
mirror_data_get: ดึงสถานะเริ่มต้นจากเซิร์ฟเวอร์ตอนบูตconnect: ส่ง UUID ของเฟิร์มแวร์ปัจจุบัน และเซิร์ฟเวอร์จะตอบกลับข้อมูลเฟิร์มแวร์ การตั้งค่า เวลา และที่อยู่เซิร์ฟเวอร์mirror_data: เซิร์ฟเวอร์เปลี่ยนสถานะของอุปกรณ์ หรืออุปกรณ์รายงานสถานะที่เปลี่ยนไปกลับไปยังเซิร์ฟเวอร์keep_alive: อุปกรณ์ส่งสถานะเป็นระยะ เช่น RSSI, RTT, packet drop, จำนวนครั้งที่เชื่อมต่อ, uptime เป็นต้น
MQTT bridge และการเชื่อมต่อกับ Home Assistant
- ใช้ MQTT เพื่อเชื่อม Home Assistant กับ custom server
- ใน Home Assistant มีการตั้งค่าแอดออน Mosquitto ซึ่งเป็น MQTT broker แบบโอเพนซอร์ส
- โครงสร้างการเชื่อมต่อเป็น
Home Assistant↔MQTT Broker↔Custom Server↔Smart Device - custom server ทำงานดังนี้
- เมื่ออุปกรณ์ร้องขอสถานะด้วย
mirror_data_getจะตอบกลับโดยใช้ค่า retained ของ MQTT broker หรือใช้ค่าเริ่มต้น - เมื่อ Home Assistant ส่งคำสั่งเปลี่ยนสถานะไปยัง MQTT topic, custom server จะส่งต่อคำสั่งนั้นไปยังอุปกรณ์
- หากสถานะอุปกรณ์เปลี่ยนไม่ว่าด้วยเหตุผลใด custom server จะ publish และ retain แพ็กเก็ต
mirror_dataของอุปกรณ์ไปยัง MQTT broker
- เมื่ออุปกรณ์ร้องขอสถานะด้วย
- แหล่งข้อมูลจริงของสถานะเป็นอุปกรณ์เสมอ
- หากการอัปเดตสถานะล้มเหลว จะไม่แสดงบน MQTT broker ว่าอัปเดตแล้ว
- แม้สถานะจะเปลี่ยนผ่านแผงควบคุมจริง ก็จะสะท้อนไปยัง MQTT broker
- ใช้การรวมระบบ MQTT Fan ของ Home Assistant เพื่อแมปเครื่องฟอกอากาศเป็นอุปกรณ์พัดลม
- ใน
configuration.yamlมีการตั้งค่า topic สถานะพลังงาน, command topic, topic สถานะความเร็วพัดลม, topic คำสั่งความเร็วพัดลม และช่วงความเร็ว1~4 - ตั้งค่าให้ local DNS ของ Pi-hole แก้โดเมนคลาวด์ของผู้ผลิตให้ชี้ไปยัง custom server เพื่อให้เซิร์ฟเวอร์ภายในเครื่องทำหน้าที่เป็นเซิร์ฟเวอร์ของอุปกรณ์
การประเมินความปลอดภัยและผลลัพธ์
- ผู้ผลิตเลือกใช้โปรโตคอลที่พัฒนาขึ้นเองแทนโปรโตคอลมาตรฐานอย่าง DTLS
- ยังไม่แน่ชัดว่าแต่ละอุปกรณ์มี private key เฉพาะของตัวเองหรือไม่ แต่ไม่ว่ากรณีไหนก็มีข้อเสีย
- หากทุกอุปกรณ์ใช้ private key ของเฟิร์มแวร์ร่วมกัน เพียงย้อนวิศวกรรมอุปกรณ์เครื่องเดียวก็อาจพยายามทำการโจมตี MITM กับอุปกรณ์อื่นได้
- หากแต่ละอุปกรณ์มี private key เฉพาะ เซิร์ฟเวอร์ก็ต้องเก็บ mapping ระหว่าง serial number กับคีย์ของอุปกรณ์ และหากข้อมูลนี้สูญหาย เซิร์ฟเวอร์จะไม่สามารถตอบสนองการสื่อสารของอุปกรณ์ได้
- มี static private key ฝังอยู่ในเฟิร์มแวร์ ทำให้ผู้โจมตีสามารถดึงคีย์จากการ dump เฟิร์มแวร์เพียงครั้งเดียวแล้วทำการโจมตี MITM ได้
- ตัว implementation ไม่ได้แย่ไปเสียทั้งหมดในมุมมองด้านความปลอดภัย และการโจมตียังคงต้องอาศัยการเข้าถึงตัวอุปกรณ์จริง
- การพัฒนาขึ้นเองทำให้การสื่อสารเครือข่ายดูทึบขึ้น แต่ Security through obscurity ใกล้เคียงกับการชะลอการโจมตีทั่วไปที่มุ่งเป้าไปยัง implementation มาตรฐานได้เพียงชั่วคราว และยังเป็นอุปสรรคที่ผู้โจมตีข้ามผ่านได้
- บรรลุเป้าหมายสุดท้ายคือการเชื่อมต่อกับ Home Assistant และเครื่องฟอกอากาศทำงานได้โดยไม่มีปัญหาตลอดหลายสัปดาห์
- ยังตั้งค่า automation ให้เร่งเครื่องฟอกอากาศช่วงเวลาหนึ่งเมื่อค่าฝุ่น PM2.5 หรือ VOC จาก air monitor แยกต่างหากสูงเกินไป
ยังไม่มีความคิดเห็น