Quantcast
Channel: cipherdyne.org | System and Network Security
Viewing all 49 articles
Browse latest View live

Tutorial on Single Packet Authorization with fwknop

$
0
0
Single Packet Authorization: The fwknop Approach One thing that has been requested a few times is a tutorial on how to use fwknop, so here it is: "Single Packet Authorization: A Comprehensive Guide to Strong Service Hardening with fwknop". This document attempts to cover most usages of fwknop to wrap an SPA layer around arbitrary services, though some less used scenarios such as SPA over Tor and SPA packet spoofing are covered as well. Please contact me if you find any errors, or if you would like to see material added on a particular fwknop use case. The complete table of contents appears below:


Software Release - fwknop-2.0.4

$
0
0
fwknop-2.0.4 released The fwknop-2.0.4 release of fwknop is available for download. This release includes new support for fuzzing the SPA protocol powered by the perl FKO module along with a set of patches designed to break libfko in subtle ways, and also includes several bug fixes and small enhancements. Among the most important of these include a new check for fwknop chains on iptables firewalls after the initial fwknopd start up (so the fwknop chains can be deleted out from under the fwknop daemon without affecting SPA operations), and a new 'upstart' config for systems running the upstart daemon. Many other changes were contributed by the open source community, and these are acknowledged in the complete fwknop-2.0.4 ChangeLog below:

  • [client] Misc fixes and the addition of save_args and last command (.fwknop.last) support on the Windows platform.
  • [client] Fixed bug in username determination code where a valid value could be overrwritten in certain circumstances.
  • [server] Added upstart config at extras/upstart/fwknop.conf. This allows the fwknopd to easily be managed with upstart via commands like "service fwknop start" and "service fwknop stop".
  • [server] (Vlad Glagolev) Submitted a patch to fix ndbm/gdbm usage when --disable-file-cache is used for the autoconf configure script. This functionality was broken in be4193d734850fe60f14a26b547525ea0b9ce1e9 through improper handling of #define macros from --disable-file-cache.
  • [server] (Vlad Glagolev) Submitted a patch to fix command exec mode under SPA message type validity test. Support for command exec mode was also added to the test suite.
  • (Vlad Glagolev) Submitted an OpenBSD port for fwknop-2.0.3, and this has been checked in under the extras/openbsd/ directory.
  • [server] Bug fix to allow GPG_ALLOW_NO_PW to result in not also having to specify a Rijndael key.
  • [Android] Added new .properties files to allow the fwknop client to build and function properly on the latest Android release (4.1.2).
  • [client] Added '-P udpraw' to allow the client to send SPA packets over UDP with a spoofed source IP address. This is in addition to the original 'tcpraw' and 'icmp' protocols that also support a spoofed source IP.
  • [libfko] Bug fix to check b64_decode() return value to ensure that non-base64 encoded data is never used. Even though other validation routines checked decoded results, it is important to discard invalid data as early as possible. Note too that such invalid data would only be provided to b64_decode() after proper decryption, so the client must provide authentic SPA data.
  • [libfko] Added validation of NAT access strings in the various NAT modes.
  • [libfko] Restricted usernames embedded in SPA packets to be alpha-numeric along with "-" chars.
  • [client] (Franck Joncourt) Contributed a patch to allow the fwknop client to be stopped during the password entry prompt with Ctrl-C before any SPA packet is sent on the wire.
  • [client+server] Applied patch from Franck Joncourt to remove unnecessary chmod() call when creating client rc file and server replay cache file. The permissions are now set appropriately via open(), and at the same time this patch fixes a potential race condition since the previous code used fopen() followed by chmod().
  • [server] Bug fix to accept SPA packets over ICMP if the fwknop client is executed with '-P icmp' and the user has the required privileges.
  • [test suite] Applied patch from Franck Joncourt to have the perl FKO module link against libfko in the local directory (if it exists) so that it doesn't have to have libfko completely installed in the /usr/lib/ directory. This allows the test suite to run FKO tests without installing libfko.
  • [test suite] Significant update to include a set of fuzzing SPA packets that are built using a patched version of libfko. These packets are located in the test/fuzzing/bogus_spa_packets file, and are designed to ensure proper validation of SPA packet data. This validation is performed in --enable-perl-module-checks mode via the perl FKO module.
  • [client] Added --icmp-type and --icmp-code arguments so the user can control the icmp type/code combination for spoofed SPA packets ('-P icmp') mode.
  • [client] Updated default TTL value to 64 for spoofed SPA packets. This is closer to more OS default TTL values than the previous 255.
  • Updated build CFLAGS and LDFLAGS to conform to the Debian hardening-includes file for PIE support (e.g. '-fPIE' for CFLAGS and '-fPIE -pie' for LDFLAGS).
  • [test suite] For GnuPG tests that require a passphrase associated with a gpg key, added a pinentry check to see if the local gpg engine requires it. If so, the gpg test that require a key are excluded since.
  • [server] Added a new '--pcap-file <file>' option to allow pcap files to be processed directly by fwknopd instead of sniffing an interface. This feature is mostly intended for debugging purposes.
  • [server] Added chain_exists() check to SPA rule creation so that if any of the fwknop chains are deleted out from under fwknopd they will be recreated on the fly. This mitigates scenarios where fwknopd might be started before a system level firewall policy is applied due to init script ordering, or if an iptables policy is re-applied without restarting fwknopd.
The complete fwknop-2.0.4 ChangeLog can also be found here via the fwknop gitweb interface.

Software Release - fwsnort-1.6.3

$
0
0
fwsnort-1.6.3 released The 1.6.3 release of fwsnort is available for download. This release adds a new test suite in the test/ directory that sends fwsnort through its paces for both iptables and ip6tables firewalls, speeds up iptables/ip6tables capabilities testing, and fixes a few bugs. In addition, one of the more significant changes is to ensure that Snort rules with HOME_NET=any -> EXTERNAL_NET=any are placed into the OUTPUT chain instead of the INPUT chain. This bug was reported by Dwight Davis. I would also like to thank Franck Joncourt for his support on the Debian side. Other changes were contributed by the open source community, and these are acknowledged in the complete fwsnort-1.6.3 ChangeLog below:

  • Bug fix to ensure that !, <, >, and = chars in content strings are converted to the appropriate hex equivalents. All content strings with characters outside of [A-Za-z0-9] are now converted to hex-string format in their entirety. This should also fix an issue that results in the following error when running /var/lib/fwsnort/fwsnort.sh:
        Using intrapositioned negation (`--option ! this`) is deprecated in
        favor of extrapositioned (`! --option this`).  Bad argument `bm'
        Error occurred at line: 64
        Try `iptables-restore -h' or 'iptables-restore --help' for more information.
        Done.
    
  • Bug fix to set default max string length in --no-ipt-test mode where iptables capabilities are not tested.
  • (Andrew Merenbach) Bug fix to properly honor --exclude-regex filtering option.
  • Added fwsnort test suite to the test/ directory. This mimics the test suites from the psad and fwknop projects, and it designed to examine many of the run time results of fwsnort.
  • Added the ability to easily revert the fwsnort policy back to the original iptables policy with "/var/lib/fwsnort/fwsnort.sh -r". Note that this reverts back to the policy as it was when fwsnort itself was executed.
  • Implemented a single unified function for iptables match parameter length testing, and optimized to drastically reduce run time for iptables capabilities checks (going from over 20 seconds to less than one second in some cases).
  • (Dwight Davis) Contributed patches for several bugs including not handling --exclude-regex properly, not ignoring the deleted.rules file, not handling --strict mode operations correctly, and more. These issues and the corresponding patch were originally reported here: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=693000
  • Bug fix for Snort rules with HOME_NET(any) -> EXTERNAL_NET(any) to ensure they go into the OUTPUT chain instead of the INPUT chain. This bug was reported by Dwight Davis.
  • Updated to bundle the latest Emerging Threats rule set.
The complete fwsnort-1.6.3 ChangeLog can also be found here via the fwsnort gitweb interface.

Software Release - psad-2.2.1

$
0
0
psad-2.2.1 released The 2.2.1 release of psad is available for download. This release adds new support for detecting a type of scan that psad has been previously blind to - IP protocol scanning (nmap -sO). Also in this release is the ability to detect Topera IPv6 scans and differentiate them from Nmap IPv6 scans. Other important changes include a new test suite, email throttling, and auto blocking timeouts that can be set for each danger level. Here is the complete ChangeLog:

  • Added IP protocol scan detection (nmap -sO). A new psad.conf variable PROTOCOL_SCAN_THRESHOLD defines the minimum number of different IP protocols (default = 5) that must be scanned before an alert is triggered.
  • Added detection for Topera IPv6 scans when --log-ip-options is used in the ip6tables logging rule. When this option is not used, the previous psad-2.2 release detected Topera scans. An example TCP SYN packet generated by Topera when --log-ip-options is used looks like this (note the series of empty IP options strings "OPT ( )":
    Dec 20 20:10:40 rohan kernel: [  488.495776] DROP IN=eth0 OUT=
    MAC=00:1b:b9:76:9c:e4:00:13:46:3a:41:36:86:dd
    SRC=2012:1234:1234:0000:0000:0000:0000:0001
    DST=2012:1234:1234:0000:0000:0000:0000:0002 LEN=132 TC=0 HOPLIMIT=64
    FLOWLBL=0 OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( ) OPT ( )
    OPT ( ) OPT ( ) PROTO=TCP SPT=61287 DPT=1 WINDOW=8192 RES=0x00 SYN
    URGP=0
    
  • Bug fix in --Analyze mode when IP fields are to be searched with the --analysis-fields argument (such as --analysis-fields "SRC:1.2.3.4"). The bug was reported by Gregorio Narvaez, and looked like this:
    Use of uninitialized value $_[0] in length at
    ../../blib/lib/NetAddr/IP/UtilPP.pm (autosplit into
    ../../blib/lib/auto/NetAddr/IP/UtilPP/hasbits.al) line 126.
    Use of uninitialized value $_[0] in length at
    ../../blib/lib/NetAddr/IP/UtilPP.pm (autosplit into
    ../../blib/lib/auto/NetAddr/IP/UtilPP/hasbits.al) line 126.
    Bad argument length for NetAddr::IP::UtilPP::hasbits, is 0, should be
    128 at ../../blib/lib/NetAddr/IP/UtilPP.pm (autosplit into
    ../../blib/lib/auto/NetAddr/IP/UtilPP/_deadlen.al) line 122.
    
  • Added --stdin argument to allow psad to collect iptables log data from STDIN in --Analyze mode. This makes it easier to run an iptables logs through psad from arbitrary files like so:
    # grep "IN=.*OUT=" /var/log/kern.log | psad -A --stdin
    
  • Added the ability to acquire Snort rule 'msg' fields from fwsnort if it's also installed. A new variable FWSNORT_RULES_DIR tells psad where to look for the fwsnort rule set. This fixes a problem reported by Pui Edylie to the psad mailing list where fwsnort logged an attack that psad could not map back to a descriptive 'msg' field.
  • Added the ability to set per-danger level timeouts when psad is configured to run in auto-blocking mode. These timeouts are implemented with new AUTO_BLOCK_DL*_TIMEOUT variables - one for each of the five possible danger levels that may be assigned to a scanning IP address.
  • Added the ability to throttle emails generated by psad via a new EMAIL_THROTTLE variable which is implemented as a per-IP threshold. That is, if EMAIL_THROTTLE is set to "10", then psad will only send 1/10th as many emails for each scanning IP as it would have normally.
The complete psad-2.2.1 ChangeLog can also be found here via the psad gitweb interface.

ShmooCon 2013 Talk on fwknop

$
0
0
ShmooCon 2013 This past weekend at ShmooCon 2013 I gave a talk entitled "Generalized Single Packet Authorization for Cloud Computing Environments" (slides, video demo), and in this blog post I thought it appropriate to give an introduction to the talk in blog format. The main point of the talk was to show that it is completely feasible to integrate SPA as implemented by fwknop with Cloud Computing environments that conform to the Infrastructure as a Service (IaaS) model. In particular, it was shown that SPA can be used to protect and access both SSH and RDP services running on EC2 instances within a Virtual Private Cloud (VPC) in Amazon's AWS environment. Accessing SSHD via SPA by itself is nothing new and has been a primary use case supported by fwknop for a long time, but maintaining a default-drop packet filtering stance for RDP is a different story due to the fact that fwknop does not support a Windows firewall. However, through the use of both SNAT and DNAT capabilities within iptables, the fwknop daemon is able to convert an Ubuntu EC2 instance running within Amazon's Cloud into an "SPA gateway" that is able to then allow access to any service running on any other system within the VPC network - including RDP on a separate Windows host. Further, such access is granted through a single externally routable Amazon Elastic IP that is associated with the Ubuntu system. The Windows host doesn't even need to have a default route back out to the Internet - it always just sees incoming RDP connections from the Ubuntu host even though they really originate out on the Internet from whatever system is allowed via the SPA protocol. Here is a graphic to illustrate this scenario: fwknop + Amazon integration If you want a video demonstration of this all in action, this demo was given during the ShmooCon talk:


Now, for more explanation, the following systems are depicted in the graphic above:

  • The SPA client system that runs the fwknop client to send SPA packets and from which SSH and RDP connections originate.
  • The Amazon border firewall.
  • An Ubuntu host on the VPC network where the fwknop daemon runs.
  • A Windows system on the VPC network where RDP lives.
At the same time, the Ubuntu VPC host is also running a webserver. This is to illustrate that everyone out on the Internet can scan the externally routable Elastic IP (107.23.221.41 in this case) associated with the Ubuntu host and see that Apache is listening on port 80. (Note that this IP is not currently associated with my Amazon account.) But, no other services are visible to a scanner on the Ubuntu system because iptables is deployed in a default-drop stance for everything except for port 80. Even so, fwknop is able to create access through the iptables policy for SSH and RDP through the Ubuntu system over port 80 (i.e. SPA "ghost services"). These two scripts that are shown in the demo video illustrate gaining access to SSH and RDP:
$ cat ssh_access.sh
#!/bin/sh -x

fwknop -A tcp/80 --server-port 40001 -R -D 107.23.221.41
sleep 2
ssh -p 80 -i ~/.ssh/cdyne-vpc-testing.pem ubuntu@107.23.221.41
exit

$ cat rdp_access.sh
#!/bin/sh -x

fwknop -A tcp/80 --server-port 40001 -N 10.0.0.223,3389 -R -D 107.23.221.41
sleep 2
rdesktop -u Administrator 107.23.221.41:80
exit

To see all of the above in action just watch the video. Hopefully the talk itself will be posted online soon, and when it is I'll post a link. More information can also be found in the talk slides.

Finally, I'd like to thank the ShmooCon organizers for putting on a great conference as usual, and I'm looking forward to next year.

Coverity Static Analysis and Open Source Software

$
0
0
Coverity Scan A few months ago Coverity announced that they would grant open source projects access to their "Scan" static analysis tool for free. This was certainly a bold move, and one that has the potential to improve the security landscape as more projects take advantage of it. The first time I had encountered Coverity was several years ago when Linux kernel ChangeLog entries were referencing Coverity's Scan tool as having found various classes of bugs in the kernel sources. This impressed me because the Linux kernel source code is not the easiest code to grok, and at the same time it is extremely widely deployed and audited so bugs get reported and fixed. Andrew Morton, second in command of the kernel, has pegged the time required to become proficient as a kernel developer at about one year of full time dedicated effort for an experienced systems programmer. Hence, any automated static analysis infrastructure that is good enough to find kernel bugs and have it credited in the kernel ChangeLog is a strong vote of confidence to my mind. Here is a recent instance of Coverity finding a NULL pointer dereference bug in Infiniband driver code for example.

Even though Coverity started being used by the Linux kernel development community circa 2005, Coverity was expensive and therefore not generally available to open source projects that typically do not have access to significant resources. Today, that has all changed with Coverity's open source initiative, and the community is better off. Simultaneously, Coverity also gets a benefit in terms of free press as more open source projects start using Coverity Scan. As of this writing, over 300 projects have signed up including fwknop, and Coverity maintains a list of these here. OpenVPN and OpenSSL are participating, but it doesn't look like OpenSSH is yet and I (for one) hope they do eventually.

Here is an example of a bug that Coverity found in the fwknop client:

diff --git a/client/spa_comm.c b/client/spa_comm.c
index fea3679..2532669 100644
--- a/client/spa_comm.c
+++ b/client/spa_comm.c
@@ -552,6 +552,7 @@ send_spa_packet_http(const char *spa_data, const int sd_len,
                 log_msg(LOG_VERBOSITY_ERROR,
                     "[-] proxy port value is invalid, must be in [%d-%d]",
                     1, MAX_PORT);
+                free(spa_data_copy);
                 return 0;
             }
         }


