【流量分析】JA 指纹识全系讲解

admin 2024年3月9日20:18:17评论9 views字数 15393阅读51分18秒阅读模式

前言

近期在学习 Burp Suite 的反制时发现 Wfox 前辈写的反制爬虫之 Burp Suite RCE一文,文末处介绍了使用 JA3 指纹识别 Burp Suite 流量的方法,简单研究后发现实战中易用性较强,故借此机会完整介绍一下 JA 指纹的全系列,并拓展到实践中

什么是 JA 指纹

JA 指纹是一种对传输层(SSL/TLS)进行指纹识别的方法,由 John Althouse、Jeff Atkinson 和 Josh Atkins 三位安全研究员在 2017 年 6 月首次发布在 Github,JA 系列指纹可以被看作是一种 IOC(通俗一点叫入侵指标)

IOC:是指有助于识别攻击是否已经发生或正在进行的数据,它就像是一件物证,侦探可能会收集物证用于确定谁出现在犯罪现场

像是我们平常使用的海内外威胁情报平台、网空测绘平台、WAF类安全产品都是以 IOC 作为数据支撑的,但是支持 JA 指纹的产品和平台较少,除了在产品侧的应用,JA 指纹也被用在识别 C2、V2ray 这类特殊流量上

如果以传统的 IP 和域名两个维度去检测,会漏掉一些隐匿程度较好的恶意流量,现在大部分 C2 和服务端之间都是使用 TLS 加密的,但如果使用 JA 指纹,哪怕无法解密恶意流量的内容,不能掌握 C2 的 IP 和域名,依然可以识别出恶意流量

但是 JA 指纹也不是万能的,它依然是可以被改变的,但是需要对客户端的 TLS 握手特征进行修改,难度较大,也会变相提升攻击成本,也是因为这个特性,JA 指纹更多被用在黑名单场景上,如果在白名单场景使用就会有误报率过高这样的问题

下面将介绍 JA 指纹的四个分支,这四个分支各有侧重点,被应用在不同的场景中

  • JA3:对 TLS 客户端进行被动识别
  • JA3s:对 TLS 服务端进行被动识别,可以看作是 JA3 的服务端版
  • JAM:对 TLS 服务端进行主动识别,可以看作是 JA3 和 JA3s 的融合
  • JA4+:JA4+是一个指纹合集,包括 JA4、JA4S、JA4H、JA4L、JA4X、JA4SSH,可以对多个检测维度进行指纹识别

JA3

上面我们说过,JA3 指纹的计算是在传输层完成的,具体一点说,是在 SSL/TLS 握手过程中的第一阶段完成的,也就是 Client Hello,先来介绍一下它的报文结构

Client Hello 报文结构

在 WireShark 中,我们可以使用以下规则过滤处 Client Hello 报文

ssl.handshake.type == 1

Client Hello 报文结构如下:

  • 客户端版本(Version):按优先级列出客户端支持的协议版本,首选客户端希望支持的最新协议版本
  • 客户端随机数(Random):引入一个新的随机因素,增加安全性,用于生成密钥
  • 会话ID(Session ID):如果客户端第一次连接到服务器,那么这个字段就会保持为空,一般用于会话恢复
  • 加密套件(Cipher Suites):给服务器发送自己已知的密码套件列表,服务端会从中选出一种来作为双方共同的加密套件
  • 扩展包(Extension):其他参数(如服务器名称,填充,支持的签名算法等)可以作为扩展名使用【流量分析】JA 指纹识全系讲解

JA3 指纹就是使用 TLS Version、Cipher Suite、Extension、EllipticCurves(Supported_Groups)、Elliptic Curve Point Formats(ec_point_formats) 这五项参数计算出来的

JA3 计算最早使用的是 EllipticCurves 和 Curve Point Formats,但随着 TLS 的发展(标准从 RFC4492 转为 RFC8422),发现这两个命名不能满足实际的需求了,于是分别改为 Supported_Groups 和 ec_point_formats,现在我们接触到的基本都是这两种命名【流量分析】JA 指纹识全系讲解

JA3 计算原理

JA3 的计算较为简洁,就是将刚才说到的五项参数的数值都转为十进制,相同项的参数使用-串联,然后使用,进行分隔(如果不存在 TLS Extension,后三项直接留空即可)

  • TLS Version
0x0303 -> 771
【流量分析】JA 指纹识全系讲解
  • Cipher Suite
0x1302 -> 4866

4866-4865-4867-49196-49195-52393-49200-52392-49199-159-52394-163-158-162-49188-49192-49187-49191-107-106-103-64-49198-49202-49197-49201-49190-49194-49189-49193-49162-49172-49161-49171-57-56-51-50-49157-49167-49156-49166-157-156-61-60-53-47-49160-49170-22-19-49155-49165-10-255
【流量分析】JA 指纹识全系讲解
  • Extension-Type
