Cobalt Strike折騰踩坑填坑記錄

0X00 背景

最近在做滲透測試相關的工作,因工作需要準備用Cobalt Strike,老早都知道這款神器,早幾年也看過官方的視頻教程,但英文水平太渣當時很多都沒聽懂,出於各種原因後來也沒怎麼深入瞭解,所以一直都是處在大概瞭解的層面上。直到現在有需求了纔開始研究,過程中體會也是蠻深,技術這東西真的不能只停留在知道和了解這個層面,就像學一門語言一樣需要多動手去實踐才能熟練運用的。當然在深入研究某一門技術的過程中難免遇到各種各樣的問題,一步一步解決這些問題纔是真正學習的過程。對Cobalt strike的學習和研究中我也同樣遇到很多的問題,辛得一些素不相識的師傅無私幫助,才解決掉所有的問題,這裏把過程中一些問題和解決辦法記錄下來,以便以後查閱,同時也希望對剛接觸Cobatl strike的朋友有所幫助。

0x01 基礎原理

基礎使用和原理網上有大把的文章和教程,我這裏只闡述我個人理解的幾個基本點,先說stagestager,在傳統的遠程控制類軟件我們都是直接生成一個完整功能的客戶端(其中包含了各種遠控所需功能代碼),比如灰鴿子(…這裏年齡已暴露。。),然後將客戶端以各種方式上傳至目標機器然後運行,運行後目標機器與我們控制端點對點的通訊。而Cobalt strike把這部分拆解爲兩部(stagestager),stager 是一個小程序,通常是手工優化的彙編指令,用於下載 stage、把它注入內存中運行。stage則就是包含了很多功能的代碼塊,用於接受和執行我們控制端的任務並返回結果。stager 通過各種方式(如http、dns、tcp等)下載stage並注入內存運行這個過程稱爲Payload Staging。同樣Cobalt strike也提供了類似傳統遠控上線的方式,把功能打包好直接運行後便可以與teamserver通訊,這個稱爲Payload Stageless,生成Stageless的客戶端可以在 Attack->Package->Windows Executeable(s)下生成。這部分我也是在研究dns上線時候纔算分清楚,這裏需要感謝B0y1n4o4師傅的幫助

0x02 關於破戒

目前網上公佈版本大多爲官方試用版破戒而來且最高版爲3.14(5月4號)版,我託朋找了一份3.14官方原版的來,原版的本身沒有試用版那麼多限制,破戒也相對容易,只需繞過license認證即可,這裏在文件common/Authorization.class的構造函數中。

public Authorization() {
    String str = CommonUtils.canonicalize("cobaltstrike.auth");
    if (!(new File(str)).exists())
      try {
        File file = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI());
        if (file.getName().toLowerCase().endsWith(".jar"))
          file = file.getParentFile(); 
        str = (new File(file, "cobaltstrike.auth")).getAbsolutePath();
      } catch (Exception exception) {
        MudgeSanity.logException("trouble locating auth file", exception, false);
      }  
    byte[] arrayOfByte1 = CommonUtils.readFile(str);
    if (arrayOfByte1.length == 0) {
      this.error = "Could not read " + str;
      return;
    } 
    AuthCrypto authCrypto = new AuthCrypto();
    byte[] arrayOfByte2 = authCrypto.decrypt(arrayOfByte1);
    if (arrayOfByte2.length == 0) {
      this.error = authCrypto.error();
      return;
    } 
    String[] arrayOfString = CommonUtils.toArray(CommonUtils.bString(arrayOfByte2));
    if (arrayOfString.length < 4) {
      this.error = "auth content is only " + arrayOfString.length + " items";
      return;
    } 
    this.licensekey = arrayOfString[0];
    if ("forever".equals(arrayOfString[1])) {
      this.validto = arrayOfString[1];
      MudgeSanity.systemDetail("valid to", "perpetual");
    } else {
      this.validto = "20" + arrayOfString[1];
      MudgeSanity.systemDetail("valid to", CommonUtils.formatDateAny("MMMMM d, YYYY", getExpirationDate()));
    } 
    this.watermark = CommonUtils.toNumber(arrayOfString[2], 0);
    this.valid = true;
    MudgeSanity.systemDetail("id", this.watermark + "");
  }

