[CVE-2019-16073] Brave Browser AdBlock: Arbitrary Out-of-Bounds Write (HashFn2Byte – AddFilterDomainsToHashSet)

Description

Brave Browser implements a built-in AdBlock component that can parse AdBlock Plus filters (e.g. EasyList). The parser is implemented from Brave in native C++ code and was found to be vulnerable to an out-of-bounds (OOB) write of arbitrary size.
Exploiting this vulnerability might allow an adversary writing to an arbitrary memory address of Chrome’s privileged process since the AdBlock initialization is executed from the main process before delegating to sandboxed workers. This means, an adversary could utilize this vulnerability to execute malicious code from Chrome’s privileged process.

CVSS 3.0 Base Score

8.8 (AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H)

Researcher

xen1thlabs Software Labs

POC

The vulnerability was identified via fuzzing of a standalone AdBlock parser implementation and was reproduced in AdBlock component as shipped with Brave version 1.0.77. The crash was initially triaged with Clang’s Address Sanitizer (ASan), which produced the following report.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
=================================================================
==18306==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcb0ee4650 at pc 0x7fb91279b77a
bp 0x7ffcb0ee4170 sp 0x7ffcb0ee3918
WRITE of size 847506 at 0x7ffcb0ee4650 thread T0
#0 0x7fb91279b779 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x79779)
#1 0x55dc1b2d6aff in AddFilterDomainsToHashSet(Filter*, HashSet<NoFingerprintDomain>*) ../../../
ad_block_client.cc:79
#2 0x55dc1b2e19e6 in AdBlockClient::parse(
char
const*, bool) ../../../ad_block_client.cc:1365
#3 0x55dc1b2d3ff6 in main ../../../main.cc:105
#4 0x7fb911db1b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
#5 0x55dc1b2d2fe9 in _start (/home/anestisb/Developer/ad-block/build/out/Default/sample
+0x143fe9)Address 0x7ffcb0ee4650 is located in stack of thread T0 at offset 1184 in frame
#0 0x55dc1b2d68b3 in AddFilterDomainsToHashSet(Filter*, HashSet<NoFingerprintDomain>*) ../../../
ad_block_client.cc:67 This frame has 4 object(s):
[32, 56)
'<unknown
[96, 120)
'<unknown>'
[160, 1184)
'buffer'
[1216, 2240)
'buffer' <== Memory access at offset 1184 partially underflows
this variable
HINT:
this may be a
false positive
if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x79779)
Shadow bytes around the buggy address:
0x1000161d4870: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000161d4880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000161d4890: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000161d48a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000161d48b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1000161d48c0: 00 00 00 00 00 00 00 00 00 00[f2]f2 f2 f2 00 00
0x1000161d48d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000161d48e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000161d48f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000161d4900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000161d4910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow
byte legend (one shadow
byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after
return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==18306==ABORTING

The top frame indicates an OOB (Out-Of-Bounds) write in line 79, with 847506 bytes being written beyond the boundaries of the buffer stack allocated buffer. Notice that buffer size is defined in line 77, although there are no checks to ensure that len is smaller than 1024.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
File: ad-block/ad_block_client.cc
66 void AddFilterDomainsToHashSet(Filter* filter,
67 HashSet<NoFingerprintDomain> *hashSet) {
68
if (filter->domainList) {
69
char * filter_domain_list = filter->domainList;
70
int start_offset = 0;
71
int len = 0;
72
const
char *p = filter_domain_list;
73
while (
true) {
74
if (*p ==
'|' || *p ==
'\0') {
75
const
char *domain = filter_domain_list + start_offset;
76
if (len > 0 && *domain !=
'~') {
77
char buffer[1024];
78 memset(buffer, 0, 1024);
79 memcpy(buffer, domain, len);

As triggered from the attached POC (Proof-Of-Concept) file, the vulnerability can be triggered if the input file contains a filter_domain_list the size of which is bigger than 1024.

POC Files

Not released

Disclosure Timeline

  • 19-Jun-2019 - Notified vendor
  • 15-Aug-2019 - Brave browser Android v1.2.0 released which resolves this
Namaste.
You can know about me at my portfolio.
I follow my own Vulnerability Disclosure Policy.
Most of my work is listed here.