Open mweinelt opened 3 months ago
Hi there.
That's cool! Never thought to try to querying the device while in AP mode.
I would like to eliminate the cloud component from this library. It still relies on the cloud to determine the token/key pair for the V3 protocol.
As for provisioning the WiFi without the app, any chance you could setup a packet capture?
Sure, just tried onboarding it onto a rather restricted quarantine WLAN I have at home (DNS/NTP DNAT, and only HTTPS outgoing), and it made it join the WLAN. I have a PCAP of when the phone joined the AP of the AC for four seconds, before returning to the previous WLAN.
https://shells.darmstadt.ccc.de/~hexa/portasplit-pairing.pcapng
Unfortunately the only exchange between phone and AC seems to be TLS encrypted.
I then ran discovery, to which it responded once, and for some reason interacted with the cloud. After that it stopped being discoverable, but it remains pingable.
./msmart-ng discover -d 192.168.121.202
DEBUG:asyncio:Using selector: EpollSelector
INFO:msmart.cli:Discovering 192.168.121.202 on local network.
DEBUG:msmart.discover:Discovery sent to 192.168.121.202:6445.
DEBUG:msmart.discover:Discovery sent to 192.168.121.202:20086.
DEBUG:msmart.discover:Waiting 5 seconds for responses...
DEBUG:msmart.discover:Discovery response from 192.168.121.202: 837000c8200f00005a5a0111b8007a80000000000000000000000000ca6da8dd72ff00000000000000000180000000003eeb02751427b9cf925e5e6f77e3a9131eb4add3f5f71f70ffd1806456d9511e3b825cf56e84f78d5c136eb663484b06c22ca8752eed0e940e8241e605c60e0e4ab5b028b105970803db5c62e6d3613d8321eeb7860067759d3cee1b455e8c267f7f6c5939a7eb7c724f8e7b1eaad44d0bb19369bf0317b24d3a4de9e6a13106b90186fda67f0ca6e7ad4936ac025e8200000000000000000000000000000000
DEBUG:msmart.discover:Decrypted data from 192.168.121.202: ca79a8c02c19000030303030303050303030303030305131414337324444413836444341303030300b6e65745f61635f364443410000bf0302000000000000000000ac000c0200000000ac72dda86dca150067012236000300000000000000000000000000000000000000000018000000000000000000000000
INFO:msmart.cloud:Using Midea cloud server: https://mp-prod.appsmb.com (China: False).
INFO:httpx:HTTP Request: POST https://mp-prod.appsmb.com/mas/v5/app/proxy?alias=/v1/user/login/id/get "HTTP/1.1 200 "
DEBUG:msmart.cloud:API response: {"code":"0","msg":"ok","data":{"loginId":"cc19aa32-dfb1-4c12-90b4-94fd05cd"}}
DEBUG:msmart.cloud:Received loginId: cc19aa32-dfb1-4c12-90b4-94fd05cd
DEBUG:msmart.discover:Discovered 1 devices.
INFO:httpx:HTTP Request: POST https://mp-prod.appsmb.com/mas/v5/app/proxy?alias=/mj/user/login "HTTP/1.1 200 OK"
DEBUG:msmart.cloud:API response: {"code":0,"msg":"成功","data":{"randomData":"fe119674796878f8b67bd229ff5880b3fcc85e9e20b2fa5e35c1157dbc2969bd","uid":"83947250d2448ffdf02e111c74bad51e","accountId":"1023665078","nickname":"midea","mdata":{"tokenPwdInfo":{"tokenPwd":"8b94ffdde444400eb0029a077c107ee3","expiredDate":1724026286065,"createDate":1721434286065},"userInfo":{"sourceId":"mj_12345","empId":"5456771537545216","address":"","gender":"0","mobile":"midea@mailinator.com","userDeptInfoList":null,"extras":null,"nameEn":null,"employeeNumber":null,"headPhoto":null,"uid":"83947250d2448ffdf02e111c74bad51e","name":"midea@mailinator.com","email":null},"doDeviceBind":null,"accessToken":"T1m0w9ju9czk39vn6","signUnlockEnabled":null},"accessToken":"7f92bf61d3a68ae4c3bfdc91021128cb35fb0d2c0c1caea4afed3f06f46aa8fb","userId":"89056511576065","email":"midea@mailinator.com"}}
DEBUG:msmart.cloud:Received accessToken: T1m0w9ju9czk39vn6
DEBUG:msmart.discover:Fetching token and key for udpid 'd51fa7950ef935ac400a7e45cdd2025b' (little).
INFO:httpx:HTTP Request: POST https://mp-prod.appsmb.com/mas/v5/app/proxy?alias=/v1/iot/secure/getToken "HTTP/1.1 200 OK"
DEBUG:msmart.cloud:API response: {"code":"0","msg":"ok","data":{"tokenlist":[{"udpId":"d51fa7950ef935ac400a7e45cdd2025b","key":"d69ca01e24b643d6b34eb31bbd7b08e63f92f69c83e9430ea5457377b3c58360","token":"1FB6C9A7FA24EAF7D2DB41741E14327121160D86E5EAE9B31506C90028BA1E8527A91C69728DDE9FABF7FFEB42B66AB37890AD8D6F5420C2646D5D5F0C7FEE6D"}]}}
INFO:msmart.lan:Creating new connection to 192.168.121.202:6444.
DEBUG:msmart.lan:Connected to 192.168.121.202:6444.
INFO:msmart.lan:Authenticating with 192.168.121.202:6444.
DEBUG:msmart.lan:Sending data to 192.168.121.202:6444: 83700040200000001fb6c9a7fa24eaf7d2db41741e14327121160d86e5eae9b31506c90028ba1e8527a91c69728dde9fabf7ffeb42b66ab37890ad8d6f5420c2646d5d5f0c7fee6d
DEBUG:msmart.lan:Received data from 192.168.121.202:6444: 83700005200fa5a54552524f52
DEBUG:msmart.discover:Fetching token and key for udpid '50e4760c8157626d39458b9d3ddea07b' (big).
INFO:httpx:HTTP Request: POST https://mp-prod.appsmb.com/mas/v5/app/proxy?alias=/v1/iot/secure/getToken "HTTP/1.1 200 OK"
DEBUG:msmart.cloud:API response: {"code":"0","msg":"ok","data":{"tokenlist":[{"udpId":"50e4760c8157626d39458b9d3ddea07b","key":"a874f04fc93c406da05e9bf6596ab458f2bc22b656bd4545874fec88f8ed8980","token":"BF050DD1177DDCB38F5EEFA280F5CE4B6C117BA59D99897BB39B68C1E70A59FB157573077AD7738426A30471AED55CA14895DBBF5F03322A02B8E424E432029D"}]}}
INFO:msmart.lan:Authenticating with 192.168.121.202:6444.
DEBUG:msmart.lan:Sending data to 192.168.121.202:6444: 8370004020000001bf050dd1177ddcb38f5eefa280f5ce4b6c117ba59d99897bb39b68c1e70a59fb157573077ad7738426a30471aed55ca14895dbbf5f03322a02b8e424e432029d
DEBUG:msmart.lan:Received data from 192.168.121.202:6444: 83700005200fa5a54552524f52
INFO:msmart.cli:Found 1 devices.
INFO:msmart.cli:Found device:
{'ip': '192.168.121.202', 'port': 6444, 'id': 280868810157514, 'online': False, 'supported': False, 'type': <DeviceType.AIR_CONDITIONER: 172>, 'name': 'net_ac_6DCA', 'sn': '000000P0000000Q1AC72DDA86DCA0000', 'key': None, 'token': None}
Oh and it now wants to establish a TCP session with some AWS host on port 28850.
00:30:02.083757 IP 192.168.121.202.60746 > 18.159.82.49.28850: Flags [S], seq 122393, win 2920, options [mss 1460], length 0
Thanks for collecting the capture. I'll take a look.
I then ran discovery, to which it responded once, and for some reason interacted with the cloud. After that it stopped being discoverable, but it remains pingable.
The cloud interaction comes from the library. It's trying to determine the token/key pair necessary for the "V3" protocol. Interesting that your first query of the device used the "V2" protocol.
Oh another thing to keep in mind. If you're totally blocking the device from connecting outside there's a watchdog that will kick and reboot the device.
Took a quick glance at your capture and it does appear you've capture some packets while it was in AP mode. I think they'll have to be decrypted but might be something useful in there.
I'm interested in this too, I have a brand new (to me) portable Midea AC. Happy to do a packet capture or whatever I can do to assist. Also,. any idea what the watchdog is looking for? wonder if a simple fake server can be setup just to keep it content.
Also,. any idea what the watchdog is looking for? wonder if a simple fake server can be setup just to keep it content.
I don't exactly. I think I've tried a DNS redirect to a valid host and it needs a little more than that. Haven't investigated any further
I've filtered down the packet capture to what I believe are the provisioning packets portasplit-pairing-provisioning.zip
Most interesting a No 9 & 10 which I believe are a provisioning command and an ACK.
The decrypted contents dumped as hex and ASCII in 16 byte chunks
ee308e61ebdda41d67a79d2fee7c529f
1664697374727573742e6c6f7373792e
6e6574776f726b0b6368616e67656d65
31323306e6956e41f7a0166469737472
7573742e6c6f7373792e6e6574776f72
6b09010101021444450204010d140024
04170034041401640b1b010304543a00
0004116d6f64756c652e617070736d62
2e636f6d0502bb010601020703020601
b'\xee0\x8ea\xeb\xdd\xa4\x1dg\xa7\x9d/\xee|R\x9f'
b'\x16distrust.lossy.'
b'network\x0bchangeme'
b'123\x06\xe6\x95nA\xf7\xa0\x16distr'
b'ust.lossy.networ'
b'k\t\x01\x01\x01\x02\x14DE\x02\x04\x01\r\x14\x00$'
b'\x04\x17\x004\x04\x14\x01d\x0b\x1b\x01\x03\x04T:\x00'
b'\x00\x04\x11module.appsmb'
b'.com\x05\x02\xbb\x01\x06\x01\x02\x07\x03\x02\x06\x01'
Here's a guess at some of the contents:
distrust.lossy.network
changeme123
DE
module.appsmb.com
SSID and PSK are correct.
Any chance either of you could perform additional captures while provisioning on networks with different security type. (e.g. None, WPA, WPA2).
It just occurred to me that some part of the provision packet probably includes a security type byte,
Including the MAC address of the network's AP might also be beneficial.
The MAC for the AP in my case was e6:95:6e:41:f7:a0
. I can check later if it even supports other modes.
\xe6\x95nA\xf7\xa0
here we are!
Cool cool.
In that case, bytes 16 - 80 probably break down like so
16 - SSID Length = 22
64697374727573742e6c6f7373792e6e6574776f726b - SSID = distrust.lossy.network
0b - PSK Length = 11
6368616e67656d65313233 - PSK = changeme123
06 - Channel? Security Type?
e6956e41f7a0 - AP MAC
16 - SSID Length 2 = 22
64697374727573742e6c6f7373792e6e6574776f726b - SSID 2
config wifi-iface 'radio0_vlan121'
option ifname 'radio0_vlan121'
option device 'radio0'
option network 'vlan121'
option mode 'ap'
option ssid 'distrust.lossy.network'
option encryption 'psk2'
option key 'changeme123'
option ieee80211w '0'
option ieee80211v '1'
phy#0
Interface radio0_vlan121
ifindex 15
wdev 0x3
addr e6:95:6e:41:f7:a0
ssid distrust.lossy.network
type AP
channel 13 (2472 MHz), width: 20 MHz, center1: 2472 MHz
txpower 20.00 dBm
Pairing with an open network:
https://shells.darmstadt.ccc.de/~hexa/midea-portasplit-open.pcapng
config wifi-iface 'radio0_vlan121'
option ifname 'radio0_vlan121'
option device 'radio0'
option network 'vlan121'
option mode 'ap'
option ssid 'open.lossy.network'
option encryption 'none'
phy#0
Interface radio0_vlan121
ifindex 15
wdev 0x3
addr e6:95:6e:41:f7:a0
ssid open.lossy.network
type AP
channel 9 (2452 MHz), width: 20 MHz, center1: 2452 MHz
txpower 20.00 dBm
Pairing with a WPA-TKIP network:
https://shells.darmstadt.ccc.de/~hexa/midea-portasplit-wpa-tkip.pcapng
config wifi-iface 'radio0_vlan121'
option ifname 'radio0_vlan121'
option device 'radio0'
option network 'vlan121'
option mode 'ap'
option encryption 'psk+tkip'
option key 'changeme123'
option ssid 'wpa-tkip.lossy.network'
phy#0
Interface radio0_vlan121
ifindex 26
wdev 0xd
addr e6:95:6e:41:f7:a0
ssid wpa-tkip.lossy.network
type AP
channel 9 (2452 MHz), width: 20 MHz, center1: 2452 MHz
txpower 20.00 dBm
I would have tried SAE as well, but the old rooted Android has no support for it. The trick for it to become capturable is to disable Bluetooth, or else it will try to do the setup that way.
The three provided captures are WPA2, Open and WPA.
Thanks.
WPA and WPA2 are nearly identical. Aside from SSID, the only difference is the first 2 bytes.
Open has a zero length PSK (obviously). The first 16 bytes are also different, but after the 2nd SSID field the packet is identical
WPA
Hex View 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 35 39 8E 61 EB DD A4 1D 67 A7 9D 2F EE 7C 52 9F 59.a....g../.|R.
00000010 16 77 70 61 2D 74 6B 69 70 2E 6C 6F 73 73 79 2E .wpa-tkip.lossy.
00000020 6E 65 74 77 6F 72 6B 0B 63 68 61 6E 67 65 6D 65 network.changeme
00000030 31 32 33 06 E6 95 6E 41 F7 A0 16 77 70 61 2D 74 123...nA...wpa-t
00000040 6B 69 70 2E 6C 6F 73 73 79 2E 6E 65 74 77 6F 72 kip.lossy.networ
00000050 6B 09 01 01 01 02 14 44 45 02 04 01 0D 14 00 24 k......DE......$
00000060 04 17 00 34 04 14 01 64 0B 1B 01 03 04 54 3A 00 ...4...d.....T:.
00000070 00 04 11 6D 6F 64 75 6C 65 2E 61 70 70 73 6D 62 ...module.appsmb
00000080 2E 63 6F 6D 05 02 BB 01 06 01 02 07 03 02 06 01 .com............
WPA2
Hex View 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 EE 30 8E 61 EB DD A4 1D 67 A7 9D 2F EE 7C 52 9F .0.a....g../.|R.
00000010 16 64 69 73 74 72 75 73 74 2E 6C 6F 73 73 79 2E .distrust.lossy.
00000020 6E 65 74 77 6F 72 6B 0B 63 68 61 6E 67 65 6D 65 network.changeme
00000030 31 32 33 06 E6 95 6E 41 F7 A0 16 64 69 73 74 72 123...nA...distr
00000040 75 73 74 2E 6C 6F 73 73 79 2E 6E 65 74 77 6F 72 ust.lossy.networ
00000050 6B 09 01 01 01 02 14 44 45 02 04 01 0D 14 00 24 k......DE......$
00000060 04 17 00 34 04 14 01 64 0B 1B 01 03 04 54 3A 00 ...4...d.....T:.
00000070 00 04 11 6D 6F 64 75 6C 65 2E 61 70 70 73 6D 62 ...module.appsmb
00000080 2E 63 6F 6D 05 02 BB 01 06 01 02 07 03 02 06 01 .com............
Open
Hex View 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 9D 4F 6B 64 7B E5 79 F7 49 BF 14 4A 38 39 6D 95 .Okd{.y.I..J89m.
00000010 12 6F 70 65 6E 2E 6C 6F 73 73 79 2E 6E 65 74 77 .open.lossy.netw
00000020 6F 72 6B 00 06 E6 95 6E 41 F7 A0 12 6F 70 65 6E ork....nA...open
00000030 2E 6C 6F 73 73 79 2E 6E 65 74 77 6F 72 6B 09 01 .lossy.network..
00000040 01 01 02 14 44 45 02 04 01 0D 14 00 24 04 17 00 ....DE......$...
00000050 34 04 14 01 64 0B 1B 01 03 04 54 3A 00 00 04 11 4...d.....T:....
00000060 6D 6F 64 75 6C 65 2E 61 70 70 73 6D 62 2E 63 6F module.appsmb.co
00000070 6D 05 02 BB 01 06 01 02 07 03 02 06 01 m............
Open w/ zero padding to match WPA length
Hex View 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 9D 4F 6B 64 7B E5 79 F7 49 BF 14 4A 38 39 6D 95 .Okd{.y.I..J89m.
00000010 12 00 00 00 00 6F 70 65 6E 2E 6C 6F 73 73 79 2E .....open.lossy.
00000020 6E 65 74 77 6F 72 6B 00 00 00 00 00 00 00 00 00 network.........
00000030 00 00 00 06 E6 95 6E 41 F7 A0 12 00 00 00 00 6F ......nA.......o
00000040 70 65 6E 2E 6C 6F 73 73 79 2E 6E 65 74 77 6F 72 pen.lossy.networ
00000050 6B 09 01 01 01 02 14 44 45 02 04 01 0D 14 00 24 k......DE......$
00000060 04 17 00 34 04 14 01 64 0B 1B 01 03 04 54 3A 00 ...4...d.....T:.
00000070 00 04 11 6D 6F 64 75 6C 65 2E 61 70 70 73 6D 62 ...module.appsmb
00000080 2E 63 6F 6D 05 02 BB 01 06 01 02 07 03 02 06 01 .com............
Hi, thanks for maintaining this software!
I'm wondering if the cloud binding can be skipped entirely, since my AC, a Midea Portasplit, is discoverable on 192.168.1.1 in AP mode.
https://gist.github.com/mweinelt/0addd575269467e8a1ad27b8c4d08fb5
The app would need to configure the WLAN credentials on the device, since otherwise the AC wouldn't be able to pair with the cloud.