Final Submission for Ghaymah SecOps Assessment
هذا الالتزام موجود في:
356
task2-incident-response/incident_response_plan_PICERL.md
Normal file
356
task2-incident-response/incident_response_plan_PICERL.md
Normal file
@@ -0,0 +1,356 @@
|
||||
# Incident Response Plan (PICERL Framework)
|
||||
## Ghaymah Cloud — API Brute Force & Data Exfiltration Response
|
||||
|
||||
> **Document ID:** GH-IRP-2026-001
|
||||
> **Classification:** CONFIDENTIAL
|
||||
> **Framework:** NIST SP 800-61 Rev. 3 / PICERL
|
||||
> **SOAR Platform:** n8n (Self-hosted on Ghaymah Kubernetes)
|
||||
|
||||
### Framework Mapping
|
||||
- **MITRE ATT&CK:** Initial Access (T1110 Brute Force) → Persistence (T1053 Scheduled Task) → Credential Access (T1040 Network Sniffing) → Exfiltration (T1567 Exfiltration Over Web Service).
|
||||
- **Cyber Kill Chain:**
|
||||
1. *Reconnaissance:* Scanning external Ghaymah endpoints.
|
||||
2. *Delivery/Exploitation:* Automated brute force against the API gateway.
|
||||
3. *Installation:* Deploying a malicious CronJob in the K8s cluster.
|
||||
4. *Command & Control:* Polling C2 via disguised HTTPS traffic.
|
||||
5. *Actions on Objectives:* Copying Ghaymah Block Storage volumes and exfiltrating.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Preparation
|
||||
|
||||
### 1.1 Team Roles & Escalation Matrix
|
||||
|
||||
| Role | Responsibility | Escalation Trigger |
|
||||
|------|---------------|--------------------|
|
||||
| **SOC Analyst L1** | Triage Wazuh alerts, validate true positives | >50 failed logins/min from same target account |
|
||||
| **SOC Analyst L2** | Deep investigation, IOC extraction, containment | Confirmed brute force with credential compromise |
|
||||
| **Incident Commander** | Coordinate response, manage communications | Any confirmed data exfiltration |
|
||||
| **Ghaymah Platform Team** | Infrastructure-level containment, network isolation | Container escape or control plane compromise |
|
||||
| **Legal/DPO** | Regulatory notification assessment | PII/PHI data confirmed exfiltrated |
|
||||
|
||||
### 1.2 Pre-Deployed Tools & Infrastructure
|
||||
|
||||
| Tool | Purpose | Deployment |
|
||||
|------|---------|------------|
|
||||
| **Wazuh** | HIDS/NIDS, log aggregation, rule-based detection | DaemonSet on all K8s nodes + dedicated manager |
|
||||
| **n8n** | SOAR orchestration, automated playbook execution | Self-hosted pod in `security-tools` namespace |
|
||||
| **Elastic Stack** | Log storage, search, visualization (Kibana) | Managed cluster on Ghaymah Block Storage |
|
||||
| **Velero** | Kubernetes backup & disaster recovery | CronJob with Block Storage snapshots |
|
||||
| **Falco** | Runtime container security monitoring | DaemonSet with custom rules |
|
||||
|
||||
### 1.3 n8n SOAR Playbook — Pre-Built Automations
|
||||
|
||||
#### Architecture Workflow Diagram
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
W[Wazuh HIDS] -->|Webhook Alert| N[n8n Webhook Node]
|
||||
N --> P[Parse Alert JSON]
|
||||
P --> E[Enrich IP: AbuseIPDB & MaxMind]
|
||||
E --> D{Decision: Attempt Count & Rep}
|
||||
|
||||
D -->|Attempts > 100 & Malicious| B[AUTO-BLOCK]
|
||||
B --> F[Ghaymah Firewall: Add Deny Rule]
|
||||
B --> A[API: Lock User Account]
|
||||
B --> R[API: Revoke Active Tokens]
|
||||
B --> S1[Slack/PagerDuty: P1 Alert]
|
||||
|
||||
D -->|Attempts > 20 & Suspicious| S[SOFT-BLOCK]
|
||||
S --> RL[API Gateway: Rate Limit 1/min]
|
||||
S --> MFA[Trigger MFA Challenge]
|
||||
S --> S2[Slack: P3 Alert]
|
||||
|
||||
D -->|Attempts > 10| M[MONITOR]
|
||||
M --> EW[Elastic Watchlist]
|
||||
|
||||
F --> T[Create Jira Incident]
|
||||
S1 --> T
|
||||
S2 --> T
|
||||
T --> G[Update Grafana Dashboard]
|
||||
```
|
||||
|
||||
#### Playbook: `brute-force-auto-response`
|
||||
```
|
||||
Trigger: Wazuh webhook → n8n (HTTP POST to /webhook/brute-force)
|
||||
|
||||
Workflow Steps:
|
||||
1. [Wazuh Webhook] → Receive alert JSON payload
|
||||
2. [Parse Alert] → Extract: source_ip, target_account, attempt_count, timestamp
|
||||
3. [Enrich IP] → Query AbuseIPDB + VirusTotal + MaxMind GeoIP
|
||||
4. [Decision Node] →
|
||||
├── IF attempts > 100 AND ip_reputation = "malicious" → AUTO-BLOCK
|
||||
│ ├── [Block IP] → POST to Ghaymah firewall API: add deny rule
|
||||
│ ├── [Disable Account] → PATCH /api/v1/users/{id}/status → "locked"
|
||||
│ ├── [Revoke Tokens] → DELETE /api/v1/auth/tokens?user={id}
|
||||
│ └── [Notify] → Slack #soc-alerts + PagerDuty (P1 if service account)
|
||||
│
|
||||
├── IF attempts > 20 AND ip_reputation = "suspicious" → SOFT-BLOCK
|
||||
│ ├── [Rate Limit] → Apply 1 req/min rate limit to source IP
|
||||
│ ├── [Force MFA] → Trigger MFA challenge on target account
|
||||
│ └── [Notify] → Slack #soc-alerts (P3)
|
||||
│
|
||||
└── IF attempts > 10 → MONITOR
|
||||
├── [Add to Watchlist] → Update Elastic watchlist index
|
||||
└── [Log] → Enrich and store in security-incidents index
|
||||
5. [Create Ticket] → Auto-create Jira/ServiceNow incident ticket
|
||||
6. [Update Dashboard] → Push metrics to Grafana security dashboard
|
||||
```
|
||||
|
||||
#### n8n Workflow JSON (Core Logic):
|
||||
```json
|
||||
{
|
||||
"name": "Brute Force Auto-Response",
|
||||
"nodes": [
|
||||
{
|
||||
"name": "Wazuh Webhook",
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"parameters": {
|
||||
"httpMethod": "POST",
|
||||
"path": "brute-force",
|
||||
"authentication": "headerAuth",
|
||||
"headerAuth": { "name": "X-Webhook-Secret", "value": "={{$env.WEBHOOK_SECRET}}" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Parse Alert",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"parameters": {
|
||||
"values": {
|
||||
"string": [
|
||||
{ "name": "source_ip", "value": "={{$json.data.srcip}}" },
|
||||
{ "name": "target_user", "value": "={{$json.data.dstuser}}" },
|
||||
{ "name": "rule_id", "value": "={{$json.rule.id}}" }
|
||||
],
|
||||
"number": [
|
||||
{ "name": "attempt_count", "value": "={{$json.data.attempt_count}}" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Enrich IP - AbuseIPDB",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"parameters": {
|
||||
"url": "https://api.abuseipdb.com/api/v2/check",
|
||||
"method": "GET",
|
||||
"queryParameters": { "ipAddress": "={{$node['Parse Alert'].json.source_ip}}", "maxAgeInDays": "90" },
|
||||
"headerParameters": { "Key": "={{$env.ABUSEIPDB_API_KEY}}", "Accept": "application/json" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Decision - Severity",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"number": [{ "value1": "={{$node['Parse Alert'].json.attempt_count}}", "operation": "largerEqual", "value2": 100 }]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Block IP - Ghaymah Firewall",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"parameters": {
|
||||
"url": "https://api.ghaymah.systems/v1/firewall/rules",
|
||||
"method": "POST",
|
||||
"body": {
|
||||
"action": "deny",
|
||||
"source_ip": "={{$node['Parse Alert'].json.source_ip}}",
|
||||
"protocol": "tcp",
|
||||
"ports": ["443", "80"],
|
||||
"ttl": 86400,
|
||||
"reason": "Automated block - brute force detection (n8n playbook)"
|
||||
},
|
||||
"authentication": "oAuth2",
|
||||
"oAuth2Api": "ghaymahApi"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Lock Account",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"parameters": {
|
||||
"url": "https://api.ghaymah.systems/v1/iam/users/={{$node['Parse Alert'].json.target_user}}/lock",
|
||||
"method": "POST",
|
||||
"body": {
|
||||
"reason": "Account targeted in brute force attack - locked pending investigation",
|
||||
"locked_by": "n8n-soar-automation"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Slack Notification",
|
||||
"type": "n8n-nodes-base.slack",
|
||||
"parameters": {
|
||||
"channel": "#soc-alerts",
|
||||
"text": "🚨 *BRUTE FORCE AUTO-RESPONSE TRIGGERED*\n• Source IP: `={{$node['Parse Alert'].json.source_ip}}`\n• Target: `={{$node['Parse Alert'].json.target_user}}`\n• Attempts: `={{$node['Parse Alert'].json.attempt_count}}`\n• Action: IP Blocked + Account Locked\n• AbuseIPDB Score: `={{$node['Enrich IP - AbuseIPDB'].json.data.abuseConfidenceScore}}%`"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Identification
|
||||
|
||||
### 2.1 Detection Sources
|
||||
|
||||
| Source | Alert Type | Threshold |
|
||||
|--------|-----------|-----------|
|
||||
| **Wazuh Rule 100201** | API brute force detection | >10 failed logins in 60s per target |
|
||||
| **Wazuh Rule 100202** | Impossible travel login | Auth from 2 geolocations <1hr apart |
|
||||
| **Elastic ML** | Anomalous authentication volume | 3σ deviation from baseline |
|
||||
| **Falco** | Unexpected exec in database pod | Any `exec` in `postgres-*` pods |
|
||||
| **K8s Audit Logs** | Secret access from unusual SA | SA accessing secrets outside its namespace |
|
||||
|
||||
### 2.2 Triage Procedure & Evidence Collection
|
||||
|
||||
**Evidence Collection (Chain of Custody):**
|
||||
1. **Memory:** If the pod is still running, capture a memory dump before killing it: `kubectl debug -it <pod> --target=<container> --image=busybox -- sh -c "cat /proc/kcore > /mnt/ebs/memory_dump.img"`
|
||||
2. **Logs:** Export all K8s API audit logs, ingress logs, and Wazuh HIDS logs for the past 7 days related to the targeted account.
|
||||
3. **Snapshots:** Take immediate forensic snapshots of any associated Block Storage volumes. Do NOT mount these snapshots on active clusters.
|
||||
|
||||
**Decision Point:**
|
||||
- If brute force is *unsuccessful*: Monitor and tune WAF rules.
|
||||
- If brute force is *successful* (credential compromised): Move to Containment Phase immediately.
|
||||
|
||||
**Triage Steps:**
|
||||
1. Validate alert is true positive (check for known scan/pentest windows).
|
||||
2. Determine blast radius: which accounts, namespaces, and data stores are affected.
|
||||
3. Classify severity using Ghaymah incident severity matrix.
|
||||
4. Assign Incident Commander if severity ≥ P2.
|
||||
|
||||
**Communication:**
|
||||
- **SOC L1 to L2:** Escalate via Jira ticket with attached Wazuh JSON alert.
|
||||
- **L2 to IC:** Escalate via PagerDuty for any P1/P2 incidents.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Containment
|
||||
|
||||
### 3.1 Immediate Containment (First 15 Minutes) — Automated via n8n
|
||||
|
||||
| Action | Method | Automated? |
|
||||
|--------|--------|------------|
|
||||
| Block attacker IPs at firewall | n8n → Ghaymah Firewall API | ✅ Yes |
|
||||
| Lock compromised accounts | n8n → IAM API | ✅ Yes |
|
||||
| Revoke all active tokens for affected accounts | n8n → Token Revocation API | ✅ Yes |
|
||||
| Kill rogue K8s workloads | `kubectl delete cronjob sync-external-v2 -n data-pipeline` | Manual (L2) |
|
||||
| Network-isolate affected namespace | Apply deny-all NetworkPolicy to `data-pipeline` | Manual (L2) |
|
||||
|
||||
**Decision Point: Hard vs. Soft Isolation**
|
||||
- *Soft Isolation:* Rate-limit IPs and force MFA. Used when confident the attacker has not gained internal execution (Phase 1-4).
|
||||
- *Hard Isolation:* Disconnect external routing entirely (deny-all NetworkPolicy) and kill pods. Used when lateral movement or exfiltration is detected (Phase 5-8).
|
||||
- **Containment Strategy Justification:** Hard isolation (NetworkPolicy) is prioritized over killing the pod initially because killing the pod destroys volatile memory. Applying a default-deny NetworkPolicy stops lateral movement and exfiltration immediately while preserving the container environment for memory forensics.
|
||||
|
||||
**Communication:**
|
||||
- Notify Engineering Leads that `data-pipeline` namespace is temporarily isolated.
|
||||
- Update internal status page: "Investigating degraded performance on Data Pipeline API."
|
||||
|
||||
### 3.2 Short-Term Containment (15-60 Minutes)
|
||||
|
||||
```bash
|
||||
# 1. Isolate affected namespace with deny-all network policy
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: emergency-isolate
|
||||
namespace: data-pipeline
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
EOF
|
||||
|
||||
# 2. Rotate all secrets in affected namespace
|
||||
kubectl get secrets -n data-pipeline -o name | xargs -I {} kubectl delete {} -n data-pipeline
|
||||
|
||||
# 3. Force-rotate database credentials
|
||||
kubectl exec -it postgres-primary-0 -n data-pipeline -- psql -c \
|
||||
"ALTER USER app_user WITH PASSWORD 'NEW_SECURE_PASSWORD_FROM_VAULT';"
|
||||
|
||||
# 4. Snapshot affected Block Storage volumes for forensics
|
||||
ghaymah block-storage snapshot create \
|
||||
--volume-id vol-data-pipeline-pvc-xxx \
|
||||
--name "forensic-snapshot-$(date +%Y%m%d)" \
|
||||
--tags "incident=GH-IR-2026-0042,type=forensic"
|
||||
```
|
||||
|
||||
### 3.3 Long-Term Containment
|
||||
- Rebuild affected pods from known-good images (pull from verified, signed registry).
|
||||
- Deploy updated NetworkPolicies with explicit allow-list (zero-trust).
|
||||
- Enable enhanced audit logging on all API endpoints.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Eradication
|
||||
|
||||
### 4.1 Eradication Checklist
|
||||
- [ ] Remove all attacker-created accounts (`svc-monitoring-ext`).
|
||||
- [ ] Delete all attacker-generated API tokens.
|
||||
- [ ] Remove rogue CronJob (`sync-external-v2`) and any associated ConfigMaps/Secrets.
|
||||
- [ ] Scan all container images in the cluster for backdoors (Trivy full scan).
|
||||
- [ ] Reset and rotate ALL service account tokens in affected namespaces.
|
||||
- [ ] Block all identified C2 domains/IPs at DNS and firewall level.
|
||||
- [ ] Verify no additional persistence mechanisms (check init containers, volume mounts, admission webhooks).
|
||||
|
||||
### 4.2 IOC Blocklist Update
|
||||
```bash
|
||||
# Push IOCs to Wazuh CDB lists for ongoing detection
|
||||
cat >> /var/ossec/etc/lists/blocked_ips <<EOF
|
||||
45.142.xxx.xxx:Brute-force-GH-IR-2026-0042
|
||||
EOF
|
||||
|
||||
cat >> /var/ossec/etc/lists/blocked_domains <<EOF
|
||||
cdn-static.xyz:C2-GH-IR-2026-0042
|
||||
storage.cdn-static.xyz:Exfil-GH-IR-2026-0042
|
||||
EOF
|
||||
|
||||
# Restart Wazuh manager to load updated lists
|
||||
systemctl restart wazuh-manager
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Recovery
|
||||
|
||||
### 5.1 Recovery Steps
|
||||
1. Restore database from last known-good backup (pre-compromise snapshot).
|
||||
2. Verify data integrity via checksum comparison.
|
||||
3. Gradually re-enable services with enhanced monitoring.
|
||||
4. Implement all prevention controls before full restoration (MFA, rate limiting, NetworkPolicies).
|
||||
5. Conduct a validation penetration test before declaring recovery complete.
|
||||
|
||||
### 5.2 Monitoring Posture (Post-Recovery)
|
||||
- Increase Wazuh alert sensitivity for 30 days.
|
||||
- Enable real-time K8s audit log streaming to Elastic.
|
||||
- Deploy honeypot service account to detect re-compromise attempts.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Lessons Learned
|
||||
|
||||
### 6.1 Post-Incident Review Meeting
|
||||
- **When:** Within 5 business days of incident closure.
|
||||
- **Attendees:** SOC team, Platform team, Engineering leads, CISO.
|
||||
- **Deliverables:** Root cause analysis, updated threat model, remediation tracking.
|
||||
|
||||
### 6.2 Identified Gaps & Remediation
|
||||
|
||||
| Gap | Impact | Remediation | Owner | Deadline |
|
||||
|-----|--------|-------------|-------|----------|
|
||||
| No MFA on service accounts | Direct cause of compromise | Enforce MFA on ALL accounts | IAM Team | 2 weeks |
|
||||
| Per-IP rate limiting only | Distributed attack bypassed | Implement per-account + global rate limiting | API Team | 1 week |
|
||||
| No impossible-travel detection | Late detection of anomalous login | Deploy Wazuh GeoIP correlation rules | SOC Team | 2 weeks |
|
||||
| Overly permissive ClusterRoleBinding | Enabled lateral movement | Audit and scope-reduce all RBAC bindings | Platform | 3 weeks |
|
||||
| No egress monitoring | Exfiltration undetected for hours | Deploy DLP + egress NetworkPolicies | Security | 2 weeks |
|
||||
| Long-lived API tokens allowed | Persistence mechanism | Enforce max 24hr token expiry + rotation | IAM Team | 1 week |
|
||||
|
||||
### 6.3 Updated Playbooks
|
||||
- Update n8n `brute-force-auto-response` to include per-account rate limiting triggers.
|
||||
- Create new n8n playbook: `impossible-travel-response`.
|
||||
- Create new n8n playbook: `egress-anomaly-response`.
|
||||
|
||||
|
||||
132
task2-incident-response/kill_chain_timeline.md
Normal file
132
task2-incident-response/kill_chain_timeline.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Kill Chain Timeline — API Brute Force to Data Exfiltration
|
||||
## Incident Reference: GH-IR-2026-0042
|
||||
|
||||
> **Classification:** CONFIDENTIAL
|
||||
> **Incident Type:** Brute Force → Credential Compromise → Data Exfiltration
|
||||
> **Affected System:** Ghaymah API Gateway (api.ghaymah.systems)
|
||||
> **MITRE ATT&CK Framework Mapping Included**
|
||||
|
||||
---
|
||||
|
||||
## Chronological Kill Chain Timeline
|
||||
|
||||
```mermaid
|
||||
timeline
|
||||
title Incident Reference: GH-IR-2026-0042
|
||||
T-30d : Reconnaissance
|
||||
: Enumerate APIs & Target Users
|
||||
T-7d : Weaponization
|
||||
: Credential Wordlists & Proxies
|
||||
T-2d : Delivery
|
||||
: Brute Force Attack Begins
|
||||
T-0 : Exploitation
|
||||
: Valid Login Achieved
|
||||
T+5m : Installation
|
||||
: Persistent API Token Generated
|
||||
T+30m : Command & Control
|
||||
: Establish Reverse Tunnel
|
||||
T+2hr : Actions on Objectives
|
||||
: Privilege Escalation & Lateral Movement
|
||||
T+6hr : Exfiltration
|
||||
: Data Staging & Exfil via Encrypted Channel
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 1: Reconnaissance (T-30 days)
|
||||
| Attribute | Detail |
|
||||
|-----------|--------|
|
||||
| **MITRE ATT&CK** | T1595 (Active Scanning), T1589 (Gather Victim Identity Info) |
|
||||
| **Timestamp** | ~30 days before breach |
|
||||
| **Activity** | Attacker performs OSINT on ghaymah.systems: enumerates public API endpoints via Swagger/OpenAPI docs, identifies user email patterns from LinkedIn, harvests employee emails from data breach dumps. |
|
||||
| **Evidence** | Unusual spike in requests to `/api/docs`, `/swagger.json`, `/.well-known/` from TOR exit nodes. |
|
||||
| **Indicators (IOCs)** | Source IPs: Multiple TOR exit nodes; User-Agent: `python-requests/2.31`, `curl/8.x` |
|
||||
|
||||
### Phase 2: Weaponization (T-7 days)
|
||||
| Attribute | Detail |
|
||||
|-----------|--------|
|
||||
| **MITRE ATT&CK** | T1588.002 (Obtain Capabilities: Tool), T1586 (Compromise Accounts) |
|
||||
| **Timestamp** | ~7 days before breach |
|
||||
| **Activity** | Attacker assembles credential lists from prior breaches (Combo lists). Configures distributed brute-force tooling (Hydra/custom Python) with rotating residential proxies to evade IP-based rate limiting. Tests against staging endpoints. |
|
||||
| **Evidence** | Low-volume test authentication attempts (2-3 per proxy IP) against `/api/v1/auth/login` detected in retrospective log analysis. |
|
||||
|
||||
### Phase 3: Delivery (T-2 days)
|
||||
| Attribute | Detail |
|
||||
|-----------|--------|
|
||||
| **MITRE ATT&CK** | T1110.001 (Brute Force: Password Guessing), T1110.004 (Credential Stuffing) |
|
||||
| **Timestamp** | 2026-07-25 02:14:00 UTC |
|
||||
| **Activity** | Distributed brute force attack begins against `/api/v1/auth/login`. ~15,000 login attempts per hour across 200+ residential proxy IPs. Targets discovered admin and service account emails. |
|
||||
| **Evidence** | Wazuh alerts: 15,247 failed login attempts in 60 minutes. Source: 214 unique IPs. Geo-distribution: 40% Eastern Europe, 35% Southeast Asia, 25% South America. |
|
||||
| **Detection Gap** | Rate limiting set at 100 req/min per IP — distributed attack stayed under threshold per individual IP. |
|
||||
|
||||
### Phase 4: Exploitation (T-0, Breach Moment)
|
||||
| Attribute | Detail |
|
||||
|-----------|--------|
|
||||
| **MITRE ATT&CK** | T1078 (Valid Accounts), T1110 (Brute Force) |
|
||||
| **Timestamp** | 2026-07-25 04:37:22 UTC |
|
||||
| **Activity** | Successful authentication to service account `svc-data-pipeline@ghaymah.systems` using compromised password from 2024 breach dump. Account had no MFA enforced. |
|
||||
| **Evidence** | Successful login from IP `45.142.xxx.xxx` (Hosting provider, Moldova). Session token issued: `eyJhbG...` |
|
||||
| **Root Cause** | Password reuse + no MFA on service accounts + no impossible-travel detection. |
|
||||
|
||||
### Phase 5: Installation (T+5 minutes)
|
||||
| Attribute | Detail |
|
||||
|-----------|--------|
|
||||
| **MITRE ATT&CK** | T1098 (Account Manipulation), T1136 (Create Account) |
|
||||
| **Timestamp** | 2026-07-25 04:42:15 UTC |
|
||||
| **Activity** | Attacker generates long-lived API token (365-day expiry) via `POST /api/v1/auth/tokens`. Creates secondary service account `svc-monitoring-ext` for persistence. |
|
||||
| **Evidence** | API audit log shows token creation with unusual expiry. New service account created outside of standard provisioning workflow (no associated Terraform/IaC change). |
|
||||
|
||||
### Phase 6: Command & Control (T+30 minutes)
|
||||
| Attribute | Detail |
|
||||
|-----------|--------|
|
||||
| **MITRE ATT&CK** | T1071.001 (Web Protocols), T1572 (Protocol Tunneling) |
|
||||
| **Timestamp** | 2026-07-25 05:07:00 UTC |
|
||||
| **Activity** | Attacker establishes persistent access via API polling mechanism. Uses legitimate HTTPS API calls to a command router endpoint, blending C2 traffic with normal API usage. Deploys a rogue CronJob in Kubernetes namespace `data-pipeline`. |
|
||||
| **Evidence** | Anomalous CronJob: `kubectl get cronjob -n data-pipeline` reveals `sync-external-v2` (not in IaC). Outbound HTTPS to `cdn-static[.]xyz` (attacker C2). |
|
||||
|
||||
### Phase 7: Actions on Objectives (T+2 hours)
|
||||
| Attribute | Detail |
|
||||
|-----------|--------|
|
||||
| **MITRE ATT&CK** | T1068 (Exploitation for Privilege Escalation), T1046 (Network Service Discovery) |
|
||||
| **Timestamp** | 2026-07-25 06:40:00 UTC |
|
||||
| **Activity** | Using the compromised service account, attacker escalates privileges by exploiting an overly permissive ClusterRoleBinding (`data-pipeline-admin`). Enumerates all namespaces, discovers PII database credentials in ConfigMap. |
|
||||
| **Evidence** | K8s audit logs: `list` and `get` on secrets across multiple namespaces from `svc-data-pipeline` SA. Unusual `exec` into `postgres-primary-0` pod. |
|
||||
|
||||
### Phase 8: Exfiltration (T+6 hours)
|
||||
| Attribute | Detail |
|
||||
|-----------|--------|
|
||||
| **MITRE ATT&CK** | T1567.002 (Exfiltration to Cloud Storage), T1048 (Exfiltration Over Alternative Protocol) |
|
||||
| **Timestamp** | 2026-07-25 10:15:00 – 10:58:00 UTC |
|
||||
| **Activity** | Attacker runs `pg_dump` on customer database (est. 2.3M records including PII). Data compressed, encrypted with AES-256, and exfiltrated via HTTPS POST to attacker-controlled S3-compatible storage at `storage.cdn-static[.]xyz`. |
|
||||
| **Evidence** | Egress anomaly: 4.7 GB outbound transfer from `postgres-primary-0` pod in 43 minutes (baseline: <100MB/hr). DNS queries to `cdn-static.xyz` from cluster. Wazuh file integrity alert on database pod. |
|
||||
| **Data Impact** | 2.3M customer records: names, emails, phone numbers, hashed passwords, billing addresses. |
|
||||
|
||||
---
|
||||
|
||||
## IOC Summary Table
|
||||
|
||||
| IOC Type | Value | Context |
|
||||
|----------|-------|---------|
|
||||
| IP Address | `45.142.xxx.xxx` | Initial brute force source (Moldova) |
|
||||
| Domain | `cdn-static[.]xyz` | C2 and exfiltration endpoint |
|
||||
| Domain | `storage.cdn-static[.]xyz` | Data staging destination |
|
||||
| API Token | `eyJhbG...` (SHA256: `a3f2...`) | Attacker-generated persistence token |
|
||||
| K8s CronJob | `sync-external-v2` | Rogue persistence mechanism |
|
||||
| Service Account | `svc-monitoring-ext` | Attacker-created backdoor account |
|
||||
| User-Agent | `python-requests/2.31.0` | Brute force tooling signature |
|
||||
| Egress Volume | 4.7 GB in 43 minutes | Data exfiltration indicator |
|
||||
|
||||
---
|
||||
|
||||
## Post-Incident Impact Assessment (Blast Radius)
|
||||
|
||||
During the incident postmortem, a deep technical analysis was conducted to quantify the exact damage and "Blast Radius" of the breach.
|
||||
|
||||
| Metric | Details & Impact |
|
||||
|--------|------------------|
|
||||
| **Blast Radius (Scope)** | The compromise was successfully **contained within the API Gateway Namespace**. Kubernetes NetworkPolicies prevented lateral movement to the Core Billing and IAM orchestration databases. Only the legacy staging database attached to the API gateway was compromised. |
|
||||
| **Data Exfiltrated (Volume)** | **4.7 GB** of compressed database dumps were transferred out via the C2 channel before the Wazuh SOAR playbook triggered a network block. |
|
||||
| **Data Type (Classification)** | The exfiltrated data consisted of **Personally Identifiable Information (PII) for ~12,400 beta users**, including: <br> - Full Names & Email Addresses <br> - bcrypt-hashed Passwords (Salted) <br> - API Access Logs (Non-financial). <br> *No credit card or payment data was exposed.* |
|
||||
| **Business Impact** | Mandatory GDPR/PDPL breach notification required within 72 hours. Forced password reset initiated for all 12,400 affected users. Minimal financial disruption due to the isolation of the billing enclave. |
|
||||
|
||||
|
||||
273
task2-incident-response/prevention_architecture.md
Normal file
273
task2-incident-response/prevention_architecture.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# Architectural Prevention Strategies on Ghaymah
|
||||
## Preventing API Brute Force & Lateral Movement
|
||||
|
||||
> **Document ID:** GH-ARCH-2026-003
|
||||
> **Applies To:** Ghaymah Managed Kubernetes & Block Storage
|
||||
|
||||
---
|
||||
|
||||
## 1. Network Policy Architecture (Zero-Trust Microsegmentation)
|
||||
|
||||
### 1.1 Default-Deny Foundation
|
||||
|
||||
Every namespace on Ghaymah Kubernetes must start with a default-deny policy. This ensures no pod can communicate unless explicitly allowed.
|
||||
|
||||
```yaml
|
||||
# default-deny-all.yaml — Apply to EVERY namespace
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny-all
|
||||
namespace: <target-namespace>
|
||||
spec:
|
||||
podSelector: {} # Applies to ALL pods in namespace
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
```
|
||||
|
||||
### 1.2 Explicit Allow Policies (Least-Privilege)
|
||||
|
||||
```yaml
|
||||
# allow-api-to-db.yaml — Only API pods can reach the database
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-api-to-postgres
|
||||
namespace: data-pipeline
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: postgres
|
||||
tier: database
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: api-gateway
|
||||
tier: backend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
---
|
||||
# allow-egress-dns-only.yaml — Pods can only resolve DNS, nothing else
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-egress-dns-only
|
||||
namespace: data-pipeline
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
tier: database
|
||||
policyTypes:
|
||||
- Egress
|
||||
egress:
|
||||
- to: []
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
```
|
||||
|
||||
### 1.3 Network Architecture Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ GHAYMAH CLOUD PERIMETER │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ DDoS Shield │ ← L3/L4 Volumetric Protection │
|
||||
│ └──────┬───────┘ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ │
|
||||
│ │ WAF (CRS 4) │ ← L7 Application Firewall (OWASP rules) │
|
||||
│ └──────┬───────┘ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ ┌─────────────────────┐ │
|
||||
│ │ API Gateway │────▶│ Rate Limiter │ │
|
||||
│ │ (Ingress) │ │ • Per-IP: 100/min │ │
|
||||
│ │ │ │ • Per-User: 20/min │ │
|
||||
│ │ │ │ • Global: 10K/min │ │
|
||||
│ └──────┬───────┘ └─────────────────────┘ │
|
||||
│ │ │
|
||||
│ ╔══════╧══════════════════════════════════════════════════════╗ │
|
||||
│ ║ KUBERNETES CLUSTER (Managed) ║ │
|
||||
│ ║ ║ │
|
||||
│ ║ ┌─────────── Namespace: api-gateway ──────────────┐ ║ │
|
||||
│ ║ │ [API Pods] ← mTLS (Istio) → [Auth Service] │ ║ │
|
||||
│ ║ │ NetworkPolicy: allow ingress from WAF only │ ║ │
|
||||
│ ║ └─────────────────────┬───────────────────────────┘ ║ │
|
||||
│ ║ │ mTLS ║ │
|
||||
│ ║ ┌─────────── Namespace: data-pipeline ────────────┐ ║ │
|
||||
│ ║ │ [Worker Pods] → [PostgreSQL] → [Redis Cache] │ ║ │
|
||||
│ ║ │ NetworkPolicy: allow from api-gateway only │ ║ │
|
||||
│ ║ │ Egress: DNS only (no internet) │ ║ │
|
||||
│ ║ └─────────────────────┬───────────────────────────┘ ║ │
|
||||
│ ║ │ ║ │
|
||||
│ ║ ┌─────────── Namespace: security-tools ───────────┐ ║ │
|
||||
│ ║ │ [Wazuh DaemonSet] [n8n SOAR] [Falco] │ ║ │
|
||||
│ ║ │ [Elastic Stack] │ ║ │
|
||||
│ ║ │ NetworkPolicy: monitoring access to all NS │ ║ │
|
||||
│ ║ └──────────────────────────────────────────────────┘ ║ │
|
||||
│ ╚══════════════════════════════════════════════════════════════╝ │
|
||||
│ │ │
|
||||
│ ┌─────────────────────┴────────────────────────────┐ │
|
||||
│ │ GHAYMAH BLOCK STORAGE │ │
|
||||
│ │ • AES-256 encryption at rest (CMEK) │ │
|
||||
│ │ • Immutable snapshots with retention lock │ │
|
||||
│ │ • Cross-region replication (DR) │ │
|
||||
│ └───────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Container Security Hardening
|
||||
|
||||
### 2.1 Pod Security Standards (Restricted Profile)
|
||||
|
||||
```yaml
|
||||
# namespace-security-labels.yaml
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: data-pipeline
|
||||
labels:
|
||||
pod-security.kubernetes.io/enforce: restricted
|
||||
pod-security.kubernetes.io/enforce-version: latest
|
||||
pod-security.kubernetes.io/audit: restricted
|
||||
pod-security.kubernetes.io/warn: restricted
|
||||
```
|
||||
|
||||
### 2.2 Hardened Pod Template
|
||||
|
||||
```yaml
|
||||
# hardened-pod-template.yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: api-server
|
||||
namespace: api-gateway
|
||||
spec:
|
||||
automountServiceAccountToken: false # No default SA token
|
||||
securityContext:
|
||||
runAsNonRoot: true # Never run as root
|
||||
runAsUser: 10001 # Explicit non-root UID
|
||||
runAsGroup: 10001
|
||||
fsGroup: 10001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault # Restrict syscalls
|
||||
containers:
|
||||
- name: api
|
||||
image: registry.ghaymah.systems/api-server:v2.3.1@sha256:abc123... # Pinned digest
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false # Cannot gain more privileges
|
||||
readOnlyRootFilesystem: true # Immutable filesystem
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL # Drop ALL Linux capabilities
|
||||
resources:
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: "256Mi"
|
||||
ephemeral-storage: "100Mi"
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: "128Mi"
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
- name: cache
|
||||
mountPath: /app/cache
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir:
|
||||
sizeLimit: 50Mi
|
||||
- name: cache
|
||||
emptyDir:
|
||||
sizeLimit: 100Mi
|
||||
```
|
||||
|
||||
### 2.3 Image Policy (OPA Gatekeeper Constraint)
|
||||
|
||||
```yaml
|
||||
# require-signed-images.yaml
|
||||
apiVersion: constraints.gatekeeper.sh/v1beta1
|
||||
kind: K8sAllowedRepos
|
||||
metadata:
|
||||
name: require-ghaymah-registry
|
||||
spec:
|
||||
match:
|
||||
kinds:
|
||||
- apiGroups: [""]
|
||||
kinds: ["Pod"]
|
||||
parameters:
|
||||
repos:
|
||||
- "registry.ghaymah.systems/" # Only allow images from trusted registry
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. API-Level Protection
|
||||
|
||||
### 3.1 Multi-Layer Rate Limiting Architecture
|
||||
|
||||
```
|
||||
Request Flow:
|
||||
Client → [Global Rate Limit: 10K/min]
|
||||
→ [Per-IP Rate Limit: 100/min]
|
||||
→ [Per-Account Rate Limit: 20/min]
|
||||
→ [Per-Endpoint Rate Limit: varies]
|
||||
→ API Handler
|
||||
|
||||
Rate Limit Response (429 Too Many Requests):
|
||||
{
|
||||
"error": "rate_limit_exceeded",
|
||||
"retry_after": 60,
|
||||
"limit": 100,
|
||||
"remaining": 0,
|
||||
"reset": 1721890800
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 Authentication Hardening
|
||||
|
||||
| Control | Implementation |
|
||||
|---------|---------------|
|
||||
| MFA Enforcement | TOTP/WebAuthn mandatory for ALL accounts (including service accounts) |
|
||||
| Password Policy | Min 14 chars, complexity required, breach database check (HaveIBeenPwned API) |
|
||||
| Token Expiry | Access tokens: 15 min, Refresh tokens: 24 hrs, API keys: 90 days max |
|
||||
| Account Lockout | Lock after 5 failed attempts, progressive delay (1min, 5min, 15min, 1hr) |
|
||||
| Session Management | Single active session per account (configurable), IP binding optional |
|
||||
|
||||
---
|
||||
|
||||
## 4. Monitoring & Detection Architecture
|
||||
|
||||
### 4.1 Security Monitoring Stack
|
||||
|
||||
```
|
||||
Data Sources:
|
||||
├── K8s API Audit Logs ──────────────────┐
|
||||
├── Container Runtime (Falco) ───────────┤
|
||||
├── Wazuh Agent Logs ────────────────────┤──→ [Elastic/OpenSearch]
|
||||
├── Application Logs (structured JSON) ──┤ │
|
||||
├── Network Flow Logs ───────────────────┤ ├──→ [Kibana Dashboards]
|
||||
└── Ghaymah Platform Audit Logs ─────────┘ │
|
||||
└──→ [Wazuh Manager]
|
||||
│
|
||||
┌──────┴──────┐
|
||||
│ n8n SOAR │
|
||||
│ Playbooks │
|
||||
└─────────────┘
|
||||
│
|
||||
┌───────────┼───────────┐
|
||||
▼ ▼ ▼
|
||||
[Firewall] [IAM API] [Slack/PD]
|
||||
Auto-block Lock acct Alert team
|
||||
```
|
||||
|
||||
|
||||
197
task2-incident-response/wazuh_brute_force_rules.xml
Normal file
197
task2-incident-response/wazuh_brute_force_rules.xml
Normal file
@@ -0,0 +1,197 @@
|
||||
<!--
|
||||
============================================================================
|
||||
Wazuh Custom Rules — API Brute Force Detection for Ghaymah
|
||||
============================================================================
|
||||
File: /var/ossec/etc/rules/ghaymah_brute_force.xml
|
||||
Purpose: Detect early-stage API brute force attempts against Ghaymah
|
||||
authentication endpoints with progressive severity escalation.
|
||||
|
||||
Rule ID Range: 100200 - 100219 (reserved for Ghaymah auth rules)
|
||||
|
||||
Installation:
|
||||
1. Copy this file to /var/ossec/etc/rules/ghaymah_brute_force.xml
|
||||
2. Add to ossec.conf: <include>ghaymah_brute_force.xml</include>
|
||||
3. Restart Wazuh manager: systemctl restart wazuh-manager
|
||||
4. Configure active response in ossec.conf for automated blocking
|
||||
============================================================================
|
||||
-->
|
||||
|
||||
<group name="ghaymah,authentication,brute_force,">
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════════════════
|
||||
BASE RULE: Single API Authentication Failure
|
||||
Matches JSON-formatted API gateway logs with failed login events.
|
||||
════════════════════════════════════════════════════════════════════════ -->
|
||||
<rule id="100200" level="3">
|
||||
<decoded_as>json</decoded_as>
|
||||
<field name="event.type">authentication_failure</field>
|
||||
<field name="event.endpoint">^/api/v\d+/auth/login$</field>
|
||||
<description>Ghaymah API: Single authentication failure on login endpoint.</description>
|
||||
<group>authentication_failed,gdpr_IV_32.2,hipaa_164.312.b,pci_dss_10.2.4,</group>
|
||||
<options>no_full_log</options>
|
||||
</rule>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════════════════
|
||||
EARLY WARNING: 5 failed logins in 60 seconds from same source IP
|
||||
Level 6 = Low severity — early indicator of possible brute force.
|
||||
════════════════════════════════════════════════════════════════════════ -->
|
||||
<rule id="100201" level="6" frequency="5" timeframe="60">
|
||||
<if_matched_sid>100200</if_matched_sid>
|
||||
<same_source_ip />
|
||||
<description>Ghaymah API: Possible brute force — $(srcip) failed 5+ logins in 60 seconds against $(data.target_user).</description>
|
||||
<mitre>
|
||||
<id>T1110.001</id>
|
||||
<id>T1078</id>
|
||||
</mitre>
|
||||
<group>authentication_failures,brute_force_early,gdpr_IV_35.7.d,pci_dss_11.4,</group>
|
||||
</rule>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════════════════
|
||||
CONFIRMED BRUTE FORCE: 20 failed logins in 120 seconds from same IP
|
||||
Level 10 = Medium severity — confirmed brute force attack in progress.
|
||||
Triggers n8n SOAR playbook for soft-block (rate limiting + MFA).
|
||||
════════════════════════════════════════════════════════════════════════ -->
|
||||
<rule id="100202" level="10" frequency="20" timeframe="120">
|
||||
<if_matched_sid>100200</if_matched_sid>
|
||||
<same_source_ip />
|
||||
<description>Ghaymah API: CONFIRMED brute force attack from $(srcip) — 20+ failures in 2 minutes. Target: $(data.target_user).</description>
|
||||
<mitre>
|
||||
<id>T1110.001</id>
|
||||
<id>T1110.003</id>
|
||||
</mitre>
|
||||
<group>brute_force_confirmed,gdpr_IV_35.7.d,pci_dss_11.4,nist_800_53_SI.4,</group>
|
||||
<options>alert_by_email</options>
|
||||
</rule>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════════════════
|
||||
AGGRESSIVE BRUTE FORCE: 50 failed logins in 120 seconds from same IP
|
||||
Level 13 = High severity — aggressive attack, automatic IP block.
|
||||
Triggers n8n SOAR playbook for hard-block (firewall + account lock).
|
||||
════════════════════════════════════════════════════════════════════════ -->
|
||||
<rule id="100203" level="13" frequency="50" timeframe="120">
|
||||
<if_matched_sid>100200</if_matched_sid>
|
||||
<same_source_ip />
|
||||
<description>Ghaymah API: AGGRESSIVE brute force from $(srcip) — 50+ failures in 2 minutes. AUTOMATIC BLOCK INITIATED.</description>
|
||||
<mitre>
|
||||
<id>T1110.001</id>
|
||||
<id>T1110.003</id>
|
||||
<id>T1110.004</id>
|
||||
</mitre>
|
||||
<group>brute_force_aggressive,gdpr_IV_33,pci_dss_11.4,nist_800_53_SI.4,</group>
|
||||
<options>alert_by_email</options>
|
||||
</rule>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════════════════
|
||||
DISTRIBUTED BRUTE FORCE: Multiple IPs targeting same account
|
||||
Level 12 = High severity — credential stuffing / distributed attack.
|
||||
This detects attacks that rotate through many source IPs but
|
||||
target the same user account.
|
||||
════════════════════════════════════════════════════════════════════════ -->
|
||||
<rule id="100204" level="12" frequency="10" timeframe="300">
|
||||
<if_matched_sid>100200</if_matched_sid>
|
||||
<same_field>data.target_user</same_field>
|
||||
<different_source_ip />
|
||||
<description>Ghaymah API: DISTRIBUTED brute force — 10+ different IPs targeting account $(data.target_user) in 5 minutes.</description>
|
||||
<mitre>
|
||||
<id>T1110.004</id>
|
||||
<id>T1078</id>
|
||||
</mitre>
|
||||
<group>brute_force_distributed,credential_stuffing,gdpr_IV_33,pci_dss_11.4,</group>
|
||||
<options>alert_by_email</options>
|
||||
</rule>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════════════════
|
||||
PASSWORD SPRAY: Same IP targeting multiple accounts
|
||||
Level 11 = Medium-High — attacker trying common passwords across
|
||||
many accounts to avoid per-account lockout.
|
||||
════════════════════════════════════════════════════════════════════════ -->
|
||||
<rule id="100205" level="11" frequency="10" timeframe="300">
|
||||
<if_matched_sid>100200</if_matched_sid>
|
||||
<same_source_ip />
|
||||
<different_field>data.target_user</different_field>
|
||||
<description>Ghaymah API: PASSWORD SPRAY detected — $(srcip) targeting 10+ different accounts in 5 minutes.</description>
|
||||
<mitre>
|
||||
<id>T1110.003</id>
|
||||
</mitre>
|
||||
<group>password_spray,brute_force_distributed,gdpr_IV_33,pci_dss_11.4,</group>
|
||||
<options>alert_by_email</options>
|
||||
</rule>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════════════════
|
||||
SUCCESSFUL LOGIN AFTER BRUTE FORCE: Credential compromise indicator
|
||||
Level 14 = Critical — a successful login following brute force
|
||||
strongly indicates the attacker found valid credentials.
|
||||
════════════════════════════════════════════════════════════════════════ -->
|
||||
<rule id="100206" level="14">
|
||||
<if_matched_sid>100202</if_matched_sid>
|
||||
<field name="event.type">authentication_success</field>
|
||||
<same_source_ip />
|
||||
<description>Ghaymah API: ⚠️ CRITICAL — Successful login from $(srcip) AFTER confirmed brute force. Account $(data.target_user) likely COMPROMISED.</description>
|
||||
<mitre>
|
||||
<id>T1078</id>
|
||||
<id>T1110</id>
|
||||
</mitre>
|
||||
<group>account_compromised,brute_force_success,gdpr_IV_33,pci_dss_10.2.4,nist_800_53_SI.4,</group>
|
||||
<options>alert_by_email</options>
|
||||
</rule>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════════════════
|
||||
IMPOSSIBLE TRAVEL: Login from geographically distant locations
|
||||
Level 12 = High — if a user logs in from two locations that would
|
||||
require impossible physical travel speed.
|
||||
════════════════════════════════════════════════════════════════════════ -->
|
||||
<rule id="100207" level="12" frequency="2" timeframe="3600">
|
||||
<field name="event.type">authentication_success</field>
|
||||
<field name="event.endpoint">^/api/v\d+/auth/login$</field>
|
||||
<same_field>data.target_user</same_field>
|
||||
<different_field>data.geoip.country_code</different_field>
|
||||
<description>Ghaymah API: IMPOSSIBLE TRAVEL — $(data.target_user) authenticated from 2+ countries within 1 hour. Possible credential compromise.</description>
|
||||
<mitre>
|
||||
<id>T1078</id>
|
||||
</mitre>
|
||||
<group>impossible_travel,account_compromised,gdpr_IV_33,</group>
|
||||
<options>alert_by_email</options>
|
||||
</rule>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════════════════════════
|
||||
SERVICE ACCOUNT BRUTE FORCE: Higher severity for service accounts
|
||||
Level 14 = Critical — service accounts have elevated privileges;
|
||||
brute force against them is always critical.
|
||||
════════════════════════════════════════════════════════════════════════ -->
|
||||
<rule id="100208" level="14" frequency="5" timeframe="60">
|
||||
<if_matched_sid>100200</if_matched_sid>
|
||||
<field name="data.target_user">^svc-|^service-|^system-</field>
|
||||
<description>Ghaymah API: ⚠️ CRITICAL — Brute force targeting SERVICE ACCOUNT $(data.target_user) from $(srcip). Service accounts have elevated privileges!</description>
|
||||
<mitre>
|
||||
<id>T1110.001</id>
|
||||
<id>T1078.001</id>
|
||||
</mitre>
|
||||
<group>brute_force_service_account,gdpr_IV_33,pci_dss_10.2.4,</group>
|
||||
<options>alert_by_email</options>
|
||||
</rule>
|
||||
|
||||
</group>
|
||||
|
||||
<!--
|
||||
============================================================================
|
||||
ACTIVE RESPONSE CONFIGURATION (add to /var/ossec/etc/ossec.conf)
|
||||
============================================================================
|
||||
|
||||
<ossec_config>
|
||||
<active-response>
|
||||
<command>firewall-drop</command>
|
||||
<location>local</location>
|
||||
<rules_id>100203</rules_id>
|
||||
<timeout>3600</timeout>
|
||||
</active-response>
|
||||
|
||||
<integration>
|
||||
<name>custom-n8n</name>
|
||||
<hook_url>https://n8n.ghaymah.internal/webhook/brute-force</hook_url>
|
||||
<rule_id>100202,100203,100204,100205,100206,100207,100208</rule_id>
|
||||
<alert_format>json</alert_format>
|
||||
</integration>
|
||||
</ossec_config>
|
||||
|
||||
============================================================================
|
||||
-->
|
||||
97
task2-incident-response/wazuh_rules_explained.md
Normal file
97
task2-incident-response/wazuh_rules_explained.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Wazuh Detection Rules — Engineering Notes
|
||||
|
||||
Reference for each custom Wazuh rule defined in `wazuh_brute_force_rules.xml`. Designed to strictly align with interview defensibility requirements.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
**Why Wazuh?**
|
||||
Wazuh natively integrates with Kubernetes (via DaemonSets) and provides out-of-the-box File Integrity Monitoring (FIM), rootkit detection, and log correlation. It's lighter and more cost-effective than deploying a full Splunk forwarder on every node in Ghaymah Containers.
|
||||
|
||||
**Rule ID Strategy:**
|
||||
Standard Wazuh rules use IDs < 100,000. Custom user rules must be >= 100,000. We reserved `100200-100219` for Ghaymah Authentication Rules to maintain organized namespaces and prevent conflicts with future official updates.
|
||||
|
||||
---
|
||||
|
||||
## Rule Definitions
|
||||
|
||||
### Rule 100200: Base API Auth Failure
|
||||
- **Purpose:** Acts as the foundational baseline rule, triggering on every single failed API login.
|
||||
- **Parent Rule:** N/A (Standalone base rule)
|
||||
- **Decoder:** `json` (Our API logs natively in structured JSON)
|
||||
- **Rule ID selection:** 100200 (Start of our reserved auth block)
|
||||
- **Alert Level:** 3 (Low) - High enough to index in Elastic, low enough to avoid spam.
|
||||
- **MITRE ATT&CK Mapping:** T1110 (Brute Force)
|
||||
- **Conditions:** `field name="event.action"` matches `login_failed`
|
||||
- **False Positives:** Legitimate users mistyping passwords.
|
||||
- **False Negatives:** Attackers exploiting token bypasses instead of password auth.
|
||||
- **Example triggering log:** `{"timestamp":"2026-07-27T10:00:00Z", "event":{"action":"login_failed"}, "source":{"ip":"192.168.1.5"}}`
|
||||
- **Expected alert:** Silent indexing. No active response.
|
||||
- **Testing method:** `curl -X POST /api/login -d '{"user":"test", "pass":"wrong"}'`
|
||||
- **Possible improvements:** Enrich with GeoIP data at the decoder level.
|
||||
|
||||
### Rule 100202: Confirmed Brute Force
|
||||
- **Purpose:** Detects sustained, aggressive credential guessing from a single IP.
|
||||
- **Parent Rule:** 100200
|
||||
- **Decoder:** `json`
|
||||
- **Rule ID selection:** 100202
|
||||
- **Alert Level:** 10 (High)
|
||||
- **MITRE ATT&CK Mapping:** T1110.001 (Password Guessing)
|
||||
- **Frequency:** 20 occurrences
|
||||
- **Timeframe:** 120 seconds
|
||||
- **Conditions:** `<same_source_ip />`
|
||||
- **False Positives:** Corporate NAT gateways where 20 different users are legitimately failing logins concurrently.
|
||||
- **False Negatives:** "Low and slow" brute force (e.g., 1 attempt per hour).
|
||||
- **Example triggering log:** (20x of Rule 100200 from the same IP)
|
||||
- **Expected alert:** "Confirmed Brute Force Attack from IP X". Triggers Soft Block via n8n.
|
||||
- **Testing method:** `hydra -l admin -P rockyou.txt https-post-form "/api/login"`
|
||||
- **Possible improvements:** Dynamically adjust the timeframe based on the IP's previous reputation score.
|
||||
|
||||
### Rule 100204: Distributed Brute Force (Credential Stuffing)
|
||||
- **Purpose:** Detects botnets using rotating proxies to attack a single account, bypassing per-IP rate limits.
|
||||
- **Parent Rule:** 100200
|
||||
- **Decoder:** `json`
|
||||
- **Rule ID selection:** 100204
|
||||
- **Alert Level:** 12 (High)
|
||||
- **MITRE ATT&CK Mapping:** T1110.003 (Password Spraying)
|
||||
- **Frequency:** 10 occurrences
|
||||
- **Timeframe:** 300 seconds
|
||||
- **Conditions:** `<same_field>data.target_user</same_field>` AND `<different_source_ip />`
|
||||
- **False Positives:** Distributed team attempting to log into a shared service account concurrently (bad practice, but happens).
|
||||
- **False Negatives:** Botnets targeting multiple accounts simultaneously (avoids `same_field` correlation).
|
||||
- **Example triggering log:** 10 failures for `admin` from 10 different AWS/Ghaymah Cloud IPs.
|
||||
- **Expected alert:** "Distributed Brute Force against Account X".
|
||||
- **Testing method:** Custom Python script rotating proxies while attacking one account.
|
||||
- **Possible improvements:** Integrate with Threat Intelligence feeds to identify known Tor exit nodes automatically.
|
||||
|
||||
### Rule 100206: Successful Login AFTER Brute Force (Compromise)
|
||||
- **Purpose:** Identifies the moment a brute force attack transitions into a successful breach.
|
||||
- **Parent Rule:** N/A (Correlates across auth success rule)
|
||||
- **Decoder:** `json`
|
||||
- **Rule ID selection:** 100206
|
||||
- **Alert Level:** 14 (Critical)
|
||||
- **MITRE ATT&CK Mapping:** T1078 (Valid Accounts)
|
||||
- **Conditions:** `<if_matched_sid>100202</if_matched_sid>` AND `authentication_success` from the same IP.
|
||||
- **False Positives:** A legitimate user legitimately forgets their password, fails 20 times, resets it, and logs in successfully.
|
||||
- **False Negatives:** The attacker brute-forces the password from IP A, but uses it to log in via VPN from IP B.
|
||||
- **Example triggering log:** Rule 100202 fires, followed immediately by `{"event":{"action":"login_success"}}`.
|
||||
- **Expected alert:** "CRITICAL: Account Compromised following Brute Force".
|
||||
- **Testing method:** Run hydra to trigger 100202, then immediately log in with correct credentials via curl.
|
||||
- **Possible improvements:** Change correlation to track the target account rather than just the source IP to prevent the IP A/B bypass.
|
||||
|
||||
### Rule 100208: Service Account Brute Force
|
||||
- **Purpose:** Protects non-MFA enabled machine accounts.
|
||||
- **Parent Rule:** 100200
|
||||
- **Decoder:** `json`
|
||||
- **Rule ID selection:** 100208
|
||||
- **Alert Level:** 14 (Critical)
|
||||
- **MITRE ATT&CK Mapping:** T1078.003 (Local Accounts)
|
||||
- **Frequency:** 5 occurrences
|
||||
- **Timeframe:** 60 seconds
|
||||
- **Conditions:** Regex match on `^svc-|^service-|^system-`
|
||||
- **False Positives:** A misconfigured internal cronjob failing to authenticate.
|
||||
- **False Negatives:** Service accounts that don't follow the naming convention.
|
||||
- **Expected alert:** "CRITICAL: Service Account Brute Force Attempt".
|
||||
- **Testing method:** `hydra -l svc-db-backup -P rockyou.txt https-post-form "/api/login"`
|
||||
- **Possible improvements:** Query Active Directory/LDAP directly rather than relying on regex string matching for the username.
|
||||
المرجع في مشكلة جديدة
حظر مستخدم