Detecting attacks based on TCP Flags (DDOS, SYN Flood, and others)

Post a Comment

During 2024, I’ve been digging into TCP flags for a while because they can reveal a lot about malicious activity based on how they’re set. These flags hold key details about network connectivity status, so understanding them is pretty important.

While exploring DeviceNetworkEvents, I noticed that in the ‘AdditionalDetails’ field, the TCPFlags value appears for inbound connections — but in integer format. That meant I had to convert it to binary manually. Surprisingly, there’s no built-in tobinary function in KQL to handle this, which feels like a missed opportunity — maybe something to request in the future?

Since I needed it right away, I went ahead and built a KQL query to convert integers to binary myself:

// Sergio Albea
let number = 42; // Replace with your integer
let binary =
range i from 0 to 31 step 1
| extend bit = toint(floor((number / pow(2, i)), 1) % 2)
| summarize binary = strcat_array(make_list(strcat(bit)), “”)
| project binary;
binary

But performance-wise, it was limiting my time range, so I just went ahead and created a list with the integers and binaries, which made things run faster. In short, here are the different TCP flags identified:

0- FIN (Finish) Signals connection termination.

1- SYN (Synchronize) Initiates a new TCP connection.

2- RST (Reset) Abruptly terminates a connection.

3- PSH (Push) Instructs immediate delivery to the application

4- ACK (Acknowledgment) Confirms receipt of data from sender.

5- URG (Urgent) Marks urgent data.

6- ECE (ECN Echo) Signals congestion notification to the sender.

7- CWR (Congestion Window Reduced) Indicates congestion control adjustment.

Here is the KQL query I developed to extract the bits of the TCP flags based on the remote IP for inbound connection attempts and queries associated to every Flag:

//Sergio Albea
let binnary_codes = externaldata(Integer: string, binary: string)[@“https://raw.githubusercontent.com/Sergio-Albea-Git/Threat-Hunting-KQL-Queries/refs/heads/main/Security-Lists/binary_list.csv”] with (format=“csv”, ignoreFirstRecord=True);
DeviceNetworkEvents
| extend tags = parse_json( AdditionalFields)
| extend direction = tags[“direction”]
| where direction has “In”
| extend Geo_IP = tostring(geo_info_from_ip_address(RemoteIP).country)
| where isnotempty(Geo_IP)
| extend TCPFlags = tostring(tags[“Tcp Flags”])
| join kind=leftouter ( binnary_codes) on $left.TCPFlags == $right.Integer
| extend num0 = strcat(substring(binary, 0,1)),num1 = strcat(substring(binary, 1,1)),num2 = strcat(substring(binary, 2,1)),num3 = strcat(substring(binary, 3,1)),num4 = strcat(substring(binary, 4,1)),num5 = strcat(substring(binary, 5,1)),num6 = strcat(substring(binary, 6,1)),num7 = strcat(substring(binary, 7,1))
| summarize make_set(binary),FIN= countif(num7 == 1),SYN= countif(num6 == 1),RST = countif(num5 == 1),PSH = countif(num4 == 1),ACK = countif(num3 == 1),URG = countif(num2 == 1),ECE = countif(num1 == 1),CWR = countif(num0 == 1), count() by RemoteIP, Geo_IP

0- FIN (Finish)

FIN Scan — Attackers send FIN packets to probe open ports and evade firewalls.

//Sergio Albea
let binnary_codes = externaldata(Integer: string, binary: string)[@“https://raw.githubusercontent.com/Sergio-Albea-Git/Threat-Hunting-KQL-Queries/refs/heads/main/Security-Lists/binary_list.csv”] with (format=“csv”, ignoreFirstRecord=True);
DeviceNetworkEvents
| extend tags = parse_json( AdditionalFields)
| extend direction = tags[“direction”]
| where direction has “In”
| extend Geo_IP = tostring(geo_info_from_ip_address(RemoteIP).country)
| where isnotempty( Geo_IP)
| extend TCPFlags = tostring(tags[“Tcp Flags”])
| join kind=leftouter ( binnary_codes) on $left.TCPFlags == $right.Integer
| extend num0 = strcat(substring(binary, 0,1)),num1 = strcat(substring(binary, 1,1)),num2 = strcat(substring(binary, 2,1)),num3 = strcat(substring(binary, 3,1)),num4 = strcat(substring(binary, 4,1)),num5 = strcat(substring(binary, 5,1)),num6 = strcat(substring(binary, 6,1)),num7 = strcat(substring(binary, 7,1))
| summarize make_set(binary),FIN= countif(num7 == 1),SYN= countif(num6 == 1),RST = countif(num5 == 1),PSH = countif(num4 == 1),ACK = countif(num3 == 1),URG = countif(num2 == 1),ECE = countif(num1 == 1),CWR = countif(num0 == 1), count() by RemoteIP, Geo_IP
| where FIN > 0

1- SYN (Synchronize)

SYN Flood Attack — Attackers send numerous SYN packets without completing the handshake to exhaust server resources.

//Sergio Albea
let binnary_codes = externaldata(Integer: string, binary: string)[@“https://raw.githubusercontent.com/Sergio-Albea-Git/Threat-Hunting-KQL-Queries/refs/heads/main/Security-Lists/binary_list.csv”] with (format=“csv”, ignoreFirstRecord=True);
DeviceNetworkEvents
| extend tags = parse_json( AdditionalFields)
| extend direction = tags[“direction”]
| where direction has “In”
| extend Geo_IP = tostring(geo_info_from_ip_address(RemoteIP).country)
| where isnotempty( Geo_IP)
| extend TCPFlags = tostring(tags[“Tcp Flags”])
| join kind=leftouter ( binnary_codes) on $left.TCPFlags == $right.Integer
| extend num0 = strcat(substring(binary, 0,1)),num1 = strcat(substring(binary, 1,1)),num2 = strcat(substring(binary, 2,1)),num3 = strcat(substring(binary, 3,1)),num4 = strcat(substring(binary, 4,1)),num5 = strcat(substring(binary, 5,1)),num6 = strcat(substring(binary, 6,1)),num7 = strcat(substring(binary, 7,1))
| summarize make_set(binary),FIN= countif(num7 == 1),SYN= countif(num6 == 1),RST = countif(num5 == 1),PSH = countif(num4 == 1),ACK = countif(num3 == 1),URG = countif(num2 == 1),ECE = countif(num1 == 1),CWR = countif(num0 == 1), count() by RemoteIP, Geo_IP
| where SYN > 100 // Adjust threshold based on baseline

2- RST (Reset)

RST Flood Attack — Attackers send excessive RST packets to disrupt ongoing connections.

//Sergio Albea
let binnary_codes = externaldata(Integer: string, binary: string)[@“https://raw.githubusercontent.com/Sergio-Albea-Git/Threat-Hunting-KQL-Queries/refs/heads/main/Security-Lists/binary_list.csv”] with (format=“csv”, ignoreFirstRecord=True);
DeviceNetworkEvents
| extend tags = parse_json( AdditionalFields)
| extend direction = tags[“direction”]
| where direction has “In”
| extend Geo_IP = tostring(geo_info_from_ip_address(RemoteIP).country)
| where isnotempty( Geo_IP)
| extend TCPFlags = tostring(tags[“Tcp Flags”])
| join kind=leftouter ( binnary_codes) on $left.TCPFlags == $right.Integer
| extend num0 = strcat(substring(binary, 0,1)),num1 = strcat(substring(binary, 1,1)),num2 = strcat(substring(binary, 2,1)),num3 = strcat(substring(binary, 3,1)),num4 = strcat(substring(binary, 4,1)),num5 = strcat(substring(binary, 5,1)),num6 = strcat(substring(binary, 6,1)),num7 = strcat(substring(binary, 7,1))
| summarize make_set(binary),FIN= countif(num7 == 1),SYN= countif(num6 == 1),RST = countif(num5 == 1),PSH = countif(num4 == 1),ACK = countif(num3 == 1),URG = countif(num2 == 1),ECE = countif(num1 == 1),CWR = countif(num0 == 1), count() by RemoteIP, Geo_IP
| where RST > 0

3- PSH (Push)

Attackers use PSH flags to quickly transmit stolen data.

//Sergio Albea
let binnary_codes = externaldata(Integer: string, binary: string)[@“https://raw.githubusercontent.com/Sergio-Albea-Git/Threat-Hunting-KQL-Queries/refs/heads/main/Security-Lists/binary_list.csv”] with (format=“csv”, ignoreFirstRecord=True);
DeviceNetworkEvents
| extend tags = parse_json( AdditionalFields)
| extend direction = tags[“direction”]
| where direction has “In”
| extend Geo_IP = tostring(geo_info_from_ip_address(RemoteIP).country)
| where isnotempty( Geo_IP)
| extend TCPFlags = tostring(tags[“Tcp Flags”])
| join kind=leftouter ( binnary_codes) on $left.TCPFlags == $right.Integer
| extend num0 = strcat(substring(binary, 0,1)),num1 = strcat(substring(binary, 1,1)),num2 = strcat(substring(binary, 2,1)),num3 = strcat(substring(binary, 3,1)),num4 = strcat(substring(binary, 4,1)),num5 = strcat(substring(binary, 5,1)),num6 = strcat(substring(binary, 6,1)),num7 = strcat(substring(binary, 7,1))
| summarize make_set(binary),FIN= countif(num7 == 1),SYN= countif(num6 == 1),RST = countif(num5 == 1),PSH = countif(num4 == 1),ACK = countif(num3 == 1),URG = countif(num2 == 1),ECE = countif(num1 == 1),CWR = countif(num0 == 1), count() by RemoteIP, Geo_IP
| where PSH > 0

4- ACK (Acknowledgment)

ACK Flood Attack — Attackers flood a target with ACK packets to exhaust system resources.

//Sergio Albea
let binnary_codes = externaldata(Integer: string, binary: string)[@“https://raw.githubusercontent.com/Sergio-Albea-Git/Threat-Hunting-KQL-Queries/refs/heads/main/Security-Lists/binary_list.csv”] with (format=“csv”, ignoreFirstRecord=True);
DeviceNetworkEvents
| extend tags = parse_json( AdditionalFields)
| extend direction = tags[“direction”]
| where direction has “In”
| extend Geo_IP = tostring(geo_info_from_ip_address(RemoteIP).country)
| where isnotempty( Geo_IP)
| extend TCPFlags = tostring(tags[“Tcp Flags”])
| join kind=leftouter ( binnary_codes) on $left.TCPFlags == $right.Integer
| extend num0 = strcat(substring(binary, 0,1)),num1 = strcat(substring(binary, 1,1)),num2 = strcat(substring(binary, 2,1)),num3 = strcat(substring(binary, 3,1)),num4 = strcat(substring(binary, 4,1)),num5 = strcat(substring(binary, 5,1)),num6 = strcat(substring(binary, 6,1)),num7 = strcat(substring(binary, 7,1))
| summarize make_set(binary),FIN= countif(num7 == 1),SYN= countif(num6 == 1),RST = countif(num5 == 1),PSH = countif(num4 == 1),ACK = countif(num3 == 1),URG = countif(num2 == 1),ECE = countif(num1 == 1),CWR = countif(num0 == 1), count() by RemoteIP, Geo_IP
| where ACK > 100

5 URG (Urgent)

Injection Attacks — Attackers manipulate urgent pointers to inject malicious payloads.

//Sergio Albea
let binnary_codes = externaldata(Integer: string, binary: string)[@“https://raw.githubusercontent.com/Sergio-Albea-Git/Threat-Hunting-KQL-Queries/refs/heads/main/Security-Lists/binary_list.csv”] with (format=“csv”, ignoreFirstRecord=True);
DeviceNetworkEvents
| extend tags = parse_json( AdditionalFields)
| extend direction = tags[“direction”]
| where direction has “In”
| extend Geo_IP = tostring(geo_info_from_ip_address(RemoteIP).country)
| where isnotempty(Geo_IP)
| extend TCPFlags = tostring(tags[“Tcp Flags”])
| join kind=leftouter ( binnary_codes) on $left.TCPFlags == $right.Integer
| extend num0 = strcat(substring(binary, 0,1)),num1 = strcat(substring(binary, 1,1)),num2 = strcat(substring(binary, 2,1)),num3 = strcat(substring(binary, 3,1)),num4 = strcat(substring(binary, 4,1)),num5 = strcat(substring(binary, 5,1)),num6 = strcat(substring(binary, 6,1)),num7 = strcat(substring(binary, 7,1))
| summarize make_set(binary),FIN= countif(num7 == 1),SYN= countif(num6 == 1),RST = countif(num5 == 1),PSH = countif(num4 == 1),ACK = countif(num3 == 1),URG = countif(num2 == 1),ECE = countif(num1 == 1),CWR = countif(num0 == 1), count() by RemoteIP, Geo_IP
| where URG > 0

6- ECE (ECN Echo)

ECN-Based Attacks — Attackers abuse ECN to cause unnecessary congestion handling.

//Sergio Albea
let binnary_codes = externaldata(Integer: string, binary: string)[@“https://raw.githubusercontent.com/Sergio-Albea-Git/Threat-Hunting-KQL-Queries/refs/heads/main/Security-Lists/binary_list.csv”] with (format=“csv”, ignoreFirstRecord=True);
DeviceNetworkEvents
| extend tags = parse_json( AdditionalFields)
| extend direction = tags[“direction”]
| where direction has “In”
| extend Geo_IP = tostring(geo_info_from_ip_address(RemoteIP).country)
| where isnotempty(Geo_IP)
| extend TCPFlags = tostring(tags[“Tcp Flags”])
| join kind=leftouter ( binnary_codes) on $left.TCPFlags == $right.Integer
| extend num0 = strcat(substring(binary, 0,1)),num1 = strcat(substring(binary, 1,1)),num2 = strcat(substring(binary, 2,1)),num3 = strcat(substring(binary, 3,1)),num4 = strcat(substring(binary, 4,1)),num5 = strcat(substring(binary, 5,1)),num6 = strcat(substring(binary, 6,1)),num7 = strcat(substring(binary, 7,1))
| summarize make_set(binary),FIN= countif(num7 == 1),SYN= countif(num6 == 1),RST = countif(num5 == 1),PSH = countif(num4 == 1),ACK = countif(num3 == 1),URG = countif(num2 == 1),ECE = countif(num1 == 1),CWR = countif(num0 == 1), count() by RemoteIP, Geo_IP
| where ECE > 0

7 — CWR (Congestion Window Reduced)

ECN Flooding Attack — Attackers manipulate congestion control mechanisms to disrupt network performance.

//Sergio Albea
let binnary_codes = externaldata(Integer: string, binary: string)[@“https://raw.githubusercontent.com/Sergio-Albea-Git/Threat-Hunting-KQL-Queries/refs/heads/main/Security-Lists/binary_list.csv”] with (format=“csv”, ignoreFirstRecord=True);
DeviceNetworkEvents
| extend tags = parse_json( AdditionalFields)
| extend direction = tags[“direction”]
| where direction has “In”
| extend Geo_IP = tostring(geo_info_from_ip_address(RemoteIP).country)
| where isnotempty(Geo_IP)
| extend TCPFlags = tostring(tags[“Tcp Flags”])
| join kind=leftouter ( binnary_codes) on $left.TCPFlags == $right.Integer
| extend num0 = strcat(substring(binary, 0,1)),num1 = strcat(substring(binary, 1,1)),num2 = strcat(substring(binary, 2,1)),num3 = strcat(substring(binary, 3,1)),num4 = strcat(substring(binary, 4,1)),num5 = strcat(substring(binary, 5,1)),num6 = strcat(substring(binary, 6,1)),num7 = strcat(substring(binary, 7,1))
| summarize make_set(binary),FIN= countif(num7 == 1),SYN= countif(num6 == 1),RST = countif(num5 == 1),PSH = countif(num4 == 1),ACK = countif(num3 == 1),URG = countif(num2 == 1),ECE = countif(num1 == 1),CWR = countif(num0 == 1), count() by RemoteIP, Geo_IP
| where CWR > 0

Conclusion

This use case helps to identify TCP Flags information allowing you to create multiple queries to detect different type of attacks such as DDOS, SYN Flood Attacks, and others. For instance:

  1. Detecting TCP Session Hijacking : Attackers inject packets into an established session using manipulated TCP flags. I would suggest to review the cases where there is an important amount of SYN packages and 0 ACK.
  2. Detecting TCP Flag Anomalies : Attackers use unusual flag combinations to evade detection. Look for unusual flag combinations (e.g., SYN+FIN, SYN+RST).
  3. Detecting TCP XMAS Scans : Attackers send packets with FIN, PSH, and URG flags set (like a “Christmas tree”). Look for TCP packets with FIN, PSH, and URG flags set.
  4. Detecting SYN Flood Attacks (DDoS) : Attackers send a large number of SYN packets without completing the TCP handshake, exhausting server resources. Look for a high volume of SYN packets with no corresponding SYN-ACK or ACK responses and create detection rules to detect unusual spikes in SYN packets.
  5. Detecting TCP RESET (RST) Attacks: Attackers send RST packets to terminate legitimate connections. Look for a high volume of RST packets from a single source IP.

I recommend executing various queries to analyse the number of occurrences for each type of TCP flag to gain a comprehensive understanding of their distribution.

Based on my findings and analysis, I strongly suggest reviewing all connection attempts that include CWR, ECE, URG, PSH, and RST TCP flags, as they may indicate unusual or potentially malicious activity.

Detecting attacks based on TCP Flags (DDOS, SYN Flood, and others) was originally published in Detect FYI on Medium, where people are continuing the conversation by highlighting and responding to this story.

Introduction to Malware Binary Triage (IMBT) Course

Looking to level up your skills? Get 10% off using coupon code: MWNEWS10 for any flavor.

Enroll Now and Save 10%: Coupon Code MWNEWS10

Note: Affiliate link – your enrollment helps support this platform at no extra cost to you.

Article Link: Detecting attacks based on TCP Flags (DDOS, SYN Flood, and others) | by Sergio Albea | Mar, 2025 | Detect FYI

1 post - 1 participant

Read full topic



Malware Analysis, News and Indicators - Latest topics
Sp123
"The real threat is actually not when the computer begins to think like a human, but when humans begin to think like computers."

Post a Comment