WEBVTT

00:00.000 --> 00:02.780
Hello, IoT Village, first and foremost.

00:02.900 --> 00:04.820
What it be, what it do.

00:05.280 --> 00:08.540
I'm Mark, and boy, have I got some zero days for you.

00:08.640 --> 00:17.240
Now, the reason why I call this talk Assembly Voluntron isn't just because I'm hacking a robot and it's a cool name, and incredibly clever, too.

00:17.240 --> 00:25.460
But also because there's four unique CVEs in this target, and when they work together, they kind of create something that's greater than the sum of its parts.

00:25.500 --> 00:27.940
Just like a mech you might have heard of.

00:29.300 --> 00:34.360
So, the next thing you might be wondering is, who are you, and why should we care what we have to say?

00:34.540 --> 00:40.060
Well, to start off, like I said, I'm Mark, to which there's really only one natural response.

00:41.680 --> 00:44.200
And you can find me on Twitter, at Ropsicle.

00:45.260 --> 00:53.400
And I'm currently a security researcher for McAfee's Advanced Threat Research Team, which I'll be referring to as ATR from now on, because it's kind of a mouthful.

00:54.120 --> 00:58.420
Now, my focus has been on finding zero-day vulnerabilities, particularly in embedded systems.

00:58.420 --> 01:01.540
So, this talk is really on-brand for me, so to speak.

01:02.140 --> 01:09.600
Now, as for previous experience, I spoke at last year's DEF CON and ICS Village, so I'm basically a celebrity.

01:10.280 --> 01:13.120
Now, for hobbies, I really only do two things.

01:13.120 --> 01:15.960
I hack and I squat.

01:18.000 --> 01:23.460
Now, depending on how nice you guys are to me in the Discord channel after, I might add streaming to that list.

01:23.460 --> 01:25.120
But for now, it's just those two.

01:25.920 --> 01:28.260
Okay, so let's move on to the target.

01:28.740 --> 01:31.640
Temmie or Teemee, or however you want to pronounce it.

01:32.040 --> 01:35.460
The fact is, it's actually a pretty cutting-edge piece of tech.

01:35.860 --> 01:43.260
So, the marketing describes it as the world's first truly intelligent, mobile, personal robot for your home.

01:43.400 --> 01:44.940
That's a lot of qualifiers.

01:45.380 --> 01:49.500
And as you can see here, it's actually a pretty small device.

01:49.500 --> 01:53.280
It's about four feet tall, and it's got kind of like an Android brain.

01:54.340 --> 01:59.660
That's like an Android tablet at the top with like a camera and a microphone and a fully functioning touchscreen.

02:00.600 --> 02:05.880
Now, this device was created by RoboTemmie Global LTD, and they're sort of like a startup company.

02:05.880 --> 02:09.360
This is their first venture into the consumer space.

02:09.360 --> 02:15.980
But they actually spun off of a parent company called RoboTeam, which did military robotics based out of Israel.

02:16.520 --> 02:17.500
Now, this thing isn't cheap.

02:17.500 --> 02:22.600
It's going 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:34.960
But more importantly, it also has autonomous movement and obstacle detection, thanks to the various sensors it features, and also the 360 LiDAR.

02:35.780 --> 02:41.220
And finally, as you'd expect, it has Alexa and smart device integration, being a smart IoT device.

02:41.420 --> 02:44.280
And you get all the standard things you'd expect from an Android tablet.

02:44.280 --> 02:50.280
Wi-Fi, Bluetooth, it even has a wireless charging pad on the back that doubles as a coaster, at least for us.

02:51.020 --> 03:02.640
So, although RoboTaming likes to advertise their robot as being, you know, sort of a consumer device, the reality is that it's actually seen a lot of use outside of that space.

03:02.980 --> 03:08.580
So, I think one of the biggest things we've seen recently is that it's used sort of as a mobile kiosk.

03:08.580 --> 03:23.700
So, in places like the Mall of America and the Nautilus Hotel, and even in certain corporate environments, like TransFighter corporate offices, you'll see that it serves as an informational kiosk that has the advantage of being able to show people around.

03:23.700 --> 03:29.460
So, instead of just telling people where to find, you know, like Jimmy John's in the mall, for example, it can actually navigate them there.

03:30.640 --> 03:37.840
But perhaps the most important and impactful application of this robot is in healthcare, especially given the recent pandemic.

03:37.880 --> 03:49.300
So, with doctors' visits becoming more and more, you know, the standards becoming more remote visits and remote, you know, teleconferencing for doctors' appointments, this has actually seen a lot of pickup in the healthcare space.

03:49.360 --> 03:53.180
So, already we're seeing it being used by places like Trillium Health Resources.

03:53.800 --> 04:04.760
In fact, it's also been picked up by Israel's Ministry of Defense as, like, the de facto teleconferencing solution for the medical wards throughout Israel.

