0% found this document useful (0 votes)
1 views

Intro to Browser Security Research

The document provides an introduction to web browser security research, focusing on how to identify vulnerabilities in web browsers. It discusses various types of vulnerabilities, including buffer overflows and use-after-free errors, and outlines methods for finding browser bugs, such as manual code review and fuzzing. Additionally, it highlights the importance of understanding JavaScript security and the role of callbacks in potential vulnerabilities.

Uploaded by

sigale1667
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views

Intro to Browser Security Research

The document provides an introduction to web browser security research, focusing on how to identify vulnerabilities in web browsers. It discusses various types of vulnerabilities, including buffer overflows and use-after-free errors, and outlines methods for finding browser bugs, such as manual code review and fuzzing. Additionally, it highlights the importance of understanding JavaScript security and the role of callbacks in potential vulnerabilities.

Uploaded by

sigale1667
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 63

How to Find Vulnerabilities in Web Browsers

(An Introduction to Web Browser Security Research)


Ivan Fratrić, Google Project Zero
2025
About me
● > 2016 Security researcher at Google Project Zero
● 2012 - 2016 Google Security Team
● < 2012 FER, Zagreb
● Author: WinAFL, Domato, TinyInst, Jackalope, …
● https://twitter.com/ifsecure, https://infosec.exchange/@ifsecure
Web Browser as an Attack Vector

Source: https://securitylab.amnesty.org/latest/2025/03/journalists-targeted-with-pegasus-spyware/
Chrome Vulnerability Reward Program
High-quality report High-quality report High-quality report Baseline
with demonstrating of demonstrated
demonstration of controlled write memory corruption
RCE

Sandbox escape / Up to $250,000 Up to $90,000 Up to $35,000 Up to


Memory corruption / RCE $25,000
in a non-sandboxed
process [1], [2]

Memory Corruption / Up to $85,000 Up to $70,000 Up to $15,000 Up to


RCE in a highly privileged $10,000
process (e.g. GPU or
network processes) [2]

Renderer RCE / memory Up to $55,000 Up to $50,000 Up to $10,000 Up to


corruption in a $7,000 [3]
sandboxed process
What is a Web Browser?
Renderer (Tab, Content) Process
Inter Process Communication (IPC)

Renderer Process

DOM engine
JavaScript engine
etc.
<html>, <body>,
let o = {‘foo’: bar}
<div>, etc.

APIs Media Parsers


Layout engine
Storage, Audio, .jpg, .png, .mp4 etc.
p {color: red;}
WebGPU, File etc.
Vulnerabilities

General: Browser Specific:


● Buffer overflows ● JIT compiler bugs
● Integer overflows ● Universal XSS
● Use after free ● Same Origin Policy bypass
● Double free ● etc.
● Type confusion
● etc.
Vulnerabilities… in this talk

General: Browser Specific:


● Buffer overflows ● JIT compiler bugs
● Integer overflows ● Universal XSS
● Use after free ● Same Origin Policy bypass
● Double free ● etc.
● Type confusion
● etc.
C++ object lifecycle
Foo *foo = new Foo();
Used memory

foo->DoSomething();

Free memory
delete foo;
C++ object lifecycle
Foo *foo = new Foo();
Used memory

foo->DoSomething();
foo

delete foo;
Free memory
C++ object lifecycle
Foo *foo = new Foo();
Used memory

foo->DoSomething();
foo

delete foo;
Free memory
C++ object lifecycle
Foo *foo = new Foo();
Used memory

vtable ptr
foo->DoSomething();
foo

delete foo;
Free memory
C++ object lifecycle
Foo *foo = new Foo();
Used memory
DoSomething ptr
vtable ptr
foo->DoSomething();
foo

delete foo;
Free memory
C++ object lifecycle
Foo *foo = new Foo();
Used memory

foo->DoSomething();
Free memory

delete foo;
Free memory
Use after free
Foo *foo = new Foo();
Used memory

foo->DoSomething();

Free memory
delete foo;
Use after free
Foo *foo = new Foo();
Used memory

delete foo;