這裏需要把該類的watermarklicensekeyvalidtovalid實例域手動設置即可,如下面代碼

  public Authorization() {
    this.valid = true;
    this.validto = "forever";
    this.licensekey = "Cartier";
    this.watermark = 1;
    MudgeSanity.systemDetail("valid to", "perpetual");
    MudgeSanity.systemDetail("id", this.watermark + "");
  }

剩餘下其他關於listener個數限制可以參考ssooking師傅的博客查看。

Exit暗樁

剩下的一個就是Cobalt strike作者留下的一個exit的暗樁問題,這裏還是請教了ssooking師傅才知道,否則我這Java渣渣不知道要找到什麼時候,這裏再次對ssooking師傅的幫助表示感謝。
作者在程序裏留了個驗證jar文件完整性的功能,如果更改了jar包的文件 這個完整性就遭到破壞,作者會在目標上線30分鐘後,在此以後添加的命令任務後門加一個exit的指令,目標的beacon就自動斷開了,如下圖。
在這裏插入圖片描述
代碼在beacon/BeaconC2.class

  protected boolean isPaddingRequired() {
    boolean bool = false;
    try {
      ZipFile zipFile = new ZipFile(this.appd);
      Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
      while (enumeration.hasMoreElements()) {
        ZipEntry zipEntry = enumeration.nextElement();
        long l1 = CommonUtils.checksum8(zipEntry.getName());
        long l2 = zipEntry.getName().length();
        if (l1 == 75L && l2 == 21L) {
          if (zipEntry.getCrc() != 1661186542L && zipEntry.getCrc() != 1309838793L)
            bool = true; 
          continue;
        } 
        if (l1 == 144L && l2 == 20L) {
          if (zipEntry.getCrc() != 1701567278L && zipEntry.getCrc() != 3030496089L)
            bool = true; 
          continue;
        } 
        if (l1 == 62L && l2 == 26L && zipEntry.getCrc() != 2913634760L && zipEntry.getCrc() != 376142471L)
          bool = true; 
      } 
      zipFile.close();
    } catch (Throwable throwable) {}
    return bool;
  }
public BeaconC2(Profile paramProfile, BeaconData paramBeaconData, Resources paramResources) {
    this.c2profile = paramProfile;
    this.resources = paramResources;
    this.data = paramBeaconData;
    this.channel_http = new BeaconHTTP(paramProfile, this);
    this.channel_dns = new BeaconDNS(paramProfile, this);
    this.socks = new BeaconSocks(this);
    this.appd = getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
    paramBeaconData.shouldPad(isPaddingRequired());	//這裏調用BeaconData類的shouldPad
    this.parsers.add(new MimikatzCredentials(paramResources));
    this.parsers.add(new MimikatzSamDump(paramResources));
    this.parsers.add(new DcSyncCredentials(paramResources));
    this.parsers.add(new MimikatzDcSyncCSV(paramResources));
    this.parsers.add(new ScanResults(paramResources));
    this.parsers.add(new NetViewResults(paramResources));
  }

再看beacon/BeaconData.class

  
  public void shouldPad(boolean paramBoolean) {
    this.shouldPad = paramBoolean;
    this.when = System.currentTimeMillis() + 1800000L;
  }
  
  public void task(String paramString, byte[] paramArrayOfbyte) {
    synchronized (this) {
      List<byte[]> list = getQueue(paramString);
      //這裏判斷文件完整性和beacon上線是否草果30分鐘
      if (this.shouldPad && System.currentTimeMillis() > this.when) {
        CommandBuilder commandBuilder = new CommandBuilder();
        commandBuilder.setCommand(3);
        commandBuilder.addString(paramArrayOfbyte);
        list.add(commandBuilder.build());
      } else {
        list.add(paramArrayOfbyte);
      } 
      this.tasked.add(paramString);
    } 
  }

破戒方法是直接更改shouldPad方法中的this.shouldPad = paramBoolean;this.shouldPad = false;

0x03 CDN+反代隱藏Teamserver