04:04.900 --> 04:15.260
And we also see a lot of applications in Southeast Asia, of all places, with places like China and South Korea, you know, ordering hundreds of these units for their nursing homes and medical institutions.

04:15.680 --> 04:26.400
And to accommodate this increased demand, RoboTemy has actually increased production of these units to about a thousand a month, I believe, just to meet this growing demand in the medical space.

04:27.400 --> 04:40.080
So, now that we know what Temy is, what it's capable of, and where it's being used, it's important for us to sort of draw a box about what the normal operations of it look like, so then we can have a lot of fun breaking that box.

04:40.660 --> 04:48.680
So, to start off, normal operation of the Temy is done through a use of its smartphone app, and this is both on Android and iOS.

04:48.840 --> 04:53.220
So, you can call the Temy from it, you remotely control it that way, that sort of thing.

04:54.000 --> 05:00.640
And the registration process for using this app is, basically, you just put in your phone number and it verifies it, and that's how it identifies you.

05:00.640 --> 05:07.040
So, if you reinstall the app and use the same phone number, it'll still find up your account details.

05:07.520 --> 05:15.060
Now, upon first booting up the robot, which already was a super fun experience unboxing this thing, but we are prompted to scan a QR code.

05:15.120 --> 05:22.440
And this, basically, just turns whatever user scans that QR code into the de facto admin of that Temy robot.

05:22.500 --> 05:28.200
And the admin is only one per Temy, 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:41.560
Phone contacts that use the Temy app, so phone contacts in, like, your smartphone, if they have the Temy app installed, they're synced automatically.

05:41.560 --> 05:43.280
And this can be done one of two ways.

05:43.280 --> 05:49.880
If the admin has phone contacts that have the Temy app, they'll be synced automatically to the robot, and the robot will be aware of them.

05:50.400 --> 06:01.260
Alternatively, if you're just a regular user of the phone app, you don't own a Temy, but you have a friend that does, for example, and they're in your phone contacts list, you'll be able to call your friend's Temy robot from the app.

06:01.640 --> 06:03.800
And we can sort of show you how that works.

06:04.000 --> 06:12.440
So once you boot up the app, if it finds a contact that owns a Temy, they'll show up down here on the left under your contacts list.

06:12.720 --> 06:17.040
So here, we have a lab phone as one of the contacts that owns a Temy.

06:17.080 --> 06:23.460
And by selecting this contact, you can see the Temy robot associated with it, and even has a button that lets you just call it straight from the screen.

06:25.380 --> 06:29.520
And then once a call is actually initiated, this is sort of the interface you're presented with.

06:29.520 --> 06:34.860
You can drive the robot around, control your audio options, pretty standard stuff.

06:36.260 --> 06:42.360
Now, calling is very much so the primo functionality of this robot.

06:42.360 --> 06:45.980
And really, callers get a lot of control over the device during the call.

06:45.980 --> 06:56.380
They get audio and video feeds from the Temy, but they also have control of its movement, which they can control manually 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:05.840
Now, the Temy does ring when someone besides its admin calls it.

07:05.840 --> 07:14.620
So in that sense, if you just added someone's phone number that they don't know you, it turns into basically just trying to cold call a cell phone.

07:15.000 --> 07:24.160
There is one exception to this, and the admins can actually grant certain users in their contacts list special privileges to bypass this limitation.

07:24.380 --> 07:34.500
So if you have like a family that all uses the same robot, and you can't be bothered with having to pick up on the other end each time, an admin can grant several other users the ability to call in without having it ring.

07:35.500 --> 07:37.160
And this is also done through the phone app.

07:37.160 --> 07:43.740
You can just invite new members and then select whatever contacts you want to be able to control the robot, whatever they want.

07:45.020 --> 07:53.200
So now that we have a good grasp of what the normal operation of this device looks like, we can sort of get into the spirit of trying to hack this thing now.

07:53.340 --> 08:01.380
Now, although this tech is pretty novel and cutting edge in a lot of ways, the approach we took to ReconnaSense was fairly standard and typical.

08:01.800 --> 08:04.840
So we started with trying to get a local shell on the device.

08:04.840 --> 08:18.940
This was actually super easy and short-circuited by the fact that the device comes with developer options, which include ADB, or Android Debug Bridge, which allows you to remotely connect to it like you would an SSH session.

08:18.940 --> 08:24.160
So that already made our lives a lot easier for moving files around and accessing the device at startup.

08:24.860 --> 08:31.040
The next thing we tried to do was actually capture traffic on the device using Wireshark.

08:31.040 --> 08:37.220
And during stuff like boot up and during phone calls, we saw three IPs being hit pretty frequently.

08:37.420 --> 08:39.540
One of these mapped to a Yahoo URL.

08:39.540 --> 08:41.780
So this is probably being used for its news app.

08:41.800 --> 08:48.720
And then two more mapped to Amazon AWS instances, which while not surprising, don't really reveal much either.

