Skip to content
CSY103 Week 04 Beginner

Practice loops and iteration before moving to reading resources.

Programming Fundamentals

Track your progress through this week's content

Opening Framing: Scale Changes Everything

In Week 3, you wrote scripts that analyze one login attempt, one IP address, one packet. But real security work involves millions. A SOC analyst doesn't review one log entry—they review millions. A vulnerability scanner doesn't check one port—it checks thousands.

Loops are what make this scale possible. Instead of writing the same code a thousand times, you write it once and let the loop repeat it. This is the fundamental difference between manual and automated security: automation means loops.

This week, you'll learn to process entire log files, scan port ranges, and iterate through lists of indicators—all with code that's barely longer than what you wrote for a single item.

Key insight: Without loops, scripts are calculators. With loops, they become security tools. Every scanner, every parser, every automated detector uses loops to achieve scale.

1) The For Loop: Iterating Over Collections

The for loop processes each item in a collection one at a time:

# Iterate over a list of IPs
suspicious_ips = ["192.168.1.50", "10.0.0.25", "172.16.0.100"]

for ip in suspicious_ips:
    print(f"Checking IP: {ip}")

# Output:
# Checking IP: 192.168.1.50
# Checking IP: 10.0.0.25
# Checking IP: 172.16.0.100

How It Works:

  • for - keyword that starts the loop
  • ip - variable that holds the current item (you choose the name)
  • in - keyword connecting variable to collection
  • suspicious_ips - the collection to iterate over
  • The indented block runs once for each item
# Iterate over characters in a string
password = "abc123"

for char in password:
    print(f"Character: {char}")

# Useful for checking password composition

Key insight: The loop variable (ip, char) automatically takes on each value in sequence. You don't manage this—Python handles it.

2) Range: Generating Number Sequences

The range() function generates sequences of numbers—perfect for port scanning, counting, and indexed access:

# range(stop) - 0 to stop-1
for i in range(5):
    print(i)  # 0, 1, 2, 3, 4

# range(start, stop) - start to stop-1
for port in range(20, 26):
    print(f"Scanning port {port}")  # 20, 21, 22, 23, 24, 25

# range(start, stop, step) - with increment
for port in range(20, 30, 2):
    print(f"Port {port}")  # 20, 22, 24, 26, 28

Security Application: Port Range Scanning

# Simulate scanning well-known ports
print("Scanning well-known ports (1-1024)...")
open_ports = []

for port in range(1, 1025):
    # In real scanner, this would check if port is open
    # Here we simulate some ports being "open"
    if port in [22, 80, 443, 8080]:
        open_ports.append(port)
        print(f"[OPEN] Port {port}")

print(f"\nScan complete. {len(open_ports)} open ports found.")

Key insight: range() is memory-efficient—it doesn't create all numbers at once, just generates them as needed. You can range(1, 1000000) without running out of memory.

3) The While Loop: Condition-Based Repetition

While loops repeat as long as a condition is True—useful when you don't know in advance how many iterations you need:

# Basic while loop
attempts = 0
max_attempts = 3

while attempts < max_attempts:
    print(f"Login attempt {attempts + 1}")
    attempts += 1

print("Max attempts reached - account locked")

Security Application: Retry with Backoff

# Simulating connection retry logic
import time

max_retries = 5
retry_count = 0
connected = False

while not connected and retry_count < max_retries:
    retry_count += 1
    print(f"Connection attempt {retry_count}...")
    
    # Simulate: connection succeeds on attempt 3
    if retry_count == 3:
        connected = True
        print("Connected successfully!")
    else:
        wait_time = retry_count * 2  # Exponential backoff
        print(f"Failed. Waiting {wait_time} seconds...")
        # time.sleep(wait_time)  # Uncomment for real delay

if not connected:
    print("All retries exhausted. Connection failed.")

WARNING: Infinite Loops

# DANGER: This runs forever!
# while True:
#     print("This never stops")

# Always ensure your condition will eventually become False
# or use 'break' to exit

Key insight: Use for when you know how many times to loop (or are iterating a collection). Use while when you loop until a condition changes.

4) Loop Control: break and continue

Sometimes you need to exit a loop early or skip certain iterations:

# break - exit loop immediately
blocklist = ["192.168.1.100", "10.0.0.50", "BLOCKED", "172.16.0.1"]

for ip in blocklist:
    if ip == "BLOCKED":
        print("Encountered invalid entry - stopping")
        break
    print(f"Processing: {ip}")

# Output:
# Processing: 192.168.1.100
# Processing: 10.0.0.50
# Encountered invalid entry - stopping
# continue - skip to next iteration
log_entries = ["INFO: Started", "ERROR: Failed", "INFO: Running", "ERROR: Crash"]

print("Showing only ERROR entries:")
for entry in log_entries:
    if not entry.startswith("ERROR"):
        continue  # Skip non-error entries
    print(entry)

