美文网首页
CS stage隐匿与汉化

CS stage隐匿与汉化

作者: RabbitMask | 来源:发表于2021-10-08 13:59 被阅读0次

    写在前面

    继我们前面铺垫的章节,我们继续改造我们的Cobaltstrike,本章我们对Beacon Stage进行特征掩藏,以更好的保护我们的C2服务器。同时目前已有成熟的汉化方案开源,我们纳入改造以适应我们的项目。

    http://cn-sec.com/archives/300922.html Cobaltstrike4.x基础特征修改之从端口到checksum8

    Beacon Stage:

    Beacon Staging Server 就是分阶段模式中,提供shellcode等功能扩展存储的Stage服务器。
    Beacon Staging Server的作用是为了防止Payload过大或者适应不同的攻击场景,可以分阶段进行payload投递。
    首先通过投递一个被称为stager的小巧的payload,然后去Beacon staging server下载体积较大更复杂的stage,并且访问stage的URL通过checksum8进行校验。
    
    由Windows Execute 模块生成的就是Stager。
    stager上线逻辑:——>运行stager——>自动生成并访问符合checksum8校验的URI进行远程下载stage——>上线
    

    stage隐匿的常规思路:

    1.修改checkSum8算法,使得按照默认的checkSum8 URI无法下载stage文件。
    2.修改内部beacon的解密密钥,使得NSE解析脚本无法解析下载到的stage的信息。
    3.从防火墙上限制访问beacon的端口。
    4.每次手动kill掉site管理中的stage和stage64
    

    我们这里选择针对dll和源码的xorkey修改作为方案。

    XOR KEY修改

    现成脚本地址:https://github.com/ca3tie1/CrackSleeve/blob/master/CrackSleeve.java
    脚本原理参考:https://mp.weixin.qq.com/s/Pneu8R0zoG0ONyFXF9VLpg

    private static byte[] OriginKey = {58, 68, 37, 73, 15, 56, -102, -18, -61, 18, -67, -41, 88, -83, 43, -103};
    

    带参运行:

    或者构建运行:java -classpath MyCS.jar;./ mytools.CrackSleeve decode,即可以获得加密后的dll文件
    关于可能遇到的报错问题,这里抄下师傅们的作业,如下是4.0和4.1版本的代码片段,来自零队,所以师傅对脚本源码进行了修改:

    在4.3版本中的片段如下:

    # common.SleevedResource line9
    public static void Setup(byte[] var0) {
       singleton = new SleevedResource(var0);
    }
    # common.Authorization line65
    SleevedResource.Setup(var15);
    

    跟踪发现是从auth文件中读key所得,所以脚本维持原样即可。顺便吐槽下CS4.3为什么所有的变量名几乎都是var*,var1-var18应有尽有,故意而为之以降低代码可读性达到代码保护的效果???

    先说下异或问题,已知异或key 3.x为0x69,4.x为0x2e

    4.3中这里写的是十进制46 对应二进制即 0x2e,我们这里进行修改,十进制100对应十六进制64:

    # beacon.BeaconPayload line3
    public static byte[] beacon_obfuscate(byte[] var0) {
       byte[] var1 = new byte[var0.length];
    
       for(int var2 = 0; var2 < var0.length; ++var2) {
    //         var1[var2] = (byte)(var0[var2] ^ 46);
          var1[var2] = (byte)(var0[var2] ^ 100);
       }
    
       return var1;
    }
    

    dll解密完成后,进入修改环节,在ida中打开,进行二进制检索,Search▶Sequence ofBytes或者alt+B,找到xor:

    修改其中的hex

    然后应用即可:

    其它dll修改类似

    beacon.dll
    beacon.x64.dll
    dnsb.dll
    dnsb.x64.dll
    pivot.dll
    pivot.x64.dll
    extc2.dll
    extc2.x64.dll
    

    师傅们的文章里都提到了上述dll,为防止4.3版本又在这里留了新的暗桩,这里用笨办法对下属非功能dll挨个审查了一般,未发现新的dll使用该xor,所以继续抄之前版本的作业即可,机制无改变,排雷结束。

    这里略改了下上面提到的脚本的加密策略,不在输入新的key,使用原key:

            if (option.toLowerCase().equals("encode"))
            {
    //            if (args.length <= 1){
    //                System.out.println("[-] Please enter key.");
    //                System.exit(0);
    //            }
    //            String CustomizeKeyStr = args[1];
    //            if (CustomizeKeyStr.length() < 16)
    //            {
    //                System.out.println("[-] key length must be 16.");
    //                System.exit(0);
    //            }
    //            System.out.println("Init Key: "+CustomizeKeyStr.substring(0,16));
                CustomizeKey = OriginKey;
            }
    

    直接带参运行即可对修改后的dll进行加密

    将加密后的sleeve直接放到根目录即可,进行重构的时候会覆盖原项目,再说一句,记得点构建工件前点重建项目!!!
    改动前:

    改动后:

    在教程最后,破解相关代码全部未删除一并封装到了最终的cobaltstrike.jar中,方便各位小伙伴学习

    当然也是可以单独调用的:

    java -classpath cobaltstrike.jar;./ mytools.CrackSleeve          //dll加解密工具,小改动encode,封装官方key不再传参
    java -classpath cobaltstrike.jar;./ mytools.GetMd5               //内置公钥哈希校验
    java -classpath cobaltstrike.jar;./ mytools.RSAKeyPairGenerator  //auth生成脚本,4.3官方key已封装
    

    checkSum8算法修改

    修改checkSum8算法,使得按照默认的checkSum8 URI无法下载stage文件。

    checkSum8算法的修改方式与其优缺点:
    1.修改checkSum8的92L与93L为非默认的值,从而加大连接获取难度。
    缺点:最多进过256次破解,也能够导致stage被下载。
    2.通过修改sum值算法,固定下载URI,这样只有指定的uri可以获取到下载连接
    缺点:更换URI需要重新编译计算sum值。

    Beacon Stager listener 去特征https://mp.weixin.qq.com/s/HibtLfikI_0ezcLVCRxqaA
    关于CobaltStrike的Stager被扫问题https://mp.weixin.qq.com/s/0MPM3bysJJYr5jbRnES_Vg

    其中修改默认值92L、93L更为简单

    # cloudstrike.WebServer line166
    public static boolean isStager(String uri) {
       return checksum8(uri) == 92L;
    }
    
    public static boolean isStagerX64(String uri) {
       return checksum8(uri) == 93L && uri.matches("/[A-Za-z0-9]{4}");
    }
    

    但优缺点大家仁者见仁智者见智,目前的团队内部版本暂未采用此方案。

    汉化

    https://github.com/Twi1ight/CSAgent

    这个已经有师傅给出4.x通用的成熟方案了,借助java的预加载进行非侵入式篡改。

    但Releases中加入了作者的个人banner的license修改,导致和我们的服务端不能适配,不过师傅贴心的提供了源码,且源码中并未有banner添加,所以在这里自己编译顺便进行小小的修改。
    主要改动涉及以下,首先我们前面已经提到了,暗桩和认证部分我们已经自己处理好了,所以这些通通可以注释掉。

    if (className == null) {
        return classfileBuffer;
        // } else if (className.equals("beacon/BeaconData")) {
        //     // 暗桩修复,修改zip包后,30分钟所有命令都会变成exit,非侵入式修改下其实不需要
        //     CtClass cls = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
        //     CtMethod mtd = cls.getDeclaredMethod("shouldPad");
        //     mtd.setBody("{$0.shouldPad = false;}");
        //     return cls.toBytecode();
    } else if (className.equals("common/Authorization")) {
        // 设置破解key
        CtClass cls = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
        String func = "public static byte[] hex2bytes(String s) {" +
                "   int len = s.length();" +
                "   byte[] data = new byte[len / 2];" +
                "   for (int i = 0; i < len; i += 2) {" +
                "       data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));" +
                "   }" +
                "   return data;" +
                "}";
        CtMethod hex2bytes = CtNewMethod.make(func, cls);
        cls.addMethod(hex2bytes);
    
        CtConstructor mtd = cls.getDeclaredConstructor(new CtClass[]{});
        mtd.setBody("{$0.watermark = 1234567890;" +
                "$0.validto = \"forever\";" +
                "$0.valid = true;" +
                "common.MudgeSanity.systemDetail(\"valid to\", \"perpetual\");" +
                "common.MudgeSanity.systemDetail(\"id\", String.valueOf($0.watermark));" +
                "common.SleevedResource.Setup(hex2bytes(\"" + hexkey + "\"));" +
                "}");
        return cls.toBytecode();
    }
    

    然后是对common.MudgeSanity的修改,主要是增加了systeminfo中的Loader内容

     else if (className.equals("common/MudgeSanity")) {
        CtClass cls = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
        CtMethod mtd = cls.getDeclaredMethod("systemInformation");
        mtd.instrument(
                new ExprEditor() {
                    public void edit(MethodCall m)
                            throws CannotCompileException {
                        if (m.getClassName().equals("java.lang.StringBuffer")
                                && m.getMethodName().equals("append")) {
                            m.replace("{" +
                                    "if ($1.startsWith(\"Version:\")) {" +
                                    "   $1 += \"Loader: https://github.com/Twi1ight/CSAgent\\n\";" +
                                    "}" +
                                    "$_ = $proceed($$);" +
                                    "}");
                        }
                    }
                });
        return cls.toBytecode();
    

    即这里,原版和csagent对比:

    不过这里不影响license比对,可以不改动,但是如果用的Releases中打好的包,是无法登录c2的,因为那个修改是改的aggressor.Aggressor

    if (className.equals("aggressor/Aggressor") || className.equals("server/TeamServer") || className.equals("aggressor/headless/Start")) {
        ctClass = this.classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
        ctMethod = ctClass.getDeclaredMethod("main");
        this.classPool.importPackage("java.lang.reflect");
        ctMethod.insertBefore("Field field = aggressor.Aggressor.class.getDeclaredField(\"VERSION\");field.setAccessible(true);Field modifiersField = null;try {    modifiersField = Field.class.getDeclaredField(\"modifiers\");} catch (NoSuchFieldException e) {    try {        Method getDeclaredFields0 = Class.class.getDeclaredMethod(\"getDeclaredFields0\", new Class[]{boolean.class});        boolean accessibleBeforeSet = getDeclaredFields0.isAccessible();        getDeclaredFields0.setAccessible(true);        Field[] fields = (Field[]) getDeclaredFields0.invoke(Field.class, new Object[]{Boolean.FALSE});        getDeclaredFields0.setAccessible(accessibleBeforeSet);        for (int i=0; i<fields.length; i++){           Field field = fields[i];            if (\"modifiers\".equals(field.getName())) {                modifiersField = field;                break;            }        }        if (modifiersField == null) {            throw e;        }    } catch (NoSuchMethodException ex) {        e.addSuppressed(ex);        throw e;    } catch (InvocationTargetException ex) {        e.addSuppressed(ex);        throw e;    }}modifiersField.setAccessible(true);modifiersField.setInt(field, Modifier.STATIC);String fieldValue = (String) field.get(null);field.set(null, fieldValue.replace(\")\", \"-Twi1ight@T00ls.Net)\"));");
        return ctClass.toBytecode();
    }
    

    也就是相当于修改主函数aggressor/Aggressor中的VERSION 字段:

    public class Aggressor {
       public static final String VERSION = "4.3 (20210317) " + (License.isTrial() ? "Trial" : "Licensed to WingsSec");
       public static final String VERSION_SHORT = "4.3";
       public static MultiFrame frame = null;
       ... ...
    }
    

    另外大家在使用csagent的时候还需要传参,这个参数传递如下:

    最终出现在我们上面提到的破解部分,所以这块也是不需要的:

    else if (className.equals("common/Authorization")) {
        // 设置破解key
        ... ...
        mtd.setBody("{$0.watermark = 1234567890;" +
                "$0.validto = \"forever\";" +
                "$0.valid = true;" +
                "common.MudgeSanity.systemDetail(\"valid to\", \"perpetual\");" +
                "common.MudgeSanity.systemDetail(\"id\", String.valueOf($0.watermark));" +
                "common.SleevedResource.Setup(hex2bytes(\"" + hexkey + "\"));" +
                "}");
        return cls.toBytecode();
    }
    

    最终修改如下:

    public class PreMain {
        public static void premain(String agentArgs, Instrumentation inst) {
    //        if (agentArgs == null) {
    //            System.out.println("[CSAgent] Agent options not found!");
    //            return;
    //        }
            inst.addTransformer(new CobaltStrikeTransformer(), true);
        }
    
        static class CobaltStrikeTransformer implements ClassFileTransformer {
            private final ClassPool classPool = ClassPool.getDefault();
    //        private final String hexkey;
            private final Boolean needTranslation;
    
            public CobaltStrikeTransformer() {
    //            this.hexkey = args;
                this.needTranslation = Files.exists(Paths.get("resources/translation.txt"));
            }
            ... ...
    }
    

    总的来说,移除破解功能,保留汉化功能,这样一个好处就是可适用于任意破解版本的汉化。

    那么最终客户端的使用为:

    java -XX:ParallelGCThreads=4 -XX:+AggressiveHeap -XX:+UseParallelGC -javaagent:CSAgent.jar -jar cobaltstrike.jar
    

    服务端正常使用即可,不需要额外修改,最终效果:

    相关文章

      网友评论

          本文标题:CS stage隐匿与汉化

          本文链接:https://www.haomeiwen.com/subject/xxfxoltx.html