1 00:00:02,460 --> 00:00:10,660 Thank you. Well, this is more people than I expected actually. Uh, thank you for coming 2 00:00:10,660 --> 00:00:16,100 to my talk. It's all, it's very great to see you all. I'm very excited to present my 3 00:00:16,100 --> 00:00:22,080 research. Your clocks have ears. Timing based browser based local network port scanner. 4 00:00:25,580 --> 00:00:32,700 Before we begin, let me introduce myself. My name is Donnie Kim. Uh, I'm a security, IT 5 00:00:32,700 --> 00:00:39,740 security expert at security office. We are based in Sweden and South Korea and we are part of the 6 00:00:39,740 --> 00:00:46,480 Trusik group. If you have any questions or comments, feel free to reach out and feel free to 7 00:00:46,480 --> 00:00:52,060 leave a comment on, uh, over Twitter and or X on Twitter. Uh, I'm a security expert and I'm 8 00:00:52,080 --> 00:00:56,560 a security expert or whatever is going to be called in the next few hours. 9 00:01:02,550 --> 00:01:10,360 In May 2020, it was revealed that eBay and other prominent companies were port scanning their 10 00:01:10,360 --> 00:01:16,940 visitors' computers via their websites. The culprit behind the whole saga was called Threat 11 00:01:16,940 --> 00:01:22,060 Metrics, a firm which pried, prides itself on tracking one-to-one, one-to-one security 12 00:01:22,080 --> 00:01:32,680 services for 1.4 billion users online and whose tool suite included port scanning. The 13 00:01:33,140 --> 00:01:40,280 implications of browser based port scanning is two-fold. One is privacy. It can be used to 14 00:01:40,280 --> 00:01:47,600 fingerprint visitors, tracking them with characteristics unique to each user, browser, and 15 00:01:47,600 --> 00:01:52,060 hardware set up. The other is security. It can be used to track the user's computer and the user's 16 00:01:52,080 --> 00:01:57,380 and that can be used to uncover Internet services, which are a great foothold for 17 00:01:57,380 --> 00:02:02,300 performing subsequent attacks like access tests or CSRF. 18 00:02:03,820 --> 00:02:21,960 Various techniques have been circulating for some time. The earliest research I found goes back to 2006, which utilized the image and iFrame tags. Later research added the script tag, and newer exploits employed. 19 00:02:22,080 --> 00:02:29,980 WebRTC and WebSocket to achieve comparable results. Browser vendors have implemented 20 00:02:29,980 --> 00:02:34,220 mitigations, making the mentioned techniques more or less ineffective. 21 00:02:40,360 --> 00:02:46,820 In this presentation, I'll put my focus on timing-based techniques for browser-based 22 00:02:46,820 --> 00:02:54,120 port scanning. Before we get into the specifics, let's take a look at how the fetch API is 23 00:02:54,120 --> 00:03:01,000 employed in measuring the timing of a network request. You can see from the function at 24 00:03:01,000 --> 00:03:09,960 line 3, we set up a timer. At line 5, we measure the time. At line 7, we start the fetch. At 25 00:03:09,960 --> 00:03:16,540 line 13, we measure the time again. Finally, the elapsed time in microseconds 26 00:03:16,540 --> 00:03:25,780 is returned at line 17. What we can observe using this function is only the elapsed time 27 00:03:25,780 --> 00:03:31,460 of a fetch request due to the restrictions imposed by browsers and web specifications. 28 00:03:32,420 --> 00:03:40,100 We cannot observe any other metadata, such as any of the response data, including TCP, 29 00:03:40,500 --> 00:03:46,520 TLS, HTTP information, any of the request data. 30 00:03:46,540 --> 00:03:56,480 Except for the scheme, IP, port, plus any of the error data, except for the generic type 31 00:03:56,480 --> 00:04:09,000 error, failed to fetch error string. Now, we can imagine at least four components that are 32 00:04:09,000 --> 00:04:16,520 each responsible for a part of a round trip time of a network request. Browser, IP, and the 33 00:04:16,520 --> 00:04:20,220 respond data. The query is generated by a server, firewall, TCP, and TLS, plus HTTP. 34 00:04:21,260 --> 00:04:28,620 Then, we can think of three possible states of a port and hypothesize which components would take 35 00:04:28,620 --> 00:04:38,440 up the observed round trip time. Firstly, if the port is closed and the firewall drops packets, 36 00:04:38,700 --> 00:04:46,260 or the host is unreachable, the observed time would be theoretically infinite. But typically, 37 00:04:46,360 --> 00:04:46,500 this is the time to be observed. Therefore, if the rocket has a target, or the host has outbound 38 00:04:46,500 --> 00:04:48,720 an arbitrary timeout would be enforced. 39 00:04:50,260 --> 00:04:52,740 Secondly, if the port is closed 40 00:04:53,120 --> 00:04:55,320 and the firewall rejects packets, 41 00:04:55,800 --> 00:04:57,960 the browser and the firewall 42 00:04:57,960 --> 00:05:00,180 would take up the observed time. 43 00:05:01,800 --> 00:05:05,920 Finally, if the port is open and the process is listening, 44 00:05:06,340 --> 00:05:09,420 the browser, the firewall, and the TCP, 45 00:05:09,760 --> 00:05:14,300 and the TLS plus HATP would take up the observed time. 46 00:05:15,260 --> 00:05:17,160 Looking at the hypotheses, 47 00:05:17,740 --> 00:05:21,820 we can expect distinct timing differences 48 00:05:21,820 --> 00:05:24,880 depending on the state of a port. 49 00:05:29,720 --> 00:05:31,180 Equipped with this knowledge, 50 00:05:31,440 --> 00:05:34,640 let's move on to the actual timing-based techniques. 51 00:05:35,620 --> 00:05:38,620 We'll try finding open ports on the local host, 52 00:05:39,000 --> 00:05:41,280 then we'll try finding the router, 53 00:05:41,560 --> 00:05:44,220 and finally, we'll try finding 54 00:05:44,220 --> 00:05:47,320 open ports on all of the LAN clients. 55 00:05:53,880 --> 00:05:57,260 First, finding open ports on the local host. 56 00:05:57,720 --> 00:06:01,780 Now, there are two things to note about local host. 57 00:06:02,720 --> 00:06:06,000 One, the firewall always rejects packets 58 00:06:06,000 --> 00:06:07,540 when the port is closed. 59 00:06:07,860 --> 00:06:11,060 And two, the host is always reachable. 60 00:06:12,400 --> 00:06:14,200 Keeping them in mind, we can remember that the host is always reachable. 61 00:06:14,220 --> 00:06:15,600 So, we can rule out the first state 62 00:06:15,980 --> 00:06:17,800 since it's simply not possible. 63 00:06:18,380 --> 00:06:20,660 For the remaining possible states, 64 00:06:21,200 --> 00:06:24,380 if the observed time is fast enough, 65 00:06:24,940 --> 00:06:29,920 the port is closed and the firewall rejects packets. 66 00:06:31,040 --> 00:06:33,800 And the observed time is slow enough, 67 00:06:34,060 --> 00:06:37,380 the port is open and the process is listening. 68 00:06:42,540 --> 00:06:44,200 So, the outcome is the following. 69 00:06:44,220 --> 00:06:45,260 The algorithm looks like this. 70 00:06:46,480 --> 00:06:50,140 Firstly, make multiple fetches to the port 2, 71 00:06:50,360 --> 00:06:52,740 a port that is generally closed, 72 00:06:53,020 --> 00:06:56,260 and calculate the average timing as a control. 73 00:06:57,100 --> 00:07:00,940 When a thousand measurements are plotted to a graph, 74 00:07:01,180 --> 00:07:02,220 it looks like this. 75 00:07:07,500 --> 00:07:11,720 Secondly, if a fetch takes a similar time as the control, 76 00:07:11,980 --> 00:07:13,960 the port can be considered closed. 77 00:07:14,220 --> 00:07:19,300 We do the same measurement to the local host port 65535. 78 00:07:20,000 --> 00:07:23,660 You can see from the graph, the two lines are very similar. 79 00:07:30,320 --> 00:07:34,640 Finally, if a fetch takes significantly more time than the control, 80 00:07:34,880 --> 00:07:36,960 the port can be considered open. 81 00:07:37,500 --> 00:07:41,540 We do the same measurement to the local host port 8000, 82 00:07:42,100 --> 00:07:44,200 where an HTTP server is open. 83 00:07:44,220 --> 00:07:48,040 As you can see from the graph, there is a clear difference. 84 00:07:49,060 --> 00:07:52,560 Repeat the algorithm against various ports of interest, 85 00:07:52,840 --> 00:07:55,200 then we get a list of open ports. 86 00:08:01,580 --> 00:08:04,140 Next, finding the router on the LAN. 87 00:08:05,040 --> 00:08:10,120 In this case, we only care if the host is responsive or not, 88 00:08:10,260 --> 00:08:12,480 regardless of the port state. 89 00:08:13,900 --> 00:08:17,720 If the host is responsive, we found a live host. 90 00:08:18,360 --> 00:08:22,260 So, if an arbitrary timeout is enforced, 91 00:08:22,660 --> 00:08:25,960 we can simply say the host is unresponsive. 92 00:08:27,000 --> 00:08:32,380 If the observed time is fast enough so that the port is closed, 93 00:08:32,640 --> 00:08:34,640 the firewall rejects packets, 94 00:08:35,060 --> 00:08:40,580 or slow enough so that the port is open and the processor is listening, 95 00:08:40,800 --> 00:08:42,460 we can conclude that the port is closed. 96 00:08:42,480 --> 00:08:43,880 We can conclude that the host is responsive. 97 00:08:49,480 --> 00:08:52,040 So, the algorithm goes like this. 98 00:08:52,760 --> 00:08:57,840 Firstly, if a fetch times out, the host can be considered unresponsive. 99 00:08:58,420 --> 00:09:03,460 When we do the measurement against the potential but non-existent router IP, 100 00:09:04,390 --> 00:09:06,640 10.0.0.1, 101 00:09:07,370 --> 00:09:08,960 as you can see from the graph, 102 00:09:09,240 --> 00:09:11,840 they are all above the timeout, 103 00:09:11,840 --> 00:09:13,420 which is 50 milliseconds. 104 00:09:18,920 --> 00:09:22,400 Secondly, if a fetch ends before the timeout, 105 00:09:22,620 --> 00:09:25,020 the host can be considered responsive. 106 00:09:25,860 --> 00:09:29,320 When we do the measurements against the live router IP, 107 00:09:30,820 --> 00:09:33,540 192.168.0.1, 108 00:09:33,720 --> 00:09:35,500 as the graph shows, 109 00:09:35,780 --> 00:09:37,960 they are mostly below the timeout. 110 00:09:38,840 --> 00:09:41,820 Repeat the algorithm against the list of potential, 111 00:09:41,840 --> 00:09:43,700 potential router IPs and ports, 112 00:09:43,960 --> 00:09:47,320 then we have a list of the live routers. 113 00:09:54,280 --> 00:09:57,800 Next, finding open ports on the LAN clients. 114 00:09:58,460 --> 00:10:02,240 Here, we will make an observation on one more thing. 115 00:10:03,560 --> 00:10:07,740 There is this new web standard called private network access. 116 00:10:08,340 --> 00:10:10,440 On Chrome, by default, 117 00:10:10,440 --> 00:10:18,280 requests to private network resources are allowed only from HTTPs webpages, 118 00:10:18,560 --> 00:10:25,480 meaning for HTTP requests to any client on the LAN to any local IP 119 00:10:25,480 --> 00:10:31,060 from an HTTP webpage would return a CORS error. 120 00:10:31,920 --> 00:10:36,480 Below is what it looks like when the error is returned. 121 00:10:36,980 --> 00:10:39,700 Access to fetch at HTTP, 122 00:10:39,700 --> 00:10:41,060 this address, 123 00:10:41,300 --> 00:10:43,280 from origin HTTP, 124 00:10:43,740 --> 00:10:44,580 this address, 125 00:10:44,740 --> 00:10:47,160 has been blocked by CORS policy. 126 00:10:48,240 --> 00:10:53,720 The error string itself is still the generic type error failed to fetch. 127 00:10:58,880 --> 00:11:04,360 Let's look at how the CORS error gets returned at the specification level. 128 00:11:05,500 --> 00:11:09,480 3.1.1 Secure context restrictions. 129 00:11:09,700 --> 00:11:18,400 5. The HTTP network fetch algorithm is amended to add three new steps. 130 00:11:18,660 --> 00:11:23,980 At 5.2, there is a private network access check, 131 00:11:24,510 --> 00:11:29,900 then 5.3 returns it if the result is a network error. 132 00:11:32,260 --> 00:11:34,100 But there is something strange. 133 00:11:34,480 --> 00:11:37,200 If you read point 5 very carefully, 134 00:11:37,200 --> 00:11:43,640 the HTTP network fetch algorithm is amended to add three new steps 135 00:11:43,860 --> 00:11:49,140 right after checking that the newly obtained connection is not failure. 136 00:11:49,960 --> 00:11:55,000 This means the CORS check happens after the connection is established, 137 00:11:55,800 --> 00:12:01,120 and the CORS error happens only when the TCP connection is successful, 138 00:12:01,440 --> 00:12:03,360 when the port is open. 139 00:12:08,340 --> 00:12:09,700 With this knowledge, 140 00:12:09,940 --> 00:12:12,160 we can think of new states and hypotheses. 141 00:12:13,060 --> 00:12:18,580 When fetching HTTP local IP from an HTTP web page, 142 00:12:18,800 --> 00:12:22,440 if the port is open and a process is listening, 143 00:12:22,880 --> 00:12:28,600 the browser and the firewall and the TCP would take up the observed time. 144 00:12:29,220 --> 00:12:31,400 A CORS error is returned, 145 00:12:31,850 --> 00:12:35,420 but we can't observe that as we discussed previously. 146 00:12:37,200 --> 00:12:38,420 On the other hand, 147 00:12:38,440 --> 00:12:43,400 when fetching HTTPS local IP from an HTTP web page, 148 00:12:43,620 --> 00:12:44,720 on the same port, 149 00:12:44,980 --> 00:12:45,840 the browser, 150 00:12:46,020 --> 00:12:47,040 the firewall, 151 00:12:47,320 --> 00:12:47,920 the TCP, 152 00:12:48,280 --> 00:12:52,600 and the TLS plus HTTP would take up the observed time. 153 00:12:56,920 --> 00:13:01,220 So this is how we find open ports on the LAN clients. 154 00:13:02,030 --> 00:13:03,980 From an HTTP web page, 155 00:13:04,220 --> 00:13:06,660 we take a measurement using HTTP. 156 00:13:07,200 --> 00:13:10,740 Then we take another measurement using HTTPS. 157 00:13:11,400 --> 00:13:14,860 If there is a difference between the two observed times, 158 00:13:15,200 --> 00:13:19,140 we can say the port is open and the process is listening. 159 00:13:25,060 --> 00:13:27,100 The algorithm goes like this. 160 00:13:27,260 --> 00:13:33,940 If an HTTPS fetch takes a similar time as an HTTP fetch, 161 00:13:34,320 --> 00:13:36,560 the port can be considered closed, 162 00:13:36,560 --> 00:13:38,520 and the firewall rejects packets. 163 00:13:39,400 --> 00:13:46,640 One line is measurements against HTTP 10.0.10.7 port 80, 164 00:13:47,230 --> 00:13:51,140 and the other line is against the same port, 165 00:13:51,280 --> 00:13:52,860 but with HTTPS. 166 00:13:53,640 --> 00:13:54,980 As you can see, 167 00:13:55,100 --> 00:13:57,400 the two lines are indistinguishable. 168 00:14:02,220 --> 00:14:03,000 However, 169 00:14:03,320 --> 00:14:05,260 if an HTTPS fetch 170 00:14:05,260 --> 00:14:09,080 is significantly slower than an HTTP fetch, 171 00:14:09,360 --> 00:14:11,300 the port can be considered open, 172 00:14:11,440 --> 00:14:12,880 and the process is listening. 173 00:14:13,800 --> 00:14:21,580 The line above is measurements against HTTPS 10.0.10.12 port 445, 174 00:14:22,040 --> 00:14:23,440 and the one below, 175 00:14:23,620 --> 00:14:24,460 almost zero, 176 00:14:25,210 --> 00:14:26,860 is against the same port, 177 00:14:27,040 --> 00:14:28,100 but with HTTP. 178 00:14:29,380 --> 00:14:33,360 The graph shows there is about 20 milliseconds of difference. 179 00:14:38,580 --> 00:14:42,560 I've created a proof of concept called urlan.js, 180 00:14:42,900 --> 00:14:45,460 which utilizes all the three techniques. 181 00:14:45,920 --> 00:14:47,660 Let me show you a demo. 182 00:14:54,440 --> 00:14:56,280 The video has been sped up, 183 00:14:56,360 --> 00:14:59,140 but you can see the actual time it took on the screen. 184 00:15:00,040 --> 00:15:00,600 First, 185 00:15:00,720 --> 00:15:03,520 we try finding open ports on the local host. 186 00:15:03,520 --> 00:15:06,020 It takes about two and a half minutes, 187 00:15:06,860 --> 00:15:08,660 and it's found airplay, 188 00:15:08,840 --> 00:15:09,560 discord, 189 00:15:10,340 --> 00:15:11,740 an HTTP server, 190 00:15:12,020 --> 00:15:12,840 line, 191 00:15:13,100 --> 00:15:13,500 steam, 192 00:15:13,700 --> 00:15:15,120 and logic options plus. 193 00:15:15,980 --> 00:15:16,580 Next, 194 00:15:16,660 --> 00:15:17,860 we try finding the router. 195 00:15:18,200 --> 00:15:19,860 It took about 10 seconds, 196 00:15:19,900 --> 00:15:22,740 and the first choice of the possible IPs was the one. 197 00:15:24,040 --> 00:15:24,640 Next, 198 00:15:24,720 --> 00:15:27,880 we try finding open ports on the oldest LAN clients. 199 00:15:28,100 --> 00:15:31,260 We search the whole subnet against ports of interest. 200 00:15:31,540 --> 00:15:33,320 It takes about 40 minutes, 201 00:15:33,320 --> 00:15:39,640 and you can see there are many IoT devices on the LAN. 202 00:15:39,840 --> 00:15:40,360 Airplay, 203 00:15:40,580 --> 00:15:41,600 Google Cast, 204 00:15:41,860 --> 00:15:42,960 LG Smart Device, 205 00:15:43,380 --> 00:15:44,040 Dyson, 206 00:15:45,640 --> 00:15:46,240 SMB, 207 00:15:46,520 --> 00:15:47,260 Homebridge, 208 00:15:47,420 --> 00:15:47,880 et cetera. 209 00:15:52,880 --> 00:15:53,480 Finally, 210 00:15:53,680 --> 00:15:55,820 let's explore some of the found ports. 211 00:15:56,260 --> 00:15:57,800 The first one is a router interface. 212 00:15:58,320 --> 00:16:02,520 The next one returns HP 470 for some reason. 213 00:16:02,520 --> 00:16:04,460 Next one is 404. 214 00:16:07,100 --> 00:16:09,360 Next one says nothing to see here. 215 00:16:10,540 --> 00:16:12,700 The next one is an actual homebridge. 216 00:16:13,620 --> 00:16:16,540 And the last one is a Philips Hue light bulb. 217 00:16:39,640 --> 00:16:40,880 In conclusion, 218 00:16:41,320 --> 00:16:44,160 a website can scan your local network, 219 00:16:44,440 --> 00:16:46,060 your local host, 220 00:16:46,220 --> 00:16:46,900 your router, 221 00:16:47,140 --> 00:16:48,860 and your clients on the LAN. 222 00:16:49,340 --> 00:16:53,320 There are some limitations on this research. 223 00:16:53,580 --> 00:16:56,220 Due to the nature of a timing-based attack, 224 00:16:56,520 --> 00:16:59,800 there can be false positives and false negatives. 225 00:17:00,200 --> 00:17:01,520 While we have 226 00:17:01,520 --> 00:17:04,640 simplified the states into 304, 227 00:17:04,860 --> 00:17:06,260 in actuality, 228 00:17:06,260 --> 00:17:08,820 there exist many other complicated scenarios. 229 00:17:09,520 --> 00:17:10,220 Also, 230 00:17:10,440 --> 00:17:13,380 the proof of concept needs further optimization 231 00:17:13,380 --> 00:17:15,320 to speed up the scanning process. 232 00:17:16,340 --> 00:17:17,080 Lastly, 233 00:17:17,280 --> 00:17:19,240 I'd like to end the talk with takeaways. 234 00:17:19,980 --> 00:17:23,480 It's always best to use Tor Browser for privacy and security. 235 00:17:24,200 --> 00:17:25,900 Related to this research, 236 00:17:26,180 --> 00:17:28,920 Tor Browser simply declines any requests 237 00:17:29,230 --> 00:17:30,280 to local host 238 00:17:30,280 --> 00:17:31,580 and local IPs. 239 00:17:32,220 --> 00:17:32,920 Also, 240 00:17:33,020 --> 00:17:34,380 use ad blockers 241 00:17:34,380 --> 00:17:36,920 to avoid malicious tracking scripts. 242 00:17:37,600 --> 00:17:38,300 Finally, 243 00:17:39,060 --> 00:17:40,620 VPNs can be a mitigation 244 00:17:40,620 --> 00:17:43,220 as long as they allow access 245 00:17:43,220 --> 00:17:45,060 to the user's local network. 246 00:17:51,020 --> 00:17:52,600 And that's it. 247 00:17:52,820 --> 00:17:54,160 I'd like to thank Oscar, 248 00:17:54,340 --> 00:17:54,800 Hansol, 249 00:17:54,960 --> 00:17:55,520 Luis, 250 00:17:55,680 --> 00:17:56,220 San, 251 00:17:56,400 --> 00:17:57,700 and the AJC group 252 00:17:57,700 --> 00:17:58,720 for helping out, 253 00:17:58,720 --> 00:18:00,120 and Betty for editing. 254 00:18:00,320 --> 00:18:01,660 Thank you very much for listening.