[00:00.000 --> 00:06.580] Hello, IoT Village, first and foremost. What it be, what it do. I'm Mark, and boy, [00:06.580 --> 00:12.440] have I got some zero days for you. Now, the reason why I call this talk Assembly Voluntron [00:12.440 --> 00:17.740] isn't just because I'm hacking a robot and it's a cool name, and incredibly clever, too. But also [00:17.740 --> 00:23.020] because there's four unique CVEs in this target, and when they work together, they kind of create [00:23.020 --> 00:27.940] something that's greater than the sum of its parts. Just like a mech you might have heard of. [00:29.300 --> 00:33.780] So, the next thing you might be wondering is, who are you, and why should we care what we have to [00:33.780 --> 00:40.060] say? Well, to start off, like I said, I'm Mark, to which there's really only one natural response. [00:41.680 --> 00:47.740] And you can find me on Twitter, at Ropsicle. And I'm currently a security researcher for [00:47.740 --> 00:52.200] McAfee's Advanced Threat Research Team, which I'll be referring to as ATR from now on, because [00:52.200 --> 00:57.020] it's kind of a mouthful. Now, my focus has been on finding zero-day vulnerabilities, [00:57.020 --> 01:01.540] particularly in embedded systems. So, this talk is really on-brand for me, so to speak. [01:02.140 --> 01:07.540] Now, as for previous experience, I spoke at last year's DEF CON and ICS Village, [01:07.540 --> 01:15.960] so I'm basically a celebrity. Now, for hobbies, I really only do two things. I hack and I squat. [01:18.000 --> 01:21.980] Now, depending on how nice you guys are to me in the Discord channel after, [01:21.980 --> 01:25.120] I might add streaming to that list. But for now, it's just those two. [01:25.920 --> 01:31.640] Okay, so let's move on to the target. Temmie or Teemee, or however you want to pronounce it. [01:32.040 --> 01:38.100] The fact is, it's actually a pretty cutting-edge piece of tech. So, the marketing describes it as [01:38.100 --> 01:43.940] the world's first truly intelligent, mobile, personal robot for your home. That's a lot of [01:43.940 --> 01:50.900] qualifiers. And as you can see here, it's actually a pretty small device. It's about four feet tall, [01:50.900 --> 01:56.360] and it's got kind of like an Android brain. That's like an Android tablet at the top with [01:56.360 --> 02:01.580] like a camera and a microphone and a fully functioning touchscreen. Now, this device [02:01.580 --> 02:06.320] was created by RoboTemmie Global LTD, and they're sort of like a startup company. This is their [02:06.320 --> 02:11.500] first venture into the consumer space. But they actually spun off of a parent company called [02:11.500 --> 02:17.940] RoboTeam, which did military robotics based out of Israel. Now, this thing isn't cheap. It's going [02:17.940 --> 02:22.600] to set you back about two grand, but you do get a lot of hardware for that price point. [02:22.700 --> 02:27.100] So, it has the ability to do remote teleconferencing, thanks to its camera and microphone. [02:27.520 --> 02:31.960] But more importantly, it also has autonomous movement and obstacle detection, thanks to the [02:31.960 --> 02:38.120] various sensors it features, and also the 360 LiDAR. And finally, as you'd expect, it has Alexa [02:38.120 --> 02:43.060] and smart device integration, being a smart IoT device. And you get all the standard things you'd [02:43.060 --> 02:47.460] expect from an Android tablet. Wi-Fi, Bluetooth, it even has a wireless charging pad on the back [02:47.460 --> 02:55.280] that doubles as a coaster, at least for us. So, although RoboTaming likes to advertise their [02:55.280 --> 03:00.480] robot as being, you know, sort of a consumer device, the reality is that it's actually seen [03:00.600 --> 03:05.620] a lot of use outside of that space. So, I think one of the biggest things we've seen recently is [03:05.620 --> 03:12.140] that it's used sort of as a mobile kiosk. So, in places like the Mall of America and the Nautilus [03:12.140 --> 03:19.040] Hotel, and even in certain corporate environments, like TransFighter corporate offices, you'll see [03:19.040 --> 03:23.700] that it serves as an informational kiosk that has the advantage of being able to show people around. [03:23.700 --> 03:27.700] So, instead of just telling people where to find, you know, like Jimmy John's in the mall, for example, [03:27.700 --> 03:33.800] it can actually navigate them there. But perhaps the most important and impactful application of [03:33.800 --> 03:39.480] this robot is in healthcare, especially given the recent pandemic. So, with doctors' visits becoming [03:39.480 --> 03:44.080] more and more, you know, the standards becoming more remote visits and remote, you know, [03:44.080 --> 03:48.420] teleconferencing for doctors' appointments, this has actually seen a lot of pickup in the healthcare [03:48.420 --> 03:53.180] space. So, already we're seeing it being used by places like Trillium Health Resources. [03:53.800 --> 03:58.820] In fact, it's also been picked up by Israel's Ministry of Defense as, like, the de facto [04:00.200 --> 04:06.140] teleconferencing solution for the medical wards throughout Israel. And we also see a lot of [04:06.140 --> 04:11.080] applications in Southeast Asia, of all places, with places like China and South Korea, you know, [04:11.080 --> 04:15.260] ordering hundreds of these units for their nursing homes and medical institutions. [04:15.680 --> 04:20.660] And to accommodate this increased demand, RoboTemy has actually increased production of these units [04:20.660 --> 04:26.400] to about a thousand a month, I believe, just to meet this growing demand in the medical space. [04:27.400 --> 04:32.140] So, now that we know what Temy is, what it's capable of, and where it's being used, [04:32.140 --> 04:37.280] it's important for us to sort of draw a box about what the normal operations of it look like, [04:37.280 --> 04:43.100] so then we can have a lot of fun breaking that box. So, to start off, normal operation of the Temy [04:43.100 --> 04:48.680] is done through a use of its smartphone app, and this is both on Android and iOS. [04:48.840 --> 04:54.680] So, you can call the Temy from it, you remotely control it that way, that sort of thing. And the [04:54.680 --> 04:58.000] registration process for using this app is, basically, you just put in your phone number [04:58.000 --> 05:01.740] and it verifies it, and that's how it identifies you. So, if you reinstall the app [05:01.740 --> 05:07.040] and use the same phone number, it'll still find up your account details. [05:07.520 --> 05:12.820] Now, upon first booting up the robot, which already was a super fun experience unboxing this thing, [05:12.820 --> 05:18.520] but we are prompted to scan a QR code. And this, basically, just turns whatever user scans that QR [05:18.520 --> 05:25.360] code into the de facto admin of that Temy robot. And the admin is only one per Temy, [05:25.360 --> 05:28.200] and they have sort of the highest privileges for that robot. [05:29.160 --> 05:32.860] Now, it doesn't mean that other people can't call your robot or even use it. [05:32.860 --> 05:38.740] Phone contacts that use the Temy app, so phone contacts in, like, your smartphone, [05:38.740 --> 05:42.100] if they have the Temy app installed, they're synced automatically. And this can be done [05:42.100 --> 05:46.280] one of two ways. If the admin has phone contacts that have the Temy app, [05:46.280 --> 05:49.880] they'll be synced automatically to the robot, and the robot will be aware of them. [05:50.400 --> 05:53.960] Alternatively, if you're just a regular user of the phone app, you don't own a Temy, [05:53.960 --> 05:57.640] but you have a friend that does, for example, and they're in your phone contacts list, [05:57.640 --> 06:01.260] you'll be able to call your friend's Temy robot from the app. [06:01.640 --> 06:06.600] And we can sort of show you how that works. So once you boot up the app, if it finds a contact [06:06.600 --> 06:13.280] that owns a Temy, they'll show up down here on the left under your contacts list. So here, [06:13.280 --> 06:18.440] we have a lab phone as one of the contacts that owns a Temy. And by selecting this contact, [06:18.440 --> 06:22.180] you can see the Temy robot associated with it, and even has a button that lets you just call [06:22.180 --> 06:28.020] it straight from the screen. And then once a call is actually initiated, this is sort of the [06:28.020 --> 06:33.580] interface you're presented with. You can drive the robot around, control your audio options, [06:33.580 --> 06:42.460] pretty standard stuff. Now, calling is very much so the primo functionality of this robot. And [06:42.460 --> 06:47.180] really, callers get a lot of control over the device during the call. They get audio and video [06:47.180 --> 06:51.480] feeds from the Temy, but they also have control of its movement, which they can control manually [06:51.480 --> 06:56.380] using the little D-pad you saw, but also has access to all of its saved locations. [06:57.300 --> 07:01.600] So this immediately became a very interesting potential attack vector to us. [07:01.600 --> 07:07.800] Now, the Temy does ring when someone besides its admin calls it. So in that sense, if you just [07:07.800 --> 07:12.740] added someone's phone number that they don't know you, it turns into basically just [07:12.740 --> 07:18.540] trying to cold call a cell phone. There is one exception to this, and the admins can actually [07:18.540 --> 07:24.160] grant certain users in their contacts list special privileges to bypass this limitation. [07:24.380 --> 07:28.060] So if you have like a family that all uses the same robot, and you can't be bothered with having [07:28.060 --> 07:32.980] to pick up on the other end each time, an admin can grant several other users the ability to call [07:32.980 --> 07:38.000] in without having it ring. And this is also done through the phone app. You can just invite new [07:38.000 --> 07:42.300] members and then select whatever contacts you want to be able to control the robot, [07:42.300 --> 07:48.460] whatever they want. So now that we have a good grasp of what the normal operation of this device [07:48.460 --> 07:53.840] looks like, we can sort of get into the spirit of trying to hack this thing now. Now, although [07:53.840 --> 07:58.960] this tech is pretty novel and cutting edge in a lot of ways, the approach we took to ReconnaSense [07:58.960 --> 08:04.840] was fairly standard and typical. So we started with trying to get a local shell on the device. [08:04.840 --> 08:10.660] This was actually super easy and short-circuited by the fact that the device comes with developer [08:10.660 --> 08:16.980] options, which include ADB, or Android Debug Bridge, which allows you to remotely connect to [08:16.980 --> 08:21.660] it like you would an SSH session. So that already made our lives a lot easier for moving files [08:21.660 --> 08:26.700] around and accessing the device at startup. The next thing we tried to do was actually capture [08:26.700 --> 08:34.460] traffic on the device using Wireshark. And during stuff like boot up and during phone calls, [08:34.460 --> 08:39.860] we saw three IPs being hit pretty frequently. One of these mapped to a Yahoo URL. So this is [08:39.860 --> 08:45.680] probably being used for its news app. And then two more mapped to Amazon AWS instances, which while [08:45.680 --> 08:53.100] not surprising, don't really reveal much either. The next thing we did was used our ADB shell to [08:53.100 --> 08:59.920] actually run... sorry, not ADB, that's a little later. We ran an Nmap port scan on the device [08:59.920 --> 09:04.180] to see what the ports it was listening on. Another standard thing you'd do for attack vectors. [09:04.260 --> 09:10.900] And the only port it identified as being open was the port 4443, which Nmap classified as [09:10.900 --> 09:15.280] being used for the service Feros, which is actually related to printing. So this is probably [09:15.420 --> 09:20.060] a false classification. It's more likely that this port is being used as an alternative to the [09:20.060 --> 09:29.120] standard 443 you'd see used for HTTPS. Now, to verify that, we actually used the ADB shell we [09:29.120 --> 09:34.680] had to the device to run Netstat, and actually found that the service associated with this port [09:34.680 --> 09:41.680] is something called com-roboteam-teamy-usa, which looks a lot more like an Android application than [09:41.680 --> 09:46.960] it does, you know, a standard Linux binary. And sure enough, that was the case. By parsing the list [09:46.960 --> 09:52.820] of installed packages on the device, we actually found the APK associated with this Android [09:52.820 --> 09:59.400] application. And using our ADB shell, it was trivial to pull this APK off and start [09:59.400 --> 10:05.780] examining the software. So now that we had access to the software, and we also had access to the [10:05.780 --> 10:10.180] phone app software at this stage as well, because we could just download the APK from the Play Store. [10:10.180 --> 10:15.960] It's completely free, and you don't even need to own a Temi to run it. So we could, you know, start looking [10:15.960 --> 10:20.860] at both of those at the same time. Now, the rest of this is really going to be, like, 80% [10:20.860 --> 10:26.760] reversing and static analysis. That's just sort of the nature of this project. Now, why, you might [10:26.760 --> 10:34.000] ask, why? Well, a great man once said, the road to exploitation is paved with months of staring [10:34.360 --> 10:43.060] a decompiled Java code. That man's name? Albert Einstein. So who am I to argue with that? [10:45.510 --> 10:54.290] Now, once we actually got to decompiling the code, we decided to use a program called JADX. [10:54.310 --> 10:59.550] And JADX was sort of a favorite of ours because it has a functionality of being able to right [10:59.550 --> 11:05.350] click on any symbol and click on it to find usage, which became really important later on. [11:06.630 --> 11:11.290] From there, we had to pick a vector. Now, I don't know how many of you have actually [11:11.290 --> 11:15.630] looked at reversing in a full Android app, but they have massive code bases frequently, [11:15.630 --> 11:19.830] and Temi was no exception. Instead of groping in the dark, we decided that we needed to sort of [11:19.830 --> 11:26.510] hone in on a specific subset of the code to refine our search. In our case, we were already interested [11:26.510 --> 11:30.250] in the calling functionality of the robot, since that would grant us the greatest level of control [11:30.250 --> 11:37.630] entirely remotely. So we began digging through the different libraries that are part of the APK. [11:37.970 --> 11:42.510] After Googling around a bit, the one that jumped out at us particularly was something called Lib [11:42.510 --> 11:49.030] Agora. And this is actually a binary related to the Agora video SDK, which is a third party library [11:49.030 --> 11:53.870] used specifically for video calling functionality. Okay, that's perfect. That's exactly what we're [11:53.870 --> 11:59.710] interested in. So from there, we needed to find an entry point related to the attack vector. [11:59.710 --> 12:03.930] And you can sort of imagine this as being like a strand on like a wool sweater, [12:03.930 --> 12:07.890] the thing you start pulling on to really unravel the whole thing. [12:08.790 --> 12:14.390] So we began by actually pulling up this library in IDA and looking at its exports, and immediately [12:14.390 --> 12:19.490] the function native join channel jumped out at us. It looked like something related to joining a [12:19.490 --> 12:26.290] chat room, for example. Opening up the APK now, we saw the same function with the same signature [12:26.290 --> 12:32.890] appear in the decompiled app. So that was a good sign. So from there, we could use JADX's [12:32.890 --> 12:38.850] find usage feature like about 600 times to sort of begin tracing the code path taken for [12:39.470 --> 12:46.730] starting video calls. Now, at this stage, there really is no more advice or cool shortcuts. [12:46.730 --> 12:51.230] It really is, you just have to draw the rest of the L. You really have to just put in the [12:51.230 --> 12:56.130] legwork to trace the different function calls that are being made in order to get a better [12:56.130 --> 13:01.130] understanding of how the code works. But the fruits of our labor in this case was actually [13:01.130 --> 13:05.590] pretty impressive. It's sort of like staring at the sun, so I'll only show it briefly. [13:08.560 --> 13:16.980] Did you catch that? All right. Let's take a closer look at it. So highlighted in the [13:16.980 --> 13:22.460] different colors near the top are the different entry points for the calling code. So there's [13:22.460 --> 13:26.060] four ways to initiate a call from the phone app, and that correlates to these four. [13:26.060 --> 13:32.300] You can call a phone contact, you can call a robot contact, you can call either contact from [13:32.300 --> 13:37.600] the recent calls list, and if you happen to be a Temi admin, you can also call your specific robot. [13:38.240 --> 13:44.600] Moreover, we decided to segregate these based on the code flow that's either for outgoing calls [13:44.600 --> 13:50.120] indicated in red or incoming calls indicated in blue. And I'm not going to go through this too [13:50.120 --> 13:55.040] deeply because it's sort of massive, but this did serve as a good reference point for a lot of the [13:55.040 --> 14:01.020] reversing we had to do later. Okay. So we have four vulnerabilities to get through, so let's just [14:01.020 --> 14:05.860] jump right into it. The very first one, both chronologically and in terms of complexity, [14:05.860 --> 14:13.180] is the CVE ending in 70. And we can see here that it's categorized as being a use of hard-coded [14:13.180 --> 14:21.560] credentials. And it's present in the Temi Android app. Now, to have a better understanding of what [14:21.560 --> 14:26.200] this vulnerability entails, let's go through the process we used to actually discover it. [14:26.780 --> 14:34.040] So this really consisted of four easy steps. R, T, F, and M. And I do mean that pretty literally. [14:34.080 --> 14:40.400] Just by looking through the Agora documentation for their video calling API, we were able to get [14:40.400 --> 14:47.220] 80% of the way to finding this vulnerability. So specifically, we decided to take a second [14:47.220 --> 14:52.300] look at that join channel function we saw earlier. According to the Agora documentation, it has two [14:52.300 --> 14:58.400] required parameters and two optional ones. And this is really all that's needed to join an existing [14:58.400 --> 15:04.900] video call. Now, the first one is something called a token. And it seems that a token, if the user [15:04.900 --> 15:10.500] uses a static app ID, the token is also optional and can be set as null. This was interesting to [15:10.500 --> 15:17.100] us. And the second required parameter for joining a channel is a channel name. This is something [15:17.100 --> 15:22.380] we'll touch on a bit later. For now, we were interested in the static app ID and whether the [15:22.380 --> 15:28.080] Temi was using a token at all. Taking a look at the same function in the code, we found that it is [15:28.080 --> 15:33.660] indeed setting that token parameter to null, which means that it's likely using a static app ID as [15:33.660 --> 15:39.720] indicated in the documentation. Okay, so then we decided to start looking for this static [15:39.720 --> 15:45.000] app ID. Where could it be found? Referring back to the Agora documentation, we found the one function [15:45.000 --> 15:51.740] or the one API call that actually uses it as a parameter. And that's the rtcengine.create function. [15:52.320 --> 15:57.640] And it uses it as a parameter and it describes it as being an app ID issued by Agora to the [15:57.640 --> 16:02.040] developers, which is sort of vague. But after some more digging, we sort of discovered that this is [16:02.040 --> 16:07.280] used as a sort of namespace that segregates different users or different implementations [16:08.000 --> 16:16.100] on the Agora remote servers. So what it means is that you have a set static app ID that's shared [16:16.100 --> 16:22.800] amongst all Temi robots and Temi phone app users. And the app ID ensures that users of that service [16:22.800 --> 16:31.140] can only call other Temi users. They can't call an arbitrary Agora client. So this is actually a [16:31.140 --> 16:36.040] pretty important credential to have access to. Well, since we knew the function that takes it [16:36.040 --> 16:39.880] argument, we decided to look for this function in the Temi's decompiled code. [16:40.320 --> 16:44.640] And sure enough, there was the app ID hard-coded directly into the app that's [16:44.640 --> 16:49.660] freely accessible at the Play Store and fairly trivial to decompile. [16:50.320 --> 16:55.440] So this was already a good start. But really, to exploit this as a vulnerability, [16:55.440 --> 17:01.040] we needed not only the app ID, but also the channel name. So we could actually join an [17:01.040 --> 17:08.880] potentially. So if we still needed the channel name, how could we get it? Well, by going through [17:08.880 --> 17:14.060] that nice little graph I showed earlier, we were able to trace down what function actually generates [17:14.060 --> 17:18.220] the channel name. And here it's being called a session ID. But they're really the same thing. [17:18.800 --> 17:24.220] And as you can see, this is doing something not too complicated. It's actually just generating [17:24.420 --> 17:30.400] a random six-digit value. Now, this is important because, you know, 900,000 possibilities may seem [17:30.400 --> 17:34.980] like a lot, but it's well within the range of brute-forceable attack vectors. [17:36.580 --> 17:42.080] So in theory, an attacker could use the hard-coded app ID they extracted from downloading the app, [17:42.080 --> 17:47.320] which is shared amongst all Temmie installs. And then they could just use a brute-force method [17:47.320 --> 17:53.280] to try and guess every single possible channel name. And by doing so, they could potentially [17:53.280 --> 17:58.880] intercept every ongoing Temmie call used by any Temmie install. [17:59.540 --> 18:03.560] Now, obviously, we couldn't test such a brute-force attack vector against a live production [18:03.560 --> 18:10.000] server. But what we could do is we could create a custom Agora app to join a Temmie call just [18:10.560 --> 18:18.020] launched locally. And we did this by logging the channel name using ADB. And sure enough, [18:18.020 --> 18:25.680] using this custom app, we were able to join the existing call and essentially spy on the other two [18:26.460 --> 18:32.320] call members. So thereby proving this is a legitimate attack vector. [18:33.320 --> 18:37.940] So the next vulnerability I'm going to discuss is sort of a helper vulnerability. [18:38.020 --> 18:45.500] It is classified as an origin validation error, and it is also present in the Temmie Android app. [18:47.860 --> 18:57.040] Now, the reason why we call this a helper vulnerability is that it actually is related to [18:57.040 --> 19:04.620] the fact that you can modify the Temmie app and it still has full access to all the remote services [19:04.620 --> 19:08.980] it uses. It doesn't perform any kind of tamper checking to make sure that it's not running on [19:09.080 --> 19:14.740] a rooted device, that the code for the app hasn't been modified in any way. It just isn't aware of [19:14.740 --> 19:20.460] that. And the reason we were motivated to even pursue this as an attack vector is that it's much [19:20.460 --> 19:25.860] easier to modify an existing code than to start from scratch, but more importantly, the Temmie [19:25.860 --> 19:31.500] Android app already has access to all those remote services, which requires some degree of authentication. [19:31.500 --> 19:35.800] Instead of trying to extract the keys it's using and whatever other authentication mechanisms [19:35.800 --> 19:41.220] from the app and trying to make it our own, we just leverage the existing app and inject our [19:41.220 --> 19:49.420] code into it. So the way we'd accomplish this is by first unpacking the APK, which we can do using [19:49.420 --> 19:57.200] APK tool. Next, we would search for the particular piece of code that we want to modify. This could [19:57.200 --> 20:01.940] be either through the decompiled code or through the various resource files included with the APK. [20:02.100 --> 20:06.800] As a proof of concept, we decided to try and change the text for the call button, [20:07.220 --> 20:12.840] which we found through some grepping. Okay, so now that we knew which part of the APK we wanted [20:12.840 --> 20:17.440] to change, the next thing was to simply make that modification. And that was as simple as pulling [20:17.440 --> 20:22.240] it up in a text editor and replacing the string with what we wanted. In this case, we decided to [20:22.240 --> 20:28.940] rename it Pwn, give it a little more spice. And the last but not least, we had to repack but also [20:28.940 --> 20:35.000] re-sign the app. And the reason why we need to re-sign it is Android does not allow apps that [20:35.000 --> 20:40.860] are not signed to be installed on the device. And by modifying the existing app's contents, [20:40.860 --> 20:45.200] we invalidated the existing signature. But no worries, since the signature is not being checked [20:45.200 --> 20:50.440] by the device, there's no reason why we can't just create our own signature and use that. [20:51.240 --> 20:57.000] So the repacking process is once again done using APK tool. And then we create a signature [20:57.000 --> 21:01.780] using a combination of key tool and jar signer, as shown here. [21:03.140 --> 21:08.340] And the end result was that we were able to successfully change the string on this call [21:08.340 --> 21:13.240] button. And perhaps more importantly, modifying the app in this way proved not to impact this [21:13.240 --> 21:18.960] functionality in the least, meaning that we could potentially make non-trivial changes and still be [21:18.960 --> 21:24.900] able to perform things like calling. Now, exploitation of this vulnerability is a little [21:24.900 --> 21:30.000] tricky without spoiling the rest of the presentation, because really its main application [21:30.000 --> 21:34.720] is used to help exploit the next two vulnerabilities. So we'll save the discussion for that. [21:35.240 --> 21:44.460] No spoilers. Okay. Vulnerability numero trace. So this one is actually missing authentication [21:44.460 --> 21:48.960] for a critical function. A little more serious than the last two. And this is actually present [21:48.960 --> 21:54.380] in Temi's MQTT broker, which if you don't know what MQTT is, I'm going to give you guys a real [21:54.380 --> 22:01.020] quick crash course on it, just so we're all on the same page. So MQTT is a publish-subscribe [22:01.020 --> 22:06.200] messaging protocol that's specifically designed for IoT and other lightweight devices. So it's [22:06.200 --> 22:11.840] not too surprising to see Temi using it. Now, the way it works is that clients will publish [22:11.840 --> 22:17.820] messages to certain topics, and then subscribers to those topics then receive the messages. [22:17.860 --> 22:21.680] You can think of it as sort of being like subscribing to a YouTube channel, [22:21.680 --> 22:26.100] and then receiving notifications whenever your favorite YouTubers upload, for example. [22:27.780 --> 22:32.060] And then the topics themselves are strings that are organized into a hierarchy, and the hierarchy [22:32.060 --> 22:37.020] itself is delineated much in the same way that a Unix file system is. So just forward slashes. [22:38.320 --> 22:44.000] Now, in terms of the Temi, it uses MQTT for basically all communication between itself, [22:44.000 --> 22:49.080] the phone app, and the various cloud services. So you see it being used for things like video [22:49.080 --> 22:54.120] call invitations, syncing contacts from the admin, and even, most importantly, [22:54.120 --> 22:57.620] privilege management, which is something we'll delve into in the next vulnerability. [23:01.000 --> 23:04.640] So let's get into the discovery and exploitation of this vulnerability. [23:05.100 --> 23:09.660] How are we using MQTT, and what authentication is not being implemented? [23:10.420 --> 23:14.960] Well, we started by looking at the code that was used by the app to subscribe to its call [23:14.960 --> 23:19.660] invite topic. After all, we are interested first and foremost in the calling functionality. [23:20.180 --> 23:26.320] This is just the topic that either a phone app or a robot will listen on when it receives phone [23:26.320 --> 23:31.740] calls, and then the person creating a call for that user will publish a message to that same topic. [23:32.920 --> 23:39.220] So in our case, it takes the form... you can see it being invoked here on line 408. That's [23:39.220 --> 23:44.660] the actual function that is used to subscribe to that topic. And the topic string itself takes [23:44.660 --> 23:50.660] the form client something followed by invite. And that something in the middle is a client ID, [23:50.660 --> 23:57.320] or an MQTT client ID, rather. And an MQTT client ID is just a unique identifier for a specific [23:57.320 --> 24:03.020] client that's connected to the same MQTT broker. It's a way to identify different users. [24:03.900 --> 24:09.580] So this actually gave us an idea. Could we subscribe to someone else's call invite topic [24:09.580 --> 24:17.660] if we're able to modify the app? Well, in order to do that, we would need to know their client ID. [24:18.260 --> 24:24.920] So we would need to somehow get this information. But how are these client IDs even assigned? [24:25.920 --> 24:30.360] Well, looking back at how recent calls are initiated actually gave us a clue. [24:32.040 --> 24:36.280] So if you try to initiate a call from the recent calls list, [24:36.280 --> 24:41.320] this is the call code that gets executed. It invokes a function called telepresence [24:41.320 --> 24:45.480] service dot initiate call. And the first parameter is actually an identifier for the [24:46.200 --> 24:51.740] contact you're trying to initiate a call with. In this case, it gets that ID by invoking a function [24:51.740 --> 24:57.540] called get MD5 phone number. At this point, we were thinking, is it possible that the client ID is [24:57.540 --> 25:04.560] just an MD5 hash of the phone number the user used to register? We decided to verify this theory. [25:05.440 --> 25:10.920] So we did this simply by taking the Google voice number we used for our Temi admin, [25:10.920 --> 25:16.460] computing the MD5 hash, and then searching for that exact hash in all the various Temi files [25:16.460 --> 25:20.520] we had. And sure enough, we got a hit in one of the logs we recorded during a call. [25:20.520 --> 25:25.200] And it classifies it right there as client ID. Seems pretty straightforward to me. [25:27.080 --> 25:32.600] Now, at this stage, we decided to modify the app, taking advantage of the previous vulnerability [25:32.600 --> 25:38.740] we outlined. And using this technique, we were able to successfully subscribe to another user's [25:38.740 --> 25:43.060] call invite topic instead of our own, which basically meant that every single time they [25:43.060 --> 25:47.840] received a call, we would get that same call. And the only thing we needed to make this happen [25:47.840 --> 25:53.200] is the victim's phone number, which telemarketers will constantly remind us is not a high bar. [25:54.800 --> 25:59.920] Okay. So getting to the last and easily the most impactful vulnerability. [26:00.780 --> 26:05.420] This one is an authentication bypass using an alternate path or channel. [26:05.420 --> 26:09.840] And this is present in the Temi's REST API, which is something we'll cover as well. [26:11.380 --> 26:16.540] Now, in order to understand the authentication bypass, we first need to understand the authentication. [26:16.700 --> 26:19.820] And this is related to Temi's privilege management system, [26:19.820 --> 26:24.140] which is something I've already sort of touched on with the admin versus regular contacts thing. [26:26.380 --> 26:31.400] So we already know about admins. That's just the person that first registers with the QR code. [26:31.480 --> 26:34.900] But there's also two other types of privilege levels. [26:35.900 --> 26:40.040] Another one is contacts, which are just the default [26:40.040 --> 26:45.380] permissions given to a user. It's also the lowest level. [26:45.380 --> 26:51.180] Now, there are two ways to become a contact. The first is simply by cold calling the Temi. [26:51.180 --> 26:56.380] And the other is through the Temi admin syncing contacts to the robot. [26:56.620 --> 27:02.600] We'll be focusing on this latter use case. So the Temi robot actually listens on the [27:02.600 --> 27:07.580] topic sync contacts and then followed by its MQTT client ID or its robot ID. [27:07.580 --> 27:13.820] They're the same thing. For requests from the admin to sync contacts, as we can see here. [27:14.780 --> 27:18.800] Now, the requests themselves have the following structure. [27:18.800 --> 27:23.060] They're called... it uses an object of type sync contacts message. [27:23.060 --> 27:29.480] And all this contains is a list of contacts and the client ID of the person sending the request. [27:29.680 --> 27:37.080] And then the contact list is just a tuples of MQTT client IDs and the display names. [27:37.220 --> 27:42.440] Pretty straightforward. And the reason why the sender client ID is included is because the Temi [27:43.460 --> 27:48.780] locally ensures that the sender is equivalent to the ID of its admin. [27:48.800 --> 27:53.360] Just as a sanity check. Okay. So that's contacts. [27:53.360 --> 27:57.640] The third privilege level that's possible is something called an owner. [27:58.700 --> 28:03.060] And owners are actually related to that functionality I showed earlier where you can [28:03.760 --> 28:11.500] add certain users as an admin and let them call into the Temi remotely without having it ring. [28:12.740 --> 28:20.000] So, a Temi admin can send... now, sorry, let me back up a bit here. [28:20.140 --> 28:26.340] This is actually a little bit different from adding contacts because while adding a contact [28:26.340 --> 28:32.200] is pretty straightforward, adding owners is a little more complex because the request sent [28:32.200 --> 28:37.860] by the admin from the phone app is actually quite a bit different than what the Temi expects on the [28:37.860 --> 28:46.400] receiving end. So, the admin sends its request to a REST API at the following URL as we can see here. [28:47.800 --> 28:50.700] And the requests themselves have the following structure. [28:51.540 --> 28:57.140] They contain an inner request and also a signature that's basically generated using [28:57.140 --> 29:02.120] the client's private key. It's a way to identify who the origin is. [29:02.680 --> 29:06.640] And then the inner request consists of the list of the users... [29:09.900 --> 29:16.780] the list of users that we want to promote to owners, the ID of the robot that we're sending [29:16.780 --> 29:22.180] the request for, the source of the request, a timestamp, and then finally a type [29:24.560 --> 29:28.000] which is simply adding an owner or removing. [29:32.580 --> 29:36.540] Now, how is this different from what the Temi expects to receive on the other end? [29:36.540 --> 29:41.480] Well, it's quite a bit different. First of all, the Temi is listening on an entirely different channel. [29:41.880 --> 29:48.040] While the admin is sending its request to a REST API, the Temi robot is listening on an MQTT topic. [29:49.460 --> 29:56.000] This one specifically. And also the structure of the request has also changed. [29:56.280 --> 30:01.660] It seems to be a subset of the request that the admin is sending where it still has the list of [30:01.660 --> 30:07.320] owner IDs and the type, but has been stripped of its signature, its timestamp, and its source. [30:08.100 --> 30:12.540] Now, at this point, we speculated that the reason for this is because the REST API itself [30:12.540 --> 30:20.180] is being used as an authentication mechanism for adding owners. This is sort of a sensitive [30:20.180 --> 30:26.300] privilege escalation type of deal. And so what the REST API would do is it verifies the [30:26.980 --> 30:32.700] request by checking the signature, and then it strips out all that verified information before [30:32.700 --> 30:37.580] sending it off to the Temi's MQTT topic, essentially serving as like a middleman. [30:39.240 --> 30:44.140] So that means that our flowchart sort of looks like this. And presumably, if the [30:45.220 --> 30:49.020] verification server deems the signature invalid, nothing happens. [30:49.900 --> 30:56.660] Okay, so these privilege levels mostly have utility in how calling works. So when a Temi [30:56.660 --> 31:03.420] receives a call from a user, if that caller is either an admin or an owner, [31:03.420 --> 31:09.560] the Temi will pick up the call automatically. On the other hand, if the caller is a contact, [31:09.560 --> 31:14.800] it'll ring. So unfortunately, as an attacker, if we just tried to cold call a Temi, [31:14.800 --> 31:17.400] we would become a contact, and the Temi would ring. [31:19.020 --> 31:24.100] What do we want? Well, we want to be able to call the Temi and have it pick up automatically. [31:24.600 --> 31:28.800] This is because calling is sort of the endgame. You know, you get full control of the [31:29.500 --> 31:32.580] Temi's movement and also audio and video feeds to it. [31:34.560 --> 31:39.040] So what do we already know and what do we already have that can help us get there? [31:39.500 --> 31:43.800] Well, we do know that the Temi uses MQTT for calling and privilege management. [31:44.380 --> 31:48.820] And we know that we can subscribe to arbitrary topics, like we showed when we subscribed to [31:48.820 --> 31:55.520] someone else's call-invite topic. So our next question was, can we also publish to arbitrary [31:55.520 --> 32:01.700] topics? Because if we could, we may be able to escalate our privilege by publishing the [32:01.700 --> 32:06.500] owner's message that the Temi expects to get from the authentication server directly, [32:06.500 --> 32:11.600] and just publish it right to that MQTT topic it's listening on, thereby bypassing that [32:11.600 --> 32:17.420] authentication middleman entirely. Well, this all sounds well and good, [32:17.420 --> 32:24.900] but there was a slight caveat here. And that was, the Temi will only process privilege escalation [32:24.900 --> 32:29.920] requests for existing contacts. Now, why is this a problem? Well, there's only two ways to become [32:30.060 --> 32:35.080] a contact, one of which is the cold call to Temi, which is far from ideal because that might arouse [32:35.080 --> 32:40.640] suspicion for various reasons, if you have some stranger calling your robot. And then the other [32:40.640 --> 32:45.260] way is to have an admin send the sync's contacts message with you on it. Those are really the only [32:45.260 --> 32:51.040] two ways. Well, the solution is actually trying... is that's the latter. What we can do is we can [32:51.040 --> 32:56.640] actually spoof the admin's sync contacts message by simply setting the sender client ID to the [32:56.640 --> 33:03.080] admin's client ID, since the Temi just implicitly trusts that this value is accurate. In this way, [33:03.080 --> 33:08.300] we can send a sync contacts message first, followed by an add owner's message, and then finally [33:08.300 --> 33:15.220] initiate the call of the robot. So, this is sort of what the same functionality looks like [33:15.220 --> 33:20.680] after we've modified the app in the following ways. We can see already that it's a lot simpler. [33:22.540 --> 33:28.040] And in order to become a contact, we just send a malformed request. In order to escalate to [33:28.040 --> 33:33.900] becoming an owner, we just send another malformed MQTT request. And then finally, unlike before, [33:33.900 --> 33:39.580] now that we have owner privileges, the Temi will pick up the call automatically. [33:45.040 --> 33:50.860] Now, just as a quick recap of what these vulnerabilities can do together, [33:50.860 --> 33:56.180] it's sort of a recipe for disaster. And the recipe includes these following steps. [33:56.240 --> 34:01.020] First, you find a vulnerability in the Temi. And then you just find three more. [34:01.600 --> 34:07.040] And here's a completely unrelated graphic of a bucket with holes. I just like buckets. [34:08.340 --> 34:13.620] The ingredients for this recipe involved just the user's phone number and honestly not much else. [34:14.280 --> 34:20.380] And what this produces is the ability to spy on calls, the ability to intercept calls intended [34:20.380 --> 34:25.320] for other users, and most importantly, the ability to remotely control the robot and [34:25.860 --> 34:33.700] see through its eyes and hear through its ears. Now, I've been teasing you guys enough. So, [34:33.700 --> 34:38.120] at this point, I think it's a good time to show you guys a demo of how this all works. [34:53.530 --> 35:01.670] So, Shane or Sam, if you guys could queue up the video. Hopefully. [35:03.690 --> 35:05.130] Demo is playing. [35:05.170 --> 35:11.750] Okay. So, on the left, we have the Temi admin. And on the right, we have the attacker's phone. [35:12.050 --> 35:15.670] And we can see that I've already added the admin as a phone contact, [35:15.670 --> 35:20.190] thereby syncing it to the Temi's contact list. And the first thing I'm going to do is I'm going [35:20.190 --> 35:28.770] install the Temi app. Normally, unmodified, just straight from the Play Store, just to show that [35:28.770 --> 35:33.390] there's no smoke and mirrors involved. We'll later be using the modified app with the exact [35:33.390 --> 35:36.930] same credentials and going through the same registration process to show you that it [35:36.930 --> 35:40.130] really is the vulnerabilities that gives us the greater privileges. [35:44.010 --> 35:47.570] So, once we're done registering it, we're just going to attempt to cold call the Temi. [35:49.330 --> 35:52.610] And you can see the Temi screen in the bottom center there. [35:54.930 --> 35:59.130] Now, as expected, the Temi rings. It does not pick up automatically. This is because [35:59.130 --> 36:03.910] we only have contact privileges at this stage. The admin hasn't granted us any special rights. [36:11.200 --> 36:15.820] Okay. Now that we know what the normal operation looks like, let's go ahead and install our custom [36:16.260 --> 36:18.700] modified app that leverages these vulnerabilities. [36:25.000 --> 36:29.000] And right off the bat, you'll see this actually looks very similar to the original app. [36:29.080 --> 36:33.420] We only modified what we needed to do. It's not until we initiate a call that we'll see [36:33.420 --> 36:38.320] how different it is. So, as I stated previously, we'll be using the exact same credentials to [36:38.320 --> 36:42.100] register. And, in theory, we should have the same privileges. [36:49.220 --> 36:52.440] All right. Now the registration is done, we'll try initiating the call again. [36:52.640 --> 36:56.480] Except this time, it says Pwn instead of Call, so you know it's going to work. [37:03.560 --> 37:06.880] This time, the Temi picks up the call automatically, [37:06.880 --> 37:12.300] and the attacker now has full access to the Temi's movement, its camera, and its microphone. [37:12.580 --> 37:16.700] Now, the first thing an attacker might do is actually mute the microphone, their microphone, [37:16.700 --> 37:21.560] I mean, and turn off their camera, thereby essentially remaining anonymous as they do this. [37:22.000 --> 37:26.900] And you can start driving around whatever location it's in, looking around at whiteboards [37:26.900 --> 37:32.420] and other sensitive information. And you can also, you know, modify its volume to annoy people. [37:32.420 --> 37:36.180] But more importantly, you can actually navigate to its various save locations. [37:36.820 --> 37:40.820] So here we're going to navigate back to its home base, just so it doesn't run out of battery. [37:52.980 --> 37:56.480] So that attack vector leveraged that last vulnerability it described, [37:56.480 --> 38:01.380] which gives us owner privileges. Let's look at how we can exploit the [38:02.660 --> 38:05.620] previous vulnerability, which had to do with intercepting calls. [38:06.120 --> 38:11.240] So first, we'll begin by starting a call from the Temi for its admin. [38:11.900 --> 38:15.640] And as normal, you know, all's well with the world, [38:15.640 --> 38:19.720] the admin gets the call, but the attacker doesn't. This is expected behavior. [38:23.880 --> 38:28.160] But from the HackDAF, with a simple button press, we can change this entirely. [38:31.660 --> 38:37.980] By subscribing to the admin's call invite topic, now when the Temi calls it again, [38:37.980 --> 38:43.460] both the attacker and the admin will receive the call. And the attacker is free to pick up this [38:43.460 --> 38:48.180] and gain the same control over the robot it did with the other attack vector. [38:56.860 --> 39:04.920] All right, that concludes the demo. Got a couple slides to finish off. [39:06.980 --> 39:10.720] So let's talk about the vendor's response to our research. [39:12.180 --> 39:18.200] So we disclosed all four vulnerabilities to RoboTemi Global LTD on March 5th. [39:19.200 --> 39:24.740] They responded very quickly, and they were very receptive to all the suggested mitigations for [39:24.740 --> 39:29.340] these vulnerabilities that we outlined in our report. But perhaps most importantly, [39:29.340 --> 39:33.320] they maintained constant communication throughout the process, [39:33.320 --> 39:36.960] working with us to mitigate the vulnerabilities. [39:38.340 --> 39:43.380] Speaking of which, all four CVEs are actually patched as of July 15th. [39:44.020 --> 39:48.940] And McAfee ATR, my team, has reviewed the patches and has confirmed that they [39:48.940 --> 39:56.980] successfully mitigate all four CVEs. Now, all code shown as a result is from the older vulnerable [39:56.980 --> 40:03.180] versions of the APKs. In fact, the code is now heavily obfuscated and much harder to parse. [40:03.300 --> 40:08.940] And this is sort of the gold standard we seek out in security researcher and vendor relationships, [40:08.940 --> 40:15.560] where it's a mutually beneficial thing where the vendor responds quickly and we're able to [40:15.560 --> 40:19.900] get these things patched as soon as possible, ultimately resulting in a safer product for [40:19.900 --> 40:29.660] everyone. Now, before I let you guys go, I do want to discuss really briefly the various impact [40:29.660 --> 40:36.320] scenarios you might see used for these vulnerabilities. I think the biggest one is [40:36.320 --> 40:42.380] healthcare. There's obvious privacy concerns whenever you, you know, spy on a potential [40:42.380 --> 40:48.100] medical appointment or anything to do with health information. That's why HIPAA is such a big deal. [40:48.640 --> 40:53.980] But another potential attack vector might be, you know, using it as a sort of espionage for [40:53.980 --> 40:59.220] getting the status or location of persons of interest within a hospital. That might be something [40:59.360 --> 41:05.680] a nation-state actor might be interested in. Another attack scenario I want to have you [41:05.680 --> 41:09.800] guys think about is the enterprise one. We've already seen that these robots are being used in [41:09.800 --> 41:16.420] corporate offices. Now, you know, this actually would grant an attacker access to certain [41:16.420 --> 41:21.560] information that simply isn't accessible from a network-based attack scenario. Things like, you [41:21.560 --> 41:27.100] know, information posted on bulletin boards, on post-its, on computers. I hope it wouldn't be a [41:27.100 --> 41:32.140] password, but who knows? Network diagrams on whiteboards and other sensitive information. [41:32.140 --> 41:36.620] And perhaps more obviously, the ability to spy on boardroom meetings. [41:36.620 --> 41:41.900] What kind of sensitive information or trade secrets could be listened through? And it's [41:41.900 --> 41:47.600] not too surprising to see a teleconference robot being used in a room for teleconferencing. [41:48.820 --> 41:54.400] And with that said, that concludes my talk. I will be present in the Discord server to [41:54.400 --> 41:59.500] answer any questions you guys have. And thanks for tuning in.