Free memory
foo->DoSomething();
Use after free
Foo *foo = new Foo();
Used memory

delete foo;
foo

foo->DoSomething();
Free memory
Use after free
Foo *foo = new Foo();
Used memory

delete foo;
Free memory

foo->DoSomething();
Free memory
Use after free
Foo *foo = new Foo();
Used memory

???
delete foo;
Free memory

foo->DoSomething();
Free memory
Use after free
Foo *foo = new Foo();
Used memory

delete foo;
Attacker-controlled
// attacker-controlled
// allocation

Free memory
foo->DoSomething();
Use after free
Foo *foo = new Foo();
Used memory

fake vtable ptr


delete foo;
Attacker-controlled
// attacker-controlled
// allocation

Free memory
foo->DoSomething();
Use after free
Foo *foo = new Foo();
Used memory
Attacker-controlled
fake vtable ptr
delete foo;
Attacker-controlled
// attacker-controlled
// allocation

Free memory
foo->DoSomething();
JavaScript security

JavaScript in web browsers is:


● Memory safe
● Single threaded
JavaScript security

JavaScript in web browsers is:


● Memory safe
● Single threaded
…but…
● Engines written (mostly) in C++
● Has callbacks
What is a callback

o = {toString:function() { alert(1); }}
What is a callback

o = {toString:function() { alert(1); }}

JavaScript object
What is a callback

o = {toString:function() { alert(1); }}

Attacker-controlled function
gets called whenever the
object is converted to string
DOM callbacks
<form onsubmit="myfunc()">
<input type="submit">
</form>
DOM callbacks
<form onsubmit="myfunc()">
<input type="submit">
</form>

Attacker-controlled function
gets called whenever certain
DOM events occur
General idea

● We use callbacks to modify data while this data is being operated on


JavaScript vulnerability (made up example)

<script>
let array = [1,2,3,4,5,6,7,8,9,10]
array.sort( function() { array.length = 2; } )
</script>
JavaScript vulnerability (made up example)

<script>
let array = [1,2,3,4,5,6,7,8,9,10]
array.sort( function() { array.length = 2; } )
</script>

Comparator function that the


JS sort algorithm calls when
comparing two elements
JavaScript vulnerability (made up example)

<script>
let array = [1,2,3,4,5,6,7,8,9,10]
array.sort( function() { array.length = 2; } )
</script>

We are resizing an array


while it is being sorted.
What will happen?
Real-world example, CVE-2017-11907, MS JScript
var arr = new Array(1000);
for(var i=1;i<600;i++) arr[i] = i;

var o = {toString:function() {
for(var i=600;i<1000;i++) { arr[i] = 1337; }
}};

arr[0] = o;
arr.sort();
DOM vulnerability (made up example)
<script>
function func() {
document.getElementById("f1").remove();
}
</script>
<form id="f1" onsubmit="func()">
<input type="submit">
</form>
DOM vulnerability (made up example)
<script>
function func() {
document.getElementById("f1").remove();
}
</script>
<form id="f1" onsubmit="func()">
<input type="submit">
</form>
Callback triggers when
form is being submitted
DOM vulnerability (made up example)
<script>
function func() {
document.getElementById("f1").remove();
}
</script>
<form id="f1" onsubmit="func()">
<input type="submit">
</form>
We delete a form while it’s
being submitted. What
happens?
But wait, what about garbage collector?

Need to understand what garbage collector is aware of


(and what it’s not aware of)
● DOM objects often not tracked / tracked using a different mechanism
● Local variables often not tracked
Interpretation vs. compilation

Languages can be
● Interpreted
● Compiled
Why can’t we have both?
Optimizing compiler

● If optimization is not correct for all inputs -> security vulnerabilities


JIT compiler bug (made up example)

function f(x) {
let arr = [1,2,3,4]
let m = x % 4;
return arr[m];
}
JIT compiler bug (made up example)

function f(x) {
let arr = [1,2,3,4]
let m = x % 4;
If the compiler (incorrectly)
return arr[m];
assumes m must be
} between 0 and 3…
JIT compiler bug (made up example)

