WEBVTT

00:14.130 --> 00:18.770
Welcome back and thanks for hanging with us here at AppSecVillage at DEF CON 2020.

00:19.270 --> 00:24.790
Before we get to our next speaker, I'd like for you to take a moment and take a look at appsecvillage.com.

00:25.050 --> 00:28.330
Out there you can find this year's t-shirt, which is incredible.

00:28.330 --> 00:30.050
This is last year's t-shirt.

00:30.050 --> 00:32.710
This year's has got more color, it's got an awesome design.

00:32.710 --> 00:35.170
I just got mine in the mail a couple of days ago.

00:35.350 --> 00:36.210
Check it out.

00:36.210 --> 00:47.750
It's a great way to support AppSecVillage and make sure that we can bring you the same kind of content and application developer security focus that we've brought the last two years.

00:47.750 --> 00:50.270
So, that's appsecvillage.com.

00:50.270 --> 00:51.610
And now for our next talk.

00:51.610 --> 00:56.750
It's entitled Local Ghost, Escaping the Browser Sandbox Without Zero Days.

00:56.910 --> 01:01.470
Parsia Hakimian is a senior security engineer at Electronic Arts.

01:01.470 --> 01:05.890
He works mostly in video games and their surprise mechanics.

01:05.990 --> 01:08.910
On a different continent, he was a C developer.

01:08.910 --> 01:17.070
You can find his rants over at parsia.net or on Twitter at at sign crypto gangsta.

01:17.070 --> 01:23.330
Now remember, crypto stands for cryptography, as everybody over in the cryptography village would tell you.

01:23.330 --> 01:27.650
So with that, welcome Parsia to the AppSecVillage stage.

01:30.910 --> 01:32.110
Hello everyone.

01:32.110 --> 01:34.050
Thanks for giving me your time.

01:34.050 --> 01:41.450
Today I'm going to talk to you about how we can jump the browser sandbox using localhost web servers without any sort of ODAs.

01:41.450 --> 01:49.250
This is part of the AppSecVillage on DEF CON 28 in the year 2020, which has been a very, very long year.

01:49.930 --> 01:51.210
My name is Parsia.

01:51.210 --> 01:54.550
I am a security engineer at Electronic Arts.

01:54.730 --> 01:56.670
Mostly work with video games.

01:56.790 --> 01:59.890
I'm the shorter guy in the picture, not the other one.

01:59.890 --> 02:05.270
I'm not here representing EA, user of my own, you know, the usual boilerplate.

02:05.270 --> 02:10.210
Similar to the boilerplate you see on the coffee cups, you know, that says caution, contents are hot.

02:10.270 --> 02:17.450
When I moved to Canada last year from the US, people told me they don't have it in Canada, but they do.

02:17.450 --> 02:19.390
So I would like my money back.

02:19.650 --> 02:22.130
This is my second time at DEF CON.

02:22.170 --> 02:23.770
First time at the village.

02:23.770 --> 02:28.030
I was here on DEF CON 2018 where I talked about enterprise blockchain.

02:28.030 --> 02:32.990
I play a lot of video games, which is good because I work for a video game company.

02:33.390 --> 02:36.630
Now, this is a slide that I put on all my presentations.

02:36.630 --> 02:42.650
It is here to tell you what I'm going to talk about.

02:42.710 --> 02:47.250
So you can decide if this is a talk for you.

02:47.310 --> 02:49.050
So your time is valuable.

02:49.050 --> 02:55.730
I don't want you to sit to the end of it and say, this is useless or I already knew this.

02:55.730 --> 03:02.690
You know, I would consider this a favor if everyone else did it too.

03:03.130 --> 03:11.790
So I'm going to talk about why modern desktop applications use local host servers to do inter-process communications.

03:11.810 --> 03:18.970
And how this is bad from a security perspective, because JavaScript and browsers can connect to these websites.

03:19.510 --> 03:24.950
Usually there's no authentication and you can get some really easy remote code executions using this.

03:24.950 --> 03:29.530
I was also discussing browser concepts and bugs related to them.

03:29.530 --> 03:33.850
And finally, I will talk about remediation and how we can fix things.

03:34.010 --> 03:37.530
And not just point and say something is bad.

03:37.830 --> 03:41.710
So these local web servers are like ghosts in your machine.

03:41.810 --> 03:48.830
You think you don't have any, but go to your machine, run netstat and check.

03:48.830 --> 03:51.990
And you will have at least a dozen of these.

03:51.990 --> 03:54.930
I cropped the screenshot, there were more.

03:54.930 --> 04:03.410
As you can see, these are like normal, typical everyday use apps like Discord and Dropbox and Apple and iTunes and NVIDIA.

04:03.410 --> 04:04.790
I mean, all of these have them.

04:04.790 --> 04:09.630
Why would Discord or Dropbox have a local web server?

04:09.730 --> 04:12.850
It's usually used for inter-process communications.

04:12.890 --> 04:15.190
Usually you have an Electron frontend.

04:15.250 --> 04:20.150
And the Electron frontend talks to a local web server that serves content to it.

04:20.290 --> 04:22.890
Sometimes you have a Windows service running a system.

04:22.890 --> 04:23.930
Those are fun.

04:23.930 --> 04:28.230
And then there's a frontend app that talks to them and they talk with each other.

04:28.230 --> 04:35.030
Sometimes you have a local host server that allows you to talk to different applications.

04:35.030 --> 04:37.710
Discord and Overvolt talk with each other.

04:38.710 --> 04:44.110
Another use case is using seamless transition from a website to a desktop app.

04:45.070 --> 04:47.450
Video conferencing apps used to do this.

04:47.450 --> 04:51.030
You would go to a meeting page.

04:51.030 --> 04:57.270
The JavaScript in the meeting page would talk to the local server from the desktop app.

04:57.270 --> 05:03.870
And the web desktop app would bring up the video conferencing app and connect to the meeting.

05:03.870 --> 05:05.470
Seamless interaction.

05:05.490 --> 05:07.270
Great for user experience.

05:07.590 --> 05:09.590
Dropbox also does this.

05:09.590 --> 05:18.990
If you have the Dropbox desktop application on your machine and you go to the web interface, sometimes you have an open button in front of a file.

05:18.990 --> 05:23.690
Let's say it's a Microsoft Office, like a doc file.

05:24.290 --> 05:28.550
You click on the open button in the website.

05:28.790 --> 05:32.690
The website talks to the local Dropbox app on your machine.

05:32.690 --> 05:36.770
The Dropbox app opens Microsoft Office and opens that doc.

05:36.770 --> 05:37.710
Great again.

05:37.710 --> 05:39.510
Great user experience.

05:39.510 --> 05:42.050
But is this really secure?

05:42.170 --> 05:43.630
Let's see.

05:44.410 --> 05:50.350
Another thing that websites do and gain a lot of traction was port scanning.

05:50.850 --> 05:56.230
Someone went to the eBay website and saw that it's scanning a lot of local ports.

05:56.230 --> 06:02.370
For example, to see if you have running a local VNC server or the remote desktop application.

06:02.370 --> 06:03.650
Like certain ports.

06:03.790 --> 06:05.950
Banks have been doing it for like four or five years.

06:05.950 --> 06:08.890
I remember I went to a bank website in 2018.

06:09.010 --> 06:10.450
It was doing the same.

06:10.450 --> 06:13.930
This is part of the fraud detection thing.

06:13.930 --> 06:22.550
They grab the results and feed it to a complex fraud detection algorithm.

06:22.550 --> 06:31.670
And it decides if your machine connected to the website is part of a botnet or is being remotely accessed or not.

06:31.670 --> 06:33.710
Should they let the transactions go through?

06:33.710 --> 06:35.150
Should they lock your account?

06:35.150 --> 06:36.010
So on and so forth.

06:36.010 --> 06:37.410
Typical stuff.

06:37.410 --> 06:42.750
If these websites are doing it, what prevents bad websites from doing it?

06:43.310 --> 06:47.290
Your app is internet connected because of that.

06:47.810 --> 06:51.650
Raymond Chen is a Microsoft employee.

06:51.650 --> 06:56.430
And he has been writing this very, very useful blog called The Old New Think.

06:56.890 --> 07:01.470
And one of his blogs, which starts with that quote.

07:01.470 --> 07:05.210
It's rather involved beings on the other side of this airtight hatchway.

07:05.210 --> 07:10.470
And by the way, this is a quote from Douglas Adams' book, Hitchhiker's Guide to the Galaxy.

07:10.670 --> 07:12.450
It's an amazing book.

07:12.530 --> 07:18.350
So Raymond talks about three privileged levels on a typical Windows machine.

07:18.350 --> 07:21.170
You have a remote attacker who is not on the machine.

07:21.190 --> 07:23.890
You have a local attacker who is a standard user.

07:23.890 --> 07:27.010
And then finally you have the local admin or system.

07:27.190 --> 07:32.170
Now browsers can be remote attackers, although they are running on your machine.

07:32.170 --> 07:37.750
So the JavaScript in the browser can talk to the local web server or talk to the local WebSocket server.

07:37.830 --> 07:40.890
And then a remote attacker can gain privilege on your machine.

07:40.910 --> 07:44.070
He also talks about how your app is internet connected.

07:44.070 --> 07:46.090
And this is from 2006.

07:46.310 --> 07:55.170
He says, if you have an app and it handles files, people can create network shares on a remote machine somewhere else.

07:55.210 --> 07:58.030
And then they can pass it to your app.

07:58.030 --> 08:02.290
And now your app is internet connected because it's grabbing a resource from a different site.

08:02.290 --> 08:04.370
Although it wasn't in your threat model.

08:04.890 --> 08:11.090
We've talked a lot about browsers and how browsers can be remote attackers.

08:11.090 --> 08:17.250
Let's talk about how browsers want to keep us safe, but they can, but they cannot.

08:17.310 --> 08:21.270
And what protections are there and how we can bypass them.

