koalazak / dorita980

Unofficial iRobot Roomba and Braava (i7/i7+, 980, 960, 900, e5, 690, 675, m6, etc) node.js library (SDK) to control your robot
MIT License
945 stars 150 forks source link

Initial wifi configuration without using phone #106

Closed kumy closed 3 years ago

kumy commented 4 years ago

I didn't found anywhere how to setup the initial wifi configuration without using the official app.

So I've tried to check by myself, looking inside the application. The TLS connections from the java code was easily intercepted, but the application core is compiled in an Android native-library, for which I don't have the necessary skills to dissect it. I failed to decipher the mqtts conversation provisioning the AP wifi parameters as I wasn't able to SSL unpin the native library.

Does anyone have insight on how to accomplish this?

@koalazak I saw in this post https://github.com/koalazak/dorita980/issues/10#issuecomment-279260404 that you successfully sniffed the traffic between the app and the robot. I only can get "alert certificate unknown" with sslsplit when it comes to the mqtts connexion. I'm on Android and tested with latest app version and v2.3.0 without success. Would you please share some pcap + key of the initial wifi setup?

kumy commented 4 years ago

The solution from @Thoro at https://github.com/koalazak/dorita980/issues/10#issuecomment-279250730 unfortunately doesn't work for me. I've tested really old app versions. Those tagged 1.x does not support mqtt, and 2.0.0 to 4.4.2 have ssl pinning active in native library :/

@rwscott1961 you said in post https://github.com/koalazak/dorita980/issues/10#issuecomment-279539893 that you use android, did you finally get sslsplit working?

Anyone with a working sslsplit configuration (iOs users?) could share a pcap file please?

Attempt reuse dst SSL session
Connecting to [192.168.10.1]:8883
===> Original server certificate:
Subject DN: /C=US/ST=MA/L=Bedford/O=iRobot/CN=Roomba-80a7082091334770
Common Names: Roomba-80a7082091334770
Fingerprint: 10:DB:F9:94:C3:76:07:3E:8E:5BE0:6B:B9:2A:E5:F3:0D:A5:D1:05
Certificate cache: HIT
===> Forged server certificate:
Subject DN: /C=US/ST=MA/L=Bedford/O=iRobot/CN=Roomba-80a7082091334770
Common Names: Roomba-80a7082091334770
Fingerprint: 7C:2C:C9:79:DB:40:4A:35:4C:CD5B:FD:F8:F1:67:E6:A0:39:EA:13
SSL connected to [192.168.10.1]:8883 TLSv1.3 TLS_AES_256_GCM_SHA384
CLIENT_RANDOM 72517A9B0C7618C95ED4C2FBBF503BEA83D22D27255BA3BEFAD8E422219035A2 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Received privsep req type 01 sz 86 on srvsock 14
Error from src bufferevent: 0:- 336151574:1046:sslv3 alert certificate unknown:20:SSL routines:148:ssl3_read_bytes
SSL disconnected to [192.168.10.1]:8883
SSL disconnected from [10.42.0.225]:47580
SSL_free() in state 0000001a = 001a = SSLERR (error) [accept socket]
SSL_free() in state 00000001 = 0001 = SSLOK  (SSL negotiation finished successfully) [connect socket]
rwscott1961 commented 4 years ago

On Wed, 2020-01-08 at 10:59 -0800, kumy wrote:

The solution from @Thoro at #10 (comment) unfortunately doesn't work for me. I've tested really old app versions. Those tagged 1.x does not support mqtt, and 2.0.0 to 4.4.2 have ssl pinning active in native library :/

@rwscott1961 you said in post #10 (comment) that you use android, did you finally get sslsplit working?

No, id did not get sslsplit working with the android app.

Anyone with a working sslsplit configuration (iOs users?) could share a pcap file please?