08:50.260 --> 08:57.320
The next thing we did was used our ADB shell to actually run... sorry, not ADB, that's a little later.

08:57.320 --> 09:01.700
We ran an Nmap port scan on the device to see what the ports it was listening on.

09:01.700 --> 09:04.180
Another standard thing you'd do for attack vectors.

09:04.260 --> 09:14.620
And the only port it identified as being open was the port 4443, which Nmap classified as being used for the service Feros, which is actually related to printing.

09:14.620 --> 09:16.840
So this is probably a false classification.

09:17.140 --> 09:23.320
It's more likely that this port is being used as an alternative to the standard 443 you'd see used for HTTPS.

09:24.740 --> 09:42.360
Now, to verify that, we actually used the ADB shell we had to the device to run Netstat, and actually found that the service associated with this port is something called com-roboteam-teamy-usa, which looks a lot more like an Android application than it does,

09:42.360 --> 09:44.060
you know, a standard Linux binary.

09:44.700 --> 09:46.080
And sure enough, that was the case.

09:46.080 --> 09:53.660
By parsing the list of installed packages on the device, we actually found the APK associated with this Android application.

09:53.660 --> 10:00.700
And using our ADB shell, it was trivial to pull this APK off and start examining the software.

10:01.640 --> 10:10.180
So now that we had access to the software, and we also had access to the phone app software at this stage as well, because we could just download the APK from the Play Store.

10:10.180 --> 10:13.600
It's completely free, and you don't even need to own a Temi to run it.

10:13.600 --> 10:18.000
So we could, you know, start looking at both of those at the same time.

10:18.180 --> 10:22.840
Now, the rest of this is really going to be, like, 80% reversing and static analysis.

10:22.980 --> 10:25.100
That's just sort of the nature of this project.

10:25.100 --> 10:27.800
Now, why, you might ask, why?

10:28.000 --> 10:36.440
Well, a great man once said, the road to exploitation is paved with months of staring a decompiled Java code.

10:36.840 --> 10:38.140
That man's name?

10:38.440 --> 10:39.580
Albert Einstein.

10:40.620 --> 10:43.060
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 --> 11:05.350
And JADX was sort of a favorite of ours because it has a functionality of being able to right click on any symbol and click on it to find usage, which became really important later on.

11:06.630 --> 11:09.070
From there, we had to pick a vector.

11:09.330 --> 11:17.030
Now, I don't know how many of you have actually looked at reversing in a full Android app, but they have massive code bases frequently, and Temi was no exception.

11:17.270 --> 11:23.930
Instead of groping in the dark, we decided that we needed to sort of hone in on a specific subset of the code to refine our search.

11:24.710 --> 11:31.690
In our case, we were already interested in the calling functionality of the robot, since that would grant us the greatest level of control entirely remotely.

11:32.210 --> 11:37.630
So we began digging through the different libraries that are part of the APK.

11:37.970 --> 11:43.410
After Googling around a bit, the one that jumped out at us particularly was something called Lib Agora.

11:43.410 --> 11:51.750
And this is actually a binary related to the Agora video SDK, which is a third party library used specifically for video calling functionality.

11:51.750 --> 11:53.110
Okay, that's perfect.

11:53.110 --> 11:54.970
That's exactly what we're interested in.

11:55.290 --> 11:59.710
So from there, we needed to find an entry point related to the attack vector.

11:59.710 --> 12:07.890
And you can sort of imagine this as being like a strand on like a wool sweater, the thing you start pulling on to really unravel the whole thing.

12:08.790 --> 12:17.170
So we began by actually pulling up this library in IDA and looking at its exports, and immediately the function native join channel jumped out at us.

12:17.170 --> 12:20.610
It looked like something related to joining a chat room, for example.

12:21.470 --> 12:28.910
Opening up the APK now, we saw the same function with the same signature appear in the decompiled app.

12:29.290 --> 12:30.930
So that was a good sign.

12:31.090 --> 12:40.990
So from there, we could use JADX's find usage feature like about 600 times to sort of begin tracing the code path taken for starting video calls.

12:41.690 --> 12:46.730
Now, at this stage, there really is no more advice or cool shortcuts.

12:46.730 --> 12:49.690
It really is, you just have to draw the rest of the L.

12:49.690 --> 12:58.530
You really have to just put in the legwork to trace the different function calls that are being made in order to get a better understanding of how the code works.

12:58.650 --> 13:02.210
But the fruits of our labor in this case was actually pretty impressive.

13:02.610 --> 13:05.590
It's sort of like staring at the sun, so I'll only show it briefly.

13:08.560 --> 13:09.960
Did you catch that?

13:11.720 --> 13:12.620
All right.

13:12.680 --> 13:14.740
Let's take a closer look at it.

13:14.840 --> 13:21.860
So highlighted in the different colors near the top are the different entry points for the calling code.

