How a SYN flood attack looks

Some weeks ago, on December 22, 2025, after logging into one of my existing VPS servers (IP 51.79.160.8) which has an Apache process listening on ports 80 and 443, I noticed on the output of the command ‘netstat -ptuan’ that there were around 100 connections (TCP Sockets) on my server port 443 in ‘SYN_RECV‘ state.

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
...
tcp        0      0 51.79.160.8:443         177.8.135.235:47130     SYN_RECV    -
tcp        0      0 51.79.160.8:443         177.8.134.2:50381       SYN_RECV    -
tcp        0      0 51.79.160.8:443         177.8.132.49:48273      SYN_RECV    -
tcp        0      0 51.79.160.8:443         177.8.135.108:59527     SYN_RECV    -
tcp        0      0 51.79.160.8:443         177.8.132.62:42140      SYN_RECV    -
tcp        0      0 51.79.160.8:443         177.8.134.237:32949     SYN_RECV    -
tcp        0      0 51.79.160.8:443         177.8.135.149:27714     SYN_RECV    -
tcp        0      0 51.79.160.8:443         177.8.132.77:28729      SYN_RECV    -
tcp        0      0 51.79.160.8:443         177.8.132.234:37897     SYN_RECV    -
tcp        0      0 51.79.160.8:443         177.8.132.120:53457     SYN_RECV    -
...

These connections were not transitioning to the ESTABLISHED state.

There were 100 connections coming from 97 different IPs (three of them have opened 2 connections). All these connections were coming from IPs with the pattern {177.8.132.X, 177.8.133.X, 177.8.134.X, 177.8.135.X} which corresponds to a Brazilian ISP, and IPs reported on AbuseIPDB.

Running a tcpdump command on the server and filtering by port 443, I was able to check for a particular connection (for example, for the connection with origin IP/port 177.8.133.239:60596) that we were receiving the initial TCP packet with the ‘SYN‘ flag, and our server was replying with the packet with flags ‘SYN+ACK‘, but after that we weren’t receiving the final ‘ACK‘ from the remote client, so the three-way TCP handshake connection was not being completed and therefore the socket on my server side won’t transition to ESTABLISHED state.

...
18:34:16.305650 IP 177.8.133.239.60596 > 51.79.160.8.443: Flags [S], seq 2505533455, win 8192, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
18:34:16.305731 IP 51.79.160.8.443 > 177.8.133.239.60596: Flags [S.], seq 3240963400, ack 2505533456, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
18:34:16.328794 IP 51.79.160.8.443 > 177.8.132.147.6361: Flags [S.], seq 1428523847, ack 3218482592, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
18:34:16.328832 IP 51.79.160.8.443 > 177.8.133.226.58612: Flags [S.], seq 3377557149, ack 1763415355, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
18:34:16.725834 IP 177.8.135.189.24683 > 51.79.160.8.443: Flags [S], seq 2199942316, win 29200, options [mss 1460,nop,wscale 5,nop,nop,sackOK], length 0
18:34:16.725931 IP 51.79.160.8.443 > 177.8.135.189.24683: Flags [S.], seq 3562566938, ack 2199942317, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
18:34:16.728751 IP 51.79.160.8.443 > 177.8.135.192.19631: Flags [S.], seq 3013492022, ack 2120380736, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
18:34:16.728770 IP 51.79.160.8.443 > 177.8.135.120.40165: Flags [S.], seq 2856274143, ack 383134197, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
18:34:16.728778 IP 51.79.160.8.443 > 177.8.133.157.32972: Flags [S.], seq 833551828, ack 3419445764, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
18:34:16.928806 IP 51.79.160.8.443 > 177.8.133.144.1211: Flags [S.], seq 2688584559, ack 4246600208, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
...

This is what we know a SYN flood attack: a network level type of Denial-of-Service (DoS) or Distributed Denial-of-Service (DDoS) attack that exploits the TCP three-way handshake to exhaust a server’s resources. By overwhelming the target with “half-open” connections, it prevents legitimate users from accessing the service.

Some network issues related to network interfaces configurations or misconfiguration in routing table rules could also cause “half-open” connections. In those cases, a legitimate client connection will retransmit the initial SYN packet if it doesn’t receive the SYN+ACK response due to network issues, but this is not the case because on the server side we don’t receive retransmissions of the initial TCP SYN packet.

Regarding the connections in ‘SYN_RECV‘ state, they are not growing indefinitely because the Linux kernel has a setting which does retries of the SYN+ACK response, and if it doesn’t receive the final ACK from the client after these retries, then it drops the connection and releases the local socket. Thanks to this, a connection in ‘SYN_RECV’ state will be dropped automatically by the Kernel after around a minute.

$ sysctl -a 2>/dev/null | grep synack
net.ipv4.tcp_synack_retries = 5

The immediate action from my side to prevent these IPs continuing causing connections in ‘SYN_RECV’ state on the server is to block that range of IPs using the server Firewalld (the server is a Red Hat Enterprise Linux based distribution). I’m blocking the network 177.8.0.0/16 which will block a larger range of IPs, but this doesn’t matter because the content of the Web service running on this server is restricted to me.

$ firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="177.8.0.0/16" reject'

$ firewall-cmd --reload

$ cat /etc/firewalld/zones/public.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Public</short>
  <description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="dhcpv6-client"/>
  <port protocol="tcp" port="80"/>
  <port protocol="tcp" port="443"/>
  <rule family="ipv4">
    <source address="177.8.0.0/16"/>
    <reject/>
  </rule>
</zone>

After applying this firewall rule, the number of connections in SYN_RECV state on my server side has started decreasing, and after a minute there are no remaining connections in that state.

A new tcpdump capture now shows that we are still receiving connection attempts from those IPs, but the firewall/kernel is rejecting those connections, so they are not causing local sockets in SYN_RECV state.

19:07:43.027650 IP 177.8.132.131.23794 > 51.79.160.8.443: Flags [S], seq 30820313, win 65535, options [mss 1412,nop,wscale 7,nop,nop,sackOK], length 0
19:07:43.027729 IP 51.79.160.8 > 177.8.132.131: ICMP 51.79.160.8 tcp port 443 unreachable, length 60
19:07:43.080080 IP 177.8.133.35.56527 > 51.79.160.8.443: Flags [S], seq 3846173219, win 16384, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
19:07:43.080147 IP 51.79.160.8 > 177.8.133.35: ICMP 51.79.160.8 tcp port 443 unreachable, length 60
19:07:43.164867 IP 177.8.133.178.31946 > 51.79.160.8.443: Flags [S], seq 2087965107, win 65535, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0
19:07:43.164935 IP 51.79.160.8 > 177.8.133.178: ICMP 51.79.160.8 tcp port 443 unreachable, length 60

It’s not easy to detect and automatically stop a SYN DDoS attack, especially because it comes from different IPs, and the connection rate limit per IP feature won’t work. For those cases, we can use a Web Application Firewall (WAF), specialized DDoS protection appliances, or either Cloud-based solutions offered by Cloud Providers like Cloudflare or AWS.

Adib Ahmed Akhtar