08:21.730 --> 08:24.290
The first thing is called same-origin policy.

08:24.290 --> 08:28.750
It's probably the most important part of the browser security model.

08:28.770 --> 08:30.550
So an origin has three parts.

08:30.550 --> 08:35.330
You have a protocol, which is HTTP, HTTPS.

08:35.330 --> 08:39.890
You have a domain, which is something like example.net.

08:39.990 --> 08:42.890
And then finally, you have a port, which is optional.

08:42.910 --> 08:46.610
If you don't include the port, the default port is used.

08:47.310 --> 08:52.970
Some browsers, for example, Internet Explorer, don't care about the port in the origin.

08:52.970 --> 08:56.290
The path is almost always ignored.

08:56.290 --> 09:02.230
Usually, one origin cannot talk to a different origin and grab resources and read them.

09:02.230 --> 09:09.370
So for example, if you open example.net, example.net sends a request to facebook.com and grabs some data.

09:09.370 --> 09:12.970
Browser doesn't let example.net read the response.

09:13.590 --> 09:18.290
Absent some other things are cores, but we're not going to talk about cores today.

09:18.850 --> 09:23.790
And that's a really good thing, because otherwise example.net would have all my Facebook data.

09:24.130 --> 09:28.230
So reads are usually not okay, but writes are.

09:28.350 --> 09:37.950
So if I open example.net and send a POST request to Facebook to change something, if there's no C-SERV protection, it goes through.

09:38.270 --> 09:41.950
As a result, C-SERV exists, which is not really so great for us.

09:41.950 --> 09:46.290
So the SOP protects us in some cases, but not in every case.

09:47.190 --> 09:58.890
But SOP also has this problem that just because the browser doesn't let you see the response to the request, doesn't mean the request is not sent.

09:59.230 --> 10:02.330
So browser sends simple requests.

10:02.330 --> 10:06.210
Simple request is a request that has some requirements.

10:06.370 --> 10:09.710
The HTTP verb can only be GET, HEAD, and POST.

10:09.890 --> 10:11.970
It cannot have any custom headers.

10:12.530 --> 10:15.690
And it cannot have every header.

10:16.070 --> 10:18.010
Only some headers are allowed.

10:18.030 --> 10:21.070
And of those headers, the most important one is content type.

10:21.210 --> 10:24.050
The content type for those headers can only be one of those.

10:24.110 --> 10:35.790
So one of the tricks that we usually use when bypassing this, if you have an application slash JSON request, you change the content type to text slash plain, see if it becomes a simple request and goes through.

10:35.790 --> 10:39.610
And now you have bypassed a bunch of protections in the app.

10:39.670 --> 10:41.190
And that brings us to our first bug.

10:42.370 --> 10:46.270
This is a bug by Tavish Romandy from 2016.

10:46.450 --> 10:49.090
Tavish Romandy is a really smart dude.

10:49.090 --> 10:51.330
He's part of the Google Project Zero.

10:51.330 --> 10:57.270
He installs Trend Micro Antivirus, and that antivirus has a password manager.

10:57.390 --> 11:05.290
So the way password managers usually work is that you have an extension in the browser, and you have a local web server, a WebSocket server.

11:05.290 --> 11:12.490
The local server is responsible for storing the passwords, updating, and a bunch of those.

11:12.490 --> 11:22.530
The extension in the browser, when, for example, you go to facebook.com, the extension in the browser talks to the web server and says, give me my username and password for facebook.com.

11:22.530 --> 11:25.090
And the web server gives it to it.

11:25.090 --> 11:29.090
And then the extension fills up the username and password.

11:30.190 --> 11:42.610
In the case of Trend Micro, the local web server was unauthenticated, and you could basically do remote code execution with a simple GET request, as you can see on this slide.

11:42.830 --> 11:54.430
You could say, OK, run this URL in the default browser, which in this case opens up the calc, runs the calc manually instead of opening it in a browser.

11:54.830 --> 12:08.910
If you go and read the bug from the URL, from the link in this slide, you can see that Tavisor says, yeah, we can see the response, but the GET request goes through because it's a simple GET request.

12:09.330 --> 12:11.350
So damage is already done.

12:11.350 --> 12:13.830
We can't see the response, but who cares about that?

12:14.510 --> 12:19.030
Another thing that is used for local IPC are WebSockets.

12:19.170 --> 12:23.970
A WebSocket is different from your typical HTTP request.

12:23.970 --> 12:32.250
In a typical HTTP request, you create a connection to a server, you send a request, get a response back, and then you close the connection.

12:32.250 --> 12:38.850
In a WebSocket, you create a WebSocket and you keep it alive.

12:38.850 --> 12:41.210
You can write to it, you can read from it.

12:41.210 --> 12:51.330
It's great for real-time data things, real-time data updates, like, you know, chats and video games and, like, stock trackers, I guess.

12:52.030 --> 12:54.590
But the WebSocket doesn't come out of the blue.

12:55.090 --> 13:02.090
It starts with a GET request that is a normal handshake.

13:02.410 --> 13:06.070
So the GET request is your typical GET request with some special headers.

13:06.390 --> 13:13.010
Now, remember, the GET request for a WebSocket is a simple request, so it always goes through.

13:13.050 --> 13:18.870
On the response side, the other side basically says, here are the things I agreed on.

13:18.870 --> 13:20.830
Yes, we can make a connection.

13:20.830 --> 13:22.250
Here's our protocol.

13:22.250 --> 13:35.010
One mistake that developers usually make is that they think that SEC WebSocket key in the request and the WebSocket ACCEPT key in the response are based on security.

13:35.110 --> 13:36.150
They're not.

13:36.310 --> 13:40.390
You can usually put something, anything in there and it usually goes through.

13:40.390 --> 13:41.570
It doesn't really matter.

13:41.570 --> 13:43.410
That's not a security control.

13:43.770 --> 13:48.030
So don't care about that.

13:48.030 --> 13:48.890
It's always there.

13:48.890 --> 13:49.690
It goes through.

13:49.690 --> 13:51.030
It doesn't really matter.

13:51.030 --> 13:59.050
And if you can see the response, you can see that there's nothing really needed there apart from how we can make a connection.

13:59.110 --> 14:09.450
And as a result, the browsers are not bound by the same-origin policy because there's nothing in the response that the browser doesn't already know.

14:10.070 --> 14:17.950
So if you send a GET request and there's no cores, you can't see the response, but the browser makes the connection for you anyway.

14:18.150 --> 14:22.510
So if you have a local WebSocket server, everyone can connect to it and talk to it.

14:22.510 --> 14:25.990
You can't rely on SOP or cores or whatever, any of that.

14:25.990 --> 14:29.010
And that brings us to our second Aviso bug.

14:30.690 --> 14:32.930
As I said, this guy is smart.

14:33.090 --> 14:38.370
This is from 2018, and he wanted to re-bind his mouse key.

14:38.370 --> 14:42.030
It was a Logitech mouse, so he installs an app called Logitech Options.

14:42.490 --> 14:47.530
Logitech Options runs a local WebSocket server, some port 10134.

14:48.030 --> 14:53.510
As I said, WebSockets are not bound by the SOP, and the WebSocket server didn't have any checks.

14:53.530 --> 15:01.130
The only authentication it had was when you sent a message to it, you had to provide a process ID of a process that the user owns.

15:01.230 --> 15:05.470
A process ID that are like three, four or five digit numbers.

15:05.770 --> 15:10.990
And you can brute force them quite easily in a few minutes until you find one that works for you.

15:11.270 --> 15:18.170
Fortunately for Logitech Options, you couldn't get remote code execution, you could create crashes.

15:18.730 --> 15:24.050
So imagine you have this app running on your machine, and it's always running because you have a Logitech mouse.

15:24.050 --> 15:26.730
You go to a website, and the app crashes.

15:26.730 --> 15:28.730
You go to the other website, the app crashes.

15:28.730 --> 15:33.910
That's not really useful, and that makes your experience really bad.

15:33.910 --> 15:38.630
On the plus side, you couldn't get remote code execution, so that's really great.

15:38.630 --> 15:42.650
The next iteration of the app, similar app, called Logitech Hub.

15:42.650 --> 15:47.470
It runs two local WebSocket servers, on port 9010 and 9100.

15:48.590 --> 15:53.650
Now, this iteration checks the origin header, which is really great.

15:53.650 --> 16:01.710
The origin header is a forbidden header, which means the JavaScript in the app cannot set it, only the browser can.

16:01.710 --> 16:04.750
There are other forbidden headers, like the host header, for example.

16:05.730 --> 16:10.830
And the origin header is always set by the browser for every cross-origin request.

16:10.830 --> 16:19.730
A request goes from one origin to a different origin, the browser sets the origin header to tell the server on the other side where this request comes from.

16:19.890 --> 16:29.970
So what Logitech Hub does in the WebSocket servers is if you send a request with an origin that is not part of their allow list, then they just say, we can't connect.

16:30.030 --> 16:37.070
And when the browser sees a response like this, which is not a 200 OK response, it says, well, I can't create a WebSocket connection.

16:37.230 --> 16:45.730
So websites cannot talk to Logitech Hub WebSockets, so this is a great thing, and this is a good thing that Logitech has done.

16:46.170 --> 16:56.190
We've talked about local WebSockets servers, but we also want to talk about how frameworks can help us get remote code execution.

16:56.190 --> 16:59.130
And I'm going to talk about one of them, which is called Electron.

16:59.130 --> 17:08.170
Electron is probably the most popular desktop application framework out there.

17:08.170 --> 17:10.110
It is based on Chromium.

17:10.110 --> 17:19.990
Chromium is the open source version, I'm sorry, the open source base for a bunch of browsers like Google Chrome and Microsoft Edge.

17:19.990 --> 17:23.990
So everything in an Electron app is a browser window.

17:24.090 --> 17:28.010
So if you open Visual Studio Code, you're looking at a browser window.

