Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Confusion on how to OTA #3

Closed
handonam opened this issue May 10, 2022 · 17 comments
Closed

Confusion on how to OTA #3

handonam opened this issue May 10, 2022 · 17 comments

Comments

@handonam
Copy link

handonam commented May 10, 2022

Hey Kendall! Great work on opening a new door with Switchbot and Tasmota!

tl;dr: I was wondering how you 'hijacked' the DNS to do OTA. It wasn't too clear in the guide, but would be helpful for other people coming to this document.

I'm currently trying to figure out how to properly DNS-hijack (or DNS Spoof) to send the file over to the devices. Currently, I'm running OPNSense, which should theoretically allow me to set any device's DNS to point somewhere else. Here's what I had going:

  • 192.168.x.99 Switchbot
  • 192.168.x.68 Macbook, running the node server @ port 80
  • 192.168.x.13 iPhone, which has the Switchbot app.

I set the DNS for both Switchbot and iPhone to use 192.168.x.68. However, after clicking upgrade, the macbook isn't loading files OTA.

I know the server is working if i go on mobile safari/chrome/ff-mobile, hitting http://192.168.x.68 directly, which allows me to "download" a fie. Furthermore, I know it's sending from the macbook via this console log i've placed in the app.get('*')

app.get('*', (req, res) => {
  const file = path.join(__dirname, 'bin', 'app.bin');
  console.log('File is sending...')
  res.setHeader('Content-Type', 'application/octet-stream');
  res.sendFile(file);
});

But, the issue is i'm missing the key knowledge piece to allow www.wohand.com to actually map to 192.168.x.68 here. Per document:

you'll need to modify your local DNS to serve the desired binary. Specifically, www.wohand.com should point to a local machine running the included web server.

Any guidance would be appreciated!

@kendallgoto
Copy link
Owner

Hi there!

For clarity on the general process of how DNS hijacking is used:

  1. When the plug connects to your internet, the router/plug's DHCP handshake provides a DNS server to use - typically the router itself
  2. The plug resolves www.wohand.com into an IP address by asking the DNS server for an IP address
  3. The DNS server / router serves whatever IP address its configured / knows to use. We hijack the request by telling our DNS server to serve a local IP address instead of the true IP address of the website
  4. The plug downloads the firmware from the specified IP address, downloading our injected firmware instead of the actual firmware.

Configuring the DNS spoofing part is very dependent on one's resources and network configuration - so I didn't include that much documentation. For many, its easiest to create an Ad-Hoc hotspot (on your laptop for example) that has a DNS override to catch the resolution of www.wohand.com (I believe MacOS does this automatically if you create a wifi hotspot and add a 127.0.0.1 www.wohand.com line in /etc/hosts, making connected clients resolve wohand.com to the local machine).

