Detect Malware with Snort 3 IDS Rules
Run Snort 3 against real malicious traffic and write custom detection rules.
Introduction
30 Second Summary
Every cyberattack that makes the news started with network traffic that someone missed. The difference between a detected threat and a full-blown breach often comes down to the quality of the detection rules.
In this project, you will set up Snort 3 inside a Docker container and run it against real malicious network traffic. You will then write custom detection rules to catch threats that the default rules miss.
What You'll Build
You type one command and Snort fires alerts across your terminal, each one pinpointing a machine in your packet capture that communicated with an attacker's command-and-control server.
By the end of this project, you'll have:
- A working Snort 3 IDS environment running inside a Docker container, ready to process any packet capture you throw at it.
- Custom detection rules that catch command-and-control (C2) traffic patterns the default community rules miss, using content matching, flow keywords, and HTTP-specific options.
- A documented detection engineering workflow pushed to GitHub, proving you can create the detection logic that generates the alerts a SOC team investigates.
- Secret Mission: Write a blocking rule and test it with Snort's inline mode, moving from passive detection to actively blocking malicious traffic.
Are there any prerequisites?
This project builds on a previous Wireshark PCAP analysis project. You should be comfortable with network protocols and reading packet captures before starting.
You also need Git installed and a GitHub account.
Before We Start
Before you dive in, take a moment to lock in what you are about to build and why it matters for your cybersecurity goals.
Set Up Docker and Pull the Snort 3 Container
Building Snort 3 from source requires compiling 12+ dependencies individually. That process takes 45+ minutes before you can even run your first scan. The official Cisco Talos Docker container gives you a pre-built Snort 3 environment in a single pull command.
In this step, you will install Docker Desktop, pull the Snort 3 container, enter it, and download a malicious PCAP to analyze in the steps ahead.
In this step, get ready to:
- Install Docker Desktop on Windows.
- Pull and start the official Cisco Talos Snort 3 container.
- Download a malicious PCAP for analysis.
Install Docker Desktop
Docker lets you run pre-built Linux environments inside lightweight containers on your Windows machine. Instead of compiling Snort 3 and its dependencies yourself, you will pull a container that already has everything installed.
- Press the Windows key to open your search bar.
- Type PowerShell and press Enter to open it.
- Check if Docker is already installed by running this command:
docker --version
✔️ I see a version number
Docker is already installed. Make sure Docker Desktop is running (the whale icon in the system tray should be still, not animating).
Skip ahead to the next substep.
ⓧ Command not found
- Open your browser and go to the Docker Desktop install page:
- https://docs.docker.com/desktop/setup/install/windows-install/
- Click Docker Desktop for Windows - x86_64 to download the installer.
- Run the downloaded installer and follow the prompts to complete the installation.
What happens during the install?
The installer may ask you to enable WSL 2 (Windows Subsystem for Linux). Accept this. Docker Desktop uses WSL 2 to run Linux containers on Windows.
You may need to restart your computer after installation. This is normal.
- After the restart, open Docker Desktop by pressing the Windows key, typing Docker Desktop, and pressing Enter.
- Wait for the Docker engine to start. The whale icon in the system tray will stop animating when the engine is ready.
- Return to PowerShell and run the version check again:
docker --version
You should now see a version number printed in the terminal.
Docker Desktop won't start?
Make sure virtualization is enabled in your BIOS settings. Docker Desktop requires hardware virtualization (Intel VT-x or AMD-V) to run containers.
If you see an error about WSL 2, open PowerShell as Administrator and run wsl --update, then restart Docker Desktop.
Help me troubleshoot Docker Desktop not starting on Windows.
Pull and start the Snort 3 container
The official Snort 3 container from Cisco Talos is a purpose-built learning environment. It includes Snort 3, all its dependencies, and training labs ready to go.
- In PowerShell, pull the Snort 3 container image by running this command:
docker pull ciscotalos/snort3
You will see Docker downloading multiple layers. This may take a few minutes depending on your internet speed.
- Once the pull completes, start the container by running this command:
docker run --name snort3 -h snort3 -u snorty -w /home/snorty -d -it ciscotalos/snort3 bash
What do these flags mean?
- --name snort3 gives the container a friendly name you can reference later.
- -h snort3 sets the hostname inside the container.
- -u snorty runs as the snorty user (not root).
- -w /home/snorty sets the working directory inside the container.
- -d runs the container in the background (detached mode) so it does not take over your PowerShell window.
- -it keeps an interactive terminal session available for when you attach to the container.
Docker prints a long container ID string. That confirms the container is running.
- Enter the running container by running this command:
docker exec -it snort3 bash
Your terminal prompt changes to show you are now inside a Linux shell as the snorty user. Everything you type from here runs inside the container, not on your Windows machine.
Before you run the next command, what do you think the output will look like? What information would a version check show for an IDS tool?
- Verify Snort 3 is working by running this command inside the container:
snort -V
Snort prints its version number along with library details. This confirms Snort 3 is installed and ready to process traffic.
Seeing 'command not found' for snort?
Make sure you ran docker exec -it snort3 bash first. The snort command only exists inside the container, not in your Windows PowerShell.
If the container is not running, go back to PowerShell and run docker start snort3 before trying docker exec again.
Help me get snort -V working inside my Docker container.
Download a malicious PCAP inside the container
You need a real malicious PCAP containing HTTP-based C2 traffic to analyze with Snort. The site malware-traffic-analysis.net hosts training PCAPs from real-world infections. You used this same source in your Wireshark project.
- Create a project directory inside the container by running this command:
mkdir -p /home/snorty/project && cd /home/snorty/project
- On your Windows machine (not inside the container), open your browser and go to the malware-traffic-analysis.net training exercises page:
- https://www.malware-traffic-analysis.net/training-exercises.html
- Choose a traffic analysis exercise that involves HTTP-based C2 traffic or malware infection activity.
- On the exercise page, find the download link for the PCAP ZIP file. Right-click the ZIP link and select Copy link address.
What about the ZIP password?
The PCAP files on malware-traffic-analysis.net are distributed as password-protected ZIP archives. The password scheme is listed on the site's About page.
Visit malware-traffic-analysis.net/about.html to find the current password before you try to extract your downloaded file.
- Switch back to your container terminal. Download the PCAP ZIP by running this command (replace the URL with the one you copied):
# Download the PCAP ZIP file
wget [[PCAP_URL="the URL you copied from the exercise page"]]
wget not found?
If wget is not available in the container, try curl instead:
curl -O [[PCAP_URL="the URL you copied from the exercise page"]]
Help me download a file inside the ciscotalos/snort3 Docker container.
- Extract the PCAP from the downloaded ZIP file using the password from the site's About page:
# Extract the PCAP from the password-protected ZIP
unzip -P [[ZIP_PASSWORD="the password from the About page"]] [[ZIP_FILENAME="the-downloaded-file.pcap.zip"]]
unzip not found?
If unzip is not available, you can download and extract the PCAP on your Windows machine using Wireshark (which you already have installed), then copy the extracted .pcap file into the container from PowerShell:
docker cp C:\Users\YourUsername\Downloads\your-pcap-file.pcap snort3:/home/snorty/project/
Help me get a PCAP file into my Snort 3 container.
- Confirm the PCAP file is in your project directory by running:
ls /home/snorty/project/
You should see your .pcap file listed in the output. If you also see the ZIP file, that is fine. The important thing is that the extracted .pcap is present.
Why handle this PCAP inside a container?
PCAPs from malware-traffic-analysis.net contain real malware traffic. Running analysis inside a Docker container isolates the work from your Windows host. The container has no access to your files or network unless you explicitly grant it.
Don't see your PCAP file?
Make sure you are inside the /home/snorty/project/ directory. Run pwd to check your current location.
If you used docker cp from Windows, make sure the destination path matches snort3:/home/snorty/project/ exactly.
Help me locate my PCAP file inside the Snort 3 container.
Your Snort 3 environment is ready, and you have a real malicious PCAP waiting to be analyzed. Next up, you will run Snort against that PCAP with community rules and see what it detects.
Run Snort Against a Malicious PCAP
Your Snort 3 environment is up and running inside the Docker container. Now it's time to put it to work on real malicious traffic.
In this step, you'll run Snort against your malicious PCAP using the community rules that come bundled in the container. This first run establishes a baseline of what gets detected out of the box. Without this baseline, you'd have no way to measure the value of the custom rules you write later.
In this step, get ready to:
- Run Snort in PCAP readback mode with community rules.
- Examine the alert output to understand what Snort detected.
- Document detection gaps where community rules missed suspicious traffic.
Run Snort with the community rules
The community rules bundled in the Snort 3 container provide thousands of pre-written detection signatures maintained by Cisco Talos. Running them against your PCAP reveals what gets caught automatically.
- Switch back to your bash shell inside the snort3 container.
Before you run this, think about what you expect. Do you think the community rules will catch every suspicious pattern in your PCAP, or will some malicious traffic slip through undetected?
- Run Snort in PCAP readback mode with the community rules and alert_fast output by running this command:
snort -c /usr/local/etc/snort/snort.lua -r /home/snorty/project/[[PCAP_FILE="your-pcap-filename.pcap"]] -A alert_fast -q
What does this command do?
- -c /usr/local/etc/snort/snort.lua points Snort to its Lua configuration file, which loads the community rules.
- -r tells Snort to read packets from your PCAP file instead of sniffing a live network interface.
- -A alert_fast sets the output mode to one-line alert summaries for clean, readable output.
- -q suppresses the startup banner and packet statistics, showing only alerts.
Alert lines scroll through your terminal. Each line represents a packet that matched a community detection rule.
Not seeing any alerts?
- Confirm the PCAP file path is correct. Run ls /home/snorty/project/ to verify your filename.
- Make sure you typed -A alert_fast with the underscore. The mode name is alert_fast, not fast.
- If Snort exits immediately with no output, the PCAP may not contain traffic that matches community rules. Try a different PCAP from malware-traffic-analysis.net that contains HTTP-based C2 traffic.
- Why isn't Snort producing alert output when I run it against my PCAP?
Read the alert output
Each alert line follows a consistent format. Understanding the fields is essential for analyzing what Snort detected and what it missed.
- Look at the beginning of each line. The timestamp shows when the packet was originally captured.
- Find the bracketed numbers, for example [1:2024056:4]. These are the GID (generator ID), SID (signature ID), and revision number. The SID identifies which specific rule fired.
- Read the quoted msg string. This is the human-readable description of the threat the rule detects.
- Check the classification and priority. These indicate the threat category (like trojan-activity) and severity level.
- Look at the end of each line for the protocol, source IP:port, and destination IP:port. These show which hosts were communicating.
What should I focus on?
You don't need to memorize every alert. Focus on three things: which SIDs fired most frequently, which source and destination IPs appear across multiple alerts, and what classification categories Snort assigned (like trojan-activity or attempted-admin).
Document your findings and identify detection gaps
The real value of this baseline run comes from comparing it against what you already know is in the PCAP. Your Wireshark analysis from your previous project is the key.
- Write down the distinct alert messages and their SIDs from the Snort output.
- List the IP addresses that Snort flagged as suspicious.
- Note the threat categories (classifications) Snort assigned to each alert.
- Now think back to your Wireshark analysis. Were there suspicious traffic patterns you identified that Snort did NOT produce an alert for?
What is a detection gap?
A detection gap is traffic your Wireshark analysis flagged as suspicious, but Snort's community rules produced no alert for. These gaps exist because community rules are general-purpose. They cannot cover every specific C2 pattern, newly observed indicator, or unique malware variant.
Common gaps include C2 beacons with custom HTTP headers, unusual URI paths, or connections to IP addresses that are too new for the community rules to include. These are exactly the patterns your custom rules will target.
- Write down at least two or three suspicious patterns from your Wireshark analysis that Snort missed. Note the specific IPs, HTTP paths, User-Agent strings, or other indicators of compromise you observed.
Keep your notes organized
Create a simple text file with two sections: "Detected by Community Rules" (with SIDs, messages, and IPs) and "Missed by Community Rules" (with the specific traffic patterns). You'll use these notes directly when writing your custom rules in the next step.
You now have a clear picture of what the community rules catch and exactly where they fall short. In the next step, you'll write custom Snort 3 rules to fill those detection gaps.
Write Custom Snort 3 Detection Rules
In the previous step, you ran Snort with community rules and documented what got detected. You also spotted traffic patterns from your Wireshark analysis that Snort missed entirely.
Those missed patterns are real detection gaps. Writing custom rules to fill them is the core skill of detection engineering. It is the difference between reading alerts someone else configured and creating the detection logic yourself.
In this step, get ready to:
- Write an IP-based detection rule that flags outbound traffic to a known C2 address.
- Write HTTP content-matching rules using flow keywords and sticky buffers.
- Verify that Snort loads your custom rules without parsing errors.
Create your rules file and write an IP-based detection rule
Every Snort 3 rule follows the same structure: an action, a protocol, source and destination addresses, and a set of rule options in parentheses. Custom rules live in their own file so you can load them alongside or instead of the community ruleset.
- In your container's bash shell, create the custom.rules file with a header and your first rule by running this command:
cat > /home/snorty/project/custom.rules << 'EOF'
# Custom Snort 3 Rules - Malware C2 Detection
# Author: Jaybee124
# Description: Custom detection rules for C2 traffic patterns
# missed by the community ruleset.
# Rule 1: Detect traffic to known C2 IP address
alert ip $HOME_NET any -> $EXTERNAL_NET any (msg:"Custom - Outbound Traffic to Known C2 IP"; sid:1000001; rev:1;)
EOF
What does this command do?
The cat > ... << 'EOF' syntax is called a heredoc. It writes everything between EOF markers into the file. The single quotes around 'EOF' prevent the shell from expanding the $HOME_NET and $EXTERNAL_NET variables, which are Snort variables, not shell variables.
The rule itself breaks down like this:
- alert is the action. It tells Snort to generate an alert when the rule matches.
- ip is the protocol. This matches all IP traffic regardless of transport layer.
- $HOME_NET any -> $EXTERNAL_NET any defines direction. It matches traffic from your internal network to any external address on any port.
- sid:1000001 is a unique Signature ID. Custom rules start at 1000001+ to avoid conflicts with community rule SIDs.
- Confirm the file was created by running:
cat /home/snorty/project/custom.rules
You should see the header comments and your first rule printed to the terminal.
See an empty file or 'No such file' error?
- Make sure you typed EOF on its own line at the end. The heredoc closes only when it sees that exact marker.
- Check that the path /home/snorty/project/ exists. This is the directory you created when you downloaded the PCAP.
- help me debug why my custom.rules file was not created
Add content-matching and URI-specific detection rules
An IP-based rule catches all traffic to a known bad address. The next two rules go deeper. They inspect the actual payload of HTTP traffic to match specific patterns that fingerprint C2 communication.
- Append two more rules to your custom.rules file by running this command:
cat >> /home/snorty/project/custom.rules << 'EOF'
# Rule 2: Detect C2 beacon via HTTP content match
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"Custom - Suspicious HTTP C2 Beacon Pattern"; flow:established,to_server; content:"suspicious-pattern"; nocase; fast_pattern; classtype:trojan-activity; sid:1000002; rev:1;)
# Rule 3: Detect C2 communication via HTTP URI path
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"Custom - Suspicious HTTP URI C2 Path"; flow:established,to_server; content:"/suspicious/path"; http_uri; nocase; classtype:trojan-activity; sid:1000003; rev:1;)
EOF
Replace the placeholder patterns with your IOCs
The strings suspicious-pattern and /suspicious/path are placeholders. Replace them with actual indicators of compromise (IOCs) you found in your Wireshark analysis of the PCAP.
Good candidates include a distinctive User-Agent string, a repeating URI path in the C2 traffic, or a unique HTTP header value that appeared in the suspicious connections.
What do these rules do?
Rule 2 uses content matching to scan the HTTP payload for a specific string. The supporting keywords fine-tune the match:
- flow:established,to_server matches only established TCP sessions heading toward the server. This filters out connection setup noise.
- nocase makes the match case-insensitive, so it catches Suspicious-Pattern and SUSPICIOUS-PATTERN too.
- fast_pattern hints Snort's pattern matcher to use this string as the primary search term, improving performance when the rule has multiple content matches.
Rule 3 introduces a sticky buffer. The http_uri keyword scopes the content match to just the URI portion of the HTTP request. This is more precise than scanning the entire payload, which reduces false positives.
- Verify the complete file by running:
cat /home/snorty/project/custom.rules
You should see all three rules printed to the terminal, each with its own comment, SID, and rule options.
See duplicate rules or missing rules?
- If you see duplicate rules, you may have run the append command (>>) more than once. Re-run the first heredoc command (the one with a single >) to overwrite the file, then run the append command exactly once.
- If a rule is cut off or missing, check that each heredoc command ends with EOF on its own line with no leading spaces.
- help me fix my custom.rules file
✔️ Awesome, I've got everything!
Great. Double check you see all three rules with SIDs 1000001, 1000002, and 1000003 in the output.
ⓧ I'd like to double check the full code
Here is the complete custom.rules file. Compare it against your cat output line by line.
# Custom Snort 3 Rules - Malware C2 Detection
# Author: Jaybee124
# Description: Custom detection rules for C2 traffic patterns
# missed by the community ruleset.
# Rule 1: Detect traffic to known C2 IP address
alert ip $HOME_NET any -> $EXTERNAL_NET any (msg:"Custom - Outbound Traffic to Known C2 IP"; sid:1000001; rev:1;)
# Rule 2: Detect C2 beacon via HTTP content match
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"Custom - Suspicious HTTP C2 Beacon Pattern"; flow:established,to_server; content:"suspicious-pattern"; nocase; fast_pattern; classtype:trojan-activity; sid:1000002; rev:1;)
# Rule 3: Detect C2 communication via HTTP URI path
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"Custom - Suspicious HTTP URI C2 Path"; flow:established,to_server; content:"/suspicious/path"; http_uri; nocase; classtype:trojan-activity; sid:1000003; rev:1;)
Verify Snort loads your custom rules
A rule that looks correct on paper can still have a syntax error that Snort catches at load time. The -R flag tells Snort to load a specific rules file alongside its Lua configuration.
Before you run this, do you think Snort will accept all three rules cleanly, or will it report a parsing error?
- Test that Snort can parse your custom rules by running:
snort -c /usr/local/etc/snort/snort.lua -R /home/snorty/project/custom.rules -r /home/snorty/project/[[PCAP_FILE="your-pcap-filename.pcap"]] -A alert_fast -q
What does this command do?
- -c /usr/local/etc/snort/snort.lua loads the main Snort Lua configuration file.
- -R /home/snorty/project/custom.rules tells Snort to load your custom rules file on top of the config.
- -r reads from your PCAP file so Snort has traffic to process.
- -A alert_fast outputs one-line alert summaries. -q suppresses non-alert output for cleaner reading.
If Snort starts and processes the PCAP without printing any rule parsing errors, your rules are syntactically valid. You may already see alert lines from your custom rules firing. That is a great sign, but you will do a thorough analysis of those alerts in the next step.
Seeing a rule parsing error?
- Check that every rule option ends with a semicolon. A missing semicolon after nocase or fast_pattern is the most common cause.
- Make sure each rule is on a single line with no line breaks in the middle. A rule that wraps across two lines looks like two broken rules to Snort.
- Verify that the parentheses around the rule options are balanced. Each rule starts with ( after the port and ends with ) at the end of the line.
- help me fix my Snort rule parsing error
Why this approach over editing the main config?
You could add rules directly to Snort's main Lua configuration. The -R flag keeps your custom rules in a separate file instead. This makes them portable, version-controllable with Git, and easy to share without touching the base Snort install.
Your custom rules are loaded and Snort accepts them. Next up, you will run Snort with only your custom rules and analyze the alerts they produce to prove they catch what the community rules missed.
Validate Rules and Analyze Alerts
In the last step, you built three custom Snort 3 rules targeting C2 traffic patterns your Wireshark analysis revealed. The rules loaded without parsing errors, but that only proves the syntax is valid.
Now you need to prove they actually fire against the target traffic. Running Snort with only your custom rules isolates your detections from the thousands of community rules. Every alert that appears is yours, making it clear exactly what your rules add.
In this step, get ready to:
- Run Snort with only your custom rules using the verbose cmg alert mode.
- Verify each alert matches your rule's SID, message, and expected C2 hosts.
- Document a comparison of community rule detections vs. your custom rule detections.
Run Snort with your custom rules in cmg mode
In Step 2, you used -A alert_fast for one-line alert summaries. This time you need more detail to confirm your content matches landed on the right bytes.
The cmg alert mode shows each alert alongside a hex dump of the alerting packet. This lets you visually verify exactly which bytes triggered the match.
- Before you run this command, predict: do you think all three of your rules will fire, or will some stay silent? Why?
- Run Snort with only your custom rules against your PCAP by running this command inside the container:
snort -c /usr/local/etc/snort/snort.lua -R /home/snorty/project/custom.rules -r /home/snorty/project/[[PCAP_FILE="your-capture.pcap"]] -A cmg -q
What does this command do?
- -R /home/snorty/project/custom.rules loads only your custom rules file, ignoring the community ruleset entirely. This isolates your detections.
- -A cmg activates the CMG alert mode, which prints each alert alongside a hex dump of the matching packet buffers.
- -q suppresses statistics and non-alert output so you only see the alerts themselves.
You should see alert lines in the terminal. Each alert shows the SID in brackets (e.g., [1:1000001:1]), the msg string from your rule, and the source/destination IP addresses involved.
Below each alert, the CMG hex dump displays the raw bytes that matched your rule's content keywords, decoded alongside their ASCII representation.
Not seeing any alerts?
- Check that the file path to your PCAP is correct. A typo in the filename means Snort reads zero packets.
- If Rule 1 (IP-based) fires but Rules 2 and 3 do not, your content strings may not match what is actually in the PCAP. Open the PCAP in Wireshark and verify the exact byte patterns you are targeting.
- Make sure your flow:established,to_server keyword matches the direction of the C2 traffic. If the traffic flows the other direction, try to_client.
- help me debug why my Snort 3 custom rules are not producing alerts against my PCAP
Verify each alert against your rules
Seeing alerts is the first hurdle. Now you need to confirm each alert actually matches what you intended.
- For each alert line, check these three things:
- The SID in the brackets matches one of your custom rule SIDs: 1000001, 1000002, or 1000003.
- The msg string matches your rule's description (e.g., Custom - Outbound Traffic to Known C2 IP).
- The source and destination IP addresses are the expected C2 hosts from your Wireshark analysis.
What if a rule did not fire?
A silent rule is not necessarily broken. It may mean the traffic pattern you targeted is not present in this specific PCAP. Cross-reference the content string in your rule against the actual packet data in Wireshark.
Common causes for silent rules include incorrect content strings (even one character off prevents a match), a missing nocase keyword when the payload uses different capitalisation, or the wrong directional flow value.
- Use the hex dump beneath each alert to confirm the content match landed on the bytes you intended. The ASCII column on the right side shows the decoded text.
Compare community rules vs. custom rules and document the results
You now have two sets of results: what the community rules caught in Step 2, and what your custom rules add here. This side-by-side comparison is the heart of your portfolio writeup. It proves you can identify what default tooling misses and fill the gaps.
- Pull up the community rule alert output you documented in Step 2.
- Create a comparison by documenting the following:
- Which threats the community rules detected (list the SIDs, alert messages, and affected IPs).
- Which threats your custom rules caught that the community rules missed (list your SIDs, alert messages, and affected IPs).
- Why those custom detections are valuable. For each custom rule, write one sentence explaining what gap it fills.
Why does this comparison matter?
In a SOC environment, the value of a detection engineer is measured by the gap between what ships out-of-the-box and what they add. This comparison is exactly the artifact that demonstrates that skill to an employer.
Your custom rules prove you can go beyond running a tool. You can extend it with original detection logic tailored to a specific threat.
Your custom rules are now validated. You have proof they fire against real malicious traffic, and you have a documented comparison showing the value they add over the defaults. Next up, you will package everything into a professional GitHub repository.
Document and Push to GitHub
Your custom rules fire correctly against the malicious PCAP, and you have a documented comparison of what the community rules caught versus what your rules add. All of this work currently lives inside a Docker container.
A detection engineering project is only portfolio-worthy if someone else can understand your analysis and reproduce your work. In this step, you will extract your files from the container, write a professional README, and push everything to GitHub.
In this step, get ready to:
- Copy your project files from the Docker container to your Windows machine.
- Create a professional README documenting your detection engineering workflow.
- Push your project to a GitHub repository as a portfolio artifact.
Save alert output and copy files from the container
Before you copy files to your Windows machine, you need to organize your work inside the container so that everything comes out in a clean folder structure.
- Switch back to your container shell. If you exited the container, re-enter it by running this command in PowerShell:
docker exec -it snort3 bash
- Create alerts/ and analysis/ directories inside your project folder by running these commands:
mkdir -p /home/snorty/project/alerts
mkdir -p /home/snorty/project/analysis
- Save your custom rule alert output to a file by re-running Snort with output redirected:
snort -c /usr/local/etc/snort/snort.lua -R /home/snorty/project/custom.rules -r /home/snorty/project/[[PCAP_FILE="your-pcap-filename.pcap"]] -A alert_fast -q > /home/snorty/project/alerts/custom-alerts.txt
What does this command do?
This is the same Snort command you ran in Step 4, but with > /home/snorty/project/alerts/custom-alerts.txt appended. The > symbol redirects the terminal output into a text file instead of printing it to the screen.
- Confirm the alert output was saved by running:
cat /home/snorty/project/alerts/custom-alerts.txt
You should see the same alert lines from your custom rules (SIDs 1000001, 1000002, 1000003) now saved in the file.
- Create a detection comparison notes file in the analysis/ folder by running:
cat > /home/snorty/project/analysis/detection-comparison.txt << 'EOF'
Community Rules Detected:
- (List the alert messages and SIDs from your Step 2 run)
Custom Rules Detected:
- (List your custom rule SIDs and what each detects)
Detection Gaps Filled:
- (Describe what your custom rules catch that the defaults missed)
EOF
What does this command do?
The cat > file << 'EOF' syntax creates a new file and lets you type its contents directly in the terminal. Everything between << 'EOF' and EOF becomes the file's content.
Replace the placeholder text in parentheses with your actual findings from Steps 2 and 4. This file documents the comparison between default and custom detections.
- Confirm both files exist by running:
ls /home/snorty/project/alerts/
ls /home/snorty/project/analysis/
You should see custom-alerts.txt in the alerts/ listing, and detection-comparison.txt in the analysis/ listing.
- Exit the container by running:
exit
You are now back in your PowerShell terminal on Windows. Time to copy everything out of the container.
- Copy the entire project directory from the container to your Windows machine by running:
docker cp snort3:/home/snorty/project C:\Users\[[WIN_USERNAME="YourUsername"]]\snort3-ids-project
What does this command do?
The docker cp command copies files between a Docker container and your host machine. Here it pulls the entire /home/snorty/project directory out of the snort3 container and saves it to your Windows user folder as snort3-ids-project.
The copied directory includes the malicious PCAP file. This file contains real malware artifacts and should not be redistributed or committed to a public repository.
- Delete the PCAP file from your local copy by running:
Remove-Item C:\Users\[[WIN_USERNAME="YourUsername"]]\snort3-ids-project\[[PCAP_FILE="your-pcap-filename.pcap"]]
- Confirm the project files are in place by running:
dir C:\Users\[[WIN_USERNAME="YourUsername"]]\snort3-ids-project
You should see custom.rules, the alerts/ folder, and the analysis/ folder listed. The PCAP file should be gone.
Not seeing the project folder?
- Make sure Docker Desktop is still running. The docker cp command needs the Docker engine to access the container's filesystem.
- Check that you replaced YourUsername with your actual Windows username. Run whoami in PowerShell to see your current username.
- Verify the container name is snort3 by running docker ps and checking the NAMES column.
Why isn't docker cp finding my container or creating the output folder?
Create a README for your project
A strong README tells a hiring manager exactly what you did, why it matters, and how to reproduce it. This is the most important file in your repository.
- Navigate to your project directory in PowerShell by running:
cd C:\Users\[[WIN_USERNAME="YourUsername"]]\snort3-ids-project
- Create a new file called README.md by running:
New-Item README.md
- Open README.md in a text editor. You can open it with Notepad by running:
notepad README.md
- Paste the following content into the file. This first section covers the project overview, skills demonstrated, and tools used:
# Snort 3 IDS Detection Engineering: Custom C2 Rules
## Overview
This project documents a detection engineering workflow using Snort 3 IDS (via the official Cisco Talos Docker container) to analyze malicious network traffic and write custom detection rules. A real-world malicious PCAP containing command-and-control (C2) traffic was analyzed first with community rules, then custom rules were written to detect traffic patterns the defaults missed.
## Skills Demonstrated
- Snort 3 IDS operation and configuration (Lua-based config)
- Docker containerization for security tooling
- Custom Snort 3 rule writing (content matching, flow keywords, HTTP sticky buffers)
- PCAP offline analysis and alert interpretation
- Detection gap analysis and documentation
- Professional detection engineering reporting
## Tools Used
- Snort 3 (ciscotalos/snort3 Docker container)
- Docker Desktop
- Wireshark
- Git / GitHub
What does this section cover?
The Overview tells the reader the scenario at a glance. The Skills Demonstrated section is what a hiring manager scans first. It maps directly to the qualifications listed in SOC analyst job postings.
- Continue adding the following content below the Tools Used section. This covers your findings, file descriptions, and reproduction steps:
## Community Rule Findings
(Summary of what the community rules detected when run against the PCAP)
## Custom Rule Detections
(Summary of what your custom rules detect and why they are needed)
## Files
- `custom.rules` - Custom Snort 3 detection rules
- `analysis/` - Alert analysis and comparison notes
- `alerts/` - Sample alert output from custom rules run
## How to Reproduce
1. Install Docker Desktop
2. Pull the Snort 3 container: `docker pull ciscotalos/snort3`
3. Start the container: `docker run --name snort3 -h snort3 -u snorty -w /home/snorty -d -it ciscotalos/snort3 bash`
4. Enter the container: `docker exec -it snort3 bash`
5. Obtain a malicious PCAP from malware-traffic-analysis.net
6. Run with custom rules: `snort -c /usr/local/etc/snort/snort.lua -R custom.rules -r <pcap-file> -A alert_fast -q`
## Source
PCAP from [malware-traffic-analysis.net](https://malware-traffic-analysis.net)
What does this section cover?
The Community Rule Findings and Custom Rule Detections sections are placeholders for now. You will fill them in with your actual findings in a moment.
The How to Reproduce section lets anyone clone your repo and re-run the analysis. This is what turns a one-time exercise into a credible portfolio piece.
- Replace the placeholder text in the Community Rule Findings section with a summary of the alert messages, SIDs, and threat categories you recorded in Step 2.
- Replace the placeholder text in the Custom Rule Detections section with a summary of what your three custom rules detect and why those detections matter.
- Save the file in your text editor.
- Confirm the file exists by running:
dir
You should see README.md, custom.rules, alerts/, and analysis/ all listed in the directory.
README not showing in the directory?
- Make sure you saved the file in your text editor before checking.
- Verify you are in the snort3-ids-project directory. Run pwd to confirm your current location.
My README.md file isn't appearing in my project directory on Windows. Help me figure out where it saved.
✔️ Awesome, I've got everything!
Great. Double check you have saved README.md with your actual findings filled in.
ⓧ I'd like to double check the full code
Your README.md was built from two chunks above. Scroll up and confirm that both chunks are present in order:
- Chunk 1: The title, Overview, Skills Demonstrated, and Tools Used sections.
- Chunk 2: Community Rule Findings, Custom Rule Detections, Files, How to Reproduce, and Source sections.
Make sure the Community Rule Findings and Custom Rule Detections sections contain your actual analysis, not the placeholder text.
Push your project to GitHub
With your files organized and documented, it is time to version-control the project and push it to GitHub where employers can see it.
- Initialize a Git repository and make your first commit by running these commands:
# Initialize a new Git repository
git init
# Stage all project files for commit
git add .
# Commit with a descriptive message
git commit -m "Add Snort 3 IDS detection engineering project"
What do these commands do?
- git init creates a new Git repository in your current folder.
- git add . stages every file in the directory for the next commit.
- git commit -m saves a snapshot of all staged files with a message describing the change.
You should see output listing the files added to the commit, including custom.rules, README.md, and files inside alerts/ and analysis/.
Seeing a warning about default branch name?
Git may print a hint about setting a default branch name. This does not affect your commit. If your default branch is named master instead of main, rename it by running:
git branch -M main
My git init or git commit is failing in PowerShell. Help me troubleshoot.
Now you need to create a remote repository on GitHub to push your local project to.
- Open your browser and go to github.com.
- Click the + icon in the top right corner.
- Select New repository.
- Enter snort3-ids-project as the repository name.
- Leave the repository set to Public.
- Do not check any of the initialization boxes (no README, no .gitignore, no license). You already have your local files ready.
- Click Create repository.
GitHub will show a quick setup page with your repository URL. Copy the HTTPS URL displayed at the top of the page.
- Back in PowerShell, connect your local repository to GitHub and push your code by running:
# Connect your local repo to the GitHub remote
git remote add origin [[REPO_URL="https://github.com/your-username/snort3-ids-project.git"]]
# Push your commit to GitHub
git push -u origin main
What do these commands do?
- git remote add origin links your local repository to the GitHub repository you just created.
- git push -u origin main uploads your committed files to GitHub. The -u flag sets origin main as the default push target for future pushes.
Push rejected or authentication error?
- If you see an authentication error, Git may prompt you to sign in via a browser window. Follow the prompts to authorize Git to access your GitHub account.
- If the push is rejected because the remote contains work you do not have locally, you may have checked one of the initialization boxes on GitHub. Delete the GitHub repository, recreate it with no initialization options, and try the push again.
My git push to GitHub is failing with an error. Help me figure out what went wrong.
Before you check your repository, what do you expect to see on the GitHub page? Think about which files should be listed and what the main page should display.
- Open your browser and visit your repository URL:
[[REPO_URL="https://github.com/your-username/snort3-ids-project.git"]]
You should see your README.md rendered on the main page with your project overview and skills demonstrated. The file list at the top should show custom.rules, README.md, and the alerts/ and analysis/ folders. No PCAP file should be present.
Secret mission
Write an Inline Blocking Rule and Test It
So far, your Snort rules detect threats and fire alerts. But an IDS can do more than watch. In this mission, you will write a blocking rule and test Snort 3's inline mode using the dump DAQ to prove your rule would have stopped the C2 traffic cold.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally using Docker, so there are no ongoing cloud costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- Docker container snort3 (running the ciscotalos/snort3 image).
- Docker image ciscotalos/snort3 (stored locally).
- Local project files at C:\Users\YourUsername\snort3-ids-project\.
- GitHub repository containing your custom rules and README.
- Docker Desktop (installed on Windows).
Keep everything running
No action needed. Choose this if you are still actively building or plan to revisit this project soon.
- Your snort3 container stays running in the background. Docker Desktop uses some memory while active.
- Your local project files and GitHub repository remain as they are.
- Docker Desktop stays installed and ready for future projects.
Pause - I'll come back to this later
Shut down the running container to free up memory, but keep your files and Docker Desktop installed so you can pick up where you left off.
- Stop the snort3 container by running this command in PowerShell:
docker kill snort3
- Your container is now stopped but still exists. You can restart it later with docker start snort3 and re-enter it with docker exec -it snort3 bash.
- Your local project files, GitHub repository, and Docker Desktop all stay in place.
Delete - I don't want to use this again
Remove all project resources and start fresh. Follow each step below to clean up everything.
- Stop and remove the snort3 container by running these commands in PowerShell:
docker kill snort3
docker rm snort3
- Remove the ciscotalos/snort3 Docker image by running:
docker rmi ciscotalos/snort3
- Delete your local project folder by running:
Remove-Item -Recurse -Force C:\Users\YourUsername\snort3-ids-project
- Delete your GitHub repository. Go to your repository page on GitHub, click Settings, scroll to the bottom of the page, and click Delete this repository under the Danger Zone section. Follow the confirmation prompts.
- Uninstall Docker Desktop. Open Windows Settings, select Apps, then Apps & features. Find Docker Desktop in the list, select Uninstall, and confirm.
Nice Work!
Nice Work!
Nice work! You just completed a full detection engineering workflow using Snort 3, from running an IDS against real malicious traffic to writing the custom rules that fill gaps the defaults missed.
You've learned how to:
- Run Snort 3 inside a Docker container against a real malicious PCAP and analyze the alert output to identify what community rules caught and what they missed.
- Write custom Snort 3 rules using content matching, flow keywords, and HTTP-specific sticky buffers to fill detection gaps, then validate them in isolation against the target traffic.
- Document a complete detection engineering workflow and push your custom rules, analysis, and report to GitHub as a portfolio artifact that proves you can create the detection logic a SOC team investigates.
- Secret Mission: Wrote a block rule and tested it with Snort's dump DAQ in inline mode, proving IPS prevention capability.
Ready to quiz yourself?