[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:30.050] Out there you can find this year's t-shirt, which is incredible. This is last year's t-shirt. [00:30.050 --> 00:35.170] This year's has got more color, it's got an awesome design. I just got mine in the mail a couple of days ago. [00:35.350 --> 00:41.750] Check it out. It's a great way to support AppSecVillage and make sure that we can bring you the same kind of content [00:41.750 --> 00:47.750] 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:56.750] And now for our next talk. 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:34.050] Hello everyone. 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:54.550] My name is Parsia. I am a security engineer at Electronic Arts. [01:54.730 --> 01:59.890] Mostly work with video games. 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:23.770] This is my second time at DEF CON. 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:09.630] I mean, all of these have them. 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:23.930] Sometimes you have a Windows service running a system. 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:07.270] Seamless interaction. Great for user experience. [05:07.590 --> 05:09.590] Dropbox also does this. [05:09.590 --> 05:15.230] If you have the Dropbox desktop application on your machine and you go to the web interface, [05:15.230 --> 05:18.990] 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:39.510] Great again. Great user experience. [05:39.510 --> 05:43.630] But is this really secure? 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:36.010] Should they lock your account? 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:51.170] He says, if you have an app and it handles files, [07:51.750 --> 07:55.170] 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:34.470] So if I open example.net and send a POST request to Facebook to change something, [09:34.470 --> 09:37.950] 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:56.130] But SOP also has this problem that just because the browser doesn't let you see the response to the request, [09:56.130 --> 09:58.890] 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:27.510] So one of the tricks that we usually use when bypassing this, [10:27.510 --> 10:30.630] if you have an application slash JSON request, [10:30.630 --> 10:33.250] you change the content type to text slash plain, [10:33.250 --> 10:35.790] 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:54.210] He installs Trend Micro Antivirus, [10:54.210 --> 10:57.270] and that antivirus has a password manager. [10:57.390 --> 10:59.790] So the way password managers usually work [10:59.790 --> 11:02.550] is that you have an extension in the browser, [11:02.550 --> 11:05.290] and you have a local web server, a WebSocket server. [11:05.290 --> 11:10.170] The local server is responsible for storing the passwords, [11:10.170 --> 11:12.490] updating, and a bunch of those. [11:12.490 --> 11:14.510] The extension in the browser, [11:14.510 --> 11:16.550] when, for example, you go to facebook.com, [11:16.550 --> 11:19.890] the extension in the browser talks to the web server and says, [11:19.890 --> 11:22.530] 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:32.430] In the case of Trend Micro, [11:32.430 --> 11:35.730] the local web server was unauthenticated, [11:35.730 --> 11:38.370] and you could basically do remote code execution [11:38.370 --> 11:42.610] with a simple GET request, as you can see on this slide. [11:42.830 --> 11:47.910] You could say, OK, run this URL in the default browser, [11:47.910 --> 11:50.870] which in this case opens up the calc, [11:50.870 --> 11:54.430] runs the calc manually instead of opening it in a browser. [11:54.830 --> 11:57.990] If you go and read the bug from the URL, [11:57.990 --> 12:00.350] from the link in this slide, [12:00.350 --> 12:02.770] you can see that Tavisor says, [12:02.770 --> 12:04.730] yeah, we can see the response, [12:04.730 --> 12:07.030] but the GET request goes through [12:07.030 --> 12:08.910] 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:25.810] In a typical HTTP request, [12:25.810 --> 12:27.950] you create a connection to a server, [12:27.950 --> 12:30.590] you send a request, get a response back, [12:30.590 --> 12:32.250] and then you close the connection. [12:32.250 --> 12:36.910] In a WebSocket, you create a WebSocket [12:36.910 --> 12:38.850] 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:43.270] It's great for real-time data things, [12:43.270 --> 12:45.230] real-time data updates, [12:45.230 --> 12:47.790] like, you know, chats and video games [12:48.430 --> 12:51.330] 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 --> 12:59.810] It starts with a GET request [12:59.810 --> 13:02.090] that is a normal handshake. [13:02.410 --> 13:04.530] So the GET request is your typical GET request [13:04.530 --> 13:06.070] with some special headers. [13:06.390 --> 13:08.990] Now, remember, the GET request for a WebSocket [13:08.990 --> 13:13.010] is a simple request, so it always goes through. [13:13.050 --> 13:14.550] On the response side, [13:14.550 --> 13:16.790] the other side basically says, [13:16.790 --> 13:18.870] 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:25.190] One mistake that developers usually make [13:25.190 --> 13:28.070] is that they think that SEC WebSocket key [13:28.990 --> 13:30.110] in the request [13:30.110 --> 13:33.050] and the WebSocket ACCEPT key in the response [13:33.050 --> 13:35.010] are based on security. [13:35.110 --> 13:36.150] They're not. [13:36.310 --> 13:38.990] You can usually put something, anything in there [13:38.990 --> 13:40.390] 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:49.690] It's always there. It goes through. [13:49.690 --> 13:51.030] It doesn't really matter. [13:51.030 --> 13:53.070] And if you can see the response, you can see that [13:53.070 --> 13:56.490] there's nothing really needed there [13:56.490 --> 13:59.050] apart from how we can make a connection. [13:59.110 --> 14:00.850] And as a result, [14:00.850 --> 14:04.290] the browsers are not bound by the same-origin policy [14:05.090 --> 14:06.930] because there's nothing in the response [14:07.420 --> 14:09.450] that the browser doesn't already know. [14:10.070 --> 14:11.830] So if you send a GET request [14:12.370 --> 14:14.250] and there's no cores, [14:14.250 --> 14:15.490] you can't see the response, [14:15.490 --> 14:17.950] but the browser makes the connection for you anyway. [14:18.150 --> 14:20.510] So if you have a local WebSocket server, [14:20.510 --> 14:22.510] 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:39.630] It was a Logitech mouse, [14:39.630 --> 14:42.030] so he installs an app called Logitech Options. [14:42.490 --> 14:45.070] Logitech Options runs a local WebSocket server, [14:45.070 --> 14:47.530] some port 10134. [14:48.030 --> 14:51.070] As I said, WebSockets are not bound by the SOP, [14:51.070 --> 14:53.510] and the WebSocket server didn't have any checks. [14:53.530 --> 14:55.110] The only authentication it had [14:55.110 --> 14:57.010] was when you sent a message to it, [14:57.010 --> 15:01.130] 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:08.430] And you can brute force them quite easily in a few minutes [15:08.430 --> 15:10.990] until you find one that works for you. [15:11.270 --> 15:13.610] Fortunately for Logitech Options, [15:13.610 --> 15:16.110] you couldn't get remote code execution, [15:16.110 --> 15:18.170] you could create crashes. [15:18.730 --> 15:21.610] So imagine you have this app running on your machine, [15:21.610 --> 15:24.050] 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:30.550] That's not really useful, [15:30.550 --> 15:33.910] and that makes your experience really bad. [15:33.910 --> 15:37.010] On the plus side, you couldn't get remote code execution, [15:37.010 --> 15:38.630] so that's really great. [15:38.630 --> 15:41.310] The next iteration of the app, similar app, [15:41.310 --> 15:42.650] called Logitech Hub. [15:42.650 --> 15:44.650] It runs two local WebSocket servers, [15:44.650 --> 15:47.470] on port 9010 and 9100. [15:48.590 --> 15:52.430] Now, this iteration checks the origin header, [15:52.430 --> 15:53.650] which is really great. [15:53.650 --> 15:57.230] The origin header is a forbidden header, [15:57.230 --> 16:00.090] which means the JavaScript in the app cannot set it, [16:00.090 --> 16:01.710] only the browser can. [16:01.710 --> 16:02.970] There are other forbidden headers, [16:02.970 --> 16:04.750] like the host header, for example. [16:05.730 --> 16:08.050] And the origin header is always set [16:08.050 --> 16:10.830] by the browser for every cross-origin request. [16:10.830 --> 16:13.950] A request goes from one origin to a different origin, [16:13.950 --> 16:15.250] the browser sets the origin header [16:15.250 --> 16:17.550] to tell the server on the other side [16:17.550 --> 16:19.730] where this request comes from. [16:19.890 --> 16:22.810] So what Logitech Hub does in the WebSocket servers [16:22.810 --> 16:24.690] is if you send a request with an origin [16:24.690 --> 16:26.770] that is not part of their allow list, [16:26.770 --> 16:29.970] then they just say, we can't connect. [16:30.030 --> 16:31.990] And when the browser sees a response like this, [16:31.990 --> 16:34.370] which is not a 200 OK response, [16:34.370 --> 16:37.070] it says, well, I can't create a WebSocket connection. [16:37.230 --> 16:40.830] So websites cannot talk to Logitech Hub WebSockets, [16:40.830 --> 16:42.490] so this is a great thing, [16:42.490 --> 16:45.730] and this is a good thing that Logitech has done. [16:46.170 --> 16:49.790] We've talked about local WebSockets servers, [16:49.790 --> 16:51.350] but we also want to talk about [16:51.350 --> 16:56.190] how frameworks can help us get remote code execution. [16:56.190 --> 16:57.770] And I'm going to talk about one of them, [16:57.770 --> 16:59.130] which is called Electron. [16:59.130 --> 17:01.870] Electron is probably the most popular [17:04.170 --> 17:08.170] desktop application framework out there. [17:08.170 --> 17:10.110] It is based on Chromium. [17:10.110 --> 17:12.990] Chromium is the open source version, [17:12.990 --> 17:16.490] I'm sorry, the open source base for a bunch of browsers [17:16.490 --> 17:19.990] 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:25.970] So if you open Visual Studio Code, [17:25.970 --> 17:28.010] 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:40.830] And these apps that you see on the slide, [17:40.830 --> 17:43.610] 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:52.410] The problem with Electron apps is that [17:52.410 --> 17:55.870] if you get a cross-site scripting, [17:55.870 --> 17:58.650] it might lead to remote code execution. [17:58.870 --> 18:01.950] So in an Electron app, you can write Node.js code [18:01.950 --> 18:05.550] that is run in the browser and can do stuff. [18:05.830 --> 18:08.370] The way for this Node.js code to run is [18:10.550 --> 18:12.630] you want this Node.js code to run, [18:12.630 --> 18:14.070] so you flip a switch. [18:14.070 --> 18:15.830] The switch is called node integration, [18:15.830 --> 18:18.950] which is off by default for a good reason. [18:19.150 --> 18:21.790] So if you set it to true, [18:21.790 --> 18:25.790] the JavaScript in your browser window in the Electron app [18:25.790 --> 18:28.070] can now talk to the Node.js APIs [18:28.070 --> 18:33.350] and, for example, spawn processes on your machine. [18:33.590 --> 18:35.970] And as a result, if you have this switch set to true [18:35.970 --> 18:38.050] and you get cross-site scripting, [18:38.050 --> 18:40.070] now you have remote code execution, [18:40.070 --> 18:41.130] which is really bad. [18:41.130 --> 18:42.650] If you have an open redirect, [18:42.650 --> 18:44.670] which means that you can click on a link [18:44.670 --> 18:46.430] and the browser goes to a different link, [18:46.430 --> 18:48.370] or you can do something like that. [18:48.370 --> 18:52.850] You can embed remote code execution payloads [18:52.850 --> 18:55.090] on your website that you control, [18:55.090 --> 18:56.630] and then you have remote code execution [18:56.630 --> 19:00.770] on someone's machine through an Electron app. [19:00.770 --> 19:03.790] This is by default set to off, [19:04.370 --> 19:07.290] 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:13.650] It's a remote code execution in a Tagged Surface Analyzer, [19:13.650 --> 19:16.690] which is an open-source Microsoft application. [19:16.710 --> 19:18.410] And we're going to talk about version two of it [19:18.410 --> 19:21.310] because it has two versions. [19:21.490 --> 19:24.210] When the second version was released, [19:24.210 --> 19:26.370] our CISO, who was one of the people [19:26.370 --> 19:28.330] who created the original app, said, [19:28.330 --> 19:31.450] oh, I worked on the original app, [19:31.450 --> 19:34.470] 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:42.490] What you can do is you can create runs, [19:42.490 --> 19:44.470] which are basically snapshots. [19:44.630 --> 19:48.650] So you can tell a Tagged Surface Analyzer [19:48.650 --> 19:52.350] to create a snapshot before you install an application [19:52.350 --> 19:55.390] on your machine, and then you install the application, [19:55.390 --> 19:58.190] and then you create a snapshot or run [19:58.190 --> 20:00.850] after you install the application. [20:00.850 --> 20:03.950] And now you can compare these two. [20:03.950 --> 20:07.450] And you can see what files were added, [20:07.450 --> 20:10.830] what registry keys were added, if there were any open ports, [20:10.830 --> 20:13.090] 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:29.330] In fact, if you don't run it as admin, [20:29.330 --> 20:31.910] 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:34.970] Because if you're not running as admin, [20:34.970 --> 20:38.190] 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:47.910] The GUI is based on electron.net, [20:47.910 --> 20:50.410] which is, again, another open source project, [20:50.410 --> 20:54.130] which is basically electron, but for .net. [20:55.930 --> 20:58.170] Which is... I mean, it works, right? [20:59.170 --> 21:01.670] So after I created the... I'm sorry, [21:01.670 --> 21:04.670] after I installed the app and ran it for the first time, [21:04.670 --> 21:06.190] I saw this pop-up. [21:06.190 --> 21:09.690] And this is a Windows firewall pop-up that says, [21:09.690 --> 21:12.510] oh, this app wants to listen on all interfaces [21:12.510 --> 21:14.430] and open ports in the firewall. [21:14.530 --> 21:17.270] And I was wondering, why would a local application, [21:17.370 --> 21:19.890] a tag surface analyzer, want to do that? [21:19.890 --> 21:22.090] So I looked at the console logs for the app, [21:22.090 --> 21:25.670] and I saw that, yeah, it is listening on all interfaces, [21:25.670 --> 21:28.870] 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:35.790] I mean, this was the cue to tell me that [21:35.790 --> 21:38.810] 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:48.690] I'm sorry, on the machine that is running the tag surface analyzer app, [21:48.690 --> 21:49.890] and I see the GUI. [21:49.890 --> 21:53.310] So the way the app works is it has an Electron frontend [21:53.310 --> 21:55.530] and a web server in the back. [21:55.530 --> 21:58.610] Electron frontend just opens this website, [21:58.610 --> 22:01.470] similar to what is in the browser, as you can see, [22:01.470 --> 22:04.050] and it does REST, [22:04.050 --> 22:08.790] which is, I guess, normal for Electron applications. [22:08.790 --> 22:12.390] Next thing I did, I tried to connect to it from outside, [22:12.390 --> 22:16.190] 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:40.930] I went and saw it's because the web server that is serving content is a Kestrel web server, [22:40.930 --> 22:43.210] 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:01.670] But here's the thing, because we are connecting from outside, [23:01.670 --> 23:05.590] and we are not bound by being in a browser on the machine, [23:05.590 --> 23:10.070] I can change the host header because I can create a tool that talks to this [23:10.070 --> 23:11.470] and changes the host header. [23:11.470 --> 23:16.870] To do this, to simulate this, I added a match-replace ruling verb [23:16.870 --> 23:21.130] 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:37.630] The next thing I did is I wanted to check if there was a way that I can do [23:37.630 --> 23:41.150] inject JavaScript, because I want to get remote code execution. [23:41.550 --> 23:46.570] Fortunately, the app only has one place to do user input, [23:46.570 --> 23:49.270] and that's the name of the run or snapshot. [23:49.390 --> 23:54.470] Again, fortunately for me, it was vulnerable to vanilla script, [23:54.470 --> 23:56.910] alert one script JavaScript. [23:56.910 --> 24:02.170] So when you start a run, you type the name of the run, [24:02.170 --> 24:06.410] script alert one script, and then you start it. [24:06.410 --> 24:08.830] At the bottom of the picture, you can see where it says [24:08.830 --> 24:10.890] status report for dot. [24:11.030 --> 24:14.490] The place before dot is where the script was injected, [24:14.490 --> 24:16.270] and the alert pops up. [24:17.370 --> 24:20.950] So this is in the web application from outside, [24:20.950 --> 24:25.290] but I want to run JavaScript code on the Electron app inside, [24:25.290 --> 24:27.230] and I got really lucky. [24:27.650 --> 24:34.830] Because when you go to the Electron GUI inside the app, [24:34.830 --> 24:37.470] and someone has already started a run from outside, [24:37.930 --> 24:42.470] the alert pops up, which is really interesting [24:42.470 --> 24:46.490] and really useful for us, because I can start a run from outside, [24:46.490 --> 24:49.750] 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:56.890] And as you can see, it's a simple request, so it always goes through, [24:56.890 --> 24:59.490] which is really great again for me. [24:59.490 --> 25:02.470] So I started looking at it, and I was like, okay, [25:02.470 --> 25:06.450] so what can I do? 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:13.830] I start the Electron app in the virtual machine, [25:13.830 --> 25:17.530] then I go to it from the virtual machine host from outside. [25:17.530 --> 25:22.150] I start a new run, I paste the payload, that pops calc, [25:22.150 --> 25:24.290] which is, again, a simple GET request. [25:24.450 --> 25:27.730] Now the run is completed, I go to the Electron app, [25:27.730 --> 25:31.610] and I click on scan, and the calc pops up, [25:31.610 --> 25:35.030] 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:42.110] That means someone from outside can connect to your machine [25:42.110 --> 25:44.150] and get remote code execution. [25:45.010 --> 25:50.330] Nice, right? So I reported it to Microsoft. [25:50.330 --> 25:54.070] I did responsible disclosure, they fixed it, [25:54.070 --> 25:58.050] and then I did a write-up after they said something is fixed, [25:58.050 --> 26:00.190] and it gained a little bit of traction. [26:01.130 --> 26:04.890] But what happened is Taviso replied to the tweet and said, [26:04.890 --> 26:08.630] I hope they actually fixed the injection point, [26:08.630 --> 26:10.790] and not just the single null interfaces, [26:10.790 --> 26:13.350] 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:23.670] So I created a web page that sends this GET request, [26:23.670 --> 26:29.010] which is basically a way to pop calc in Node.js, [26:29.010 --> 26:33.250] and I want to do another proof of concept and see what is up. [26:33.330 --> 26:36.430] So I created a web page with that payload, [26:36.430 --> 26:40.250] 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:47.570] I open it, and the browser says, oh, I can't see the response [26:47.570 --> 26:51.070] because there's no cores. It doesn't really matter, does it? [26:51.070 --> 26:53.950] The GET request has already gone through, the damage is done, [26:53.950 --> 26:55.830] the run has been started. [26:55.830 --> 26:59.750] And now you click on the Electron app and go to scan, [27:00.130 --> 27:02.110] and calc pops up. Yay! [27:02.150 --> 27:05.290] So if the injection hadn't been fixed, [27:05.290 --> 27:11.050] and only the listening on all interfaces had been fixed, [27:11.050 --> 27:13.170] then we would have had a problem. [27:13.170 --> 27:16.510] Imagine you're running a tag surface analyzer on a machine, [27:16.510 --> 27:19.170] running it as admin, you open a website, [27:19.170 --> 27:20.970] and that website runs code on your machine, [27:20.970 --> 27:25.430] 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:40.190] Unfortunately, it hasn't been disclosed yet, [27:40.190 --> 27:42.190] so I cannot talk about it today. [27:42.370 --> 27:44.870] But life is full of disappointments anyway, [27:44.870 --> 27:47.550] 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:55.950] We have talked a lot about bugs and pointing at things and saying, [27:55.950 --> 27:58.250] 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:18.250] These two guys are playing video games, [28:18.250 --> 28:20.410] and the boss comes in and says, [28:20.410 --> 28:24.510] have you guys finished this game? I need another video game designed. [28:24.510 --> 28:27.410] This guy says, we just finished level 3, [28:27.410 --> 28:30.310] 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:37.670] Every time someone asks me what I do at my job, [28:37.670 --> 28:44.770] 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:49.670] It's from Westwood College, which has nothing to do with the Westwood studios [28:50.230 --> 28:52.710] 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:05.690] I talked about how the browser doesn't help us, [29:05.690 --> 29:08.890] 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:28.410] So if you're a local web server, you see a request that comes in, [29:28.410 --> 29:31.790] 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:39.210] You check. 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:04.090] Again, with WebSockets, they are not bound by the same-origin policy, [30:04.090 --> 30:07.550] but the handshake was a GET request. [30:07.550 --> 30:11.790] So when you see a handshake in your WebSocket server, [30:11.790 --> 30:14.250] you do not process it, you do not respond. [30:14.250 --> 30:17.210] You check the origin header. If it's something that you want, [30:17.650 --> 30:20.070] then you send a correct response. [30:20.070 --> 30:23.810] If it's not, do something like what Logitech Hub did, [30:23.810 --> 30:26.370] 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:38.830] One thing that I've seen developers do that is not useful [30:38.830 --> 30:40.690] is checking the remote address. [30:40.690 --> 30:44.270] That's where the request is coming from. [30:44.270 --> 30:48.090] This works to some extent if you have something listening along interfaces [30:48.090 --> 30:51.730] and don't want local address, you only want local addresses. [30:51.730 --> 30:54.490] But that's not useful in browsers, [30:54.490 --> 30:57.230] because if a request is coming from your browser, [30:57.230 --> 30:59.250] the browser is running on your machine, [30:59.250 --> 31:02.930] the JavaScript is running in the browser, [31:02.930 --> 31:05.890] and as a result, the remote address of the request [31:05.890 --> 31:08.990] coming from the browser from a website, example.net, [31:08.990 --> 31:12.950] is actually local host because the browser is running on your machine. [31:13.770 --> 31:16.190] That's really useful. Don't do that. [31:16.750 --> 31:21.150] I know, it took a little bit of time to wrap my head around this, [31:21.150 --> 31:22.850] 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:29.130] With Electron, there's a lot of advice, [31:29.130 --> 31:31.870] 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:42.230] But more importantly, in order to eliminate an entire class of bugs, [31:42.230 --> 31:46.070] 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:51.130] A lot of developers set it to true [31:51.130 --> 31:56.230] 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:10.670] So preload is a script that gets loaded in the browser window [32:10.670 --> 32:12.590] before everything else. [32:12.590 --> 32:16.130] Even if you have set node integration to false, [32:16.910 --> 32:20.370] the JavaScript in the preload has access to the Node.js API. [32:20.370 --> 32:24.470] So that means that you can't run your own Node.js code [32:24.470 --> 32:28.350] and you can't have node integration set to false. [32:28.350 --> 32:30.970] Even if you have XSS in this case, [32:30.970 --> 32:34.190] 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:41.430] If you click on the link in the Electron.js website, [32:41.430 --> 32:45.570] they have a lot of useful information on how to prevent these attacks, [32:45.570 --> 32:47.810] how to do things properly. [32:47.810 --> 32:49.510] If you use a local web server [32:49.510 --> 32:54.850] to serve content to an Electron app, [32:54.850 --> 32:56.790] disable cores. [32:56.990 --> 32:58.490] So if you have a local web server, [32:58.490 --> 33:01.670] so there was this app I was looking at, a third-party app, [33:01.670 --> 33:03.890] and it was running a local web server system [33:03.890 --> 33:06.370] that had a front-end Electron. [33:06.370 --> 33:10.530] They had enabled cores on the web server, [33:10.530 --> 33:14.470] so basically access control allow origin was star, [33:14.470 --> 33:16.990] which is not really great, because that means any browser [33:16.990 --> 33:19.950] could talk to the web server and grab the results. [33:19.950 --> 33:22.970] There was no sort of checking the path, [33:22.970 --> 33:26.410] so any website could read all files on your machine. [33:26.410 --> 33:28.190] And the server was running a system, [33:28.190 --> 33:30.590] which means that it could read everything, [33:30.590 --> 33:33.890] and that's not really great. That's not something you want to do. [33:33.890 --> 33:37.930] So disable cores, that means you are not leaking information [33:37.930 --> 33:40.370] 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:49.370] He's a hacker character [33:50.370 --> 33:52.630] in Apex Legends, the video game. [33:54.350 --> 33:57.050] Crypto doesn't need to be in an internet cafe somewhere [33:57.050 --> 33:58.910] and directly connected to a machine [33:58.910 --> 34:01.910] to be enabled as a hacker machine. [34:02.290 --> 34:05.210] If you have one of these servers on your machine, [34:05.210 --> 34:09.050] and you go to a website where Crypto controls, [34:09.050 --> 34:12.370] or if Crypto has injected JavaScript into, [34:12.370 --> 34:15.030] and he might get remote code execution on your machine, [34:15.030 --> 34:18.170] and as a result, he's now listening to what you are [34:18.170 --> 34:21.470] saying on the machine, listening to a Discord conversation, [34:21.470 --> 34:23.770] so on and so forth. So don't do that. [34:23.770 --> 34:27.230] If you have a local server, think browsers can [34:27.230 --> 34:29.630] connect to it and add them to a thread model, [34:29.630 --> 34:31.270] have your proper checks. [34:31.990 --> 34:35.850] As I said, checks are really simple and we can defeat it [34:35.850 --> 34:38.570] and we'll be fine. So I've talked a lot about [34:38.570 --> 34:42.210] how to find things, [34:42.210 --> 34:44.670] how to fix things, but your [34:44.670 --> 34:47.770] next question is, how do I get started in this [34:47.770 --> 34:50.530] niche? Practice is the [34:50.530 --> 34:53.850] best thing. Start a virtual machine, [34:54.410 --> 34:57.450] install a bunch of these client apps, run Headstat, [34:57.450 --> 35:00.910] see what servers you have. Start poking at those servers, [35:00.910 --> 35:02.770] look at the cores, look at the [35:05.750 --> 35:06.870] APIs they [35:08.810 --> 35:09.930] expose. [35:10.330 --> 35:13.430] The peripheral utility apps [35:13.430 --> 35:16.630] are really great candidates. If you have a mouse that comes [35:16.630 --> 35:17.930] with a utility to [35:20.470 --> 35:22.730] control it, they are usually good [35:22.730 --> 35:25.790] candidates. Or you can go to that link on [35:25.790 --> 35:28.610] 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:36.350] If you want to learn more about hacking Electron, there is a [35:36.350 --> 35:38.230] GitHub repository with a bunch of [35:38.230 --> 35:41.310] links, a lot of useful information, a lot of [35:41.310 --> 35:44.110] great research, a lot of great books. [35:44.110 --> 35:47.670] And last but not least, read Taviso books. [35:47.670 --> 35:49.990] The awesome book that I told you about that hasn't [35:49.990 --> 35:52.430] been disclosed, it was [35:53.530 --> 35:56.410] two Taviso books mixed together. [35:56.410 --> 35:59.030] So I combined two of them and it [35:59.030 --> 36:02.330] worked. So that was great. [36:03.510 --> 36:05.870] And finally, thanks for giving [36:05.870 --> 36:09.010] me your time. Because this is recorded, so I can't [36:09.010 --> 36:12.350] answer your questions on the fly in this presentation. [36:12.350 --> 36:14.530] What's going to happen is I'm going to be on the Discord [36:14.530 --> 36:17.910] and I will answer your questions there and then. [36:17.910 --> 36:21.330] To find more about me or if you want to ask questions, [36:21.330 --> 36:23.530] you can contact me on those social [36:23.530 --> 36:26.650] media links, Twitter [36:26.650 --> 36:29.590] 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:35.950] Again, thanks for listening to [36:35.950 --> 36:39.010] my presentation and giving me your time. [36:39.090 --> 36:41.790] And fingers crossed, 2020 won't get worse [36:41.790 --> 36:45.610] than this. We can get through this. Have a great day.