This is a classic memory leak bug in the fwknop client that is only triggered when an invalid port number is specified from the command line when sending SPA packet data through an HTTP proxy (this is not a widely used method for SPA packet transmission, but it is supported by the fwknop client along with other transmission modes). The spa_data_copy variable points to heap allocated memory that wasn't free()'d after the error condition was detected and before returning from the send_spa_packet_http() function call. Coverity was able to spot this bug through static analysis, and the diff output above shows the corresponding fix. In terms of other bugs found by Coverity, they have all been fixed in the current fwknop sources in preparation for the 2.5 release. A -pre release is available through the new Github releases feature, and will likely become 2.5 within a week: fwknop-2.5-pre3.tar.gz.

This same bug could also have been caught at run time with the excellent valgrind "memcheck" tool, but the invalid port number error would have had to be triggered in order for valgrind to detect the memory leak. While the fwknop test suite is fairly comprehensive and can automatically run every test underneath valgrind to help with the detection of memory leaks, not every error condition is triggered by the test suite and hence static analysis is quite important. At the same time, run time analysis is also important to pick up leaks and other problems that static analysis techniques may miss, so running valgrind will continue to be a critical test suite component.

Now, on the vulnerability research side, there are implications for vulnerability discovery. That is, source control changelogs that mention Coverity or other static analysis tools can help malicious actors find potentially exploitable code. Here is an example Github search that shows all issues where Coverity is mentioned. Is this a bad thing? Well, in a word I would say "no". The exploit community is constantly looking for ways to exploit software regardless of whether static analysis tools are used by project developers. The real problem is that bugs are frequently never discovered or fixed in the first place. Further, keeping bugs under wraps in a vein effort to hope they won't be found has never worked, and this is true regardless of whether a project is open source or not (binary patches released by Microsoft are reversed engineered to figure out how to exploit unpatched code for example). What we need is better, more security conscious software engineering - not imagined bug secrecy. Consistent, advertised usage of static analysis tools helps to drive this. In addition, static analysis tools should be seen as a piece of the bug hunting puzzle and be used in conjunction with other standard techniques such as dynamic analysis, unit tests, and good old fashioned code reviews.

Finally, in terms of Coverity's own competition such as Veracode, Klocwork, or Checkmarx, it seems to me that Coverity has made a shrewd move by offering code analysis to open source projects for free. They will continue to make important inroads into the OS community (which has become quite powerful over the past, say, 15 years and longer), and will most likely see a gain on the commercial side as a result.

The bottom line is that Coverity has an excellent static analysis product, and if you run or contribute to an open source project written in C/C++, you should be using Coverity Scan. It will likely find bugs that can certainly have security implications in your code. Even if Coverity doesn't turn up any bugs, additional verification is always a good thing - especially for security projects.

Software Release: fwknop-2.5 with HMAC Support

$
0
0
fwknop-2.5 with HMAC support After a long development cycle started over a year ago that has focused on how fwknop uses cryptography, the 2.5 release of fwknop is available for download. This release now includes support for HMAC authenticated encryption, with SHA-256 being the default digest algorithm though others such as SHA-512 are supported as well. The HMAC mode can be applied to SPA packets that have been encrypted with either Rijndael or GnuPG, and the order of operation is always encrypt-then-authenticate which is considered to be the most secure option among all possible orders. Not only does using the new HMAC mode provide a cryptographically strong authentication step for SPA communications, it also affords a significant security benefit because maliciously constructed SPA packets can be discarded before they are even sent through decryption routines. I.e. HMAC verification is a much more simplistic operation than decryption, and therefore generally less prone to programming bugs and potential security vulnerabilities.

There are many other enhancements in fwknop-2.5 as well such as usage of the Coverity static analyzer, a new ~/.fwknoprc stanza saving feature for fwknop client usage simplification, support for automatic Rijndael+HMAC key generation with the --key-gen option, many test suite improvements, an updated tutorial, and more. There is a robust roadmap for fwknop, and new releases will come faster now that a solid foundation is made upon HMAC authenticated encryption for SPA packets.

I wish to thank all who contributed to this effort - particularly Damien Stuart, Franck Joncourt, Blair Zajac, Michael T. Dean, and Ryman. Additional contributors are listed in the git history.

NOTE: If you are upgrading from a previous version of fwknop you will want to read the following information on backwards compatibility. In short, fwknop-2.5 is compatible with prior versions, but it requires one configuration tweak to either the client (add "-M legacy" to the command line) or server config (add "ENCRYPTION_MODE legacy" to each stanza in the access.conf file) if you wish to run a mixed environment of older clients and/or older servers. The reason for the incompatibility is that prior to 2.5, fwknop was not properly using PBKDF1 for Rijndael key derivation - this has been fixed.