Attempt reuse dst SSL session Connecting to [192.168.10.1]:8883 ===> Original server certificate: Subject DN: /C=US/ST=MA/L=Bedford/O=iRobot/CN=Roomba-80a7082091334770 Common Names: Roomba-80a7082091334770 Fingerprint: 10:DB:F9:94:C3:76:07:3E:8E:5BE0:6B:B9:2A:E5:F3:0D:A5:D1:05 Certificate cache: HIT ===> Forged server certificate: Subject DN: /C=US/ST=MA/L=Bedford/O=iRobot/CN=Roomba-80a7082091334770 Common Names: Roomba-80a7082091334770 Fingerprint: 7C:2C:C9:79:DB:40:4A:35:4C:CD5B:FD:F8:F1:67:E6:A0:39:EA:13 SSL connected to [192.168.10.1]:8883 TLSv1.3 TLS_AES_256_GCM_SHA384 CLIENT_RANDOM 72517A9B0C7618C95ED4C2FBBF503BEA83D22D27255BA3BEFAD8E422219035A2 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Received privsep req type 01 sz 86 on srvsock 14 Error from src bufferevent: 0:- 336151574:1046:sslv3 alert certificate unknown:20:SSL routines:148:ssl3_read_bytes SSL disconnected to [192.168.10.1]:8883 SSL disconnected from [10.42.0.225]:47580 SSL_free() in state 0000001a = 001a = SSLERR (error) [accept socket] SSL_free() in state 00000001 = 0001 = SSLOK (SSL negotiation finished successfully) [connect socket]

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe. [ { "@context": "http://schema.org", "@type": "EmailMessage", "potentialAction": { "@type": "ViewAction", "target": "https://github.com/koalazak/dorita980/issues/106?email_source=notifications\u0026email_token=AGEI5ZHBNY56MHSZOYKL4RTQ4YO7NA5CNFSM4KEALTS2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEINTLQA#issuecomment-572208576", "url": "https://github.com/koalazak/dorita980/issues/106?email_source=notifications\u0026email_token=AGEI5ZHBNY56MHSZOYKL4RTQ4YO7NA5CNFSM4KEALTS2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEINTLQA#issuecomment-572208576", "name": "View Issue" }, "description": "View this Issue on GitHub", "publisher": { "@type": "Organization", "name": "GitHub", "url": "https://github.com" } } ]

koalazak commented 4 years ago

Hi @kumy, I don't have pcap files of the initial password setup process :/ I do not remember the exaclty setup that I made to sniff the trafic, I tried a lot of things. I barely remember: ARP spoofing to force the roobot to use one machine as gateway sslsplit on that gateway NAT forwarding on that gateway CA with that robot BLID in the name. iOS application

I notice your certificate with Subject DN: /C=US/ST=MA/L=Bedford/O=iRobot/CN=Roomba-80a7082091334770 Is your BLID edited with the a? or you misspell generating the cert?

kumy commented 4 years ago

That's my exact Blid. I have all the setup in place to dump traffic, but failed to have the android app internal library to accept my sslsplit ca as a trusted ca (it works however for pure java application parts). cert DN is automatically generated by sslsplit with same values as original one provided by robot. I m waiting for my brother in law to come at home with it's ios device to test. Not luck until now with android devices.

kumy commented 4 years ago

I finally got there! Please find prototype there https://github.com/kumy/Roomba980-Wifi/blob/master/initial-config.py @koalazak would you be kind to implement it in dorita980?

Steps to provision the robot

Push a password

  1. Reset to robot (press Home+Spot+Clean until all lights up)
  2. Start Soft AP (press Home+Spot) until sound + green wifi led blink - Eventually try again if the error bip sounds
  3. The password is pushed to the robot using an MQTT Authentication Exchange packet echo -n "f023efcc3b29003a313a313537393139353338363a386678376e597156744b67574a39744f" | xxd -r -p | openssl s_client -CAfile robot-ca.pem -connect 192.168.10.1 -quiet -noservername. This output the password back if set correctly.

packet format:

Value Description
0xf0 MQTT Authentication Exchange packet fixed header
0x23 The size of the remaining Bytes after this (35 in decimal)
0xefcc3b2900 Voodoo packet :smile_cat:
:1:1579195386:8fx7nYqVtKgWJ9tO Format: :1:timestamp:16 alpha-decimal chars

Note: I have not played using different password format, so use with caution.

Provision wifi settings

Connect using mqtt protocol v3.1.1 and send commands via json messages from the table bellow on the right topic and disconnect after. (I use only 6, 9, 10, 11, 12, it seems to be sufficient for a basic configuration). Having a little pause between commands seems to help the process a bit. Once sent, the SoftAP should turn off and the wifi led should turn fixed white.

  Topic payload Comment
1 delta { "state" : { "timezone" : "Europe/Paris" } } makes the robot bip once of two
2 wifictl { "state" : { "sdiscUrl" : "https://disc-prod.iot.irobotapi.com/v1/robot/discover?robot_id=0000000000000000&country_code=FR&sku=R966040" } } I did not checked what is this api…
3 wifictl { "state" : { "ntphosts" : "0.irobot.pool.ntp.org 1.irobot.pool.ntp.org 2.irobot.pool.ntp.org 3.irobot.pool.ntp.org" } }
4 delta { "state" : {"country" : "FR"} }
5 delta { "state" : { "cloudEnv" : "prod" } }
6 wifictl {"state": {"wlcfg": {"pass": "wifisecretpasssword", "sec": 7, "ssid": "575757"}}} pass as clear text, ssid as hex (mine is WWW here), sec???
7 wifictl { "state" : { "utctime" : 1579291795 } } timestamp
8 wifictl { "state" : { "localtimeoffset" : 60 } }
9 wifictl { "state" : { "chkssid" : true } }
10 wifictl { "state" : { "wactivate" : true } }
11 wifictl { "state" : { "get" : "netinfo" } }
12 wifictl { "state" : { "uap" : false } }
rwscott1961 commented 4 years ago

Did you "get there" using the android app, or did you have to use an iOS app?

On Fri, 2020-01-17 at 15:56 -0800, kumy wrote:

I finally got there! Please find prototype there https://github.com/k umy/Roomba980-Wifi/blob/master/initial-config.py @koalazak would you be kind to implement it in dorita980? Steps to provision the robot Push a password Reset to robot (press Home+Spot+Clean until all lights up) Start Soft AP (press Home+Spot) until sound + green wifi led blink - Eventually try again if the error bip sounds The password is pushed to the robot using an MQTT Authentication Exchange packet echo -n "f023efcc3b29003a313a313537393139353338363a386678376e597156744b67574a 39744f" | xxd -r -p | openssl s_client -CAfile robot-ca.pem -connect 192.168.10.1 -quiet -noservername. This output the password back if set correctly. packet format: Value Description 0xf0 MQTT Authentication Exchange packet fixed header 0x23 The size of the remaining Bytes after this (35 in decimal) 0xefcc3b2900 Voodoo packet 😸 :1:1579195386:8fx7nYqVtKgWJ9tO Format: :1:timestamp:16 alpha- decimal chars Note: I have not played using different password format, so use with caution. Provision wifi settings Connect using mqtt protocol v3.1.1 and send commands via json messages from the table bellow on the right topic and disconnect after. (I use only 6, 9, 10, 11, 12, it seems to be sufficient for a basic configuration). Having a little pause between commands seems to help the process a bit. Once sent, the SoftAP should turn off and the wifi led should turn fixed white. Topic payload Comment 1 delta { "state" : { "timezone" : "Europe/Paris" } }
makes the robot bip once of two 2 wifictl { "state" : { "sdiscUrl" : "https://disc-prod .iot.irobotapi.com/v1/robot/discover?robot_id=0000000000000000&countr y_code=FR&sku=R966040" } } I did not checked what is this api… 3 wifictl { "state" : { "ntphosts" : "0.irobot.pool.ntp.org 1.irobot.pool.ntp.org 2.irobot.pool.ntp.org 3.irobot.pool.ntp.org" } }
4 delta { "state" : {"country" : "FR"} }
5 delta { "state" : { "cloudEnv" : "prod" } }
6 wifictl {"state": {"wlcfg": {"pass": "wifisecretpasssword", "sec": 7, "ssid": "575757"}}} pass as clear text, ssid as octal (mine is WWW here), sec??? 7 wifictl { "state" : { "utctime" : 1579291795 } }
timestamp 8 wifictl { "state" : { "localtimeoffset" : 60 } }
9 wifictl { "state" : { "chkssid" : true } }
10 wifictl { "state" : { "wactivate" : true } }
11 wifictl { "state" : { "get" : "netinfo" } } 12 wifictl { "state" : { "uap" : false } } — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