Domain Fronting

這部分原理參考垃圾桶師傅的文章(點這裏),這裏幫垃圾桶師傅填一個他在文章中說遇到的坑。
在這裏插入圖片描述
在這裏插入圖片描述
這裏垃圾桶師傅在添加Listener的時候Host填寫的是CDN的地址,在使用powershell下載stager運行,stager再去下載stage的時候就是直接訪問cdn的地址下載,但是malleable profile沒有配置制定stager的行爲,所以無法正常回源到teamserver下載,這裏只需要在profile文件中配置http-stager模塊,像http-get一樣指定好Host即可從CDN訪問到teamserver下載stage了。

Proxy

反向代理原理這裏借用垃圾桶師傅的圖,我就不具體再闡述,垃圾桶師傅已經講得很明白。
在這裏插入圖片描述
我使用的是Nginx做的反向代理,這裏如果剛研究這個的朋友可能會遇到客戶端上線後IP是Nginx服務器IP,走CDN的時候顯爲CDN節點IP的情況,這裏有兩個解決辦法,先看看server/ServerUtils.class類中代碼:

  public static String getRemoteAddress(Profile paramProfile, Map paramMap) {
    boolean bool = paramProfile.option(".http-config.trust_x_forwarded_for");
    if (bool && paramMap.containsKey("X-Forwarded-For")) {
      String str1 = (String)paramMap.get("X-Forwarded-For");
      if (str1.indexOf(",") > -1) {
        str1 = CommonUtils.strrep(str1, " ", "");
        StringStack stringStack = new StringStack(str1, ",");
        str1 = stringStack.shift();
      } 
      if (CommonUtils.isIP(str1) || CommonUtils.isIPv6(str1))
        return str1; 
      CommonUtils.print_error("remote address '" + (String)paramMap.get("X-Forwarded-For") + "' in X-Forwarded-For header is not valid.");
    } 
    String str = (String)paramMap.get("REMOTE_ADDRESS");
    return "".equals(str) ? "" : str.substring(1);
  }
}

這裏Cobatl Strike可以從HttpHeader中的REMOTE_ADDRESSX-Forwarded-For中取得IP,我們要麼在Nginx反向代理的時候設置REMOTE_ADDRESS值,要麼在profile的配置文件中的http-config模塊設置trust_x_forwarded_for值爲true,這也是看了代碼從知道有這個配置,英文渣渣表示很慚愧,官方寫得很詳細。
這裏有個問題就是反向代理時候自定義REMOTE_ADDRESS時候往往無效,不知道具體啥情況,我之前在另外的機器上都有測試成功過。

0x04 DNS上線

一個未填的坑

這個坑是研究和使用Cobalt Strike來最大一個坑,至發文今日都沒有解決。問題是出在使用DNS的listener不管是beacon_dns/reverse_http還是beacon_dns/reverse_dns_txt時候,若使用staging方式stager在下載stage注入到內存中的時候崩掉,如下圖。
在這裏插入圖片描述
而若使用beacon_dns/reverse_http時候,選用非純dns模式就沒問題,非純dns模式狀態下stager在下載stage時候使用http方式,stage只要成功下載注入內存後便可以mode改用dns方式來通訊了,要是有師傅知道怎麼回事還賜教。

DNS Listener特性

最後經B0y1n4o4師傅指點,改用stageless方式上線就沒有問題了。但是在使用dns上線的時候還需要注意個問題。在添加Listener的時候beacon_dns/reverse_httpbeacon_dns/reverst_dns_txt都需要填寫端口信息,如下圖。
在這裏插入圖片描述
如果端口使用80的情況下,上線之後的通訊優先使用http方式,若想用純dns通訊的話就需要在上線之後首先使用mode 指令切換至dns、dns-txt或者dns6模式。添加listener自定一個非80的端口上線之後所以的通訊都將默認採用dns方式,且不能使用mode切換成http模式。

0x05 結語

以上均爲我個人一些研究測試結論,有不到之處還請多多指正,Cobalt Strike確實是一個蠻強大的工具,還有很多內容和技術有待研究,本人也正在學習Java,爭取早日通讀內核代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章