Moderate
Google Chrome CVE-2019-5786 FileReader Use-After-Free Vulnerability
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below:
Add References:
Google Chrome CVE-2019-5786 FileReader Use-After-Free Vulnerability
MITRE ATT&CK
Collection
Command and Control
Credential Access
Defense Evasion
Discovery
Execution
Exfiltration
Impact
Initial Access
Lateral Movement
Persistence
Privilege Escalation
Topic Tags
Description
Object lifetime issue in Blink in Google Chrome prior to 72.0.3626.121 allowed a remote attacker to potentially perform out of bounds memory access via a crafted HTML page.
Add Assessment
Technical Analysis
This was exploited in the wild as noted at https://security.googleblog.com/2019/03/disclosing-vulnerabilities-to-protect.html and https://blog.exodusintel.com/2019/05/17/windows-within-windows/
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportRatings
-
Attacker ValueMedium
-
ExploitabilityLow
Technical Analysis
Exploit doesn’t work within the Chrome sandbox, so an attacker will need to escape that first. Couple that with the facts that x64 is more difficult to target and the auto-update nature of Chrome, this one wouldn’t be the easiest to exploit, methinks…
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportTechnical Analysis
a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
+++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -143,14 +143,16 @@ DOMArrayBuffer* FileReaderLoader::ArrayBufferResult() {
if (!rawdata || errorcode != FileErrorCode::kOK)
return nullptr;
- DOMArrayBuffer* result = DOMArrayBuffer::Create(rawdata–>ToArrayBuffer());
- if (finishedloading) {
- array_bufferresult = result;
- AdjustReportedMemoryUsageToV8(
- -1 * static_cast
<int64_t>
(rawdata–>ByteLength()));
- rawdata.reset();
- if (!finishedloading) {
- return DOMArrayBuffer::Create(
- ArrayBuffer::Create(rawdata–>Data(), rawdata–>ByteLength()));
}
- return result;
+
- array_bufferresult = DOMArrayBuffer::Create(rawdata–>ToArrayBuffer());
- AdjustReportedMemoryUsageToV8(-1 *
- static_cast
<int64_t>
(rawdata–>ByteLength()));
- rawdata.reset();
- return array_bufferresult;
}
String FileReaderLoader::StringResult() {
#### Clue 1: readAsArrayBuffer This patch provides a lot of insight about the user-after-free. The first thing that stands out is the patched method named `FileReaderLoader::ArrayBufferResult`, which clearly indicates the use of `readAsArrayBuffer` in the exploit. #### Clue 2: The finished_loading_ condition A major difference between patched vs unpatched is the `finished_loading_` check, which is a flag that is set when body is finished loading. In the vulnerable version, our method is always doing the following: ```cpp DOMArrayBuffer* result = DOMArrayBuffer::Create(raw_data_->ToArrayBuffer());
In the patched version, it is doing:
if (!finished_loading_) { return DOMArrayBuffer::Create( ArrayBuffer::Create(raw_data_->Data(), raw_data_->ByteLength())); } array_buffer_result_ = DOMArrayBuffer::Create(raw_data_->ToArrayBuffer());
The difference is that if loading isn’t finished, it will make sure to create a new ArrayBuffer
(which increments the reference counter), instead of obtaining ownership of ArrayBuffer
, and passing to MakeGarbageCollected
:
static DOMArrayBuffer* Create(scoped_refptr<WTF::ArrayBuffer> buffer) { return MakeGarbageCollected<DOMArrayBuffer>(std::move(buffer)); }
Note: The ToArrayBuffer
method always return the actual state of the ArrayBuffer asynchronously.
Clue 3: The Arbitrary free
Another clue comes from the comment in the commit, stating:
… multiple references to the same underlying ArrayBuffer.
This is rather hard to get, but Istvan Kurucsai from Exodus Intel found a great way to acheive that with JavaScript’s postMessage
method:
targetWindow.postMessage(message, targetOrigin, [transfer]);
The transfer
parameter is a sequence of Transferable objects that are transferred with the message. The ownership of these objects is given to the desitnation side and they are no longer usable on the sending side.
By doing so, we could pass multiple DOMArrayBuffers
that refere to the same ArrayBuffer to a JS worker through postMessage in a onprogress
event handler, for example:
// last = reader ArrayBuffer result // lastlast = the previous result worker.postMessage([last], [last, lastlast]);
This allows the first transfer to take ownership of its buffer, but the second transfer will fail because the ArrayBuffer
has already been neutered. When this failure happens, this causes the transferred ArrayBuffer
to be freed, while a reference still exists in the second DOMArrayBuffer
.
Proof-of-Concept
Thanks to Istvan from Exodus, the community gets a clean proof-of-concept for testing purposes:
https://github.com/exodusintel/CVE-2019-5786
32-bit Windows 7
One of the reasons memory corruption bugs are much harder to exploit against Chrome is because the use of a custom memory allocator: ParitionAlloc. PartitionAlloc guarantees that different partitions exist in different regions of the process’ address space, it also prevents various scenarios of linear overflows, object allocations, deferences, pointer overwrite, gard pages for large allocations.
It seems one of the limitations with ParitionAlloc is that although it effectively separates our ArrayBuffer from other kinds of allocations, and that it will never reuse those allocations, the scenario only applies if the region that is freed is below 2MiB in size. It is more possible to successfully reclaim the freed region on a 32-bit platform, which explains why a 32-bit Windows 7 is a much more ideal target for Chrome.
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportCVSS V3 Severity and Metrics
General Information
Vendors
Products
- chrome
Exploited in the Wild
Would you like to delete this Exploited in the Wild Report?
Yes, delete this reportReferences
Miscellaneous
Additional Info
Technical Analysis
Report as Exploited in the Wild
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below: