[00:00.940 --> 00:03.400] Hello everyone, and thank you for joining my talk today [00:03.400 --> 00:06.080] called Don't Be Silly, It's Only a Lightbulb. [00:06.080 --> 00:08.680] Before we begin, just a brief introduction. [00:09.280 --> 00:11.440] My name is Eyal Itkin. [00:11.440 --> 00:12.640] I'm a vulnerability researcher [00:12.640 --> 00:15.060] working at Checkpoints Research Group. [00:15.240 --> 00:16.580] In my research projects, [00:16.580 --> 00:20.020] I tend to focus on embedded devices and protocols, [00:20.020 --> 00:22.680] and in which case I combine these both together. [00:23.100 --> 00:25.560] You can usually read more about my recent publications [00:25.560 --> 00:27.360] on my Twitter account. [00:28.500 --> 00:31.140] The motivation for this specific research [00:31.140 --> 00:33.860] started a few years ago in 2016, [00:33.860 --> 00:37.760] when I heard of a new smart IoT device, smart lightbulbs. [00:37.940 --> 00:41.020] I was already quite familiar with many smart gadgets [00:41.020 --> 00:43.960] and even smart air conditioner, [00:43.960 --> 00:46.620] which allows you to activate it remotely on your way home [00:46.620 --> 00:49.620] so the temperature will be just fine when you arrive. [00:49.920 --> 00:53.540] But why would I need a smart lightbulb? [00:53.540 --> 00:56.720] I only need a light when I'm physically in a room [00:56.720 --> 00:59.500] and I'm fully capable of toggling the switch on and off [00:59.500 --> 01:01.520] when I enter and leave the room. [01:01.520 --> 01:03.480] Why would I need an app for that? [01:03.480 --> 01:06.220] Well, I figured out that it won't catch, [01:06.220 --> 01:08.400] people won't buy it, and that's it. [01:08.600 --> 01:10.460] And apparently I was wrong, [01:10.460 --> 01:14.140] because according to a report from the end of 2018, [01:14.140 --> 01:16.940] more than 400,000 households in the UK [01:17.360 --> 01:19.740] were already using smart lighting solutions. [01:19.740 --> 01:22.360] So people are apparently buying this gadget. [01:23.000 --> 01:27.800] Okay, but if I connect my lightbulb to the mobile phone [01:27.800 --> 01:29.220] or to the internet, [01:29.220 --> 01:32.440] there will be some security risk about it, right? [01:32.920 --> 01:34.740] But when I ask people about it, [01:34.740 --> 01:37.220] I always receive the same response. [01:37.260 --> 01:40.820] Don't be silly, it's only a lightbulb, it's fine. [01:42.060 --> 01:45.220] Obviously, I'm not the first to study this test case [01:45.220 --> 01:48.400] and there is some great firework before me. [01:49.200 --> 01:51.300] We will start with a lightbulb worm [01:51.300 --> 01:53.580] by Colin Flynn and Eyal Ronen, [01:53.580 --> 01:57.260] which presented their research on Blackhead USA on 2016. [01:57.580 --> 01:59.680] Later on, they developed the research [01:59.680 --> 02:04.160] into IoT goes nuclear, creating a ZigBee chain reaction. [02:04.540 --> 02:06.600] This time they were joined by Adi Shamir [02:06.600 --> 02:08.180] and Achior Weingarten, [02:08.180 --> 02:11.500] and you can read all about it on their website. [02:11.860 --> 02:13.940] I really recommend you reading about the research [02:13.940 --> 02:15.240] because it was so cool, [02:15.240 --> 02:17.620] they actually took over all of the lightbulbs [02:17.620 --> 02:21.600] on campus in a war flying demo from their drone. [02:22.320 --> 02:26.260] Since I already was familiar with Eyal Ronen's work [02:26.260 --> 02:30.160] and both Eyal Ronen and Achior are all colleagues of mine, [02:30.160 --> 02:32.400] I talked with Eyal Ronen and together we decided [02:32.400 --> 02:35.740] that with his help, I'm going to continue on the research [02:35.740 --> 02:37.720] and take it to the next level. [02:38.160 --> 02:40.280] So, what did they find? [02:40.880 --> 02:44.040] Well, it turns out that attackers can remotely steal [02:44.200 --> 02:45.980] a lightbulb from a given ZigBee network [02:45.980 --> 02:47.920] and force it to join their own. [02:48.300 --> 02:49.940] Once it joined the network, [02:49.940 --> 02:52.840] attackers can send the lightbulb a malicious firmware update [02:52.840 --> 02:54.820] to fully take over it. [02:55.220 --> 02:57.020] And if that wasn't enough, [02:57.020 --> 02:59.120] it turns out that even a regular lightbulb [02:59.120 --> 03:00.520] can steal other lightbulbs [03:00.520 --> 03:02.760] and you don't need any fancy RF equipment [03:02.760 --> 03:04.980] or an antenna in order to do it. [03:05.840 --> 03:08.220] Using these three primitives together, [03:08.220 --> 03:10.220] the researchers claim that you can take over [03:10.720 --> 03:13.420] a selected set of lightbulbs in a given city. [03:13.420 --> 03:14.280] From each lightbulb, [03:14.280 --> 03:17.240] you'll take over the other lightbulbs in close proximity [03:17.750 --> 03:20.200] and so on and so forth in order to propagate [03:20.200 --> 03:23.380] and take over all of the lightbulbs in a given city [03:23.380 --> 03:26.080] in a nuclear-like chain reaction. [03:26.640 --> 03:30.260] Sadly for us, the vendor did fix the last vulnerability [03:30.710 --> 03:32.940] and we were only left with the first two. [03:33.840 --> 03:35.740] If you put it visually, [03:35.740 --> 03:38.420] we can see the network diagram over here. [03:39.300 --> 03:41.200] On the right, we can see a smart lightbulb [03:41.200 --> 03:44.100] which communicates with its bridge, the controller, [03:44.100 --> 03:45.980] over ZigBee radio. [03:46.060 --> 03:48.180] The bridge is connected to both the radio network [03:48.180 --> 03:50.700] and the computer network with an ethernet cable [03:50.700 --> 03:54.180] so we could control the lightbulb from our mobile phone [03:54.960 --> 03:56.580] through the controller. [03:57.040 --> 03:58.860] The attack itself will start [03:58.860 --> 04:00.280] when the attacker will transmit [04:00.280 --> 04:02.960] ZigBee factory reset messages to the lightbulb [04:02.960 --> 04:04.300] in order to confuse it [04:04.300 --> 04:07.280] and convince it to join their own network. [04:07.500 --> 04:09.120] Once it joined the network, [04:09.120 --> 04:11.860] attackers can send a malicious over-the-air firmware update [04:11.860 --> 04:15.220] to the lightbulb to fully take over the lightbulb itself. [04:16.300 --> 04:17.680] And while the original research [04:17.680 --> 04:19.300] only focused on the lightbulbs, [04:19.300 --> 04:21.940] we are focused on a much broader target [04:21.940 --> 04:25.460] and we want to take their research to the next step. [04:25.460 --> 04:27.520] We want to infiltrate the network. [04:28.340 --> 04:30.240] In order to infiltrate the network, [04:30.240 --> 04:31.780] we are hoping to find a vulnerability [04:32.300 --> 04:36.620] so that our lightbulb will be able to remotely exploit [04:36.620 --> 04:38.820] the ZigBee vulnerability in the bridge itself [04:38.820 --> 04:40.640] in order to take over it. [04:41.240 --> 04:42.820] Once we took over the bridge, [04:42.820 --> 04:45.380] the bridge can launch attack inside a computer network [04:45.380 --> 04:47.740] and hopefully allow us to take over the computers [04:47.740 --> 04:49.740] inside the network itself. [04:50.300 --> 04:52.580] Once we understood our attack vector, [04:52.580 --> 04:54.240] it's time to get started. [04:59.540 --> 05:03.000] But first, some preliminary slides on ZigBee. [05:03.460 --> 05:05.440] ZigBee is a suite of high-level protocols [05:05.440 --> 05:07.740] for closed proximity networks. [05:07.880 --> 05:11.580] It's an IEEE 802.154-based specs [05:11.580 --> 05:15.540] that defines a low-range, low-power radio. [05:16.000 --> 05:18.720] Not to be confused with IEEE 802.11, [05:18.720 --> 05:21.840] which stands for the more commonly used Wi-Fi. [05:22.720 --> 05:25.660] The maximal transmission unit, or the MTU, [05:25.660 --> 05:29.280] over ZigBee is only 127 bytes long. [05:29.280 --> 05:30.460] And I repeat that. [05:30.460 --> 05:33.440] The maximal packet we can transmit over the air [05:33.440 --> 05:36.680] contains only 127 bytes. [05:36.680 --> 05:39.120] And with this harsh limit, [05:39.120 --> 05:42.580] we should be able to somehow exploit vulnerabilities [05:42.580 --> 05:45.100] that we hope to find in the bridge. [05:46.540 --> 05:48.760] ZigBee has a full network stack of its own. [05:49.360 --> 05:51.000] Like any other network stack, [05:51.000 --> 05:52.420] it starts with the lower levels, [05:52.420 --> 05:53.740] which is the physical layer [05:53.740 --> 05:55.740] and the medium access control layer, [05:55.740 --> 05:58.000] which acts as the internet acts [05:58.000 --> 06:00.200] in normal computer networks. [06:01.040 --> 06:03.680] On top of that, we have the network access layer, [06:03.680 --> 06:07.060] which is responsible for both routing and encryption. [06:07.820 --> 06:10.200] Above that, we have the application sub-layer, [06:10.200 --> 06:12.340] which is responsible for routing our packet [06:12.340 --> 06:15.380] to the respective application in the upper layers. [06:15.820 --> 06:18.260] This application could be ZDP, [06:18.260 --> 06:20.380] which stands for ZigBee Device Profile [06:20.380 --> 06:23.180] and responsible for managing different aspects [06:23.180 --> 06:24.840] of the ZigBee protocol. [06:25.280 --> 06:28.760] It could be ZCL, ZigBee Cluster Library, [06:28.760 --> 06:31.100] which is responsible for managing the configurations [06:31.100 --> 06:32.960] of the different devices. [06:33.660 --> 06:35.920] And it could be whatever other application [06:35.920 --> 06:37.880] that the vendor decided to implement. [06:38.500 --> 06:40.780] Now that we understood how ZigBee works, [06:40.780 --> 06:42.420] it's time to meet our target. [06:43.360 --> 06:44.700] The target for this research [06:44.700 --> 06:47.320] is going to be the Philips Hue Smart Lighting, [06:47.320 --> 06:49.160] now under Signify. [06:50.400 --> 06:53.140] Signify controls approximately one third of the market [06:53.140 --> 06:55.600] in the UK, so it's a broad target. [06:56.040 --> 06:58.280] And we're going to focus specifically on the bridge [06:58.280 --> 07:00.560] because as we mentioned earlier, [07:00.560 --> 07:02.560] the bridge is connected to both the radio network [07:02.560 --> 07:03.780] and the computer network, [07:03.780 --> 07:05.280] and we hope to bridge the two. [07:07.000 --> 07:09.660] Specifically, we're going to focus on a second generation [07:09.660 --> 07:11.300] of hardware for the bridge, [07:11.300 --> 07:13.160] which is the rectangular version of the bridge [07:13.160 --> 07:14.380] as seen on the right. [07:15.460 --> 07:17.780] If you remove the plastic cover from the bridge, [07:17.780 --> 07:19.140] we can see the board. [07:19.760 --> 07:20.840] When looking on a board, [07:20.840 --> 07:22.860] we can see on the right, the main CPU, [07:22.860 --> 07:24.980] which is a Qualcomm CPU usually found [07:24.980 --> 07:27.060] on Wi-Fi enabled devices. [07:27.960 --> 07:30.840] Over the left, we can see an Atmel CPU, [07:30.840 --> 07:34.080] which we'll refer to as the ZigBee modem. [07:34.080 --> 07:36.440] And like any other embedded device, [07:36.440 --> 07:39.220] we have a clear pinout for serial debug, [07:39.220 --> 07:42.440] which turned out to be quite useful throughout this research. [07:44.120 --> 07:46.420] The main CPU is a MIPS architecture, [07:46.420 --> 07:47.720] which is quite unique. [07:47.800 --> 07:50.560] And the operating system is Linux. [07:50.620 --> 07:53.740] This is quite refreshing because in prior research projects, [07:53.740 --> 07:57.520] we mainly had to handle real-time operating systems, [07:57.520 --> 07:59.280] which are harder to debug. [07:59.340 --> 08:01.420] This time, since we have Linux, [08:01.420 --> 08:02.740] we hope to be able to root it [08:02.740 --> 08:05.240] and to access it directly using an SSH connection [08:05.560 --> 08:08.580] in order to extract the file of the firmware itself, [08:09.260 --> 08:12.680] and in order to hopefully install a remote GDB server [08:12.680 --> 08:14.940] in order to debug the device. [08:15.580 --> 08:18.400] And luckily enough, Colin O'Flynn details in his blog [08:18.400 --> 08:19.840] exactly how to root the bridge [08:19.840 --> 08:24.300] with a step-by-step guide followed by a video. [08:25.000 --> 08:28.400] Once finished, we will get a root SSH connection. [08:29.840 --> 08:31.920] When I started this research, [08:31.920 --> 08:34.840] LLNN told me that the bridge is using a single huge process [08:34.840 --> 08:37.720] that's pretty much doing everything. [08:37.720 --> 08:39.560] And this is the IP bridge. [08:40.460 --> 08:41.840] The IP bridge is a single process [08:41.840 --> 08:44.120] that acts as the brain of the device. [08:44.120 --> 08:48.020] It is responsible for parsing incoming ZigBee messages, [08:48.020 --> 08:50.380] maintaining the different ZigBee state machines, [08:50.380 --> 08:53.160] and pretty much doing everything it needs. [08:54.200 --> 08:56.280] And like any other embedded device, [08:56.280 --> 08:58.720] IP bridge runs with root privileges, [08:58.720 --> 09:01.580] which means that once we took over this process, [09:01.580 --> 09:04.040] we don't need any other vulnerability. [09:04.860 --> 09:07.300] Now that we saw all of these data, [09:07.300 --> 09:10.420] it's time to start looking for vulnerabilities [09:10.420 --> 09:13.120] and IP bridge is going to be our target. [09:17.320 --> 09:19.400] We had quite a slow start to begin with [09:19.400 --> 09:21.040] because due to technical issues, [09:21.040 --> 09:22.300] I couldn't root the bridge. [09:22.300 --> 09:24.820] It turns out that I don't have the right hardware equipment [09:24.820 --> 09:27.840] as my younger brother rightfully pointed out. [09:28.400 --> 09:30.520] And the package we ordered got delayed [09:30.520 --> 09:33.080] like pretty much any other research project [09:33.080 --> 09:35.320] I've done thus far. [09:35.780 --> 09:37.340] Instead of sitting idle, [09:37.340 --> 09:40.260] we decided to start working on the old firmware version, [09:40.260 --> 09:42.880] which we received from the original research team. [09:43.240 --> 09:45.780] This is a firmware version, which is a few years old, [09:45.780 --> 09:48.220] and we really hope that it didn't change a lot [09:48.220 --> 09:50.680] throughout the years, but we really don't know. [09:50.680 --> 09:54.300] We simply have to cross our fingers and hope for good. [09:55.980 --> 09:57.840] When analyzing IP bridge, [09:57.840 --> 10:00.420] we soon enough saw something quite odd. [10:00.920 --> 10:03.460] The code expects strings to be found inside [10:03.460 --> 10:05.840] incoming messages instead of bits, [10:05.840 --> 10:10.460] because we can see the strings as such as ZDP or ZCL [10:10.460 --> 10:11.940] or even connection, [10:11.940 --> 10:16.800] but the maximum message size is only 127 bytes long. [10:16.800 --> 10:20.180] We don't have enough room for textual strings. [10:20.180 --> 10:23.880] We have enough room for mere single bits and that's it. [10:23.880 --> 10:26.260] So what's going on? [10:26.780 --> 10:29.300] And things got complicated. [10:29.980 --> 10:32.700] It turns out we forgot about the ZigBee modem. [10:32.940 --> 10:35.400] The ZigBee modem uses Atmel's BitCloud SDK [10:35.400 --> 10:37.960] in order to parse incoming ZigBee messages [10:37.960 --> 10:40.900] before they arrive to the main CPU. [10:42.080 --> 10:43.980] Effectively, it acts as a co-processor [10:43.980 --> 10:46.100] that handles the ZigBee lower network layers [10:46.100 --> 10:48.060] instead of the main CPU. [10:48.840 --> 10:51.600] It converts the parse messages to textual form [10:51.600 --> 10:55.520] and sends them over serial to the main CPU to be handled. [10:56.200 --> 10:59.040] And of course we don't have the firmware for it, [10:59.040 --> 11:00.400] so it's a black box. [11:02.520 --> 11:04.840] The modem reduces the attack surface on the main CPU [11:04.840 --> 11:08.880] because complex parsing is offloaded to the modem. [11:08.880 --> 11:11.960] And if the main CPU doesn't handle a specific task, [11:11.960 --> 11:14.620] it can be vulnerable when doing so. [11:15.020 --> 11:16.980] And we don't fully control the messages [11:16.980 --> 11:18.840] which are sent to the main CPU [11:18.840 --> 11:22.520] because they are constructed on the modem itself. [11:23.960 --> 11:25.860] And if that wasn't enough, [11:25.860 --> 11:28.100] it puts a huge question mark on everything we find [11:28.100 --> 11:31.100] because maybe the modem checks it. [11:31.840 --> 11:33.660] Maybe there's no check at all. [11:33.880 --> 11:36.380] So we'll have to add this to the list of ongoing issues [11:36.380 --> 11:38.480] and really hope for the best. [11:40.100 --> 11:42.060] Our first vulnerability attempt focus [11:42.060 --> 11:46.340] on ZigBee cluster library, which is ZCL. [11:46.540 --> 11:49.160] ZCL is responsible for managing configurations [11:49.160 --> 11:52.140] and it really is similar to SNMP [11:52.140 --> 11:54.460] in traditional IT networks. [11:54.780 --> 11:57.720] It offers a read attribute, write attribute interface [11:57.720 --> 12:00.660] and it supports multiple data types. [12:00.880 --> 12:03.620] The first data type is Boolean. [12:03.640 --> 12:06.840] Then we have an unsigned integer of eight bits, [12:06.840 --> 12:11.080] an unsigned integer of 32 bits, and even a dynamic array. [12:11.760 --> 12:15.320] And a variable size data type in an embedded device [12:15.320 --> 12:17.740] is a sure recipe for vulnerabilities. [12:17.960 --> 12:19.680] It looks promising. [12:20.020 --> 12:22.620] When we dived in to look how ZCL arrays [12:22.620 --> 12:24.340] are being parsed in the code, [12:24.340 --> 12:26.280] we saw the following code snippet. [12:27.220 --> 12:29.180] Here we can see that at first, [12:29.300 --> 12:31.500] a one byte length field is read from the message [12:32.040 --> 12:35.100] and then a fixed buffer is allocated over the heap [12:35.100 --> 12:37.300] with 33 bytes. [12:37.940 --> 12:40.800] Don't be confused by the delay slot in MIPS. [12:40.800 --> 12:44.260] The assignment into register A0 is done chronologically [12:44.260 --> 12:47.280] before the invocation of the malloc function [12:47.820 --> 12:50.520] and that's why it's called a delay slot. [12:50.820 --> 12:53.720] Effectively, we allocate a fixed size buffer over the heap [12:53.720 --> 12:54.820] and that's it. [12:55.520 --> 12:57.840] Later on, we'll read the entire blob [12:57.840 --> 13:01.920] from our attackers packet into the fixed size buffer. [13:02.320 --> 13:03.860] And what does it mean? [13:03.860 --> 13:06.420] Well, a controlled one byte name copy [13:06.420 --> 13:08.040] into a fixed size heap buffer [13:08.040 --> 13:11.380] and that's the definition of a heap-based buffer overflow. [13:12.740 --> 13:14.460] Sadly for us, it isn't a vulnerability [13:14.460 --> 13:17.700] until we have a working proof of concept to trigger it. [13:17.840 --> 13:19.340] We don't have the latest firmware [13:19.340 --> 13:21.240] and things might get changed. [13:21.700 --> 13:23.640] The modem might block large ZCL arrays [13:23.640 --> 13:24.780] because we don't know. [13:25.140 --> 13:26.260] And we can't test it [13:26.260 --> 13:27.700] because we don't have the radio equipment [13:27.700 --> 13:30.380] to transmit the attack and check it. [13:30.900 --> 13:33.700] Luckily enough, the package arrived quite in time [13:34.180 --> 13:35.520] and we can now load the bridge [13:35.520 --> 13:36.720] and extract the latest firmware [13:36.720 --> 13:39.220] and check if something got changed. [13:39.560 --> 13:41.680] And of course it did. [13:42.040 --> 13:45.380] It turns out that now ZCL arrays are no longer supported [13:45.740 --> 13:48.140] and instead there was an additional support [13:48.140 --> 13:50.000] for ZCL strings. [13:50.000 --> 13:52.560] But if we look on the support of strings, [13:53.640 --> 13:56.520] we can see that the following code was changed. [13:56.520 --> 13:59.180] Now we allocate a dynamic buffer on the heap [13:59.180 --> 14:00.820] using the one byte length field [14:00.820 --> 14:04.760] plus an additional one byte for the added null terminator. [14:05.260 --> 14:08.240] This means we don't have any vulnerability this time, [14:08.240 --> 14:09.240] which is bad. [14:10.280 --> 14:12.500] Of course, we still have some good news [14:12.500 --> 14:14.320] because as you can see, [14:15.160 --> 14:18.260] the firmware was shipped with debug symbols. [14:18.660 --> 14:20.520] For some unknown reason, [14:20.520 --> 14:22.180] the new firmware version supports [14:23.140 --> 14:25.780] and was shipped with all of the names [14:25.780 --> 14:27.980] of all of the functions in the firmware, [14:27.980 --> 14:30.080] which was really quite useful for us [14:30.080 --> 14:32.340] for reverse engineering the new firmware. [14:33.220 --> 14:34.740] So what do we have? [14:35.000 --> 14:37.680] The latest firmware version dropped support for the ZCL arrays [14:37.680 --> 14:40.160] because now they use strings instead [14:40.160 --> 14:42.660] and strings don't have a vulnerability in them. [14:43.440 --> 14:46.620] It's a good time to search for other vulnerabilities. [14:47.000 --> 14:48.560] And we did try. [14:48.560 --> 14:50.260] We really, really did try [14:50.260 --> 14:51.660] and we covered most of the firmware [14:51.660 --> 14:54.840] and still we found pretty much nothing. [14:55.800 --> 14:57.400] And then remember, [14:58.640 --> 15:00.700] the ZCL strings were handled correctly [15:00.700 --> 15:02.680] and sent to another thread. [15:02.680 --> 15:05.460] But what does this thread do [15:05.460 --> 15:07.600] with the incoming ZCL strings? [15:07.600 --> 15:11.160] So we traced it down to this code snippet. [15:11.160 --> 15:12.220] In this code snippet, [15:12.220 --> 15:15.800] we can see the same memory location over the heap [15:15.800 --> 15:19.580] using the same fixed size we saw earlier. [15:19.580 --> 15:22.300] So that's quite suspicious. [15:22.920 --> 15:24.980] We can even see that later on, [15:24.980 --> 15:27.020] the buffer is being copied [15:27.260 --> 15:29.400] to the newly allocated heap buffer [15:29.740 --> 15:32.340] using the length field stored in the struct itself [15:32.340 --> 15:34.280] without any side checks. [15:34.560 --> 15:37.000] The only condition for reaching this code snippet [15:37.000 --> 15:40.700] is to have the fixed size of code of 16 [15:41.300 --> 15:43.320] stored in our struct. [15:43.540 --> 15:44.620] And when we go back [15:44.620 --> 15:47.480] to how we initialize the ZCL string struct, [15:47.480 --> 15:51.600] we can see that it indeed uses the same opcode, 16. [15:51.600 --> 15:55.100] So it turns out that someone forgot [15:55.100 --> 15:58.140] to finish the migration from arrays to strings. [15:58.180 --> 16:01.660] Strings should have been marked with F for strings [16:01.660 --> 16:05.620] and then be duplicated using a call to strdup. [16:05.620 --> 16:08.420] Instead, for some reason, [16:08.420 --> 16:11.260] internally they are still marked with 16 for arrays [16:11.260 --> 16:14.060] and are handled using the same vulnerable code snippet [16:14.060 --> 16:15.780] we saw in the earlier firmware version, [16:15.780 --> 16:18.040] which is quite good from our perspective. [16:18.040 --> 16:21.540] So the original vulnerability still exists. [16:21.540 --> 16:24.760] It is just buried deeper, that's all. [16:25.520 --> 16:27.560] Time to start transmitting ZigBee messages [16:27.560 --> 16:29.540] and hope to trigger the vulnerability. [16:38.300 --> 16:40.120] In order to play around with ZigBee, [16:40.120 --> 16:41.320] like the previous research, [16:41.320 --> 16:47.200] we decided to use the ATmega256RFR2x probe board. [16:47.340 --> 16:50.720] It enables us to send and receive ZigBee frames [16:50.720 --> 16:51.740] over the radio. [16:53.200 --> 16:55.840] It should be computationally equivalent to a light bulb, [16:55.840 --> 16:56.940] which is quite important [16:56.940 --> 16:59.680] because we are going to do all of our exploit [16:59.680 --> 17:01.080] from this board. [17:01.080 --> 17:02.580] And if we will succeed, [17:02.580 --> 17:04.920] then the same exploit could have been performed [17:04.920 --> 17:06.420] from a light bulb we took over [17:06.420 --> 17:08.700] using the previous research findings. [17:10.220 --> 17:12.840] In addition, it turned out to be even more important [17:13.780 --> 17:17.840] because there's really strict timing constraints in ZigBee. [17:17.840 --> 17:19.200] And the timing constraints dictate [17:19.200 --> 17:22.200] that we actually use C code from the board itself. [17:22.200 --> 17:25.040] We can't use Python from our laptop, for example. [17:25.980 --> 17:28.260] This means that the entire ZigBee code, [17:28.260 --> 17:30.340] the entire ZigBee stack that we need to implement [17:30.340 --> 17:31.620] should be in C. [17:31.620 --> 17:35.020] And the entire exploit should also be implemented in C. [17:35.020 --> 17:36.320] So it's not going to be easy, [17:36.320 --> 17:39.080] but we'll have to live with this. [17:40.260 --> 17:42.260] And the vulnerable flow is only accessible [17:42.260 --> 17:44.840] during a process called commissioning. [17:44.940 --> 17:47.120] And what is commissioning? [17:47.120 --> 17:50.380] Well, commissioning is a process of pairing [17:50.380 --> 17:52.340] and associating a new light bulb. [17:52.340 --> 17:54.260] We have two types of commissioning. [17:54.260 --> 17:56.060] We have classic commissioning [17:56.060 --> 17:59.280] and we have touch link commissioning. [17:59.280 --> 18:01.900] The Philips Hue app on Android, which we use, [18:01.900 --> 18:04.260] initiates a classic commissioning process. [18:04.260 --> 18:06.120] And so we focus on this one. [18:06.740 --> 18:08.480] Technically, in theory, [18:08.480 --> 18:11.260] the ZigBee specs explain the entire process. [18:12.080 --> 18:14.480] In practice, there's a lot of room for vendors [18:14.480 --> 18:17.340] to do as they wish, and trust me, they do. [18:18.960 --> 18:21.640] When analyzing the protocol, we got quite stuck [18:21.640 --> 18:25.300] because there was no documented flow, [18:25.300 --> 18:27.980] or at least no documented flow we could find. [18:27.980 --> 18:29.180] There was enough documentation [18:29.180 --> 18:32.000] for the structure of each specific message, [18:32.000 --> 18:34.460] but we don't know what message is supposed to be sent [18:34.890 --> 18:37.260] and when, as a response for what, [18:37.260 --> 18:40.540] so we don't have any clear flow for the commissioning. [18:41.300 --> 18:44.340] In addition, we can't sniff a full conversation [18:44.340 --> 18:46.040] from our light bulb and the bridge [18:46.040 --> 18:48.160] because too many messages are sent [18:48.160 --> 18:49.600] and they are sent too fast, [18:49.600 --> 18:51.780] and we simply miss some of them. [18:52.920 --> 18:56.780] If that wasn't enough, we need a cryptographic key. [18:56.900 --> 18:58.380] There is a transport key, [18:58.380 --> 19:01.240] which is shared between all of the ZigBee Lite devices, [19:01.240 --> 19:03.920] but we don't have the key inside. [19:03.920 --> 19:05.280] So how do we get it? [19:05.280 --> 19:08.640] We need to decrypt the messages really from an early phase [19:08.640 --> 19:09.860] in the commissioning. [19:09.880 --> 19:11.660] We will need the key. [19:13.040 --> 19:15.640] Luckily for us, we are not the first to tackle this issue, [19:15.640 --> 19:17.980] and in this blog post, [19:17.980 --> 19:19.500] you can find all of the information [19:19.500 --> 19:22.640] for all of the keys used in touch link commissioning [19:22.640 --> 19:24.080] and in classic commissioning [19:24.780 --> 19:27.260] with the values of the keys themselves. [19:27.440 --> 19:30.700] So we took the keys, we inserted them to Wireshark, [19:30.700 --> 19:32.140] and Wireshark can now automatically [19:32.140 --> 19:34.340] decrypt the messages we sniff. [19:35.740 --> 19:38.140] The analysis and the implementation part [19:38.140 --> 19:41.380] took a lot of effort, a lot of work days, [19:41.380 --> 19:43.100] but eventually it worked. [19:43.560 --> 19:45.940] We managed to fake our own light bulb. [19:45.940 --> 19:48.400] You can see a brand new checkpoint research light bulb [19:48.400 --> 19:51.100] with the model CPR123. [19:51.100 --> 19:54.180] So now our board is doing [19:54.180 --> 19:56.500] all of the classic commissioning phase, [19:56.500 --> 19:58.480] faking our own light bulb, [19:59.080 --> 20:01.180] so we could continue on. [20:01.480 --> 20:04.460] In order to help other researchers with this task, [20:04.460 --> 20:06.360] we decided to open source the full pickup [20:06.360 --> 20:07.820] of the classic commissioning [20:07.820 --> 20:10.360] as we sent it from our board. [20:10.360 --> 20:11.880] So instead of other researchers [20:11.880 --> 20:14.940] having to manually analyze the commissioning phase, [20:14.940 --> 20:16.480] you can now look on the pickup, [20:16.480 --> 20:20.000] the decrypted pickup with all of the messages we've sent. [20:21.940 --> 20:24.420] The lessons we learned thus far are, [20:25.340 --> 20:26.840] without user interaction, [20:26.840 --> 20:28.660] the bridge won't accept new light bulbs, [20:28.660 --> 20:30.880] which is a good security precaution, [20:30.880 --> 20:32.120] but it doesn't help us. [20:32.120 --> 20:36.340] We will need somehow to bypass this limitation. [20:36.900 --> 20:40.100] In addition, we have approximately one minute [20:40.100 --> 20:42.500] to commission as many light bulbs as we want. [20:42.500 --> 20:44.860] There is no check about it. [20:45.180 --> 20:47.540] The user will only see the light bulbs in the app [20:47.540 --> 20:51.420] after they finished a specific phase we labeled ZCL phase, [20:51.420 --> 20:57.280] which is pretty much the last phase in the commissioning. [20:57.780 --> 20:59.880] If we fake other light bulbs [20:59.880 --> 21:02.040] and we stop before the ZCL phase, [21:02.040 --> 21:03.600] the user won't be aware of that, [21:03.600 --> 21:05.840] which is pretty good for our attack. [21:06.520 --> 21:08.340] And the really good news are, [21:08.340 --> 21:09.660] we managed to trigger the vulnerability [21:09.660 --> 21:13.680] during the ZCL phase, so we have a success. [21:13.680 --> 21:15.300] We really have a vulnerability. [21:16.600 --> 21:18.820] There is no state machine check in place. [21:18.820 --> 21:21.880] We can simply send whatever ZCL strings we want, [21:21.880 --> 21:25.220] whenever we want, without any request to get them. [21:25.220 --> 21:27.480] So we can pretty much do anything we want [21:27.480 --> 21:29.020] with the long ZCL strings, [21:29.700 --> 21:32.900] as long as we do it during the ZCL phase, [21:32.900 --> 21:35.260] and specifically during the commissioning. [21:35.260 --> 21:38.320] Once the light bulb was fully added to the network, [21:38.320 --> 21:40.560] it can no longer trigger the vulnerability. [21:40.580 --> 21:42.420] The vulnerability will only be accessible [21:42.420 --> 21:44.440] during the commissioning phase. [21:45.560 --> 21:47.700] Time to start the exploit. [21:52.430 --> 21:56.090] Just a basic recap on our vulnerability before we continue. [21:56.730 --> 22:00.310] We have a linear-based buffer overflow over the heap. [22:00.850 --> 22:04.110] Our buffer size is limited to 70 controllable bytes. [22:04.270 --> 22:08.030] And this is because we only started with 127 bytes, [22:08.030 --> 22:09.930] which is the MTU on ZigBee, [22:09.930 --> 22:12.470] and the ZCL is quite high on the ZigBee stack. [22:12.470 --> 22:14.790] So we lost a lot of bytes due to headers. [22:15.230 --> 22:18.450] We will have to settle down with the 70 bytes we have. [22:19.330 --> 22:21.670] We don't have any byte constraints on our payload, [22:21.670 --> 22:22.490] which is good. [22:22.490 --> 22:25.270] We can send null bytes, non-printable bytes, [22:25.270 --> 22:26.950] pretty much everything we want. [22:27.730 --> 22:30.550] And the destination buffer is allocated over the heap [22:30.550 --> 22:34.270] using a fixed size buffer of 43 bytes. [22:35.870 --> 22:37.570] Time to focus the heap. [22:38.450 --> 22:40.050] The bridge uses uclibc, [22:40.050 --> 22:42.270] which is an old embedded libc implementation [22:42.270 --> 22:44.190] used in embedded devices. [22:44.830 --> 22:47.130] The chosen heap implementation inside uclibc [22:47.130 --> 22:48.610] is the malloc standard, [22:48.610 --> 22:51.110] which is dlmalloc behind the scene. [22:52.210 --> 22:54.770] Effectively, it is much like glibc, [22:54.770 --> 22:57.230] but with way less sanity checks. [22:57.510 --> 23:01.670] And this is because uclibc stands for micro-libc. [23:01.670 --> 23:05.390] It is meant to be used by devices without a lot of RAM, [23:05.390 --> 23:07.590] without a lot of CPU power, [23:07.590 --> 23:09.610] so it has to be slim. [23:09.750 --> 23:12.130] And being slim means there's less code [23:12.130 --> 23:14.150] and less sanity checks. [23:15.750 --> 23:17.810] All of our free buffers will fall into the range [23:17.810 --> 23:19.730] of what is called fast bins. [23:20.330 --> 23:21.910] There's a bin for each buffer size [23:21.910 --> 23:23.530] in multiple of eight bytes, [23:23.530 --> 23:26.490] starting from 16 being the minimal size. [23:26.490 --> 23:32.870] So we have a bin for all of the buffers up to 16 bytes, [23:33.030 --> 23:35.930] a bin for 16 to 24, [23:36.130 --> 23:37.930] a bin for 24 to 32, [23:37.930 --> 23:39.790] and so on and so forth. [23:40.210 --> 23:42.950] Inside each bin, we will have a singly-linked list [23:42.950 --> 23:44.670] of all of the free buffers. [23:45.910 --> 23:49.650] When examining the code for free in uclibc, [23:49.650 --> 23:51.850] we saw the following check. [23:52.110 --> 23:54.290] If size is less than or equal [23:54.290 --> 23:57.210] to some configurable amount called max-fast, [23:57.210 --> 23:59.990] we will use the fast bins [23:59.990 --> 24:01.830] and store our buffer inside them. [24:01.830 --> 24:05.450] In order to find the respective fast bin for our buffer, [24:05.450 --> 24:07.290] we will use the fast bin index macro [24:07.290 --> 24:08.870] we can see over here. [24:09.450 --> 24:12.350] In short, the macro divides the size by eight [24:12.350 --> 24:13.830] and subtracts two, [24:13.830 --> 24:17.070] because 16 should be the minimal size. [24:17.070 --> 24:18.910] But there's no check in place [24:18.910 --> 24:24.190] that the size indeed is bigger or equal to 16. [24:24.190 --> 24:27.710] So if we will be able to corrupt a buffer over the heap [24:27.710 --> 24:29.170] and modify the size, [24:29.170 --> 24:31.310] we could change the size to be eight [24:31.310 --> 24:33.090] or even zero, [24:33.090 --> 24:35.090] giving us the indices of minus one [24:35.090 --> 24:36.970] and minus two, respectively. [24:37.450 --> 24:39.510] In order to understand what will happen [24:39.510 --> 24:41.690] if we will use negative indices, [24:41.690 --> 24:44.170] we can see the malloc state start over here [24:44.170 --> 24:47.330] and the variables before the fast bins array. [24:47.810 --> 24:51.190] So if we will use index minus one, [24:51.190 --> 24:53.850] we will store our buffer on top of the max-fast [24:53.850 --> 24:55.970] before the fast bin array. [24:56.410 --> 24:59.130] Storing a pointer over the configurable size [24:59.130 --> 25:02.690] for fast bins will be too risky. [25:02.690 --> 25:04.690] It will simply ruin the heap. [25:04.830 --> 25:07.950] But what will happen if we'll use index minus two? [25:08.030 --> 25:12.270] Well, index minus two will store the pointer to our buffer [25:12.270 --> 25:14.730] before the malloc state variable. [25:14.730 --> 25:17.830] And before the malloc state start in memory, [25:17.830 --> 25:20.950] it turns out to be an unused variable, [25:20.950 --> 25:22.390] simply nothing. [25:22.470 --> 25:26.430] So if we free a buffer with size of zero, [25:26.430 --> 25:28.330] it will be stored somewhere in memory [25:28.330 --> 25:30.010] before the malloc state, [25:30.010 --> 25:31.630] and no one will reach it. [25:31.770 --> 25:33.930] The next buffer will be joined to it, [25:33.930 --> 25:35.450] creating a ghost link list [25:35.450 --> 25:38.750] we can refer to as the dev null fast bin. [25:38.850 --> 25:41.430] Since malloc is not aware of this bin, [25:41.430 --> 25:43.710] it won't extract buffers from it. [25:43.710 --> 25:45.490] And all of the buffers we free [25:45.490 --> 25:47.310] will be joined to this bin, [25:47.310 --> 25:49.710] but won't be returned to the heap itself, [25:49.710 --> 25:54.030] effectively enabling us to gradually shape the heap [25:54.030 --> 25:55.750] in the desired structure. [25:57.510 --> 26:00.710] The plan for our heap overflow is quite simple. [26:00.730 --> 26:02.470] We can see our buffer in blue [26:02.470 --> 26:06.050] and a buffer adjacent to it in memory in purple. [26:07.190 --> 26:09.170] The plan is to modify only the size [26:09.170 --> 26:11.830] and the pointer of the adjacent buffer. [26:12.890 --> 26:15.130] If you change the size to one, [26:15.130 --> 26:17.310] which means a size of zero bytes [26:17.310 --> 26:21.950] and one for the previous buffer is in use, [26:21.950 --> 26:24.990] then the buffer will go to the dev null link list [26:24.990 --> 26:29.650] because size zero will reflect it to index minus two. [26:29.930 --> 26:34.450] And the pointer will be changed to be our arbitrary address. [26:35.210 --> 26:37.870] Effectively, we want to get this structure. [26:37.870 --> 26:40.970] We want to corrupt the singly linked list inside fastbin [26:40.970 --> 26:44.530] so that an arbitrary buffer will be stored, [26:44.530 --> 26:47.510] or at least malloc will think that an arbitrary buffer [26:47.510 --> 26:50.630] will be stored in our arbitrary address. [26:51.090 --> 26:53.570] The goal is we want to confuse malloc [26:53.570 --> 26:56.210] so it will allocate a buffer at an arbitrary address [26:56.210 --> 27:00.470] and then will let us write our data into this buffer, [27:00.470 --> 27:04.250] effectively giving us a write-what-where exploit primitive. [27:05.070 --> 27:08.270] The heap shaping strategy is as follows. [27:08.570 --> 27:11.470] If we overflow this free fastbin buffer buffer, [27:11.470 --> 27:12.930] then we won. [27:12.930 --> 27:14.610] This is exactly what we aim at. [27:14.610 --> 27:17.030] We corrupted the singly linked list inside the fastbin [27:17.030 --> 27:19.510] and we will get our allocation. [27:20.490 --> 27:22.810] If we overflow the use buffer, [27:22.810 --> 27:24.370] then when it will be freed, [27:24.370 --> 27:26.310] it will go to the dev null fastbin [27:26.310 --> 27:28.230] and we won't see it any longer. [27:29.570 --> 27:33.150] If we overflow the use buffer that lives forever, [27:33.150 --> 27:36.630] oh, well, nothing would happen and no one will notice it. [27:37.650 --> 27:40.470] But if we overflow the free large buffer, [27:40.470 --> 27:41.790] then we're in trouble. [27:41.790 --> 27:43.270] We will probably crash soon, [27:43.270 --> 27:45.450] so we really don't want to do that. [27:46.150 --> 27:47.470] If done correctly, [27:47.470 --> 27:50.010] we will get the desired malloc-where primitive. [27:51.330 --> 27:54.850] malloc-where will grant us the ability to write over the got. [27:54.850 --> 27:58.030] The got is the global offset table. [27:58.090 --> 28:00.130] It's a global table of function pointers [28:00.130 --> 28:02.130] used to execute library functions, [28:02.130 --> 28:06.310] such as free, malloc, sleep, memcpy, [28:06.310 --> 28:09.170] and pretty much every other library call. [28:09.270 --> 28:12.530] And luckily for us, the got is at a fixed address. [28:13.630 --> 28:17.090] The modified function pointer will jump to our shell code, [28:17.090 --> 28:18.590] or at least in theory, [28:18.590 --> 28:20.430] because it sounds easy on paper, [28:20.430 --> 28:22.750] but it's way harder in real life. [28:28.190 --> 28:30.400] Time to construct the shell code. [28:32.310 --> 28:34.730] Location, location, location. [28:35.230 --> 28:37.510] We need to store a binary shell code [28:37.510 --> 28:39.470] in a fixed global address. [28:40.050 --> 28:42.390] The problem is we only get textual messages [28:42.390 --> 28:43.990] from the ZigBee modem, [28:43.990 --> 28:47.390] so we don't get any controlled binary data [28:48.070 --> 28:50.190] into the main CPU. [28:50.770 --> 28:55.250] We found only one good candidate for such a possible buffer, [28:55.250 --> 28:57.450] and this is the ZigBee phone book. [28:57.990 --> 29:00.070] This is an array of ZigBee addresses [29:00.070 --> 29:03.470] seen by, or advertised to, the bridge. [29:04.430 --> 29:07.610] It can hold up to 65 records of 16 byte each, [29:07.610 --> 29:10.990] giving us an upper bound of approximately one kilobyte [29:10.990 --> 29:12.870] for the entire shell code. [29:13.550 --> 29:17.130] It's not a lot of bytes, but it should be enough for us. [29:18.350 --> 29:20.990] The neighbor record inside the ZigBee phone book [29:20.990 --> 29:23.410] is constructed as follows. [29:23.470 --> 29:27.210] The first eight bytes are for the extended network address, [29:27.210 --> 29:28.830] which we fully control. [29:28.910 --> 29:31.290] After that, we have additional two bytes [29:31.290 --> 29:35.190] for the short network address, again, fully controlled. [29:35.890 --> 29:38.390] And our stroke of luck ended, [29:38.390 --> 29:41.650] which is quite reasonable, sorry, [29:41.650 --> 29:45.910] because now we have six bytes for miscellaneous fields, [29:45.910 --> 29:47.870] and we don't really control them. [29:47.870 --> 29:50.290] So we have 10 consecutive bytes we control, [29:50.290 --> 29:53.010] but we don't control the entire memory. [29:54.970 --> 29:57.310] Oh, and about that. [29:57.310 --> 29:58.930] It turns out the bridge is unstable [29:58.930 --> 30:01.710] when it gets more than 20 records, [30:01.710 --> 30:06.730] so this is going to be quite a small shell code. [30:07.790 --> 30:11.370] The initial plan was simple. [30:11.610 --> 30:14.530] It looks infeasible to restore the execution flow, [30:14.530 --> 30:16.690] because we pretty much ruined the heap. [30:17.350 --> 30:20.550] Instead, our shell code will try to patch the binary [30:20.550 --> 30:23.870] on the file system and install a backdoor. [30:23.870 --> 30:26.370] After the process will crash, [30:26.510 --> 30:30.230] a daemon will reboot the binary with our backdoor, [30:30.230 --> 30:33.390] and then we will trigger it from another light bulb. [30:34.410 --> 30:37.950] Problem is, both the patch and the file path [30:37.950 --> 30:40.770] don't fit in 10 consecutive bytes each, [30:40.770 --> 30:44.510] so we can't decode them properly in the ZigBee phone book. [30:44.530 --> 30:48.990] The solution for this problem is purely academic. [30:49.890 --> 30:53.270] An ideal shell code by reduction will be, [30:53.270 --> 30:57.250] use the 10 consecutive bytes per record to build a decoder, [30:57.250 --> 30:59.470] and the decoder will decode the rest of the records [30:59.470 --> 31:02.570] to be nicely ordered in memory. [31:03.430 --> 31:05.850] In MIPS 16, a jump to the next record [31:05.850 --> 31:07.870] will only cost us two bytes, [31:07.870 --> 31:10.570] giving us eight spare bytes in each record [31:10.570 --> 31:12.730] to construct our decoder. [31:14.530 --> 31:17.110] But there are problems with this plan. [31:17.650 --> 31:19.670] We need to clear the instruction cache [31:19.670 --> 31:22.730] before jumping to the unpacked shell code, [31:22.730 --> 31:26.650] and because this is a MIPS CPU and we crashed when trying. [31:27.590 --> 31:30.070] And if we use sleep to clear the cache, [31:30.070 --> 31:33.470] as people usually do, the watchdog will kill the process [31:33.470 --> 31:35.550] because it doesn't respond. [31:36.430 --> 31:40.310] And we don't have enough records to silence the watchdog, [31:40.310 --> 31:42.390] sleep, and use a decoder, [31:42.390 --> 31:45.090] so the ideal shell code is good on paper, [31:45.090 --> 31:47.270] but it's not practical. [31:48.350 --> 31:51.390] Instead, we went for a more bold design. [31:52.120 --> 31:53.930] We will restore the execution flow. [31:53.930 --> 31:56.130] We really don't have any choice. [31:56.830 --> 31:58.790] This means we will call mprotect [31:58.790 --> 32:02.270] to modify the permissions of the code in memory [32:02.270 --> 32:06.410] from executable to be executable and writable, [32:06.410 --> 32:08.830] and we will install the backdoor in RAM [32:08.830 --> 32:10.270] during the execution. [32:12.390 --> 32:16.750] A few days and one hand-crafted shell code later on, [32:16.750 --> 32:20.450] we have a shell code that fully restores the execution. [32:20.450 --> 32:22.850] It restores the GOT, it restores the HEAP, [32:22.850 --> 32:25.390] and it restores pretty much everything we need. [32:26.250 --> 32:29.710] In addition, the shell code will only cost us 16 records, [32:29.710 --> 32:32.570] which is well in budget, less than 20. [32:33.810 --> 32:37.090] And here we can see the shell code in IDA. [32:37.490 --> 32:40.510] From the first record, we will jump to the second, [32:40.510 --> 32:42.450] and then we'll jump to the third, [32:42.450 --> 32:46.030] and so on and so forth until we install the backdoor [32:46.030 --> 32:48.010] and restore the execution flow. [32:49.630 --> 32:52.670] When we connect all of the dots together, [32:52.670 --> 32:54.050] the backdoor shell code will give us [32:54.050 --> 32:55.810] an arbitrary write primitive. [32:56.590 --> 32:59.530] Our exploit will fake an additional legitimate light bulb, [32:59.530 --> 33:02.310] but we'll leverage this arbitrary write primitive we installed [33:03.030 --> 33:06.510] and we'll use it to write Scout's loader to memory. [33:07.450 --> 33:10.670] Upon execution, Scout will load the full payload, [33:10.670 --> 33:13.450] which in this case, we've chosen to use EternalBlue. [33:14.590 --> 33:17.470] Here we can see that Scout dropped the file [33:17.470 --> 33:21.110] on tmp.exploit with root privileges, [33:21.110 --> 33:24.010] and this tmp.exploit file will use EternalBlue [33:24.010 --> 33:26.830] to attack computers inside a computer network, [33:26.830 --> 33:29.830] which is a good time for our demo. [33:39.100 --> 33:42.200] Here we can see the light bulb and the user using it. [33:42.560 --> 33:43.920] We can see that it works. [33:43.920 --> 33:45.380] The app works fine. [33:45.380 --> 33:47.860] And the user can modify the color of the light bulb [33:47.860 --> 33:49.000] as he wishes. [33:54.900 --> 33:56.240] When the attacker starts, [33:56.240 --> 33:58.540] he will try to hijack the light bulb [33:58.540 --> 34:00.440] and steal it from the network. [34:00.820 --> 34:03.220] And once he joined the attacker's network, [34:03.220 --> 34:05.720] the attacker will change the light bulb to a hideous color [34:05.720 --> 34:06.980] to annoy the user, [34:07.840 --> 34:10.020] so that the user will see that something is wrong [34:10.020 --> 34:11.160] with his light bulb. [34:12.680 --> 34:16.500] So we took over the light bulb and now it's ours. [34:17.180 --> 34:19.140] When the user sees that something is wrong, [34:19.140 --> 34:22.000] you can see that he no longer controls the light bulb, [34:22.000 --> 34:23.900] he can't change the light bulb's color, [34:23.900 --> 34:28.240] and it seems to be unreachable when it sees it over the app. [34:29.120 --> 34:32.080] The only way to reinstall the light bulb is to delete it [34:32.080 --> 34:35.200] and tell the bridge to search for new light bulbs. [34:35.200 --> 34:38.160] And this is where our attack will officially start. [34:38.880 --> 34:40.680] We will fake a legitimate light bulb, [34:40.680 --> 34:43.620] so the user will be happy, this is our light bulb, [34:43.620 --> 34:47.620] and we will fake it as the user actually configures [34:47.620 --> 34:49.240] the light bulb as he wishes, [34:49.240 --> 34:51.320] so the user won't see that something is wrong [34:51.320 --> 34:53.500] with our fake light bulb. [34:56.270 --> 34:59.030] Behind the scene, the full attack will take place. [35:02.640 --> 35:06.680] Here we can see that the bridge is connected to the laptop, [35:06.680 --> 35:08.780] so it's connected to the computer network. [35:09.440 --> 35:12.100] And now behind the scene, we will use our vulnerability, [35:12.100 --> 35:14.140] shape the heap and take over the bridge. [35:14.140 --> 35:16.020] And from the bridge, we will use EternalBlue [35:16.020 --> 35:20.300] to attack the computer inside the network and pop a cock. [35:20.440 --> 35:22.480] So our attack worked. [35:24.420 --> 35:26.920] Time for the coordinated disclosure. [35:27.700 --> 35:29.480] The vulnerability was reported to Signify [35:29.480 --> 35:32.120] on the 5th of November, 2019. [35:32.780 --> 35:35.200] The vendor confirmed the vulnerability on the same day, [35:35.200 --> 35:36.660] which is quite impressive. [35:36.660 --> 35:39.820] It's even more impressive because not only the vendor [35:40.420 --> 35:43.060] sent its acknowledgement on the same day [35:43.060 --> 35:45.140] when it received our report, [35:45.140 --> 35:49.040] it actually acknowledged the existence of the vulnerability, [35:49.040 --> 35:52.320] which it found in the code according to our report. [35:52.380 --> 35:56.060] So the vendor did pretty much everything in a single day, [35:56.060 --> 35:58.000] which is very impressive. [35:59.700 --> 36:01.340] Later on, Signify issued a patch [36:01.340 --> 36:03.520] via an automatic update in January. [36:04.260 --> 36:06.500] And you can find the full details and advisory [36:06.500 --> 36:07.680] in our blog post. [36:07.680 --> 36:10.820] And the official CVE issued for this specific vulnerability [36:11.440 --> 36:14.940] is CVE-2020-6007. [36:15.580 --> 36:18.860] And if you have Philips Hue lighting in your office [36:18.860 --> 36:21.140] or in your home, don't worry. [36:21.140 --> 36:24.380] All of the products should have received the update by now. [36:25.660 --> 36:26.860] Conclusion. [36:27.960 --> 36:31.940] Even with an MTU of 127 bytes, ZigBee vulnerabilities [36:31.940 --> 36:35.180] are indeed exploitable as we've shown in our demo. [36:36.580 --> 36:41.000] Security mitigations only work when they are on by default. [36:41.480 --> 36:43.320] The IP bridge binary was compiled [36:43.320 --> 36:45.740] to use static fixed addresses. [36:45.740 --> 36:47.720] So we were able to target the GOT [36:47.720 --> 36:49.480] which was on a fixed address, [36:49.480 --> 36:52.160] even without an information leak vulnerability. [36:52.860 --> 36:55.780] The binary was not compiled with any stacking areas. [36:55.780 --> 36:57.120] The GOT was writable, [36:57.120 --> 36:59.520] so we could do pretty much everything we want to do [36:59.520 --> 37:02.000] once we had an initial vulnerability. [37:02.620 --> 37:06.160] Still, there was ASLR in place for the heap, [37:06.160 --> 37:08.700] for the stack, and for the loaded libraries, [37:08.700 --> 37:10.200] and that's thanks to Linux. [37:10.200 --> 37:12.760] So if it's on by default, you will get it, [37:12.760 --> 37:15.340] but if you need to manually do something in your makefile, [37:15.340 --> 37:18.580] you won't get it in most common cases. [37:20.000 --> 37:23.380] And small devices are becoming popular by the minute, [37:23.380 --> 37:26.200] and yet we can't even trust our own light bulbs. [37:26.200 --> 37:28.780] So maybe we should do something about it. [37:30.060 --> 37:33.240] We can't finish this research and this presentation [37:33.240 --> 37:34.900] without saying special thanks [37:34.900 --> 37:37.500] to everyone that helped make this research possible. [37:37.500 --> 37:40.740] So we have Eyal Ronyan for the research idea [37:40.740 --> 37:42.840] and the active guidance. [37:43.580 --> 37:45.420] Colin O'Flynn for the detailed write-ups [37:45.420 --> 37:46.240] on routing the bridge [37:46.240 --> 37:48.860] and the entire hardware analysis of it. [37:49.640 --> 37:52.500] For Peter, for publishing the ZigBee transport keys [37:52.500 --> 37:53.480] for the light bulbs, [37:53.480 --> 37:56.100] which we used and couldn't continue without. [37:56.960 --> 37:58.780] And for Yaron Itkin, [37:58.780 --> 38:01.440] for the crucial hardware support along the way. [38:01.560 --> 38:02.980] Thanks, little brother. [38:03.540 --> 38:05.120] And last but not least, [38:05.120 --> 38:06.980] for the entire CPR research team [38:06.980 --> 38:10.760] and for their support alongside this very long research. [38:11.340 --> 38:14.460] Until the next time, thank you for joining this talk.