8.8 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
REQUIRED
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
9.3 High
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:N/AC:M/Au:N/C:C/I:C/A:C
0.017 Low
EPSS
Percentile
87.6%
Google Chrome < M73 - FileSystemOperationRunner Use-After-Free
There's a comment in FileSystemOperationRunner::BeginOperation
OperationID FileSystemOperationRunner::BeginOperation(
std::unique_ptr<FileSystemOperation> operation) {
OperationID id = next_operation_id_++;
// TODO(https://crbug.com/864351): Diagnostic to determine whether OperationID
// wrap-around is occurring in the wild.
DCHECK(operations_.find(id) == operations_.end());
// ! If id already in operations_, this will free operation
operations_.emplace(id, std::move(operation));
return id;
}
The id is an int, and it can wrap, and if it does this will cause a use-after-free in the browser process, since the normal usage of BeginOperation is the following:
OperationID FileSystemOperationRunner::Truncate(const FileSystemURL& url,
int64_t length,
StatusCallback callback) {
base::File::Error error = base::File::FILE_OK;
std::unique_ptr<FileSystemOperation> operation = base::WrapUnique(
file_system_context_->CreateFileSystemOperation(url, &error));
// ! take a raw pointer to the contents of the unique_ptr
FileSystemOperation* operation_raw = operation.get();
// ! call BeginOperation passing the move'd unique_ptr, freeing operation
OperationID id = BeginOperation(std::move(operation));
base::AutoReset<bool> beginning(&is_beginning_operation_, true);
if (!operation_raw) {
DidFinish(id, std::move(callback), error);
return id;
}
PrepareForWrite(id, url);
// ! use the raw free'd pointer here.
operation_raw->Truncate(url, length,
base::BindOnce(&FileSystemOperationRunner::DidFinish,
weak_ptr_, id, std::move(callback)));
return id;
}
I think that to trigger this, you'd need either a malformed blob in the blob registry, or access to the FileWriter api, so at present this would require a compromised renderer.
I've attached two PoCs that should trigger this issue; it looks like the runtime for either approach from javascript should take ~2 days on my machine. (I'd suggest patching the OperationId typedef to short to reproduce, unless you are extremely patient).
$ python ./copy_mojo_js_bindings.py /path/to/chrome/.../out/Asan/gen
$ python -m SimpleHTTPServer&
$ /ssd/chrome_trunk/src/out/Asan/chrome --enable-blink-features=MojoJS --user-data-dir=/tmp/aa 'http://localhost:8000/id_overflow_no_filewriter.html'
Proof of Concept:
https://github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/46571.zip
8.8 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
REQUIRED
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
9.3 High
CVSS2
Access Vector
NETWORK
Access Complexity
MEDIUM
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:N/AC:M/Au:N/C:C/I:C/A:C
0.017 Low
EPSS
Percentile
87.6%