Controllo del client ciao per la classificazione https

7

Devo rilevare i pacchetti https nel traffico di rete. Fino ad ora stavo contrassegnando tutti "443" come https ma non voglio più utilizzare le informazioni sulla porta per questi.

Sarà sufficiente controllare il messaggio di benvenuto del cliente come:

//Check 22 and version info 0300 0301 or 0302
if (packet->payload[0] == 0x16 && packet->payload[1] == 0x03
  && (packet->payload[2] == 0x00 || packet->payload[2] == 0x01 || packet->payload[2] == 0x02)

{
    int temp = ntohs(get_u16(packet->payload, 3)) + 5;//Get lenght 
//Check lenght is valid and 6th byte is client hello(which is 1)
    if (temp < packet->payload_length && temp > 50 && packet->payload[5]) == 1) 
        MARK AS HTTPS 
}

A causa del mio progetto, non posso controllare più di un pacchetto. Puoi per favore avvisare se solo il controllo del cliente ciao come sopra è ok o no?

    
posta Kadir Erdem Demir 24.04.2013 - 15:58
fonte

3 risposte

12

In SSL / TLS , i messaggi vengono inviati come parte di record . Quello che ci si deve aspettare è che il client invii prima un messaggio ClientHello che è contenuto in uno o più record.

Il formato del record è:

record type: 1 byte (0x16 for "records contains some handshake message data")
protocol version: 2 bytes (0x03 0x00 for SSL 3.0, 0x03 0x01 for TLS 1.0, and so on)
record length: 2 bytes (big endian)
then the record data...

Per il primo record (da client a server), il client invierà prima un messaggio ClientHello che è un tipo di messaggio handshake, quindi incapsulato in un record come mostrato sopra (il primo byte del record sarà 0x16 ). In teoria , il client può inviare la suddivisione ClientHello in più record e può iniziare con uno o più record vuoti, ma ciò non è molto probabile. Il messaggio ClientHello inizia con la sua intestazione a quattro byte, con un byte per il tipo di messaggio (0x01 per ClientHello ), quindi la lunghezza del messaggio su tre byte (di nuovo big-endian).

Una volta che il client ha inviato il suo ClientHello , allora si aspetta una risposta dal server, quindi ClientHello sarà solo nel suo record.

Quindi potresti aspettarti un payload che inizi con i seguenti 9 byte:

0x16 0x03 X Y Z 0x01 A B C

con:

  • X sarà 0, 1, 2, 3 ... o più , a seconda della versione del protocollo utilizzata dal client per questo primo messaggio. Attualmente , le versioni SSL / TLS definite sono SSL 3.0 , TLS 1.0 , TLS 1.1 e TLS 1.2 . Altre versioni potrebbero essere definite in futuro. probabilmente useranno lo schema di numerazione 3. X , quindi puoi aspettarti che il secondo byte di intestazione rimanga un 0x03, ma non dovresti limitare arbitrariamente il terzo byte.

  • Y Z è la codifica della lunghezza del record; A B C è la codifica della lunghezza del messaggio ClientHello . Poiché il messaggio ClientHello inizia con un'intestazione di 4 byte (non compresa nella sua lunghezza) e si suppone che sia solo nel suo record, dovresti avere: A = 0 e 256 * X + Y = 256 * B + C + 4 .

Se vedi 9 di questi byte, che verificano queste condizioni, è probabile che si tratti di ClientHello da un client SSL.

Alcuni client SSL non recenti possono supportare anche una versione precedente del protocollo, denominata SSL 2.0. Questi client emetteranno un ClientHello che segue le regole SSL 2.0, dove messaggi e record sono in qualche modo uniti. Il messaggio diClientHello di SSL 2.0% indicherà che il client conosce anche SSL 3.0 o più recente, ma non inizierà con la sequenza di 9 byte spiegata sopra.

La struttura diClientHello di SSL 2.0% è spiegata in appendice E.2 o RFC 5246 . Anche se tali client sono rarefatti (esiste un RFC sul divieto del supporto di SSL 2.0 del tutto), ci sono ancora molti implementati là fuori.

