使用 openssl 命令行工具解密 SSL 流量 - 续第 5 部分

使用 openssl 命令行工具解密 SSL 流量 - 续第 5 部分

来自我以前的帖子第1部分第2部分第 3 部分第 4 部分我相信我已经正确地计算/解密了所有内容,并准备好尝试解密客户端加密的握手消息。一旦我拥有所有密钥,我就无法进行下一步了。我已经阅读和研究了几天,但就是卡住了。

按照我以前文章中的指导方针,我得出了

20 bytes for a client MAC key: 64666eafe1cbd51f2e2b50799b40f6007c3dc56f
20 bytes for a server MAC key: e0aac1312d35b5e8b6bf9af6ecf07e1dff27c784
32 bytes client encryption key:
4bf20108190203c4210ff9df6c4eb6e907ddd1f49646ab4b243c80a6ae9b4808
32 bytes for a server encryption key:
 ca94445e3d771d3e06b71ee0deb4c1879986c4c6a4b78bf1c3c1083a6ddce9ff

我的加密客户端握手信息:

Hex.       FILE SIZE: 40
 ADDRESS   000 001 002 003 004 005 006 007       ASCII
===============================================================================
00000000   09A 01B 0F3 06B 078 06C 03B 059      ~Z  ^[  -s   k   x   l   ;   Y
00000008   085 061 07C 076 0AF 0D9 085 0D6      ~E   a   |   v  -/  -Y  ~E  -V
00000010   08F 0FD 0AF 06D 09F 01A 025 0EF      ~O  -}  -/   m  ~_  ^Z   %  -o
00000018   040 015 097 002 0B5 0AD 0EF 040       @  ^U  ~W  ^B  -5  --  -o   @
00000020   02B 0DB 051 096 0CE 076 0A9 03F       +  -[   Q  ~V  -N   v  -)   ?
00000028   0D7 030 049 03A 0CC 0F9 029 044      -W   0   I   :  -L  -y   )   D
00000030   07F 0A9 0C6 0F1 017 02D 06B 040      ^?  -)  -F  -q  ^W   -   k   @
00000038   035 0F5 057 08E 0BF 0E9 05C 06D       5  -u   W  ~N  -?  -i   \   m
00000040

我认为我需要使用 openssl end -d -K 的变体,但在 RFC 和谷歌之间徘徊,找不到一个能清楚解释它的解决方案/示例。有人知道我如何在 openssl 的命令行中执行此操作吗?谢谢

更新。我不确定为什么/如何我忽略了RFC 7.4.9 PRF(master_secret, finished_label, Hash(handshake_messages))我确实记录了所有握手消息,有人能解释一下如何仅使用 openssl 命令行以及到目前为止我捕获/解密的数据来模拟这一点吗?看起来我需要在此之前执行握手消息的哈希值RFC 第 5 节我假设我将使用我生成的 master_secret,我不确定使用 openssl 的种子应该是什么,就像我以前使用的那样。我没有看到这个哈希有一个连接的标签,所以我是否只使用到这一点的所有握手消息连接在一起?有很多步骤我都迷路了。谢谢

openssl dgst -sha256 -mac hmac -macopt hexkey:$key <seed -binary >a1

答案1

我很好奇你每次发帖时似乎都使用一种新的文件转储格式:-)

假设您像以前一样使用 (RSA-with-)AES256CBC-(HMAC)SHA1:是的,你可以使用以下方法解密 TLS CBC 密码openssl enc,ARIA 除外。(还有 RC4,尽管你应该避免将 RC4 用于任何目的,包括 TLS。另一方面enc不能使用任何 AEAD 密码:不能使用 GCM 或 CCM,也不能使用 ChaCha/Poly。)TLS1.2(和 1.1)中 CBC 密码的记录格式包含在RFC5246 第 6.2.3.2 节对于 AES,前 16 个八位字节是 IV,其余部分是密文,应该解密为纯文本记录主体(在本例中为完成消息)加上 HMAC 加上填充 - 但 TLS 填充与 API 支持的(以及enc内部支持的EVP_{??crypt,Cipher}*) PKCS5/7 填充不同,因此您需要自己完成该部分。

如您的系统上的手册页中所述或在网上,以及几个 Stacks 上的很多问题(尽管我注意到大多数问题都是关于将命令行与其他代码(如 Java 和 python 等)进行匹配,而不是与规范进行匹配),openssl enc默认为基于密码加密(PBE)不是您想要的。要进行“基于密钥”的解密,您需要指定-d-K(大写而不是小写),密钥为十六进制,-ivIV 为十六进制(如果由密码使用的话)(AES-CBC 会使用):