17:28.750 --> 17:31.650
Yeah, I know, it's silly like that.

17:32.490 --> 17:34.690
And Electron is very popular.

17:34.750 --> 17:36.310
You can see these apps on this.

17:36.310 --> 17:38.110
There are so many of these apps.

17:38.110 --> 17:43.610
And these apps that you see on the slide, you probably have at least one of them on your machine.

17:43.650 --> 17:48.590
Slack or Discord or Visual Studio Code or Skype or whatever.

17:49.190 --> 17:58.650
The problem with Electron apps is that if you get a cross-site scripting, it might lead to remote code execution.

17:58.870 --> 18:05.550
So in an Electron app, you can write Node.js code that is run in the browser and can do stuff.

18:05.830 --> 18:14.070
The way for this Node.js code to run is you want this Node.js code to run, so you flip a switch.

18:14.070 --> 18:18.950
The switch is called node integration, which is off by default for a good reason.

18:19.150 --> 18:33.350
So if you set it to true, the JavaScript in your browser window in the Electron app can now talk to the Node.js APIs and, for example, spawn processes on your machine.

18:33.590 --> 18:41.130
And as a result, if you have this switch set to true and you get cross-site scripting, now you have remote code execution, which is really bad.

18:41.130 --> 18:48.370
If you have an open redirect, which means that you can click on a link and the browser goes to a different link, or you can do something like that.

18:48.370 --> 19:00.770
You can embed remote code execution payloads on your website that you control, and then you have remote code execution on someone's machine through an Electron app.

19:00.770 --> 19:07.290
This is by default set to off, and as we saw, it's great for a good reason.

19:07.690 --> 19:10.090
Now I'm going to talk about one of my own bugs.

19:10.090 --> 19:16.690
It's a remote code execution in a Tagged Surface Analyzer, which is an open-source Microsoft application.

19:16.710 --> 19:21.310
And we're going to talk about version two of it because it has two versions.

19:21.490 --> 19:34.470
When the second version was released, our CISO, who was one of the people who created the original app, said, oh, I worked on the original app, and I went and looked at it and see what kind of app it is.

19:34.470 --> 19:37.850
And it's a very useful app for desktop security research.

19:38.670 --> 19:44.470
What you can do is you can create runs, which are basically snapshots.

19:44.630 --> 20:00.850
So you can tell a Tagged Surface Analyzer to create a snapshot before you install an application on your machine, and then you install the application, and then you create a snapshot or run after you install the application.

20:00.850 --> 20:03.950
And now you can compare these two.

20:03.950 --> 20:13.090
And you can see what files were added, what registry keys were added, if there were any open ports, if there were any new Windows services.

20:13.330 --> 20:18.770
So again, it's very useful for this kind of security research.

20:19.090 --> 20:20.870
It comes in two flavors.

20:20.890 --> 20:23.510
There's a command line interface, and there's a GUI.

20:23.590 --> 20:25.850
I usually want to run it as admin.

20:26.030 --> 20:31.910
In fact, if you don't run it as admin, it basically tells you you're not running as admin.

20:31.910 --> 20:33.330
You should be running as admin.

20:33.330 --> 20:38.190
Because if you're not running as admin, you can't see everything that happens in the computer.

20:38.350 --> 20:40.770
You can't see what the application does.

20:40.770 --> 20:42.490
You can't get the big picture.

20:43.430 --> 20:44.590
It's open source.

20:44.770 --> 20:54.130
The GUI is based on electron.net, which is, again, another open source project, which is basically electron, but for .net.

20:55.930 --> 20:58.170
Which is... I mean, it works, right?

20:59.170 --> 21:06.190
So after I created the... I'm sorry, after I installed the app and ran it for the first time, I saw this pop-up.

21:06.190 --> 21:14.430
And this is a Windows firewall pop-up that says, oh, this app wants to listen on all interfaces and open ports in the firewall.

21:14.530 --> 21:19.890
And I was wondering, why would a local application, a tag surface analyzer, want to do that?

21:19.890 --> 21:28.870
So I looked at the console logs for the app, and I saw that, yeah, it is listening on all interfaces, 0, 0, 0, 0, port 8001.

21:29.470 --> 21:31.550
That sounds really great.

21:31.690 --> 21:33.790
So I started to dig further.

21:33.790 --> 21:38.810
I mean, this was the cue to tell me that there might be something wrong with this application.

21:38.810 --> 21:43.850
So I go to port 8001 on my own, on the...

21:43.850 --> 21:49.890
I'm sorry, on the machine that is running the tag surface analyzer app, and I see the GUI.

21:49.890 --> 21:55.530
So the way the app works is it has an Electron frontend and a web server in the back.

21:55.530 --> 22:08.790
Electron frontend just opens this website, similar to what is in the browser, as you can see, and it does REST, which is, I guess, normal for Electron applications.

22:08.790 --> 22:16.190
Next thing I did, I tried to connect to it from outside, because it's opening the port and listening on all interfaces.

22:16.190 --> 22:17.790
I might be able to talk to it.

