1 00:00:00,940 --> 00:00:06,080 Hello everyone, and thank you for joining my talk today called Don't Be Silly, It's Only a Lightbulb. 2 00:00:06,080 --> 00:00:08,680 Before we begin, just a brief introduction. 3 00:00:09,280 --> 00:00:11,440 My name is Eyal Itkin. 4 00:00:11,440 --> 00:00:15,060 I'm a vulnerability researcher working at Checkpoints Research Group. 5 00:00:15,240 --> 00:00:22,680 In my research projects, I tend to focus on embedded devices and protocols, and in which case I combine these both together. 6 00:00:23,100 --> 00:00:27,360 You can usually read more about my recent publications on my Twitter account. 7 00:00:28,500 --> 00:00:37,760 The motivation for this specific research started a few years ago in 2016, when I heard of a new smart IoT device, smart lightbulbs. 8 00:00:37,940 --> 00:00:49,620 I was already quite familiar with many smart gadgets and even smart air conditioner, which allows you to activate it remotely on your way home so the temperature will be just fine when you arrive. 9 00:00:49,920 --> 00:00:53,540 But why would I need a smart lightbulb? 10 00:00:53,540 --> 00:01:01,520 I only need a light when I'm physically in a room and I'm fully capable of toggling the switch on and off when I enter and leave the room. 11 00:01:01,520 --> 00:01:03,480 Why would I need an app for that? 12 00:01:03,480 --> 00:01:08,400 Well, I figured out that it won't catch, people won't buy it, and that's it. 13 00:01:08,600 --> 00:01:19,740 And apparently I was wrong, because according to a report from the end of 2018, more than 400,000 households in the UK were already using smart lighting solutions. 14 00:01:19,740 --> 00:01:22,360 So people are apparently buying this gadget. 15 00:01:23,000 --> 00:01:32,440 Okay, but if I connect my lightbulb to the mobile phone or to the internet, there will be some security risk about it, right? 16 00:01:32,920 --> 00:01:37,220 But when I ask people about it, I always receive the same response. 17 00:01:37,260 --> 00:01:40,820 Don't be silly, it's only a lightbulb, it's fine. 18 00:01:42,060 --> 00:01:48,400 Obviously, I'm not the first to study this test case and there is some great firework before me. 19 00:01:49,200 --> 00:01:57,260 We will start with a lightbulb worm by Colin Flynn and Eyal Ronen, which presented their research on Blackhead USA on 2016. 20 00:01:57,580 --> 00:02:04,160 Later on, they developed the research into IoT goes nuclear, creating a ZigBee chain reaction. 21 00:02:04,540 --> 00:02:11,500 This time they were joined by Adi Shamir and Achior Weingarten, and you can read all about it on their website. 22 00:02:11,860 --> 00:02:21,600 I really recommend you reading about the research because it was so cool, they actually took over all of the lightbulbs on campus in a war flying demo from their drone. 23 00:02:22,320 --> 00:02:37,720 Since I already was familiar with Eyal Ronen's work and both Eyal Ronen and Achior are all colleagues of mine, I talked with Eyal Ronen and together we decided that with his help, I'm going to continue on the research and take it to the next level. 24 00:02:38,160 --> 00:02:40,280 So, what did they find? 25 00:02:40,880 --> 00:02:47,920 Well, it turns out that attackers can remotely steal a lightbulb from a given ZigBee network and force it to join their own. 26 00:02:48,300 --> 00:02:54,820 Once it joined the network, attackers can send the lightbulb a malicious firmware update to fully take over it. 27 00:02:55,220 --> 00:03:04,980 And if that wasn't enough, it turns out that even a regular lightbulb can steal other lightbulbs and you don't need any fancy RF equipment or an antenna in order to do it. 28 00:03:05,840 --> 00:03:13,420 Using these three primitives together, the researchers claim that you can take over a selected set of lightbulbs in a given city. 29 00:03:13,420 --> 00:03:26,080 From each lightbulb, you'll take over the other lightbulbs in close proximity and so on and so forth in order to propagate and take over all of the lightbulbs in a given city in a nuclear-like chain reaction. 30 00:03:26,640 --> 00:03:32,940 Sadly for us, the vendor did fix the last vulnerability and we were only left with the first two. 31 00:03:33,840 --> 00:03:38,420 If you put it visually, we can see the network diagram over here. 32 00:03:39,300 --> 00:03:45,980 On the right, we can see a smart lightbulb which communicates with its bridge, the controller, over ZigBee radio. 33 00:03:46,060 --> 00:03:56,580 The bridge is connected to both the radio network and the computer network with an ethernet cable so we could control the lightbulb from our mobile phone through the controller. 34 00:03:57,040 --> 00:04:07,280 The attack itself will start when the attacker will transmit ZigBee factory reset messages to the lightbulb in order to confuse it and convince it to join their own network. 35 00:04:07,500 --> 00:04:15,220 Once it joined the network, attackers can send a malicious over-the-air firmware update to the lightbulb to fully take over the lightbulb itself. 36 00:04:16,300 --> 00:04:25,460 And while the original research only focused on the lightbulbs, we are focused on a much broader target and we want to take their research to the next step. 37 00:04:25,460 --> 00:04:27,520 We want to infiltrate the network. 38 00:04:28,340 --> 00:04:40,640 In order to infiltrate the network, we are hoping to find a vulnerability so that our lightbulb will be able to remotely exploit the ZigBee vulnerability in the bridge itself in order to take over it. 39 00:04:41,240 --> 00:04:49,740 Once we took over the bridge, the bridge can launch attack inside a computer network and hopefully allow us to take over the computers inside the network itself. 40 00:04:50,300 --> 00:04:54,240 Once we understood our attack vector, it's time to get started. 41 00:04:59,540 --> 00:05:03,000 But first, some preliminary slides on ZigBee. 42 00:05:03,460 --> 00:05:07,740 ZigBee is a suite of high-level protocols for closed proximity networks. 43 00:05:07,880 --> 00:05:15,540 It's an IEEE 802.154-based specs that defines a low-range, low-power radio. 44 00:05:16,000 --> 00:05:21,840 Not to be confused with IEEE 802.11, which stands for the more commonly used Wi-Fi. 45 00:05:22,720 --> 00:05:29,280 The maximal transmission unit, or the MTU, over ZigBee is only 127 bytes long. 46 00:05:29,280 --> 00:05:30,460 And I repeat that. 47 00:05:30,460 --> 00:05:36,680 The maximal packet we can transmit over the air contains only 127 bytes. 48 00:05:36,680 --> 00:05:45,100 And with this harsh limit, we should be able to somehow exploit vulnerabilities that we hope to find in the bridge. 49 00:05:46,540 --> 00:05:48,760 ZigBee has a full network stack of its own. 50 00:05:49,360 --> 00:06:00,200 Like any other network stack, it starts with the lower levels, which is the physical layer and the medium access control layer, which acts as the internet acts in normal computer networks. 51 00:06:01,040 --> 00:06:07,060 On top of that, we have the network access layer, which is responsible for both routing and encryption. 52 00:06:07,820 --> 00:06:15,380 Above that, we have the application sub-layer, which is responsible for routing our packet to the respective application in the upper layers. 53 00:06:15,820 --> 00:06:24,840 This application could be ZDP, which stands for ZigBee Device Profile and responsible for managing different aspects of the ZigBee protocol. 54 00:06:25,280 --> 00:06:32,960 It could be ZCL, ZigBee Cluster Library, which is responsible for managing the configurations of the different devices. 55 00:06:33,660 --> 00:06:37,880 And it could be whatever other application that the vendor decided to implement. 56 00:06:38,500 --> 00:06:42,420 Now that we understood how ZigBee works, it's time to meet our target. 57 00:06:43,360 --> 00:06:49,160 The target for this research is going to be the Philips Hue Smart Lighting, now under Signify. 58 00:06:50,400 --> 00:06:55,600 Signify controls approximately one third of the market in the UK, so it's a broad target. 59 00:06:56,040 --> 00:07:05,280 And we're going to focus specifically on the bridge because as we mentioned earlier, the bridge is connected to both the radio network and the computer network, and we hope to bridge the two. 60 00:07:07,000 --> 00:07:14,380 Specifically, we're going to focus on a second generation of hardware for the bridge, which is the rectangular version of the bridge as seen on the right. 61 00:07:15,460 --> 00:07:19,140 If you remove the plastic cover from the bridge, we can see the board. 62 00:07:19,760 --> 00:07:27,060 When looking on a board, we can see on the right, the main CPU, which is a Qualcomm CPU usually found on Wi-Fi enabled devices. 63 00:07:27,960 --> 00:07:34,080 Over the left, we can see an Atmel CPU, which we'll refer to as the ZigBee modem. 64 00:07:34,080 --> 00:07:42,440 And like any other embedded device, we have a clear pinout for serial debug, which turned out to be quite useful throughout this research. 65 00:07:44,120 --> 00:07:47,720 The main CPU is a MIPS architecture, which is quite unique. 66 00:07:47,800 --> 00:07:50,560 And the operating system is Linux. 67 00:07:50,620 --> 00:07:59,280 This is quite refreshing because in prior research projects, we mainly had to handle real-time operating systems, which are harder to debug. 68 00:07:59,340 --> 00:08:14,940 This time, since we have Linux, we hope to be able to root it and to access it directly using an SSH connection in order to extract the file of the firmware itself, and in order to hopefully install a remote GDB server in order to debug the device. 69 00:08:15,580 --> 00:08:24,300 And luckily enough, Colin O'Flynn details in his blog exactly how to root the bridge with a step-by-step guide followed by a video. 70 00:08:25,000 --> 00:08:28,400 Once finished, we will get a root SSH connection. 71 00:08:29,840 --> 00:08:37,720 When I started this research, LLNN told me that the bridge is using a single huge process that's pretty much doing everything. 72 00:08:37,720 --> 00:08:39,560 And this is the IP bridge. 73 00:08:40,460 --> 00:08:44,120 The IP bridge is a single process that acts as the brain of the device. 74 00:08:44,120 --> 00:08:53,160 It is responsible for parsing incoming ZigBee messages, maintaining the different ZigBee state machines, and pretty much doing everything it needs. 75 00:08:54,200 --> 00:09:04,040 And like any other embedded device, IP bridge runs with root privileges, which means that once we took over this process, we don't need any other vulnerability. 76 00:09:04,860 --> 00:09:13,120 Now that we saw all of these data, it's time to start looking for vulnerabilities and IP bridge is going to be our target. 77 00:09:17,320 --> 00:09:22,300 We had quite a slow start to begin with because due to technical issues, I couldn't root the bridge. 78 00:09:22,300 --> 00:09:27,840 It turns out that I don't have the right hardware equipment as my younger brother rightfully pointed out. 79 00:09:28,400 --> 00:09:35,320 And the package we ordered got delayed like pretty much any other research project I've done thus far. 80 00:09:35,780 --> 00:09:42,880 Instead of sitting idle, we decided to start working on the old firmware version, which we received from the original research team. 81 00:09:43,240 --> 00:09:50,680 This is a firmware version, which is a few years old, and we really hope that it didn't change a lot throughout the years, but we really don't know. 82 00:09:50,680 --> 00:09:54,300 We simply have to cross our fingers and hope for good. 83 00:09:55,980 --> 00:10:00,420 When analyzing IP bridge, we soon enough saw something quite odd. 84 00:10:00,920 --> 00:10:16,800 The code expects strings to be found inside incoming messages instead of bits, because we can see the strings as such as ZDP or ZCL or even connection, but the maximum message size is only 127 bytes long. 85 00:10:16,800 --> 00:10:20,180 We don't have enough room for textual strings. 86 00:10:20,180 --> 00:10:23,880 We have enough room for mere single bits and that's it. 87 00:10:23,880 --> 00:10:26,260 So what's going on? 88 00:10:26,780 --> 00:10:29,300 And things got complicated. 89 00:10:29,980 --> 00:10:32,700 It turns out we forgot about the ZigBee modem. 90 00:10:32,940 --> 00:10:40,900 The ZigBee modem uses Atmel's BitCloud SDK in order to parse incoming ZigBee messages before they arrive to the main CPU. 91 00:10:42,080 --> 00:10:48,060 Effectively, it acts as a co-processor that handles the ZigBee lower network layers instead of the main CPU. 92 00:10:48,840 --> 00:10:55,520 It converts the parse messages to textual form and sends them over serial to the main CPU to be handled. 93 00:10:56,200 --> 00:11:00,400 And of course we don't have the firmware for it, so it's a black box. 94 00:11:02,520 --> 00:11:08,880 The modem reduces the attack surface on the main CPU because complex parsing is offloaded to the modem. 95 00:11:08,880 --> 00:11:14,620 And if the main CPU doesn't handle a specific task, it can be vulnerable when doing so. 96 00:11:15,020 --> 00:11:22,520 And we don't fully control the messages which are sent to the main CPU because they are constructed on the modem itself. 97 00:11:23,960 --> 00:11:31,100 And if that wasn't enough, it puts a huge question mark on everything we find because maybe the modem checks it. 98 00:11:31,840 --> 00:11:33,660 Maybe there's no check at all. 99 00:11:33,880 --> 00:11:38,480 So we'll have to add this to the list of ongoing issues and really hope for the best. 100 00:11:40,100 --> 00:11:46,340 Our first vulnerability attempt focus on ZigBee cluster library, which is ZCL. 101 00:11:46,540 --> 00:11:54,460 ZCL is responsible for managing configurations and it really is similar to SNMP in traditional IT networks. 102 00:11:54,780 --> 00:12:00,660 It offers a read attribute, write attribute interface and it supports multiple data types. 103 00:12:00,880 --> 00:12:03,620 The first data type is Boolean. 104 00:12:03,640 --> 00:12:11,080 Then we have an unsigned integer of eight bits, an unsigned integer of 32 bits, and even a dynamic array. 105 00:12:11,760 --> 00:12:17,740 And a variable size data type in an embedded device is a sure recipe for vulnerabilities. 106 00:12:17,960 --> 00:12:19,680 It looks promising. 107 00:12:20,020 --> 00:12:26,280 When we dived in to look how ZCL arrays are being parsed in the code, we saw the following code snippet. 108 00:12:27,220 --> 00:12:37,300 Here we can see that at first, a one byte length field is read from the message and then a fixed buffer is allocated over the heap with 33 bytes. 109 00:12:37,940 --> 00:12:40,800 Don't be confused by the delay slot in MIPS. 110 00:12:40,800 --> 00:12:50,520 The assignment into register A0 is done chronologically before the invocation of the malloc function and that's why it's called a delay slot. 111 00:12:50,820 --> 00:12:54,820 Effectively, we allocate a fixed size buffer over the heap and that's it. 112 00:12:55,520 --> 00:13:01,920 Later on, we'll read the entire blob from our attackers packet into the fixed size buffer. 113 00:13:02,320 --> 00:13:03,860 And what does it mean? 114 00:13:03,860 --> 00:13:11,380 Well, a controlled one byte name copy into a fixed size heap buffer and that's the definition of a heap-based buffer overflow. 115 00:13:12,740 --> 00:13:17,700 Sadly for us, it isn't a vulnerability until we have a working proof of concept to trigger it. 116 00:13:17,840 --> 00:13:21,240 We don't have the latest firmware and things might get changed. 117 00:13:21,700 --> 00:13:24,780 The modem might block large ZCL arrays because we don't know. 118 00:13:25,140 --> 00:13:30,380 And we can't test it because we don't have the radio equipment to transmit the attack and check it. 119 00:13:30,900 --> 00:13:39,220 Luckily enough, the package arrived quite in time and we can now load the bridge and extract the latest firmware and check if something got changed. 120 00:13:39,560 --> 00:13:41,680 And of course it did. 121 00:13:42,040 --> 00:13:50,000 It turns out that now ZCL arrays are no longer supported and instead there was an additional support for ZCL strings. 122 00:13:50,000 --> 00:13:56,520 But if we look on the support of strings, we can see that the following code was changed. 123 00:13:56,520 --> 00:14:04,760 Now we allocate a dynamic buffer on the heap using the one byte length field plus an additional one byte for the added null terminator. 124 00:14:05,260 --> 00:14:09,240 This means we don't have any vulnerability this time, which is bad. 125 00:14:10,280 --> 00:14:18,260 Of course, we still have some good news because as you can see, the firmware was shipped with debug symbols. 126 00:14:18,660 --> 00:14:32,340 For some unknown reason, the new firmware version supports and was shipped with all of the names of all of the functions in the firmware, which was really quite useful for us for reverse engineering the new firmware. 127 00:14:33,220 --> 00:14:34,740 So what do we have? 128 00:14:35,000 --> 00:14:42,660 The latest firmware version dropped support for the ZCL arrays because now they use strings instead and strings don't have a vulnerability in them. 129 00:14:43,440 --> 00:14:46,620 It's a good time to search for other vulnerabilities. 130 00:14:47,000 --> 00:14:48,560 And we did try. 131 00:14:48,560 --> 00:14:54,840 We really, really did try and we covered most of the firmware and still we found pretty much nothing. 132 00:14:55,800 --> 00:15:02,680 And then remember, the ZCL strings were handled correctly and sent to another thread. 133 00:15:02,680 --> 00:15:07,600 But what does this thread do with the incoming ZCL strings? 134 00:15:07,600 --> 00:15:11,160 So we traced it down to this code snippet. 135 00:15:11,160 --> 00:15:19,580 In this code snippet, we can see the same memory location over the heap using the same fixed size we saw earlier. 136 00:15:19,580 --> 00:15:22,300 So that's quite suspicious. 137 00:15:22,920 --> 00:15:34,280 We can even see that later on, the buffer is being copied to the newly allocated heap buffer using the length field stored in the struct itself without any side checks. 138 00:15:34,560 --> 00:15:43,320 The only condition for reaching this code snippet is to have the fixed size of code of 16 stored in our struct. 139 00:15:43,540 --> 00:15:51,600 And when we go back to how we initialize the ZCL string struct, we can see that it indeed uses the same opcode, 16. 140 00:15:51,600 --> 00:15:58,140 So it turns out that someone forgot to finish the migration from arrays to strings. 141 00:15:58,180 --> 00:16:05,620 Strings should have been marked with F for strings and then be duplicated using a call to strdup. 142 00:16:05,620 --> 00:16:18,040 Instead, for some reason, internally they are still marked with 16 for arrays and are handled using the same vulnerable code snippet we saw in the earlier firmware version, which is quite good from our perspective. 143 00:16:18,040 --> 00:16:21,540 So the original vulnerability still exists. 144 00:16:21,540 --> 00:16:24,760 It is just buried deeper, that's all. 145 00:16:25,520 --> 00:16:29,540 Time to start transmitting ZigBee messages and hope to trigger the vulnerability. 146 00:16:38,300 --> 00:16:47,200 In order to play around with ZigBee, like the previous research, we decided to use the ATmega256RFR2x probe board. 147 00:16:47,340 --> 00:16:51,740 It enables us to send and receive ZigBee frames over the radio. 148 00:16:53,200 --> 00:17:01,080 It should be computationally equivalent to a light bulb, which is quite important because we are going to do all of our exploit from this board. 149 00:17:01,080 --> 00:17:08,700 And if we will succeed, then the same exploit could have been performed from a light bulb we took over using the previous research findings. 150 00:17:10,220 --> 00:17:17,840 In addition, it turned out to be even more important because there's really strict timing constraints in ZigBee. 151 00:17:17,840 --> 00:17:22,200 And the timing constraints dictate that we actually use C code from the board itself. 152 00:17:22,200 --> 00:17:25,040 We can't use Python from our laptop, for example. 153 00:17:25,980 --> 00:17:31,620 This means that the entire ZigBee code, the entire ZigBee stack that we need to implement should be in C. 154 00:17:31,620 --> 00:17:35,020 And the entire exploit should also be implemented in C. 155 00:17:35,020 --> 00:17:39,080 So it's not going to be easy, but we'll have to live with this. 156 00:17:40,260 --> 00:17:44,840 And the vulnerable flow is only accessible during a process called commissioning. 157 00:17:44,940 --> 00:17:47,120 And what is commissioning? 158 00:17:47,120 --> 00:17:52,340 Well, commissioning is a process of pairing and associating a new light bulb. 159 00:17:52,340 --> 00:17:54,260 We have two types of commissioning. 160 00:17:54,260 --> 00:17:59,280 We have classic commissioning and we have touch link commissioning. 161 00:17:59,280 --> 00:18:04,260 The Philips Hue app on Android, which we use, initiates a classic commissioning process. 162 00:18:04,260 --> 00:18:06,120 And so we focus on this one. 163 00:18:06,740 --> 00:18:11,260 Technically, in theory, the ZigBee specs explain the entire process. 164 00:18:12,080 --> 00:18:17,340 In practice, there's a lot of room for vendors to do as they wish, and trust me, they do. 165 00:18:18,960 --> 00:18:27,980 When analyzing the protocol, we got quite stuck because there was no documented flow, or at least no documented flow we could find. 166 00:18:27,980 --> 00:18:40,540 There was enough documentation for the structure of each specific message, but we don't know what message is supposed to be sent and when, as a response for what, so we don't have any clear flow for the commissioning. 167 00:18:41,300 --> 00:18:51,780 In addition, we can't sniff a full conversation from our light bulb and the bridge because too many messages are sent and they are sent too fast, and we simply miss some of them. 168 00:18:52,920 --> 00:18:56,780 If that wasn't enough, we need a cryptographic key. 169 00:18:56,900 --> 00:19:03,920 There is a transport key, which is shared between all of the ZigBee Lite devices, but we don't have the key inside. 170 00:19:03,920 --> 00:19:05,280 So how do we get it? 171 00:19:05,280 --> 00:19:09,860 We need to decrypt the messages really from an early phase in the commissioning. 172 00:19:09,880 --> 00:19:11,660 We will need the key. 173 00:19:13,040 --> 00:19:27,260 Luckily for us, we are not the first to tackle this issue, and in this blog post, you can find all of the information for all of the keys used in touch link commissioning and in classic commissioning with the values of the keys themselves. 174 00:19:27,440 --> 00:19:34,340 So we took the keys, we inserted them to Wireshark, and Wireshark can now automatically decrypt the messages we sniff. 175 00:19:35,740 --> 00:19:43,100 The analysis and the implementation part took a lot of effort, a lot of work days, but eventually it worked. 176 00:19:43,560 --> 00:19:45,940 We managed to fake our own light bulb. 177 00:19:45,940 --> 00:19:51,100 You can see a brand new checkpoint research light bulb with the model CPR123. 178 00:19:51,100 --> 00:20:01,180 So now our board is doing all of the classic commissioning phase, faking our own light bulb, so we could continue on. 179 00:20:01,480 --> 00:20:10,360 In order to help other researchers with this task, we decided to open source the full pickup of the classic commissioning as we sent it from our board. 180 00:20:10,360 --> 00:20:20,000 So instead of other researchers having to manually analyze the commissioning phase, you can now look on the pickup, the decrypted pickup with all of the messages we've sent. 181 00:20:21,940 --> 00:20:32,120 The lessons we learned thus far are, without user interaction, the bridge won't accept new light bulbs, which is a good security precaution, but it doesn't help us. 182 00:20:32,120 --> 00:20:36,340 We will need somehow to bypass this limitation. 183 00:20:36,900 --> 00:20:42,500 In addition, we have approximately one minute to commission as many light bulbs as we want. 184 00:20:42,500 --> 00:20:44,860 There is no check about it. 185 00:20:45,180 --> 00:20:57,280 The user will only see the light bulbs in the app after they finished a specific phase we labeled ZCL phase, which is pretty much the last phase in the commissioning. 186 00:20:57,780 --> 00:21:05,840 If we fake other light bulbs and we stop before the ZCL phase, the user won't be aware of that, which is pretty good for our attack. 187 00:21:06,520 --> 00:21:13,680 And the really good news are, we managed to trigger the vulnerability during the ZCL phase, so we have a success. 188 00:21:13,680 --> 00:21:15,300 We really have a vulnerability. 189 00:21:16,600 --> 00:21:18,820 There is no state machine check in place. 190 00:21:18,820 --> 00:21:25,220 We can simply send whatever ZCL strings we want, whenever we want, without any request to get them. 191 00:21:25,220 --> 00:21:35,260 So we can pretty much do anything we want with the long ZCL strings, as long as we do it during the ZCL phase, and specifically during the commissioning. 192 00:21:35,260 --> 00:21:40,560 Once the light bulb was fully added to the network, it can no longer trigger the vulnerability. 193 00:21:40,580 --> 00:21:44,440 The vulnerability will only be accessible during the commissioning phase. 194 00:21:45,560 --> 00:21:47,700 Time to start the exploit. 195 00:21:52,430 --> 00:21:56,090 Just a basic recap on our vulnerability before we continue. 196 00:21:56,730 --> 00:22:00,310 We have a linear-based buffer overflow over the heap. 197 00:22:00,850 --> 00:22:04,110 Our buffer size is limited to 70 controllable bytes. 198 00:22:04,270 --> 00:22:12,470 And this is because we only started with 127 bytes, which is the MTU on ZigBee, and the ZCL is quite high on the ZigBee stack. 199 00:22:12,470 --> 00:22:14,790 So we lost a lot of bytes due to headers. 200 00:22:15,230 --> 00:22:18,450 We will have to settle down with the 70 bytes we have. 201 00:22:19,330 --> 00:22:22,490 We don't have any byte constraints on our payload, which is good. 202 00:22:22,490 --> 00:22:26,950 We can send null bytes, non-printable bytes, pretty much everything we want. 203 00:22:27,730 --> 00:22:34,270 And the destination buffer is allocated over the heap using a fixed size buffer of 43 bytes. 204 00:22:35,870 --> 00:22:37,570 Time to focus the heap. 205 00:22:38,450 --> 00:22:44,190 The bridge uses uclibc, which is an old embedded libc implementation used in embedded devices. 206 00:22:44,830 --> 00:22:51,110 The chosen heap implementation inside uclibc is the malloc standard, which is dlmalloc behind the scene. 207 00:22:52,210 --> 00:22:57,230 Effectively, it is much like glibc, but with way less sanity checks. 208 00:22:57,510 --> 00:23:01,670 And this is because uclibc stands for micro-libc. 209 00:23:01,670 --> 00:23:09,610 It is meant to be used by devices without a lot of RAM, without a lot of CPU power, so it has to be slim. 210 00:23:09,750 --> 00:23:14,150 And being slim means there's less code and less sanity checks. 211 00:23:15,750 --> 00:23:19,730 All of our free buffers will fall into the range of what is called fast bins. 212 00:23:20,330 --> 00:23:26,490 There's a bin for each buffer size in multiple of eight bytes, starting from 16 being the minimal size. 213 00:23:26,490 --> 00:23:39,790 So we have a bin for all of the buffers up to 16 bytes, a bin for 16 to 24, a bin for 24 to 32, and so on and so forth. 214 00:23:40,210 --> 00:23:44,670 Inside each bin, we will have a singly-linked list of all of the free buffers. 215 00:23:45,910 --> 00:23:51,850 When examining the code for free in uclibc, we saw the following check. 216 00:23:52,110 --> 00:24:01,830 If size is less than or equal to some configurable amount called max-fast, we will use the fast bins and store our buffer inside them. 217 00:24:01,830 --> 00:24:08,870 In order to find the respective fast bin for our buffer, we will use the fast bin index macro we can see over here. 218 00:24:09,450 --> 00:24:17,070 In short, the macro divides the size by eight and subtracts two, because 16 should be the minimal size. 219 00:24:17,070 --> 00:24:24,190 But there's no check in place that the size indeed is bigger or equal to 16. 220 00:24:24,190 --> 00:24:36,970 So if we will be able to corrupt a buffer over the heap and modify the size, we could change the size to be eight or even zero, giving us the indices of minus one and minus two, respectively. 221 00:24:37,450 --> 00:24:47,330 In order to understand what will happen if we will use negative indices, we can see the malloc state start over here and the variables before the fast bins array. 222 00:24:47,810 --> 00:24:55,970 So if we will use index minus one, we will store our buffer on top of the max-fast before the fast bin array. 223 00:24:56,410 --> 00:25:02,690 Storing a pointer over the configurable size for fast bins will be too risky. 224 00:25:02,690 --> 00:25:04,690 It will simply ruin the heap. 225 00:25:04,830 --> 00:25:07,950 But what will happen if we'll use index minus two? 226 00:25:08,030 --> 00:25:14,730 Well, index minus two will store the pointer to our buffer before the malloc state variable. 227 00:25:14,730 --> 00:25:22,390 And before the malloc state start in memory, it turns out to be an unused variable, simply nothing. 228 00:25:22,470 --> 00:25:31,630 So if we free a buffer with size of zero, it will be stored somewhere in memory before the malloc state, and no one will reach it. 229 00:25:31,770 --> 00:25:38,750 The next buffer will be joined to it, creating a ghost link list we can refer to as the dev null fast bin. 230 00:25:38,850 --> 00:25:43,710 Since malloc is not aware of this bin, it won't extract buffers from it. 231 00:25:43,710 --> 00:25:55,750 And all of the buffers we free will be joined to this bin, but won't be returned to the heap itself, effectively enabling us to gradually shape the heap in the desired structure. 232 00:25:57,510 --> 00:26:00,710 The plan for our heap overflow is quite simple. 233 00:26:00,730 --> 00:26:06,050 We can see our buffer in blue and a buffer adjacent to it in memory in purple. 234 00:26:07,190 --> 00:26:11,830 The plan is to modify only the size and the pointer of the adjacent buffer. 235 00:26:12,890 --> 00:26:29,650 If you change the size to one, which means a size of zero bytes and one for the previous buffer is in use, then the buffer will go to the dev null link list because size zero will reflect it to index minus two. 236 00:26:29,930 --> 00:26:34,450 And the pointer will be changed to be our arbitrary address. 237 00:26:35,210 --> 00:26:37,870 Effectively, we want to get this structure. 238 00:26:37,870 --> 00:26:50,630 We want to corrupt the singly linked list inside fastbin so that an arbitrary buffer will be stored, or at least malloc will think that an arbitrary buffer will be stored in our arbitrary address. 239 00:26:51,090 --> 00:27:04,250 The goal is we want to confuse malloc so it will allocate a buffer at an arbitrary address and then will let us write our data into this buffer, effectively giving us a write-what-where exploit primitive. 240 00:27:05,070 --> 00:27:08,270 The heap shaping strategy is as follows. 241 00:27:08,570 --> 00:27:12,930 If we overflow this free fastbin buffer buffer, then we won. 242 00:27:12,930 --> 00:27:14,610 This is exactly what we aim at. 243 00:27:14,610 --> 00:27:19,510 We corrupted the singly linked list inside the fastbin and we will get our allocation. 244 00:27:20,490 --> 00:27:28,230 If we overflow the use buffer, then when it will be freed, it will go to the dev null fastbin and we won't see it any longer. 245 00:27:29,570 --> 00:27:36,630 If we overflow the use buffer that lives forever, oh, well, nothing would happen and no one will notice it. 246 00:27:37,650 --> 00:27:41,790 But if we overflow the free large buffer, then we're in trouble. 247 00:27:41,790 --> 00:27:45,450 We will probably crash soon, so we really don't want to do that. 248 00:27:46,150 --> 00:27:50,010 If done correctly, we will get the desired malloc-where primitive. 249 00:27:51,330 --> 00:27:54,850 malloc-where will grant us the ability to write over the got. 250 00:27:54,850 --> 00:27:58,030 The got is the global offset table. 251 00:27:58,090 --> 00:28:09,170 It's a global table of function pointers used to execute library functions, such as free, malloc, sleep, memcpy, and pretty much every other library call. 252 00:28:09,270 --> 00:28:12,530 And luckily for us, the got is at a fixed address. 253 00:28:13,630 --> 00:28:22,750 The modified function pointer will jump to our shell code, or at least in theory, because it sounds easy on paper, but it's way harder in real life. 254 00:28:28,190 --> 00:28:30,400 Time to construct the shell code. 255 00:28:32,310 --> 00:28:34,730 Location, location, location. 256 00:28:35,230 --> 00:28:39,470 We need to store a binary shell code in a fixed global address. 257 00:28:40,050 --> 00:28:50,190 The problem is we only get textual messages from the ZigBee modem, so we don't get any controlled binary data into the main CPU. 258 00:28:50,770 --> 00:28:57,450 We found only one good candidate for such a possible buffer, and this is the ZigBee phone book. 259 00:28:57,990 --> 00:29:03,470 This is an array of ZigBee addresses seen by, or advertised to, the bridge. 260 00:29:04,430 --> 00:29:12,870 It can hold up to 65 records of 16 byte each, giving us an upper bound of approximately one kilobyte for the entire shell code. 261 00:29:13,550 --> 00:29:17,130 It's not a lot of bytes, but it should be enough for us. 262 00:29:18,350 --> 00:29:23,410 The neighbor record inside the ZigBee phone book is constructed as follows. 263 00:29:23,470 --> 00:29:28,830 The first eight bytes are for the extended network address, which we fully control. 264 00:29:28,910 --> 00:29:35,190 After that, we have additional two bytes for the short network address, again, fully controlled. 265 00:29:35,890 --> 00:29:47,870 And our stroke of luck ended, which is quite reasonable, sorry, because now we have six bytes for miscellaneous fields, and we don't really control them. 266 00:29:47,870 --> 00:29:53,010 So we have 10 consecutive bytes we control, but we don't control the entire memory. 267 00:29:54,970 --> 00:29:57,310 Oh, and about that. 268 00:29:57,310 --> 00:30:06,730 It turns out the bridge is unstable when it gets more than 20 records, so this is going to be quite a small shell code. 269 00:30:07,790 --> 00:30:11,370 The initial plan was simple. 270 00:30:11,610 --> 00:30:16,690 It looks infeasible to restore the execution flow, because we pretty much ruined the heap. 271 00:30:17,350 --> 00:30:23,870 Instead, our shell code will try to patch the binary on the file system and install a backdoor. 272 00:30:23,870 --> 00:30:33,390 After the process will crash, a daemon will reboot the binary with our backdoor, and then we will trigger it from another light bulb. 273 00:30:34,410 --> 00:30:44,510 Problem is, both the patch and the file path don't fit in 10 consecutive bytes each, so we can't decode them properly in the ZigBee phone book. 274 00:30:44,530 --> 00:30:48,990 The solution for this problem is purely academic. 275 00:30:49,890 --> 00:31:02,570 An ideal shell code by reduction will be, use the 10 consecutive bytes per record to build a decoder, and the decoder will decode the rest of the records to be nicely ordered in memory. 276 00:31:03,430 --> 00:31:12,730 In MIPS 16, a jump to the next record will only cost us two bytes, giving us eight spare bytes in each record to construct our decoder. 277 00:31:14,530 --> 00:31:17,110 But there are problems with this plan. 278 00:31:17,650 --> 00:31:26,650 We need to clear the instruction cache before jumping to the unpacked shell code, and because this is a MIPS CPU and we crashed when trying. 279 00:31:27,590 --> 00:31:35,550 And if we use sleep to clear the cache, as people usually do, the watchdog will kill the process because it doesn't respond. 280 00:31:36,430 --> 00:31:47,270 And we don't have enough records to silence the watchdog, sleep, and use a decoder, so the ideal shell code is good on paper, but it's not practical. 281 00:31:48,350 --> 00:31:51,390 Instead, we went for a more bold design. 282 00:31:52,120 --> 00:31:53,930 We will restore the execution flow. 283 00:31:53,930 --> 00:31:56,130 We really don't have any choice. 284 00:31:56,830 --> 00:32:10,270 This means we will call mprotect to modify the permissions of the code in memory from executable to be executable and writable, and we will install the backdoor in RAM during the execution. 285 00:32:12,390 --> 00:32:20,450 A few days and one hand-crafted shell code later on, we have a shell code that fully restores the execution. 286 00:32:20,450 --> 00:32:25,390 It restores the GOT, it restores the HEAP, and it restores pretty much everything we need. 287 00:32:26,250 --> 00:32:32,570 In addition, the shell code will only cost us 16 records, which is well in budget, less than 20. 288 00:32:33,810 --> 00:32:37,090 And here we can see the shell code in IDA. 289 00:32:37,490 --> 00:32:48,010 From the first record, we will jump to the second, and then we'll jump to the third, and so on and so forth until we install the backdoor and restore the execution flow. 290 00:32:49,630 --> 00:32:55,810 When we connect all of the dots together, the backdoor shell code will give us an arbitrary write primitive. 291 00:32:56,590 --> 00:33:06,510 Our exploit will fake an additional legitimate light bulb, but we'll leverage this arbitrary write primitive we installed and we'll use it to write Scout's loader to memory. 292 00:33:07,450 --> 00:33:13,450 Upon execution, Scout will load the full payload, which in this case, we've chosen to use EternalBlue. 293 00:33:14,590 --> 00:33:29,830 Here we can see that Scout dropped the file on tmp.exploit with root privileges, and this tmp.exploit file will use EternalBlue to attack computers inside a computer network, which is a good time for our demo. 294 00:33:39,100 --> 00:33:42,200 Here we can see the light bulb and the user using it. 295 00:33:42,560 --> 00:33:43,920 We can see that it works. 296 00:33:43,920 --> 00:33:45,380 The app works fine. 297 00:33:45,380 --> 00:33:49,000 And the user can modify the color of the light bulb as he wishes. 298 00:33:54,900 --> 00:34:00,440 When the attacker starts, he will try to hijack the light bulb and steal it from the network. 299 00:34:00,820 --> 00:34:11,160 And once he joined the attacker's network, the attacker will change the light bulb to a hideous color to annoy the user, so that the user will see that something is wrong with his light bulb. 300 00:34:12,680 --> 00:34:16,500 So we took over the light bulb and now it's ours. 301 00:34:17,180 --> 00:34:28,240 When the user sees that something is wrong, you can see that he no longer controls the light bulb, he can't change the light bulb's color, and it seems to be unreachable when it sees it over the app. 302 00:34:29,120 --> 00:34:35,200 The only way to reinstall the light bulb is to delete it and tell the bridge to search for new light bulbs. 303 00:34:35,200 --> 00:34:38,160 And this is where our attack will officially start. 304 00:34:38,880 --> 00:34:53,500 We will fake a legitimate light bulb, so the user will be happy, this is our light bulb, and we will fake it as the user actually configures the light bulb as he wishes, so the user won't see that something is wrong with our fake light bulb. 305 00:34:56,270 --> 00:34:59,030 Behind the scene, the full attack will take place. 306 00:35:02,640 --> 00:35:08,780 Here we can see that the bridge is connected to the laptop, so it's connected to the computer network. 307 00:35:09,440 --> 00:35:14,140 And now behind the scene, we will use our vulnerability, shape the heap and take over the bridge. 308 00:35:14,140 --> 00:35:20,300 And from the bridge, we will use EternalBlue to attack the computer inside the network and pop a cock. 309 00:35:20,440 --> 00:35:22,480 So our attack worked. 310 00:35:24,420 --> 00:35:26,920 Time for the coordinated disclosure. 311 00:35:27,700 --> 00:35:32,120 The vulnerability was reported to Signify on the 5th of November, 2019. 312 00:35:32,780 --> 00:35:36,660 The vendor confirmed the vulnerability on the same day, which is quite impressive. 313 00:35:36,660 --> 00:35:52,320 It's even more impressive because not only the vendor sent its acknowledgement on the same day when it received our report, it actually acknowledged the existence of the vulnerability, which it found in the code according to our report. 314 00:35:52,380 --> 00:35:58,000 So the vendor did pretty much everything in a single day, which is very impressive. 315 00:35:59,700 --> 00:36:03,520 Later on, Signify issued a patch via an automatic update in January. 316 00:36:04,260 --> 00:36:07,680 And you can find the full details and advisory in our blog post. 317 00:36:07,680 --> 00:36:14,940 And the official CVE issued for this specific vulnerability is CVE-2020-6007. 318 00:36:15,580 --> 00:36:21,140 And if you have Philips Hue lighting in your office or in your home, don't worry. 319 00:36:21,140 --> 00:36:24,380 All of the products should have received the update by now. 320 00:36:25,660 --> 00:36:26,860 Conclusion. 321 00:36:27,960 --> 00:36:35,180 Even with an MTU of 127 bytes, ZigBee vulnerabilities are indeed exploitable as we've shown in our demo. 322 00:36:36,580 --> 00:36:41,000 Security mitigations only work when they are on by default. 323 00:36:41,480 --> 00:36:45,740 The IP bridge binary was compiled to use static fixed addresses. 324 00:36:45,740 --> 00:36:52,160 So we were able to target the GOT which was on a fixed address, even without an information leak vulnerability. 325 00:36:52,860 --> 00:36:55,780 The binary was not compiled with any stacking areas. 326 00:36:55,780 --> 00:37:02,000 The GOT was writable, so we could do pretty much everything we want to do once we had an initial vulnerability. 327 00:37:02,620 --> 00:37:10,200 Still, there was ASLR in place for the heap, for the stack, and for the loaded libraries, and that's thanks to Linux. 328 00:37:10,200 --> 00:37:18,580 So if it's on by default, you will get it, but if you need to manually do something in your makefile, you won't get it in most common cases. 329 00:37:20,000 --> 00:37:26,200 And small devices are becoming popular by the minute, and yet we can't even trust our own light bulbs. 330 00:37:26,200 --> 00:37:28,780 So maybe we should do something about it. 331 00:37:30,060 --> 00:37:37,500 We can't finish this research and this presentation without saying special thanks to everyone that helped make this research possible. 332 00:37:37,500 --> 00:37:42,840 So we have Eyal Ronyan for the research idea and the active guidance. 333 00:37:43,580 --> 00:37:48,860 Colin O'Flynn for the detailed write-ups on routing the bridge and the entire hardware analysis of it. 334 00:37:49,640 --> 00:37:56,100 For Peter, for publishing the ZigBee transport keys for the light bulbs, which we used and couldn't continue without. 335 00:37:56,960 --> 00:38:01,440 And for Yaron Itkin, for the crucial hardware support along the way. 336 00:38:01,560 --> 00:38:02,980 Thanks, little brother. 337 00:38:03,540 --> 00:38:10,760 And last but not least, for the entire CPR research team and for their support alongside this very long research. 338 00:38:11,340 --> 00:38:14,460 Until the next time, thank you for joining this talk.