# Output:
# Showing only ERROR entries:
# ERROR: Failed
# ERROR: Crash

Security Application: Finding First Match

# Search for malicious indicator - stop at first match
indicators = ["clean.exe", "safe.dll", "malware.exe", "normal.doc"]
known_malware = ["malware.exe", "trojan.exe", "virus.dll"]

found_threat = None
for file in indicators:
    if file in known_malware:
        found_threat = file
        break  # No need to continue searching

if found_threat:
    print(f"ALERT: Malware detected - {found_threat}")
else:
    print("Scan complete - no threats found")

Key insight: break is essential for efficiency. Why check 10,000 more files once you've found malware? Exit early, respond fast.

5) Nested Loops and Loop Patterns

Loops can contain other loops—useful for multi-dimensional data like scanning multiple hosts across multiple ports:

# Nested loop: scan multiple hosts, multiple ports
hosts = ["192.168.1.1", "192.168.1.2", "192.168.1.3"]
ports = [22, 80, 443]

for host in hosts:
    print(f"\nScanning {host}...")
    for port in ports:
        print(f"  Checking {host}:{port}")

# This produces 9 checks (3 hosts × 3 ports)

Accumulator Pattern: Building Results

# Count occurrences in log
log_lines = [
    "Failed login from 192.168.1.50",
    "Successful login from 192.168.1.10",
    "Failed login from 192.168.1.50",
    "Failed login from 10.0.0.25",
    "Failed login from 192.168.1.50"
]

failed_count = 0
for line in log_lines:
    if "Failed" in line:
        failed_count += 1

print(f"Total failed logins: {failed_count}")

Filter Pattern: Collecting Matches

# Extract all IPs with failed logins
failed_ips = []
for line in log_lines:
    if "Failed" in line:
        # Extract IP (simplified - assumes consistent format)
        ip = line.split("from ")[1]
        if ip not in failed_ips:
            failed_ips.append(ip)

print(f"IPs with failed logins: {failed_ips}")

Key insight: Most security scripts follow these patterns—iterate through data, accumulate counts, filter matches. Recognize the pattern, apply it to any problem.

Real-World Context: Loops in Security Operations

Loops power every security tool you'll encounter:

Nmap Port Scanner: At its core, Nmap loops through IP ranges and port ranges. A command like nmap -p 1-1000 192.168.1.0/24 creates nested loops: for each of 256 hosts, check each of 1000 ports. That's 256,000 checks from one command.

Log Analysis: Tools like Splunk and ELK process billions of log entries using loops. Every search query loops through indexed data. The SPL query index=firewall action=blocked | stats count by src_ip loops through entries, filtering and counting.

Brute Force Attacks: From the attacker's perspective, credential stuffing is a loop: for each username/password pair in a list, attempt login. A 10,000-entry credential list is just a for loop with 10,000 iterations.

MITRE ATT&CK Reference: Technique T1110 (Brute Force) describes attacks that are essentially loops. Understanding loops helps you understand how attacks scale and how to detect them through iteration patterns (many attempts from one source).

Key insight: Loops are morally neutral—they amplify both attack and defense. Attackers loop to brute force; defenders loop to detect. The tool is the same.

Guided Lab: Log File Analyzer

Let's build a script that processes multiple log entries and produces a security summary—a simplified version of what SIEM tools do.

Step 1: Create the Script

Create log_analyzer.py:

# Log File Analyzer
# Demonstrates loops for security log processing

# Simulated log entries (in reality, read from file)
log_entries = [
    "2024-01-15 09:23:45 INFO Login successful user=jsmith src=192.168.1.10",
    "2024-01-15 09:24:12 WARN Failed login user=admin src=203.0.113.50",
    "2024-01-15 09:24:15 WARN Failed login user=admin src=203.0.113.50",
    "2024-01-15 09:24:18 WARN Failed login user=admin src=203.0.113.50",
    "2024-01-15 09:25:00 INFO Login successful user=mjones src=192.168.1.25",
    "2024-01-15 09:25:30 WARN Failed login user=root src=203.0.113.50",
    "2024-01-15 09:26:00 ERROR Connection timeout src=10.0.0.5",
    "2024-01-15 09:27:00 WARN Failed login user=admin src=203.0.113.50",
    "2024-01-15 09:28:00 INFO Login successful user=admin src=192.168.1.100",
]

# Initialize counters
total_entries = 0
info_count = 0
warn_count = 0
error_count = 0
failed_logins = 0
suspicious_ips = {}

print("=" * 50)
print("LOG ANALYSIS REPORT")
print("=" * 50)