22:17.790 --> 22:20.770
So this is from the virtual machine host.

22:21.050 --> 22:26.170
I went to the virtual machine on 8001, and it didn't work.

22:26.370 --> 22:29.150
I saw this error that says invalid hosting.

22:29.730 --> 22:33.010
So I was looking at it, what is wrong with that?

22:33.010 --> 22:43.210
I went and saw it's because the web server that is serving content is a Kestrel web server, which is an ASP.NET web server.

22:43.210 --> 22:46.650
I'm sorry, a web server written in ASP.NET.

22:46.830 --> 22:50.690
It has a host header filtering.

22:50.950 --> 22:53.870
So when you see the request, it looks at the host header.

22:53.870 --> 22:57.710
If it's not local host, it says, I can't do it.

22:57.710 --> 23:11.470
But here's the thing, because we are connecting from outside, and we are not bound by being in a browser on the machine, I can change the host header because I can create a tool that talks to this and changes the host header.

23:11.470 --> 23:21.130
To do this, to simulate this, I added a match-replace ruling verb that whenever it saw the host header, it would replace it with local host.

23:21.230 --> 23:24.410
And that means I would be able to connect to it.

23:24.870 --> 23:30.950
So this is me connecting to the app from outside.

23:30.950 --> 23:33.590
And doing quest.scripting.

23:33.590 --> 23:41.150
The next thing I did is I wanted to check if there was a way that I can do inject JavaScript, because I want to get remote code execution.

23:41.550 --> 23:49.270
Fortunately, the app only has one place to do user input, and that's the name of the run or snapshot.

23:49.390 --> 23:56.910
Again, fortunately for me, it was vulnerable to vanilla script, alert one script JavaScript.

23:56.910 --> 24:06.410
So when you start a run, you type the name of the run, script alert one script, and then you start it.

24:06.410 --> 24:10.890
At the bottom of the picture, you can see where it says status report for dot.

24:11.030 --> 24:16.270
The place before dot is where the script was injected, and the alert pops up.

24:17.370 --> 24:27.230
So this is in the web application from outside, but I want to run JavaScript code on the Electron app inside, and I got really lucky.

24:27.650 --> 24:49.750
Because when you go to the Electron GUI inside the app, and someone has already started a run from outside, the alert pops up, which is really interesting and really useful for us, because I can start a run from outside, and I can get a pop-up on a user inside.

24:50.090 --> 24:53.230
And the way to create a run is a simple GET request.

24:53.230 --> 24:59.490
And as you can see, it's a simple request, so it always goes through, which is really great again for me.

24:59.490 --> 25:04.330
So I started looking at it, and I was like, okay, so what can I do?

25:04.510 --> 25:06.450
How can I use this?

25:06.590 --> 25:09.430
So I created a payload and a proof of concept.

25:10.110 --> 25:17.530
I start the Electron app in the virtual machine, then I go to it from the virtual machine host from outside.

25:17.530 --> 25:24.290
I start a new run, I paste the payload, that pops calc, which is, again, a simple GET request.

25:24.450 --> 25:35.030
Now the run is completed, I go to the Electron app, and I click on scan, and the calc pops up, which is the payload that I injected into it.

25:35.030 --> 25:39.730
And now, remember, attack surface analyzer is running as admin.

25:39.730 --> 25:44.150
That means someone from outside can connect to your machine and get remote code execution.

25:45.010 --> 25:46.030
Nice, right?

25:46.030 --> 25:50.330
So I reported it to Microsoft.

25:50.330 --> 26:00.190
I did responsible disclosure, they fixed it, and then I did a write-up after they said something is fixed, and it gained a little bit of traction.

26:01.130 --> 26:13.350
But what happened is Taviso replied to the tweet and said, I hope they actually fixed the injection point, and not just the single null interfaces, because the browser can connect to it.

26:13.490 --> 26:19.450
And I was thinking and said, yeah, that is exactly it.

26:19.450 --> 26:33.250
So I created a web page that sends this GET request, which is basically a way to pop calc in Node.js, and I want to do another proof of concept and see what is up.

26:33.330 --> 26:40.250
So I created a web page with that payload, and then opened the web page in the browser on the virtual machine.

26:40.250 --> 26:44.230
To the right you have the browser, to the left you have the Electron GUI.

26:44.230 --> 26:49.330
I open it, and the browser says, oh, I can't see the response because there's no cores.

26:49.330 --> 26:51.070
It doesn't really matter, does it?

26:51.070 --> 26:55.830
The GET request has already gone through, the damage is done, the run has been started.

26:55.830 --> 27:01.390
And now you click on the Electron app and go to scan, and calc pops up.

27:01.390 --> 27:02.110
Yay!

27:02.150 --> 27:13.170
So if the injection hadn't been fixed, and only the listening on all interfaces had been fixed, then we would have had a problem.

27:13.170 --> 27:25.430
Imagine you're running a tag surface analyzer on a machine, running it as admin, you open a website, and that website runs code on your machine, literally jumping the browser sandbox and getting back to your machine.

27:26.070 --> 27:27.410
So really fun.

27:28.310 --> 27:31.210
One of the funnest bugs I have found.

27:31.390 --> 27:38.050
Fortunately, I found a different bug that was much better than this.

27:38.050 --> 27:42.190
Unfortunately, it hasn't been disclosed yet, so I cannot talk about it today.

27:42.370 --> 27:47.550
But life is full of disappointments anyway, so that's one on top of the other ones.

27:48.050 --> 27:52.610
As a product security engineer, I do a lot of remediation.

27:52.610 --> 27:58.250
We have talked a lot about bugs and pointing at things and saying, this is bad, this is bad, and this is bad.

27:58.910 --> 28:03.710
But half of my job is talking to developers and telling them how to fix things.

28:03.710 --> 28:07.890
Or better yet, how we can eliminate an entire class of bugs together.

28:09.010 --> 28:13.670
This picture is from a YouTube video from a game design college.

28:13.670 --> 28:15.310
This is pretty old.

28:15.310 --> 28:22.090
These two guys are playing video games, and the boss comes in and says, have you guys finished this game?

28:22.090 --> 28:24.510
I need another video game designed.

28:24.510 --> 28:30.310
This guy says, we just finished level 3, so we need to tighten up the graphics a little bit.

28:31.470 --> 28:33.930
I don't know, for some reason I love it.

28:33.930 --> 28:44.770
Every time someone asks me what I do at my job, I tell them that I write how to tighten up the graphics a little bit of level 3.

28:44.830 --> 28:46.230
So it's a great thing.

28:46.230 --> 28:52.710
It's from Westwood College, which has nothing to do with the Westwood studios who made the Command & Conquer applications.

28:52.750 --> 28:55.750
I'm sorry, Command & Conquer games, which are now part of EA.

28:56.190 --> 28:58.390
So what can help us?

28:58.670 --> 29:02.550
Our most trustworthy friend, in this case, is the browser.

29:02.990 --> 29:08.890
I talked about how the browser doesn't help us, but the browsers can help us through the origin header.

29:08.890 --> 29:13.150
So origin header is set by the browsers on every cross-origin request.

29:13.250 --> 29:16.210
Example.net to facebook.com, you have an origin header.

29:16.210 --> 29:19.490
Example.net to example.net, don't have an origin header.

29:19.490 --> 29:23.750
It's a forbidden header, so JavaScript in the browsers cannot change it.

29:24.290 --> 29:31.790
So if you're a local web server, you see a request that comes in, you do not process the request before checking the origin header.

29:31.790 --> 29:35.350
You have an allow list of headers that are good.

29:35.350 --> 29:36.290
You check.

29:36.290 --> 29:39.210
If it works, then you get to let the request go through.

29:39.210 --> 29:41.410
Do not rely on same-origin policy.

29:41.410 --> 29:45.950
We already know that the simple GET requests are not going to go through.

29:45.950 --> 29:48.450
Do not learn cross-origin resource sharing.

29:48.450 --> 29:50.330
We don't need to see the response.

29:50.330 --> 29:53.950
We sent a GET request, we got remote code execution.

29:54.430 --> 29:58.190
Check the origin header before processing the request.

29:58.290 --> 30:00.910
Same thing can help us with WebSockets.

30:00.910 --> 30:07.550
Again, with WebSockets, they are not bound by the same-origin policy, but the handshake was a GET request.

30:07.550 --> 30:14.250
So when you see a handshake in your WebSocket server, you do not process it, you do not respond.

30:14.250 --> 30:15.630
You check the origin header.

30:15.630 --> 30:20.070
If it's something that you want, then you send a correct response.

30:20.070 --> 30:26.370
If it's not, do something like what Logitech Hub did, return a 403, 404, or whatever.

30:26.370 --> 30:30.230
Anything that tells the browser that this request was not successful.

30:30.230 --> 30:35.530
That means the WebSocket is not going to get created.

30:35.870 --> 30:40.690
One thing that I've seen developers do that is not useful is checking the remote address.

30:40.690 --> 30:44.270
That's where the request is coming from.

30:44.270 --> 30:51.730
This works to some extent if you have something listening along interfaces and don't want local address, you only want local addresses.

30:51.730 --> 31:07.970
But that's not useful in browsers, because if a request is coming from your browser, the browser is running on your machine, the JavaScript is running in the browser, and as a result, the remote address of the request coming from the browser from a website,

31:07.970 --> 31:12.950
example.net, is actually local host because the browser is running on your machine.

31:13.770 --> 31:15.010
That's really useful.

31:15.170 --> 31:16.190
Don't do that.

31:16.750 --> 31:22.850
I know, it took a little bit of time to wrap my head around this, but I finally got it.

31:23.130 --> 31:25.990
It's a simple check, so check the origin header.

31:25.990 --> 31:31.870
With Electron, there's a lot of advice, but I'm going to give you some generic XSS advice.

31:31.870 --> 31:35.010
Don't trust user input because you don't want XSS.