kumy commented 4 years ago

Using android :)

Hypfer commented 3 years ago

Does this enable cloud-free operation or does it still need to connect to the vendor cloud and/or require other stuff such as creating an account etc?

If it's possible to avoid that altogether, it might be possible to add support to Valetudo

kumy commented 3 years ago

Does this enable cloud-free operation or does it still need to connect to the vendor cloud and/or require other stuff such as creating an account etc?

It doesn't require any account creation. Logically, the official app is no use then.

If it's possible to avoid that altogether, it might be possible to add support to Valetudo

I didn't knew about Valetudo, this sound great OSS app! Valetudo developers are free (and welcome) to implement the initial robot wifi configuration in their app - with proper credits ;) "Official' instruction are in repo https://github.com/kumy/Roomba980-Wifi

kFYatek commented 2 years ago

Just to update on this topic: I managed to connect my Roomba i3 using the procedure from @kumy's script, but I had to hexlify both the SSID and the password, as opposed to just the SSID. It seems to use the V3 firmware API (it reports 'ver': '3' during discovery even though the version string reads 2.0.3), so probably that's where the difference comes from.

v6ak commented 1 year ago

I've tried to connect Roomba i7 this way. After some adjustments (primarily error handling + parameters), I realized that the MQTT server disconnects during the second connection. I was unable to get a reasonable error message from the library, so I have used Wireshark: (If you provide Wireshark TLS keylog file, it can decrypt the communication.)

First connection (after TLS handshake):

  1. The client sends Roomba a packet with password. (Protocol=MQTT Info=Authentication Exchange)
  2. The server responds something similar back. (Protocol=MQTT Info=Authentication Exchange)

Second connection (after TLS handshake):

  1. Client sends Connect Command with username=$BLID.
  2. Roomba responds with Connect Ack, which is a bit misnomer, because it contains Return Code: Connection Refused: identifier rejected (2).
  3. Client sends timezone publish packet. It seems the Paho library completely ignores that the server has rejected the connection.
  4. Roomba terminates the connection on TCP level by RST packet. (No TLS alert.)

Have you seen something similar?

v6ak commented 1 year ago

My fork of @kumy's Python script is there: https://github.com/v6ak/Roomba-Wifi-Initial-Provisioning

It should be easier to use (you can use a config file, without modifying the code and without manually encoding anything), but I haven't succeeded with my i7.

kFYatek commented 1 year ago

@v6ak I forgot to post my version of the script here, it's in this PR for another project: https://github.com/NickWaterton/Roomba980-Python/pull/108

Maybe you'll have more luck with that? It worked with my i3. Although I remember the process being somewhat finicky, I think I might have needed a full factory reset at some point to make it work.

kumy commented 1 year ago

My fork of @kumy's Python script is there: https://github.com/v6ak/Roomba-Wifi-Initial-Provisioning

@v6ak Please create a PR :)

v6ak commented 1 year ago

@kFYatek Thank you, I'll try that.

@kumy While I hopefully haven't broken anything that used to work, I hesitate creating a PR before having a success with the script.

v6ak commented 1 year ago

@kFYatek I've suceeded with your code (trimmed down to minimal-ish subset) after slight adjustments (for newer Python versions).