Tasmota: Local access security issue due to HTTP CORS header

Created on 27 Oct 2019  路  8Comments  路  Source: arendst/Tasmota

BUG DESCRIPTION

Tasmota has CORS HTTP headers enabled by default. This is a major security issue that could easily be exploited by any website with some simple Javascript, especially since Tasmota does not require a web password by default.

REQUESTED INFORMATION

  • [X] Read the Contributing Guide and Policy and the Code of Conduct
  • [X] Searched the problem in issues
  • [X] Searched the problem in the wiki
  • [X] Searched the problem in the forum
  • [X] Searched the problem in the chat
  • [X] Device used (e.g., Sonoff Basic): _Shelly 1 and Sonoff Basic, but this issue isn't device specific_
  • [X] Tasmota binary firmware version number used: _6.7_

    • [X] Pre-compiled

    • [ ] Self-compiled

    • [ ] IDE / Compiler used: _____

  • [X] Flashing tools used: _FlashESP8266.exe_
  • [X] Provide the output of command: Backlog Template; Module; GPIO:
17:36:26 RSL: stat/sonoff/RESULT = {"NAME":"Shelly 1","GPIO":[0,0,0,0,21,82,0,0,0,0,0,0,0],"FLAG":0,"BASE":46}
17:36:26 RSL: stat/sonoff/RESULT = {"Module":{"46":"Shelly 1"}}
17:36:27 RSL: stat/sonoff/RESULT = {"GPIO":"Not supported"}
  • [X] If using rules, provide the output of this command: Backlog Rule1; Rule2; Rule3:
N/A  
  • [X] Provide the output of this command: Status 0:
17:38:36 RSL: stat/sonoff/STATUS = {"Status":{"Module":46,"FriendlyName":["Garage Shelly"],"Topic":"sonoff","ButtonTopic":"0","Power":0,"PowerOnState":3,"LedState":1,"LedMask":"FFFF","SaveData":1,"SaveState":1,"SwitchTopic":"0","SwitchMode":[0,0,0,0,0,0,0,0],"ButtonRetain":0,"SwitchRetain":0,"SensorRetain":0,"PowerRetain":0}}
17:38:36 RSL: stat/sonoff/STATUS1 = {"StatusPRM":{"Baudrate":115200,"GroupTopic":"sonoffs","OtaUrl":"http://thehackbox.org/tasmota/release/020502/sonoff.bin","RestartReason":"Software/System restart","Uptime":"0T00:05:06","StartupUTC":"2019-10-27T16:33:30","Sleep":50,"CfgHolder":4617,"BootCount":765,"SaveCount":785,"SaveAddress":"FB000"}}
17:38:36 RSL: stat/sonoff/STATUS2 = {"StatusFWR":{"Version":"6.7.1(sonoff)","BuildDateTime":"2019-10-26T13:19:13","Boot":31,"Core":"STAGE","SDK":"2.2.2-dev(38a443e)"}}
17:38:36 RSL: stat/sonoff/STATUS3 = {"StatusLOG":{"SerialLog":2,"WebLog":2,"MqttLog":0,"SysLog":0,"LogHost":"","LogPort":514,"SSId":["ellis-ac",""],"TelePeriod":300,"Resolution":"55A180C0","SetOption":["00008009","2805C8000100060000005AFF000000000000","00000000"]}}
17:38:36 RSL: stat/sonoff/STATUS4 = {"StatusMEM":{"ProgramSize":564,"Free":440,"Heap":27,"ProgramFlashSize":1024,"FlashSize":2048,"FlashChipId":"1540EF","FlashMode":3,"Features":["00000809","8FDAE397","043683A0","22B617CD","01001BC0","0000F081"],"Drivers":"1,2,3,4,5,6,7,8,9,10,12,16,18,19,20,21,22,24,26,30","Sensors":"1,2,3,4,5,6,7,8,9,10,14,15,17,18,20,22,26,34"}}
17:38:36 RSL: stat/sonoff/STATUS5 = {"StatusNET":{"Hostname":"garage-door-opener","IPAddress":"192.168.1.175","Gateway":"192.168.1.1","Subnetmask":"255.255.255.0","DNSServer":"192.168.1.1","Mac":"A4:CF:12:BA:24:E5","Webserver":2,"WifiConfig":4}}
17:38:36 RSL: stat/sonoff/STATUS6 = {"StatusMQT":{"MqttHost":"router.local","MqttPort":1883,"MqttClientMask":"DVES_%06X","MqttClient":"DVES_BA24E5","MqttUser":"DVES_USER","MqttCount":0,"MAX_PACKET_SIZE":1000,"KEEPALIVE":30}}
17:38:36 RSL: stat/sonoff/STATUS7 = {"StatusTIM":{"UTC":"Sun Oct 27 16:38:36 2019","Local":"Sun Oct 27 17:38:36 2019","StartDST":"Sun Mar 31 02:00:00 2019","EndDST":"Sun Oct 27 03:00:00 2019","Timezone":"+01:00","Sunrise":"07:28","Sunset":"17:39"}}
17:38:36 RSL: stat/sonoff/STATUS10 = {"StatusSNS":{"Time":"2019-10-27T17:38:36","Switch1":"OFF"}}
17:38:36 RSL: stat/sonoff/STATUS11 = {"StatusSTS":{"Time":"2019-10-27T17:38:36","Uptime":"0T00:05:06","UptimeSec":306,"Heap":27,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":19,"MqttCount":0,"POWER":"OFF","Wifi":{"AP":1,"SSId":"ellis-ac","BSSId":"F4:F2:6D:9C:23:B5","Channel":1,"RSSI":92,"LinkCount":1,"Downtime":"0T00:00:05"}}}
  • [X] Provide the output of the Console log output when you experience your issue; if applicable: _(Please use_ weblog 4 _for more debug information)_
N/A  

TO REPRODUCE

  1. Make any HTTP request to a Tasmota device (i.e. curl --user username:password --head 192.168.1.100
  2. See that Access-Control-Allow-Origin: * CORS header is included as an HTTP response header
  3. Go to Tasmota Device Locator
  4. See that TDL is able to make arbitrary HTTP requests to every Tasmota device on my network

EXPECTED BEHAVIOUR

  1. CORS is disabled by default
  2. Any public Internet website should not be able to query/enumerate Tasmota devices on my local network

SCREENSHOTS

_N/A_

ADDITIONAL CONTEXT

It would be very easy to create a script could be dropped into any web page that would:

  1. Enumerate every IP in common subnets (192.168.1.x, 192.168.0.x, 10.0.0.x, etc) to discover Tasmota devices
  2. Once Tasmota devices have been identified, if they are password protected the script could attempt to bruteforce the password
  3. Once a password is discovered, or if the device isn't password protected (default), the site has complete control of the Tasmota device. They can reflash the firmware.
  4. By replacing the firmware a malicious actor could:

    1. Setup a proxy server to enable arbitrary access to any local network device (not just Tasmota)

    2. Push malicious payloads (hacked IP webcam firmware, etc) to local network devices

    3. Contact a command-and-control service to wait for further instructions

This attack vector could largely be mitigated by making CORS configurable (disabled by default), and requiring a web password to be set when first configuring the wifi. Those that prefer to control their Tasmota devices using HTTP requests could still use that method by using an HTTP password and/or enabling CORS.

fixed security

Most helpful comment

I did some research and trial-and-error to look at the consequences of disabling CORS.

Regarding TDL I think the author has to re-think his solution. There must be other ways to scan for Tasmota devices with CORS disabled.

TasmoAdmin is still able to find the device with CORS disabled.

I will release command SetOption73 0/1 with default CORS disabled (0).

All 8 comments

A PR is welcome ;-)

Once upon a time there was this #5852

Thx for the elaborate information.

As you suggested I will disable sending Access-Control-Allow-Origin by default and allow a user to enable it with a SetOption command.

BTW Nice tool this Tasmota Device Locator

So, with this update to disable CORS by default, users will not be able to use the "live" version of TDL and will have to deploy TDL on their own local server?

I will make a note in the TDL wiki article if this is so.

Just tested it and as expected it doesn't find it (192.168.2.223) on the local network too.

Access to XMLHttpRequest at 'http://192.168.2.223/cm?cmnd=Module' from origin 'http://domus1' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
xhr.js:178 Cross-Origin Read Blocking (CORB) blocked cross-origin response http://192.168.2.223/cm?cmnd=Module with MIME type application/json. See https://www.chromestatus.com/feature/5629709824032768 for more details.

This will make TDL useless but increases security ;-)

I did some research and trial-and-error to look at the consequences of disabling CORS.

Regarding TDL I think the author has to re-think his solution. There must be other ways to scan for Tasmota devices with CORS disabled.

TasmoAdmin is still able to find the device with CORS disabled.

I will release command SetOption73 0/1 with default CORS disabled (0).

Closing this issue as it has been fixed. Thanks for reporting.

Wow, what a fast turnaround! Thanks! This is such a great project!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

esp32x picture esp32x  路  3Comments

belidzs picture belidzs  路  3Comments

luisfpinto picture luisfpinto  路  3Comments

kckepz picture kckepz  路  3Comments

smadds picture smadds  路  3Comments