溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么分析CobaltStrike3.12

發(fā)布時(shí)間:2021-12-24 10:16:45 來(lái)源:億速云 閱讀:126 作者:柒染 欄目:網(wǎng)絡(luò)安全

怎么分析CobaltStrike3.12,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

1 - 概述

CobaltStrike是一款內(nèi)網(wǎng)滲透的商業(yè)遠(yuǎn)控軟件,支持自定義腳本擴(kuò)展,功能非常強(qiáng)大。前段時(shí)間Github上有好心人放出了CobaltStrike3.12的試用版,接著Lz1y很快就放出了Patch版,加上熱心老哥提供了的xor64.bin(試用版中沒(méi)有這個(gè)文件),一個(gè)比較完美的最新可用版本誕生了。下面我們看下最新試用版是如何被完美Patch的。

2 - 上手

CobaltStrike(下面簡(jiǎn)稱CS)主體代碼是用Java開(kāi)發(fā)的,逆起來(lái)比較友好。用jd-gui反編譯cobaltstrike.jar文件,可以看到代碼幾乎沒(méi)有做加固。Java源碼沒(méi)有任何混淆。但是查看反編譯的源碼時(shí),很多地方出現(xiàn)了// INTERNAL ERROR //,這里我推薦一款Java反編譯工具luyten,幾乎可以100%反編譯獲得cobaltstrike.jar源碼。

CS的License處理邏輯在common/License.java文件中:

package common;

import aggressor.*;

import javax.swing.*;

import java.awt.*;

public class License

{

    private static long life;

    private static long today;

    private static long start;

    private static long difference;



    private static long getTimeSinceStart() {

        final Prefs options = Prefs.getPreferences();

        License.today = System.currentTimeMillis();

        License.start = options.getLongNumber("cobaltstrike.start.int", 0L);

        if (License.start == 0L) {

            options.set("cobaltstrike.start.int", License.today + "");

            options.save();

            License.start = License.today;

        }

        return License.difference = (License.today - License.start) / 86400000L;

    }



    public static void checkLicenseGUI(final Authorization auth) {

        getTimeSinceStart();

        if (License.difference > License.life || License.today - License.start < 0L) {

            JOptionPane.showMessageDialog(null, "Your Cobalt Strike trial is now expired.\nPlease purchase a license and use the\nsoftware update feature to continue.\n\nFor details, visit:\nhttps://www.cobaltstrike.com/", null, 0);

            System.exit(0);

        }

        else {

            final long left = License.life - License.difference;

            String form = left + " day";

            if (left != 1L) {

                form += "s";

            }

            CommonUtils.print_warn("This is a trial version of Cobalt Strike. You have " + form + " left of your trial. If you purchased Cobalt Strike. Run the Update program and enter your license.");

            CommonUtils.print_trial("WARNING! This trial is *built* to get caught by standard defenses. The licensed product does not have these restrictions. See: http://blog.cobaltstrike.com/2015/10/14/the-cobalt-strike-trials-evil-bit/");

            JOptionPane.showMessageDialog(null, "This is a trial version of Cobalt Strike.\nYou have " + form + " left of your trial.\n\nIf you purchased Cobalt Strike. Run the\nUpdate program and enter your license.", null, 1);

        }

    }



    public static boolean isTrial() {

        return true;

    }



    public static void checkLicenseConsole(final Authorization auth) {

        getTimeSinceStart();

        if (License.difference > License.life || License.today - License.start < 0L) {

            CommonUtils.print_error("Your Cobalt Strike trial is now expired. Please purchase a license and use the software update feature to continue. For details, visit: https://www.cobaltstrike.com/");

            System.exit(0);

        }

        else {

            final long left = License.life - License.difference;

            String form = left + " day";

            if (left != 1L) {

                form += "s";

            }

            CommonUtils.print_warn("This is a trial version of Cobalt Strike. You have " + form + " left of your trial. If you purchased Cobalt Strike. Run the Update program and enter your license.");

            CommonUtils.print_trial("WARNING! This trial is *built* to get caught by standard defenses. The licensed product does not have these restrictions. See: http://blog.cobaltstrike.com/2015/10/14/the-cobalt-strike-trials-evil-bit/");

        }

    }



    static {

        License.life = 21L;

        License.today = 0L;

        License.start = 0L;

        License.difference = 0L;

    }

}

代碼邏輯很清晰,這里我們有兩個(gè)方向進(jìn)行patch:

  1. 修改License.life無(wú)限延長(zhǎng)試用

  2. 修改isTrial()返回值,偽造成正式版

因?yàn)镃S很多地方的試用版和正式版處理邏輯不同,所以修改了isTrial()返回值之后,我們還需要修改所有調(diào)用了isTrial()函數(shù)的地方,對(duì)代碼進(jìn)行調(diào)整。另外試用版CS留了一些特征指紋和限制,我們也需要去除相應(yīng)的特征代碼。

修改重打包

既然知道了破解思路,我們看下如何動(dòng)手操作去修改源碼并重編譯。Java編程中我們可以使用jar工具將一系列的.class文件打包成jar包,供其他java程序使用。我們也可以修改jar包中.class文件的內(nèi)容,并重新編譯打包。比如修改demo.jar中的kingx.class并重新編譯的過(guò)程如下:

  1. 使用jd-gui、luyten等工具把demo.jar包中的class反編譯成源碼,從中提取得到kingx.java

  2. 執(zhí)行jar xvf demo.jar 解壓demo.jar得到j(luò)ar包的子文件(注意會(huì)解壓到當(dāng)前目錄),將kingx.java文件放置到與example.class文件同一目錄

  3. 執(zhí)行javac -cp a.jar;b.jar;c.jar kingx.java重新編譯。(或者javac -cp demo.jar kingx.java)得到新的kingx.class文件。

    其中a.jar、b.jar、c.jar是依賴包,一般直接依賴一個(gè)原始解壓的demo.jar包即可

  4. 確保編譯后的kingx.class替換了原來(lái)的kingx.class文件(可以通過(guò)jd-gui反編譯查看)

  5. 執(zhí)行jar -uvf  demo.jar com/some/path/kingx.class更新demo.jar包