13:22.000 --> 13:26.060
So there's four ways to initiate a call from the phone app, and that correlates to these four.

13:26.060 --> 13:37.600
You can call a phone contact, you can call a robot contact, you can call either contact from the recent calls list, and if you happen to be a Temi admin, you can also call your specific robot.

13:38.240 --> 13:48.280
Moreover, we decided to segregate these based on the code flow that's either for outgoing calls indicated in red or incoming calls indicated in blue.

13:48.560 --> 13:56.580
And I'm not going to go through this too deeply because it's sort of massive, but this did serve as a good reference point for a lot of the reversing we had to do later.

13:58.160 --> 13:58.720
Okay.

13:58.720 --> 14:02.080
So we have four vulnerabilities to get through, so let's just jump right into it.

14:02.080 --> 14:08.440
The very first one, both chronologically and in terms of complexity, is the CVE ending in 70.

14:09.180 --> 14:14.160
And we can see here that it's categorized as being a use of hard-coded credentials.

14:14.720 --> 14:17.360
And it's present in the Temi Android app.

14:18.440 --> 14:26.200
Now, to have a better understanding of what this vulnerability entails, let's go through the process we used to actually discover it.

14:26.780 --> 14:29.960
So this really consisted of four easy steps.

14:30.320 --> 14:32.060
R, T, F, and M.

14:32.380 --> 14:34.040
And I do mean that pretty literally.

14:34.080 --> 14:42.720
Just by looking through the Agora documentation for their video calling API, we were able to get 80% of the way to finding this vulnerability.

14:44.040 --> 14:50.100
So specifically, we decided to take a second look at that join channel function we saw earlier.

14:50.240 --> 14:55.260
According to the Agora documentation, it has two required parameters and two optional ones.

14:55.480 --> 14:59.560
And this is really all that's needed to join an existing video call.

14:59.980 --> 15:02.860
Now, the first one is something called a token.

15:02.860 --> 15:09.580
And it seems that a token, if the user uses a static app ID, the token is also optional and can be set as null.

15:09.740 --> 15:11.260
This was interesting to us.

15:11.320 --> 15:16.720
And the second required parameter for joining a channel is a channel name.

15:16.720 --> 15:18.520
This is something we'll touch on a bit later.

15:18.520 --> 15:24.280
For now, we were interested in the static app ID and whether the Temi was using a token at all.

15:25.020 --> 15:35.180
Taking a look at the same function in the code, we found that it is indeed setting that token parameter to null, which means that it's likely using a static app ID as indicated in the documentation.

15:36.360 --> 15:40.260
Okay, so then we decided to start looking for this static app ID.

15:40.260 --> 15:41.320
Where could it be found?

15:41.540 --> 15:48.660
Referring back to the Agora documentation, we found the one function or the one API call that actually uses it as a parameter.

15:48.660 --> 15:51.740
And that's the rtcengine.create function.

15:52.320 --> 15:59.280
And it uses it as a parameter and it describes it as being an app ID issued by Agora to the developers, which is sort of vague.

15:59.280 --> 16:11.020
But after some more digging, we sort of discovered that this is used as a sort of namespace that segregates different users or different implementations on the Agora remote servers.

16:11.020 --> 16:19.100
So what it means is that you have a set static app ID that's shared amongst all Temi robots and Temi phone app users.

16:19.100 --> 16:25.460
And the app ID ensures that users of that service can only call other Temi users.

16:25.460 --> 16:29.380
They can't call an arbitrary Agora client.

16:29.940 --> 16:33.520
So this is actually a pretty important credential to have access to.

16:33.660 --> 16:39.880
Well, since we knew the function that takes it argument, we decided to look for this function in the Temi's decompiled code.

16:40.320 --> 16:49.660
And sure enough, there was the app ID hard-coded directly into the app that's freely accessible at the Play Store and fairly trivial to decompile.

16:50.320 --> 16:52.300
So this was already a good start.

16:52.300 --> 16:59.820
But really, to exploit this as a vulnerability, we needed not only the app ID, but also the channel name.

16:59.820 --> 17:02.280
So we could actually join an potentially.

17:03.800 --> 17:07.160
So if we still needed the channel name, how could we get it?

17:07.160 --> 17:15.120
Well, by going through that nice little graph I showed earlier, we were able to trace down what function actually generates the channel name.

17:15.120 --> 17:16.840
And here it's being called a session ID.

17:16.840 --> 17:18.220
But they're really the same thing.

17:18.800 --> 17:22.320
And as you can see, this is doing something not too complicated.

17:22.320 --> 17:26.160
It's actually just generating a random six-digit value.

17:26.340 --> 17:34.980
Now, this is important because, you know, 900,000 possibilities may seem like a lot, but it's well within the range of brute-forceable attack vectors.

17:36.580 --> 17:44.280
So in theory, an attacker could use the hard-coded app ID they extracted from downloading the app, which is shared amongst all Temmie installs.

17:44.320 --> 17:51.460
And then they could just use a brute-force method to try and guess every single possible channel name.

17:51.460 --> 17:58.880
And by doing so, they could potentially intercept every ongoing Temmie call used by any Temmie install.

17:59.540 --> 18:04.380
Now, obviously, we couldn't test such a brute-force attack vector against a live production server.

18:04.380 --> 18:11.980
But what we could do is we could create a custom Agora app to join a Temmie call just launched locally.

18:11.980 --> 18:16.980
And we did this by logging the channel name using ADB.

18:17.220 --> 18:28.700
And sure enough, using this custom app, we were able to join the existing call and essentially spy on the other two call members.

18:28.700 --> 18:32.320
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 --> 19:05.500
Now, the reason why we call this a helper vulnerability is that it actually is related to the fact that you can modify the Temmie app and it still has full access to all the remote services it uses.

19:05.500 --> 19:13.540
It doesn't perform any kind of tamper checking to make sure that it's not running on a rooted device, that the code for the app hasn't been modified in any way.

19:13.540 --> 19:15.300
It just isn't aware of that.

19:15.600 --> 19:31.500
And the reason we were motivated to even pursue this as an attack vector is that it's much easier to modify an existing code than to start from scratch, but more importantly, the Temmie Android app already has access to all those remote services, which requires some degree of authentication.

19:31.500 --> 19:42.680
Instead of trying to extract the keys it's using and whatever other authentication mechanisms from the app and trying to make it our own, we just leverage the existing app and inject our code into it.

19:43.680 --> 19:50.700
So the way we'd accomplish this is by first unpacking the APK, which we can do using APK tool.

19:52.220 --> 19:56.520
Next, we would search for the particular piece of code that we want to modify.

19:56.600 --> 20:01.940
This could be either through the decompiled code or through the various resource files included with the APK.

20:02.100 --> 20:09.140
As a proof of concept, we decided to try and change the text for the call button, which we found through some grepping.

20:09.940 --> 20:15.740
Okay, so now that we knew which part of the APK we wanted to change, the next thing was to simply make that modification.

20:16.080 --> 20:21.380
And that was as simple as pulling it up in a text editor and replacing the string with what we wanted.

20:21.380 --> 20:24.240
In this case, we decided to rename it Pwn, give it a little more spice.

20:25.560 --> 20:30.120
And the last but not least, we had to repack but also re-sign the app.

20:30.120 --> 20:38.120
And the reason why we need to re-sign it is Android does not allow apps that are not signed to be installed on the device.

20:38.240 --> 20:42.920
And by modifying the existing app's contents, we invalidated the existing signature.

20:42.920 --> 20:50.440
But no worries, since the signature is not being checked by the device, there's no reason why we can't just create our own signature and use that.

20:51.240 --> 20:55.640
So the repacking process is once again done using APK tool.

20:55.740 --> 21:01.780
And then we create a signature using a combination of key tool and jar signer, as shown here.

21:03.140 --> 21:09.140
And the end result was that we were able to successfully change the string on this call button.

21:09.140 --> 21:20.980
And perhaps more importantly, modifying the app in this way proved not to impact this functionality in the least, meaning that we could potentially make non-trivial changes and still be able to perform things like calling.

21:22.540 --> 21:32.840
Now, exploitation of this vulnerability is a little tricky without spoiling the rest of the presentation, because really its main application is used to help exploit the next two vulnerabilities.

21:32.900 --> 21:34.720
So we'll save the discussion for that.

21:35.240 --> 21:36.500
No spoilers.

21:37.440 --> 21:38.160
Okay.

21:39.420 --> 21:41.380
Vulnerability numero trace.

21:41.520 --> 21:45.960
So this one is actually missing authentication for a critical function.

21:45.960 --> 21:47.860
A little more serious than the last two.

21:47.860 --> 21:57.180
And this is actually present in Temi's MQTT broker, which if you don't know what MQTT is, I'm going to give you guys a real quick crash course on it, just so we're all on the same page.

21:58.580 --> 22:05.540
So MQTT is a publish-subscribe messaging protocol that's specifically designed for IoT and other lightweight devices.

22:05.640 --> 22:08.800
So it's not too surprising to see Temi using it.

22:09.380 --> 22:17.820
Now, the way it works is that clients will publish messages to certain topics, and then subscribers to those topics then receive the messages.

22:17.860 --> 22:26.100
You can think of it as sort of being like subscribing to a YouTube channel, and then receiving notifications whenever your favorite YouTubers upload, for example.

22:27.780 --> 22:35.620
And then the topics themselves are strings that are organized into a hierarchy, and the hierarchy itself is delineated much in the same way that a Unix file system is.

22:35.620 --> 22:37.020
So just forward slashes.

22:38.320 --> 22:46.540
Now, in terms of the Temi, it uses MQTT for basically all communication between itself, the phone app, and the various cloud services.