Here is the complete ChangeLog for fwknop-2.5:

  • ***** IMPORTANT *****: If you are upgrading from an older version of fwknop, you will want to read the "Backwards Compatibility" section of the fwknop tutorial available here:

    http://www.cipherdyne.org/fwknop/docs/fwknop-tutorial.html#backwards-compatibility

    In summary, it is possible to have a mixed environment of fwknop-2.5 clients and/or servers with older client and/or servers, but this requires some configuration in order to work properly. On the server side, the directive "ENCRYPTION_MODE legacy" will need to be added to every access.conf stanza that uses Rijndael and that needs to support SPA packets from pre-2.5 clients. On the client side when generating Rijndael-encrypted SPA packets from a pre-2.5 server, the command line argument "-M legacy" will need to be given. GnuPG operations are not affected however and don't require the above steps whenever the new HMAC authenticated encryption feature (offered in fwknop-2.5) is not used.
  • Major release of new functionality - HMAC authenticated encryption support in the encrypt-then-authenticate model for SPA communications. Supported HMAC digests include MD5, SHA1, SHA256, SHA384, and SHA512. The default is HMAC-SHA256 when an HMAC is used. The HMAC mode is supported for both Rijndael and GPG encrypted SPA packet data, and provides a significant security benefit for the fwknopd server since the HMAC verification is more simplistic than decryption operations. This is particularly true for GPG. Beyond this, HMAC authenticated encryption in the encrypt-then-authenticate mode does not suffer from things like CBC-mode padding oracle attacks (see the Vaudenay attack and the more recent "Lucky 13" attack against SSL). HMAC verifications are performed with a constant time comparison function.
  • [libfko] Significant bug fix to honor the full encryption key length for user-supplied Rijndael keys > 16 bytes long. Previous to this fix, only the first 16 bytes of a key were actually used in the encryption/ decryption process even if the supplied key was longer. The result was a weakening of expected security for users that had keys > 16 bytes. Note that "passphrase" is perhaps technically a better word for "user-supplied key" in this context since the actual key is generated with the PBKDF1 key derivation algorithm. This issue was reported by Michael T. Dean. Closes issue #18 on github.
  • [libfko] Added the ability to maintain backwards compatibility with the now deprecated "zero padding" key derivation strategy in AES mode that was a hold over from the old perl fwknop implementation. This is NOT compliant with PBKDF1 and is only brought forward into fwknop-2.5 for backwards compatibility. Future versions of fwknop will remove this code altogether since PBKDF1 is now implemented.
  • [libfko+server] Ensure that all HMAC, digest, and other comparisons are done via a dedicated constant_runtime_cmp() function so that a potential attacker cannot gain any information about fail/success just by mounting a timing attack. This function always compares two buffers from beginning to end regardless of whether a difference is detected early on in the comparison, and this strategy mirrors changes in SSL libraries such as yaSSL to protect against potential timing attacks. This change fixes #85 on github which was reported by Ryman.
  • [test suite] Added --enable-openssl-checks to send all SPA packets encrypted via libfko through the OpenSSL library to ensure that the libfko usage of AES is always compatible with OpenSSL. This ensures that the fwknop usage of AES is properly implemented as verified by the OpenSSL library, which is a frequently audited high profile crypto engine. If a vulnerability is discovered in OpenSSL and a change is made, then the --enable-openssl-checks mode will allow the test suite to discover this in a automated fashion for fwknop.
  • The fwknop project is using Coverity for source code validation (in addition to other tools such as the CLANG static analyzer). Many bugs have been fixed in this release that were discovered by Coverity. These bugs spanned multiple classes of problems from memory leaks, improper use of sizeof(), potential double-free conditions, and more. Full details on these fixes are available in the git history. Any open source project that is written in a language supported by Coverity would benefit highly from participating. As of the 2.5 release, fwknop has a Coverity defect score of zero.
  • [test suite] Changed how the test suite interacts with the fwknop client and server by looking for indications that SPA packets are actually received. This is done by first waiting for 'main event loop' in fwknopd log output to ensure that fwknopd is ready to receive packets, sending the SPA packet(s), and then watching for for 'SPA Packet from IP' in fwknopd output. This is an improvement over the previous strategy that was only based on timeout values since it works identically regardless of whether fwknop is being run under valgrind or when the test suite is run on an embedded system with very limited resources. Another check is run for fwknopd receiving the SIGTERM signal to shutdown via 'fwknopd -K', and that failing, the test suite manually kills the process (though this should be rarely needed). This change was implemented based on discussions with George Herlin.
  • (Franck Joncourt) Added support for resolving hostnames in various NAT modes (fixes issue #43 in github).
  • (Franck Joncourt) Bug fix in the client for resolving hostnames in '-P icmp' mode (fixes issue #64).
  • (Franck Joncourt) Added support for saving fwknop client command line arguments via a new options --save-rc-stanza.
  • (Franck Joncourt) Added log module support for the client.
  • [client] Bug fix for --nat-rand-port mode to ensure that the port to be NAT'd is properly defined so that the fwknopd server will NAT connections to this port instead of applying the NAT operation to the port that is to be accessed via -A. This change also prints the randomly assigned port to stdout regardless of whether --verbose mode is used (since if not then the user will have no idea which port is actually going to be NAT'd on the fwknopd side).
  • (Vlad Glagolev) Submitted an OpenBSD port for fwknop-2.0.4, and this has been checked in under the extras/openbsd/fwknop-2.0.4 directory.
  • (Shawn Wilson) Added better SPA source IP logging for various fwknopd logging messages. This helps to make it more clear why certain SPA packets are rejected from some systems.
  • [client] Added --get-hmac-key to allow HMAC keys to be acquired from the specified file similarly to the --get-key option. This is a convenience only, and the fwknop rc file feature should be used instead since it is far more powerful.

Crossing the Streams in IDS Signature Languages

$
0
0
Snort/Suricata xbits proposal This blog post is a proposal for a new SNORT®/Suricata keyword "xbits" that could change how IDS signature developers approach detection of exploits that cross multiple streams. Today in both Snort and Suricata, it is possible to build up a state machine out of a set of related signatures with the flowbits keyword in order to track how an exploit progresses through a vulnerable application layer protocol. This is an important feature, and is used in many standard Snort signature sets - as of this writing it is in about 6% of all active Snort rules in the Emerging Threats rule set. However, flowbits has an important limitation: it can only apply within single TCP connections or single UDP conversations (forward and reverse flows). So, it is not possible to set a flowbit on one TCP connection and then test whether this flowbit is set in a completely separate connection. This limitation represents an opportunity for innovation, and it is my belief that this shortcoming partially helped to fuel the demand for products offered by SIEM vendors (more on this below).

flowbits Example

First, let's see an example of flowbits usage within two Snort signatures - this comes from the online Snort manual. The following Snort signatures (or "rules" if you like) show a basic example of tracking the IMAP protocol and generate an event for the IMAP "LIST" command but only after a successful login:
alert tcp any 143 -> any any (msg:"IMAP login"; content:"OK LOGIN"; flowbits:set,logged_in; flowbits:noalert;)
alert tcp any any -> any 143 (msg:"IMAP LIST"; content:"LIST"; flowbits:isset,logged_in;)
So, the first signature sets the flowbit "logged_in", and then the second tests whether this flowbit has been set on the same TCP connection along with the "LIST" content match. Note the "noalert" modifier suppresses the alert from the first rule and triggering it merely signals internally to Snort that a necessary precondition for the second signature has been met. It is the second signature that causes an alert to be generated if it is triggered. Note also that the "logged_in" flowbit is set on traffic returned to the client from the IMAP server vs. the "isset" criteria which tests the logged_in flowbit in the second rule on traffic coming from the client. This illustrates the ability of flowbits to place match criteria on communications emanating from both sides of a connection.

Why is flowbits useful?

flowbits is important because it allows the signature developer to let network traffic progress in a natural way and have Snort/Suricata track it as it unfolds. It lets sets of signatures work together as group for more reliable exploit detection, and there are plenty of exploits that can be detected using the current flowbits implementation. However, what types of exploits are missed because flowbits cannot apply across multiple TCP connections? Put another way, would detection of malicious traffic be significantly improved with a cross-stream flowbits keyword?

A New Keyword: xbits

The proposed xbits keyword would function as follows:

  • Fundamentally, an xbit could be set on one TCP connection or UDP conversation, and tested in a different connection or conversation. This would require a different interface to the stream tracking portions of Snort and Suricata than currently implemented by flowbits.
  • All xbits semantics would match those in flowbits for existing flowbits modifiers such as set, unset, noalert, etc.
  • xbits would offer a new modifier "track" that accepts arguments "ip_pair" (to associate xbits by pairs of IP addresses), and "expire" (to allow xbits to be cleared automatically after a specified number of seconds).
This blog post is not to say that existing Snort rules that use flowbits don't work properly, or that flowbits is fundamentally flawed. Rather, in some cases these rules could be made more reliable and harder to evade with the proposed xbits keyword. It is the sequence of connections that look a certain way that is important, and xbits tries to promote this concept directly into the Snort signature language. Without xbits, the information conveyed by such sequences is lost. One could imagine other cases where having xbits would be useful such as:

  1. Use of a compromised system after successful exploitation. An attacker sends an exploit against a system where the exploit itself is difficult to detect, but following the exploit connection a new successful connection is made to a backdoor port that the exploit forces the compromised system to open (or a connect-back shell can be initiated the other way - the detection rules can be written to take either scenario into account). If the exploit itself can only be described by a signature that may also produce unacceptably high rates of false positives on legitimate traffic, then xbits provides an alternative since this rule never has to trigger any alert at all. Only the use of the compromised system after successful exploitation causes an alert.

    Now, why not just have a signature that triggers on every connection to the backdoor port? Well, sure, but if xbits existed then a set of higher confidence signatures related together by xbits can be created for the same thing. Once again, the sequence of communications contains information that is important for better exploit detection. Further, nothing prohibits both strategies from being used simultaneously; existing non-xbits signatures can be used at the same time.

  2. Better detection of Metasploit traffic, and by extension better detection of sophisticated adversaries. Here are a few examples of Metasploit modules that require multiple streams for successful exploitation:

                - SCADA 7-Technologies IGSS Rename Overflow
                - Apache ISAPI DoS
                - ContentKeeper Web Remote Code Execution

    There are many more modules that require multiple streams, and here is a quick way to identify those that may fall into this category (requires additional investigation). We just look for calls to connect(), connect_udp(), and send_request_cgi():
    $ git grep -c "^[[:space:]]*connect" modules | grep -v ":1" | wc -l
    125
    $ git grep -c "send_request_cgi" modules | grep -v ":1" | wc -l
    154
    

  3. Detection of network trickery that by its nature requires multiple streams. How about detecting SSH connections that have been authenticated with Single Packet Authorization? In this case, one needs a way to trigger an alert if a base64-encoded blob of data goes to UDP port 62201 followed closely after this by an SSH connection to the same system. Note that there are many ways SPA can deployed where this technique would not be effective (port randomization, SPA packet spoofing, sending SPA packets over Tor, and more), but still it is useful to consider how xbits could be applied to detect styles of communications that can't easily be expressed with current Snort/Suricata signature languages.

Metasploit Example

Let's examine the ContentKeeper Web remote code execution exploit mentioned above in a little more depth, and show how xbits can offer a detection alternative. This exploit attempts to escalate privilege and execute code as either the Apache or root user on the webserver as follows:

  1. Check for a vulnerable version of ContentKeeper by looking for a '500 Internal' error in response to issuing an HTTP request to /cgi-bin/ck/mimencode as seen here. This is an optional step (part of the Metasploit check() function for this exploit), but is generally a good idea since the Metasploit user probably does not want to upload a payload to a patched version of ContentKeeper (and thereby needlessly expand their own risk).
  2. Upload a base64-encoded perl script payload via an HTTP POST to the ContentKeeper webserver. Due to the vulnerability, the payload overwrites a specified file in the webserver filesystem. This connection is made to /cgi-bin/ck/mimencode as seen here.
  3. Wait three seconds after the HTTP upload connection is closed.
  4. Connect to the webserver via an HTTP GET and execute the uploaded payload script via /cgi-bin/ck/<script>. This step can be seen here.
In the context of this post, the important thing to note about the exploit steps above is that two separate HTTP connections are required - one to upload the payload via an HTTP POST, and the second to execute the payload via an HTTP GET. These two requests are required for exploitation regardless of whether the reconnaissance check is made in step one, though in our example rule set below we'll assume the recon check is issued as well. With the xbits keyword, the following signatures can detect this pattern of communications:

  1. Set xbit "Metasploit.ContentKeeper.recon" on initial HTTP connection in Metasploit step 1 above. Track by ip_pair.
  2. Test "Metasploit.ContentKeeper.recon" xbit with 'isset' and if it matches, then set xbit "Metasploit.ContentKeeper.recon_status_is_vuln" on '500 Internal' webserver response. Track by ip_pair.
  3. Look for an HTTP POST that uploads the base64 encoded perl script and test "Metasploit.ContentKeeper.recon_status_is_vuln" xbit. If this xbit is set, then set xbit "Metasploit.ContentKeeper.payload_uploaded" and track by ip_pair.
  4. Look for an HTTP GET to /cgi-bin/ck/ and test the "Metasploit.ContentKeeper.payload_uploaded" xbit. If it is set then generate an event "Metasploit ContentKeeper Web remote code exec".
The complete example rule set can be downloaded here. Obviously these won't run properly in Snort or Suricata until xbits is actually implemented. In this rule set a number of trade offs have been made such as: looking for the recon '500 Internal' error check, tracking by IP pair for the recon check and the exploit step, tracking by IP pair between the payload upload connection and the exploit connection, and allowing xbit values to expire after 30 seconds (see the xbits "track" criteria). The attacker is always free to slow things down and not use the same IP pair across each of these connections and still gain successful code execution. But, the attacker may not utilize different source IP's across these connections, and if not then the pattern above becomes a highly reliable indicator of a successful attack. Further, as mentioned previously, individual non-xbits rules can be deployed at the same time to catch each step by itself as well.

The SIEM Connection

At its core, xbits allows the IDS engine to process network traffic such that associations are made among groups of signatures in a manner that is not restricted to single TCP connections or UDP conversations. There is much analogous precedence for this concept in the SIEM world. SIEM vendors commonly allow security alerts to be built up from multiple independent sources of information such syslog data, firewall logs, IDS events, webserver logs, netflow data, and more. A good example is "send an alert if source IP a.b.c.d triggers a port sweep event in my IDS, followed by SQL errors via my webserver, followed by a connection initiated back from the webserver to IP a.b.c.d". Having the SIEM automatically trigger an alert based on all of these events coming together in the specified order is far more valuable than trying to arrive at the same result through manual interpretation of each indicator by itself (which isn't practically possible for any decently large network).

This doesn't mean the raw event data is turned off or thrown away - far from it. The event data is simply processed by the SIEM in a way that gives priority to the sequence of events without necessarily caring about the sources of the events themselves (firewall log, etc.). Making an analogy to Snort/Suricata, the absence of xbits would be like a SIEM that could only generate an alert based on looking at one event source at a time. I.e., SSH brute force attempts logged via syslog could not be correlated with, say, a port sweep event from an IDS.

Further, in the absence of xbits, in the Metasploit example above a set of regular Snort rules could be deployed to detect each stage of the Metasploit traffic individually and log this data to a SIEM. From there, the SIEM itself could implement the same logic as xbits does - i.e. generate an alert if the raw events come together in the same sequence as what the xbits rules require. Given that this style of matching is useful, why not implement such a capability within the Snort signature language directly?

Performance?

The implementation of xbits would certainly impact performance, and this may be one reason neither Snort nor Suricata have developed something similar. However, some portion of xbits is clearly possible to implement with a reasonable set of constraints. These constraints may include limitations on the maximum number of xbits, enforcing a maximum amount of time that a set xbit is allowed to remain set, or limiting the number of comparisons that a signature is allowed to trigger for checking whether an xbit is set. It is my belief that a workable performance level could be achieved for many deployments of Snort/Suricata.

What About Shared Object (SO) Rules?

The whole point of binary shared object (SO) rules is to allow the signature author to alter the detection capabilities offered in the standard Snort signature language. However, implementing an SO rule is significantly more complex than just writing a regular Snort rule for most signature authors. If the concept of xbits could improve the detection landscape, then it would be desirable to have it built directly into the signature language itself where it is more accessible and readily applied to real world network traffic.

Why Not Just Extend flowbits?

Instead of creating a new Snort/Suricata signature language keyword, why not just extend flowbits so that it can apply to multiple transport layer conversations? Because maintaining backwards compatibility with existing Snort rule sets would become difficult and error prone. Matching across mutiple conversations is such a fundamentally different model that it would be better to clearly differentiate this capability with a new keyword.

Conclusion

This blog post proposes an extension to the Snort/Suricata signature language to allow those IDS engines to detect malicious traffic that crosses multiple streams. Attackers do not limit themselves to traffic patterns that must stay within a single transport layer conversation, and neither should standard intrusion detection engines. One only needs to look at the Metasploit project for excellent examples of exploits that span multiple streams. For the record, I had proposed this idea on a panel discussion with Ron Gula and Marty Roesch at the SANS "What Works in Incident Detection and Log Management Summit" in 2010. At the time I didn't use the "xbits" name, but (to me) writing up this blog post has solidified xbits as a decent name for the concept.

Design of a New 'xbits' Cross-Stream IDS Keyword

$
0
0
Snort and Suricata xbits implementation In the previous blog post a proposal was made for a new Snort and Suricata keyword "xbits" for cross-stream signature matching. This post had little discussion of implementation tradeoffs, and some have reacted to the blog post by saying that it is difficult to properly design and implement the type of cross-stream state tracking that would be necessary for xbits to work. I agree. However, the initial xbits proposal did not assume that such an implementation would be easy or straightforward, and this blog post will attempt to illustrate where some of the pitfalls are likely to be. In the end, I'm confident that is possible to develop something similar to xbits. Victor Julien, lead developer of Suricata, commented on my Google+ posting on the xbits keyword to state that Suricata has been considering implementing something similar to xbits for a while.

First, before diving into xbits itself, I would argue that there is already precedent in IDS/IPS engines for detecting an important class of communications that cross multiple transport layer "conversations" (using this term loosely for a moment): port scans and sweeps. Detecting such traffic is mostly about setting thresholds on various things such as the number of ports and IP addresses that are contacted within a given period of time, prioritizing on sets of ports that are usually associated with important services (with sweeps for certain ports sometimes spiking after a new vulnerability is discovered), and differentiating TCP flags that are used (a TCP FIN scan looks a lot different than a connect() scan and indicates some things about the adversary such as privileged OS access). By definition, the raw ability to differentiate scans and sweeps vs. normal traffic requires the capability of keeping some state across transport layer conversations. It just so happens that Snort and Suricata track this state within dedicated preprocessors and do not also expose port scan detection configuration in the signature language itself. By contrast, other preprocessors do offer signature language interfaces such as stream5 with the flow keyword. To be clear, I'm not at all advocating that configuration aspects of the sfPortscan preprocessor actually belong in the signature language (that would be unnatural to say the least) - I'm merely making the point that the idea of maintaining some state across transport layer conversations is something that Snort and Suricata already do. So, in this area at least, such a concept is not foreign.

Traffic Visibility

Now, in terms of factors that would affect an xbits implementation, it should be noted that not every IDS/IPS necessarily has a global view of all traffic on a given network. This can be the result of several different factors that depend not only on the physical hardware, but also how the IDS/IPS itself is developed (multi-threaded or not), and configured. Starting with the hardware, I've seen major IDS deployments that require multiple IDS appliances working together in order to inspect all of the network traffic. Essentially the IDS appliances form a cluster of systems (not in the HPC sense) where portions of the traffic are split across each appliance with a device such as a Gigamon tap. This allows each IDS appliance to handle a fraction of the traffic that it would otherwise have had to inspect, and this in turn enables the cluster as a whole to scale to massive amounts of network traffic. But, this also means portions of the traffic are physically separated from one IDS to the next, and therefore xbits on a single IDS can only apply to the set of transport layer conversations that actually traverse it. So, is there an opportunity for an attacker to evade xbits when deployed in this fashion? Sure, if the attacker knows how the traffic splitting is done, then attacks could most likely be sent against systems in ways that nullify xbits criteria just by using different source networks to force each individual IDS appliance into having only a limited view of a cross-stream attack. There are potential evasions at every level, but many attackers are not going to have access to such traffic splitting details.

Other IDS/IPS architectures such as those that rely on network processors or specialized packet acquisition hardware can also result in limited traffic visibility. Some organizations run multiple Snort processes on a single appliance, and have a network processor split packet data based on IP network ranges or transport layer port number across the Snort instances. Once again, each Snort process has a limited few of the traffic. Similarly, in a multi-threaded IDS/IPS such as Suricata, each thread may be tasked with processing a portion of the total network traffic, and this can result in a limited view within software even if there is no hardware enforced traffic splitting mechanism.

The Stream Preprocessor

Modifying the stream preprocessor to handle the xbits keyword could be tricky. By its nature, xbits would force the stream preprocessor to consider information that is not derived from single transport layer conversations, so locking issues against a global xbits tracking data structure in a multi-threaded context would become important. Also, it would be nice to not place onerous restrictions on xbits such as requiring that a connection close before a set xbit can be tested within a different connection. My guess is that stream preprocessor modifications have previously been a barrier to implementing something like xbits.

xbits Design

Given all of the above, what would be the ideal xbits design? Stepping back for a moment, when any signature language feature is implemented in an IDS, what should be the primary goal? Better attack detection. Performance is certainly a consideration too, and performance features sometimes bleed into the signature language (see the fast_pattern keyword for example), but usually a new signature language feature is added because it enables better detection of threats at acceptable performance levels. Further, some features of the language are important enough to expend lots of CPU cycles and consume precious memory anyway because the detection accuracy would be significantly harmed without them - see the pcre keyword for example. So, we should strive for the ideal xbits design from a detection perspective and let performance and other tradeoffs take place where they must:

  1. Allow an xbit to be set on one transport layer conversation and inspected in a different conversation before the first is closed.
  2. Allow an xbit to be set on a conversation that involves one IP protocol, and tested in a conversation that involves a different IP protocol. E.g. set a bit on a UDP flow and test it in a subsequent TCP connection.
  3. Interface with the current stream preprocessor to allow the setting and testing of xbits to take advantage of existing connection tracking capabilities. This most likely can be implemented as an extension to stream5 without requiring a wholly new preprocessor.
  4. For multi-threaded intrusion detection engines such as Suricata, some of the same tradeoffs that allow port scan detection to apply across threads could be used for xbits. Ideally, xbits would not be limited to traffic that is seen within a single thread.

TCP Options and Detection of Masscan Port Scans

$
0
0
After Errata Security scanned port 22 across the entire Internet earlier this month, I thought I would go back through my iptables logs to see how the scan appeared against one of my systems. Errata Security published the IP they used for the scan as 71.6.151.167 so that it is easy to differentiate their scan from all of the other scans and probes:
[minastirith]# grep 71.6.151.167 /var/log/syslog | grep "DPT=22 "
Sep 12 21:19:15 minastirith kernel: [555953.034807] DROP IN=eth0 OUT= MAC=00:13:46:11:11:11:78:cd:11:6b:11:7e:11:00 SRC=71.6.151.167 DST=1.2.3.4 LEN=40 TOS=0x00 PREC=0x20 TTL=241 ID=17466 PROTO=TCP SPT=61000 DPT=22 WINDOW=0 RES=0x00 SYN URGP=0
Interestingly, the SYN packet that produced the log message above does not contain TCP options. The LOG rule in the iptables policy was built with the --log-tcp-options switch, and yet the OPT field for TCP options is not included. Looking through the Masscan sources, TCP SYN packets are created with the tcp_create_packet() function which does not appear to include code to set TCP options, and neither does the default template used for describing TCP packets. This is most likely done in order to maximize performance - not from the perspective of the sender since a static hard-coded TLV encoded buffer would have done nicely - but rather to minimize the time that scanned TCP stacks must spend processing the incoming SYN packets before a response is made. While this processing time is trivial for individual TCP connections, it would start to become substantial when trying to rapidly scan the entire IPv4 address space.

A consequence of this strategy is that SYN packets produced by Masscan look different on the wire from SYN packets produced by most operating systems (at least according to p0f), and they also differ from SYN scans produced by Nmap (which do include options as we'll see below). This is not to say that every SYN packet without options necessarily comes from Masscan. There are operating systems in the p0f signature set (such as Ultrix-4.4) that do not include options, and the Scapy project also seems not to set options by default when producing SYN scans like this. In addition it looks like Zmap also does not include TCP options in SYN scans. For reference, here are three iptables LOG messages for SYN packets produced by a standard TCP connect() call from an Ubuntu 12.04 system, an Nmap SYN (-sS) scan, and Scapy (source and destination IP's and MAC addresses have been obscured):
### TCP connect() SYN:
Sep 29 21:16:00 minastirith kernel: [171470.436701] DROP IN=eth0 OUT= MAC=00:13:46:11:11:11:78:cd:11:6b:11:7e:11:00 SRC=2.2.2.2 DST=1.2.3.4 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=15593 DF PROTO=TCP SPT=58884 DPT=12345 WINDOW=14600 RES=0x00 SYN URGP=0 OPT (020405B40402080A0CE97C070000000001030306)

### Nmap SYN (-sS):
Sep 29 21:16:12 minastirith kernel: [171482.094163] DROP IN=eth0 OUT= MAC=00:13:46:11:11:11:78:cd:11:6b:11:7e:11:00 SRC=2.2.2.2 DST=1.2.3.4 LEN=44 TOS=0x00 PREC=0x00 TTL=39 ID=26480 PROTO=TCP SPT=48271 DPT=12345 WINDOW=4096 RES=0x00 SYN URGP=0 OPT (020405B4)

### Scapy SYN via: sr1(IP(dst="1.2.3.4")/TCP(dport=12345,flags="S"))
Sep 29 21:35:15 minastirith kernel: [172625.207745] DROP IN=eth0 OUT= MAC=00:13:46:11:11:11:78:cd:11:6b:11:7e:11:00 SRC=2.2.2.2 DST=1.2.3.4 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=1 PROTO=TCP SPT=20 DPT=12345 WINDOW=8192 RES=0x00 SYN URGP=0
As a result, we can infer that SYN scans without options may originate from Masscan (the Scapy example not withstanding since Scapy's usage as a port scanner is a probably a lot less common than Masscan usage), and this will become more likely true over time as Masscan's popularity increases. (It is included as a tool leveraged by Rapid7's Sonar project for example.)

The upcoming 2.2.2 release of psad will include detection of scans that originate from Masscan, and if you check out the latest psad sources from git, this feature has already been added. To make this work, the iptables LOG rule needs to be instantiated with the --log-tcp-options switch, and a new psad.conf configuration variable "EXPECT_TCP_OPTIONS" has been added to assist. When looking for Masscan SYN scans, psad requires at least one TCP options field to be populated within a LOG message (so that it knows --log-tcp-options has been set for at least some logged traffic), and after seeing this then subsequent SYN packets with no options are attributed to Masscan traffic. All usual psad threshold variables continue to apply however, so (by default) a single Masscan SYN packet will not trigger a psad alert. Masscan detection can be disabled altogether by setting EXPECT_TCP_OPTIONS to "N", and this will not affect any other psad detection techniques such as passive OS fingerprinting, etc.

Port Knocking: Why You Should Give It Another Look

$
0
0
Port Knocking: Why you Should Give It Another Look (Update 10/20/2013: There is a Reddit comment thread going on this post here.)

It has been a decade since Port Knocking was first introduced to the security community in 2003, so it seemed fitting to recap how far the concept has evolved. Much effort has gone into solving architectural problems with PK systems, and today Single Packet Authorization (SPA) embodies the primary benefits of PK while fixing its limitations.

There are noted security researchers on both sides of the debate as to whether PK/SPA has any security value, but it is interesting that researchers who don't find value seem to concentrate on aspects of PK/SPA that have little to do with the chief benefit: cryptographically strong concealment. At least, this is the property offered by Single Packet Authorization but admittedly not necessarily with Port Knocking. Let's first go through some of the more common criticisms of PK/SPA, and show what the SPA answer is to each one. For those that haven't considered SPA in the past, perhaps it is time to give it a second look if for no other reason than to propose a method for breaking it.

1) Isn't PK/SPA just another password?

Suppose I hand you an arbitrary IP, say 2.2.2.2 that is running a default-drop firewall policy. As an attacker, you scan 2.2.2.2 and can't get any information back whatsoever. It doesn't respond to pings, Nmap cannot detect any TCP or UDP service under all scanning techniques, and any Metasploit module that relies on a TCP connect() call is ineffective. In the absence of a routing issue, it is safe to assume there is a firewall or ACL blocking all incoming scans. It is not feasible to tell whether there are any services listening (SSH or otherwise), and it also not feasible to tell whether there is a PK/SPA daemon either - the firewall is being used to do what it does best: block network traffic. The point is that there is no information coming back from the target. A PK/SPA daemon may be deployed, but the passive nature of PK/SPA makes it undiscoverable [1].

As a thought experiment, what would it take to make PK/SPA "just another password"? Well, if the PK/SPA daemon listened on a TCP socket and advertised itself via a server banner (like "fwknop-2.5.1, enter password for SSH access:") this would go a long way. Then Nmap would once again become an effective tool for finding the PK/SPA daemon, and an attacker could start to try different passwords. In other words, the daemon would no longer be passive, which is the whole point of PK/SPA to begin with.

But wait, you might say "but attackers can just try to brute force passive PK/SPA daemons anyway (even though they can't scan for them directly) and see if a port opens up", which brings us to:

2) Can PK/SPA be brute-forced?

Port Knocking implementations that use simple shared sequences are certainly vulnerable to brute forcing, and they are also vulnerable to replay attacks. These vulnerabilities (among other problems) were primary motivators for the development of SPA, and any modern SPA implementation is not vulnerable to either of these attacks. For example, fwknop uses AES in CBC mode authenticated with an HMAC SHA-256 in the encrypt-then-authenticate model, and both the encryption and HMAC keys (256 and 512 bits respectively for a total of 768 bits) are generated from random data in --key-gen mode. Further, fwknop can leverage GnuPG instead of AES, and 2048-bit GnuPG keys are fully supported. If it were practical to brute force fwknop encryption and authentication, then it would also be practical to brute force a lot of other cryptographic software too. Hence, fwknop is not vulnerable to such attacks in any practical sense [2].

Beyond this, from 1) above remember that the very existence of the SPA daemon is not discoverable by an attacker. For the average adversary, interacting with the SPA daemon must be done blindly "by chance". So, the target - even if it is running an SPA daemon which the attacker can't see - which implementation should the attacker try to brute force? If the target is running Moxie Marlinspike's knockknock (which uses AES in CTR mode authenticated with a truncated HMAC SHA-1), then the attacker needs to try and brute force the daemon with crafted TCP SYN packets via the following fields: TCP window size, TCP sequence, TCP acknowledgement, and the network layer IP ID. On the other hand, if the target is running fwknop, then the attacker would have to try and brute force the fwknopd daemon with UDP payloads to a port that the fwknopd pcap filter statement allows (although fwknopd can also be configured to only accept SPA payloads over ICMP instead). Should the attacker try to brute force the fwknop AES-CBC + HMAC SHA-256 mode? Or the GnuPG + HMAC SHA-256 mode? Further, the fwknopd daemon can place restrictions on the services that an authenticated client is authorized to request via the access.conf file. There are a lot of bits adding up, and the entire time the attacker doesn't even know whether an SPA daemon is actually running let alone which one.

Unfortunately for the attacker it gets worse. Even if the attacker could somehow brute force both the encryption and authentication steps in fwknop or other SPA software, to which service should the attacker try to make a connection? No service has to listen on the default port, so if a connection to SSH isn't answered should the attacker scan the target looking for a service? Maybe SPA is being used to conceal an IMAP daemon, a webserver, or OpenVPN instead of SSHD? Further, because the SPA daemon never acknowledges anything to begin with, the attacker can only infer that a brute force attempt was successful by seeing if a service is finally available after each attempt. So, in order for the attacker to be effective, the work flow for every brute force attempt should be: (1) brute force attempt, (2) scan for SSH (just because SPA is usually used to conceal SSH), (3) full scan if the SSH scan doesn't work. This starts to become extremely noisy to say the least. Even if full scans aren't also used, the volume of traffic just to attempt brute force operations by themselves is prohibitively huge.

Regardless of the attacker work flow, which service is concealed, or how heavily the attacker scans the target after every attempt, the brute force resistance offered by fwknop is fundamentally provided through the strength of cryptography. Getting past the authentication step alone would require breaking the 512-bit HMAC SHA-256 key (or forcing a hash collision against SHA-256), and fwknop even supports HMAC SHA-512 if one prefers that instead. Beyond this, the encryption key would also need to be brute-forced. For all intents and purposes it is not practical to brute force fwknop, and similar arguments apply to other SPA software.

3) Does PK/SPA add intolerable complexity?