# Process each entry
for entry in log_entries:
    total_entries += 1
    
    # Count by severity
    if "INFO" in entry:
        info_count += 1
    elif "WARN" in entry:
        warn_count += 1
    elif "ERROR" in entry:
        error_count += 1
    
    # Track failed logins
    if "Failed login" in entry:
        failed_logins += 1
        
        # Extract source IP
        if "src=" in entry:
            src_start = entry.find("src=") + 4
            src_ip = entry[src_start:].split()[0]
            
            # Count by IP
            if src_ip in suspicious_ips:
                suspicious_ips[src_ip] += 1
            else:
                suspicious_ips[src_ip] = 1

# Print summary
print(f"\nTotal entries processed: {total_entries}")
print(f"\nBy Severity:")
print(f"  INFO:  {info_count}")
print(f"  WARN:  {warn_count}")
print(f"  ERROR: {error_count}")

print(f"\nSecurity Findings:")
print(f"  Failed login attempts: {failed_logins}")

print(f"\nFailed logins by source IP:")
for ip, count in suspicious_ips.items():
    status = "ALERT: Possible brute force!" if count >= 3 else ""
    print(f"  {ip}: {count} attempts {status}")

print("\n" + "=" * 50)
print("END OF REPORT")
print("=" * 50)

Step 2: Run and Analyze

Observe how the loop processes each entry and builds the summary.

Step 3: Reflection (mandatory)

  1. How many times does the main for loop execute?
  2. What pattern is used to count entries by severity?
  3. How does the script track counts per IP address?
  4. How would you modify this to read from an actual file?

Week 4 Outcome Check

By the end of this week, you should be able to:

Next week: Functions—where we package our loop-powered logic into reusable, callable tools.

🎯 Hands-On Labs (Free & Essential)

Practice loops and iteration before moving to reading resources.

🎮 TryHackMe: Python Basics (Loops)

What you'll do: Use for/while loops to process lists and ranges.
Why it matters: Every parser and scanner relies on iteration.
Time estimate: 1-1.5 hours

Start TryHackMe Python Basics →

📝 Lab Exercise: Log Loop Parser

Task: Iterate through a list of log entries and count failed logins per IP.
Deliverable: Dictionary output of IP → fail count.
Why it matters: Loop-based aggregation is a core detection pattern.
Time estimate: 45-60 minutes

🏁 PicoCTF Practice: General Skills (Iteration)

What you'll do: Solve beginner challenges that involve loops and repetition.
Why it matters: Many security tasks require repeating checks at scale.
Time estimate: 1-2 hours

Start PicoCTF General Skills →

🛡️ Lab: Eliminate Hardcoded Secrets

What you'll do: Refactor a config loop to pull secrets from environment variables.
Deliverable: Script that loads API key and token from env and prints masked values.
Why it matters: Hardcoded secrets leak in repos, logs, and screenshots.
Time estimate: 45-60 minutes

💡 Lab Tip: Always test loops on small data first to avoid runaway scripts.

🛡️ Secure Coding: Secrets Hygiene

Scripts that process configuration often touch sensitive values. Defensive code keeps secrets out of source control and out of logs.

Secrets handling checklist:
- Never hardcode API keys or passwords
- Load secrets from environment or a vault
- Mask secrets in logs (show last 4 chars)
- Rotate and revoke exposed keys quickly

📚 Building on CSY101 Week-14: Align secrets handling with CIS Controls and ISO 27001 guidance.

Resources

Complete the required resources to build your foundation.

Lab: Brute Force Detector

Goal: Build a script that detects potential brute force attacks by analyzing login attempt patterns.

Linux/Windows Path (same for both)

  1. Create brute_force_detector.py
  2. Create a list of 20+ simulated login attempts with format: "timestamp,username,source_ip,result"
  3. Include a mix of successful and failed logins
  4. Include at least one IP with 5+ failed attempts
  5. Loop through all entries and:
    • Count failed attempts per IP
    • Count failed attempts per username
    • Track timestamps of failures
  6. Alert if any IP has 5+ failures (threshold)
  7. Alert if any username has 3+ failures

Deliverable (submit):

Checkpoint Questions

  1. What is the output of range(5, 10)?
  2. When would you use a while loop instead of a for loop?
  3. What does break do inside a loop?
  4. What does continue do inside a loop?
  5. How many iterations does a nested loop with outer=3 and inner=4 produce?
  6. How do brute force attacks relate to loops conceptually?

Weekly Reflection

Reflection Prompt (200-300 words):

This week you learned loops—the mechanism that transforms single-item processing into scalable automation. Loops are what make security tools capable of handling enterprise-scale data.

Reflect on these questions:

A strong reflection will connect loops to the concept of scale in security operations—both offensive and defensive.

Verified Resources & Videos

Loops unlock scale. With this week's knowledge, you can process thousands of log entries, scan port ranges, and build real security automation. Next week: packaging this power into reusable functions.

← Previous: Week 03 Next: Week 05 →

Week 04 Quiz

Test your understanding of the weekly concepts.

Format: 10 multiple-choice questions. Passing score: 70%. Time: Untimed.

Take Quiz