0-5-10-11-17-23-13-43-45-50-51
【流量分析】JA 指纹识全系讲解
  • Supported_Groups
29-23-24-25-30-256-257-258-259-260
【流量分析】JA 指纹识全系讲解
  • ec_point_formats
0
【流量分析】JA 指纹识全系讲解

之后我们把这些数据按照规则拼接起来

771,4866-4865-4867-49196-49195-52393-49200-52392-49199-159-52394-163-158-162-49188-49192-49187-49191-107-106-103-64-49198-49202-49197-49201-49190-49194-49189-49193-49162-49172-49161-49171-57-56-51-50-49157-49167-49156-49166-157-156-61-60-53-47-49160-49170-22-19-49155-49165-10-255,0-5-10-11-17-23-13-43-45-50-51,29-23-24-25-30-256-257-258-259-260,0|

最终加密形成 32 位 MD5,就是这条报文的 JA3 指纹

dc86f13deee08e265833d3d9c6ae5694

JA3 的优化

起初是想收集一下 Chrome 的 JA3 指纹的,结果发现 Wireshark 计算出的 MD5 (Wireshark 中的 MD5 只是计算后显示出来的,真实报文里并不包含)每次都是不一样的,这就问题很大了【流量分析】JA 指纹识全系讲解

按照研究员博客中所说,JA3 只受客户端版本的影响,照这样的说法 JA3 是不会随意变化的,后来仔细查阅资料后发现在 RFC8701 标准中引入了 GREASE(生成随机扩展并维持可扩展性)这项机制,简单来说就是在发送请求时在 JA3 算子处加入随机值

同时,许多攻击者使用了 “Cipher Stunting” 这项技术,落地到实际应用就是使 Cipher Suite 随机化,实现逃避检测的目的,这两者共同作用导致最终计算出的 JA3 指纹也是随机的【流量分析】JA 指纹识全系讲解

通过观察多组不同的 JA3 指纹,发现都是 Extension 这项不同,因此去掉第三项的检测(留空),以剩下的四项作为算子【流量分析】JA 指纹识全系讲解

这样优化后使得 JA3 从现在的无法检测变为可以检测,但对比早期无 GREASE 机制时检测精度固然会下降,属于是不得已之策,后面会专门写一篇落地应用相关的内容,从代码层面实现这个优化

GREASE 机制

GREASE 是 Generate Random Extensions And Sustain Extensibility 的缩写,在 RFC8701 中被正式定义,主要的用处是通过设计一种机制,来防止 TLS 协议在将来进行扩展的时候受到阻碍

在 TLS 中 Cipher Suite 和 Extension 等字段会有一些保留值,留待之后的版本使用,GREASE 机制就是对这些参数分别限定了一些保留值,但这些保留值是没有意义的,比如用于 Cipher Suites 和 ALPN 两项的拓展值有:

{0x0A,0x0A}, {0x1A,0x1A}, {0x2A,0x2A}, {0x3A,0x3A}, {0x4A,0x4A}, {0x5A,0x5A}, {0x6A,0x6A}, {0x7A,0x7A}, {0x8A,0x8A}, {0x9A,0x9A}, {0xAA,0xAA}, {0xBA,0xBA}, {0xCA,0xCA}, {0xDA,0xDA}, {0xEA,0xEA}, {0xFA,0xFA}

同时,协议中也规定了客户端如何处理 GREASE 值和服务端接收到 GREASE 值后如何使用【流量分析】JA 指纹识全系讲解

JA3s

上文我们说过,JA3s 就是服务端版的 JA3,它是使用 SSL/TLS 握手过程中的 Server Hello 报文(SSL/TLS 握手过程中的第二阶段)来进行计算的,我们先来看一下 Server Hello 的报文结构

Server Hello 报文结构

在 WireShark 中,我们可以使用以下规则过滤处 Server Hello 报文

ssl.handshake.type == 2

Server Hello 报文结构如下:

  • 服务端版本(Version):和服务端最终协商使用的版本
  • 服务端随机数(Random):引入一个新的随机因素,增加安全性,用于生成密钥
  • 会话ID(Session ID):与本次连接相对应的会话的标识
  • 加密套件(Cipher Suites):由服务端选择一个 Client Hello 提供的加密套件
  • 扩展包(Extension):拓展列表,由 Client Hello 给出的扩展才能出现在这个列表中【流量分析】JA 指纹识全系讲解

JA3s 计算原理

具体算法与 JA3 完全一致,就是参与计算的内容不一样,JA3s 是由 TLS Version、Cipher Suite、Extension 三项计算出来的

  • TLS Version
0x0303 -> 771
【流量分析】JA 指纹识全系讲解
  • Cipher Suite
0xc02f -> 49199
【流量分析】JA 指纹识全系讲解
  • Extension-Type
0-11-65281-35-23
【流量分析】JA 指纹识全系讲解