31:35.690 --> 31:46.070
But more importantly, in order to eliminate an entire class of bugs, you set node integration to false, which is off by default.

31:46.070 --> 31:49.230
Don't set it to true if you don't absolutely need it.

31:49.350 --> 31:56.230
A lot of developers set it to true because the Electron app needs to run Node.js code in the back.

31:58.130 --> 32:01.370
And I don't really blame them because it's very convenient.

32:01.770 --> 32:07.510
But what you can do is you can run your Node.js code in preload.

32:07.510 --> 32:12.590
So preload is a script that gets loaded in the browser window before everything else.

32:12.590 --> 32:20.370
Even if you have set node integration to false, the JavaScript in the preload has access to the Node.js API.

32:20.370 --> 32:28.350
So that means that you can't run your own Node.js code and you can't have node integration set to false.

32:28.350 --> 32:34.190
Even if you have XSS in this case, you have XSS, which is really not great.

32:34.190 --> 32:37.650
But on the plus side, you won't have remote code execution.

32:37.710 --> 32:47.810
If you click on the link in the Electron.js website, they have a lot of useful information on how to prevent these attacks, how to do things properly.

32:47.810 --> 32:56.790
If you use a local web server to serve content to an Electron app, disable cores.

32:56.990 --> 33:06.370
So if you have a local web server, so there was this app I was looking at, a third-party app, and it was running a local web server system that had a front-end Electron.

33:06.370 --> 33:19.950
They had enabled cores on the web server, so basically access control allow origin was star, which is not really great, because that means any browser could talk to the web server and grab the results.

33:19.950 --> 33:26.410
There was no sort of checking the path, so any website could read all files on your machine.

33:26.410 --> 33:32.170
And the server was running a system, which means that it could read everything, and that's not really great.

33:32.170 --> 33:33.890
That's not something you want to do.

33:33.890 --> 33:40.370
So disable cores, that means you are not leaking information to websites when they talk to it.

33:40.370 --> 33:44.390
And last but not least, you want to add browsers to your thread models.

33:45.250 --> 33:47.030
So this is Crypto.

33:47.030 --> 33:52.630
He's a hacker character in Apex Legends, the video game.

33:54.350 --> 34:01.910
Crypto doesn't need to be in an internet cafe somewhere and directly connected to a machine to be enabled as a hacker machine.

34:02.290 --> 34:19.830
If you have one of these servers on your machine, and you go to a website where Crypto controls, or if Crypto has injected JavaScript into, and he might get remote code execution on your machine, and as a result, he's now listening to what you are saying on the machine,

34:19.830 --> 34:22.410
listening to a Discord conversation, so on and so forth.

34:22.410 --> 34:23.770
So don't do that.

34:23.770 --> 34:31.270
If you have a local server, think browsers can connect to it and add them to a thread model, have your proper checks.

34:31.990 --> 34:37.350
As I said, checks are really simple and we can defeat it and we'll be fine.

34:37.350 --> 34:48.950
So I've talked a lot about how to find things, how to fix things, but your next question is, how do I get started in this niche?

34:49.370 --> 34:52.170
Practice is the best thing.

34:52.170 --> 34:59.050
Start a virtual machine, install a bunch of these client apps, run Headstat, see what servers you have.

34:59.050 --> 35:09.930
Start poking at those servers, look at the cores, look at the APIs they expose.

35:10.330 --> 35:15.350
The peripheral utility apps are really great candidates.

35:15.350 --> 35:23.970
If you have a mouse that comes with a utility to control it, they are usually good candidates.

35:24.090 --> 35:28.610
Or you can go to that link on Electron.js website, which has all the Electron apps.

35:28.610 --> 35:31.430
Electron apps are usually to have the same thing.

35:31.430 --> 35:43.830
If you want to learn more about hacking Electron, there is a GitHub repository with a bunch of links , a lot of useful information, a lot of great research, a lot of great books.

35:43.990 --> 35:46.690
And last but not least, read Taviso books.

35:47.190 --> 35:56.190
The awesome book that I told you about that hasn't been disclosed, it was two Taviso books mixed together.

35:56.190 --> 35:59.890
So I combined two of them and it worked.

36:00.130 --> 36:02.330
So that was great.

36:03.510 --> 36:07.050
And finally, thanks for giving me your time.

36:07.110 --> 36:12.350
Because this is recorded, so I can't answer your questions on the fly in this presentation.

36:12.350 --> 36:17.910
What's going to happen is I'm going to be on the Discord and I will answer your questions there and then.

36:17.910 --> 36:29.590
To find more about me or if you want to ask questions, you can contact me on those social media links, Twitter or my website or on GitHub.

36:29.610 --> 36:32.970
If you have any questions, I'll be happy to answer.

36:32.990 --> 36:39.010
Again, thanks for listening to my presentation and giving me your time.

36:39.090 --> 36:42.650
And fingers crossed, 2020 won't get worse than this.

36:42.650 --> 36:44.110
We can get through this.

36:44.110 --> 36:45.610
Have a great day.