22:46.980 --> 22:57.620
So you see it being used for things like video call invitations, syncing contacts from the admin, and even, most importantly, 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:15.940
Well, we started by looking at the code that was used by the app to subscribe to its call invite topic.

23:15.940 --> 23:19.660
After all, we are interested first and foremost in the calling functionality.

23:20.180 --> 23:31.740
This is just the topic that either a phone app or a robot will listen on when it receives phone calls, and then the person creating a call for that user will publish a message to that same topic.

23:32.920 --> 23:38.900
So in our case, it takes the form... you can see it being invoked here on line 408.

23:38.900 --> 23:43.200
That's the actual function that is used to subscribe to that topic.

23:43.200 --> 23:47.920
And the topic string itself takes the form client something followed by invite.

23:47.920 --> 23:53.540
And that something in the middle is a client ID, or an MQTT client ID, rather.

23:53.740 --> 24:00.280
And an MQTT client ID is just a unique identifier for a specific client that's connected to the same MQTT broker.

24:00.280 --> 24:03.020
It's a way to identify different users.

24:03.900 --> 24:06.100
So this actually gave us an idea.

24:06.760 --> 24:11.500
Could we subscribe to someone else's call invite topic if we're able to modify the app?

24:14.020 --> 24:17.660
Well, in order to do that, we would need to know their client ID.

24:18.260 --> 24:22.240
So we would need to somehow get this information.

24:22.380 --> 24:24.920
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:39.100
So if you try to initiate a call from the recent calls list, this is the call code that gets executed.

24:39.420 --> 24:43.080
It invokes a function called telepresence service dot initiate call.

24:43.080 --> 24:48.700
And the first parameter is actually an identifier for the contact you're trying to initiate a call with.

24:48.820 --> 24:54.020
In this case, it gets that ID by invoking a function called get MD5 phone number.

24:54.660 --> 25:02.040
At this point, we were thinking, is it possible that the client ID is just an MD5 hash of the phone number the user used to register?

25:02.280 --> 25:04.560
We decided to verify this theory.

25:05.440 --> 25:17.000
So we did this simply by taking the Google voice number we used for our Temi admin, computing the MD5 hash, and then searching for that exact hash in all the various Temi files we had.

25:17.000 --> 25:20.520
And sure enough, we got a hit in one of the logs we recorded during a call.

25:20.520 --> 25:23.040
And it classifies it right there as client ID.

25:23.380 --> 25:25.200
Seems pretty straightforward to me.

25:27.080 --> 25:33.700
Now, at this stage, we decided to modify the app, taking advantage of the previous vulnerability we outlined.

25:34.220 --> 25:45.440
And using this technique, we were able to successfully subscribe to another user's call invite topic instead of our own, which basically meant that every single time they received a call, we would get that same call.

25:45.900 --> 25:53.200
And the only thing we needed to make this happen is the victim's phone number, which telemarketers will constantly remind us is not a high bar.

25:54.800 --> 25:55.720
Okay.

25:56.220 --> 25:59.920
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:24.140
And this is related to Temi's privilege management system, which is something I've already sort of touched on with the admin versus regular contacts thing.

26:26.380 --> 26:28.460
So we already know about admins.

26:28.460 --> 26:31.400
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:41.900
Another one is contacts, which are just the default permissions given to a user.

26:41.900 --> 26:43.580
It's also the lowest level.

26:45.020 --> 26:48.760
Now , there are two ways to become a contact.

26:48.760 --> 26:51.180
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 --> 26:59.340
We'll be focusing on this latter use case.

27:00.100 --> 27:07.580
So the Temi robot actually listens on the topic sync contacts and then followed by its MQTT client ID or its robot ID.

27:07.580 --> 27:08.920
They're the same thing.

27:08.940 --> 27:13.820
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:38.400
Pretty straightforward.

27:39.120 --> 27:48.780
And the reason why the sender client ID is included is because the Temi locally ensures that the sender is equivalent to the ID of its admin.

27:48.800 --> 27:50.540
Just as a sanity check.

27:51.440 --> 27:52.040
Okay.

27:52.040 --> 27:53.360
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:11.500
And owners are actually related to that functionality I showed earlier where you can 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:39.100
This is actually a little bit different from adding contacts because while adding a contact is pretty straightforward, adding owners is a little more complex because the request sent by the admin from the phone app is actually quite a bit different than what the Temi expects on the receiving end.

28:39.480 --> 28:46.400
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:59.080
They contain an inner request and also a signature that's basically generated using the client's private key.

28:59.080 --> 29:02.120
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:28.000
the list of users that we want to promote to owners, the ID of the robot that we're sending the request for, the source of the request, a timestamp, and then finally a type 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:37.860
Well, it's quite a bit different.

29:38.160 --> 29:41.480
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:50.840
This one specifically.

29:51.800 --> 29:56.000
And also the structure of the request has also changed.

