|
22 | 22 | // Replace with actual KMP types (common.Verdict, common.RiskAssessment) when ready. |
23 | 23 |
|
24 | 24 | import Foundation |
| 25 | +import SwiftUI |
25 | 26 |
|
26 | 27 | // MARK: - Verdict Mock |
27 | 28 |
|
@@ -170,4 +171,199 @@ struct HistoryItemMock: Identifiable, Sendable, Hashable, Codable { |
170 | 171 | } |
171 | 172 | } |
172 | 173 |
|
| 174 | +// MARK: - Red Team Scenario |
| 175 | + |
| 176 | +/// A red team test scenario with a description and malicious URL. |
| 177 | +struct RedTeamScenario: Identifiable { |
| 178 | + let id: String |
| 179 | + let category: String |
| 180 | + let title: String |
| 181 | + let description: String |
| 182 | + let maliciousUrl: String |
| 183 | + let targetBrand: String? |
| 184 | + let expectedScore: ClosedRange<Int> |
| 185 | + |
| 186 | + init( |
| 187 | + id: String, |
| 188 | + category: String, |
| 189 | + title: String, |
| 190 | + description: String, |
| 191 | + maliciousUrl: String, |
| 192 | + targetBrand: String? = nil, |
| 193 | + expectedScore: ClosedRange<Int> = 50...100 |
| 194 | + ) { |
| 195 | + self.id = id |
| 196 | + self.category = category |
| 197 | + self.title = title |
| 198 | + self.description = description |
| 199 | + self.maliciousUrl = maliciousUrl |
| 200 | + self.targetBrand = targetBrand |
| 201 | + self.expectedScore = expectedScore |
| 202 | + } |
| 203 | + |
| 204 | + /// Returns the emoji icon for this scenario's category |
| 205 | + var categoryIcon: String { |
| 206 | + switch category.lowercased() { |
| 207 | + case let c where c.contains("homograph"): |
| 208 | + return "🔤" |
| 209 | + case let c where c.contains("ip"): |
| 210 | + return "🔢" |
| 211 | + case let c where c.contains("tld"): |
| 212 | + return "🌐" |
| 213 | + case let c where c.contains("redirect"): |
| 214 | + return "↪️" |
| 215 | + case let c where c.contains("brand"): |
| 216 | + return "🏷️" |
| 217 | + case let c where c.contains("shortener"): |
| 218 | + return "🔗" |
| 219 | + case let c where c.contains("safe"): |
| 220 | + return "✅" |
| 221 | + default: |
| 222 | + return "⚠️" |
| 223 | + } |
| 224 | + } |
| 225 | + |
| 226 | + /// Returns the color for this scenario's category |
| 227 | + var categoryColor: Color { |
| 228 | + switch category.lowercased() { |
| 229 | + case let c where c.contains("homograph"): |
| 230 | + return .red |
| 231 | + case let c where c.contains("ip"): |
| 232 | + return .orange |
| 233 | + case let c where c.contains("tld"): |
| 234 | + return .pink |
| 235 | + case let c where c.contains("redirect"): |
| 236 | + return .purple |
| 237 | + case let c where c.contains("brand"): |
| 238 | + return .indigo |
| 239 | + case let c where c.contains("shortener"): |
| 240 | + return .cyan |
| 241 | + case let c where c.contains("safe"): |
| 242 | + return .green |
| 243 | + default: |
| 244 | + return Color(red: 1.0, green: 0.34, blue: 0.13) |
| 245 | + } |
| 246 | + } |
| 247 | +} |
| 248 | + |
| 249 | +// MARK: - Red Team Scenarios Repository |
| 250 | + |
| 251 | +/// Repository of all red team scenarios for testing the detection engine. |
| 252 | +enum RedTeamScenarios { |
| 253 | + |
| 254 | + /// All available red team scenarios for testing. |
| 255 | + static let scenarios: [RedTeamScenario] = [ |
| 256 | + // HOMOGRAPH ATTACKS |
| 257 | + RedTeamScenario( |
| 258 | + id: "HG-001", |
| 259 | + category: "Homograph Attack", |
| 260 | + title: "Cyrillic 'а' in Apple", |
| 261 | + description: "Uses Cyrillic 'а' (U+0430) instead of Latin 'a' to impersonate Apple", |
| 262 | + maliciousUrl: "https://аpple.com/verify", |
| 263 | + targetBrand: "Apple", |
| 264 | + expectedScore: 70...100 |
| 265 | + ), |
| 266 | + RedTeamScenario( |
| 267 | + id: "HG-002", |
| 268 | + category: "Homograph Attack", |
| 269 | + title: "Cyrillic in PayPal", |
| 270 | + description: "Uses Cyrillic 'р' and 'а' to impersonate PayPal", |
| 271 | + maliciousUrl: "https://раypal.com/login", |
| 272 | + targetBrand: "PayPal", |
| 273 | + expectedScore: 70...100 |
| 274 | + ), |
| 275 | + |
| 276 | + // IP OBFUSCATION |
| 277 | + RedTeamScenario( |
| 278 | + id: "IP-001", |
| 279 | + category: "IP Obfuscation", |
| 280 | + title: "Decimal IP Address", |
| 281 | + description: "Uses decimal encoding instead of dotted notation", |
| 282 | + maliciousUrl: "http://3232235777/malware", |
| 283 | + targetBrand: nil, |
| 284 | + expectedScore: 60...100 |
| 285 | + ), |
| 286 | + RedTeamScenario( |
| 287 | + id: "IP-002", |
| 288 | + category: "IP Obfuscation", |
| 289 | + title: "Hexadecimal IP Address", |
| 290 | + description: "Uses hex encoding to hide IP address", |
| 291 | + maliciousUrl: "http://0xC0A80101/payload", |
| 292 | + targetBrand: nil, |
| 293 | + expectedScore: 60...100 |
| 294 | + ), |
| 295 | + |
| 296 | + // SUSPICIOUS TLD |
| 297 | + RedTeamScenario( |
| 298 | + id: "TLD-001", |
| 299 | + category: "Suspicious TLD", |
| 300 | + title: "PayPal on .tk domain", |
| 301 | + description: ".tk is a free TLD commonly abused for phishing", |
| 302 | + maliciousUrl: "https://paypa1-secure.tk/login/verify", |
| 303 | + targetBrand: "PayPal", |
| 304 | + expectedScore: 70...100 |
| 305 | + ), |
| 306 | + RedTeamScenario( |
| 307 | + id: "TLD-002", |
| 308 | + category: "Suspicious TLD", |
| 309 | + title: "Bank on .ml domain", |
| 310 | + description: ".ml is a free TLD commonly abused for phishing", |
| 311 | + maliciousUrl: "https://bank-secure.ml/verify", |
| 312 | + targetBrand: "Banking", |
| 313 | + expectedScore: 60...100 |
| 314 | + ), |
| 315 | + |
| 316 | + // BRAND IMPERSONATION |
| 317 | + RedTeamScenario( |
| 318 | + id: "BI-001", |
| 319 | + category: "Brand Impersonation", |
| 320 | + title: "PayPal Typosquatting", |
| 321 | + description: "Uses '1' instead of 'l' in paypal (paypa1)", |
| 322 | + maliciousUrl: "https://paypa1.com/signin", |
| 323 | + targetBrand: "PayPal", |
| 324 | + expectedScore: 60...100 |
| 325 | + ), |
| 326 | + RedTeamScenario( |
| 327 | + id: "BI-002", |
| 328 | + category: "Brand Impersonation", |
| 329 | + title: "Netflix Subdomain Attack", |
| 330 | + description: "Uses netflix as subdomain of malicious domain", |
| 331 | + maliciousUrl: "https://netflix.secure-verify.com/billing", |
| 332 | + targetBrand: "Netflix", |
| 333 | + expectedScore: 50...90 |
| 334 | + ), |
| 335 | + |
| 336 | + // URL SHORTENERS |
| 337 | + RedTeamScenario( |
| 338 | + id: "SH-001", |
| 339 | + category: "URL Shortener", |
| 340 | + title: "Bit.ly Shortened URL", |
| 341 | + description: "URL shorteners hide final destination", |
| 342 | + maliciousUrl: "https://bit.ly/3xYz123", |
| 343 | + targetBrand: nil, |
| 344 | + expectedScore: 30...60 |
| 345 | + ), |
| 346 | + |
| 347 | + // SAFE CONTROL |
| 348 | + RedTeamScenario( |
| 349 | + id: "SAFE-001", |
| 350 | + category: "Safe (Control)", |
| 351 | + title: "Legitimate Google URL", |
| 352 | + description: "Baseline safe URL - should score low", |
| 353 | + maliciousUrl: "https://www.google.com", |
| 354 | + targetBrand: "Google", |
| 355 | + expectedScore: 0...30 |
| 356 | + ), |
| 357 | + RedTeamScenario( |
| 358 | + id: "SAFE-002", |
| 359 | + category: "Safe (Control)", |
| 360 | + title: "Legitimate GitHub URL", |
| 361 | + description: "Baseline safe URL - should score low", |
| 362 | + maliciousUrl: "https://github.com/Raoof128/QDKMP-KotlinConf-2026-", |
| 363 | + targetBrand: "GitHub", |
| 364 | + expectedScore: 0...30 |
| 365 | + ) |
| 366 | + ] |
| 367 | +} |
| 368 | + |
173 | 369 | #endif |
0 commit comments