tuya-cloudcutter / lightleak

Firmware version-agnostic PoC exploit for smart devices
47 stars 10 forks source link

Couldn't receive packages from the device #3

Open jpbarrettob opened 1 year ago

jpbarrettob commented 1 year ago

Hi,

I keep getting the error "Couldn't receive packages from the device" while trying to read the flash from a bulb. Tried selecting BK7231N - Variant 1 ( Standard), BK7231N - Variant 1 ( XOR) and BK7231N - Variant JTAG ( XOR) but they all get the same error.

-- UPDATE--

I opened one of the bulbs and it's using a WB2L chip, from what I found online the WB2L is a BK7231T chip, I tried selecting the BK7231T profile just gives me an "The device doesn't respond to ping requests" error.

kuba2k2 commented 1 year ago

You probably need to try again. If you know it's using WB2L, then just use BK7231T profile, as the N won't work.

If it still shows the same message, check the firmware version in the Tuya app. Also, post Lightleak logs (from the folder you've chosen) and a screenshot showing the error.

jpbarrettob commented 1 year ago

Tried multiple times selecting the BK7231T profile, always getting the same error "The device doesn't respond to ping requests" which is wired since I can confirm it is a WB2L. Tried checking the firmware version on the Tuya App, but unfortunately it is asking me to update to the 3.0.1 version, so it doesn't show the current version. Attached the log and screenshot showing the error. Screenshot_20221224-163328_Cloudcutter log_exploit.txt

kuba2k2 commented 1 year ago

From the log I can see that it dropped you out of the wifi around 15 seconds after checking the exploitability status. Did the device stop blinking or reboot?

We've never seen a device with 3.0.x firmware version, so it's likely that it's actually not exploitable using Lightleak. If you can create an account on iot.tuya.com to get the "product key" of the device, I can try to grab the 3.0.1 update and check if it should work.

kuba2k2 commented 1 year ago

There's also an app called "Sniffer" on Google Play (with an orange dog icon). If you put the device in pairing mode and run the app, it will show some hexadecimal data for a device named "TY". That data should contain the Product Key, so you can post a screenshot of that or copy the hex bytes here.

jpbarrettob commented 1 year ago

It does stop Blinking and tells me "The device exited Ap mode.." and asks me to restart the device, after I restart the device it does connect again and stops blinking, right after that it gives me the error "The device doesn't respond to ping requests" about a minute later it restarts and starts blinking again.

It is possibly that the device is not exploitable, although I got this lights back in 2020, and the 3.0.1 update has been out since I got them. I just never updated some of them. According to the update info the only changes are the the increase from 3 to 7 power cycles in order to reset the bulb and the "Do not Disturb" function that allow the user to select the bulb state after a power loss.

This is the Device ID from the bulb that is asking for the update eb87433fcad3214f4beuja

And this is the Device ID from a bulb that is already on 3.0.1 ebe250baa820378fcewjkm

kuba2k2 commented 1 year ago

The situation you're describing most likely means that it's not exploitable using the current Lightleak profile - crash after 1 minute is the most obvious symptom.

The 3.0.1 version is a new one, which may indicate that the software was compiled by the manufacturer (as opposed to using standard Tuya firmwares). The SSID prefix "Positivo" is also not something we've seen before.

If that's the case, the manufacturer could've changed some settings of the compilation, which make Lightleak incompatible. It might also just be a different bootloader which needs a profile. Or a different SSID encryption setting (like Standard vs XOR), but I haven't seen any encryption on BK7231T yet.

The device ID you posted is not what I need - the product key is something different. It's easiest to check using the sniffer app I mentioned.

jpbarrettob commented 1 year ago

Got two different results on Sniffer searching for the TY device

First

02 01 06 03 02 01 A2 14
16 01 A2 01 F9 09 B3 39
FA 2D 7A 67 05 FF 01 07
BB DB D8 84 03 09 54 59
19 FF D0 07 80 03 00 00
0C 00 87 B5 CA F1 C9 CF
DA 6E CA 7F B3 82 2D B8
08 59

Second

02 01 06 03 02 01 A2 14
16 01 A2 01 6B 65 79 74
67 35 6B 71 38 67 76 6B
76 39 64 68 03 09 54 59
19 FF D0 07 00 03 00 00
04 00 3B 7E BA 2E 02 18
67 5C D0 6B 05 F8 CB B7
A3 6A

Converting the data to ASCII results in some gibberish in the first device, and the second device gives me something that I think is what you're looking for keytg5kq8gvkv9dh - This is from the device that hasn't been updated to 3.0.1

kuba2k2 commented 1 year ago

This is the Firmware Key - I thought this will show the PK but apparently it doesn't. You can create an account on iot.tuya.com, go to Cloud -> Development -> Create Cloud Project. Then, click on the project, go to Devices -> Link Tuya App Account. After doing that, go to Cloud -> API Explorer -> Smart Home Device System -> Device Management -> Batch query for the list of associated App user dimension devices -> Submit Request. The resulting JSON should include product_id for the device in question.

jpbarrettob commented 1 year ago

Already had an account on iot.tuya.com

This is the product_id for a bulb that hasn't been updated to firmware 3.0.1 hikdqiki4afxjzpx This is the product_id for a bulb already on firmware 3.0.1 v1bsbjn80zmeo1yk

Cossid commented 1 year ago

keytg5kq8gvkv9dh indicates it is a standard oem_bk7231s_light_ty so 3.0.0 means this has a better than 0 chance of being SDK 2.3.2. Question is if it's the older vulnerable version (still missing a reversed exploit) or the patched version. The AP SSID prefix is just a configuration settings (gw_bi->ap_ssid)

kuba2k2 commented 1 year ago

If 3.0.1 is there since 2020, it's not the patched version and probably the vulnerable version. I'll check if I can pull the update.

Cossid commented 1 year ago

Ah, I missed that they are from 2020. Really strange for a 3.x with a Beken in that time period.

kuba2k2 commented 1 year ago

I can't pull the update from Tuya API. We didn't yet figure out what exactly is needed to make the API return an update URL. I'm only able to do this for one Firmware Key that @Cossid has.

Since 3.0.1 is new for us, both Lightleak and Cloudcutter won't work unless we get a firmware dump. I know that WB2L is pretty much impossible to serial-dump without desoldering, but there's not much else we can do at the time.

kuba2k2 commented 1 year ago

I found a different way of getting the upgrade URL, somewhat easier to perform on your side.

  1. Create a package.json file in an empty directory.
    {
    "dependencies": {
    "@tuyapi/cloud": "^0.6.0"
    },
    "scripts": {
    "start": "node index.js"
    }
    }
  2. Run npm install. Create index.js file as well.
    
    const Cloud = require('@tuyapi/cloud');
    const debug = require('debug');

debug.enable("@tuyapi/cloud");

let api = new Cloud({ key: "3cxxt3au9x33ytvq3h9j", secret: "5gdtanjtf38vyxkqh87cjwfcqjhvjjqa", secret2: "f3hd7pet4p83kemjdf5wqsa5tavrv579", certSign: "93:21:9F:C2:73:E2:20:0F:4A:DE:E5:F7:19:1D:C6:56:BA:2A:2D:7B:2F:F5:D2:4C:D5:5C:4B:61:55:00:1E:40", apiEtVersion: '0.0.1', region: 'AZ', // replace with EU if appropriate endpoint: "https://a1.tuyaus.com/api.json", // replace with tuyaeu.com if appropriate // sid: "", });

api.loginEx({ email: "YOUR_APP_EMAIL", password: "YOUR_APP_PASSWORD" }).then(async sid => { console.log(sid); });

3. Run it using `npm start` - it should print some debugging info, as well as your new SID (session ID). It looks like `az167122p2038823CnhFaqh32d6a070d2b0adffb54d6808335acdd3a`.
4. Paste the SID into the `index.js` - uncomment the `sid: ""` line and put it there.
5. Check the Device ID in the Tuya app (`Virtual ID`). Remove the `api.loginEx()` block and paste this instead:
```js
api.request({
    action: "tuya.m.device.check.for.updates",
    data: {
        "devId": "PUT_YOUR_DEVICE_ID_HERE",
    },
}).then(async data => {
    console.log(data);
});
  1. Run npm start again. It should print the update details in a JSON-like format, including the current FW version, the updated FW version, and - the firmware download URL.
jpbarrettob commented 1 year ago

Here is the resulting JSON

{
  productUpgrade: [ { currentVersion: '1.0.0', upgradeStatus: 0 } ],
  ota: [
    {
      devType: 0,
      typeDesc: 'Main Module',
      canUpgrade: true,
      type: 0,
      firmwareDeployTime: 1630511310,
      version: '3.0.1',
      url: 'https://images.tuyaus.com/smart/firmware/upgrade/202107/1626078774-oem_bk7231s_light_ty_yb_UG_3.0.1.bin',
      timeout: 60,
      currentVersion: '1.1.2',
      upgradingDesc: '1. Please keep the power of the device connected during the upgrade process.\n' +
        '2. The device will not be used during the upgrade process, please be patient.',
      upgradeStatus: 1,
      controlType: 0,
      fileSize: '677648',
      upgradeType: 0,
      lastUpgradeTime: 0,
      md5: '0fdd36f63bb45b9f98bf577409bf0e9d',
      desc: 'Alterações para melhoria de experiência:\n' +
        '-Número de toques no interruptor para reset de 3 para 7 vezes\n' +
        '-Incluída função "Não perturbe" para que a lâmpada não retorne acesa em caso de queda de energia'
    },
    {
      devType: 0,
      typeDesc: 'MCU Module',
      type: 9,
      timeout: 60,
      currentVersion: '1.1.2',
      upgradeStatus: 0,
      controlType: 0,
      lastUpgradeTime: 0
    }
  ]
}

This is the 3.0.1 update URL https://images.tuyaus.com/smart/firmware/upgrade/202107/1626078774-oem_bk7231s_light_ty_yb_UG_3.0.1.bin

And from what I understand the current version is 1.1.2

kuba2k2 commented 1 year ago

Yes, the current version is 1.1.2. I'll check the firmware later, if it's exploitable or different in any way.

Still, if the bootloader differs, we'll not be able to perform Lightleak without having the BL. But having the 3.0.1 firmware itself should be enough to build a cloudcutter profile.

kuba2k2 commented 1 year ago
hexdump -C 1626078774-oem_bk7231s_light_ty_yb_3.0.1.bin | grep -A 15 -B 5 "TUYA IOT"
000ef0e0  20 64 6e 73 20 69 6e 66  6f 20 6e 6f 77 20 70 72  | dns info now pr|
000ef0f0  69 6f 20 25 64 20 72 65  67 69 6f 6e 20 25 64 00  |io %d region %d.|
000ef100  74 6c 73 20 63 65 72 74  20 65 78 70 69 72 65 64  |tls cert expired|
000ef110  00 6c 6f 63 61 6c 20 63  65 72 74 20 65 78 69 70  |.local cert exip|
000ef120  72 65 64 2e 20 72 65 71  75 69 72 65 20 4e 65 77  |red. require New|
000ef130  20 43 41 00 3c 20 54 55  59 41 20 49 4f 54 20 53  | CA.< TUYA IOT S|
000ef140  44 4b 20 56 3a 31 2e 30  2e 38 20 42 53 3a 34 30  |DK V:1.0.8 BS:40|
000ef150  2e 30 30 5f 50 54 3a 32  2e 32 5f 4c 41 4e 3a 33  |.00_PT:2.2_LAN:3|
000ef160  2e 33 5f 43 41 44 3a 31  2e 30 2e 32 5f 43 44 3a  |.3_CAD:1.0.2_CD:|
000ef170  31 2e 30 2e 30 20 3e 0d  0a 3c 20 42 55 49 4c 44  |1.0.0 >..< BUILD|
000ef180  20 41 54 3a 32 30 32 31  5f 30 34 5f 32 31 5f 31  | AT:2021_04_21_1|
000ef190  32 5f 31 31 5f 34 39 20  42 59 20 65 6d 62 65 64  |2_11_49 BY embed|
000ef1a0  20 46 4f 52 20 74 79 5f  69 6f 74 5f 77 66 5f 62  | FOR ty_iot_wf_b|
000ef1b0  74 5f 73 64 6b 5f 62 6b  20 41 54 20 62 6b 37 32  |t_sdk_bk AT bk72|
000ef1c0  33 31 74 20 3e 0d 0a 49  4f 54 20 44 45 46 53 20  |31t >..IOT DEFS |
000ef1d0  3c 20 57 49 46 49 5f 47  57 3a 31 20 44 45 42 55  |< WIFI_GW:1 DEBU|
000ef1e0  47 3a 31 20 4b 56 5f 46  49 4c 45 3a 30 20 53 48  |G:1 KV_FILE:0 SH|
000ef1f0  55 54 44 4f 57 4e 5f 4d  4f 44 45 3a 30 20 4c 49  |UTDOWN_MODE:0 LI|
000ef200  54 54 4c 45 5f 45 4e 44  3a 31 20 54 4c 53 5f 4d  |TTLE_END:1 TLS_M|
000ef210  4f 44 45 3a 32 20 45 4e  41 42 4c 45 5f 4c 4f 43  |ODE:2 ENABLE_LOC|
000ef220  41 4c 5f 4c 49 4e 4b 41  47 45 3a 30 20 45 4e 41  |AL_LINKAGE:0 ENA|

SDK version 1.0.8 - I don't think we've seen that version before.

jpbarrettob commented 1 year ago

I've been trying to follow along here, is there a reason why hexdump -C 1626078774-oem_bk7231s_light_ty_yb_3.0.1.bin | grep -A 15 -B 5 "TUYA IOT" gives no result, am I missing something?

kuba2k2 commented 1 year ago

It does give a result. You have the UG file, which is encrypted and compressed. I ran this command on the unencrypted file. You can do this with this command:

ltchiptool soc bkpackager deota --key 0123456789ABCDEF0123456789ABCDEF --iv 0123456789ABCDEF

Cossid commented 1 year ago

SDK version 1.0.8 - I don't think we've seen that version before.

We have, 1.0.8 SDK is common and will work with Haxomatic. We also have some bulbs with 1.1.2 already cut (Euarne BR30, LSC 970715, but they're from the older 2.0.0 SDK). I haven't done much lightleak with BK7231T, does it currently only work with the 1.0.5 bootloader? I can easily point out 1.0.4. and 1.0.6 bins If a profile is needed for each.

The issue is without schema, we won't have a verified schema for cut mode. We can generate one to use local files, but won't add to the repository until we get the schema verified.

kuba2k2 commented 1 year ago

So it would be the best to make Lightleak work. LL should work with all known bootloaders (1.0.3, 1.0.4, 1.0.5, 1.0.6). I would need to check that 3.0.1 in IDA to see if it should work on Lightleak.

I have a 1.1.2 bulb as well (no update for it though) which I tried in the early Lightleak days, and was disappointed that it didn't work. The issue was just like yours - freezing ans rebooting after 1 minute. That may indicate 1.1.2 is problematic.

Did you try to Lightleak the other bulb with 3.0.1 already installed? (don't update the first bulb yet)

jpbarrettob commented 1 year ago

I tried on other bulbs that have already been updated to 3.0.1, but I get the same result.

jpbarrettob commented 1 year ago

Let me know if there is anything else I can do to help. I already have a bulb that i removed the cover to confirm that it was a WBL2, i could try desoldering the chip and perform a serial-dump if needed.

Also, I did try ltchiptool tool but got the following error

ERROR: ValueError: Invalid RBL CRC (expected 979E1A1C, found 30303030)
 - File "/home/joao/.local/lib/python3.10/site-packages/ltchiptool/cli/../../ltchiptool/soc/bk72xx/util/rbl.py", line 72, in deserialize
kuba2k2 commented 1 year ago

Right, I forgot you need to trim 32 bytes from the beginning:

dd if=<UG file> of=<output file> bs=32 skip=1
Cossid commented 1 year ago

positivo-bulb.zip

Here is a profile to cut 3.0.1. Extract it to your device-profiles then use -p positivo-bulb to cut. It just has a standard RGBCT bulb schema assigned, so may or may not work in cut mode.

@kuba2k2 if he cuts and flashes to ESPHome, is it possible to dump storage, or does ESPHome overwrite it? Also, is it possible to somehow do a full dump with bootloader from ESPHome?

kuba2k2 commented 1 year ago

Yes, it should be possible, but we'd need some code to do that (i.e. a custom component, or a route in the webserver). I haven't done that before, so there's no code to do that yet.

jpbarrettob commented 1 year ago

Just tried with the positivo-bulb profile, but unfortunately it did not work. I first tried on the bulb that hasn't been updated and got [!] The profile you selected did not result in a successful exploit.

So I assumed it had to be on 3.0.1 and tried on a bulb that was already on 3.0.1, it got a bit further, but eventually got Error: Connection activation failed: (53) The Wi-Fi network could not be found.

-- UPDATE--

I tried putting the bulb in AP mode again after the Connection activation failed: error, it connected but then gave me the error [!] The profile you selected did not result in a successful exploit.

Cossid commented 1 year ago

Yes, it should only work on the bulb already on 3.0.1. Can you post the full log please (masking any personal info)?

jpbarrettob commented 1 year ago

I attached the log. Even though it says it failed, I can no longer connect the bulb to the Tuya App, so I guess it kinda worked?

putty.log

Cossid commented 1 year ago

Did this device come with 3.0.1 or was it upgraded? There is a chance they somehow have a different compile. Log looks like a normal failure. Hopefully I haven't broken haxomatic.

jpbarrettob commented 1 year ago

As far as I remember, it was updated to 3.0.1 at some point. I got 5 bulbs back in 2020, 4 of them I updated to 3.0.1 at some point, the last one hasn't been updated yet. I haven't tried on all 4 bulbs that are on 3.0.1, just on o single one so far and got the result telling me [!] The profile you selected did not result in a successful exploit.

I also tried flashing a 3rd party firmware through cloudcutter, but it didn't work either.

Cossid commented 1 year ago

Well, I have verified haxomatic is outputting expected values. At this point my only theory is that putting the device into AP mode on a device that has taken an OTA update switches back to the original app partition. I'm not sure anyone has tried cutting an OTA updated device. I have dumped them, but I serial flashed. I'll try to test that theory in a couple days when I'm better equipped.

Cossid commented 1 year ago

Ah, we're offsetting expecting APP0, but OTA will usually be APP1, we probably need to offset the exploit addresses. Let me verify what app1 offset is, and I'll have an updated profile for you to test.

kuba2k2 commented 1 year ago

BK7231 doesn't have dual OTA. There's no APP0/1, there's only a "download" partition which is used by the bootloader. The image contained in download partition is decrypted and decompressed, then flashed to the app partition.

Cossid commented 1 year ago

After a bit of research, like @kuba2k2 said, there is only a single app partition on Beken devices, and the exploit addresses in the 3.0.1 profile appear valid. Unfortunately, I cannot test this any further, as I can't seem to get this on a device to better test myself.

uzlonewolf commented 1 year ago

dd if=<UG file> of=<output file> bs=32 skip=1

If you have a modern dd you can speed this up tremendously by doing dd if=<UG file> of=<output file> bs=1M skip=32 iflag=skip_bytes instead.