29:56.280 --> 30:07.320
It seems to be a subset of the request that the admin is sending where it still has the list of owner IDs and the type, but has been stripped of its signature, its timestamp, and its source.

30:08.100 --> 30:18.840
Now, at this point, we speculated that the reason for this is because the REST API itself is being used as an authentication mechanism for adding owners.

30:18.840 --> 30:22.380
This is sort of a sensitive privilege escalation type of deal.

30:23.000 --> 30:37.580
And so what the REST API would do is it verifies the request by checking the signature, and then it strips out all that verified information before sending it off to the Temi's MQTT topic, essentially serving as like a middleman.

30:39.240 --> 30:42.580
So that means that our flowchart sort of looks like this.

30:42.580 --> 30:49.020
And presumably, if the verification server deems the signature invalid, nothing happens.

30:49.900 --> 30:55.560
Okay, so these privilege levels mostly have utility in how calling works.

30:55.840 --> 31:05.600
So when a Temi receives a call from a user, if that caller is either an admin or an owner, the Temi will pick up the call automatically.

31:06.200 --> 31:10.780
On the other hand, if the caller is a contact, it'll ring.

31:11.240 --> 31:17.400
So unfortunately, as an attacker, if we just tried to cold call a Temi, we would become a contact, and the Temi would ring.

31:19.020 --> 31:20.280
What do we want?

31:20.520 --> 31:24.100
Well, we want to be able to call the Temi and have it pick up automatically.

31:24.600 --> 31:27.340
This is because calling is sort of the endgame.

31:27.340 --> 31:32.580
You know, you get full control of the 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:51.220
And we know that we can subscribe to arbitrary topics, like we showed when we subscribed to someone else's call-invite topic.

31:51.780 --> 31:56.640
So our next question was, can we also publish to arbitrary topics?

31:56.800 --> 32:14.220
Because if we could, we may be able to escalate our privilege by publishing the owner's message that the Temi expects to get from the authentication server directly, and just publish it right to that MQTT topic it's listening on, thereby bypassing that authentication middleman entirely.

32:15.360 --> 32:20.060
Well, this all sounds well and good, but there was a slight caveat here.

32:21.020 --> 32:26.920
And that was, the Temi will only process privilege escalation requests for existing contacts.

32:27.060 --> 32:28.360
Now, why is this a problem?

32:28.560 --> 32:39.140
Well, there's only two ways to become a contact, one of which is the cold call to Temi, which is far from ideal because that might arouse suspicion for various reasons, if you have some stranger calling your robot.

32:39.660 --> 32:44.480
And then the other way is to have an admin send the sync's contacts message with you on it.

32:44.500 --> 32:46.220
Those are really the only two ways.

32:47.140 --> 32:50.060
Well, the solution is actually trying... is that's the latter.

32:50.060 --> 33:01.500
What we can do is we can actually spoof the admin's sync contacts message by simply setting the sender client ID to the admin's client ID, since the Temi just implicitly trusts that this value is accurate.

33:02.180 --> 33:09.980
In this way, we can send a sync contacts message first, followed by an add owner's message, and then finally initiate the call of the robot.

33:11.200 --> 33:17.880
So, this is sort of what the same functionality looks like after we've modified the app in the following ways.

33:18.000 --> 33:20.680
We can see already that it's a lot simpler.

33:22.540 --> 33:26.240
And in order to become a contact, we just send a malformed request.

33:26.460 --> 33:31.780
In order to escalate to becoming an owner, we just send another malformed MQTT request.

33:32.140 --> 33:39.580
And then finally, unlike before, now that we have owner privileges, the Temi will pick up the call automatically.

33:45.040 --> 33:53.080
Now, just as a quick recap of what these vulnerabilities can do together, it's sort of a recipe for disaster.

33:53.080 --> 33:56.180
And the recipe includes these following steps.

33:56.240 --> 33:58.600
First, you find a vulnerability in the Temi.

33:58.660 --> 34:01.020
And then you just find three more.

34:01.600 --> 34:05.800
And here's a completely unrelated graphic of a bucket with holes.

34:05.800 --> 34:07.040
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:28.060
And what this produces is the ability to spy on calls, the ability to intercept calls intended for other users, and most importantly, the ability to remotely control the robot and see through its eyes and hear through its ears.

34:31.340 --> 34:33.500
Now, I've been teasing you guys enough.

34:33.500 --> 34:38.120
So, at this point, I think it's a good time to show you guys a demo of how this all works.

34:53.530 --> 34:59.650
So, Shane or Sam, if you guys could queue up the video.

35:00.790 --> 35:01.670
Hopefully.

35:03.690 --> 35:05.130
Demo is playing.

35:05.170 --> 35:05.890
Okay.

35:05.890 --> 35:08.230
So, on the left, we have the Temi admin.

35:08.390 --> 35:11.750
And on the right, we have the attacker's phone.

35:12.050 --> 35:18.350
And we can see that I've already added the admin as a phone contact, thereby syncing it to the Temi's contact list.

35:18.610 --> 35:21.690
And the first thing I'm going to do is I'm going install the Temi app.

35:25.370 --> 35:30.490
Normally, unmodified, just straight from the Play Store, just to show that there's no smoke and mirrors involved.

35:31.230 --> 35:40.130
We'll later be using the modified app with the exact same credentials and going through the same registration process to show you that it 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:57.030
Now, as expected, the Temi rings.

35:57.030 --> 35:58.590
It does not pick up automatically.

35:58.590 --> 36:01.590
This is because we only have contact privileges at this stage.

36:01.590 --> 36:03.910
The admin hasn't granted us any special rights.

36:11.200 --> 36:11.880
Okay.

36:11.900 --> 36:18.700
Now that we know what the normal operation looks like, let's go ahead and install our custom 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:31.280
We only modified what we needed to do.

36:31.400 --> 36:34.560
It's not until we initiate a call that we'll see how different it is.

36:35.160 --> 36:38.980
So, as I stated previously, we'll be using the exact same credentials to register.

36:39.560 --> 36:42.100
And, in theory, we should have the same privileges.

36:49.220 --> 36:49.740
All right.

36:49.740 --> 36:52.440
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:12.300
This time, the Temi picks up the call automatically, and the attacker now has full access to the Temi's movement, its camera, and its microphone.

37:12.580 --> 37:21.560
Now, the first thing an attacker might do is actually mute the microphone, their microphone, I mean, and turn off their camera, thereby essentially remaining anonymous as they do this.

37:22.000 --> 37:28.620
And you can start driving around whatever location it's in, looking around at whiteboards and other sensitive information.

37:29.020 --> 37:32.420
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:58.300
So that attack vector leveraged that last vulnerability it described, which gives us owner privileges.

37:58.700 --> 38:05.620
Let's look at how we can exploit the 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:18.180
And as normal, you know, all's well with the world, the admin gets the call, but the attacker doesn't.

38:18.180 --> 38:19.720
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:41.300
By subscribing to the admin's call invite topic, now when the Temi calls it again, both the attacker and the admin will receive the call.

38:41.860 --> 38:48.180
And the attacker is free to pick up this and gain the same control over the robot it did with the other attack vector.

38:56.860 --> 38:59.680
All right, that concludes the demo.

39:02.280 --> 39:04.920
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:27.500
They responded very quickly, and they were very receptive to all the suggested mitigations for these vulnerabilities that we outlined in our report.

39:27.640 --> 39:36.960
But perhaps most importantly, they maintained constant communication throughout the process, 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:51.900
And McAfee ATR, my team, has reviewed the patches and has confirmed that they successfully mitigate all four CVEs.

39:53.220 --> 39:59.460
Now, all code shown as a result is from the older vulnerable versions of the APKs.

39:59.460 --> 40:03.180
In fact, the code is now heavily obfuscated and much harder to parse.

40:03.300 --> 40:20.720
And this is sort of the gold standard we seek out in security researcher and vendor relationships, where it's a mutually beneficial thing where the vendor responds quickly and we're able to get these things patched as soon as possible, ultimately resulting in a safer product for everyone.

40:23.580 --> 40:34.060
Now, before I let you guys go, I do want to discuss really briefly the various impact scenarios you might see used for these vulnerabilities.

40:34.920 --> 40:37.160
I think the biggest one is healthcare.

40:38.000 --> 40:46.180
There's obvious privacy concerns whenever you, you know, spy on a potential medical appointment or anything to do with health information.

40:46.180 --> 40:48.100
That's why HIPAA is such a big deal.

40:48.640 --> 40:57.360
But another potential attack vector might be, you know, using it as a sort of espionage for getting the status or location of persons of interest within a hospital.

40:58.220 --> 41:01.660
That might be something a nation-state actor might be interested in.

41:02.620 --> 41:07.600
Another attack scenario I want to have you guys think about is the enterprise one.

41:07.600 --> 41:10.880
We've already seen that these robots are being used in corporate offices.

41:12.760 --> 41:20.780
Now, you know, this actually would grant an attacker access to certain information that simply isn't accessible from a network-based attack scenario.

41:20.780 --> 41:25.960
Things like, you know, information posted on bulletin boards, on post-its, on computers.

41:25.960 --> 41:28.600
I hope it wouldn't be a password , but who knows?

41:28.780 --> 41:32.140
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.540
What kind of sensitive information or trade secrets could be listened through?

41:41.540 --> 41:47.600
And it's not too surprising to see a teleconference robot being used in a room for teleconferencing.

41:48.820 --> 41:52.200
And with that said, that concludes my talk.

41:52.200 --> 41:56.280
I will be present in the Discord server to answer any questions you guys have.

41:56.680 --> 41:59.500
And thanks for tuning in.

