使用mitmproxy审计浏览行为并发送日志到QRadar SIEM

原创内容,转载请注明来源https://songyue.wang

本人正在学习使用QRadar SIEM,想在家用网络环境中模拟企业场景,向SIEM添加一些真实的日志源。Web代理是常见的保护企业免受信息外泄,恶意网站,内部人员威胁的手段之一。本文介绍如何使用开源的web代理工具mitmproxy检查网络中PC的HTTP/HTTPS流量,并将日志发送到QRadar SIEM统一管理分析。此笔记中所用到的工具均为开源或商业软件免费版。

SIEM记录该用户曾收到来自portali.hku.hk的HTTPS响应

大致思路

使用mitmproxy的挂脚本功能实现用户在访问外网时把日志JSON以HTTP POST形式发送,在QRadar服务端上监听这个HTTP Request,对JSON进行剖析,使之以正确的格式显示在看板上并且识别对应安全事件。

前置条件

  • 已安装IBM Security QRadar SIEM Community Edition免费版(在VMware虚拟机中安装QRadar,可以参考这篇笔记
  • 已在另一个实体主机或虚拟机上,安装Ubuntu/Debian操作系统

配置新的QRadar日志来源

首先使用QRadar服务器IP访问控制台,选择管理 => 日志来源。在新窗口内选择管理日志源 ,待列出已有日志来源之后,点击新建日志源 => 单个日志源,显示新增日志来源向导。

按照下列信息配置日志源:

日志源类型: Universal DSM
协议类型: HTTP Receiver
名称: mitmproxy
Log Source Identifier: mitmproxy
Communication Type: HTTP
Listen Port: 12469

Log Source Identifier需要唯一,Communication Type选择HTTP(我之后慢慢研究下如何设置TLS证书改成加密传输日志),Listen Port也需要唯一(比如之后添加其它设备,依次增加端口号,如12470,12471等)。完成设置后,点一下启动测试,QRadar会检查有没有参数错误(例如端口占用)。

这个时候可以看到新的日志源已经启用,回到管理页面进行部署变更

设置QRadar服务器端口转发

由于我的QRadar是设置Vmware VLAN的VMnet1,只能与宿主机通信,因此需要在宿主机场进行把安全设备发来的日志转发到QRadar服务器。这边使用PortProxyGUI来设置Windows主机的端口转发,端口统一输入刚刚在QRadar管理端设置的端口号,目的地IP输入VMnet1局域网内虚拟机的IP地址。当然,也可使用netsh在PowerShell里设置端口转发(需要以管理员运行)。

netsh interface portproxy add v4tov4 listenport=12469 listenaddress=0.0.0.0 connectport=12469 connectaddress=192.168.206.2

Windows防火墙放通端口

控制面板找到Windows Defender Firewall => Advanced Settings => Inbound Rules => New Rule,规则类型选择端口,放通12469即可。

设置mitmproxy及拦截脚本

如果计划使用虚拟机搭载代理服务器,需要将虚拟机实例的网络连接模式设置为桥接,即使用宿主机的网卡直接连接到家庭网络,这样代理服务器会获得路由器直接分配的局域网IP地址,可以跟家庭内所有设备(例如移动端)通信。

登录代理主机或虚拟机,从https://mitmproxy.org/downloads/#11.1.0/下载mitmproxy。解压后有mitmdumpmitmproxy,及mitmweb三个可执行文件。mitmdump提供终端输出,mitmproxy可以用命令行方式对截获的流量进行操作,mitmweb则提供类似QRadar的网页端管理平台。

mitmproxy的主要优势是可以通过Python脚本定义代理服务器作为中间的操作,对通信进行截断,更改,转发,存底,甚至重放操作。mitmproxy官方给了很多脚本样例,本人根据官网教程写了以下脚本,用来实现以JSON格式记录用户的全部HTTP/HTTPS Request & Response流量,并发送JSON到QRadar SIEM审计。

import requests
import ipaddress
from mitmproxy import http
from datetime import datetime

SIEM_HOST = 'http://192.168.87.237' # 你的QRadar服务端IP
SIEM_PORT = 12469 # 你的QRadar日志源的监听端口
SIEM_URL = f"{SIEM_HOST}:{SIEM_PORT}"
HOSTNAME = '192.168.xxx.xxx'  # mitmproxy主机或虚拟机IP

# 发送流量日志到QRadar SIEM
def send_to_siem(log):
    headers = {'Content-Type': 'application/json'}
    response = requests.post(SIEM_URL, json=log, headers=headers)
    print(f"Sent to SIEM, response status: {response.status_code}")

# IPv4-mapped IPv6转换成IPv4
def convert_ipv6_to_ipv4(ipv6):
    try:
        ip = ipaddress.ip_address(ipv6)
        if ip.ipv4_mapped:
            return str(ip.ipv4_mapped)  
        return str(ip)  
    except ValueError:
        return "Invalid IP address"  

# 截获客户端请求时执行的操作
def request(flow: http.HTTPFlow) -> None:
    log = {
        "eventName": "HTTPRequest",
        "eventCategory": "ExternalCommunication",
        "timestamp": datetime.utcnow().isoformat() + "Z",
        "sourceIP": convert_ipv6_to_ipv4(flow.client_conn.address[0]),
        "destinationIP": flow.server_conn.ip_address[0],
        "destinationPort": flow.server_conn.ip_address[1],
        "method": flow.request.method,
        "url": flow.request.url,
        "status": None,
        "bytes": len(flow.request.content)
    }
    print(f"Request log entry: {log}")
    send_to_siem(log)

# 截获服务端响应时执行的操作
def response(flow: http.HTTPFlow) -> None:
    log = {
        "eventName": "HTTPResponse",
        "eventCategory": "ExternalCommunication",
        "timestamp": datetime.utcnow().isoformat() + "Z",
        "sourceIP": convert_ipv6_to_ipv4(flow.client_conn.address[0]),
        "destinationIP": flow.server_conn.ip_address[0],
        "destinationPort": flow.server_conn.ip_address[1],
        "method": flow.request.method,
        "url": flow.request.url,
        "status": flow.response.status_code,
        "bytes": len(flow.response.content)
    }
    print(f"Response log entry: {log}")
    send_to_siem(log)

response(flow: http.HTTPFlow)request(flow: http.HTTPFlow)为mitmproxy的callback函数,在有HTTP/HTTPS Request & Response时自动调用。这两个函数还有很多其它玩法,例如对已知的恶意IP/网站进行封锁,防止内网用户访问。因为mitmproxy会对TLS流量解密,所以能看到payload明文,也可以实现一些DLP敏感数据防外泄的功能。感兴趣的读者可自行阅读官方文档。另外,因为mitmproxy会将IPv4地址以IPv4-mapped IPv6格式输出,例如::ffff:192.0.2.124,我们需要加入convert_ipv6_to_ipv4(ipv6)函数,让QRadar正确剖析来源和目的IP地址。

修改好SIEM_HOST, SIEM_PORT, HOSTNAME变量,将Python脚本上传到代理机,并启动mitmweb:

./mitmweb -s proxy.py

就可以看到代理服务器按照指定脚本运行,截获的通信可以在http://127.0.0.1:8081的前端实时看到。

设置用户设备并安装证书

Windows设备

设置应用找到Network & internet => Proxy => Manual proxy setup => Setup,输入安装mitmproxy主机或虚拟机的IP,mitmproxy的默认端口为8080,启用并保存。

这个时候如果打开浏览器访问一些应用(例如hkuportal.hku.hk),会显示如下页面。原因是港大强制了TLS连接,即HTTP Strict Transport Security(HSTS),而用户设备到代理服务器这段的通信却是未加密的HTTP(用户没有安装并信任代理服务器的证书),因此访问http://mitm.it安装证书。

这个域名应该指向你mitmproxy服务器内置的一个静态页面,里面可以下载不同格式的代理服务器证书。Windows设备安装证书的方法,内置文档已经很详细写了,照着操作即可。

Android设备

测试设备为Samsung S24 Ultra(EMUI系统),和代理服务器在同一个局域网的情况下,设置选择Wi-Fi => network => 设置图标 => Proxy => Manual,填入相同的IP和端口即可。

下载证书后,Security and privacy => More security settings => Install from device storage => CA certificate => Install anyway输入密码或指纹,载入证书文件,就可以通过代理正常访问HSTS的网站了。

这个时候再用手机或者电脑访问网站,mitmproxy已经可以向QRadar SIEM实时发送日志了!我们访问https://www.hsbc.com.hk,在QRadar的管理端日志活动页面可以看到如下事件日志。

有效荷载(payload)样本为:

{"eventName": "HTTPRequest", "eventCategory": "ExternalCommunication", "timestamp": "2025-01-06T15:35:28.440548Z", "sourceIP": "192.168.87.6", "destinationIP": "3.165.102.8", "destinationPort": 443, "method": "GET", "url": "https://www.hsbc.com.hk/zh-hk/", "status": 200, "bytes": 235382}

编写QRadar DSM及事件对映

此时虽然payload已经储存在QRadar,但是能注意到在上述事件中,事件名称低层次种类均为Unknown/不明,且目的地IP均为QRadar主机自己的地址(192.168.206.2),而不是实际监控到web流量的相关方。这是因为在QRadar看来,我们的mitmproxy属于自定义安全设备,内置Device Support Module(DSM)无法从payload里剖析出相应的参数并识别事件(是正常的web流量?用户不小心点进phishing website?还是有内部人员试图发送敏感资料?)。只有编辑好DSM,QRadar才能基于mitmproxy提供的审计日志进行一些有意义的威胁响应。比如监控到员工看了不该看的网站,自动发送邮件通知经理以及employee compliance部门。

日志活动页面随便选中一条mitmproxy的事件,右键选择在DSM编辑器中检视,就可以看到一个类似regex101的界面。

点一下左上角日志来源类型变更,搜索框输入mitmproxy(我这边已经有了,如果第一次操作要新建)并选择。

对于代理类设备,我们最起码需要设置四个参数的剖析(事件ID事件种类来源IP目的地IP)。选择相应参数 => 置换系统行为表示式类型选择JSON,表示式格式为/”eventName”,双引号里为键名。如果JSON是嵌套结构,可以用/”keyName1″/”keyName2″找到需要填入的值。

DSM编写好后,工作区下方“日志活动预览”中的“剖析失败:1/1”就回变成“剖析成功”。选择事件对映 => +,为上一个步骤定义抓取的每一个可能的事件ID事件种类设置事件对映。根据我们的mitmproxy脚本,事件ID(JSON中eventName可能的值)只有HTTPRequestHTTPResponse两种,事件类型(eventCategory可能的值)都为ExternalCommunication,所以设置两个对映即可。

按照下面的信息设置QID记录,日志来源类型这里写的不对,记得改成mitmproxy,此处为了方便,我们把HTTPRequestHTTPResponse全部对映到Workstation External Web Traffic这个记录。

最后,回到管理 => 日志来源 => mitmproxy (或你起的其它名字) => 编辑,将日志源类型从原先的Universal DSM改成刚刚新建的mitmproxy,保存即可。这次不需要在进行部署变更,因为我们只是对已有的日志源进行维护,没有更改QRadar的配置。

使用已配置代理的电脑或手机“网上冲浪”一会儿,再回到刷新QRadar的日志活动页面,我们就能看到用户浏览记录的审计信息正确显示出来了!

后续探索

目前通过集成QRadar和mitmproxy,我们仅仅达到了威胁感知的目的(比如使用AQL在QRadar查看用户是否有访问过可疑网站,或者筛选有没有员工在短时间内向外界发出大量的数据)。在后续学习QRadar的威胁响应功能的时候,我们可以继续利用mitmproxy,在脚本中加入一个黑名单功能。在用户试图访问已知恶意网站或者易产生泄密的应用(例如OneDrive Personal和CodeShare)时直接discard掉请求,并发送给QRadar特殊的事件ID事件类型,使之出现在QRadar攻击面板里。同时触发一些自动化操作,例如邮件通知和断开用户电脑的网络连接。

Next