前言

前段时间对SSL指纹的获取实现很感兴趣,从表面到深入再到实现让我更加深刻理解SSL设计。
本篇介绍:

  • SSL指纹在web容器(Kestrel)下如何获取,并实现一个Middleware来很方便集成到web工程里面(下文附源码地址)。

  • 解析ClientHello的套路以及如何生成SSL指纹

  • 测试不同的客户端的SSL指纹(java curl Fiddler python csharp chrome edge)

本次对SSL指纹的研究就算是完结篇了,
本次系列

  1. 从SSL的理解误区走出

  2. SSL证书的作用表现

  3. 正文开始

先来说说这个SSL指纹用来干嘛

  • waf里面一般会有用到

  • 说实话在目前的话也只能干干script Boy

举个例子,之前看过说为什么同样的请求地址一样的参数 一样的httpHeader,在浏览器访问就正常,用python发送的就会被waf拦截

正常用户访问:

[截图出自ParrotSecurity的A佬]

script Boy 用Python 发 Request,直接就被waf拦截了

[截图出自ParrotSecurity的A佬]

类似这样的求问帖有很多

  • https://stackoverflow.com/questions/60407057/python-requests-being-fingerprinted

  • https://stackoverflow.com/questions/63343106/how-to-avoid-request-fingerprinted-in-python

结论就是 python的tls握手有特征,被waf识别到独特的指纹了!

SSL指纹识别原理

巨人的肩膀在这里:https://github.com/salesforce/ja3

就是解析TLS握手客户端发送的ClientHello报文并获取

  • SSLVersion 版本

  • Cipher 客户端支持的加密套件

  • SSLExtention SSL的扩展内容集合

  • EllipticCurve SSL的扩展内容里面的【supported_groups】(CurveP256,CurveP384,CurveP521,X25519)

  • EllipticCurvePointFormat SSL的扩展参数里面的【sec_point_formats】(uncompressed,ansiX962_compressed_prime,ansiX962_compressed_char2)

把上面解析出来的版本,加密套件,扩展等内容按顺序排列然后计算hash值,便可得到一个客户端的TLS FingerPrint,waf防护规则其实就是整理提取一些常见的非浏览器客户端requests,curl的指纹然后在客户端发起https请求时进行识别并拦截!

同一个客户端的报文对比,除了Ramdom和SessionId有变化其他不变

不同的客户端的报文对比就各式各样了

动手实践

本次技术实现基于aspnet5.0,web容器是微软为aspnetcore打造的高性能Kestrel!
得益于Kestrel的中间件设计,我们可以很容易的
在配置Kestrel的时候指定自己的中间件去拦截ClientHello
(感谢微软大神davidfowl的指点)