If you use a "smarter" router OS (like Ubiquiti's, pfSense, OpenWRT, OPNSense come to mind), it's not too hard to setup alternative DNS resolutions. I use pfSense for my home router & resolve DNS with the built-in "DNS Forwarder". Generally, this forwards all of my DNS requests directly to a third party DNS service; however it also allows me to make overrides:

pfSense DNS Forwarder Config

pfSense also has a DNS resolver that can be used instead that actually handles the DNS resolution manually, which also allows for a similar "Host Override"

I'm less familiar with OPNSense, but I believe you can configure the builtin Unbound DNS service with a host override in the GUI - it should be fairly similar to the pfSense screenshot I sent above. The only issue would be if you are currently using third-party DNS resolution (for example, your DHCP config tells clients to use 8.8.8.8 for all DNS queries, instead of your router) -- if that's the case, you'd probably be best using the ad-hoc method I mentioned above

If you happen to be using Pi-hole to handle your DNS, you may instead have to adjust the Unbound configuration via the Pi.

I'd love to document this better but the extreme breadth of configurations makes it a bit verbose + hard to offer much support for. Additionally, since this is just a proof of concept, I want to be careful to not make the process "too straightforward" to avoid someone accidentally bricking their devices, if that makes sense.

Please let me know if this helps & you're able to get your device working! Testing DNS changes is a bit tedious since your computer will cache the results, however, the end goal is that dig www.wohand.com in a terminal on the plug's network should show a local A record:

;; ANSWER SECTION:
www.wohand.com.		1	IN	A	10.0.1.210

@handonam
Copy link
Author

I'd love to document this better but the extreme breadth of configurations makes it a bit verbose + hard to offer much support for.

Totally understood. I figured i'd glean into how you approached this. Very lucky you had gone in a very similar direction i did.

In regards to how your pfSense looks compared to OPNSense, your Services / DNS Forwarder / Edit Host Override is actually under Services -> Dnsmasq DNS. Therefore, very similar
Screen Shot 2022-05-09 at 8 14 12 PM

However, I have a custom setup for unbound, which works its magic with pi-hole.

therefore, I went to pi-hole to do that work, and managed to get it working there:
Screen Shot 2022-05-09 at 8 10 32 PM

So that totally works! Thank you!!

The only issue now is that I already updated my firmware for two of my switches to the latest SwitchBot firmware, meaning the button is disabled ;(.

Therefore, I need to figure out how to spoof the XML to pretend there's a newer update. Going to dive into that now.

@kendallgoto
Copy link
Owner

Don't look too far! You can actually just trigger an update with a well crafted bluetooth packet. It's a little bit tricky and not documented, but if you connect to the device with a bluetooth app (I use nRF Connect) you can deliver a custom payload to trigger the firmware update

I don't have a plug to show directly what I mean, but if you connect to a plug and view its characteristics, you can write to the first one listed by pushing the up arrow: image

Select byte array and enter the hex commands below - it should look like:
image

To start the firmware upgrade process, write:
57 0f 0a 01 0c

Then, after 40 seconds or so, reset the device and initiate the firmware exchange by writing
57 0f 0b

The plug should immediately make a relay click sound and reboot. Sorry I don't have photos to share - please let me know if it works & follow up if I can help further

@handonam
Copy link
Author

handonam commented May 10, 2022

Awesome!

So i actually did it with Bluetility on the mac, adding the hex and pressing enter, and that worked! Seemed to work fine:
Screen Shot 2022-05-09 at 9 16 38 PM

Few things to note:

  • Make sure your plug is connected to wifi by checking in SwitchBot Mobile App (your Switchbot device -> Wi-Fi Settings) and ensuring the SSID is right. Due to DNS Hijacking, it should be expected that it has trouble connecting to the internet.
  • Your phone may need to be off of wifi, so stay connected with bluetooth to your SwitchBot device. Otherwise, your phone will try to find a connection via wohand.com, which may fail.
  • Afterwards, close the SwitchBot app, otherwise the bluetooth will pair to the app, and not to bluetility

Thanks for sending me on my way! Maybe i can help you with the onboarding wiki for this as I'm also coming from a lesser-experienced ESP/IoT background.

Feel free to close this, unless you plan to add a few more things and then tagging this issue into a wiki. Thanks!

@kendallgoto
Copy link
Owner

Closing this now - da7a8a7 links here in the README ... if more people have questions / confusions, I'd be happy to tack on a more detailed wiki describing the install / setup process and its quirks.

@linagee
Copy link
Contributor

linagee commented May 23, 2022

Serving spoofed DNS from index.js and temporary changing DNS IPs to our local computer's IP might be easier than trying to figure out how to spoof DNS for your particular router. See PR: #16

@smartmatic
Copy link

To start the firmware upgrade process, write: 57 0f 0a 01 0c

Then, after 40 seconds or so, reset the device and initiate the firmware exchange by writing 57 0f 0b

The plug should immediately make a relay click sound and reboot. Sorry I don't have photos to share - please let me know if it works & follow up if I can help further

Hi

i am struggling a bit to get this method working for a Switchbot Bulb. The web server is running and if i try to open www.wohand.com i see in the console logs of the web server that the request is redirected to my machine. So i think the web server part is correct configured.

But can it be that the codes to start the upgrade process are different for the light bulb compared to the Plug?

@kendallgoto
Copy link
Owner

@smartmatic I don't personally have a Switchbot Bulb to test, but I wouldn't be surprised if the BLE command differed (I believe the first 2 bytes are a device identifier 57 0f, so this likely changes at bare minimum.

I believe @Cossid has a Switchbot Bulb - could you take a look at this?

@Cossid
Copy link
Contributor

Cossid commented Aug 22, 2022

Bulbs come out of the box with 1.2 with an upgrade to 1.4 already available, so I'm not sure anyone has needed to use the Bluetooth method. I'll see if we can probe the firmware for values, but will need some time, on vacation and won't have pc access for a few days.

@Cossid
Copy link
Contributor

Cossid commented Aug 23, 2022

Smartmatic joined us on discord and I believe it has been found that they had dns/dhcp issues. Others have stated the byte code for plugs and bulbs is the same, just following up here for reference.

@ivlis
Copy link

ivlis commented Oct 10, 2022

It seems it does not work anymore.

After 57 0f 0a 01 0c the plug downloads /version/wocaotech/firmware/WoPlugUS/WoPlugUS_V12.bin
but after that it fails to download the payload.bin.

I tried resetting the plug, sending 57 0f 0b in different combinations - no dice. The plug came with v1.3 firmware.

Edit:
It worked after I sent 57 0f 0a 01 0d as a first command.

@peddamat
Copy link

For folks cutting and pasting on their phones, the codes are:

570f0a010d

570f0b

@cendern
Copy link

cendern commented Mar 29, 2023

Got a 4-pack of these from Amazon last week as a gift, so I'm keeping them even though they don't work. They have Firmware Version 1.4 and do not respond to either of the BT commands sent using the nRF Connect app. Don't buy any more of these until a fix has been found that works for 1.4.
I would be happy to test out any suggestions the community has.

@cendern
Copy link

cendern commented Mar 29, 2023

Am I'm just interpreting nRF Connect incorrectly? It looks like I'm using a different version (Android 4.26.1) from the one that's screenshotted above.
My 'Unknown Characteristic' entry has Properties: WRITE, WRITE NO RESPONSE where the example above says Write, Notify, and Extended Properties, but maybe that's just a result of the (newer?) version I'm using displaying the same information differently. Note that there's not a line below "Value" in the screenshot below (screenshot above shows both Value: and Value Written:).
nRF Connect screenshot

I'm using the included Node server app to intercept requests to www.wohand.com. Requests from my browser to that domain show in the Node app, and my router gives out the same DNS to all clients. Pretty sure that's not the problem.

browser and Node output

@kendallgoto
Copy link
Owner

@cendern FW version v1.4 was tested back in July when it came out on the HomeKit edition plugs; #19 (comment). Also from testimonial here: #38 (comment)

The latest version seems to be currently 1.5 (#23). I installed 1.5 on a fresh plug via the standard UI, then used

57 0f 0a 01 0c
...
57 0f 0b

to install down to version v1.2 (I didn't have switchbota running; so it just fetched the actual v1.2 binaries from wohand). I assume your plugs are connected to a network, right? Switchbota aside, 57 0f 0a 01 0c should trigger an update to v1.2 and 57 0f 0b should trigger a reset from official wohand servers if the plug has internet access, at least on v1.5. If that doesn't work at all, what's the hardware revision of your plug - model # and FCC ID# printed on the side.

@cendern
Copy link

cendern commented Mar 30, 2023

Thanks for the reply and I really appreciate all the work you've done to uncover and share all this info!
The reason it wasn't working for me was...me. I had put the SwitchBot on a guest network that didn't have access to the machine running the Node app. I just got the first one flashed.
A few additional notes:

  • nRF Connect allows you to send the byte array as either a 'request' or a 'command'. Not sure if it matters, but it worked for me when I used 'request'.
  • I used the BT value ending in 0c not 0d
  • I interpreted 'reset' in the instructions above as 'unplug the SwitchBot from the outlet'
  • After plugging it back in again I was unable to connect to it via bluetooth to send the second sequence. I thought maybe I had bricked it (couldn't get the LED to light up with any combo of button press/long press/unplug) but it turns out that it had already flashed to Tasmota 11.1.0 and was serving its wifi creds AP.

@kendallgoto
Copy link
Owner

kendallgoto commented Mar 30, 2023

To provide a bit more context:

  • I've always used request.
  • 0c/0d/etc doesn't matter; its a hex encoded target version number (i.e. v1.2 = 0x0C = 12; v1.3 = 0x0D = 13). As long as it differs from your installed version, it'll trigger an update. The reason people needed to switch from 0c to 0d before was because v1.2 became the factory installed version, so users couldn't "target" v1.2/0x0c. (AFAIK). I had v1.1 first iteration plugs when I wrote the initial documentation since v1.2 wasn't in GA, but now its largely irrelevant since v1.4/v1.5 are factory standard. From recollection, the command literally runs sprintf("http://www.wohand.com/version/wocaodebug/firmware/WoPlugUS/WoPlugUS_%d.bin", value).
  • The second command itself triggers a reset. If you unplug and plug back in and it worked, then the second command is irrelevant. Specifically, if I recall correctly, the second command requests the update progress from the device - if you do it early, i.e. within the first 10 seconds of the update, it'll report back a hex value indicating completion 0-100. If the completion is 100, then the command reports 100 back and also triggers a self reset. Thus, using the command guarantees safety by ensuring the plug is actually ready to be reset rather than unplugging it, and also allows for performing the full process w/o physical interaction. If you unplug the plug and it happens to still be in the middle of flashing, you'll end up with a sad, bricked plug.

Locking this thread since it's linked off the README; if you have a related issue please open a separate issue.

Repository owner locked as resolved and limited conversation to collaborators Apr 4, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants