00:00:00
All right, imagine this. You're browsing
00:00:02
online and someone sends you a link. You
00:00:05
click on it and the page tells you that
00:00:07
you need to update your Chrome. You
00:00:09
follow the instructions. First, you drag
00:00:11
and drop the image into a new tab and
00:00:13
then you click on this update Google
00:00:16
Chrome link. Seems harmless, right? But
00:00:19
here's what's actually happening. The
00:00:20
drag and drop interaction isn't really
00:00:23
updating anything. Instead, it's
00:00:25
exploiting a vulnerability chain in
00:00:27
Google's Chrome that gives attacker
00:00:30
complete control over your browser and
00:00:33
also the access to your local file
00:00:35
system. What looked like a simple
00:00:37
browser update now just became a system
00:00:40
compromise. A portion of the video is
00:00:43
sponsored by Snake. More on that at the
00:00:45
end of the video. This really cool
00:00:48
exploit was discovered by Matan. He's 17
00:00:52
years old and he's a security researcher
00:00:55
from Israel. It all started when Matan
00:00:58
was experimenting with a Chrome
00:01:00
extension and discovered that by
00:01:02
navigating to Chrome inspect URL, he
00:01:06
could actually inspect the DevTools
00:01:07
window itself. For those of you who are
00:01:10
not familiar with what DevTools is,
00:01:12
DevTools is a Chrome's in-built
00:01:15
debugging suite that lets developers
00:01:17
inspect web pages, debug JavaScript,
00:01:20
monitor network performance, and analyze
00:01:23
rendering behavior. What makes this
00:01:25
particularly interesting is that the dev
00:01:28
tools itself is just another web
00:01:30
application built with HTML, CSS, and
00:01:33
JavaScript, which means it can be
00:01:36
inspected just like any other web page.
00:01:38
This opens up a fascinating meta
00:01:41
debugging scenario where one can use
00:01:44
DevTools schema or protocol and inspect
00:01:47
one of the DevTools pages. Essentially,
00:01:50
Matan here was trying to debug the
00:01:52
debugger itself. By the way, you can try
00:01:55
to debug the debugger yourself if you
00:01:57
visit this link. But since Chromium is
00:02:00
open- source, which powers Chrome and
00:02:03
also Edge browser, he started digging a
00:02:07
little bit deeper. While looking at the
00:02:09
code, he noticed a parameter labeled WS.
00:02:12
So investigating this a little bit
00:02:14
further, he realized that he could
00:02:16
specify any URL using this WS parameter
00:02:20
which stands for websockets and the dev
00:02:23
tools would establish a websocket
00:02:25
connection back to the specified
00:02:27
address. So this is essentially a
00:02:29
legitimate feature designed for remote
00:02:32
debugging purposes. Now he thought, what
00:02:35
if we could connect to an attacker
00:02:37
server? Well, you could, but what can
00:02:40
you really do with this? Apparently,
00:02:42
there's a simple protocol that the dev
00:02:45
tools use to talk between the client and
00:02:47
the server and it's called Chrome
00:02:49
DevTools protocol. The protocol is
00:02:52
organized into different domains like
00:02:55
DOM, network, runtime and so on. Each
00:02:58
defining various commands and events.
00:03:00
So, there are some interesting stuff you
00:03:02
can do like execute commands on your
00:03:05
browser or mess with security
00:03:07
configurations, monitor networking, that
00:03:10
sort of stuff. But it's all confined to
00:03:12
the current DevTools session. You don't
00:03:15
get any extra privileges or access
00:03:18
beyond what DevTools normally has. There
00:03:21
was one event that caught his attention.
00:03:24
Log entry added. You can send this event
00:03:27
from the attacker's remote server to the
00:03:30
browser with fields like text and URL
00:03:33
and it would actually do a console log
00:03:35
entry in the dev tools. The interesting
00:03:38
bit, however, is that the URL becomes a
00:03:41
clickable link. Since we control this
00:03:43
URL, what if we set it to a JavaScript
00:03:47
URI? Something as simple as this. For
00:03:49
those of you who don't know about
00:03:51
JavaScript URIs, there's simply a way to
00:03:54
execute JavaScript code directly in the
00:03:56
URL. Instead of linking to a web page,
00:04:00
you can use this JavaScript protocol
00:04:02
followed by your code. And when someone
00:04:05
clicks on this link, the browser
00:04:06
executes this JavaScript code instead of
00:04:09
actually navigating to a specific page.
00:04:12
Pretty slick. But there was a problem.
00:04:14
The JavaScript URIs were not allowed by
00:04:16
DevTools, and you can't make them into a
00:04:19
link. Here's the code responsible for
00:04:21
that check. But if you look closely,
00:04:24
there seems to be an oversight by the
00:04:26
developers. They're just checking if the
00:04:29
string starts with the JavaScript after
00:04:32
doing a lowercase on it. But what this
00:04:35
check misses is whether there are any
00:04:37
whites space characters like back slash
00:04:39
r or back slashn embedded within the
00:04:42
protocol itself. If you insert a new
00:04:45
line, for example, anywhere between the
00:04:47
word javascript, it will actually still
00:04:49
execute the JavaScript URI because the
00:04:52
browser internally normalizes these
00:04:55
characters away. You can test this by
00:04:57
creating a link that looks like this.
00:05:00
And here the XA embedded within the
00:05:02
JavaScript that's actually an HTML
00:05:05
entity encoded new line character. Now,
00:05:07
if you click on this link, it will
00:05:09
trigger an alert. Pretty cool. Now, we
00:05:12
have a way to bypass the security check
00:05:15
with the normalization trick. All we
00:05:17
have to do is just set the URL and send
00:05:20
it through the websocket connection. And
00:05:22
when we click on
00:05:24
it, it doesn't work. Why is that? Well,
00:05:27
the
00:05:29
DevTools_app.html file has this line of
00:05:32
code. That's CSP, content security
00:05:35
policy. We successfully did inject our
00:05:37
JavaScript URI within the dev tools
00:05:40
window, but it just wouldn't execute
00:05:43
because the policy is stopping us. It
00:05:46
prevents inline JavaScript execution
00:05:48
from sources like the JavaScript URI. So
00:05:51
almost all pages in DevTools bundle also
00:05:55
have the CSP enabled except for just one
00:05:58
file and that's called integration
00:06:02
testrRunner.html. The developers did
00:06:04
write the CSP line in the HTML file too,
00:06:07
but the funny part is that it's it's
00:06:10
commented out. Yeah, lucky us. So if we
00:06:14
change our target from dev tools app
00:06:17
html to this new integration test html
00:06:21
it should work right. Well almost. When
00:06:23
we try this we get an error. The test
00:06:26
file requires a valid URL parameter
00:06:30
called inspect test and it needs to be a
00:06:34
valid URL. So you can supply anything
00:06:37
like
00:06:39
httpsacample.com and it should just
00:06:41
work. Now the moment of truth. We click
00:06:44
on the JavaScript URI. Boom. We do get
00:06:46
an alert. The exploit did work, but it's
00:06:50
uh lacking some UX. So, let's actually
00:06:53
fix that. First of all, we can clearly
00:06:55
see the JavaScript URI code. So, users
00:06:58
would be really suspicious about
00:07:01
clicking on it in the first place. So, a
00:07:03
solution Matan found was that to simply
00:07:06
add a bunch of uh back slash R uh
00:07:09
characters before the JavaScript URI.
00:07:12
And uh this would actually make the URI
00:07:14
too long to be displayed. So it will
00:07:17
only show the end parts of the URI. To
00:07:20
make this even more cleaner, he added
00:07:22
some comments at the end of the
00:07:24
JavaScript code so that only the
00:07:27
innocent parts of the string gets shown
00:07:29
to the user. A pretty clever social
00:07:31
engineering trick. Also, when you open
00:07:34
the dev tools window, it defaults to the
00:07:36
elements tab panel, but we can change
00:07:39
that via the get parameter called panel,
00:07:42
and we set it to console. And that
00:07:45
should take care of it. Now, instead of
00:07:47
simply popping an alert, let's take it
00:07:49
up a notch. Let's read the contents of
00:07:52
the past WD file. This can be done if
00:07:55
you get a handle to the DevTools API
00:07:57
object. He noticed that this object
00:08:00
wasn't really there in the pages that
00:08:02
were opened by the exploit window. But
00:08:05
when he manually opened a new tab in the
00:08:08
browser and navigated to some dev tools
00:08:11
front-end page, this object was
00:08:14
accessible. So this led him to think
00:08:16
that this object might only be
00:08:18
accessible in a tab which doesn't have
00:08:21
any opener. So he made the exploit open
00:08:25
the DevTools front-end URL like the
00:08:27
DevTools app HTML in a new tab and
00:08:30
manually set the tab opener to null and
00:08:33
then refresh the tab. This trick
00:08:35
actually worked and it actually gave him
00:08:38
access to the DevTools API object which
00:08:41
is very powerful and having access to
00:08:44
this would let us read local files and
00:08:47
also get a universal XSS in the DevTools
00:08:50
API. There's actually a method called
00:08:53
send message to the embedder and and
00:08:56
also there's a bunch of other different
00:08:58
messages types you can send. Uh one of
00:09:01
them is load network resource. You can
00:09:04
specify any URL and it would actually
00:09:06
load it. So if we specify something like
00:09:09
file
00:09:10
Etsd, we can actually read local files.
00:09:14
Sweet. And by the way, there's actually
00:09:16
a big issue we need to solve. We can't
00:09:19
really navigate to the DevTools URL
00:09:22
directly from a malicious website. The
00:09:24
user would have to manually copy paste
00:09:27
this link to the address bar and then
00:09:30
press enter which is pretty unlikely to
00:09:32
do by a user. So here comes the drag and
00:09:36
drop trick. So when the user drags an
00:09:39
element from the malicious web page to a
00:09:41
new tab, it automatically navigates to
00:09:44
the dev tools URL because we are
00:09:47
overwriting the data. All right, that
00:09:49
was a lot and let's actually summarize
00:09:52
and put everything in order. So we start
00:09:55
with the drag and drop interaction trick
00:09:57
that we just talked about to open up the
00:10:00
DevTools URL with the integration
00:10:02
testrunner HTML as the target. And this
00:10:05
opens up in a new tab. This will have
00:10:08
the WS parameter, which is the websocket
00:10:10
parameter that connects back to the
00:10:13
attacker server. This server then
00:10:15
emulates being a debugger and then sends
00:10:18
a log entry with the JavaScript URI. The
00:10:22
XSS works because we're actually
00:10:24
bypassing Chrome's JavaScript URI check
00:10:27
with a new line normalization and also
00:10:29
skipping the CSP thanks to the commented
00:10:32
out CSP. And then when the user clicks
00:10:36
on the URI, we open the DevTools app
00:10:39
HTML, set the opener to null, and then
00:10:42
reload the page. This somehow makes the
00:10:44
DevTools API available. And then we can
00:10:48
use the send message embed on the
00:10:50
DevTools API object itself to read local
00:10:53
files. Pretty wild chain of
00:10:55
vulnerabilities working all together.
00:10:58
All right, let's actually run the
00:11:00
exploit. We visit the page, drag and
00:11:03
drop the icon, and we click on this
00:11:06
update Chrome button. Wait for
00:11:09
it, and there goes my Ets WD file.
00:11:14
Pretty cool. By the way, one can also
00:11:16
get a universal XSS with this exploit.
00:11:19
Meaning this privileged access to the
00:11:22
dev tools will let the attacker inject
00:11:25
any JavaScript into any website with
00:11:28
your session, even though there's no XSS
00:11:31
on the website itself. Pretty slick. And
00:11:34
also this issue was reported a long time
00:11:37
ago to the Chromium team almost two
00:11:39
years ago and it was found in this
00:11:42
version and was assigned with this CVE
00:11:46
ID. Speaking of security
00:11:48
vulnerabilities, if you're a developer,
00:11:50
you're probably thinking about security
00:11:52
in your own projects, too. So, while we
00:11:55
can't really predict wild browser
00:11:58
exploits like this one, most security
00:12:00
issues actually come from everyday stuff
00:12:03
like vulnerable dependencies,
00:12:05
misconfigurations, or bugs in your own
00:12:07
code. So, today's sponsor, Snake, has a
00:12:10
tool that will help you with this side
00:12:13
of security. They do code scanning,
00:12:16
dependency checking, container security,
00:12:18
infrastructures code, that kind of
00:12:20
thing. I use their platform personally
00:12:23
and they do some great work. It's
00:12:25
actually free for individuals and small
00:12:27
teams. So if that sounds useful, go
00:12:30
check him out at
00:12:32
sneak.co/ponefunction. Links will be
00:12:34
down in the description. So back then
00:12:37
when I reached out to Matan as soon as
00:12:40
he tweeted about this bug, this was
00:12:42
right around the time when the Chromium
00:12:44
team had just patched the vulnerability.
00:12:47
Uh Matan was really kind and helpful
00:12:50
walking me through the bug. Uh huge
00:12:53
thanks to him for blowing my mind
00:12:55
multiple times. Uh thanks again. And the
00:12:59
the video was supposed to come out uh a
00:13:02
year ago but ended up getting delayed
00:13:04
for various reasons. And uh even though
00:13:07
this bug has been out for a while, I
00:13:10
still think it's a really unique find.
00:13:12
So just wanted to share it with
00:13:14
everyone. Uh, anyways, I'll leave all
00:13:16
the relevant links down in the
00:13:18
description, including the original
00:13:20
report by Matan and socials. So, check
00:13:23
them out. Thank you for the view, and
00:13:25
I'll see you in the next one. Peace.