TLSv1.2抓包解密分析过程之DHE_RSA_WITH_AES_128_CBC_SHA256

DHE_RSA_WITH_AES_128_CBC_SHA256模式下, RSA只用于身份验证, 不用于加密. 加密密钥是通过DH算法交换的. 因此需要DH相关的参数才能解密. 本文的demo样本使用了特殊方法来获取这些参数.

准备工作

已经准备好的抓包数据
https://github.com/wzjwhut/tlsv12-demo/blob/master/src/main/resources/TLS_DHE_RSA_WITH_AES_128_CBC_SHA256.pcapng

下载和修改最新版的openssl源码

修改crypto/dh/dh_key.c
加入一段日志函数

/** 用于打印一段数据内容 */
static const char hexdig[] = "0123456789abcdef";
void log_hex(const char* tag, unsigned char* data, int len){
    char msg[50], *ptr;
    int i;
    ptr = msg;

    for(i=0; i<len; i++) {
        *ptr++ = hexdig[0x0f & (data[i] >> 4)];
        *ptr++ = hexdig[0x0f & data[i]];
        if ((i & 0x0f) == 0x0f) {
            *ptr = '\0';
            ptr = msg;
            printf("%s:  %s\r\n", tag, msg);
        } else {
            *ptr++ = ' ';
        }
    }
    if (i & 0x0f) {
        *ptr = '\0';
        printf("%s:  %s\r\n",tag, msg);
    }
}

修改static int generate_key(DH *dh)函数, 将DH参数打印出来

    /** log */
    unsigned char temp[1024];
    memset(temp, 0, 1024);
    BN_bn2bin(pub_key, temp);
    printf("pub key, bits: %d\r\n", BN_num_bits(pub_key));
    log_hex("pub key: ", temp, 1024);

    memset(temp, 0, 1024);
    BN_bn2bin(priv_key, temp);
    printf("priv key, bits: %d\r\n", BN_num_bits(priv_key));
    log_hex("priv key: ", temp, 1024);

    memset(temp, 0, 1024);
    BN_bn2bin(dh->g, temp);
    printf("dh->g, bits: %d\r\n", BN_num_bits(dh->g));
    log_hex("dh->g: ", temp, 1024);

    memset(temp, 0, 1024);
    BN_bn2bin(dh->p, temp);
    printf("dh->p, bits: %d\r\n", BN_num_bits(dh->p));
    log_hex("dh->p: ", temp, 1024);


    dh->pub_key = pub_key;
    dh->priv_key = priv_key;
    ok = 1;
 err:

然后编译

./config
make
cd apps

抓包

tcpdump -v -w ./my.tcpdump

连接服务器

./openssl s_client -debug -connect x.x.x.x:443 -cipher DHE-RSA-AES128-SHA256

这里修改成自己的IP
然后使用wireshark打开my.tcpdump, 导出相关的参数

开始解析

本文中, 通过修改openssl, 拿到了client的DH私钥, 再加上server的DH公钥, 就可以计算出pre-master.
计算公式为
服务端DH公钥客户端私钥 mod p

    public static final BigInteger DH_P = new BigInteger(HexUtils.fromHexString(
            "00 " + //为了保证BigInteger按照正数解析, 第1个字节必须为0
            "ff ff ff ff ff ff ff ff c9 0f da a2 21 68 c2 34\n" +
            "c4 c6 62 8b 80 dc 1c d1 29 02 4e 08 8a 67 cc 74\n" +
            "02 0b be a6 3b 13 9b 22 51 4a 08 79 8e 34 04 dd\n" +
            "ef 95 19 b3 cd 3a 43 1b 30 2b 0a 6d f2 5f 14 37\n" +
            "4f e1 35 6d 6d 51 c2 45 e4 85 b5 76 62 5e 7e c6\n" +
            "f4 4c 42 e9 a6 37 ed 6b 0b ff 5c b6 f4 06 b7 ed\n" +
            "ee 38 6b fb 5a 89 9f a5 ae 9f 24 11 7c 4b 1f e6\n" +
            "49 28 66 51 ec e6 53 81 ff ff ff ff ff ff ff ff"));
            
    /** PUBKEY = g^privkey mod p */
    public static final BigInteger DH_SERVER_PUBKEY = new BigInteger(HexUtils.fromHexString(
            "78 8d 66 69 7b bf c9 01 f8 2c f0 02 cc 5b 70 cf\n" +
            "af 53 4e 65 26 19 16 48 21 7d 43 50 2f af a1 8c\n" +
            "e8 c9 7c c6 52 f9 a9 fc f9 8d 57 35 e9 c2 d6 41\n" +
            "75 4d 96 15 fa ae 3e 90 b5 47 96 1c 7e e9 10 46\n" +
            "d7 25 73 f7 c6 f2 7b c0 10 3f 76 ab 5c c5 fd 65\n" +
            "ec d0 8f 36 c9 28 66 3f 64 78 84 9c 5a 16 17 8e\n" +
            "78 f5 30 d1 11 f9 d3 19 fa f8 83 2e 97 50 f7 d4\n" +
            "7a 70 b2 10 c2 db 45 73 e6 ef 8a 1c 27 a2 73 86"));

    public static final BigInteger DH_CLIENT_PRIVKEY = new BigInteger(HexUtils.fromHexString(
            "57 99 8b f0 c8 9b bd 7f 42 3a 57 c8 e6 ad 10 80\n" +
            "ad 5e 25 7f e9 a3 c0 ea cc 28 21 35 bb f5 88 69\n" +
            "d0 9c 03 0e a6 d3 9a 5d 93 5a 6b ff 0e aa 93 91\n" +
            "a2 93 f9 5d fd dd a9 fa 26 e9 4a cd b3 17 b9 ab\n" +
            "f9 b8 72 38 90 3c 0e 50 b2 b4 4a 40 61 dd 45 64\n" +
            "f9 d2 cc d3 26 b3 e3 5c ac 02 0d 31 91 2a f5 46\n" +
            "e3 58 70 6b 62 68 a3 be 93 7d 41 1b 1b a9 73 35\n" +
            "1b 52 60 3d f8 d1 45 94 3c ff 76 bf a1 9a 07 7d"));

    /** 使用DH算法, 计算出pre master */
    public static byte[] computePreMaster(){
        byte[] preMaster = DH_SERVER_PUBKEY.modPow(DH_CLIENT_PRIVKEY, DH_P).toByteArray();
        logger.info("premaster:\r\n{}", HexUtils.dumpString(preMaster, 16));
        return preMaster;
    }

通过pre master, 可以计算出master secret, 进而计算出各端的加密私钥. 参照本人写的
https://blog.csdn.net/wzj_whut/article/details/86626529#Master_Secret_106
代码参考
https://github.com/wzjwhut/tlsv12-demo/blob/master/src/main/java/com/wzjwhut/example/Analyse_DHE_RSA_WITH_AES_128_CBC_SHA256.java

猜你喜欢

转载自blog.csdn.net/wzj_whut/article/details/86646812
今日推荐