(Taken from ph rack. com, the best Hacker zine ever) Defeating Sniffers and Intrusion Detection Systems Overview The purpose of this article is to demonstrate some techniques that can be used to defeat sniffers and intrusion detection systems. This article focuses mainly on confusing your average ‘hacker’s sniffer, with some rough coverage of Intrusion Detection Systems (IDS). However, the methods and code present in this article should be a good starting point for getting your packets past ID systems. For an intense examination of attack techniques against IDS, checkout: web are a large number of effective techniques other than those that are implemented in this article. I have chosen a few generic techniques that hopefully can be easily expanded into more targeted and complex attacks.
After implementing these attacks, I have gone through and attempted to correlate them to the attacks described in the NAI paper, where appropriate. The root cause of the flaws discussed in this article is that most sniffers and intrusion detection systems do not have as robust of a TCP/IP implementation as the machines that are actually communicating on the network. Many sniffers and IDS use a form of data link level access, such as BPF, DLP I, or SOCK PACKET. The sniffer receives the entire data link level frame, and gets no contextual clues from the kernel as to how that frame will be interpreted. Thus, the sniffer has the job of interpreting the entire packet and guessing how the kernel of the receiving machine is going to process it. Luckily, 95% of the time, the packet is going to be sane, and the kernel TCP/IP stack is going to behave rather predictably.
It is the other 5% of the time that we will be focusing on. This article is divided into three sections: an overview of the techniques employed, a description of the implementation and usage, and the code. Where possible, the code has been implemented in a somewhat portable format: a shared library that wraps around connect (), which you can use LD PRELOAD to ” install’ into your normal client programs. This shared library uses raw sockets to create TCP packets, which should work on most unixes. However, some of the attacks described are too complex to implement with raw sockets, so simple OpenBSD kernel patches are supplied. I am working on complementary kernel patches for Linux, which will be placed on the rhino 9 web site when they are complete.
The rhino 9 web site is at: web Section 1. The Tricks The first set of tricks are solely designed to fool most sniffers, and will most likely have no effect on a decent ID system. The second set of tricks should be advanced enough to start to have an impact on the effectiveness of an intrusion detection system. Sniffer Specific Attacks 1.
Sniffer Design – One Host Design The first technique is extremely simple, and takes advantage of the design of many sniffers. Several hacker sniffers are designed to follow one connection, and ignore everything else until that connection is closed or reaches some internal time out. Sniffers designed in this fashion have a very low profile, as far as memory usage and CPU time. However, they obviously miss a great deal of the data that can be obtained. This gives us an easy way of preventing our packets from being captured: before our connection, we send a spoofed SYN packet from a non-existent host to the same port that we are attempting to connect to. Thus, the sniffer sees the SYN packet, and if it is listening, it will set up its internal state to monitor all packets related to that connection.
Then, when we make our connection, the sniffer ignores our SYN because it is watching the fake host. When the host later times out, our connection will not be logged because our initial SYN packet has long been sent. 2. Sniffer Design – IP options The next technique depends on uninformed coding practices within sniffers. If you look at the code for some of the hacker sniffers, namely ones based-off of the original lin sniffer, you will see that they have a structure that looks like this: struck ether packet{ether header eh; ip header ip; tcp header tcp; char data[8192]; }; The sniffer will read a packet off of the data link interface, and then slam it into that structure so it can analyze it easily. This should work fine most of the time.
However, this approach makes a lot of assumptions: it assumes that the size of the IP header is 20 bytes, and it also assumes that the size of the TCP header is 20 bytes. If you send an IP packet with 40 bytes of options, then the sniffer is going to look inside your IP options for the TCP header, and completely misinterpret your packet. If the sniffer handles your IP header correctly, but incorrectly handles the TCP header, that doesn’t buy you quite as much. In that situation, you get an extra 40 bytes of data that the sniffer will log. I have implemented mandatory IP options in the OpenBSDkernel such that it is manageable by a. 3.
Insertion – FIN and RST Spoofing – Invalid Sequence Numbers This technique takes advantage of the fact that your typical sniffer is not going to keep track of the specific details of the ongoing connection. In a TCP connection, sequence numbers are used as a control mechanism for determining how much data has been sent, and the correct order for the data that has been sent. Most sniffers do not keep track of the sequence numbers in an ongoing TCP connection. This allows us to insert packets into the data stream that the kernel will disregard, but the sniffer will interpret as valid. The first technique we will use based on this is spoofing FIN and RST packets. FIN and RST are control flags inside the TCP packets, a FIN indicating the initiation of a shutdown sequence for one side of a connection, and an RST indicating that a connection should be immediately torn down.
If we send a packet with a FIN or RST, with a sequence number that is far off of the current sequence number expected by the kernel, then the kernel will disregard it. However, the sniffer will likely regard this as a legitimate connection close request or connection reset, and cease logging. It is interesting to note that certain implementations of TCP stacks do not check the sequence numbers properly upon receipt of an RST. This obviously provides a large potential for a denial of service attack.
Specifically, Have noticed that Digital Unix 4. 0 d will tear down connections without checking the sequence numbers on RST packets. 4. Insertion – Data Spoofing – Invalid Sequence Numbers This technique is a variation of the previous technique, which takes advantage of the fact that a typical sniffer will not follow the sequence numbers of a TCP connection. A lot of sniffers have a certain data capture length, such that they will stop logging a connection after that amount of data has been captured. If we send a large amount of data after the connection initiation, with completely wrong sequence numbers, our packets will be dropped by the kernel.
However, the sniffer will potentially log all of that data as valid information. This is roughly an implementation of the ‘tcp-7’ attack mentioned in the NAI paper. IDS / Sniffer Attacks: The above techniques work surprisingly well for most sniffers, but they are not going to have much of an impact on most IDS. The next six techniques are a bit more complicated, but represent good starting points for getting past the more complex network monitors. 5.
Evasion – IP Fragmentation IP fragmentation allows packets to be split over multiple data grams in order to fit packets within the maximum transmission unit of the physical network interface. Typically, TCP is aware of the m tu, and doesn’t send packets that need to be fragmented at an IP level. We can use this to our advantage to try to confuse sniffers and IDS. There are several potential attacks involving fragmentation, but we will only cover a simple one. We can send a TCP packet split over several IP data grams such that the first 8 bytes of the TCP header are in a single packet, and the rest of the data is sent in 32 byte packets. This actually buys us a lot in our ability to fool a network analysis tool.
First of all, the sniffer/IDS will have to be capable of doing fragment reassembly. Second of all, it will have to be capable of dealing with fragmented TCP headers. It turns out that this simple technique is more than sufficient to get your packets past most data link level network monitors. This an another attack that I chose to implement as a in the OpenBSDkernel. This technique is very powerful in it’s ability to get past most sniffers completely.
However, it requires some experimentation because you have to make sure that your packets will get past all of the filters between you and the target. Certain packet filters wisely drop fragmented packets that look like they are going to rewrite the UDP/TCP header, or that look like they are unduly small. The implementation in this article provides a decent deal of control over the size of the fragments that your machine will output. This will allow you to implement the ‘frag-1’ and ‘frag-2’ attacks described in the NAI paper. 6. Desynchronization – Post Connection SYN If we are attempting to fool an intelligent sniffer, or an ID system, then we can be pretty certain that it will keep track of the TCP sequence numbers.
Forth is technique, we will attempt to de synchronize the sniffer/IDS from the actual sequence numbers that the kernel is honoring. We will implement this attack by sending a post connection SYN packet in our data stream, which will have divergent sequence numbers, but otherwise meet all of the necessary criteria to be accepted by our target host. However, the target host will ignore this SYN packet, because it references an already established connection. The intent of this attack is to get the sniffer/IDS to resynchronize its notion of the sequence numbers to the new SYN packet. I twill then ignore any data that is a legitimate part of the original stream, because it will be awaiting a different sequence number.
If we succeed in resynchronizing the IDS with a SYN packet, we can then send an RST packet with the new sequence number and close down its notion of the connection. This roughly corresponds with the ‘t cbc-2’ attack mentioned in the NAI paper. 7. Desynchronization – Pre Connection SYN Another attack we perform which is along this theme is to send an initial SYN before the real connection, with an invalid TCP checksum.
If the sniffer is smart enough to ignore subsequent Syn in a connection, but not smart enough to check the TCP checksum, then this attack will synchronize the sniffer/IDS to a bogus sequence number before the real connection occurs. This attack calls bind to get the kernel to assign a local port to the socket before calling connect. 8. Insertion – FIN and RST Spoofing – TCP checksum validation This technique is a variation of the FIN/RST spoofing technique mentioned above.
However, this time we will attempt to send FIN and RST packets that should legitimately close the connection, with one notable exception: the TCPchecksum will be invalid. These packets will be immediately dropped by the kernel, but potentially honored by the IDS/sniffer. This attack requires kernel support in order to determine the correct sequence numbers to use on the packet. This is similar to the ‘insert-2’ attack in the NAI paper. 9. Insertion – Invalid Data – TCP checksum validation This technique is a variation of the previous data insertion attack, with the exception that we will be inserting data with the correct sequence numbers, but incorrect TCP checksum’s.
This will serve to confuse and and ID by feeding it a lot of data that will not be honored by the participating kernels. This attack requires kernel support to get the correct sequence numbers for the outgoing packets. This attack is also similar to the ” insert-2′ attack described in the NAI paper. 10.
Insertion – FIN and RST Spoofing – Short TTL If the IDS or sniffer is sitting on the network such that it is one or more hops away from the host it is monitoring, then we can do a simple attack, utilizing the TTL field of the IP packet. For this attack, we determine the lowest TTL that can be used to reach the target host, and then subtract one. This allows us to send packets that will not reach the target host, but that have the potential of reaching the IDS or sniffer. In this attack, we send a couple of FIN packets, and a couple of RST packets. 11. Insertion – Data Spoofing – Short TTL For our final attack, we will send 8 k of data with the correct sequence numbers and TCP checksum’s.
However, the TTL will be one hop too short to reach our target host. Summary All of these attacks work in concert to confuse sniffers and IDS. Here is a breakdown of the order in which we perform them: Attack 1 – One Host Sniffer Design. FAKEHOST -> TARGET SYN Attack 7 – Pre-connect Desynchronization Attempt. REALHOST -> TARGET SYN (Bad TCP Checksum, Arbitrary Seq Number) Kernel ActivityREALHOST -> TARGET SYN (This is the real SYN, sent by our kernel) Attack 6 – Post-connect Desynchronization Attempt. REALHOST -> TARGET SYN (Arbitrary Seq Number X) REALHOST -> TARGET SYN (Seq Number X+1) Attack 4 – Data Spoofing – Invalid Sequence NumbersREALHOST -> TARGET DATA x 8 (1024 bytes, Seq Number X+2) Attack 5 – FIN/RST Spoofing – Invalid Sequence NumbersREALHOST -> TARGET FIN (Seq Number X+2+8192) REALHOST -> TARGET FIN (Seq Number X+3+8192) REALHOST -> TARGET RST (Seq Number X+4+8192) REALHOST -> TARGET RST (Seq Number X+5+8192) Attack 11 – Data Spoofing – TTL REALHOST -> TARGET DATA x 8 (1024 bytes, Short TTL, Real Seq Number Y) Attack 10 – FIN/RST Spoofing – TTL REALHOST -> TARGET FIN (Short TTL, Seq Number Y+8192) REALHOST -> TARGET FIN (Short TTL, Seq Number Y+1+8192) REALHOST -> TARGET RST (Short TTL, Seq Number Y+2+8192) REALHOST -> TARGET RST (Short TTL, Seq Number Y+3+8192) Attack 9 – Data Spoofing – Checksum REALHOST -> TARGET DATA x 8 (1024 bytes, Bad TCP Checksum, Real Seq Number Z) Attack 8 – FIN/RST Spoofing – Checksum REALHOST -> TARGET FIN (Bad TCP Checksum, Seq Number Z+8192) REALHOST -> TARGET FIN (Bad TCP Checksum, Seq Number Z+1+8192) REALHOST -> TARGET RST (Bad TCP Checksum, Seq Number Z+2+8192) REALHOST -> TARGET RST (Bad TCP Checksum, Seq Number Z+3+8192) The attacks with an asterisk require kernel support to determine the correct sequence numbers.
Arguably, this could be done without kernel support, utilizing a data link level sniffer, but it would make the code significantly more complex, because it would have to reassemble fragments, and do several validation checks in order to follow the real connection. The user can choose which of these attacks he / she would like to perform, and the sequence numbers will adjust themselves accordingly. Section 2 – Implementation and Usage My primary goal when implementing these techniques was to keep the changes necessary to normal system usage as slight as possible. I had to divide the techniques into two categories: attacks that can be performed from user context, and attacks that have to be augmented by the kernel in some fashion. My secondary goal was to make the user land set of attacks reasonably portable to other Unix environments, besides OpenBSD and Linux. The user land attacks are implemented using shared library redirection, an extremely useful technique borrowed from half life’s P 51-08 article.
The first program listed below, contestant. c, is a shared library that the user requests the loader to link first. This is done with the LD PRELOAD environment variable on several unixes. For more information about this technique, refer to the original article by half life. The shared library defines the connect symbol, thus pre-empting the normal connect function from lib c (or lib socket) during the loading phase of program execution.
Thus, you should be able to use these techniques with most any client program that utilizes normal BSD socket functionality. OpenBSD does not let us do shared library redirection (when you attempt to the old symbol out of lib c, it gives you a pointer to the function you had pre-loaded). However, this is not a problem because we can just call the connect (). This shared library has some definite drawbacks, but you get what you pay for. It will not work correctly with programs that do non-blocking connect calls, or RAW or data link level access.
Furthermore, it is designed for use on TCP sockets, and without kernel support to determine the type of a socket, it will attempt the TCP attacks on UDP connections. This support is currently only implemented under OpenBSD. However, this isn’t that big of a drawback because it just sends a few packets that get ignored. Another drawback to the shared library is that it picks a sequence number out of the blue to represent the ” wrong’s sequence number. Due to this fact, there is a very small possibility that the shared library will pick a legitimate sequence number, and the stream. This, however, is extremely unlikely.
A Makefile accompanies the shared library. Edit it to fit your host, and then go into the source file and make it point to your copy of lib c. so, and you should be ready to go. The code has been tested on OpenBSD 2.
3, 2. 4, Debian Linux, Slackware Linux, Debian glib c Linux, Solaris 2. 5, and Solaris 2. 6.
You can use the library like this: # export LD PRELOAD = . /congestion. so# export CONGCONF = ‘DEBUG, OH, SC, SS, DS, FS, RS’# telnet web library will ‘wrap’ around any connects in the programs you run from that point on, and provide you some protection behind the scenes. You can control the program by defining the CONGCONF environment variable. You give it a comma delimited list of attacks, which break out like this: DEBUG: Show debugging information OH: Do the One Host Design Attacks: Spoof a SYN prior to the connect with a bad TCP checksum. SS: Spoof a SYN after the connection in a de synchronization attempt.
DS: Insert 8 k of data with bad sequence numbers. FS: Spoof FIN packets with bad sequence numbers. RS: Spoof RST packets with bad sequence numbers. DC: Insert 8 k of data with bad TCP checksum’s. (needs kernel support) FC: Spoof FIN packets with bad TCP checksum’s. (needs kernel support) RC: Spoof RST packets with bad TCP checksum’s.
(needs kernel support) DT: Insert 8 k of data with short TTLs. (needs kernel support) FT: Spoof FIN packets with short TTLs. (needs kernel support) RT: Spoof RST packets with short TTLs. (needs kernel support) Kernel Support OpenBSD kernel patches are provided to facilitate several of the techniques described above.
These patches have been made against the 2. 4 source distribution. I have added three variables to the kernel, and one new system call. The three variables are: net. in et. ip.
(integer) net. in et. ip. (integer) net. in et.
ip. option shack (integer) The new system call is (), and it is system call number 242. The three ‘s can be used to modify the characteristics of every outgoing IP packet coming from the machine. The variable specifies a, in bytes, for outgoing IP data grams. is applied to every outgoing data gram, unless is also defined.
In that case, the m tufor the first fragment of a packet is read from, and the m tu for every consecutive fragment is read from. This allows you to force your machine into fragmenting all of its traffic, to any size that you specify. The reason it is divided into two variables is so that you can have the first fragment contain the entire TCP/UDP header, and have the following fragments be 8 or 16 bytes. This way, you can get your fragmented packets past certain filtering routers that block any sort of potential header rewriting. The option shack allows you to turn on mandatory 40 bytes of NULL IP options on every outgoing packet.
I implemented these controls such that they do not have any effect on packets sent through raw sockets. The implication of this is that our attacking packets will not be fragmented or contain IP options. Using these ‘s is pretty simple: for the frag hack variables, you specify a number of bytes (or 0 to turn them off), and for the option shack, you either set it to 0 or 1. Here is an example use: # -w net. in et.
ip. option shack = 1 # 40 bytes added to header# -w net. in et. ip. = 80 # 20 + 40 + 20 = full protocol header # -w net. in et.
ip. = 68 # 20 + 40 + 8 = smallest possible frag It is very important to note that you should be careful with the. When you specify extreme fragmentation, you quickly eat up the memory that the kernel has available for storing packet headers. If memory usage is too high, you will notice send to () returning a no buffer space error. If you stick to programs like telnet or ssh, that use small packets, then you should be fine with 28 or 28/36. However, if you use programs that use large packets like ftp or rip, then you should bump up to a higher number, such as 200.
The system call, , is needed by the user land program to determine if socket is a TCP socket, and to query the kernel for the next sequence number that it expects to send on the next outgoing packet, as well as the next sequence number it expects to receive from it’s peer. This allows program to implement attacks based on having a correct sequence number, but some other flaw in the packet such as a short TTL or bad TCPchecksum. Kernel Patch Installation Here are the steps I use to install the kernel patches. Disclaimer: I am not an experienced kernel programmer, so don’t be too upset if your box gets a little flaky. The testing I’ve done on my own machines has gone well, but be aware that you really are screwing with critical stuff by installing these patches. You may suffer performance hits, or other.
But hey, you can’t have any fun if you don’t take any risks. : >Step 1. Apply the neti net. patch to /us / s rc / says /neti net/Step 2. cp /us / s rc / says /neti net / in . h to /us / include /neti net / in .
step 3. go into /us / s rc / us . sb in/, and rebuild and install it Step 4. Apply kern. patch to /us / s rc / says /kern/Step 5. cd /us / s rc / says /kern; make Step 6.
Apply says. patch to /us / s rc / says /says/Step 7. cd into your kernel build directory (/us / s rc / says /arch/XXX/compile/XXX), and do a make depend && make. Step 8. cp bsd /bsd, reboot, and cross your fingers. : The Code contestant/Makefile# OpenBSD LDPRE = -BshareableLDPOST = OPTS = -DKERNELSUPPORT# Linux#LDPRE = -B shareable#LDPOST = -ldl#OPTS = # Solaris#LDPRE = -G#LDPOST = -ldl#OPTS = -D BIG ENDIAN = 42 -DBYTEORDER = 42 contestant.
so: contestant. o ld ${LDPRE} -o contestant. so contestant. o ${LDPOST}contestant. o: contestant. c gcc ${OPTS} -fPIC -c contestant.
clean: rm -f contestant. o contestant. so contestant / contestant . c/ contestant.
c – demonstration of sniffer/ID defeating techniques by horizon special thanks to str an 9 er, me culpa, plague, half life, and fy odor open bsd doesn’t let us do shared lib redirection, so we implement the connect system call directly. Also, the kernel support for certain attacks is only implemented in open bsd. When I finish the linux support, it will be available at web This whole thing is a conditionally compiling nightmare. : > This has been tested under OpenBSD 2. 3, 2. 4, Solaris 2.
5, Solaris 2. 5. 1, Solaris 2. 6, Debian Linux, and the glib c Debian Linux // The path to our lib c. (lib socket under Solaris) // You don’t need this if you are running OpenBSD // #define LIB PATH ‘/us / lib /lib socket. so’ /#define LIB PATH ‘/lib / lib c-2.
0. 7. so’/ #define LIB PATH ‘/us / lib /lib c. so’ // The source of our initial spoofed SYN in the One Host Design attack // This has to be some host that will survive any outbound packet filters /#define FAKEHOST ’42. 42. 42.
42’#include #include #include #include #include #include.