之后我们把这些数据按照规则拼接起来

771,49199,0-11-65281-35-23

计算出 32 位的 MD5,就是这条报文的 JA3s 指纹

2ab44dd8c27bdce434a961463587356a

JARM

JAM 可以看作是 JA3 和 JA3s 的融合版本,它与 JA3 和 JA3s 相比,个人认为有两点最大的区别,即主动和双向,下面我们来详细解释一下:

  • 主动:主动是探测方式上的主动,与 JA3 和 JA3s 的被动探测相比,JAM 主动向服务端发送 Client Hello 报文,而不是被动接受报文,它更像是一个扫描工具
  • 双向:双向体现在计算维度上,JA3 和 JA3s 都是对单项的报文进行计算,而 JAM 的计算是同时结合 Client Hello 报文和 Server Hello 报文进行计算

JARM 获取

JAM 同样也是开源的,并且 JAM 单独给出了一个计算指定网站的脚本,Github 地址如下:

https://github.com/salesforce/jarm/blob/master/jarm.py

这里我们对baidu.comweibo.com的 JAM 指纹进行计算,我们需要先创建一个 txt 把它们放入里面,再用-i指令运行(直接在jarm.py后跟扫描目标也可以),还可以使用-v参数列出进行模糊哈希前的参数【流量分析】JA 指纹识全系讲解

更多操作见以下参数

  -h, --help 显示帮助信息并退出
  -i INPUT, --input INPUT
                        提供要扫描的 IP 地址或域名列表,每行一个域名或 IP 地址。
                        可选: 用逗号分隔指定要扫描的端口(如 8.8.4.4,853)。
  -p PORT, --port PORT 输入要扫描的端口(默认为 443)
  -v,--verbose 冗余模式:在散列前显示 JARM 结果
  -V, --version 打印出版本并退出
  -o OUTPUT, --output OUTPUT
                        提供文件名,将结果输出/附加到 CSV 文件
  -j, --json 输出 ndjson(输出到文件或 stdout;覆盖 --output 默认值为 CSV)
  -P PROXY, --proxy PROXY
                        要使用 SOCKS5 代理,请提供地址:端口

下面我们来简单的分析一下程序是如何实现的,它首先定义了十个数组,用于配置 Client Hello 报文,每个数组代表一个特定的 TLS 握手配置,包括目标主机、目标端口、TLS 版本、密码套件列表、密码套件顺序、是否使用 GREASE、应用层协议协商(ALPN)、是否支持特定的 TLS 版本以及 TLS 扩展的顺序【流量分析】JA 指纹识全系讲解

之后这些数组被添加到queue队列中,通过while循环进行处理,之后这十个数组会被packet_building函数构建为特征不同的数据包,之后通过send_packet函数发送,最终的结果(十个与之对应的 Server Hello 报文)由read_packet函数进行处理【流量分析】JA 指纹识全系讲解

比较值得一提的是,程序还使用了一个choose_grease()函数修复了前代 JA3/3s 收到 GREASE 影响的问题,具体如何应用的可以跟踪choose_grease()函数自行查看,这里就不再赘述【流量分析】JA 指纹识全系讲解

JARM 计算原理

JARM 指纹是一种模糊哈希,一共 62 位,前 30 位是基于 Server Hello 选择的 Cipher Suites 和 TLS Version 经过私有算法计算出来的,后 32 位是基于 Extensions 经过 SHA256 计算出来的【流量分析】JA 指纹识全系讲解

上述计算原理在 Blog 中只给出了简单的原理,并没有做细节的介绍,这里我将通过程序中的源码分析出具体的加密过程,仅供参考,这里我们根据result回推【流量分析】JA 指纹识全系讲解

可以发现result是由jarm_hash函数加密而来【流量分析】JA 指纹识全系讲解

继续跟踪jarm_hash函数可以发现,当原始格式的 JARM 指纹为全部空时,将返回 62 个 0,不为空时分为四个部分(用|隔开)【流量分析】JA 指纹识全系讲解

我们可以使用-v参数打开冗余模式看到未计算前的结果

服务器返回的加密套件 | 服务器返回选择使用的TLS协议版本 |  TLS扩展ALPN协议信息 | TLS扩展列表
【流量分析】JA 指纹识全系讲解

从这里我们便可以窥见它的算法结构,使用了cipher_bytes函数、version_byte函数、SHA256 三种方法,分别计算 Cipher Suites、TLS Version、Extensions 三项维度,计算出结果后,依次拼接到fuzzy_hash中,形成最后的 JARM 指纹【流量分析】JA 指纹识全系讲解

前 30 位计算

根据 Blog 可知,JARM 前 30 位的结构如下【流量分析】JA 指纹识全系讲解

这里我们使用抓包对程序的探测流量进行分析,可以发现components第0项和第1项的原格式【流量分析】JA 指纹识全系讲解