Every security measure has some associated complexity. Firewalls add complexity. Encryption adds complexity. SSH itself adds complexity. If complexity were always the trump card against higher levels of security, then people would connect admin shells to sockets directly via netcat (or just run telnet) and not worry about encryption. People would not run firewalls because vanilla IP stacks without firewalling hooks would be simpler. Filesystem permissions overlays would be considered insecure because they add complexity. Obviously such viewpoints don't pass muster in the real world. The point is that using more complex code sometimes enables higher levels of security against widely understood threat models. For example, people use SSH and SSL because they want authentication and confidentiality over untrusted networks. Firewalls are used to reduce the attack surface that an adversary can easily communicate with. Application and/or filesystem layer policy controls are engineered to place restrictions on classes of users. The list continues.

This is not to say that complexity is not an important consideration - far from it. Rather, a real security benefit must be realized in order to justify increasing the complexity of a system. In the SPA community, we assert there is a security benefit afforded by passive, cryptographically strong service concealment. How would an attacker try to brute force user passwords via SSH when it is concealed by SPA? How would an attacker exploit even a zero-day vulnerability in a service protected by SPA? How would an attacker exploit a vulnerability in the SPA daemon itself when it is indistinguishable from a system that is running a default-drop firewall policy? (An attacker may interact with the SPA daemon, but it is more or less "by chance" [3].)