function f(x) {
let arr = [1,2,3,4]
let m = x % 4;
…then it might remove
return arr[m];
(optimize away) the array
} index check
JIT compiler bug (made up example)

function f(x) {
let arr = [1,2,3,4]
let m = x % 4;
return arr[m];
}

What happens if we call f(-1) ?


Real-world example

● Chrome: V8: incorrect type information on Math.expm1

The typer sets the type of Math.expm1 to be Union(PlainNumber, NaN).


This is missing the -0 case: Math.expm1(-0) returns -0.
How to find browser bugs

● Manual source code review


● Variant analysis (look at previous bugs)
● Automated (Fuzzing)
What is fuzzing
“Fuzzing or fuzz testing is an automated software testing technique that involves
providing invalid, unexpected, or random data as inputs to a computer program.”

Source: https://en.wikipedia.org/wiki/Fuzzing
Domato (2017), https://github.com/googleprojectzero/domato

● Generational
● Grammar-based
● Context-free grammars for HTML, CSS and JavaScript

<html> = <lt>html<gt><head><body><lt>/html<gt>
<head> = <lt>head<gt><elements><lt>/head<gt>
<body> = <lt>body<gt><elements><lt>/body<gt>
<elements> = <element><elements>
<elements> = <element>
<element> = <a>
<element> = <audio>
Domato (2017), https://github.com/googleprojectzero/domato
Domato (2017), https://github.com/googleprojectzero/domato

Vendor Browser Engine Number of Bugs Project Zero Bug IDs

Google Chrome Blink 2 994, 1024

Mozilla Firefox Gecko 4 1130, 1155, 1160, 1185

Microsoft Internet Explorer Trident 4 1011, 1076, 1118, 1233

Microsoft Edge EdgeHtml 6 1011, 1254, 1255, 1264, 1301, 1309

Apple Safari WebKit 17 999, 1038, 1044, 1080, 1082, 1087, 1090,
1097, 1105, 1114, 1241, 1242, 1243, 1244,
1246, 1249, 1250

Total 31*
Then vs. Now
Then:
● Generational Fuzzing
● “Let’s find bugs in the entire browser”
Now:
● Mutational, coverage-guided fuzzing
○ Jackalope, LibAFL, libFuzzer
● Focus on a single component (or interaction between several components)
Future?
● AI (agents)
Let’s analyze a recent Firefox bug
Let’s analyze a recent Firefox bug

What is this?
<items> <xsl:stylesheet version="1.0"
<item>Item 1</item> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<item>Item 2</item> <xsl:template match="/">
</items> <ul>
<xsl:for-each select="items/item">
<li><xsl:value-of select="."/></li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>

<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
A hidden callback

setTimeout(callback, 0);
A hidden callback

setTimeout(callback, 0);

● “Execute callback function after x ms”


● Normally, callback() function would execute after the current script is
done, so not really a callback
● But in this case…
A hidden callback
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:copy-of select="document('delay.xml')"/>
</xsl:template>
</xsl:stylesheet>
A hidden callback
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:copy-of select="document('delay.xml')"/>
</xsl:template>
</xsl:stylesheet>

Fetch an external document


A hidden callback
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:copy-of select="document('delay.xml')"/>
</xsl:template>
</xsl:stylesheet>

Fetch an external document


… and handle events (including timeout events) while waiting
Inside the callback…

function callback() {
xmlDoc.removeChild(xmlDoc.childNodes[0]);

FuzzingFunctions.garbageCollect();
FuzzingFunctions.cycleCollect();
}
Inside the callback…

function callback() {
xmlDoc.removeChild(xmlDoc.childNodes[0]);

FuzzingFunctions.garbageCollect();
FuzzingFunctions.cycleCollect();
}
Remove an element from
an XML document, while
that XML document is being
transformed
DEMO
Where to go from now?
● Read more:
○ bug writeups
○ conference talks
○ blog posts
● Take a previous bug
○ Try to reproduce it
○ Analyze how it works
● Find people who report cool bugs and follow them on social media
○ Find people they follow
● Try to do something on your own!

You might also like