更新jar包中的class文件時(shí),新的class文件目錄路徑需要與原package路徑保持一致。比如修改了aggressor.AggressorClient.java并重新編譯之后,更新jar包的命令如下:

17:16 KINGX modified_java_files >jar -uvf cobaltstrike-with-xor64.jar aggressor/AggressorClient*.class

正在添加: aggressor/AggressorClient$1.class(輸入 = 650) (輸出 = 403)(壓縮了 38%)

正在添加: aggressor/AggressorClient$2.class(輸入 = 1263) (輸出 = 704)(壓縮了 44%)

正在添加: aggressor/AggressorClient.class(輸入 = 11115) (輸出 = 5196)(壓縮了 53%)

可能遇到的問(wèn)題

修改后的java文件在重新編譯為class文件時(shí),可能會(huì)遇到很多奇怪的報(bào)錯(cuò)。有時(shí)候是因?yàn)榉淳幾g出的源碼存在錯(cuò)誤導(dǎo)致的,這個(gè)時(shí)候我們可以將luyten、jad、jd-gui等反編譯工具結(jié)合使用,盡量還原成正確的源碼,再重新編譯。

比如:AggressorClient.java,jad aggressor/AggressorClient*.classluyten反編譯得到的源碼是不一樣的。

3 - 試用版Patch詳細(xì)分析

Tips: 以下代碼片段中行首的 - 代表刪除,+ 代表新增

Patch 試用版本

修改common.License,去掉checkLicenseGUI()、checkLicenseConsole()函數(shù)體,修改isTrial()返回值為true

修改主程序標(biāo)題

aggressor.AggressorClient,修改getTitle()函數(shù)

解除listener同類數(shù)量限制

一個(gè)teamserver默認(rèn)只能監(jiān)聽(tīng)一個(gè)listener,可以通過(guò)修改代碼去除限制。

aggressor.dialogs.ListenerDialog,去除以下代碼:

...

else if (Listener.isEgressBeacon(payload) && DataUtils.isBeaconDefined(this.datal) && !name.equals(DataUtils.getEgressBeaconListener(this.datal))) {

    DialogUtils.showError("You may only define one egress Beacon per team server.\nThere are a few things I need to sort before you can\nput multiple Beacon HTTP/DNS listeners on one server.\nSpin up a new team server and add your listener there.");

}

...

去除EICAR后門(mén)指紋特征

試用版有幾個(gè)地方存在EICAR特征字符:X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*,都需要進(jìn)行清理:

common.ListenerConfig

修改pad()函數(shù):

-  result.append("5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*\u0000");

+  result.append("123\u0000");

resources/template.x64.ps1、resources/template.x86.ps1

-  $eicar = 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*'

+  $eicar = ''

server.ProfileEdits

-  c2profile.addCommand(".http-get.server", "!header", "X-Malware: X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*");

-  c2profile.addCommand(".http-post.server", "!header", "X-Malware: X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*");

-  c2profile.addCommand(".http-stager.server", "!header", "X-Malware: X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*");

-  c2profile.addCommand(".stage.transform-x86", "append", "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*");

-  c2profile.addCommand(".stage.transform-x64", "append", "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*");

common.ArtifactUtils

因?yàn)橐呀?jīng)修改了License.isTrial()返回值為false,所以下面這段改不改也沒(méi)什么影響。

if (License.isTrial()) {

    packer.addString("X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*");

    CommonUtils.print_trial("Added EICAR string to " + s);

}

添加X(jué)OR64.BIN

生成payload時(shí),會(huì)調(diào)用common.ArtifactUtils中的XorEncode()進(jìn)行編碼:

public static byte[] _XorEncode(final byte[] data, final String arch) {

    AssertUtils.TestArch(arch);

    if ("x86".equals(arch)) {

        final byte[] decoder = XorStub();

        final byte[] payload = XorEncoder.encode(data);

        return CommonUtils.join(decoder, payload);

    }

    if ("x64".equals(arch)) {

        final byte[] decoder = CommonUtils.readResource("resources/xor64.bin");

        final byte[] payload = XorEncoder.encode(data);

        return CommonUtils.join(decoder, payload);

    }

    return new byte[0];

}

public static byte[] XorEncode(final byte[] data, final String arch) {

    if (License.isTrial()) {

        CommonUtils.print_trial("Disabled " + arch + " payload stage encoding.");

        return data;

    }

    AssertUtils.Test(data.length > 16384, "XorEncode used on a stager (or some other small thing)");

    return _XorEncode(data, arch);

}

試用版不會(huì)進(jìn)行payload stage encoding,所以試用版軟件包中并沒(méi)有帶xor.bin/xor64.bin文件,如果有這兩個(gè)文件的話,可以添加到resources/xor.bin、resources/xor64.bin路徑下。

關(guān)于怎么分析CobaltStrike3.12問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問(wèn)一下細(xì)節(jié)
推薦閱讀:
  1. CrackMe 分析
  2. volatile分析

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI