Whilst looking for interesting detects to analyse from www.incidents.org/logs/Raw, I came across the Snort "BACKDOOR Q access" alert and was fascinated by the strange packets. As far as I could tell, nobody else from the IT security community had taken a really good look at Q and published their findings as yet, despite various versions of Q having been around since 1999. My goal for this paper was to investigate Q's capabilities, assess the risk posed by this software, see whether the existing standard Snort signatures and those at www.whitehats.com are in fact adequate, and suggest new signatures which may perhaps be more effective. I will be concentrating on Q's network traffic behaviour in order to develop more effective NIDS detection capability. It's beyond the scope of this paper to detail Q's behaviour and how to identify/locate Q binaries on the compromised host itself.
I investigated versions 0.9, 1.0, 2.0 and 2.4, however I concentrated mainly on versions 1.0 and 2.4, since 1.0 is simply a bug-fixed version of 0.9, and 2.4 is an evolution of 2.0 and I couldn't get the version 2.0 client/server pairs to establish a session. There will be two types of Q traffic that we'll be examining. One is the one-way traffic that is sent by "qs", the Q stealth messenger to "qd", the Q server daemon, and the other is the encrypted remote-shell session traffic. We'll also briefly touch on a bounce/redirector or port-forwarder session.
All testing was conducted using two Red Hat Linux 7.3 and one Windows XP Professional Virtual Machines running under VMware Workstation 3.2/3.3 and confined to their own virtual ethernet network (192.168.2.0/24). The host operating system was Windows XP Professional. Tcpdump version 3.6 with libpcap 0.6 was used to capture the network traces.
What is Q? A brief run-down
Q is a primarily Unix-based remote-access tool that provides stealth capabilities to make it's presence less obvious both on the host, and in network traffic. The product could conceivably be used by sysadmins, but I think it's far more likely to appeal to those with less pure motives. The latest version at time of writing (2.4) may be able to be compiled and run on W32 systems as well, although I didn't try this myself. All versions of Q are compiled as a client/server pair. Different client/server pairs cannot establish usable sessions with each other by default. "qd" is the server portion of Q. "qs" is used to send covert messages to the qd server. These messages are used to remotely execute privileged commands, invoke single-use encrypted remote shell processes, and to set up port redirection or "bounce" servers on the target host.
Q has evolved over a number of years and seems to have been developed more or less in parallel with the ubiquitous Tribe Flood Network (TFN) and TFN2K Distributed Denial of Service software. All of these are the work of Mixter , and claim to be proof of concept - the idea being to scare IT security folk into taking system security more seriously and relying less on perimeter defences. Mixter points out quite rightly that there are more capable tools than the ones he has made public that are being developed and used privately. The only problem is, that making this code public has encouraged another whole demographic - the "script kiddie" - to make use of it. The stealth messaging concept used by TFN has also been used in Q, but expanded upon by adding TCP and UDP-based messages as well as ICMP. TFN2K later went on to use this expanded capability also. David Dittrich performed a great analysis of TFN and Jason Barlow and Woody Thrower did the same for TFN2K . I could find no previous analysis of Q specifically, and referred mainly to the documentation (and source) available on Mixter's web-site in addition to my own testing and observation whilst writing this paper. I'll begin by discussing v1.0, touch on v2.0 and then move on to v2.4, and will describe notable differences.
Versions 0.9 and 1.0 - Overview
v0.9 and v1.0 are virtually identical, apart from a few minor bug-fixes. The Q v1.0 software is comprised of several components:
The qd server uses raw sockets to watch all TCP, UDP and ICMP traffic sent to the host it's running on, and accepts traffic that it recognises as having been generated by qs. It doesn't care what destination port is used, nor does it care which protocol is used. This type of "sniffing" of packets is different to having the network adapter listen to all traffic on the wire in promiscuous mode. qd only sees traffic addressed to the host that qd is running on, at layer 3, and only for the 3 IP protocols already mentioned.
Figure 1 - Standard Q v1.0 conf.h file
The standard conf.h file shown in Figure 1 defines things like the static IP ID value used (12345 is the default), the type of shell to execute for remote sessions, the user-id to use for the session bouncer/redirector, whether syslog logging of Q sessions is enabled or not, what names to disguise the Q processes as, and what "code" numbers to use for activating Q's various capabilities (these act like passwords). Note the line beginning with "#error". The software will not compile until you remove this line - this is to encourage the default values in this file to be changed.
Figure 2 - qs usage message
The qs usage message in Figure 2 shows us some of the capabilities of this software. qs is used to send crafted "stealth" messages to "qd" using raw sockets (SOCK_RAW), that are a reasonable facsimile of what normal TCP, UDP or ICMP packets look like. In this version, TCP is the default protocol used. Assuming that you have managed to install a compatible qd on the target, you can use qs to execute commands on the target as root or instruct qd to spawn a listener process which can be either a Q secure shell, or a Q session bouncer that will redirect your session to a 3rd party.
Versions 0.9 and 1.0 - Control / Activation
Figure 3 - qs v1.0 control message using TCP
Figure 3 is tcpdump output (using "tcpdump -nnvvX") of the network traffic resulting from the execution of the shown qs command. Note that the payload is clear text - i.e. not encrypted. Later versions do not have this weakness. Note also the bad tcp checksum. I feel that this is in fact by design, rather than a bug. Having an incorrect checksum here means that the regular TCP at the receiving end will not process the segment, believing it to be corrupt. Instead it will be dropped quietly. This doesn't bother qd, because qd watches for all TCP traffic using SOCK_RAW and will accept and process this packet. This behaviour prevents the target machine from generating TCP RST artefacts back to the spoofed source. Another odd characteristic of this generation of qs is that it always sets one of the TCP reserved bits in the high-order nibble (the relevant nibble is bolded and underlined in Figure 3). This may just be a bug or it may serve some other purpose (My C programming skills were too rudimentary to work it out). Other general characteristics relevant to the TCP packets are that the TCP ACK bit is always set, and the TCP sequence, acknowledgement number and window size are always randomly generated values.
Figure 4 - qs v1.0 control message using UDP Figure 4 shows us the tcpdump trace of the same qs command, but using UDP as the transport. Again, the checksum value is incorrect, by design. The payload is much the same as for the TCP packet. We have a different random source IP address this time and all of the other tell-tale characteristics of the qs-generated IP packet are there - The IP ID is fixed to the value set in the file "conf.h" shown back in Figure 1; the IP TTL is always 240 and the IP Type Of Service field is always zero (both defined in "forge.c"). Unfortunately, since UDP is such a simple protocol, there are no obvious flaws from which a reliable Snort NIDS signature could be drawn.
Figure 5 - qs v1.0 control message using ICMP
In figure 5, we look at an ICMP packet generated by qs v1.0. All the usual unchanging values are there in the IP header, and for ICMP we note that qs uses an ICMP echo reply (code 0, type 0). This type of packet should never draw a reply from the recipient, but we still note that the ICMP checksum is incorrectly calculated. Later versions of qs do in fact calculate this correctly. Something interesting here is that the ICMP echo reply identifier or sequence number fields are both zero. According to W. Richard Stevens , "As with other ICMP query messages, the server must echo the identifier and sequence number fields" and "The sequence number starts at 0 and is incremented every time a new echo request is sent". So, the sequence number could be zero if this were the 1st packet of a ping, but what are the chances that the identifier would also be zero? On a Unix system, this is set to the process ID of the sending process - others may generate a unique random value. Examining the payload, the 1st thing we see is "31". This tells qd that qs wants it to specify that encryption is required for any shell processes it spawns. If encryption is not required, we'd see a "30" here instead. Next we see "20" (space character), which is simply the delimiter. Following that we see "31303238", which is hex for the ASCII characters "1028" - the port number that we specified on the qs command-line using the option "-p".
Versions 0.9 and 1.0 - Remote Shell Request & Session
Assuming that we had a compatible version of qd running on 192.168.2.128 and that at least one of these packets made it through the site's defences, we should now have a Q encrypted shell process listening on port 1028. Let's now take a look at one of these sessions through the eyes of tcpdump and connect to our target - refer to Figure 6. We need to enter an encryption key - the same one (min 8 characters) that is prompted for at compile time.
Figure 6a - Connecting to a Q secure shell process using Q v1.0
Note that in the interests of brevity, I've removed superfluous ACK packets. The first exchange we see in Figure 7 is the familiar TCP 3-way handshake. Next is our command "id", AES encrypted and base-64 encoded. Following is the returned response that you can see in Figure 6a, also encrypted and base-64 encoded. There are a few things to note here. Raw sockets are not used for these sessions. This is the normal TCP/IP stack. Note the incrementing IP ID values, matching sequence & acknowledgment numbers etc. The 2nd thing is that base-64 encoding results in ASCII output, and trailing nulls become 'A's. This is a weakness and a potential signature, although in the absence of other defining characteristics, the likelihood of false positives is fairly high. Another thing is that since these sessions use the standard TCP/IP protocol stack and real TCP sessions, we can learn a lot about the end-points by using passive fingerprinting techniques, such as matching up TCP options, TCP window sizes, guessing initial TTLs and so on. We can also be fairly certain that the source IP used has not been spoofed, although it also likely that this IP doesn't belong to the attacker and is just one in a long chain of session "bouncers" and open proxies used to hide the attacker's actual location.
Figure 6b - Connecting to a Q secure shell process using Q v1.0 - tcpdump trace
Next we look at the encrypted payload from three different sessions. All sessions have the same payload. The 1st two are by the same client/server pair, and the 3rd is generated by a different client/server pair, using a different encryption key.
Figure 7 - Payload from two Q sessions using the same encryption key
Figure 8 - Payload from a Q session using a different encryption key to those in Figure 7
The results displayed in Figure 7 and 8 suggest that the encryption algorithm used by Q v1.0 will generate the same hash repeatedly, given the same input. This is a possible weakness, although in reality it would not be trivial to exploit. It may be possible to brute force the encryption key if one knew the encryption algorithm used and what the unencrypted string was, however with a strong key (min 8 characters by default) this could take some doing.
Versions 0.9 and 1.0 - Session Redirection / Bouncer Request
Refer to Figure 9 to see what a request for a session "bouncer" looks like. The "-p" option specifies the port that the session bouncer should listen for connections on and the "-B "192.168.1.1 23" option specifies that the session will be redirected to 192.168.1.1, port 23. The session between this host and the host running the session bouncer can be encrypted (not in this case, because I specified "-n"), whereas the session traffic bounced from that server to the ultimate target, is never encrypted.
Figure 9 - Requesting a session "bouncer" using qs v1.0 - command/output + tcpdump trace
Referring to Figure 9, note that the "30" indicates a request for an unencrypted shell, "20" is the command parameter delimiter, "383838" indicates that the session redirection server should listen on port 888, and the subsequent space-delimited parameters "23" and "192.168.1.1" indicate the port and IP address of the 3rd party target to which the session is to be forwarded.
Versions 0.9 and 1.0 - Remote Command Execution Request
Finally, in Figure 10, you will see a qs request to execute a command on the target (192.168.2.128) server running qd. Note that there is no encryption of the payload.
Figure 10 - Requesting remote command execution with qs v1.0 - command/output + tcpdump trace
Versions 2.0 - Overview
Version 2.0 sees an almost complete re-write of this software. Mixter has produced a library called libmix (libmix-v107 comes with Q-2.0), which is a collection of functions designed specifically for crafting TCP, UDP and ICMP packets using raw IP. It also provides cryptographic and other general functions. libmix is also used by the ubiquitous TFN2K or Tribe Flood Network 2000. In fact, the functions used by qs and qd to communicate (still one-way, of course) in V2.x are even called "tfntransmit" and "tfnread". These functions now incorporate the ability to encrypt the payload of qs packets. Since v2.0, what used to be the Q client 'Q' is now 'q'. q can run qs for you, rather than it having to be a separate step as before. "transd" is now built into 'q'. Version 2.0 incorporates Mixter's own challenge authentication scheme "CSA". Q v2.x generates a random "auth number" automatically in the file hash.h at compile time. You are strongly encouraged to make a note of these credentials, and then remove that file. If you need to connect to a server that was compiled with a different auth number than your q client, then you can supply the number with the command-line option '-s'.
With regards to protocol header characteristics for packets generated by qs v2.0, they appear to be identical to those generated by v2.4. Shell sessions use the normal TCP/IP stack and should follow the standard rules for that protocol as implemented by the Operating System they're running on. It's now easier to choose a different encryption algorithm. From "q.h":
/* AES Algorithm, one of: CAST256, MARS, SAFERP, TWOFISH, RIJNDAEL */
#define Q_ALG SAFERP
Versions 2.4 - Overview
This release changes from CSA to RSA style authentication for remote shell and session bouncer sessions, introduces Mixter's own SSL-style protocol, "iSSL" and uses Rijndael encryption. RSA bit strength is 4096 bits by default, although this can be reduced (minimum is 1536) to improve performance. Versions of Q prior to 2.4 prompted for an encryption key at compile time. That's now optional and not required by default. The README file for v2.4 gives a inkling that since version 2.2, Q may compile and run on W32 systems as well as Unix and describes the extensive security and privacy features incorporated in the latest publicly available version (2.4):
Tunneling version release by zer0. Incorporated changes and win32 compatibility fixes from zer0
....Control packets contain double AES encrypted data and are authenticated with an authentication token that is not sent over the network in plaintext. The server has the ability to log all incoming queries to syslog........ Client/server sessions (encrypted redirection and interactive shells) are AES encrypted and authenticated with both authentication and a password. The Q program suite uses CSA, a password challenging method, which determines the password out of a secure one-way hash, and the highly secure RSA with for establishing longer shell/bouncer sessions. Temporary, changing strong RSA keys ensure that connections cannot be eavesdropped easily.....
Figure 11 - standard Q "conf.h" file
Let's begin by referring to Figure 11 and looking at the standard "conf.h" file for Q v2.4. This time there is nothing which forces you to change any defaults, but any respectable hacker would want to disable messages being generated to syslog and probably wouldn't want any files named ".q" containing the Q daemon's process ID created. :) Almost all protocol header fields used in packets generated by executing qs are now randomly generated, so no IP ID value is statically defined here this time. Extra CODE_* values hint at extra functionality. Refer to Figure 12 for a look at the usage message:
Figure 12 - qs v2.4 usage message
qs now allows you to specify the spoofed source IP address of control packets sent to activate servers or execute remote commands. By default, they are randomly generated. The protocol used is now randomly chosen between TCP, UDP and ICMP, unless otherwise specified. This version (and 2.0) seems to have a bug which prevents you from selecting a protocol of your own choosing - you are stuck with the random choice. As well as executing remote commands using the shell predefined in the "conf.h" file, you can now specify what remote program to use as your remote shell using qs.
Version 2.0 and 2.4 - Control / Activation
Refer to the command shown in Figure 13 - because I was unable to get the "-i" option working, I simply executed the same command repeatedly. As the default is to select a protocol at random, I eventually ended up with samples of each - refer to Figures 13-16.
Figure 13 - qs v2.4 request to spawn a remote encrypted shell - command/output
In figures 14 and 15, notice that we still have the now familiar incorrectly calculated checksums for TCP and UDP, but in Figure 16, the ICMP checksum is now calculated correctly. This is probably because an ICMP echo reply should never elicit a response, regardless of the state of the checksum, whereas TCP and UDP would likely reply to the spoofed source address.
Figure 14 - qs v2.4 request to spawn a remote encrypted shell (TCP) - tcpdump trace
In figure 14, note that the TCP header length field is always set to zero. This is a useful signature, although it's probably easy enough for a seasoned coder to correct this flaw. Looking at the c code, I don't think this behaviour was intentional. In this particular example, we ended up with TCP ACK and Window sizes of zero, however, most header fields for raw IP control packets generated by 'qs' are now randomly generated, including Source IP address, IP ID (>=1024), initial TTL (>=200), presence or absence of TCP SYN and/or ACK flags, TCP (and UDP) source and destination ports, TCP Sequence and Acknowledge numbers, ICMP ID and sequence numbers (>=0). The algorithm is not clever enough to take into account that it's ok to have, for instance a TCP acknowledgment number of zero if the TCP SYN flag is set, but not if there is no SYN flag set, and so on. Every now and then, inappropriate values are generated for fields. It's possible to draw "all ones" and "all zeros" values for many fields, including the spoofed source IP address.
Figure 15 - qs v2.4 request to spawn a remote encrypted shell (UDP) - tcpdump trace
In Figures 14-16, note that a portion of the encrypted payload is always the same, at least for this client/server pair using this particular encryption algorithm. The encrypted result will change for different client/server pairs, compiled using different randomly generated auth IDs and encryption keys, and also where different encryption algorithms to the default (SAFERP) are specified.
Figure 16 - qs v2.4 request to spawn a remote encrypted shell (ICMP) - tcpdump trace
In Figure 16, note that we have drawn an ICMP echo reply identifier value of zero, and a rather large ICMP echo sequence number of 0x2671 (decimal 9841). Anomalies such as this are likely the best way to catch this version of Q out.
Version 2.0 - Remote Shell Request
Version 2.0 encrypts the payload of control packets and the only thing to note in the payload is that for any given content, given the same encryption scheme and key, the same payload is generated repeatedly, regardless of the protocol used i.e. TCP, UDP or ICMP. Also, Mixter no longer uses base-64 encoding (so no trailing 'A's). The protocol-header characteristics and anomalies are identical to v2.4.
Version 2.4 - Remote Shell Request & Session
Figure 17a examines a session establishment using 'q'. As with version 1.0, notice that this is a "normal" TCP connection, NOT using raw sockets, and that all the usual rules are followed i.e. incrementing IP ID values etc. Passive O/S fingerprinting and identification of the source is possible. During this establishment phase, we see the exchange of a 4096 bit hash of the encryption key. The highlighted data would appear to be a protocol header for the key exchange mechanism and a potential candidate for a NIDS signature - we'll see how much this data changes later, from algorithm to algorithm and depending upon the bit-strength chosen for the hash.
Figure 17a - 'q' 2.4 encrypted session establishment - command/output + tcpdump trace
Figure 17b is a trace of actual data transfer from a Q v2.4 encrypted shell session - sending across a Unix "id" command and receiving back the result. The data is of course encrypted and there don't appear to be any opportunities for NIDS signature development here.
Figure 17b - 'q' 2.4 encrypted session - command/output + tcpdump trace
Version 2.4 - Session Redirection / Bouncer Request and Session
Next we set up a Q2.4 session bouncer/redirector. This will spawn a port listener process on our target (192.168.2.128 - the one running qd) and redirect any sessions on to a 3rd party (192.168.2.1). Firstly, we set up a netcat shell on 192.168.2.1 using the command "nc -l -p 23 -t -e cmd.exe". Next, we request that qd spawn the session bouncer - refer to Figure 18 for the syntax. The tcpdump trace has been omitted this time, as the content is well encrypted and adds nothing more to this discussion.
Figure 18 - Requesting a session bouncer/redirector using qs v2.4
Moving on, Figure 19 shows the syntax for establishing the bounced session (to 192.168.2.1 port 23) via 192.168.2.128 port 888. 192.168.2.128 is a Red Hat Linux 7.3 host and 192.168.2.1 is obviously Microsoft Windows XP. Notice that the packets sent to port 888 on 192.168.2.128 are indeed forwarded on to 192.168.2.1 port 23, and replies follow the same path. Traffic between the Q client and server is encrypted. This would be a very useful hacker's tool, allowing our villain to establish a long chain of encrypted, bounced sessions with ease to help maintain anonymity and lessen the risk of being traced and caught. I have noticed though, that the session is prone to producing some pretty serious corruption, and needs further debugging to be entirely useful for complex tasks.
Examining the tcpdump trace, you will see a familiar pattern emerging during the authentication phase. Concentrating on the payload starting at packet offset 0x34, you initially see the client send what appears to be a 24 byte header "8000 0000 8000 0000 8000 0000 0000 0000 0000 0000 0000 0000" to the server (followed by 512 bytes of encrypted data). This header is echoed back in the reply. Next, the client sends another header "0100 0000 0100 0000 0100 0000 0000 0000 0000 0000 0000 0000" along with "1100 0000". All of this is echoed back unchanged. The next exchange from client to server sends the header "0001 0000 0001 0000 8000 0000 0000 0000 0000 0000 0000 0000" along with 1024 bytes of additional data (probably the hashed encryption key). In this case though, the response header returned is "0500 0000 0500 0000 0500 0000 0000 0000 0000 0000 0000 0000", along with 20 bytes of additional data. This looks to be the best opportunity yet for development of NIDS signatures, so long as some portion of these exchanges is repeatable when different RSA bit strengths and different hashing algorithms are used. We'll look into that next.
Figure 19 - Q v2.4 redirected session command/output + tcpdump trace
Version 2.4 - RSA-Style Session Authentication
During the authentication phase of a Q2.4 encrypted session, the content of the 1st exchange header seems to depend upon the RSA bit strength selected via "#define Q_RSABITS" in the "conf.h" file. The examples in Figures 17a and 19 used the default of 4096. Using the minimum value of 1536 with any algorithm produced the following header values: "3000 0000 3000 0000 3000 0000 0000 0000 0000 0000 0000 0000". Basically, all the 8's are now 3's instead. The 2nd exchange from client to server always uses the following values, regardless of hashing algorithm or bit strength used: "0100 0000 0100 0000 0100 0000 0000 0000 0000 0000 0000 0000 1100 0000". This is a definite signature candidate, but if this exchange is in fact based on a standard RSA key-exchange protocol, we may have some false-positives as a result, but this may be unavoidable and acceptable - especially at sites that don't actually make legitimate use of the mechanism. The reply from server to client in the 2nd exchange is sometimes the same as the header sent from client to server, and other times it varies - it's beyond the scope of this analysis to determine the reasons why, but it doesn't seem to be a good candidate for a signature at any rate.
The header content for the 3rd client to server exchange varies depending upon the RSA bit strength specified, and doesn't appear readily decipherable The reply from server to client for the 3rd exchange however, appears to always be "0500 0000 0500 0000 0500 0000 0000 0000 0000 0000 0000 0000 0000" + 20 bytes of hashed data, regardless of protocol, RSA bit strength specified, or any other variable.
Assessment of Threat
Although Q is not a Trojan out of the box, it could easily be packaged up and deployed as such via email, IRC and so on. This utility however is more likely to be used as part of a hacker's root-kit and deployed as a fairly secure back-door means of accessing an already compromised system. Q is able to disguise its process-names, and uses techniques to communicate from client to server that make it difficult to detect with signature-based NIDS. Particularly in later versions, payloads are well encrypted and would make it impossible for NIDS to monitor malicious traffic that uses Q as a tunnel. Q can also set up session redirection services on a compromised target and use this as a staging point for further attacks. I'd rate the threat from this software as quite high, especially as later versions may be able to run on W32 platforms. The greater threat is not so much from Q itself, but from the techniques it uses to evade NIDS and packet filters. These techniques and others that haven't yet been leaked to the public but are in active use privately, constitute the major threat. We must recognise the need for mechanisms to detect traffic making use of stealth techniques such as these and most of all we must embrace the idea of "Security in Depth".
Currently Available Snort Signatures
From arachNIDS :
arachNIDS has a separate rule for each of the 3 protocols that Q control / activation packets use: TCP, UDP and ICMP. They all look for traffic with a source address of 255.255.255.255, any source port, any destination IP address bound for the internal network and any destination port. The payload has to be greater than 1 byte. Additionally, for TCP traffic, the ACK flag only must be set, and for ICMP traffic, the ICMP type must be zero. These signatures are inadequate for a number of reasons. Q always defaults to generating a random source IP address, so these signatures will only catch a pitifully small number of Q control packets, unless the intruder is bold enough to actually specify 255.255.255.255 as the spoofed source address - and this is only possible pre-Q 2.0 versions. Another problem is that Since Q 2.0, the presence or absence of the TCP ACK flag is determined at random, and the same goes for a SYN. These factors further diminish the chances of these rules catching out Q control/activation packets for Q versions >= 2.0.
The standard Snort rules that pertain to Q, found in the "backdoor.rules" file are:
The standard Snort rules for Q suffer a similar problem to their arachNIDS cousins. They specify a source address that could range from 255.255.255.0 to 255.255.255.255, which does increase the chances of catching a randomised source IP address, but it's still much more likely to ignore real Q traffic than it is to alert on it. The standard Snort rules do not include a rule for UDP. The two rules that do exist both expect a payload greater than one byte in length and the rule for TCP specifies that the ACK flag (+ optionally, any other flags) need to be set in order for traffic to trigger those rules. Due to using "flags:A+", the standard Snort TCP rule will catch more instances of Q control traffic than the ArachNIDS equivalent, as it allows for the possibility of a SYN also being set, but doesn't account for the possibility of only a SYN being set.
Issues regarding signature development for Q
All of these rules concentrate on a subset of possible Q control / activation traffic only and fail to consider active Q sessions. This is probably because finding anything to trigger on for versions of Q prior to 2.0 was quite a challenge and Snort is currently not flexible enough to be able to check all of the required protocol header fields for control traffic. Q 2.4 however presents several possibilities, due to its use of the RSA authentication scheme.
Another problem I have discovered whilst testing the Snort rules above, is that none of the above rules that specify TCP as the protocol will ever trigger for Q 2.x control / activation packets that are based on TCP. This is because the TCP header-length field is always set to zero in Q 2.x and this confuses Snort - it doesn't know where the TCP header should end. This highlights one of the biggest failings of signature-based IDS today - dealing with software that doesn't follow the rules. What we need to remember here, is that Q's stealth messenger "qs" sends data in a format that resembles TCP, UDP, or ICMP, but which in reality is none of these, and Snort doesn't currently appear to be able to cater for this.
Next, I'll discuss what is required to be able to trigger an alert for major categories of Q traffic and suggest a few signatures where this is possible. Please note, that due to time and resource constraints, it was not possible to production test these rules, so they should be trialled with a fair degree of caution, in case they produce a lot of false-positives.
NIDS signature strategies - Q Activation / Control - TCP-based
Snort is not capable of checking for the required TCP reserved bits, and so an effective Snort compatible signature cannot, at the time of writing, be developed for this type of packet. The bits that I'm talking about are illustrated in Figure 20, bolded and with a red border. The capability to check for static values and non-zero values, in all of the protocol header fields is required to detect anomalies such as these, which are tell-tale signs of packet crafting. I thought I might be able to get around the problem by using the snort "content", "offset" and "depth" keywords with an "alert ip" rule and thereby check for values in the malformed TCP header, but Snort doesn't appear to support the use of the "content" keyword with "alert ip" - it silently ignores them.
Figure 20 - High-order TCP Reserved bits
For qs versions 2.0 and 2.4, the TCP header-length field is always zero, but Snort cannot check for this. If it could, this would be an excellent signature. As it is, no packet that has this field set to zero will trigger any Snort TCP signature whatsoever. This is a huge problem, and right this moment may be used by the bad guys to evade the Snort IDS and perhaps others also. The work-around is to use "Alert IP" instead of "Alert TCP" and run a separate Snort process using BPF filters, with its own bare-bones configuration file and a special rules file for q control / activation packets. This strategy will catch all TCP-based Q control packets, except for "qs -B" (request for session bouncer) traffic in Q 0.9/1.0, which for some reason doesn't set any of the high-order TCP reserved bits. Do as follows:
1) Create the file "/etc/snort/snort-q.conf" with the content:
2) Create the file "/etc/snort/q-control.rules" as per Figure 21.
3) Run another instance of snort using the command:
# snort -c /etc/snort/snort-q.conf -A full -q -l snortlog-q "(tcp & 0xf0 = 0 or tcp & 0x0f != 0)"
This strategy will produce alerts similar to those shown in Figure 22. If you wanted to be doubly sure that you had Q 0.9/1.0 control packets, you could set up Snort rules to search for content, like "(content: "|3120|" depth: 2)" and "(content: "|3020|" depth: 2)" to cater for the possibility of a command requesting encryption or no encryption for a shell (refer to Figure 3). One must remember, though that when qs 0.9/1.0 requests that a single shell command be executed, there will be no "3120" or "3030" preceding the command (refer to Figure 10).
Figure 21 - Suggested rules file to catch many TCP-based Q control messages
Figure 22 - Snort output generated by rules in Figure 21
One final possibility is if the IDS could calculate and confirm the TCP checksum, which is always invalid for Q control/activation packets. Snort doesn't have this ability in IDS mode.
NIDS signature strategies - Q Activation / Control - UDP-based
Q UDP-based control/activation packets have nothing unusual about them in any version, except that it's possible that the source or destination port could sometimes be zero, or rarely, the source IP could be 255.255.255.255 or even 0.0.0.0. Other standard Snort rules, such as "BAD TRAFFIC udp port 0 traffic" should hopefully alert on the anomalous ports. The existing arachNIDS rule "TROJAN-ACTIVE-Q-UDP" will account for the 255.255.255.255 address, but there are plenty of other anomalous addresses that it could choose at random. The best bet is probably to set up rules that check for external sources that are IANA reserved / RFC1918 private addresses + some RFC3330 special-use addresses and alert on these (better still, just block them at the perimeter). A list of reserved blocks can be found here (entries marked "IANA - Reserved"): http://www.iana.org/assignments/ipv4-address-space. RFC3330 can be found here: http://www.landfield.com/rfcs/rfc3330.html. These can be set up in the "snort.conf" file and an appropriate rules file as per Figure 23, although I'm not sure what sort of performance detriment this would introduce, as the list is lengthy. One other catch is that as IANA allocates more address-blocks to organisations, this list will need to be updated, so as not to deny service to potentially legitimate users. The other detection possibility is if the NIDS were capable of checking the validity of the UDP checksum, which is always invalid on Q control/activation packets. Snort IDS doesn't support this.
Figure 21 - Suggested Snort configuration for alerting on invalid Source IP addresses
NIDS signature strategies - Q Activation / Control - ICMP-based
The two older versions of qs tested (0.9, 1.0) were able to specify the ICMP type and code, but regardless of the ICMP types or codes used, the fields that would be the ICMP echo request/reply identifier and sequence fields are always set to zero. The identifier field at the very least should have a non-zero value. This can be tested for in snort using the rule option "icmp_id:0". Versions 2.0 and 2.4 do not allow the option to choose ICMP type or code, and always default to type 0, code 0 (echo reply) and randomly generate the identifier and sequence numbers, but do seem to generate a zero identifier quite often, so checking for this is better than nothing. The older versions of qs generate packets with invalid ICMP checksums. If the IDS were capable of confirming this value, this could be checked for. Versions of qs >= 2.0 calculate a valid checksum. Another problem with the standard Snort rules is if you have "icmp-info.rules" enabled, Snort will alert with "[**] ICMP Echo Reply [**]" before it can match any local rules that you may have set up using "icmp_id:0" in "local.rules", because by default, "local.rules" is included last of all. I suggest moving the "include" for "local.rules" to somewhere near the top of the list in "snort.conf".
NIDS signature strategies - Q Encrypted Sessions (All real TCP)
For the earlier versions of Q (using the 'Q' binary) all you can really do is look for strings of trailing 'A's, but this is likely to result in an unacceptable number of false positives. The payload is encrypted and the protocol is capable of tunnelling other traffic, SSH-style, so this is a big issue. The best defence is prevention, by making sure systems are well-patched and that all network and host-based access-controls are as tight as possible, and use host-based IDS to look for signs of unauthorised activity and violations of system integrity. I was not able to get a session working on Q2.0, but was able to capture some authentication packets and could find nothing useful as a signature. Version 2.4 does offer some interesting possibilities with regards to signatures in the session authentication process though. The string that seems to come up the most is the one that appears during the 2nd exchange of authentication data - "0100 0000 0100 0000 0100 0000 0000 0000 0000 0000 0000 0000 1100 0000", closely followed by the last packet sent from server back to client, which seems to indicate acceptance of the client connection - "0500 0000 0500 0000 0500 0000 0000 0000 0000 0000 0000 0000", although this does seem to vary. The snort rules could look something like those in Figure 22.
Figure 22 - Snort rules to alert on Q 2.4 authentication data
In Figure 23, I present some general rules that I used whilst testing, that would assist in picking up traffic with anomalous Source IP Address or invalid TCP header-field value combinations. Note that the rules that are commented out use syntax not currently supported by Snort, but which I feel ought to be included.
Figure 23 - Snort rules to alert on invalid addresses and header field combinations
If there is a lesson to be learned from this paper, it is that you cannot safely assume anything. You cannot assume that just because you have implemented a network based IDS, that you can be backward with patching, or that the IDS will even report on the types of malicious traffic that you expect. You cannot assume that IDS signatures are always correct, or will work as you expect. You cannot assume that traffic which on the surface looks to be innocent is not in fact malicious. You must not underestimate the ingenuity of the bad guys.
Q is a potentially very capable back-door program that makes use of several techniques that make its traffic difficult to detect using signature-based IDS. In addition, this study has revealed a number of shortcomings in Snort's rule options which make it more difficult and inconvenient than it ought to be to look for certain types of packet crafting, and as a result, make it quite simple to evade this NIDS in the scenario presented here. These will no doubt be addressed in future versions once I make the developers aware of the issue. The real danger is perhaps not from Q itself, but from other private software which makes use of similar "stealth" techniques which we don't have signatures for, or for which simple pattern-matching signatures cannot be developed, due to the nature of the traffic.
AES. "Advanced Encryption Standard - Questions and Answers." Jan. 28 2002.
URL: http://csrc.nist.gov/encryption/aes/ (Aug. 28 2002)
Barlow & Thrower. "TFN2K - An Analysis." Mar. 7 2000.
URL: http://packetstormsecurity.nl/distributed/TFN2k_Analysis-1.3.txt (Aug. 18 2002)
Dittrich, David. "The "Tribe Flood Network." distributed denial of service attack tool". Oct. 21 1999.
URL: http://packetstormsecurity.nl/distributed/TFN2k_Analysis-1.3.txt (Aug. 18 2002)
IANA. "INTERNET PROTOCOL V4 ADDRESS SPACE." IANA Assignments. Oct. 25 2002
URL: http://www.iana.org/assignments/ipv4-address-space (Oct. 29 2002)
Internet Assigned Numbers Authority. "INTERNET PROTOCOL V4 ADDRESS SPACE." Aug. 6 2002.
URL: http://www.iana.org/assignments/ipv4-address-space (Oct. 20 2002)
Internet Society, The. "RFC3330 - Special-Use IPv4 Addresses." Sep. 2002
URL: http://www.landfield.com/rfcs/rfc3330.html (Oct. 29 2002)
Mixter. "README." and C source code. Q 0.9 source distribution. Apr. 14 2001.
URL: http://mixter.void.ru/Q-0.9.tgz (Aug. 6 2002)
Mixter. "README." and C source code. Q 1.0 source distribution. Apr. 14 2001.
URL: http://mixter.void.ru/Q-1.0.tgz (Aug. 6 2002)
Mixter. "README." and C source code. Q 2.0 source distribution. Apr. 14 2001.
URL: http://mixter.void.ru/Q-2.0.tgz (Aug. 6 2002)
Mixter. "README." and C source code. Q 2.4 source distribution. Apr. 14 2001.
URL: http://mixter.void.ru/Q-2.4.tgz (Aug. 6 2002)
Mixter. "README." and C source code. TFN source distribution. Aug. 20 2001.
URL: http://mixter.void.ru/tfn.tgz (Aug. 28 2002)
Mixter. "README." and C source code. TFN2K source distribution. 14 Apr 2001.
URL: http://mixter.void.ru/tfn2k.tgz (Aug. 28 2002)
NIST. "Announcing the Advanced Encryption Standard". Nov. 26 2001
URL: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf (Aug. 20 2002)
Roesch, Martin. "snort.conf". Snort configuration & signatures. Oct. 3 2002
URL:http://www.snort.org/dl/binaries/1.9.0/snort-1.9.0-1snort.i386.rpm (Oct. 20 2002)
Roesch & Green. "Snort Users Manual Snort Release: 1.9.0.".
URL: http://www.snort.org/docs/writing_rules-1.9.0/ (Oct. 20 2002)
Stevens, W. Richard. "TCP/IP Illustrated, Volume 1 - The Protocols."
Reading: Addison Wesley Longman, inc, 1994. PP 70, 71, 86, 171
Vision, Max. "TROJAN-ACTIVE-Q-UDP." arachNIDS.
URL: http://www.whitehats.com/cgi/arachNIDS/Show?_id=ids201&view=research (18 Aug 2002)
Vision, Max. "TROJAN-ACTIVE-Q-ICMP." arachNIDS.
URL: http://www.whitehats.com/cgi/arachNIDS/Show?_id=ids202&view=research (18 Aug 2002)
Vision, Max. "TROJAN-ACTIVE-Q-TCP." arachNIDS.
URL: http://www.whitehats.com/cgi/arachNIDS/Show?_id=ids203&view=research (18 Aug 2002)