$ echo $key; echo $iv
4bf20108190203c4210ff9df6c4eb6e907ddd1f49646ab4b243c80a6ae9b4808
9A1BF36B786C3B5985617C76AFD985D6
$ sed 1,2d <1346633.dat
8FFDAF6D9F1A25EF
40159702B5ADEF40
2BDB5196CE76A93F
D730493ACCF92944
7FA9C6F1172D6B40
35F5578EBFE95C6D
$ sed 1,2d <1346633.dat |xxd -p -r |openssl aes-256-cbc -d -K $key -iv $iv -nopad |xxd
0000000: f730 34cc b90f b0b0 6313 9a0f 239c 6e87  .04.....c...#.n.
0000010: 187f ff00 52d1 3e9c 2aef d5cd c07e 15be  ....R.>.*....~..
0000020: dee0 aa95 6994 5ce6 768d 1952 ac00 17ba  ....i.\.v..R....

不幸的是,如您所见,此解密无效:它没有以 TLS 样式的填充结束,也没有以 Finished 消息开始,而客户端的第一个后 CCS 传输必须是这样的。要么是您的派生密钥有误,要么是您对此记录的转储有误。

一个可能有帮助的建议:使用(编辑) openssl s_client -debug并将其输出记录到文件中。这会转储所有十六进制(和 ASCII)记录,您可以将其用作数据或验证各种输入(包括包含已完成的加密记录),并且末尾的“SSL-Session”块包含主密钥的正确值,您可以将其用作交叉检查。您可以添加-msg以转储加密消息;这比较麻烦,但更方便一些,这就是我下面所做的。另一种可能性,需要做更多的设置工作,是从使用 sysprop 和 log 运行的 Java SSL/TLS(JSSE)客户端程序进行连接javax.net.debug=ssl;该程序会转储很多包括主秘密在内的信息工作键。


举个例子应该工作中,我在一个记录的示例会话中完成了该过程(实际上是我在几周前在您的第一个 Q 中创建的),手动执行主控和工作派生并解密和验证客户端的完成消息:

$ cat tempc
2f e9 97 3e e4 11 89 81 c5 bc 18   11 7b c9 e9 3d
64 cb 88 6e a4 ac f2 01 95 05 d7
fe 3d 09 f4 13 4a d7 39 77 bf 50 dc f4 7b 9b b8
3c 0b 2f bf 98 5a 9c 4c 2d 28 6c 6a b6 93 a9 29
c5 5f f1 a3 cd
$ # this is the hexdump of from s_client -debug, cleaned up 
$
$ echo $key; echo $iv
7d18617e178fc6320019442c6cd071ca4b4f7d2bb83f6194c23681aefd84f120
2fe9973ee4118981c5bc18117bc9e93d
$ # you can see the IV is the first line (16 bytes) of tempc
$ sed 1d tempc |xxd -p -r |openssl aes-256-cbc -d -K $key -iv $iv -nopad |tee tempc! |xxd
0000000: 1400 000c 5bbc 39d8 6c5d dbb1 076b b91b  ....[.9.l]...k..
0000010: 9f4e 5c55 fd9e a185 6901 4bc0 6f02 2c0d  .N\U....i.K.o.,.
0000020: 5bb0 d8c9 0b0b 0b0b 0b0b 0b0b 0b0b 0b0b  [...............
$ # those last 12 bytes are SSL/TLS-style padding 
$ # the first 4 bytes are a handshake message header for x14=Finished,
$ # followed by the 12 byte verify_data value, total 16 bytes 
$
$ echo $mkey
28a3244d49c644f889b44f2bae54466b6913fb1e
$ { printf '\0\0\0\0\0\0\0\0\x16\x03\x03\0\x10'; head -c16 tempc! ; } \
> |openssl sha1 -mac hmac -macopt hexkey:$mkey -binary |xxd -p 
9f4e5c55fd9ea18569014bc06f022c0d5bb0d8c9
$ # the 20 bytes after the 16-byte message and before the padding 
$ # correctly match HMAC-SHA1 of the pseudoheader plus the message

至于‘验证数据’完成消息是的,您需要获取所有先前握手消息的哈希值,如 7.4.9 中所述(在 TLS1.3 中,这被称为“抄本”哈希值),然后获取 PRF(如之前的帖子中所述),其中密钥是主密钥,种子是固定标签“客户端完成”或“服务器完成”(视情况而定)加上该抄本哈希值。这需要做大量的工作,我没有为示例做这件事,尽管如果有必要我可能会做。

相关内容