Il tuo codice ha alcuni problemi:

  • Non rileva un messaggio diClientHello di SSL 2.0%.
  • Verifica che il terzo byte di intestazione ( X nella mia descrizione sopra) sia uguale a 0, 1 o 2, che esclude TLS 1.2. Questo è troppo restrittivo.
  • Presume che l'intero ClientHello sarà in un singolo record (che è un'ipotesi ragionevole) e che questo ClientHello sarà codificato in un singolo pacchetto (che è un'ipotesi molto meno ragionevole).
  • Non prova a guardare la lunghezza del messaggio di handshake e a confermarlo con la lunghezza del record.

Di conseguenza, l'evasione del rilevamento sarà facile (utilizzando unClientHello di SSL 2.0%, utilizzando un record codificato con la versione TLS 1.2, creando un messaggio di ClientHello che non rientra in un singolo pacchetto ... il il metodo è numeroso); e alcuni client esistenti non verranno rilevati: non solo uno può evitare il rilevamento di proposito , ma è anche possibile involontariamente .

    
risposta data 24.04.2013 - 16:33
fonte
1

Because of my project design, I can't check more than one packet . Can you please advise if just checking client hello like above is ok or not ?

Se non ti aspetti che il client aggiri il tuo rilevamento potrebbe essere sufficiente controllare i byte tipici all'inizio del client ciao all'interno del primo pacchetto che ricevi. Ma, se si usasse questo per bloccare il traffico https ma consentire qualsiasi altra cosa sarebbe facile aggirare il rilevamento distribuendo i primi byte del client hello su più pacchetti TCP. Questo è possibile perché https usa TCP come protocollo sottostante e TCP è un trasporto di flusso che non si preoccupa dei confini dei pacchetti.

Si noti inoltre che ci sono alcune applicazioni che cercano di apparire come il traffico https per ingannare i firewall facendoli passare. Un tipico esempio è Skype quando tenta di eseguire il tunneling tramite un proxy HTTP (s).

Inoltre, non controlli veramente https ma solo SSL. HTTPS è HTTP all'interno di un tunnel SSL, ma non è possibile rilevare se il protocollo nel tunnel è realmente HTTP o un altro protocollo come IMAP, POP, SMTP ecc.

    
risposta data 20.10.2014 - 22:32
fonte
0

Tom la tua risposta è così dettagliata e utile. Sono molto grato. Ho considerato i punti e ho cercato di migliorare la mia implementazione. Perché è un po 'grande sto scrivendo come una nuova risposta. È diventato un po 'lungo che non mi aspetto che qualcuno analizzi, ma se forse qualcuno ha bisogno, può essere utile.

if (flow_special_packet_counter == 0)
{
    //SSLv2 no server name extension I don't have to mark it now I will wait for server hello 
    if (pkt->pllen >= 27 && pkt->pl[2] == 0x01 && pkt->pl[3] == 0x03
    && (pkt->pl[4] == 0x00 || pkt->pl[4] == 0x01 || pkt->pl[4] == 0x02 || pkt->pl[4] == 0x03)
    && (pkt->pllen - pkt->pl[1]) == 2)
    // SSLv2 Record
    {
        flow_special_packet_counter++;
        return;
    }
    //SSLv3 client hello is important for me I will try to mark it if only package lenght is bigger I will wait for server hello 
    else if (pkt->pllen >= 47 && pkt->pl[0] == 0x16 && pkt->pl[1] == 0x03
      && (pkt->pl[2] == 0x00 || pkt->pl[2] == 0x01 || pkt->pl[2] == 0x02 || pkt->pl[2] == 0x03 ))
    // SSLv3 Record
    {
        if (pkt->pl[5] != 0x02)//No client hello 
             return;

        unsigned short sslv3ClientHelloLength = ntohs(getU16n2h(pkt->pl[3]));
        if (sslv3ClientHelloLength > (pkt->pllen - 5))//client hello bigger than payload than wait for second 
        {
            flow_special_packet_counter++;  
            return;
        }
        else 
        {
            if((pkt->pllen - sslv3ClientHelloLength) == 5)
               MARKS AS HTTPS return;
            else 
               return;
        }

    }
    else if (flow_special_packet_counter == 0 && flow_pktcount > 10) //Enough checking this flow is not https 
    {
        NEVER HTTPS return; 
    }
}
else if (flow_special_packet_counter == 1)
{
    if (flow_pktcount > 20)
    NEVER HTTPS return;
    if (pkt->pllen >= 47 && pkt->pl[0] == 0x16 && pkt->pl[1] == 0x03
      && (pkt->pl[2] == 0x00 || pkt->pl[2] == 0x01 || pkt->pl[2] == 0x02 || pkt->pl[2] == 0x03 && pkt->pl[5] == 0x02))
      {
            MARKS AS HTTPS return;//Double records been check I think that is enough now time for testing :) 
      }  
}
    
risposta data 25.04.2013 - 15:46
fonte

Leggi altre domande sui tag