Prerequisites¶
projectx-prod-vpchas been created with subnets configured.- VPC Flow Logs have been enabled and are delivering logs to your S3 security datalake (see VPC Flow Logs & Integration).
- Wazuh is configured to ingest VPC Flow Logs from S3 (see VPC Flow Logs & Integration).
project-x-sec-boxconfigured with Wazuh.
Note
This guide builds on the Open VPC Configuration attack scenario. The detections below are designed to identify indicators of that attack in VPC Flow Log data.
Network Topology¶
Overview¶
VPC Flow Logs capture network traffic (source/destination IPs, ports, protocols, and whether traffic was accepted or rejected). By creating Wazuh detection rules, you can identify patterns consistent with the Open VPC Configuration attack—such as inbound traffic from the internet to high-value ports (SSH, RDP, databases) and port-scanning behavior.
This guide provides custom Wazuh rules to deploy on your Wazuh manager.
Detection Strategy¶
How would we detect malicious activity?
Well, we have the visibility, through our logs.
We can start with the attack and work backward...
Attackers scan for open ports (discovery), probe high-value ports (enumeration), then attempt access (exploitation).
In VPC Flow Logs, we look for flows where source IP (attacker), destination port (target service), and action (ACCEPT/REJECT) tell the story.
Legitimate access typically comes from internal ranges (10.x, 172.16–31.x, 192.168.x).
Uncommon or unknown external IPs hitting SSH, RDP, or database ports is a strong signal. Especially if they continously attempt to establish a connection.
Port scanning shows as one source IP connecting to multiple high-value ports in a short window—we detect that by correlating alerts from the same source. The rules below encode these patterns.
So here's what we can come up with...
| Attack Phase | VPC Flow Log Indicator | Detection Approach |
|---|---|---|
| Discovery / Scanning | Same source IP connecting to multiple high-value ports in short time | Port scan detection |
| Exploitation | Inbound traffic from external IPs to SSH (22), RDP (3389), DB ports (3306, 5432, 1433) | High-value port exposure |
| Exploitation | Accepted (ACCEPT) traffic to database ports from non-private IPs | Database port exposure |
VPC Flow Log fields used in our rules include:
- srcaddr / pkt-srcaddr: Source IP (attacker or scanner)
- dstaddr / pkt-dstaddr: Destination IP (your instance)
- dstport: Destination port (service being targeted)
- action: ACCEPT or REJECT
Create Wazuh Detection Rules¶
High-Value Port Exposure (Open VPC)¶
We want to detect inbound traffic from the internet to high-risk ports. The open_vpc scenario exposes SSH (22), RDP (3389), and database ports (3306, 5432, 1433) to 0.0.0.0/0. Let's build the rule step by step.
Rule Description In Layman Terms¶
Our condition is: "Alert when we see ACCEPTed traffic to a high-value port (22, 3389, etc.) and the source IP is not in a private range." We express this with three requirements:
- The event must be a VPC Flow Log (we inherit that from the grouping rule).
- The destination port and action must match our criteria.
- The source IP must be external.
Wazuh Rule Syntax Walkthrough¶
Each rule is an XML <rule> element. Here's what each part does:
| Element | Purpose | Example |
|---|---|---|
level |
Alert severity (0–16). Higher = more severe. 10 = warning, 12 = critical. | 10 |
field name="data.aws.dstport" |
Match the decoded field aws.dstport against a regex. |
22 = port 22 |
field name="data.aws.action" |
Match the action field. | ACCEPT = traffic was allowed |
field name="data.aws.srcaddr |
Match the srcaddr field. | srcaddr against a range of IPs |
description |
Human-readable text for the alert. | Shown in the dashboard |
The External-IP Regex¶
We need to exclude private addresses: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
Luckily, with the help of AI Models, generating the proper regex is no longer difficult.
The regex uses a negative lookahead (?!...) to skip those:
(?!10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.)— "not starting with 10., 172.16–31., or 192.168."[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+— then match a valid IPv4 address
So we're matching: "an IP that does not start with a private prefix."
Create a Monitor¶
If you can recall from Enterprise 101, we used the "Alerting" capability inside Wazuh. Under Alerting, we can create a Monitor, which will run a pre-defined query against all incoming logs. If the log matches the query content, an alert is generated.
We will use the Monitoring and Alerting capability to capture rogue opened ports.
The workflow for the following be as follow:
Navigate to Alerting ➔ Monitors.
Monitor Details:
-
Monitor name: Name your monitor. Select "Per query monitor".
-
Monitor type: Choose "Extraction query editor".
Schedule:
-
By interval.
-
Run every 1 Minute(s).
Select Data:
- Indexes:
wazuh-alerts-4.x-*
Query: Paste in Query.
Triggers:
-
Trigger Name: Name Trigger.
-
Severity level: Choose severity level.
Inbound SSH Exposed To The Internet¶
<!-- CA101: Inbound traffic to PORT from source (open security group indicator) -->
{
"size": 0,
"query": {
"bool": {
"filter": [
{
"term": {
"data.aws.action": {
"value": "ACCEPT",
"boost": 1
}
}
},
{
"term": {
"data.aws.dstport": {
"value": 22,
"boost": 1
}
}
}
],
"must_not": [
{
"range": {
"data.aws.srcaddr": {
"from": "10.0.0.0",
"to": "10.255.255.255",
"include_lower": true,
"include_upper": true,
"boost": 1
}
}
},
{
"range": {
"data.aws.srcaddr": {
"from": "172.16.0.0",
"to": "172.31.255.255",
"include_lower": true,
"include_upper": true,
"boost": 1
}
}
},
{
"range": {
"data.aws.srcaddr": {
"from": "192.168.0.0",
"to": "192.168.255.255",
"include_lower": true,
"include_upper": true,
"boost": 1
}
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
}
}
Inbound RDP/VNC Exposed To The Internet¶
Change the above SSH rule with:
-
3389: RDP -
5900: TigerVNC, TightVNC, RealVNC
Inbound Database Ports Exposed To The Internet¶
Change the above SSH or RDP rule with:
-
3306: MySQL Server -
5432: PostGreSQL -
1433: Microsoft SQL Server
Port Scan Detection Trigger¶
Here we detect a single source IP connecting to multiple high-value ports in a short window—consistent with nmap-style scanning in the open_vpc discovery phase.
Rule Description In Layman Terms¶
"Alert when the same source IP has triggered our high-value port rules at least four times within 120 seconds."
One IP hitting SSH, then RDP, then MySQL in quick succession is a strong indicator of a port scan.
All we have to do is modify the trigger to be above or equal to whatever we decide to choose.
For example:
return ctx.results[0].hits.total.value >= 4;
Would trigger if the value is above or equal to 4 based on the run frequency interval, so within the last 1 minutes.
Verify Detections¶
We won't be able to use the open-vpc CloudFormation stack. This is due to the settings we used to configure the VPC Flow Logs.
If you can recall, we set up a S3 data lake bucket, which collects our VPC flow logs from project-x-vpc. The CloudFormation stack creates an entirely new VPC.
We can "simulate" this attack by creating a new EC2 instance with any of the above ports opened.
Create EC2 Instance¶
We won't walk though this.
Create a new EC2 intance, under the project-x-vpc. Ensure it is deployed in the public subnet.
Attach a new or pre-defined security group with whatever port you want opened.
Remember, the EC2 instance must also have a service running with the exposed port.
We recommend default port 22 since you will not have to log into the ec2 instance.
Generate Test Traffic (Open VPC Scenario)¶
From an external machine (or [project-x-attacker]), run:
# Scan high-value ports
nmap -p 22,80,443,3306,5432,3389 $PUBLIC_IP
# Or simple connectivity checks
nc -zv $PUBLIC_IP 22
nc -zv $PUBLIC_IP 3389
Wait 5–15 minutes for VPC Flow Logs to be written to S3 and ingested by Wazuh.
View Alerts¶
Navigate to Alerting.
You should see a new alert generate with the opened port in question.
You should see alerts for inbound SSH, RDP, or database traffic from external IPs when the open-vpc stack is deployed and the rules are firing.