In the context of PK/SPA, the real issue is whether the complexity of the code that an attacker can interact with is more or less when PK/SPA is deployed. Anyone protecting networked services is probably already running a firewall, so the firewall usage by the PK/SPA software isn't adding to complexity that wasn't already there. Next, if PK/SPA is used to conceal multiple services (say, SSH, an IMAP daemon, and a webserver all at the same time), a would-be attacker cannot interact with any of those code bases without first getting past the PK/SPA daemon. It is a good bet that the complexity of the PK/SPA daemon is a lot less than the aggregate complexity of all three of those services if they were open to the world. Further, this may still be true even for a single daemon such as SSH as well. In essence, the effective complexity of code that an attacker can interact with may actually go down with PK/SPA deployed - that is, until the PK/SPA daemon can be circumvented (and hence a method for doing this becomes an important question for an attacker).

4) What happens if the PK/SPA daemon dies?

This is a solved problem. Process monitoring software has been around for decades. Many options exist for any OS on which a PK/SPA daemon is deployed. For example, on Ubuntu systems fwknopd is monitored by upstart. Having said this, fwknopd is extremely stable anyway so this feature is hardly ever needed in practice. Still, it is certainly important to ensure that PK/SPA usage does not cause a single point of failure, so using process monitoring software is a good idea.

Summary

There are other criticisms of SPA that are not included in this blog post, and certainly some of them are legitimate such as the fact that SPA requires a specialized client to access concealed services and the fact that "NAT piggybacking" is possible for users on the same network from which an SPA client is used when behind a NAT. However, these points don't generally rise to the level that they invalidate the SPA strategy. This blog post attempts to address those criticisms that could rise to this level were it not for the effort that has gone into solid SPA design by fwknop and other projects. More information on the design goals that guide fwknop can be found in the project tutorial.

In conclusion, SSL uses cryptography to provide authentication and confidentiality, Tor uses cryptography to provide anonymity, and SPA uses cryptography to conceal service existence. For those that assert there is no security value in the later strategy, it should consequently not be difficult to circumvent. To those in this camp, given the material in this post, please propose a method for breaking SPA.

[1] At least, a PK/SPA daemon is not discoverable by attackers who aren't already in a privileged position to sniff all traffic to and from the target. Clearly, most attackers - including password-guessing botnets - do not fall into this category.

[2] It is possible to weaken the security of fwknop SPA communications by not using --key-gen mode to generate random encryption and HMAC keys and thereby make them more susceptible to brute force attacks. However, this type of problems similarly affects other cryptographic software so it isn't unique to fwknop. And, even if a user doesn't use --key-gen mode, it is still not as easy to brute force fwknopd (which never confirms its existence to an attacker) as other software which an attacker can readily see is available to exploit.

[3] The security of fwknopd code itself is nonetheless quite important, and this is why the fwknop project uses static analysis provided by Coverity (and has a Coverity scan score of zero), the CLANG static analyzer, and also implements dynamic analysis with valgrind via a comprehensive test suite.

Validating libfko Memory Usage with Test::Valgrind

$
0
0
Validating libfko Memory Usage with Test::Valgrind The fwknop project consistently uses valgrind to ensure that memory leaks, double free() conditions, and other problems do not creep into the code base. A high level of automation is built around valgrind usage with the fwknop test suite, and a recent addition extends this even further by using the excellent CPAN Test::Valgrind module. Even though the test suite has had the ability to run tests through valgrind, previous to this change these tests only applied to the fwknop C binaries when executed directly by the test suite. Further, some of the most rigorous testing is done through the usage of the perl FKO extension to fuzz libfko functions, so without the Test::Valgrind module these tests also could not take advantage of valgrind support. Now that the test suite supports Test::Valgrind (and a check is done to see if it is installed), all fuzzing tests can also be validated with valgrind. Technically, the fuzzing tests have been added as FKO built-in tests in the t/ directory, and the test suite runs them through Test::Valgrind like this:
# prove --exec 'perl -Iblib/lib -Iblib/arch -MTest::Valgrind' t/*.t
Here is a complete example - first, run the test suite like so:
# ./test-fwknop.pl --enable-all --include perl --test-limit 3

[+] Starting the fwknop test suite...

    args: --enable-all --include perl --test-limit 3

[+] Total test buckets to execute: 3

[perl FKO module] [compile/install] to: ./FKO...................pass (1)
[perl FKO module] [make test] run built-in tests................pass (2)
[perl FKO module] [prove t/*.t] Test::Valgrind..................pass (3)
[valgrind output] [flagged functions] ..........................pass (4)

    Run time: 1.27 minutes

[+] 0/0/0 OpenSSL tests passed/failed/executed
[+] 0/0/0 OpenSSL HMAC tests passed/failed/executed
[+] 4/0/4 test buckets passed/failed/executed
Note that all tests passed as shown above. This indicates that the test suite has not found any memory leaks through the fuzzing tests run via Test::Valgrind. But, let's validate this by artificially introducing a memory leak and see if the test suite can automatically catch it. For example, here is a patch that forces a memory leak in the validate_access_msg() libfko function. This function ensures that the shape of the access request conforms to something fwknop expects like "1.2.3.4,tcp/22". The memory leak happens because a new buffer is allocated from the heap but is never free()'d before returning from the function (obviously this patch is for illustration and testing purposes only):
$ git diff
diff --git a/lib/fko_message.c b/lib/fko_message.c
index fa6803b..c04e035 100644
--- a/lib/fko_message.c
+++ b/lib/fko_message.c
@@ -251,6 +251,13 @@ validate_access_msg(const char *msg)
     const char   *ndx;
     int     res         = FKO_SUCCESS;
     int     startlen    = strnlen(msg, MAX_SPA_MESSAGE_SIZE);
+    char *leak = NULL;
+
+    leak = malloc(100);
+    leak[0] = 'a';
+    leak[1] = 'a';
+    leak[2] = '\0';
+    printf("LEAK: %s\n", leak);

     if(startlen == MAX_SPA_MESSAGE_SIZE)
         return(FKO_ERROR_INVALID_DATA_MESSAGE_ACCESS_MISSING);
Now recompile fwknop and run the test suite again, after applying the patch (recompilation output is not shown):
# cd ../
# make
# test
# ./test-fwknop.pl --enable-all --include perl --test-limit 3
[+] Starting the fwknop test suite...

    args: --enable-all --include perl --test-limit 3

    Saved results from previous run to: output.last/

    Valgrind mode enabled, will import previous coverage from:
        output.last/valgrind-coverage/

[+] Total test buckets to execute: 3

[perl FKO module] [compile/install] to: ./FKO...................pass (1)
[perl FKO module] [make test] run built-in tests................pass (2)
[perl FKO module] [prove t/*.t] Test::Valgrind..................fail (3)
[valgrind output] [flagged functions] ..........................fail (4)

    Run time: 1.27 minutes

[+] 0/0/0 OpenSSL tests passed/failed/executed
[+] 0/0/0 OpenSSL HMAC tests passed/failed/executed
[+] 2/2/4 test buckets passed/failed/executed

This time two tests fail. The first is the test that runs the perl FKO module built-in tests under Test::Valgrind, and the second is the "flagged functions" test which compares test suite output looking for new functions that valgrind has flagged vs. the previous test suite execution. By looking at the output file of the "flagged functions" test it is easy to see the offending function where the new memory leak exists. This provides an easy, automated way of memory leak detection that is driven by perl FKO fuzzing tests.
# cat output/4.test
[+] fwknop client functions (with call line numbers):
       10 : validate_access_msg [fko_message.c:256]
        6 : fko_set_spa_message [fko_message.c:184]
        4 : fko_new_with_data [fko_funcs.c:263]
        4 : fko_decrypt_spa_data [fko_encryption.c:264]
        4 : fko_decode_spa_data [fko_decode.c:350]
Currently, there are no known memory leaks in the fwknop code, and automation built around the Test::Valgrind module will help keep it that way.

Software Release: fwknop-2.6.0

$
0
0
fwknop-2.6.0 software release The 2.6.0 release of fwknop is available for download. This release incorporates a number of feature enhancements such as an AppArmor policy for fwknopd, HMAC authenticated encryption support for the Android client, new NAT criteria that are independently configurable for each access.conf stanza, and more rigorous valgrind verification powered by the CPAN Test::Valgrind module. A few bugs were fixed as well, and similarly to the 2.5 and 2.5.1 releases, the fwknop project has a Coverity defect count of zero. As proof of this, you can see the Coverity high-level defect stats for fwknop here (you'll need to sign up for an account): Coverity Scan Build Status I would encourage any open source project that is using Coverity to publish their scan results. At last count, it appears that over 1,100 projects are using Coverity, but OpenSSH is still not one of them.

Development on fwknop-2.6.1 will begin shortly, and here is the complete ChangeLog for fwknop-2.6.0:

  • (Radostan Riedel) Added an AppArmor policy for fwknopd that is known to work on Debian and Ubuntu systems. The policy file is available at extras/apparmor/usr.sbin/fwknopd.
  • [libfko] Nikolay Kolev reported a build issue with Mac OS X Mavericks where local fwknop copies of strlcat() and strlcpy() were conflicting with those that already ship with OS X 10.9. Closes #108 on github.
  • [libfko] (Franck Joncourt) Consolidated FKO context dumping function into lib/fko_util.c. In addition to adding a shared utility function for printing an FKO context, this change also makes the FKO context output slightly easier to parse by printing each FKO attribute on a single line (this change affected the printing of the final SPA packet data). The test suite has been updated to account for this change as well.
  • [libfko] Bug fix to not attempt SPA packet decryption with GnuPG without an fko object with encryption_mode set to FKO_ENC_MODE_ASYMMETRIC. This bug was caught with valgrind validation against the perl FKO extension together with the set of SPA fuzzing packets in test/fuzzing/fuzzing_spa_packets. Note that this bug cannot be triggered via fwknopd because additional checks are made within fwknopd itself to force FKO_ENC_MODE_ASYMMETRIC whenever an access.conf stanza contains GPG key information. This fix strengthens libfko itself to independently require that the usage of fko objects without GPG key information does not result in attempted GPG decryption operations. Hence this fix applies mostly to third party usage of libfko - i.e. stock installations of fwknopd are not affected. As always, it is recommended to use HMAC authenticated encryption whenever possible even for GPG modes since this also provides a work around even for libfko prior to this fix.
  • [Android] (Gerry Reno) Updated the Android client to be compatible with Android-4.4.
  • [Android] Added HMAC support (currently optional).
  • [server] Updated pcap_dispatch() default packet count from zero to 100. This change was made to ensure backwards compatibility with older versions of libpcap per the pcap_dispatch() man page, and also because some of a report from Les Aker of an unexpected crash on Arch Linux with libpcap-1.5.1 that is fixed by this change (closes #110).
  • [server] Bug fix for SPA NAT modes on iptables firewalls to ensure that custom fwknop chains are re-created if they get deleted out from under the running fwknopd instance.
  • [server] Added FORCE_SNAT to the access.conf file so that per-access stanza SNAT criteria can be specified for SPA access.
  • [test suite] added --gdb-test to allow a previously executed fwknop or fwknopd command to be sent through gdb with the same command line args as the test suite used. This is for convenience to rapidly allow gdb to be launched when investigating fwknop/fwknopd problems.
  • [client] (Franck Joncourt) Added --stanza-list argument to show the stanza names from ~/.fwknoprc.
  • [libfko] (Hank Leininger) Contributed a patch to greatly extend libfko error code descriptions at various places in order to give much better information on what certain error conditions mean. Closes #98.
  • [test suite] Added the ability to run perl FKO module built-in tests in the t/ directory underneath the CPAN Test::Valgrind module. This allows valgrind memory checks to be applied to libfko functions via the perl FKO module (and hence rapid prototyping can be combined with memory leak detection). A check is made to see whether the Test::Valgrind module has been installed, and --enable-valgrind is also required (or --enable-all) on the test-fwknop.pl command line.

Software Release: fwknop-2.6.3

$
0
0
fwknop-2.6.3 software release The 2.6.3 release of fwknop is available for download. The emphasis in this release is maximizing code coverage through a new python SPA packet fuzzer, and also on fault injection testing with the excellent fault injection library libfiu developed by Alberto Bertogli. Another important change in 2.6.3 is all IP resolution lookups in '-R' mode now happen over SSL to make it harder for an adversary to mount a MITM attack on the resolution lookup. As always, manually specifying the IP to allow through the remote firewall is safer than relying on any network communication - even when SSL would be involved.

Here is the complete ChangeLog for fwknop-2.6.3:

  • [client] External IP resolution via '-R' (or '--resolve-ip-http') is now done via SSL by default. The IP resolution URL is now 'https://www.cipherdyne.org/cgi-gin/myip', and a warning is generated in '-R' mode whenever a non-HTTPS URL is specified (it is safer just to use the default). The fwknop client leverages 'wget' for this operation since that is cleaner than having fwknop link against an SSL library.
  • Integrated the 'libfiu' fault injection library available from http://blitiri.com.ar/p/libfiu/ This feature is disabled by default, and requires the --enable-libfiu-support argument to the 'configure' script in order to enable it. With fwknop compiled against libfiu, fault injections are done at various locations within the fwknop sources and the test suite verifies that the faults are properly handled at run time via test/fko-wrapper/fko_fault_injection.c. In addition, the libfiu tool 'fiu-run' is used against the fwknop binaries to ensure they handle faults that libfiu introduces into libc functions. For example, fiu-run can force malloc() to fail even without huge memory pressure on the local system, and the test suite ensures the fwknop binaries properly handle this.
  • [test suite] Integrated a new python fuzzer for fwknop SPA packets (see test/spa_fuzzing.py). This greatly extends the ability of the test suite to validate libfko operations since SPA fuzzing packets are sent through libfko routines directly (independently of encryption and authentication) with a special 'configure' option --enable-fuzzing-interfaces. The python fuzzer generates over 300K SPA packets, and when used by the test suite consumes about 400MB of disk. For reference, to use both the libfiu fault injection feature mentioned above and the python fuzzer, use the --enable-complete option to the test suite.
  • [test suite] With the libfiu fault injection support and the new python fuzzer, automated testing of fwknop achieves 99.7% function coverage and 90.2% line coverage as determined by 'gcov'. The full report may be viewed here: http://www.cipherdyne.org/fwknop/lcov-results/
  • [server] Add a new GPG_FINGERPRINT_ID variable to the access.conf file so that full GnuPG fingerprints can be required for incoming SPA packets in addition to the abbreviated GnuPG signatures listed in GPG_REMOTE_ID. From the test suite, an example fingerprint is:
    GPG_FINGERPRINT_ID     00CC95F05BC146B6AC4038C9E36F443C6A3FAD56
    
  • [server] When validating access.conf stanzas make sure that one of GPG_REMOTE_ID or GPG_FINGERPRINT_ID is specified whenever GnuPG signatures are to be verified for incoming SPA packets. Signature verification is the default, and can only be disabled with GPG_DISABLE_SIG but this is NOT recommended.
  • [server] Bug fix for PF firewalls without ALTQ support on FreeBSD. With this fix it doesn't matter whether ALTQ support is available or not. Thanks to Barry Allard for discovering and reporting this issue. Closes issue #121 on github.
  • [server] Bug fix discovered with the libfiu fault injection tag "fko_get_username_init" combined with valgrind analysis. This bug is only triggered after a valid authenticated and decrypted SPA packet is sniffed by fwknopd:
    ==11181== Conditional jump or move depends on uninitialised value(s)
    ==11181==    at 0x113B6D: incoming_spa (incoming_spa.c:707)
    ==11181==    by 0x11559F: process_packet (process_packet.c:211)
    ==11181==    by 0x5270857: ??? (in /usr/lib/x86_64-linux-gnu/libpcap.so.1.4.0)
    ==11181==    by 0x114BCC: pcap_capture (pcap_capture.c:270)
    ==11181==    by 0x10F32C: main (fwknopd.c:195)
    ==11181==  Uninitialised value was created by a stack allocation
    ==11181==    at 0x113476: incoming_spa (incoming_spa.c:294)
    
  • [server] Bug fix to handle SPA packets over HTTP by making sure to honor the ENABLE_SPA_OVER_HTTP fwknopd.conf variable and to properly account for SPA packet lengths when delivered via HTTP.
  • [server] Add --test mode to instruct fwknopd to acquire and process SPA packets, but not manipulate firewall rules or execute commands that are provided by SPA clients. This option is mostly useful for the fuzzing tests in the test suite to ensure broad code coverage under adverse conditions.

Code Coverage: Challenges For Open Source Projects

$
0
0
In this blog post I'll pose a few challenges to open source projects. These challenges, among other goals, are designed to push automated test suites to maximize code coverage. For motivation, I'll present code coverage stats from the OpenSSL and OpenSSH test suites, and contrast this with what I'm trying to achieve in the fwknop project.

Stated bluntly, if comprehensive code coverage is not achieved by your test suite, you're doing it wrong.

With major bugs like Heartbleed and "goto fail", there is clearly a renewed need for better automated testing. As Mike Bland demonstrated, the problem isn't so much about technology since unit tests can be built for both Heartbleed and "goto fail". Rather, the problem is that the whole software engineering life cycle needs to embrace better testing.

1) Publish your code coverage stats

Just as open source projects publish source code, test suite code coverage results should be published too. The mere act of publishing code coverage - just as open source itself - is a way to engage developers and users alike to improve such results. Clearly displayed should be all branches, lines, and functions that are exercised by the test suite, and these results should be published for every software release. Without such stats, how can users have confidence that the project test suite is comprehensive? Bugs still crop up even with good code coverage, but many many bugs will be squashed during the development of a test suite that strives to exercise every line of source code.

For a project written in C and compiled with gcc, the lcov tool provides a nice front-end for gcov coverage data. lcov was used to generate the following code coverage reports on OpenSSL-1.0.1h, OpenSSH-6.6p1, and fwknop-2.6.3 using the respective test suite in each project:

Hit Total Coverage
OpenSSL-1.0.1h Lines: 44604 96783 46.1 %
Full code coverage report Functions: 3518 6574 53.5 %
Branches: 22653 67181 33.7 %

OpenSSH-6.6p1 Lines: 18241 33466 54.5 %
Full code coverage report Functions: 1217 1752 69.5 %
Branches: 9362 22674 41.3 %

fwknop-2.6.3 Lines: 6971 7748 90.0 %
Full code coverage report Functions: 376 377 99.7 %
Branches: 4176 5239 79.7 %


The numbers speak for themselves. To be fair, fwknop has a much smaller code base than OpenSSL or OpenSSH - less than 1/10th the size of OpenSSL and about 1/5th the size of OpenSSH in terms of lines reported by gcov. So, presumaby it's a lot easier to reach higher levels of code coverage in fwknop than the other two projects. Nevertheless, it is shocking that the line coverage in the OpenSSL test suite is below 50%, and not much better in OpenSSH. What are the odds that the other half of the code is bug free? What are the odds that changes in newer versions won't break assumptions made in the untested code? What are the odds that one of the next security vulnerabilities announced in either project stems from this code? Of course, test suites are not a panacea, but there are almost certainly bugs lying in wait within the untested code. It is easier to have confidence in code that has at least some test suite coverage than code that has zero coverage - at least as far as the test suite is concerned (I'm not saying that other tools are not being used). Both OpenSSL and OpenSSH use tools beyond their respective test suites to try and maintain code quality - OpenSSL uses Coverity for example - but these tools are not integrated with test suite results and do not contribute to the code coverage stats above. What I'm suggesting is that the test suites themselves should get much closer to 100% coverage, and this may require the integration of infrastructure like a custom fuzzer or fault injection library (more on this below).

On another note, given that an explicit design goal of the fwknop test suite is to maximize code coverage, and given the results above, it is clear there is significant work left to do.

2) Make it easy to automatically produce code coverage results

Neither OpenSSL nor OpenSSH make it easy to automatically generate code coverage stats like those shown above. One can always Google for the appropriate CFLAGS and LDFLAGS settings, recompile, and run lcov, but you shouldn't have to. This should be automatic and built into the test suite as an option. If your project is using autoconf, then there should be a top level --enable-code-coverage switch (or similar) to the configure script, and the test suite should take the next steps to produce the code coverage reports. Without this, there is unnecessary complexity and manual work, and this affects users and developers alike. My guess is this lack of automation is a factor for why code coverage for OpenSSL and OpenSSH is not better. Of course, it takes a lot of effort to develop a test suite with comprehensive code coverage support, but automation is low hanging fruit.

If you want to generate the code coverage reports above, here are two trivial scripts - one for OpenSSH and another for OpenSSL. This one works for OpenSSH:


mkdir $LCOV_DIR

make clean
make
make tests

lcov --capture --directory . --output-file $LCOV_FILE
lcov -r $LCOV_FILE /usr/include/\* --output-file $LCOV_DIR/$LCOV_FILTERED

genhtml $LCOV_DIR/$LCOV_FILTERED --output-directory $LCOV_DIR

3) Integrate a fuzzer into your test suite

If your test suite does not achieve 99%/95% function/line coverage, architectural changes should be made to reach these goals and beyond. This will likely require that test suite drive a fuzzer against your project and measure how well it exercises the code base.

Looking at code coverage results for older versions of the fwknop project was an eye opener. Although the test suite had hundreds of tests, there were large sections of code that were not exercised. It was for this reason the 2.6.3 release concentrated on more comprehensive automated test coverage. However, achieving better coverage was not a simple matter of executing fwknop components with different configuration files or command line arguments - it required the development of a dedicated SPA packet fuzzer along with a special macro -DENABLE_FUZZING built into the source code to allow the fuzzer to reach portions of code that would have otherwise been more difficult to trigger due to encryption and authentication requirements. This is a similar to the strategy proposed in Michal Zalewski's fuzzer American Fuzzy Lop here (see the "Known Limitations" section).

The main point is that fwknop was changed to support fuzzing driven by the test suite as a way to extend code coverage. It is the strong integration of fuzzing into the test suite that provides a powerful testing technique, and looking at code coverage results allows you to measure it.

Incidentally, an example double free() bug that the fwknop packet fuzzer triggered in conjunction with the test suite can be found here (fixed in 2.6.3).

4) Further extend your code coverage with fault injection

Any C project leveraging libc functions should implement error checking against function return values. The canonical example is checking to see whether malloc() returned NULL, and if so this is usually treated as an unrecoverable error like so:

    clean_up();
Some projects elect to write a "safe_malloc()" wrapper for malloc() or other libc functions so that error handling can be done in one place, but it is not feasible to do this for every libc function. So, how to verify whether error conditions are properly handled at run time? For malloc(), NULL is typically returned under extremely high memory pressure, so it is hard to trigger this condition and still have a functioning system let alone a functioning test suite. In other words, in the example above, how can the test suite achieve code coverage for the clean_up() function? Other examples include filesystem or network function errors that are returned when disks fill up, or a network communication is blocked, etc.

What's needed is a mechanism for triggering libc faults artificially, without requiring the underlying conditions to actually exist that would normally cause such faults. This is where a fault injection library like libfiu comes in. Not only does it support fault injection at run time against libc functions without the need to link against libfiu (a dedicated binary "fiu-run" takes care of this), but it can also be used to trigger faults in arbitrary non-libc functions within a project to see how function callers handle errors. In fwknop, both strategies are used by the test suite, and this turned up a number of bugs like this one.

Full disclosure: libfiu does not yet support code coverage when executing a binary under fiu-run because there are problems interacting with libc functions necessary to write out the various source_file.c.gcno and source_file.c.gcda coverage files. This issue is being worked on for an upcoming release of libfiu. So, in the context of fwknop, libfiu is used to trigger faults directly in fwknop functions to see how calling functions handle errors, and this strategy is compatible with gcov coverage results. The fiu-run tool is also used, but more from the perspective of trying to crash one of the fwknop binaries since we can't (yet) see code coverage results under fiu-run. Here is an example fault introduced into the fko_get_username() function:
fko_get_username(fko_ctx_t ctx, char **username)
    fiu_return_on("fko_get_username_init", FKO_ERROR_CTX_NOT_INITIALIZED);
With the fault set (there is a special command line argument --fault-injection-tag on the fwknopd server command line to enable the fault), the error handling code seen at the end of the example below is executed via the test suite. For proof of error handling execution, see the full coverage report (look at line 240).
get_spa_data_fields(fko_ctx_t ctx, spa_data_t *spdat)

    res = fko_get_username(ctx, &(spdat->username));

Once again, it is the integration of fault injection with the test suite and corresponding code coverage reports that extends testing efforts in a powerful way. libfiu offers many nice features, including thread safey, the ability to enable a fault injection tag relative to other functions in the stack, and more.

5) Negative valgrind findings should force tests to fail

So far, a theme in this blog post has been better code coverage through integration. I've attempted to make the case for the integration of fuzzing and fault injection with project test suites, and code coverage stats should be produced for both styles of testing.

A third integration effort is to leverage valgrind. That is, the test suite should run tests underneath valgrind when possible (speed and memory usage may be constraints here depending on the project). If valgrind discovers a memory leak, double free(), or other problem, this finding should automatically cause corresponding tests to fail. In some cases valgrind suppressions will need to be created if a project depends on libraries or other code that is known to have issues under valgrind, but findings within project sources should cause tests to fail. For projects heavy on the crypto side, there are some instances where code is very deliberately built in a manner that triggers a valgrind error (see Tonnerre Lombard's write up on the old Debian OpenSSL vulnerability), but these are not common occurrences and suppressions can always be applied. The average valgrind finding in a large code base should cause test failure.

Although running tests under valgrind will not expand code coverage, valgrind is a powerful tool that should be tightly integrated with your test suite.

Summary

  • Publish your code coverage stats
  • Make it easy to automatically produce code coverage results
  • Integrate a fuzzer into your test suite
  • Further extend your code coverage with fault injection
  • Negative valgrind findings should automatically force tests to fail

Software Release: fwknop-2.6.4

$
0
0
fwknop-2.6.4 software release The 2.6.4 release of fwknop is available for download. New functionality has been developed for 2.6.4, including a new UDP listener mode to remove libpcap as a dependency for fwknopd, support for firewalld on recent versions of Fedora, RHEL, and Centos (contributed by Gerry Reno), and support for Michal Zalewski's 'American Fuzzy Lop' fuzzer. Further, on systems where execvpe() is available, all system() and popen() calls have been replaced so that the shell is not invoked and no environment is used. As usual, fwknop has a Coverity Scan score of zero, and the code coverage report achieved by the 2.6.4 test suite is available here.

Here is the complete ChangeLog for fwknop-2.6.4:

  • [server] Added a UDP server mode so that SPA packets can be acquired via UDP directly without having to use libpcap. This is an optional feature since it opens a UDP port (and therefore requires the local firewall be opened for communications to this port), but fwknopd is careful to never send anything back to a client that sends data to this port. So, from the perspective of an attacker or scanner, fwknopd remains invisible. This feature is enabled in fwknopd either with a new command line argument --udp-server or in the fwknopd.conf file with the ENABLE_UDP_SERVER variable. When deployed in this mode, it is advisable to recompile fwknop beforehand with './configure --enable-udp-server' so that fwknopd does not link against libpcap.
  • [server] Replaced all popen() and system() calls with execvpe() with no usage of the environment. This is a defensive measure to not make use of the shell for firewall command execution, and is supported on systems where execvpe() is available.
  • (Gerry Reno) Added support for firewalld to the fwknopd daemon on RHEL 7 and CentOS 7. This is implemented using the current firewalld '--direct --passthrough' capability which accepts raw iptables commands. More information on firewalld can be found here: https://fedoraproject.org/wiki/FirewallD
  • [server] Added support for the 'American Fuzzy Lop' (AFL) fuzzer from Michal Zalewski. This requires that fwknop is compiled with the '--enable-afl-fuzzing' argument to the configure script as this allows encryption/digest short circuiting in a manner necessary for AFL to function properly. The benefit of this strategy is that AFL can fuzz the SPA packet decoding routines implemented by libfko. See the test/afl/ directory for some automation around AFL fuzzing.
  • (Bill Stubbs) submitted a patch to fix a bug where fwknopd could not handle Ethernet frames that include the Frame Check Sequence (FCS) header. This header is four bytes long, and is placed at the end of each Ethernet frame. Normally the FCS header is not visible to libpcap, but some card/driver combinations result in it being included. Bill noticed this on the following platform: BeagleBone Black rev C running 3.8.13-bone50 #1 SMP Tue May 13 13:24:52 UTC 2014 armv7l GNU/Linux
  • [client] Bug fix to ensure that a User-Agent string can be specified when the fwknop client uses wget via SSL to resolve the external IP address. This closes issue #134 on github reported by Barry Allard. The fwknop client now uses the wget '-U' option to specify the User-Agent string with a default of "Fwknop/<version>". In addition, a new command line argument "--use-wget-user-agent" to allow the default wget User-Agent string to apply instead.
  • [python module] When an HMAC key is passed to spa_data_final() then default to HMAC SHA256 if no HMAC mode was specified.

Integrating fwknop with the 'American Fuzzy Lop' Fuzzer

$
0
0
Over the past few months, the American Fuzzy Lop (AFL) fuzzer written by Michal Zalewski has become a tour de force in the security field. Many interesting bugs have been found, including a late breaking bug in the venerable cpio utility that Michal announced to the full-disclosure list. It is clear that AFL is succeeding perhaps where other fuzzers have either failed or not been applied, and this is an important development for anyone trying to maintain a secure code base. That is, the ease of use coupled with powerful fuzzing strategies offered by AFL mean that open source projects should integrate it directly into their testing systems. This has been done for the fwknop project with some basic scripting and one patch to the fwknop code base. The patch was necessary because according to AFL documentation, projects that leverage things like encryption and cryptographic signatures are not well suited to brute force fuzzing coverage, and fwknop definitely fits into this category. Crypto being a fuzzing barrier is not unique to AFL - other fuzzers have the same problem. So, similarly to the libpng-nocrc.patch included in the AFL sources, encryption, digests, and base64 encoding are bypassed when fwknop is compiled with --enable-afl-fuzzing on the configure command line. One doesn't need to apply the patch manually - it is built directly into fwknop as of the 2.6.4 release. This is in support of a major goal for the fwknop project which is comprehensive testing.

If you maintain an open source project that involves crypto and does any sort of encoding/decoding/parsing gated by crypto operations, then you should patch your project so that it natively supports fuzzing with AFL through an optional compile time step. As an example, here is a portion of the patch to fwknop that disables base64 encoding by just copying data manually:
index b8423c2..5b51121 100644
 int
 b64_decode(const char *in, unsigned char *out)
 {
     unsigned char *dst = out;
     v = 0;
     for (i = 0; in[i] && in[i] != '='; i++) {
         unsigned int index= in[i]-43;
@@ -68,6 +80,7 @@ b64_decode(const char *in, unsigned char *out)
         if (i & 3)
             *dst++ = v >> (6 - 2 * (i & 3));
     }

     *dst = '\0';
Fortunately, so far all fuzzing runs with AFL have turned up zero issues (crashes or hangs) with fwknop, but the testing continues.

Within fwknop, a series of wrapper scripts are used to fuzz the following four areas with AFL. These areas represent the major places within fwknop where data is consumed either via a configuration file or from over the network in the form of an SPA packet:

  1. SPA packet encoding/decoding: spa-pkts.sh
  2. Server access.conf parsing: server-access.sh
  3. Server fwknopd.conf parsing: server-conf.sh
  4. Client fwknoprc file parsing: client-rc.sh
Each wrapper script makes sure fwknop is compiled with AFL support, executes afl-fuzz with the corresponding test cases necessary for good coverage, archives previous fuzzing output data, and supports resuming of previously stopped fuzzing jobs. Here is an example where the SPA packet encoding/decoding routines are fuzzed with AFL after fwknop is compiled with AFL support:
$ cd fwknop.git/test/afl/
$ ./compile/afl-compile.sh
$ ./fuzzing-wrappers/spa-pkts.sh
+ ./fuzzing-wrappers/helpers/fwknopd-stdin-test.sh
+ SPA_PKT=1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:AAAAA
+ LD_LIBRARY_PATH=../../lib/.libs ../../server/.libs/fwknopd -c ../conf/default_fwknopd.conf -a ../conf/default_access.conf -A -f -t
Warning: REQUIRE_SOURCE_ADDRESS not enabled for access stanza source: 'ANY'+ echo -n 1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:AAAAA

SPA Field Values:
=================
   Random Value: 1716411011200157
       Username: root
      Timestamp: 1397329899
    FKO Version: 2.0.1
   Message Type: 1 (Access msg)
 Message String: 127.0.0.2,tcp/22
     Nat Access: <NULL>
    Server Auth: <NULL>
 Client Timeout: 0
    Digest Type: 3 (SHA256)
      HMAC Type: 0 (None)
Encryption Type: 1 (Rijndael)
Encryption Mode: 2 (CBC)
   Encoded Data: 1716411011200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22
SPA Data Digest: AAAAA
           HMAC: <NULL>
 Final SPA Data: 200157:root:1397329899:2.0.1:1:127.0.0.2,tcp/22:AAAAA

SPA packet decode: Success
+ exit 0
+ LD_LIBRARY_PATH=../../lib/.libs afl-fuzz -T fwknopd,SPA,encode/decode,00ffe19 -t 1000 -i test-cases/spa-pkts -o fuzzing-output/spa-pkts.out ../../server/.libs/fwknopd -c ../conf/default_fwknopd.conf -a ../conf/default_access.conf -A -f -t
afl-fuzz 0.66b (Nov 23 2014 22:29:48) by <lcamtuf@google.com>
[+] You have 1 CPU cores and 2 runnable tasks (utilization: 200%).
[*] Checking core_pattern...
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Scanning 'test-cases/spa-pkts'...
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Attempting dry run with 'id:000000,orig:spa.start'...
[*] Spinning up the fork server...
[+] All right - fork server is up.
And now AFL is up and running (note the git --abbrev-commit tag integrated into the text banner to make clear which code is being fuzzed): AFL SPA packets fuzzing If the fuzzing run is stopped by hitting Ctrl-C, it can always be resumed as follows:
$ ./fuzzing-wrappers/spa-pkts.sh resume
Although major areas in fwknop where data is consumed are effectively fuzzed with AFL, there is always room for improvement. With the wrapper scripts in place, it is easy to add new support for fuzzing other functionality in fwknop. For example, the digest cache file (used by fwknopd to track SHA-256 digests of previously seen SPA packets) is a good candidate.

UPDATE (11/30/2014): The suggestion above about fuzzing the digest cache file proved to be fruitful, and AFL discovered a bounds checking bug that has been fixed in this commit. The next release of fwknop (2.6.5) will contain this fix and will be made soon.

Taking things to the next level, another powerful technique that would make an interesting side project would be to build a syntax-aware version of AFL that handles SPA packets and/or configuration files natively. The AFL documentation hints at this type of modification, and states that this could be done by altering the fuzz_one() routine in afl-fuzz.c. There is already a fuzzer written in python for the fwknop project that is syntax-aware of the SPA data format (see: spa_fuzzing.py), but the mutators within AFL are undoubtedly much better than in spa_fuzzing.py. Hence, modifying AFL directly would be an effective strategy.

Please feel free to open an issue against fwknop in github if you have a suggestion for enhanced integration with AFL. Most importantly, if you find a bug please let me know. Happy fuzzing!

RAM Disks and Saving Your SSD From AFL Fuzzing

$
0
0
The American Fuzzy Lop fuzzer has become a critical tool for finding security vulnerabilities in all sorts of software. It has the ability to send fuzzing data through programs on the order of hundreds of millions of executions per day on a capable system, and can certainly put strain on your hardware and OS. If you are fuzzing a target program with the AFL mode where a file is written and the target binary reads from this file, then AFL is going to conduct a huge number of writes to the local disk. For a solid-state drive this can reduce its life expectancy because of write amplification.

My main workstation is a Mac running OS X Yosemite, and I run a lot of Linux, FreeBSD, and OpenBSD virtual machines under Parallels for development purposes. The drive on this system is an SSD which keeps everything quite fast, but I don't want to prematurely shorten its life through huge AFL fuzzing runs. Normally, I'm using AFL to fuzz fwknop from an Ubuntu-14.10 VM, and what is needed is a way to keep disk writes down. The solution is to use a RAM disk from within the VM.

First, from the Ubuntu VM, let's get set up for AFL fuzzing and show what the disk writes look like without using a RAM disk from the perspective of the host OS X system. This assumes AFL 0.89 has been installed already and is in the current path:
$ git clone https://github.com/mrash/fwknop.git fwknop.git
$ cd fwknop.git
$ ./autogen.sh
$ cd test/afl/
$ ./compile/afl-compile.sh
We're not running AFL yet. Now, from the Mac, launch the Activity Monitor (under Applications > Utilities) and look at current disk utilization: AFL not running disk writes So, not terrible - currently 31 writes per second at the time the snapshot was taken, and that includes OS X itself and the VM at the same time. But, now let's fire up AFL using the digest cache wrapper on the Ubuntu VM (the main AFL text UI is not shown for brevity):
$ ./fuzzing-wrappers/server-digest-cache.sh
[+] All right - fork server is up.
[+] All test cases processed.

[+] Here are some useful stats:

    Test case count : 1 favored, 0 variable, 1 total
           Bitmap range : 727 to 727 bits (average: 727.00 bits)
                   Exec timing : 477 to 477 us (average: 477 us)

[+] All set and ready to roll!
And now let's take a look at disk writes again from OS X: AFL no RAM disk writes Whoa, that's a massive difference - nearly two orders of magnitude. AFL has caused disk writes to spike to over 2,700 per second with total data written averaging at 19.5MB/sec. Long term fuzzing at this level of disk writes would clearly present a problem for the SSD - AFL frequently needs to be left running for days on end in order to be thorough. So, let's switch everything over to use a RAM disk on the Ubuntu VM instead and see if that reduces disk writes:
# mkdir /tmp/afl-ramdisk && chmod 777 /tmp/afl-ramdisk
# mount -t tmpfs -o size=512M tmpfs /tmp/afl-ramdisk
$ mv fwknop.git /tmp/afl-ramdisk
$ cd /tmp/afl-ramdisk/fwknop.git/test/afl/
$ ./fuzzing-wrappers/server-digest-cache.sh
Here is disk utilization once again from the Mac: AFL RAM disk writes We're back to less than 10 writes per second to the SSD even though AFL is going strong on the Ubuntu VM (not shown). The writes for the previous fuzzing run are still shown to the left of the graph (since they haven't quite aged out yet when the screenshot was taken), and new writes are so low they don't even make it above the X-axis at this scale. Although the total execs per second - about 2,000 - achieved by AFL is not appreciably faster under the RAM disk, the main benefit is that my SSD will last a lot longer. For those that don't run AFL underneath a VM, a similar strategy should still apply on the main OS. Assuming enough RAM is available for whatever software you want to fuzz, just create a RAM disk and run everything from it and extend the life of your hard drive in the process.

Single Packet Authorization Threat Modeling

$
0
0
fwknop Threat Modeling Last week there was an interesting question posed by Peter Smith to the fwknop mailing list that focused on running fwknop in UDP listener mode vs. using libpcap. I thought it would be useful to turn this into a blog post, so here is Peter's original question along with my response:

"...I want to deploy fwknop on my server, but I'm not sure If I should use the UDP listener mode or libpcap. At first UDP listener mode seems to be the choice, because I don't have to compile libpcap. However, I then have to open a port in the firewall. Thinking about this, I get the feeling that I'm defeating the purpose of using SPA, by allowing Internet access to a privileged processe.

If an exploitable security issue is found, even though fwknop remains passive and undiscoverable, an attacker could blindly send his exploit to random ports on servers he suspects running fwknopd, and after maximum 65535 tries he would have root access. I'm not a programmer, so I can't review the code of fwknop or SSH daemon, but if both is equally likely of having security issues, I might as well just allow direct access to the SSH daemon and skip using SPA.

Is my point correct?..."


First, let me acknowledge your point as an important issue to bring up. If someone finds a vulnerability in fwknopd, it doesn't matter whether fwknopd is collecting packets via UDP sockets or from libpcap (assuming we're talking about a vulnerability in fwknopd itself). The mere processing of network traffic is the problem.

So, why run fwknopd at all?

This is something of a long-winded answer, but I want to be thorough. I'll likely not settle the issue with this response, but it's good to start the discussion.

Starting with your example above with SSHD open to the world, suppose there is a vulnerability in SSHD. What does the exploit model look like? Well, an attacker armed with an exploit can trivially find the SSH daemon with any scanner, and from there a single TCP connection is sufficient for exploitation. I would argue that a primary enabling factor benefiting the attacker in this scenario is that vulnerable targets that listen on TCP sockets are so easy to find. The combination of scannable services + zero-day exploits is just too nice for an attacker. Several years ago I personally had a system running SSHD compromised because of this. (At the time, it was my fault for not patching SSHD before I put it out on the Internet, but still - the system was compromised within about 12 hours of being online.)

Now, in the fwknopd world, assuming a vulnerability, what would exploitation look like? Well, targets aren't scannable as you say, so an attacker would have to guess that a target is running fwknopd and the corresponding port on which it watches/listens for SPA packets [1]. Forcing an attacker to send thousands of packets to different ports (assuming a custom non-default port instead of UDP port 62201 that fwknopd normally watches) is likely a security benefit in contrast to an obviously targetable service. That is, sending tons of SPA exploit packets to different ports is a common pattern that is quite noisy and is frequently flagged by IDS's, firewalls, SIEM's, and flow analysis engines. How many systems could an attacker target with such heavyweight scans before the attacker's own ISP would notice? Or before the attacker's IP is included within one of the Emerging Threats compromised hosts lists? Or within DShield as a known bad actor? 10 million? How many of these are actually running fwknopd? I know there are some spectacular scanning results out there, so it's really hard to quantify this, but either way there is a big difference between sending thousands of > 100-byte UDP packets to each target vs. a port sweep for TCP/22.

Further, when a system is literally blocking every incoming packet [2], an attacker can't even necessarily be sure there is any target connected to the network at all. Many attackers would likely move on fairly quickly from a system that is simply returning zero data to some other system.

In contrast, for a service that advertises itself via TCP, an attacker immediately knows - with 100% certainty - there is a userspace daemon with a set of functions that they can interact with. This presents a risk. In my view, this risk is greater than the risk of running fwknopd where an attacker gets no data.

Another fair question to ask is about the architecture of fwknopd. When an HMAC is used (this will be the default in a future release), fwknopd reads SPA packet data, computes an HMAC, and does nothing else if the HMAC does not match. This is an effort to try to stay faithful to a simplistic design, and to minimize the functions an attacker can interact with - even for packets that are blindly sent to the correct port where fwknopd is watching. Thus, most functions in fwknopd, including those that parse user-supplied data and hence where bugs are more likely to crop up, are not even accessible without first passing the HMAC which is a cryptographically strong test. When libpcap is also eliminated through the use of UDP, not even libpcap functions are in the mix [3]. In other words, the security of fwknop does not rely on not being discoverable or scannable - it is merely a nice side effect of not using TCP to gather data from the network.

To me, another way to think of fwknopd in UDP mode is that it provides a lightweight generic UDP authenticator for TCP-based services. Suppose that SSHD had a design built-in where it would bind to a UDP socket, wait for a similar authentication packet as SPA provides, and then switch over to TCP. In this case, there would not be a need for SPA because you would get the best of both worlds - non-scannability [4] plus everything that TCP provides for reliable data delivery at the same time. SPA in UDP listening mode is an effort to bridge these worlds. Further, there is nothing that ties fwknopd to SSH. I know people who expose RDP to the Internet for example. Personally, I'm quite confident there are fewer vulnerabilities in fwknopd than something like RDP. Even if there isn't a benefit in terms of the arguments above in terms of service concealment and forcing an attacker to be noisy, my bet is that fwknopd - even if it advertised itself via TCP - would provide better security than RDP or other services derived from massive code bases.

Now, beyond all of the above, there are some additional blog posts and other material that may interest some readers:


[1] If an attacker is in the position to watch legitimate SPA packets from an existing client then this guesswork can be largely eliminated. However, even in this case, if fwknopd is sniffing via libpcap (so not using the UDP only mode), there is no requirement for fwknopd to be running on the system where access is actually granted. It only needs to be able to sniff packets somewhere on the routing path of the destination IP chosen by the client. I mention this to illustrate that it may not be obvious to an attacker where a targetable fwknopd instance runs even when SPA packets can be monitored. Also, there aren't too many attackers who are in this position. At least, the number of attackers in this position is _far_ lower than those people (everyone) who are in a position to discover a vulnerable service from any system worldwide with a single TCP connection.

[2] As you point out, in UDP-only mode, the firewall must allow incoming packets to the UDP port where fwknopd is listening. But, given that fwknopd never sends anything back over this port, it remains indistinguishable to every other filtered port.

[3] There are more things built into the development process that may be worth noting too that heighten security such as the use of Coverity, AFL fuzzing, valgrind, etc., but these probably takes us too far afield from the topic at hand. Also, there are some roadmap items that have not been implemented yet (such as privilege separation) that will make the architecture even stronger.

[4] Assuming a strong firewall stance against incoming UDP packets to other ports so one cannot infer service existence because UDP/22 doesn't respond to a scan but other ports respond with an ICMP port unreachable, etc.

NAT and Single Packet Authorization

$
0
0
People who use Single Packet Authorization (SPA) or its security-challenged cousin Port Knocking (PK) usually access SSHD running on the same system where the SPA/PK software is deployed. That is, a firewall running on a host has a default-drop policy against all incoming SSH connections so that SSHD cannot be scanned, but a SPA daemon reconfigures the firewall to temporarily grant access to a passively authenticated SPA client: SPA and basic SSH access This works well enough, but both port knocking and SPA work in conjunction with a firewall, and "important" firewalls are usually gateways between networks as opposed to just being deployed on standalone hosts. Further, Network Address Translation (NAT) is commonly used on such firewalls (at least for IPv4 communications) to provide Internet access to internal networks that are on RFC 1918 address space, and also to allow external hosts access to services hosted on internal systems.

The prevalence of NAT suggests that SPA should integrate strongly with it. Properly done, this would extend the notion of SPA beyond just supporting the basic feature of granting access to a local service. To drive this point home, and to see what a NAT-enabled vision for SPA would look like, consider the following two scenarios:

  1. A user out on the Internet wants to leverage SPA to access an SSH daemon that is running on a system behind a firewall. One option is to just use SPA to access SSHD on the firewall first, and then initiate a new SSH connection to the desired internal host from the firewall itself. However, this is clunky and unnecessary. The SPA system should just integrate with the NAT features of the firewall to translate a SPA-authenticated incoming SSH connection through to the internal host and bypass the firewall SSH daemon altogether: SPA and DNAT SSH access to internal host

  2. A local user population is behind a firewall that is configured to block all access by default from the internal network out to the Internet. Any user can acquire an IP on the local network via DHCP, but gaining access to the Internet is only possible after authenticating to the SPA daemon running on the firewall. So, instead of gaining access to a specific service on a single IP via SPA, the local users leverage SPA to gain access to every service on every external IP. In effect, the firewall in this configuration does not trust the local user population, and Internet access is only granted for users that can authenticate via SPA. I.e., only those users who have valid SPA encryption and HMAC keys can access the Internet: SPA and SNAT to external hosts
(A quick note on the network diagrams above - each red line represents a connection that is only possible to establish after a proper SPA packet is sent.)

Both of the above scenarios are supported with fwknop-2.6.6, which has been released today. So far, to my knowledge, fwknop is the only SPA/PK implementation with any built-in NAT support. The first scenario of gaining access to an internal service through the firewall has been supported by fwknop for a long time, but the second is new for 2.6.6. The idea for using SPA to gain access to the Internet instead of just for a specific service was proposed by "spartan1833" to the fwknop mailing list, and is a powerful extension of SPA into the world of NAT - in this case, SNAT in iptables parlance.

Before diving into the technical specifics, below is a video demonstration of the NAT capabilities of fwknop being used within Amazon's AWS cloud. This shows fwknop using NAT to turn a VPC host into a new gateway within Amazon's own border controls for the purposes of accessing SSH and RDP running on other internal VPC hosts. So, this illustrates the first scenario above. In addition, the video shows the usage of SPA ghost services to NAT both SSH and RDP connections through port 80 instead of their respective default ports. This shows yet another twist that strong NAT integration makes possible in the SPA world.



Now, let's see a practical example. This is for the second scenario above where a system with the fwknop client installed is on a network behind a default-drop firewall running the fwknop daemon, and the new SNAT capabilities are used to grant access to the Internet.

First, we fire up fwknopd on the firewall after showing the access.conf and fwknopd.conf files (note that some lines have been abbreviated for space):
[firewall]# cat /etc/fwknop/access.conf
SOURCE                      ANY
KEY_BASE64                  wzNP62oPPgEc+k...XDPQLHPuNbYUTPP+QrErNDmg=
HMAC_KEY_BASE64             d6F/uWTZmjqYor...eT7K0G5B2W9CDn6pAqqg6Oek=
FW_ACCESS_TIMEOUT           1000
FORCE_SNAT                  123.1.2.3
DISABLE_DNAT                Y
FORWARD_ALL                 Y

[firewall]# cat /etc/fwknop/fwknopd.conf
ENABLE_IPT_FORWARDING       Y;
ENABLE_IPT_SNAT             Y;

[firewall]# fwknopd -i eth0 -f
Starting fwknopd
Added jump rule from chain: FORWARD to chain: FWKNOP_FORWARD
Added jump rule from chain: POSTROUTING to chain: FWKNOP_POSTROUTING
iptables 'comment' match is available
Sniffing interface: eth3
PCAP filter is: 'udp port 62201'
Starting fwknopd main event loop.
With the fwknopd daemon up and running on the firewall/SPA gateway system, we now run the client to gain access to the Internet after showing the "[internet]" stanza in the ~/.fwknoprc file:
[spaclient]$ cat ~/.fwknoprc
[internet]
KEY_BASE64                  wzNP62oPPgEc+k...XDPQLHPuNbYUTPP+QrErNDmg=
HMAC_KEY_BASE64             d6F/uWTZmjqYor...eT7K0G5B2W9CDn6pAqqg6Oek=
ACCESS                      tcp/22  ### ignored by FORWARD_ALL
SPA_SERVER                  192.168.10.1
USE_HMAC                    Y
ALLOW_IP                    source

[spaclient]$ nc -v google.com 80
### nothing comes back here because the SPA packet hasn't been sent yet
### and therefore everything is blocked (except for DNS in this case)
[spaclient]$ fwknop -n internet
[spaclient]$ nc -v google.com 80
Connection to google.com 80 port [tcp/http] succeeded!
Back on the server, below are the rules that are added to grant Internet access to the spaclient system. Note that all ports/protocols are accepted for forwarding through the firewall, and an SNAT rule has been applied to the spaclient source IP of 192.168.10.55:
(stanza #1) SPA Packet from IP: 192.168.10.55 received with access source match
Added FORWARD ALL rule to FWKNOP_FORWARD for 192.168.10.55 -> 0.0.0.0/0 */*, expires at 1429387561
Added SNAT ALL rule to FWKNOP_POSTROUTING for 192.168.10.55 -> 0.0.0.0/0 */*, expires at 1429387561
Conclusion
Most users think of port knocking and Single Packet Authorization as a means to passively gain access to a service like SSHD running on the same system as the PK/SPA software itself. This notion can be greatly extended through strong integration with NAT features in a firewall. If the SPA daemon integrates with SNAT and DNAT (in the iptables world), then both internal services can be accessed from outside the firewall, and Internet access can be gated by SPA too. The latest release of fwknop supports both of these scenarios, and please email me or send me a message on Twitter @michaelrash if you have any questions or comments.
Viewing all 49 articles
Browse latest View live




Latest Images