我们先来分析cipher_bytes函数是如何实现的,它的功能是计算components的第0项(Cipher Suites),首先遍历 list 中的每个字节,将其转换为十六进制字符串,并与 cipher 进行比较,如果为空就返回 00,反之则返回十六进制字符串(去掉0x【流量分析】JA 指纹识全系讲解

其次是version_byte函数,它的功能是计算components的第1项(TLS Version),如果没有获取到 Version 则返回 0,反之则返回abcdef其中一个【流量分析】JA 指纹识全系讲解

后 32 位计算

后 32 个字符是由 TLS 扩展 ALPN 协议信息和 TLS 扩展列表通过 SHA256 哈希并截取而来,首先拼接components的第 2 项和第 3 项到alpns_and_ext参数,经过 SHA256 后再拼接到fuzzy_hash中,形成完整的 JARM 指纹【流量分析】JA 指纹识全系讲解

JARM 的短板

在 Blog 中,作者也给出了 JARM 的应用场景,也就是对 C2 的主动探测和识别,并给出了常见 C2 的 JARM 指纹【流量分析】JA 指纹识全系讲解

FOFA 是支持 JARM 指纹搜索的,我们使用结合产品语法对 Cobalt Strike 服务端进行搜集(这里的是早期版本的指纹,保有量少是正常情况)发现只有 13 台机器可以被确定是 Cobalt Strike 的服务端

jarm="07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1" && category="其他安全产品"
【流量分析】JA 指纹识全系讲解

如果单以 JARM 作为依据搜索,则会出现许多不相关的服务,说明实际情况下,JARM 并不与某一 C2 唯一对应,只能对某一类 TLS 服务器进行探测,对于不同类型的 C2 服务器来说,它们的 JARM 也会随着版本或基础库的变化而变化【流量分析】JA 指纹识全系讲解

在 Blog 中,研究员也说明了这个问题,它们的解决方案是可以根据其他特征指标进行研判,例如存活时长、名称、托管提供商、证书颁发机构等,所以客观来说,JARM 只是丰富了 IOC 的维度,并提供了一个主动探测的手段,在对某些 APT/勒索/恶意 组织进行资产拓线时,JARM 也许是一个不错的指标,若对此方向感兴趣可以参考《FOFA资产拓线实战系列:响尾蛇APT组织》一文

JA4+

JA4+ 首发于 2023 年九月,是 JA3/3s 的升级替代,它由早期针对 TLS 流量的指纹升级为多样协议的指纹识别方法,变为了指纹集,这也就是后缀带一个+的原因了

截至发稿,JA4+ 指纹集已开源的分支有:JA4、JA4S、JA4H、JA4L、JA4X、JA4SSH、JA4T、JA4TS、JA4TScan,它们应用的场景如下

JA4+ 分支 支持协议
JA4 TLS Client
JA4S TLS Server Response
JA4H HTTP Client
JA4L Light Distance/Location
JA4X X509 TLS Certificate
JA4SSH SSH Traffic
JA4T TCP Client/Server
JA4TS TCP Server Response
JA4TScan Active TCP Server Fingerprint Scanner

在 WireShark 中配置 JA4+

如果想要在 WireShark 中使用 JA4+,需要保证其版本高于或等于4.2.0,在 Github 下载 ja4.dll,完成后将其放入Wiresharkplugins版本epan目录【流量分析】JA 指纹识全系讲解

启动 WireShark 后还需要在【编辑】—> 【首选项】中进行配置【流量分析】JA 指纹识全系讲解

打开首选项中的【外观】—> 【列】,点击+号添加一个新的列,类型选择自定义(Custom),具体配置可参考官方的配置表【流量分析】JA 指纹识全系讲解

假设我们这里添加了 JA4 的规则,打开抓包页面后就会出现一条与 JA4 相关的列【流量分析】JA 指纹识全系讲解

同时也支持以 JA4 指纹作为过滤器【流量分析】JA 指纹识全系讲解

目前 WireShark 最新版已经原生支持 JA4 指纹了,如果对系列中的其他分支无需求就不用做上述额外的配置,同时还发现通过插件实现的 JA4 计算存在无法正确获取版本号的问题,导致计算出的 JA4_a 不同【流量分析】JA 指纹识全系讲解

JA4+ 与 JA3/3s 的区别

JA4+ 相比对 JA3/3s 来说,有三点较大的变化,分别是:拓展化、模块化、可读化,下面来分别解读一下这三点变化

拓展化

拓展化指的是协议层面上的拓展化,早期的 JA 系指纹,都是对 TLS 层的流量进行分析,到了 JA4+ 不止有 TLS,还拓展了 TCP、HTTP、SSH 层面的流量识别,甚至还可以对 TLS 证书和物理位置进行分析

模块化

在更早的 JARM 中(前 30 位和后 32 位分开计算),其实我们就可以看到 JA 系指纹模块化的思路了,到了 JA4+ 这一代,彻底将模块化的概念引入了,所有 JA4+ 指纹都有形如 a_b_c 这样的结构,它们分别代表指纹的不同部分【流量分析】JA 指纹识全系讲解

模块化最大好处是,使整个指纹不再局限于某一个指标,哪怕再次更新类似 GREASE 的机制,也不会使整个指纹变得不可用,同时,模块化还可以让检测变得更加灵活和细化,例如,可以单独以 JA4_a 搜索或者使用 JA4_ab 进行搜索

可读化

在早期的 JA 系指纹中,最终产生的指纹都是机器可读的,对人类来说并没有意义,而 JA4+ 的可读化升级使得人类也可以通过指纹中的字符判断指纹的基础信息【流量分析】JA 指纹识全系讲解

JA4

JA4 对标的是早期的 JA3,主要是对 Client Hello 报文实现指纹化,升级之处在于兼容了新的 QUIC(Quick UDP Internet Connections)协议,同时也依然支持之前的 TCP 协议,顺便解决了随机化带来的各种问题【流量分析】JA 指纹识全系讲解

什么是 QUIC

对于用户侧来说 QUIC 主要解决的是延迟的问题,这里我们主要说一下它和 TCP 的区别,简单来说,QUIC 进行了一次 “资源整合”,它把之前 HTTP/2、TLS、TCP 三者的优势集合起来

由于 QUIC 已经整合了这些内容,那么让它继续工作在 HTTP/2 下会出现许多问题,所以便催生了 HTTP/3,因为 QUIC 本身是要取代 TCP 的,所以它的传输层协议选择的是 UDP【流量分析】JA 指纹识全系讲解

JA4 计算原理

JA4 计算的是 Client Hello 报文,这里以官方给出的 Chrome JA4 指纹作为样例来进行演示JA4=t13d1516h2_8daaf6152771_02713d6af862,分成 JA4_a、JA4_b、JA4_c 三部分,计算的大原则是:按照规定顺序排列,忽略所有 GREASE 值

JA4_a

  • t:代表 TCP,此位置代表协议,还有q,代表 QUIC
  • 13:代表 TLS Version,这里代表 1.3,更多情况请见下表
0x0304 = TLS 1.3 = “13”  
0x0303 = TLS 1.2 = “12”  
0x0302 = TLS 1.1 = “11”  
0x0301 = TLS 1.0 = “10”  
0x0300 = SSL 3.0 = “s3”  
0x0200 = SSL 2.0 = “s2”  
0x0100 = SSL 1.0 = “s1”
Unknown = “00”

当我们仔细观察抓到的包时,可以发现有些包 WireShark 显示的是 TLS 1.2 但 JA4_a 中给出的却是 13,这并不是计算上的错误,是因为 JA4 计算时实际上读取的是数据包中的最高版本【流量分析】JA 指纹识全系讲解

出现 TLS Version 的部分一共有三个部分,上面出现 13 的原因就是在拓展(Extension)中有一项supported_version存在 TLS 1.3【流量分析】JA 指纹识全系讲解【流量分析】JA 指纹识全系讲解

  • d:代表 Domain,这里的判断依据是 SNI Extensions,如果它存在则访问的是域名,不存在则说明访问的是 IP,此时为i【流量分析】JA 指纹识全系讲解
  • 15:代表 Cipher Suites 的数量,即便是单数也选择两位输出,例如 6 个就是06,最大值显示到99,忽略 GREASE 值
  • h2:代表 ALPN 值,选取第一个值,更多情况见官方文档,若报文中没有此项,则使用00【流量分析】JA 指纹识全系讲解

ALPN 主要负责应用层协议的协商,浏览器发送 Client Hello 报文时同时提供两种选项,若服务器支持 HTTP/2 则选择 h2,如果不支持,则从客户端支持的协议列表中选取一个它支持的协议,一般情况下选择 HTTP/1.1,体现在 JA4 指纹中就是h1

JA4_b

JA4_b 的计算根据是 Cipher Suite 值,使用,分隔不同字段(忽略 GREASE 值),但是会进行一个从小到大的排序,例如

1301,1302,1303,c02b,c02f,c02c,c030,cca9,cca8,c013,c014,009c,009d,002f,0035

按照从小到大的排序原则处理后,变为

002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9

对这串数据再进行 SHA256 加密,最终截取加密后字符串(小写)的前 12 位,组成 JA4_b

8daaf6152771e33e12d734f9bc6478ed341f16cde27aee3aa36f2402f2c53b44

JA4_b = 8daaf6152771

这里排序的意义在于降低 “Cipher Stunting“ 的影响,关于什么是 “Cipher Stunting“ 请见【JA3 优化】部分,但是并不是说顺序不重要,这里是为了保真度所做的取舍,作者给出的原因是,在研究时发现大多数应用使用的是独特的 Cipher,而不是独特的 Cipher Suite 排序(It does but in our research we’ve found that applications and libraries choose a unique cipher list more than unique ordering)

JA4_c

JA4_c 的计算根据是 Extensions-Type 值,忽略 GREASE 值、SNI 扩展名(0000)、ALPN 扩展名(0010),这里使用的是 Extensions-Type 值的十六进制格式(不含0x【流量分析】JA 指纹识全系讲解【流量分析】JA 指纹识全系讲解

例如以下原始数据

001b,0000,0033,0010,4469,0017,002d,000d,0005,0023,0012,002b,ff01,000b,000a,0015

经过排序后(从小到大,同时去除00000010

0005,000a,000b,000d,0012,0015,0017,001b,0023,002b,002d,0033,4469,ff01

这里的排序目的和 JA4_b 类似,但主要对抗的是 Extension 随机化问题,例如 Google 在 2023 年更新了 Chrome,主要实现的就是随机化 Extension,避免开发者过于依赖此功能【流量分析】JA 指纹识全系讲解

之后会再读取一个 Extension 中 signature_algorithms(签名算法) 的值,同样使用,作为分隔符【流量分析】JA 指纹识全系讲解

这里直接使用默认排序

0403,0804,0401,0503,0805,0501,0806,0601

最后将两串字符串合二为一,中间使用_分隔,处理后的 Extensions-Type 在前,未处理的 signature_algorithms 在后

0005,000a,000b,000d,0012,0015,0017,001b,0023,002b,002d,0033,4469,ff01_0403,0804,0401,0503,0805,0501,0806,0601

对这串数据再进行 SHA256 加密,最终截取加密后字符串(小写)的前 12 位,组成 JA4_c

e5627efa2ab19723084c1033a96c694a45826ab5a460d2d3fd5ffcfe97161c95

JA4_c = e5627efa2ab1

JA4s(JA4-Server)

JA4s 对标的是 JA3s,主要是对 Server Hello 报文实现指纹化,结构上和 JA4 相同,分成 JA4_a、JA4_b、JA4_c 三部分【流量分析】JA 指纹识全系讲解

JA4s 计算原理

JA4s_a

JA4s_a 基本和 JA4_a 结构差不多,只是去掉了 SNI Extensions 和 Ciper Suite 的个数,不计算个数的原因是因为在 Server Hello 报文中,Ciper Suite 只有一个(服务端最终在 Client Hello 报文中选择的),作为算子也就没有了意义

JA4s_b

上面我们说到服务端会从 Client Hello 选择一个 Ciper Suite 组成 Server Hello,JA4s_b 就是这个被选中的 Ciper Suite(去掉0x【流量分析】JA 指纹识全系讲解

JA4s_c

JA4s_c 的计算根据是 Extensions-Type 值,忽略 APLN 拓展名(0010),这点 Blog 中没有提及,但是实践中是这样操作的,至于 SNI 扩展名(0000)在 Server Hello 报文中不可能出现,所以无需考虑【流量分析】JA 指纹识全系讲解【流量分析】JA 指纹识全系讲解

之后用,分隔 Extensions-Type 值,进行 SHA256,取前 12 位,组成 JA4s_c

ff01,000b
SHA256:344b4dce5a5224d9ab24d970214dd88f8bdc9f8af56e3262f798e9cc25385256

JA4s_c = 344b4dce5a52

JA4H(JA4-HTTP)

JA4/4s 还是在之前 JA3 的基础上做了升级,到了 JA4H 以及后面更多的 JA4+ 指纹就已经拓展到其他协议上了,不再仅仅局限于 TLS 的指纹分析

JA4H 只能在 TLS 解密或者 TLS 加密不存在的情况下使用,分为 JA4H_a、JA4H_b、JA4H_c、JA4H_d 四部分,其中 JA4H_ab 基于 HTTP 响应标头计算,JA4H_c 基于 Cookie 计算,JA4H_d 是用户指纹【流量分析】JA 指纹识全系讲解

JA4H 计算原理

下面以官方给出的 JA4H 作为分析案例:ge20cr13enus_974ebe531c03_b66fa821d02c_e97928733c74

JA4H_a

  • ge:代表 GET,此位置代表请求方法,除此以外还有pu代表 PUT,po代表 POST,核心规则就是取请求方法的前两个字母,适用于所有 HTTP 请求方式
  • 20:代表 HTTP Version,HTTP 2.0 为20,HTTP 1.1 为11
  • c:代表是否存在 Cookie,有 Cookie 为c,没有 Cookie 为n
  • r:代表是否存在来源地址(Referer),存在为r。反之为n
  • 13:代表 HTTP 请求头的个数,忽略 Cookie 和 Referer
  • enus:代表 Accept-Language(取前四位字符),若不存在此项则为0000

JA4H_b

JA4H_b 是基于响应标头计算的,按照出现的顺序将其排序进行 SHA256 加密,Cookie 和 Referer 不参与计算,最终取加密后前 12 位组成 JA4H_b【流量分析】JA 指纹识全系讲解【流量分析】JA 指纹识全系讲解

JA4H_c

JA4H_c 是基于网站的 Cookie 字段计算的,同样是按照 HTTP 报文的顺序排列后使用 SHA256 加密,最终取前 12 位组成 JAH_c(若不存在 Cookie 则输出 12 个 0 占位),在官方的 Python 脚本中给出了两种处理 Cookie 的方法【流量分析】JA 指纹识全系讲解

JA4H_d

JA4H_d 在官方 Blog 中被称为 “用户指纹”,其本质还是对 Cookie 的计算,只是加入了用户的 Cookie 值(不包含敏感的个人身份信息),

换句话说,就是将网站的 Cookie 字段和用户唯一的 Cookie 值一起作为算子,依然是按照 HTTP 报文的顺序排列后进行 SHA256 加密后取其前 12 位作为 JA4H_d(若不存在 Cookie 则输出 12 个 0 占位)【流量分析】JA 指纹识全系讲解

JA4L(JA4-Latency)

JA4L 主要是通过 TCP 或 UDP 流量测量客户端和服务器的物理距离,从应用层面来说,拓展了新的测绘维度,例如可以与 JA4H 指纹配合可以实现对会话劫持和中间人攻击的检测

如果 JA4L 在服务器端运行,它将测量客户端与服务器的距离;如果在客户端运行,它将测量服务器与客户端的距离。如果它在网络接口上运行,它将测量每个设备与网络接口位置的距离【流量分析】JA 指纹识全系讲解

JA4L 计算原理

JA4L 分为两个测量模式,分别是JA4L-C代表 Client,JA4L-S代表 Server,JA4L 分为 JA4L_a 和 JA4L_b 两部分,JA4L_a 代表单项延迟,单位为微秒(1ms = 1000μs),使用如此小的时间单位是因为负责转发数据包的大多数是底层机器,基本不存在延迟

JA4L_b 代表 TTL(Time To Live,译为生存时间),简单来说就是规定一个数据包能在网络中最多存在多久(以秒为单位),每经过一次转发就会减 1,若归零时依然没有到达目标主机,就会自动丢失

  • TCP 流量 在分析 TCP 流量中的 JA4L 指纹时,是根据其三次握手来确定的,例如通过下图的三次握手数据,可以计算出其两个测量模式的值【流量分析】JA 指纹识全系讲解
JA4L-C = {(C-B)/2}_Client TTL

JA4L-S = {(B-A)/2}_Server TTL
  • UDP 流量(QUIC) 前文我们介绍过 QUIC,作为 TCP 的替代,其传输层协议选择的是 UDP,当计算JA4L-C时,使用的是       HandShake 包,当计算JA4L-S时,使用的是 Initial 包【流量分析】JA 指纹识全系讲解
JA4L-C = {(D-C)/2}_Client TTL

JA4L-S = {(B-A)/2}_Server TTL

使用 JA4L 测量距离

我们可以使用以下公式对客户端和服务器之间的距离进行测算:

  • D:Distance,距离
  • j:JA4L_a
  • c:光速常量,0.128英里/μs或0.206公里/μs
  • p:Propagation delay factor,延迟传播系数

关于延迟传播系数,Blog 给出了两种,对应了恶劣和良好两种情况

  • 恶劣地形系数 = 2(山、水周围)
  • 良好的地形系数 = 1.5(沿高速公路、海底电缆)

同时也可以使用 TTL 为依据计算延迟传播系数,需要注意的是,这里的 TTL 是连接时产生的(Hop Count,译为跃点计数),而不是完整的 TTL,需要从初始值(例如 Windows 的初始值为 128)减去观察到的 TTL(JA4L_b),例如当JA4L-S2449_104时,跃点计数为 24,则使用 1.8 作为延迟传播系数【流量分析】JA 指纹识全系讲解

使用公式便可以列出以下式子,得出该服务器距离客户端 257.385 公里以内,服务器物理距离只可能比这个数据近,不可能更远,因为从光速是恒定的,如果存在多个 JA4L 值,则应选取最低值进行计算

附:初始值计算表

JA4L_b 初始 TTL 值
<64 64
65-128 128
>128 155

JA4X(JA4-X.509)

JA4X 主要是对 X.509 TLS 证书进行指纹识别,但是其核心并不是识别证书中的值,而是对生成方式进行归类,因为证书的值是随机的,但是证书的生成方式相对单一,所以对生成方式的归类更为有效

JA4X 也是由 JA4X_a、JA4X_b、JA4X_c 三部分组成的,分别基于 Issuer RDNs、Subject RDNs 和拓展三部分计算而来【流量分析】JA 指纹识全系讲解

JA4X 计算原理

【流量分析】JA 指纹识全系讲解

JA4X_a

在介绍具体算法前,先介绍 Issuer RDNs,译为颁发者相对专有名称,如果是自签证书,其名称是自己;如果是 CA 证书,则其内容是机构的相关信息

在 JA4X_a 部分,只对其原始排序的 Issuer RDNs 的字段名(具体的数值不参与计算,这也就是为什么说 JA4X 是根据生成方式进行归类的)进行 SHA256 加密,最终的 JA4X_a 部分就是由其前 12 位组成

JA4X_b

Subject RDNs 译为主题相对专有名称,标识了证书涉及的实体,对于 SSL/TLS 证书来说,一般涉及其域名、申请单位所在地、电子邮件、邮政编码等等,生成方式与 JA4X_a 完全一致,只是算子变为 Subject RDNs 的字段名

JA4X_c

这里的 Extensions 并不是之前数据包的 Extensions,而是 X.509 V3 的 Extensions,JA4X_c 就是对其原始顺序进行 SHA256 加密,取其前 12 位作为 JA4X_c

JA4SSH

JA4SSH 是从 SSH 会话流量中提取的指纹,默认情况下每 200 个数据包进行一次指纹计算,分为 JA4SSH_a、JA4SSH_b、JA4SSH_c 三项,它主要是从检测范围的宏观角度提取数据,即使流量是加密的,最终也可以计算出一个流量特征指纹【流量分析】JA 指纹识全系讲解

JA4SSH 计算原理

JA4SSH_a

JA4SSH_a 表示的是计算客户端和服务器端的负载长度的众数,简单来说就是最经常出现的负载长度,需要注意的是,这里的长度并不是整个报文的长度,而是 SSH(TCP Payload)部分的长度,可以在 WireShark 中添加以下规则,方便我们观察其长度

tcp.len
【流量分析】JA 指纹识全系讲解

在传输数据时,SSH 会根据使用的密码算法和 HMAC 算法将 TCP Payload 填充为指定的长度,这也就是将 Client/Server 的 TCP Payload 长度众数作为算子的原因,这里由于截图限制,无法展示所有报文,可以通过 Github 获取完整数据包

例如这里就使用了chacha20-poly1305加密,当客户端在 SSH 终端中键入一个字符时,该字符会被填充为 36 字节的数据包加密,然后发送到服务器,服务器将在 36 字节数据包中以相同的字符进行响应【流量分析】JA 指纹识全系讲解

需要注意的是,Client 和 Server 的 TCP Payload 并不是一直保持相等的,例如,当 SCP 文件传输时, JA4SSH 为c112s1460_c0s179_c21s0,表明 Server 端的 TCP Payload 长度已经到达最大值 1460,而 Client 只有 112

JA4SSH_b

JA4SSH_b 的计算比较简单,就是统计 Client 和 Server 各自发送 SSH 数据的报文个数,在默认情况下,两者相加一定为 200

JA4SSH_c

JA4SSH_c 代表 Client 和 Server 各自发送的 ACK(Acknowledge character,译为确认字符)消息的个数,当发起方成功的接收到数据,那么会回复一个 ACK 消息,将 ACK 消息的方向和 TCP Payload 长度结合,我们可以分析出流量的行为和异常

例如在 JA4SSH_a 的例子如果发生在静态环境,则有可能是内网已经被攻破,攻击者正在横向攻击或下载服务器数据

参考文献

JA3

  • https://ares-x.com/2021/04/18/SSL-%E6%8C%87%E7%BA%B9%E8%AF%86%E5%88%AB%E5%92%8C%E7%BB%95%E8%BF%87
  • https://www.tr0y.wang/2020/06/28/ja3/
  • https://infosecwriteups.com/demystifying-ja3-one-handshake-at-a-time-c80b04ccb393
  • https://medium.com/salesforce-engineering/tls-fingerprinting-with-ja3-and-ja3s-247362855967

JARM

  • https://mp.weixin.qq.com/s/CTBO22SuQft1dBoHv2WRQg
  • https://engineering.salesforce.com/easily-identify-malicious-servers-on-the-internet-with-jarm-e095edac525a/

JA4+

  • https://github.com/FoxIO-LLC/ja4
  • https://blog.foxio.io/ja4-network-fingerprinting-9376fe9ca637
  • https://www.trisul.org/blog/traffic-analysis-of-secure-shell-ssh/
  • https://www.trisul.org/blog/detecting-ssh-tunnels/
  • https://www.cnblogs.com/xiaoxi-jinchen/p/15434662.html

原文始发于微信公众号(天禧信安):【流量分析】JA 指纹识全系讲解

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年3月9日20:18:17
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【流量分析】JA 指纹识全系讲解https://cn-sec.com/archives/2563091.html

发表评论

匿名网友 填写信息