Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

I need to detect https packets in network traffic . Until now I were marking all "443" as https but I don't want to use port information for these any more .

Will it be enough to check client hello message like :

//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 
}

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 ?

share|improve this question

2 Answers 2

up vote 6 down vote accepted

In SSL/TLS, messages are sent as part of records. What should be expected is that the client first send a ClientHello message which itself is contained in one or several records.

Record format is:

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...

For the first record (from client to server), the client will first send a ClientHello message which is a type of handshake message, hence encapsulated in a record as shown above (the first byte of the record will be 0x16). Theoretically, the client may send the ClientHello split into several records, and it may begin with one or several empty records, but this is not very probable. The ClientHello message itself begins with its own four-byte header, with one byte for the message type (0x01 for ClientHello), then the message length over three bytes (there again, big-endian).

Once the client has sent its ClientHello, then it expects a response from the server, so the ClientHello will be alone in its record.

So you could expect a payload which begins with the following 9 bytes:

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

with:

  • X will be 0, 1, 2, 3... or more, depending on the protocol version used by the client for this first message. Currently, defined SSL/TLS versions are SSL 3.0, TLS 1.0, TLS 1.1 and TLS 1.2. Other versions may be defined in the future. They will probably use the 3.X numbering scheme, so you can expect the second header byte to remain a 0x03, but you should not arbitrarily limit the third byte.

  • Y Z is the encoding of the record length; A B C is the encoding of the ClientHello message length. Since the ClientHello message begins with a 4-byte header (not including in its length) and is supposed to be alone in its record, you should have: A = 0 and 256*X+Y = 256*B+C+4.

If you see 9 such bytes, which verify these conditions, then chances are that this is a ClientHello from a SSL client.


Some non-very-recent SSL client may also support an older protocol version, called SSL 2.0. These clients will emit a ClientHello which follows the SSL 2.0 rules, where messages and records are somehow merged. That SSL 2.0 ClientHello message will state that the client also knows SSL 3.0 or more recent, but it won't begin with the 9-byte sequence explained above.

SSL 2.0 ClientHello structure is explained in appendix E.2 or RFC 5246. Although such clients are rarefying (there is a RFC about prohibiting SSL 2.0 support altogether), there are still many deployed out there.


Your code has a few problems:

  • It does not detect a SSL 2.0 ClientHello message.
  • It checks that the third header byte (X in my description above) is equal to 0, 1 or 2, which rules out TLS 1.2. This is too restrictive.
  • It assumes that the whole ClientHello will be in a single record (which is a reasonable assumption) and that this ClientHello will be encoded in a single packet (which is a much less reasonable assumption).
  • It does not try to look at the length in the handshake message and corroborate it with the record length.

Correspondingly, evading detection will be easy (by using a SSL 2.0 ClientHello, by using a record tagged with TLS 1.2 version, by making a big ClientHello message which does not fit in a single packet... the method are numerous); and some existing deployed clients will not be detected: not only one can avoid detection on purpose, but it is also possible unwillingly.

share|improve this answer

Tom your answer is so much detailed and useful . I am very thankful . I considered points and tried to improve my implementation. Because it is a little big I am writing as a new answer . It became a little long I don't expect anyone to analyze but if maybe someone needs , it can be useful .

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 :) 
      }  
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.