Wireshark分析RDP服务器专有证书
编辑本文记录一次使用Wireshark分析RDP证书的过程,这次遇到的证书比较特殊,是服务器专有证书(Server Proprietary Certificate),不能直接使用X.509格式的方式查看,当时为了分析这个证书花了不少时间。
下面记录一下分析过程,不想看过程可以直接跳到第三章节看快速判断方法。
一、定位数据位置
1. 筛选数据包
首先筛选RDP协议并找到ServerData Encryption
包
2. 定位数据
定位到serverCertificate
字段,就是证书数据
Remote Desktop Protocol
-> serverData
-> serverSecurityData
-> serverCertificate
3. 查看数据
右键serverCertificate
那一行,选择“显示分组字节”,以“原始数据”方式显示,看到的就是字段数据了。
二、提取关键信息
上一步得到的数据为:
01000000010000000100000006001c01525341310801000000080000ff00000001000100ed35ff44bcce04b388cce4d949a30712111fd4a82fdde4a26245e5758a713f8b1d3cfe8cfd4393730f7b296c18df1a25b0983fb6f864b956cf6559379635b47bbf69caa76947db43e5bc4ed39299d821b7283f29c7e85555088e17616faef0fcef7902b711acbe01fabf1dd945c5a8a4f24c019a348ad2ecaf67a0ffeacf65a142ee5fa1e11e48d5d8969df007c48daa82ad4eed59276a8673e0faf5932f636d0b1e45e03d7ea2697a438fda3126cdded07944e6cc97119d0931d01726f059fa42b1597c802112d5e753571bac85359d9cd0441d5d4ba3599057eefea251c2708d3375bdb25bea8d19166f007e7f061d86b43366f15de48b679d2e59f594cac00000000000000000080048006001ac441fd87ad6978c35a093a794cb94fd32f8bce3a4ebbf2b24b0f7323eb3ecb633e57c187c4609c3a7811a4731e326e7fafd64c386badcbe5bf28e9e45010000000000000000
参考微软官方文档:[MS-RDPBCGR]: Server Certificate (SERVER_CERTIFICATE) | Microsoft Learn
文档中给出了每组字节的含义:
内容如下表:
文档解释:
dwVersion (4 bytes): A 32-bit, unsigned integer. The format of this field is described by the following bitmask diagram.
最开头的4个字节是dwVersion
字段,之后的数据就是证书数据certData
。
接着看,dwVersion
又分为两部分:
内容如下表:
文档解释:
certChainVersion (31 bits): A 31-bit, unsigned integer that contains the certificate version.
t (1 bit): A 1-bit field that indicates whether the certificate contained in the certData field has been permanently or temporarily issued to the server.
前31个bit是证书链版本(certChainVersion),第32个bit代表有效期类型。
1. 判断证书链版本
再看证书链版本的说明:
当certChainVersion
的值为0x00000001
时,证书属于“服务器专有证书”,格式内容可以参考文档:[MS-RDPBCGR]: Server Proprietary Certificate (PROPRIETARYSERVERCERTIFICATE) | Microsoft Learn
当certChainVersion
的值为0x00000002
时,证书就属于常见的X.509格式证书。
这里补充说明一下这个字节怎么读,涉及到一个叫“字节序”的知识点,可以自行百度了解一下,现在例子中就属于“小端序”。
取证书中前4个字节为例,可以看到证书数据前8个字符是:
[ 01000000 ]
一个“字符”代表一位十六进制数,也就是4位二进制。一个字节是8位二进制,那就是2个“字符”表示一个字节,所以每两个字符分为一组,就是4个字节:
[ 01 ; 00 ; 00 ; 00 ]
然后以字节位单位从右往左读,得到:
[ 00000001 ]
也就是上面所说的0x00000001
,那么表示证书属于“服务器专有证书”。
上面例子中零太多了,不直观,再举个例子,假设Wireshark中看到的数据是:
[ 12 ; 34 ; 56 ; 78 ]
那么实际的数据不是87654321
,而是:
[ 78563412 ]
2. 分析证书内容
确定了证书版本,下一步就是按照专有证书的格式分析内容。继续参考文档:[MS-RDPBCGR]: Server Proprietary Certificate (PROPRIETARYSERVERCERTIFICATE) | Microsoft Learn
字段的官方说明:
dwVersion (4 bytes): A 32-bit, unsigned integer. The certificate version number. This field MUST be set to CERT_CHAIN_VERSION_1 (0x00000001).
dwSigAlgId (4 bytes): A 32-bit, unsigned integer. The signature algorithm identifier. This field MUST be set to SIGNATURE_ALG_RSA (0x00000001).
dwKeyAlgId (4 bytes): A 32-bit, unsigned integer. The key algorithm identifier. This field MUST be set to KEY_EXCHANGE_ALG_RSA (0x00000001).
wPublicKeyBlobType (2 bytes): A 16-bit, unsigned integer. The type of data in the PublicKeyBlob field. This field MUST be set to BB_RSA_KEY_BLOB (0x0006).
wPublicKeyBlobLen (2 bytes): A 16-bit, unsigned integer. The size in bytes of the PublicKeyBlob field.
PublicKeyBlob (variable): Variable-length server public key bytes, formatted using the Rivest-Shamir-Adleman (RSA) Public Key structure (section 2.2.1.4.3.1.1.1). The length in bytes is given by the wPublicKeyBlobLen field.
wSignatureBlobType (2 bytes): A 16-bit, unsigned integer. The type of data in the SignatureBlob field. This field is set to BB_RSA_SIGNATURE_BLOB (0x0008).
wSignatureBlobLen (2 bytes): A 16-bit, unsigned integer. The size in bytes of the SignatureBlob field.
SignatureBlob (variable): Variable-length signature of the certificate created with the Terminal Services Signing Key (sections 5.3.3.1.1 and 5.3.3.1.2). The length in bytes is given by the wSignatureBlobLen field.
版本(4字节):固定值0x00000001
。
签名算法ID(4字节):固定值0x00000001
,代表RSA算法。
密钥交换算法(4字节):固定值0x00000001
,代表RSA算法。
公钥类型(2字节):固定值0x0006
,代表RSA类型的密钥。
公钥长度(2字节):表示下边“PublicKeyBlob”公钥值的长度有多长,单位是字节。
公钥对象:根据上面的长度判断占用几个字节。
签名类型(2字节):固定值0x0008
,代表RSA签名。
签名长度(2字节):表示下边“SignatureBlob”签名值的长度有多长,单位是字节。
签名对象:根据上面的长度判断占用几个字节。
算法已经定死了,所以直接看公钥长度,第13、14字节代表公钥长度,既第25~28个字符,或者直接找0600
后面的4个字符:
[ 1c ; 01 ]
按小端序读法这个十六进制数就是:
[ 011c ]
转换成十进制就是284,就是说公钥对象长度是284个字节,即之后( 284 times 2 = 568 )个字符是公钥对象,注意公钥对象不等于公钥,后面还要继续分析:
525341310801000000080000ff00000001000100ed35ff44bcce04b388cce4d949a30712111fd4a82fdde4a26245e5758a713f8b1d3cfe8cfd4393730f7b296c18df1a25b0983fb6f864b956cf6559379635b47bbf69caa76947db43e5bc4ed39299d821b7283f29c7e85555088e17616faef0fcef7902b711acbe01fabf1dd945c5a8a4f24c019a348ad2ecaf67a0ffeacf65a142ee5fa1e11e48d5d8969df007c48daa82ad4eed59276a8673e0faf5932f636d0b1e45e03d7ea2697a438fda3126cdded07944e6cc97119d0931d01726f059fa42b1597c802112d5e753571bac85359d9cd0441d5d4ba3599057eefea251c2708d3375bdb25bea8d19166f007e7f061d86b43366f15de48b679d2e59f594cac00000000000000000
小技巧,复制到记事本里就很方便选取一定长度的字符。
公钥对象后面必定是0800
,也可以用这个帮助判断有没有选对。
公钥对象分析参考这篇:[MS-RDPBCGR]: RSA Public Key (RSA_PUBLIC_KEY) | Microsoft Learn
官方字段解释:
magic (4 bytes): A 32-bit, unsigned integer. The sentinel value. This field MUST be set to 0x31415352.
keylen (4 bytes): A 32-bit, unsigned integer. The size in bytes of the modulus field. This value is directly related to the bitlen field and MUST be ((bitlen / 8) + 8) bytes.
bitlen (4 bytes): A 32-bit, unsigned integer. The number of bits in the public key modulus.
datalen (4 bytes): A 32-bit, unsigned integer. The maximum number of bytes that can be encoded using the public key. This value is directly related to the bitlen field and MUST be ((bitlen / 8) - 1) bytes.
pubExp (4 bytes): A 32-bit, unsigned integer. The public exponent of the public key.
modulus (variable): A variable-length array of bytes containing the public key modulus. The length in bytes of this field is given by the keylen field. The modulus field contains all (bitlen / 8) bytes of the public key modulus and 8 bytes of zero padding (which MUST follow after the modulus bytes).
一个固定值(4字节):0x31415352
modulus字段的长度(4字节):等于((bitlen / 8) + 8) 个字节。
bitlen(4字节):公钥的模的比特数。
可用公钥编码的数据的最大长度(4字节):等于((bitlen / 8) - 1)个字节。
公钥的E值(4字节):E值,通常是0x00010001
,也就是65537。
modulus字段:包含公钥的模值,即N值,最后用8个字节的零填充。
所以进行如下操作,modulus字段去掉最后16个零,得到小端序顺序的N值:
ed35ff44bcce04b388cce4d949a30712111fd4a82fdde4a26245e5758a713f8b1d3cfe8cfd4393730f7b296c18df1a25b0983fb6f864b956cf6559379635b47bbf69caa76947db43e5bc4ed39299d821b7283f29c7e85555088e17616faef0fcef7902b711acbe01fabf1dd945c5a8a4f24c019a348ad2ecaf67a0ffeacf65a142ee5fa1e11e48d5d8969df007c48daa82ad4eed59276a8673e0faf5932f636d0b1e45e03d7ea2697a438fda3126cdded07944e6cc97119d0931d01726f059fa42b1597c802112d5e753571bac85359d9cd0441d5d4ba3599057eefea251c2708d3375bdb25bea8d19166f007e7f061d86b43366f15de48b679d2e59f594cac0
写了小脚本将小端序转成大端序(正常阅读顺序):
def read_pairs(input_string):
if len(input_string) % 2 != 0:
raise ValueError(" 输入字符串的长度必须是偶数")
pairs = [input_string[i:i+2] for i in range(0, len(input_string), 2)]
return pairs
little_endian_data = input(" 请输入字符串:")
pairs = read_pairs(little_endian_data)
integer_in_big_endian = ''
for pair in pairs:
integer_in_big_endian = pair + integer_in_big_endian
print(integer_in_big_endian)
最后提取签名对象的方法也是一样的。
三、总结:快速判断的方法
直接看serverCertificate
的开头,如果是02
那就是X.509的证书,去除前8个字符剩下的就是证书的十六进制数据,转成base64编码保存到文本文件(注意是十六进制转base64,不是字符转base64),重命名为cer
后缀即可双击打开。
X.509格式证书第一个字节是0x30
,可以利用这点帮助判断数据正确性。
如果serverCertificate
是以01
开头,那属于专有证书。密评中只需要知道用什么算法即可,那签名算法、密钥交换算法都固定是RSA了,直接看第25~28个字符(或0600
后的4个字符)得到公钥长度(注意是小端序读法),以此判断是RSA2048还是RSA1024算法,完成!
- 0
- 0
-
分享