在一次友情访问中,发现使用不同的客户端发起请求会得到不同的响应,就很好奇为什么会这样?
如下面,使用Burp和python请求:
Burp:
python Requests:
同样的请求复制到python3中用requests发包:
<body data-spm="7663354">
<div data-spm="1998410538">
<div class="header">
<div class="container">
<div class="message">
很抱歉,由于您访问的URL有可能对网站造成安全威胁,您的访问被阻断。
<div>您的请求ID是: <strong>
276aedd416186716424122798e3951</strong></div>
</div>
</div>
</div>
<div class="main">
<div class="container">
一样的请求地址一样的参数一样的http header,burp发送的请求正常响应,python发送的被waf拦截,curl模拟请求也被拦截。
waf是阿里云的waf,dig域名也能看出来 ,cname 解析到了上面。
多地ping发现并没有cdn,不是cdn的waf。
本来以为是ua的问题,后来更换了ua发现并没有什么卵用
问了问朋友,说python的tls握手有特征
在网上搜了一下,发现确实有很多类似的问题
相关链接:
-
https://stackoverflow.com/questions/64967706/python-requests-https-code-403-without-but-code-200-when-using-burpsuite
-
https://stackoverflow.com/questions/63343106/how-to-avoid-request-fingerprinted-in-python
-
https://stackoverflow.com/questions/60407057/python-requests-being-fingerprinted
我们来看一下不同客户端的clienthello报文:
客户端发起https的请求第一步是向服务器发送tls握手请求,其中就包含了客户端的一些特征。
相关内容在tls协议报文中Client Hello的Transport Layer Security当中。
对比一下burp和requests的Client Hello有什么区别:
一些不同的点:
Burp Suite | Requests |
TLSv1.2 Record Layer: Handshake Protocol: Client Hello Version: TLS 1.2 (0x0303) Length: 466 Cipher Suites Length: 104 Cipher Suites (52 suites) Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301) Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c) ….. Extensions Length: 285 Extension: signature_algorithms (len=46) Extension: supported_versions (len=11) |
TLSv1.2 Record Layer: Handshake Protocol: Client Hello Version: TLS 1.0 (0x0301) Length: 338 Cipher Suites Length: 86 Cipher Suites (43 suites) Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302) Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303) Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301) ….. Extensions Length: 175 Extension: signature_algorithms (len=48) Extension: supported_versions (len=9) |
可以看到很多地方都存在差异,主要为支持的协议,length,支持的加密套件,加密套件的排列方式等。
多次请求可以发现相同的客户端发起请求,除了Random和Session ID之外其他内容是完全一样的。
所以这里面固定的内容其实就可以作为指纹来进行识别
比如加密套件13 02-00 ff在tcp流当中就有固定的字节顺序
TLS Fingerprint识别原理
相关链接:
-
https://idea.popcount.org/2012-06-17-ssl-fingerprinting-for-p0f/
-
https://github.com/salesforce/ja3
看了下ja3 的指纹计算规则:
SSLVersion,Cipher,SSLExtension,EllipticCurve,EllipticCurvePointFormat
Example:
769,47-53-5-10-49161-49162-49171-49172-50-56-19-4,0-10-11,23-24-25,0
把版本,加密套件,扩展等内容按顺序排列然后计算hash值,便可得到一个客户端的TLS FingerPrint,waf防护规则其实就是整理提取一些常见的非浏览器客户端requests,curl的指纹然后在客户端发起https请求时进行识别并拦截
Bypass
import requests
proxies = {
'http': 'http://127.0.0.1:8080',
'https': 'http://127.0.0.1:8080'
}
rsp=requests.get(url,proxies=proxies)
翻了翻aiohttp的源码发现貌似并没有用urllib3,抓包发现tls指纹和requests也有着明显的差异,实际测试aiohttp确实没有被拦截
4、魔改request
从根本上解决问题,debug跟踪到了几处可能可以修改TLS握手特征的代码
举例:
/usr/local/lib/python3.9/site-packages/urllib3/util/ssl_.py
DEFAULT_CIPHERS = ":".join(
[
,
,
,
,
,
,
,
,
,
,
,
,
,
,
]
)
DEFAULT_CIPHERS
中定义了一部分的加密套件,直接进行一个删除,当然其他能改的地方也很多
成功绕过了阿里云的拦截
原本内容:
Cipher Suites Length: 86
Cipher Suites (43 suites)
Cipher Suites Length: 80
Cipher Suites (40 suites)
往期精彩:
点个在看你最好看
本文始发于微信公众号(Qingy之安全):SSL指纹的识别与绕过阿里云WAF
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论