Changeset 1165

Show
Ignore:
Timestamp:
07/03/08 19:06:27 (5 months ago)
Author:
mbr
Message:

- SPA packets are base64-encoded by the fwknop client, and this encoding
pads data with '=' chars until the total length of the encoded data is a
multiple of four. This characteristic can be used within a Snort rule
to assist in the detection of SPA communications. The 1.9.6 release of
fwknop strips out these padding characters before the client sends an
SPA packet, and the fwknopd server adds them back in (to form a multiple
of four) before base64 decoding the packet data. This reduces the level
of identifying information in SPA packets and therefore makes it more
difficult to detect the usage of SPA for service access. For reference,
a Snort rule that would detect SPA packets via the trailing '=' chars
(previous to this release) would be:

alert udp any any -> any 62201 (msg:"fwknop SPA traffic"; \
dsize:>150; pcre:"/==$/"; sid:20080001; rev:1;)

- According to the 'file' command (via it's 'magic') database, files that
are encrypted with GnuPG begin with 0x8502, and this is true for SPA
packets generated by fwknop (previous to this release). In
fwknop-1.9.6, the "hQ" prefix is removed by the fwknop client and added
back in by the fwknopd server if it doesn't exist. This measure is
another effort to make SPA packets more difficult to detect on the wire,
such as with the following Snort rule:

alert udp any any -> any 62201 (msg:"fwknop GnuPG encrypted SPA
traffic"; content:"hQ"; depth:2; dsize:>1000; sid:20080003; rev:1;)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • fwknop/trunk/ChangeLog

    r1163 r1165  
    11fwknop-1.9.6 (07//2008): 
     2    - SPA packets are base64-encoded by the fwknop client, and this encoding 
     3      pads data with '=' chars until the total length of the encoded data is a 
     4      multiple of four.  This characteristic can be used within a Snort rule 
     5      to assist in the detection of SPA communications.  The 1.9.6 release of 
     6      fwknop strips out these padding characters before the client sends an 
     7      SPA packet, and the fwknopd server adds them back in (to form a multiple 
     8      of four) before base64 decoding the packet data.  This reduces the level 
     9      of identifying information in SPA packets and therefore makes it more 
     10      difficult to detect the usage of SPA for service access.  For reference, 
     11      a Snort rule that would detect SPA packets via the trailing '=' chars 
     12      (previous to this release) would be: 
     13 
     14        alert udp any any -> any 62201 (msg:"fwknop SPA traffic"; \ 
     15        dsize:>150; pcre:"/==$/"; sid:20080001; rev:1;) 
     16 
     17    - According to the 'file' command (via it's 'magic') database, files that 
     18      are encrypted with GnuPG begin with 0x8502, and this is true for SPA 
     19      packets generated by fwknop (previous to this release).  In 
     20      fwknop-1.9.6, the "hQ" prefix is removed by the fwknop client and added 
     21      back in by the fwknopd server if it doesn't exist.  This measure is 
     22      another effort to make SPA packets more difficult to detect on the wire, 
     23      such as with the following Snort rule: 
     24 
     25        alert udp any any -> any 62201 (msg:"fwknop GnuPG encrypted SPA 
     26        traffic"; content:"hQ"; depth:2; dsize:>1000; sid:20080003; rev:1;) 
     27 
    228    - (Test suite): Added the ability to explicitly run major classes of tests 
    329      with two new command line arguments to the fwknop_test.pl script: 
  • fwknop/trunk/fwknop

    r1163 r1165  
    103103my $knock_dst_pre_resolve = ''; 
    104104my $selected_random_nat_port = 0; 
     105my $include_base64_trailing_equals = 0; 
     106my $include_base64_gnupg_prefix = 0; 
    105107my $rand_port     = 0;  ### for SPA packet destination port 
    106108my $NAT_rand_port = 0;  ### for randomized access based on 
     
    509511    } 
    510512 
     513    my $encrypted_msg = ''; 
    511514    if ($gpg_signing_key or $gpg_default_key) { 
    512         return &pcap_GPG_encrypt_msg($msg); 
    513     } 
    514     return &pcap_Rijndael_encrypt_msg($msg); 
     515        $encrypted_msg = &pcap_GPG_encrypt_msg($msg); 
     516    } else { 
     517        $encrypted_msg = &pcap_Rijndael_encrypt_msg($msg); 
     518    } 
     519 
     520    unless ($include_base64_trailing_equals) { 
     521        print "[+] Stripping trailing equals chars from base64 encoding.\n" 
     522            if $debug; 
     523        $encrypted_msg =~ s/=*$//; 
     524    } 
     525 
     526    return $encrypted_msg; 
    515527} 
    516528 
     
    777789    my $encoded_msg = encode_base64($ctext, ''); 
    778790 
     791    if ($verbose and $debug) { 
     792        print "[+] base64-encoded message before stripping identifying chars:\n", 
     793            $encoded_msg, "\n"; 
     794    } 
     795 
     796    unless ($include_base64_gnupg_prefix) { 
     797        print "[+] Stripping encoded '0x8502' prefix (hQ) from ", 
     798            "outgoing encoded SPA packet.\n" if $debug; 
     799        $encoded_msg =~ s/^hQ//; 
     800        ### perl -MMIME::Base64 -e 'print encode_base64("\x85\x02\n")' 
     801        ### The 'magic' database (via the 'file') command identifies GnuPG 
     802        ### encrypted files as starting with 0x8502 
     803    } 
     804 
    779805    print "[+] Encrypted message: $encoded_msg\n" if $debug; 
    780806    return $encoded_msg; 
     
    784810    my $msg = shift; 
    785811 
    786     my $cipher = Crypt::CBC->new( 
    787         { 
    788             'key'    => $enc_key, 
    789             'cipher' => $enc_alg, 
    790         } 
    791     ); 
     812    my $cipher = Crypt::CBC->new({ 
     813        'key'    => $enc_key, 
     814        'cipher' => $enc_alg, 
     815    }); 
    792816 
    793817    my $encrypted_msg = $cipher->encrypt($msg); 
     
    800824 
    801825    my $encoded_msg = encode_base64($encrypted_msg, ''); 
     826 
     827    if ($verbose and $debug) { 
     828        print "[+] base64-encoded message before stripping identifying chars:\n", 
     829            $encoded_msg, "\n"; 
     830    } 
    802831 
    803832    ### Crypt::CBC adds the string "Salted__" to the beginning of the 
     
    809838    ### string "U2FsdGVkX1" over UDP port 62201). 
    810839    unless ($include_salted) { 
    811         print "[+] Stripping encoded Salted__ prefix (U2FsdGVkX1) from ", 
     840        print "[+] Stripping encoded 'Salted__' prefix (U2FsdGVkX1) from ", 
    812841            "outgoing encoded SPA packet.\n" if $debug; 
    813842        $encoded_msg =~ s/^U2FsdGVkX1//;  ### encoded "Salted__" string 
     
    15101539        'Home-dir=s'     => \$cmdl_homedir, 
    15111540        'Include-salted' => \$include_salted, 
     1541        'Include-equals' => \$include_base64_trailing_equals, 
    15121542        'Test-mode'      => \$test_mode, 
    15131543        'LC_ALL=s'       => \$locale, 
     
    18011831                                 PERMIT_CLIENT_TIMEOUT in access.conf on the 
    18021832                                 fwknopd server side). 
    1803     --I, --Include-salted      - Include the encoded "Salted__" prefix; this 
     1833    --Include-salted           - Include the encoded "Salted__" prefix; this 
    18041834                                 is only necessary for older versions of the 
    18051835                                 fwknopd server (< 1.9.2). 
     1836    --Include-equals           - Include the trailing "=" chars used by 
     1837                                 base64 encoding scheme; this is only 
     1838                                 necessary for older versions of the fwknopd 
     1839                                 server (< 1.9.6). 
     1840    --Include-gpg-prefix       - Include the base64-encoded "hQ" prefix that 
     1841                                 GnuPG includes by default; this is only 
     1842                                 necessary for older versions of the fwknopd 
     1843                                 server (< 1.9.6). 
    18061844    --Save-dst                 - Save the command line args for this 
    18071845                                 invocation against the destination to the 
  • fwknop/trunk/fwknopd

    r1163 r1165  
    21502150    my $gpg_sign_id   = ''; 
    21512151 
     2152    my $equals_padding = &base64_equals_padding($msg); 
     2153 
     2154    if ($equals_padding) { 
     2155        print STDERR localtime() . " [+] Padding base64-encoded message ", 
     2156            "with '$equals_padding'.\n" if $debug; 
     2157        $msg .= $equals_padding; 
     2158    } 
     2159 
     2160    unless ($msg =~ /^hQ/) { 
     2161        print STDERR localtime() . " [+] Adding 'hQ' prefix to ", 
     2162            "base64-encoded message.\n" if $debug; 
     2163        $msg = 'hQ' . $msg; 
     2164    } 
     2165 
    21522166    print STDERR localtime() . " [+] Attempting GnuPG decrypt...\n" if $debug; 
    21532167    if ($debug and $verbose) { 
     
    22652279    unless ($msg =~ /^U2FsdGVkX1/) { 
    22662280        if ($debug) { 
    2267             print STDERR localtime() . " [+] Adding encoded Salted__ prefix ", 
     2281            print STDERR localtime() . " [+] Adding encoded 'Salted__' prefix ", 
    22682282                "(U2FsdGVkX1) to incoming encoded SPA packet.\n" 
    22692283        } 
    22702284        $msg = 'U2FsdGVkX1' . $msg; 
     2285    } 
     2286 
     2287    my $equals_padding = &base64_equals_padding($msg); 
     2288 
     2289    if ($equals_padding) { 
     2290        print STDERR localtime() . " [+] Padding base64-encoded message ", 
     2291            "with '$equals_padding'.\n" if $debug; 
     2292        $msg .= $equals_padding; 
    22712293    } 
    22722294 
     
    48714893} 
    48724894 
     4895sub base64_equals_padding() { 
     4896    my $msg = shift; 
     4897    my $padding = ''; 
     4898 
     4899    ### base64 encoding pads encoded data to a multiple of four 
     4900    ### with '=' chars, but the fwknop client strips these out 
     4901    ### before sending to make it more difficult to detect SPA 
     4902    ### traffic 
     4903    my $remainder = 4 - length($msg) % 4; 
     4904 
     4905    unless ($remainder == 4) { 
     4906        $padding .= '='x$remainder; 
     4907    } 
     4908    return $padding; 
     4909} 
     4910 
    48734911sub null_func() { 
    48744912    return; 
  • fwknop/trunk/test/fwknop_test.pl

    r1163 r1165  
    14761476                ### [-] Decrypted message does not conform to a valid SPA packet 
    14771477                return &print_errors("[-] Invalid SPA packet"); 
     1478            } elsif (/Unable\s+to\s+compile\s+packet\s+capture/) { 
     1479                return &print_errors("[-] Could not compile pcap filter, " . 
     1480                    "upgrade libpcap?"); 
    14781481            } 
    14791482        } 
     
    27192722    $cache_encrypted_spa_packet = ''; 
    27202723 
     2724    my $found_packet_data = 0; 
     2725 
    27212726    open F, "< $current_test_file" 
    27222727        or die "[*] Could not open $current_test_file: $!"; 
     
    27262731            next; 
    27272732        } 
    2728         if (/^\s*\[\+\]\s+Encrypted\s+message:\s+(.*)/) { 
     2733        if (/^\s*\[\+\]\s+Packet\s+data:/) { 
     2734            $found_packet_data = 1; 
     2735            next; 
     2736        } 
     2737        if ($found_packet_data and /(\S+)/) { 
    27292738            $cache_encrypted_spa_packet = $1; 
     2739            $found_packet_data = 0; 
    27302740            next; 
    27312741        }