webBuilder.UseKestrel(options =>
{var logger = options.ApplicationServices.GetRequiredService<ILogger<Program>>();options.ListenLocalhost(5002, listenOption =>{var httpsOptions = new HttpsConnectionAdapterOptions();//本地测试证书var serverCert = new X509Certificate2("server.pfx", "1234");httpsOptions.ServerCertificate = serverCert;//注册tls拦截中间件listenOption.Use(async (connectionContext, next) =>{await TlsFilterConnectionMiddlewareExtensions.ProcessAsync(connectionContext, next, logger);});listenOption.UseHttps(httpsOptions);});
});

接下来就是在我们自定义的中间件做解析

public static async Task ProcessAsync(ConnectionContext connectionContext, Func<Task> next, ILogger<Program> logger)
{var input = connectionContext.Transport.Input;var minBytesExamined = 0L;while (true){var result = await input.ReadAsync();var buffer = result.Buffer;if (result.IsCompleted){return;}if (buffer.Length == 0){continue;}//开启处理ClientHello报文if (!TryReadHello(buffer, logger, out var abort)){minBytesExamined = buffer.Length;input.AdvanceTo(buffer.Start, buffer.End);continue;}//上面我们读了流这里要归位var examined = buffer.Slice(buffer.Start, minBytesExamined).End;input.AdvanceTo(buffer.Start, examined);if (abort){// Close the connection.return;}break;}await next();
}

解析ClientHello报文

private static bool TryReadHello(ReadOnlySequence<byte> buffer, ILogger logger, out bool abort)
{abort = false;if (!buffer.IsSingleSegment){throw new NotImplementedException("Multiple buffer segments");}var data = buffer.First.Span;TlsFrameHelper.TlsFrameInfo info = default;if (!TlsFrameHelper.TryGetFrameInfo(data, ref info)){return false;}//解析的版本logger.LogInformation("Protocol versions: {versions}",      info.SupportedVersions);//解析客户端请求的Host//这里有一个小技巧,waf防御的一个简单的ByPass手段就是绕过域名直接访问Ip进行访问,如果服务端在这里增加一个Host白名单,就能防止绕过。logger.LogInformation("SNI: {host}", info.TargetName);//其他字段省略Console.WriteLine("ClientHello=>" + info);return true;
}

ClientHello报文解析

解析报文没啥特别的,就是根据RCF文档,:

 public enum ExtensionType : ushort{server_name = 0,max_fragment_length = 1,client_certificate_url = 2,trusted_ca_keys = 3,truncated_hmac = 4,status_request = 5,user_mapping = 6,client_authz = 7,server_authz = 8,cert_type = 9,supported_groups = 10,//  Elliptic curve pointsec_point_formats = 11, // Elliptic curve point formatssrp = 12,signature_algorithms = 13,use_srtp = 14,heartbeat = 15,application_layer_protocol_negotiation = 16,status_request_v2 = 17,signed_certificate_timestamp = 18,client_certificate_type = 19,server_certificate_type = 20,padding = 21,encrypt_then_mac = 22,extended_master_secret = 23,token_binding = 24,cached_info = 25,tls_lts = 26,compress_certificate = 27,record_size_limit = 28,pwd_protect = 29,pwd_clear = 30,password_salt = 31,session_ticket = 35,pre_shared_key = 41,early_data = 42,supported_versions = 43,cookie = 44,psk_key_exchange_modes = 45,certificate_authorities = 47,oid_filters = 48,post_handshake_auth = 49,signature_algorithms_cert = 50,key_share = 51,renegotiation_info = 65281}

tips:解析Extention的套路:

byte数组 前2个byte为长度 后面的是内容 然后根据RFC的struct进行解析

struct枚举 我从Go SDK的tls直接复制过来用的

GoSDK里面的注释很详细 RFC的相关也在注释里面,点赞!

这部分代码有点多,我都放在了我的github,想研究的可以
点击查看

最后就是按照原理将数据进行拼接在md5生成SSL指纹
public string getSig()
{StringBuilder sb = new StringBuilder();//版本sb.Append((int)Header.Version);sb.Append(",");//加密套件if (_ciphers != null){sb.Append(string.Join("-", _ciphers.Select(r => (int)r)));}sb.Append(",");//SSL扩展字段if (_extensions != null){sb.Append(string.Join("-", _extensions.Select(r => (int)r)));}sb.Append(",");//Elliptic curve pointsif (_supportedgroups != null){sb.Append(string.Join("-", _supportedgroups.Select(r => (int)r)));}sb.Append(",");// Elliptic curve point formatsif (_ecPointFormats != null){sb.Append(string.Join("-", _ecPointFormats.Select(r => (int)r)));}String str = sb.ToString();using var md5 = MD5.Create();var result = md5.ComputeHash(Encoding.ASCII.GetBytes(str));var strResult = BitConverter.ToString(result);//和其他语言的实现保持一致var sig = strResult.Replace("-", "").ToLower();return sig;
}

精彩时刻 来试试效果

用不同的客户端来测试下看看收集的指纹

1. chrome
指纹:
192,
0-4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,
0-23-65281-10-11-35-16-5-13-18-51-45-43-27-21,
29-23-24,
0
2. edge
指纹:
192,
0-4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,
0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513-21,
29-23-24,
0

新版edge也是用的chromium的内核,Extention扩展多了一个17513

3. csharp的HttpClient
指纹:
3072,
49196-49195-49200-49199-159-158-49188-49187-49192-49191-49162-49161-49172-49171-157-156-61-60-53-47-10,
0-10-11-13-35-23-65281,
29-23-24,
0
4. Fiddler
指纹:
3072,
49196-49195-49200-49199-159-158-49188-49187-49192-49191-49162-49161-49172-49171-157-156-61-60-53-47-10,
0-10-11-13-35-23-65281,
29-23-24,
0

因为Fiddler是csharp写的,应该用的都是微软的封装的ssl实现吧。
所以和csharp的HttpClient是一样的指纹。

5. java JDK自带的HttpsURLConnection
指纹:
3072,
49187-49191-60-49189-49193-103-64-49161-49171-47-49156-49166-51-50-49195-49199-156-49197-49201-158-162-49160-49170-10-49155-49165-22-19-255,
10-11-13,
23-1-3-19-21-6-7-9-10-24-11-12-25-13-14-15-16-17-2-18-4-5-20-8-22,
0

明显可以看出来 EllipticCurve 多了很多!

6. Apache HttpClient
指纹:
3072,
49188-49192-61-49190-49194-107-106-49162-49172-53-49157-49167-57-56-49187-49191-60-49189-49193-103-64-49161-49171-47-49156-49166-51-50-49196-49195-49200-157-49198-49202-159-163-49199-156-49197-49201-158-162-255,
10-11-13-23,
23-24-25,
0

相比上面几个 在 EllipticCurve 上面有明显不一样!

7. curl
指纹:
192,
4866-4867-4865-49196-49200-159-52393-52392-52394-49195-49199-158-49188-49192-107-49187-49191-103-49162-49172-57-49161-49171-51-157-156-61-60-53-47-255,
0-11-10-13172-16-22-23-49-13-43-45-51-21,
29-23-30-25-24,
0-1-2
8. python3的Request
指纹:
192,
4866-4867-4865-49196-49200-49195-49199-52393-52392-163-159-162-158-52394-49327-49325-49188-49192-49162-49172-49315-49311-107-106-57-56-49326-49324-49187-49191-49161-49171-49314-49310-103-64-51-50-157-156-49313-49309-49312-49308-61-60-53-47-255,
0-11-10-35-22-23-13-43-45-51-21,
29-23-30-25-24,
0-1-2

哈哈,实践是检验真理的唯一标准,
不难看出来为什么阿里的waf这么容易就能干掉curl 和 python脚本

ByPass 有办法??当然可以

可以私信交流


我是正东,学的越多不知道也越多。如果决定去深究一个东西, 一定要完全搞懂, 并认真总结一篇博客让以后能在短时间拾起来 ( 因为不搞懂你很难写一篇半年后还能理解的博客 )

欢迎白嫖点赞!

web容器获取SSL指纹实现和ByPass相关推荐

  1. web容器的加载过程

    web容器的加载过程: Web应用由Tomcat实例添加到Tomcat中,即由Tomcat管理一个新添加的Context容器.前面已经提到一个Web应用对应一个Context容器,也就是Servlet ...

  2. Python 实现Web容器指纹识别

    当今的Web安全行业在进行渗透测试时普遍第一步就是去识别目标网站的指纹,从而进一步根据目标框架进行针对性的安全测试,指纹识别的原理其实很简单,目前主流的识别方式有下面这几种. 1.识别特定网页中的关键 ...

  3. 几种常见web 容器

    web容器 1. Tomcat是Apache鼎力支持的Java Web应用服务器,由于它优秀的稳定性以及丰富的文档资料,广泛的使用人群,从而在开源领域受到最广泛的青睐. 2. Jboss作为Java ...

  4. 几种常见web 容器比较

    web 容器比较 tomcat jboss resin weblogic websphere glassfish Tomcat是Apache鼎力支持的Java Web应用服务器,由于它优秀的稳定性以及 ...

  5. 几种常见web 容器比较 (tomcat、 jboss 、resin、 weblogic、 websphere、 glassfish)

    点击打开PDF下载链接 web 容器比较 tomcat jboss resin weblogic websphere glassfish 1. Tomcat是Apache鼎力支持的Java Web应用 ...

  6. Web简单快捷的指纹识别小工具_在线指纹识别平台设计

    Web 指纹识别 本文通过分析 Web 指纹的检测对象.检测方法.检测原理及常用工具,设计了一个简易的指纹搜集脚本来协助发现新指纹,并提取了多个开源指纹识别工具的规则库并进行了规则重组,开发了一个简单 ...

  7. weblogic多次连接后tcp服务堵塞_一文看懂 Web服务器、应用服务器、Web容器、反......

    导读:我们知道,不同肤色的人外貌差别很大,而双胞胎的辨识很难.有意思的是Web服务器/Web容器/Web应用程序服务器/反向代理有点像四胞胎,在网络上经常一起出现.本文将带读者对这四个相似概念如何区分 ...

  8. Web服务器 Web容器 Servlet容器

    WEB服务器也称为WWW(WORLD WIDE WEB)服务器,主要功能是提供网上信息浏览服务. WWW 是 Internet 的多媒体信息查询工具,是 Internet 上近年才发展起来的服务,也是 ...

  9. Web容器自动对HTTP请求中参数进行URLDecode处理

    这篇文章转载自 : Web容器自动对HTTP请求中参数进行URLDecode处理 如题,在Java中也许很多人都没有注意到当我们发送一个http请求时,如果附带的参数被URLEncode之后,到达we ...

最新文章

  1. 【例4-4】最小花费
  2. mac mysql 移动硬盘_MAC一些高能过程记录(一些没必要的坑)
  3. 大恶人吉日嘎拉之走火入魔闭门造车之.NET疯狂架构经验分享系列之(十二)多语言支持...
  4. 清华大学迎来外籍院长!
  5. elasticsearch初次查询超时_ElasticSearch的工作流程
  6. wpf-容易误解的Image
  7. Android 事件拦截分发
  8. NVIDIA发布移动超级计算机“Jetson TK1”性能超树莓派
  9. domoticz添加和风天气,让domoticz显示天气信息
  10. 组合数学之二 —— 容斥原理及应用
  11. 2023年美赛C题Wordle预测问题二建模及Python代码详细讲解
  12. 如何制作gif表情包?试试这个gif表情包制作神器!
  13. 2019年中国幼儿园数量、幼儿园入园率、幼儿园政策及幼儿园市场规模发展趋势分析[图]
  14. 操作系统——放置策略
  15. Java 设计模式——中介者模式(行为型设计模式)
  16. 刘汝佳训练指南《网络流》专题 BY 9974
  17. 小学教师资格考试——综合素质——材料分析
  18. 文献管理三剑客之mendeley 寻找投稿期刊的相关参考文献格式和插入
  19. 怎么下载微信公众号里的视频文件
  20. 从一个角色建模师角度谈谈游戏角色设计

热门文章

  1. 扫描java类文件_java递归与非递归实现扫描文件夹下文件的实例代码
  2. MySQL日期数据类型、时间类型使用总结
  3. 通过java类的反射机制获取类的属性类型
  4. iptables (2) 基本配置
  5. JQuery 判断滚动条是否到底部
  6. 搜索引擎 ElasticSearch 之 步步为营2 【基础概念】
  7. SqlServer和MySQL中存储过程out返回值处理C#代码
  8. 在php中使用sockets:从新闻组中获取文章
  9. 在ie6下实现position-fixed的效果--------续集---对联效果(02)
  10. 鼠标指针放置上面,显示内容_使鼠标指针远离您键入的内容