From 55388f0118e4c2e9300aec525c35731eb279f9a1 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Tue, 19 Dec 2023 14:31:24 +0100 Subject: [PATCH 01/37] Added very simple wrapper around testssl --- Cargo.lock | 1 + leech/Cargo.toml | 4 +- leech/src/main.rs | 16 ++- leech/src/modules/mod.rs | 1 + leech/src/modules/testssl/json.rs | 42 ++++++++ leech/src/modules/testssl/json_pretty.rs | 127 +++++++++++++++++++++++ leech/src/modules/testssl/mod.rs | 67 ++++++++++++ 7 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 leech/src/modules/testssl/json.rs create mode 100644 leech/src/modules/testssl/json_pretty.rs create mode 100644 leech/src/modules/testssl/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 22767d76d..d764490c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2050,6 +2050,7 @@ dependencies = [ "serde", "serde_json", "surge-ping", + "tempfile", "thiserror", "tokio", "tokio-native-tls", diff --git a/leech/Cargo.toml b/leech/Cargo.toml index 299f84627..51282f351 100644 --- a/leech/Cargo.toml +++ b/leech/Cargo.toml @@ -27,7 +27,7 @@ uuid = { version = "~1", features = ["v4"] } byte-unit = { version = "~5", features = ["serde"] } # Async runtime -tokio = { version = ">=1.23.1", features = ["macros", "sync", "rt-multi-thread", "net", "time"] } +tokio = { version = ">=1.23.1", features = ["macros", "sync", "rt-multi-thread", "net", "time", "process"] } # Abstractions for async programming futures = { version = "~0.3" } # Tokio streams @@ -83,6 +83,8 @@ native-tls = { version = "~0.2", features = ["alpn"] } tokio-native-tls = { version = "~0.3" } probe-config = { path = "probe-config" } +tempfile = "~3" + [build-dependencies] tonic-build = { version = "~0.10" } probe-config = { path = "probe-config" } diff --git a/leech/src/main.rs b/leech/src/main.rs index 441a5ba96..11cb6c972 100644 --- a/leech/src/main.rs +++ b/leech/src/main.rs @@ -44,7 +44,8 @@ use crate::modules::certificate_transparency::{query_ct_api, CertificateTranspar use crate::modules::host_alive::icmp_scan::{start_icmp_scan, IcmpScanSettings}; use crate::modules::port_scanner::tcp_con::{start_tcp_con_port_scan, TcpPortScannerSettings}; use crate::modules::service_detection::DetectServiceSettings; -use crate::modules::{dehashed, service_detection, whois}; +use crate::modules::testssl::TestSSLSettings; +use crate::modules::{dehashed, service_detection, testssl, whois}; use crate::rpc::rpc_attacks::attack_results_service_client::AttackResultsServiceClient; use crate::rpc::rpc_attacks::shared::CertEntry; use crate::rpc::rpc_attacks::{CertificateTransparencyResult, MetaAttackInfo}; @@ -177,6 +178,11 @@ pub enum RunCommand { #[clap(long)] dont_stop_on_match: bool, }, + /// Run `testssl.sh` + TestSSL { + /// Domain to scan + uri: String, + }, } /// All available subcommands @@ -525,6 +531,14 @@ async fn main() -> Result<(), Box> { .await; println!("{result:?}"); } + RunCommand::TestSSL { uri } => { + let json = testssl::run_testssl(TestSSLSettings { + binary_path: None, + uri, + }) + .await?; + println!("{}", serde_json::to_string_pretty(&json)?); + } } } } diff --git a/leech/src/modules/mod.rs b/leech/src/modules/mod.rs index 12288cbbb..cd7b6ef87 100644 --- a/leech/src/modules/mod.rs +++ b/leech/src/modules/mod.rs @@ -8,4 +8,5 @@ pub mod dns; pub mod host_alive; pub mod port_scanner; pub mod service_detection; +pub mod testssl; pub mod whois; diff --git a/leech/src/modules/testssl/json.rs b/leech/src/modules/testssl/json.rs new file mode 100644 index 000000000..be7bd93ac --- /dev/null +++ b/leech/src/modules/testssl/json.rs @@ -0,0 +1,42 @@ +//! Struct defining `testssl.sh`'s `--json` output + +use serde::{Deserialize, Serialize}; + +/// The entire output file +#[allow(dead_code)] +pub type File = Vec; + +/// This struct's fields are found in [`fileout_json_finding`]. +/// +/// [`fileout_json_finding`]: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L844 +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Finding { + pub id: String, + pub severity: Severity, + pub finding: String, + + pub ip: String, + pub port: String, + + pub cve: Option, + pub cwe: Option, + pub hint: Option, +} + +/// Different levels has been taken from [`show_finding`] +/// +/// [`show_finding`]: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L473 +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "UPPERCASE")] +pub enum Severity { + Debug, + Info, + Warn, + Fatal, + + Ok, + Low, + Medium, + High, + Critical, +} diff --git a/leech/src/modules/testssl/json_pretty.rs b/leech/src/modules/testssl/json_pretty.rs new file mode 100644 index 000000000..d327049fb --- /dev/null +++ b/leech/src/modules/testssl/json_pretty.rs @@ -0,0 +1,127 @@ +//! Struct defining `testssl.sh`'s `--json-pretty` output + +use std::num::NonZeroU64; + +use serde::{Deserialize, Serialize}; + +/// The entire output file +/// +/// This struct's fields are found in [`fileout_pretty_json_banner`] and [`fileout_json_footer`]. +/// +/// [`fileout_pretty_json_banner`]: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L896 +/// [`fileout_json_footer`]: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L774 +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct File { + /// The command line arguments which lead to this file + #[serde(rename = "Invocation")] + pub invocation: String, + + /// Combination of the executing computer's hostname and `testssl.sh`'s file location + /// + /// `{hostname}:{path}` + pub at: String, + + /// The version of `testssl.sh` + pub version: String, + + /// The version of openssl + pub openssl: String, + + /// Unix epoch as string + pub start_time: String, + + /// List of scans + pub scan_result: Vec, + + /// Time it took to scan in seconds + pub scan_time: ScanTime, +} + +/// Header: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L863 +/// Sections: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L783 +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ScanResult { + pub target_host: String, + pub ip: String, + pub port: String, + #[serde(rename = "rDNS")] + pub rdns: String, + pub service: String, + pub hostname: Option, + + #[serde(default)] + pub pretest: Vec, + #[serde(default)] + pub single_cipher: Vec, + #[serde(default)] + pub protocols: Vec, + #[serde(default)] + pub grease: Vec, + #[serde(default)] + pub ciphers: Vec, + #[serde(default)] + pub pfs: Vec, + #[serde(default)] + pub server_preferences: Vec, + #[serde(default)] + pub server_defaults: Vec, + #[serde(default)] + pub header_response: Vec, + #[serde(default)] + pub vulnerabilities: Vec, + #[serde(default)] + pub cipher_tests: Vec, + #[serde(default)] + pub browser_simulations: Vec, +} + +/// This struct's fields are found in [`fileout_json_finding`]. +/// +/// [`fileout_json_finding`]: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L873 +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Finding { + pub id: String, + pub severity: Severity, + pub finding: String, + + pub cve: Option, + pub cwe: Option, + pub hint: Option, +} + +/// Different levels has been taken from [`show_finding`] +/// +/// [`show_finding`]: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L473 +#[derive(Serialize, Deserialize, Debug, Copy, Clone)] +#[serde(rename_all = "UPPERCASE")] +pub enum Severity { + Debug, + Info, + Warn, + Fatal, + + Ok, + Low, + Medium, + High, + Critical, +} + +/// The time it took to scan in seconds is either a [`NonZeroU64`] or the string `"Scan interrupted"` +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum ScanTime { + /// Time it took to scan in seconds + Normal( + /// Time it took to scan in seconds + NonZeroU64, + ), + + /// Always `"Scan interrupted"` + Error( + /// Always `"Scan interrupted"` + String, + ), +} diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs new file mode 100644 index 000000000..37a785336 --- /dev/null +++ b/leech/src/modules/testssl/mod.rs @@ -0,0 +1,67 @@ +//! Holds data and code to interact with `testssl.sh` + +use std::borrow::Cow; +use std::io; + +use log::error; +use tempfile::NamedTempFile; +use thiserror::Error; +use tokio::fs::File as TokioFile; +use tokio::io::AsyncReadExt; +use tokio::process::Command; + +mod json; +mod json_pretty; + +/// The settings of a `testssl.sh` invocation +pub struct TestSSLSettings { + /// Optional alternative path to the `testssl.sh` + pub binary_path: Option>, + + /// The domain to scan + pub uri: String, +} +/// Run `testssl.sh` and parse its output +pub async fn run_testssl(settings: TestSSLSettings) -> Result { + let (json_file, json_path) = NamedTempFile::new()?.into_parts(); + let mut json_file = TokioFile::from_std(json_file); + + let output = Command::new(settings.binary_path.as_deref().unwrap_or("testssl")) + .arg("--jsonfile-pretty") + .arg(&json_path) + .arg(&settings.uri) + .output() + .await?; + + if output.status.success() { + let mut json_output = Vec::new(); + json_file.read_to_end(&mut json_output).await?; + let json = serde_json::from_slice(&json_output)?; + Ok(json) + } else { + error!( + "testssl.sh exited with [{}]", + output + .status + .code() + .expect("None should have send this process a signal") + ); + Err(TestSSLError::NonZeroExitStatus) + } +} + +/// Error type produced by [`run_testssl`] +#[derive(Error, Debug)] +pub enum TestSSLError { + /// An io error occurred while running the subprocess or interacting with its output file + #[error("Io error: {}", .0)] + Io(#[from] io::Error), + + /// Failed to parse the json output + #[error("Json error: {}", .0)] + Json(#[from] serde_json::Error), + + /// The `testssl` process exited with a non zero status + #[error("testssl exited with a non zero status")] + NonZeroExitStatus, +} From 3abb3ebe14dfd633f12f8f30e0c37f8e4391d177 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Wed, 20 Dec 2023 16:04:33 +0100 Subject: [PATCH 02/37] Added more options to testssl --- leech/src/main.rs | 2 +- leech/src/modules/testssl/json_pretty.rs | 25 ++- leech/src/modules/testssl/mod.rs | 205 +++++++++++++++++++++-- 3 files changed, 220 insertions(+), 12 deletions(-) diff --git a/leech/src/main.rs b/leech/src/main.rs index 11cb6c972..cf6738ec7 100644 --- a/leech/src/main.rs +++ b/leech/src/main.rs @@ -533,8 +533,8 @@ async fn main() -> Result<(), Box> { } RunCommand::TestSSL { uri } => { let json = testssl::run_testssl(TestSSLSettings { - binary_path: None, uri, + ..Default::default() }) .await?; println!("{}", serde_json::to_string_pretty(&json)?); diff --git a/leech/src/modules/testssl/json_pretty.rs b/leech/src/modules/testssl/json_pretty.rs index d327049fb..c4d936052 100644 --- a/leech/src/modules/testssl/json_pretty.rs +++ b/leech/src/modules/testssl/json_pretty.rs @@ -54,25 +54,48 @@ pub struct ScanResult { #[serde(default)] pub pretest: Vec, #[serde(default)] - pub single_cipher: Vec, + pub single_cipher: Vec, // + + /// Which tls protocols are supported #[serde(default)] pub protocols: Vec, + + /// Server implementation bugs and [GREASE](https://www.ietf.org/archive/id/draft-ietf-tls-grease-01.txt) #[serde(default)] pub grease: Vec, + + /// Which cipher suites are supported #[serde(default)] pub ciphers: Vec, + + /// Checks robust (perfect) forward secrecy key exchange #[serde(default)] pub pfs: Vec, + + /// The server's preferences #[serde(default)] pub server_preferences: Vec, + + /// The server's defaults #[serde(default)] pub server_defaults: Vec, + + /// The http header set by the server #[serde(default)] pub header_response: Vec, + + /// List of several vulnerabilities #[serde(default)] pub vulnerabilities: Vec, + + /// Which concrete ciphers are supported + /// + /// Depending on the option `testssl` is invoked with, + /// this is either a list of all ciphers or a list of all cipher per tls protocol. #[serde(default)] pub cipher_tests: Vec, + + /// Which browser is able to establish a connection #[serde(default)] pub browser_simulations: Vec, } diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index 37a785336..d787f1530 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -1,6 +1,5 @@ //! Holds data and code to interact with `testssl.sh` -use std::borrow::Cow; use std::io; use log::error; @@ -14,24 +13,210 @@ mod json; mod json_pretty; /// The settings of a `testssl.sh` invocation +#[derive(Default, Debug)] pub struct TestSSLSettings { - /// Optional alternative path to the `testssl.sh` - pub binary_path: Option>, - /// The domain to scan pub uri: String, + + /// Timeout for TCP handshakes in seconds + pub connect_timeout: Option, + + /// Timeout for `openssl` connections in seconds + pub openssl_timeout: Option, + + /// Enable ip v6 + pub v6: bool, + + /// Set the `BASICAUTH` header when checking http headers + pub basic_auth: Option<(String, String)>, + + /// Run against a STARTTLS enabled protocol + pub starttls: Option, + + /// Which scans `testssl.sh` should run + pub scans: TestSSLScans, } + +/// Protocols to select from when using `--starttls` +pub enum StartTLSProtocol { + FTP, + SMTP, + POP3, + IMAP, + XMPP, + // Telnet, // WIP + // LDAP, // Requires `--ssl-native` which is less precise + // IRC, // WIP + LMTP, + NNTP, + Postgres, + MySQL, +} + +/// Config option which scans `testssl.sh` should run +#[derive(Default, Debug)] +pub enum TestSSLScans { + /// Sets no option and uses `testssl.sh`'s default run + #[default] + Default, + + /// Sets the `--full` option to run everything + All, + + /// Select the scans to run manually + /// + /// Each field (except `cipher_tests_...`) correspond directly to a section in [`json_pretty::ScanResult`] + Manual { + /// Enables [`ScanResult`]'s `protocols` section + protocols: bool, + + /// Enables [`ScanResult`]'s `grease` section + grease: bool, + + /// Enables [`ScanResult`]'s `ciphers` section + ciphers: bool, + + /// Enables [`ScanResult`]'s `pfs` section + pfs: bool, + + /// Enables [`ScanResult`]'s `server_preferences` section + server_preferences: bool, + + /// Enables [`ScanResult`]'s `server_defaults` section + server_defaults: bool, + + /// Enables [`ScanResult`]'s `header_response` section + header_response: bool, + + /// Enables [`ScanResult`]'s `vulnerabilities` section + vulnerabilities: bool, + + /// Enables [`ScanResult`]'s `cipher_tests` section + cipher_tests_all: bool, + + /// Enables [`ScanResult`]'s `cipher_tests` section + cipher_tests_per_proto: bool, + + /// Enables [`ScanResult`]'s `browser_simulations` section + browser_simulations: bool, + }, +} + /// Run `testssl.sh` and parse its output pub async fn run_testssl(settings: TestSSLSettings) -> Result { + let TestSSLSettings { + uri, + connect_timeout, + openssl_timeout, + v6, + basic_auth, + starttls, + scans, + } = settings; + let (json_file, json_path) = NamedTempFile::new()?.into_parts(); let mut json_file = TokioFile::from_std(json_file); - let output = Command::new(settings.binary_path.as_deref().unwrap_or("testssl")) - .arg("--jsonfile-pretty") - .arg(&json_path) - .arg(&settings.uri) - .output() - .await?; + let cmd = &mut Command::new("testssl"); + + // Declare json output + cmd.arg("--jsonfile-pretty").arg(&json_path); + use std::borrow::Cow; + + // Don't wait for user confirmation when encountering problems + cmd.arg("--warnings").arg("batch"); + + // Add timeouts + if let Some(seconds) = connect_timeout { + cmd.arg("--connect-timeout").arg(&seconds.to_string()); + } + if let Some(seconds) = openssl_timeout { + cmd.arg("--openssl-timeout").arg(&seconds.to_string()); + } + + // Enable ip v6 + if v6 { + cmd.arg("-6"); + } + + // Set BASICAUTH header + if let Some((username, password)) = basic_auth { + cmd.arg("--basicauth") + .arg(&format!("{username}:{password}")); + } + + // Enable STARTTLS + if let Some(protocol) = starttls { + cmd.arg("--starttls"); + match protocol { + StartTLSProtocol::FTP => cmd.arg("ftp"), + StartTLSProtocol::SMTP => cmd.arg("smtp"), + StartTLSProtocol::POP3 => cmd.arg("pop3"), + StartTLSProtocol::IMAP => cmd.arg("imap"), + StartTLSProtocol::XMPP => cmd.arg("xmpp"), + StartTLSProtocol::LMTP => cmd.arg("lmtp"), + StartTLSProtocol::NNTP => cmd.arg("nntp"), + StartTLSProtocol::Postgres => cmd.arg("postgres"), + StartTLSProtocol::MySQL => cmd.arg("mysql"), + } + } + + // https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L20277 + match scans { + TestSSLScans::Default => {} + TestSSLScans::All => { + cmd.arg("--full"); + } + TestSSLScans::Manual { + protocols, + grease, + ciphers, + pfs, + server_preferences, + server_defaults, + header_response, + vulnerabilities, + cipher_tests_all, + cipher_tests_per_proto, + browser_simulations, + } => { + if protocols { + cmd.arg("--protocols"); + } + if grease { + cmd.arg("--grease"); + } + if ciphers { + cmd.arg("--std"); + } + if pfs { + cmd.arg("--pfs"); + } + if server_preferences { + cmd.arg("--server-preferences"); + } + if server_defaults { + cmd.arg("--server-defaults"); + } + if header_response { + cmd.arg("--headers"); + } + if vulnerabilities { + cmd.arg("--vulnerabilities"); + } + if cipher_tests_all { + cmd.arg("--each-cipher"); + } + if cipher_tests_per_proto { + cmd.arg("--cipher-per-proto"); + } + if browser_simulations { + cmd.arg("--client-simulation"); + } + } + } + + let output = cmd.arg(&uri).output().await?; if output.status.success() { let mut json_output = Vec::new(); From 9511613e84d69f8178bd2f25128c4ccae898b0cf Mon Sep 17 00:00:00 2001 From: gammelalf Date: Thu, 21 Dec 2023 14:39:17 +0100 Subject: [PATCH 03/37] Propageted the new testssl attack through the entire rpc-http chain This commit doesn't implement storing and aggregating the results yet --- .../api/handler/aggregation_source/schema.rs | 6 +- .../api/handler/aggregation_source/utils.rs | 21 +++- .../src/api/handler/attack_results/schema.rs | 6 + kraken/src/api/handler/attacks/handler.rs | 56 ++++++++- kraken/src/api/handler/attacks/schema.rs | 45 +++++++ kraken/src/api/server.rs | 1 + kraken/src/api/swagger.rs | 3 + kraken/src/models/aggregation/mod.rs | 2 + kraken/src/models/attack/mod.rs | 15 +++ kraken/src/modules/attack_results/mod.rs | 2 + kraken/src/modules/attack_results/testssl.rs | 24 ++++ kraken/src/modules/attacks/mod.rs | 40 ++++++- kraken/src/modules/attacks/testssl.rs | 49 ++++++++ leech/src/modules/testssl/mod.rs | 26 ++--- leech/src/rpc/attacks.rs | 79 ++++++++++++- proto/attacks.proto | 110 ++++++++++++++++++ 16 files changed, 463 insertions(+), 22 deletions(-) create mode 100644 kraken/src/modules/attack_results/testssl.rs create mode 100644 kraken/src/modules/attacks/testssl.rs diff --git a/kraken/src/api/handler/aggregation_source/schema.rs b/kraken/src/api/handler/aggregation_source/schema.rs index a7b4dbba4..ba6ad87df 100644 --- a/kraken/src/api/handler/aggregation_source/schema.rs +++ b/kraken/src/api/handler/aggregation_source/schema.rs @@ -6,7 +6,7 @@ use uuid::Uuid; use crate::api::handler::attack_results::schema::{ FullQueryCertificateTransparencyResult, FullServiceDetectionResult, SimpleBruteforceSubdomainsResult, SimpleDnsResolutionResult, SimpleHostAliveResult, - SimpleQueryUnhashedResult, SimpleTcpPortScanResult, + SimpleQueryUnhashedResult, SimpleTcpPortScanResult, SimpleTestSSLResult, }; use crate::api::handler::users::schema::SimpleUser; use crate::models::{ @@ -40,6 +40,8 @@ pub struct SimpleAggregationSource { pub udp_port_scan: usize, /// Perform version detection pub version_detection: usize, + /// Ran `testssl.sh` + pub test_ssl: usize, /// Manually inserted pub manual: bool, } @@ -91,6 +93,8 @@ pub enum SourceAttackResult { ServiceDetection(Vec), /// The [`AttackType::DnsResolution`] and its results DnsResolution(Vec), + /// The [`AttackType::TestSSL`] and its results + TestSSL(Vec), } /// The different types of manual inserts diff --git a/kraken/src/api/handler/aggregation_source/utils.rs b/kraken/src/api/handler/aggregation_source/utils.rs index 50605c614..51fad78c0 100644 --- a/kraken/src/api/handler/aggregation_source/utils.rs +++ b/kraken/src/api/handler/aggregation_source/utils.rs @@ -15,14 +15,14 @@ use crate::api::handler::aggregation_source::schema::{ use crate::api::handler::attack_results::schema::{ FullQueryCertificateTransparencyResult, FullServiceDetectionResult, SimpleBruteforceSubdomainsResult, SimpleDnsResolutionResult, SimpleHostAliveResult, - SimpleQueryUnhashedResult, SimpleTcpPortScanResult, + SimpleQueryUnhashedResult, SimpleTcpPortScanResult, SimpleTestSSLResult, }; use crate::api::handler::users::schema::SimpleUser; use crate::models::{ AggregationSource, AggregationTable, Attack, AttackType, BruteforceSubdomainsResult, CertificateTransparencyResult, CertificateTransparencyValueName, DehashedQueryResult, DnsResolutionResult, HostAliveResult, ManualDomain, ManualHost, ManualPort, ManualService, - ServiceDetectionName, ServiceDetectionResult, SourceType, TcpPortScanResult, + ServiceDetectionName, ServiceDetectionResult, SourceType, TcpPortScanResult, TestSSLResult, }; fn field_in<'a, T, F, P, Any>( @@ -108,6 +108,7 @@ impl SimpleAggregationSource { SourceType::OSDetection => self.os_detection += 1, SourceType::VersionDetection => self.version_detection += 1, SourceType::AntiPortScanningDetection => self.anti_port_scanning_detection += 1, + SourceType::TestSSL => self.test_ssl += 1, SourceType::ManualDomain | SourceType::ManualHost | SourceType::ManualPort @@ -163,6 +164,7 @@ impl FullAggregationSource { let mut host_alive: Results = Results::new(); let mut service_detection: Results = Results::new(); let mut dns_resolution: Results = Results::new(); + let mut testssl: Results = Results::new(); let mut manual_insert = Vec::new(); for (source_type, uuids) in sources { if uuids.is_empty() { @@ -337,6 +339,17 @@ impl FullAggregationSource { }); } } + SourceType::TestSSL => { + let mut stream = query!(&mut *tx, TestSSLResult) + .condition(field_in(TestSSLResult::F.uuid, uuids)) + .stream(); + while let Some(result) = stream.try_next().await? { + testssl + .entry(*result.attack.key()) + .or_default() + .push(SimpleTestSSLResult {}); + } + } SourceType::UdpPortScan | SourceType::ForcedBrowsing | SourceType::OSDetection @@ -480,6 +493,7 @@ impl FullAggregationSource { .chain(host_alive.keys()) .chain(service_detection.keys()) .chain(dns_resolution.keys()) + .chain(testssl.keys()) .copied(), )) .stream(); @@ -521,6 +535,9 @@ impl FullAggregationSource { AttackType::DnsResolution => SourceAttackResult::DnsResolution( dns_resolution.remove(&uuid).unwrap_or_default(), ), + AttackType::TestSSL => { + SourceAttackResult::TestSSL(testssl.remove(&uuid).unwrap_or_default()) + } AttackType::UdpPortScan | AttackType::ForcedBrowsing | AttackType::OSDetection diff --git a/kraken/src/api/handler/attack_results/schema.rs b/kraken/src/api/handler/attack_results/schema.rs index 7c8a49e50..a4c8b4d33 100644 --- a/kraken/src/api/handler/attack_results/schema.rs +++ b/kraken/src/api/handler/attack_results/schema.rs @@ -193,3 +193,9 @@ pub struct SimpleDnsResolutionResult { #[schema(inline)] pub dns_record_type: DnsRecordType, } + +/// A simple representation of a testssl result +#[derive(Serialize, Deserialize, ToSchema, Debug, Clone)] +pub struct SimpleTestSSLResult { + // TODO +} diff --git a/kraken/src/api/handler/attacks/handler.rs b/kraken/src/api/handler/attacks/handler.rs index dda980b8a..2b02116e2 100644 --- a/kraken/src/api/handler/attacks/handler.rs +++ b/kraken/src/api/handler/attacks/handler.rs @@ -9,7 +9,7 @@ use crate::api::extractors::SessionUser; use crate::api::handler::attacks::schema::{ BruteforceSubdomainsRequest, DnsResolutionRequest, HostsAliveRequest, ListAttacks, QueryCertificateTransparencyRequest, QueryDehashedRequest, ScanTcpPortsRequest, - ServiceDetectionRequest, SimpleAttack, + ServiceDetectionRequest, SimpleAttack, TestSSLRequest, }; use crate::api::handler::common::error::{ApiError, ApiResult}; use crate::api::handler::common::schema::{PathUuid, UuidResponse}; @@ -20,8 +20,8 @@ use crate::models::{Attack, User, UserPermission, WordList, Workspace, Workspace use crate::modules::attacks::{ start_bruteforce_subdomains, start_certificate_transparency, start_dehashed_query, start_dns_resolution, start_host_alive, start_service_detection, start_tcp_port_scan, - BruteforceSubdomainsParams, CertificateTransparencyParams, DehashedQueryParams, - DnsResolutionParams, HostAliveParams, ServiceDetectionParams, TcpPortScanParams, + start_testssl, BruteforceSubdomainsParams, CertificateTransparencyParams, DehashedQueryParams, + DnsResolutionParams, HostAliveParams, ServiceDetectionParams, TcpPortScanParams, TestSSLParams, }; /// Bruteforce subdomains through a DNS wordlist attack @@ -380,6 +380,56 @@ pub async fn dns_resolution( Ok(HttpResponse::Accepted().json(UuidResponse { uuid: attack_uuid })) } +/// Run testssl +#[utoipa::path( + tag = "Attacks", + context_path = "/api/v1", + responses( + (status = 202, description = "Attack scheduled", body = UuidResponse), + (status = 400, description = "Client error", body = ApiErrorResponse), + (status = 500, description = "Server error", body = ApiErrorResponse) + ), + request_body = TestSSLRequest, + security(("api_key" = [])) +)] +#[post("/attacks/testssl")] +pub async fn testssl( + req: Json, + SessionUser(user_uuid): SessionUser, +) -> ApiResult { + let TestSSLRequest { + leech_uuid, + workspace_uuid, + uri, + connect_timeout, + openssl_timeout, + basic_auth, + starttls, + } = req.into_inner(); + + let client = if let Some(leech_uuid) = leech_uuid { + GLOBAL.leeches.get_leech(&leech_uuid)? + } else { + GLOBAL.leeches.random_leech()? + }; + + let (attack_uuid, _) = start_testssl( + workspace_uuid, + user_uuid, + client, + TestSSLParams { + uri, + connect_timeout, + openssl_timeout, + basic_auth, + starttls, + }, + ) + .await?; + + Ok(HttpResponse::Accepted().json(UuidResponse { uuid: attack_uuid })) +} + /// Retrieve an attack by id #[utoipa::path( tag = "Attacks", diff --git a/kraken/src/api/handler/attacks/schema.rs b/kraken/src/api/handler/attacks/schema.rs index 182207428..f8e464984 100644 --- a/kraken/src/api/handler/attacks/schema.rs +++ b/kraken/src/api/handler/attacks/schema.rs @@ -203,6 +203,33 @@ pub struct DnsResolutionRequest { pub workspace_uuid: Uuid, } +/// Request to run testssl +#[derive(Deserialize, ToSchema)] +pub struct TestSSLRequest { + /// The leech to use + /// + /// Leave empty to use a random leech + pub leech_uuid: Option, + + /// The workspace to execute the attack in + pub workspace_uuid: Uuid, + + /// The domain to scan + pub uri: String, + + /// Timeout for TCP handshakes in seconds + pub connect_timeout: Option, + + /// Timeout for `openssl` connections in seconds + pub openssl_timeout: Option, + + /// Set the `BASICAUTH` header when checking http headers + pub basic_auth: Option<[String; 2]>, + + /// Run against a STARTTLS enabled protocol + pub starttls: Option, +} + /// A simple version of an attack #[derive(Clone, Serialize, Deserialize, ToSchema, Debug)] pub struct SimpleAttack { @@ -242,6 +269,24 @@ pub enum DomainOrNetwork { Domain(String), } +/// Protocols to select from when using `--starttls` +#[derive(Serialize, Deserialize, ToSchema, Debug, Copy, Clone)] +#[allow(missing_docs)] // The names are pretty unambiguous +pub enum StartTLSProtocol { + FTP, + SMTP, + POP3, + IMAP, + XMPP, + // Telnet, // WIP + // LDAP, // Requires `--ssl-native` which is less precise + // IRC, // WIP + LMTP, + NNTP, + Postgres, + MySQL, +} + /// Deserializes a string and parses it as `{start}-{end}` where `start` and `end` are both `u16` pub fn deserialize_port_range<'de, D>(deserializer: D) -> Result, D::Error> where diff --git a/kraken/src/api/server.rs b/kraken/src/api/server.rs index 58900144e..5f4cd0c6f 100644 --- a/kraken/src/api/server.rs +++ b/kraken/src/api/server.rs @@ -163,6 +163,7 @@ pub async fn start_server(config: &Config) -> Result<(), StartServerError> { .service(attacks::handler::query_dehashed) .service(attacks::handler::service_detection) .service(attacks::handler::dns_resolution) + .service(attacks::handler::testssl) .service(attack_results::handler::get_bruteforce_subdomains_results) .service(attack_results::handler::get_tcp_port_scan_results) .service(attack_results::handler::get_query_certificate_transparency_results) diff --git a/kraken/src/api/swagger.rs b/kraken/src/api/swagger.rs index 88697fec5..d5f786f9a 100644 --- a/kraken/src/api/swagger.rs +++ b/kraken/src/api/swagger.rs @@ -87,6 +87,7 @@ impl Modify for SecurityAddon2 { attacks::handler::hosts_alive_check, attacks::handler::service_detection, attacks::handler::dns_resolution, + attacks::handler::testssl, attack_results::handler::get_bruteforce_subdomains_results, attack_results::handler::get_tcp_port_scan_results, attack_results::handler::get_query_certificate_transparency_results, @@ -195,7 +196,9 @@ impl Modify for SecurityAddon2 { attacks::schema::PortOrRange, attacks::schema::ServiceDetectionRequest, attacks::schema::DnsResolutionRequest, + attacks::schema::TestSSLRequest, attacks::schema::DomainOrNetwork, + attacks::schema::StartTLSProtocol, attack_results::schema::SimpleBruteforceSubdomainsResult, attack_results::schema::SimpleTcpPortScanResult, attack_results::schema::FullQueryCertificateTransparencyResult, diff --git a/kraken/src/models/aggregation/mod.rs b/kraken/src/models/aggregation/mod.rs index f88b259de..4a7cca37c 100644 --- a/kraken/src/models/aggregation/mod.rs +++ b/kraken/src/models/aggregation/mod.rs @@ -529,6 +529,8 @@ pub enum SourceType { VersionDetection, /// The table for the not yet implemented [`AttackType::AntiPortScanningDetection`] results AntiPortScanningDetection, + /// The table for the not yet implemented [`AttackType::TestSSL`] results + TestSSL, /// The [`ManualDomain`] table ManualDomain, /// The [`ManualHost`] table diff --git a/kraken/src/models/attack/mod.rs b/kraken/src/models/attack/mod.rs index 032ed2b46..e9931a832 100644 --- a/kraken/src/models/attack/mod.rs +++ b/kraken/src/models/attack/mod.rs @@ -48,6 +48,8 @@ pub enum AttackType { VersionDetection, /// Detect an anti port scan system AntiPortScanningDetection, + /// Run `testssl.sh` to check a servers TLS configuration + TestSSL, } /// Representation of an attack @@ -317,3 +319,16 @@ pub struct ServiceDetectionResult { /// The found names of the service pub service_names: BackRef, } + +/// Representation of a [TestSSL](AttackType::TestSSL) attack's result +#[derive(Model)] +pub struct TestSSLResult { + /// The primary key + #[rorm(primary_key)] + pub uuid: Uuid, + + /// The [attack](Attack) which produced this result + #[rorm(on_delete = "Cascade", on_update = "Cascade")] + pub attack: ForeignModel, + // TODO +} diff --git a/kraken/src/modules/attack_results/mod.rs b/kraken/src/modules/attack_results/mod.rs index c39d259e1..98ae5c0a2 100644 --- a/kraken/src/modules/attack_results/mod.rs +++ b/kraken/src/modules/attack_results/mod.rs @@ -6,6 +6,7 @@ mod host_alive_check; mod query_certificate_transparency; mod service_detection; mod tcp_port_scan; +mod testssl; pub use bruteforce_subdomains::store_bruteforce_subdomains_result; pub use dns_resolution::store_dns_resolution_result; @@ -13,3 +14,4 @@ pub use host_alive_check::store_host_alive_check_result; pub use query_certificate_transparency::store_query_certificate_transparency_result; pub use service_detection::store_service_detection_result; pub use tcp_port_scan::store_tcp_port_scan_result; +pub use testssl::store_testssl_result; diff --git a/kraken/src/modules/attack_results/testssl.rs b/kraken/src/modules/attack_results/testssl.rs new file mode 100644 index 000000000..8d045f66b --- /dev/null +++ b/kraken/src/modules/attack_results/testssl.rs @@ -0,0 +1,24 @@ +use rorm::db::Executor; +use rorm::insert; +use rorm::prelude::ForeignModelByField; +use uuid::Uuid; + +use crate::models::TestSSLResult; +use crate::rpc::rpc_definitions::TestSslResponse; + +/// Store a query certificate transparency's result and update the aggregated domains and hosts +pub async fn store_testssl_result( + executor: impl Executor<'_>, + attack_uuid: Uuid, + workspace_uuid: Uuid, + result: TestSslResponse, +) -> Result<(), rorm::Error> { + insert!(executor, TestSSLResult) + .return_nothing() + .single(&TestSSLResult { + uuid: Uuid::new_v4(), + attack: ForeignModelByField::Key(attack_uuid), + }) + .await + // TODO +} diff --git a/kraken/src/modules/attacks/mod.rs b/kraken/src/modules/attacks/mod.rs index 6a19ab557..7bd90bf09 100644 --- a/kraken/src/modules/attacks/mod.rs +++ b/kraken/src/modules/attacks/mod.rs @@ -17,7 +17,9 @@ use tokio::task::JoinHandle; use tonic::{Response, Status, Streaming}; use uuid::Uuid; -use crate::api::handler::attacks::schema::{DomainOrNetwork, PortOrRange, SimpleAttack}; +use crate::api::handler::attacks::schema::{ + DomainOrNetwork, PortOrRange, SimpleAttack, StartTLSProtocol, +}; use crate::api::handler::users::schema::SimpleUser; use crate::api::handler::workspaces::schema::SimpleWorkspace; use crate::chan::global::GLOBAL; @@ -36,6 +38,7 @@ mod dns_resolution; mod host_alive; mod service_detection; mod tcp_port_scan; +mod testssl; /// The parameters of a "bruteforce subdomains" attack pub struct BruteforceSubdomainsParams { @@ -259,6 +262,41 @@ pub async fn start_tcp_port_scan( )) } +/// The parameters of a "testssl" attack +pub struct TestSSLParams { + /// The domain to scan + pub uri: String, + + /// Timeout for TCP handshakes in seconds + pub connect_timeout: Option, + + /// Timeout for `openssl` connections in seconds + pub openssl_timeout: Option, + + /// Set the `BASICAUTH` header when checking http headers + pub basic_auth: Option<[String; 2]>, + + /// Run against a STARTTLS enabled protocol + pub starttls: Option, +} +/// Start a "testssl" attack +pub async fn start_testssl( + workspace: Uuid, + user: Uuid, + leech: LeechClient, + params: TestSSLParams, +) -> Result<(Uuid, JoinHandle<()>), InsertAttackError> { + let ctx = AttackContext::new(workspace, user, AttackType::TestSSL).await?; + Ok(( + ctx.attack_uuid, + tokio::spawn(async move { + ctx.set_started().await; + let result = ctx.testssl(leech, params).await; + ctx.set_finished(result).await; + }), + )) +} + /// Collection of uuids required for a running attack #[derive(Clone)] struct AttackContext { diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs new file mode 100644 index 000000000..b1080128e --- /dev/null +++ b/kraken/src/modules/attacks/testssl.rs @@ -0,0 +1,49 @@ +use crate::api::handler::attacks::schema::StartTLSProtocol; +use crate::chan::global::GLOBAL; +use crate::chan::leech_manager::LeechClient; +use crate::modules::attack_results::store_testssl_result; +use crate::modules::attacks::{AttackContext, AttackError, TestSSLParams}; +use crate::rpc::rpc_definitions::{ + test_ssl_scans, BasicAuth, StartTlsProtocol, TestSslRequest, TestSslScans, +}; + +impl AttackContext { + /// Executes the "testssl" attack + pub async fn testssl( + &self, + mut leech: LeechClient, + params: TestSSLParams, + ) -> Result<(), AttackError> { + let request = TestSslRequest { + attack_uuid: self.attack_uuid.to_string(), + uri: params.uri, + connect_timeout: params.connect_timeout, + openssl_timeout: params.openssl_timeout, + v6: Some(true), + basic_auth: params + .basic_auth + .map(|[username, password]| BasicAuth { username, password }), + starttls: params.starttls.map(|p| { + match p { + StartTLSProtocol::FTP => StartTlsProtocol::Ftp, + StartTLSProtocol::SMTP => StartTlsProtocol::Smtp, + StartTLSProtocol::POP3 => StartTlsProtocol::Pop3, + StartTLSProtocol::IMAP => StartTlsProtocol::Imap, + StartTLSProtocol::XMPP => StartTlsProtocol::Xmpp, + StartTLSProtocol::LMTP => StartTlsProtocol::Lmtp, + StartTLSProtocol::NNTP => StartTlsProtocol::Nntp, + StartTLSProtocol::Postgres => StartTlsProtocol::Postgres, + StartTLSProtocol::MySQL => StartTlsProtocol::MySql, + } + .into() + }), + scans: Some(TestSslScans { + testssl_scans: Some(test_ssl_scans::TestsslScans::All(true)), + }), + }; + let response = leech.test_ssl(request).await?.into_inner(); + store_testssl_result(&GLOBAL.db, self.attack_uuid, self.workspace.uuid, response).await?; + + Ok(()) + } +} diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index d787f1530..41afb554a 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -38,6 +38,8 @@ pub struct TestSSLSettings { } /// Protocols to select from when using `--starttls` +#[derive(Debug)] +#[allow(missing_docs)] // The names are pretty unambiguous pub enum StartTLSProtocol { FTP, SMTP, @@ -121,7 +123,6 @@ pub async fn run_testssl(settings: TestSSLSettings) -> Result Result cmd.arg("ftp"), - StartTLSProtocol::SMTP => cmd.arg("smtp"), - StartTLSProtocol::POP3 => cmd.arg("pop3"), - StartTLSProtocol::IMAP => cmd.arg("imap"), - StartTLSProtocol::XMPP => cmd.arg("xmpp"), - StartTLSProtocol::LMTP => cmd.arg("lmtp"), - StartTLSProtocol::NNTP => cmd.arg("nntp"), - StartTLSProtocol::Postgres => cmd.arg("postgres"), - StartTLSProtocol::MySQL => cmd.arg("mysql"), - } + cmd.arg("--starttls").arg(match protocol { + StartTLSProtocol::FTP => "ftp", + StartTLSProtocol::SMTP => "smtp", + StartTLSProtocol::POP3 => "pop3", + StartTLSProtocol::IMAP => "imap", + StartTLSProtocol::XMPP => "xmpp", + StartTLSProtocol::LMTP => "lmtp", + StartTLSProtocol::NNTP => "nntp", + StartTLSProtocol::Postgres => "postgres", + StartTLSProtocol::MySQL => "mysql", + }); } // https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L20277 diff --git a/leech/src/rpc/attacks.rs b/leech/src/rpc/attacks.rs index f99525e4b..706ae5824 100644 --- a/leech/src/rpc/attacks.rs +++ b/leech/src/rpc/attacks.rs @@ -6,7 +6,7 @@ use std::time::Duration; use chrono::{Datelike, Timelike}; use futures::Stream; -use log::error; +use log::{debug, error}; use prost_types::Timestamp; use tonic::{Request, Response, Status}; use uuid::Uuid; @@ -20,13 +20,16 @@ use crate::modules::dns::{dns_resolution, DnsRecordResult, DnsResolutionSettings use crate::modules::host_alive::icmp_scan::{start_icmp_scan, IcmpScanSettings}; use crate::modules::port_scanner::tcp_con::{start_tcp_con_port_scan, TcpPortScannerSettings}; use crate::modules::service_detection::{detect_service, DetectServiceSettings, Service}; +use crate::modules::testssl::{run_testssl, StartTLSProtocol, TestSSLScans, TestSSLSettings}; use crate::rpc::rpc_attacks::req_attack_service_server::ReqAttackService; use crate::rpc::rpc_attacks::shared::CertEntry; +use crate::rpc::rpc_attacks::test_ssl_scans::TestsslScans; use crate::rpc::rpc_attacks::{ BruteforceSubdomainRequest, BruteforceSubdomainResponse, CertificateTransparencyRequest, CertificateTransparencyResponse, DnsResolutionRequest, DnsResolutionResponse, HostsAliveRequest, HostsAliveResponse, ServiceDetectionRequest, ServiceDetectionResponse, - ServiceDetectionResponseType, TcpPortScanRequest, TcpPortScanResponse, + ServiceDetectionResponseType, StartTlsProtocol, TcpPortScanRequest, TcpPortScanResponse, + TestSslRequest, TestSslResponse, }; use crate::rpc::utils::stream_attack; @@ -299,4 +302,76 @@ impl ReqAttackService for Attacks { }, ) } + + async fn test_ssl( + &self, + request: Request, + ) -> Result, Status> { + let TestSslRequest { + attack_uuid, + uri, + connect_timeout, + openssl_timeout, + v6, + basic_auth, + starttls, + scans, + } = request.into_inner(); + let settings = TestSSLSettings { + uri, + connect_timeout, + openssl_timeout, + v6: v6.unwrap_or(false), + basic_auth: basic_auth.map(|x| (x.username, x.password)), + starttls: starttls + .map(|x| { + StartTlsProtocol::try_from(x).map_err(|_| { + Status::invalid_argument(format!( + "Invalid enum value {x} for StartTlsProtocol" + )) + }) + }) + .transpose()? + .map(|x| match x { + StartTlsProtocol::Ftp => StartTLSProtocol::FTP, + StartTlsProtocol::Smtp => StartTLSProtocol::SMTP, + StartTlsProtocol::Pop3 => StartTLSProtocol::POP3, + StartTlsProtocol::Imap => StartTLSProtocol::IMAP, + StartTlsProtocol::Xmpp => StartTLSProtocol::XMPP, + StartTlsProtocol::Lmtp => StartTLSProtocol::LMTP, + StartTlsProtocol::Nntp => StartTLSProtocol::NNTP, + StartTlsProtocol::Postgres => StartTLSProtocol::Postgres, + StartTlsProtocol::MySql => StartTLSProtocol::MySQL, + }), + scans: scans + .and_then(|x| x.testssl_scans) + .map(|x| match x { + TestsslScans::All(true) => TestSSLScans::All, + TestsslScans::All(false) => TestSSLScans::Default, + TestsslScans::Manual(x) => TestSSLScans::Manual { + protocols: x.protocols, + grease: x.grease, + ciphers: x.ciphers, + pfs: x.pfs, + server_preferences: x.server_preferences, + server_defaults: x.server_defaults, + header_response: x.header_response, + vulnerabilities: x.vulnerabilities, + cipher_tests_all: x.cipher_tests_all, + cipher_tests_per_proto: x.cipher_tests_per_proto, + browser_simulations: x.browser_simulations, + }, + }) + .unwrap_or_default(), + }; + + let results = run_testssl(settings).await.map_err(|err| { + error!("testssl failed: {err:?}"); + Status::internal("testssl failed. See logs") + })?; + + // TODO + debug!("{results:#?}"); + Ok(Response::new(TestSslResponse {})) + } } diff --git a/proto/attacks.proto b/proto/attacks.proto index 864165c07..894297986 100644 --- a/proto/attacks.proto +++ b/proto/attacks.proto @@ -192,6 +192,115 @@ message DnsResolutionResponse { shared.DNSRecord record = 1; } +/* + * testssl.sh + */ + +// Request for running testssl.sh +message TestSSLRequest { + // A unique id that identifier the attack + string attack_uuid = 1; + // The domain to scan + string uri = 2; + // Timeout for TCP handshakes in seconds + optional uint64 connect_timeout = 3; + // Timeout for `openssl` connections in seconds + optional uint64 openssl_timeout = 4; + // Enable ip v6 + optional bool v6 = 5; + // Set the `BASICAUTH` header when checking http headers + optional BasicAuth basic_auth = 6; + // Run against a STARTTLS enabled protocol + optional StartTLSProtocol starttls = 7; + // Which scans `testssl.sh` should run + optional TestSSLScans scans = 8; +} + +// The `BASICAUTH` header +message BasicAuth { + // The username + string username = 1; + // The password + string password = 2; +} + +// Protocols to select from when using `testssl.sh`'s `--starttls` option +enum StartTLSProtocol { + // FTP + FTP = 0; + // SMTP + SMTP = 1; + // POP3 + POP3 = 2; + // IMAP + IMAP = 3; + // XMPP + XMPP = 4; + // LMTP + LMTP = 5; + // NNTP + NNTP = 6; + // Postgres + Postgres = 7; + // MySQL + MySQL = 8; +} + +/// Config option which scans `testssl.sh` should run +message TestSSLScans { + // Workaround field to store a `oneof` + oneof testssl_scans { + // Either run all scans or just the default ones + bool all = 1; + + // Select the scans to run manually + TestSSLScansManual manual = 2; + } +} + +// Select the scans to run manually +// +// Each field (except `cipher_tests_...`) correspond directly to a section in `testssl.sh`'s output +message TestSSLScansManual { + /// Enables [`ScanResult`]'s `protocols` section + bool protocols = 1; + + /// Enables [`ScanResult`]'s `grease` section + bool grease = 2; + + /// Enables [`ScanResult`]'s `ciphers` section + bool ciphers = 3; + + /// Enables [`ScanResult`]'s `pfs` section + bool pfs = 4; + + /// Enables [`ScanResult`]'s `server_preferences` section + bool server_preferences = 5; + + /// Enables [`ScanResult`]'s `server_defaults` section + bool server_defaults = 6; + + /// Enables [`ScanResult`]'s `header_response` section + bool header_response = 7; + + /// Enables [`ScanResult`]'s `vulnerabilities` section + bool vulnerabilities = 8; + + /// Enables [`ScanResult`]'s `cipher_tests` section + bool cipher_tests_all = 9; + + /// Enables [`ScanResult`]'s `cipher_tests` section + bool cipher_tests_per_proto = 10; + + /// Enables [`ScanResult`]'s `browser_simulations` section + bool browser_simulations = 11; +} + +// Response to a test ssl request +message TestSSLResponse { + // TODO +} + // Implemented by leech; allows kraken to request attack from a leech service ReqAttackService { rpc BruteforceSubdomains(BruteforceSubdomainRequest) returns (stream BruteforceSubdomainResponse); @@ -200,6 +309,7 @@ service ReqAttackService { rpc ServiceDetection(ServiceDetectionRequest) returns (ServiceDetectionResponse); rpc HostsAliveCheck(HostsAliveRequest) returns (stream HostsAliveResponse); rpc DnsResolution(DnsResolutionRequest) returns (stream DnsResolutionResponse); + rpc TestSSL(TestSSLRequest) returns (TestSSLResponse); } /* From b19c42141edd2f04ef122c538cfb0c4747e43f66 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Thu, 21 Dec 2023 19:57:15 +0100 Subject: [PATCH 04/37] Made testssl run in dev environment --- leech/src/modules/testssl/mod.rs | 2 +- vagrant/leech.yml | 10 ++++++++++ vagrant/leech/leech.service | 2 +- vagrant/leech/testssl-fix | 13 +++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 vagrant/leech/testssl-fix diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index 41afb554a..ae8692bbd 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -119,7 +119,7 @@ pub async fn run_testssl(settings: TestSSLSettings) -> Result Date: Fri, 22 Dec 2023 13:46:55 +0100 Subject: [PATCH 05/37] Send testssl results over grpc and aggregate into a service --- kraken/src/modules/attack_results/testssl.rs | 134 +++++++++++++++++-- kraken/src/modules/attacks/testssl.rs | 13 +- leech/src/modules/testssl/json_pretty.rs | 60 ++++++++- leech/src/modules/testssl/mod.rs | 2 + leech/src/rpc/attacks.rs | 112 ++++++++++++---- proto/attacks.proto | 111 ++++++++++++++- 6 files changed, 386 insertions(+), 46 deletions(-) diff --git a/kraken/src/modules/attack_results/testssl.rs b/kraken/src/modules/attack_results/testssl.rs index 8d045f66b..9f73fbfa8 100644 --- a/kraken/src/modules/attack_results/testssl.rs +++ b/kraken/src/modules/attack_results/testssl.rs @@ -1,24 +1,134 @@ -use rorm::db::Executor; -use rorm::insert; -use rorm::prelude::ForeignModelByField; +use std::str::FromStr; + +use ipnetwork::IpNetwork; +use log::error; +use rorm::prelude::{ForeignModel, ForeignModelByField}; +use rorm::{insert, Patch}; use uuid::Uuid; -use crate::models::TestSSLResult; -use crate::rpc::rpc_definitions::TestSslResponse; +use crate::chan::global::GLOBAL; +use crate::models::{ + AggregationSource, AggregationTable, Attack, HostCertainty, PortCertainty, PortProtocol, + ServiceCertainty, SourceType, TestSSLResult, +}; +use crate::rpc::rpc_definitions::TestSslScanResult; /// Store a query certificate transparency's result and update the aggregated domains and hosts pub async fn store_testssl_result( - executor: impl Executor<'_>, attack_uuid: Uuid, workspace_uuid: Uuid, - result: TestSslResponse, + result: TestSslScanResult, ) -> Result<(), rorm::Error> { - insert!(executor, TestSSLResult) - .return_nothing() - .single(&TestSSLResult { + // TODO + + let mut tx = GLOBAL.db.start_transaction().await?; + + let TestSslScanResult { + target_host, + ip, + port, + rdns, + service, + pretest, + protocols, + grease, + ciphers, + pfs, + server_preferences, + server_defaults, + header_response, + vulnerabilities, + cipher_tests, + browser_simulations, + } = result; + + let ip = match IpNetwork::from_str(&ip) { + Ok(ip) => ip, + Err(err) => { + error!("Testssl didn't return a valid ip: {err}"); + return Ok(()); + } + }; + + let port = match u16::from_str(&port) { + Ok(port) => port, + Err(err) => { + error!("Testssl didn't return a valid port: {err}"); + return Ok(()); + } + }; + + let host_uuid = GLOBAL + .aggregator + .aggregate_host(workspace_uuid, ip, HostCertainty::Verified) + .await?; + + let port_uuid = GLOBAL + .aggregator + .aggregate_port( + workspace_uuid, + host_uuid, + port, + PortProtocol::Tcp, + PortCertainty::Verified, + ) + .await?; + + let service_uuid = GLOBAL + .aggregator + .aggregate_service( + workspace_uuid, + host_uuid, + Some(port_uuid), + &service, + ServiceCertainty::MaybeVerified, // TODO might be DefinitelyVerified? + ) + .await?; + + let source_uuid = insert!(&mut tx, TestSSLResult) + .return_primary_key() + .single(&InsertTestSSLResult { uuid: Uuid::new_v4(), attack: ForeignModelByField::Key(attack_uuid), }) - .await - // TODO + .await?; + + insert!(&mut tx, AggregationSource) + .return_nothing() + .bulk([ + AggregationSource { + uuid: Uuid::new_v4(), + workspace: ForeignModelByField::Key(workspace_uuid), + source_type: SourceType::TestSSL, + source_uuid, + aggregated_table: AggregationTable::Host, + aggregated_uuid: host_uuid, + }, + AggregationSource { + uuid: Uuid::new_v4(), + workspace: ForeignModelByField::Key(workspace_uuid), + source_type: SourceType::TestSSL, + source_uuid, + aggregated_table: AggregationTable::Port, + aggregated_uuid: port_uuid, + }, + AggregationSource { + uuid: Uuid::new_v4(), + workspace: ForeignModelByField::Key(workspace_uuid), + source_type: SourceType::TestSSL, + source_uuid, + aggregated_table: AggregationTable::Service, + aggregated_uuid: service_uuid, + }, + ]) + .await?; + + tx.commit().await +} + +#[derive(Patch)] +#[rorm(model = "TestSSLResult")] +struct InsertTestSSLResult { + uuid: Uuid, + attack: ForeignModel, } diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index b1080128e..32fe149d6 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -1,10 +1,11 @@ +use log::debug; + use crate::api::handler::attacks::schema::StartTLSProtocol; -use crate::chan::global::GLOBAL; use crate::chan::leech_manager::LeechClient; use crate::modules::attack_results::store_testssl_result; use crate::modules::attacks::{AttackContext, AttackError, TestSSLParams}; use crate::rpc::rpc_definitions::{ - test_ssl_scans, BasicAuth, StartTlsProtocol, TestSslRequest, TestSslScans, + test_ssl_scans, test_ssl_service, BasicAuth, StartTlsProtocol, TestSslRequest, TestSslScans, }; impl AttackContext { @@ -42,7 +43,13 @@ impl AttackContext { }), }; let response = leech.test_ssl(request).await?.into_inner(); - store_testssl_result(&GLOBAL.db, self.attack_uuid, self.workspace.uuid, response).await?; + debug!("{response:#?}"); + for service in response.services { + if let Some(test_ssl_service::TestsslService::Result(result)) = service.testssl_service + { + store_testssl_result(self.attack_uuid, self.workspace.uuid, result).await?; + } + } Ok(()) } diff --git a/leech/src/modules/testssl/json_pretty.rs b/leech/src/modules/testssl/json_pretty.rs index c4d936052..1572b6709 100644 --- a/leech/src/modules/testssl/json_pretty.rs +++ b/leech/src/modules/testssl/json_pretty.rs @@ -32,29 +32,58 @@ pub struct File { pub start_time: String, /// List of scans - pub scan_result: Vec, + pub scan_result: Vec, /// Time it took to scan in seconds pub scan_time: ScanTime, } +/// A service's scan results or an error +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum Service { + /// A service's scan results + Result(ScanResult), + + /// Some error prevented a service from being scanned + Error(Finding), +} + +/// A service's scan results +/// /// Header: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L863 /// Sections: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L783 #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct ScanResult { + /// The original user target this result belongs to pub target_host: String, + + /// The scanned ip address pub ip: String, + + /// The scanned port pub port: String, + + /// The ip address' rDNS name #[serde(rename = "rDNS")] pub rdns: String, + + /// The detected service pub service: String, + + /// TODO: not found yet in the wild pub hostname: Option, + /// Some sanity checks which can't be disabled #[serde(default)] pub pretest: Vec, + + /// The results of a single cipher check + /// + /// [`run_testssl`](super::run_testssl) doesn't expose the necessary option. #[serde(default)] - pub single_cipher: Vec, // + pub single_cipher: Vec, /// Which tls protocols are supported #[serde(default)] @@ -100,35 +129,62 @@ pub struct ScanResult { pub browser_simulations: Vec, } +/// Either a test's result or a log message +/// +/// Which one it is might be determined by the [`Severity`] +/// /// This struct's fields are found in [`fileout_json_finding`]. /// /// [`fileout_json_finding`]: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L873 #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Finding { + /// The test's id pub id: String, + + /// The test result's severity or the log message's log level pub severity: Severity, + + /// The test result or a log message pub finding: String, + /// An CVE associated with the test pub cve: Option, + + /// An CWE associated with the test pub cwe: Option, + + /// An hint on how to fix the problem + /// + /// Not completely implemented yet in `testssl.sh` pub hint: Option, } +/// Either a test result's severity or a log message's log level +/// /// Different levels has been taken from [`show_finding`] /// /// [`show_finding`]: https://github.com/drwetter/testssl.sh/blob/68dec54cc5aedf856a83425cb4cd475a3766fad5/testssl.sh#L473 #[derive(Serialize, Deserialize, Debug, Copy, Clone)] #[serde(rename_all = "UPPERCASE")] pub enum Severity { + /// A debug level log message Debug, + /// An info level log message Info, + /// A warning level log message Warn, + /// An error level log message Fatal, + /// The test's result doesn't pose an issue Ok, + /// The test's result pose a low priority issue Low, + /// The test's result pose a medium priority issue Medium, + /// The test's result pose a high priority issue High, + /// The test's result pose a critical priority issue Critical, } diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index ae8692bbd..379f60d7f 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -12,6 +12,8 @@ use tokio::process::Command; mod json; mod json_pretty; +pub use self::json_pretty::*; + /// The settings of a `testssl.sh` invocation #[derive(Default, Debug)] pub struct TestSSLSettings { diff --git a/leech/src/rpc/attacks.rs b/leech/src/rpc/attacks.rs index 706ae5824..64404e7df 100644 --- a/leech/src/rpc/attacks.rs +++ b/leech/src/rpc/attacks.rs @@ -6,7 +6,7 @@ use std::time::Duration; use chrono::{Datelike, Timelike}; use futures::Stream; -use log::{debug, error}; +use log::error; use prost_types::Timestamp; use tonic::{Request, Response, Status}; use uuid::Uuid; @@ -20,16 +20,16 @@ use crate::modules::dns::{dns_resolution, DnsRecordResult, DnsResolutionSettings use crate::modules::host_alive::icmp_scan::{start_icmp_scan, IcmpScanSettings}; use crate::modules::port_scanner::tcp_con::{start_tcp_con_port_scan, TcpPortScannerSettings}; use crate::modules::service_detection::{detect_service, DetectServiceSettings, Service}; -use crate::modules::testssl::{run_testssl, StartTLSProtocol, TestSSLScans, TestSSLSettings}; +use crate::modules::testssl::{self, run_testssl}; use crate::rpc::rpc_attacks::req_attack_service_server::ReqAttackService; use crate::rpc::rpc_attacks::shared::CertEntry; -use crate::rpc::rpc_attacks::test_ssl_scans::TestsslScans; use crate::rpc::rpc_attacks::{ - BruteforceSubdomainRequest, BruteforceSubdomainResponse, CertificateTransparencyRequest, - CertificateTransparencyResponse, DnsResolutionRequest, DnsResolutionResponse, - HostsAliveRequest, HostsAliveResponse, ServiceDetectionRequest, ServiceDetectionResponse, - ServiceDetectionResponseType, StartTlsProtocol, TcpPortScanRequest, TcpPortScanResponse, - TestSslRequest, TestSslResponse, + test_ssl_scans, test_ssl_service, BruteforceSubdomainRequest, BruteforceSubdomainResponse, + CertificateTransparencyRequest, CertificateTransparencyResponse, DnsResolutionRequest, + DnsResolutionResponse, HostsAliveRequest, HostsAliveResponse, ServiceDetectionRequest, + ServiceDetectionResponse, ServiceDetectionResponseType, StartTlsProtocol, TcpPortScanRequest, + TcpPortScanResponse, TestSslFinding, TestSslRequest, TestSslResponse, TestSslScanResult, + TestSslService, TestSslSeverity, }; use crate::rpc::utils::stream_attack; @@ -317,7 +317,7 @@ impl ReqAttackService for Attacks { starttls, scans, } = request.into_inner(); - let settings = TestSSLSettings { + let settings = testssl::TestSSLSettings { uri, connect_timeout, openssl_timeout, @@ -333,22 +333,22 @@ impl ReqAttackService for Attacks { }) .transpose()? .map(|x| match x { - StartTlsProtocol::Ftp => StartTLSProtocol::FTP, - StartTlsProtocol::Smtp => StartTLSProtocol::SMTP, - StartTlsProtocol::Pop3 => StartTLSProtocol::POP3, - StartTlsProtocol::Imap => StartTLSProtocol::IMAP, - StartTlsProtocol::Xmpp => StartTLSProtocol::XMPP, - StartTlsProtocol::Lmtp => StartTLSProtocol::LMTP, - StartTlsProtocol::Nntp => StartTLSProtocol::NNTP, - StartTlsProtocol::Postgres => StartTLSProtocol::Postgres, - StartTlsProtocol::MySql => StartTLSProtocol::MySQL, + StartTlsProtocol::Ftp => testssl::StartTLSProtocol::FTP, + StartTlsProtocol::Smtp => testssl::StartTLSProtocol::SMTP, + StartTlsProtocol::Pop3 => testssl::StartTLSProtocol::POP3, + StartTlsProtocol::Imap => testssl::StartTLSProtocol::IMAP, + StartTlsProtocol::Xmpp => testssl::StartTLSProtocol::XMPP, + StartTlsProtocol::Lmtp => testssl::StartTLSProtocol::LMTP, + StartTlsProtocol::Nntp => testssl::StartTLSProtocol::NNTP, + StartTlsProtocol::Postgres => testssl::StartTLSProtocol::Postgres, + StartTlsProtocol::MySql => testssl::StartTLSProtocol::MySQL, }), scans: scans .and_then(|x| x.testssl_scans) .map(|x| match x { - TestsslScans::All(true) => TestSSLScans::All, - TestsslScans::All(false) => TestSSLScans::Default, - TestsslScans::Manual(x) => TestSSLScans::Manual { + test_ssl_scans::TestsslScans::All(true) => testssl::TestSSLScans::All, + test_ssl_scans::TestsslScans::All(false) => testssl::TestSSLScans::Default, + test_ssl_scans::TestsslScans::Manual(x) => testssl::TestSSLScans::Manual { protocols: x.protocols, grease: x.grease, ciphers: x.ciphers, @@ -365,13 +365,69 @@ impl ReqAttackService for Attacks { .unwrap_or_default(), }; - let results = run_testssl(settings).await.map_err(|err| { - error!("testssl failed: {err:?}"); - Status::internal("testssl failed. See logs") - })?; + let services = run_testssl(settings) + .await + .map_err(|err| { + error!("testssl failed: {err:?}"); + Status::internal("testssl failed. See logs") + })? + .scan_result; + + fn conv_finding(finding: testssl::Finding) -> TestSslFinding { + TestSslFinding { + id: finding.id, + severity: match finding.severity { + testssl::Severity::Debug => TestSslSeverity::Debug, + testssl::Severity::Info => TestSslSeverity::Info, + testssl::Severity::Warn => TestSslSeverity::Warn, + testssl::Severity::Fatal => TestSslSeverity::Fatal, + testssl::Severity::Ok => TestSslSeverity::Ok, + testssl::Severity::Low => TestSslSeverity::Low, + testssl::Severity::Medium => TestSslSeverity::Medium, + testssl::Severity::High => TestSslSeverity::High, + testssl::Severity::Critical => TestSslSeverity::Critical, + } + .into(), + finding: finding.finding, + cve: finding.cve, + cwe: finding.cwe, + } + } + fn conv_findings(findings: Vec) -> Vec { + findings.into_iter().map(conv_finding).collect() + } - // TODO - debug!("{results:#?}"); - Ok(Response::new(TestSslResponse {})) + Ok(Response::new(TestSslResponse { + services: services + .into_iter() + .map(|service| TestSslService { + testssl_service: Some(match service { + testssl::Service::Result(service) => { + test_ssl_service::TestsslService::Result(TestSslScanResult { + target_host: service.target_host, + ip: service.ip, + port: service.port, + rdns: service.rdns, + service: service.service, + pretest: conv_findings(service.pretest), + protocols: conv_findings(service.protocols), + grease: conv_findings(service.grease), + ciphers: conv_findings(service.ciphers), + pfs: conv_findings(service.pfs), + server_preferences: conv_findings(service.server_preferences), + server_defaults: conv_findings(service.server_defaults), + header_response: conv_findings(service.header_response), + vulnerabilities: conv_findings(service.vulnerabilities), + cipher_tests: conv_findings(service.cipher_tests), + browser_simulations: conv_findings(service.browser_simulations), + }) + } + testssl::Service::Error(finding) => { + test_ssl_service::TestsslService::Error(conv_finding(finding)) + } + }), + }) + .collect(), + })) } } diff --git a/proto/attacks.proto b/proto/attacks.proto index 894297986..298cfb649 100644 --- a/proto/attacks.proto +++ b/proto/attacks.proto @@ -298,9 +298,118 @@ message TestSSLScansManual { // Response to a test ssl request message TestSSLResponse { - // TODO + // The services' scan results or their errors + repeated TestSSLService services = 1; } +// A service's scan results or an error +message TestSSLService { + // Workaround field to store a `oneof` + oneof testssl_service { + // The result from scanning a service + TestSSLScanResult result = 1; + + // Some error prevented a service from being scanned + TestSSLFinding error = 2; + } +} + +// A service's scan results +message TestSSLScanResult { + // The original user target this result belongs to + string target_host = 1; + + // The scanned ip address + string ip = 2; + + // The scanned port + string port = 3; + + // The ip address' rDNS name + string rdns = 4; + + // The detected service + string service = 5; + + // TODO: not found yet in the wild + // optional string hostname = 6; + + // Some sanity checks which can't be disabled + repeated TestSSLFinding pretest = 7; + + // Which tls protocols are supported + repeated TestSSLFinding protocols = 8; + + // Server implementation bugs and [GREASE](https://www.ietf.org/archive/id/draft-ietf-tls-grease-01.txt) + repeated TestSSLFinding grease = 9; + + // Which cipher suites are supported + repeated TestSSLFinding ciphers = 10; + + // Checks robust (perfect) forward secrecy key exchange + repeated TestSSLFinding pfs = 11; + + // The server's preferences + repeated TestSSLFinding server_preferences = 12; + + // The server's defaults + repeated TestSSLFinding server_defaults = 13; + + // The http header set by the server + repeated TestSSLFinding header_response = 14; + + // List of several vulnerabilities + repeated TestSSLFinding vulnerabilities = 15; + + // Which concrete ciphers are supported + // + // Depending on the option `testssl` is invoked with, + // this is either a list of all ciphers or a list of all cipher per tls protocol. + repeated TestSSLFinding cipher_tests = 16; + + // Which browser is able to establish a connection + repeated TestSSLFinding browser_simulations = 17; +} + +// A single test's result or testssl log message +message TestSSLFinding { + // The test's id + string id = 1; + // The result's severity + TestSSLSeverity severity = 2; + // The test's result + string finding = 3; + + // The associated CVE + optional string cve = 4; + // The associated CWE + optional string cwe = 5; +} + +// A TestSSLFinding's severity +enum TestSSLSeverity { + // A debug level log message + Debug = 0; + // An info level log message + Info = 1; + // A warning level log message + Warn = 2; + // An error level log message + Fatal = 3; + + // The test's result doesn't pose an issue + Ok = 4; + // The test's result pose a low priority issue + Low = 5; + // The test's result pose a medium priority issue + Medium = 6; + // The test's result pose a high priority issue + High = 7; + // The test's result pose a critical priority issue + Critical = 8; +} + + // Implemented by leech; allows kraken to request attack from a leech service ReqAttackService { rpc BruteforceSubdomains(BruteforceSubdomainRequest) returns (stream BruteforceSubdomainResponse); From 9b00d8870c22796b6f06d9224bac5cbd481d4726 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Fri, 22 Dec 2023 14:15:14 +0100 Subject: [PATCH 06/37] Store a testssl attack's most basic results --- kraken/migrations/0001_initial.toml | 2025 +++++++++-------- kraken/migrations/0002_placeholder.toml | 72 + .../api/handler/aggregation_source/utils.rs | 16 +- .../src/api/handler/attack_results/schema.rs | 23 + kraken/src/api/swagger.rs | 1 + kraken/src/models/attack/mod.rs | 22 + kraken/src/models/attack/patches.rs | 14 +- kraken/src/modules/attack_results/testssl.rs | 45 +- kraken/src/modules/attacks/testssl.rs | 8 +- 9 files changed, 1217 insertions(+), 1009 deletions(-) create mode 100644 kraken/migrations/0002_placeholder.toml diff --git a/kraken/migrations/0001_initial.toml b/kraken/migrations/0001_initial.toml index 3f6f6b78a..7acae846c 100644 --- a/kraken/migrations/0001_initial.toml +++ b/kraken/migrations/0001_initial.toml @@ -1,11 +1,11 @@ [Migration] -Hash = "17131517629269041261" +Hash = "15196245589917706392" Initial = true Replaces = [] [[Migration.Operations]] Type = "CreateModel" -Name = "settings" +Name = "oauthclient" [[Migration.Operations.Fields]] Name = "uuid" @@ -15,56 +15,66 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "mfa_required" -Type = "boolean" +Name = "name" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "oidc_initial_permission_level" -Type = "choices" +Name = "secret" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "ReadOnly", - "Default", - "Admin", -] +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "dehashed_email" +Name = "redirect_uri" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 1024 +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateModel" +Name = "oauthdecision" [[Migration.Operations.Fields]] -Name = "dehashed_api_key" -Type = "varchar" +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 1024 +Type = "primary_key" [[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" +Name = "action" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Type = "choices" +Value = [ + "Accept", + "Deny", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "wordlist" +Name = "leech" [[Migration.Operations.Fields]] Name = "uuid" @@ -88,33 +98,41 @@ Type = "unique" Type = "not_null" [[Migration.Operations.Fields]] -Name = "description" +Name = "address" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 1024 +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "unique" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "path" +Name = "description" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 255 +Value = 65535 + +[[Migration.Operations.Fields]] +Name = "secret" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "unique" +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "manualhost" +Name = "search" [[Migration.Operations.Fields]] Name = "uuid" @@ -124,57 +142,96 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "ip_addr" -Type = "ipnetwork" +Name = "finished_at" +Type = "datetime" +Annotations = [] + +[[Migration.Operations.Fields]] +Name = "error" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "os_type" -Type = "choices" +Name = "search_term" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "Unknown", - "Linux", - "Windows", - "Apple", - "Android", - "FreeBSD", -] +Type = "max_length" +Value = 20 [[Migration.Operations.Fields.Annotations]] Type = "not_null" +[[Migration.Operations]] +Type = "CreateModel" +Name = "searchresult" + [[Migration.Operations.Fields]] -Name = "certainty" +Name = "uuid" +Type = "uuid" + +[[Migration.Operations.Fields.Annotations]] +Type = "primary_key" + +[[Migration.Operations.Fields]] +Name = "ref_key" +Type = "uuid" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "ref_type" Type = "choices" [[Migration.Operations.Fields.Annotations]] Type = "choices" Value = [ - "Historical", - "SupposedTo", + "Host", + "Service", + "Port", + "Domain", + "DnsRecordResult", + "TcpPortScanResult", + "DehashedQueryResult", + "CertificateTransparencyResult", + "HostAliveResult", + "ServiceDetectionResult", ] +[[Migration.Operations.Fields.Annotations]] +Type = "index" + [[Migration.Operations.Fields.Annotations]] Type = "not_null" -[[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" +[[Migration.Operations]] +Type = "CreateModel" +Name = "oidcuser" -[[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +[[Migration.Operations.Fields]] +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "not_null" +Type = "primary_key" [[Migration.Operations]] Type = "CreateModel" -Name = "manualservice" +Name = "localuser" [[Migration.Operations.Fields]] Name = "uuid" @@ -184,63 +241,48 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "name" +Name = "password_hash" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 255 +Value = 1024 [[Migration.Operations.Fields.Annotations]] Type = "not_null" +[[Migration.Operations]] +Type = "CreateModel" +Name = "localuserkey" + [[Migration.Operations.Fields]] -Name = "version" -Type = "varchar" +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "primary_key" [[Migration.Operations.Fields]] -Name = "certainty" -Type = "choices" - -[[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "Historical", - "SupposedTo", -] +Name = "name" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "not_null" - -[[Migration.Operations.Fields]] -Name = "host" -Type = "ipnetwork" +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "port" -Type = "int32" -Annotations = [] - -[[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" - -[[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Name = "key" +Type = "binary" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "manualport" +Name = "user" [[Migration.Operations.Fields]] Name = "uuid" @@ -250,51 +292,52 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "port" -Type = "int32" +Name = "username" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "index" +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "unique" + [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "protocol" -Type = "choices" +Name = "display_name" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "Unknown", - "Tcp", - "Udp", - "Sctp", -] +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "certainty" +Name = "permission" Type = "choices" [[Migration.Operations.Fields.Annotations]] Type = "choices" Value = [ - "Historical", - "SupposedTo", + "ReadOnly", + "Default", + "Admin", ] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "host" -Type = "ipnetwork" - -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" +Name = "last_login" +Type = "datetime" +Annotations = [] [[Migration.Operations.Fields]] Name = "created_at" @@ -308,7 +351,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "manualdomain" +Name = "leechapikey" [[Migration.Operations.Fields]] Name = "uuid" @@ -318,29 +361,33 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "domain" +Name = "key" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" Value = 255 +[[Migration.Operations.Fields.Annotations]] +Type = "unique" + [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" +Name = "name" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" - +Type = "max_length" +Value = 255 + [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "oauthclient" +Name = "settings" [[Migration.Operations.Fields]] Name = "uuid" @@ -350,66 +397,95 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "name" -Type = "varchar" +Name = "mfa_required" +Type = "boolean" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "oidc_initial_permission_level" +Type = "choices" + +[[Migration.Operations.Fields.Annotations]] +Type = "choices" +Value = [ + "ReadOnly", + "Default", + "Admin", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "secret" +Name = "dehashed_email" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 255 - -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" +Value = 1024 [[Migration.Operations.Fields]] -Name = "redirect_uri" +Name = "dehashed_api_key" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 255 +Value = 1024 + +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "oauthdecision" +Name = "workspacemember" [[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" +Name = "id" +Type = "int64" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_increment" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" [[Migration.Operations.Fields]] -Name = "action" +Name = "permission" Type = "choices" [[Migration.Operations.Fields.Annotations]] Type = "choices" Value = [ - "Accept", - "Deny", + "ReadOnly", + "AttackOnly", + "ReadWrite", ] [[Migration.Operations.Fields.Annotations]] Type = "not_null" +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + [[Migration.Operations]] Type = "CreateModel" -Name = "globaltag" +Name = "workspace" [[Migration.Operations.Fields]] Name = "uuid" @@ -427,31 +503,53 @@ Type = "max_length" Value = 255 [[Migration.Operations.Fields.Annotations]] -Type = "unique" +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "description" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 65535 + +[[Migration.Operations.Fields]] +Name = "archived" +Type = "boolean" + +[[Migration.Operations.Fields.Annotations]] +Type = "default_value" +Value = false [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "color" -Type = "int32" +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "workspacetag" +Name = "workspaceaccesstoken" [[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" +Name = "id" +Type = "int64" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_increment" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" [[Migration.Operations.Fields]] -Name = "name" +Name = "token" Type = "varchar" [[Migration.Operations.Fields.Annotations]] @@ -462,15 +560,15 @@ Value = 255 Type = "not_null" [[Migration.Operations.Fields]] -Name = "color" -Type = "int32" +Name = "expires_at" +Type = "datetime" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "attack" +Name = "workspaceinvitation" [[Migration.Operations.Fields]] Name = "uuid" @@ -479,44 +577,6 @@ Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" -[[Migration.Operations.Fields]] -Name = "attack_type" -Type = "choices" - -[[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "Undefined", - "BruteforceSubdomains", - "TcpPortScan", - "QueryCertificateTransparency", - "QueryUnhashed", - "HostAlive", - "ServiceDetection", - "DnsResolution", - "UdpPortScan", - "ForcedBrowsing", - "OSDetection", - "VersionDetection", - "AntiPortScanningDetection", -] - -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" - -[[Migration.Operations.Fields]] -Name = "finished_at" -Type = "datetime" -Annotations = [] - -[[Migration.Operations.Fields]] -Name = "error" -Type = "varchar" - -[[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 - [[Migration.Operations.Fields]] Name = "created_at" Type = "datetime" @@ -529,7 +589,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "dnsrecordresult" +Name = "workspacequeryfilter" [[Migration.Operations.Fields]] Name = "uuid" @@ -539,7 +599,7 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "source" +Name = "name" Type = "varchar" [[Migration.Operations.Fields.Annotations]] @@ -550,30 +610,28 @@ Value = 255 Type = "not_null" [[Migration.Operations.Fields]] -Name = "destination" +Name = "query" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 255 +Value = 1024 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "dns_record_type" +Name = "target" Type = "choices" [[Migration.Operations.Fields.Annotations]] Type = "choices" Value = [ - "A", - "Aaaa", - "Caa", - "Cname", - "Mx", - "Tlsa", - "Txt", + "Global", + "Domain", + "Host", + "Port", + "Service", ] [[Migration.Operations.Fields.Annotations]] @@ -591,7 +649,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "tcpportscanresult" +Name = "workspacequeryfilterview" [[Migration.Operations.Fields]] Name = "uuid" @@ -601,140 +659,104 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" +Name = "name" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "address" -Type = "ipnetwork" +Name = "global_query" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "not_null" +Type = "default_value" +Value = "" -[[Migration.Operations.Fields]] -Name = "port" -Type = "int32" +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 1024 [[Migration.Operations.Fields.Annotations]] Type = "not_null" -[[Migration.Operations]] -Type = "CreateModel" -Name = "dehashedqueryresult" - [[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" +Name = "domain_query" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "primary_key" - -[[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" +Type = "default_value" +Value = "" [[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Type = "max_length" +Value = 1024 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "dehashed_id" -Type = "int64" +Name = "host_query" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "not_null" - -[[Migration.Operations.Fields]] -Name = "email" -Type = "varchar" +Type = "default_value" +Value = "" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 255 - -[[Migration.Operations.Fields]] -Name = "username" -Type = "varchar" +Value = 1024 [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "not_null" [[Migration.Operations.Fields]] -Name = "password" +Name = "port_query" Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 - -[[Migration.Operations.Fields]] -Name = "hashed_password" -Type = "varchar" +Type = "default_value" +Value = "" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 8192 - -[[Migration.Operations.Fields]] -Name = "ip_address" -Type = "ipnetwork" +Value = 1024 [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "not_null" [[Migration.Operations.Fields]] -Name = "name" +Name = "service_query" Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 - -[[Migration.Operations.Fields]] -Name = "vin" -Type = "varchar" +Type = "default_value" +Value = "" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 255 - -[[Migration.Operations.Fields]] -Name = "address" -Type = "varchar" +Value = 1024 [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "not_null" [[Migration.Operations.Fields]] -Name = "phone" -Type = "varchar" +Name = "created_at" +Type = "datetime" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 - -[[Migration.Operations.Fields]] -Name = "database_name" -Type = "varchar" +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "certificatetransparencyvaluename" +Name = "host" [[Migration.Operations.Fields]] Name = "uuid" @@ -744,39 +766,40 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "value_name" -Type = "varchar" +Name = "ip_addr" +Type = "ipnetwork" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "index" [[Migration.Operations.Fields.Annotations]] Type = "not_null" -[[Migration.Operations]] -Type = "CreateModel" -Name = "certificatetransparencyresult" - -[[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" - -[[Migration.Operations.Fields.Annotations]] -Type = "primary_key" - [[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" +Name = "os_type" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Type = "choices" +Value = [ + "Unknown", + "Linux", + "Windows", + "Apple", + "Android", + "FreeBSD", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "issuer_name" +Name = "response_time" +Type = "int32" +Annotations = [] + +[[Migration.Operations.Fields]] +Name = "comment" Type = "varchar" [[Migration.Operations.Fields.Annotations]] @@ -787,40 +810,33 @@ Value = 255 Type = "not_null" [[Migration.Operations.Fields]] -Name = "common_name" -Type = "varchar" +Name = "certainty" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "choices" +Value = [ + "Historical", + "SupposedTo", + "Verified", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "not_before" -Type = "datetime" -Annotations = [] - -[[Migration.Operations.Fields]] -Name = "not_after" +Name = "created_at" Type = "datetime" -Annotations = [] - -[[Migration.Operations.Fields]] -Name = "serial_number" -Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "hostaliveresult" +Name = "hostglobaltag" [[Migration.Operations.Fields]] Name = "uuid" @@ -829,26 +845,20 @@ Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" -[[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" - -[[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" - -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" +[[Migration.Operations]] +Type = "CreateModel" +Name = "hostworkspacetag" [[Migration.Operations.Fields]] -Name = "host" -Type = "ipnetwork" +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "not_null" +Type = "primary_key" [[Migration.Operations]] Type = "CreateModel" -Name = "servicedetectionname" +Name = "service" [[Migration.Operations.Fields]] Name = "uuid" @@ -861,6 +871,9 @@ Type = "primary_key" Name = "name" Type = "varchar" +[[Migration.Operations.Fields.Annotations]] +Type = "index" + [[Migration.Operations.Fields.Annotations]] Type = "max_length" Value = 255 @@ -868,26 +881,16 @@ Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" -[[Migration.Operations]] -Type = "CreateModel" -Name = "servicedetectionresult" - -[[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" - -[[Migration.Operations.Fields.Annotations]] -Type = "primary_key" - [[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" +Name = "version" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Type = "index" [[Migration.Operations.Fields.Annotations]] -Type = "not_null" +Type = "max_length" +Value = 255 [[Migration.Operations.Fields]] Name = "certainty" @@ -906,44 +909,12 @@ Value = [ Type = "not_null" [[Migration.Operations.Fields]] -Name = "host" -Type = "ipnetwork" - -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" - -[[Migration.Operations.Fields]] -Name = "port" -Type = "int32" - -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" - -[[Migration.Operations]] -Type = "CreateModel" -Name = "workspacemember" - -[[Migration.Operations.Fields]] -Name = "id" -Type = "int64" - -[[Migration.Operations.Fields.Annotations]] -Type = "auto_increment" - -[[Migration.Operations.Fields.Annotations]] -Type = "primary_key" - -[[Migration.Operations.Fields]] -Name = "permission" -Type = "choices" +Name = "comment" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "ReadOnly", - "AttackOnly", - "ReadWrite", -] +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" @@ -960,7 +931,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "workspace" +Name = "serviceglobaltag" [[Migration.Operations.Fields]] Name = "uuid" @@ -969,62 +940,71 @@ Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" +[[Migration.Operations]] +Type = "CreateModel" +Name = "serviceworkspacetag" + [[Migration.Operations.Fields]] -Name = "name" -Type = "varchar" +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "primary_key" -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" +[[Migration.Operations]] +Type = "CreateModel" +Name = "port" [[Migration.Operations.Fields]] -Name = "description" -Type = "varchar" +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 65535 +Type = "primary_key" [[Migration.Operations.Fields]] -Name = "archived" -Type = "boolean" +Name = "port" +Type = "int32" [[Migration.Operations.Fields.Annotations]] -Type = "default_value" -Value = false +Type = "index" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" +Name = "protocol" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Type = "choices" +Value = [ + "Unknown", + "Tcp", + "Udp", + "Sctp", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" -[[Migration.Operations]] -Type = "CreateModel" -Name = "workspaceaccesstoken" - [[Migration.Operations.Fields]] -Name = "id" -Type = "int64" +Name = "certainty" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "auto_increment" +Type = "choices" +Value = [ + "Historical", + "SupposedTo", + "Verified", +] [[Migration.Operations.Fields.Annotations]] -Type = "primary_key" +Type = "not_null" [[Migration.Operations.Fields]] -Name = "token" +Name = "comment" Type = "varchar" [[Migration.Operations.Fields.Annotations]] @@ -1035,15 +1015,18 @@ Value = 255 Type = "not_null" [[Migration.Operations.Fields]] -Name = "expires_at" +Name = "created_at" Type = "datetime" +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" + [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "workspaceinvitation" +Name = "portglobaltag" [[Migration.Operations.Fields]] Name = "uuid" @@ -1052,19 +1035,20 @@ Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" +[[Migration.Operations]] +Type = "CreateModel" +Name = "portworkspacetag" + [[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" - -[[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "not_null" +Type = "primary_key" [[Migration.Operations]] Type = "CreateModel" -Name = "workspacequeryfilter" +Name = "domain" [[Migration.Operations.Fields]] Name = "uuid" @@ -1074,9 +1058,12 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "name" +Name = "domain" Type = "varchar" +[[Migration.Operations.Fields.Annotations]] +Type = "index" + [[Migration.Operations.Fields.Annotations]] Type = "max_length" Value = 255 @@ -1085,29 +1072,26 @@ Value = 255 Type = "not_null" [[Migration.Operations.Fields]] -Name = "query" -Type = "varchar" +Name = "certainty" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 1024 +Type = "choices" +Value = [ + "Unverified", + "Verified", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "target" -Type = "choices" +Name = "comment" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "Global", - "Domain", - "Host", - "Port", - "Service", -] +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" @@ -1124,7 +1108,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "workspacequeryfilterview" +Name = "domaindomainrelation" [[Migration.Operations.Fields]] Name = "uuid" @@ -1133,105 +1117,119 @@ Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" +[[Migration.Operations]] +Type = "CreateModel" +Name = "domainhostrelation" + [[Migration.Operations.Fields]] -Name = "name" -Type = "varchar" +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "primary_key" + +[[Migration.Operations.Fields]] +Name = "is_direct" +Type = "boolean" [[Migration.Operations.Fields.Annotations]] Type = "not_null" -[[Migration.Operations.Fields]] -Name = "global_query" -Type = "varchar" +[[Migration.Operations]] +Type = "CreateModel" +Name = "domainglobaltag" -[[Migration.Operations.Fields.Annotations]] -Type = "default_value" -Value = "" +[[Migration.Operations.Fields]] +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 1024 +Type = "primary_key" -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" +[[Migration.Operations]] +Type = "CreateModel" +Name = "domainworkspacetag" [[Migration.Operations.Fields]] -Name = "domain_query" -Type = "varchar" - -[[Migration.Operations.Fields.Annotations]] -Type = "default_value" -Value = "" +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 1024 +Type = "primary_key" -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" +[[Migration.Operations]] +Type = "CreateModel" +Name = "aggregationsource" [[Migration.Operations.Fields]] -Name = "host_query" -Type = "varchar" +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "default_value" -Value = "" +Type = "primary_key" + +[[Migration.Operations.Fields]] +Name = "source_type" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 1024 +Type = "choices" +Value = [ + "BruteforceSubdomains", + "TcpPortScan", + "QueryCertificateTransparency", + "QueryDehashed", + "HostAlive", + "ServiceDetection", + "DnsResolution", + "UdpPortScan", + "ForcedBrowsing", + "OSDetection", + "VersionDetection", + "AntiPortScanningDetection", + "TestSSL", + "ManualDomain", + "ManualHost", + "ManualPort", + "ManualService", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "port_query" -Type = "varchar" - -[[Migration.Operations.Fields.Annotations]] -Type = "default_value" -Value = "" - -[[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 1024 +Name = "source_uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "service_query" -Type = "varchar" - -[[Migration.Operations.Fields.Annotations]] -Type = "default_value" -Value = "" +Name = "aggregated_table" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 1024 +Type = "choices" +Value = [ + "Host", + "Port", + "Service", + "Domain", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" - -[[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Name = "aggregated_uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "search" +Name = "globaltag" [[Migration.Operations.Fields]] Name = "uuid" @@ -1241,42 +1239,29 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "finished_at" -Type = "datetime" -Annotations = [] - -[[Migration.Operations.Fields]] -Name = "error" +Name = "name" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" Value = 255 -[[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" - [[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Type = "unique" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "search_term" -Type = "varchar" - -[[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 20 +Name = "color" +Type = "int32" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "searchresult" +Name = "workspacetag" [[Migration.Operations.Fields]] Name = "uuid" @@ -1286,40 +1271,26 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "ref_key" -Type = "uuid" +Name = "name" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "not_null" - -[[Migration.Operations.Fields]] -Name = "ref_type" -Type = "choices" +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "Host", - "Service", - "Port", - "Domain", - "DnsRecordResult", - "TcpPortScanResult", - "DehashedQueryResult", - "CertificateTransparencyResult", - "HostAliveResult", - "ServiceDetectionResult", -] +Type = "not_null" -[[Migration.Operations.Fields.Annotations]] -Type = "index" +[[Migration.Operations.Fields]] +Name = "color" +Type = "int32" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "leech" +Name = "wordlist" [[Migration.Operations.Fields]] Name = "uuid" @@ -1343,41 +1314,33 @@ Type = "unique" Type = "not_null" [[Migration.Operations.Fields]] -Name = "address" +Name = "description" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 255 - -[[Migration.Operations.Fields.Annotations]] -Type = "unique" +Value = 1024 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "description" +Name = "path" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 65535 - -[[Migration.Operations.Fields]] -Name = "secret" -Type = "varchar" +Value = 255 [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "unique" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "host" +Name = "attack" [[Migration.Operations.Fields]] Name = "uuid" @@ -1387,40 +1350,67 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "ip_addr" -Type = "ipnetwork" +Name = "attack_type" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "index" +Type = "choices" +Value = [ + "Undefined", + "BruteforceSubdomains", + "TcpPortScan", + "QueryCertificateTransparency", + "QueryUnhashed", + "HostAlive", + "ServiceDetection", + "DnsResolution", + "UdpPortScan", + "ForcedBrowsing", + "OSDetection", + "VersionDetection", + "AntiPortScanningDetection", + "TestSSL", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "os_type" -Type = "choices" +Name = "finished_at" +Type = "datetime" +Annotations = [] + +[[Migration.Operations.Fields]] +Name = "error" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "Unknown", - "Linux", - "Windows", - "Apple", - "Android", - "FreeBSD", -] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] Type = "not_null" +[[Migration.Operations]] +Type = "CreateModel" +Name = "dnsrecordresult" + [[Migration.Operations.Fields]] -Name = "response_time" -Type = "int32" -Annotations = [] +Name = "uuid" +Type = "uuid" + +[[Migration.Operations.Fields.Annotations]] +Type = "primary_key" [[Migration.Operations.Fields]] -Name = "comment" +Name = "source" Type = "varchar" [[Migration.Operations.Fields.Annotations]] @@ -1431,15 +1421,30 @@ Value = 255 Type = "not_null" [[Migration.Operations.Fields]] -Name = "certainty" +Name = "destination" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "dns_record_type" Type = "choices" [[Migration.Operations.Fields.Annotations]] Type = "choices" Value = [ - "Historical", - "SupposedTo", - "Verified", + "A", + "Aaaa", + "Caa", + "Cname", + "Mx", + "Tlsa", + "Txt", ] [[Migration.Operations.Fields.Annotations]] @@ -1457,7 +1462,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "hostglobaltag" +Name = "tcpportscanresult" [[Migration.Operations.Fields]] Name = "uuid" @@ -1466,20 +1471,33 @@ Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" -[[Migration.Operations]] -Type = "CreateModel" -Name = "hostworkspacetag" +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" [[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" +Name = "address" +Type = "ipnetwork" [[Migration.Operations.Fields.Annotations]] -Type = "primary_key" +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "port" +Type = "int32" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "service" +Name = "dehashedqueryresult" [[Migration.Operations.Fields]] Name = "uuid" @@ -1489,92 +1507,105 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "name" -Type = "varchar" +Name = "created_at" +Type = "datetime" [[Migration.Operations.Fields.Annotations]] -Type = "index" +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "dehashed_id" +Type = "int64" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "version" +Name = "email" Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "index" +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields]] +Name = "username" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" Value = 255 [[Migration.Operations.Fields]] -Name = "certainty" -Type = "choices" +Name = "password" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "Historical", - "SupposedTo", - "MaybeVerified", - "DefinitelyVerified", -] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields]] +Name = "hashed_password" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "not_null" +Type = "max_length" +Value = 8192 [[Migration.Operations.Fields]] -Name = "comment" -Type = "varchar" +Name = "ip_address" +Type = "ipnetwork" [[Migration.Operations.Fields.Annotations]] Type = "max_length" Value = 255 +[[Migration.Operations.Fields]] +Name = "name" +Type = "varchar" + [[Migration.Operations.Fields.Annotations]] -Type = "not_null" +Type = "max_length" +Value = 255 [[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" +Name = "vin" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Type = "max_length" +Value = 255 -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" +[[Migration.Operations.Fields]] +Name = "address" +Type = "varchar" -[[Migration.Operations]] -Type = "CreateModel" -Name = "serviceglobaltag" +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 [[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" +Name = "phone" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "primary_key" - -[[Migration.Operations]] -Type = "CreateModel" -Name = "serviceworkspacetag" +Type = "max_length" +Value = 255 [[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" +Name = "database_name" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "primary_key" +Type = "max_length" +Value = 255 [[Migration.Operations]] Type = "CreateModel" -Name = "port" +Name = "certificatetransparencyvaluename" [[Migration.Operations.Fields]] Name = "uuid" @@ -1584,48 +1615,50 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "port" -Type = "int32" +Name = "value_name" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "index" +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" +[[Migration.Operations]] +Type = "CreateModel" +Name = "certificatetransparencyresult" + [[Migration.Operations.Fields]] -Name = "protocol" -Type = "choices" +Name = "uuid" +Type = "uuid" [[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "Unknown", - "Tcp", - "Udp", - "Sctp", -] +Type = "primary_key" + +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "certainty" -Type = "choices" +Name = "issuer_name" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "Historical", - "SupposedTo", - "Verified", -] +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "comment" +Name = "common_name" Type = "varchar" [[Migration.Operations.Fields.Annotations]] @@ -1636,18 +1669,29 @@ Value = 255 Type = "not_null" [[Migration.Operations.Fields]] -Name = "created_at" +Name = "not_before" +Type = "datetime" +Annotations = [] + +[[Migration.Operations.Fields]] +Name = "not_after" Type = "datetime" +Annotations = [] + +[[Migration.Operations.Fields]] +Name = "serial_number" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Type = "max_length" +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "portglobaltag" +Name = "hostaliveresult" [[Migration.Operations.Fields]] Name = "uuid" @@ -1656,9 +1700,26 @@ Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "host" +Type = "ipnetwork" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + [[Migration.Operations]] Type = "CreateModel" -Name = "portworkspacetag" +Name = "servicedetectionname" [[Migration.Operations.Fields]] Name = "uuid" @@ -1667,9 +1728,20 @@ Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" +[[Migration.Operations.Fields]] +Name = "name" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + [[Migration.Operations]] Type = "CreateModel" -Name = "domain" +Name = "servicedetectionresult" [[Migration.Operations.Fields]] Name = "uuid" @@ -1679,15 +1751,11 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "domain" -Type = "varchar" - -[[Migration.Operations.Fields.Annotations]] -Type = "index" +Name = "created_at" +Type = "datetime" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] Type = "not_null" @@ -1699,37 +1767,32 @@ Type = "choices" [[Migration.Operations.Fields.Annotations]] Type = "choices" Value = [ - "Unverified", - "Verified", + "Historical", + "SupposedTo", + "MaybeVerified", + "DefinitelyVerified", ] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "comment" -Type = "varchar" - -[[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Name = "host" +Type = "ipnetwork" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "created_at" -Type = "datetime" - -[[Migration.Operations.Fields.Annotations]] -Type = "auto_create_time" +Name = "port" +Type = "int32" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "domaindomainrelation" +Name = "testsslresult" [[Migration.Operations.Fields]] Name = "uuid" @@ -1738,38 +1801,19 @@ Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" -[[Migration.Operations]] -Type = "CreateModel" -Name = "domainhostrelation" - [[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" +Name = "created_at" +Type = "datetime" [[Migration.Operations.Fields.Annotations]] -Type = "primary_key" - -[[Migration.Operations.Fields]] -Name = "is_direct" -Type = "boolean" +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "domainglobaltag" - -[[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" - -[[Migration.Operations.Fields.Annotations]] -Type = "primary_key" - -[[Migration.Operations]] -Type = "CreateModel" -Name = "domainworkspacetag" +Name = "manualhost" [[Migration.Operations.Fields]] Name = "uuid" @@ -1778,89 +1822,58 @@ Type = "uuid" [[Migration.Operations.Fields.Annotations]] Type = "primary_key" -[[Migration.Operations]] -Type = "CreateModel" -Name = "aggregationsource" - [[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" +Name = "ip_addr" +Type = "ipnetwork" [[Migration.Operations.Fields.Annotations]] -Type = "primary_key" +Type = "not_null" [[Migration.Operations.Fields]] -Name = "source_type" +Name = "os_type" Type = "choices" [[Migration.Operations.Fields.Annotations]] Type = "choices" Value = [ - "BruteforceSubdomains", - "TcpPortScan", - "QueryCertificateTransparency", - "QueryDehashed", - "HostAlive", - "ServiceDetection", - "DnsResolution", - "UdpPortScan", - "ForcedBrowsing", - "OSDetection", - "VersionDetection", - "AntiPortScanningDetection", - "ManualDomain", - "ManualHost", - "ManualPort", - "ManualService", + "Unknown", + "Linux", + "Windows", + "Apple", + "Android", + "FreeBSD", ] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "source_uuid" -Type = "uuid" - -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" - -[[Migration.Operations.Fields]] -Name = "aggregated_table" +Name = "certainty" Type = "choices" [[Migration.Operations.Fields.Annotations]] Type = "choices" Value = [ - "Host", - "Port", - "Service", - "Domain", + "Historical", + "SupposedTo", ] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "aggregated_uuid" -Type = "uuid" +Name = "created_at" +Type = "datetime" [[Migration.Operations.Fields.Annotations]] -Type = "not_null" - -[[Migration.Operations]] -Type = "CreateModel" -Name = "oidcuser" - -[[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] -Type = "primary_key" +Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "localuser" +Name = "manualservice" [[Migration.Operations.Fields]] Name = "uuid" @@ -1870,48 +1883,63 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "password_hash" +Name = "name" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" -Value = 1024 +Value = 255 [[Migration.Operations.Fields.Annotations]] Type = "not_null" -[[Migration.Operations]] -Type = "CreateModel" -Name = "localuserkey" - [[Migration.Operations.Fields]] -Name = "uuid" -Type = "uuid" +Name = "version" +Type = "varchar" [[Migration.Operations.Fields.Annotations]] -Type = "primary_key" +Type = "max_length" +Value = 255 [[Migration.Operations.Fields]] -Name = "name" -Type = "varchar" +Name = "certainty" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "choices" +Value = [ + "Historical", + "SupposedTo", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "key" -Type = "binary" +Name = "host" +Type = "ipnetwork" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "port" +Type = "int32" +Annotations = [] + +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "user" +Name = "manualport" [[Migration.Operations.Fields]] Name = "uuid" @@ -1921,52 +1949,51 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "username" -Type = "varchar" +Name = "port" +Type = "int32" [[Migration.Operations.Fields.Annotations]] Type = "index" -[[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 - -[[Migration.Operations.Fields.Annotations]] -Type = "unique" - [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "display_name" -Type = "varchar" +Name = "protocol" +Type = "choices" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "choices" +Value = [ + "Unknown", + "Tcp", + "Udp", + "Sctp", +] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "permission" +Name = "certainty" Type = "choices" [[Migration.Operations.Fields.Annotations]] Type = "choices" -Value = [ - "ReadOnly", - "Default", - "Admin", +Value = [ + "Historical", + "SupposedTo", ] [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "last_login" -Type = "datetime" -Annotations = [] +Name = "host" +Type = "ipnetwork" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" [[Migration.Operations.Fields]] Name = "created_at" @@ -1980,7 +2007,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateModel" -Name = "leechapikey" +Name = "manualdomain" [[Migration.Operations.Fields]] Name = "uuid" @@ -1990,26 +2017,22 @@ Type = "uuid" Type = "primary_key" [[Migration.Operations.Fields]] -Name = "key" +Name = "domain" Type = "varchar" [[Migration.Operations.Fields.Annotations]] Type = "max_length" Value = 255 -[[Migration.Operations.Fields.Annotations]] -Type = "unique" - [[Migration.Operations.Fields.Annotations]] Type = "not_null" [[Migration.Operations.Fields]] -Name = "name" -Type = "varchar" +Name = "created_at" +Type = "datetime" [[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 +Type = "auto_create_time" [[Migration.Operations.Fields.Annotations]] Type = "not_null" @@ -2046,17 +2069,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domainglobaltag" +Model = "serviceworkspacetag" [Migration.Operations.Field] -Name = "global_tag" +Name = "workspace_tag" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "globaltag" +TableName = "workspacetag" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2066,17 +2089,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domainglobaltag" +Model = "serviceworkspacetag" [Migration.Operations.Field] -Name = "domain" +Name = "service" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "domain" +TableName = "service" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2086,17 +2109,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "oidcuser" +Model = "serviceglobaltag" [Migration.Operations.Field] -Name = "user" +Name = "global_tag" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "globaltag" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2106,37 +2129,37 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "manualhost" +Model = "serviceglobaltag" [Migration.Operations.Field] -Name = "user" +Name = "service" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "service" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "manualhost" +Model = "domainglobaltag" [Migration.Operations.Field] -Name = "workspace" +Name = "global_tag" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "globaltag" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2146,17 +2169,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "dehashedqueryresult" +Model = "domainglobaltag" [Migration.Operations.Field] -Name = "attack" +Name = "domain" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "attack" +TableName = "domain" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2166,7 +2189,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspacetag" +Model = "workspacequeryfilterview" [Migration.Operations.Field] Name = "workspace" @@ -2178,15 +2201,15 @@ Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] TableName = "workspace" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspaceinvitation" +Model = "domain" [Migration.Operations.Field] Name = "workspace" @@ -2206,10 +2229,10 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspaceinvitation" +Model = "workspaceaccesstoken" [Migration.Operations.Field] -Name = "from" +Name = "user" Type = "uuid" [[Migration.Operations.Field.Annotations]] @@ -2226,17 +2249,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspaceinvitation" +Model = "workspaceaccesstoken" [Migration.Operations.Field] -Name = "target" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "workspace" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2246,17 +2269,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "service" +Model = "workspaceaccesstoken" [Migration.Operations.Field] -Name = "host" +Name = "application" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "host" +TableName = "oauthclient" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2266,54 +2289,57 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "service" +Model = "domainhostrelation" [Migration.Operations.Field] -Name = "port" +Name = "domain" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "port" +TableName = "domain" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "service" +Model = "domainhostrelation" [Migration.Operations.Field] -Name = "workspace" +Name = "host" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "host" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "certificatetransparencyresult" +Model = "domainhostrelation" [Migration.Operations.Field] -Name = "attack" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "attack" +TableName = "workspace" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2323,20 +2349,20 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "attack" +Model = "searchresult" [Migration.Operations.Field] -Name = "started_by" +Name = "search" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "search" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" @@ -2346,54 +2372,54 @@ Type = "CreateField" Model = "attack" [Migration.Operations.Field] -Name = "workspace" +Name = "started_by" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "user" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "manualservice" +Model = "attack" [Migration.Operations.Field] -Name = "user" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "workspace" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "manualservice" +Model = "dehashedqueryresult" [Migration.Operations.Field] -Name = "workspace" +Name = "attack" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "attack" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2403,17 +2429,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "tcpportscanresult" +Model = "servicedetectionname" [Migration.Operations.Field] -Name = "attack" +Name = "result" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "attack" +TableName = "servicedetectionresult" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2423,17 +2449,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "certificatetransparencyvaluename" +Model = "certificatetransparencyresult" [Migration.Operations.Field] -Name = "ct_result" +Name = "attack" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "certificatetransparencyresult" +TableName = "attack" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2443,7 +2469,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspacequeryfilterview" +Model = "host" [Migration.Operations.Field] Name = "workspace" @@ -2455,25 +2481,25 @@ Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] TableName = "workspace" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "serviceglobaltag" +Model = "oauthdecision" [Migration.Operations.Field] -Name = "global_tag" +Name = "user" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "globaltag" +TableName = "user" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2483,17 +2509,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "serviceglobaltag" +Model = "oauthdecision" [Migration.Operations.Field] -Name = "service" +Name = "application" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "service" +TableName = "oauthclient" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2503,7 +2529,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domain" +Model = "oauthdecision" [Migration.Operations.Field] Name = "workspace" @@ -2523,17 +2549,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domainworkspacetag" +Model = "tcpportscanresult" [Migration.Operations.Field] -Name = "workspace_tag" +Name = "attack" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspacetag" +TableName = "attack" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2543,17 +2569,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domainworkspacetag" +Model = "portglobaltag" [Migration.Operations.Field] -Name = "domain" +Name = "global_tag" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "domain" +TableName = "globaltag" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2563,17 +2589,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "localuser" +Model = "portglobaltag" [Migration.Operations.Field] -Name = "user" +Name = "port" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "port" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2583,60 +2609,57 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "localuserkey" +Model = "certificatetransparencyvaluename" [Migration.Operations.Field] -Name = "user" +Name = "ct_result" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "localuser" +TableName = "certificatetransparencyresult" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspace" +Model = "hostworkspacetag" [Migration.Operations.Field] -Name = "owner" +Name = "workspace_tag" Type = "uuid" -[[Migration.Operations.Field.Annotations]] -Type = "index" - [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "workspacetag" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "host" +Model = "hostworkspacetag" [Migration.Operations.Field] -Name = "workspace" +Name = "host" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "host" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2646,17 +2669,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "aggregationsource" +Model = "dnsrecordresult" [Migration.Operations.Field] -Name = "workspace" +Name = "attack" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "attack" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2666,37 +2689,37 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "searchresult" +Model = "localuserkey" [Migration.Operations.Field] -Name = "search" +Name = "user" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "search" +TableName = "localuser" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspaceaccesstoken" +Model = "hostaliveresult" [Migration.Operations.Field] -Name = "user" +Name = "attack" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "attack" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2706,17 +2729,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspaceaccesstoken" +Model = "domainworkspacetag" [Migration.Operations.Field] -Name = "workspace" +Name = "workspace_tag" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "workspacetag" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2726,17 +2749,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspaceaccesstoken" +Model = "domainworkspacetag" [Migration.Operations.Field] -Name = "application" +Name = "domain" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "oauthclient" +TableName = "domain" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2746,17 +2769,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "manualport" +Model = "workspacequeryfilter" [Migration.Operations.Field] -Name = "user" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "workspace" ColumnName = "uuid" OnDelete = "Restrict" OnUpdate = "Restrict" @@ -2766,17 +2789,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "manualport" +Model = "service" [Migration.Operations.Field] -Name = "workspace" +Name = "host" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "host" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2786,37 +2809,34 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "serviceworkspacetag" +Model = "service" [Migration.Operations.Field] -Name = "workspace_tag" +Name = "port" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspacetag" +TableName = "port" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" -[[Migration.Operations.Field.Annotations]] -Type = "not_null" - [[Migration.Operations]] Type = "CreateField" -Model = "serviceworkspacetag" +Model = "service" [Migration.Operations.Field] -Name = "service" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "service" +TableName = "workspace" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2826,37 +2846,37 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "manualdomain" +Model = "testsslresult" [Migration.Operations.Field] -Name = "user" +Name = "attack" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "attack" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "manualdomain" +Model = "oidcuser" [Migration.Operations.Field] -Name = "workspace" +Name = "user" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "user" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -2866,20 +2886,23 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "servicedetectionresult" +Model = "workspace" [Migration.Operations.Field] -Name = "attack" +Name = "owner" Type = "uuid" +[[Migration.Operations.Field.Annotations]] +Type = "index" + [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "attack" +TableName = "user" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" @@ -2926,10 +2949,10 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspacemember" +Model = "manualdomain" [Migration.Operations.Field] -Name = "member" +Name = "user" Type = "uuid" [[Migration.Operations.Field.Annotations]] @@ -2938,15 +2961,15 @@ Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] TableName = "user" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspacemember" +Model = "manualdomain" [Migration.Operations.Field] Name = "workspace" @@ -2966,30 +2989,30 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "workspacequeryfilter" +Model = "servicedetectionresult" [Migration.Operations.Field] -Name = "workspace" +Name = "attack" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "attack" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "search" +Model = "localuser" [Migration.Operations.Field] -Name = "started_by" +Name = "user" Type = "uuid" [[Migration.Operations.Field.Annotations]] @@ -2998,15 +3021,35 @@ Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] TableName = "user" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "search" +Model = "leechapikey" + +[Migration.Operations.Field] +Name = "user" +Type = "uuid" + +[[Migration.Operations.Field.Annotations]] +Type = "foreign_key" + +[Migration.Operations.Field.Annotations.Value] +TableName = "user" +ColumnName = "uuid" +OnDelete = "Cascade" +OnUpdate = "Cascade" + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateField" +Model = "workspaceinvitation" [Migration.Operations.Field] Name = "workspace" @@ -3026,57 +3069,57 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domaindomainrelation" +Model = "workspaceinvitation" [Migration.Operations.Field] -Name = "source" +Name = "from" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "domain" +TableName = "user" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domaindomainrelation" +Model = "workspaceinvitation" [Migration.Operations.Field] -Name = "destination" +Name = "target" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "domain" +TableName = "user" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domaindomainrelation" +Model = "port" [Migration.Operations.Field] -Name = "workspace" +Name = "host" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspace" +TableName = "host" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -3086,37 +3129,37 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domainhostrelation" +Model = "port" [Migration.Operations.Field] -Name = "domain" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "domain" +TableName = "workspace" ColumnName = "uuid" -OnDelete = "Restrict" -OnUpdate = "Restrict" +OnDelete = "Cascade" +OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domainhostrelation" +Model = "search" [Migration.Operations.Field] -Name = "host" +Name = "started_by" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "host" +TableName = "user" ColumnName = "uuid" OnDelete = "Restrict" OnUpdate = "Restrict" @@ -3126,7 +3169,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "domainhostrelation" +Model = "search" [Migration.Operations.Field] Name = "workspace" @@ -3146,57 +3189,57 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "servicedetectionname" +Model = "domaindomainrelation" [Migration.Operations.Field] -Name = "result" +Name = "source" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "servicedetectionresult" +TableName = "domain" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "portworkspacetag" +Model = "domaindomainrelation" [Migration.Operations.Field] -Name = "workspace_tag" +Name = "destination" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspacetag" +TableName = "domain" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "portworkspacetag" +Model = "domaindomainrelation" [Migration.Operations.Field] -Name = "port" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "port" +TableName = "workspace" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -3206,17 +3249,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "hostaliveresult" +Model = "aggregationsource" [Migration.Operations.Field] -Name = "attack" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "attack" +TableName = "workspace" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -3226,27 +3269,27 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "port" +Model = "manualhost" [Migration.Operations.Field] -Name = "host" +Name = "user" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "host" +TableName = "user" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "port" +Model = "manualhost" [Migration.Operations.Field] Name = "workspace" @@ -3266,17 +3309,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "portglobaltag" +Model = "portworkspacetag" [Migration.Operations.Field] -Name = "global_tag" +Name = "workspace_tag" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "globaltag" +TableName = "workspacetag" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -3286,7 +3329,7 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "portglobaltag" +Model = "portworkspacetag" [Migration.Operations.Field] Name = "port" @@ -3306,17 +3349,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "hostworkspacetag" +Model = "workspacetag" [Migration.Operations.Field] -Name = "workspace_tag" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "workspacetag" +TableName = "workspace" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -3326,17 +3369,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "hostworkspacetag" +Model = "workspacemember" [Migration.Operations.Field] -Name = "host" +Name = "member" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "host" +TableName = "user" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -3346,17 +3389,17 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "oauthdecision" +Model = "workspacemember" [Migration.Operations.Field] -Name = "user" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "workspace" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" @@ -3366,27 +3409,27 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "oauthdecision" +Model = "manualservice" [Migration.Operations.Field] -Name = "application" +Name = "user" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "oauthclient" +TableName = "user" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "oauthdecision" +Model = "manualservice" [Migration.Operations.Field] Name = "workspace" @@ -3406,37 +3449,37 @@ Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "dnsrecordresult" +Model = "manualport" [Migration.Operations.Field] -Name = "attack" +Name = "user" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "attack" +TableName = "user" ColumnName = "uuid" -OnDelete = "Cascade" -OnUpdate = "Cascade" +OnDelete = "Restrict" +OnUpdate = "Restrict" [[Migration.Operations.Field.Annotations]] Type = "not_null" [[Migration.Operations]] Type = "CreateField" -Model = "leechapikey" +Model = "manualport" [Migration.Operations.Field] -Name = "user" +Name = "workspace" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "user" +TableName = "workspace" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" diff --git a/kraken/migrations/0002_placeholder.toml b/kraken/migrations/0002_placeholder.toml new file mode 100644 index 000000000..999179cf3 --- /dev/null +++ b/kraken/migrations/0002_placeholder.toml @@ -0,0 +1,72 @@ +[Migration] +Hash = "14978321572218628097" +Initial = false +Dependency = 1 +Replaces = [] + +[[Migration.Operations]] +Type = "CreateField" +Model = "testsslresult" + +[Migration.Operations.Field] +Name = "target_host" +Type = "varchar" + +[[Migration.Operations.Field.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateField" +Model = "testsslresult" + +[Migration.Operations.Field] +Name = "ip" +Type = "ipnetwork" + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateField" +Model = "testsslresult" + +[Migration.Operations.Field] +Name = "port" +Type = "int32" + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateField" +Model = "testsslresult" + +[Migration.Operations.Field] +Name = "rdns" +Type = "varchar" + +[[Migration.Operations.Field.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateField" +Model = "testsslresult" + +[Migration.Operations.Field] +Name = "service" +Type = "varchar" + +[[Migration.Operations.Field.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" diff --git a/kraken/src/api/handler/aggregation_source/utils.rs b/kraken/src/api/handler/aggregation_source/utils.rs index 51fad78c0..5aa6dd72c 100644 --- a/kraken/src/api/handler/aggregation_source/utils.rs +++ b/kraken/src/api/handler/aggregation_source/utils.rs @@ -344,10 +344,18 @@ impl FullAggregationSource { .condition(field_in(TestSSLResult::F.uuid, uuids)) .stream(); while let Some(result) = stream.try_next().await? { - testssl - .entry(*result.attack.key()) - .or_default() - .push(SimpleTestSSLResult {}); + testssl.entry(*result.attack.key()).or_default().push( + SimpleTestSSLResult { + uuid: result.uuid, + attack: *result.attack.key(), + created_at: result.created_at, + target_host: result.target_host, + ip: result.ip.ip().to_string(), + port: result.port as u16, + rdns: result.rdns, + service: result.service, + }, + ); } } SourceType::UdpPortScan diff --git a/kraken/src/api/handler/attack_results/schema.rs b/kraken/src/api/handler/attack_results/schema.rs index a4c8b4d33..3c7d1f2df 100644 --- a/kraken/src/api/handler/attack_results/schema.rs +++ b/kraken/src/api/handler/attack_results/schema.rs @@ -197,5 +197,28 @@ pub struct SimpleDnsResolutionResult { /// A simple representation of a testssl result #[derive(Serialize, Deserialize, ToSchema, Debug, Clone)] pub struct SimpleTestSSLResult { + /// The primary key + pub uuid: Uuid, + + /// The attack which produced this result + pub attack: Uuid, + + /// The point in time, this result was produced + pub created_at: DateTime, + + /// The original user target this result belongs to + pub target_host: String, + + /// The scanned ip address + pub ip: String, + + /// The scanned port + pub port: u16, + + /// The ip address' rDNS name + pub rdns: String, + + /// The detected service + pub service: String, // TODO } diff --git a/kraken/src/api/swagger.rs b/kraken/src/api/swagger.rs index d5f786f9a..b24a9bca9 100644 --- a/kraken/src/api/swagger.rs +++ b/kraken/src/api/swagger.rs @@ -206,6 +206,7 @@ impl Modify for SecurityAddon2 { attack_results::schema::SimpleHostAliveResult, attack_results::schema::FullServiceDetectionResult, attack_results::schema::SimpleDnsResolutionResult, + attack_results::schema::SimpleTestSSLResult, dehashed_rs::Query, dehashed_rs::SearchType, attacks::schema::QueryDehashedRequest, diff --git a/kraken/src/models/attack/mod.rs b/kraken/src/models/attack/mod.rs index e9931a832..77606eeb1 100644 --- a/kraken/src/models/attack/mod.rs +++ b/kraken/src/models/attack/mod.rs @@ -330,5 +330,27 @@ pub struct TestSSLResult { /// The [attack](Attack) which produced this result #[rorm(on_delete = "Cascade", on_update = "Cascade")] pub attack: ForeignModel, + + /// The point in time, this result was produced + #[rorm(auto_create_time)] + pub created_at: DateTime, + + /// The original user target this result belongs to + #[rorm(max_length = 255)] + pub target_host: String, + + /// The scanned ip address + pub ip: IpNetwork, + + /// The scanned port + pub port: i32, + + /// The ip address' rDNS name + #[rorm(max_length = 255)] + pub rdns: String, + + /// The detected service + #[rorm(max_length = 255)] + pub service: String, // TODO } diff --git a/kraken/src/models/attack/patches.rs b/kraken/src/models/attack/patches.rs index d44c973d6..f20b43ad9 100644 --- a/kraken/src/models/attack/patches.rs +++ b/kraken/src/models/attack/patches.rs @@ -6,7 +6,7 @@ use uuid::Uuid; use crate::models::{ Attack, CertificateTransparencyResult, CertificateTransparencyValueName, DehashedQueryResult, DnsRecordResult, DnsRecordType, HostAliveResult, ServiceCertainty, ServiceDetectionResult, - TcpPortScanResult, + TcpPortScanResult, TestSSLResult, }; pub(crate) type BruteforceSubdomainsResultInsert = DnsRecordResultInsert; @@ -85,3 +85,15 @@ pub(crate) struct ServiceDetectionResultInsert { pub(crate) host: IpNetwork, pub(crate) port: i32, } + +#[derive(Patch)] +#[rorm(model = "TestSSLResult")] +pub(crate) struct TestSSLResultInsert { + pub(crate) uuid: Uuid, + pub(crate) attack: ForeignModel, + pub(crate) target_host: String, + pub(crate) ip: IpNetwork, + pub(crate) port: i32, + pub(crate) rdns: String, + pub(crate) service: String, +} diff --git a/kraken/src/modules/attack_results/testssl.rs b/kraken/src/modules/attack_results/testssl.rs index 9f73fbfa8..cb39e98e2 100644 --- a/kraken/src/modules/attack_results/testssl.rs +++ b/kraken/src/modules/attack_results/testssl.rs @@ -2,14 +2,14 @@ use std::str::FromStr; use ipnetwork::IpNetwork; use log::error; -use rorm::prelude::{ForeignModel, ForeignModelByField}; -use rorm::{insert, Patch}; +use rorm::insert; +use rorm::prelude::ForeignModelByField; use uuid::Uuid; use crate::chan::global::GLOBAL; use crate::models::{ - AggregationSource, AggregationTable, Attack, HostCertainty, PortCertainty, PortProtocol, - ServiceCertainty, SourceType, TestSSLResult, + AggregationSource, AggregationTable, DomainCertainty, HostCertainty, PortCertainty, + PortProtocol, ServiceCertainty, SourceType, TestSSLResult, TestSSLResultInsert, }; use crate::rpc::rpc_definitions::TestSslScanResult; @@ -17,6 +17,7 @@ use crate::rpc::rpc_definitions::TestSslScanResult; pub async fn store_testssl_result( attack_uuid: Uuid, workspace_uuid: Uuid, + user_uuid: Uuid, result: TestSslScanResult, ) -> Result<(), rorm::Error> { // TODO @@ -58,6 +59,20 @@ pub async fn store_testssl_result( } }; + let mut domain = rdns.clone(); + if domain.ends_with('.') { + domain.pop(); + } + let domain_uuid = GLOBAL + .aggregator + .aggregate_domain( + workspace_uuid, + &domain, + DomainCertainty::Unverified, + user_uuid, + ) + .await?; + let host_uuid = GLOBAL .aggregator .aggregate_host(workspace_uuid, ip, HostCertainty::Verified) @@ -87,15 +102,28 @@ pub async fn store_testssl_result( let source_uuid = insert!(&mut tx, TestSSLResult) .return_primary_key() - .single(&InsertTestSSLResult { + .single(&TestSSLResultInsert { uuid: Uuid::new_v4(), attack: ForeignModelByField::Key(attack_uuid), + target_host, + ip, + port: port as i32, + rdns, + service, }) .await?; insert!(&mut tx, AggregationSource) .return_nothing() .bulk([ + AggregationSource { + uuid: Uuid::new_v4(), + workspace: ForeignModelByField::Key(workspace_uuid), + source_type: SourceType::TestSSL, + source_uuid, + aggregated_table: AggregationTable::Domain, + aggregated_uuid: domain_uuid, + }, AggregationSource { uuid: Uuid::new_v4(), workspace: ForeignModelByField::Key(workspace_uuid), @@ -125,10 +153,3 @@ pub async fn store_testssl_result( tx.commit().await } - -#[derive(Patch)] -#[rorm(model = "TestSSLResult")] -struct InsertTestSSLResult { - uuid: Uuid, - attack: ForeignModel, -} diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index 32fe149d6..91f236da6 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -47,7 +47,13 @@ impl AttackContext { for service in response.services { if let Some(test_ssl_service::TestsslService::Result(result)) = service.testssl_service { - store_testssl_result(self.attack_uuid, self.workspace.uuid, result).await?; + store_testssl_result( + self.attack_uuid, + self.workspace.uuid, + self.user.uuid, + result, + ) + .await?; } } From b1e7c21820dd6bf29054a254b5480dad82c56b26 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Fri, 22 Dec 2023 14:37:38 +0100 Subject: [PATCH 07/37] Updated frontend SDK to testssl --- kraken_frontend/openapi.json | 2 +- kraken_frontend/scripts/gen-api.sh | 2 +- .../api/generated/.openapi-generator/FILES | 4 + .../src/api/generated/apis/AttacksApi.ts | 42 +++ .../src/api/generated/models/AttackType.ts | 3 +- .../src/api/generated/models/ManualInsert.ts | 48 +-- .../models/SimpleAggregationSource.ts | 9 + .../generated/models/SimpleTestSSLResult.ts | 129 ++++++++ .../src/api/generated/models/SourceAttack.ts | 10 +- .../generated/models/SourceAttackResult.ts | 110 ++++--- .../models/SourceAttackResultOneOf7.ts | 92 ++++++ .../api/generated/models/StartTLSProtocol.ts | 45 +++ .../api/generated/models/TestSSLRequest.ts | 124 ++++++++ .../src/api/generated/models/WsMessage.ts | 282 +++++++++--------- .../src/api/generated/models/index.ts | 4 + kraken_frontend/src/utils/attack-resolver.ts | 1 + 16 files changed, 685 insertions(+), 222 deletions(-) create mode 100644 kraken_frontend/src/api/generated/models/SimpleTestSSLResult.ts create mode 100644 kraken_frontend/src/api/generated/models/SourceAttackResultOneOf7.ts create mode 100644 kraken_frontend/src/api/generated/models/StartTLSProtocol.ts create mode 100644 kraken_frontend/src/api/generated/models/TestSSLRequest.ts diff --git a/kraken_frontend/openapi.json b/kraken_frontend/openapi.json index fb6d6e608..1f5df13db 100644 --- a/kraken_frontend/openapi.json +++ b/kraken_frontend/openapi.json @@ -1 +1 @@ -{"openapi":"3.0.3","info":{"title":"kraken","description":"The core component of kraken-project","contact":{"name":"Niklas Pfister","email":"git@omikron.dev"},"license":{"name":"AGPL-3.0"},"version":"0.1.0"},"paths":{"/api/v1/admin/applications":{"get":{"tags":["OAuth Application"],"operationId":"get_all_oauth_apps","responses":{"200":{"description":"Returns all oauth applications","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOauthApplications"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["OAuth Application"],"summary":"Create a new application","description":"Create a new application","operationId":"create_oauth_app","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAppRequest"}}},"required":true},"responses":{"200":{"description":"Application was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/applications/{uuid}":{"get":{"tags":["OAuth Application"],"operationId":"get_oauth_app","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns an oauth applications","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullOauthClient"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["OAuth Application"],"summary":"Update an application","description":"Update an application","operationId":"update_oauth_app","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAppRequest"}}},"required":true},"responses":{"200":{"description":"Application got updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["OAuth Application"],"summary":"Delete an application","description":"Delete an application","operationId":"delete_oauth_app","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Application was deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/globalTags":{"post":{"tags":["Global Tags"],"summary":"Create a global tag.","description":"Create a global tag.\n\nThis action requires admin privileges.","operationId":"create_global_tag","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGlobalTagRequest"}}},"required":true},"responses":{"200":{"description":"Global tag was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/globalTags/{uuid}":{"put":{"tags":["Global Tags"],"summary":"Update a global tag","description":"Update a global tag\n\nOne of the options must be set\n\nRequires admin privileges.","operationId":"update_global_tag","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGlobalTag"}}},"required":true},"responses":{"200":{"description":"Global tag was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Global Tags"],"summary":"Delete a global tag","description":"Delete a global tag\n\nRequires admin privileges.","operationId":"delete_global_tag","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Global tag was deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/leeches":{"get":{"tags":["Leech management"],"summary":"Retrieve all leeches","description":"Retrieve all leeches","operationId":"get_all_leeches","responses":{"200":{"description":"Matched leeches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListLeeches"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Leech management"],"summary":"Create a leech","description":"Create a leech\n\nThe `name` parameter must be unique.\n\n`address` must be a valid address including a scheme and port.\nCurrently only https and http are supported as scheme.","operationId":"create_leech","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLeechRequest"}}},"required":true},"responses":{"200":{"description":"Leech got created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/leeches/{uuid}":{"get":{"tags":["Leech management"],"summary":"Retrieve a leech by its id","description":"Retrieve a leech by its id","operationId":"get_leech","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Matched leeches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimpleLeech"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Leech management"],"summary":"Update a leech by its id","description":"Update a leech by its id\n\nAll parameter are optional, but at least one of them must be specified.\n\n`address` must be a valid address including a scheme and port.\nCurrently only https and http are supported as scheme.","operationId":"update_leech","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLeechRequest"}}},"required":true},"responses":{"200":{"description":"Leech got updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Leech management"],"summary":"Delete a leech by its uuid","description":"Delete a leech by its uuid","operationId":"delete_leech","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Leech got deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/leeches/{uuid}/cert":{"get":{"tags":["Leech management"],"summary":"Generate a new config for the leech","description":"Generate a new config for the leech","operationId":"gen_leech_config","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Newly generated leech cert","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeechConfig"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/settings":{"get":{"tags":["Settings Management"],"summary":"Retrieve the currently active settings","description":"Retrieve the currently active settings","operationId":"get_settings","responses":{"200":{"description":"Returns the currently active settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsFull"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Settings Management"],"summary":"Update the settings","description":"Update the settings","operationId":"update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Settings have been updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/users":{"get":{"tags":["User Admin Management"],"summary":"Retrieve all users","description":"Retrieve all users","operationId":"get_all_users_admin","responses":{"200":{"description":"Returns all users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListFullUsers"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["User Admin Management"],"summary":"Create a user","description":"Create a user","operationId":"create_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"200":{"description":"User got created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/users/{uuid}":{"get":{"tags":["User Admin Management"],"summary":"Retrieve a user by its uuid","description":"Retrieve a user by its uuid","operationId":"get_user","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns the user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullUser"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["User Admin Management"],"summary":"Delete a user by its uuid","description":"Delete a user by its uuid","operationId":"delete_user","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User got deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/wordlists":{"get":{"tags":["Wordlist management"],"summary":"Get a list of all wordlists including their paths","description":"Get a list of all wordlists including their paths","operationId":"get_all_wordlists_admin","responses":{"200":{"description":"List of all wordlists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWordlistsAdmin"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Wordlist management"],"summary":"Create a new wordlist","description":"Create a new wordlist","operationId":"create_wordlist_admin","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWordlistRequest"}}},"required":true},"responses":{"200":{"description":"Wordlist got created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/wordlists/{uuid}":{"put":{"tags":["Wordlist management"],"summary":"Update an existing wordlist","description":"Update an existing wordlist","operationId":"update_wordlist_admin","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWordlistRequest"}}},"required":true},"responses":{"200":{"description":"Wordlist got updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Wordlist management"],"summary":"Delete an existing wordlist","description":"Delete an existing wordlist","operationId":"delete_wordlist_admin","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Wordlist got deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/workspaces":{"get":{"tags":["Admin Workspaces"],"summary":"Retrieve all workspaces","description":"Retrieve all workspaces","operationId":"get_all_workspaces_admin","responses":{"200":{"description":"Returns all workspaces","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWorkspaces"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/workspaces/{uuid}":{"get":{"tags":["Admin Workspaces"],"summary":"Retrieve a workspace by id","description":"Retrieve a workspace by id","operationId":"get_workspace_admin","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns the workspace with the given id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullWorkspace"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/apiKeys":{"get":{"tags":["Api Keys"],"summary":"Retrieve all api keys","description":"Retrieve all api keys","operationId":"get_api_keys","responses":{"200":{"description":"The uses api keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListApiKeys"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Api Keys"],"summary":"Create new api key","description":"Create new api key","operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"Api key was created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/apiKeys/{uuid}":{"put":{"tags":["Api Keys"],"summary":"Update an api key by its id","description":"Update an api key by its id\n\nAll parameter are optional, but at least one of them must be specified.","operationId":"update_api_key","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"Api key got updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Api Keys"],"summary":"Delete an existing api key","description":"Delete an existing api key","operationId":"delete_api_key","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Api key got deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks":{"get":{"tags":["Attacks"],"summary":"Retrieve all attacks the user has access to","description":"Retrieve all attacks the user has access to","operationId":"get_all_attacks","responses":{"200":{"description":"Retrieve a list of all attacks the user has access to","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAttacks"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/bruteforceSubdomains":{"post":{"tags":["Attacks"],"summary":"Bruteforce subdomains through a DNS wordlist attack","description":"Bruteforce subdomains through a DNS wordlist attack\n\nEnumerate possible subdomains by querying a DNS server with constructed domains.\nSee [OWASP](https://owasp.org/www-community/attacks/Brute_force_attack) for further information.","operationId":"bruteforce_subdomains","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BruteforceSubdomainsRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/dnsResolution":{"post":{"tags":["Attacks"],"summary":"Perform domain name resolution","description":"Perform domain name resolution","operationId":"dns_resolution","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsResolutionRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/hostsAlive":{"post":{"tags":["Attacks"],"summary":"Check if hosts are reachable","description":"Check if hosts are reachable\n\nJust an ICMP scan for now to see which targets respond.\n\nAll intervals are interpreted in milliseconds. E.g. a `timeout` of 3000 means 3 seconds.","operationId":"hosts_alive_check","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostsAliveRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/queryCertificateTransparency":{"post":{"tags":["Attacks"],"summary":"Query a certificate transparency log collector.","description":"Query a certificate transparency log collector.\n\nFor further information, see [the explanation](https://certificate.transparency.dev/).\n\nCertificate transparency can be used to find subdomains or related domains.\n\n`retry_interval` is specified in milliseconds.","operationId":"query_certificate_transparency","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryCertificateTransparencyRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/queryDehashed":{"post":{"tags":["Attacks"],"summary":"Query the [dehashed](https://dehashed.com/) API.","description":"Query the [dehashed](https://dehashed.com/) API.\nIt provides email, password, credit cards and other types of information from leak-databases.\n\nNote that you are only able to query the API if you have bought access and have a running\nsubscription saved in kraken.","operationId":"query_dehashed","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDehashedRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/scanTcpPorts":{"post":{"tags":["Attacks"],"summary":"Start a tcp port scan","description":"Start a tcp port scan\n\n`exclude` accepts a list of ip networks in CIDR notation.\n\nAll intervals are interpreted in milliseconds. E.g. a `timeout` of 3000 means 3 seconds.\n\nSet `max_retries` to 0 if you don't want to try a port more than 1 time.","operationId":"scan_tcp_ports","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanTcpPortsRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/serviceDetection":{"post":{"tags":["Attacks"],"summary":"Perform service detection on a ip and port combination","description":"Perform service detection on a ip and port combination","operationId":"service_detection","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceDetectionRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}":{"get":{"tags":["Attacks"],"summary":"Retrieve an attack by id","description":"Retrieve an attack by id","operationId":"get_attack","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns the attack","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimpleAttack"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Attacks"],"summary":"Delete an attack and its results","description":"Delete an attack and its results","operationId":"delete_attack","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Attack was deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/bruteforceSubdomainsResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a bruteforce subdomains' results by the attack's id","description":"Retrieve a bruteforce subdomains' results by the attack's id","operationId":"get_bruteforce_subdomains_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BruteforceSubdomainsResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/dnsResolutionResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a dns resolution's results by the attack's id","description":"Retrieve a dns resolution's results by the attack's id","operationId":"get_dns_resolution_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsResolutionResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/hostAliveResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a host alive's results by the attack's id","description":"Retrieve a host alive's results by the attack's id","operationId":"get_host_alive_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostAliveResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/queryCertificateTransparencyResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a query certificate transparency's results by the attack's id","description":"Retrieve a query certificate transparency's results by the attack's id","operationId":"get_query_certificate_transparency_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryCertificateTransparencyResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/queryUnhashedResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a query dehashed's results by the attack's id","description":"Retrieve a query dehashed's results by the attack's id","operationId":"get_query_unhashed_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryUnhashedResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/serviceDetectionResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a detect service's results by the attack's id","description":"Retrieve a detect service's results by the attack's id","operationId":"get_service_detection_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceDetectionResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/tcpPortScanResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a tcp port scan's results by the attack's id","description":"Retrieve a tcp port scan's results by the attack's id","operationId":"get_tcp_port_scan_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TcpPortScanResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/auth/finishAuth":{"post":{"tags":["Authentication"],"summary":"Finishes the authentication with a security key","description":"Finishes the authentication with a security key\n\nUse `startAuth` to retrieve the challenge response data.","operationId":"finish_auth","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"description":"2FA Authentication finished"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/finishRegister":{"post":{"tags":["Authentication"],"summary":"Finish the registration of a security key","description":"Finish the registration of a security key\n\nUse `startRegister` to retrieve the challenge response data.","operationId":"finish_register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FinishRegisterRequest"}}},"required":true},"responses":{"200":{"description":"2FA Key registration finished"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/login":{"post":{"tags":["Authentication"],"summary":"Login to kraken","description":"Login to kraken","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/logout":{"get":{"tags":["Authentication"],"summary":"Log out of this session","description":"Log out of this session\n\nLogs a logged-in user out of his session.","operationId":"logout","responses":{"200":{"description":"Logout successful"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/startAuth":{"post":{"tags":["Authentication"],"summary":"Starts the authentication with a security key","description":"Starts the authentication with a security key\n\nUse the `login` endpoint before calling this one.\n\nProceed with `finishAuth`.","operationId":"start_auth","responses":{"200":{"description":"2FA Authentication started","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/startRegister":{"post":{"tags":["Authentication"],"summary":"Start the registration of a security key","description":"Start the registration of a security key\n\nProceed to the `finishRegister` endpoint.","operationId":"start_register","responses":{"200":{"description":"2FA Key registration started","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/test":{"get":{"tags":["Authentication"],"summary":"Test the current login state","description":"Test the current login state\n\nYou can use this endpoint to test the current login state of your client.\n\nIf logged in, a 200 without a body is returned.","operationId":"test","responses":{"200":{"description":"Logged in"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/globalTags":{"get":{"tags":["Global Tags"],"summary":"Retrieve all global tags","description":"Retrieve all global tags","operationId":"get_all_global_tags","responses":{"200":{"description":"Retrieve all global tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListGlobalTags"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/invitations":{"get":{"tags":["Workspace Invitations"],"summary":"Retrieve all open invitations to workspaces the currently logged-in user","description":"Retrieve all open invitations to workspaces the currently logged-in user\nhas retrieved","operationId":"get_all_invitations","responses":{"200":{"description":"Returns all invitations of a user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceInvitationList"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/invitations/{uuid}/accept":{"post":{"tags":["Workspace Invitations"],"summary":"Accept an invitation to a workspace","description":"Accept an invitation to a workspace","operationId":"accept_invitation","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Accept an invitation"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/invitations/{uuid}/decline":{"post":{"tags":["Workspace Invitations"],"summary":"Decline an invitation to a workspace","description":"Decline an invitation to a workspace","operationId":"decline_invitation","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Decline an invitation"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/oauth/accept/{uuid}":{"get":{"tags":["OAuth"],"summary":"Endpoint visited by user to grant a requesting application access","description":"Endpoint visited by user to grant a requesting application access","operationId":"accept","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"remember","in":"query","description":"Should kraken remember this decision?","required":false,"schema":{"type":"boolean"}}],"responses":{"302":{"description":"The user is redirected back to the requesting client"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/oauth/deny/{uuid}":{"get":{"tags":["OAuth"],"summary":"Endpoint visited by user to deny a requesting application access","description":"Endpoint visited by user to deny a requesting application access","operationId":"deny","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"remember","in":"query","description":"Should kraken remember this decision?","required":false,"schema":{"type":"boolean"}}],"responses":{"302":{"description":"The user is redirected back to the requesting client"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/oauth/info/{uuid}":{"get":{"tags":["OAuth"],"summary":"Queried by the frontend to display information about the oauth request to the user","description":"Queried by the frontend to display information about the oauth request to the user","operationId":"info","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Return information about an ongoing oauth request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenRequestInfo"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/oauthDecisions":{"get":{"tags":["OAuth Decisions"],"summary":"Retrieve a user's remembered oauth decisions","description":"Retrieve a user's remembered oauth decisions","operationId":"get_decisions","responses":{"200":{"description":"The user's remember oauth decisions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOauthDecisions"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/oauthDecisions/{uuid}":{"delete":{"tags":["OAuth Decisions"],"summary":"Revoke a user's remembered oauth decision","description":"Revoke a user's remembered oauth decision","operationId":"revoke_decision","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Revoked decision"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/users":{"get":{"tags":["User Management"],"summary":"Request all users","description":"Request all users\n\nThis may be used to create invitations for workspaces","operationId":"get_all_users","responses":{"200":{"description":"Simple representation of all users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListUsers"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/users/me":{"get":{"tags":["User Management"],"summary":"Retrieve the own user","description":"Retrieve the own user","operationId":"get_me","responses":{"200":{"description":"Returns the own user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullUser"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["User Management"],"summary":"Updates the own user","description":"Updates the own user\n\nAll parameters are optional, but at least one of them must be supplied.","operationId":"update_me","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMeRequest"}}},"required":true},"responses":{"200":{"description":"Changes were applied"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/users/setPassword":{"post":{"tags":["User Management"],"summary":"Set a new password","description":"Set a new password","operationId":"set_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/wordlists":{"get":{"tags":["Wordlist"],"summary":"Get a list of all wordlist for the user to select from when starting an bruteforce subdomains attack","description":"Get a list of all wordlist for the user to select from when starting an bruteforce subdomains attack","operationId":"get_all_wordlists","responses":{"200":{"description":"Matched leeches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWordlists"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces":{"get":{"tags":["Workspaces"],"summary":"Retrieve all workspaces that the executing user has access to","description":"Retrieve all workspaces that the executing user has access to\n\nFor administration access, look at the `/admin/workspaces` endpoint.","operationId":"get_all_workspaces","responses":{"200":{"description":"Returns all workspaces that the executing user has access to","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWorkspaces"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Workspaces"],"summary":"Create a new workspace","description":"Create a new workspace","operationId":"create_workspace","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkspaceRequest"}}},"required":true},"responses":{"200":{"description":"Workspace was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}":{"get":{"tags":["Workspaces"],"summary":"Retrieve a workspace by id","description":"Retrieve a workspace by id","operationId":"get_workspace","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns the workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullWorkspace"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Workspaces"],"summary":"Updates a workspace by its id","description":"Updates a workspace by its id\n\nAll parameter are optional, but at least one of them must be specified.\n\n`name` must not be empty.\n\nYou can set `description` to null to remove the description from the database.\nIf you leave the parameter out, the description will remain unchanged.","operationId":"update_workspace","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkspaceRequest"}}},"required":true},"responses":{"200":{"description":"Workspace got updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Workspaces"],"summary":"Delete a workspace by its id","description":"Delete a workspace by its id","operationId":"delete_workspace","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Workspace was deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/attacks":{"get":{"tags":["Attacks"],"summary":"Query all attacks of a workspace","description":"Query all attacks of a workspace","operationId":"get_workspace_attacks","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieve a list of all attacks of a workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAttacks"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/domains":{"post":{"tags":["Domains"],"summary":"Manually add a domain","description":"Manually add a domain","operationId":"create_domain","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"200":{"description":"Domain was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/domains/all":{"post":{"tags":["Domains"],"summary":"Retrieve all domains of a specific workspace","description":"Retrieve all domains of a specific workspace","operationId":"get_all_domains","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAllDomainsQuery"}}},"required":true},"responses":{"200":{"description":"Retrieve all domains of a workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/hosts":{"post":{"tags":["Hosts"],"summary":"Manually add a host","description":"Manually add a host","operationId":"create_host","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHostRequest"}}},"required":true},"responses":{"200":{"description":"Host was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/hosts/all":{"post":{"tags":["Hosts"],"summary":"Retrieve all hosts.","description":"Retrieve all hosts.\n\nHosts are created out of aggregating data or by user input.\nThey represent a single host and can be created by providing an IP address","operationId":"get_all_hosts","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAllHostsQuery"}}},"required":true},"responses":{"200":{"description":"All hosts in the workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/invitations":{"get":{"tags":["Workspaces"],"summary":"Query all open invitations to a workspace","description":"Query all open invitations to a workspace","operationId":"get_all_workspace_invitations","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns all open invitations to the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceInvitationList"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Workspaces"],"summary":"Invite a user to the workspace","description":"Invite a user to the workspace\n\nThis action can only be invoked by the owner of a workspace","operationId":"create_invitation","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteToWorkspaceRequest"}}},"required":true},"responses":{"200":{"description":"The user was invited."},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/ports":{"post":{"tags":["Ports"],"summary":"Manually add a port","description":"Manually add a port","operationId":"create_port","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePortRequest"}}},"required":true},"responses":{"200":{"description":"Port was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/ports/all":{"post":{"tags":["Ports"],"summary":"List the ports of a workspace","description":"List the ports of a workspace","operationId":"get_all_ports","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAllPortsQuery"}}},"required":true},"responses":{"200":{"description":"Retrieve all ports of a workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/search":{"get":{"tags":["Workspaces"],"summary":"Query all searches","description":"Query all searches","operationId":"get_searches","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchesResultPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Workspaces"],"summary":"Search through a workspaces' data","description":"Search through a workspaces' data","operationId":"search","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchWorkspaceRequest"}}},"required":true},"responses":{"200":{"description":"Search has been scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/services":{"post":{"tags":["Services"],"summary":"Manually add a service","description":"Manually add a service","operationId":"create_service","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/services/all":{"post":{"tags":["Services"],"summary":"List the services of a workspace","description":"List the services of a workspace","operationId":"get_all_services","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAllServicesQuery"}}},"required":true},"responses":{"200":{"description":"Retrieve all services of a workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/tags":{"get":{"tags":["Workspace Tags"],"summary":"Retrieve all workspace tags","description":"Retrieve all workspace tags","operationId":"get_all_workspace_tags","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieve all workspace tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWorkspaceTags"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Workspace Tags"],"summary":"Create a workspace tag.","description":"Create a workspace tag.","operationId":"create_workspace_tag","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkspaceTagRequest"}}},"required":true},"responses":{"200":{"description":"Workspace tag was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/transfer":{"post":{"tags":["Workspaces"],"summary":"Transfer ownership to another account","description":"Transfer ownership to another account\n\nYou will loose access to the workspace.","operationId":"transfer_ownership","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferWorkspaceRequest"}}},"required":true},"responses":{"200":{"description":"Workspace was transferred"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/domains/{d_uuid}":{"get":{"tags":["Domains"],"summary":"Retrieve all information about a single domain","description":"Retrieve all information about a single domain","operationId":"get_domain","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"d_uuid","in":"path","description":"The domain's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieved the selected domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullDomain"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Domains"],"summary":"Update a domain","description":"Update a domain\n\nYou must include at least on parameter","operationId":"update_domain","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"d_uuid","in":"path","description":"The domain's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDomainRequest"}}},"required":true},"responses":{"200":{"description":"Domain was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/domains/{d_uuid}/sources":{"get":{"tags":["Domains"],"summary":"Get all data sources which referenced this domain","description":"Get all data sources which referenced this domain","operationId":"get_domain_sources","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"d_uuid","in":"path","description":"The domain's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The domain's sources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullAggregationSource"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/hosts/{h_uuid}":{"get":{"tags":["Hosts"],"summary":"Retrieve all information about a single host","description":"Retrieve all information about a single host","operationId":"get_host","parameters":[{"name":"w_uuid","in":"path","description":"Workspace uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"h_uuid","in":"path","description":"Host uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieved the selected host","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullHost"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Hosts"],"summary":"Update a host","description":"Update a host\n\nYou must include at least on parameter","operationId":"update_host","parameters":[{"name":"w_uuid","in":"path","description":"Workspace uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"h_uuid","in":"path","description":"Host uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateHostRequest"}}},"required":true},"responses":{"200":{"description":"Host was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/hosts/{h_uuid}/sources":{"get":{"tags":["Hosts"],"summary":"Get all data sources which referenced this host","description":"Get all data sources which referenced this host","operationId":"get_host_sources","parameters":[{"name":"w_uuid","in":"path","description":"Workspace uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"h_uuid","in":"path","description":"Host uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The host's sources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullAggregationSource"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/invitations/{i_uuid}":{"delete":{"tags":["Workspaces"],"summary":"Retract an invitation to the workspace","description":"Retract an invitation to the workspace\n\nThis action can only be invoked by the owner of a workspace","operationId":"retract_invitation","parameters":[{"name":"w_uuid","in":"path","description":"The UUID of the workspace","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"i_uuid","in":"path","description":"The UUID of the invitation","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The invitation was retracted."},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/ports/{p_uuid}":{"get":{"tags":["Ports"],"summary":"Retrieve all information about a single port","description":"Retrieve all information about a single port","operationId":"get_port","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"p_uuid","in":"path","description":"The port's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieved the selected port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullPort"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Ports"],"summary":"Update a port","description":"Update a port\n\nYou must include at least on parameter","operationId":"update_port","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"p_uuid","in":"path","description":"The port's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePortRequest"}}},"required":true},"responses":{"200":{"description":"Port was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/ports/{p_uuid}/sources":{"get":{"tags":["Ports"],"summary":"Get all data sources which referenced this port","description":"Get all data sources which referenced this port","operationId":"get_port_sources","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"p_uuid","in":"path","description":"The port's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The port's sources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullAggregationSource"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/search/{s_uuid}":{"get":{"tags":["Workspaces"],"summary":"Retrieve results for a search by it's uuid","description":"Retrieve results for a search by it's uuid","operationId":"get_search_results","parameters":[{"name":"w_uuid","in":"path","description":"The UUID of the workspace","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"s_uuid","in":"path","description":"The UUID of the search","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResultPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/services/{s_uuid}":{"get":{"tags":["Services"],"summary":"Retrieve all information about a single service","description":"Retrieve all information about a single service","operationId":"get_service","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"s_uuid","in":"path","description":"The service's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieved the selected service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullService"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Services"],"summary":"Update a service","description":"Update a service\n\nYou must include at least on parameter","operationId":"update_service","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"s_uuid","in":"path","description":"The service's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/services/{s_uuid}/sources":{"get":{"tags":["Services"],"summary":"Get all data sources which referenced this service","description":"Get all data sources which referenced this service","operationId":"get_service_sources","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"s_uuid","in":"path","description":"The service's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The service's sources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullAggregationSource"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/tags/{t_uuid}":{"put":{"tags":["Workspace Tags"],"summary":"Update a workspace tag","description":"Update a workspace tag\n\nOne of the options must be set\n\nRequires privileges to access the workspace this tags belongs to.","operationId":"update_workspace_tag","parameters":[{"name":"w_uuid","in":"path","description":"Workspace uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"t_uuid","in":"path","description":"Tag uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkspaceTag"}}},"required":true},"responses":{"200":{"description":"Workspace tag was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Workspace Tags"],"summary":"Delete a workspace tag","description":"Delete a workspace tag\n\nRequires privileges to access the workspace this tag belongs to.","operationId":"delete_workspace_tag","parameters":[{"name":"w_uuid","in":"path","description":"Workspace uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"t_uuid","in":"path","description":"Tag uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Workspace tag was deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/ws":{"get":{"tags":["Websocket"],"summary":"Start a websocket connection","description":"Start a websocket connection\n\nA heartbeat PING packet is sent constantly (every 10s).\nIf no response is retrieved within 30s of the last transmission, the socket\nwill be closed.","operationId":"websocket","responses":{"101":{"description":"Websocket connection established"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}}},"components":{"schemas":{"AggregationType":{"type":"string","description":"The different types of aggregations","enum":["Domain","Host","Service","Port"]},"ApiErrorResponse":{"type":"object","description":"Representation of an error response\n\n`status_code` holds the error code, `message` a human readable description of the error","required":["status_code","message"],"properties":{"status_code":{"$ref":"#/components/schemas/ApiStatusCode"},"message":{"type":"string","example":"Error message will be here"}}},"ApiStatusCode":{"type":"integer","description":"This type holds all possible error types that can be returned by the API.\n\nNumbers between 1000 and 1999 (inclusive) are client errors that can be handled by the client.\nNumbers between 2000 and 2999 (inclusive) are server errors.","default":1000,"enum":[1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,2000,2001,2002,2003,2004,2005],"example":1000},"AttackType":{"type":"string","description":"The type of an attack","enum":["Undefined","BruteforceSubdomains","TcpPortScan","QueryCertificateTransparency","QueryUnhashed","HostAlive","ServiceDetection","DnsResolution","UdpPortScan","ForcedBrowsing","OSDetection","VersionDetection","AntiPortScanningDetection"]},"BruteforceSubdomainsRequest":{"type":"object","description":"The settings of a subdomain bruteforce request","required":["domain","wordlist_uuid","concurrent_limit","workspace_uuid"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"domain":{"type":"string","description":"Domain to construct subdomains for","example":"example.com"},"wordlist_uuid":{"type":"string","format":"uuid","description":"The wordlist to use"},"concurrent_limit":{"type":"integer","format":"int32","description":"The concurrent task limit","example":100,"minimum":0},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"BruteforceSubdomainsResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SimpleBruteforceSubdomainsResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"CertificateTransparencyEntry":{"type":"object","description":"Entry of certificate transparency results","required":["serial_number","issuer_name","common_name","value_names"],"properties":{"serial_number":{"type":"string","description":"The serial number of the certificate"},"issuer_name":{"type":"string","description":"The name of the issuer for the certificate"},"common_name":{"type":"string","description":"The common name of the certificate"},"value_names":{"type":"array","items":{"type":"string"},"description":"The value names of the certificate"},"not_before":{"type":"string","format":"date-time","description":"The point in time after the certificate is valid","nullable":true},"not_after":{"type":"string","format":"date-time","description":"The point in time before the certificate is valid","nullable":true}}},"Color":{"type":"object","description":"Color value","required":["r","g","b","a"],"properties":{"r":{"type":"integer","format":"int32","description":"Red value","minimum":0},"g":{"type":"integer","format":"int32","description":"Green value","minimum":0},"b":{"type":"integer","format":"int32","description":"Blue value","minimum":0},"a":{"type":"integer","format":"int32","description":"Alpha value","minimum":0}}},"CreateApiKeyRequest":{"type":"object","description":"Request to create a new api key","required":["name"],"properties":{"name":{"type":"string","description":"A descriptive name helping the user to identify the key","example":"Leech on my local machine"}}},"CreateAppRequest":{"type":"object","description":"Create a new oauth application","required":["name","redirect_uri"],"properties":{"name":{"type":"string","description":"The name of the application","example":"Trustworthy application"},"redirect_uri":{"type":"string","description":"The redirect url of the application","example":"http://127.0.0.1:8080"}}},"CreateDomainRequest":{"type":"object","description":"The request to manually add a domain","required":["domain"],"properties":{"domain":{"type":"string","description":"The domain to add","example":"kraken.test"}}},"CreateGlobalTagRequest":{"type":"object","description":"The request to create a global tag","required":["name","color"],"properties":{"name":{"type":"string","description":"Name of the tag"},"color":{"$ref":"#/components/schemas/Color"}}},"CreateHostRequest":{"type":"object","description":"The request to manually add a host","required":["ip_addr","certainty"],"properties":{"ip_addr":{"type":"string","description":"The host's ip address","example":"127.0.0.1"},"certainty":{"$ref":"#/components/schemas/ManualHostCertainty"}}},"CreateLeechRequest":{"type":"object","description":"The request to create a new leech","required":["name","address"],"properties":{"name":{"type":"string","description":"Name of the leech","example":"leech-01"},"address":{"type":"string","description":"Address of the leech with schema","example":"https://10.13.37:8081"},"description":{"type":"string","description":"Description of the leech","example":"The first leech in a private net","nullable":true}}},"CreatePortRequest":{"type":"object","description":"The request to manually add a port","required":["ip_addr","port","certainty","protocol"],"properties":{"ip_addr":{"type":"string","description":"The ip address the port is open on","example":"127.0.0.1"},"port":{"type":"integer","format":"int32","description":"The port to add","example":"8080","minimum":0},"certainty":{"$ref":"#/components/schemas/ManualPortCertainty"},"protocol":{"$ref":"#/components/schemas/PortProtocol"}}},"CreateServiceRequest":{"type":"object","description":"The request to manually add a service","required":["name","certainty","host"],"properties":{"name":{"type":"string","description":"The service's name","example":"django"},"certainty":{"$ref":"#/components/schemas/ManualServiceCertainty"},"host":{"type":"string","description":"The ip address the service runs on","example":"127.0.0.1"},"port":{"type":"integer","format":"int32","description":"An optional port the service runs on","example":"8080","nullable":true,"minimum":0}}},"CreateUserRequest":{"type":"object","description":"The request to create a user","required":["username","display_name","password","permission"],"properties":{"username":{"type":"string","description":"The username","example":"user123"},"display_name":{"type":"string","description":"The displayname","example":"Anon"},"password":{"type":"string","description":"The password that should be set","example":"super-secure-password"},"permission":{"$ref":"#/components/schemas/UserPermission"}}},"CreateWordlistRequest":{"type":"object","description":"Arguments for creating a new wordlist","required":["name","description","path"],"properties":{"name":{"type":"string","description":"The wordlist's name to be displayed select buttons","example":"subdomains-top1million-5000.txt"},"description":{"type":"string","description":"A description explaining the wordlist's intended use case","example":"List of 5000 subdomains"},"path":{"type":"string","description":"The file path the wordlist is deployed under on each leech","example":"/opt/wordlists/Discovery/DNS/subdomains-top1million-5000.txt"}}},"CreateWorkspaceRequest":{"type":"object","description":"The request to create a new workspace","required":["name"],"properties":{"name":{"type":"string","description":"The name of the workspace","example":"secure-workspace"},"description":{"type":"string","description":"The description of the workspace","example":"This workspace is super secure and should not be looked at!!","nullable":true}}},"CreateWorkspaceTagRequest":{"type":"object","description":"The request to create a workspace tag","required":["name","color"],"properties":{"name":{"type":"string","description":"Name of the tag"},"color":{"$ref":"#/components/schemas/Color"}}},"DnsResolutionRequest":{"type":"object","description":"Request to resolve domains","required":["targets","concurrent_limit","workspace_uuid"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"targets":{"type":"array","items":{"type":"string"},"description":"The domains to resolve","example":["example.com","example.org"]},"concurrent_limit":{"type":"integer","format":"int32","description":"The concurrent task limit","example":2,"minimum":0},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"DnsResolutionResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SimpleDnsResolutionResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"DomainCertainty":{"type":"string","description":"The certainty of a domain","enum":["Unverified","Verified"]},"DomainOrNetwork":{"oneOf":[{"type":"string","description":"A ip address / network","example":"10.13.37.10"},{"type":"string","description":"A domain name","example":"kraken.test"}],"description":"Either an ip address / network or a domain name"},"DomainResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullDomain"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"FinishRegisterRequest":{"allOf":[{"type":"object","description":"The public key credentials register request"},{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Name of the key","example":"my-security-key-01"}}}],"description":"The request to finish the registration of a security key"},"FullAggregationSource":{"type":"object","description":"All data sources which contributed to an aggregated model","required":["attacks","manual_insert"],"properties":{"attacks":{"type":"array","items":{"$ref":"#/components/schemas/SourceAttack"},"description":"All attack which contributed to an aggregated model"},"manual_insert":{"type":"array","items":{"$ref":"#/components/schemas/ManualInsert"},"description":"All manual inserts which contributed to an aggregated model"}}},"FullApiKey":{"type":"object","description":"A representation of a full api key","required":["uuid","name","key"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The key's identifier"},"name":{"type":"string","description":"A descriptive name helping the user to identify the key","example":"Leech on my local machine"},"key":{"type":"string","description":"The actual key's value","example":"fsn83r0jfis84nfthw..."}}},"FullDomain":{"type":"object","description":"A full representation of a domain in a workspace","required":["uuid","domain","comment","workspace","tags","sources","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the domain"},"domain":{"type":"string","description":"The domain's name","example":"example.com"},"comment":{"type":"string","description":"A comment","example":"This is a important domain!"},"workspace":{"type":"string","format":"uuid","description":"The workspace this domain is in"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTag"},"description":"The list of tags this domain has attached to"},"sources":{"$ref":"#/components/schemas/SimpleAggregationSource"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"FullGlobalTag":{"type":"object","description":"The full representation of a full","required":["uuid","name","color"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the tag"},"name":{"type":"string","description":"The name of the tag"},"color":{"$ref":"#/components/schemas/Color"}}},"FullHost":{"type":"object","description":"The full representation of a host","required":["uuid","ip_addr","os_type","comment","workspace","tags","sources","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the host"},"ip_addr":{"type":"string","description":"The ip address of the host","example":"172.0.0.1"},"os_type":{"$ref":"#/components/schemas/OsType"},"comment":{"type":"string","description":"A comment"},"workspace":{"type":"string","format":"uuid","description":"The workspace this host is in"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTag"},"description":"The list of tags this host has attached to"},"sources":{"$ref":"#/components/schemas/SimpleAggregationSource"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"FullOauthClient":{"type":"object","description":"A complete version of a workspace","required":["uuid","name","redirect_uri","secret"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the client"},"name":{"type":"string","description":"The name of the client","example":"Trustworthy application"},"redirect_uri":{"type":"string","description":"The redirect url of the client","example":"http://127.0.0.1:8080"},"secret":{"type":"string","description":"The secret of the client","example":"IPSPL29BSDw5HFir5LYamdlm6SiaBdwx"}}},"FullOauthDecision":{"type":"object","description":"A user's remembered oauth decision","required":["uuid","app","workspace","action"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"app":{"type":"string","description":"The application the decision was made for"},"workspace":{"$ref":"#/components/schemas/SimpleWorkspace"},"action":{"type":"string","description":"Action what to do with new oauth requests","enum":["Accept","Deny"]}}},"FullPort":{"type":"object","description":"The full representation of a port","required":["uuid","port","protocol","host","comment","tags","workspace","sources","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"Uuid of the port"},"port":{"type":"integer","format":"int32","description":"Port number","example":1337,"minimum":0},"protocol":{"$ref":"#/components/schemas/PortProtocol"},"host":{"$ref":"#/components/schemas/SimpleHost"},"comment":{"type":"string","description":"A comment to the port"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTag"},"description":"The tags this port is linked to"},"workspace":{"type":"string","format":"uuid","description":"The workspace this port is linked to"},"sources":{"$ref":"#/components/schemas/SimpleAggregationSource"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"FullQueryCertificateTransparencyResult":{"type":"object","description":"A simple representation of a query certificate transparency result","required":["uuid","attack","created_at","issuer_name","common_name","value_names","serial_number"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"issuer_name":{"type":"string","description":"The name of the issuer"},"common_name":{"type":"string","description":"The common name of the certificate"},"value_names":{"type":"array","items":{"type":"string"},"description":"The values of the certificate"},"not_before":{"type":"string","format":"date-time","description":"The start date of the certificate","nullable":true},"not_after":{"type":"string","format":"date-time","description":"The end date of the certificate","nullable":true},"serial_number":{"type":"string","description":"The serial number of the certificate"}}},"FullService":{"type":"object","description":"A full representation of a service","required":["uuid","name","certainty","host","comment","workspace","tags","sources","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"Uuid of the service"},"name":{"type":"string","description":"The service's name","example":"postgresql"},"version":{"type":"string","description":"An optional version of the running service","example":"13.0.1","nullable":true},"certainty":{"$ref":"#/components/schemas/ServiceCertainty"},"host":{"$ref":"#/components/schemas/SimpleHost"},"port":{"allOf":[{"$ref":"#/components/schemas/SimplePort"}],"nullable":true},"comment":{"type":"string","description":"A comment to the service","example":"Holds all relevant information"},"workspace":{"type":"string","format":"uuid","description":"The workspace this service is linked to"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTag"},"description":"The tags this service is linked to"},"sources":{"$ref":"#/components/schemas/SimpleAggregationSource"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"FullServiceDetectionResult":{"type":"object","description":"A simple representation of a service detection result","required":["uuid","attack","created_at","certainty","service_names","host","port"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"certainty":{"type":"string","description":"The certainty a service is detected","enum":["Historical","SupposedTo","MaybeVerified","DefinitelyVerified"]},"service_names":{"type":"array","items":{"type":"string"},"description":"The found names of the service"},"host":{"type":"string","description":"The ip address a port was found on","example":"127.0.0.1"},"port":{"type":"integer","format":"int32","description":"Port number","minimum":0}}},"FullUser":{"type":"object","description":"A single user representation","required":["uuid","username","display_name","permission","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the user"},"username":{"type":"string","description":"The username of the user","example":"user123"},"display_name":{"type":"string","description":"The displayname of the user","example":"Anon"},"permission":{"$ref":"#/components/schemas/UserPermission"},"created_at":{"type":"string","format":"date-time","description":"The point in time this user was created"},"last_login":{"type":"string","format":"date-time","description":"The last point in time when the user has logged in","nullable":true}}},"FullWordlist":{"type":"object","description":"A wordlist including its `path` field only meant for admins","required":["uuid","name","description","path"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the wordlist"},"name":{"type":"string","description":"The wordlist's name to be displayed select buttons","example":"subdomains-top1million-5000.txt"},"description":{"type":"string","description":"A description explaining the wordlist's intended use case","example":"List of 5000 subdomains"},"path":{"type":"string","description":"The file path the wordlist is deployed under on each leech","example":"/opt/wordlists/Discovery/DNS/subdomains-top1million-5000.txt"}}},"FullWorkspace":{"type":"object","description":"A full version of a workspace","required":["uuid","name","owner","attacks","members","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the workspace"},"name":{"type":"string","description":"The name of the workspace","example":"ultra-secure-workspace"},"description":{"type":"string","description":"The description of the workspace","example":"This workspace is ultra secure and should not be looked at!!","nullable":true},"owner":{"$ref":"#/components/schemas/SimpleUser"},"attacks":{"type":"array","items":{"$ref":"#/components/schemas/SimpleAttack"},"description":"The attacks linked to this workspace"},"members":{"type":"array","items":{"$ref":"#/components/schemas/SimpleUser"},"description":"The member of the workspace"},"created_at":{"type":"string","format":"date-time","description":"The point in time the workspace was created"}}},"FullWorkspaceInvitation":{"type":"object","description":"The full representation of an invitation to a workspace","required":["uuid","workspace","from","target"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the invitation"},"workspace":{"$ref":"#/components/schemas/SimpleWorkspace"},"from":{"$ref":"#/components/schemas/SimpleUser"},"target":{"$ref":"#/components/schemas/SimpleUser"}}},"FullWorkspaceTag":{"type":"object","description":"The full representation of a full workspace tag","required":["uuid","name","color","workspace"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the workspace tag"},"name":{"type":"string","description":"The name of the tag","example":"seems broken"},"color":{"$ref":"#/components/schemas/Color"},"workspace":{"type":"string","format":"uuid","description":"The workspace this tag is linked to"}}},"GetAllDomainsQuery":{"allOf":[{"$ref":"#/components/schemas/PageParams"},{"type":"object","properties":{"host":{"type":"string","format":"uuid","description":"Only get domains pointing to a specific host\n\nThis includes domains which point to another domain which points to this host.","nullable":true},"global_filter":{"type":"string","description":"An optional general filter to apply","nullable":true},"domain_filter":{"type":"string","description":"An optional domain specific filter to apply","nullable":true}}}],"description":"Query parameters for filtering the domains to get"},"GetAllHostsQuery":{"allOf":[{"$ref":"#/components/schemas/PageParams"},{"type":"object","properties":{"global_filter":{"type":"string","description":"An optional general filter to apply","nullable":true},"host_filter":{"type":"string","description":"An optional host specific filter to apply","nullable":true}}}],"description":"Query parameters for filtering the hosts to get"},"GetAllPortsQuery":{"allOf":[{"$ref":"#/components/schemas/PageParams"},{"type":"object","properties":{"host":{"type":"string","format":"uuid","description":"Only get ports associated with a specific host","nullable":true},"global_filter":{"type":"string","description":"An optional general filter to apply","nullable":true},"port_filter":{"type":"string","description":"An optional port specific filter to apply","nullable":true}}}],"description":"Query parameters for filtering the ports to get"},"GetAllServicesQuery":{"allOf":[{"$ref":"#/components/schemas/PageParams"},{"type":"object","properties":{"host":{"type":"string","format":"uuid","description":"Only get services associated with a specific host","nullable":true},"global_filter":{"type":"string","description":"An optional general filter to apply","nullable":true},"service_filter":{"type":"string","description":"An optional service specific filter to apply","nullable":true}}}],"description":"Query parameters for filtering the services to get"},"HostAliveResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SimpleHostAliveResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"HostCertainty":{"type":"string","description":"The certainty of a host","enum":["Historical","SupposedTo","Verified"]},"HostResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullHost"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"HostsAliveRequest":{"type":"object","description":"Host Alive check request","required":["targets","timeout","concurrent_limit","workspace_uuid"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"targets":{"type":"array","items":{"type":"string"},"description":"The ip addresses / networks or domains to scan","example":["10.13.37.1","10.13.37.0/24","google.com"]},"timeout":{"type":"integer","format":"int64","description":"The time to wait until a host is considered down.\n\nThe timeout is specified in milliseconds.","example":3000,"minimum":0},"concurrent_limit":{"type":"integer","format":"int32","description":"The concurrent task limit","example":30,"minimum":0},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"InviteToWorkspaceRequest":{"type":"object","description":"The request to invite a user to the workspace","required":["user"],"properties":{"user":{"type":"string","format":"uuid","description":"The user to invite"}}},"LeechConfig":{"allOf":[{"$ref":"#/components/schemas/LeechTlsConfig"},{"type":"object","required":["secret"],"properties":{"secret":{"type":"string","description":"The secret of the leech"}}}],"description":"The configuration of a leech"},"LeechTlsConfig":{"type":"object","description":"The tls related part of a leech's config","required":["ca","cert","key","sni"],"properties":{"ca":{"type":"string","description":"PEM encoded CA managed by kraken"},"cert":{"type":"string","description":"PEM encoded certificate"},"key":{"type":"string","description":"PEM encoded private key for the certificate"},"sni":{"type":"string","description":"The randomly generated fake domain for the kraken to be used for sni"}}},"ListApiKeys":{"type":"object","description":"The response that contains all api keys","required":["keys"],"properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/FullApiKey"},"description":"The list of api keys"}}},"ListAttacks":{"type":"object","description":"A list of attacks","required":["attacks"],"properties":{"attacks":{"type":"array","items":{"$ref":"#/components/schemas/SimpleAttack"},"description":"The list of the attacks"}}},"ListFullUsers":{"type":"object","description":"The response of all users","required":["users"],"properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/FullUser"},"description":"The list of full users"}}},"ListGlobalTags":{"type":"object","description":"The response to a request to retrieve all global tags","required":["global_tags"],"properties":{"global_tags":{"type":"array","items":{"$ref":"#/components/schemas/FullGlobalTag"},"description":"List of global tags"}}},"ListLeeches":{"type":"object","description":"The response that hold all leeches","required":["leeches"],"properties":{"leeches":{"type":"array","items":{"$ref":"#/components/schemas/SimpleLeech"},"description":"The list of leeches"}}},"ListOauthApplications":{"type":"object","description":"List all oauth applications","required":["apps"],"properties":{"apps":{"type":"array","items":{"$ref":"#/components/schemas/FullOauthClient"},"description":"The list of applications"}}},"ListOauthDecisions":{"type":"object","description":"Response holding a user's oauth decisions","required":["decisions"],"properties":{"decisions":{"type":"array","items":{"$ref":"#/components/schemas/FullOauthDecision"},"description":"A user's oauth decisions"}}},"ListUsers":{"type":"object","description":"The response with all users","required":["users"],"properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/SimpleUser"},"description":"List of users"}}},"ListWordlists":{"type":"object","description":"Response containing all wordlists","required":["wordlists"],"properties":{"wordlists":{"type":"array","items":{"$ref":"#/components/schemas/SimpleWordlist"},"description":"List of all wordlists"}}},"ListWordlistsAdmin":{"type":"object","description":"Response containing all wordlists including their `path` fields","required":["wordlists"],"properties":{"wordlists":{"type":"array","items":{"$ref":"#/components/schemas/FullWordlist"},"description":"List of all wordlists including their `path` fields"}}},"ListWorkspaceTags":{"type":"object","description":"The response to a request to retrieve all workspace tags","required":["workspace_tags"],"properties":{"workspace_tags":{"type":"array","items":{"$ref":"#/components/schemas/FullWorkspaceTag"},"description":"Workspace tags"}}},"ListWorkspaces":{"type":"object","description":"The response to retrieve a list of workspaces","required":["workspaces"],"properties":{"workspaces":{"type":"array","items":{"$ref":"#/components/schemas/SimpleWorkspace"},"description":"The list of workspaces"}}},"LoginRequest":{"type":"object","description":"The request to login","required":["username","password"],"properties":{"username":{"type":"string","description":"The username that should be used for login","example":"user123"},"password":{"type":"string","description":"The password that should be used for login","example":"super-secure-password"}}},"ManualHostCertainty":{"type":"string","description":"The certainty of a manually added host","enum":["Historical","SupposedTo"]},"ManualInsert":{"oneOf":[{"type":"object","description":"A manually inserted domain","required":["domain","user","workspace","created_at","type"],"properties":{"domain":{"type":"string","description":"The inserted domain"},"user":{"$ref":"#/components/schemas/SimpleUser"},"workspace":{"type":"string","format":"uuid","description":"The workspace the domain was inserted to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the domain was inserted"},"type":{"type":"string","enum":["Domain"]}}},{"type":"object","description":"A manually inserted host","required":["ip_addr","os_type","certainty","user","workspace","created_at","type"],"properties":{"ip_addr":{"type":"string","description":"The host's ip address","example":"172.0.0.1"},"os_type":{"$ref":"#/components/schemas/OsType"},"certainty":{"$ref":"#/components/schemas/ManualHostCertainty"},"user":{"$ref":"#/components/schemas/SimpleUser"},"workspace":{"type":"string","format":"uuid","description":"The workspace the host was inserted to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the host was inserted"},"type":{"type":"string","enum":["Host"]}}},{"type":"object","description":"A manually inserted port","required":["port","protocol","certainty","host","user","workspace","created_at","type"],"properties":{"port":{"type":"integer","format":"int32","description":"The inserted port","minimum":0},"protocol":{"$ref":"#/components/schemas/PortProtocol"},"certainty":{"$ref":"#/components/schemas/ManualPortCertainty"},"host":{"type":"string","description":"The host's ip address","example":"172.0.0.1"},"user":{"$ref":"#/components/schemas/SimpleUser"},"workspace":{"type":"string","format":"uuid","description":"The workspace the port was inserted to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the port was inserted"},"type":{"type":"string","enum":["Port"]}}},{"type":"object","description":"A manually inserted service","required":["name","certainty","host","user","workspace","created_at","type"],"properties":{"name":{"type":"string","description":"The inserted service"},"version":{"type":"string","description":"The service's version","nullable":true},"certainty":{"$ref":"#/components/schemas/ManualServiceCertainty"},"port":{"type":"integer","format":"int32","description":"The service's port","nullable":true,"minimum":0},"host":{"type":"string","description":"The host's ip address","example":"172.0.0.1"},"user":{"$ref":"#/components/schemas/SimpleUser"},"workspace":{"type":"string","format":"uuid","description":"The workspace the service was inserted to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the service was inserted"},"type":{"type":"string","enum":["Service"]}}}],"description":"The different types of manual inserts","discriminator":{"propertyName":"type"}},"ManualPortCertainty":{"type":"string","description":"The certainty of a manually added port","enum":["Historical","SupposedTo"]},"ManualServiceCertainty":{"type":"string","description":"The certainty of a manually added service","enum":["Historical","SupposedTo"]},"OpenRequestInfo":{"type":"object","description":"The information about an oauth request","required":["workspace","oauth_application"],"properties":{"workspace":{"$ref":"#/components/schemas/SimpleWorkspace"},"oauth_application":{"$ref":"#/components/schemas/SimpleOauthClient"}}},"OsType":{"type":"string","description":"A representation of an OS type","enum":["Unknown","Linux","Windows","Apple","Android","FreeBSD"]},"PageParams":{"type":"object","description":"Query parameters for paginated data","required":["limit","offset"],"properties":{"limit":{"type":"integer","format":"int64","description":"Number of items to retrieve","minimum":0},"offset":{"type":"integer","format":"int64","description":"Position in the whole list to start retrieving from","minimum":0}}},"PortCertainty":{"type":"string","description":"The certainty states of a port","enum":["Historical","SupposedTo","Verified"]},"PortOrRange":{"oneOf":[{"type":"integer","format":"int32","description":"A single port","example":8000,"minimum":0},{"type":"string","description":"In inclusive range of ports","example":"1-1024"}],"description":"Single port or a range of ports"},"PortProtocol":{"type":"string","description":"A protocol of a port","enum":["Unknown","Tcp","Udp","Sctp"]},"PortResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullPort"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"Query":{"oneOf":[{"type":"object","required":["Email"],"properties":{"Email":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["IpAddress"],"properties":{"IpAddress":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Username"],"properties":{"Username":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Password"],"properties":{"Password":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["HashedPassword"],"properties":{"HashedPassword":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Name"],"properties":{"Name":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Domain"],"properties":{"Domain":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Vin"],"properties":{"Vin":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Phone"],"properties":{"Phone":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Address"],"properties":{"Address":{"$ref":"#/components/schemas/SearchType"}}}],"description":"A query for dehashed"},"QueryCertificateTransparencyRequest":{"type":"object","description":"The settings to configure a certificate transparency request","required":["target","include_expired","max_retries","retry_interval","workspace_uuid"],"properties":{"target":{"type":"string","description":"Domain to query certificates for","example":"example.com"},"include_expired":{"type":"boolean","description":"Should expired certificates be included as well","example":true},"max_retries":{"type":"integer","format":"int32","description":"The number of times the query should be retried if it failed.","example":3,"minimum":0},"retry_interval":{"type":"integer","format":"int64","description":"The interval that should be waited between retries.\n\nThe interval is specified in milliseconds.","example":500,"minimum":0},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"QueryCertificateTransparencyResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullQueryCertificateTransparencyResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"QueryDehashedRequest":{"type":"object","description":"The request to query the dehashed API","required":["query","workspace_uuid"],"properties":{"query":{"$ref":"#/components/schemas/Query"},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"QueryUnhashedResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SimpleQueryUnhashedResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"ScanTcpPortsRequest":{"type":"object","description":"The settings to configure a tcp port scan","required":["targets","retry_interval","max_retries","timeout","concurrent_limit","skip_icmp_check","workspace_uuid"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"targets":{"type":"array","items":{"type":"string"},"description":"The ip addresses / networks or domains to scan","example":["10.13.37.1","10.13.37.0/24","google.com"]},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortOrRange"},"description":"List of single ports and port ranges\n\nIf no values are supplied, 1-65535 is used as default"},"retry_interval":{"type":"integer","format":"int64","description":"The interval that should be wait between retries on a port.\n\nThe interval is specified in milliseconds.","example":100,"minimum":0},"max_retries":{"type":"integer","format":"int32","description":"The number of times the connection should be retried if it failed.","example":2,"minimum":0},"timeout":{"type":"integer","format":"int64","description":"The time to wait until a connection is considered failed.\n\nThe timeout is specified in milliseconds.","example":3000,"minimum":0},"concurrent_limit":{"type":"integer","format":"int32","description":"The concurrent task limit","example":5000,"minimum":0},"skip_icmp_check":{"type":"boolean","description":"Skips the initial icmp check.\n\nAll hosts are assumed to be reachable","example":false},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"SearchEntry":{"type":"object","description":"Searched entry","required":["uuid","created_at","search_term"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the search"},"created_at":{"type":"string","format":"date-time","description":"The point in time this search was created"},"finished_at":{"type":"string","format":"date-time","description":"The point in time this search was finished","nullable":true},"search_term":{"type":"string","description":"The search term that was used"}}},"SearchResultEntry":{"oneOf":[{"type":"object","required":["HostEntry"],"properties":{"HostEntry":{"$ref":"#/components/schemas/SimpleHost"}}},{"type":"object","required":["ServiceEntry"],"properties":{"ServiceEntry":{"$ref":"#/components/schemas/SimpleService"}}},{"type":"object","required":["PortEntry"],"properties":{"PortEntry":{"$ref":"#/components/schemas/SimplePort"}}},{"type":"object","required":["DomainEntry"],"properties":{"DomainEntry":{"$ref":"#/components/schemas/SimpleDomain"}}},{"type":"object","required":["DnsRecordResultEntry"],"properties":{"DnsRecordResultEntry":{"$ref":"#/components/schemas/SimpleDnsResolutionResult"}}},{"type":"object","required":["TcpPortScanResultEntry"],"properties":{"TcpPortScanResultEntry":{"$ref":"#/components/schemas/SimpleTcpPortScanResult"}}},{"type":"object","required":["DehashedQueryResultEntry"],"properties":{"DehashedQueryResultEntry":{"$ref":"#/components/schemas/SimpleQueryUnhashedResult"}}},{"type":"object","required":["CertificateTransparencyResultEntry"],"properties":{"CertificateTransparencyResultEntry":{"$ref":"#/components/schemas/FullQueryCertificateTransparencyResult"}}},{"type":"object","required":["HostAliveResult"],"properties":{"HostAliveResult":{"$ref":"#/components/schemas/SimpleHostAliveResult"}}},{"type":"object","required":["ServiceDetectionResult"],"properties":{"ServiceDetectionResult":{"$ref":"#/components/schemas/FullServiceDetectionResult"}}}],"description":"Dynamic result of a search"},"SearchResultPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SearchResultEntry"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"SearchType":{"oneOf":[{"type":"object","required":["Simple"],"properties":{"Simple":{"type":"string","description":"Search for a simple pattern"}}},{"type":"object","required":["Exact"],"properties":{"Exact":{"type":"string","description":"Search for an exact pattern"}}},{"type":"object","required":["Regex"],"properties":{"Regex":{"type":"string","description":"A regex search pattern"}}},{"type":"object","required":["Or"],"properties":{"Or":{"type":"array","items":{"$ref":"#/components/schemas/SearchType"},"description":"Add multiple [SearchType]s with an OR"}}},{"type":"object","required":["And"],"properties":{"And":{"type":"array","items":{"$ref":"#/components/schemas/SearchType"},"description":"Add multiple [SearchType]s with an AND"}}}],"description":"A specific search type"},"SearchWorkspaceRequest":{"type":"object","description":"Request to search the workspace","required":["search_term"],"properties":{"search_term":{"type":"string","description":"the term to search for"}}},"SearchesResultPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SearchEntry"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"ServiceCertainty":{"type":"string","description":"The certainty a service is detected","enum":["Historical","SupposedTo","MaybeVerified","DefinitelyVerified"]},"ServiceDetectionRequest":{"type":"object","description":"The request to start a service detection","required":["address","port","timeout","workspace_uuid"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"address":{"type":"string","description":"The ip address the service listens on","example":"10.13.37.1"},"port":{"type":"integer","format":"int32","description":"The port the service listens on","example":443,"minimum":0},"timeout":{"type":"integer","format":"int64","description":"Time to wait for a response after sending the payload\n(or after establishing a connection, if not payload is to be sent)\n\nThe timeout is specified in milliseconds.","example":3000,"minimum":0},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"ServiceDetectionResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullServiceDetectionResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"ServiceResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullService"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"SetPasswordRequest":{"type":"object","description":"The request to set a new password for a user","required":["current_password","new_password"],"properties":{"current_password":{"type":"string","description":"The current password","example":"super-secure-password"},"new_password":{"type":"string","description":"The new password","example":"ultra-secure-password!1!1!"}}},"SettingsFull":{"type":"object","description":"The live settings of kraken","required":["mfa_required","oidc_initial_permission_level","created_at"],"properties":{"mfa_required":{"type":"boolean","description":"Require mfa for local users"},"oidc_initial_permission_level":{"$ref":"#/components/schemas/UserPermission"},"dehashed_email":{"type":"string","description":"The email for the dehashed account","example":"foo@example.com","nullable":true},"dehashed_api_key":{"type":"string","description":"The api key for the dehashed account","example":"1231kb3kkb51kj31kjb231kj3b1jk23bkj123","nullable":true},"created_at":{"type":"string","format":"date-time","description":"The point in time the settings were created"}}},"SimpleAggregationSource":{"type":"object","description":"Numbers how many attacks of a certain kind found an aggregated model","required":["bruteforce_subdomains","tcp_port_scan","query_certificate_transparency","query_dehashed","host_alive","service_detection","dns_resolution","forced_browsing","os_detection","anti_port_scanning_detection","udp_port_scan","version_detection","manual"],"properties":{"bruteforce_subdomains":{"type":"integer","description":"Bruteforce subdomains via DNS requests","minimum":0},"tcp_port_scan":{"type":"integer","description":"Scan tcp ports","minimum":0},"query_certificate_transparency":{"type":"integer","description":"Query certificate transparency","minimum":0},"query_dehashed":{"type":"integer","description":"Query the dehashed API","minimum":0},"host_alive":{"type":"integer","description":"Check if a host is reachable via icmp","minimum":0},"service_detection":{"type":"integer","description":"Detect the service that is running on a port","minimum":0},"dns_resolution":{"type":"integer","description":"Resolve domain names","minimum":0},"forced_browsing":{"type":"integer","description":"Perform forced browsing","minimum":0},"os_detection":{"type":"integer","description":"Detect the OS of the target","minimum":0},"anti_port_scanning_detection":{"type":"integer","description":"Detect if anti-port scanning techniques are in place","minimum":0},"udp_port_scan":{"type":"integer","description":"Scan udp ports","minimum":0},"version_detection":{"type":"integer","description":"Perform version detection","minimum":0},"manual":{"type":"boolean","description":"Manually inserted"}}},"SimpleAttack":{"type":"object","description":"A simple version of an attack","required":["uuid","workspace","attack_type","started_by","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The identifier of the attack"},"workspace":{"$ref":"#/components/schemas/SimpleWorkspace"},"attack_type":{"$ref":"#/components/schemas/AttackType"},"started_by":{"$ref":"#/components/schemas/SimpleUser"},"finished_at":{"type":"string","format":"date-time","description":"If this is None, the attack is still running","nullable":true},"error":{"type":"string","description":"If this field is set, the attack has finished with an error","nullable":true},"created_at":{"type":"string","format":"date-time","description":"The point in time this attack was started"}}},"SimpleBruteforceSubdomainsResult":{"type":"object","description":"A simple representation of a bruteforce subdomains result","required":["uuid","attack","created_at","source","destination","dns_record_type"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"source":{"type":"string","description":"The source address"},"destination":{"type":"string","description":"The destination address"},"dns_record_type":{"type":"string","description":"The type of DNS Record","enum":["A","Aaaa","Caa","Cname","Mx","Tlsa","Txt"]}}},"SimpleDnsResolutionResult":{"type":"object","description":"A simple representation of a dns resolution result","required":["uuid","attack","created_at","source","destination","dns_record_type"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"source":{"type":"string","description":"The source address"},"destination":{"type":"string","description":"The destination address"},"dns_record_type":{"type":"string","description":"The type of DNS Record","enum":["A","Aaaa","Caa","Cname","Mx","Tlsa","Txt"]}}},"SimpleDomain":{"type":"object","description":"A simple representation of a domain in a workspace","required":["uuid","domain","comment","workspace","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the domain"},"domain":{"type":"string","description":"The domain name","example":"example.com"},"comment":{"type":"string","description":"The comment to the domain","example":"This is a important domain!"},"workspace":{"type":"string","format":"uuid","description":"The workspace this domain is linked to"},"created_at":{"type":"string","format":"date-time","description":"The point in time this domain was created"}}},"SimpleHost":{"type":"object","description":"The simple representation of a host","required":["uuid","ip_addr","os_type","comment","workspace","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the host"},"ip_addr":{"type":"string","description":"The ip address of the host","example":"172.0.0.1"},"os_type":{"$ref":"#/components/schemas/OsType"},"comment":{"type":"string","description":"A comment"},"workspace":{"type":"string","format":"uuid","description":"The workspace this host is in"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"SimpleHostAliveResult":{"type":"object","description":"A simple representation of a host alive result","required":["uuid","attack","created_at","host"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"host":{"type":"string","description":"A host that responded","example":"127.0.0.1"}}},"SimpleLeech":{"type":"object","description":"The simple representation of a leech","required":["uuid","name","address"],"properties":{"uuid":{"type":"string","format":"uuid","description":"uuid of the leech"},"name":{"type":"string","description":"Name of the leech","example":"leech-01"},"address":{"type":"string","description":"Address of the leech","example":"https://10.13.37.1:8081"}}},"SimpleOauthClient":{"type":"object","description":"A simple (secret-less) version of a workspace","required":["uuid","name","redirect_uri"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the client"},"name":{"type":"string","description":"The name of the client","example":"Trustworthy application"},"redirect_uri":{"type":"string","description":"The redirect url of the client","example":"http://127.0.0.1:8080"}}},"SimplePort":{"type":"object","description":"The simple representation of a port","required":["uuid","port","protocol","host","comment","workspace","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"Uuid of the port"},"port":{"type":"integer","format":"int32","description":"Port number","example":1337,"minimum":0},"protocol":{"$ref":"#/components/schemas/PortProtocol"},"host":{"type":"string","format":"uuid","description":"The host this port is assigned to"},"comment":{"type":"string","description":"A comment to the port"},"workspace":{"type":"string","format":"uuid","description":"The workspace this port is linked to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"SimpleQueryUnhashedResult":{"type":"object","description":"A simple representation of a query unhashed result","required":["uuid","attack","created_at","dehashed_id","ip_address"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"dehashed_id":{"type":"integer","format":"int64","description":"ID of the entry"},"email":{"type":"string","description":"An email address","nullable":true},"username":{"type":"string","description":"An username","nullable":true},"password":{"type":"string","description":"A password","nullable":true},"hashed_password":{"type":"string","description":"An hashed password","nullable":true},"ip_address":{"type":"string","description":"An ip address","example":"127.0.0.1"},"name":{"type":"string","description":"A name","nullable":true},"vin":{"type":"string","description":"A vin","nullable":true},"address":{"type":"string","description":"An address","nullable":true},"phone":{"type":"string","description":"A phone number","nullable":true},"database_name":{"type":"string","description":"A database name","nullable":true}}},"SimpleService":{"type":"object","description":"A simple representation of a service","required":["uuid","name","host","comment","workspace","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the service"},"name":{"type":"string","description":"The name of the service","example":"postgresql"},"version":{"type":"string","description":"The version of the service","example":"13.0.1","nullable":true},"host":{"type":"string","format":"uuid","description":"The host this service is linked to"},"port":{"type":"string","format":"uuid","description":"The port this service may linked to","nullable":true},"comment":{"type":"string","description":"The comment attached to the service","example":"Holds all relevant information"},"workspace":{"type":"string","format":"uuid","description":"The workspace is service is linked to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"SimpleTag":{"type":"object","description":"A simple tag","required":["uuid","name","color","tag_type"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the tag"},"name":{"type":"string","description":"The name of the tag"},"color":{"$ref":"#/components/schemas/Color"},"tag_type":{"$ref":"#/components/schemas/TagType"}}},"SimpleTcpPortScanResult":{"type":"object","description":"A simple representation of a tcp port scan result","required":["uuid","attack","created_at","address","port"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"address":{"type":"string","description":"The ip address a port was found on","example":"127.0.0.1"},"port":{"type":"integer","format":"int32","description":"The found port","minimum":0}}},"SimpleUser":{"type":"object","description":"This struct holds the user information.\n\nNote that `username` is unique, but as it is changeable,\nidentify the user by its `uuid`","required":["uuid","username","display_name"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the user"},"username":{"type":"string","description":"The username of the user"},"display_name":{"type":"string","description":"The displayname of the user"}}},"SimpleWordlist":{"type":"object","description":"A wordlist without its `path` field","required":["uuid","name","description"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the wordlist"},"name":{"type":"string","description":"The wordlist's name to be displayed select buttons","example":"subdomains-top1million-5000.txt"},"description":{"type":"string","description":"A description explaining the wordlist's intended use case","example":"List of 5000 subdomains"}}},"SimpleWorkspace":{"type":"object","description":"A simple version of a workspace","required":["uuid","name","owner","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the workspace"},"name":{"type":"string","description":"The name of the workspace","example":"ultra-secure-workspace"},"description":{"type":"string","description":"The description of the workspace","example":"This workspace is ultra secure and should not be looked at!!","nullable":true},"owner":{"$ref":"#/components/schemas/SimpleUser"},"created_at":{"type":"string","format":"date-time","description":"The point in time the workspace was created"}}},"SourceAttack":{"allOf":[{"$ref":"#/components/schemas/SourceAttackResult"},{"type":"object","required":["uuid","workspace_uuid","started_by","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The identifier of the attack"},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace this attack is attached to"},"started_by":{"$ref":"#/components/schemas/SimpleUser"},"finished_at":{"type":"string","format":"date-time","description":"If this is None, the attack is still running","nullable":true},"error":{"type":"string","description":"If this field is set, the attack has finished with an error","nullable":true},"created_at":{"type":"string","format":"date-time","description":"The point in time this attack was started"}}}],"description":"Copy of [`SimpleAttack`](crate::api::handler::attacks::SimpleAttack) with an added `results` field"},"SourceAttackResult":{"oneOf":[{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["BruteforceSubdomains"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleBruteforceSubdomainsResult"},"description":"The [`AttackType::BruteforceSubdomains`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["TcpPortScan"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTcpPortScanResult"},"description":"The [`AttackType::TcpPortScan`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["QueryCertificateTransparency"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/FullQueryCertificateTransparencyResult"},"description":"The [`AttackType::QueryCertificateTransparency`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["QueryDehashed"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleQueryUnhashedResult"},"description":"The [`AttackType::QueryUnhashed`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["HostAlive"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleHostAliveResult"},"description":"The [`AttackType::HostAlive`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["ServiceDetection"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/FullServiceDetectionResult"},"description":"The [`AttackType::ServiceDetection`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["DnsResolution"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleDnsResolutionResult"},"description":"The [`AttackType::DnsResolution`] and its results"}}}],"description":"The different types of attack and their results","discriminator":{"propertyName":"attack_type"}},"TagType":{"type":"string","description":"The type of a tag","enum":["Workspace","Global"]},"TcpPortScanResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTcpPortScanResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"TransferWorkspaceRequest":{"type":"object","description":"The request to transfer a workspace to another account","required":["user"],"properties":{"user":{"type":"string","format":"uuid","description":"The uuid of the user that should receive the workspace"}}},"UpdateApiKeyRequest":{"type":"object","description":"The request to update an api key","required":["name"],"properties":{"name":{"type":"string","description":"A descriptive name helping the user to identify the key","example":"Leech on my local machine"}}},"UpdateAppRequest":{"type":"object","description":"Update an oauth application","properties":{"name":{"type":"string","description":"The name of the application","example":"Trustworthy application","nullable":true},"redirect_uri":{"type":"string","description":"The redirect url of the application","example":"http://127.0.0.1:8080","nullable":true}}},"UpdateDomainRequest":{"type":"object","description":"The request to update a domain","properties":{"comment":{"type":"string","description":"The comment of the domain","nullable":true},"global_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Global tags that are linked to the domain","nullable":true},"workspace_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Workspace tags that are linked to the domain","nullable":true}}},"UpdateGlobalTag":{"type":"object","description":"The request to update a global tag","properties":{"name":{"type":"string","description":"Name of the global tag","nullable":true},"color":{"allOf":[{"$ref":"#/components/schemas/Color"}],"nullable":true}}},"UpdateHostRequest":{"type":"object","description":"The request to update a host","properties":{"comment":{"type":"string","description":"The comment of a host","nullable":true},"global_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The global tags of a host","nullable":true},"workspace_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The workspace tags of a host","nullable":true}}},"UpdateLeechRequest":{"type":"object","description":"The request to update a leech","required":["address"],"properties":{"name":{"type":"string","description":"Name of the leech","example":"leech-01","nullable":true},"address":{"type":"string","description":"Address of the leech","example":"https://10.13.37.1:8081"},"description":{"type":"string","description":"Description of the leech","example":"First leech in a private network","nullable":true}}},"UpdateMeRequest":{"type":"object","description":"The request to update the own user\n\nAt least one of the options must be set","properties":{"username":{"type":"string","description":"The username","example":"cyber-user-123","nullable":true},"display_name":{"type":"string","description":"The displayname","example":"Cyberhacker","nullable":true}}},"UpdatePortRequest":{"type":"object","description":"The request to update a port","properties":{"comment":{"type":"string","description":"The comment of the port","nullable":true},"global_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Global tags that are linked to the port","nullable":true},"workspace_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Workspace tags that are linked to the port","nullable":true}}},"UpdateServiceRequest":{"type":"object","description":"The request to update a service","properties":{"comment":{"type":"string","description":"The comment of the service","nullable":true},"global_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The global tags that are attached to the service","nullable":true},"workspace_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The workspace tags that are attached to the service","nullable":true}}},"UpdateSettingsRequest":{"type":"object","description":"The request to update the settings","required":["mfa_required","oidc_initial_permission_level"],"properties":{"mfa_required":{"type":"boolean","description":"Require mfa for local users"},"oidc_initial_permission_level":{"$ref":"#/components/schemas/UserPermission"},"dehashed_email":{"type":"string","description":"The email for the dehashed account","example":"foo@example.com","nullable":true},"dehashed_api_key":{"type":"string","description":"The api key for the dehashed account","example":"1231kb3kkb51kj31kjb231kj3b1jk23bkj123","nullable":true}}},"UpdateWordlistRequest":{"type":"object","description":"Arguments for updating an existing wordlist","required":["uuid"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the wordlist to update"},"name":{"type":"string","description":"The wordlist's name to be displayed select buttons","example":"subdomains-top1million-5000.txt","nullable":true},"description":{"type":"string","description":"A description explaining the wordlist's intended use case","example":"List of 5000 subdomains","nullable":true},"path":{"type":"string","description":"The file path the wordlist is deployed under on each leech","example":"/opt/wordlists/Discovery/DNS/subdomains-top1million-5000.txt","nullable":true}}},"UpdateWorkspaceRequest":{"type":"object","description":"The request type to update a workspace\n\nAll parameter are optional, but at least one of them must be specified","properties":{"name":{"type":"string","description":"Name of the workspace","example":"Workspace for work","nullable":true},"description":{"type":"string","description":"Description of the workspace","example":"This workspace is for work and for work only!","nullable":true}}},"UpdateWorkspaceTag":{"type":"object","description":"The request to update a workspace tag","properties":{"name":{"type":"string","description":"Name of the tag","nullable":true},"color":{"allOf":[{"$ref":"#/components/schemas/Color"}],"nullable":true}}},"UserPermission":{"type":"string","description":"The permission of a user","enum":["ReadOnly","Default","Admin"]},"UuidResponse":{"type":"object","description":"A common response that contains a single uuid","required":["uuid"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid"}}},"WorkspaceInvitationList":{"type":"object","description":"A list of invitations to workspaces","required":["invitations"],"properties":{"invitations":{"type":"array","items":{"$ref":"#/components/schemas/FullWorkspaceInvitation"},"description":"All invitations of the current user"}}},"WsMessage":{"oneOf":[{"type":"object","description":"An invalid message was received.\n\nThis message type is sent to the client.","required":["type"],"properties":{"type":{"type":"string","enum":["InvalidMessage"]}}},{"type":"object","description":"An invitation to a workspace was issued","required":["invitation_uuid","workspace","from","type"],"properties":{"invitation_uuid":{"type":"string","format":"uuid","description":"The uuid of the invitation"},"workspace":{"$ref":"#/components/schemas/SimpleWorkspace"},"from":{"$ref":"#/components/schemas/SimpleUser"},"type":{"type":"string","enum":["InvitationToWorkspace"]}}},{"type":"object","description":"A notification about a started attack","required":["attack","type"],"properties":{"attack":{"$ref":"#/components/schemas/SimpleAttack"},"type":{"type":"string","enum":["AttackStarted"]}}},{"type":"object","description":"A notification about a finished attack","required":["attack","type"],"properties":{"attack":{"$ref":"#/components/schemas/SimpleAttack"},"type":{"type":"string","enum":["AttackFinished"]}}},{"type":"object","description":"A notification about a finished search","required":["search_uuid","finished_successful","type"],"properties":{"search_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the search"},"finished_successful":{"type":"boolean","description":"Whether the search was finished successfully"},"type":{"type":"string","enum":["SearchFinished"]}}},{"type":"object","description":"A notification about a search result","required":["search_uuid","result_uuid","type"],"properties":{"search_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the search results"},"result_uuid":{"type":"string","format":"uuid","description":"A result entry"},"type":{"type":"string","enum":["SearchNotify"]}}},{"type":"object","description":"A result for a subdomain enumeration using bruteforce DNS requests","required":["attack_uuid","source","destination","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"source":{"type":"string","description":"The source address that was queried"},"destination":{"type":"string","description":"The destination address that was returned"},"type":{"type":"string","enum":["BruteforceSubdomainsResult"]}}},{"type":"object","description":"A result for hosts alive check","required":["attack_uuid","host","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"host":{"type":"string","description":"A host which could be reached"},"type":{"type":"string","enum":["HostsAliveCheck"]}}},{"type":"object","description":"A result for a tcp scan","required":["attack_uuid","address","port","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"address":{"type":"string","description":"The address of the result"},"port":{"type":"integer","format":"int32","description":"The port of the result","minimum":0},"type":{"type":"string","enum":["ScanTcpPortsResult"]}}},{"type":"object","description":"A result to a certificate transparency request","required":["attack_uuid","entries","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/CertificateTransparencyEntry"},"description":"The entries of the result"},"type":{"type":"string","enum":["CertificateTransparencyResult"]}}},{"type":"object","description":"A result to service detection request","required":["attack_uuid","service","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"service":{"type":"string","description":"Name of the service"},"type":{"type":"string","enum":["ServiceDetectionResult"]}}},{"type":"object","description":"A result for a DNS resolution requests","required":["attack_uuid","source","destination","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"source":{"type":"string","description":"The source address that was queried"},"destination":{"type":"string","description":"The destination address that was returned"},"type":{"type":"string","enum":["DnsResolutionResult"]}}},{"type":"object","description":"A new domain was found","required":["workspace","domain","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace this domain is related to"},"domain":{"$ref":"#/components/schemas/SimpleDomain"},"type":{"type":"string","enum":["NewDomain"]}}},{"type":"object","description":"A new host was found","required":["workspace","host","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace this host is related to"},"host":{"$ref":"#/components/schemas/SimpleHost"},"type":{"type":"string","enum":["NewHost"]}}},{"type":"object","description":"A new port was found","required":["workspace","port","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace this port is related to"},"port":{"$ref":"#/components/schemas/SimplePort"},"type":{"type":"string","enum":["NewPort"]}}},{"type":"object","description":"A new service was found","required":["workspace","service","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace this service is related to"},"service":{"$ref":"#/components/schemas/SimpleService"},"type":{"type":"string","enum":["NewService"]}}},{"type":"object","description":"Global tags were updated on an aggregation","required":["workspace","aggregation","uuid","tags","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace the aggregation is related to"},"aggregation":{"$ref":"#/components/schemas/AggregationType"},"uuid":{"type":"string","format":"uuid","description":"The uuid of the model"},"tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The updated list of tags"},"type":{"type":"string","enum":["UpdatedGlobalTags"]}}},{"type":"object","description":"Workspace tags were updated on an aggregation","required":["workspace","aggregation","uuid","tags","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace the aggregation is related to"},"aggregation":{"$ref":"#/components/schemas/AggregationType"},"uuid":{"type":"string","format":"uuid","description":"The uuid of the model"},"tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The updated list of tags"},"type":{"type":"string","enum":["UpdatedWorkspaceTags"]}}}],"description":"Message that is sent via websocket","discriminator":{"propertyName":"type"}}},"securitySchemes":{"api_key":{"type":"apiKey","in":"cookie","name":"id"}}}} \ No newline at end of file +{"openapi":"3.0.3","info":{"title":"kraken","description":"The core component of kraken-project","contact":{"name":"Niklas Pfister","email":"git@omikron.dev"},"license":{"name":"AGPL-3.0"},"version":"0.1.0"},"paths":{"/api/v1/admin/applications":{"get":{"tags":["OAuth Application"],"operationId":"get_all_oauth_apps","responses":{"200":{"description":"Returns all oauth applications","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOauthApplications"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["OAuth Application"],"summary":"Create a new application","description":"Create a new application","operationId":"create_oauth_app","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAppRequest"}}},"required":true},"responses":{"200":{"description":"Application was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/applications/{uuid}":{"get":{"tags":["OAuth Application"],"operationId":"get_oauth_app","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns an oauth applications","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullOauthClient"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["OAuth Application"],"summary":"Update an application","description":"Update an application","operationId":"update_oauth_app","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAppRequest"}}},"required":true},"responses":{"200":{"description":"Application got updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["OAuth Application"],"summary":"Delete an application","description":"Delete an application","operationId":"delete_oauth_app","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Application was deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/globalTags":{"post":{"tags":["Global Tags"],"summary":"Create a global tag.","description":"Create a global tag.\n\nThis action requires admin privileges.","operationId":"create_global_tag","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGlobalTagRequest"}}},"required":true},"responses":{"200":{"description":"Global tag was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/globalTags/{uuid}":{"put":{"tags":["Global Tags"],"summary":"Update a global tag","description":"Update a global tag\n\nOne of the options must be set\n\nRequires admin privileges.","operationId":"update_global_tag","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGlobalTag"}}},"required":true},"responses":{"200":{"description":"Global tag was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Global Tags"],"summary":"Delete a global tag","description":"Delete a global tag\n\nRequires admin privileges.","operationId":"delete_global_tag","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Global tag was deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/leeches":{"get":{"tags":["Leech management"],"summary":"Retrieve all leeches","description":"Retrieve all leeches","operationId":"get_all_leeches","responses":{"200":{"description":"Matched leeches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListLeeches"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Leech management"],"summary":"Create a leech","description":"Create a leech\n\nThe `name` parameter must be unique.\n\n`address` must be a valid address including a scheme and port.\nCurrently only https and http are supported as scheme.","operationId":"create_leech","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLeechRequest"}}},"required":true},"responses":{"200":{"description":"Leech got created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/leeches/{uuid}":{"get":{"tags":["Leech management"],"summary":"Retrieve a leech by its id","description":"Retrieve a leech by its id","operationId":"get_leech","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Matched leeches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimpleLeech"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Leech management"],"summary":"Update a leech by its id","description":"Update a leech by its id\n\nAll parameter are optional, but at least one of them must be specified.\n\n`address` must be a valid address including a scheme and port.\nCurrently only https and http are supported as scheme.","operationId":"update_leech","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLeechRequest"}}},"required":true},"responses":{"200":{"description":"Leech got updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Leech management"],"summary":"Delete a leech by its uuid","description":"Delete a leech by its uuid","operationId":"delete_leech","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Leech got deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/leeches/{uuid}/cert":{"get":{"tags":["Leech management"],"summary":"Generate a new config for the leech","description":"Generate a new config for the leech","operationId":"gen_leech_config","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Newly generated leech cert","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeechConfig"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/settings":{"get":{"tags":["Settings Management"],"summary":"Retrieve the currently active settings","description":"Retrieve the currently active settings","operationId":"get_settings","responses":{"200":{"description":"Returns the currently active settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsFull"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Settings Management"],"summary":"Update the settings","description":"Update the settings","operationId":"update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Settings have been updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/users":{"get":{"tags":["User Admin Management"],"summary":"Retrieve all users","description":"Retrieve all users","operationId":"get_all_users_admin","responses":{"200":{"description":"Returns all users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListFullUsers"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["User Admin Management"],"summary":"Create a user","description":"Create a user","operationId":"create_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"200":{"description":"User got created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/users/{uuid}":{"get":{"tags":["User Admin Management"],"summary":"Retrieve a user by its uuid","description":"Retrieve a user by its uuid","operationId":"get_user","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns the user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullUser"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["User Admin Management"],"summary":"Delete a user by its uuid","description":"Delete a user by its uuid","operationId":"delete_user","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User got deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/wordlists":{"get":{"tags":["Wordlist management"],"summary":"Get a list of all wordlists including their paths","description":"Get a list of all wordlists including their paths","operationId":"get_all_wordlists_admin","responses":{"200":{"description":"List of all wordlists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWordlistsAdmin"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Wordlist management"],"summary":"Create a new wordlist","description":"Create a new wordlist","operationId":"create_wordlist_admin","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWordlistRequest"}}},"required":true},"responses":{"200":{"description":"Wordlist got created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/wordlists/{uuid}":{"put":{"tags":["Wordlist management"],"summary":"Update an existing wordlist","description":"Update an existing wordlist","operationId":"update_wordlist_admin","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWordlistRequest"}}},"required":true},"responses":{"200":{"description":"Wordlist got updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Wordlist management"],"summary":"Delete an existing wordlist","description":"Delete an existing wordlist","operationId":"delete_wordlist_admin","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Wordlist got deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/workspaces":{"get":{"tags":["Admin Workspaces"],"summary":"Retrieve all workspaces","description":"Retrieve all workspaces","operationId":"get_all_workspaces_admin","responses":{"200":{"description":"Returns all workspaces","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWorkspaces"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/admin/workspaces/{uuid}":{"get":{"tags":["Admin Workspaces"],"summary":"Retrieve a workspace by id","description":"Retrieve a workspace by id","operationId":"get_workspace_admin","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns the workspace with the given id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullWorkspace"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/apiKeys":{"get":{"tags":["Api Keys"],"summary":"Retrieve all api keys","description":"Retrieve all api keys","operationId":"get_api_keys","responses":{"200":{"description":"The uses api keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListApiKeys"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Api Keys"],"summary":"Create new api key","description":"Create new api key","operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"Api key was created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/apiKeys/{uuid}":{"put":{"tags":["Api Keys"],"summary":"Update an api key by its id","description":"Update an api key by its id\n\nAll parameter are optional, but at least one of them must be specified.","operationId":"update_api_key","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"Api key got updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Api Keys"],"summary":"Delete an existing api key","description":"Delete an existing api key","operationId":"delete_api_key","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Api key got deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks":{"get":{"tags":["Attacks"],"summary":"Retrieve all attacks the user has access to","description":"Retrieve all attacks the user has access to","operationId":"get_all_attacks","responses":{"200":{"description":"Retrieve a list of all attacks the user has access to","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAttacks"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/bruteforceSubdomains":{"post":{"tags":["Attacks"],"summary":"Bruteforce subdomains through a DNS wordlist attack","description":"Bruteforce subdomains through a DNS wordlist attack\n\nEnumerate possible subdomains by querying a DNS server with constructed domains.\nSee [OWASP](https://owasp.org/www-community/attacks/Brute_force_attack) for further information.","operationId":"bruteforce_subdomains","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BruteforceSubdomainsRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/dnsResolution":{"post":{"tags":["Attacks"],"summary":"Perform domain name resolution","description":"Perform domain name resolution","operationId":"dns_resolution","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsResolutionRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/hostsAlive":{"post":{"tags":["Attacks"],"summary":"Check if hosts are reachable","description":"Check if hosts are reachable\n\nJust an ICMP scan for now to see which targets respond.\n\nAll intervals are interpreted in milliseconds. E.g. a `timeout` of 3000 means 3 seconds.","operationId":"hosts_alive_check","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostsAliveRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/queryCertificateTransparency":{"post":{"tags":["Attacks"],"summary":"Query a certificate transparency log collector.","description":"Query a certificate transparency log collector.\n\nFor further information, see [the explanation](https://certificate.transparency.dev/).\n\nCertificate transparency can be used to find subdomains or related domains.\n\n`retry_interval` is specified in milliseconds.","operationId":"query_certificate_transparency","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryCertificateTransparencyRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/queryDehashed":{"post":{"tags":["Attacks"],"summary":"Query the [dehashed](https://dehashed.com/) API.","description":"Query the [dehashed](https://dehashed.com/) API.\nIt provides email, password, credit cards and other types of information from leak-databases.\n\nNote that you are only able to query the API if you have bought access and have a running\nsubscription saved in kraken.","operationId":"query_dehashed","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDehashedRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/scanTcpPorts":{"post":{"tags":["Attacks"],"summary":"Start a tcp port scan","description":"Start a tcp port scan\n\n`exclude` accepts a list of ip networks in CIDR notation.\n\nAll intervals are interpreted in milliseconds. E.g. a `timeout` of 3000 means 3 seconds.\n\nSet `max_retries` to 0 if you don't want to try a port more than 1 time.","operationId":"scan_tcp_ports","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanTcpPortsRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/serviceDetection":{"post":{"tags":["Attacks"],"summary":"Perform service detection on a ip and port combination","description":"Perform service detection on a ip and port combination","operationId":"service_detection","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceDetectionRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/testssl":{"post":{"tags":["Attacks"],"summary":"Run testssl","description":"Run testssl","operationId":"testssl","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestSSLRequest"}}},"required":true},"responses":{"202":{"description":"Attack scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}":{"get":{"tags":["Attacks"],"summary":"Retrieve an attack by id","description":"Retrieve an attack by id","operationId":"get_attack","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns the attack","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimpleAttack"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Attacks"],"summary":"Delete an attack and its results","description":"Delete an attack and its results","operationId":"delete_attack","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Attack was deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/bruteforceSubdomainsResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a bruteforce subdomains' results by the attack's id","description":"Retrieve a bruteforce subdomains' results by the attack's id","operationId":"get_bruteforce_subdomains_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BruteforceSubdomainsResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/dnsResolutionResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a dns resolution's results by the attack's id","description":"Retrieve a dns resolution's results by the attack's id","operationId":"get_dns_resolution_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsResolutionResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/hostAliveResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a host alive's results by the attack's id","description":"Retrieve a host alive's results by the attack's id","operationId":"get_host_alive_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostAliveResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/queryCertificateTransparencyResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a query certificate transparency's results by the attack's id","description":"Retrieve a query certificate transparency's results by the attack's id","operationId":"get_query_certificate_transparency_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryCertificateTransparencyResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/queryUnhashedResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a query dehashed's results by the attack's id","description":"Retrieve a query dehashed's results by the attack's id","operationId":"get_query_unhashed_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryUnhashedResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/serviceDetectionResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a detect service's results by the attack's id","description":"Retrieve a detect service's results by the attack's id","operationId":"get_service_detection_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceDetectionResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/attacks/{uuid}/tcpPortScanResults":{"get":{"tags":["Attacks"],"summary":"Retrieve a tcp port scan's results by the attack's id","description":"Retrieve a tcp port scan's results by the attack's id","operationId":"get_tcp_port_scan_results","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Returns attack's results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TcpPortScanResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/auth/finishAuth":{"post":{"tags":["Authentication"],"summary":"Finishes the authentication with a security key","description":"Finishes the authentication with a security key\n\nUse `startAuth` to retrieve the challenge response data.","operationId":"finish_auth","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}},"required":true},"responses":{"200":{"description":"2FA Authentication finished"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/finishRegister":{"post":{"tags":["Authentication"],"summary":"Finish the registration of a security key","description":"Finish the registration of a security key\n\nUse `startRegister` to retrieve the challenge response data.","operationId":"finish_register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FinishRegisterRequest"}}},"required":true},"responses":{"200":{"description":"2FA Key registration finished"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/login":{"post":{"tags":["Authentication"],"summary":"Login to kraken","description":"Login to kraken","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/logout":{"get":{"tags":["Authentication"],"summary":"Log out of this session","description":"Log out of this session\n\nLogs a logged-in user out of his session.","operationId":"logout","responses":{"200":{"description":"Logout successful"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/startAuth":{"post":{"tags":["Authentication"],"summary":"Starts the authentication with a security key","description":"Starts the authentication with a security key\n\nUse the `login` endpoint before calling this one.\n\nProceed with `finishAuth`.","operationId":"start_auth","responses":{"200":{"description":"2FA Authentication started","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/startRegister":{"post":{"tags":["Authentication"],"summary":"Start the registration of a security key","description":"Start the registration of a security key\n\nProceed to the `finishRegister` endpoint.","operationId":"start_register","responses":{"200":{"description":"2FA Key registration started","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/auth/test":{"get":{"tags":["Authentication"],"summary":"Test the current login state","description":"Test the current login state\n\nYou can use this endpoint to test the current login state of your client.\n\nIf logged in, a 200 without a body is returned.","operationId":"test","responses":{"200":{"description":"Logged in"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/api/v1/globalTags":{"get":{"tags":["Global Tags"],"summary":"Retrieve all global tags","description":"Retrieve all global tags","operationId":"get_all_global_tags","responses":{"200":{"description":"Retrieve all global tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListGlobalTags"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/invitations":{"get":{"tags":["Workspace Invitations"],"summary":"Retrieve all open invitations to workspaces the currently logged-in user","description":"Retrieve all open invitations to workspaces the currently logged-in user\nhas retrieved","operationId":"get_all_invitations","responses":{"200":{"description":"Returns all invitations of a user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceInvitationList"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/invitations/{uuid}/accept":{"post":{"tags":["Workspace Invitations"],"summary":"Accept an invitation to a workspace","description":"Accept an invitation to a workspace","operationId":"accept_invitation","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Accept an invitation"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/invitations/{uuid}/decline":{"post":{"tags":["Workspace Invitations"],"summary":"Decline an invitation to a workspace","description":"Decline an invitation to a workspace","operationId":"decline_invitation","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Decline an invitation"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/oauth/accept/{uuid}":{"get":{"tags":["OAuth"],"summary":"Endpoint visited by user to grant a requesting application access","description":"Endpoint visited by user to grant a requesting application access","operationId":"accept","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"remember","in":"query","description":"Should kraken remember this decision?","required":false,"schema":{"type":"boolean"}}],"responses":{"302":{"description":"The user is redirected back to the requesting client"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/oauth/deny/{uuid}":{"get":{"tags":["OAuth"],"summary":"Endpoint visited by user to deny a requesting application access","description":"Endpoint visited by user to deny a requesting application access","operationId":"deny","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"remember","in":"query","description":"Should kraken remember this decision?","required":false,"schema":{"type":"boolean"}}],"responses":{"302":{"description":"The user is redirected back to the requesting client"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/oauth/info/{uuid}":{"get":{"tags":["OAuth"],"summary":"Queried by the frontend to display information about the oauth request to the user","description":"Queried by the frontend to display information about the oauth request to the user","operationId":"info","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Return information about an ongoing oauth request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenRequestInfo"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/oauthDecisions":{"get":{"tags":["OAuth Decisions"],"summary":"Retrieve a user's remembered oauth decisions","description":"Retrieve a user's remembered oauth decisions","operationId":"get_decisions","responses":{"200":{"description":"The user's remember oauth decisions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOauthDecisions"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/oauthDecisions/{uuid}":{"delete":{"tags":["OAuth Decisions"],"summary":"Revoke a user's remembered oauth decision","description":"Revoke a user's remembered oauth decision","operationId":"revoke_decision","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Revoked decision"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/users":{"get":{"tags":["User Management"],"summary":"Request all users","description":"Request all users\n\nThis may be used to create invitations for workspaces","operationId":"get_all_users","responses":{"200":{"description":"Simple representation of all users","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListUsers"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/users/me":{"get":{"tags":["User Management"],"summary":"Retrieve the own user","description":"Retrieve the own user","operationId":"get_me","responses":{"200":{"description":"Returns the own user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullUser"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["User Management"],"summary":"Updates the own user","description":"Updates the own user\n\nAll parameters are optional, but at least one of them must be supplied.","operationId":"update_me","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMeRequest"}}},"required":true},"responses":{"200":{"description":"Changes were applied"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/users/setPassword":{"post":{"tags":["User Management"],"summary":"Set a new password","description":"Set a new password","operationId":"set_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/wordlists":{"get":{"tags":["Wordlist"],"summary":"Get a list of all wordlist for the user to select from when starting an bruteforce subdomains attack","description":"Get a list of all wordlist for the user to select from when starting an bruteforce subdomains attack","operationId":"get_all_wordlists","responses":{"200":{"description":"Matched leeches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWordlists"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces":{"get":{"tags":["Workspaces"],"summary":"Retrieve all workspaces that the executing user has access to","description":"Retrieve all workspaces that the executing user has access to\n\nFor administration access, look at the `/admin/workspaces` endpoint.","operationId":"get_all_workspaces","responses":{"200":{"description":"Returns all workspaces that the executing user has access to","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWorkspaces"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Workspaces"],"summary":"Create a new workspace","description":"Create a new workspace","operationId":"create_workspace","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkspaceRequest"}}},"required":true},"responses":{"200":{"description":"Workspace was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}":{"get":{"tags":["Workspaces"],"summary":"Retrieve a workspace by id","description":"Retrieve a workspace by id","operationId":"get_workspace","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns the workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullWorkspace"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Workspaces"],"summary":"Updates a workspace by its id","description":"Updates a workspace by its id\n\nAll parameter are optional, but at least one of them must be specified.\n\n`name` must not be empty.\n\nYou can set `description` to null to remove the description from the database.\nIf you leave the parameter out, the description will remain unchanged.","operationId":"update_workspace","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkspaceRequest"}}},"required":true},"responses":{"200":{"description":"Workspace got updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Workspaces"],"summary":"Delete a workspace by its id","description":"Delete a workspace by its id","operationId":"delete_workspace","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Workspace was deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/attacks":{"get":{"tags":["Attacks"],"summary":"Query all attacks of a workspace","description":"Query all attacks of a workspace","operationId":"get_workspace_attacks","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieve a list of all attacks of a workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAttacks"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/domains":{"post":{"tags":["Domains"],"summary":"Manually add a domain","description":"Manually add a domain","operationId":"create_domain","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"200":{"description":"Domain was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/domains/all":{"post":{"tags":["Domains"],"summary":"Retrieve all domains of a specific workspace","description":"Retrieve all domains of a specific workspace","operationId":"get_all_domains","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAllDomainsQuery"}}},"required":true},"responses":{"200":{"description":"Retrieve all domains of a workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/hosts":{"post":{"tags":["Hosts"],"summary":"Manually add a host","description":"Manually add a host","operationId":"create_host","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHostRequest"}}},"required":true},"responses":{"200":{"description":"Host was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/hosts/all":{"post":{"tags":["Hosts"],"summary":"Retrieve all hosts.","description":"Retrieve all hosts.\n\nHosts are created out of aggregating data or by user input.\nThey represent a single host and can be created by providing an IP address","operationId":"get_all_hosts","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAllHostsQuery"}}},"required":true},"responses":{"200":{"description":"All hosts in the workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/invitations":{"get":{"tags":["Workspaces"],"summary":"Query all open invitations to a workspace","description":"Query all open invitations to a workspace","operationId":"get_all_workspace_invitations","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Returns all open invitations to the workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceInvitationList"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Workspaces"],"summary":"Invite a user to the workspace","description":"Invite a user to the workspace\n\nThis action can only be invoked by the owner of a workspace","operationId":"create_invitation","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteToWorkspaceRequest"}}},"required":true},"responses":{"200":{"description":"The user was invited."},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/ports":{"post":{"tags":["Ports"],"summary":"Manually add a port","description":"Manually add a port","operationId":"create_port","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePortRequest"}}},"required":true},"responses":{"200":{"description":"Port was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/ports/all":{"post":{"tags":["Ports"],"summary":"List the ports of a workspace","description":"List the ports of a workspace","operationId":"get_all_ports","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAllPortsQuery"}}},"required":true},"responses":{"200":{"description":"Retrieve all ports of a workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/search":{"get":{"tags":["Workspaces"],"summary":"Query all searches","description":"Query all searches","operationId":"get_searches","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchesResultPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Workspaces"],"summary":"Search through a workspaces' data","description":"Search through a workspaces' data","operationId":"search","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchWorkspaceRequest"}}},"required":true},"responses":{"200":{"description":"Search has been scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/services":{"post":{"tags":["Services"],"summary":"Manually add a service","description":"Manually add a service","operationId":"create_service","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/services/all":{"post":{"tags":["Services"],"summary":"List the services of a workspace","description":"List the services of a workspace","operationId":"get_all_services","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAllServicesQuery"}}},"required":true},"responses":{"200":{"description":"Retrieve all services of a workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResultsPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/tags":{"get":{"tags":["Workspace Tags"],"summary":"Retrieve all workspace tags","description":"Retrieve all workspace tags","operationId":"get_all_workspace_tags","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieve all workspace tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListWorkspaceTags"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"post":{"tags":["Workspace Tags"],"summary":"Create a workspace tag.","description":"Create a workspace tag.","operationId":"create_workspace_tag","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkspaceTagRequest"}}},"required":true},"responses":{"200":{"description":"Workspace tag was created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UuidResponse"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{uuid}/transfer":{"post":{"tags":["Workspaces"],"summary":"Transfer ownership to another account","description":"Transfer ownership to another account\n\nYou will loose access to the workspace.","operationId":"transfer_ownership","parameters":[{"name":"uuid","in":"path","description":"The uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferWorkspaceRequest"}}},"required":true},"responses":{"200":{"description":"Workspace was transferred"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/domains/{d_uuid}":{"get":{"tags":["Domains"],"summary":"Retrieve all information about a single domain","description":"Retrieve all information about a single domain","operationId":"get_domain","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"d_uuid","in":"path","description":"The domain's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieved the selected domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullDomain"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Domains"],"summary":"Update a domain","description":"Update a domain\n\nYou must include at least on parameter","operationId":"update_domain","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"d_uuid","in":"path","description":"The domain's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDomainRequest"}}},"required":true},"responses":{"200":{"description":"Domain was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/domains/{d_uuid}/sources":{"get":{"tags":["Domains"],"summary":"Get all data sources which referenced this domain","description":"Get all data sources which referenced this domain","operationId":"get_domain_sources","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"d_uuid","in":"path","description":"The domain's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The domain's sources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullAggregationSource"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/hosts/{h_uuid}":{"get":{"tags":["Hosts"],"summary":"Retrieve all information about a single host","description":"Retrieve all information about a single host","operationId":"get_host","parameters":[{"name":"w_uuid","in":"path","description":"Workspace uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"h_uuid","in":"path","description":"Host uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieved the selected host","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullHost"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Hosts"],"summary":"Update a host","description":"Update a host\n\nYou must include at least on parameter","operationId":"update_host","parameters":[{"name":"w_uuid","in":"path","description":"Workspace uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"h_uuid","in":"path","description":"Host uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateHostRequest"}}},"required":true},"responses":{"200":{"description":"Host was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/hosts/{h_uuid}/sources":{"get":{"tags":["Hosts"],"summary":"Get all data sources which referenced this host","description":"Get all data sources which referenced this host","operationId":"get_host_sources","parameters":[{"name":"w_uuid","in":"path","description":"Workspace uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"h_uuid","in":"path","description":"Host uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The host's sources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullAggregationSource"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/invitations/{i_uuid}":{"delete":{"tags":["Workspaces"],"summary":"Retract an invitation to the workspace","description":"Retract an invitation to the workspace\n\nThis action can only be invoked by the owner of a workspace","operationId":"retract_invitation","parameters":[{"name":"w_uuid","in":"path","description":"The UUID of the workspace","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"i_uuid","in":"path","description":"The UUID of the invitation","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The invitation was retracted."},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/ports/{p_uuid}":{"get":{"tags":["Ports"],"summary":"Retrieve all information about a single port","description":"Retrieve all information about a single port","operationId":"get_port","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"p_uuid","in":"path","description":"The port's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieved the selected port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullPort"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Ports"],"summary":"Update a port","description":"Update a port\n\nYou must include at least on parameter","operationId":"update_port","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"p_uuid","in":"path","description":"The port's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePortRequest"}}},"required":true},"responses":{"200":{"description":"Port was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/ports/{p_uuid}/sources":{"get":{"tags":["Ports"],"summary":"Get all data sources which referenced this port","description":"Get all data sources which referenced this port","operationId":"get_port_sources","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"p_uuid","in":"path","description":"The port's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The port's sources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullAggregationSource"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/search/{s_uuid}":{"get":{"tags":["Workspaces"],"summary":"Retrieve results for a search by it's uuid","description":"Retrieve results for a search by it's uuid","operationId":"get_search_results","parameters":[{"name":"w_uuid","in":"path","description":"The UUID of the workspace","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"s_uuid","in":"path","description":"The UUID of the search","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","description":"Number of items to retrieve","required":true,"schema":{"type":"integer","format":"int64","minimum":1},"example":50},{"name":"offset","in":"query","description":"Position in the whole list to start retrieving from","required":true,"schema":{"type":"integer","format":"int64","minimum":0},"example":0}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResultPage"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/services/{s_uuid}":{"get":{"tags":["Services"],"summary":"Retrieve all information about a single service","description":"Retrieve all information about a single service","operationId":"get_service","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"s_uuid","in":"path","description":"The service's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrieved the selected service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullService"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"put":{"tags":["Services"],"summary":"Update a service","description":"Update a service\n\nYou must include at least on parameter","operationId":"update_service","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"s_uuid","in":"path","description":"The service's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/services/{s_uuid}/sources":{"get":{"tags":["Services"],"summary":"Get all data sources which referenced this service","description":"Get all data sources which referenced this service","operationId":"get_service_sources","parameters":[{"name":"w_uuid","in":"path","description":"The workspace's uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"s_uuid","in":"path","description":"The service's uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The service's sources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullAggregationSource"}}}},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/workspaces/{w_uuid}/tags/{t_uuid}":{"put":{"tags":["Workspace Tags"],"summary":"Update a workspace tag","description":"Update a workspace tag\n\nOne of the options must be set\n\nRequires privileges to access the workspace this tags belongs to.","operationId":"update_workspace_tag","parameters":[{"name":"w_uuid","in":"path","description":"Workspace uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"t_uuid","in":"path","description":"Tag uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkspaceTag"}}},"required":true},"responses":{"200":{"description":"Workspace tag was updated"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]},"delete":{"tags":["Workspace Tags"],"summary":"Delete a workspace tag","description":"Delete a workspace tag\n\nRequires privileges to access the workspace this tag belongs to.","operationId":"delete_workspace_tag","parameters":[{"name":"w_uuid","in":"path","description":"Workspace uuid","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"t_uuid","in":"path","description":"Tag uuid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Workspace tag was deleted"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}},"/api/v1/ws":{"get":{"tags":["Websocket"],"summary":"Start a websocket connection","description":"Start a websocket connection\n\nA heartbeat PING packet is sent constantly (every 10s).\nIf no response is retrieved within 30s of the last transmission, the socket\nwill be closed.","operationId":"websocket","responses":{"101":{"description":"Websocket connection established"},"400":{"description":"Client error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"security":[{"api_key":[]}]}}},"components":{"schemas":{"AggregationType":{"type":"string","description":"The different types of aggregations","enum":["Domain","Host","Service","Port"]},"ApiErrorResponse":{"type":"object","description":"Representation of an error response\n\n`status_code` holds the error code, `message` a human readable description of the error","required":["status_code","message"],"properties":{"status_code":{"$ref":"#/components/schemas/ApiStatusCode"},"message":{"type":"string","example":"Error message will be here"}}},"ApiStatusCode":{"type":"integer","description":"This type holds all possible error types that can be returned by the API.\n\nNumbers between 1000 and 1999 (inclusive) are client errors that can be handled by the client.\nNumbers between 2000 and 2999 (inclusive) are server errors.","default":1000,"enum":[1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,2000,2001,2002,2003,2004,2005],"example":1000},"AttackType":{"type":"string","description":"The type of an attack","enum":["Undefined","BruteforceSubdomains","TcpPortScan","QueryCertificateTransparency","QueryUnhashed","HostAlive","ServiceDetection","DnsResolution","UdpPortScan","ForcedBrowsing","OSDetection","VersionDetection","AntiPortScanningDetection","TestSSL"]},"BruteforceSubdomainsRequest":{"type":"object","description":"The settings of a subdomain bruteforce request","required":["domain","wordlist_uuid","concurrent_limit","workspace_uuid"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"domain":{"type":"string","description":"Domain to construct subdomains for","example":"example.com"},"wordlist_uuid":{"type":"string","format":"uuid","description":"The wordlist to use"},"concurrent_limit":{"type":"integer","format":"int32","description":"The concurrent task limit","example":100,"minimum":0},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"BruteforceSubdomainsResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SimpleBruteforceSubdomainsResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"CertificateTransparencyEntry":{"type":"object","description":"Entry of certificate transparency results","required":["serial_number","issuer_name","common_name","value_names"],"properties":{"serial_number":{"type":"string","description":"The serial number of the certificate"},"issuer_name":{"type":"string","description":"The name of the issuer for the certificate"},"common_name":{"type":"string","description":"The common name of the certificate"},"value_names":{"type":"array","items":{"type":"string"},"description":"The value names of the certificate"},"not_before":{"type":"string","format":"date-time","description":"The point in time after the certificate is valid","nullable":true},"not_after":{"type":"string","format":"date-time","description":"The point in time before the certificate is valid","nullable":true}}},"Color":{"type":"object","description":"Color value","required":["r","g","b","a"],"properties":{"r":{"type":"integer","format":"int32","description":"Red value","minimum":0},"g":{"type":"integer","format":"int32","description":"Green value","minimum":0},"b":{"type":"integer","format":"int32","description":"Blue value","minimum":0},"a":{"type":"integer","format":"int32","description":"Alpha value","minimum":0}}},"CreateApiKeyRequest":{"type":"object","description":"Request to create a new api key","required":["name"],"properties":{"name":{"type":"string","description":"A descriptive name helping the user to identify the key","example":"Leech on my local machine"}}},"CreateAppRequest":{"type":"object","description":"Create a new oauth application","required":["name","redirect_uri"],"properties":{"name":{"type":"string","description":"The name of the application","example":"Trustworthy application"},"redirect_uri":{"type":"string","description":"The redirect url of the application","example":"http://127.0.0.1:8080"}}},"CreateDomainRequest":{"type":"object","description":"The request to manually add a domain","required":["domain"],"properties":{"domain":{"type":"string","description":"The domain to add","example":"kraken.test"}}},"CreateGlobalTagRequest":{"type":"object","description":"The request to create a global tag","required":["name","color"],"properties":{"name":{"type":"string","description":"Name of the tag"},"color":{"$ref":"#/components/schemas/Color"}}},"CreateHostRequest":{"type":"object","description":"The request to manually add a host","required":["ip_addr","certainty"],"properties":{"ip_addr":{"type":"string","description":"The host's ip address","example":"127.0.0.1"},"certainty":{"$ref":"#/components/schemas/ManualHostCertainty"}}},"CreateLeechRequest":{"type":"object","description":"The request to create a new leech","required":["name","address"],"properties":{"name":{"type":"string","description":"Name of the leech","example":"leech-01"},"address":{"type":"string","description":"Address of the leech with schema","example":"https://10.13.37:8081"},"description":{"type":"string","description":"Description of the leech","example":"The first leech in a private net","nullable":true}}},"CreatePortRequest":{"type":"object","description":"The request to manually add a port","required":["ip_addr","port","certainty","protocol"],"properties":{"ip_addr":{"type":"string","description":"The ip address the port is open on","example":"127.0.0.1"},"port":{"type":"integer","format":"int32","description":"The port to add","example":"8080","minimum":0},"certainty":{"$ref":"#/components/schemas/ManualPortCertainty"},"protocol":{"$ref":"#/components/schemas/PortProtocol"}}},"CreateServiceRequest":{"type":"object","description":"The request to manually add a service","required":["name","certainty","host"],"properties":{"name":{"type":"string","description":"The service's name","example":"django"},"certainty":{"$ref":"#/components/schemas/ManualServiceCertainty"},"host":{"type":"string","description":"The ip address the service runs on","example":"127.0.0.1"},"port":{"type":"integer","format":"int32","description":"An optional port the service runs on","example":"8080","nullable":true,"minimum":0}}},"CreateUserRequest":{"type":"object","description":"The request to create a user","required":["username","display_name","password","permission"],"properties":{"username":{"type":"string","description":"The username","example":"user123"},"display_name":{"type":"string","description":"The displayname","example":"Anon"},"password":{"type":"string","description":"The password that should be set","example":"super-secure-password"},"permission":{"$ref":"#/components/schemas/UserPermission"}}},"CreateWordlistRequest":{"type":"object","description":"Arguments for creating a new wordlist","required":["name","description","path"],"properties":{"name":{"type":"string","description":"The wordlist's name to be displayed select buttons","example":"subdomains-top1million-5000.txt"},"description":{"type":"string","description":"A description explaining the wordlist's intended use case","example":"List of 5000 subdomains"},"path":{"type":"string","description":"The file path the wordlist is deployed under on each leech","example":"/opt/wordlists/Discovery/DNS/subdomains-top1million-5000.txt"}}},"CreateWorkspaceRequest":{"type":"object","description":"The request to create a new workspace","required":["name"],"properties":{"name":{"type":"string","description":"The name of the workspace","example":"secure-workspace"},"description":{"type":"string","description":"The description of the workspace","example":"This workspace is super secure and should not be looked at!!","nullable":true}}},"CreateWorkspaceTagRequest":{"type":"object","description":"The request to create a workspace tag","required":["name","color"],"properties":{"name":{"type":"string","description":"Name of the tag"},"color":{"$ref":"#/components/schemas/Color"}}},"DnsResolutionRequest":{"type":"object","description":"Request to resolve domains","required":["targets","concurrent_limit","workspace_uuid"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"targets":{"type":"array","items":{"type":"string"},"description":"The domains to resolve","example":["example.com","example.org"]},"concurrent_limit":{"type":"integer","format":"int32","description":"The concurrent task limit","example":2,"minimum":0},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"DnsResolutionResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SimpleDnsResolutionResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"DomainCertainty":{"type":"string","description":"The certainty of a domain","enum":["Unverified","Verified"]},"DomainOrNetwork":{"oneOf":[{"type":"string","description":"A ip address / network","example":"10.13.37.10"},{"type":"string","description":"A domain name","example":"kraken.test"}],"description":"Either an ip address / network or a domain name"},"DomainResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullDomain"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"FinishRegisterRequest":{"allOf":[{"type":"object","description":"The public key credentials register request"},{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Name of the key","example":"my-security-key-01"}}}],"description":"The request to finish the registration of a security key"},"FullAggregationSource":{"type":"object","description":"All data sources which contributed to an aggregated model","required":["attacks","manual_insert"],"properties":{"attacks":{"type":"array","items":{"$ref":"#/components/schemas/SourceAttack"},"description":"All attack which contributed to an aggregated model"},"manual_insert":{"type":"array","items":{"$ref":"#/components/schemas/ManualInsert"},"description":"All manual inserts which contributed to an aggregated model"}}},"FullApiKey":{"type":"object","description":"A representation of a full api key","required":["uuid","name","key"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The key's identifier"},"name":{"type":"string","description":"A descriptive name helping the user to identify the key","example":"Leech on my local machine"},"key":{"type":"string","description":"The actual key's value","example":"fsn83r0jfis84nfthw..."}}},"FullDomain":{"type":"object","description":"A full representation of a domain in a workspace","required":["uuid","domain","comment","workspace","tags","sources","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the domain"},"domain":{"type":"string","description":"The domain's name","example":"example.com"},"comment":{"type":"string","description":"A comment","example":"This is a important domain!"},"workspace":{"type":"string","format":"uuid","description":"The workspace this domain is in"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTag"},"description":"The list of tags this domain has attached to"},"sources":{"$ref":"#/components/schemas/SimpleAggregationSource"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"FullGlobalTag":{"type":"object","description":"The full representation of a full","required":["uuid","name","color"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the tag"},"name":{"type":"string","description":"The name of the tag"},"color":{"$ref":"#/components/schemas/Color"}}},"FullHost":{"type":"object","description":"The full representation of a host","required":["uuid","ip_addr","os_type","comment","workspace","tags","sources","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the host"},"ip_addr":{"type":"string","description":"The ip address of the host","example":"172.0.0.1"},"os_type":{"$ref":"#/components/schemas/OsType"},"comment":{"type":"string","description":"A comment"},"workspace":{"type":"string","format":"uuid","description":"The workspace this host is in"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTag"},"description":"The list of tags this host has attached to"},"sources":{"$ref":"#/components/schemas/SimpleAggregationSource"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"FullOauthClient":{"type":"object","description":"A complete version of a workspace","required":["uuid","name","redirect_uri","secret"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the client"},"name":{"type":"string","description":"The name of the client","example":"Trustworthy application"},"redirect_uri":{"type":"string","description":"The redirect url of the client","example":"http://127.0.0.1:8080"},"secret":{"type":"string","description":"The secret of the client","example":"IPSPL29BSDw5HFir5LYamdlm6SiaBdwx"}}},"FullOauthDecision":{"type":"object","description":"A user's remembered oauth decision","required":["uuid","app","workspace","action"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"app":{"type":"string","description":"The application the decision was made for"},"workspace":{"$ref":"#/components/schemas/SimpleWorkspace"},"action":{"type":"string","description":"Action what to do with new oauth requests","enum":["Accept","Deny"]}}},"FullPort":{"type":"object","description":"The full representation of a port","required":["uuid","port","protocol","host","comment","tags","workspace","sources","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"Uuid of the port"},"port":{"type":"integer","format":"int32","description":"Port number","example":1337,"minimum":0},"protocol":{"$ref":"#/components/schemas/PortProtocol"},"host":{"$ref":"#/components/schemas/SimpleHost"},"comment":{"type":"string","description":"A comment to the port"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTag"},"description":"The tags this port is linked to"},"workspace":{"type":"string","format":"uuid","description":"The workspace this port is linked to"},"sources":{"$ref":"#/components/schemas/SimpleAggregationSource"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"FullQueryCertificateTransparencyResult":{"type":"object","description":"A simple representation of a query certificate transparency result","required":["uuid","attack","created_at","issuer_name","common_name","value_names","serial_number"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"issuer_name":{"type":"string","description":"The name of the issuer"},"common_name":{"type":"string","description":"The common name of the certificate"},"value_names":{"type":"array","items":{"type":"string"},"description":"The values of the certificate"},"not_before":{"type":"string","format":"date-time","description":"The start date of the certificate","nullable":true},"not_after":{"type":"string","format":"date-time","description":"The end date of the certificate","nullable":true},"serial_number":{"type":"string","description":"The serial number of the certificate"}}},"FullService":{"type":"object","description":"A full representation of a service","required":["uuid","name","certainty","host","comment","workspace","tags","sources","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"Uuid of the service"},"name":{"type":"string","description":"The service's name","example":"postgresql"},"version":{"type":"string","description":"An optional version of the running service","example":"13.0.1","nullable":true},"certainty":{"$ref":"#/components/schemas/ServiceCertainty"},"host":{"$ref":"#/components/schemas/SimpleHost"},"port":{"allOf":[{"$ref":"#/components/schemas/SimplePort"}],"nullable":true},"comment":{"type":"string","description":"A comment to the service","example":"Holds all relevant information"},"workspace":{"type":"string","format":"uuid","description":"The workspace this service is linked to"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTag"},"description":"The tags this service is linked to"},"sources":{"$ref":"#/components/schemas/SimpleAggregationSource"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"FullServiceDetectionResult":{"type":"object","description":"A simple representation of a service detection result","required":["uuid","attack","created_at","certainty","service_names","host","port"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"certainty":{"type":"string","description":"The certainty a service is detected","enum":["Historical","SupposedTo","MaybeVerified","DefinitelyVerified"]},"service_names":{"type":"array","items":{"type":"string"},"description":"The found names of the service"},"host":{"type":"string","description":"The ip address a port was found on","example":"127.0.0.1"},"port":{"type":"integer","format":"int32","description":"Port number","minimum":0}}},"FullUser":{"type":"object","description":"A single user representation","required":["uuid","username","display_name","permission","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the user"},"username":{"type":"string","description":"The username of the user","example":"user123"},"display_name":{"type":"string","description":"The displayname of the user","example":"Anon"},"permission":{"$ref":"#/components/schemas/UserPermission"},"created_at":{"type":"string","format":"date-time","description":"The point in time this user was created"},"last_login":{"type":"string","format":"date-time","description":"The last point in time when the user has logged in","nullable":true}}},"FullWordlist":{"type":"object","description":"A wordlist including its `path` field only meant for admins","required":["uuid","name","description","path"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the wordlist"},"name":{"type":"string","description":"The wordlist's name to be displayed select buttons","example":"subdomains-top1million-5000.txt"},"description":{"type":"string","description":"A description explaining the wordlist's intended use case","example":"List of 5000 subdomains"},"path":{"type":"string","description":"The file path the wordlist is deployed under on each leech","example":"/opt/wordlists/Discovery/DNS/subdomains-top1million-5000.txt"}}},"FullWorkspace":{"type":"object","description":"A full version of a workspace","required":["uuid","name","owner","attacks","members","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the workspace"},"name":{"type":"string","description":"The name of the workspace","example":"ultra-secure-workspace"},"description":{"type":"string","description":"The description of the workspace","example":"This workspace is ultra secure and should not be looked at!!","nullable":true},"owner":{"$ref":"#/components/schemas/SimpleUser"},"attacks":{"type":"array","items":{"$ref":"#/components/schemas/SimpleAttack"},"description":"The attacks linked to this workspace"},"members":{"type":"array","items":{"$ref":"#/components/schemas/SimpleUser"},"description":"The member of the workspace"},"created_at":{"type":"string","format":"date-time","description":"The point in time the workspace was created"}}},"FullWorkspaceInvitation":{"type":"object","description":"The full representation of an invitation to a workspace","required":["uuid","workspace","from","target"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the invitation"},"workspace":{"$ref":"#/components/schemas/SimpleWorkspace"},"from":{"$ref":"#/components/schemas/SimpleUser"},"target":{"$ref":"#/components/schemas/SimpleUser"}}},"FullWorkspaceTag":{"type":"object","description":"The full representation of a full workspace tag","required":["uuid","name","color","workspace"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the workspace tag"},"name":{"type":"string","description":"The name of the tag","example":"seems broken"},"color":{"$ref":"#/components/schemas/Color"},"workspace":{"type":"string","format":"uuid","description":"The workspace this tag is linked to"}}},"GetAllDomainsQuery":{"allOf":[{"$ref":"#/components/schemas/PageParams"},{"type":"object","properties":{"host":{"type":"string","format":"uuid","description":"Only get domains pointing to a specific host\n\nThis includes domains which point to another domain which points to this host.","nullable":true},"global_filter":{"type":"string","description":"An optional general filter to apply","nullable":true},"domain_filter":{"type":"string","description":"An optional domain specific filter to apply","nullable":true}}}],"description":"Query parameters for filtering the domains to get"},"GetAllHostsQuery":{"allOf":[{"$ref":"#/components/schemas/PageParams"},{"type":"object","properties":{"global_filter":{"type":"string","description":"An optional general filter to apply","nullable":true},"host_filter":{"type":"string","description":"An optional host specific filter to apply","nullable":true}}}],"description":"Query parameters for filtering the hosts to get"},"GetAllPortsQuery":{"allOf":[{"$ref":"#/components/schemas/PageParams"},{"type":"object","properties":{"host":{"type":"string","format":"uuid","description":"Only get ports associated with a specific host","nullable":true},"global_filter":{"type":"string","description":"An optional general filter to apply","nullable":true},"port_filter":{"type":"string","description":"An optional port specific filter to apply","nullable":true}}}],"description":"Query parameters for filtering the ports to get"},"GetAllServicesQuery":{"allOf":[{"$ref":"#/components/schemas/PageParams"},{"type":"object","properties":{"host":{"type":"string","format":"uuid","description":"Only get services associated with a specific host","nullable":true},"global_filter":{"type":"string","description":"An optional general filter to apply","nullable":true},"service_filter":{"type":"string","description":"An optional service specific filter to apply","nullable":true}}}],"description":"Query parameters for filtering the services to get"},"HostAliveResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SimpleHostAliveResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"HostCertainty":{"type":"string","description":"The certainty of a host","enum":["Historical","SupposedTo","Verified"]},"HostResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullHost"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"HostsAliveRequest":{"type":"object","description":"Host Alive check request","required":["targets","timeout","concurrent_limit","workspace_uuid"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"targets":{"type":"array","items":{"type":"string"},"description":"The ip addresses / networks or domains to scan","example":["10.13.37.1","10.13.37.0/24","google.com"]},"timeout":{"type":"integer","format":"int64","description":"The time to wait until a host is considered down.\n\nThe timeout is specified in milliseconds.","example":3000,"minimum":0},"concurrent_limit":{"type":"integer","format":"int32","description":"The concurrent task limit","example":30,"minimum":0},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"InviteToWorkspaceRequest":{"type":"object","description":"The request to invite a user to the workspace","required":["user"],"properties":{"user":{"type":"string","format":"uuid","description":"The user to invite"}}},"LeechConfig":{"allOf":[{"$ref":"#/components/schemas/LeechTlsConfig"},{"type":"object","required":["secret"],"properties":{"secret":{"type":"string","description":"The secret of the leech"}}}],"description":"The configuration of a leech"},"LeechTlsConfig":{"type":"object","description":"The tls related part of a leech's config","required":["ca","cert","key","sni"],"properties":{"ca":{"type":"string","description":"PEM encoded CA managed by kraken"},"cert":{"type":"string","description":"PEM encoded certificate"},"key":{"type":"string","description":"PEM encoded private key for the certificate"},"sni":{"type":"string","description":"The randomly generated fake domain for the kraken to be used for sni"}}},"ListApiKeys":{"type":"object","description":"The response that contains all api keys","required":["keys"],"properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/FullApiKey"},"description":"The list of api keys"}}},"ListAttacks":{"type":"object","description":"A list of attacks","required":["attacks"],"properties":{"attacks":{"type":"array","items":{"$ref":"#/components/schemas/SimpleAttack"},"description":"The list of the attacks"}}},"ListFullUsers":{"type":"object","description":"The response of all users","required":["users"],"properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/FullUser"},"description":"The list of full users"}}},"ListGlobalTags":{"type":"object","description":"The response to a request to retrieve all global tags","required":["global_tags"],"properties":{"global_tags":{"type":"array","items":{"$ref":"#/components/schemas/FullGlobalTag"},"description":"List of global tags"}}},"ListLeeches":{"type":"object","description":"The response that hold all leeches","required":["leeches"],"properties":{"leeches":{"type":"array","items":{"$ref":"#/components/schemas/SimpleLeech"},"description":"The list of leeches"}}},"ListOauthApplications":{"type":"object","description":"List all oauth applications","required":["apps"],"properties":{"apps":{"type":"array","items":{"$ref":"#/components/schemas/FullOauthClient"},"description":"The list of applications"}}},"ListOauthDecisions":{"type":"object","description":"Response holding a user's oauth decisions","required":["decisions"],"properties":{"decisions":{"type":"array","items":{"$ref":"#/components/schemas/FullOauthDecision"},"description":"A user's oauth decisions"}}},"ListUsers":{"type":"object","description":"The response with all users","required":["users"],"properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/SimpleUser"},"description":"List of users"}}},"ListWordlists":{"type":"object","description":"Response containing all wordlists","required":["wordlists"],"properties":{"wordlists":{"type":"array","items":{"$ref":"#/components/schemas/SimpleWordlist"},"description":"List of all wordlists"}}},"ListWordlistsAdmin":{"type":"object","description":"Response containing all wordlists including their `path` fields","required":["wordlists"],"properties":{"wordlists":{"type":"array","items":{"$ref":"#/components/schemas/FullWordlist"},"description":"List of all wordlists including their `path` fields"}}},"ListWorkspaceTags":{"type":"object","description":"The response to a request to retrieve all workspace tags","required":["workspace_tags"],"properties":{"workspace_tags":{"type":"array","items":{"$ref":"#/components/schemas/FullWorkspaceTag"},"description":"Workspace tags"}}},"ListWorkspaces":{"type":"object","description":"The response to retrieve a list of workspaces","required":["workspaces"],"properties":{"workspaces":{"type":"array","items":{"$ref":"#/components/schemas/SimpleWorkspace"},"description":"The list of workspaces"}}},"LoginRequest":{"type":"object","description":"The request to login","required":["username","password"],"properties":{"username":{"type":"string","description":"The username that should be used for login","example":"user123"},"password":{"type":"string","description":"The password that should be used for login","example":"super-secure-password"}}},"ManualHostCertainty":{"type":"string","description":"The certainty of a manually added host","enum":["Historical","SupposedTo"]},"ManualInsert":{"oneOf":[{"type":"object","description":"A manually inserted domain","required":["domain","user","workspace","created_at","type"],"properties":{"domain":{"type":"string","description":"The inserted domain"},"user":{"$ref":"#/components/schemas/SimpleUser"},"workspace":{"type":"string","format":"uuid","description":"The workspace the domain was inserted to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the domain was inserted"},"type":{"type":"string","enum":["Domain"]}}},{"type":"object","description":"A manually inserted host","required":["ip_addr","os_type","certainty","user","workspace","created_at","type"],"properties":{"ip_addr":{"type":"string","description":"The host's ip address","example":"172.0.0.1"},"os_type":{"$ref":"#/components/schemas/OsType"},"certainty":{"$ref":"#/components/schemas/ManualHostCertainty"},"user":{"$ref":"#/components/schemas/SimpleUser"},"workspace":{"type":"string","format":"uuid","description":"The workspace the host was inserted to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the host was inserted"},"type":{"type":"string","enum":["Host"]}}},{"type":"object","description":"A manually inserted port","required":["port","protocol","certainty","host","user","workspace","created_at","type"],"properties":{"port":{"type":"integer","format":"int32","description":"The inserted port","minimum":0},"protocol":{"$ref":"#/components/schemas/PortProtocol"},"certainty":{"$ref":"#/components/schemas/ManualPortCertainty"},"host":{"type":"string","description":"The host's ip address","example":"172.0.0.1"},"user":{"$ref":"#/components/schemas/SimpleUser"},"workspace":{"type":"string","format":"uuid","description":"The workspace the port was inserted to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the port was inserted"},"type":{"type":"string","enum":["Port"]}}},{"type":"object","description":"A manually inserted service","required":["name","certainty","host","user","workspace","created_at","type"],"properties":{"name":{"type":"string","description":"The inserted service"},"version":{"type":"string","description":"The service's version","nullable":true},"certainty":{"$ref":"#/components/schemas/ManualServiceCertainty"},"port":{"type":"integer","format":"int32","description":"The service's port","nullable":true,"minimum":0},"host":{"type":"string","description":"The host's ip address","example":"172.0.0.1"},"user":{"$ref":"#/components/schemas/SimpleUser"},"workspace":{"type":"string","format":"uuid","description":"The workspace the service was inserted to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the service was inserted"},"type":{"type":"string","enum":["Service"]}}}],"description":"The different types of manual inserts","discriminator":{"propertyName":"type"}},"ManualPortCertainty":{"type":"string","description":"The certainty of a manually added port","enum":["Historical","SupposedTo"]},"ManualServiceCertainty":{"type":"string","description":"The certainty of a manually added service","enum":["Historical","SupposedTo"]},"OpenRequestInfo":{"type":"object","description":"The information about an oauth request","required":["workspace","oauth_application"],"properties":{"workspace":{"$ref":"#/components/schemas/SimpleWorkspace"},"oauth_application":{"$ref":"#/components/schemas/SimpleOauthClient"}}},"OsType":{"type":"string","description":"A representation of an OS type","enum":["Unknown","Linux","Windows","Apple","Android","FreeBSD"]},"PageParams":{"type":"object","description":"Query parameters for paginated data","required":["limit","offset"],"properties":{"limit":{"type":"integer","format":"int64","description":"Number of items to retrieve","minimum":0},"offset":{"type":"integer","format":"int64","description":"Position in the whole list to start retrieving from","minimum":0}}},"PortCertainty":{"type":"string","description":"The certainty states of a port","enum":["Historical","SupposedTo","Verified"]},"PortOrRange":{"oneOf":[{"type":"integer","format":"int32","description":"A single port","example":8000,"minimum":0},{"type":"string","description":"In inclusive range of ports","example":"1-1024"}],"description":"Single port or a range of ports"},"PortProtocol":{"type":"string","description":"A protocol of a port","enum":["Unknown","Tcp","Udp","Sctp"]},"PortResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullPort"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"Query":{"oneOf":[{"type":"object","required":["Email"],"properties":{"Email":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["IpAddress"],"properties":{"IpAddress":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Username"],"properties":{"Username":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Password"],"properties":{"Password":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["HashedPassword"],"properties":{"HashedPassword":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Name"],"properties":{"Name":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Domain"],"properties":{"Domain":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Vin"],"properties":{"Vin":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Phone"],"properties":{"Phone":{"$ref":"#/components/schemas/SearchType"}}},{"type":"object","required":["Address"],"properties":{"Address":{"$ref":"#/components/schemas/SearchType"}}}],"description":"A query for dehashed"},"QueryCertificateTransparencyRequest":{"type":"object","description":"The settings to configure a certificate transparency request","required":["target","include_expired","max_retries","retry_interval","workspace_uuid"],"properties":{"target":{"type":"string","description":"Domain to query certificates for","example":"example.com"},"include_expired":{"type":"boolean","description":"Should expired certificates be included as well","example":true},"max_retries":{"type":"integer","format":"int32","description":"The number of times the query should be retried if it failed.","example":3,"minimum":0},"retry_interval":{"type":"integer","format":"int64","description":"The interval that should be waited between retries.\n\nThe interval is specified in milliseconds.","example":500,"minimum":0},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"QueryCertificateTransparencyResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullQueryCertificateTransparencyResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"QueryDehashedRequest":{"type":"object","description":"The request to query the dehashed API","required":["query","workspace_uuid"],"properties":{"query":{"$ref":"#/components/schemas/Query"},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"QueryUnhashedResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SimpleQueryUnhashedResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"ScanTcpPortsRequest":{"type":"object","description":"The settings to configure a tcp port scan","required":["targets","retry_interval","max_retries","timeout","concurrent_limit","skip_icmp_check","workspace_uuid"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"targets":{"type":"array","items":{"type":"string"},"description":"The ip addresses / networks or domains to scan","example":["10.13.37.1","10.13.37.0/24","google.com"]},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortOrRange"},"description":"List of single ports and port ranges\n\nIf no values are supplied, 1-65535 is used as default"},"retry_interval":{"type":"integer","format":"int64","description":"The interval that should be wait between retries on a port.\n\nThe interval is specified in milliseconds.","example":100,"minimum":0},"max_retries":{"type":"integer","format":"int32","description":"The number of times the connection should be retried if it failed.","example":2,"minimum":0},"timeout":{"type":"integer","format":"int64","description":"The time to wait until a connection is considered failed.\n\nThe timeout is specified in milliseconds.","example":3000,"minimum":0},"concurrent_limit":{"type":"integer","format":"int32","description":"The concurrent task limit","example":5000,"minimum":0},"skip_icmp_check":{"type":"boolean","description":"Skips the initial icmp check.\n\nAll hosts are assumed to be reachable","example":false},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"SearchEntry":{"type":"object","description":"Searched entry","required":["uuid","created_at","search_term"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the search"},"created_at":{"type":"string","format":"date-time","description":"The point in time this search was created"},"finished_at":{"type":"string","format":"date-time","description":"The point in time this search was finished","nullable":true},"search_term":{"type":"string","description":"The search term that was used"}}},"SearchResultEntry":{"oneOf":[{"type":"object","required":["HostEntry"],"properties":{"HostEntry":{"$ref":"#/components/schemas/SimpleHost"}}},{"type":"object","required":["ServiceEntry"],"properties":{"ServiceEntry":{"$ref":"#/components/schemas/SimpleService"}}},{"type":"object","required":["PortEntry"],"properties":{"PortEntry":{"$ref":"#/components/schemas/SimplePort"}}},{"type":"object","required":["DomainEntry"],"properties":{"DomainEntry":{"$ref":"#/components/schemas/SimpleDomain"}}},{"type":"object","required":["DnsRecordResultEntry"],"properties":{"DnsRecordResultEntry":{"$ref":"#/components/schemas/SimpleDnsResolutionResult"}}},{"type":"object","required":["TcpPortScanResultEntry"],"properties":{"TcpPortScanResultEntry":{"$ref":"#/components/schemas/SimpleTcpPortScanResult"}}},{"type":"object","required":["DehashedQueryResultEntry"],"properties":{"DehashedQueryResultEntry":{"$ref":"#/components/schemas/SimpleQueryUnhashedResult"}}},{"type":"object","required":["CertificateTransparencyResultEntry"],"properties":{"CertificateTransparencyResultEntry":{"$ref":"#/components/schemas/FullQueryCertificateTransparencyResult"}}},{"type":"object","required":["HostAliveResult"],"properties":{"HostAliveResult":{"$ref":"#/components/schemas/SimpleHostAliveResult"}}},{"type":"object","required":["ServiceDetectionResult"],"properties":{"ServiceDetectionResult":{"$ref":"#/components/schemas/FullServiceDetectionResult"}}}],"description":"Dynamic result of a search"},"SearchResultPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SearchResultEntry"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"SearchType":{"oneOf":[{"type":"object","required":["Simple"],"properties":{"Simple":{"type":"string","description":"Search for a simple pattern"}}},{"type":"object","required":["Exact"],"properties":{"Exact":{"type":"string","description":"Search for an exact pattern"}}},{"type":"object","required":["Regex"],"properties":{"Regex":{"type":"string","description":"A regex search pattern"}}},{"type":"object","required":["Or"],"properties":{"Or":{"type":"array","items":{"$ref":"#/components/schemas/SearchType"},"description":"Add multiple [SearchType]s with an OR"}}},{"type":"object","required":["And"],"properties":{"And":{"type":"array","items":{"$ref":"#/components/schemas/SearchType"},"description":"Add multiple [SearchType]s with an AND"}}}],"description":"A specific search type"},"SearchWorkspaceRequest":{"type":"object","description":"Request to search the workspace","required":["search_term"],"properties":{"search_term":{"type":"string","description":"the term to search for"}}},"SearchesResultPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SearchEntry"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"ServiceCertainty":{"type":"string","description":"The certainty a service is detected","enum":["Historical","SupposedTo","MaybeVerified","DefinitelyVerified"]},"ServiceDetectionRequest":{"type":"object","description":"The request to start a service detection","required":["address","port","timeout","workspace_uuid"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"address":{"type":"string","description":"The ip address the service listens on","example":"10.13.37.1"},"port":{"type":"integer","format":"int32","description":"The port the service listens on","example":443,"minimum":0},"timeout":{"type":"integer","format":"int64","description":"Time to wait for a response after sending the payload\n(or after establishing a connection, if not payload is to be sent)\n\nThe timeout is specified in milliseconds.","example":3000,"minimum":0},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"}}},"ServiceDetectionResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullServiceDetectionResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"ServiceResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FullService"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"SetPasswordRequest":{"type":"object","description":"The request to set a new password for a user","required":["current_password","new_password"],"properties":{"current_password":{"type":"string","description":"The current password","example":"super-secure-password"},"new_password":{"type":"string","description":"The new password","example":"ultra-secure-password!1!1!"}}},"SettingsFull":{"type":"object","description":"The live settings of kraken","required":["mfa_required","oidc_initial_permission_level","created_at"],"properties":{"mfa_required":{"type":"boolean","description":"Require mfa for local users"},"oidc_initial_permission_level":{"$ref":"#/components/schemas/UserPermission"},"dehashed_email":{"type":"string","description":"The email for the dehashed account","example":"foo@example.com","nullable":true},"dehashed_api_key":{"type":"string","description":"The api key for the dehashed account","example":"1231kb3kkb51kj31kjb231kj3b1jk23bkj123","nullable":true},"created_at":{"type":"string","format":"date-time","description":"The point in time the settings were created"}}},"SimpleAggregationSource":{"type":"object","description":"Numbers how many attacks of a certain kind found an aggregated model","required":["bruteforce_subdomains","tcp_port_scan","query_certificate_transparency","query_dehashed","host_alive","service_detection","dns_resolution","forced_browsing","os_detection","anti_port_scanning_detection","udp_port_scan","version_detection","test_ssl","manual"],"properties":{"bruteforce_subdomains":{"type":"integer","description":"Bruteforce subdomains via DNS requests","minimum":0},"tcp_port_scan":{"type":"integer","description":"Scan tcp ports","minimum":0},"query_certificate_transparency":{"type":"integer","description":"Query certificate transparency","minimum":0},"query_dehashed":{"type":"integer","description":"Query the dehashed API","minimum":0},"host_alive":{"type":"integer","description":"Check if a host is reachable via icmp","minimum":0},"service_detection":{"type":"integer","description":"Detect the service that is running on a port","minimum":0},"dns_resolution":{"type":"integer","description":"Resolve domain names","minimum":0},"forced_browsing":{"type":"integer","description":"Perform forced browsing","minimum":0},"os_detection":{"type":"integer","description":"Detect the OS of the target","minimum":0},"anti_port_scanning_detection":{"type":"integer","description":"Detect if anti-port scanning techniques are in place","minimum":0},"udp_port_scan":{"type":"integer","description":"Scan udp ports","minimum":0},"version_detection":{"type":"integer","description":"Perform version detection","minimum":0},"test_ssl":{"type":"integer","description":"Ran `testssl.sh`","minimum":0},"manual":{"type":"boolean","description":"Manually inserted"}}},"SimpleAttack":{"type":"object","description":"A simple version of an attack","required":["uuid","workspace","attack_type","started_by","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The identifier of the attack"},"workspace":{"$ref":"#/components/schemas/SimpleWorkspace"},"attack_type":{"$ref":"#/components/schemas/AttackType"},"started_by":{"$ref":"#/components/schemas/SimpleUser"},"finished_at":{"type":"string","format":"date-time","description":"If this is None, the attack is still running","nullable":true},"error":{"type":"string","description":"If this field is set, the attack has finished with an error","nullable":true},"created_at":{"type":"string","format":"date-time","description":"The point in time this attack was started"}}},"SimpleBruteforceSubdomainsResult":{"type":"object","description":"A simple representation of a bruteforce subdomains result","required":["uuid","attack","created_at","source","destination","dns_record_type"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"source":{"type":"string","description":"The source address"},"destination":{"type":"string","description":"The destination address"},"dns_record_type":{"type":"string","description":"The type of DNS Record","enum":["A","Aaaa","Caa","Cname","Mx","Tlsa","Txt"]}}},"SimpleDnsResolutionResult":{"type":"object","description":"A simple representation of a dns resolution result","required":["uuid","attack","created_at","source","destination","dns_record_type"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"source":{"type":"string","description":"The source address"},"destination":{"type":"string","description":"The destination address"},"dns_record_type":{"type":"string","description":"The type of DNS Record","enum":["A","Aaaa","Caa","Cname","Mx","Tlsa","Txt"]}}},"SimpleDomain":{"type":"object","description":"A simple representation of a domain in a workspace","required":["uuid","domain","comment","workspace","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the domain"},"domain":{"type":"string","description":"The domain name","example":"example.com"},"comment":{"type":"string","description":"The comment to the domain","example":"This is a important domain!"},"workspace":{"type":"string","format":"uuid","description":"The workspace this domain is linked to"},"created_at":{"type":"string","format":"date-time","description":"The point in time this domain was created"}}},"SimpleHost":{"type":"object","description":"The simple representation of a host","required":["uuid","ip_addr","os_type","comment","workspace","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the host"},"ip_addr":{"type":"string","description":"The ip address of the host","example":"172.0.0.1"},"os_type":{"$ref":"#/components/schemas/OsType"},"comment":{"type":"string","description":"A comment"},"workspace":{"type":"string","format":"uuid","description":"The workspace this host is in"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"SimpleHostAliveResult":{"type":"object","description":"A simple representation of a host alive result","required":["uuid","attack","created_at","host"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"host":{"type":"string","description":"A host that responded","example":"127.0.0.1"}}},"SimpleLeech":{"type":"object","description":"The simple representation of a leech","required":["uuid","name","address"],"properties":{"uuid":{"type":"string","format":"uuid","description":"uuid of the leech"},"name":{"type":"string","description":"Name of the leech","example":"leech-01"},"address":{"type":"string","description":"Address of the leech","example":"https://10.13.37.1:8081"}}},"SimpleOauthClient":{"type":"object","description":"A simple (secret-less) version of a workspace","required":["uuid","name","redirect_uri"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the client"},"name":{"type":"string","description":"The name of the client","example":"Trustworthy application"},"redirect_uri":{"type":"string","description":"The redirect url of the client","example":"http://127.0.0.1:8080"}}},"SimplePort":{"type":"object","description":"The simple representation of a port","required":["uuid","port","protocol","host","comment","workspace","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"Uuid of the port"},"port":{"type":"integer","format":"int32","description":"Port number","example":1337,"minimum":0},"protocol":{"$ref":"#/components/schemas/PortProtocol"},"host":{"type":"string","format":"uuid","description":"The host this port is assigned to"},"comment":{"type":"string","description":"A comment to the port"},"workspace":{"type":"string","format":"uuid","description":"The workspace this port is linked to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"SimpleQueryUnhashedResult":{"type":"object","description":"A simple representation of a query unhashed result","required":["uuid","attack","created_at","dehashed_id","ip_address"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"dehashed_id":{"type":"integer","format":"int64","description":"ID of the entry"},"email":{"type":"string","description":"An email address","nullable":true},"username":{"type":"string","description":"An username","nullable":true},"password":{"type":"string","description":"A password","nullable":true},"hashed_password":{"type":"string","description":"An hashed password","nullable":true},"ip_address":{"type":"string","description":"An ip address","example":"127.0.0.1"},"name":{"type":"string","description":"A name","nullable":true},"vin":{"type":"string","description":"A vin","nullable":true},"address":{"type":"string","description":"An address","nullable":true},"phone":{"type":"string","description":"A phone number","nullable":true},"database_name":{"type":"string","description":"A database name","nullable":true}}},"SimpleService":{"type":"object","description":"A simple representation of a service","required":["uuid","name","host","comment","workspace","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the service"},"name":{"type":"string","description":"The name of the service","example":"postgresql"},"version":{"type":"string","description":"The version of the service","example":"13.0.1","nullable":true},"host":{"type":"string","format":"uuid","description":"The host this service is linked to"},"port":{"type":"string","format":"uuid","description":"The port this service may linked to","nullable":true},"comment":{"type":"string","description":"The comment attached to the service","example":"Holds all relevant information"},"workspace":{"type":"string","format":"uuid","description":"The workspace is service is linked to"},"created_at":{"type":"string","format":"date-time","description":"The point in time, the record was created"}}},"SimpleTag":{"type":"object","description":"A simple tag","required":["uuid","name","color","tag_type"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the tag"},"name":{"type":"string","description":"The name of the tag"},"color":{"$ref":"#/components/schemas/Color"},"tag_type":{"$ref":"#/components/schemas/TagType"}}},"SimpleTcpPortScanResult":{"type":"object","description":"A simple representation of a tcp port scan result","required":["uuid","attack","created_at","address","port"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"address":{"type":"string","description":"The ip address a port was found on","example":"127.0.0.1"},"port":{"type":"integer","format":"int32","description":"The found port","minimum":0}}},"SimpleTestSSLResult":{"type":"object","description":"A simple representation of a testssl result","required":["uuid","attack","created_at","target_host","ip","port","rdns","service"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key"},"attack":{"type":"string","format":"uuid","description":"The attack which produced this result"},"created_at":{"type":"string","format":"date-time","description":"The point in time, this result was produced"},"target_host":{"type":"string","description":"The original user target this result belongs to"},"ip":{"type":"string","description":"The scanned ip address"},"port":{"type":"integer","format":"int32","description":"The scanned port","minimum":0},"rdns":{"type":"string","description":"The ip address' rDNS name"},"service":{"type":"string","description":"The detected service"}}},"SimpleUser":{"type":"object","description":"This struct holds the user information.\n\nNote that `username` is unique, but as it is changeable,\nidentify the user by its `uuid`","required":["uuid","username","display_name"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the user"},"username":{"type":"string","description":"The username of the user"},"display_name":{"type":"string","description":"The displayname of the user"}}},"SimpleWordlist":{"type":"object","description":"A wordlist without its `path` field","required":["uuid","name","description"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the wordlist"},"name":{"type":"string","description":"The wordlist's name to be displayed select buttons","example":"subdomains-top1million-5000.txt"},"description":{"type":"string","description":"A description explaining the wordlist's intended use case","example":"List of 5000 subdomains"}}},"SimpleWorkspace":{"type":"object","description":"A simple version of a workspace","required":["uuid","name","owner","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid of the workspace"},"name":{"type":"string","description":"The name of the workspace","example":"ultra-secure-workspace"},"description":{"type":"string","description":"The description of the workspace","example":"This workspace is ultra secure and should not be looked at!!","nullable":true},"owner":{"$ref":"#/components/schemas/SimpleUser"},"created_at":{"type":"string","format":"date-time","description":"The point in time the workspace was created"}}},"SourceAttack":{"allOf":[{"$ref":"#/components/schemas/SourceAttackResult"},{"type":"object","required":["uuid","workspace_uuid","started_by","created_at"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The identifier of the attack"},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace this attack is attached to"},"started_by":{"$ref":"#/components/schemas/SimpleUser"},"finished_at":{"type":"string","format":"date-time","description":"If this is None, the attack is still running","nullable":true},"error":{"type":"string","description":"If this field is set, the attack has finished with an error","nullable":true},"created_at":{"type":"string","format":"date-time","description":"The point in time this attack was started"}}}],"description":"Copy of [`SimpleAttack`](crate::api::handler::attacks::SimpleAttack) with an added `results` field"},"SourceAttackResult":{"oneOf":[{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["BruteforceSubdomains"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleBruteforceSubdomainsResult"},"description":"The [`AttackType::BruteforceSubdomains`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["TcpPortScan"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTcpPortScanResult"},"description":"The [`AttackType::TcpPortScan`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["QueryCertificateTransparency"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/FullQueryCertificateTransparencyResult"},"description":"The [`AttackType::QueryCertificateTransparency`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["QueryDehashed"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleQueryUnhashedResult"},"description":"The [`AttackType::QueryUnhashed`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["HostAlive"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleHostAliveResult"},"description":"The [`AttackType::HostAlive`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["ServiceDetection"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/FullServiceDetectionResult"},"description":"The [`AttackType::ServiceDetection`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["DnsResolution"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleDnsResolutionResult"},"description":"The [`AttackType::DnsResolution`] and its results"}}},{"type":"object","required":["attack_type","results"],"properties":{"attack_type":{"type":"string","enum":["TestSSL"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTestSSLResult"},"description":"The [`AttackType::TestSSL`] and its results"}}}],"description":"The different types of attack and their results","discriminator":{"propertyName":"attack_type"}},"StartTLSProtocol":{"type":"string","description":"Protocols to select from when using `--starttls`","enum":["FTP","SMTP","POP3","IMAP","XMPP","LMTP","NNTP","Postgres","MySQL"]},"TagType":{"type":"string","description":"The type of a tag","enum":["Workspace","Global"]},"TcpPortScanResultsPage":{"type":"object","description":"Response containing paginated data","required":["items","limit","offset","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SimpleTcpPortScanResult"},"description":"The page's items"},"limit":{"type":"integer","format":"int64","description":"The limit this page was retrieved with","example":50,"minimum":0},"offset":{"type":"integer","format":"int64","description":"The offset this page was retrieved with","example":0,"minimum":0},"total":{"type":"integer","format":"int64","description":"The total number of items this page is a subset of","minimum":0}}},"TestSSLRequest":{"type":"object","description":"Request to run testssl","required":["workspace_uuid","uri"],"properties":{"leech_uuid":{"type":"string","format":"uuid","description":"The leech to use\n\nLeave empty to use a random leech","nullable":true},"workspace_uuid":{"type":"string","format":"uuid","description":"The workspace to execute the attack in"},"uri":{"type":"string","description":"The domain to scan"},"connect_timeout":{"type":"integer","format":"int64","description":"Timeout for TCP handshakes in seconds","nullable":true,"minimum":0},"openssl_timeout":{"type":"integer","format":"int64","description":"Timeout for `openssl` connections in seconds","nullable":true,"minimum":0},"basic_auth":{"type":"array","items":{"type":"string"},"description":"Set the `BASICAUTH` header when checking http headers","nullable":true},"starttls":{"allOf":[{"$ref":"#/components/schemas/StartTLSProtocol"}],"nullable":true}}},"TransferWorkspaceRequest":{"type":"object","description":"The request to transfer a workspace to another account","required":["user"],"properties":{"user":{"type":"string","format":"uuid","description":"The uuid of the user that should receive the workspace"}}},"UpdateApiKeyRequest":{"type":"object","description":"The request to update an api key","required":["name"],"properties":{"name":{"type":"string","description":"A descriptive name helping the user to identify the key","example":"Leech on my local machine"}}},"UpdateAppRequest":{"type":"object","description":"Update an oauth application","properties":{"name":{"type":"string","description":"The name of the application","example":"Trustworthy application","nullable":true},"redirect_uri":{"type":"string","description":"The redirect url of the application","example":"http://127.0.0.1:8080","nullable":true}}},"UpdateDomainRequest":{"type":"object","description":"The request to update a domain","properties":{"comment":{"type":"string","description":"The comment of the domain","nullable":true},"global_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Global tags that are linked to the domain","nullable":true},"workspace_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Workspace tags that are linked to the domain","nullable":true}}},"UpdateGlobalTag":{"type":"object","description":"The request to update a global tag","properties":{"name":{"type":"string","description":"Name of the global tag","nullable":true},"color":{"allOf":[{"$ref":"#/components/schemas/Color"}],"nullable":true}}},"UpdateHostRequest":{"type":"object","description":"The request to update a host","properties":{"comment":{"type":"string","description":"The comment of a host","nullable":true},"global_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The global tags of a host","nullable":true},"workspace_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The workspace tags of a host","nullable":true}}},"UpdateLeechRequest":{"type":"object","description":"The request to update a leech","required":["address"],"properties":{"name":{"type":"string","description":"Name of the leech","example":"leech-01","nullable":true},"address":{"type":"string","description":"Address of the leech","example":"https://10.13.37.1:8081"},"description":{"type":"string","description":"Description of the leech","example":"First leech in a private network","nullable":true}}},"UpdateMeRequest":{"type":"object","description":"The request to update the own user\n\nAt least one of the options must be set","properties":{"username":{"type":"string","description":"The username","example":"cyber-user-123","nullable":true},"display_name":{"type":"string","description":"The displayname","example":"Cyberhacker","nullable":true}}},"UpdatePortRequest":{"type":"object","description":"The request to update a port","properties":{"comment":{"type":"string","description":"The comment of the port","nullable":true},"global_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Global tags that are linked to the port","nullable":true},"workspace_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Workspace tags that are linked to the port","nullable":true}}},"UpdateServiceRequest":{"type":"object","description":"The request to update a service","properties":{"comment":{"type":"string","description":"The comment of the service","nullable":true},"global_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The global tags that are attached to the service","nullable":true},"workspace_tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The workspace tags that are attached to the service","nullable":true}}},"UpdateSettingsRequest":{"type":"object","description":"The request to update the settings","required":["mfa_required","oidc_initial_permission_level"],"properties":{"mfa_required":{"type":"boolean","description":"Require mfa for local users"},"oidc_initial_permission_level":{"$ref":"#/components/schemas/UserPermission"},"dehashed_email":{"type":"string","description":"The email for the dehashed account","example":"foo@example.com","nullable":true},"dehashed_api_key":{"type":"string","description":"The api key for the dehashed account","example":"1231kb3kkb51kj31kjb231kj3b1jk23bkj123","nullable":true}}},"UpdateWordlistRequest":{"type":"object","description":"Arguments for updating an existing wordlist","required":["uuid"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The primary key of the wordlist to update"},"name":{"type":"string","description":"The wordlist's name to be displayed select buttons","example":"subdomains-top1million-5000.txt","nullable":true},"description":{"type":"string","description":"A description explaining the wordlist's intended use case","example":"List of 5000 subdomains","nullable":true},"path":{"type":"string","description":"The file path the wordlist is deployed under on each leech","example":"/opt/wordlists/Discovery/DNS/subdomains-top1million-5000.txt","nullable":true}}},"UpdateWorkspaceRequest":{"type":"object","description":"The request type to update a workspace\n\nAll parameter are optional, but at least one of them must be specified","properties":{"name":{"type":"string","description":"Name of the workspace","example":"Workspace for work","nullable":true},"description":{"type":"string","description":"Description of the workspace","example":"This workspace is for work and for work only!","nullable":true}}},"UpdateWorkspaceTag":{"type":"object","description":"The request to update a workspace tag","properties":{"name":{"type":"string","description":"Name of the tag","nullable":true},"color":{"allOf":[{"$ref":"#/components/schemas/Color"}],"nullable":true}}},"UserPermission":{"type":"string","description":"The permission of a user","enum":["ReadOnly","Default","Admin"]},"UuidResponse":{"type":"object","description":"A common response that contains a single uuid","required":["uuid"],"properties":{"uuid":{"type":"string","format":"uuid","description":"The uuid"}}},"WorkspaceInvitationList":{"type":"object","description":"A list of invitations to workspaces","required":["invitations"],"properties":{"invitations":{"type":"array","items":{"$ref":"#/components/schemas/FullWorkspaceInvitation"},"description":"All invitations of the current user"}}},"WsMessage":{"oneOf":[{"type":"object","description":"An invalid message was received.\n\nThis message type is sent to the client.","required":["type"],"properties":{"type":{"type":"string","enum":["InvalidMessage"]}}},{"type":"object","description":"An invitation to a workspace was issued","required":["invitation_uuid","workspace","from","type"],"properties":{"invitation_uuid":{"type":"string","format":"uuid","description":"The uuid of the invitation"},"workspace":{"$ref":"#/components/schemas/SimpleWorkspace"},"from":{"$ref":"#/components/schemas/SimpleUser"},"type":{"type":"string","enum":["InvitationToWorkspace"]}}},{"type":"object","description":"A notification about a started attack","required":["attack","type"],"properties":{"attack":{"$ref":"#/components/schemas/SimpleAttack"},"type":{"type":"string","enum":["AttackStarted"]}}},{"type":"object","description":"A notification about a finished attack","required":["attack","type"],"properties":{"attack":{"$ref":"#/components/schemas/SimpleAttack"},"type":{"type":"string","enum":["AttackFinished"]}}},{"type":"object","description":"A notification about a finished search","required":["search_uuid","finished_successful","type"],"properties":{"search_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the search"},"finished_successful":{"type":"boolean","description":"Whether the search was finished successfully"},"type":{"type":"string","enum":["SearchFinished"]}}},{"type":"object","description":"A notification about a search result","required":["search_uuid","result_uuid","type"],"properties":{"search_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the search results"},"result_uuid":{"type":"string","format":"uuid","description":"A result entry"},"type":{"type":"string","enum":["SearchNotify"]}}},{"type":"object","description":"A result for a subdomain enumeration using bruteforce DNS requests","required":["attack_uuid","source","destination","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"source":{"type":"string","description":"The source address that was queried"},"destination":{"type":"string","description":"The destination address that was returned"},"type":{"type":"string","enum":["BruteforceSubdomainsResult"]}}},{"type":"object","description":"A result for hosts alive check","required":["attack_uuid","host","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"host":{"type":"string","description":"A host which could be reached"},"type":{"type":"string","enum":["HostsAliveCheck"]}}},{"type":"object","description":"A result for a tcp scan","required":["attack_uuid","address","port","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"address":{"type":"string","description":"The address of the result"},"port":{"type":"integer","format":"int32","description":"The port of the result","minimum":0},"type":{"type":"string","enum":["ScanTcpPortsResult"]}}},{"type":"object","description":"A result to a certificate transparency request","required":["attack_uuid","entries","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/CertificateTransparencyEntry"},"description":"The entries of the result"},"type":{"type":"string","enum":["CertificateTransparencyResult"]}}},{"type":"object","description":"A result to service detection request","required":["attack_uuid","service","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"service":{"type":"string","description":"Name of the service"},"type":{"type":"string","enum":["ServiceDetectionResult"]}}},{"type":"object","description":"A result for a DNS resolution requests","required":["attack_uuid","source","destination","type"],"properties":{"attack_uuid":{"type":"string","format":"uuid","description":"The corresponding id of the attack"},"source":{"type":"string","description":"The source address that was queried"},"destination":{"type":"string","description":"The destination address that was returned"},"type":{"type":"string","enum":["DnsResolutionResult"]}}},{"type":"object","description":"A new domain was found","required":["workspace","domain","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace this domain is related to"},"domain":{"$ref":"#/components/schemas/SimpleDomain"},"type":{"type":"string","enum":["NewDomain"]}}},{"type":"object","description":"A new host was found","required":["workspace","host","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace this host is related to"},"host":{"$ref":"#/components/schemas/SimpleHost"},"type":{"type":"string","enum":["NewHost"]}}},{"type":"object","description":"A new port was found","required":["workspace","port","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace this port is related to"},"port":{"$ref":"#/components/schemas/SimplePort"},"type":{"type":"string","enum":["NewPort"]}}},{"type":"object","description":"A new service was found","required":["workspace","service","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace this service is related to"},"service":{"$ref":"#/components/schemas/SimpleService"},"type":{"type":"string","enum":["NewService"]}}},{"type":"object","description":"Global tags were updated on an aggregation","required":["workspace","aggregation","uuid","tags","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace the aggregation is related to"},"aggregation":{"$ref":"#/components/schemas/AggregationType"},"uuid":{"type":"string","format":"uuid","description":"The uuid of the model"},"tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The updated list of tags"},"type":{"type":"string","enum":["UpdatedGlobalTags"]}}},{"type":"object","description":"Workspace tags were updated on an aggregation","required":["workspace","aggregation","uuid","tags","type"],"properties":{"workspace":{"type":"string","format":"uuid","description":"The workspace the aggregation is related to"},"aggregation":{"$ref":"#/components/schemas/AggregationType"},"uuid":{"type":"string","format":"uuid","description":"The uuid of the model"},"tags":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The updated list of tags"},"type":{"type":"string","enum":["UpdatedWorkspaceTags"]}}}],"description":"Message that is sent via websocket","discriminator":{"propertyName":"type"}}},"securitySchemes":{"api_key":{"type":"apiKey","in":"cookie","name":"id"}}}} \ No newline at end of file diff --git a/kraken_frontend/scripts/gen-api.sh b/kraken_frontend/scripts/gen-api.sh index 18e5e8302..06649098a 100644 --- a/kraken_frontend/scripts/gen-api.sh +++ b/kraken_frontend/scripts/gen-api.sh @@ -181,7 +181,7 @@ ${IMPORTS} */ export type SourceAttackResult = ${TYPE_DECL}; -function enumToString(obj: Record): T { +function enumToString(obj: Record): V { // @ts-ignore return Object.values(obj)[0]; } diff --git a/kraken_frontend/src/api/generated/.openapi-generator/FILES b/kraken_frontend/src/api/generated/.openapi-generator/FILES index 1082cbaa4..edf675c67 100644 --- a/kraken_frontend/src/api/generated/.openapi-generator/FILES +++ b/kraken_frontend/src/api/generated/.openapi-generator/FILES @@ -166,6 +166,7 @@ models/SimpleQueryUnhashedResult.ts models/SimpleService.ts models/SimpleTag.ts models/SimpleTcpPortScanResult.ts +models/SimpleTestSSLResult.ts models/SimpleUser.ts models/SimpleWordlist.ts models/SimpleWorkspace.ts @@ -179,8 +180,11 @@ models/SourceAttackResultOneOf3.ts models/SourceAttackResultOneOf4.ts models/SourceAttackResultOneOf5.ts models/SourceAttackResultOneOf6.ts +models/SourceAttackResultOneOf7.ts +models/StartTLSProtocol.ts models/TagType.ts models/TcpPortScanResultsPage.ts +models/TestSSLRequest.ts models/TransferWorkspaceRequest.ts models/UpdateApiKeyRequest.ts models/UpdateAppRequest.ts diff --git a/kraken_frontend/src/api/generated/apis/AttacksApi.ts b/kraken_frontend/src/api/generated/apis/AttacksApi.ts index 16dea832d..e7fa6db55 100644 --- a/kraken_frontend/src/api/generated/apis/AttacksApi.ts +++ b/kraken_frontend/src/api/generated/apis/AttacksApi.ts @@ -32,6 +32,7 @@ import type { ServiceDetectionResultsPage, SimpleAttack, TcpPortScanResultsPage, + TestSSLRequest, UuidResponse, } from '../models'; import { @@ -69,6 +70,8 @@ import { SimpleAttackToJSON, TcpPortScanResultsPageFromJSON, TcpPortScanResultsPageToJSON, + TestSSLRequestFromJSON, + TestSSLRequestToJSON, UuidResponseFromJSON, UuidResponseToJSON, } from '../models'; @@ -155,6 +158,10 @@ export interface ServiceDetectionOperationRequest { serviceDetectionRequest: ServiceDetectionRequest; } +export interface TestsslRequest { + testSSLRequest: TestSSLRequest; +} + /** * */ @@ -864,4 +871,39 @@ export class AttacksApi extends runtime.BaseAPI { return await response.value(); } + /** + * Run testssl + * Run testssl + */ + async testsslRaw(requestParameters: TestsslRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + if (requestParameters.testSSLRequest === null || requestParameters.testSSLRequest === undefined) { + throw new runtime.RequiredError('testSSLRequest','Required parameter requestParameters.testSSLRequest was null or undefined when calling testssl.'); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + const response = await this.request({ + path: `/api/v1/attacks/testssl`, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: TestSSLRequestToJSON(requestParameters.testSSLRequest), + }, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => UuidResponseFromJSON(jsonValue)); + } + + /** + * Run testssl + * Run testssl + */ + async testssl(requestParameters: TestsslRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.testsslRaw(requestParameters, initOverrides); + return await response.value(); + } + } diff --git a/kraken_frontend/src/api/generated/models/AttackType.ts b/kraken_frontend/src/api/generated/models/AttackType.ts index 3b42bf998..3223b721d 100644 --- a/kraken_frontend/src/api/generated/models/AttackType.ts +++ b/kraken_frontend/src/api/generated/models/AttackType.ts @@ -30,7 +30,8 @@ export const AttackType = { ForcedBrowsing: 'ForcedBrowsing', OsDetection: 'OSDetection', VersionDetection: 'VersionDetection', - AntiPortScanningDetection: 'AntiPortScanningDetection' + AntiPortScanningDetection: 'AntiPortScanningDetection', + TestSsl: 'TestSSL' } as const; export type AttackType = typeof AttackType[keyof typeof AttackType]; diff --git a/kraken_frontend/src/api/generated/models/ManualInsert.ts b/kraken_frontend/src/api/generated/models/ManualInsert.ts index 01f0f29ba..f36fba7b4 100644 --- a/kraken_frontend/src/api/generated/models/ManualInsert.ts +++ b/kraken_frontend/src/api/generated/models/ManualInsert.ts @@ -3,29 +3,29 @@ import { - ManualInsertOneOf, - ManualInsertOneOfTypeEnum, - ManualInsertOneOfFromJSONTyped, - ManualInsertOneOfToJSON, -} from './ManualInsertOneOf'; + ManualInsertOneOf3, + ManualInsertOneOf3TypeEnum, + ManualInsertOneOf3FromJSONTyped, + ManualInsertOneOf3ToJSON, +} from './ManualInsertOneOf3'; import { ManualInsertOneOf1, ManualInsertOneOf1TypeEnum, ManualInsertOneOf1FromJSONTyped, ManualInsertOneOf1ToJSON, } from './ManualInsertOneOf1'; +import { + ManualInsertOneOf, + ManualInsertOneOfTypeEnum, + ManualInsertOneOfFromJSONTyped, + ManualInsertOneOfToJSON, +} from './ManualInsertOneOf'; import { ManualInsertOneOf2, ManualInsertOneOf2TypeEnum, ManualInsertOneOf2FromJSONTyped, ManualInsertOneOf2ToJSON, } from './ManualInsertOneOf2'; -import { - ManualInsertOneOf3, - ManualInsertOneOf3TypeEnum, - ManualInsertOneOf3FromJSONTyped, - ManualInsertOneOf3ToJSON, -} from './ManualInsertOneOf3'; /** * @type ManualInsert @@ -33,20 +33,20 @@ import { * @export */ export type ManualInsert = - | ManualInsertOneOf + | ManualInsertOneOf3 | ManualInsertOneOf1 - | ManualInsertOneOf2 - | ManualInsertOneOf3; + | ManualInsertOneOf + | ManualInsertOneOf2; function enumToString(obj: Record): T { // @ts-ignore return Object.values(obj)[0]; } -const ManualInsertOneOfType = enumToString(ManualInsertOneOfTypeEnum); +const ManualInsertOneOf3Type = enumToString(ManualInsertOneOf3TypeEnum); const ManualInsertOneOf1Type = enumToString(ManualInsertOneOf1TypeEnum); +const ManualInsertOneOfType = enumToString(ManualInsertOneOfTypeEnum); const ManualInsertOneOf2Type = enumToString(ManualInsertOneOf2TypeEnum); -const ManualInsertOneOf3Type = enumToString(ManualInsertOneOf3TypeEnum); export function ManualInsertFromJSON(json: any): ManualInsert { return ManualInsertFromJSONTyped(json, false); @@ -58,14 +58,14 @@ export function ManualInsertFromJSONTyped(json: any, ignoreDiscriminator: boolea } switch (json['type']) { - case ManualInsertOneOfType: - return ManualInsertOneOfFromJSONTyped(json, ignoreDiscriminator); + case ManualInsertOneOf3Type: + return ManualInsertOneOf3FromJSONTyped(json, ignoreDiscriminator); case ManualInsertOneOf1Type: return ManualInsertOneOf1FromJSONTyped(json, ignoreDiscriminator); + case ManualInsertOneOfType: + return ManualInsertOneOfFromJSONTyped(json, ignoreDiscriminator); case ManualInsertOneOf2Type: return ManualInsertOneOf2FromJSONTyped(json, ignoreDiscriminator); - case ManualInsertOneOf3Type: - return ManualInsertOneOf3FromJSONTyped(json, ignoreDiscriminator); default: throw new Error("No variant of ManualInsert exists with 'type=" + json["type"] + "'"); } @@ -80,14 +80,14 @@ export function ManualInsertToJSON(value?: ManualInsert | null): any { } switch (value['type']) { - case ManualInsertOneOfType: - return ManualInsertOneOfToJSON(value); + case ManualInsertOneOf3Type: + return ManualInsertOneOf3ToJSON(value); case ManualInsertOneOf1Type: return ManualInsertOneOf1ToJSON(value); + case ManualInsertOneOfType: + return ManualInsertOneOfToJSON(value); case ManualInsertOneOf2Type: return ManualInsertOneOf2ToJSON(value); - case ManualInsertOneOf3Type: - return ManualInsertOneOf3ToJSON(value); default: throw new Error("No variant of ManualInsert exists with 'type=" + value["type"] + "'"); } diff --git a/kraken_frontend/src/api/generated/models/SimpleAggregationSource.ts b/kraken_frontend/src/api/generated/models/SimpleAggregationSource.ts index f6c96d4fb..8de46019b 100644 --- a/kraken_frontend/src/api/generated/models/SimpleAggregationSource.ts +++ b/kraken_frontend/src/api/generated/models/SimpleAggregationSource.ts @@ -91,6 +91,12 @@ export interface SimpleAggregationSource { * @memberof SimpleAggregationSource */ versionDetection: number; + /** + * Ran `testssl.sh` + * @type {number} + * @memberof SimpleAggregationSource + */ + testSsl: number; /** * Manually inserted * @type {boolean} @@ -116,6 +122,7 @@ export function instanceOfSimpleAggregationSource(value: object): boolean { isInstance = isInstance && "antiPortScanningDetection" in value; isInstance = isInstance && "udpPortScan" in value; isInstance = isInstance && "versionDetection" in value; + isInstance = isInstance && "testSsl" in value; isInstance = isInstance && "manual" in value; return isInstance; @@ -143,6 +150,7 @@ export function SimpleAggregationSourceFromJSONTyped(json: any, ignoreDiscrimina 'antiPortScanningDetection': json['anti_port_scanning_detection'], 'udpPortScan': json['udp_port_scan'], 'versionDetection': json['version_detection'], + 'testSsl': json['test_ssl'], 'manual': json['manual'], }; } @@ -168,6 +176,7 @@ export function SimpleAggregationSourceToJSON(value?: SimpleAggregationSource | 'anti_port_scanning_detection': value.antiPortScanningDetection, 'udp_port_scan': value.udpPortScan, 'version_detection': value.versionDetection, + 'test_ssl': value.testSsl, 'manual': value.manual, }; } diff --git a/kraken_frontend/src/api/generated/models/SimpleTestSSLResult.ts b/kraken_frontend/src/api/generated/models/SimpleTestSSLResult.ts new file mode 100644 index 000000000..f72caaf3f --- /dev/null +++ b/kraken_frontend/src/api/generated/models/SimpleTestSSLResult.ts @@ -0,0 +1,129 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * kraken + * The core component of kraken-project + * + * The version of the OpenAPI document: 0.1.0 + * Contact: git@omikron.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * A simple representation of a testssl result + * @export + * @interface SimpleTestSSLResult + */ +export interface SimpleTestSSLResult { + /** + * The primary key + * @type {string} + * @memberof SimpleTestSSLResult + */ + uuid: string; + /** + * The attack which produced this result + * @type {string} + * @memberof SimpleTestSSLResult + */ + attack: string; + /** + * The point in time, this result was produced + * @type {Date} + * @memberof SimpleTestSSLResult + */ + createdAt: Date; + /** + * The original user target this result belongs to + * @type {string} + * @memberof SimpleTestSSLResult + */ + targetHost: string; + /** + * The scanned ip address + * @type {string} + * @memberof SimpleTestSSLResult + */ + ip: string; + /** + * The scanned port + * @type {number} + * @memberof SimpleTestSSLResult + */ + port: number; + /** + * The ip address' rDNS name + * @type {string} + * @memberof SimpleTestSSLResult + */ + rdns: string; + /** + * The detected service + * @type {string} + * @memberof SimpleTestSSLResult + */ + service: string; +} + +/** + * Check if a given object implements the SimpleTestSSLResult interface. + */ +export function instanceOfSimpleTestSSLResult(value: object): boolean { + let isInstance = true; + isInstance = isInstance && "uuid" in value; + isInstance = isInstance && "attack" in value; + isInstance = isInstance && "createdAt" in value; + isInstance = isInstance && "targetHost" in value; + isInstance = isInstance && "ip" in value; + isInstance = isInstance && "port" in value; + isInstance = isInstance && "rdns" in value; + isInstance = isInstance && "service" in value; + + return isInstance; +} + +export function SimpleTestSSLResultFromJSON(json: any): SimpleTestSSLResult { + return SimpleTestSSLResultFromJSONTyped(json, false); +} + +export function SimpleTestSSLResultFromJSONTyped(json: any, ignoreDiscriminator: boolean): SimpleTestSSLResult { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'uuid': json['uuid'], + 'attack': json['attack'], + 'createdAt': (new Date(json['created_at'])), + 'targetHost': json['target_host'], + 'ip': json['ip'], + 'port': json['port'], + 'rdns': json['rdns'], + 'service': json['service'], + }; +} + +export function SimpleTestSSLResultToJSON(value?: SimpleTestSSLResult | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'uuid': value.uuid, + 'attack': value.attack, + 'created_at': (value.createdAt.toISOString()), + 'target_host': value.targetHost, + 'ip': value.ip, + 'port': value.port, + 'rdns': value.rdns, + 'service': value.service, + }; +} + diff --git a/kraken_frontend/src/api/generated/models/SourceAttack.ts b/kraken_frontend/src/api/generated/models/SourceAttack.ts index 9bf64a99e..2c05f7a51 100644 --- a/kraken_frontend/src/api/generated/models/SourceAttack.ts +++ b/kraken_frontend/src/api/generated/models/SourceAttack.ts @@ -13,12 +13,12 @@ */ import { exists, mapValues } from '../runtime'; -import type { SimpleDnsResolutionResult } from './SimpleDnsResolutionResult'; +import type { SimpleTestSSLResult } from './SimpleTestSSLResult'; import { - SimpleDnsResolutionResultFromJSON, - SimpleDnsResolutionResultFromJSONTyped, - SimpleDnsResolutionResultToJSON, -} from './SimpleDnsResolutionResult'; + SimpleTestSSLResultFromJSON, + SimpleTestSSLResultFromJSONTyped, + SimpleTestSSLResultToJSON, +} from './SimpleTestSSLResult'; import type { SimpleUser } from './SimpleUser'; import { SimpleUserFromJSON, diff --git a/kraken_frontend/src/api/generated/models/SourceAttackResult.ts b/kraken_frontend/src/api/generated/models/SourceAttackResult.ts index f049c2c52..f30ec9169 100644 --- a/kraken_frontend/src/api/generated/models/SourceAttackResult.ts +++ b/kraken_frontend/src/api/generated/models/SourceAttackResult.ts @@ -2,24 +2,6 @@ /* eslint-disable */ -import { - SourceAttackResultOneOf, - SourceAttackResultOneOfAttackTypeEnum, - SourceAttackResultOneOfFromJSONTyped, - SourceAttackResultOneOfToJSON, -} from './SourceAttackResultOneOf'; -import { - SourceAttackResultOneOf1, - SourceAttackResultOneOf1AttackTypeEnum, - SourceAttackResultOneOf1FromJSONTyped, - SourceAttackResultOneOf1ToJSON, -} from './SourceAttackResultOneOf1'; -import { - SourceAttackResultOneOf2, - SourceAttackResultOneOf2AttackTypeEnum, - SourceAttackResultOneOf2FromJSONTyped, - SourceAttackResultOneOf2ToJSON, -} from './SourceAttackResultOneOf2'; import { SourceAttackResultOneOf3, SourceAttackResultOneOf3AttackTypeEnum, @@ -27,11 +9,11 @@ import { SourceAttackResultOneOf3ToJSON, } from './SourceAttackResultOneOf3'; import { - SourceAttackResultOneOf4, - SourceAttackResultOneOf4AttackTypeEnum, - SourceAttackResultOneOf4FromJSONTyped, - SourceAttackResultOneOf4ToJSON, -} from './SourceAttackResultOneOf4'; + SourceAttackResultOneOf7, + SourceAttackResultOneOf7AttackTypeEnum, + SourceAttackResultOneOf7FromJSONTyped, + SourceAttackResultOneOf7ToJSON, +} from './SourceAttackResultOneOf7'; import { SourceAttackResultOneOf5, SourceAttackResultOneOf5AttackTypeEnum, @@ -44,32 +26,58 @@ import { SourceAttackResultOneOf6FromJSONTyped, SourceAttackResultOneOf6ToJSON, } from './SourceAttackResultOneOf6'; +import { + SourceAttackResultOneOf4, + SourceAttackResultOneOf4AttackTypeEnum, + SourceAttackResultOneOf4FromJSONTyped, + SourceAttackResultOneOf4ToJSON, +} from './SourceAttackResultOneOf4'; +import { + SourceAttackResultOneOf2, + SourceAttackResultOneOf2AttackTypeEnum, + SourceAttackResultOneOf2FromJSONTyped, + SourceAttackResultOneOf2ToJSON, +} from './SourceAttackResultOneOf2'; +import { + SourceAttackResultOneOf1, + SourceAttackResultOneOf1AttackTypeEnum, + SourceAttackResultOneOf1FromJSONTyped, + SourceAttackResultOneOf1ToJSON, +} from './SourceAttackResultOneOf1'; +import { + SourceAttackResultOneOf, + SourceAttackResultOneOfAttackTypeEnum, + SourceAttackResultOneOfFromJSONTyped, + SourceAttackResultOneOfToJSON, +} from './SourceAttackResultOneOf'; /** * @type SourceAttackResult * @export */ export type SourceAttackResult = - | SourceAttackResultOneOf - | SourceAttackResultOneOf1 - | SourceAttackResultOneOf2 | SourceAttackResultOneOf3 - | SourceAttackResultOneOf4 + | SourceAttackResultOneOf7 | SourceAttackResultOneOf5 - | SourceAttackResultOneOf6; + | SourceAttackResultOneOf6 + | SourceAttackResultOneOf4 + | SourceAttackResultOneOf2 + | SourceAttackResultOneOf1 + | SourceAttackResultOneOf; -function enumToString(obj: Record): T { +function enumToString(obj: Record): V { // @ts-ignore return Object.values(obj)[0]; } -const SourceAttackResultOneOfAttackType = enumToString(SourceAttackResultOneOfAttackTypeEnum); -const SourceAttackResultOneOf1AttackType = enumToString(SourceAttackResultOneOf1AttackTypeEnum); -const SourceAttackResultOneOf2AttackType = enumToString(SourceAttackResultOneOf2AttackTypeEnum); const SourceAttackResultOneOf3AttackType = enumToString(SourceAttackResultOneOf3AttackTypeEnum); -const SourceAttackResultOneOf4AttackType = enumToString(SourceAttackResultOneOf4AttackTypeEnum); +const SourceAttackResultOneOf7AttackType = enumToString(SourceAttackResultOneOf7AttackTypeEnum); const SourceAttackResultOneOf5AttackType = enumToString(SourceAttackResultOneOf5AttackTypeEnum); const SourceAttackResultOneOf6AttackType = enumToString(SourceAttackResultOneOf6AttackTypeEnum); +const SourceAttackResultOneOf4AttackType = enumToString(SourceAttackResultOneOf4AttackTypeEnum); +const SourceAttackResultOneOf2AttackType = enumToString(SourceAttackResultOneOf2AttackTypeEnum); +const SourceAttackResultOneOf1AttackType = enumToString(SourceAttackResultOneOf1AttackTypeEnum); +const SourceAttackResultOneOfAttackType = enumToString(SourceAttackResultOneOfAttackTypeEnum); export function SourceAttackResultFromJSON(json: any): SourceAttackResult { return SourceAttackResultFromJSONTyped(json, false); @@ -81,20 +89,22 @@ export function SourceAttackResultFromJSONTyped(json: any, ignoreDiscriminator: } switch (json['attack_type']) { - case SourceAttackResultOneOfAttackType: - return SourceAttackResultOneOfFromJSONTyped(json, ignoreDiscriminator); - case SourceAttackResultOneOf1AttackType: - return SourceAttackResultOneOf1FromJSONTyped(json, ignoreDiscriminator); - case SourceAttackResultOneOf2AttackType: - return SourceAttackResultOneOf2FromJSONTyped(json, ignoreDiscriminator); case SourceAttackResultOneOf3AttackType: return SourceAttackResultOneOf3FromJSONTyped(json, ignoreDiscriminator); - case SourceAttackResultOneOf4AttackType: - return SourceAttackResultOneOf4FromJSONTyped(json, ignoreDiscriminator); + case SourceAttackResultOneOf7AttackType: + return SourceAttackResultOneOf7FromJSONTyped(json, ignoreDiscriminator); case SourceAttackResultOneOf5AttackType: return SourceAttackResultOneOf5FromJSONTyped(json, ignoreDiscriminator); case SourceAttackResultOneOf6AttackType: return SourceAttackResultOneOf6FromJSONTyped(json, ignoreDiscriminator); + case SourceAttackResultOneOf4AttackType: + return SourceAttackResultOneOf4FromJSONTyped(json, ignoreDiscriminator); + case SourceAttackResultOneOf2AttackType: + return SourceAttackResultOneOf2FromJSONTyped(json, ignoreDiscriminator); + case SourceAttackResultOneOf1AttackType: + return SourceAttackResultOneOf1FromJSONTyped(json, ignoreDiscriminator); + case SourceAttackResultOneOfAttackType: + return SourceAttackResultOneOfFromJSONTyped(json, ignoreDiscriminator); default: throw new Error("No variant of SourceAttackResult exists with 'attackType=" + json["attack_type"] + "'"); } @@ -109,20 +119,22 @@ export function SourceAttackResultToJSON(value?: SourceAttackResult | null): any } switch (value['attackType']) { - case SourceAttackResultOneOfAttackType: - return SourceAttackResultOneOfToJSON(value); - case SourceAttackResultOneOf1AttackType: - return SourceAttackResultOneOf1ToJSON(value); - case SourceAttackResultOneOf2AttackType: - return SourceAttackResultOneOf2ToJSON(value); case SourceAttackResultOneOf3AttackType: return SourceAttackResultOneOf3ToJSON(value); - case SourceAttackResultOneOf4AttackType: - return SourceAttackResultOneOf4ToJSON(value); + case SourceAttackResultOneOf7AttackType: + return SourceAttackResultOneOf7ToJSON(value); case SourceAttackResultOneOf5AttackType: return SourceAttackResultOneOf5ToJSON(value); case SourceAttackResultOneOf6AttackType: return SourceAttackResultOneOf6ToJSON(value); + case SourceAttackResultOneOf4AttackType: + return SourceAttackResultOneOf4ToJSON(value); + case SourceAttackResultOneOf2AttackType: + return SourceAttackResultOneOf2ToJSON(value); + case SourceAttackResultOneOf1AttackType: + return SourceAttackResultOneOf1ToJSON(value); + case SourceAttackResultOneOfAttackType: + return SourceAttackResultOneOfToJSON(value); default: throw new Error("No variant of SourceAttackResult exists with 'attackType=" + value["attackType"] + "'"); } diff --git a/kraken_frontend/src/api/generated/models/SourceAttackResultOneOf7.ts b/kraken_frontend/src/api/generated/models/SourceAttackResultOneOf7.ts new file mode 100644 index 000000000..2ee486096 --- /dev/null +++ b/kraken_frontend/src/api/generated/models/SourceAttackResultOneOf7.ts @@ -0,0 +1,92 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * kraken + * The core component of kraken-project + * + * The version of the OpenAPI document: 0.1.0 + * Contact: git@omikron.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { SimpleTestSSLResult } from './SimpleTestSSLResult'; +import { + SimpleTestSSLResultFromJSON, + SimpleTestSSLResultFromJSONTyped, + SimpleTestSSLResultToJSON, +} from './SimpleTestSSLResult'; + +/** + * + * @export + * @interface SourceAttackResultOneOf7 + */ +export interface SourceAttackResultOneOf7 { + /** + * + * @type {string} + * @memberof SourceAttackResultOneOf7 + */ + attackType: SourceAttackResultOneOf7AttackTypeEnum; + /** + * The [`AttackType::TestSSL`] and its results + * @type {Array} + * @memberof SourceAttackResultOneOf7 + */ + results: Array; +} + + +/** + * @export + */ +export const SourceAttackResultOneOf7AttackTypeEnum = { + TestSsl: 'TestSSL' +} as const; +export type SourceAttackResultOneOf7AttackTypeEnum = typeof SourceAttackResultOneOf7AttackTypeEnum[keyof typeof SourceAttackResultOneOf7AttackTypeEnum]; + + +/** + * Check if a given object implements the SourceAttackResultOneOf7 interface. + */ +export function instanceOfSourceAttackResultOneOf7(value: object): boolean { + let isInstance = true; + isInstance = isInstance && "attackType" in value; + isInstance = isInstance && "results" in value; + + return isInstance; +} + +export function SourceAttackResultOneOf7FromJSON(json: any): SourceAttackResultOneOf7 { + return SourceAttackResultOneOf7FromJSONTyped(json, false); +} + +export function SourceAttackResultOneOf7FromJSONTyped(json: any, ignoreDiscriminator: boolean): SourceAttackResultOneOf7 { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'attackType': json['attack_type'], + 'results': ((json['results'] as Array).map(SimpleTestSSLResultFromJSON)), + }; +} + +export function SourceAttackResultOneOf7ToJSON(value?: SourceAttackResultOneOf7 | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'attack_type': value.attackType, + 'results': ((value.results as Array).map(SimpleTestSSLResultToJSON)), + }; +} + diff --git a/kraken_frontend/src/api/generated/models/StartTLSProtocol.ts b/kraken_frontend/src/api/generated/models/StartTLSProtocol.ts new file mode 100644 index 000000000..d27302f2b --- /dev/null +++ b/kraken_frontend/src/api/generated/models/StartTLSProtocol.ts @@ -0,0 +1,45 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * kraken + * The core component of kraken-project + * + * The version of the OpenAPI document: 0.1.0 + * Contact: git@omikron.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +/** + * Protocols to select from when using `--starttls` + * @export + */ +export const StartTLSProtocol = { + Ftp: 'FTP', + Smtp: 'SMTP', + Pop3: 'POP3', + Imap: 'IMAP', + Xmpp: 'XMPP', + Lmtp: 'LMTP', + Nntp: 'NNTP', + Postgres: 'Postgres', + MySql: 'MySQL' +} as const; +export type StartTLSProtocol = typeof StartTLSProtocol[keyof typeof StartTLSProtocol]; + + +export function StartTLSProtocolFromJSON(json: any): StartTLSProtocol { + return StartTLSProtocolFromJSONTyped(json, false); +} + +export function StartTLSProtocolFromJSONTyped(json: any, ignoreDiscriminator: boolean): StartTLSProtocol { + return json as StartTLSProtocol; +} + +export function StartTLSProtocolToJSON(value?: StartTLSProtocol | null): any { + return value as any; +} + diff --git a/kraken_frontend/src/api/generated/models/TestSSLRequest.ts b/kraken_frontend/src/api/generated/models/TestSSLRequest.ts new file mode 100644 index 000000000..276c0822d --- /dev/null +++ b/kraken_frontend/src/api/generated/models/TestSSLRequest.ts @@ -0,0 +1,124 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * kraken + * The core component of kraken-project + * + * The version of the OpenAPI document: 0.1.0 + * Contact: git@omikron.dev + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { StartTLSProtocol } from './StartTLSProtocol'; +import { + StartTLSProtocolFromJSON, + StartTLSProtocolFromJSONTyped, + StartTLSProtocolToJSON, +} from './StartTLSProtocol'; + +/** + * Request to run testssl + * @export + * @interface TestSSLRequest + */ +export interface TestSSLRequest { + /** + * The leech to use + * + * Leave empty to use a random leech + * @type {string} + * @memberof TestSSLRequest + */ + leechUuid?: string | null; + /** + * The workspace to execute the attack in + * @type {string} + * @memberof TestSSLRequest + */ + workspaceUuid: string; + /** + * The domain to scan + * @type {string} + * @memberof TestSSLRequest + */ + uri: string; + /** + * Timeout for TCP handshakes in seconds + * @type {number} + * @memberof TestSSLRequest + */ + connectTimeout?: number | null; + /** + * Timeout for `openssl` connections in seconds + * @type {number} + * @memberof TestSSLRequest + */ + opensslTimeout?: number | null; + /** + * Set the `BASICAUTH` header when checking http headers + * @type {Array} + * @memberof TestSSLRequest + */ + basicAuth?: Array | null; + /** + * + * @type {StartTLSProtocol} + * @memberof TestSSLRequest + */ + starttls?: StartTLSProtocol | null; +} + +/** + * Check if a given object implements the TestSSLRequest interface. + */ +export function instanceOfTestSSLRequest(value: object): boolean { + let isInstance = true; + isInstance = isInstance && "workspaceUuid" in value; + isInstance = isInstance && "uri" in value; + + return isInstance; +} + +export function TestSSLRequestFromJSON(json: any): TestSSLRequest { + return TestSSLRequestFromJSONTyped(json, false); +} + +export function TestSSLRequestFromJSONTyped(json: any, ignoreDiscriminator: boolean): TestSSLRequest { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'leechUuid': !exists(json, 'leech_uuid') ? undefined : json['leech_uuid'], + 'workspaceUuid': json['workspace_uuid'], + 'uri': json['uri'], + 'connectTimeout': !exists(json, 'connect_timeout') ? undefined : json['connect_timeout'], + 'opensslTimeout': !exists(json, 'openssl_timeout') ? undefined : json['openssl_timeout'], + 'basicAuth': !exists(json, 'basic_auth') ? undefined : json['basic_auth'], + 'starttls': !exists(json, 'starttls') ? undefined : StartTLSProtocolFromJSON(json['starttls']), + }; +} + +export function TestSSLRequestToJSON(value?: TestSSLRequest | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'leech_uuid': value.leechUuid, + 'workspace_uuid': value.workspaceUuid, + 'uri': value.uri, + 'connect_timeout': value.connectTimeout, + 'openssl_timeout': value.opensslTimeout, + 'basic_auth': value.basicAuth, + 'starttls': StartTLSProtocolToJSON(value.starttls), + }; +} + diff --git a/kraken_frontend/src/api/generated/models/WsMessage.ts b/kraken_frontend/src/api/generated/models/WsMessage.ts index c5ac30652..460592d2d 100644 --- a/kraken_frontend/src/api/generated/models/WsMessage.ts +++ b/kraken_frontend/src/api/generated/models/WsMessage.ts @@ -2,12 +2,36 @@ /* eslint-disable */ +import { + WsMessageOneOf16, + WsMessageOneOf16TypeEnum, + WsMessageOneOf16FromJSONTyped, + WsMessageOneOf16ToJSON, +} from './WsMessageOneOf16'; +import { + WsMessageOneOf8, + WsMessageOneOf8TypeEnum, + WsMessageOneOf8FromJSONTyped, + WsMessageOneOf8ToJSON, +} from './WsMessageOneOf8'; +import { + WsMessageOneOf13, + WsMessageOneOf13TypeEnum, + WsMessageOneOf13FromJSONTyped, + WsMessageOneOf13ToJSON, +} from './WsMessageOneOf13'; import { WsMessageOneOf, WsMessageOneOfTypeEnum, WsMessageOneOfFromJSONTyped, WsMessageOneOfToJSON, } from './WsMessageOneOf'; +import { + WsMessageOneOf2, + WsMessageOneOf2TypeEnum, + WsMessageOneOf2FromJSONTyped, + WsMessageOneOf2ToJSON, +} from './WsMessageOneOf2'; import { WsMessageOneOf1, WsMessageOneOf1TypeEnum, @@ -15,17 +39,47 @@ import { WsMessageOneOf1ToJSON, } from './WsMessageOneOf1'; import { - WsMessageOneOf10, - WsMessageOneOf10TypeEnum, - WsMessageOneOf10FromJSONTyped, - WsMessageOneOf10ToJSON, -} from './WsMessageOneOf10'; + WsMessageOneOf5, + WsMessageOneOf5TypeEnum, + WsMessageOneOf5FromJSONTyped, + WsMessageOneOf5ToJSON, +} from './WsMessageOneOf5'; +import { + WsMessageOneOf9, + WsMessageOneOf9TypeEnum, + WsMessageOneOf9FromJSONTyped, + WsMessageOneOf9ToJSON, +} from './WsMessageOneOf9'; +import { + WsMessageOneOf17, + WsMessageOneOf17TypeEnum, + WsMessageOneOf17FromJSONTyped, + WsMessageOneOf17ToJSON, +} from './WsMessageOneOf17'; +import { + WsMessageOneOf4, + WsMessageOneOf4TypeEnum, + WsMessageOneOf4FromJSONTyped, + WsMessageOneOf4ToJSON, +} from './WsMessageOneOf4'; import { WsMessageOneOf11, WsMessageOneOf11TypeEnum, WsMessageOneOf11FromJSONTyped, WsMessageOneOf11ToJSON, } from './WsMessageOneOf11'; +import { + WsMessageOneOf3, + WsMessageOneOf3TypeEnum, + WsMessageOneOf3FromJSONTyped, + WsMessageOneOf3ToJSON, +} from './WsMessageOneOf3'; +import { + WsMessageOneOf10, + WsMessageOneOf10TypeEnum, + WsMessageOneOf10FromJSONTyped, + WsMessageOneOf10ToJSON, +} from './WsMessageOneOf10'; import { WsMessageOneOf12, WsMessageOneOf12TypeEnum, @@ -33,59 +87,17 @@ import { WsMessageOneOf12ToJSON, } from './WsMessageOneOf12'; import { - WsMessageOneOf13, - WsMessageOneOf13TypeEnum, - WsMessageOneOf13FromJSONTyped, - WsMessageOneOf13ToJSON, -} from './WsMessageOneOf13'; + WsMessageOneOf7, + WsMessageOneOf7TypeEnum, + WsMessageOneOf7FromJSONTyped, + WsMessageOneOf7ToJSON, +} from './WsMessageOneOf7'; import { WsMessageOneOf14, WsMessageOneOf14TypeEnum, WsMessageOneOf14FromJSONTyped, WsMessageOneOf14ToJSON, } from './WsMessageOneOf14'; -import { - WsMessageOneOf15, - WsMessageOneOf15TypeEnum, - WsMessageOneOf15FromJSONTyped, - WsMessageOneOf15ToJSON, -} from './WsMessageOneOf15'; -import { - WsMessageOneOf16, - WsMessageOneOf16TypeEnum, - WsMessageOneOf16FromJSONTyped, - WsMessageOneOf16ToJSON, -} from './WsMessageOneOf16'; -import { - WsMessageOneOf17, - WsMessageOneOf17TypeEnum, - WsMessageOneOf17FromJSONTyped, - WsMessageOneOf17ToJSON, -} from './WsMessageOneOf17'; -import { - WsMessageOneOf2, - WsMessageOneOf2TypeEnum, - WsMessageOneOf2FromJSONTyped, - WsMessageOneOf2ToJSON, -} from './WsMessageOneOf2'; -import { - WsMessageOneOf3, - WsMessageOneOf3TypeEnum, - WsMessageOneOf3FromJSONTyped, - WsMessageOneOf3ToJSON, -} from './WsMessageOneOf3'; -import { - WsMessageOneOf4, - WsMessageOneOf4TypeEnum, - WsMessageOneOf4FromJSONTyped, - WsMessageOneOf4ToJSON, -} from './WsMessageOneOf4'; -import { - WsMessageOneOf5, - WsMessageOneOf5TypeEnum, - WsMessageOneOf5FromJSONTyped, - WsMessageOneOf5ToJSON, -} from './WsMessageOneOf5'; import { WsMessageOneOf6, WsMessageOneOf6TypeEnum, @@ -93,23 +105,11 @@ import { WsMessageOneOf6ToJSON, } from './WsMessageOneOf6'; import { - WsMessageOneOf7, - WsMessageOneOf7TypeEnum, - WsMessageOneOf7FromJSONTyped, - WsMessageOneOf7ToJSON, -} from './WsMessageOneOf7'; -import { - WsMessageOneOf8, - WsMessageOneOf8TypeEnum, - WsMessageOneOf8FromJSONTyped, - WsMessageOneOf8ToJSON, -} from './WsMessageOneOf8'; -import { - WsMessageOneOf9, - WsMessageOneOf9TypeEnum, - WsMessageOneOf9FromJSONTyped, - WsMessageOneOf9ToJSON, -} from './WsMessageOneOf9'; + WsMessageOneOf15, + WsMessageOneOf15TypeEnum, + WsMessageOneOf15FromJSONTyped, + WsMessageOneOf15ToJSON, +} from './WsMessageOneOf15'; /** * @type WsMessage @@ -117,48 +117,48 @@ import { * @export */ export type WsMessage = + | WsMessageOneOf16 + | WsMessageOneOf8 + | WsMessageOneOf13 | WsMessageOneOf + | WsMessageOneOf2 | WsMessageOneOf1 - | WsMessageOneOf10 + | WsMessageOneOf5 + | WsMessageOneOf9 + | WsMessageOneOf17 + | WsMessageOneOf4 | WsMessageOneOf11 + | WsMessageOneOf3 + | WsMessageOneOf10 | WsMessageOneOf12 - | WsMessageOneOf13 + | WsMessageOneOf7 | WsMessageOneOf14 - | WsMessageOneOf15 - | WsMessageOneOf16 - | WsMessageOneOf17 - | WsMessageOneOf2 - | WsMessageOneOf3 - | WsMessageOneOf4 - | WsMessageOneOf5 | WsMessageOneOf6 - | WsMessageOneOf7 - | WsMessageOneOf8 - | WsMessageOneOf9; + | WsMessageOneOf15; function enumToString(obj: Record): T { // @ts-ignore return Object.values(obj)[0]; } +const WsMessageOneOf16Type = enumToString(WsMessageOneOf16TypeEnum); +const WsMessageOneOf8Type = enumToString(WsMessageOneOf8TypeEnum); +const WsMessageOneOf13Type = enumToString(WsMessageOneOf13TypeEnum); const WsMessageOneOfType = enumToString(WsMessageOneOfTypeEnum); +const WsMessageOneOf2Type = enumToString(WsMessageOneOf2TypeEnum); const WsMessageOneOf1Type = enumToString(WsMessageOneOf1TypeEnum); -const WsMessageOneOf10Type = enumToString(WsMessageOneOf10TypeEnum); +const WsMessageOneOf5Type = enumToString(WsMessageOneOf5TypeEnum); +const WsMessageOneOf9Type = enumToString(WsMessageOneOf9TypeEnum); +const WsMessageOneOf17Type = enumToString(WsMessageOneOf17TypeEnum); +const WsMessageOneOf4Type = enumToString(WsMessageOneOf4TypeEnum); const WsMessageOneOf11Type = enumToString(WsMessageOneOf11TypeEnum); +const WsMessageOneOf3Type = enumToString(WsMessageOneOf3TypeEnum); +const WsMessageOneOf10Type = enumToString(WsMessageOneOf10TypeEnum); const WsMessageOneOf12Type = enumToString(WsMessageOneOf12TypeEnum); -const WsMessageOneOf13Type = enumToString(WsMessageOneOf13TypeEnum); +const WsMessageOneOf7Type = enumToString(WsMessageOneOf7TypeEnum); const WsMessageOneOf14Type = enumToString(WsMessageOneOf14TypeEnum); -const WsMessageOneOf15Type = enumToString(WsMessageOneOf15TypeEnum); -const WsMessageOneOf16Type = enumToString(WsMessageOneOf16TypeEnum); -const WsMessageOneOf17Type = enumToString(WsMessageOneOf17TypeEnum); -const WsMessageOneOf2Type = enumToString(WsMessageOneOf2TypeEnum); -const WsMessageOneOf3Type = enumToString(WsMessageOneOf3TypeEnum); -const WsMessageOneOf4Type = enumToString(WsMessageOneOf4TypeEnum); -const WsMessageOneOf5Type = enumToString(WsMessageOneOf5TypeEnum); const WsMessageOneOf6Type = enumToString(WsMessageOneOf6TypeEnum); -const WsMessageOneOf7Type = enumToString(WsMessageOneOf7TypeEnum); -const WsMessageOneOf8Type = enumToString(WsMessageOneOf8TypeEnum); -const WsMessageOneOf9Type = enumToString(WsMessageOneOf9TypeEnum); +const WsMessageOneOf15Type = enumToString(WsMessageOneOf15TypeEnum); export function WsMessageFromJSON(json: any): WsMessage { return WsMessageFromJSONTyped(json, false); @@ -170,42 +170,42 @@ export function WsMessageFromJSONTyped(json: any, ignoreDiscriminator: boolean): } switch (json['type']) { + case WsMessageOneOf16Type: + return WsMessageOneOf16FromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf8Type: + return WsMessageOneOf8FromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf13Type: + return WsMessageOneOf13FromJSONTyped(json, ignoreDiscriminator); case WsMessageOneOfType: return WsMessageOneOfFromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf2Type: + return WsMessageOneOf2FromJSONTyped(json, ignoreDiscriminator); case WsMessageOneOf1Type: return WsMessageOneOf1FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf10Type: - return WsMessageOneOf10FromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf5Type: + return WsMessageOneOf5FromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf9Type: + return WsMessageOneOf9FromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf17Type: + return WsMessageOneOf17FromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf4Type: + return WsMessageOneOf4FromJSONTyped(json, ignoreDiscriminator); case WsMessageOneOf11Type: return WsMessageOneOf11FromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf3Type: + return WsMessageOneOf3FromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf10Type: + return WsMessageOneOf10FromJSONTyped(json, ignoreDiscriminator); case WsMessageOneOf12Type: return WsMessageOneOf12FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf13Type: - return WsMessageOneOf13FromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf7Type: + return WsMessageOneOf7FromJSONTyped(json, ignoreDiscriminator); case WsMessageOneOf14Type: return WsMessageOneOf14FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf15Type: - return WsMessageOneOf15FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf16Type: - return WsMessageOneOf16FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf17Type: - return WsMessageOneOf17FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf2Type: - return WsMessageOneOf2FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf3Type: - return WsMessageOneOf3FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf4Type: - return WsMessageOneOf4FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf5Type: - return WsMessageOneOf5FromJSONTyped(json, ignoreDiscriminator); case WsMessageOneOf6Type: return WsMessageOneOf6FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf7Type: - return WsMessageOneOf7FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf8Type: - return WsMessageOneOf8FromJSONTyped(json, ignoreDiscriminator); - case WsMessageOneOf9Type: - return WsMessageOneOf9FromJSONTyped(json, ignoreDiscriminator); + case WsMessageOneOf15Type: + return WsMessageOneOf15FromJSONTyped(json, ignoreDiscriminator); default: throw new Error("No variant of WsMessage exists with 'type=" + json["type"] + "'"); } @@ -220,42 +220,42 @@ export function WsMessageToJSON(value?: WsMessage | null): any { } switch (value['type']) { + case WsMessageOneOf16Type: + return WsMessageOneOf16ToJSON(value); + case WsMessageOneOf8Type: + return WsMessageOneOf8ToJSON(value); + case WsMessageOneOf13Type: + return WsMessageOneOf13ToJSON(value); case WsMessageOneOfType: return WsMessageOneOfToJSON(value); + case WsMessageOneOf2Type: + return WsMessageOneOf2ToJSON(value); case WsMessageOneOf1Type: return WsMessageOneOf1ToJSON(value); - case WsMessageOneOf10Type: - return WsMessageOneOf10ToJSON(value); + case WsMessageOneOf5Type: + return WsMessageOneOf5ToJSON(value); + case WsMessageOneOf9Type: + return WsMessageOneOf9ToJSON(value); + case WsMessageOneOf17Type: + return WsMessageOneOf17ToJSON(value); + case WsMessageOneOf4Type: + return WsMessageOneOf4ToJSON(value); case WsMessageOneOf11Type: return WsMessageOneOf11ToJSON(value); + case WsMessageOneOf3Type: + return WsMessageOneOf3ToJSON(value); + case WsMessageOneOf10Type: + return WsMessageOneOf10ToJSON(value); case WsMessageOneOf12Type: return WsMessageOneOf12ToJSON(value); - case WsMessageOneOf13Type: - return WsMessageOneOf13ToJSON(value); + case WsMessageOneOf7Type: + return WsMessageOneOf7ToJSON(value); case WsMessageOneOf14Type: return WsMessageOneOf14ToJSON(value); - case WsMessageOneOf15Type: - return WsMessageOneOf15ToJSON(value); - case WsMessageOneOf16Type: - return WsMessageOneOf16ToJSON(value); - case WsMessageOneOf17Type: - return WsMessageOneOf17ToJSON(value); - case WsMessageOneOf2Type: - return WsMessageOneOf2ToJSON(value); - case WsMessageOneOf3Type: - return WsMessageOneOf3ToJSON(value); - case WsMessageOneOf4Type: - return WsMessageOneOf4ToJSON(value); - case WsMessageOneOf5Type: - return WsMessageOneOf5ToJSON(value); case WsMessageOneOf6Type: return WsMessageOneOf6ToJSON(value); - case WsMessageOneOf7Type: - return WsMessageOneOf7ToJSON(value); - case WsMessageOneOf8Type: - return WsMessageOneOf8ToJSON(value); - case WsMessageOneOf9Type: - return WsMessageOneOf9ToJSON(value); + case WsMessageOneOf15Type: + return WsMessageOneOf15ToJSON(value); default: throw new Error("No variant of WsMessage exists with 'type=" + value["type"] + "'"); } diff --git a/kraken_frontend/src/api/generated/models/index.ts b/kraken_frontend/src/api/generated/models/index.ts index 296f292b1..2b2959773 100644 --- a/kraken_frontend/src/api/generated/models/index.ts +++ b/kraken_frontend/src/api/generated/models/index.ts @@ -144,6 +144,7 @@ export * from './SimpleQueryUnhashedResult'; export * from './SimpleService'; export * from './SimpleTag'; export * from './SimpleTcpPortScanResult'; +export * from './SimpleTestSSLResult'; export * from './SimpleUser'; export * from './SimpleWordlist'; export * from './SimpleWorkspace'; @@ -157,8 +158,11 @@ export * from './SourceAttackResultOneOf3'; export * from './SourceAttackResultOneOf4'; export * from './SourceAttackResultOneOf5'; export * from './SourceAttackResultOneOf6'; +export * from './SourceAttackResultOneOf7'; +export * from './StartTLSProtocol'; export * from './TagType'; export * from './TcpPortScanResultsPage'; +export * from './TestSSLRequest'; export * from './TransferWorkspaceRequest'; export * from './UpdateApiKeyRequest'; export * from './UpdateAppRequest'; diff --git a/kraken_frontend/src/utils/attack-resolver.ts b/kraken_frontend/src/utils/attack-resolver.ts index 52cf98e8e..1074c3e77 100644 --- a/kraken_frontend/src/utils/attack-resolver.ts +++ b/kraken_frontend/src/utils/attack-resolver.ts @@ -29,5 +29,6 @@ export const ATTACKS: AttackResolver = { }, UdpPortScan: { abbreviation: "PsU", long: "UDP port scan", key: "udpPortScan" }, VersionDetection: { abbreviation: "VsD", long: "Version detection", key: "versionDetection" }, + TestSSL: { abbreviation: "TS", long: "testssl.sh", key: "testSsl" }, Undefined: { abbreviation: "?", long: "Undefined", key: "undefined" }, }; From c94df0262e62ec0a9465e671b41a52c522b54927 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Thu, 11 Jan 2024 16:31:46 +0100 Subject: [PATCH 08/37] Added --experimental_allow_proto3_optional flag --- kraken-proto/build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kraken-proto/build.rs b/kraken-proto/build.rs index 33852bbea..0be0c2d53 100644 --- a/kraken-proto/build.rs +++ b/kraken-proto/build.rs @@ -1,4 +1,6 @@ fn main() -> Result<(), Box> { - tonic_build::configure().compile(&["./proto/attacks.proto"], &["./proto/"])?; + tonic_build::configure() + .protoc_arg("--experimental_allow_proto3_optional") + .compile(&["./proto/attacks.proto"], &["./proto/"])?; Ok(()) } From 82d20414a98dcf3c741016f5202fe540685ce90b Mon Sep 17 00:00:00 2001 From: gammelalf Date: Mon, 15 Jan 2024 16:17:25 +0100 Subject: [PATCH 09/37] Added scaffolding for Mitre ATT&CK categories --- kraken-proto/proto/attacks.proto | 2 + kraken-proto/proto/attacks.shared.proto | 9 + kraken-proto/src/convert.rs | 8 + kraken-proto/src/lib.rs | 1 + kraken-proto/src/mitre.rs | 2024 +++++++++++++++++++++++ leech/src/modules/testssl/mitre.rs | 7 + leech/src/modules/testssl/mod.rs | 3 +- leech/src/rpc/attacks.rs | 6 +- 8 files changed, 2058 insertions(+), 2 deletions(-) create mode 100644 kraken-proto/src/mitre.rs create mode 100644 leech/src/modules/testssl/mitre.rs diff --git a/kraken-proto/proto/attacks.proto b/kraken-proto/proto/attacks.proto index 796b143d7..1f86992c7 100644 --- a/kraken-proto/proto/attacks.proto +++ b/kraken-proto/proto/attacks.proto @@ -388,6 +388,8 @@ message TestSSLFinding { optional string cve = 4; // The associated CWE optional string cwe = 5; + // The MITRE ATT&CK tactic and technique associated with this weakness + optional shared.AttackTechnique mitre = 6; } // A TestSSLFinding's severity diff --git a/kraken-proto/proto/attacks.shared.proto b/kraken-proto/proto/attacks.shared.proto index 2e9a7eceb..870389bc6 100644 --- a/kraken-proto/proto/attacks.shared.proto +++ b/kraken-proto/proto/attacks.shared.proto @@ -127,3 +127,12 @@ message CertEntry { // The serial number of the certificate string serial_number = 6; } + +// A mitre ATT&CK tactic and technique +message AttackTechnique { + // The tactic's id i.e. TA00xx + optional uint32 tactic = 1; + + // The technique's id i.e. Txxxx + optional uint32 technique = 2; +} \ No newline at end of file diff --git a/kraken-proto/src/convert.rs b/kraken-proto/src/convert.rs index c4b4c8a73..9f839a9e8 100644 --- a/kraken-proto/src/convert.rs +++ b/kraken-proto/src/convert.rs @@ -44,6 +44,14 @@ pub enum InvalidArgumentError { /// Received an invalid value for a ipv4 network prefix #[error("Got invalid network prefix for v6: {}", .0)] InvalidV6Prefix(u32), + + /// Received an unknown mitre att&ck tactic + #[error("Got unknown mitre att&ck tactic: TA{:04}", .0)] + InvalidMitreTactic(u32), + + /// Received an unknown mitre att&ck technique + #[error("Got unknown mitre att&ck technique: T{:04} (for TA{:04})", .1, .0)] + InvalidMitreTechnique(u32, u32), } impl From for Status { fn from(value: InvalidArgumentError) -> Self { diff --git a/kraken-proto/src/lib.rs b/kraken-proto/src/lib.rs index c5c40d5f9..bc97ba457 100644 --- a/kraken-proto/src/lib.rs +++ b/kraken-proto/src/lib.rs @@ -5,6 +5,7 @@ pub use convert::InvalidArgumentError; pub use generated::*; mod convert; +pub mod mitre; #[allow(clippy::unwrap_used, clippy::expect_used)] mod generated { diff --git a/kraken-proto/src/mitre.rs b/kraken-proto/src/mitre.rs new file mode 100644 index 000000000..8d981ca5e --- /dev/null +++ b/kraken-proto/src/mitre.rs @@ -0,0 +1,2024 @@ +use crate::InvalidArgumentError; +use crate::shared::AttackTechnique; +pub enum Tactic { + /// [Credential Access](https://attack.mitre.org/tactics/TA0006) + /// + /// The adversary is trying to steal account names and passwords. + CredentialAccess(CredentialAccess), + + /// [Execution](https://attack.mitre.org/tactics/TA0002) + /// + /// The adversary is trying to run malicious code. + Execution(Execution), + + /// [Impact](https://attack.mitre.org/tactics/TA0040) + /// + /// The adversary is trying to manipulate, interrupt, or destroy your systems and data. + Impact(Impact), + + /// [Persistence](https://attack.mitre.org/tactics/TA0003) + /// + /// The adversary is trying to maintain their foothold. + Persistence(Persistence), + + /// [Privilege Escalation](https://attack.mitre.org/tactics/TA0004) + /// + /// The adversary is trying to gain higher-level permissions. + PrivilegeEscalation(PrivilegeEscalation), + + /// [Lateral Movement](https://attack.mitre.org/tactics/TA0008) + /// + /// The adversary is trying to move through your environment. + LateralMovement(LateralMovement), + + /// [Defense Evasion](https://attack.mitre.org/tactics/TA0005) + /// + /// The adversary is trying to avoid being detected. + DefenseEvasion(DefenseEvasion), + + /// [Exfiltration](https://attack.mitre.org/tactics/TA0010) + /// + /// The adversary is trying to steal data. + Exfiltration(Exfiltration), + + /// [Discovery](https://attack.mitre.org/tactics/TA0007) + /// + /// The adversary is trying to figure out your environment. + Discovery(Discovery), + + /// [Collection](https://attack.mitre.org/tactics/TA0009) + /// + /// The adversary is trying to gather data of interest to their goal. + Collection(Collection), + + /// [Resource Development](https://attack.mitre.org/tactics/TA0042) + /// + /// The adversary is trying to establish resources they can use to support operations. + ResourceDevelopment(ResourceDevelopment), + + /// [Reconnaissance](https://attack.mitre.org/tactics/TA0043) + /// + /// The adversary is trying to gather information they can use to plan future operations. + Reconnaissance(Reconnaissance), + + /// [Command and Control](https://attack.mitre.org/tactics/TA0011) + /// + /// The adversary is trying to communicate with compromised systems to control them. + CommandAndControl(CommandAndControl), + + /// [Initial Access](https://attack.mitre.org/tactics/TA0001) + /// + /// The adversary is trying to get into your network. + InitialAccess(InitialAccess), + + Other, +} +pub enum CredentialAccess { + /// [Adversary-in-the-Middle](https://attack.mitre.org/techniques/T1557) + /// + /// Adversaries may attempt to position themselves between two or more networked devices using an adversary-in-the-middle (AiTM) technique to support follow-on behaviors such as [Network Sniffing](https://attack.mitre.org/techniques/T1040), [Transmitted Data Manipulation](https://attack.mitre.org/techniques/T1565/002), or replay attacks ([Exploitation for Credential Access](https://attack.mitre.org/techniques/T1212)). By abusing features of common networking protocols that can determine the flow of network traffic (e.g. ARP, DNS, LLMNR, etc.), adversaries may force a device to communicate through an adversary controlled system so they can collect information or perform additional actions.(Citation: Rapid7 MiTM Basics) + AdversaryInTheMiddle, + + /// [OS Credential Dumping](https://attack.mitre.org/techniques/T1003) + /// + /// Adversaries may attempt to dump credentials to obtain account login and credential material, normally in the form of a hash or a clear text password, from the operating system and software. Credentials can then be used to perform [Lateral Movement](https://attack.mitre.org/tactics/TA0008) and access restricted information. + OsCredentialDumping, + + /// [Steal Web Session Cookie](https://attack.mitre.org/techniques/T1539) + /// + /// An adversary may steal web application or service session cookies and use them to gain access to web applications or Internet services as an authenticated user without needing credentials. Web applications and services often use session cookies as an authentication token after a user has authenticated to a website. + StealWebSessionCookie, + + /// [Network Sniffing](https://attack.mitre.org/techniques/T1040) + /// + /// Adversaries may sniff network traffic to capture information about an environment, including authentication material passed over the network. Network sniffing refers to using the network interface on a system to monitor or capture information sent over a wired or wireless connection. An adversary may place a network interface into promiscuous mode to passively access data in transit over the network, or use span ports to capture a larger amount of data. + NetworkSniffing, + + /// [Steal or Forge Kerberos Tickets](https://attack.mitre.org/techniques/T1558) + /// + /// Adversaries may attempt to subvert Kerberos authentication by stealing or forging Kerberos tickets to enable [Pass the Ticket](https://attack.mitre.org/techniques/T1550/003). Kerberos is an authentication protocol widely used in modern Windows domain environments. In Kerberos environments, referred to as “realms”, there are three basic participants: client, service, and Key Distribution Center (KDC).(Citation: ADSecurity Kerberos Ring Decoder) Clients request access to a service and through the exchange of Kerberos tickets, originating from KDC, they are granted access after having successfully authenticated. The KDC is responsible for both authentication and ticket granting. Adversaries may attempt to abuse Kerberos by stealing tickets or forging tickets to enable unauthorized access. + StealOrForgeKerberosTickets, + + /// [Credentials from Password Stores](https://attack.mitre.org/techniques/T1555) + /// + /// Adversaries may search for common password storage locations to obtain user credentials. Passwords are stored in several places on a system, depending on the operating system or application holding the credentials. There are also specific applications and services that store passwords to make them easier for users to manage and maintain, such as password managers and cloud secrets vaults. Once credentials are obtained, they can be used to perform lateral movement and access restricted information. + CredentialsFromPasswordStores, + + /// [Unsecured Credentials](https://attack.mitre.org/techniques/T1552) + /// + /// Adversaries may search compromised systems to find and obtain insecurely stored credentials. These credentials can be stored and/or misplaced in many locations on a system, including plaintext files (e.g. [Bash History](https://attack.mitre.org/techniques/T1552/003)), operating system or application-specific repositories (e.g. [Credentials in Registry](https://attack.mitre.org/techniques/T1552/002)), or other specialized files/artifacts (e.g. [Private Keys](https://attack.mitre.org/techniques/T1552/004)). + UnsecuredCredentials, + + /// [Steal or Forge Authentication Certificates](https://attack.mitre.org/techniques/T1649) + /// + /// Adversaries may steal or forge certificates used for authentication to access remote systems or resources. Digital certificates are often used to sign and encrypt messages and/or files. Certificates are also used as authentication material. For example, Azure AD device certificates and Active Directory Certificate Services (AD CS) certificates bind to an identity and can be used as credentials for domain accounts.(Citation: O365 Blog Azure AD Device IDs)(Citation: Microsoft AD CS Overview) + StealOrForgeAuthenticationCertificates, + + /// [Steal Application Access Token](https://attack.mitre.org/techniques/T1528) + /// + /// Adversaries can steal application access tokens as a means of acquiring credentials to access remote systems and resources. + StealApplicationAccessToken, + + /// [Forge Web Credentials](https://attack.mitre.org/techniques/T1606) + /// + /// Adversaries may forge credential materials that can be used to gain access to web applications or Internet services. Web applications and services (hosted in cloud SaaS environments or on-premise servers) often use session cookies, tokens, or other materials to authenticate and authorize user access. + ForgeWebCredentials, + + /// [Multi-Factor Authentication Request Generation](https://attack.mitre.org/techniques/T1621) + /// + /// Adversaries may attempt to bypass multi-factor authentication (MFA) mechanisms and gain access to accounts by generating MFA requests sent to users. + MultiFactorAuthenticationRequestGeneration, + + /// [Exploitation for Credential Access](https://attack.mitre.org/techniques/T1212) + /// + /// Adversaries may exploit software vulnerabilities in an attempt to collect credentials. Exploitation of a software vulnerability occurs when an adversary takes advantage of a programming error in a program, service, or within the operating system software or kernel itself to execute adversary-controlled code.  + ExploitationForCredentialAccess, + + /// [Brute Force](https://attack.mitre.org/techniques/T1110) + /// + /// Adversaries may use brute force techniques to gain access to accounts when passwords are unknown or when password hashes are obtained. Without knowledge of the password for an account or set of accounts, an adversary may systematically guess the password using a repetitive or iterative mechanism. Brute forcing passwords can take place via interaction with a service that will check the validity of those credentials or offline against previously acquired credential data, such as password hashes. + BruteForce, + + /// [Forced Authentication](https://attack.mitre.org/techniques/T1187) + /// + /// Adversaries may gather credential material by invoking or forcing a user to automatically provide authentication information through a mechanism in which they can intercept. + ForcedAuthentication, + + /// [Input Capture](https://attack.mitre.org/techniques/T1056) + /// + /// Adversaries may use methods of capturing user input to obtain credentials or collect information. During normal system usage, users often provide credentials to various different locations, such as login pages/portals or system dialog boxes. Input capture mechanisms may be transparent to the user (e.g. [Credential API Hooking](https://attack.mitre.org/techniques/T1056/004)) or rely on deceiving the user into providing input into what they believe to be a genuine service (e.g. [Web Portal Capture](https://attack.mitre.org/techniques/T1056/003)). + InputCapture, + + /// [Multi-Factor Authentication Interception](https://attack.mitre.org/techniques/T1111) + /// + /// Adversaries may target multi-factor authentication (MFA) mechanisms, (i.e., smart cards, token generators, etc.) to gain access to credentials that can be used to access systems, services, and network resources. Use of MFA is recommended and provides a higher level of security than usernames and passwords alone, but organizations should be aware of techniques that could be used to intercept and bypass these security mechanisms. + MultiFactorAuthenticationInterception, + + /// [Modify Authentication Process](https://attack.mitre.org/techniques/T1556) + /// + /// Adversaries may modify authentication mechanisms and processes to access user credentials or enable otherwise unwarranted access to accounts. The authentication process is handled by mechanisms, such as the Local Security Authentication Server (LSASS) process and the Security Accounts Manager (SAM) on Windows, pluggable authentication modules (PAM) on Unix-based systems, and authorization plugins on MacOS systems, responsible for gathering, storing, and validating credentials. By modifying an authentication process, an adversary may be able to authenticate to a service or system without using [Valid Accounts](https://attack.mitre.org/techniques/T1078). + ModifyAuthenticationProcess, + + Other, +} +pub enum Execution { + /// [Windows Management Instrumentation](https://attack.mitre.org/techniques/T1047) + /// + /// Adversaries may abuse Windows Management Instrumentation (WMI) to execute malicious commands and payloads. WMI is an administration feature that provides a uniform environment to access Windows system components. The WMI service enables both local and remote access, though the latter is facilitated by [Remote Services](https://attack.mitre.org/techniques/T1021) such as [Distributed Component Object Model](https://attack.mitre.org/techniques/T1021/003) (DCOM) and [Windows Remote Management](https://attack.mitre.org/techniques/T1021/006) (WinRM).(Citation: MSDN WMI) Remote WMI over DCOM operates using port 135, whereas WMI over WinRM operates over port 5985 when using HTTP and 5986 for HTTPS.(Citation: MSDN WMI)(Citation: FireEye WMI 2015) + WindowsManagementInstrumentation, + + /// [Shared Modules](https://attack.mitre.org/techniques/T1129) + /// + /// Adversaries may execute malicious payloads via loading shared modules. Shared modules are executable files that are loaded into processes to provide access to reusable code, such as specific custom functions or invoking OS API functions (i.e., [Native API](https://attack.mitre.org/techniques/T1106)). + SharedModules, + + /// [Scheduled Task/Job](https://attack.mitre.org/techniques/T1053) + /// + /// Adversaries may abuse task scheduling functionality to facilitate initial or recurring execution of malicious code. Utilities exist within all major operating systems to schedule programs or scripts to be executed at a specified date and time. A task can also be scheduled on a remote system, provided the proper authentication is met (ex: RPC and file and printer sharing in Windows environments). Scheduling a task on a remote system typically may require being a member of an admin or otherwise privileged group on the remote system.(Citation: TechNet Task Scheduler Security) + ScheduledTaskJob, + + /// [Native API](https://attack.mitre.org/techniques/T1106) + /// + /// Adversaries may interact with the native OS application programming interface (API) to execute behaviors. Native APIs provide a controlled means of calling low-level OS services within the kernel, such as those involving hardware/devices, memory, and processes.(Citation: NT API Windows)(Citation: Linux Kernel API) These native APIs are leveraged by the OS during system boot (when other system components are not yet initialized) as well as carrying out tasks and requests during routine operations. + NativeApi, + + /// [Deploy Container](https://attack.mitre.org/techniques/T1610) + /// + /// Adversaries may deploy a container into an environment to facilitate execution or evade defenses. In some cases, adversaries may deploy a new container to execute processes associated with a particular image or deployment, such as processes that execute or download malware. In others, an adversary may deploy a new container configured without network rules, user limitations, etc. to bypass existing defenses within the environment. + DeployContainer, + + /// [Command and Scripting Interpreter](https://attack.mitre.org/techniques/T1059) + /// + /// Adversaries may abuse command and script interpreters to execute commands, scripts, or binaries. These interfaces and languages provide ways of interacting with computer systems and are a common feature across many different platforms. Most systems come with some built-in command-line interface and scripting capabilities, for example, macOS and Linux distributions include some flavor of [Unix Shell](https://attack.mitre.org/techniques/T1059/004) while Windows installations include the [Windows Command Shell](https://attack.mitre.org/techniques/T1059/003) and [PowerShell](https://attack.mitre.org/techniques/T1059/001). + CommandAndScriptingInterpreter, + + /// [Container Administration Command](https://attack.mitre.org/techniques/T1609) + /// + /// Adversaries may abuse a container administration service to execute commands within a container. A container administration service such as the Docker daemon, the Kubernetes API server, or the kubelet may allow remote management of containers within an environment.(Citation: Docker Daemon CLI)(Citation: Kubernetes API)(Citation: Kubernetes Kubelet) + ContainerAdministrationCommand, + + /// [User Execution](https://attack.mitre.org/techniques/T1204) + /// + /// An adversary may rely upon specific actions by a user in order to gain execution. Users may be subjected to social engineering to get them to execute malicious code by, for example, opening a malicious document file or link. These user actions will typically be observed as follow-on behavior from forms of [Phishing](https://attack.mitre.org/techniques/T1566). + UserExecution, + + /// [Software Deployment Tools](https://attack.mitre.org/techniques/T1072) + /// + /// Adversaries may gain access to and use third-party software suites installed within an enterprise network, such as administration, monitoring, and deployment systems, to move laterally through the network. Third-party applications and software deployment systems may be in use in the network environment for administration purposes (e.g., SCCM, HBSS, Altiris, etc.). + SoftwareDeploymentTools, + + /// [Inter-Process Communication](https://attack.mitre.org/techniques/T1559) + /// + /// Adversaries may abuse inter-process communication (IPC) mechanisms for local code or command execution. IPC is typically used by processes to share data, communicate with each other, or synchronize execution. IPC is also commonly used to avoid situations such as deadlocks, which occurs when processes are stuck in a cyclic waiting pattern. + InterProcessCommunication, + + /// [Exploitation for Client Execution](https://attack.mitre.org/techniques/T1203) + /// + /// Adversaries may exploit software vulnerabilities in client applications to execute code. Vulnerabilities can exist in software due to unsecure coding practices that can lead to unanticipated behavior. Adversaries can take advantage of certain vulnerabilities through targeted exploitation for the purpose of arbitrary code execution. Oftentimes the most valuable exploits to an offensive toolkit are those that can be used to obtain code execution on a remote system because they can be used to gain access to that system. Users will expect to see files related to the applications they commonly used to do work, so they are a useful target for exploit research and development because of their high utility. + ExploitationForClientExecution, + + /// [System Services](https://attack.mitre.org/techniques/T1569) + /// + /// Adversaries may abuse system services or daemons to execute commands or programs. Adversaries can execute malicious content by interacting with or creating services either locally or remotely. Many services are set to run at boot, which can aid in achieving persistence ([Create or Modify System Process](https://attack.mitre.org/techniques/T1543)), but adversaries can also abuse services for one-time or temporary execution. + SystemServices, + + /// [Cloud Administration Command](https://attack.mitre.org/techniques/T1651) + /// + /// Adversaries may abuse cloud management services to execute commands within virtual machines or hybrid-joined devices. Resources such as AWS Systems Manager, Azure RunCommand, and Runbooks allow users to remotely run scripts in virtual machines by leveraging installed virtual machine agents. Similarly, in Azure AD environments, Microsoft Endpoint Manager allows Global or Intune Administrators to run scripts as SYSTEM on on-premises devices joined to the Azure AD.(Citation: AWS Systems Manager Run Command)(Citation: Microsoft Run Command)(Citation: SpecterOps Lateral Movement from Azure to On-Prem AD 2020) + CloudAdministrationCommand, + + /// [Serverless Execution](https://attack.mitre.org/techniques/T1648) + /// + /// Adversaries may abuse serverless computing, integration, and automation services to execute arbitrary code in cloud environments. Many cloud providers offer a variety of serverless resources, including compute engines, application integration services, and web servers. + ServerlessExecution, + + Other, +} +pub enum Impact { + /// [Disk Wipe](https://attack.mitre.org/techniques/T1561) + /// + /// Adversaries may wipe or corrupt raw disk data on specific systems or in large numbers in a network to interrupt availability to system and network resources. With direct write access to a disk, adversaries may attempt to overwrite portions of disk data. Adversaries may opt to wipe arbitrary portions of disk data and/or wipe disk structures like the master boot record (MBR). A complete wipe of all disk sectors may be attempted. + DiskWipe, + + /// [Service Stop](https://attack.mitre.org/techniques/T1489) + /// + /// Adversaries may stop or disable services on a system to render those services unavailable to legitimate users. Stopping critical services or processes can inhibit or stop response to an incident or aid in the adversary's overall objectives to cause damage to the environment.(Citation: Talos Olympic Destroyer 2018)(Citation: Novetta Blockbuster) + ServiceStop, + + /// [Defacement](https://attack.mitre.org/techniques/T1491) + /// + /// Adversaries may modify visual content available internally or externally to an enterprise network, thus affecting the integrity of the original content. Reasons for [Defacement](https://attack.mitre.org/techniques/T1491) include delivering messaging, intimidation, or claiming (possibly false) credit for an intrusion. Disturbing or offensive images may be used as a part of [Defacement](https://attack.mitre.org/techniques/T1491) in order to cause user discomfort, or to pressure compliance with accompanying messages. + Defacement, + + /// [Financial Theft](https://attack.mitre.org/techniques/T1657) + /// + /// Adversaries may steal monetary resources from targets through extortion, social engineering, technical theft, or other methods aimed at their own financial gain at the expense of the availability of these resources for victims. Financial theft is the ultimate objective of several popular campaign types including extortion by ransomware,(Citation: FBI-ransomware) business email compromise (BEC) and fraud,(Citation: FBI-BEC) "pig butchering,"(Citation: wired-pig butchering) bank hacking,(Citation: DOJ-DPRK Heist) and exploiting cryptocurrency networks.(Citation: BBC-Ronin) + FinancialTheft, + + /// [Data Manipulation](https://attack.mitre.org/techniques/T1565) + /// + /// Adversaries may insert, delete, or manipulate data in order to influence external outcomes or hide activity, thus threatening the integrity of the data. By manipulating data, adversaries may attempt to affect a business process, organizational understanding, or decision making. + DataManipulation, + + /// [Account Access Removal](https://attack.mitre.org/techniques/T1531) + /// + /// Adversaries may interrupt availability of system and network resources by inhibiting access to accounts utilized by legitimate users. Accounts may be deleted, locked, or manipulated (ex: changed credentials) to remove access to accounts. Adversaries may also subsequently log off and/or perform a [System Shutdown/Reboot](https://attack.mitre.org/techniques/T1529) to set malicious changes into place.(Citation: CarbonBlack LockerGoga 2019)(Citation: Unit42 LockerGoga 2019) + AccountAccessRemoval, + + /// [Data Encrypted for Impact](https://attack.mitre.org/techniques/T1486) + /// + /// Adversaries may encrypt data on target systems or on large numbers of systems in a network to interrupt availability to system and network resources. They can attempt to render stored data inaccessible by encrypting files or data on local and remote drives and withholding access to a decryption key. This may be done in order to extract monetary compensation from a victim in exchange for decryption or a decryption key (ransomware) or to render data permanently inaccessible in cases where the key is not saved or transmitted.(Citation: US-CERT Ransomware 2016)(Citation: FireEye WannaCry 2017)(Citation: US-CERT NotPetya 2017)(Citation: US-CERT SamSam 2018) + DataEncryptedForImpact, + + /// [Endpoint Denial of Service](https://attack.mitre.org/techniques/T1499) + /// + /// Adversaries may perform Endpoint Denial of Service (DoS) attacks to degrade or block the availability of services to users. Endpoint DoS can be performed by exhausting the system resources those services are hosted on or exploiting the system to cause a persistent crash condition. Example services include websites, email services, DNS, and web-based applications. Adversaries have been observed conducting DoS attacks for political purposes(Citation: FireEye OpPoisonedHandover February 2016) and to support other malicious activities, including distraction(Citation: FSISAC FraudNetDoS September 2012), hacktivism, and extortion.(Citation: Symantec DDoS October 2014) + EndpointDenialOfService, + + /// [Resource Hijacking](https://attack.mitre.org/techniques/T1496) + /// + /// Adversaries may leverage the resources of co-opted systems to complete resource-intensive tasks, which may impact system and/or hosted service availability. + ResourceHijacking, + + /// [Data Destruction](https://attack.mitre.org/techniques/T1485) + /// + /// Adversaries may destroy data and files on specific systems or in large numbers on a network to interrupt availability to systems, services, and network resources. Data destruction is likely to render stored data irrecoverable by forensic techniques through overwriting files or data on local and remote drives.(Citation: Symantec Shamoon 2012)(Citation: FireEye Shamoon Nov 2016)(Citation: Palo Alto Shamoon Nov 2016)(Citation: Kaspersky StoneDrill 2017)(Citation: Unit 42 Shamoon3 2018)(Citation: Talos Olympic Destroyer 2018) Common operating system file deletion commands such as del and rm often only remove pointers to files without wiping the contents of the files themselves, making the files recoverable by proper forensic methodology. This behavior is distinct from [Disk Content Wipe](https://attack.mitre.org/techniques/T1561/001) and [Disk Structure Wipe](https://attack.mitre.org/techniques/T1561/002) because individual files are destroyed rather than sections of a storage disk or the disk's logical structure. + DataDestruction, + + /// [Network Denial of Service](https://attack.mitre.org/techniques/T1498) + /// + /// Adversaries may perform Network Denial of Service (DoS) attacks to degrade or block the availability of targeted resources to users. Network DoS can be performed by exhausting the network bandwidth services rely on. Example resources include specific websites, email services, DNS, and web-based applications. Adversaries have been observed conducting network DoS attacks for political purposes(Citation: FireEye OpPoisonedHandover February 2016) and to support other malicious activities, including distraction(Citation: FSISAC FraudNetDoS September 2012), hacktivism, and extortion.(Citation: Symantec DDoS October 2014) + NetworkDenialOfService, + + /// [Firmware Corruption](https://attack.mitre.org/techniques/T1495) + /// + /// Adversaries may overwrite or corrupt the flash memory contents of system BIOS or other firmware in devices attached to a system in order to render them inoperable or unable to boot, thus denying the availability to use the devices and/or the system.(Citation: Symantec Chernobyl W95.CIH) Firmware is software that is loaded and executed from non-volatile memory on hardware devices in order to initialize and manage device functionality. These devices may include the motherboard, hard drive, or video cards. + FirmwareCorruption, + + /// [Inhibit System Recovery](https://attack.mitre.org/techniques/T1490) + /// + /// Adversaries may delete or remove built-in data and turn off services designed to aid in the recovery of a corrupted system to prevent recovery.(Citation: Talos Olympic Destroyer 2018)(Citation: FireEye WannaCry 2017) This may deny access to available backups and recovery options. + InhibitSystemRecovery, + + /// [System Shutdown/Reboot](https://attack.mitre.org/techniques/T1529) + /// + /// Adversaries may shutdown/reboot systems to interrupt access to, or aid in the destruction of, those systems. Operating systems may contain commands to initiate a shutdown/reboot of a machine or network device. In some cases, these commands may also be used to initiate a shutdown/reboot of a remote computer or network device via [Network Device CLI](https://attack.mitre.org/techniques/T1059/008) (e.g. reload).(Citation: Microsoft Shutdown Oct 2017)(Citation: alert_TA18_106A) + SystemShutdownReboot, + + Other, +} +pub enum Persistence { + /// [Boot or Logon Initialization Scripts](https://attack.mitre.org/techniques/T1037) + /// + /// Adversaries may use scripts automatically executed at boot or logon initialization to establish persistence. Initialization scripts can be used to perform administrative functions, which may often execute other programs or send information to an internal logging server. These scripts can vary based on operating system and whether applied locally or remotely. + BootOrLogonInitializationScripts, + + /// [Create or Modify System Process](https://attack.mitre.org/techniques/T1543) + /// + /// Adversaries may create or modify system-level processes to repeatedly execute malicious payloads as part of persistence. When operating systems boot up, they can start processes that perform background system functions. On Windows and Linux, these system processes are referred to as services.(Citation: TechNet Services) On macOS, launchd processes known as [Launch Daemon](https://attack.mitre.org/techniques/T1543/004) and [Launch Agent](https://attack.mitre.org/techniques/T1543/001) are run to finish system initialization and load user specific parameters.(Citation: AppleDocs Launch Agent Daemons) + CreateOrModifySystemProcess, + + /// [External Remote Services](https://attack.mitre.org/techniques/T1133) + /// + /// Adversaries may leverage external-facing remote services to initially access and/or persist within a network. Remote services such as VPNs, Citrix, and other access mechanisms allow users to connect to internal enterprise network resources from external locations. There are often remote service gateways that manage connections and credential authentication for these services. Services such as [Windows Remote Management](https://attack.mitre.org/techniques/T1021/006) and [VNC](https://attack.mitre.org/techniques/T1021/005) can also be used externally.(Citation: MacOS VNC software for Remote Desktop) + ExternalRemoteServices, + + /// [Boot or Logon Autostart Execution](https://attack.mitre.org/techniques/T1547) + /// + /// Adversaries may configure system settings to automatically execute a program during system boot or logon to maintain persistence or gain higher-level privileges on compromised systems. Operating systems may have mechanisms for automatically running a program on system boot or account logon.(Citation: Microsoft Run Key)(Citation: MSDN Authentication Packages)(Citation: Microsoft TimeProvider)(Citation: Cylance Reg Persistence Sept 2013)(Citation: Linux Kernel Programming) These mechanisms may include automatically executing programs that are placed in specially designated directories or are referenced by repositories that store configuration information, such as the Windows Registry. An adversary may achieve the same goal by modifying or extending features of the kernel. + BootOrLogonAutostartExecution, + + /// [Office Application Startup](https://attack.mitre.org/techniques/T1137) + /// + /// Adversaries may leverage Microsoft Office-based applications for persistence between startups. Microsoft Office is a fairly common application suite on Windows-based operating systems within an enterprise network. There are multiple mechanisms that can be used with Office for persistence when an Office-based application is started; this can include the use of Office Template Macros and add-ins. + OfficeApplicationStartup, + + /// [Scheduled Task/Job](https://attack.mitre.org/techniques/T1053) + /// + /// Adversaries may abuse task scheduling functionality to facilitate initial or recurring execution of malicious code. Utilities exist within all major operating systems to schedule programs or scripts to be executed at a specified date and time. A task can also be scheduled on a remote system, provided the proper authentication is met (ex: RPC and file and printer sharing in Windows environments). Scheduling a task on a remote system typically may require being a member of an admin or otherwise privileged group on the remote system.(Citation: TechNet Task Scheduler Security) + ScheduledTaskJob, + + /// [Browser Extensions](https://attack.mitre.org/techniques/T1176) + /// + /// Adversaries may abuse Internet browser extensions to establish persistent access to victim systems. Browser extensions or plugins are small programs that can add functionality and customize aspects of Internet browsers. They can be installed directly or through a browser's app store and generally have access and permissions to everything that the browser can access.(Citation: Wikipedia Browser Extension)(Citation: Chrome Extensions Definition) + BrowserExtensions, + + /// [Traffic Signaling](https://attack.mitre.org/techniques/T1205) + /// + /// Adversaries may use traffic signaling to hide open ports or other malicious functionality used for persistence or command and control. Traffic signaling involves the use of a magic value or sequence that must be sent to a system to trigger a special response, such as opening a closed port or executing a malicious task. This may take the form of sending a series of packets with certain characteristics before a port will be opened that the adversary can use for command and control. Usually this series of packets consists of attempted connections to a predefined sequence of closed ports (i.e. [Port Knocking](https://attack.mitre.org/techniques/T1205/001)), but can involve unusual flags, specific strings, or other unique characteristics. After the sequence is completed, opening a port may be accomplished by the host-based firewall, but could also be implemented by custom software. + TrafficSignaling, + + /// [Implant Internal Image](https://attack.mitre.org/techniques/T1525) + /// + /// Adversaries may implant cloud or container images with malicious code to establish persistence after gaining access to an environment. Amazon Web Services (AWS) Amazon Machine Images (AMIs), Google Cloud Platform (GCP) Images, and Azure Images as well as popular container runtimes such as Docker can be implanted or backdoored. Unlike [Upload Malware](https://attack.mitre.org/techniques/T1608/001), this technique focuses on adversaries implanting an image in a registry within a victim’s environment. Depending on how the infrastructure is provisioned, this could provide persistent access if the infrastructure provisioning tool is instructed to always use the latest image.(Citation: Rhino Labs Cloud Image Backdoor Technique Sept 2019) + ImplantInternalImage, + + /// [Pre-OS Boot](https://attack.mitre.org/techniques/T1542) + /// + /// Adversaries may abuse Pre-OS Boot mechanisms as a way to establish persistence on a system. During the booting process of a computer, firmware and various startup services are loaded before the operating system. These programs control flow of execution before the operating system takes control.(Citation: Wikipedia Booting) + PreOsBoot, + + /// [Compromise Client Software Binary](https://attack.mitre.org/techniques/T1554) + /// + /// Adversaries may modify client software binaries to establish persistent access to systems. Client software enables users to access services provided by a server. Common client software types are SSH clients, FTP clients, email clients, and web browsers. + CompromiseClientSoftwareBinary, + + /// [Account Manipulation](https://attack.mitre.org/techniques/T1098) + /// + /// Adversaries may manipulate accounts to maintain and/or elevate access to victim systems. Account manipulation may consist of any action that preserves or modifies adversary access to a compromised account, such as modifying credentials or permission groups. These actions could also include account activity designed to subvert security policies, such as performing iterative password updates to bypass password duration policies and preserve the life of compromised credentials. + AccountManipulation, + + /// [Hijack Execution Flow](https://attack.mitre.org/techniques/T1574) + /// + /// Adversaries may execute their own malicious payloads by hijacking the way operating systems run programs. Hijacking execution flow can be for the purposes of persistence, since this hijacked execution may reoccur over time. Adversaries may also use these mechanisms to elevate privileges or evade defenses, such as application control or other restrictions on execution. + HijackExecutionFlow, + + /// [Valid Accounts](https://attack.mitre.org/techniques/T1078) + /// + /// Adversaries may obtain and abuse credentials of existing accounts as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Compromised credentials may be used to bypass access controls placed on various resources on systems within the network and may even be used for persistent access to remote systems and externally available services, such as VPNs, Outlook Web Access, network devices, and remote desktop.(Citation: volexity_0day_sophos_FW) Compromised credentials may also grant an adversary increased privilege to specific systems or access to restricted areas of the network. Adversaries may choose not to use malware or tools in conjunction with the legitimate access those credentials provide to make it harder to detect their presence. + ValidAccounts, + + /// [Event Triggered Execution](https://attack.mitre.org/techniques/T1546) + /// + /// Adversaries may establish persistence and/or elevate privileges using system mechanisms that trigger execution based on specific events. Various operating systems have means to monitor and subscribe to events such as logons or other user activity such as running specific applications/binaries. Cloud environments may also support various functions and services that monitor and can be invoked in response to specific cloud events.(Citation: Backdooring an AWS account)(Citation: Varonis Power Automate Data Exfiltration)(Citation: Microsoft DART Case Report 001) + EventTriggeredExecution, + + /// [BITS Jobs](https://attack.mitre.org/techniques/T1197) + /// + /// Adversaries may abuse BITS jobs to persistently execute code and perform various background tasks. Windows Background Intelligent Transfer Service (BITS) is a low-bandwidth, asynchronous file transfer mechanism exposed through [Component Object Model](https://attack.mitre.org/techniques/T1559/001) (COM).(Citation: Microsoft COM)(Citation: Microsoft BITS) BITS is commonly used by updaters, messengers, and other applications preferred to operate in the background (using available idle bandwidth) without interrupting other networked applications. File transfer tasks are implemented as BITS jobs, which contain a queue of one or more file operations. + BitsJobs, + + /// [Server Software Component](https://attack.mitre.org/techniques/T1505) + /// + /// Adversaries may abuse legitimate extensible development features of servers to establish persistent access to systems. Enterprise server applications may include features that allow developers to write and install software or scripts to extend the functionality of the main application. Adversaries may install malicious components to extend and abuse server applications.(Citation: volexity_0day_sophos_FW) + ServerSoftwareComponent, + + /// [Create Account](https://attack.mitre.org/techniques/T1136) + /// + /// Adversaries may create an account to maintain access to victim systems. With a sufficient level of access, creating such accounts may be used to establish secondary credentialed access that do not require persistent remote access tools to be deployed on the system. + CreateAccount, + + /// [Power Settings](https://attack.mitre.org/techniques/T1653) + /// + /// Adversaries may impair a system's ability to hibernate, reboot, or shut down in order to extend access to infected machines. When a computer enters a dormant state, some or all software and hardware may cease to operate which can disrupt malicious activity.(Citation: Sleep, shut down, hibernate) + PowerSettings, + + /// [Modify Authentication Process](https://attack.mitre.org/techniques/T1556) + /// + /// Adversaries may modify authentication mechanisms and processes to access user credentials or enable otherwise unwarranted access to accounts. The authentication process is handled by mechanisms, such as the Local Security Authentication Server (LSASS) process and the Security Accounts Manager (SAM) on Windows, pluggable authentication modules (PAM) on Unix-based systems, and authorization plugins on MacOS systems, responsible for gathering, storing, and validating credentials. By modifying an authentication process, an adversary may be able to authenticate to a service or system without using [Valid Accounts](https://attack.mitre.org/techniques/T1078). + ModifyAuthenticationProcess, + + Other, +} +pub enum PrivilegeEscalation { + /// [Boot or Logon Initialization Scripts](https://attack.mitre.org/techniques/T1037) + /// + /// Adversaries may use scripts automatically executed at boot or logon initialization to establish persistence. Initialization scripts can be used to perform administrative functions, which may often execute other programs or send information to an internal logging server. These scripts can vary based on operating system and whether applied locally or remotely. + BootOrLogonInitializationScripts, + + /// [Create or Modify System Process](https://attack.mitre.org/techniques/T1543) + /// + /// Adversaries may create or modify system-level processes to repeatedly execute malicious payloads as part of persistence. When operating systems boot up, they can start processes that perform background system functions. On Windows and Linux, these system processes are referred to as services.(Citation: TechNet Services) On macOS, launchd processes known as [Launch Daemon](https://attack.mitre.org/techniques/T1543/004) and [Launch Agent](https://attack.mitre.org/techniques/T1543/001) are run to finish system initialization and load user specific parameters.(Citation: AppleDocs Launch Agent Daemons) + CreateOrModifySystemProcess, + + /// [Boot or Logon Autostart Execution](https://attack.mitre.org/techniques/T1547) + /// + /// Adversaries may configure system settings to automatically execute a program during system boot or logon to maintain persistence or gain higher-level privileges on compromised systems. Operating systems may have mechanisms for automatically running a program on system boot or account logon.(Citation: Microsoft Run Key)(Citation: MSDN Authentication Packages)(Citation: Microsoft TimeProvider)(Citation: Cylance Reg Persistence Sept 2013)(Citation: Linux Kernel Programming) These mechanisms may include automatically executing programs that are placed in specially designated directories or are referenced by repositories that store configuration information, such as the Windows Registry. An adversary may achieve the same goal by modifying or extending features of the kernel. + BootOrLogonAutostartExecution, + + /// [Scheduled Task/Job](https://attack.mitre.org/techniques/T1053) + /// + /// Adversaries may abuse task scheduling functionality to facilitate initial or recurring execution of malicious code. Utilities exist within all major operating systems to schedule programs or scripts to be executed at a specified date and time. A task can also be scheduled on a remote system, provided the proper authentication is met (ex: RPC and file and printer sharing in Windows environments). Scheduling a task on a remote system typically may require being a member of an admin or otherwise privileged group on the remote system.(Citation: TechNet Task Scheduler Security) + ScheduledTaskJob, + + /// [Process Injection](https://attack.mitre.org/techniques/T1055) + /// + /// Adversaries may inject code into processes in order to evade process-based defenses as well as possibly elevate privileges. Process injection is a method of executing arbitrary code in the address space of a separate live process. Running code in the context of another process may allow access to the process's memory, system/network resources, and possibly elevated privileges. Execution via process injection may also evade detection from security products since the execution is masked under a legitimate process. + ProcessInjection, + + /// [Escape to Host](https://attack.mitre.org/techniques/T1611) + /// + /// Adversaries may break out of a container to gain access to the underlying host. This can allow an adversary access to other containerized resources from the host level or to the host itself. In principle, containerized resources should provide a clear separation of application functionality and be isolated from the host environment.(Citation: Docker Overview) + EscapeToHost, + + /// [Abuse Elevation Control Mechanism](https://attack.mitre.org/techniques/T1548) + /// + /// Adversaries may circumvent mechanisms designed to control elevate privileges to gain higher-level permissions. Most modern systems contain native elevation control mechanisms that are intended to limit privileges that a user can perform on a machine. Authorization has to be granted to specific users in order to perform tasks that can be considered of higher risk. An adversary can perform several methods to take advantage of built-in control mechanisms in order to escalate privileges on a system. + AbuseElevationControlMechanism, + + /// [Account Manipulation](https://attack.mitre.org/techniques/T1098) + /// + /// Adversaries may manipulate accounts to maintain and/or elevate access to victim systems. Account manipulation may consist of any action that preserves or modifies adversary access to a compromised account, such as modifying credentials or permission groups. These actions could also include account activity designed to subvert security policies, such as performing iterative password updates to bypass password duration policies and preserve the life of compromised credentials. + AccountManipulation, + + /// [Hijack Execution Flow](https://attack.mitre.org/techniques/T1574) + /// + /// Adversaries may execute their own malicious payloads by hijacking the way operating systems run programs. Hijacking execution flow can be for the purposes of persistence, since this hijacked execution may reoccur over time. Adversaries may also use these mechanisms to elevate privileges or evade defenses, such as application control or other restrictions on execution. + HijackExecutionFlow, + + /// [Valid Accounts](https://attack.mitre.org/techniques/T1078) + /// + /// Adversaries may obtain and abuse credentials of existing accounts as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Compromised credentials may be used to bypass access controls placed on various resources on systems within the network and may even be used for persistent access to remote systems and externally available services, such as VPNs, Outlook Web Access, network devices, and remote desktop.(Citation: volexity_0day_sophos_FW) Compromised credentials may also grant an adversary increased privilege to specific systems or access to restricted areas of the network. Adversaries may choose not to use malware or tools in conjunction with the legitimate access those credentials provide to make it harder to detect their presence. + ValidAccounts, + + /// [Exploitation for Privilege Escalation](https://attack.mitre.org/techniques/T1068) + /// + /// Adversaries may exploit software vulnerabilities in an attempt to elevate privileges. Exploitation of a software vulnerability occurs when an adversary takes advantage of a programming error in a program, service, or within the operating system software or kernel itself to execute adversary-controlled code. Security constructs such as permission levels will often hinder access to information and use of certain techniques, so adversaries will likely need to perform privilege escalation to include use of software exploitation to circumvent those restrictions. + ExploitationForPrivilegeEscalation, + + /// [Event Triggered Execution](https://attack.mitre.org/techniques/T1546) + /// + /// Adversaries may establish persistence and/or elevate privileges using system mechanisms that trigger execution based on specific events. Various operating systems have means to monitor and subscribe to events such as logons or other user activity such as running specific applications/binaries. Cloud environments may also support various functions and services that monitor and can be invoked in response to specific cloud events.(Citation: Backdooring an AWS account)(Citation: Varonis Power Automate Data Exfiltration)(Citation: Microsoft DART Case Report 001) + EventTriggeredExecution, + + /// [Access Token Manipulation](https://attack.mitre.org/techniques/T1134) + /// + /// Adversaries may modify access tokens to operate under a different user or system security context to perform actions and bypass access controls. Windows uses access tokens to determine the ownership of a running process. A user can manipulate access tokens to make a running process appear as though it is the child of a different process or belongs to someone other than the user that started the process. When this occurs, the process also takes on the security context associated with the new token. + AccessTokenManipulation, + + /// [Domain Policy Modification](https://attack.mitre.org/techniques/T1484) + /// + /// Adversaries may modify the configuration settings of a domain to evade defenses and/or escalate privileges in domain environments. Domains provide a centralized means of managing how computer resources (ex: computers, user accounts) can act, and interact with each other, on a network. The policy of the domain also includes configuration settings that may apply between domains in a multi-domain/forest environment. Modifications to domain settings may include altering domain Group Policy Objects (GPOs) or changing trust settings for domains, including federation trusts. + DomainPolicyModification, + + Other, +} +pub enum LateralMovement { + /// [Taint Shared Content](https://attack.mitre.org/techniques/T1080) + /// + /// + TaintSharedContent, + + /// [Replication Through Removable Media](https://attack.mitre.org/techniques/T1091) + /// + /// Adversaries may move onto systems, possibly those on disconnected or air-gapped networks, by copying malware to removable media and taking advantage of Autorun features when the media is inserted into a system and executes. In the case of Lateral Movement, this may occur through modification of executable files stored on removable media or by copying malware and renaming it to look like a legitimate file to trick users into executing it on a separate system. In the case of Initial Access, this may occur through manual manipulation of the media, modification of systems used to initially format the media, or modification to the media's firmware itself. + ReplicationThroughRemovableMedia, + + /// [Use Alternate Authentication Material](https://attack.mitre.org/techniques/T1550) + /// + /// Adversaries may use alternate authentication material, such as password hashes, Kerberos tickets, and application access tokens, in order to move laterally within an environment and bypass normal system access controls. + UseAlternateAuthenticationMaterial, + + /// [Remote Services](https://attack.mitre.org/techniques/T1021) + /// + /// Adversaries may use [Valid Accounts](https://attack.mitre.org/techniques/T1078) to log into a service that accepts remote connections, such as telnet, SSH, and VNC. The adversary may then perform actions as the logged-on user. + RemoteServices, + + /// [Remote Service Session Hijacking](https://attack.mitre.org/techniques/T1563) + /// + /// Adversaries may take control of preexisting sessions with remote services to move laterally in an environment. Users may use valid credentials to log into a service specifically designed to accept remote connections, such as telnet, SSH, and RDP. When a user logs into a service, a session will be established that will allow them to maintain a continuous interaction with that service. + RemoteServiceSessionHijacking, + + /// [Software Deployment Tools](https://attack.mitre.org/techniques/T1072) + /// + /// Adversaries may gain access to and use third-party software suites installed within an enterprise network, such as administration, monitoring, and deployment systems, to move laterally through the network. Third-party applications and software deployment systems may be in use in the network environment for administration purposes (e.g., SCCM, HBSS, Altiris, etc.). + SoftwareDeploymentTools, + + /// [Exploitation of Remote Services](https://attack.mitre.org/techniques/T1210) + /// + /// Adversaries may exploit remote services to gain unauthorized access to internal systems once inside of a network. Exploitation of a software vulnerability occurs when an adversary takes advantage of a programming error in a program, service, or within the operating system software or kernel itself to execute adversary-controlled code. A common goal for post-compromise exploitation of remote services is for lateral movement to enable access to a remote system. + ExploitationOfRemoteServices, + + /// [Internal Spearphishing](https://attack.mitre.org/techniques/T1534) + /// + /// Adversaries may use internal spearphishing to gain access to additional information or exploit other users within the same organization after they already have access to accounts or systems within the environment. Internal spearphishing is multi-staged campaign where an email account is owned either by controlling the user's device with previously installed malware or by compromising the account credentials of the user. Adversaries attempt to take advantage of a trusted internal account to increase the likelihood of tricking the target into falling for the phish attempt.(Citation: Trend Micro When Phishing Starts from the Inside 2017) + InternalSpearphishing, + + /// [Lateral Tool Transfer](https://attack.mitre.org/techniques/T1570) + /// + /// Adversaries may transfer tools or other files between systems in a compromised environment. Once brought into the victim environment (i.e., [Ingress Tool Transfer](https://attack.mitre.org/techniques/T1105)) files may then be copied from one system to another to stage adversary tools or other files over the course of an operation. + LateralToolTransfer, + + Other, +} +pub enum DefenseEvasion { + /// [Direct Volume Access](https://attack.mitre.org/techniques/T1006) + /// + /// Adversaries may directly access a volume to bypass file access controls and file system monitoring. Windows allows programs to have direct access to logical volumes. Programs with direct access may read and write files directly from the drive by analyzing file system data structures. This technique may bypass Windows file access controls as well as file system monitoring tools. (Citation: Hakobyan 2009) + DirectVolumeAccess, + + /// [Rootkit](https://attack.mitre.org/techniques/T1014) + /// + /// Adversaries may use rootkits to hide the presence of programs, files, network connections, services, drivers, and other system components. Rootkits are programs that hide the existence of malware by intercepting/hooking and modifying operating system API calls that supply system information. (Citation: Symantec Windows Rootkits) + Rootkit, + + /// [Modify Cloud Compute Infrastructure](https://attack.mitre.org/techniques/T1578) + /// + /// An adversary may attempt to modify a cloud account's compute service infrastructure to evade defenses. A modification to the compute service infrastructure can include the creation, deletion, or modification of one or more components such as compute instances, virtual machines, and snapshots. + ModifyCloudComputeInfrastructure, + + /// [Weaken Encryption](https://attack.mitre.org/techniques/T1600) + /// + /// Adversaries may compromise a network device’s encryption capability in order to bypass encryption that would otherwise protect data communications. (Citation: Cisco Synful Knock Evolution) + WeakenEncryption, + + /// [Hide Artifacts](https://attack.mitre.org/techniques/T1564) + /// + /// Adversaries may attempt to hide artifacts associated with their behaviors to evade detection. Operating systems may have features to hide various artifacts, such as important system files and administrative task execution, to avoid disrupting user work environments and prevent users from changing files or features on the system. Adversaries may abuse these features to hide artifacts such as files, directories, user accounts, or other system activity to evade detection.(Citation: Sofacy Komplex Trojan)(Citation: Cybereason OSX Pirrit)(Citation: MalwareBytes ADS July 2015) + HideArtifacts, + + /// [Indirect Command Execution](https://attack.mitre.org/techniques/T1202) + /// + /// Adversaries may abuse utilities that allow for command execution to bypass security restrictions that limit the use of command-line interpreters. Various Windows utilities may be used to execute commands, possibly without invoking [cmd](https://attack.mitre.org/software/S0106). For example, [Forfiles](https://attack.mitre.org/software/S0193), the Program Compatibility Assistant (pcalua.exe), components of the Windows Subsystem for Linux (WSL), as well as other utilities may invoke the execution of programs and commands from a [Command and Scripting Interpreter](https://attack.mitre.org/techniques/T1059), Run window, or via scripts. (Citation: VectorSec ForFiles Aug 2017) (Citation: Evi1cg Forfiles Nov 2017) + IndirectCommandExecution, + + /// [Deobfuscate/Decode Files or Information](https://attack.mitre.org/techniques/T1140) + /// + /// Adversaries may use [Obfuscated Files or Information](https://attack.mitre.org/techniques/T1027) to hide artifacts of an intrusion from analysis. They may require separate mechanisms to decode or deobfuscate that information depending on how they intend to use it. Methods for doing that include built-in functionality of malware or by using utilities present on the system. + DeobfuscateDecodeFilesOrInformation, + + /// [Impair Defenses](https://attack.mitre.org/techniques/T1562) + /// + /// Adversaries may maliciously modify components of a victim environment in order to hinder or disable defensive mechanisms. This not only involves impairing preventative defenses, such as firewalls and anti-virus, but also detection capabilities that defenders can use to audit activity and identify malicious behavior. This may also span both native defenses as well as supplemental capabilities installed by users and administrators. + ImpairDefenses, + + /// [Masquerading](https://attack.mitre.org/techniques/T1036) + /// + /// Adversaries may attempt to manipulate features of their artifacts to make them appear legitimate or benign to users and/or security tools. Masquerading occurs when the name or location of an object, legitimate or malicious, is manipulated or abused for the sake of evading defenses and observation. This may include manipulating file metadata, tricking users into misidentifying the file type, and giving legitimate task or service names. + Masquerading, + + /// [Process Injection](https://attack.mitre.org/techniques/T1055) + /// + /// Adversaries may inject code into processes in order to evade process-based defenses as well as possibly elevate privileges. Process injection is a method of executing arbitrary code in the address space of a separate live process. Running code in the context of another process may allow access to the process's memory, system/network resources, and possibly elevated privileges. Execution via process injection may also evade detection from security products since the execution is masked under a legitimate process. + ProcessInjection, + + /// [Traffic Signaling](https://attack.mitre.org/techniques/T1205) + /// + /// Adversaries may use traffic signaling to hide open ports or other malicious functionality used for persistence or command and control. Traffic signaling involves the use of a magic value or sequence that must be sent to a system to trigger a special response, such as opening a closed port or executing a malicious task. This may take the form of sending a series of packets with certain characteristics before a port will be opened that the adversary can use for command and control. Usually this series of packets consists of attempted connections to a predefined sequence of closed ports (i.e. [Port Knocking](https://attack.mitre.org/techniques/T1205/001)), but can involve unusual flags, specific strings, or other unique characteristics. After the sequence is completed, opening a port may be accomplished by the host-based firewall, but could also be implemented by custom software. + TrafficSignaling, + + /// [System Binary Proxy Execution](https://attack.mitre.org/techniques/T1218) + /// + /// Adversaries may bypass process and/or signature-based defenses by proxying execution of malicious content with signed, or otherwise trusted, binaries. Binaries used in this technique are often Microsoft-signed files, indicating that they have been either downloaded from Microsoft or are already native in the operating system.(Citation: LOLBAS Project) Binaries signed with trusted digital certificates can typically execute on Windows systems protected by digital signature validation. Several Microsoft signed binaries that are default on Windows installations can be used to proxy execution of other files or commands. + SystemBinaryProxyExecution, + + /// [Reflective Code Loading](https://attack.mitre.org/techniques/T1620) + /// + /// Adversaries may reflectively load code into a process in order to conceal the execution of malicious payloads. Reflective loading involves allocating then executing payloads directly within the memory of the process, vice creating a thread or process backed by a file path on disk. Reflectively loaded payloads may be compiled binaries, anonymous files (only present in RAM), or just snubs of fileless executable code (ex: position-independent shellcode).(Citation: Introducing Donut)(Citation: S1 Custom Shellcode Tool)(Citation: Stuart ELF Memory)(Citation: 00sec Droppers)(Citation: Mandiant BYOL) + ReflectiveCodeLoading, + + /// [Use Alternate Authentication Material](https://attack.mitre.org/techniques/T1550) + /// + /// Adversaries may use alternate authentication material, such as password hashes, Kerberos tickets, and application access tokens, in order to move laterally within an environment and bypass normal system access controls. + UseAlternateAuthenticationMaterial, + + /// [Rogue Domain Controller](https://attack.mitre.org/techniques/T1207) + /// + /// Adversaries may register a rogue Domain Controller to enable manipulation of Active Directory data. DCShadow may be used to create a rogue Domain Controller (DC). DCShadow is a method of manipulating Active Directory (AD) data, including objects and schemas, by registering (or reusing an inactive registration) and simulating the behavior of a DC. (Citation: DCShadow Blog) Once registered, a rogue DC may be able to inject and replicate changes into AD infrastructure for any domain object, including credentials and keys. + RogueDomainController, + + /// [Deploy Container](https://attack.mitre.org/techniques/T1610) + /// + /// Adversaries may deploy a container into an environment to facilitate execution or evade defenses. In some cases, adversaries may deploy a new container to execute processes associated with a particular image or deployment, such as processes that execute or download malware. In others, an adversary may deploy a new container configured without network rules, user limitations, etc. to bypass existing defenses within the environment. + DeployContainer, + + /// [Modify Registry](https://attack.mitre.org/techniques/T1112) + /// + /// Adversaries may interact with the Windows Registry to hide configuration information within Registry keys, remove information as part of cleaning up, or as part of other techniques to aid in persistence and execution. + ModifyRegistry, + + /// [Unused/Unsupported Cloud Regions](https://attack.mitre.org/techniques/T1535) + /// + /// Adversaries may create cloud instances in unused geographic service regions in order to evade detection. Access is usually obtained through compromising accounts used to manage cloud infrastructure. + UnusedUnsupportedCloudRegions, + + /// [File and Directory Permissions Modification](https://attack.mitre.org/techniques/T1222) + /// + /// Adversaries may modify file or directory permissions/attributes to evade access control lists (ACLs) and access protected files.(Citation: Hybrid Analysis Icacls1 June 2018)(Citation: Hybrid Analysis Icacls2 May 2018) File and directory permissions are commonly managed by ACLs configured by the file or directory owner, or users with the appropriate permissions. File and directory ACL implementations vary by platform, but generally explicitly designate which users or groups can perform which actions (read, write, execute, etc.). + FileAndDirectoryPermissionsModification, + + /// [Abuse Elevation Control Mechanism](https://attack.mitre.org/techniques/T1548) + /// + /// Adversaries may circumvent mechanisms designed to control elevate privileges to gain higher-level permissions. Most modern systems contain native elevation control mechanisms that are intended to limit privileges that a user can perform on a machine. Authorization has to be granted to specific users in order to perform tasks that can be considered of higher risk. An adversary can perform several methods to take advantage of built-in control mechanisms in order to escalate privileges on a system. + AbuseElevationControlMechanism, + + /// [Indicator Removal](https://attack.mitre.org/techniques/T1070) + /// + /// Adversaries may delete or modify artifacts generated within systems to remove evidence of their presence or hinder defenses. Various artifacts may be created by an adversary or something that can be attributed to an adversary’s actions. Typically these artifacts are used as defensive indicators related to monitored events, such as strings from downloaded files, logs that are generated from user actions, and other data analyzed by defenders. Location, format, and type of artifact (such as command or login history) are often specific to each platform. + IndicatorRemoval, + + /// [Plist File Modification](https://attack.mitre.org/techniques/T1647) + /// + /// Adversaries may modify property list files (plist files) to enable other malicious activity, while also potentially evading and bypassing system defenses. macOS applications use plist files, such as the info.plist file, to store properties and configuration settings that inform the operating system how to handle the application at runtime. Plist files are structured metadata in key-value pairs formatted in XML based on Apple's Core Foundation DTD. Plist files can be saved in text or binary format.(Citation: fileinfo plist file description) + PlistFileModification, + + /// [Pre-OS Boot](https://attack.mitre.org/techniques/T1542) + /// + /// Adversaries may abuse Pre-OS Boot mechanisms as a way to establish persistence on a system. During the booting process of a computer, firmware and various startup services are loaded before the operating system. These programs control flow of execution before the operating system takes control.(Citation: Wikipedia Booting) + PreOsBoot, + + /// [Build Image on Host](https://attack.mitre.org/techniques/T1612) + /// + /// Adversaries may build a container image directly on a host to bypass defenses that monitor for the retrieval of malicious images from a public registry. A remote build request may be sent to the Docker API that includes a Dockerfile that pulls a vanilla base image, such as alpine, from a public or local registry and then builds a custom image upon it.(Citation: Docker Build Image) + BuildImageOnHost, + + /// [Virtualization/Sandbox Evasion](https://attack.mitre.org/techniques/T1497) + /// + /// Adversaries may employ various means to detect and avoid virtualization and analysis environments. This may include changing behaviors based on the results of checks for the presence of artifacts indicative of a virtual machine environment (VME) or sandbox. If the adversary detects a VME, they may alter their malware to disengage from the victim or conceal the core functions of the implant. They may also search for VME artifacts before dropping secondary or additional payloads. Adversaries may use the information learned from [Virtualization/Sandbox Evasion](https://attack.mitre.org/techniques/T1497) during automated discovery to shape follow-on behaviors.(Citation: Deloitte Environment Awareness) + VirtualizationSandboxEvasion, + + /// [Execution Guardrails](https://attack.mitre.org/techniques/T1480) + /// + /// Adversaries may use execution guardrails to constrain execution or actions based on adversary supplied and environment specific conditions that are expected to be present on the target. Guardrails ensure that a payload only executes against an intended target and reduces collateral damage from an adversary’s campaign.(Citation: FireEye Kevin Mandia Guardrails) Values an adversary can provide about a target system or environment to use as guardrails may include specific network share names, attached physical devices, files, joined Active Directory (AD) domains, and local/external IP addresses.(Citation: FireEye Outlook Dec 2019) + ExecutionGuardrails, + + /// [Modify System Image](https://attack.mitre.org/techniques/T1601) + /// + /// Adversaries may make changes to the operating system of embedded network devices to weaken defenses and provide new capabilities for themselves. On such devices, the operating systems are typically monolithic and most of the device functionality and capabilities are contained within a single file. + ModifySystemImage, + + /// [Hijack Execution Flow](https://attack.mitre.org/techniques/T1574) + /// + /// Adversaries may execute their own malicious payloads by hijacking the way operating systems run programs. Hijacking execution flow can be for the purposes of persistence, since this hijacked execution may reoccur over time. Adversaries may also use these mechanisms to elevate privileges or evade defenses, such as application control or other restrictions on execution. + HijackExecutionFlow, + + /// [Valid Accounts](https://attack.mitre.org/techniques/T1078) + /// + /// Adversaries may obtain and abuse credentials of existing accounts as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Compromised credentials may be used to bypass access controls placed on various resources on systems within the network and may even be used for persistent access to remote systems and externally available services, such as VPNs, Outlook Web Access, network devices, and remote desktop.(Citation: volexity_0day_sophos_FW) Compromised credentials may also grant an adversary increased privilege to specific systems or access to restricted areas of the network. Adversaries may choose not to use malware or tools in conjunction with the legitimate access those credentials provide to make it harder to detect their presence. + ValidAccounts, + + /// [Obfuscated Files or Information](https://attack.mitre.org/techniques/T1027) + /// + /// Adversaries may attempt to make an executable or file difficult to discover or analyze by encrypting, encoding, or otherwise obfuscating its contents on the system or in transit. This is common behavior that can be used across different platforms and the network to evade defenses. + ObfuscatedFilesOrInformation, + + /// [Network Boundary Bridging](https://attack.mitre.org/techniques/T1599) + /// + /// Adversaries may bridge network boundaries by compromising perimeter network devices or internal devices responsible for network segmentation. Breaching these devices may enable an adversary to bypass restrictions on traffic routing that otherwise separate trusted and untrusted networks. + NetworkBoundaryBridging, + + /// [Subvert Trust Controls](https://attack.mitre.org/techniques/T1553) + /// + /// Adversaries may undermine security controls that will either warn users of untrusted activity or prevent execution of untrusted programs. Operating systems and security products may contain mechanisms to identify programs or websites as possessing some level of trust. Examples of such features would include a program being allowed to run because it is signed by a valid code signing certificate, a program prompting the user with a warning because it has an attribute set from being downloaded from the Internet, or getting an indication that you are about to connect to an untrusted site. + SubvertTrustControls, + + /// [BITS Jobs](https://attack.mitre.org/techniques/T1197) + /// + /// Adversaries may abuse BITS jobs to persistently execute code and perform various background tasks. Windows Background Intelligent Transfer Service (BITS) is a low-bandwidth, asynchronous file transfer mechanism exposed through [Component Object Model](https://attack.mitre.org/techniques/T1559/001) (COM).(Citation: Microsoft COM)(Citation: Microsoft BITS) BITS is commonly used by updaters, messengers, and other applications preferred to operate in the background (using available idle bandwidth) without interrupting other networked applications. File transfer tasks are implemented as BITS jobs, which contain a queue of one or more file operations. + BitsJobs, + + /// [Impersonation](https://attack.mitre.org/techniques/T1656) + /// + /// Adversaries may impersonate a trusted person or organization in order to persuade and trick a target into performing some action on their behalf. For example, adversaries may communicate with victims (via [Phishing for Information](https://attack.mitre.org/techniques/T1598), [Phishing](https://attack.mitre.org/techniques/T1566), or [Internal Spearphishing](https://attack.mitre.org/techniques/T1534)) while impersonating a known sender such as an executive, colleague, or third-party vendor. Established trust can then be leveraged to accomplish an adversary’s ultimate goals, possibly against multiple victims. + Impersonation, + + /// [Template Injection](https://attack.mitre.org/techniques/T1221) + /// + /// Adversaries may create or modify references in user document templates to conceal malicious code or force authentication attempts. For example, Microsoft’s Office Open XML (OOXML) specification defines an XML-based format for Office documents (.docx, xlsx, .pptx) to replace older binary formats (.doc, .xls, .ppt). OOXML files are packed together ZIP archives compromised of various XML files, referred to as parts, containing properties that collectively define how a document is rendered.(Citation: Microsoft Open XML July 2017) + TemplateInjection, + + /// [Access Token Manipulation](https://attack.mitre.org/techniques/T1134) + /// + /// Adversaries may modify access tokens to operate under a different user or system security context to perform actions and bypass access controls. Windows uses access tokens to determine the ownership of a running process. A user can manipulate access tokens to make a running process appear as though it is the child of a different process or belongs to someone other than the user that started the process. When this occurs, the process also takes on the security context associated with the new token. + AccessTokenManipulation, + + /// [Debugger Evasion](https://attack.mitre.org/techniques/T1622) + /// + /// Adversaries may employ various means to detect and avoid debuggers. Debuggers are typically used by defenders to trace and/or analyze the execution of potential malware payloads.(Citation: ProcessHacker Github) + DebuggerEvasion, + + /// [Domain Policy Modification](https://attack.mitre.org/techniques/T1484) + /// + /// Adversaries may modify the configuration settings of a domain to evade defenses and/or escalate privileges in domain environments. Domains provide a centralized means of managing how computer resources (ex: computers, user accounts) can act, and interact with each other, on a network. The policy of the domain also includes configuration settings that may apply between domains in a multi-domain/forest environment. Modifications to domain settings may include altering domain Group Policy Objects (GPOs) or changing trust settings for domains, including federation trusts. + DomainPolicyModification, + + /// [XSL Script Processing](https://attack.mitre.org/techniques/T1220) + /// + /// Adversaries may bypass application control and obscure execution of code by embedding scripts inside XSL files. Extensible Stylesheet Language (XSL) files are commonly used to describe the processing and rendering of data within XML files. To support complex operations, the XSL standard includes support for embedded scripting in various languages. (Citation: Microsoft XSLT Script Mar 2017) + XslScriptProcessing, + + /// [Modify Authentication Process](https://attack.mitre.org/techniques/T1556) + /// + /// Adversaries may modify authentication mechanisms and processes to access user credentials or enable otherwise unwarranted access to accounts. The authentication process is handled by mechanisms, such as the Local Security Authentication Server (LSASS) process and the Security Accounts Manager (SAM) on Windows, pluggable authentication modules (PAM) on Unix-based systems, and authorization plugins on MacOS systems, responsible for gathering, storing, and validating credentials. By modifying an authentication process, an adversary may be able to authenticate to a service or system without using [Valid Accounts](https://attack.mitre.org/techniques/T1078). + ModifyAuthenticationProcess, + + /// [System Script Proxy Execution](https://attack.mitre.org/techniques/T1216) + /// + /// Adversaries may use trusted scripts, often signed with certificates, to proxy the execution of malicious files. Several Microsoft signed scripts that have been downloaded from Microsoft or are default on Windows installations can be used to proxy execution of other files.(Citation: LOLBAS Project) This behavior may be abused by adversaries to execute malicious files that could bypass application control and signature validation on systems.(Citation: GitHub Ultimate AppLocker Bypass List) + SystemScriptProxyExecution, + + /// [Exploitation for Defense Evasion](https://attack.mitre.org/techniques/T1211) + /// + /// Adversaries may exploit a system or application vulnerability to bypass security features. Exploitation of a vulnerability occurs when an adversary takes advantage of a programming error in a program, service, or within the operating system software or kernel itself to execute adversary-controlled code. Vulnerabilities may exist in defensive security software that can be used to disable or circumvent them. + ExploitationForDefenseEvasion, + + /// [Trusted Developer Utilities Proxy Execution](https://attack.mitre.org/techniques/T1127) + /// + /// Adversaries may take advantage of trusted developer utilities to proxy execution of malicious payloads. There are many utilities used for software development related tasks that can be used to execute code in various forms to assist in development, debugging, and reverse engineering.(Citation: engima0x3 DNX Bypass)(Citation: engima0x3 RCSI Bypass)(Citation: Exploit Monday WinDbg)(Citation: LOLBAS Tracker) These utilities may often be signed with legitimate certificates that allow them to execute on a system and proxy execution of malicious code through a trusted process that effectively bypasses application control solutions. + TrustedDeveloperUtilitiesProxyExecution, + + Other, +} +pub enum Exfiltration { + /// [Exfiltration Over Web Service](https://attack.mitre.org/techniques/T1567) + /// + /// Adversaries may use an existing, legitimate external Web service to exfiltrate data rather than their primary command and control channel. Popular Web services acting as an exfiltration mechanism may give a significant amount of cover due to the likelihood that hosts within a network are already communicating with them prior to compromise. Firewall rules may also already exist to permit traffic to these services. + ExfiltrationOverWebService, + + /// [Scheduled Transfer](https://attack.mitre.org/techniques/T1029) + /// + /// Adversaries may schedule data exfiltration to be performed only at certain times of day or at certain intervals. This could be done to blend traffic patterns with normal activity or availability. + ScheduledTransfer, + + /// [Exfiltration Over Other Network Medium](https://attack.mitre.org/techniques/T1011) + /// + /// Adversaries may attempt to exfiltrate data over a different network medium than the command and control channel. If the command and control network is a wired Internet connection, the exfiltration may occur, for example, over a WiFi connection, modem, cellular data connection, Bluetooth, or another radio frequency (RF) channel. + ExfiltrationOverOtherNetworkMedium, + + /// [Automated Exfiltration](https://attack.mitre.org/techniques/T1020) + /// + /// Adversaries may exfiltrate data, such as sensitive documents, through the use of automated processing after being gathered during Collection. + AutomatedExfiltration, + + /// [Exfiltration Over C2 Channel](https://attack.mitre.org/techniques/T1041) + /// + /// Adversaries may steal data by exfiltrating it over an existing command and control channel. Stolen data is encoded into the normal communications channel using the same protocol as command and control communications. + ExfiltrationOverC2Channel, + + /// [Exfiltration Over Alternative Protocol](https://attack.mitre.org/techniques/T1048) + /// + /// Adversaries may steal data by exfiltrating it over a different protocol than that of the existing command and control channel. The data may also be sent to an alternate network location from the main command and control server. + ExfiltrationOverAlternativeProtocol, + + /// [Data Transfer Size Limits](https://attack.mitre.org/techniques/T1030) + /// + /// An adversary may exfiltrate data in fixed size chunks instead of whole files or limit packet sizes below certain thresholds. This approach may be used to avoid triggering network data transfer threshold alerts. + DataTransferSizeLimits, + + /// [Transfer Data to Cloud Account](https://attack.mitre.org/techniques/T1537) + /// + /// Adversaries may exfiltrate data by transferring the data, including backups of cloud environments, to another cloud account they control on the same service to avoid typical file transfers/downloads and network-based exfiltration detection. + TransferDataToCloudAccount, + + /// [Exfiltration Over Physical Medium](https://attack.mitre.org/techniques/T1052) + /// + /// Adversaries may attempt to exfiltrate data via a physical medium, such as a removable drive. In certain circumstances, such as an air-gapped network compromise, exfiltration could occur via a physical medium or device introduced by a user. Such media could be an external hard drive, USB drive, cellular phone, MP3 player, or other removable storage and processing device. The physical medium or device could be used as the final exfiltration point or to hop between otherwise disconnected systems. + ExfiltrationOverPhysicalMedium, + + Other, +} +pub enum Discovery { + /// [System Owner/User Discovery](https://attack.mitre.org/techniques/T1033) + /// + /// Adversaries may attempt to identify the primary user, currently logged in user, set of users that commonly uses a system, or whether a user is actively using the system. They may do this, for example, by retrieving account usernames or by using [OS Credential Dumping](https://attack.mitre.org/techniques/T1003). The information may be collected in a number of different ways using other Discovery techniques, because user and username details are prevalent throughout a system and include running process ownership, file/directory ownership, session information, and system logs. Adversaries may use the information from [System Owner/User Discovery](https://attack.mitre.org/techniques/T1033) during automated discovery to shape follow-on behaviors, including whether or not the adversary fully infects the target and/or attempts specific actions. + SystemOwnerUserDiscovery, + + /// [Container and Resource Discovery](https://attack.mitre.org/techniques/T1613) + /// + /// Adversaries may attempt to discover containers and other resources that are available within a containers environment. Other resources may include images, deployments, pods, nodes, and other information such as the status of a cluster. + ContainerAndResourceDiscovery, + + /// [Permission Groups Discovery](https://attack.mitre.org/techniques/T1069) + /// + /// Adversaries may attempt to discover group and permission settings. This information can help adversaries determine which user accounts and groups are available, the membership of users in particular groups, and which users and groups have elevated permissions. + PermissionGroupsDiscovery, + + /// [Group Policy Discovery](https://attack.mitre.org/techniques/T1615) + /// + /// Adversaries may gather information on Group Policy settings to identify paths for privilege escalation, security measures applied within a domain, and to discover patterns in domain objects that can be manipulated or used to blend in the environment. Group Policy allows for centralized management of user and computer settings in Active Directory (AD). Group policy objects (GPOs) are containers for group policy settings made up of files stored within a predictable network path `\\SYSVOL\\Policies\`.(Citation: TechNet Group Policy Basics)(Citation: ADSecurity GPO Persistence 2016) + GroupPolicyDiscovery, + + /// [Device Driver Discovery](https://attack.mitre.org/techniques/T1652) + /// + /// Adversaries may attempt to enumerate local device drivers on a victim host. Information about device drivers may highlight various insights that shape follow-on behaviors, such as the function/purpose of the host, present security tools (i.e. [Security Software Discovery](https://attack.mitre.org/techniques/T1518/001)) or other defenses (e.g., [Virtualization/Sandbox Evasion](https://attack.mitre.org/techniques/T1497)), as well as potential exploitable vulnerabilities (e.g., [Exploitation for Privilege Escalation](https://attack.mitre.org/techniques/T1068)). + DeviceDriverDiscovery, + + /// [System Service Discovery](https://attack.mitre.org/techniques/T1007) + /// + /// Adversaries may try to gather information about registered local system services. Adversaries may obtain information about services using tools as well as OS utility commands such as sc query, tasklist /svc, systemctl --type=service, and net start. + SystemServiceDiscovery, + + /// [Network Sniffing](https://attack.mitre.org/techniques/T1040) + /// + /// Adversaries may sniff network traffic to capture information about an environment, including authentication material passed over the network. Network sniffing refers to using the network interface on a system to monitor or capture information sent over a wired or wireless connection. An adversary may place a network interface into promiscuous mode to passively access data in transit over the network, or use span ports to capture a larger amount of data. + NetworkSniffing, + + /// [Network Share Discovery](https://attack.mitre.org/techniques/T1135) + /// + /// Adversaries may look for folders and drives shared on remote systems as a means of identifying sources of information to gather as a precursor for Collection and to identify potential systems of interest for Lateral Movement. Networks often contain shared network drives and folders that enable users to access file directories on various systems across a network. + NetworkShareDiscovery, + + /// [Peripheral Device Discovery](https://attack.mitre.org/techniques/T1120) + /// + /// Adversaries may attempt to gather information about attached peripheral devices and components connected to a computer system.(Citation: Peripheral Discovery Linux)(Citation: Peripheral Discovery macOS) Peripheral devices could include auxiliary resources that support a variety of functionalities such as keyboards, printers, cameras, smart card readers, or removable storage. The information may be used to enhance their awareness of the system and network environment or may be used for further actions. + PeripheralDeviceDiscovery, + + /// [System Information Discovery](https://attack.mitre.org/techniques/T1082) + /// + /// An adversary may attempt to get detailed information about the operating system and hardware, including version, patches, hotfixes, service packs, and architecture. Adversaries may use the information from [System Information Discovery](https://attack.mitre.org/techniques/T1082) during automated discovery to shape follow-on behaviors, including whether or not the adversary fully infects the target and/or attempts specific actions. + SystemInformationDiscovery, + + /// [Application Window Discovery](https://attack.mitre.org/techniques/T1010) + /// + /// Adversaries may attempt to get a listing of open application windows. Window listings could convey information about how the system is used.(Citation: Prevailion DarkWatchman 2021) For example, information about application windows could be used identify potential data to collect as well as identifying security tooling ([Security Software Discovery](https://attack.mitre.org/techniques/T1518/001)) to evade.(Citation: ESET Grandoreiro April 2020) + ApplicationWindowDiscovery, + + /// [Cloud Infrastructure Discovery](https://attack.mitre.org/techniques/T1580) + /// + /// An adversary may attempt to discover infrastructure and resources that are available within an infrastructure-as-a-service (IaaS) environment. This includes compute service resources such as instances, virtual machines, and snapshots as well as resources of other services including the storage and database services. + CloudInfrastructureDiscovery, + + /// [Browser Information Discovery](https://attack.mitre.org/techniques/T1217) + /// + /// Adversaries may enumerate information about browsers to learn more about compromised environments. Data saved by browsers (such as bookmarks, accounts, and browsing history) may reveal a variety of personal information about users (e.g., banking sites, relationships/interests, social media, etc.) as well as details about internal network resources such as servers, tools/dashboards, or other related infrastructure.(Citation: Kaspersky Autofill) + BrowserInformationDiscovery, + + /// [System Network Configuration Discovery](https://attack.mitre.org/techniques/T1016) + /// + /// Adversaries may look for details about the network configuration and settings, such as IP and/or MAC addresses, of systems they access or through information discovery of remote systems. Several operating system administration utilities exist that can be used to gather this information. Examples include [Arp](https://attack.mitre.org/software/S0099), [ipconfig](https://attack.mitre.org/software/S0100)/[ifconfig](https://attack.mitre.org/software/S0101), [nbtstat](https://attack.mitre.org/software/S0102), and [route](https://attack.mitre.org/software/S0103). + SystemNetworkConfigurationDiscovery, + + /// [Account Discovery](https://attack.mitre.org/techniques/T1087) + /// + /// Adversaries may attempt to get a listing of valid accounts, usernames, or email addresses on a system or within a compromised environment. This information can help adversaries determine which accounts exist, which can aid in follow-on behavior such as brute-forcing, spear-phishing attacks, or account takeovers (e.g., [Valid Accounts](https://attack.mitre.org/techniques/T1078)). + AccountDiscovery, + + /// [Domain Trust Discovery](https://attack.mitre.org/techniques/T1482) + /// + /// Adversaries may attempt to gather information on domain trust relationships that may be used to identify lateral movement opportunities in Windows multi-domain/forest environments. Domain trusts provide a mechanism for a domain to allow access to resources based on the authentication procedures of another domain.(Citation: Microsoft Trusts) Domain trusts allow the users of the trusted domain to access resources in the trusting domain. The information discovered may help the adversary conduct [SID-History Injection](https://attack.mitre.org/techniques/T1134/005), [Pass the Ticket](https://attack.mitre.org/techniques/T1550/003), and [Kerberoasting](https://attack.mitre.org/techniques/T1558/003).(Citation: AdSecurity Forging Trust Tickets)(Citation: Harmj0y Domain Trusts) Domain trusts can be enumerated using the `DSEnumerateDomainTrusts()` Win32 API call, .NET methods, and LDAP.(Citation: Harmj0y Domain Trusts) The Windows utility [Nltest](https://attack.mitre.org/software/S0359) is known to be used by adversaries to enumerate domain trusts.(Citation: Microsoft Operation Wilysupply) + DomainTrustDiscovery, + + /// [File and Directory Discovery](https://attack.mitre.org/techniques/T1083) + /// + /// Adversaries may enumerate files and directories or may search in specific locations of a host or network share for certain information within a file system. Adversaries may use the information from [File and Directory Discovery](https://attack.mitre.org/techniques/T1083) during automated discovery to shape follow-on behaviors, including whether or not the adversary fully infects the target and/or attempts specific actions. + FileAndDirectoryDiscovery, + + /// [System Network Connections Discovery](https://attack.mitre.org/techniques/T1049) + /// + /// Adversaries may attempt to get a listing of network connections to or from the compromised system they are currently accessing or from remote systems by querying for information over the network. + SystemNetworkConnectionsDiscovery, + + /// [Virtualization/Sandbox Evasion](https://attack.mitre.org/techniques/T1497) + /// + /// Adversaries may employ various means to detect and avoid virtualization and analysis environments. This may include changing behaviors based on the results of checks for the presence of artifacts indicative of a virtual machine environment (VME) or sandbox. If the adversary detects a VME, they may alter their malware to disengage from the victim or conceal the core functions of the implant. They may also search for VME artifacts before dropping secondary or additional payloads. Adversaries may use the information learned from [Virtualization/Sandbox Evasion](https://attack.mitre.org/techniques/T1497) during automated discovery to shape follow-on behaviors.(Citation: Deloitte Environment Awareness) + VirtualizationSandboxEvasion, + + /// [Cloud Storage Object Discovery](https://attack.mitre.org/techniques/T1619) + /// + /// Adversaries may enumerate objects in cloud storage infrastructure. Adversaries may use this information during automated discovery to shape follow-on behaviors, including requesting all or specific objects from cloud storage. Similar to [File and Directory Discovery](https://attack.mitre.org/techniques/T1083) on a local host, after identifying available storage services (i.e. [Cloud Infrastructure Discovery](https://attack.mitre.org/techniques/T1580)) adversaries may access the contents/objects stored in cloud infrastructure. + CloudStorageObjectDiscovery, + + /// [Log Enumeration](https://attack.mitre.org/techniques/T1654) + /// + /// Adversaries may enumerate system and service logs to find useful data. These logs may highlight various types of valuable insights for an adversary, such as user authentication records ([Account Discovery](https://attack.mitre.org/techniques/T1087)), security or vulnerable software ([Software Discovery](https://attack.mitre.org/techniques/T1518)), or hosts within a compromised network ([Remote System Discovery](https://attack.mitre.org/techniques/T1018)). + LogEnumeration, + + /// [Process Discovery](https://attack.mitre.org/techniques/T1057) + /// + /// Adversaries may attempt to get information about running processes on a system. Information obtained could be used to gain an understanding of common software/applications running on systems within the network. Adversaries may use the information from [Process Discovery](https://attack.mitre.org/techniques/T1057) during automated discovery to shape follow-on behaviors, including whether or not the adversary fully infects the target and/or attempts specific actions. + ProcessDiscovery, + + /// [Password Policy Discovery](https://attack.mitre.org/techniques/T1201) + /// + /// Adversaries may attempt to access detailed information about the password policy used within an enterprise network or cloud environment. Password policies are a way to enforce complex passwords that are difficult to guess or crack through [Brute Force](https://attack.mitre.org/techniques/T1110). This information may help the adversary to create a list of common passwords and launch dictionary and/or brute force attacks which adheres to the policy (e.g. if the minimum password length should be 8, then not trying passwords such as 'pass123'; not checking for more than 3-4 passwords per account if the lockout is set to 6 as to not lock out accounts). + PasswordPolicyDiscovery, + + /// [Query Registry](https://attack.mitre.org/techniques/T1012) + /// + /// Adversaries may interact with the Windows Registry to gather information about the system, configuration, and installed software. + QueryRegistry, + + /// [System Location Discovery](https://attack.mitre.org/techniques/T1614) + /// + /// + SystemLocationDiscovery, + + /// [Cloud Service Discovery](https://attack.mitre.org/techniques/T1526) + /// + /// An adversary may attempt to enumerate the cloud services running on a system after gaining access. These methods can differ from platform-as-a-service (PaaS), to infrastructure-as-a-service (IaaS), or software-as-a-service (SaaS). Many services exist throughout the various cloud providers and can include Continuous Integration and Continuous Delivery (CI/CD), Lambda Functions, Azure AD, etc. They may also include security services, such as AWS GuardDuty and Microsoft Defender for Cloud, and logging services, such as AWS CloudTrail and Google Cloud Audit Logs. + CloudServiceDiscovery, + + /// [Remote System Discovery](https://attack.mitre.org/techniques/T1018) + /// + /// Adversaries may attempt to get a listing of other systems by IP address, hostname, or other logical identifier on a network that may be used for Lateral Movement from the current system. Functionality could exist within remote access tools to enable this, but utilities available on the operating system could also be used such as [Ping](https://attack.mitre.org/software/S0097) or net view using [Net](https://attack.mitre.org/software/S0039). + RemoteSystemDiscovery, + + /// [Network Service Discovery](https://attack.mitre.org/techniques/T1046) + /// + /// Adversaries may attempt to get a listing of services running on remote hosts and local network infrastructure devices, including those that may be vulnerable to remote software exploitation. Common methods to acquire this information include port and/or vulnerability scans using tools that are brought onto a system.(Citation: CISA AR21-126A FIVEHANDS May 2021) + NetworkServiceDiscovery, + + /// [Software Discovery](https://attack.mitre.org/techniques/T1518) + /// + /// Adversaries may attempt to get a listing of software and software versions that are installed on a system or in a cloud environment. Adversaries may use the information from [Software Discovery](https://attack.mitre.org/techniques/T1518) during automated discovery to shape follow-on behaviors, including whether or not the adversary fully infects the target and/or attempts specific actions. + SoftwareDiscovery, + + /// [Cloud Service Dashboard](https://attack.mitre.org/techniques/T1538) + /// + /// An adversary may use a cloud service dashboard GUI with stolen credentials to gain useful information from an operational cloud environment, such as specific services, resources, and features. For example, the GCP Command Center can be used to view all assets, findings of potential security risks, and to run additional queries, such as finding public IP addresses and open ports.(Citation: Google Command Center Dashboard) + CloudServiceDashboard, + + /// [Debugger Evasion](https://attack.mitre.org/techniques/T1622) + /// + /// Adversaries may employ various means to detect and avoid debuggers. Debuggers are typically used by defenders to trace and/or analyze the execution of potential malware payloads.(Citation: ProcessHacker Github) + DebuggerEvasion, + + /// [System Time Discovery](https://attack.mitre.org/techniques/T1124) + /// + /// An adversary may gather the system time and/or time zone from a local or remote system. The system time is set and stored by the Windows Time Service within a domain to maintain time synchronization between systems and services in an enterprise network. (Citation: MSDN System Time)(Citation: Technet Windows Time Service) + SystemTimeDiscovery, + + Other, +} +pub enum Collection { + /// [Screen Capture](https://attack.mitre.org/techniques/T1113) + /// + /// Adversaries may attempt to take screen captures of the desktop to gather information over the course of an operation. Screen capturing functionality may be included as a feature of a remote access tool used in post-compromise operations. Taking a screenshot is also typically possible through native utilities or API calls, such as CopyFromScreen, xwd, or screencapture.(Citation: CopyFromScreen .NET)(Citation: Antiquated Mac Malware) + ScreenCapture, + + /// [Adversary-in-the-Middle](https://attack.mitre.org/techniques/T1557) + /// + /// Adversaries may attempt to position themselves between two or more networked devices using an adversary-in-the-middle (AiTM) technique to support follow-on behaviors such as [Network Sniffing](https://attack.mitre.org/techniques/T1040), [Transmitted Data Manipulation](https://attack.mitre.org/techniques/T1565/002), or replay attacks ([Exploitation for Credential Access](https://attack.mitre.org/techniques/T1212)). By abusing features of common networking protocols that can determine the flow of network traffic (e.g. ARP, DNS, LLMNR, etc.), adversaries may force a device to communicate through an adversary controlled system so they can collect information or perform additional actions.(Citation: Rapid7 MiTM Basics) + AdversaryInTheMiddle, + + /// [Data from Configuration Repository](https://attack.mitre.org/techniques/T1602) + /// + /// Adversaries may collect data related to managed devices from configuration repositories. Configuration repositories are used by management systems in order to configure, manage, and control data on remote systems. Configuration repositories may also facilitate remote access and administration of devices. + DataFromConfigurationRepository, + + /// [Audio Capture](https://attack.mitre.org/techniques/T1123) + /// + /// An adversary can leverage a computer's peripheral devices (e.g., microphones and webcams) or applications (e.g., voice and video call services) to capture audio recordings for the purpose of listening into sensitive conversations to gather information. + AudioCapture, + + /// [Email Collection](https://attack.mitre.org/techniques/T1114) + /// + /// Adversaries may target user email to collect sensitive information. Emails may contain sensitive data, including trade secrets or personal information, that can prove valuable to adversaries. Adversaries can collect or forward email from mail servers or clients. + EmailCollection, + + /// [Data from Removable Media](https://attack.mitre.org/techniques/T1025) + /// + /// Adversaries may search connected removable media on computers they have compromised to find files of interest. Sensitive data can be collected from any removable media (optical disk drive, USB memory, etc.) connected to the compromised system prior to Exfiltration. Interactive command shells may be in use, and common functionality within [cmd](https://attack.mitre.org/software/S0106) may be used to gather information. + DataFromRemovableMedia, + + /// [Automated Collection](https://attack.mitre.org/techniques/T1119) + /// + /// Once established within a system or network, an adversary may use automated techniques for collecting internal data. Methods for performing this technique could include use of a [Command and Scripting Interpreter](https://attack.mitre.org/techniques/T1059) to search for and copy information fitting set criteria such as file type, location, or name at specific time intervals. In cloud-based environments, adversaries may also use cloud APIs, command line interfaces, or extract, transform, and load (ETL) services to automatically collect data. This functionality could also be built into remote access tools. + AutomatedCollection, + + /// [Clipboard Data](https://attack.mitre.org/techniques/T1115) + /// + /// Adversaries may collect data stored in the clipboard from users copying information within or between applications. + ClipboardData, + + /// [Data from Cloud Storage](https://attack.mitre.org/techniques/T1530) + /// + /// Adversaries may access data from cloud storage. + DataFromCloudStorage, + + /// [Data from Local System](https://attack.mitre.org/techniques/T1005) + /// + /// Adversaries may search local system sources, such as file systems and configuration files or local databases, to find files of interest and sensitive data prior to Exfiltration. + DataFromLocalSystem, + + /// [Archive Collected Data](https://attack.mitre.org/techniques/T1560) + /// + /// An adversary may compress and/or encrypt data that is collected prior to exfiltration. Compressing the data can help to obfuscate the collected data and minimize the amount of data sent over the network. Encryption can be used to hide information that is being exfiltrated from detection or make exfiltration less conspicuous upon inspection by a defender. + ArchiveCollectedData, + + /// [Browser Session Hijacking](https://attack.mitre.org/techniques/T1185) + /// + /// Adversaries may take advantage of security vulnerabilities and inherent functionality in browser software to change content, modify user-behaviors, and intercept information as part of various browser session hijacking techniques.(Citation: Wikipedia Man in the Browser) + BrowserSessionHijacking, + + /// [Video Capture](https://attack.mitre.org/techniques/T1125) + /// + /// An adversary can leverage a computer's peripheral devices (e.g., integrated cameras or webcams) or applications (e.g., video call services) to capture video recordings for the purpose of gathering information. Images may also be captured from devices or applications, potentially in specified intervals, in lieu of video files. + VideoCapture, + + /// [Data Staged](https://attack.mitre.org/techniques/T1074) + /// + /// Adversaries may stage collected data in a central location or directory prior to Exfiltration. Data may be kept in separate files or combined into one file through techniques such as [Archive Collected Data](https://attack.mitre.org/techniques/T1560). Interactive command shells may be used, and common functionality within [cmd](https://attack.mitre.org/software/S0106) and bash may be used to copy data into a staging location.(Citation: PWC Cloud Hopper April 2017) + DataStaged, + + /// [Data from Network Shared Drive](https://attack.mitre.org/techniques/T1039) + /// + /// Adversaries may search network shares on computers they have compromised to find files of interest. Sensitive data can be collected from remote systems via shared network drives (host shared directory, network file server, etc.) that are accessible from the current system prior to Exfiltration. Interactive command shells may be in use, and common functionality within [cmd](https://attack.mitre.org/software/S0106) may be used to gather information. + DataFromNetworkSharedDrive, + + /// [Input Capture](https://attack.mitre.org/techniques/T1056) + /// + /// Adversaries may use methods of capturing user input to obtain credentials or collect information. During normal system usage, users often provide credentials to various different locations, such as login pages/portals or system dialog boxes. Input capture mechanisms may be transparent to the user (e.g. [Credential API Hooking](https://attack.mitre.org/techniques/T1056/004)) or rely on deceiving the user into providing input into what they believe to be a genuine service (e.g. [Web Portal Capture](https://attack.mitre.org/techniques/T1056/003)). + InputCapture, + + /// [Data from Information Repositories](https://attack.mitre.org/techniques/T1213) + /// + /// Adversaries may leverage information repositories to mine valuable information. Information repositories are tools that allow for storage of information, typically to facilitate collaboration or information sharing between users, and can store a wide variety of data that may aid adversaries in further objectives, or direct access to the target information. Adversaries may also abuse external sharing features to share sensitive documents with recipients outside of the organization. + DataFromInformationRepositories, + + Other, +} +pub enum ResourceDevelopment { + /// [Acquire Infrastructure](https://attack.mitre.org/techniques/T1583) + /// + /// Adversaries may buy, lease, or rent infrastructure that can be used during targeting. A wide variety of infrastructure exists for hosting and orchestrating adversary operations. Infrastructure solutions include physical or cloud servers, domains, and third-party web services.(Citation: TrendmicroHideoutsLease) Additionally, botnets are available for rent or purchase. + AcquireInfrastructure, + + /// [Compromise Infrastructure](https://attack.mitre.org/techniques/T1584) + /// + /// Adversaries may compromise third-party infrastructure that can be used during targeting. Infrastructure solutions include physical or cloud servers, domains, and third-party web and DNS services. Instead of buying, leasing, or renting infrastructure an adversary may compromise infrastructure and use it during other phases of the adversary lifecycle.(Citation: Mandiant APT1)(Citation: ICANNDomainNameHijacking)(Citation: Talos DNSpionage Nov 2018)(Citation: FireEye EPS Awakens Part 2) Additionally, adversaries may compromise numerous machines to form a botnet they can leverage. + CompromiseInfrastructure, + + /// [Compromise Accounts](https://attack.mitre.org/techniques/T1586) + /// + /// Adversaries may compromise accounts with services that can be used during targeting. For operations incorporating social engineering, the utilization of an online persona may be important. Rather than creating and cultivating accounts (i.e. [Establish Accounts](https://attack.mitre.org/techniques/T1585)), adversaries may compromise existing accounts. Utilizing an existing persona may engender a level of trust in a potential victim if they have a relationship, or knowledge of, the compromised persona. + CompromiseAccounts, + + /// [Stage Capabilities](https://attack.mitre.org/techniques/T1608) + /// + /// Adversaries may upload, install, or otherwise set up capabilities that can be used during targeting. To support their operations, an adversary may need to take capabilities they developed ([Develop Capabilities](https://attack.mitre.org/techniques/T1587)) or obtained ([Obtain Capabilities](https://attack.mitre.org/techniques/T1588)) and stage them on infrastructure under their control. These capabilities may be staged on infrastructure that was previously purchased/rented by the adversary ([Acquire Infrastructure](https://attack.mitre.org/techniques/T1583)) or was otherwise compromised by them ([Compromise Infrastructure](https://attack.mitre.org/techniques/T1584)). Capabilities may also be staged on web services, such as GitHub or Pastebin, or on Platform-as-a-Service (PaaS) offerings that enable users to easily provision applications.(Citation: Volexity Ocean Lotus November 2020)(Citation: Dragos Heroku Watering Hole)(Citation: Malwarebytes Heroku Skimmers)(Citation: Netskope GCP Redirection)(Citation: Netskope Cloud Phishing) + StageCapabilities, + + /// [Establish Accounts](https://attack.mitre.org/techniques/T1585) + /// + /// Adversaries may create and cultivate accounts with services that can be used during targeting. Adversaries can create accounts that can be used to build a persona to further operations. Persona development consists of the development of public information, presence, history and appropriate affiliations. This development could be applied to social media, website, or other publicly available information that could be referenced and scrutinized for legitimacy over the course of an operation using that persona or identity.(Citation: NEWSCASTER2014)(Citation: BlackHatRobinSage) + EstablishAccounts, + + /// [Obtain Capabilities](https://attack.mitre.org/techniques/T1588) + /// + /// Adversaries may buy and/or steal capabilities that can be used during targeting. Rather than developing their own capabilities in-house, adversaries may purchase, freely download, or steal them. Activities may include the acquisition of malware, software (including licenses), exploits, certificates, and information relating to vulnerabilities. Adversaries may obtain capabilities to support their operations throughout numerous phases of the adversary lifecycle. + ObtainCapabilities, + + /// [Acquire Access](https://attack.mitre.org/techniques/T1650) + /// + /// Adversaries may purchase or otherwise acquire an existing access to a target system or network. A variety of online services and initial access broker networks are available to sell access to previously compromised systems.(Citation: Microsoft Ransomware as a Service)(Citation: CrowdStrike Access Brokers)(Citation: Krebs Access Brokers Fortune 500) In some cases, adversary groups may form partnerships to share compromised systems with each other.(Citation: CISA Karakurt 2022) + AcquireAccess, + + /// [Develop Capabilities](https://attack.mitre.org/techniques/T1587) + /// + /// Adversaries may build capabilities that can be used during targeting. Rather than purchasing, freely downloading, or stealing capabilities, adversaries may develop their own capabilities in-house. This is the process of identifying development requirements and building solutions such as malware, exploits, and self-signed certificates. Adversaries may develop capabilities to support their operations throughout numerous phases of the adversary lifecycle.(Citation: Mandiant APT1)(Citation: Kaspersky Sofacy)(Citation: Bitdefender StrongPity June 2020)(Citation: Talos Promethium June 2020) + DevelopCapabilities, + + Other, +} +pub enum Reconnaissance { + /// [Gather Victim Host Information](https://attack.mitre.org/techniques/T1592) + /// + /// Adversaries may gather information about the victim's hosts that can be used during targeting. Information about hosts may include a variety of details, including administrative data (ex: name, assigned IP, functionality, etc.) as well as specifics regarding its configuration (ex: operating system, language, etc.). + GatherVictimHostInformation, + + /// [Search Victim-Owned Websites](https://attack.mitre.org/techniques/T1594) + /// + /// Adversaries may search websites owned by the victim for information that can be used during targeting. Victim-owned websites may contain a variety of details, including names of departments/divisions, physical locations, and data about key employees such as names, roles, and contact info (ex: [Email Addresses](https://attack.mitre.org/techniques/T1589/002)). These sites may also have details highlighting business operations and relationships.(Citation: Comparitech Leak) + SearchVictimOwnedWebsites, + + /// [Gather Victim Identity Information](https://attack.mitre.org/techniques/T1589) + /// + /// Adversaries may gather information about the victim's identity that can be used during targeting. Information about identities may include a variety of details, including personal data (ex: employee names, email addresses, etc.) as well as sensitive details such as credentials. + GatherVictimIdentityInformation, + + /// [Search Open Technical Databases](https://attack.mitre.org/techniques/T1596) + /// + /// Adversaries may search freely available technical databases for information about victims that can be used during targeting. Information about victims may be available in online databases and repositories, such as registrations of domains/certificates as well as public collections of network data/artifacts gathered from traffic and/or scans.(Citation: WHOIS)(Citation: DNS Dumpster)(Citation: Circl Passive DNS)(Citation: Medium SSL Cert)(Citation: SSLShopper Lookup)(Citation: DigitalShadows CDN)(Citation: Shodan) + SearchOpenTechnicalDatabases, + + /// [Active Scanning](https://attack.mitre.org/techniques/T1595) + /// + /// Adversaries may execute active reconnaissance scans to gather information that can be used during targeting. Active scans are those where the adversary probes victim infrastructure via network traffic, as opposed to other forms of reconnaissance that do not involve direct interaction. + ActiveScanning, + + /// [Gather Victim Org Information](https://attack.mitre.org/techniques/T1591) + /// + /// Adversaries may gather information about the victim's organization that can be used during targeting. Information about an organization may include a variety of details, including the names of divisions/departments, specifics of business operations, as well as the roles and responsibilities of key employees. + GatherVictimOrgInformation, + + /// [Gather Victim Network Information](https://attack.mitre.org/techniques/T1590) + /// + /// Adversaries may gather information about the victim's networks that can be used during targeting. Information about networks may include a variety of details, including administrative data (ex: IP ranges, domain names, etc.) as well as specifics regarding its topology and operations. + GatherVictimNetworkInformation, + + /// [Search Open Websites/Domains](https://attack.mitre.org/techniques/T1593) + /// + /// Adversaries may search freely available websites and/or domains for information about victims that can be used during targeting. Information about victims may be available in various online sites, such as social media, new sites, or those hosting information about business operations such as hiring or requested/rewarded contracts.(Citation: Cyware Social Media)(Citation: SecurityTrails Google Hacking)(Citation: ExploitDB GoogleHacking) + SearchOpenWebsitesDomains, + + /// [Search Closed Sources](https://attack.mitre.org/techniques/T1597) + /// + /// Adversaries may search and gather information about victims from closed sources that can be used during targeting. Information about victims may be available for purchase from reputable private sources and databases, such as paid subscriptions to feeds of technical/threat intelligence data.(Citation: D3Secutrity CTI Feeds) Adversaries may also purchase information from less-reputable sources such as dark web or cybercrime blackmarkets.(Citation: ZDNET Selling Data) + SearchClosedSources, + + /// [Phishing for Information](https://attack.mitre.org/techniques/T1598) + /// + /// Adversaries may send phishing messages to elicit sensitive information that can be used during targeting. Phishing for information is an attempt to trick targets into divulging information, frequently credentials or other actionable information. Phishing for information is different from [Phishing](https://attack.mitre.org/techniques/T1566) in that the objective is gathering data from the victim rather than executing malicious code. + PhishingForInformation, + + Other, +} +pub enum CommandAndControl { + /// [Application Layer Protocol](https://attack.mitre.org/techniques/T1071) + /// + /// Adversaries may communicate using OSI application layer protocols to avoid detection/network filtering by blending in with existing traffic. Commands to the remote system, and often the results of those commands, will be embedded within the protocol traffic between the client and server. + ApplicationLayerProtocol, + + /// [Remote Access Software](https://attack.mitre.org/techniques/T1219) + /// + /// An adversary may use legitimate desktop support and remote access software to establish an interactive command and control channel to target systems within networks. These services, such as `VNC`, `Team Viewer`, `AnyDesk`, `ScreenConnect`, `LogMein`, `AmmyyAdmin`, and other remote monitoring and management (RMM) tools, are commonly used as legitimate technical support software and may be allowed by application control within a target environment.(Citation: Symantec Living off the Land)(Citation: CrowdStrike 2015 Global Threat Report)(Citation: CrySyS Blog TeamSpy) + RemoteAccessSoftware, + + /// [Content Injection](https://attack.mitre.org/techniques/T1659) + /// + /// Adversaries may gain access and continuously communicate with victims by injecting malicious content into systems through online network traffic. Rather than luring victims to malicious payloads hosted on a compromised website (i.e., [Drive-by Target](https://attack.mitre.org/techniques/T1608/004) followed by [Drive-by Compromise](https://attack.mitre.org/techniques/T1189)), adversaries may initially access victims through compromised data-transfer channels where they can manipulate traffic and/or inject their own content. These compromised online network channels may also be used to deliver additional payloads (i.e., [Ingress Tool Transfer](https://attack.mitre.org/techniques/T1105)) and other data to already compromised systems.(Citation: ESET MoustachedBouncer) + ContentInjection, + + /// [Traffic Signaling](https://attack.mitre.org/techniques/T1205) + /// + /// Adversaries may use traffic signaling to hide open ports or other malicious functionality used for persistence or command and control. Traffic signaling involves the use of a magic value or sequence that must be sent to a system to trigger a special response, such as opening a closed port or executing a malicious task. This may take the form of sending a series of packets with certain characteristics before a port will be opened that the adversary can use for command and control. Usually this series of packets consists of attempted connections to a predefined sequence of closed ports (i.e. [Port Knocking](https://attack.mitre.org/techniques/T1205/001)), but can involve unusual flags, specific strings, or other unique characteristics. After the sequence is completed, opening a port may be accomplished by the host-based firewall, but could also be implemented by custom software. + TrafficSignaling, + + /// [Protocol Tunneling](https://attack.mitre.org/techniques/T1572) + /// + /// Adversaries may tunnel network communications to and from a victim system within a separate protocol to avoid detection/network filtering and/or enable access to otherwise unreachable systems. Tunneling involves explicitly encapsulating a protocol within another. This behavior may conceal malicious traffic by blending in with existing traffic and/or provide an outer layer of encryption (similar to a VPN). Tunneling could also enable routing of network packets that would otherwise not reach their intended destination, such as SMB, RDP, or other traffic that would be filtered by network appliances or not routed over the Internet. + ProtocolTunneling, + + /// [Communication Through Removable Media](https://attack.mitre.org/techniques/T1092) + /// + /// Adversaries can perform command and control between compromised hosts on potentially disconnected networks using removable media to transfer commands from system to system. Both systems would need to be compromised, with the likelihood that an Internet-connected system was compromised first and the second through lateral movement by [Replication Through Removable Media](https://attack.mitre.org/techniques/T1091). Commands and files would be relayed from the disconnected system to the Internet-connected system to which the adversary has direct access. + CommunicationThroughRemovableMedia, + + /// [Proxy](https://attack.mitre.org/techniques/T1090) + /// + /// Adversaries may use a connection proxy to direct network traffic between systems or act as an intermediary for network communications to a command and control server to avoid direct connections to their infrastructure. Many tools exist that enable traffic redirection through proxies or port redirection, including [HTRAN](https://attack.mitre.org/software/S0040), ZXProxy, and ZXPortMap. (Citation: Trend Micro APT Attack Tools) Adversaries use these types of proxies to manage command and control communications, reduce the number of simultaneous outbound network connections, provide resiliency in the face of connection loss, or to ride over existing trusted communications paths between victims to avoid suspicion. Adversaries may chain together multiple proxies to further disguise the source of malicious traffic. + Proxy, + + /// [Dynamic Resolution](https://attack.mitre.org/techniques/T1568) + /// + /// Adversaries may dynamically establish connections to command and control infrastructure to evade common detections and remediations. This may be achieved by using malware that shares a common algorithm with the infrastructure the adversary uses to receive the malware's communications. These calculations can be used to dynamically adjust parameters such as the domain name, IP address, or port number the malware uses for command and control. + DynamicResolution, + + /// [Web Service](https://attack.mitre.org/techniques/T1102) + /// + /// Adversaries may use an existing, legitimate external Web service as a means for relaying data to/from a compromised system. Popular websites and social media acting as a mechanism for C2 may give a significant amount of cover due to the likelihood that hosts within a network are already communicating with them prior to a compromise. Using common services, such as those offered by Google or Twitter, makes it easier for adversaries to hide in expected noise. Web service providers commonly use SSL/TLS encryption, giving adversaries an added level of protection. + WebService, + + /// [Multi-Stage Channels](https://attack.mitre.org/techniques/T1104) + /// + /// Adversaries may create multiple stages for command and control that are employed under different conditions or for certain functions. Use of multiple stages may obfuscate the command and control channel to make detection more difficult. + MultiStageChannels, + + /// [Data Obfuscation](https://attack.mitre.org/techniques/T1001) + /// + /// Adversaries may obfuscate command and control traffic to make it more difficult to detect. Command and control (C2) communications are hidden (but not necessarily encrypted) in an attempt to make the content more difficult to discover or decipher and to make the communication less conspicuous and hide commands from being seen. This encompasses many methods, such as adding junk data to protocol traffic, using steganography, or impersonating legitimate protocols. + DataObfuscation, + + /// [Non-Standard Port](https://attack.mitre.org/techniques/T1571) + /// + /// Adversaries may communicate using a protocol and port pairing that are typically not associated. For example, HTTPS over port 8088(Citation: Symantec Elfin Mar 2019) or port 587(Citation: Fortinet Agent Tesla April 2018) as opposed to the traditional port 443. Adversaries may make changes to the standard port used by a protocol to bypass filtering or muddle analysis/parsing of network data. + NonStandardPort, + + /// [Encrypted Channel](https://attack.mitre.org/techniques/T1573) + /// + /// Adversaries may employ a known encryption algorithm to conceal command and control traffic rather than relying on any inherent protections provided by a communication protocol. Despite the use of a secure algorithm, these implementations may be vulnerable to reverse engineering if secret keys are encoded and/or generated within malware samples/configuration files. + EncryptedChannel, + + /// [Non-Application Layer Protocol](https://attack.mitre.org/techniques/T1095) + /// + /// Adversaries may use an OSI non-application layer protocol for communication between host and C2 server or among infected hosts within a network. The list of possible protocols is extensive.(Citation: Wikipedia OSI) Specific examples include use of network layer protocols, such as the Internet Control Message Protocol (ICMP), transport layer protocols, such as the User Datagram Protocol (UDP), session layer protocols, such as Socket Secure (SOCKS), as well as redirected/tunneled protocols, such as Serial over LAN (SOL). + NonApplicationLayerProtocol, + + /// [Data Encoding](https://attack.mitre.org/techniques/T1132) + /// + /// Adversaries may encode data to make the content of command and control traffic more difficult to detect. Command and control (C2) information can be encoded using a standard data encoding system. Use of data encoding may adhere to existing protocol specifications and includes use of ASCII, Unicode, Base64, MIME, or other binary-to-text and character encoding systems.(Citation: Wikipedia Binary-to-text Encoding) (Citation: Wikipedia Character Encoding) Some data encoding systems may also result in data compression, such as gzip. + DataEncoding, + + /// [Ingress Tool Transfer](https://attack.mitre.org/techniques/T1105) + /// + /// Adversaries may transfer tools or other files from an external system into a compromised environment. Tools or files may be copied from an external adversary-controlled system to the victim network through the command and control channel or through alternate protocols such as [ftp](https://attack.mitre.org/software/S0095). Once present, adversaries may also transfer/spread tools between victim devices within a compromised environment (i.e. [Lateral Tool Transfer](https://attack.mitre.org/techniques/T1570)). + IngressToolTransfer, + + /// [Fallback Channels](https://attack.mitre.org/techniques/T1008) + /// + /// Adversaries may use fallback or alternate communication channels if the primary channel is compromised or inaccessible in order to maintain reliable command and control and to avoid data transfer thresholds. + FallbackChannels, + + Other, +} +pub enum InitialAccess { + /// [External Remote Services](https://attack.mitre.org/techniques/T1133) + /// + /// Adversaries may leverage external-facing remote services to initially access and/or persist within a network. Remote services such as VPNs, Citrix, and other access mechanisms allow users to connect to internal enterprise network resources from external locations. There are often remote service gateways that manage connections and credential authentication for these services. Services such as [Windows Remote Management](https://attack.mitre.org/techniques/T1021/006) and [VNC](https://attack.mitre.org/techniques/T1021/005) can also be used externally.(Citation: MacOS VNC software for Remote Desktop) + ExternalRemoteServices, + + /// [Replication Through Removable Media](https://attack.mitre.org/techniques/T1091) + /// + /// Adversaries may move onto systems, possibly those on disconnected or air-gapped networks, by copying malware to removable media and taking advantage of Autorun features when the media is inserted into a system and executes. In the case of Lateral Movement, this may occur through modification of executable files stored on removable media or by copying malware and renaming it to look like a legitimate file to trick users into executing it on a separate system. In the case of Initial Access, this may occur through manual manipulation of the media, modification of systems used to initially format the media, or modification to the media's firmware itself. + ReplicationThroughRemovableMedia, + + /// [Supply Chain Compromise](https://attack.mitre.org/techniques/T1195) + /// + /// Adversaries may manipulate products or product delivery mechanisms prior to receipt by a final consumer for the purpose of data or system compromise. + SupplyChainCompromise, + + /// [Exploit Public-Facing Application](https://attack.mitre.org/techniques/T1190) + /// + /// Adversaries may attempt to exploit a weakness in an Internet-facing host or system to initially access a network. The weakness in the system can be a software bug, a temporary glitch, or a misconfiguration. + ExploitPublicFacingApplication, + + /// [Content Injection](https://attack.mitre.org/techniques/T1659) + /// + /// Adversaries may gain access and continuously communicate with victims by injecting malicious content into systems through online network traffic. Rather than luring victims to malicious payloads hosted on a compromised website (i.e., [Drive-by Target](https://attack.mitre.org/techniques/T1608/004) followed by [Drive-by Compromise](https://attack.mitre.org/techniques/T1189)), adversaries may initially access victims through compromised data-transfer channels where they can manipulate traffic and/or inject their own content. These compromised online network channels may also be used to deliver additional payloads (i.e., [Ingress Tool Transfer](https://attack.mitre.org/techniques/T1105)) and other data to already compromised systems.(Citation: ESET MoustachedBouncer) + ContentInjection, + + /// [Trusted Relationship](https://attack.mitre.org/techniques/T1199) + /// + /// Adversaries may breach or otherwise leverage organizations who have access to intended victims. Access through trusted third party relationship abuses an existing connection that may not be protected or receives less scrutiny than standard mechanisms of gaining access to a network. + TrustedRelationship, + + /// [Phishing](https://attack.mitre.org/techniques/T1566) + /// + /// Adversaries may send phishing messages to gain access to victim systems. All forms of phishing are electronically delivered social engineering. Phishing can be targeted, known as spearphishing. In spearphishing, a specific individual, company, or industry will be targeted by the adversary. More generally, adversaries can conduct non-targeted phishing, such as in mass malware spam campaigns. + Phishing, + + /// [Valid Accounts](https://attack.mitre.org/techniques/T1078) + /// + /// Adversaries may obtain and abuse credentials of existing accounts as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Compromised credentials may be used to bypass access controls placed on various resources on systems within the network and may even be used for persistent access to remote systems and externally available services, such as VPNs, Outlook Web Access, network devices, and remote desktop.(Citation: volexity_0day_sophos_FW) Compromised credentials may also grant an adversary increased privilege to specific systems or access to restricted areas of the network. Adversaries may choose not to use malware or tools in conjunction with the legitimate access those credentials provide to make it harder to detect their presence. + ValidAccounts, + + /// [Hardware Additions](https://attack.mitre.org/techniques/T1200) + /// + /// Adversaries may introduce computer accessories, networking hardware, or other computing devices into a system or network that can be used as a vector to gain access. Rather than just connecting and distributing payloads via removable storage (i.e. [Replication Through Removable Media](https://attack.mitre.org/techniques/T1091)), more robust hardware additions can be used to introduce new functionalities and/or features into a system that can then be abused. + HardwareAdditions, + + /// [Drive-by Compromise](https://attack.mitre.org/techniques/T1189) + /// + /// Adversaries may gain access to a system through a user visiting a website over the normal course of browsing. With this technique, the user's web browser is typically targeted for exploitation, but adversaries may also use compromised websites for non-exploitation behavior such as acquiring [Application Access Token](https://attack.mitre.org/techniques/T1550/001). + DriveByCompromise, + + Other, +} +impl TryFrom for Tactic { + type Error = InvalidArgumentError; + fn try_from(value: AttackTechnique) -> Result { + let AttackTechnique { tactic: Some(tactic), technique } = value else { return Ok(Self::Other); }; + Ok(match tactic { + 0006 => Self::CredentialAccess(CredentialAccess::try_from(technique)?), + 0002 => Self::Execution(Execution::try_from(technique)?), + 0040 => Self::Impact(Impact::try_from(technique)?), + 0003 => Self::Persistence(Persistence::try_from(technique)?), + 0004 => Self::PrivilegeEscalation(PrivilegeEscalation::try_from(technique)?), + 0008 => Self::LateralMovement(LateralMovement::try_from(technique)?), + 0005 => Self::DefenseEvasion(DefenseEvasion::try_from(technique)?), + 0010 => Self::Exfiltration(Exfiltration::try_from(technique)?), + 0007 => Self::Discovery(Discovery::try_from(technique)?), + 0009 => Self::Collection(Collection::try_from(technique)?), + 0042 => Self::ResourceDevelopment(ResourceDevelopment::try_from(technique)?), + 0043 => Self::Reconnaissance(Reconnaissance::try_from(technique)?), + 0011 => Self::CommandAndControl(CommandAndControl::try_from(technique)?), + 0001 => Self::InitialAccess(InitialAccess::try_from(technique)?), + _ => return Err(InvalidArgumentError::InvalidMitreTactic(tactic)), + }) + } +} +impl TryFrom> for CredentialAccess { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1557 => Self::AdversaryInTheMiddle, + 1003 => Self::OsCredentialDumping, + 1539 => Self::StealWebSessionCookie, + 1040 => Self::NetworkSniffing, + 1558 => Self::StealOrForgeKerberosTickets, + 1555 => Self::CredentialsFromPasswordStores, + 1552 => Self::UnsecuredCredentials, + 1649 => Self::StealOrForgeAuthenticationCertificates, + 1528 => Self::StealApplicationAccessToken, + 1606 => Self::ForgeWebCredentials, + 1621 => Self::MultiFactorAuthenticationRequestGeneration, + 1212 => Self::ExploitationForCredentialAccess, + 1110 => Self::BruteForce, + 1187 => Self::ForcedAuthentication, + 1056 => Self::InputCapture, + 1111 => Self::MultiFactorAuthenticationInterception, + 1556 => Self::ModifyAuthenticationProcess, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0006, technique)), + }) + } +} +impl TryFrom> for Execution { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1047 => Self::WindowsManagementInstrumentation, + 1129 => Self::SharedModules, + 1053 => Self::ScheduledTaskJob, + 1106 => Self::NativeApi, + 1610 => Self::DeployContainer, + 1059 => Self::CommandAndScriptingInterpreter, + 1609 => Self::ContainerAdministrationCommand, + 1204 => Self::UserExecution, + 1072 => Self::SoftwareDeploymentTools, + 1559 => Self::InterProcessCommunication, + 1203 => Self::ExploitationForClientExecution, + 1569 => Self::SystemServices, + 1651 => Self::CloudAdministrationCommand, + 1648 => Self::ServerlessExecution, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0002, technique)), + }) + } +} +impl TryFrom> for Impact { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1561 => Self::DiskWipe, + 1489 => Self::ServiceStop, + 1491 => Self::Defacement, + 1657 => Self::FinancialTheft, + 1565 => Self::DataManipulation, + 1531 => Self::AccountAccessRemoval, + 1486 => Self::DataEncryptedForImpact, + 1499 => Self::EndpointDenialOfService, + 1496 => Self::ResourceHijacking, + 1485 => Self::DataDestruction, + 1498 => Self::NetworkDenialOfService, + 1495 => Self::FirmwareCorruption, + 1490 => Self::InhibitSystemRecovery, + 1529 => Self::SystemShutdownReboot, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0040, technique)), + }) + } +} +impl TryFrom> for Persistence { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1037 => Self::BootOrLogonInitializationScripts, + 1543 => Self::CreateOrModifySystemProcess, + 1133 => Self::ExternalRemoteServices, + 1547 => Self::BootOrLogonAutostartExecution, + 1137 => Self::OfficeApplicationStartup, + 1053 => Self::ScheduledTaskJob, + 1176 => Self::BrowserExtensions, + 1205 => Self::TrafficSignaling, + 1525 => Self::ImplantInternalImage, + 1542 => Self::PreOsBoot, + 1554 => Self::CompromiseClientSoftwareBinary, + 1098 => Self::AccountManipulation, + 1574 => Self::HijackExecutionFlow, + 1078 => Self::ValidAccounts, + 1546 => Self::EventTriggeredExecution, + 1197 => Self::BitsJobs, + 1505 => Self::ServerSoftwareComponent, + 1136 => Self::CreateAccount, + 1653 => Self::PowerSettings, + 1556 => Self::ModifyAuthenticationProcess, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0003, technique)), + }) + } +} +impl TryFrom> for PrivilegeEscalation { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1037 => Self::BootOrLogonInitializationScripts, + 1543 => Self::CreateOrModifySystemProcess, + 1547 => Self::BootOrLogonAutostartExecution, + 1053 => Self::ScheduledTaskJob, + 1055 => Self::ProcessInjection, + 1611 => Self::EscapeToHost, + 1548 => Self::AbuseElevationControlMechanism, + 1098 => Self::AccountManipulation, + 1574 => Self::HijackExecutionFlow, + 1078 => Self::ValidAccounts, + 1068 => Self::ExploitationForPrivilegeEscalation, + 1546 => Self::EventTriggeredExecution, + 1134 => Self::AccessTokenManipulation, + 1484 => Self::DomainPolicyModification, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0004, technique)), + }) + } +} +impl TryFrom> for LateralMovement { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1080 => Self::TaintSharedContent, + 1091 => Self::ReplicationThroughRemovableMedia, + 1550 => Self::UseAlternateAuthenticationMaterial, + 1021 => Self::RemoteServices, + 1563 => Self::RemoteServiceSessionHijacking, + 1072 => Self::SoftwareDeploymentTools, + 1210 => Self::ExploitationOfRemoteServices, + 1534 => Self::InternalSpearphishing, + 1570 => Self::LateralToolTransfer, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0008, technique)), + }) + } +} +impl TryFrom> for DefenseEvasion { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1006 => Self::DirectVolumeAccess, + 1014 => Self::Rootkit, + 1578 => Self::ModifyCloudComputeInfrastructure, + 1600 => Self::WeakenEncryption, + 1564 => Self::HideArtifacts, + 1202 => Self::IndirectCommandExecution, + 1140 => Self::DeobfuscateDecodeFilesOrInformation, + 1562 => Self::ImpairDefenses, + 1036 => Self::Masquerading, + 1055 => Self::ProcessInjection, + 1205 => Self::TrafficSignaling, + 1218 => Self::SystemBinaryProxyExecution, + 1620 => Self::ReflectiveCodeLoading, + 1550 => Self::UseAlternateAuthenticationMaterial, + 1207 => Self::RogueDomainController, + 1610 => Self::DeployContainer, + 1112 => Self::ModifyRegistry, + 1535 => Self::UnusedUnsupportedCloudRegions, + 1222 => Self::FileAndDirectoryPermissionsModification, + 1548 => Self::AbuseElevationControlMechanism, + 1070 => Self::IndicatorRemoval, + 1647 => Self::PlistFileModification, + 1542 => Self::PreOsBoot, + 1612 => Self::BuildImageOnHost, + 1497 => Self::VirtualizationSandboxEvasion, + 1480 => Self::ExecutionGuardrails, + 1601 => Self::ModifySystemImage, + 1574 => Self::HijackExecutionFlow, + 1078 => Self::ValidAccounts, + 1027 => Self::ObfuscatedFilesOrInformation, + 1599 => Self::NetworkBoundaryBridging, + 1553 => Self::SubvertTrustControls, + 1197 => Self::BitsJobs, + 1656 => Self::Impersonation, + 1221 => Self::TemplateInjection, + 1134 => Self::AccessTokenManipulation, + 1622 => Self::DebuggerEvasion, + 1484 => Self::DomainPolicyModification, + 1220 => Self::XslScriptProcessing, + 1556 => Self::ModifyAuthenticationProcess, + 1216 => Self::SystemScriptProxyExecution, + 1211 => Self::ExploitationForDefenseEvasion, + 1127 => Self::TrustedDeveloperUtilitiesProxyExecution, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0005, technique)), + }) + } +} +impl TryFrom> for Exfiltration { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1567 => Self::ExfiltrationOverWebService, + 1029 => Self::ScheduledTransfer, + 1011 => Self::ExfiltrationOverOtherNetworkMedium, + 1020 => Self::AutomatedExfiltration, + 1041 => Self::ExfiltrationOverC2Channel, + 1048 => Self::ExfiltrationOverAlternativeProtocol, + 1030 => Self::DataTransferSizeLimits, + 1537 => Self::TransferDataToCloudAccount, + 1052 => Self::ExfiltrationOverPhysicalMedium, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0010, technique)), + }) + } +} +impl TryFrom> for Discovery { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1033 => Self::SystemOwnerUserDiscovery, + 1613 => Self::ContainerAndResourceDiscovery, + 1069 => Self::PermissionGroupsDiscovery, + 1615 => Self::GroupPolicyDiscovery, + 1652 => Self::DeviceDriverDiscovery, + 1007 => Self::SystemServiceDiscovery, + 1040 => Self::NetworkSniffing, + 1135 => Self::NetworkShareDiscovery, + 1120 => Self::PeripheralDeviceDiscovery, + 1082 => Self::SystemInformationDiscovery, + 1010 => Self::ApplicationWindowDiscovery, + 1580 => Self::CloudInfrastructureDiscovery, + 1217 => Self::BrowserInformationDiscovery, + 1016 => Self::SystemNetworkConfigurationDiscovery, + 1087 => Self::AccountDiscovery, + 1482 => Self::DomainTrustDiscovery, + 1083 => Self::FileAndDirectoryDiscovery, + 1049 => Self::SystemNetworkConnectionsDiscovery, + 1497 => Self::VirtualizationSandboxEvasion, + 1619 => Self::CloudStorageObjectDiscovery, + 1654 => Self::LogEnumeration, + 1057 => Self::ProcessDiscovery, + 1201 => Self::PasswordPolicyDiscovery, + 1012 => Self::QueryRegistry, + 1614 => Self::SystemLocationDiscovery, + 1526 => Self::CloudServiceDiscovery, + 1018 => Self::RemoteSystemDiscovery, + 1046 => Self::NetworkServiceDiscovery, + 1518 => Self::SoftwareDiscovery, + 1538 => Self::CloudServiceDashboard, + 1622 => Self::DebuggerEvasion, + 1124 => Self::SystemTimeDiscovery, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0007, technique)), + }) + } +} +impl TryFrom> for Collection { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1113 => Self::ScreenCapture, + 1557 => Self::AdversaryInTheMiddle, + 1602 => Self::DataFromConfigurationRepository, + 1123 => Self::AudioCapture, + 1114 => Self::EmailCollection, + 1025 => Self::DataFromRemovableMedia, + 1119 => Self::AutomatedCollection, + 1115 => Self::ClipboardData, + 1530 => Self::DataFromCloudStorage, + 1005 => Self::DataFromLocalSystem, + 1560 => Self::ArchiveCollectedData, + 1185 => Self::BrowserSessionHijacking, + 1125 => Self::VideoCapture, + 1074 => Self::DataStaged, + 1039 => Self::DataFromNetworkSharedDrive, + 1056 => Self::InputCapture, + 1213 => Self::DataFromInformationRepositories, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0009, technique)), + }) + } +} +impl TryFrom> for ResourceDevelopment { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1583 => Self::AcquireInfrastructure, + 1584 => Self::CompromiseInfrastructure, + 1586 => Self::CompromiseAccounts, + 1608 => Self::StageCapabilities, + 1585 => Self::EstablishAccounts, + 1588 => Self::ObtainCapabilities, + 1650 => Self::AcquireAccess, + 1587 => Self::DevelopCapabilities, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0042, technique)), + }) + } +} +impl TryFrom> for Reconnaissance { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1592 => Self::GatherVictimHostInformation, + 1594 => Self::SearchVictimOwnedWebsites, + 1589 => Self::GatherVictimIdentityInformation, + 1596 => Self::SearchOpenTechnicalDatabases, + 1595 => Self::ActiveScanning, + 1591 => Self::GatherVictimOrgInformation, + 1590 => Self::GatherVictimNetworkInformation, + 1593 => Self::SearchOpenWebsitesDomains, + 1597 => Self::SearchClosedSources, + 1598 => Self::PhishingForInformation, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0043, technique)), + }) + } +} +impl TryFrom> for CommandAndControl { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1071 => Self::ApplicationLayerProtocol, + 1219 => Self::RemoteAccessSoftware, + 1659 => Self::ContentInjection, + 1205 => Self::TrafficSignaling, + 1572 => Self::ProtocolTunneling, + 1092 => Self::CommunicationThroughRemovableMedia, + 1090 => Self::Proxy, + 1568 => Self::DynamicResolution, + 1102 => Self::WebService, + 1104 => Self::MultiStageChannels, + 1001 => Self::DataObfuscation, + 1571 => Self::NonStandardPort, + 1573 => Self::EncryptedChannel, + 1095 => Self::NonApplicationLayerProtocol, + 1132 => Self::DataEncoding, + 1105 => Self::IngressToolTransfer, + 1008 => Self::FallbackChannels, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0011, technique)), + }) + } +} +impl TryFrom> for InitialAccess { + type Error = InvalidArgumentError; + fn try_from(value: Option) -> Result { + let Some(technique) = value else { return Ok(Self::Other); }; + Ok(match technique { + 1133 => Self::ExternalRemoteServices, + 1091 => Self::ReplicationThroughRemovableMedia, + 1195 => Self::SupplyChainCompromise, + 1190 => Self::ExploitPublicFacingApplication, + 1659 => Self::ContentInjection, + 1199 => Self::TrustedRelationship, + 1566 => Self::Phishing, + 1078 => Self::ValidAccounts, + 1200 => Self::HardwareAdditions, + 1189 => Self::DriveByCompromise, + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0001, technique)), + }) + } +} +impl From for AttackTechnique { + fn from(value: Tactic) -> Self { + let (tactic, technique) = match value { + Tactic::CredentialAccess(technique) => (Some(0006), technique.into()), + Tactic::Execution(technique) => (Some(0002), technique.into()), + Tactic::Impact(technique) => (Some(0040), technique.into()), + Tactic::Persistence(technique) => (Some(0003), technique.into()), + Tactic::PrivilegeEscalation(technique) => (Some(0004), technique.into()), + Tactic::LateralMovement(technique) => (Some(0008), technique.into()), + Tactic::DefenseEvasion(technique) => (Some(0005), technique.into()), + Tactic::Exfiltration(technique) => (Some(0010), technique.into()), + Tactic::Discovery(technique) => (Some(0007), technique.into()), + Tactic::Collection(technique) => (Some(0009), technique.into()), + Tactic::ResourceDevelopment(technique) => (Some(0042), technique.into()), + Tactic::Reconnaissance(technique) => (Some(0043), technique.into()), + Tactic::CommandAndControl(technique) => (Some(0011), technique.into()), + Tactic::InitialAccess(technique) => (Some(0001), technique.into()), + Tactic::Other => (None, None), + }; + AttackTechnique { tactic, technique } + } +} +impl From for Option { + fn from(value: CredentialAccess) -> Self { + match value { + CredentialAccess::AdversaryInTheMiddle => Some(1557), + CredentialAccess::OsCredentialDumping => Some(1003), + CredentialAccess::StealWebSessionCookie => Some(1539), + CredentialAccess::NetworkSniffing => Some(1040), + CredentialAccess::StealOrForgeKerberosTickets => Some(1558), + CredentialAccess::CredentialsFromPasswordStores => Some(1555), + CredentialAccess::UnsecuredCredentials => Some(1552), + CredentialAccess::StealOrForgeAuthenticationCertificates => Some(1649), + CredentialAccess::StealApplicationAccessToken => Some(1528), + CredentialAccess::ForgeWebCredentials => Some(1606), + CredentialAccess::MultiFactorAuthenticationRequestGeneration => Some(1621), + CredentialAccess::ExploitationForCredentialAccess => Some(1212), + CredentialAccess::BruteForce => Some(1110), + CredentialAccess::ForcedAuthentication => Some(1187), + CredentialAccess::InputCapture => Some(1056), + CredentialAccess::MultiFactorAuthenticationInterception => Some(1111), + CredentialAccess::ModifyAuthenticationProcess => Some(1556), + CredentialAccess::Other => None, + } + } +} +impl From for Option { + fn from(value: Execution) -> Self { + match value { + Execution::WindowsManagementInstrumentation => Some(1047), + Execution::SharedModules => Some(1129), + Execution::ScheduledTaskJob => Some(1053), + Execution::NativeApi => Some(1106), + Execution::DeployContainer => Some(1610), + Execution::CommandAndScriptingInterpreter => Some(1059), + Execution::ContainerAdministrationCommand => Some(1609), + Execution::UserExecution => Some(1204), + Execution::SoftwareDeploymentTools => Some(1072), + Execution::InterProcessCommunication => Some(1559), + Execution::ExploitationForClientExecution => Some(1203), + Execution::SystemServices => Some(1569), + Execution::CloudAdministrationCommand => Some(1651), + Execution::ServerlessExecution => Some(1648), + Execution::Other => None, + } + } +} +impl From for Option { + fn from(value: Impact) -> Self { + match value { + Impact::DiskWipe => Some(1561), + Impact::ServiceStop => Some(1489), + Impact::Defacement => Some(1491), + Impact::FinancialTheft => Some(1657), + Impact::DataManipulation => Some(1565), + Impact::AccountAccessRemoval => Some(1531), + Impact::DataEncryptedForImpact => Some(1486), + Impact::EndpointDenialOfService => Some(1499), + Impact::ResourceHijacking => Some(1496), + Impact::DataDestruction => Some(1485), + Impact::NetworkDenialOfService => Some(1498), + Impact::FirmwareCorruption => Some(1495), + Impact::InhibitSystemRecovery => Some(1490), + Impact::SystemShutdownReboot => Some(1529), + Impact::Other => None, + } + } +} +impl From for Option { + fn from(value: Persistence) -> Self { + match value { + Persistence::BootOrLogonInitializationScripts => Some(1037), + Persistence::CreateOrModifySystemProcess => Some(1543), + Persistence::ExternalRemoteServices => Some(1133), + Persistence::BootOrLogonAutostartExecution => Some(1547), + Persistence::OfficeApplicationStartup => Some(1137), + Persistence::ScheduledTaskJob => Some(1053), + Persistence::BrowserExtensions => Some(1176), + Persistence::TrafficSignaling => Some(1205), + Persistence::ImplantInternalImage => Some(1525), + Persistence::PreOsBoot => Some(1542), + Persistence::CompromiseClientSoftwareBinary => Some(1554), + Persistence::AccountManipulation => Some(1098), + Persistence::HijackExecutionFlow => Some(1574), + Persistence::ValidAccounts => Some(1078), + Persistence::EventTriggeredExecution => Some(1546), + Persistence::BitsJobs => Some(1197), + Persistence::ServerSoftwareComponent => Some(1505), + Persistence::CreateAccount => Some(1136), + Persistence::PowerSettings => Some(1653), + Persistence::ModifyAuthenticationProcess => Some(1556), + Persistence::Other => None, + } + } +} +impl From for Option { + fn from(value: PrivilegeEscalation) -> Self { + match value { + PrivilegeEscalation::BootOrLogonInitializationScripts => Some(1037), + PrivilegeEscalation::CreateOrModifySystemProcess => Some(1543), + PrivilegeEscalation::BootOrLogonAutostartExecution => Some(1547), + PrivilegeEscalation::ScheduledTaskJob => Some(1053), + PrivilegeEscalation::ProcessInjection => Some(1055), + PrivilegeEscalation::EscapeToHost => Some(1611), + PrivilegeEscalation::AbuseElevationControlMechanism => Some(1548), + PrivilegeEscalation::AccountManipulation => Some(1098), + PrivilegeEscalation::HijackExecutionFlow => Some(1574), + PrivilegeEscalation::ValidAccounts => Some(1078), + PrivilegeEscalation::ExploitationForPrivilegeEscalation => Some(1068), + PrivilegeEscalation::EventTriggeredExecution => Some(1546), + PrivilegeEscalation::AccessTokenManipulation => Some(1134), + PrivilegeEscalation::DomainPolicyModification => Some(1484), + PrivilegeEscalation::Other => None, + } + } +} +impl From for Option { + fn from(value: LateralMovement) -> Self { + match value { + LateralMovement::TaintSharedContent => Some(1080), + LateralMovement::ReplicationThroughRemovableMedia => Some(1091), + LateralMovement::UseAlternateAuthenticationMaterial => Some(1550), + LateralMovement::RemoteServices => Some(1021), + LateralMovement::RemoteServiceSessionHijacking => Some(1563), + LateralMovement::SoftwareDeploymentTools => Some(1072), + LateralMovement::ExploitationOfRemoteServices => Some(1210), + LateralMovement::InternalSpearphishing => Some(1534), + LateralMovement::LateralToolTransfer => Some(1570), + LateralMovement::Other => None, + } + } +} +impl From for Option { + fn from(value: DefenseEvasion) -> Self { + match value { + DefenseEvasion::DirectVolumeAccess => Some(1006), + DefenseEvasion::Rootkit => Some(1014), + DefenseEvasion::ModifyCloudComputeInfrastructure => Some(1578), + DefenseEvasion::WeakenEncryption => Some(1600), + DefenseEvasion::HideArtifacts => Some(1564), + DefenseEvasion::IndirectCommandExecution => Some(1202), + DefenseEvasion::DeobfuscateDecodeFilesOrInformation => Some(1140), + DefenseEvasion::ImpairDefenses => Some(1562), + DefenseEvasion::Masquerading => Some(1036), + DefenseEvasion::ProcessInjection => Some(1055), + DefenseEvasion::TrafficSignaling => Some(1205), + DefenseEvasion::SystemBinaryProxyExecution => Some(1218), + DefenseEvasion::ReflectiveCodeLoading => Some(1620), + DefenseEvasion::UseAlternateAuthenticationMaterial => Some(1550), + DefenseEvasion::RogueDomainController => Some(1207), + DefenseEvasion::DeployContainer => Some(1610), + DefenseEvasion::ModifyRegistry => Some(1112), + DefenseEvasion::UnusedUnsupportedCloudRegions => Some(1535), + DefenseEvasion::FileAndDirectoryPermissionsModification => Some(1222), + DefenseEvasion::AbuseElevationControlMechanism => Some(1548), + DefenseEvasion::IndicatorRemoval => Some(1070), + DefenseEvasion::PlistFileModification => Some(1647), + DefenseEvasion::PreOsBoot => Some(1542), + DefenseEvasion::BuildImageOnHost => Some(1612), + DefenseEvasion::VirtualizationSandboxEvasion => Some(1497), + DefenseEvasion::ExecutionGuardrails => Some(1480), + DefenseEvasion::ModifySystemImage => Some(1601), + DefenseEvasion::HijackExecutionFlow => Some(1574), + DefenseEvasion::ValidAccounts => Some(1078), + DefenseEvasion::ObfuscatedFilesOrInformation => Some(1027), + DefenseEvasion::NetworkBoundaryBridging => Some(1599), + DefenseEvasion::SubvertTrustControls => Some(1553), + DefenseEvasion::BitsJobs => Some(1197), + DefenseEvasion::Impersonation => Some(1656), + DefenseEvasion::TemplateInjection => Some(1221), + DefenseEvasion::AccessTokenManipulation => Some(1134), + DefenseEvasion::DebuggerEvasion => Some(1622), + DefenseEvasion::DomainPolicyModification => Some(1484), + DefenseEvasion::XslScriptProcessing => Some(1220), + DefenseEvasion::ModifyAuthenticationProcess => Some(1556), + DefenseEvasion::SystemScriptProxyExecution => Some(1216), + DefenseEvasion::ExploitationForDefenseEvasion => Some(1211), + DefenseEvasion::TrustedDeveloperUtilitiesProxyExecution => Some(1127), + DefenseEvasion::Other => None, + } + } +} +impl From for Option { + fn from(value: Exfiltration) -> Self { + match value { + Exfiltration::ExfiltrationOverWebService => Some(1567), + Exfiltration::ScheduledTransfer => Some(1029), + Exfiltration::ExfiltrationOverOtherNetworkMedium => Some(1011), + Exfiltration::AutomatedExfiltration => Some(1020), + Exfiltration::ExfiltrationOverC2Channel => Some(1041), + Exfiltration::ExfiltrationOverAlternativeProtocol => Some(1048), + Exfiltration::DataTransferSizeLimits => Some(1030), + Exfiltration::TransferDataToCloudAccount => Some(1537), + Exfiltration::ExfiltrationOverPhysicalMedium => Some(1052), + Exfiltration::Other => None, + } + } +} +impl From for Option { + fn from(value: Discovery) -> Self { + match value { + Discovery::SystemOwnerUserDiscovery => Some(1033), + Discovery::ContainerAndResourceDiscovery => Some(1613), + Discovery::PermissionGroupsDiscovery => Some(1069), + Discovery::GroupPolicyDiscovery => Some(1615), + Discovery::DeviceDriverDiscovery => Some(1652), + Discovery::SystemServiceDiscovery => Some(1007), + Discovery::NetworkSniffing => Some(1040), + Discovery::NetworkShareDiscovery => Some(1135), + Discovery::PeripheralDeviceDiscovery => Some(1120), + Discovery::SystemInformationDiscovery => Some(1082), + Discovery::ApplicationWindowDiscovery => Some(1010), + Discovery::CloudInfrastructureDiscovery => Some(1580), + Discovery::BrowserInformationDiscovery => Some(1217), + Discovery::SystemNetworkConfigurationDiscovery => Some(1016), + Discovery::AccountDiscovery => Some(1087), + Discovery::DomainTrustDiscovery => Some(1482), + Discovery::FileAndDirectoryDiscovery => Some(1083), + Discovery::SystemNetworkConnectionsDiscovery => Some(1049), + Discovery::VirtualizationSandboxEvasion => Some(1497), + Discovery::CloudStorageObjectDiscovery => Some(1619), + Discovery::LogEnumeration => Some(1654), + Discovery::ProcessDiscovery => Some(1057), + Discovery::PasswordPolicyDiscovery => Some(1201), + Discovery::QueryRegistry => Some(1012), + Discovery::SystemLocationDiscovery => Some(1614), + Discovery::CloudServiceDiscovery => Some(1526), + Discovery::RemoteSystemDiscovery => Some(1018), + Discovery::NetworkServiceDiscovery => Some(1046), + Discovery::SoftwareDiscovery => Some(1518), + Discovery::CloudServiceDashboard => Some(1538), + Discovery::DebuggerEvasion => Some(1622), + Discovery::SystemTimeDiscovery => Some(1124), + Discovery::Other => None, + } + } +} +impl From for Option { + fn from(value: Collection) -> Self { + match value { + Collection::ScreenCapture => Some(1113), + Collection::AdversaryInTheMiddle => Some(1557), + Collection::DataFromConfigurationRepository => Some(1602), + Collection::AudioCapture => Some(1123), + Collection::EmailCollection => Some(1114), + Collection::DataFromRemovableMedia => Some(1025), + Collection::AutomatedCollection => Some(1119), + Collection::ClipboardData => Some(1115), + Collection::DataFromCloudStorage => Some(1530), + Collection::DataFromLocalSystem => Some(1005), + Collection::ArchiveCollectedData => Some(1560), + Collection::BrowserSessionHijacking => Some(1185), + Collection::VideoCapture => Some(1125), + Collection::DataStaged => Some(1074), + Collection::DataFromNetworkSharedDrive => Some(1039), + Collection::InputCapture => Some(1056), + Collection::DataFromInformationRepositories => Some(1213), + Collection::Other => None, + } + } +} +impl From for Option { + fn from(value: ResourceDevelopment) -> Self { + match value { + ResourceDevelopment::AcquireInfrastructure => Some(1583), + ResourceDevelopment::CompromiseInfrastructure => Some(1584), + ResourceDevelopment::CompromiseAccounts => Some(1586), + ResourceDevelopment::StageCapabilities => Some(1608), + ResourceDevelopment::EstablishAccounts => Some(1585), + ResourceDevelopment::ObtainCapabilities => Some(1588), + ResourceDevelopment::AcquireAccess => Some(1650), + ResourceDevelopment::DevelopCapabilities => Some(1587), + ResourceDevelopment::Other => None, + } + } +} +impl From for Option { + fn from(value: Reconnaissance) -> Self { + match value { + Reconnaissance::GatherVictimHostInformation => Some(1592), + Reconnaissance::SearchVictimOwnedWebsites => Some(1594), + Reconnaissance::GatherVictimIdentityInformation => Some(1589), + Reconnaissance::SearchOpenTechnicalDatabases => Some(1596), + Reconnaissance::ActiveScanning => Some(1595), + Reconnaissance::GatherVictimOrgInformation => Some(1591), + Reconnaissance::GatherVictimNetworkInformation => Some(1590), + Reconnaissance::SearchOpenWebsitesDomains => Some(1593), + Reconnaissance::SearchClosedSources => Some(1597), + Reconnaissance::PhishingForInformation => Some(1598), + Reconnaissance::Other => None, + } + } +} +impl From for Option { + fn from(value: CommandAndControl) -> Self { + match value { + CommandAndControl::ApplicationLayerProtocol => Some(1071), + CommandAndControl::RemoteAccessSoftware => Some(1219), + CommandAndControl::ContentInjection => Some(1659), + CommandAndControl::TrafficSignaling => Some(1205), + CommandAndControl::ProtocolTunneling => Some(1572), + CommandAndControl::CommunicationThroughRemovableMedia => Some(1092), + CommandAndControl::Proxy => Some(1090), + CommandAndControl::DynamicResolution => Some(1568), + CommandAndControl::WebService => Some(1102), + CommandAndControl::MultiStageChannels => Some(1104), + CommandAndControl::DataObfuscation => Some(1001), + CommandAndControl::NonStandardPort => Some(1571), + CommandAndControl::EncryptedChannel => Some(1573), + CommandAndControl::NonApplicationLayerProtocol => Some(1095), + CommandAndControl::DataEncoding => Some(1132), + CommandAndControl::IngressToolTransfer => Some(1105), + CommandAndControl::FallbackChannels => Some(1008), + CommandAndControl::Other => None, + } + } +} +impl From for Option { + fn from(value: InitialAccess) -> Self { + match value { + InitialAccess::ExternalRemoteServices => Some(1133), + InitialAccess::ReplicationThroughRemovableMedia => Some(1091), + InitialAccess::SupplyChainCompromise => Some(1195), + InitialAccess::ExploitPublicFacingApplication => Some(1190), + InitialAccess::ContentInjection => Some(1659), + InitialAccess::TrustedRelationship => Some(1199), + InitialAccess::Phishing => Some(1566), + InitialAccess::ValidAccounts => Some(1078), + InitialAccess::HardwareAdditions => Some(1200), + InitialAccess::DriveByCompromise => Some(1189), + InitialAccess::Other => None, + } + } +} diff --git a/leech/src/modules/testssl/mitre.rs b/leech/src/modules/testssl/mitre.rs new file mode 100644 index 000000000..743c60e14 --- /dev/null +++ b/leech/src/modules/testssl/mitre.rs @@ -0,0 +1,7 @@ +use kraken_proto::mitre::Tactic; + +use crate::modules::testssl::Finding; + +pub fn categorize(finding: &Finding) -> Option { + None // TODO +} diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index 379f60d7f..cad776b13 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -11,8 +11,9 @@ use tokio::process::Command; mod json; mod json_pretty; - +mod mitre; pub use self::json_pretty::*; +pub use self::mitre::categorize; /// The settings of a `testssl.sh` invocation #[derive(Default, Debug)] diff --git a/leech/src/rpc/attacks.rs b/leech/src/rpc/attacks.rs index 0367cf415..d4c2f67d1 100644 --- a/leech/src/rpc/attacks.rs +++ b/leech/src/rpc/attacks.rs @@ -12,7 +12,9 @@ use futures::Stream; use ipnetwork::IpNetwork; use kraken_proto::req_attack_service_server::ReqAttackService; use kraken_proto::shared::dns_record::Record; -use kraken_proto::shared::{Aaaa, Address, CertEntry, DnsRecord, GenericRecord, A}; +use kraken_proto::shared::{ + Aaaa, Address, AttackTechnique, CertEntry, DnsRecord, GenericRecord, A, +}; use kraken_proto::{ any_attack_response, shared, test_ssl_scans, test_ssl_service, BruteforceSubdomainRequest, BruteforceSubdomainResponse, CertificateTransparencyRequest, CertificateTransparencyResponse, @@ -425,6 +427,7 @@ impl ReqAttackService for Attacks { .scan_result; fn conv_finding(finding: testssl::Finding) -> TestSslFinding { + let mitre = testssl::categorize(&finding); TestSslFinding { id: finding.id, severity: match finding.severity { @@ -442,6 +445,7 @@ impl ReqAttackService for Attacks { finding: finding.finding, cve: finding.cve, cwe: finding.cwe, + mitre: mitre.map(AttackTechnique::from), } } fn conv_findings(findings: Vec) -> Vec { From 70e09c35b54d9c1a440b70494a28feb411125ff3 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Mon, 15 Jan 2024 16:30:30 +0100 Subject: [PATCH 10/37] Parse testssl findings' ids --- leech/src/main.rs | 16 + leech/src/modules/testssl/finding_id.rs | 629 +++++++++++++++++++++++ leech/src/modules/testssl/json_pretty.rs | 41 ++ leech/src/modules/testssl/mitre.rs | 13 +- leech/src/modules/testssl/mod.rs | 1 + 5 files changed, 699 insertions(+), 1 deletion(-) create mode 100644 leech/src/modules/testssl/finding_id.rs diff --git a/leech/src/main.rs b/leech/src/main.rs index ccb4a75c8..8eb63f08f 100644 --- a/leech/src/main.rs +++ b/leech/src/main.rs @@ -541,6 +541,22 @@ async fn main() -> Result<(), Box> { ..Default::default() }) .await?; + for result in &json.scan_result { + if let testssl::Service::Result(service) = result { + for (_section, findings) in service.iter() { + for finding in findings { + let finding_id = testssl::finding_id::FindingId::from( + finding.id.as_str(), + ); + if let testssl::finding_id::FindingId::Unknown(id) = + finding_id + { + warn!("Unknown finding_id: {id}"); + } + } + } + } + } println!("{}", serde_json::to_string_pretty(&json)?); } } diff --git a/leech/src/modules/testssl/finding_id.rs b/leech/src/modules/testssl/finding_id.rs new file mode 100644 index 000000000..ab4f9f7f8 --- /dev/null +++ b/leech/src/modules/testssl/finding_id.rs @@ -0,0 +1,629 @@ +use std::num::NonZeroUsize; +use std::str::FromStr; + +pub enum FindingId { + /// Issues with your testssl installation + ScanIssues(ScanIssues), + + /// Ids which are purely for logging + Logging(Logging), + + /// Pre test for the 128 cipher limit + /// + /// Some servers have either a ClientHello total size limit or a 128 cipher limit (e.g. old ASAs) + PreTest128, + + /// `SSLv...` | `TLS...`: Offered protocols + Protocol(Protocol), + + /// `NPN`: Is NPN offered? + Npn, + + /// `ALPN`: Is Alpn offered? + Alpn, + + /// `ALPN_HTTP2"`: Is Alpn offered? + AlpnHttp2, + + /// `cipherlist_...`: Offered cipher categories + CipherList(CipherList), + + /// Tests Perfect Forward Secrecy + Pfs(Option), + + /// `protocol_negotiated`: Default protocol used by server + DefaultProtocol, + + /// `cipher_negotiated`: Default cipher used by server + DefaultCipher, + + /// `TLS_session_ticket`: Check the session ticket's lifetime + TlsSessionTicket, + + /// `cipher_order` | `cipher_order_...` | `cipherorder_...`: Ordered list of ciphers use by each protocol + CipherOrder(Option), + + /// `cert_...`: Information about the used certificate(s) + /// + /// They will be numbered if the server uses more than one certificate. + /// + /// The number is reported by [`Logging::CertCount`]. + Certificate(Cert, Option), + + /// `insecure_redirect`: Redirect to an http url + InsecureRedirect, + + /// `ipv4_in_header`: An ipv4 address has been found in the http header + Ipv4InHeader, + + /// Security related http header + /// + /// The `bool` flag indicates whether the header is set more than once. + /// + /// [`HttpHeader::StrictTransportSecurity`] will only be reported with `true` + /// as it is checked in depth in [`FindingId::Hsts`] + HttpHeader(HttpHeader, bool), + + /// `security_headers`: Absence of security related http header + SecurityHeaders, + + /// HTTP Strict Transport Security parameters + Hsts(Option), + + ///HTTP Public Key Pinning + Hpkp(Option), + + /// `cookie_...`: Http cookies + Cookie(Cookie), + + /// Test of known vulnerabilities + Vulnerabilities(Vulnerabilities), + + Cipher(Option, String), + + /// Tls clients simulated by testssl + /// + /// May contain a `short` name of the simulated client. + /// The list of clients can be found in `$TESTSSL_INSTALL_DIR/etc/client-simulation.txt`. + ClientSimulation(Option), + + /// An id which has not been categorized yet + Unknown(String), +} + +pub enum Pfs { + /// `PFS_ciphers`: Offered ciphers + Ciphers, + + /// `PFS_ECDHE_curves`: Offered elliptic curves + Curves, + + /// `DH_groups`: Offered Diffie Hellman groups + Groups, +} + +/// Checks about http cookies +pub enum Cookie { + /// `cookie_bigip_f5`: Cookie set by [BIG-IP](https://www.f5.com/products/big-ip-services) + BigIp, + /// `cookie_count`: Number of cookies + Count, + /// `cookie_secure`: Ratio of secure cookies + Secure, + /// `cookie_httponly`: Ratio of http only cookies + HttpOnly, +} + +/// Ids which are purely for logging +pub enum Logging { + /// `optimal_proto`: Determines the optimal protocol to connect to the server with, + /// + /// before running service detection and any other checks + OptimalProtocol, + + /// `service`: The service detection's result + Service, + + /// `host_certificate_Problem`: Could not retrieve host cert + CertProblem, + + /// `TLS_timestamp`: The tls server's reported time + TlsClockSkew, + + /// `TLS_extensions`: Tls extensions supported by server + TlsExtensions, + + /// `SSL_sessionID_support`: Is ssl's session ID supported? + SslSessionId, + + /// `sessionresumption_ticket` + SessionResumptionTicket, + + /// `sessionresumption_ID` + SessionResumptionId, + + /// `cert_numbers`: Number of certificates found + CertCount, + + /// `http_get`: A utility function used to query revoked certificates + HttpGet, + + /// `HTTP_status_code`: Queries the http headers + HttpHeader, + + /// `HTTP_clock_skew`: The http server's reported time + HttpClockSkew, + + /// `HTTP_headerAge`: The `Age` header indicating caching + HttpAge, + + /// `banner_server`: Retrieves the server's banner + ServerBanner, + + /// `banner_application`: Retrieves the application's banner + ApplicationBanner, + + /// `banner_reverseproxy`: Retrieves the reverse proxy's banner + ProxyBanner, +} + +/// Http Header retrieved by testssl +pub enum HttpHeader { + /// `X-Frame-Options` + XFrameOptions, + /// `X-Content-Type-Options` + XContentTypeOptions, + /// `Content-Security-Policy` + ContentSecurityPolicy, + /// `X-Content-Security-Policy` + XContentSecurityPolicy, + /// `X-WebKit-CSP` + XWebKitCSP, + /// `Content-Security-Policy-Report-Only` + ContentSecurityPolicyReportOnly, + /// `Expect-CT` + ExpectCT, + /// `Access-Control-Allow-Origin` + AccessControlAllowOrigin, + /// `Upgrade` + Upgrade, + /// `X-Served-By` + XServedBy, + /// `Referrer-Policy` + ReferrerPolicy, + /// `X-UA-Compatible` + XUACompatible, + /// `Cache-Control` + CacheControl, + /// `Pragma` + Pragma, + /// `X-XSS-Protection` + XXSSProtection, + /// `Strict-Transport-Security` + StrictTransportSecurity, +} + +/// Cipher categories +pub enum CipherList { + /// `NULL` + Null, + /// `aNULL` + ANull, + /// `EXPORT` + Export, + /// `LOW` + Low, + /// `3DES_IDEA` + TripleDes, + /// `AVERAGE` + Average, + /// `STRONG` + Strong, +} + +/// Protocol used to secure a connection +pub enum Protocol { + /// `SSL v2` + SSL2, + /// `SSL v3` + SSL3, + /// `TLS v1` + TLS1, + /// `TLS v1.1` + TLS11, + /// `TLS v1.2` + TLS12, + /// `TLS v1.3` + TLS13, +} + +/// Known vulnerabilities which are tested +pub enum Vulnerabilities { + Heartbleed, + CCS, + Ticketbleed, + Robot, + SecRen, + SecCliRen, + CRIME, + BREACH, + PoodleSsl, + PoodleTls, + FallbackSCSV, + Sweet32, + Freak, + Drown, + DrownHint, + LogJam, + LogJamCommonPrimes, + Beast, + BeastSsl3, + BeastTls1, + Lucky32, + Rc4, + Grease, +} + +/// HTTP Strict Transport Security's parameters +pub enum Hsts { + /// `HSTS_time`: HTTP Strict Transport Security's `max-age` parameter + MaxAge, + /// `HSTS_subdomains`: HTTP Strict Transport Security's `includeSubDomains` parameter + Subdomains, + /// `HSTS_preload`: HTTP Strict Transport Security's `preload` parameter + Preload, +} + +/// HTTP Public Key Pinning's parameters +pub enum Hpkp { + /// `HPKP_error`: Multiple `Public-Key-Pins` in http header + Multiple, + /// `HPKP_notice`: Multiple `Public-Key-Pins-Report-Only` in header + MultipleReportOnly, + /// `HPKP_age`: HTTP Public Key Pinning's `max-age` parameter + MaxAge, + /// `HPKP_subdomains`: HTTP Public Key Pinning's `includeSubDomains` parameter + Subdomains, + /// `HPKP_preload`: HTTP Public Key Pinning's `preload` parameter + Preload, + /// `HPKP_SPKIs`: Number of spkis + Spkis, + /// `HPKP_...`: Information about a specific spki + Spki(String), + /// `HPKP_SPKImatch`: Does an spki match the host's certificate? + SpkiMatch, + /// `HPKP_backup`: Missing backup keys + Backup, +} + +pub enum Cert { + /// `cert` + Cert, + /// `cert_mustStapleExtension` + MustStapleExtension, + /// `cert_signatureAlgorithm` + SignatureAlgorithm, + /// `cert_keySize` + KeySize, + /// `cert_keyUsage` + KeyUsage, + /// `cert_extKeyUsage` + ExtKeyUsage, + /// `cert_serialNumber` + SerialNumber, + /// `cert_serialNumberLen` + SerialNumberLen, + /// `cert_fingerprintSHA1` + FingerprintSHA1, + /// `cert_fingerprintSHA256` + FingerprintSHA256, + /// `cert_commonName` + CommonName, + /// `cert_commonName_wo_SNI` + CommonNameWithoutSNI, + /// `cert_subjectAltName` + SubjectAltName, + /// `cert_caIssuers` + CAIssuers, + /// `cert_trust` + Trust, + /// `cert_chain_of_trust` + ChainOfTrust, + /// `cert_certificatePolicies_EV` + CertificatePoliciesEV, + /// `cert_eTLS` + ETS, + /// `cert_expirationStatus` + ExpirationStatus, + /// `cert_notBefore` + NotBefore, + /// `cert_notAfter` + NotAfter, + /// `cert_validityPeriod` + ValidityPeriod, + /// `certs_countServer` + CertsCountServer, + /// `certs_list_ordering_problem` + CertsListOrderingProblem, + /// `pwnedkeys` + PwnedKeys, + /// `cert_crlDistributionPoints` + CRLDistributionPoints, + /// `cert_ocspURL` + OCSPUrl, + /// `cert_revocation` + Revocation, + /// `OCSP_stapling` + OCSPStapling, + /// `DNS_CAArecord` + CAARecord, + /// `cert_crlRevoked` + CRLRevoked, + /// `cert_ocspRevoked` + OCSPRevoked, +} + +/// Issues with your testssl installation +pub enum ScanIssues { + /// `scanProblem`: an error occurred during the scan + ScanProblem, + /// `old_fart` | `too_old_openssl`: your openssl version is way too old + OldOpenssl, + /// `engine_problem`: No engine or GOST support via engine with your openssl + EngineProblem, +} + +impl From<&str> for FindingId { + fn from(s: &str) -> Self { + use FindingId::{ + Certificate as crt, CipherList as cl, CipherOrder as co, Cookie as c, Hpkp as kp, + Hsts as ts, HttpHeader as hh, Logging as l, Pfs as pfs, Protocol as p, + ScanIssues as si, Vulnerabilities as v, + }; + const T: bool = true; + const F: bool = false; + + match s { + "http_get" => l(Logging::HttpGet), + "service" => l(Logging::Service), + "HTTP_status_code" => l(Logging::HttpHeader), + "insecure_redirect" => Self::InsecureRedirect, + "ipv4_in_header" => Self::Ipv4InHeader, + "HTTP_clock_skew" => l(Logging::HttpClockSkew), + "HTTP_headerAge" => l(Logging::HttpAge), + "HSTS_time" => ts(Some(Hsts::MaxAge)), + "HSTS_subdomains" => ts(Some(Hsts::Subdomains)), + "HSTS_preload" => ts(Some(Hsts::Preload)), + "HSTS" => ts(None), + "HPKP_error" => kp(Some(Hpkp::Multiple)), + "HPKP_notice" => kp(Some(Hpkp::MultipleReportOnly)), + "HPKP_SPKIs" => kp(Some(Hpkp::Spkis)), + "HPKP_age" => kp(Some(Hpkp::MaxAge)), + "HPKP_subdomains" => kp(Some(Hpkp::Subdomains)), + "HPKP_preload" => kp(Some(Hpkp::Preload)), + "HPKP_SPKImatch" => kp(Some(Hpkp::SpkiMatch)), + "HPKP_backup" => kp(Some(Hpkp::Backup)), + "HPKP" => kp(None), + "banner_server" => l(Logging::ServerBanner), + "banner_application" => l(Logging::ApplicationBanner), + "banner_reverseproxy" => l(Logging::ProxyBanner), + "cookie_bigip_f5" => c(Cookie::BigIp), + "cookie_count" => c(Cookie::Count), + "cookie_secure" => c(Cookie::Secure), + "cookie_httponly" => c(Cookie::HttpOnly), + "X-Frame-Options" => hh(HttpHeader::XFrameOptions, F), + "X-Content-Type-Options" => hh(HttpHeader::XContentTypeOptions, F), + "Content-Security-Policy" => hh(HttpHeader::ContentSecurityPolicy, F), + "X-Content-Security-Policy" => hh(HttpHeader::XContentSecurityPolicy, F), + "X-WebKit-CSP" => hh(HttpHeader::XWebKitCSP, F), + "Content-Security-Policy-Report-Only" => { + hh(HttpHeader::ContentSecurityPolicyReportOnly, F) + } + "Expect-CT" => hh(HttpHeader::ExpectCT, F), + "Access-Control-Allow-Origin" => hh(HttpHeader::AccessControlAllowOrigin, F), + "Upgrade" => hh(HttpHeader::Upgrade, F), + "X-Served-By" => hh(HttpHeader::XServedBy, F), + "Referrer-Policy" => hh(HttpHeader::ReferrerPolicy, F), + "X-UA-Compatible" => hh(HttpHeader::XUACompatible, F), + "Cache-Control" => hh(HttpHeader::CacheControl, F), + "Pragma" => hh(HttpHeader::Pragma, F), + "X-XSS-Protection" => hh(HttpHeader::XXSSProtection, F), + "X-Frame-Options_multiple" => hh(HttpHeader::XFrameOptions, T), + "X-Content-Type-Options_multiple" => hh(HttpHeader::XContentTypeOptions, T), + "Content-Security-Policy_multiple" => hh(HttpHeader::ContentSecurityPolicy, T), + "X-Content-Security-Policy_multiple" => hh(HttpHeader::XContentSecurityPolicy, T), + "X-WebKit-CSP_multiple" => hh(HttpHeader::XWebKitCSP, T), + "Content-Security-Policy-Report-Only_multiple" => { + hh(HttpHeader::ContentSecurityPolicyReportOnly, T) + } + "Expect-CT_multiple" => hh(HttpHeader::ExpectCT, T), + "Access-Control-Allow-Origin_multiple" => hh(HttpHeader::AccessControlAllowOrigin, T), + "Upgrade_multiple" => hh(HttpHeader::Upgrade, T), + "X-Served-By_multiple" => hh(HttpHeader::XServedBy, T), + "Referrer-Policy_multiple" => hh(HttpHeader::ReferrerPolicy, T), + "X-UA-Compatible_multiple" => hh(HttpHeader::XUACompatible, T), + "Cache-Control_multiple" => hh(HttpHeader::CacheControl, T), + "Pragma_multiple" => hh(HttpHeader::Pragma, T), + "X-XSS-Protection_multiple" => hh(HttpHeader::XXSSProtection, T), + "Strict-Transport-Security_multiple" => hh(HttpHeader::StrictTransportSecurity, T), + "security_headers" => Self::SecurityHeaders, + "SSLv2" => p(Protocol::SSL2), + "SSLv3" => p(Protocol::SSL3), + "TLS1" => p(Protocol::TLS1), + "TLS1_1" => p(Protocol::TLS11), + "TLS1_2" => p(Protocol::TLS12), + "TLS1_3" => p(Protocol::TLS13), + "cipherlist_NULL" => cl(CipherList::Null), + "cipherlist_aNULL" => cl(CipherList::ANull), + "cipherlist_EXPORT" => cl(CipherList::Export), + "cipherlist_LOW" => cl(CipherList::Low), + "cipherlist_3DES_IDEA" => cl(CipherList::TripleDes), + "cipherlist_AVERAGE" => cl(CipherList::Average), + "cipherlist_STRONG" => cl(CipherList::Strong), + "cipher_order" => co(None), + "cipher_order_SSLV2" => co(Some(Protocol::SSL2)), + "cipher_order_SSLV3" => co(Some(Protocol::SSL3)), + "cipher_order_TLSv1" => co(Some(Protocol::TLS1)), + "cipher_order_TLSv1.1" => co(Some(Protocol::TLS11)), + "cipher_order_TLSv1.2" => co(Some(Protocol::TLS12)), + "cipher_order_TLSv1.3" => co(Some(Protocol::TLS13)), + "cipherorder_SSLV2" => co(Some(Protocol::SSL2)), + "cipherorder_SSLV3" => co(Some(Protocol::SSL3)), + "cipherorder_TLSv1" => co(Some(Protocol::TLS1)), + "cipherorder_TLSv1_1" => co(Some(Protocol::TLS11)), + "cipherorder_TLSv1_2" => co(Some(Protocol::TLS12)), + "cipherorder_TLSv1_3" => co(Some(Protocol::TLS13)), + "protocol_negotiated" => Self::DefaultProtocol, + "cipher_negotiated" => Self::DefaultCipher, + "host_certificate_Problem" => l(Logging::CertProblem), + "TLS_timestamp" => l(Logging::TlsClockSkew), + "TLS_extensions" => l(Logging::TlsExtensions), + "TLS_session_ticket" => Self::TlsSessionTicket, + "SSL_sessionID_support" => l(Logging::SslSessionId), + "sessionresumption_ticket" => l(Logging::SessionResumptionTicket), + "sessionresumption_ID" => l(Logging::SessionResumptionId), + "PFS" => pfs(None), + "PFS_ciphers" => pfs(Some(Pfs::Ciphers)), + "PFS_ECDHE_curves" => pfs(Some(Pfs::Curves)), + "DH_groups" => pfs(Some(Pfs::Groups)), + "NPN" => Self::Npn, + "ALPN" => Self::Alpn, + "ALPN_HTTP2" => Self::AlpnHttp2, + "heartbleed" => v(Vulnerabilities::Heartbleed), + "CCS" => v(Vulnerabilities::CCS), + "ticketbleed" => v(Vulnerabilities::Ticketbleed), + "secure_renego" => v(Vulnerabilities::SecRen), + "secure_client_renego" => v(Vulnerabilities::SecCliRen), + "CRIME_TLS" => v(Vulnerabilities::CRIME), + "BREACH" => v(Vulnerabilities::BREACH), + "SWEET32" => v(Vulnerabilities::Sweet32), + "POODLE_SSL" => v(Vulnerabilities::PoodleSsl), + "POODLE_TLS" => v(Vulnerabilities::PoodleTls), + "fallback_SCSV" => v(Vulnerabilities::FallbackSCSV), + "FREAK" => v(Vulnerabilities::Freak), + "LOGJAM" => v(Vulnerabilities::LogJam), + "LOGJAM-common_primes" => v(Vulnerabilities::LogJamCommonPrimes), + "DROWN" => v(Vulnerabilities::Drown), + "DROWN_hint" => v(Vulnerabilities::DrownHint), + "BEAST" => v(Vulnerabilities::Beast), + "BEAST_CBC_SSL3" => v(Vulnerabilities::BeastSsl3), + "BEAST_CBC_TLS1" => v(Vulnerabilities::BeastTls1), + "LUCKY13" => v(Vulnerabilities::Lucky32), + "RC4" => v(Vulnerabilities::Rc4), + "GREASE" => v(Vulnerabilities::Grease), + "ROBOT" => v(Vulnerabilities::Robot), + "scanProblem" => si(ScanIssues::ScanProblem), + "optimal_proto" => l(Logging::OptimalProtocol), + "pre_128cipher" => Self::PreTest128, + "old_fart" => si(ScanIssues::OldOpenssl), + "too_old_openssl" => si(ScanIssues::OldOpenssl), + "engine_problem" => si(ScanIssues::EngineProblem), + "cert_numbers" => l(Logging::CertCount), + "cert" => crt(Cert::Cert, None), + "cert_mustStapleExtension" => crt(Cert::MustStapleExtension, None), + "cert_signatureAlgorithm" => crt(Cert::SignatureAlgorithm, None), + "cert_keySize" => crt(Cert::KeySize, None), + "cert_keyUsage" => crt(Cert::KeyUsage, None), + "cert_extKeyUsage" => crt(Cert::ExtKeyUsage, None), + "cert_serialNumber" => crt(Cert::SerialNumber, None), + "cert_serialNumberLen" => crt(Cert::SerialNumberLen, None), + "cert_fingerprintSHA1" => crt(Cert::FingerprintSHA1, None), + "cert_fingerprintSHA256" => crt(Cert::FingerprintSHA256, None), + "cert_commonName" => crt(Cert::CommonName, None), + "cert_commonName_wo_SNI" => crt(Cert::CommonNameWithoutSNI, None), + "cert_subjectAltName" => crt(Cert::SubjectAltName, None), + "cert_caIssuers" => crt(Cert::CAIssuers, None), + "cert_trust" => crt(Cert::Trust, None), + "cert_chain_of_trust" => crt(Cert::ChainOfTrust, None), + "cert_certificatePolicies_EV" => crt(Cert::CertificatePoliciesEV, None), + "cert_eTLS" => crt(Cert::ETS, None), + "cert_expirationStatus" => crt(Cert::ExpirationStatus, None), + "cert_notBefore" => crt(Cert::NotBefore, None), + "cert_notAfter" => crt(Cert::NotAfter, None), + "cert_validityPeriod" => crt(Cert::ValidityPeriod, None), + "certs_countServer" => crt(Cert::CertsCountServer, None), + "certs_list_ordering_problem" => crt(Cert::CertsListOrderingProblem, None), + "pwnedkeys" => crt(Cert::PwnedKeys, None), + "cert_crlDistributionPoints" => crt(Cert::CRLDistributionPoints, None), + "cert_ocspURL" => crt(Cert::OCSPUrl, None), + "cert_revocation" => crt(Cert::Revocation, None), + "OCSP_stapling" => crt(Cert::OCSPStapling, None), + "DNS_CAArecord" => crt(Cert::CAARecord, None), + "cert_crlRevoked" => crt(Cert::CRLRevoked, None), + "cert_ocspRevoked" => crt(Cert::OCSPRevoked, None), + "clientsimulation" => Self::ClientSimulation(None), + _ => { + if let Some((test, number)) = s.split_once(" Some(Cert::Cert), + "cert_mustStapleExtension" => Some(Cert::MustStapleExtension), + "cert_signatureAlgorithm" => Some(Cert::SignatureAlgorithm), + "cert_keySize" => Some(Cert::KeySize), + "cert_keyUsage" => Some(Cert::KeyUsage), + "cert_extKeyUsage" => Some(Cert::ExtKeyUsage), + "cert_serialNumber" => Some(Cert::SerialNumber), + "cert_serialNumberLen" => Some(Cert::SerialNumberLen), + "cert_fingerprintSHA1" => Some(Cert::FingerprintSHA1), + "cert_fingerprintSHA256" => Some(Cert::FingerprintSHA256), + "cert_commonName" => Some(Cert::CommonName), + "cert_commonName_wo_SNI" => Some(Cert::CommonNameWithoutSNI), + "cert_subjectAltName" => Some(Cert::SubjectAltName), + "cert_caIssuers" => Some(Cert::CAIssuers), + "cert_trust" => Some(Cert::Trust), + "cert_chain_of_trust" => Some(Cert::ChainOfTrust), + "cert_certificatePolicies_EV" => Some(Cert::CertificatePoliciesEV), + "cert_eTLS" => Some(Cert::ETS), + "cert_expirationStatus" => Some(Cert::ExpirationStatus), + "cert_notBefore" => Some(Cert::NotBefore), + "cert_notAfter" => Some(Cert::NotAfter), + "cert_validityPeriod" => Some(Cert::ValidityPeriod), + "certs_countServer" => Some(Cert::CertsCountServer), + "certs_list_ordering_problem" => Some(Cert::CertsListOrderingProblem), + "pwnedkeys" => Some(Cert::PwnedKeys), + "cert_crlDistributionPoints" => Some(Cert::CRLDistributionPoints), + "cert_ocspURL" => Some(Cert::OCSPUrl), + "cert_revocation" => Some(Cert::Revocation), + "OCSP_stapling" => Some(Cert::OCSPStapling), + "DNS_CAArecord" => Some(Cert::CAARecord), + "cert_crlRevoked" => Some(Cert::CRLRevoked), + "cert_ocspRevoked" => Some(Cert::OCSPRevoked), + _ => None, + }; + let number = number + .strip_suffix('>') + .map(NonZeroUsize::from_str) + .and_then(Result::ok); + if let Some((cert, number)) = cert.zip(number) { + return crt(cert, Some(number)); + } + } + if let Some(client) = s.strip_prefix("clientsimulation-") { + return Self::ClientSimulation(Some(client.to_string())); + } + if let Some(spki) = s.strip_prefix("HPKP_") { + return Self::Hpkp(Some(Hpkp::Spki(spki.to_string()))); + } + if let Some(hexcode) = s.strip_prefix("cipher_x") { + return Self::Cipher(None, hexcode.to_string()); + } + if let Some(string) = s.strip_prefix("cipher-") { + if let Some((proto, hexcode)) = string.split_once("_x") { + let proto = match proto { + "ssl2" => Some(Protocol::SSL2), + "ssl3" => Some(Protocol::SSL3), + "tls1" => Some(Protocol::TLS1), + "tls1_1" => Some(Protocol::TLS11), + "tls1_2" => Some(Protocol::TLS12), + "tls1_3" => Some(Protocol::TLS13), + _ => None, + }; + if proto.is_some() { + return Self::Cipher(proto, hexcode.to_string()); + } + } + } + Self::Unknown(s.to_string()) + } + } + } +} diff --git a/leech/src/modules/testssl/json_pretty.rs b/leech/src/modules/testssl/json_pretty.rs index 1572b6709..a27a6aae8 100644 --- a/leech/src/modules/testssl/json_pretty.rs +++ b/leech/src/modules/testssl/json_pretty.rs @@ -129,6 +129,47 @@ pub struct ScanResult { pub browser_simulations: Vec, } +impl ScanResult { + /// Iterate over all sections + pub fn iter(&self) -> impl Iterator { + let Self { + target_host: _, + ip: _, + port: _, + rdns: _, + service: _, + hostname: _, + pretest, + single_cipher, + protocols, + grease, + ciphers, + pfs, + server_preferences, + server_defaults, + header_response, + vulnerabilities, + cipher_tests, + browser_simulations, + } = self; + [ + ("pretest", pretest.as_slice()), + ("single_cipher", single_cipher.as_slice()), + ("protocols", protocols.as_slice()), + ("grease", grease.as_slice()), + ("ciphers", ciphers.as_slice()), + ("pfs", pfs.as_slice()), + ("server_preferences", server_preferences.as_slice()), + ("server_defaults", server_defaults.as_slice()), + ("header_response", header_response.as_slice()), + ("vulnerabilities", vulnerabilities.as_slice()), + ("cipher_tests", cipher_tests.as_slice()), + ("browser_simulations", browser_simulations.as_slice()), + ] + .into_iter() + } +} + /// Either a test's result or a log message /// /// Which one it is might be determined by the [`Severity`] diff --git a/leech/src/modules/testssl/mitre.rs b/leech/src/modules/testssl/mitre.rs index 743c60e14..bcf1a5e16 100644 --- a/leech/src/modules/testssl/mitre.rs +++ b/leech/src/modules/testssl/mitre.rs @@ -1,7 +1,18 @@ use kraken_proto::mitre::Tactic; -use crate::modules::testssl::Finding; +use crate::modules::testssl::finding_id::FindingId; +use crate::modules::testssl::{Finding, Severity}; +/// Categorize a finding into a tactic and technique from Mitre ATT&CK pub fn categorize(finding: &Finding) -> Option { + // Only categorize actual problems + if matches!( + &finding.severity, + Severity::Debug | Severity::Info | Severity::Warn | Severity::Fatal | Severity::Ok + ) { + return None; + } + + let id = FindingId::from(finding.id.as_str()); None // TODO } diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index cad776b13..c4db40992 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -9,6 +9,7 @@ use tokio::fs::File as TokioFile; use tokio::io::AsyncReadExt; use tokio::process::Command; +pub mod finding_id; mod json; mod json_pretty; mod mitre; From 78548214ba8fc51a4a41e60510a5e9584e3a73fa Mon Sep 17 00:00:00 2001 From: gammelalf Date: Mon, 15 Jan 2024 16:54:09 +0100 Subject: [PATCH 11/37] Removed Other variants --- kraken-proto/proto/attacks.shared.proto | 4 +- kraken-proto/src/mitre.rs | 698 ++++++++++++------------ 2 files changed, 337 insertions(+), 365 deletions(-) diff --git a/kraken-proto/proto/attacks.shared.proto b/kraken-proto/proto/attacks.shared.proto index 870389bc6..a256dd3dc 100644 --- a/kraken-proto/proto/attacks.shared.proto +++ b/kraken-proto/proto/attacks.shared.proto @@ -131,8 +131,8 @@ message CertEntry { // A mitre ATT&CK tactic and technique message AttackTechnique { // The tactic's id i.e. TA00xx - optional uint32 tactic = 1; + uint32 tactic = 1; // The technique's id i.e. Txxxx - optional uint32 technique = 2; + uint32 technique = 2; } \ No newline at end of file diff --git a/kraken-proto/src/mitre.rs b/kraken-proto/src/mitre.rs index 8d981ca5e..ef065e693 100644 --- a/kraken-proto/src/mitre.rs +++ b/kraken-proto/src/mitre.rs @@ -1,5 +1,7 @@ +//! Enums representing the tactics and techniques from [Mitre ATT&CK](https://attack.mitre.org/) use crate::InvalidArgumentError; use crate::shared::AttackTechnique; +/// An entry in the [Mitre ATT&CK table](https://attack.mitre.org/) pub enum Tactic { /// [Credential Access](https://attack.mitre.org/tactics/TA0006) /// @@ -71,8 +73,8 @@ pub enum Tactic { /// The adversary is trying to get into your network. InitialAccess(InitialAccess), - Other, } +/// [Credential Access](https://attack.mitre.org/tactics/TA0006)'s techniques pub enum CredentialAccess { /// [Adversary-in-the-Middle](https://attack.mitre.org/techniques/T1557) /// @@ -159,8 +161,8 @@ pub enum CredentialAccess { /// Adversaries may modify authentication mechanisms and processes to access user credentials or enable otherwise unwarranted access to accounts. The authentication process is handled by mechanisms, such as the Local Security Authentication Server (LSASS) process and the Security Accounts Manager (SAM) on Windows, pluggable authentication modules (PAM) on Unix-based systems, and authorization plugins on MacOS systems, responsible for gathering, storing, and validating credentials. By modifying an authentication process, an adversary may be able to authenticate to a service or system without using [Valid Accounts](https://attack.mitre.org/techniques/T1078). ModifyAuthenticationProcess, - Other, } +/// [Execution](https://attack.mitre.org/tactics/TA0002)'s techniques pub enum Execution { /// [Windows Management Instrumentation](https://attack.mitre.org/techniques/T1047) /// @@ -232,8 +234,8 @@ pub enum Execution { /// Adversaries may abuse serverless computing, integration, and automation services to execute arbitrary code in cloud environments. Many cloud providers offer a variety of serverless resources, including compute engines, application integration services, and web servers. ServerlessExecution, - Other, } +/// [Impact](https://attack.mitre.org/tactics/TA0040)'s techniques pub enum Impact { /// [Disk Wipe](https://attack.mitre.org/techniques/T1561) /// @@ -305,8 +307,8 @@ pub enum Impact { /// Adversaries may shutdown/reboot systems to interrupt access to, or aid in the destruction of, those systems. Operating systems may contain commands to initiate a shutdown/reboot of a machine or network device. In some cases, these commands may also be used to initiate a shutdown/reboot of a remote computer or network device via [Network Device CLI](https://attack.mitre.org/techniques/T1059/008) (e.g. reload).(Citation: Microsoft Shutdown Oct 2017)(Citation: alert_TA18_106A) SystemShutdownReboot, - Other, } +/// [Persistence](https://attack.mitre.org/tactics/TA0003)'s techniques pub enum Persistence { /// [Boot or Logon Initialization Scripts](https://attack.mitre.org/techniques/T1037) /// @@ -408,8 +410,8 @@ pub enum Persistence { /// Adversaries may modify authentication mechanisms and processes to access user credentials or enable otherwise unwarranted access to accounts. The authentication process is handled by mechanisms, such as the Local Security Authentication Server (LSASS) process and the Security Accounts Manager (SAM) on Windows, pluggable authentication modules (PAM) on Unix-based systems, and authorization plugins on MacOS systems, responsible for gathering, storing, and validating credentials. By modifying an authentication process, an adversary may be able to authenticate to a service or system without using [Valid Accounts](https://attack.mitre.org/techniques/T1078). ModifyAuthenticationProcess, - Other, } +/// [Privilege Escalation](https://attack.mitre.org/tactics/TA0004)'s techniques pub enum PrivilegeEscalation { /// [Boot or Logon Initialization Scripts](https://attack.mitre.org/techniques/T1037) /// @@ -481,8 +483,8 @@ pub enum PrivilegeEscalation { /// Adversaries may modify the configuration settings of a domain to evade defenses and/or escalate privileges in domain environments. Domains provide a centralized means of managing how computer resources (ex: computers, user accounts) can act, and interact with each other, on a network. The policy of the domain also includes configuration settings that may apply between domains in a multi-domain/forest environment. Modifications to domain settings may include altering domain Group Policy Objects (GPOs) or changing trust settings for domains, including federation trusts. DomainPolicyModification, - Other, } +/// [Lateral Movement](https://attack.mitre.org/tactics/TA0008)'s techniques pub enum LateralMovement { /// [Taint Shared Content](https://attack.mitre.org/techniques/T1080) /// @@ -529,8 +531,8 @@ pub enum LateralMovement { /// Adversaries may transfer tools or other files between systems in a compromised environment. Once brought into the victim environment (i.e., [Ingress Tool Transfer](https://attack.mitre.org/techniques/T1105)) files may then be copied from one system to another to stage adversary tools or other files over the course of an operation. LateralToolTransfer, - Other, } +/// [Defense Evasion](https://attack.mitre.org/tactics/TA0005)'s techniques pub enum DefenseEvasion { /// [Direct Volume Access](https://attack.mitre.org/techniques/T1006) /// @@ -747,8 +749,8 @@ pub enum DefenseEvasion { /// Adversaries may take advantage of trusted developer utilities to proxy execution of malicious payloads. There are many utilities used for software development related tasks that can be used to execute code in various forms to assist in development, debugging, and reverse engineering.(Citation: engima0x3 DNX Bypass)(Citation: engima0x3 RCSI Bypass)(Citation: Exploit Monday WinDbg)(Citation: LOLBAS Tracker) These utilities may often be signed with legitimate certificates that allow them to execute on a system and proxy execution of malicious code through a trusted process that effectively bypasses application control solutions. TrustedDeveloperUtilitiesProxyExecution, - Other, } +/// [Exfiltration](https://attack.mitre.org/tactics/TA0010)'s techniques pub enum Exfiltration { /// [Exfiltration Over Web Service](https://attack.mitre.org/techniques/T1567) /// @@ -795,8 +797,8 @@ pub enum Exfiltration { /// Adversaries may attempt to exfiltrate data via a physical medium, such as a removable drive. In certain circumstances, such as an air-gapped network compromise, exfiltration could occur via a physical medium or device introduced by a user. Such media could be an external hard drive, USB drive, cellular phone, MP3 player, or other removable storage and processing device. The physical medium or device could be used as the final exfiltration point or to hop between otherwise disconnected systems. ExfiltrationOverPhysicalMedium, - Other, } +/// [Discovery](https://attack.mitre.org/tactics/TA0007)'s techniques pub enum Discovery { /// [System Owner/User Discovery](https://attack.mitre.org/techniques/T1033) /// @@ -958,8 +960,8 @@ pub enum Discovery { /// An adversary may gather the system time and/or time zone from a local or remote system. The system time is set and stored by the Windows Time Service within a domain to maintain time synchronization between systems and services in an enterprise network. (Citation: MSDN System Time)(Citation: Technet Windows Time Service) SystemTimeDiscovery, - Other, } +/// [Collection](https://attack.mitre.org/tactics/TA0009)'s techniques pub enum Collection { /// [Screen Capture](https://attack.mitre.org/techniques/T1113) /// @@ -1046,8 +1048,8 @@ pub enum Collection { /// Adversaries may leverage information repositories to mine valuable information. Information repositories are tools that allow for storage of information, typically to facilitate collaboration or information sharing between users, and can store a wide variety of data that may aid adversaries in further objectives, or direct access to the target information. Adversaries may also abuse external sharing features to share sensitive documents with recipients outside of the organization. DataFromInformationRepositories, - Other, } +/// [Resource Development](https://attack.mitre.org/tactics/TA0042)'s techniques pub enum ResourceDevelopment { /// [Acquire Infrastructure](https://attack.mitre.org/techniques/T1583) /// @@ -1089,8 +1091,8 @@ pub enum ResourceDevelopment { /// Adversaries may build capabilities that can be used during targeting. Rather than purchasing, freely downloading, or stealing capabilities, adversaries may develop their own capabilities in-house. This is the process of identifying development requirements and building solutions such as malware, exploits, and self-signed certificates. Adversaries may develop capabilities to support their operations throughout numerous phases of the adversary lifecycle.(Citation: Mandiant APT1)(Citation: Kaspersky Sofacy)(Citation: Bitdefender StrongPity June 2020)(Citation: Talos Promethium June 2020) DevelopCapabilities, - Other, } +/// [Reconnaissance](https://attack.mitre.org/tactics/TA0043)'s techniques pub enum Reconnaissance { /// [Gather Victim Host Information](https://attack.mitre.org/techniques/T1592) /// @@ -1142,8 +1144,8 @@ pub enum Reconnaissance { /// Adversaries may send phishing messages to elicit sensitive information that can be used during targeting. Phishing for information is an attempt to trick targets into divulging information, frequently credentials or other actionable information. Phishing for information is different from [Phishing](https://attack.mitre.org/techniques/T1566) in that the objective is gathering data from the victim rather than executing malicious code. PhishingForInformation, - Other, } +/// [Command and Control](https://attack.mitre.org/tactics/TA0011)'s techniques pub enum CommandAndControl { /// [Application Layer Protocol](https://attack.mitre.org/techniques/T1071) /// @@ -1230,8 +1232,8 @@ pub enum CommandAndControl { /// Adversaries may use fallback or alternate communication channels if the primary channel is compromised or inaccessible in order to maintain reliable command and control and to avoid data transfer thresholds. FallbackChannels, - Other, } +/// [Initial Access](https://attack.mitre.org/tactics/TA0001)'s techniques pub enum InitialAccess { /// [External Remote Services](https://attack.mitre.org/techniques/T1133) /// @@ -1283,12 +1285,11 @@ pub enum InitialAccess { /// Adversaries may gain access to a system through a user visiting a website over the normal course of browsing. With this technique, the user's web browser is typically targeted for exploitation, but adversaries may also use compromised websites for non-exploitation behavior such as acquiring [Application Access Token](https://attack.mitre.org/techniques/T1550/001). DriveByCompromise, - Other, } impl TryFrom for Tactic { type Error = InvalidArgumentError; fn try_from(value: AttackTechnique) -> Result { - let AttackTechnique { tactic: Some(tactic), technique } = value else { return Ok(Self::Other); }; + let AttackTechnique { tactic, technique } = value; Ok(match tactic { 0006 => Self::CredentialAccess(CredentialAccess::try_from(technique)?), 0002 => Self::Execution(Execution::try_from(technique)?), @@ -1308,11 +1309,10 @@ impl TryFrom for Tactic { }) } } -impl TryFrom> for CredentialAccess { +impl TryFrom for CredentialAccess { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1557 => Self::AdversaryInTheMiddle, 1003 => Self::OsCredentialDumping, 1539 => Self::StealWebSessionCookie, @@ -1330,15 +1330,14 @@ impl TryFrom> for CredentialAccess { 1056 => Self::InputCapture, 1111 => Self::MultiFactorAuthenticationInterception, 1556 => Self::ModifyAuthenticationProcess, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0006, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0006, value)), }) } } -impl TryFrom> for Execution { +impl TryFrom for Execution { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1047 => Self::WindowsManagementInstrumentation, 1129 => Self::SharedModules, 1053 => Self::ScheduledTaskJob, @@ -1353,15 +1352,14 @@ impl TryFrom> for Execution { 1569 => Self::SystemServices, 1651 => Self::CloudAdministrationCommand, 1648 => Self::ServerlessExecution, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0002, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0002, value)), }) } } -impl TryFrom> for Impact { +impl TryFrom for Impact { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1561 => Self::DiskWipe, 1489 => Self::ServiceStop, 1491 => Self::Defacement, @@ -1376,15 +1374,14 @@ impl TryFrom> for Impact { 1495 => Self::FirmwareCorruption, 1490 => Self::InhibitSystemRecovery, 1529 => Self::SystemShutdownReboot, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0040, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0040, value)), }) } } -impl TryFrom> for Persistence { +impl TryFrom for Persistence { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1037 => Self::BootOrLogonInitializationScripts, 1543 => Self::CreateOrModifySystemProcess, 1133 => Self::ExternalRemoteServices, @@ -1405,15 +1402,14 @@ impl TryFrom> for Persistence { 1136 => Self::CreateAccount, 1653 => Self::PowerSettings, 1556 => Self::ModifyAuthenticationProcess, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0003, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0003, value)), }) } } -impl TryFrom> for PrivilegeEscalation { +impl TryFrom for PrivilegeEscalation { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1037 => Self::BootOrLogonInitializationScripts, 1543 => Self::CreateOrModifySystemProcess, 1547 => Self::BootOrLogonAutostartExecution, @@ -1428,15 +1424,14 @@ impl TryFrom> for PrivilegeEscalation { 1546 => Self::EventTriggeredExecution, 1134 => Self::AccessTokenManipulation, 1484 => Self::DomainPolicyModification, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0004, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0004, value)), }) } } -impl TryFrom> for LateralMovement { +impl TryFrom for LateralMovement { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1080 => Self::TaintSharedContent, 1091 => Self::ReplicationThroughRemovableMedia, 1550 => Self::UseAlternateAuthenticationMaterial, @@ -1446,15 +1441,14 @@ impl TryFrom> for LateralMovement { 1210 => Self::ExploitationOfRemoteServices, 1534 => Self::InternalSpearphishing, 1570 => Self::LateralToolTransfer, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0008, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0008, value)), }) } } -impl TryFrom> for DefenseEvasion { +impl TryFrom for DefenseEvasion { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1006 => Self::DirectVolumeAccess, 1014 => Self::Rootkit, 1578 => Self::ModifyCloudComputeInfrastructure, @@ -1498,15 +1492,14 @@ impl TryFrom> for DefenseEvasion { 1216 => Self::SystemScriptProxyExecution, 1211 => Self::ExploitationForDefenseEvasion, 1127 => Self::TrustedDeveloperUtilitiesProxyExecution, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0005, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0005, value)), }) } } -impl TryFrom> for Exfiltration { +impl TryFrom for Exfiltration { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1567 => Self::ExfiltrationOverWebService, 1029 => Self::ScheduledTransfer, 1011 => Self::ExfiltrationOverOtherNetworkMedium, @@ -1516,15 +1509,14 @@ impl TryFrom> for Exfiltration { 1030 => Self::DataTransferSizeLimits, 1537 => Self::TransferDataToCloudAccount, 1052 => Self::ExfiltrationOverPhysicalMedium, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0010, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0010, value)), }) } } -impl TryFrom> for Discovery { +impl TryFrom for Discovery { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1033 => Self::SystemOwnerUserDiscovery, 1613 => Self::ContainerAndResourceDiscovery, 1069 => Self::PermissionGroupsDiscovery, @@ -1557,15 +1549,14 @@ impl TryFrom> for Discovery { 1538 => Self::CloudServiceDashboard, 1622 => Self::DebuggerEvasion, 1124 => Self::SystemTimeDiscovery, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0007, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0007, value)), }) } } -impl TryFrom> for Collection { +impl TryFrom for Collection { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1113 => Self::ScreenCapture, 1557 => Self::AdversaryInTheMiddle, 1602 => Self::DataFromConfigurationRepository, @@ -1583,15 +1574,14 @@ impl TryFrom> for Collection { 1039 => Self::DataFromNetworkSharedDrive, 1056 => Self::InputCapture, 1213 => Self::DataFromInformationRepositories, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0009, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0009, value)), }) } } -impl TryFrom> for ResourceDevelopment { +impl TryFrom for ResourceDevelopment { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1583 => Self::AcquireInfrastructure, 1584 => Self::CompromiseInfrastructure, 1586 => Self::CompromiseAccounts, @@ -1600,15 +1590,14 @@ impl TryFrom> for ResourceDevelopment { 1588 => Self::ObtainCapabilities, 1650 => Self::AcquireAccess, 1587 => Self::DevelopCapabilities, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0042, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0042, value)), }) } } -impl TryFrom> for Reconnaissance { +impl TryFrom for Reconnaissance { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1592 => Self::GatherVictimHostInformation, 1594 => Self::SearchVictimOwnedWebsites, 1589 => Self::GatherVictimIdentityInformation, @@ -1619,15 +1608,14 @@ impl TryFrom> for Reconnaissance { 1593 => Self::SearchOpenWebsitesDomains, 1597 => Self::SearchClosedSources, 1598 => Self::PhishingForInformation, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0043, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0043, value)), }) } } -impl TryFrom> for CommandAndControl { +impl TryFrom for CommandAndControl { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1071 => Self::ApplicationLayerProtocol, 1219 => Self::RemoteAccessSoftware, 1659 => Self::ContentInjection, @@ -1645,15 +1633,14 @@ impl TryFrom> for CommandAndControl { 1132 => Self::DataEncoding, 1105 => Self::IngressToolTransfer, 1008 => Self::FallbackChannels, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0011, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0011, value)), }) } } -impl TryFrom> for InitialAccess { +impl TryFrom for InitialAccess { type Error = InvalidArgumentError; - fn try_from(value: Option) -> Result { - let Some(technique) = value else { return Ok(Self::Other); }; - Ok(match technique { + fn try_from(value: u32) -> Result { + Ok(match value { 1133 => Self::ExternalRemoteServices, 1091 => Self::ReplicationThroughRemovableMedia, 1195 => Self::SupplyChainCompromise, @@ -1664,361 +1651,346 @@ impl TryFrom> for InitialAccess { 1078 => Self::ValidAccounts, 1200 => Self::HardwareAdditions, 1189 => Self::DriveByCompromise, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0001, technique)), + _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0001, value)), }) } } impl From for AttackTechnique { fn from(value: Tactic) -> Self { let (tactic, technique) = match value { - Tactic::CredentialAccess(technique) => (Some(0006), technique.into()), - Tactic::Execution(technique) => (Some(0002), technique.into()), - Tactic::Impact(technique) => (Some(0040), technique.into()), - Tactic::Persistence(technique) => (Some(0003), technique.into()), - Tactic::PrivilegeEscalation(technique) => (Some(0004), technique.into()), - Tactic::LateralMovement(technique) => (Some(0008), technique.into()), - Tactic::DefenseEvasion(technique) => (Some(0005), technique.into()), - Tactic::Exfiltration(technique) => (Some(0010), technique.into()), - Tactic::Discovery(technique) => (Some(0007), technique.into()), - Tactic::Collection(technique) => (Some(0009), technique.into()), - Tactic::ResourceDevelopment(technique) => (Some(0042), technique.into()), - Tactic::Reconnaissance(technique) => (Some(0043), technique.into()), - Tactic::CommandAndControl(technique) => (Some(0011), technique.into()), - Tactic::InitialAccess(technique) => (Some(0001), technique.into()), - Tactic::Other => (None, None), + Tactic::CredentialAccess(technique) => (0006, technique.into()), + Tactic::Execution(technique) => (0002, technique.into()), + Tactic::Impact(technique) => (0040, technique.into()), + Tactic::Persistence(technique) => (0003, technique.into()), + Tactic::PrivilegeEscalation(technique) => (0004, technique.into()), + Tactic::LateralMovement(technique) => (0008, technique.into()), + Tactic::DefenseEvasion(technique) => (0005, technique.into()), + Tactic::Exfiltration(technique) => (0010, technique.into()), + Tactic::Discovery(technique) => (0007, technique.into()), + Tactic::Collection(technique) => (0009, technique.into()), + Tactic::ResourceDevelopment(technique) => (0042, technique.into()), + Tactic::Reconnaissance(technique) => (0043, technique.into()), + Tactic::CommandAndControl(technique) => (0011, technique.into()), + Tactic::InitialAccess(technique) => (0001, technique.into()), }; AttackTechnique { tactic, technique } } } -impl From for Option { +impl From for u32 { fn from(value: CredentialAccess) -> Self { match value { - CredentialAccess::AdversaryInTheMiddle => Some(1557), - CredentialAccess::OsCredentialDumping => Some(1003), - CredentialAccess::StealWebSessionCookie => Some(1539), - CredentialAccess::NetworkSniffing => Some(1040), - CredentialAccess::StealOrForgeKerberosTickets => Some(1558), - CredentialAccess::CredentialsFromPasswordStores => Some(1555), - CredentialAccess::UnsecuredCredentials => Some(1552), - CredentialAccess::StealOrForgeAuthenticationCertificates => Some(1649), - CredentialAccess::StealApplicationAccessToken => Some(1528), - CredentialAccess::ForgeWebCredentials => Some(1606), - CredentialAccess::MultiFactorAuthenticationRequestGeneration => Some(1621), - CredentialAccess::ExploitationForCredentialAccess => Some(1212), - CredentialAccess::BruteForce => Some(1110), - CredentialAccess::ForcedAuthentication => Some(1187), - CredentialAccess::InputCapture => Some(1056), - CredentialAccess::MultiFactorAuthenticationInterception => Some(1111), - CredentialAccess::ModifyAuthenticationProcess => Some(1556), - CredentialAccess::Other => None, + CredentialAccess::AdversaryInTheMiddle => 1557, + CredentialAccess::OsCredentialDumping => 1003, + CredentialAccess::StealWebSessionCookie => 1539, + CredentialAccess::NetworkSniffing => 1040, + CredentialAccess::StealOrForgeKerberosTickets => 1558, + CredentialAccess::CredentialsFromPasswordStores => 1555, + CredentialAccess::UnsecuredCredentials => 1552, + CredentialAccess::StealOrForgeAuthenticationCertificates => 1649, + CredentialAccess::StealApplicationAccessToken => 1528, + CredentialAccess::ForgeWebCredentials => 1606, + CredentialAccess::MultiFactorAuthenticationRequestGeneration => 1621, + CredentialAccess::ExploitationForCredentialAccess => 1212, + CredentialAccess::BruteForce => 1110, + CredentialAccess::ForcedAuthentication => 1187, + CredentialAccess::InputCapture => 1056, + CredentialAccess::MultiFactorAuthenticationInterception => 1111, + CredentialAccess::ModifyAuthenticationProcess => 1556, } } } -impl From for Option { +impl From for u32 { fn from(value: Execution) -> Self { match value { - Execution::WindowsManagementInstrumentation => Some(1047), - Execution::SharedModules => Some(1129), - Execution::ScheduledTaskJob => Some(1053), - Execution::NativeApi => Some(1106), - Execution::DeployContainer => Some(1610), - Execution::CommandAndScriptingInterpreter => Some(1059), - Execution::ContainerAdministrationCommand => Some(1609), - Execution::UserExecution => Some(1204), - Execution::SoftwareDeploymentTools => Some(1072), - Execution::InterProcessCommunication => Some(1559), - Execution::ExploitationForClientExecution => Some(1203), - Execution::SystemServices => Some(1569), - Execution::CloudAdministrationCommand => Some(1651), - Execution::ServerlessExecution => Some(1648), - Execution::Other => None, + Execution::WindowsManagementInstrumentation => 1047, + Execution::SharedModules => 1129, + Execution::ScheduledTaskJob => 1053, + Execution::NativeApi => 1106, + Execution::DeployContainer => 1610, + Execution::CommandAndScriptingInterpreter => 1059, + Execution::ContainerAdministrationCommand => 1609, + Execution::UserExecution => 1204, + Execution::SoftwareDeploymentTools => 1072, + Execution::InterProcessCommunication => 1559, + Execution::ExploitationForClientExecution => 1203, + Execution::SystemServices => 1569, + Execution::CloudAdministrationCommand => 1651, + Execution::ServerlessExecution => 1648, } } } -impl From for Option { +impl From for u32 { fn from(value: Impact) -> Self { match value { - Impact::DiskWipe => Some(1561), - Impact::ServiceStop => Some(1489), - Impact::Defacement => Some(1491), - Impact::FinancialTheft => Some(1657), - Impact::DataManipulation => Some(1565), - Impact::AccountAccessRemoval => Some(1531), - Impact::DataEncryptedForImpact => Some(1486), - Impact::EndpointDenialOfService => Some(1499), - Impact::ResourceHijacking => Some(1496), - Impact::DataDestruction => Some(1485), - Impact::NetworkDenialOfService => Some(1498), - Impact::FirmwareCorruption => Some(1495), - Impact::InhibitSystemRecovery => Some(1490), - Impact::SystemShutdownReboot => Some(1529), - Impact::Other => None, + Impact::DiskWipe => 1561, + Impact::ServiceStop => 1489, + Impact::Defacement => 1491, + Impact::FinancialTheft => 1657, + Impact::DataManipulation => 1565, + Impact::AccountAccessRemoval => 1531, + Impact::DataEncryptedForImpact => 1486, + Impact::EndpointDenialOfService => 1499, + Impact::ResourceHijacking => 1496, + Impact::DataDestruction => 1485, + Impact::NetworkDenialOfService => 1498, + Impact::FirmwareCorruption => 1495, + Impact::InhibitSystemRecovery => 1490, + Impact::SystemShutdownReboot => 1529, } } } -impl From for Option { +impl From for u32 { fn from(value: Persistence) -> Self { match value { - Persistence::BootOrLogonInitializationScripts => Some(1037), - Persistence::CreateOrModifySystemProcess => Some(1543), - Persistence::ExternalRemoteServices => Some(1133), - Persistence::BootOrLogonAutostartExecution => Some(1547), - Persistence::OfficeApplicationStartup => Some(1137), - Persistence::ScheduledTaskJob => Some(1053), - Persistence::BrowserExtensions => Some(1176), - Persistence::TrafficSignaling => Some(1205), - Persistence::ImplantInternalImage => Some(1525), - Persistence::PreOsBoot => Some(1542), - Persistence::CompromiseClientSoftwareBinary => Some(1554), - Persistence::AccountManipulation => Some(1098), - Persistence::HijackExecutionFlow => Some(1574), - Persistence::ValidAccounts => Some(1078), - Persistence::EventTriggeredExecution => Some(1546), - Persistence::BitsJobs => Some(1197), - Persistence::ServerSoftwareComponent => Some(1505), - Persistence::CreateAccount => Some(1136), - Persistence::PowerSettings => Some(1653), - Persistence::ModifyAuthenticationProcess => Some(1556), - Persistence::Other => None, + Persistence::BootOrLogonInitializationScripts => 1037, + Persistence::CreateOrModifySystemProcess => 1543, + Persistence::ExternalRemoteServices => 1133, + Persistence::BootOrLogonAutostartExecution => 1547, + Persistence::OfficeApplicationStartup => 1137, + Persistence::ScheduledTaskJob => 1053, + Persistence::BrowserExtensions => 1176, + Persistence::TrafficSignaling => 1205, + Persistence::ImplantInternalImage => 1525, + Persistence::PreOsBoot => 1542, + Persistence::CompromiseClientSoftwareBinary => 1554, + Persistence::AccountManipulation => 1098, + Persistence::HijackExecutionFlow => 1574, + Persistence::ValidAccounts => 1078, + Persistence::EventTriggeredExecution => 1546, + Persistence::BitsJobs => 1197, + Persistence::ServerSoftwareComponent => 1505, + Persistence::CreateAccount => 1136, + Persistence::PowerSettings => 1653, + Persistence::ModifyAuthenticationProcess => 1556, } } } -impl From for Option { +impl From for u32 { fn from(value: PrivilegeEscalation) -> Self { match value { - PrivilegeEscalation::BootOrLogonInitializationScripts => Some(1037), - PrivilegeEscalation::CreateOrModifySystemProcess => Some(1543), - PrivilegeEscalation::BootOrLogonAutostartExecution => Some(1547), - PrivilegeEscalation::ScheduledTaskJob => Some(1053), - PrivilegeEscalation::ProcessInjection => Some(1055), - PrivilegeEscalation::EscapeToHost => Some(1611), - PrivilegeEscalation::AbuseElevationControlMechanism => Some(1548), - PrivilegeEscalation::AccountManipulation => Some(1098), - PrivilegeEscalation::HijackExecutionFlow => Some(1574), - PrivilegeEscalation::ValidAccounts => Some(1078), - PrivilegeEscalation::ExploitationForPrivilegeEscalation => Some(1068), - PrivilegeEscalation::EventTriggeredExecution => Some(1546), - PrivilegeEscalation::AccessTokenManipulation => Some(1134), - PrivilegeEscalation::DomainPolicyModification => Some(1484), - PrivilegeEscalation::Other => None, + PrivilegeEscalation::BootOrLogonInitializationScripts => 1037, + PrivilegeEscalation::CreateOrModifySystemProcess => 1543, + PrivilegeEscalation::BootOrLogonAutostartExecution => 1547, + PrivilegeEscalation::ScheduledTaskJob => 1053, + PrivilegeEscalation::ProcessInjection => 1055, + PrivilegeEscalation::EscapeToHost => 1611, + PrivilegeEscalation::AbuseElevationControlMechanism => 1548, + PrivilegeEscalation::AccountManipulation => 1098, + PrivilegeEscalation::HijackExecutionFlow => 1574, + PrivilegeEscalation::ValidAccounts => 1078, + PrivilegeEscalation::ExploitationForPrivilegeEscalation => 1068, + PrivilegeEscalation::EventTriggeredExecution => 1546, + PrivilegeEscalation::AccessTokenManipulation => 1134, + PrivilegeEscalation::DomainPolicyModification => 1484, } } } -impl From for Option { +impl From for u32 { fn from(value: LateralMovement) -> Self { match value { - LateralMovement::TaintSharedContent => Some(1080), - LateralMovement::ReplicationThroughRemovableMedia => Some(1091), - LateralMovement::UseAlternateAuthenticationMaterial => Some(1550), - LateralMovement::RemoteServices => Some(1021), - LateralMovement::RemoteServiceSessionHijacking => Some(1563), - LateralMovement::SoftwareDeploymentTools => Some(1072), - LateralMovement::ExploitationOfRemoteServices => Some(1210), - LateralMovement::InternalSpearphishing => Some(1534), - LateralMovement::LateralToolTransfer => Some(1570), - LateralMovement::Other => None, + LateralMovement::TaintSharedContent => 1080, + LateralMovement::ReplicationThroughRemovableMedia => 1091, + LateralMovement::UseAlternateAuthenticationMaterial => 1550, + LateralMovement::RemoteServices => 1021, + LateralMovement::RemoteServiceSessionHijacking => 1563, + LateralMovement::SoftwareDeploymentTools => 1072, + LateralMovement::ExploitationOfRemoteServices => 1210, + LateralMovement::InternalSpearphishing => 1534, + LateralMovement::LateralToolTransfer => 1570, } } } -impl From for Option { +impl From for u32 { fn from(value: DefenseEvasion) -> Self { match value { - DefenseEvasion::DirectVolumeAccess => Some(1006), - DefenseEvasion::Rootkit => Some(1014), - DefenseEvasion::ModifyCloudComputeInfrastructure => Some(1578), - DefenseEvasion::WeakenEncryption => Some(1600), - DefenseEvasion::HideArtifacts => Some(1564), - DefenseEvasion::IndirectCommandExecution => Some(1202), - DefenseEvasion::DeobfuscateDecodeFilesOrInformation => Some(1140), - DefenseEvasion::ImpairDefenses => Some(1562), - DefenseEvasion::Masquerading => Some(1036), - DefenseEvasion::ProcessInjection => Some(1055), - DefenseEvasion::TrafficSignaling => Some(1205), - DefenseEvasion::SystemBinaryProxyExecution => Some(1218), - DefenseEvasion::ReflectiveCodeLoading => Some(1620), - DefenseEvasion::UseAlternateAuthenticationMaterial => Some(1550), - DefenseEvasion::RogueDomainController => Some(1207), - DefenseEvasion::DeployContainer => Some(1610), - DefenseEvasion::ModifyRegistry => Some(1112), - DefenseEvasion::UnusedUnsupportedCloudRegions => Some(1535), - DefenseEvasion::FileAndDirectoryPermissionsModification => Some(1222), - DefenseEvasion::AbuseElevationControlMechanism => Some(1548), - DefenseEvasion::IndicatorRemoval => Some(1070), - DefenseEvasion::PlistFileModification => Some(1647), - DefenseEvasion::PreOsBoot => Some(1542), - DefenseEvasion::BuildImageOnHost => Some(1612), - DefenseEvasion::VirtualizationSandboxEvasion => Some(1497), - DefenseEvasion::ExecutionGuardrails => Some(1480), - DefenseEvasion::ModifySystemImage => Some(1601), - DefenseEvasion::HijackExecutionFlow => Some(1574), - DefenseEvasion::ValidAccounts => Some(1078), - DefenseEvasion::ObfuscatedFilesOrInformation => Some(1027), - DefenseEvasion::NetworkBoundaryBridging => Some(1599), - DefenseEvasion::SubvertTrustControls => Some(1553), - DefenseEvasion::BitsJobs => Some(1197), - DefenseEvasion::Impersonation => Some(1656), - DefenseEvasion::TemplateInjection => Some(1221), - DefenseEvasion::AccessTokenManipulation => Some(1134), - DefenseEvasion::DebuggerEvasion => Some(1622), - DefenseEvasion::DomainPolicyModification => Some(1484), - DefenseEvasion::XslScriptProcessing => Some(1220), - DefenseEvasion::ModifyAuthenticationProcess => Some(1556), - DefenseEvasion::SystemScriptProxyExecution => Some(1216), - DefenseEvasion::ExploitationForDefenseEvasion => Some(1211), - DefenseEvasion::TrustedDeveloperUtilitiesProxyExecution => Some(1127), - DefenseEvasion::Other => None, + DefenseEvasion::DirectVolumeAccess => 1006, + DefenseEvasion::Rootkit => 1014, + DefenseEvasion::ModifyCloudComputeInfrastructure => 1578, + DefenseEvasion::WeakenEncryption => 1600, + DefenseEvasion::HideArtifacts => 1564, + DefenseEvasion::IndirectCommandExecution => 1202, + DefenseEvasion::DeobfuscateDecodeFilesOrInformation => 1140, + DefenseEvasion::ImpairDefenses => 1562, + DefenseEvasion::Masquerading => 1036, + DefenseEvasion::ProcessInjection => 1055, + DefenseEvasion::TrafficSignaling => 1205, + DefenseEvasion::SystemBinaryProxyExecution => 1218, + DefenseEvasion::ReflectiveCodeLoading => 1620, + DefenseEvasion::UseAlternateAuthenticationMaterial => 1550, + DefenseEvasion::RogueDomainController => 1207, + DefenseEvasion::DeployContainer => 1610, + DefenseEvasion::ModifyRegistry => 1112, + DefenseEvasion::UnusedUnsupportedCloudRegions => 1535, + DefenseEvasion::FileAndDirectoryPermissionsModification => 1222, + DefenseEvasion::AbuseElevationControlMechanism => 1548, + DefenseEvasion::IndicatorRemoval => 1070, + DefenseEvasion::PlistFileModification => 1647, + DefenseEvasion::PreOsBoot => 1542, + DefenseEvasion::BuildImageOnHost => 1612, + DefenseEvasion::VirtualizationSandboxEvasion => 1497, + DefenseEvasion::ExecutionGuardrails => 1480, + DefenseEvasion::ModifySystemImage => 1601, + DefenseEvasion::HijackExecutionFlow => 1574, + DefenseEvasion::ValidAccounts => 1078, + DefenseEvasion::ObfuscatedFilesOrInformation => 1027, + DefenseEvasion::NetworkBoundaryBridging => 1599, + DefenseEvasion::SubvertTrustControls => 1553, + DefenseEvasion::BitsJobs => 1197, + DefenseEvasion::Impersonation => 1656, + DefenseEvasion::TemplateInjection => 1221, + DefenseEvasion::AccessTokenManipulation => 1134, + DefenseEvasion::DebuggerEvasion => 1622, + DefenseEvasion::DomainPolicyModification => 1484, + DefenseEvasion::XslScriptProcessing => 1220, + DefenseEvasion::ModifyAuthenticationProcess => 1556, + DefenseEvasion::SystemScriptProxyExecution => 1216, + DefenseEvasion::ExploitationForDefenseEvasion => 1211, + DefenseEvasion::TrustedDeveloperUtilitiesProxyExecution => 1127, } } } -impl From for Option { +impl From for u32 { fn from(value: Exfiltration) -> Self { match value { - Exfiltration::ExfiltrationOverWebService => Some(1567), - Exfiltration::ScheduledTransfer => Some(1029), - Exfiltration::ExfiltrationOverOtherNetworkMedium => Some(1011), - Exfiltration::AutomatedExfiltration => Some(1020), - Exfiltration::ExfiltrationOverC2Channel => Some(1041), - Exfiltration::ExfiltrationOverAlternativeProtocol => Some(1048), - Exfiltration::DataTransferSizeLimits => Some(1030), - Exfiltration::TransferDataToCloudAccount => Some(1537), - Exfiltration::ExfiltrationOverPhysicalMedium => Some(1052), - Exfiltration::Other => None, + Exfiltration::ExfiltrationOverWebService => 1567, + Exfiltration::ScheduledTransfer => 1029, + Exfiltration::ExfiltrationOverOtherNetworkMedium => 1011, + Exfiltration::AutomatedExfiltration => 1020, + Exfiltration::ExfiltrationOverC2Channel => 1041, + Exfiltration::ExfiltrationOverAlternativeProtocol => 1048, + Exfiltration::DataTransferSizeLimits => 1030, + Exfiltration::TransferDataToCloudAccount => 1537, + Exfiltration::ExfiltrationOverPhysicalMedium => 1052, } } } -impl From for Option { +impl From for u32 { fn from(value: Discovery) -> Self { match value { - Discovery::SystemOwnerUserDiscovery => Some(1033), - Discovery::ContainerAndResourceDiscovery => Some(1613), - Discovery::PermissionGroupsDiscovery => Some(1069), - Discovery::GroupPolicyDiscovery => Some(1615), - Discovery::DeviceDriverDiscovery => Some(1652), - Discovery::SystemServiceDiscovery => Some(1007), - Discovery::NetworkSniffing => Some(1040), - Discovery::NetworkShareDiscovery => Some(1135), - Discovery::PeripheralDeviceDiscovery => Some(1120), - Discovery::SystemInformationDiscovery => Some(1082), - Discovery::ApplicationWindowDiscovery => Some(1010), - Discovery::CloudInfrastructureDiscovery => Some(1580), - Discovery::BrowserInformationDiscovery => Some(1217), - Discovery::SystemNetworkConfigurationDiscovery => Some(1016), - Discovery::AccountDiscovery => Some(1087), - Discovery::DomainTrustDiscovery => Some(1482), - Discovery::FileAndDirectoryDiscovery => Some(1083), - Discovery::SystemNetworkConnectionsDiscovery => Some(1049), - Discovery::VirtualizationSandboxEvasion => Some(1497), - Discovery::CloudStorageObjectDiscovery => Some(1619), - Discovery::LogEnumeration => Some(1654), - Discovery::ProcessDiscovery => Some(1057), - Discovery::PasswordPolicyDiscovery => Some(1201), - Discovery::QueryRegistry => Some(1012), - Discovery::SystemLocationDiscovery => Some(1614), - Discovery::CloudServiceDiscovery => Some(1526), - Discovery::RemoteSystemDiscovery => Some(1018), - Discovery::NetworkServiceDiscovery => Some(1046), - Discovery::SoftwareDiscovery => Some(1518), - Discovery::CloudServiceDashboard => Some(1538), - Discovery::DebuggerEvasion => Some(1622), - Discovery::SystemTimeDiscovery => Some(1124), - Discovery::Other => None, + Discovery::SystemOwnerUserDiscovery => 1033, + Discovery::ContainerAndResourceDiscovery => 1613, + Discovery::PermissionGroupsDiscovery => 1069, + Discovery::GroupPolicyDiscovery => 1615, + Discovery::DeviceDriverDiscovery => 1652, + Discovery::SystemServiceDiscovery => 1007, + Discovery::NetworkSniffing => 1040, + Discovery::NetworkShareDiscovery => 1135, + Discovery::PeripheralDeviceDiscovery => 1120, + Discovery::SystemInformationDiscovery => 1082, + Discovery::ApplicationWindowDiscovery => 1010, + Discovery::CloudInfrastructureDiscovery => 1580, + Discovery::BrowserInformationDiscovery => 1217, + Discovery::SystemNetworkConfigurationDiscovery => 1016, + Discovery::AccountDiscovery => 1087, + Discovery::DomainTrustDiscovery => 1482, + Discovery::FileAndDirectoryDiscovery => 1083, + Discovery::SystemNetworkConnectionsDiscovery => 1049, + Discovery::VirtualizationSandboxEvasion => 1497, + Discovery::CloudStorageObjectDiscovery => 1619, + Discovery::LogEnumeration => 1654, + Discovery::ProcessDiscovery => 1057, + Discovery::PasswordPolicyDiscovery => 1201, + Discovery::QueryRegistry => 1012, + Discovery::SystemLocationDiscovery => 1614, + Discovery::CloudServiceDiscovery => 1526, + Discovery::RemoteSystemDiscovery => 1018, + Discovery::NetworkServiceDiscovery => 1046, + Discovery::SoftwareDiscovery => 1518, + Discovery::CloudServiceDashboard => 1538, + Discovery::DebuggerEvasion => 1622, + Discovery::SystemTimeDiscovery => 1124, } } } -impl From for Option { +impl From for u32 { fn from(value: Collection) -> Self { match value { - Collection::ScreenCapture => Some(1113), - Collection::AdversaryInTheMiddle => Some(1557), - Collection::DataFromConfigurationRepository => Some(1602), - Collection::AudioCapture => Some(1123), - Collection::EmailCollection => Some(1114), - Collection::DataFromRemovableMedia => Some(1025), - Collection::AutomatedCollection => Some(1119), - Collection::ClipboardData => Some(1115), - Collection::DataFromCloudStorage => Some(1530), - Collection::DataFromLocalSystem => Some(1005), - Collection::ArchiveCollectedData => Some(1560), - Collection::BrowserSessionHijacking => Some(1185), - Collection::VideoCapture => Some(1125), - Collection::DataStaged => Some(1074), - Collection::DataFromNetworkSharedDrive => Some(1039), - Collection::InputCapture => Some(1056), - Collection::DataFromInformationRepositories => Some(1213), - Collection::Other => None, + Collection::ScreenCapture => 1113, + Collection::AdversaryInTheMiddle => 1557, + Collection::DataFromConfigurationRepository => 1602, + Collection::AudioCapture => 1123, + Collection::EmailCollection => 1114, + Collection::DataFromRemovableMedia => 1025, + Collection::AutomatedCollection => 1119, + Collection::ClipboardData => 1115, + Collection::DataFromCloudStorage => 1530, + Collection::DataFromLocalSystem => 1005, + Collection::ArchiveCollectedData => 1560, + Collection::BrowserSessionHijacking => 1185, + Collection::VideoCapture => 1125, + Collection::DataStaged => 1074, + Collection::DataFromNetworkSharedDrive => 1039, + Collection::InputCapture => 1056, + Collection::DataFromInformationRepositories => 1213, } } } -impl From for Option { +impl From for u32 { fn from(value: ResourceDevelopment) -> Self { match value { - ResourceDevelopment::AcquireInfrastructure => Some(1583), - ResourceDevelopment::CompromiseInfrastructure => Some(1584), - ResourceDevelopment::CompromiseAccounts => Some(1586), - ResourceDevelopment::StageCapabilities => Some(1608), - ResourceDevelopment::EstablishAccounts => Some(1585), - ResourceDevelopment::ObtainCapabilities => Some(1588), - ResourceDevelopment::AcquireAccess => Some(1650), - ResourceDevelopment::DevelopCapabilities => Some(1587), - ResourceDevelopment::Other => None, + ResourceDevelopment::AcquireInfrastructure => 1583, + ResourceDevelopment::CompromiseInfrastructure => 1584, + ResourceDevelopment::CompromiseAccounts => 1586, + ResourceDevelopment::StageCapabilities => 1608, + ResourceDevelopment::EstablishAccounts => 1585, + ResourceDevelopment::ObtainCapabilities => 1588, + ResourceDevelopment::AcquireAccess => 1650, + ResourceDevelopment::DevelopCapabilities => 1587, } } } -impl From for Option { +impl From for u32 { fn from(value: Reconnaissance) -> Self { match value { - Reconnaissance::GatherVictimHostInformation => Some(1592), - Reconnaissance::SearchVictimOwnedWebsites => Some(1594), - Reconnaissance::GatherVictimIdentityInformation => Some(1589), - Reconnaissance::SearchOpenTechnicalDatabases => Some(1596), - Reconnaissance::ActiveScanning => Some(1595), - Reconnaissance::GatherVictimOrgInformation => Some(1591), - Reconnaissance::GatherVictimNetworkInformation => Some(1590), - Reconnaissance::SearchOpenWebsitesDomains => Some(1593), - Reconnaissance::SearchClosedSources => Some(1597), - Reconnaissance::PhishingForInformation => Some(1598), - Reconnaissance::Other => None, + Reconnaissance::GatherVictimHostInformation => 1592, + Reconnaissance::SearchVictimOwnedWebsites => 1594, + Reconnaissance::GatherVictimIdentityInformation => 1589, + Reconnaissance::SearchOpenTechnicalDatabases => 1596, + Reconnaissance::ActiveScanning => 1595, + Reconnaissance::GatherVictimOrgInformation => 1591, + Reconnaissance::GatherVictimNetworkInformation => 1590, + Reconnaissance::SearchOpenWebsitesDomains => 1593, + Reconnaissance::SearchClosedSources => 1597, + Reconnaissance::PhishingForInformation => 1598, } } } -impl From for Option { +impl From for u32 { fn from(value: CommandAndControl) -> Self { match value { - CommandAndControl::ApplicationLayerProtocol => Some(1071), - CommandAndControl::RemoteAccessSoftware => Some(1219), - CommandAndControl::ContentInjection => Some(1659), - CommandAndControl::TrafficSignaling => Some(1205), - CommandAndControl::ProtocolTunneling => Some(1572), - CommandAndControl::CommunicationThroughRemovableMedia => Some(1092), - CommandAndControl::Proxy => Some(1090), - CommandAndControl::DynamicResolution => Some(1568), - CommandAndControl::WebService => Some(1102), - CommandAndControl::MultiStageChannels => Some(1104), - CommandAndControl::DataObfuscation => Some(1001), - CommandAndControl::NonStandardPort => Some(1571), - CommandAndControl::EncryptedChannel => Some(1573), - CommandAndControl::NonApplicationLayerProtocol => Some(1095), - CommandAndControl::DataEncoding => Some(1132), - CommandAndControl::IngressToolTransfer => Some(1105), - CommandAndControl::FallbackChannels => Some(1008), - CommandAndControl::Other => None, + CommandAndControl::ApplicationLayerProtocol => 1071, + CommandAndControl::RemoteAccessSoftware => 1219, + CommandAndControl::ContentInjection => 1659, + CommandAndControl::TrafficSignaling => 1205, + CommandAndControl::ProtocolTunneling => 1572, + CommandAndControl::CommunicationThroughRemovableMedia => 1092, + CommandAndControl::Proxy => 1090, + CommandAndControl::DynamicResolution => 1568, + CommandAndControl::WebService => 1102, + CommandAndControl::MultiStageChannels => 1104, + CommandAndControl::DataObfuscation => 1001, + CommandAndControl::NonStandardPort => 1571, + CommandAndControl::EncryptedChannel => 1573, + CommandAndControl::NonApplicationLayerProtocol => 1095, + CommandAndControl::DataEncoding => 1132, + CommandAndControl::IngressToolTransfer => 1105, + CommandAndControl::FallbackChannels => 1008, } } } -impl From for Option { +impl From for u32 { fn from(value: InitialAccess) -> Self { match value { - InitialAccess::ExternalRemoteServices => Some(1133), - InitialAccess::ReplicationThroughRemovableMedia => Some(1091), - InitialAccess::SupplyChainCompromise => Some(1195), - InitialAccess::ExploitPublicFacingApplication => Some(1190), - InitialAccess::ContentInjection => Some(1659), - InitialAccess::TrustedRelationship => Some(1199), - InitialAccess::Phishing => Some(1566), - InitialAccess::ValidAccounts => Some(1078), - InitialAccess::HardwareAdditions => Some(1200), - InitialAccess::DriveByCompromise => Some(1189), - InitialAccess::Other => None, + InitialAccess::ExternalRemoteServices => 1133, + InitialAccess::ReplicationThroughRemovableMedia => 1091, + InitialAccess::SupplyChainCompromise => 1195, + InitialAccess::ExploitPublicFacingApplication => 1190, + InitialAccess::ContentInjection => 1659, + InitialAccess::TrustedRelationship => 1199, + InitialAccess::Phishing => 1566, + InitialAccess::ValidAccounts => 1078, + InitialAccess::HardwareAdditions => 1200, + InitialAccess::DriveByCompromise => 1189, } } } From d351440d41db7f0606aeed09f3bf477e4cff190f Mon Sep 17 00:00:00 2001 From: gammelalf Date: Mon, 15 Jan 2024 17:22:00 +0100 Subject: [PATCH 12/37] Commited and documented mitre code generator --- .gitignore | 2 + kraken-proto/src/mitre.rs | 2 + utilities/README.md | 1 + utilities/mitre/README.md | 7 ++ utilities/mitre/main.py | 133 +++++++++++++++++++++++++++++++ utilities/mitre/requirements.txt | 1 + 6 files changed, 146 insertions(+) create mode 100644 utilities/README.md create mode 100644 utilities/mitre/README.md create mode 100644 utilities/mitre/main.py create mode 100644 utilities/mitre/requirements.txt diff --git a/.gitignore b/.gitignore index 0023a09ba..b7792c39b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ .idea/ .vagrant/ +venv/ +__pycache__/ vagrant/vars.yml .models.json diff --git a/kraken-proto/src/mitre.rs b/kraken-proto/src/mitre.rs index ef065e693..ce6fc00fb 100644 --- a/kraken-proto/src/mitre.rs +++ b/kraken-proto/src/mitre.rs @@ -1,4 +1,6 @@ //! Enums representing the tactics and techniques from [Mitre ATT&CK](https://attack.mitre.org/) +//! +//! This file is auto-generated by `utilities/mitre`! Don't edit it directly! use crate::InvalidArgumentError; use crate::shared::AttackTechnique; /// An entry in the [Mitre ATT&CK table](https://attack.mitre.org/) diff --git a/utilities/README.md b/utilities/README.md new file mode 100644 index 000000000..390a053d1 --- /dev/null +++ b/utilities/README.md @@ -0,0 +1 @@ +# Utility scripts for the kraken codebase diff --git a/utilities/mitre/README.md b/utilities/mitre/README.md new file mode 100644 index 000000000..89dbe2b3f --- /dev/null +++ b/utilities/mitre/README.md @@ -0,0 +1,7 @@ +# [Mitre](https://attack.mitre.org/) enum generator + +This python script generates `kraken-proto/src/mitre.rs`. + +It takes no arguments and writes the rust code to `stdout`. + +The json is takes its data from, is downloaded from [github](https://github.com/mitre/cti/blob/230f6c26b1554d90993e59cb60e0aeefef530147/enterprise-attack/enterprise-attack.json) and cached in `/tmp/`. \ No newline at end of file diff --git a/utilities/mitre/main.py b/utilities/mitre/main.py new file mode 100644 index 000000000..31007601c --- /dev/null +++ b/utilities/mitre/main.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 + +import os +import typing +import urllib.request + +from mitreattack.stix20 import MitreAttackData + + +FILE = "/tmp/enterprise-attack.json" +URL = "https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json" + + +class Technique: + name: str + ident: str + id: str + url: str + description: str + + +class Tactic: + name: str + ident: str + id: str + url: str + description: str + techniques: list[Technique] + + +def main(): + if not os.path.isfile(FILE): + urllib.request.urlretrieve(URL, FILE) + data = MitreAttackData(FILE) + + tactics: list[Tactic] = [] + for tactic in data.get_tactics(True): + tactics.append(Tactic()) + tactics[-1].name = tactic["name"] + tactics[-1].ident = to_camel_case(tactic["name"]) + tactics[-1].id = tactic["external_references"][0]["external_id"][2:] + tactics[-1].url = tactic["external_references"][0]["url"] + tactics[-1].description = tactic["description"].splitlines()[0] + tactics[-1].techniques = [] + for technique in data.get_techniques_by_tactic(tactic["x_mitre_shortname"], "enterprise-attack", True): + if technique["x_mitre_is_subtechnique"]: + continue + tactics[-1].techniques.append(Technique()) + tactics[-1].techniques[-1].name = technique["name"] + tactics[-1].techniques[-1].ident = to_camel_case(technique["name"]) + tactics[-1].techniques[-1].id = technique["external_references"][0]["external_id"][1:] + tactics[-1].techniques[-1].url = technique["external_references"][0]["url"] + tactics[-1].techniques[-1].description = technique["description"].splitlines()[0] + + print("//! Enums representing the tactics and techniques from [Mitre ATT&CK](https://attack.mitre.org/)") + print("//!") + print("//! This file is auto-generated by `utilities/mitre`! Don't edit it directly!") + print("use crate::InvalidArgumentError;") + print("use crate::shared::AttackTechnique;") + print("/// An entry in the [Mitre ATT&CK table](https://attack.mitre.org/)") + print("pub enum Tactic {") + for tactic in tactics: + print(f" /// [{tactic.name}]({tactic.url})") + print(f" ///") + print(f" /// {tactic.description}") + print(f" {tactic.ident}({tactic.ident}),") + print("") + print("}") + + for tactic in tactics: + print(f"/// [{tactic.name}]({tactic.url})'s techniques") + print(f"pub enum {tactic.ident} {{") + for technique in tactic.techniques: + print(f" /// [{technique.name}]({technique.url})") + print(f" ///") + print(f" /// {technique.description}") + print(f" {technique.ident},") + print("") + print("}") + + print("impl TryFrom for Tactic {") + print(" type Error = InvalidArgumentError;") + print(" fn try_from(value: AttackTechnique) -> Result {") + print(" let AttackTechnique { tactic, technique } = value;") + print(" Ok(match tactic {") + for tactic in tactics: + print(f" {tactic.id} => Self::{tactic.ident}({tactic.ident}::try_from(technique)?),") + print(" _ => return Err(InvalidArgumentError::InvalidMitreTactic(tactic)),") + print(" })") + print(" }") + print("}") + + for tactic in tactics: + print(f"impl TryFrom for {tactic.ident} {{") + print(" type Error = InvalidArgumentError;") + print(" fn try_from(value: u32) -> Result {") + print(" Ok(match value {") + for technique in tactic.techniques: + print(f" {technique.id} => Self::{technique.ident},") + print(f" _ => return Err(InvalidArgumentError::InvalidMitreTechnique({tactic.id}, value)),") + print(" })") + print(" }") + print("}") + + print("impl From for AttackTechnique {") + print(" fn from(value: Tactic) -> Self {") + print(" let (tactic, technique) = match value {") + for tactic in tactics: + print(f" Tactic::{tactic.ident}(technique) => ({tactic.id}, technique.into()),") + print(" };") + print(" AttackTechnique { tactic, technique }") + print(" }") + print("}") + + for tactic in tactics: + print(f"impl From<{tactic.ident}> for u32 {{") + print(f" fn from(value: {tactic.ident}) -> Self {{") + print(" match value {") + for technique in tactic.techniques: + print(f" {tactic.ident}::{technique.ident} => {technique.id},") + print(" }") + print(" }") + print("}") + + +def to_camel_case(name: str) -> str: + import re + return "".join((part.capitalize() for part in re.split("[-/_ ]", name))) + + +if __name__ == "__main__": + main() + diff --git a/utilities/mitre/requirements.txt b/utilities/mitre/requirements.txt new file mode 100644 index 000000000..00394d798 --- /dev/null +++ b/utilities/mitre/requirements.txt @@ -0,0 +1 @@ +mitreattack-python==3.0.2 From 536cf3b738cb9032d95b09f8310587ab4bfe62a3 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Wed, 17 Jan 2024 13:54:14 +0100 Subject: [PATCH 13/37] Added conversion to and from string for mitre types --- kraken-proto/src/mitre.rs | 706 ++++++++++++++++++++++++++++++++++++++ utilities/mitre/main.py | 84 ++++- 2 files changed, 772 insertions(+), 18 deletions(-) diff --git a/kraken-proto/src/mitre.rs b/kraken-proto/src/mitre.rs index ce6fc00fb..a8cc30a79 100644 --- a/kraken-proto/src/mitre.rs +++ b/kraken-proto/src/mitre.rs @@ -1,6 +1,8 @@ //! Enums representing the tactics and techniques from [Mitre ATT&CK](https://attack.mitre.org/) //! //! This file is auto-generated by `utilities/mitre`! Don't edit it directly! +use std::fmt; +use std::str::FromStr; use crate::InvalidArgumentError; use crate::shared::AttackTechnique; /// An entry in the [Mitre ATT&CK table](https://attack.mitre.org/) @@ -1996,3 +1998,707 @@ impl From for u32 { } } } +impl fmt::Display for Tactic { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Tactic::CredentialAccess(technique) => technique.fmt(f), + Tactic::Execution(technique) => technique.fmt(f), + Tactic::Impact(technique) => technique.fmt(f), + Tactic::Persistence(technique) => technique.fmt(f), + Tactic::PrivilegeEscalation(technique) => technique.fmt(f), + Tactic::LateralMovement(technique) => technique.fmt(f), + Tactic::DefenseEvasion(technique) => technique.fmt(f), + Tactic::Exfiltration(technique) => technique.fmt(f), + Tactic::Discovery(technique) => technique.fmt(f), + Tactic::Collection(technique) => technique.fmt(f), + Tactic::ResourceDevelopment(technique) => technique.fmt(f), + Tactic::Reconnaissance(technique) => technique.fmt(f), + Tactic::CommandAndControl(technique) => technique.fmt(f), + Tactic::InitialAccess(technique) => technique.fmt(f), + } + } +} +impl fmt::Display for CredentialAccess { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + CredentialAccess::AdversaryInTheMiddle => "Adversary-in-the-Middle", + CredentialAccess::OsCredentialDumping => "OS Credential Dumping", + CredentialAccess::StealWebSessionCookie => "Steal Web Session Cookie", + CredentialAccess::NetworkSniffing => "Network Sniffing", + CredentialAccess::StealOrForgeKerberosTickets => "Steal or Forge Kerberos Tickets", + CredentialAccess::CredentialsFromPasswordStores => "Credentials from Password Stores", + CredentialAccess::UnsecuredCredentials => "Unsecured Credentials", + CredentialAccess::StealOrForgeAuthenticationCertificates => "Steal or Forge Authentication Certificates", + CredentialAccess::StealApplicationAccessToken => "Steal Application Access Token", + CredentialAccess::ForgeWebCredentials => "Forge Web Credentials", + CredentialAccess::MultiFactorAuthenticationRequestGeneration => "Multi-Factor Authentication Request Generation", + CredentialAccess::ExploitationForCredentialAccess => "Exploitation for Credential Access", + CredentialAccess::BruteForce => "Brute Force", + CredentialAccess::ForcedAuthentication => "Forced Authentication", + CredentialAccess::InputCapture => "Input Capture", + CredentialAccess::MultiFactorAuthenticationInterception => "Multi-Factor Authentication Interception", + CredentialAccess::ModifyAuthenticationProcess => "Modify Authentication Process", + }) + } +} +impl fmt::Display for Execution { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + Execution::WindowsManagementInstrumentation => "Windows Management Instrumentation", + Execution::SharedModules => "Shared Modules", + Execution::ScheduledTaskJob => "Scheduled Task/Job", + Execution::NativeApi => "Native API", + Execution::DeployContainer => "Deploy Container", + Execution::CommandAndScriptingInterpreter => "Command and Scripting Interpreter", + Execution::ContainerAdministrationCommand => "Container Administration Command", + Execution::UserExecution => "User Execution", + Execution::SoftwareDeploymentTools => "Software Deployment Tools", + Execution::InterProcessCommunication => "Inter-Process Communication", + Execution::ExploitationForClientExecution => "Exploitation for Client Execution", + Execution::SystemServices => "System Services", + Execution::CloudAdministrationCommand => "Cloud Administration Command", + Execution::ServerlessExecution => "Serverless Execution", + }) + } +} +impl fmt::Display for Impact { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + Impact::DiskWipe => "Disk Wipe", + Impact::ServiceStop => "Service Stop", + Impact::Defacement => "Defacement", + Impact::FinancialTheft => "Financial Theft", + Impact::DataManipulation => "Data Manipulation", + Impact::AccountAccessRemoval => "Account Access Removal", + Impact::DataEncryptedForImpact => "Data Encrypted for Impact", + Impact::EndpointDenialOfService => "Endpoint Denial of Service", + Impact::ResourceHijacking => "Resource Hijacking", + Impact::DataDestruction => "Data Destruction", + Impact::NetworkDenialOfService => "Network Denial of Service", + Impact::FirmwareCorruption => "Firmware Corruption", + Impact::InhibitSystemRecovery => "Inhibit System Recovery", + Impact::SystemShutdownReboot => "System Shutdown/Reboot", + }) + } +} +impl fmt::Display for Persistence { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + Persistence::BootOrLogonInitializationScripts => "Boot or Logon Initialization Scripts", + Persistence::CreateOrModifySystemProcess => "Create or Modify System Process", + Persistence::ExternalRemoteServices => "External Remote Services", + Persistence::BootOrLogonAutostartExecution => "Boot or Logon Autostart Execution", + Persistence::OfficeApplicationStartup => "Office Application Startup", + Persistence::ScheduledTaskJob => "Scheduled Task/Job", + Persistence::BrowserExtensions => "Browser Extensions", + Persistence::TrafficSignaling => "Traffic Signaling", + Persistence::ImplantInternalImage => "Implant Internal Image", + Persistence::PreOsBoot => "Pre-OS Boot", + Persistence::CompromiseClientSoftwareBinary => "Compromise Client Software Binary", + Persistence::AccountManipulation => "Account Manipulation", + Persistence::HijackExecutionFlow => "Hijack Execution Flow", + Persistence::ValidAccounts => "Valid Accounts", + Persistence::EventTriggeredExecution => "Event Triggered Execution", + Persistence::BitsJobs => "BITS Jobs", + Persistence::ServerSoftwareComponent => "Server Software Component", + Persistence::CreateAccount => "Create Account", + Persistence::PowerSettings => "Power Settings", + Persistence::ModifyAuthenticationProcess => "Modify Authentication Process", + }) + } +} +impl fmt::Display for PrivilegeEscalation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + PrivilegeEscalation::BootOrLogonInitializationScripts => "Boot or Logon Initialization Scripts", + PrivilegeEscalation::CreateOrModifySystemProcess => "Create or Modify System Process", + PrivilegeEscalation::BootOrLogonAutostartExecution => "Boot or Logon Autostart Execution", + PrivilegeEscalation::ScheduledTaskJob => "Scheduled Task/Job", + PrivilegeEscalation::ProcessInjection => "Process Injection", + PrivilegeEscalation::EscapeToHost => "Escape to Host", + PrivilegeEscalation::AbuseElevationControlMechanism => "Abuse Elevation Control Mechanism", + PrivilegeEscalation::AccountManipulation => "Account Manipulation", + PrivilegeEscalation::HijackExecutionFlow => "Hijack Execution Flow", + PrivilegeEscalation::ValidAccounts => "Valid Accounts", + PrivilegeEscalation::ExploitationForPrivilegeEscalation => "Exploitation for Privilege Escalation", + PrivilegeEscalation::EventTriggeredExecution => "Event Triggered Execution", + PrivilegeEscalation::AccessTokenManipulation => "Access Token Manipulation", + PrivilegeEscalation::DomainPolicyModification => "Domain Policy Modification", + }) + } +} +impl fmt::Display for LateralMovement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + LateralMovement::TaintSharedContent => "Taint Shared Content", + LateralMovement::ReplicationThroughRemovableMedia => "Replication Through Removable Media", + LateralMovement::UseAlternateAuthenticationMaterial => "Use Alternate Authentication Material", + LateralMovement::RemoteServices => "Remote Services", + LateralMovement::RemoteServiceSessionHijacking => "Remote Service Session Hijacking", + LateralMovement::SoftwareDeploymentTools => "Software Deployment Tools", + LateralMovement::ExploitationOfRemoteServices => "Exploitation of Remote Services", + LateralMovement::InternalSpearphishing => "Internal Spearphishing", + LateralMovement::LateralToolTransfer => "Lateral Tool Transfer", + }) + } +} +impl fmt::Display for DefenseEvasion { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + DefenseEvasion::DirectVolumeAccess => "Direct Volume Access", + DefenseEvasion::Rootkit => "Rootkit", + DefenseEvasion::ModifyCloudComputeInfrastructure => "Modify Cloud Compute Infrastructure", + DefenseEvasion::WeakenEncryption => "Weaken Encryption", + DefenseEvasion::HideArtifacts => "Hide Artifacts", + DefenseEvasion::IndirectCommandExecution => "Indirect Command Execution", + DefenseEvasion::DeobfuscateDecodeFilesOrInformation => "Deobfuscate/Decode Files or Information", + DefenseEvasion::ImpairDefenses => "Impair Defenses", + DefenseEvasion::Masquerading => "Masquerading", + DefenseEvasion::ProcessInjection => "Process Injection", + DefenseEvasion::TrafficSignaling => "Traffic Signaling", + DefenseEvasion::SystemBinaryProxyExecution => "System Binary Proxy Execution", + DefenseEvasion::ReflectiveCodeLoading => "Reflective Code Loading", + DefenseEvasion::UseAlternateAuthenticationMaterial => "Use Alternate Authentication Material", + DefenseEvasion::RogueDomainController => "Rogue Domain Controller", + DefenseEvasion::DeployContainer => "Deploy Container", + DefenseEvasion::ModifyRegistry => "Modify Registry", + DefenseEvasion::UnusedUnsupportedCloudRegions => "Unused/Unsupported Cloud Regions", + DefenseEvasion::FileAndDirectoryPermissionsModification => "File and Directory Permissions Modification", + DefenseEvasion::AbuseElevationControlMechanism => "Abuse Elevation Control Mechanism", + DefenseEvasion::IndicatorRemoval => "Indicator Removal", + DefenseEvasion::PlistFileModification => "Plist File Modification", + DefenseEvasion::PreOsBoot => "Pre-OS Boot", + DefenseEvasion::BuildImageOnHost => "Build Image on Host", + DefenseEvasion::VirtualizationSandboxEvasion => "Virtualization/Sandbox Evasion", + DefenseEvasion::ExecutionGuardrails => "Execution Guardrails", + DefenseEvasion::ModifySystemImage => "Modify System Image", + DefenseEvasion::HijackExecutionFlow => "Hijack Execution Flow", + DefenseEvasion::ValidAccounts => "Valid Accounts", + DefenseEvasion::ObfuscatedFilesOrInformation => "Obfuscated Files or Information", + DefenseEvasion::NetworkBoundaryBridging => "Network Boundary Bridging", + DefenseEvasion::SubvertTrustControls => "Subvert Trust Controls", + DefenseEvasion::BitsJobs => "BITS Jobs", + DefenseEvasion::Impersonation => "Impersonation", + DefenseEvasion::TemplateInjection => "Template Injection", + DefenseEvasion::AccessTokenManipulation => "Access Token Manipulation", + DefenseEvasion::DebuggerEvasion => "Debugger Evasion", + DefenseEvasion::DomainPolicyModification => "Domain Policy Modification", + DefenseEvasion::XslScriptProcessing => "XSL Script Processing", + DefenseEvasion::ModifyAuthenticationProcess => "Modify Authentication Process", + DefenseEvasion::SystemScriptProxyExecution => "System Script Proxy Execution", + DefenseEvasion::ExploitationForDefenseEvasion => "Exploitation for Defense Evasion", + DefenseEvasion::TrustedDeveloperUtilitiesProxyExecution => "Trusted Developer Utilities Proxy Execution", + }) + } +} +impl fmt::Display for Exfiltration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + Exfiltration::ExfiltrationOverWebService => "Exfiltration Over Web Service", + Exfiltration::ScheduledTransfer => "Scheduled Transfer", + Exfiltration::ExfiltrationOverOtherNetworkMedium => "Exfiltration Over Other Network Medium", + Exfiltration::AutomatedExfiltration => "Automated Exfiltration", + Exfiltration::ExfiltrationOverC2Channel => "Exfiltration Over C2 Channel", + Exfiltration::ExfiltrationOverAlternativeProtocol => "Exfiltration Over Alternative Protocol", + Exfiltration::DataTransferSizeLimits => "Data Transfer Size Limits", + Exfiltration::TransferDataToCloudAccount => "Transfer Data to Cloud Account", + Exfiltration::ExfiltrationOverPhysicalMedium => "Exfiltration Over Physical Medium", + }) + } +} +impl fmt::Display for Discovery { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + Discovery::SystemOwnerUserDiscovery => "System Owner/User Discovery", + Discovery::ContainerAndResourceDiscovery => "Container and Resource Discovery", + Discovery::PermissionGroupsDiscovery => "Permission Groups Discovery", + Discovery::GroupPolicyDiscovery => "Group Policy Discovery", + Discovery::DeviceDriverDiscovery => "Device Driver Discovery", + Discovery::SystemServiceDiscovery => "System Service Discovery", + Discovery::NetworkSniffing => "Network Sniffing", + Discovery::NetworkShareDiscovery => "Network Share Discovery", + Discovery::PeripheralDeviceDiscovery => "Peripheral Device Discovery", + Discovery::SystemInformationDiscovery => "System Information Discovery", + Discovery::ApplicationWindowDiscovery => "Application Window Discovery", + Discovery::CloudInfrastructureDiscovery => "Cloud Infrastructure Discovery", + Discovery::BrowserInformationDiscovery => "Browser Information Discovery", + Discovery::SystemNetworkConfigurationDiscovery => "System Network Configuration Discovery", + Discovery::AccountDiscovery => "Account Discovery", + Discovery::DomainTrustDiscovery => "Domain Trust Discovery", + Discovery::FileAndDirectoryDiscovery => "File and Directory Discovery", + Discovery::SystemNetworkConnectionsDiscovery => "System Network Connections Discovery", + Discovery::VirtualizationSandboxEvasion => "Virtualization/Sandbox Evasion", + Discovery::CloudStorageObjectDiscovery => "Cloud Storage Object Discovery", + Discovery::LogEnumeration => "Log Enumeration", + Discovery::ProcessDiscovery => "Process Discovery", + Discovery::PasswordPolicyDiscovery => "Password Policy Discovery", + Discovery::QueryRegistry => "Query Registry", + Discovery::SystemLocationDiscovery => "System Location Discovery", + Discovery::CloudServiceDiscovery => "Cloud Service Discovery", + Discovery::RemoteSystemDiscovery => "Remote System Discovery", + Discovery::NetworkServiceDiscovery => "Network Service Discovery", + Discovery::SoftwareDiscovery => "Software Discovery", + Discovery::CloudServiceDashboard => "Cloud Service Dashboard", + Discovery::DebuggerEvasion => "Debugger Evasion", + Discovery::SystemTimeDiscovery => "System Time Discovery", + }) + } +} +impl fmt::Display for Collection { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + Collection::ScreenCapture => "Screen Capture", + Collection::AdversaryInTheMiddle => "Adversary-in-the-Middle", + Collection::DataFromConfigurationRepository => "Data from Configuration Repository", + Collection::AudioCapture => "Audio Capture", + Collection::EmailCollection => "Email Collection", + Collection::DataFromRemovableMedia => "Data from Removable Media", + Collection::AutomatedCollection => "Automated Collection", + Collection::ClipboardData => "Clipboard Data", + Collection::DataFromCloudStorage => "Data from Cloud Storage", + Collection::DataFromLocalSystem => "Data from Local System", + Collection::ArchiveCollectedData => "Archive Collected Data", + Collection::BrowserSessionHijacking => "Browser Session Hijacking", + Collection::VideoCapture => "Video Capture", + Collection::DataStaged => "Data Staged", + Collection::DataFromNetworkSharedDrive => "Data from Network Shared Drive", + Collection::InputCapture => "Input Capture", + Collection::DataFromInformationRepositories => "Data from Information Repositories", + }) + } +} +impl fmt::Display for ResourceDevelopment { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + ResourceDevelopment::AcquireInfrastructure => "Acquire Infrastructure", + ResourceDevelopment::CompromiseInfrastructure => "Compromise Infrastructure", + ResourceDevelopment::CompromiseAccounts => "Compromise Accounts", + ResourceDevelopment::StageCapabilities => "Stage Capabilities", + ResourceDevelopment::EstablishAccounts => "Establish Accounts", + ResourceDevelopment::ObtainCapabilities => "Obtain Capabilities", + ResourceDevelopment::AcquireAccess => "Acquire Access", + ResourceDevelopment::DevelopCapabilities => "Develop Capabilities", + }) + } +} +impl fmt::Display for Reconnaissance { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + Reconnaissance::GatherVictimHostInformation => "Gather Victim Host Information", + Reconnaissance::SearchVictimOwnedWebsites => "Search Victim-Owned Websites", + Reconnaissance::GatherVictimIdentityInformation => "Gather Victim Identity Information", + Reconnaissance::SearchOpenTechnicalDatabases => "Search Open Technical Databases", + Reconnaissance::ActiveScanning => "Active Scanning", + Reconnaissance::GatherVictimOrgInformation => "Gather Victim Org Information", + Reconnaissance::GatherVictimNetworkInformation => "Gather Victim Network Information", + Reconnaissance::SearchOpenWebsitesDomains => "Search Open Websites/Domains", + Reconnaissance::SearchClosedSources => "Search Closed Sources", + Reconnaissance::PhishingForInformation => "Phishing for Information", + }) + } +} +impl fmt::Display for CommandAndControl { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + CommandAndControl::ApplicationLayerProtocol => "Application Layer Protocol", + CommandAndControl::RemoteAccessSoftware => "Remote Access Software", + CommandAndControl::ContentInjection => "Content Injection", + CommandAndControl::TrafficSignaling => "Traffic Signaling", + CommandAndControl::ProtocolTunneling => "Protocol Tunneling", + CommandAndControl::CommunicationThroughRemovableMedia => "Communication Through Removable Media", + CommandAndControl::Proxy => "Proxy", + CommandAndControl::DynamicResolution => "Dynamic Resolution", + CommandAndControl::WebService => "Web Service", + CommandAndControl::MultiStageChannels => "Multi-Stage Channels", + CommandAndControl::DataObfuscation => "Data Obfuscation", + CommandAndControl::NonStandardPort => "Non-Standard Port", + CommandAndControl::EncryptedChannel => "Encrypted Channel", + CommandAndControl::NonApplicationLayerProtocol => "Non-Application Layer Protocol", + CommandAndControl::DataEncoding => "Data Encoding", + CommandAndControl::IngressToolTransfer => "Ingress Tool Transfer", + CommandAndControl::FallbackChannels => "Fallback Channels", + }) + } +} +impl fmt::Display for InitialAccess { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match self { + InitialAccess::ExternalRemoteServices => "External Remote Services", + InitialAccess::ReplicationThroughRemovableMedia => "Replication Through Removable Media", + InitialAccess::SupplyChainCompromise => "Supply Chain Compromise", + InitialAccess::ExploitPublicFacingApplication => "Exploit Public-Facing Application", + InitialAccess::ContentInjection => "Content Injection", + InitialAccess::TrustedRelationship => "Trusted Relationship", + InitialAccess::Phishing => "Phishing", + InitialAccess::ValidAccounts => "Valid Accounts", + InitialAccess::HardwareAdditions => "Hardware Additions", + InitialAccess::DriveByCompromise => "Drive-by Compromise", + }) + } +} +impl FromStr for Tactic { + type Err = (); + fn from_str(s: &str) -> Result { + Err(()) + .or_else(|_| CredentialAccess::from_str(s).map(Tactic::CredentialAccess)) + .or_else(|_| Execution::from_str(s).map(Tactic::Execution)) + .or_else(|_| Impact::from_str(s).map(Tactic::Impact)) + .or_else(|_| Persistence::from_str(s).map(Tactic::Persistence)) + .or_else(|_| PrivilegeEscalation::from_str(s).map(Tactic::PrivilegeEscalation)) + .or_else(|_| LateralMovement::from_str(s).map(Tactic::LateralMovement)) + .or_else(|_| DefenseEvasion::from_str(s).map(Tactic::DefenseEvasion)) + .or_else(|_| Exfiltration::from_str(s).map(Tactic::Exfiltration)) + .or_else(|_| Discovery::from_str(s).map(Tactic::Discovery)) + .or_else(|_| Collection::from_str(s).map(Tactic::Collection)) + .or_else(|_| ResourceDevelopment::from_str(s).map(Tactic::ResourceDevelopment)) + .or_else(|_| Reconnaissance::from_str(s).map(Tactic::Reconnaissance)) + .or_else(|_| CommandAndControl::from_str(s).map(Tactic::CommandAndControl)) + .or_else(|_| InitialAccess::from_str(s).map(Tactic::InitialAccess)) + } +} +impl FromStr for CredentialAccess { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Adversary-in-the-Middle" => Ok(CredentialAccess::AdversaryInTheMiddle), + "OS Credential Dumping" => Ok(CredentialAccess::OsCredentialDumping), + "Steal Web Session Cookie" => Ok(CredentialAccess::StealWebSessionCookie), + "Network Sniffing" => Ok(CredentialAccess::NetworkSniffing), + "Steal or Forge Kerberos Tickets" => Ok(CredentialAccess::StealOrForgeKerberosTickets), + "Credentials from Password Stores" => Ok(CredentialAccess::CredentialsFromPasswordStores), + "Unsecured Credentials" => Ok(CredentialAccess::UnsecuredCredentials), + "Steal or Forge Authentication Certificates" => Ok(CredentialAccess::StealOrForgeAuthenticationCertificates), + "Steal Application Access Token" => Ok(CredentialAccess::StealApplicationAccessToken), + "Forge Web Credentials" => Ok(CredentialAccess::ForgeWebCredentials), + "Multi-Factor Authentication Request Generation" => Ok(CredentialAccess::MultiFactorAuthenticationRequestGeneration), + "Exploitation for Credential Access" => Ok(CredentialAccess::ExploitationForCredentialAccess), + "Brute Force" => Ok(CredentialAccess::BruteForce), + "Forced Authentication" => Ok(CredentialAccess::ForcedAuthentication), + "Input Capture" => Ok(CredentialAccess::InputCapture), + "Multi-Factor Authentication Interception" => Ok(CredentialAccess::MultiFactorAuthenticationInterception), + "Modify Authentication Process" => Ok(CredentialAccess::ModifyAuthenticationProcess), + _ => Err(()), + } + } +} +impl FromStr for Execution { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Windows Management Instrumentation" => Ok(Execution::WindowsManagementInstrumentation), + "Shared Modules" => Ok(Execution::SharedModules), + "Scheduled Task/Job" => Ok(Execution::ScheduledTaskJob), + "Native API" => Ok(Execution::NativeApi), + "Deploy Container" => Ok(Execution::DeployContainer), + "Command and Scripting Interpreter" => Ok(Execution::CommandAndScriptingInterpreter), + "Container Administration Command" => Ok(Execution::ContainerAdministrationCommand), + "User Execution" => Ok(Execution::UserExecution), + "Software Deployment Tools" => Ok(Execution::SoftwareDeploymentTools), + "Inter-Process Communication" => Ok(Execution::InterProcessCommunication), + "Exploitation for Client Execution" => Ok(Execution::ExploitationForClientExecution), + "System Services" => Ok(Execution::SystemServices), + "Cloud Administration Command" => Ok(Execution::CloudAdministrationCommand), + "Serverless Execution" => Ok(Execution::ServerlessExecution), + _ => Err(()), + } + } +} +impl FromStr for Impact { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Disk Wipe" => Ok(Impact::DiskWipe), + "Service Stop" => Ok(Impact::ServiceStop), + "Defacement" => Ok(Impact::Defacement), + "Financial Theft" => Ok(Impact::FinancialTheft), + "Data Manipulation" => Ok(Impact::DataManipulation), + "Account Access Removal" => Ok(Impact::AccountAccessRemoval), + "Data Encrypted for Impact" => Ok(Impact::DataEncryptedForImpact), + "Endpoint Denial of Service" => Ok(Impact::EndpointDenialOfService), + "Resource Hijacking" => Ok(Impact::ResourceHijacking), + "Data Destruction" => Ok(Impact::DataDestruction), + "Network Denial of Service" => Ok(Impact::NetworkDenialOfService), + "Firmware Corruption" => Ok(Impact::FirmwareCorruption), + "Inhibit System Recovery" => Ok(Impact::InhibitSystemRecovery), + "System Shutdown/Reboot" => Ok(Impact::SystemShutdownReboot), + _ => Err(()), + } + } +} +impl FromStr for Persistence { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Boot or Logon Initialization Scripts" => Ok(Persistence::BootOrLogonInitializationScripts), + "Create or Modify System Process" => Ok(Persistence::CreateOrModifySystemProcess), + "External Remote Services" => Ok(Persistence::ExternalRemoteServices), + "Boot or Logon Autostart Execution" => Ok(Persistence::BootOrLogonAutostartExecution), + "Office Application Startup" => Ok(Persistence::OfficeApplicationStartup), + "Scheduled Task/Job" => Ok(Persistence::ScheduledTaskJob), + "Browser Extensions" => Ok(Persistence::BrowserExtensions), + "Traffic Signaling" => Ok(Persistence::TrafficSignaling), + "Implant Internal Image" => Ok(Persistence::ImplantInternalImage), + "Pre-OS Boot" => Ok(Persistence::PreOsBoot), + "Compromise Client Software Binary" => Ok(Persistence::CompromiseClientSoftwareBinary), + "Account Manipulation" => Ok(Persistence::AccountManipulation), + "Hijack Execution Flow" => Ok(Persistence::HijackExecutionFlow), + "Valid Accounts" => Ok(Persistence::ValidAccounts), + "Event Triggered Execution" => Ok(Persistence::EventTriggeredExecution), + "BITS Jobs" => Ok(Persistence::BitsJobs), + "Server Software Component" => Ok(Persistence::ServerSoftwareComponent), + "Create Account" => Ok(Persistence::CreateAccount), + "Power Settings" => Ok(Persistence::PowerSettings), + "Modify Authentication Process" => Ok(Persistence::ModifyAuthenticationProcess), + _ => Err(()), + } + } +} +impl FromStr for PrivilegeEscalation { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Boot or Logon Initialization Scripts" => Ok(PrivilegeEscalation::BootOrLogonInitializationScripts), + "Create or Modify System Process" => Ok(PrivilegeEscalation::CreateOrModifySystemProcess), + "Boot or Logon Autostart Execution" => Ok(PrivilegeEscalation::BootOrLogonAutostartExecution), + "Scheduled Task/Job" => Ok(PrivilegeEscalation::ScheduledTaskJob), + "Process Injection" => Ok(PrivilegeEscalation::ProcessInjection), + "Escape to Host" => Ok(PrivilegeEscalation::EscapeToHost), + "Abuse Elevation Control Mechanism" => Ok(PrivilegeEscalation::AbuseElevationControlMechanism), + "Account Manipulation" => Ok(PrivilegeEscalation::AccountManipulation), + "Hijack Execution Flow" => Ok(PrivilegeEscalation::HijackExecutionFlow), + "Valid Accounts" => Ok(PrivilegeEscalation::ValidAccounts), + "Exploitation for Privilege Escalation" => Ok(PrivilegeEscalation::ExploitationForPrivilegeEscalation), + "Event Triggered Execution" => Ok(PrivilegeEscalation::EventTriggeredExecution), + "Access Token Manipulation" => Ok(PrivilegeEscalation::AccessTokenManipulation), + "Domain Policy Modification" => Ok(PrivilegeEscalation::DomainPolicyModification), + _ => Err(()), + } + } +} +impl FromStr for LateralMovement { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Taint Shared Content" => Ok(LateralMovement::TaintSharedContent), + "Replication Through Removable Media" => Ok(LateralMovement::ReplicationThroughRemovableMedia), + "Use Alternate Authentication Material" => Ok(LateralMovement::UseAlternateAuthenticationMaterial), + "Remote Services" => Ok(LateralMovement::RemoteServices), + "Remote Service Session Hijacking" => Ok(LateralMovement::RemoteServiceSessionHijacking), + "Software Deployment Tools" => Ok(LateralMovement::SoftwareDeploymentTools), + "Exploitation of Remote Services" => Ok(LateralMovement::ExploitationOfRemoteServices), + "Internal Spearphishing" => Ok(LateralMovement::InternalSpearphishing), + "Lateral Tool Transfer" => Ok(LateralMovement::LateralToolTransfer), + _ => Err(()), + } + } +} +impl FromStr for DefenseEvasion { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Direct Volume Access" => Ok(DefenseEvasion::DirectVolumeAccess), + "Rootkit" => Ok(DefenseEvasion::Rootkit), + "Modify Cloud Compute Infrastructure" => Ok(DefenseEvasion::ModifyCloudComputeInfrastructure), + "Weaken Encryption" => Ok(DefenseEvasion::WeakenEncryption), + "Hide Artifacts" => Ok(DefenseEvasion::HideArtifacts), + "Indirect Command Execution" => Ok(DefenseEvasion::IndirectCommandExecution), + "Deobfuscate/Decode Files or Information" => Ok(DefenseEvasion::DeobfuscateDecodeFilesOrInformation), + "Impair Defenses" => Ok(DefenseEvasion::ImpairDefenses), + "Masquerading" => Ok(DefenseEvasion::Masquerading), + "Process Injection" => Ok(DefenseEvasion::ProcessInjection), + "Traffic Signaling" => Ok(DefenseEvasion::TrafficSignaling), + "System Binary Proxy Execution" => Ok(DefenseEvasion::SystemBinaryProxyExecution), + "Reflective Code Loading" => Ok(DefenseEvasion::ReflectiveCodeLoading), + "Use Alternate Authentication Material" => Ok(DefenseEvasion::UseAlternateAuthenticationMaterial), + "Rogue Domain Controller" => Ok(DefenseEvasion::RogueDomainController), + "Deploy Container" => Ok(DefenseEvasion::DeployContainer), + "Modify Registry" => Ok(DefenseEvasion::ModifyRegistry), + "Unused/Unsupported Cloud Regions" => Ok(DefenseEvasion::UnusedUnsupportedCloudRegions), + "File and Directory Permissions Modification" => Ok(DefenseEvasion::FileAndDirectoryPermissionsModification), + "Abuse Elevation Control Mechanism" => Ok(DefenseEvasion::AbuseElevationControlMechanism), + "Indicator Removal" => Ok(DefenseEvasion::IndicatorRemoval), + "Plist File Modification" => Ok(DefenseEvasion::PlistFileModification), + "Pre-OS Boot" => Ok(DefenseEvasion::PreOsBoot), + "Build Image on Host" => Ok(DefenseEvasion::BuildImageOnHost), + "Virtualization/Sandbox Evasion" => Ok(DefenseEvasion::VirtualizationSandboxEvasion), + "Execution Guardrails" => Ok(DefenseEvasion::ExecutionGuardrails), + "Modify System Image" => Ok(DefenseEvasion::ModifySystemImage), + "Hijack Execution Flow" => Ok(DefenseEvasion::HijackExecutionFlow), + "Valid Accounts" => Ok(DefenseEvasion::ValidAccounts), + "Obfuscated Files or Information" => Ok(DefenseEvasion::ObfuscatedFilesOrInformation), + "Network Boundary Bridging" => Ok(DefenseEvasion::NetworkBoundaryBridging), + "Subvert Trust Controls" => Ok(DefenseEvasion::SubvertTrustControls), + "BITS Jobs" => Ok(DefenseEvasion::BitsJobs), + "Impersonation" => Ok(DefenseEvasion::Impersonation), + "Template Injection" => Ok(DefenseEvasion::TemplateInjection), + "Access Token Manipulation" => Ok(DefenseEvasion::AccessTokenManipulation), + "Debugger Evasion" => Ok(DefenseEvasion::DebuggerEvasion), + "Domain Policy Modification" => Ok(DefenseEvasion::DomainPolicyModification), + "XSL Script Processing" => Ok(DefenseEvasion::XslScriptProcessing), + "Modify Authentication Process" => Ok(DefenseEvasion::ModifyAuthenticationProcess), + "System Script Proxy Execution" => Ok(DefenseEvasion::SystemScriptProxyExecution), + "Exploitation for Defense Evasion" => Ok(DefenseEvasion::ExploitationForDefenseEvasion), + "Trusted Developer Utilities Proxy Execution" => Ok(DefenseEvasion::TrustedDeveloperUtilitiesProxyExecution), + _ => Err(()), + } + } +} +impl FromStr for Exfiltration { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Exfiltration Over Web Service" => Ok(Exfiltration::ExfiltrationOverWebService), + "Scheduled Transfer" => Ok(Exfiltration::ScheduledTransfer), + "Exfiltration Over Other Network Medium" => Ok(Exfiltration::ExfiltrationOverOtherNetworkMedium), + "Automated Exfiltration" => Ok(Exfiltration::AutomatedExfiltration), + "Exfiltration Over C2 Channel" => Ok(Exfiltration::ExfiltrationOverC2Channel), + "Exfiltration Over Alternative Protocol" => Ok(Exfiltration::ExfiltrationOverAlternativeProtocol), + "Data Transfer Size Limits" => Ok(Exfiltration::DataTransferSizeLimits), + "Transfer Data to Cloud Account" => Ok(Exfiltration::TransferDataToCloudAccount), + "Exfiltration Over Physical Medium" => Ok(Exfiltration::ExfiltrationOverPhysicalMedium), + _ => Err(()), + } + } +} +impl FromStr for Discovery { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "System Owner/User Discovery" => Ok(Discovery::SystemOwnerUserDiscovery), + "Container and Resource Discovery" => Ok(Discovery::ContainerAndResourceDiscovery), + "Permission Groups Discovery" => Ok(Discovery::PermissionGroupsDiscovery), + "Group Policy Discovery" => Ok(Discovery::GroupPolicyDiscovery), + "Device Driver Discovery" => Ok(Discovery::DeviceDriverDiscovery), + "System Service Discovery" => Ok(Discovery::SystemServiceDiscovery), + "Network Sniffing" => Ok(Discovery::NetworkSniffing), + "Network Share Discovery" => Ok(Discovery::NetworkShareDiscovery), + "Peripheral Device Discovery" => Ok(Discovery::PeripheralDeviceDiscovery), + "System Information Discovery" => Ok(Discovery::SystemInformationDiscovery), + "Application Window Discovery" => Ok(Discovery::ApplicationWindowDiscovery), + "Cloud Infrastructure Discovery" => Ok(Discovery::CloudInfrastructureDiscovery), + "Browser Information Discovery" => Ok(Discovery::BrowserInformationDiscovery), + "System Network Configuration Discovery" => Ok(Discovery::SystemNetworkConfigurationDiscovery), + "Account Discovery" => Ok(Discovery::AccountDiscovery), + "Domain Trust Discovery" => Ok(Discovery::DomainTrustDiscovery), + "File and Directory Discovery" => Ok(Discovery::FileAndDirectoryDiscovery), + "System Network Connections Discovery" => Ok(Discovery::SystemNetworkConnectionsDiscovery), + "Virtualization/Sandbox Evasion" => Ok(Discovery::VirtualizationSandboxEvasion), + "Cloud Storage Object Discovery" => Ok(Discovery::CloudStorageObjectDiscovery), + "Log Enumeration" => Ok(Discovery::LogEnumeration), + "Process Discovery" => Ok(Discovery::ProcessDiscovery), + "Password Policy Discovery" => Ok(Discovery::PasswordPolicyDiscovery), + "Query Registry" => Ok(Discovery::QueryRegistry), + "System Location Discovery" => Ok(Discovery::SystemLocationDiscovery), + "Cloud Service Discovery" => Ok(Discovery::CloudServiceDiscovery), + "Remote System Discovery" => Ok(Discovery::RemoteSystemDiscovery), + "Network Service Discovery" => Ok(Discovery::NetworkServiceDiscovery), + "Software Discovery" => Ok(Discovery::SoftwareDiscovery), + "Cloud Service Dashboard" => Ok(Discovery::CloudServiceDashboard), + "Debugger Evasion" => Ok(Discovery::DebuggerEvasion), + "System Time Discovery" => Ok(Discovery::SystemTimeDiscovery), + _ => Err(()), + } + } +} +impl FromStr for Collection { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Screen Capture" => Ok(Collection::ScreenCapture), + "Adversary-in-the-Middle" => Ok(Collection::AdversaryInTheMiddle), + "Data from Configuration Repository" => Ok(Collection::DataFromConfigurationRepository), + "Audio Capture" => Ok(Collection::AudioCapture), + "Email Collection" => Ok(Collection::EmailCollection), + "Data from Removable Media" => Ok(Collection::DataFromRemovableMedia), + "Automated Collection" => Ok(Collection::AutomatedCollection), + "Clipboard Data" => Ok(Collection::ClipboardData), + "Data from Cloud Storage" => Ok(Collection::DataFromCloudStorage), + "Data from Local System" => Ok(Collection::DataFromLocalSystem), + "Archive Collected Data" => Ok(Collection::ArchiveCollectedData), + "Browser Session Hijacking" => Ok(Collection::BrowserSessionHijacking), + "Video Capture" => Ok(Collection::VideoCapture), + "Data Staged" => Ok(Collection::DataStaged), + "Data from Network Shared Drive" => Ok(Collection::DataFromNetworkSharedDrive), + "Input Capture" => Ok(Collection::InputCapture), + "Data from Information Repositories" => Ok(Collection::DataFromInformationRepositories), + _ => Err(()), + } + } +} +impl FromStr for ResourceDevelopment { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Acquire Infrastructure" => Ok(ResourceDevelopment::AcquireInfrastructure), + "Compromise Infrastructure" => Ok(ResourceDevelopment::CompromiseInfrastructure), + "Compromise Accounts" => Ok(ResourceDevelopment::CompromiseAccounts), + "Stage Capabilities" => Ok(ResourceDevelopment::StageCapabilities), + "Establish Accounts" => Ok(ResourceDevelopment::EstablishAccounts), + "Obtain Capabilities" => Ok(ResourceDevelopment::ObtainCapabilities), + "Acquire Access" => Ok(ResourceDevelopment::AcquireAccess), + "Develop Capabilities" => Ok(ResourceDevelopment::DevelopCapabilities), + _ => Err(()), + } + } +} +impl FromStr for Reconnaissance { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Gather Victim Host Information" => Ok(Reconnaissance::GatherVictimHostInformation), + "Search Victim-Owned Websites" => Ok(Reconnaissance::SearchVictimOwnedWebsites), + "Gather Victim Identity Information" => Ok(Reconnaissance::GatherVictimIdentityInformation), + "Search Open Technical Databases" => Ok(Reconnaissance::SearchOpenTechnicalDatabases), + "Active Scanning" => Ok(Reconnaissance::ActiveScanning), + "Gather Victim Org Information" => Ok(Reconnaissance::GatherVictimOrgInformation), + "Gather Victim Network Information" => Ok(Reconnaissance::GatherVictimNetworkInformation), + "Search Open Websites/Domains" => Ok(Reconnaissance::SearchOpenWebsitesDomains), + "Search Closed Sources" => Ok(Reconnaissance::SearchClosedSources), + "Phishing for Information" => Ok(Reconnaissance::PhishingForInformation), + _ => Err(()), + } + } +} +impl FromStr for CommandAndControl { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "Application Layer Protocol" => Ok(CommandAndControl::ApplicationLayerProtocol), + "Remote Access Software" => Ok(CommandAndControl::RemoteAccessSoftware), + "Content Injection" => Ok(CommandAndControl::ContentInjection), + "Traffic Signaling" => Ok(CommandAndControl::TrafficSignaling), + "Protocol Tunneling" => Ok(CommandAndControl::ProtocolTunneling), + "Communication Through Removable Media" => Ok(CommandAndControl::CommunicationThroughRemovableMedia), + "Proxy" => Ok(CommandAndControl::Proxy), + "Dynamic Resolution" => Ok(CommandAndControl::DynamicResolution), + "Web Service" => Ok(CommandAndControl::WebService), + "Multi-Stage Channels" => Ok(CommandAndControl::MultiStageChannels), + "Data Obfuscation" => Ok(CommandAndControl::DataObfuscation), + "Non-Standard Port" => Ok(CommandAndControl::NonStandardPort), + "Encrypted Channel" => Ok(CommandAndControl::EncryptedChannel), + "Non-Application Layer Protocol" => Ok(CommandAndControl::NonApplicationLayerProtocol), + "Data Encoding" => Ok(CommandAndControl::DataEncoding), + "Ingress Tool Transfer" => Ok(CommandAndControl::IngressToolTransfer), + "Fallback Channels" => Ok(CommandAndControl::FallbackChannels), + _ => Err(()), + } + } +} +impl FromStr for InitialAccess { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "External Remote Services" => Ok(InitialAccess::ExternalRemoteServices), + "Replication Through Removable Media" => Ok(InitialAccess::ReplicationThroughRemovableMedia), + "Supply Chain Compromise" => Ok(InitialAccess::SupplyChainCompromise), + "Exploit Public-Facing Application" => Ok(InitialAccess::ExploitPublicFacingApplication), + "Content Injection" => Ok(InitialAccess::ContentInjection), + "Trusted Relationship" => Ok(InitialAccess::TrustedRelationship), + "Phishing" => Ok(InitialAccess::Phishing), + "Valid Accounts" => Ok(InitialAccess::ValidAccounts), + "Hardware Additions" => Ok(InitialAccess::HardwareAdditions), + "Drive-by Compromise" => Ok(InitialAccess::DriveByCompromise), + _ => Err(()), + } + } +} diff --git a/utilities/mitre/main.py b/utilities/mitre/main.py index 31007601c..89caa4741 100644 --- a/utilities/mitre/main.py +++ b/utilities/mitre/main.py @@ -3,6 +3,7 @@ import os import typing import urllib.request +from dataclasses import dataclass from mitreattack.stix20 import MitreAttackData @@ -11,6 +12,7 @@ URL = "https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json" +@dataclass class Technique: name: str ident: str @@ -19,6 +21,7 @@ class Technique: description: str +@dataclass class Tactic: name: str ident: str @@ -33,28 +36,33 @@ def main(): urllib.request.urlretrieve(URL, FILE) data = MitreAttackData(FILE) - tactics: list[Tactic] = [] - for tactic in data.get_tactics(True): - tactics.append(Tactic()) - tactics[-1].name = tactic["name"] - tactics[-1].ident = to_camel_case(tactic["name"]) - tactics[-1].id = tactic["external_references"][0]["external_id"][2:] - tactics[-1].url = tactic["external_references"][0]["url"] - tactics[-1].description = tactic["description"].splitlines()[0] - tactics[-1].techniques = [] - for technique in data.get_techniques_by_tactic(tactic["x_mitre_shortname"], "enterprise-attack", True): - if technique["x_mitre_is_subtechnique"]: - continue - tactics[-1].techniques.append(Technique()) - tactics[-1].techniques[-1].name = technique["name"] - tactics[-1].techniques[-1].ident = to_camel_case(technique["name"]) - tactics[-1].techniques[-1].id = technique["external_references"][0]["external_id"][1:] - tactics[-1].techniques[-1].url = technique["external_references"][0]["url"] - tactics[-1].techniques[-1].description = technique["description"].splitlines()[0] + tactics = [ + Tactic( + tactic["name"], + to_camel_case(tactic["name"]), + tactic["external_references"][0]["external_id"][2:], + tactic["external_references"][0]["url"], + tactic["description"].splitlines()[0], + [ + Technique( + technique["name"], + to_camel_case(technique["name"]), + technique["external_references"][0]["external_id"][1:], + technique["external_references"][0]["url"], + technique["description"].splitlines()[0] + ) + for technique in data.get_techniques_by_tactic(tactic["x_mitre_shortname"], "enterprise-attack", True) + if not technique["x_mitre_is_subtechnique"] + ], + ) + for tactic in data.get_tactics(True) + ] print("//! Enums representing the tactics and techniques from [Mitre ATT&CK](https://attack.mitre.org/)") print("//!") print("//! This file is auto-generated by `utilities/mitre`! Don't edit it directly!") + print("use std::fmt;") + print("use std::str::FromStr;") print("use crate::InvalidArgumentError;") print("use crate::shared::AttackTechnique;") print("/// An entry in the [Mitre ATT&CK table](https://attack.mitre.org/)") @@ -122,6 +130,46 @@ def main(): print(" }") print("}") + print("impl fmt::Display for Tactic {") + print(" fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {") + print(" match self {") + for tactic in tactics: + print(f" Tactic::{tactic.ident}(technique) => technique.fmt(f),") + print(" }") + print(" }") + print("}") + + for tactic in tactics: + print(f"impl fmt::Display for {tactic.ident} {{") + print(" fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {") + print(" f.write_str(match self {") + for technique in tactic.techniques: + print(f" {tactic.ident}::{technique.ident} => \"{technique.name}\",") + print(" })") + print(" }") + print("}") + + print("impl FromStr for Tactic {") + print(" type Err = ();") + print(" fn from_str(s: &str) -> Result {") + print(" Err(())") + for tactic in tactics: + print(f" .or_else(|_| {tactic.ident}::from_str(s).map(Tactic::{tactic.ident}))") + print(" }") + print("}") + + for tactic in tactics: + print(f"impl FromStr for {tactic.ident} {{") + print(" type Err = ();") + print(" fn from_str(s: &str) -> Result {") + print(" match s {") + for technique in tactic.techniques: + print(f" \"{technique.name}\" => Ok({tactic.ident}::{technique.ident}),") + print(" _ => Err(()),") + print(" }") + print(" }") + print("}") + def to_camel_case(name: str) -> str: import re From 012a9a98abd5a59059efcf2e1137440616b502a5 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Mon, 22 Jan 2024 12:46:50 +0100 Subject: [PATCH 14/37] Require port and ip for testssl attack --- kraken-proto/proto/attacks.proto | 18 +++++---- kraken/src/api/handler/attacks/handler.rs | 4 ++ kraken/src/api/handler/attacks/schema.rs | 7 ++++ kraken/src/modules/attacks/mod.rs | 8 +++- kraken/src/modules/attacks/testssl.rs | 3 ++ leech/src/main.rs | 11 +++++- leech/src/modules/testssl/finding_id.rs | 4 +- leech/src/modules/testssl/mod.rs | 46 +++++++++++++++++++++-- leech/src/rpc/attacks.rs | 4 ++ 9 files changed, 90 insertions(+), 15 deletions(-) diff --git a/kraken-proto/proto/attacks.proto b/kraken-proto/proto/attacks.proto index 1f86992c7..34cc52b8c 100644 --- a/kraken-proto/proto/attacks.proto +++ b/kraken-proto/proto/attacks.proto @@ -204,20 +204,24 @@ message DnsResolutionResponse { message TestSSLRequest { // A unique id that identifier the attack string attack_uuid = 1; - // The domain to scan + // The domain used for SNI and cert validity check string uri = 2; + // The ip address to scan + shared.Address ip = 3; + // The port to scan + uint32 port = 4; // Timeout for TCP handshakes in seconds - optional uint64 connect_timeout = 3; + optional uint64 connect_timeout = 5; // Timeout for `openssl` connections in seconds - optional uint64 openssl_timeout = 4; + optional uint64 openssl_timeout = 6; // Enable ip v6 - optional bool v6 = 5; + optional bool v6 = 7; // Set the `BASICAUTH` header when checking http headers - optional BasicAuth basic_auth = 6; + optional BasicAuth basic_auth = 8; // Run against a STARTTLS enabled protocol - optional StartTLSProtocol starttls = 7; + optional StartTLSProtocol starttls = 9; // Which scans `testssl.sh` should run - optional TestSSLScans scans = 8; + optional TestSSLScans scans = 10; } // The `BASICAUTH` header diff --git a/kraken/src/api/handler/attacks/handler.rs b/kraken/src/api/handler/attacks/handler.rs index 2b02116e2..140fffda4 100644 --- a/kraken/src/api/handler/attacks/handler.rs +++ b/kraken/src/api/handler/attacks/handler.rs @@ -401,6 +401,8 @@ pub async fn testssl( leech_uuid, workspace_uuid, uri, + host, + port, connect_timeout, openssl_timeout, basic_auth, @@ -419,6 +421,8 @@ pub async fn testssl( client, TestSSLParams { uri, + ip: host, + port, connect_timeout, openssl_timeout, basic_auth, diff --git a/kraken/src/api/handler/attacks/schema.rs b/kraken/src/api/handler/attacks/schema.rs index f8e464984..2a104c498 100644 --- a/kraken/src/api/handler/attacks/schema.rs +++ b/kraken/src/api/handler/attacks/schema.rs @@ -217,6 +217,13 @@ pub struct TestSSLRequest { /// The domain to scan pub uri: String, + /// The host to scan + #[schema(value_type = String)] + pub host: IpAddr, + + /// The port to scan + pub port: u16, + /// Timeout for TCP handshakes in seconds pub connect_timeout: Option, diff --git a/kraken/src/modules/attacks/mod.rs b/kraken/src/modules/attacks/mod.rs index f6c16f94d..47f49ddbf 100644 --- a/kraken/src/modules/attacks/mod.rs +++ b/kraken/src/modules/attacks/mod.rs @@ -265,9 +265,15 @@ pub async fn start_tcp_port_scan( /// The parameters of a "testssl" attack pub struct TestSSLParams { - /// The domain to scan + /// The domain to use for sni and cert validation pub uri: String, + /// The ip to scan + pub ip: IpAddr, + + /// The port to scan + pub port: u16, + /// Timeout for TCP handshakes in seconds pub connect_timeout: Option, diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index 4f7b22386..9683a1492 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -1,6 +1,7 @@ use std::str::FromStr; use ipnetwork::IpNetwork; +use kraken_proto::shared::Address; use kraken_proto::{ test_ssl_scans, test_ssl_service, BasicAuth, StartTlsProtocol, TestSslRequest, TestSslResponse, TestSslScanResult, TestSslScans, @@ -29,6 +30,8 @@ impl AttackContext { let request = TestSslRequest { attack_uuid: self.attack_uuid.to_string(), uri: params.uri, + ip: Some(Address::from(params.ip)), + port: params.port as u32, connect_timeout: params.connect_timeout, openssl_timeout: params.openssl_timeout, v6: Some(true), diff --git a/leech/src/main.rs b/leech/src/main.rs index 8eb63f08f..e5dd6842b 100644 --- a/leech/src/main.rs +++ b/leech/src/main.rs @@ -182,6 +182,13 @@ pub enum RunCommand { TestSSL { /// Domain to scan uri: String, + + /// The ip address to scan + ip: IpAddr, + + /// The port to scan + #[clap(default_value_t = 443)] + port: u16, }, } @@ -535,9 +542,11 @@ async fn main() -> Result<(), Box> { .await; println!("{result:?}"); } - RunCommand::TestSSL { uri } => { + RunCommand::TestSSL { uri, ip, port } => { let json = testssl::run_testssl(TestSSLSettings { uri, + ip, + port, ..Default::default() }) .await?; diff --git a/leech/src/modules/testssl/finding_id.rs b/leech/src/modules/testssl/finding_id.rs index ab4f9f7f8..8c7a79fab 100644 --- a/leech/src/modules/testssl/finding_id.rs +++ b/leech/src/modules/testssl/finding_id.rs @@ -259,7 +259,7 @@ pub enum Vulnerabilities { Beast, BeastSsl3, BeastTls1, - Lucky32, + Lucky13, Rc4, Grease, } @@ -508,7 +508,7 @@ impl From<&str> for FindingId { "BEAST" => v(Vulnerabilities::Beast), "BEAST_CBC_SSL3" => v(Vulnerabilities::BeastSsl3), "BEAST_CBC_TLS1" => v(Vulnerabilities::BeastTls1), - "LUCKY13" => v(Vulnerabilities::Lucky32), + "LUCKY13" => v(Vulnerabilities::Lucky13), "RC4" => v(Vulnerabilities::Rc4), "GREASE" => v(Vulnerabilities::Grease), "ROBOT" => v(Vulnerabilities::Robot), diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index c4db40992..ea3cc37c1 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -1,8 +1,9 @@ //! Holds data and code to interact with `testssl.sh` use std::io; +use std::net::IpAddr; -use log::error; +use log::{debug, error, trace}; use tempfile::NamedTempFile; use thiserror::Error; use tokio::fs::File as TokioFile; @@ -17,11 +18,17 @@ pub use self::json_pretty::*; pub use self::mitre::categorize; /// The settings of a `testssl.sh` invocation -#[derive(Default, Debug)] +#[derive(Debug)] pub struct TestSSLSettings { /// The domain to scan pub uri: String, + /// The ip address to scan + pub ip: IpAddr, + + /// The port to scan + pub port: u16, + /// Timeout for TCP handshakes in seconds pub connect_timeout: Option, @@ -40,6 +47,21 @@ pub struct TestSSLSettings { /// Which scans `testssl.sh` should run pub scans: TestSSLScans, } +impl Default for TestSSLSettings { + fn default() -> Self { + Self { + uri: "localhost".to_string(), + ip: IpAddr::from([127, 0, 0, 1]), + port: 443, + connect_timeout: None, + openssl_timeout: None, + v6: true, + basic_auth: None, + starttls: None, + scans: TestSSLScans::default(), + } + } +} /// Protocols to select from when using `--starttls` #[derive(Debug)] @@ -112,6 +134,8 @@ pub enum TestSSLScans { pub async fn run_testssl(settings: TestSSLSettings) -> Result { let TestSSLSettings { uri, + ip, + port, connect_timeout, openssl_timeout, v6, @@ -220,7 +244,12 @@ pub async fn run_testssl(settings: TestSSLSettings) -> Result Result Date: Mon, 22 Jan 2024 16:55:30 +0100 Subject: [PATCH 15/37] Store testssl results in db --- kraken/migrations/0003_testssl.toml | 245 ++++++++++++++++++ .../api/handler/aggregation_source/schema.rs | 6 +- .../api/handler/aggregation_source/utils.rs | 131 ++++++---- .../src/api/handler/attack_results/handler.rs | 65 ++++- .../src/api/handler/attack_results/schema.rs | 39 ++- kraken/src/api/server.rs | 1 + kraken/src/api/swagger.rs | 6 +- kraken/src/models/aggregation/mod.rs | 2 +- kraken/src/models/attack/mod.rs | 137 +++++++++- kraken/src/models/attack/patches.rs | 22 +- kraken/src/modules/attacks/testssl.rs | 88 +++++-- 11 files changed, 648 insertions(+), 94 deletions(-) create mode 100644 kraken/migrations/0003_testssl.toml diff --git a/kraken/migrations/0003_testssl.toml b/kraken/migrations/0003_testssl.toml new file mode 100644 index 000000000..03198e741 --- /dev/null +++ b/kraken/migrations/0003_testssl.toml @@ -0,0 +1,245 @@ +[Migration] +Hash = "6102967724574231408" +Initial = false +Dependency = 2 +Replaces = [] + +[[Migration.Operations]] +Type = "CreateModel" +Name = "testsslresultheader" + +[[Migration.Operations.Fields]] +Name = "uuid" +Type = "uuid" + +[[Migration.Operations.Fields.Annotations]] +Type = "primary_key" + +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "target_host" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "ip" +Type = "ipnetwork" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "port" +Type = "int32" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "rdns" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "service" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateModel" +Name = "testsslresultfinding" + +[[Migration.Operations.Fields]] +Name = "uuid" +Type = "uuid" + +[[Migration.Operations.Fields.Annotations]] +Type = "primary_key" + +[[Migration.Operations.Fields]] +Name = "created_at" +Type = "datetime" + +[[Migration.Operations.Fields.Annotations]] +Type = "auto_create_time" + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "section" +Type = "choices" + +[[Migration.Operations.Fields.Annotations]] +Type = "choices" +Value = [ + "Pretest", + "Protocols", + "Grease", + "Ciphers", + "Pfs", + "ServerPreferences", + "ServerDefaults", + "HeaderResponse", + "Vulnerabilities", + "CipherTests", + "BrowserSimulations", +] + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "key" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "value" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 1024 + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "testssl_severity" +Type = "choices" + +[[Migration.Operations.Fields.Annotations]] +Type = "choices" +Value = [ + "Debug", + "Info", + "Warn", + "Fatal", + "Ok", + "Low", + "Medium", + "High", + "Critical", +] + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations.Fields]] +Name = "cve" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields]] +Name = "cwe" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields]] +Name = "mitre" +Type = "varchar" + +[[Migration.Operations.Fields.Annotations]] +Type = "max_length" +Value = 255 + +[[Migration.Operations.Fields]] +Name = "severity" +Type = "choices" + +[[Migration.Operations.Fields.Annotations]] +Type = "choices" +Value = [ + "None", + "Low", + "Medium", + "High", + "Critical", +] + +[[Migration.Operations.Fields.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateField" +Model = "testsslresultfinding" + +[Migration.Operations.Field] +Name = "attack" +Type = "uuid" + +[[Migration.Operations.Field.Annotations]] +Type = "foreign_key" + +[Migration.Operations.Field.Annotations.Value] +TableName = "attack" +ColumnName = "uuid" +OnDelete = "Cascade" +OnUpdate = "Cascade" + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "CreateField" +Model = "testsslresultheader" + +[Migration.Operations.Field] +Name = "attack" +Type = "uuid" + +[[Migration.Operations.Field.Annotations]] +Type = "foreign_key" + +[Migration.Operations.Field.Annotations.Value] +TableName = "attack" +ColumnName = "uuid" +OnDelete = "Cascade" +OnUpdate = "Cascade" + +[[Migration.Operations.Field.Annotations]] +Type = "not_null" + +[[Migration.Operations]] +Type = "DeleteModel" +Name = "testsslresult" diff --git a/kraken/src/api/handler/aggregation_source/schema.rs b/kraken/src/api/handler/aggregation_source/schema.rs index ba6ad87df..f82eccfbf 100644 --- a/kraken/src/api/handler/aggregation_source/schema.rs +++ b/kraken/src/api/handler/aggregation_source/schema.rs @@ -4,9 +4,9 @@ use utoipa::ToSchema; use uuid::Uuid; use crate::api::handler::attack_results::schema::{ - FullQueryCertificateTransparencyResult, FullServiceDetectionResult, + FullQueryCertificateTransparencyResult, FullServiceDetectionResult, FullTestSSLResult, SimpleBruteforceSubdomainsResult, SimpleDnsResolutionResult, SimpleHostAliveResult, - SimpleQueryUnhashedResult, SimpleTcpPortScanResult, SimpleTestSSLResult, + SimpleQueryUnhashedResult, SimpleTcpPortScanResult, }; use crate::api::handler::users::schema::SimpleUser; use crate::models::{ @@ -94,7 +94,7 @@ pub enum SourceAttackResult { /// The [`AttackType::DnsResolution`] and its results DnsResolution(Vec), /// The [`AttackType::TestSSL`] and its results - TestSSL(Vec), + TestSSL(FullTestSSLResult), } /// The different types of manual inserts diff --git a/kraken/src/api/handler/aggregation_source/utils.rs b/kraken/src/api/handler/aggregation_source/utils.rs index 5aa6dd72c..08d3d3248 100644 --- a/kraken/src/api/handler/aggregation_source/utils.rs +++ b/kraken/src/api/handler/aggregation_source/utils.rs @@ -13,16 +13,17 @@ use crate::api::handler::aggregation_source::schema::{ FullAggregationSource, ManualInsert, SimpleAggregationSource, SourceAttack, SourceAttackResult, }; use crate::api::handler::attack_results::schema::{ - FullQueryCertificateTransparencyResult, FullServiceDetectionResult, + FullQueryCertificateTransparencyResult, FullServiceDetectionResult, FullTestSSLResult, SimpleBruteforceSubdomainsResult, SimpleDnsResolutionResult, SimpleHostAliveResult, - SimpleQueryUnhashedResult, SimpleTcpPortScanResult, SimpleTestSSLResult, + SimpleQueryUnhashedResult, SimpleTcpPortScanResult, TestSSLFinding, }; use crate::api::handler::users::schema::SimpleUser; use crate::models::{ AggregationSource, AggregationTable, Attack, AttackType, BruteforceSubdomainsResult, CertificateTransparencyResult, CertificateTransparencyValueName, DehashedQueryResult, DnsResolutionResult, HostAliveResult, ManualDomain, ManualHost, ManualPort, ManualService, - ServiceDetectionName, ServiceDetectionResult, SourceType, TcpPortScanResult, TestSSLResult, + ServiceDetectionName, ServiceDetectionResult, SourceType, TcpPortScanResult, + TestSSLResultFinding, TestSSLResultHeader, }; fn field_in<'a, T, F, P, Any>( @@ -164,7 +165,7 @@ impl FullAggregationSource { let mut host_alive: Results = Results::new(); let mut service_detection: Results = Results::new(); let mut dns_resolution: Results = Results::new(); - let mut testssl: Results = Results::new(); + let mut testssl: HashMap = HashMap::new(); let mut manual_insert = Vec::new(); for (source_type, uuids) in sources { if uuids.is_empty() { @@ -340,22 +341,47 @@ impl FullAggregationSource { } } SourceType::TestSSL => { - let mut stream = query!(&mut *tx, TestSSLResult) - .condition(field_in(TestSSLResult::F.uuid, uuids)) - .stream(); - while let Some(result) = stream.try_next().await? { - testssl.entry(*result.attack.key()).or_default().push( - SimpleTestSSLResult { - uuid: result.uuid, - attack: *result.attack.key(), - created_at: result.created_at, - target_host: result.target_host, - ip: result.ip.ip().to_string(), - port: result.port as u16, - rdns: result.rdns, - service: result.service, - }, - ); + { + let mut stream = query!(&mut *tx, TestSSLResultHeader) + .condition(field_in(TestSSLResultHeader::F.uuid, uuids)) + .stream(); + while let Some(result) = stream.try_next().await? { + testssl.insert( + *result.attack.key(), + FullTestSSLResult { + uuid: result.uuid, + attack: *result.attack.key(), + created_at: result.created_at, + target_host: result.target_host, + ip: result.ip.ip().to_string(), + port: result.port as u16, + rdns: result.rdns, + service: result.service, + findings: Vec::new(), + }, + ); + } + } + { + let mut stream = query!(&mut *tx, TestSSLResultFinding) + .condition(field_in( + TestSSLResultFinding::F.attack, + testssl.keys().copied(), + )) + .stream(); + while let Some(result) = stream.try_next().await? { + testssl.get_mut(result.attack.key()).unwrap().findings.push( + TestSSLFinding { + section: result.section, + id: result.key.to_string(), + value: result.value, + severity: result.testssl_severity, + cve: result.cve, + cwe: result.cwe, + issue: (), + }, + ); + } } } SourceType::UdpPortScan @@ -520,32 +546,29 @@ impl FullAggregationSource { error!("An `AttackType::Undefined` shouldn't have been queried"); continue; } - AttackType::BruteforceSubdomains => SourceAttackResult::BruteforceSubdomains( - bruteforce_subdomains.remove(&uuid).unwrap_or_default(), - ), - AttackType::TcpPortScan => SourceAttackResult::TcpPortScan( - tcp_port_scan.remove(&uuid).unwrap_or_default(), - ), - AttackType::QueryCertificateTransparency => { - SourceAttackResult::QueryCertificateTransparency( - certificate_transparency.remove(&uuid).unwrap_or_default(), - ) - } - AttackType::QueryUnhashed => SourceAttackResult::QueryDehashed( - query_dehashed.remove(&uuid).unwrap_or_default(), - ), + AttackType::BruteforceSubdomains => bruteforce_subdomains + .remove(&uuid) + .map(SourceAttackResult::BruteforceSubdomains), + + AttackType::TcpPortScan => tcp_port_scan + .remove(&uuid) + .map(SourceAttackResult::TcpPortScan), + AttackType::QueryCertificateTransparency => certificate_transparency + .remove(&uuid) + .map(SourceAttackResult::QueryCertificateTransparency), + AttackType::QueryUnhashed => query_dehashed + .remove(&uuid) + .map(SourceAttackResult::QueryDehashed), AttackType::HostAlive => { - SourceAttackResult::HostAlive(host_alive.remove(&uuid).unwrap_or_default()) - } - AttackType::ServiceDetection => SourceAttackResult::ServiceDetection( - service_detection.remove(&uuid).unwrap_or_default(), - ), - AttackType::DnsResolution => SourceAttackResult::DnsResolution( - dns_resolution.remove(&uuid).unwrap_or_default(), - ), - AttackType::TestSSL => { - SourceAttackResult::TestSSL(testssl.remove(&uuid).unwrap_or_default()) + host_alive.remove(&uuid).map(SourceAttackResult::HostAlive) } + AttackType::ServiceDetection => service_detection + .remove(&uuid) + .map(SourceAttackResult::ServiceDetection), + AttackType::DnsResolution => dns_resolution + .remove(&uuid) + .map(SourceAttackResult::DnsResolution), + AttackType::TestSSL => testssl.remove(&uuid).map(SourceAttackResult::TestSSL), AttackType::UdpPortScan | AttackType::ForcedBrowsing | AttackType::OSDetection @@ -555,15 +578,17 @@ impl FullAggregationSource { continue; } }; - attacks.push(SourceAttack { - uuid, - workspace_uuid: *workspace.key(), - started_by, - finished_at, - error, - created_at, - results, - }); + if let Some(results) = results { + attacks.push(SourceAttack { + uuid, + workspace_uuid: *workspace.key(), + started_by, + finished_at, + error, + created_at, + results, + }); + } } } diff --git a/kraken/src/api/handler/attack_results/handler.rs b/kraken/src/api/handler/attack_results/handler.rs index c874b92a6..46456f818 100644 --- a/kraken/src/api/handler/attack_results/handler.rs +++ b/kraken/src/api/handler/attack_results/handler.rs @@ -9,9 +9,9 @@ use uuid::Uuid; use crate::api::extractors::SessionUser; use crate::api::handler::attack_results::schema::{ - FullQueryCertificateTransparencyResult, FullServiceDetectionResult, + FullQueryCertificateTransparencyResult, FullServiceDetectionResult, FullTestSSLResult, SimpleBruteforceSubdomainsResult, SimpleDnsResolutionResult, SimpleHostAliveResult, - SimpleQueryUnhashedResult, SimpleTcpPortScanResult, + SimpleQueryUnhashedResult, SimpleTcpPortScanResult, TestSSLFinding, }; use crate::api::handler::common::error::{ApiError, ApiResult}; use crate::api::handler::common::schema::{ @@ -25,6 +25,7 @@ use crate::models::{ Attack, BruteforceSubdomainsResult, CertificateTransparencyResult, CertificateTransparencyValueName, DehashedQueryResult, DnsResolutionResult, HostAliveResult, ServiceCertainty, ServiceDetectionName, ServiceDetectionResult, TcpPortScanResult, + TestSSLResultFinding, TestSSLResultHeader, }; /// Retrieve a bruteforce subdomains' results by the attack's id @@ -510,3 +511,63 @@ pub async fn get_dns_resolution_results( total: total as u64, })) } + +/// Retrieve a `testssl.sh`'s results by the attack's id +#[utoipa::path( + tag = "Attacks", + context_path = "/api/v1", + responses( + (status = 200, description = "Returns attack's results", body = FullTestSSLResult), + (status = 400, description = "Client error", body = ApiErrorResponse), + (status = 500, description = "Server error", body = ApiErrorResponse), + ), + params(PathUuid), + security(("api_key" = [])) +)] +#[get("/attacks/{uuid}/testsslResults")] +pub async fn get_testssl_results( + path: Path, + SessionUser(user_uuid): SessionUser, +) -> ApiResult> { + let mut tx = GLOBAL.db.start_transaction().await?; + + let attack_uuid = path.uuid; + + if !Attack::has_access(&mut tx, attack_uuid, user_uuid).await? { + return Err(ApiError::MissingPrivileges); + } + + let header = query!(&mut tx, TestSSLResultHeader) + .condition(TestSSLResultHeader::F.attack.equals(attack_uuid)) + .one() + .await?; + + let result = FullTestSSLResult { + uuid: header.uuid, + attack: attack_uuid, + created_at: header.created_at, + target_host: header.target_host, + ip: header.ip.ip().to_string(), + port: header.port as u16, + rdns: header.rdns, + service: header.service, + findings: query!(&mut tx, TestSSLResultFinding) + .condition(TestSSLResultFinding::F.attack.equals(attack_uuid)) + .stream() + .map_ok(|x| TestSSLFinding { + section: x.section, + id: x.key, + value: x.value, + severity: x.testssl_severity, + cve: x.cve, + cwe: x.cwe, + issue: (), + }) + .try_collect() + .await?, + }; + + tx.commit().await?; + + Ok(Json(result)) +} diff --git a/kraken/src/api/handler/attack_results/schema.rs b/kraken/src/api/handler/attack_results/schema.rs index 3c7d1f2df..2c49ffd2b 100644 --- a/kraken/src/api/handler/attack_results/schema.rs +++ b/kraken/src/api/handler/attack_results/schema.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use utoipa::ToSchema; use uuid::Uuid; -use crate::models::{DnsRecordType, ServiceCertainty}; +use crate::models::{DnsRecordType, ServiceCertainty, TestSSLSection, TestSSLSeverity}; /// A simple representation of a bruteforce subdomains result #[derive(Serialize, Deserialize, ToSchema, Debug, Clone)] @@ -194,9 +194,9 @@ pub struct SimpleDnsResolutionResult { pub dns_record_type: DnsRecordType, } -/// A simple representation of a testssl result +/// The results of a `testssl.sh` scan #[derive(Serialize, Deserialize, ToSchema, Debug, Clone)] -pub struct SimpleTestSSLResult { +pub struct FullTestSSLResult { /// The primary key pub uuid: Uuid, @@ -220,5 +220,36 @@ pub struct SimpleTestSSLResult { /// The detected service pub service: String, - // TODO + + /// The scan's findings + /// + /// This includes, log messages, extracted information (for example cert parameters) and tests for vulnerabilities / bad options. + pub findings: Vec, +} + +/// A single finding reported by `testssl.sh` +/// +/// This includes, log messages, extracted information (for example cert parameters) and tests for vulnerabilities / bad options. +#[derive(Serialize, Deserialize, ToSchema, Debug, Clone)] +pub struct TestSSLFinding { + /// The section `testssl.sh` reported this finding under + pub section: TestSSLSection, + + /// The finding's id (not db id, but `testssl.sh` id) + pub id: String, + + /// The finding's value (the value's semantics are highly dependant on the `id` and `severity`) + pub value: String, + + /// The severity reported by `testssl.sh` (this also includes log levels) + pub severity: TestSSLSeverity, + + /// An associated cve + pub cve: Option, + + /// An associated cwe category + pub cwe: Option, + + /// An issue categorized by kraken TODO + pub issue: (), } diff --git a/kraken/src/api/server.rs b/kraken/src/api/server.rs index df024458c..1fbf9ff18 100644 --- a/kraken/src/api/server.rs +++ b/kraken/src/api/server.rs @@ -171,6 +171,7 @@ pub async fn start_server(config: &Config) -> Result<(), StartServerError> { .service(attack_results::handler::get_host_alive_results) .service(attack_results::handler::get_service_detection_results) .service(attack_results::handler::get_dns_resolution_results) + .service(attack_results::handler::get_testssl_results) .service(api_keys::handler::create_api_key) .service(api_keys::handler::get_api_keys) .service(api_keys::handler::update_api_key) diff --git a/kraken/src/api/swagger.rs b/kraken/src/api/swagger.rs index 96503ac8b..9e6012858 100644 --- a/kraken/src/api/swagger.rs +++ b/kraken/src/api/swagger.rs @@ -95,6 +95,7 @@ impl Modify for SecurityAddon2 { attack_results::handler::get_host_alive_results, attack_results::handler::get_service_detection_results, attack_results::handler::get_dns_resolution_results, + attack_results::handler::get_testssl_results, oauth_applications::handler_admin::create_oauth_app, oauth_applications::handler_admin::get_all_oauth_apps, oauth_applications::handler_admin::get_oauth_app, @@ -210,7 +211,8 @@ impl Modify for SecurityAddon2 { attack_results::schema::SimpleHostAliveResult, attack_results::schema::FullServiceDetectionResult, attack_results::schema::SimpleDnsResolutionResult, - attack_results::schema::SimpleTestSSLResult, + attack_results::schema::FullTestSSLResult, + attack_results::schema::TestSSLFinding, dehashed_rs::Query, dehashed_rs::SearchType, attacks::schema::QueryDehashedRequest, @@ -268,6 +270,8 @@ impl Modify for SecurityAddon2 { models::ManualHostCertainty, models::ManualPortCertainty, models::ManualServiceCertainty, + models::TestSSLSection, + models::TestSSLSeverity, global_tags::schema::CreateGlobalTagRequest, global_tags::schema::FullGlobalTag, global_tags::schema::ListGlobalTags, diff --git a/kraken/src/models/aggregation/mod.rs b/kraken/src/models/aggregation/mod.rs index 4a7cca37c..660b1c149 100644 --- a/kraken/src/models/aggregation/mod.rs +++ b/kraken/src/models/aggregation/mod.rs @@ -529,7 +529,7 @@ pub enum SourceType { VersionDetection, /// The table for the not yet implemented [`AttackType::AntiPortScanningDetection`] results AntiPortScanningDetection, - /// The table for the not yet implemented [`AttackType::TestSSL`] results + /// The [`TestSSLResultHeader`] table TestSSL, /// The [`ManualDomain`] table ManualDomain, diff --git a/kraken/src/models/attack/mod.rs b/kraken/src/models/attack/mod.rs index 77606eeb1..91c9bcc5c 100644 --- a/kraken/src/models/attack/mod.rs +++ b/kraken/src/models/attack/mod.rs @@ -320,9 +320,11 @@ pub struct ServiceDetectionResult { pub service_names: BackRef, } -/// Representation of a [TestSSL](AttackType::TestSSL) attack's result +/// Meta information about a single `testssl.sh` scan's results +/// +/// The actual results are stored in [`TestSSLResultFinding`]. #[derive(Model)] -pub struct TestSSLResult { +pub struct TestSSLResultHeader { /// The primary key #[rorm(primary_key)] pub uuid: Uuid, @@ -352,5 +354,134 @@ pub struct TestSSLResult { /// The detected service #[rorm(max_length = 255)] pub service: String, - // TODO +} + +/// A single finding reported by `testssl.sh` +/// +/// This includes, log messages, extracted information (for example cert parameters) and tests for vulnerabilities / bad options. +#[derive(Model)] +pub struct TestSSLResultFinding { + /// The primary key + #[rorm(primary_key)] + pub uuid: Uuid, + + /// The [attack](Attack) which produced this result + #[rorm(on_delete = "Cascade", on_update = "Cascade")] + pub attack: ForeignModel, + + /// The point in time, this result was produced + #[rorm(auto_create_time)] + pub created_at: DateTime, + + /// The section `testssl.sh` reported this finding under + pub section: TestSSLSection, + + /// The finding's id (not db id, but `testssl.sh` id) + #[rorm(max_length = 255)] + pub key: String, + + /// The finding's value (the value's semantics are highly dependant on the `key` and `testssl_severity`) + #[rorm(max_length = 1024)] + pub value: String, + + /// The severity reported by `testssl.sh` (this also includes log levels) + pub testssl_severity: TestSSLSeverity, + + /// An associated cve + #[rorm(max_length = 255)] + pub cve: Option, + + /// An associated cwe category + #[rorm(max_length = 255)] + pub cwe: Option, + + /// An associated mitre ATT&CK technique + #[rorm(max_length = 255)] + pub mitre: Option, + + /// An associated severity + pub severity: Severity, +} + +/// A [`TestSSLResultFinding`]'s section +#[derive( + Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, DbEnum, Deserialize, Serialize, ToSchema, +)] +pub enum TestSSLSection { + /// Some sanity checks which can't be disabled + Pretest = 0, + + /// Which tls protocols are supported + Protocols = 1, + + /// Server implementation bugs and [GREASE](https://www.ietf.org/archive/id/draft-ietf-tls-grease-01.txt) + Grease = 2, + + /// Which cipher suites are supported + Ciphers = 3, + + /// Checks robust (perfect) forward secrecy key exchange + Pfs = 4, + + /// The server's preferences + ServerPreferences = 5, + + /// The server's defaults + ServerDefaults = 6, + + /// The http header set by the server + HeaderResponse = 7, + + /// List of several vulnerabilities + Vulnerabilities = 8, + + /// Which concrete ciphers are supported + /// + /// Depending on the option `testssl` is invoked with, + /// this is either a list of all ciphers or a list of all cipher per tls protocol. + CipherTests = 9, + + /// Which browser is able to establish a connection + BrowserSimulations = 10, +} + +/// A [`TestSSLResultFinding`]'s severity +#[derive(Copy, Clone, Debug, DbEnum, Deserialize, Serialize, ToSchema)] +pub enum TestSSLSeverity { + /// A debug level log message + Debug, + /// An info level log message + Info, + /// A warning level log message + Warn, + /// An error level log message + Fatal, + + /// The test's result doesn't pose an issue + Ok, + /// The test's result pose a low priority issue + Low, + /// The test's result pose a medium priority issue + Medium, + /// The test's result pose a high priority issue + High, + /// The test's result pose a critical priority issue + Critical, +} + +/// A generic attack result's severity +#[derive( + Copy, Clone, Debug, DbEnum, Deserialize, Serialize, ToSchema, Ord, PartialOrd, Eq, PartialEq, +)] +pub enum Severity { + /// No issue + None = 0, + /// The test's result pose a low priority issue + Low = 1, + /// The test's result pose a medium priority issue + Medium = 2, + /// The test's result pose a high priority issue + High = 3, + /// The test's result pose a critical priority issue + Critical = 4, } diff --git a/kraken/src/models/attack/patches.rs b/kraken/src/models/attack/patches.rs index f20b43ad9..e57f62c54 100644 --- a/kraken/src/models/attack/patches.rs +++ b/kraken/src/models/attack/patches.rs @@ -6,7 +6,8 @@ use uuid::Uuid; use crate::models::{ Attack, CertificateTransparencyResult, CertificateTransparencyValueName, DehashedQueryResult, DnsRecordResult, DnsRecordType, HostAliveResult, ServiceCertainty, ServiceDetectionResult, - TcpPortScanResult, TestSSLResult, + Severity, TcpPortScanResult, TestSSLResultFinding, TestSSLResultHeader, TestSSLSection, + TestSSLSeverity, }; pub(crate) type BruteforceSubdomainsResultInsert = DnsRecordResultInsert; @@ -87,8 +88,8 @@ pub(crate) struct ServiceDetectionResultInsert { } #[derive(Patch)] -#[rorm(model = "TestSSLResult")] -pub(crate) struct TestSSLResultInsert { +#[rorm(model = "TestSSLResultHeader")] +pub(crate) struct TestSSLResultHeaderInsert { pub(crate) uuid: Uuid, pub(crate) attack: ForeignModel, pub(crate) target_host: String, @@ -97,3 +98,18 @@ pub(crate) struct TestSSLResultInsert { pub(crate) rdns: String, pub(crate) service: String, } + +#[derive(Patch)] +#[rorm(model = "TestSSLResultFinding")] +pub(crate) struct TestSSLResultFindingInsert { + pub(crate) uuid: Uuid, + pub(crate) attack: ForeignModel, + pub(crate) section: TestSSLSection, + pub(crate) key: String, + pub(crate) value: String, + pub(crate) testssl_severity: TestSSLSeverity, + pub(crate) cve: Option, + pub(crate) cwe: Option, + pub(crate) mitre: Option, + pub(crate) severity: Severity, +} diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index 9683a1492..758bbeeaf 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -3,8 +3,8 @@ use std::str::FromStr; use ipnetwork::IpNetwork; use kraken_proto::shared::Address; use kraken_proto::{ - test_ssl_scans, test_ssl_service, BasicAuth, StartTlsProtocol, TestSslRequest, TestSslResponse, - TestSslScanResult, TestSslScans, + mitre, test_ssl_scans, test_ssl_service, BasicAuth, StartTlsProtocol, TestSslRequest, + TestSslResponse, TestSslScanResult, TestSslScans, TestSslSeverity, }; use log::error; use rorm::insert; @@ -16,7 +16,8 @@ use crate::chan::global::GLOBAL; use crate::chan::leech_manager::LeechClient; use crate::models::{ AggregationSource, AggregationTable, DomainCertainty, HostCertainty, PortCertainty, - PortProtocol, ServiceCertainty, SourceType, TestSSLResult, TestSSLResultInsert, + PortProtocol, Severity, SourceType, TestSSLResultFinding, TestSSLResultFindingInsert, + TestSSLResultHeader, TestSSLResultHeaderInsert, TestSSLSection, TestSSLSeverity, }; use crate::modules::attacks::{AttackContext, AttackError, HandleAttackResponse, TestSSLParams}; @@ -109,6 +110,59 @@ impl HandleAttackResponse for AttackContext { if domain.ends_with('.') { domain.pop(); } + + let findings = [ + (pretest, TestSSLSection::Pretest), + (protocols, TestSSLSection::Protocols), + (grease, TestSSLSection::Grease), + (ciphers, TestSSLSection::Ciphers), + (pfs, TestSSLSection::Pfs), + (server_preferences, TestSSLSection::ServerPreferences), + (server_defaults, TestSSLSection::ServerDefaults), + (header_response, TestSSLSection::HeaderResponse), + (vulnerabilities, TestSSLSection::Vulnerabilities), + (cipher_tests, TestSSLSection::CipherTests), + (browser_simulations, TestSSLSection::BrowserSimulations), + ] + .into_iter() + .flat_map(|(findings, section)| { + findings + .into_iter() + .filter(|finding| finding.id != "cert") + .map(move |finding| { + Ok(TestSSLResultFindingInsert { + uuid: Uuid::new_v4(), + attack: ForeignModelByField::Key(self.attack_uuid), + section, + key: finding.id, + value: finding.finding, + testssl_severity: match TestSslSeverity::try_from(finding.severity) + .map_err(|e| AttackError::Custom(Box::new(e)))? + { + TestSslSeverity::Debug => TestSSLSeverity::Debug, + TestSslSeverity::Info => TestSSLSeverity::Info, + TestSslSeverity::Warn => TestSSLSeverity::Warn, + TestSslSeverity::Fatal => TestSSLSeverity::Fatal, + TestSslSeverity::Ok => TestSSLSeverity::Ok, + TestSslSeverity::Low => TestSSLSeverity::Low, + TestSslSeverity::Medium => TestSSLSeverity::Medium, + TestSslSeverity::High => TestSSLSeverity::High, + TestSslSeverity::Critical => TestSSLSeverity::Critical, + }, + cve: finding.cve, + cwe: finding.cwe, + mitre: finding + .mitre + .map(mitre::Tactic::try_from) + .transpose()? + .as_ref() + .map(ToString::to_string), + severity: Severity::None, + }) + }) + }) + .collect::, AttackError>>()?; + let domain_uuid = GLOBAL .aggregator .aggregate_domain( @@ -135,20 +189,9 @@ impl HandleAttackResponse for AttackContext { ) .await?; - let service_uuid = GLOBAL - .aggregator - .aggregate_service( - self.workspace.uuid, - host_uuid, - Some(port_uuid), - &service, - ServiceCertainty::MaybeVerified, // TODO might be DefinitelyVerified? - ) - .await?; - - let source_uuid = insert!(&mut tx, TestSSLResult) + let source_uuid = insert!(&mut tx, TestSSLResultHeader) .return_primary_key() - .single(&TestSSLResultInsert { + .single(&TestSSLResultHeaderInsert { uuid: Uuid::new_v4(), attack: ForeignModelByField::Key(self.attack_uuid), target_host, @@ -159,6 +202,11 @@ impl HandleAttackResponse for AttackContext { }) .await?; + insert!(&mut tx, TestSSLResultFinding) + .return_nothing() + .bulk(&findings) + .await?; + insert!(&mut tx, AggregationSource) .return_nothing() .bulk([ @@ -186,14 +234,6 @@ impl HandleAttackResponse for AttackContext { aggregated_table: AggregationTable::Port, aggregated_uuid: port_uuid, }, - AggregationSource { - uuid: Uuid::new_v4(), - workspace: ForeignModelByField::Key(self.workspace.uuid), - source_type: SourceType::TestSSL, - source_uuid, - aggregated_table: AggregationTable::Service, - aggregated_uuid: service_uuid, - }, ]) .await?; From 6afce2808d4754b1a46b9e7795390ac805b82d42 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Mon, 22 Jan 2024 17:24:58 +0100 Subject: [PATCH 16/37] Documented finding ids --- leech/src/modules/testssl/finding_id.rs | 55 +++++++++++++++++++++---- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/leech/src/modules/testssl/finding_id.rs b/leech/src/modules/testssl/finding_id.rs index 8c7a79fab..f79fb1251 100644 --- a/leech/src/modules/testssl/finding_id.rs +++ b/leech/src/modules/testssl/finding_id.rs @@ -1,6 +1,9 @@ +//! Parse and group the finding ids reported by `testssl` + use std::num::NonZeroUsize; use std::str::FromStr; +/// Enum representing the finding ids `testssl` uses in its json output in a structured way pub enum FindingId { /// Issues with your testssl installation ScanIssues(ScanIssues), @@ -43,7 +46,7 @@ pub enum FindingId { /// `cipher_order` | `cipher_order_...` | `cipherorder_...`: Ordered list of ciphers use by each protocol CipherOrder(Option), - /// `cert_...`: Information about the used certificate(s) + /// Information about the used certificate(s) /// /// They will be numbered if the server uses more than one certificate. /// @@ -79,6 +82,9 @@ pub enum FindingId { /// Test of known vulnerabilities Vulnerabilities(Vulnerabilities), + /// Testing individual ciphers identified by hexcode + /// + /// Might be tested per (and then grouped by) [`Protocol`] Cipher(Option, String), /// Tls clients simulated by testssl @@ -91,6 +97,7 @@ pub enum FindingId { Unknown(String), } +/// Perfect Forward Secrecy pub enum Pfs { /// `PFS_ciphers`: Offered ciphers Ciphers, @@ -223,44 +230,75 @@ pub enum CipherList { /// Protocol used to secure a connection pub enum Protocol { - /// `SSL v2` + /// `SSLv2` SSL2, - /// `SSL v3` + /// `SSLv3` SSL3, - /// `TLS v1` + /// `TLS1` TLS1, - /// `TLS v1.1` + /// `TLS1_1` TLS11, - /// `TLS v1.2` + /// `TLS1_2` TLS12, - /// `TLS v1.3` + /// `TLS1_3` TLS13, } /// Known vulnerabilities which are tested pub enum Vulnerabilities { + /// `heartbleed`: Buffer overflow which allows reading of RAM Heartbleed, + + /// `CCS`: Bad "ChangeCipherSpec" implementation allows mitm decoding entire session if hijacked at initiation. CCS, + + /// `ticketbleed`: Read 31 uninitialized bytes from a F5 BIG-IP application Ticketbleed, + + /// `ROBOT`: Allows breaking RSA on a set of recorded messages with affordable resources Robot, + + /// `secure_renego`: Secure Renegotiation (RFC 5746) usually consumes more resources on the server than on the client SecRen, + + /// `secure_client_renego`: Denial of service by triggering a resource intensive secure renegotiation from the client SecCliRen, + + /// `CRIME_TLS`: Info leak through observable changes in compression CRIME, + + /// `BREACH`: Specialized version of [`Vulnerabilities::CRIME`] BREACH, + + /// `POODLE_SSL` PoodleSsl, + /// `POODLE_TLS` PoodleTls, + /// `fallback_SCSV` FallbackSCSV, + /// `SWEET32` Sweet32, + /// `FREAK` Freak, + /// `DROWN` Drown, + /// `DROWN_hint` DrownHint, + /// `LOGJAM` LogJam, + /// `LOGJAM-common_primes` LogJamCommonPrimes, + /// `BEAST` Beast, + /// `BEAST_CBC_SSL3` BeastSsl3, + /// `BEAST_CBC_TLS1` BeastTls1, + /// `LUCKY13` Lucky13, + /// `RC4` Rc4, + /// `GREASE` Grease, } @@ -296,6 +334,7 @@ pub enum Hpkp { Backup, } +/// Information about the used certificate(s) pub enum Cert { /// `cert` Cert, @@ -367,8 +406,10 @@ pub enum Cert { pub enum ScanIssues { /// `scanProblem`: an error occurred during the scan ScanProblem, + /// `old_fart` | `too_old_openssl`: your openssl version is way too old OldOpenssl, + /// `engine_problem`: No engine or GOST support via engine with your openssl EngineProblem, } From c9eb4e8d41412354cdc2915f8d67ae93a3362ae4 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Mon, 22 Jan 2024 17:50:40 +0100 Subject: [PATCH 17/37] Fixed clippy --- kraken-proto/src/lib.rs | 2 +- kraken-proto/src/mitre.rs | 1 + kraken/src/api/handler/aggregation_source/utils.rs | 8 ++++---- leech/src/modules/testssl/json_pretty.rs | 1 + leech/src/modules/testssl/mitre.rs | 2 +- utilities/mitre/main.py | 1 + 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/kraken-proto/src/lib.rs b/kraken-proto/src/lib.rs index bc97ba457..fb636abd0 100644 --- a/kraken-proto/src/lib.rs +++ b/kraken-proto/src/lib.rs @@ -7,7 +7,7 @@ pub use generated::*; mod convert; pub mod mitre; -#[allow(clippy::unwrap_used, clippy::expect_used)] +#[allow(clippy::unwrap_used, clippy::expect_used, clippy::large_enum_variant)] mod generated { /// The autogenerated rpc definitions from `attacks.shared.proto` diff --git a/kraken-proto/src/mitre.rs b/kraken-proto/src/mitre.rs index a8cc30a79..3b6a483a1 100644 --- a/kraken-proto/src/mitre.rs +++ b/kraken-proto/src/mitre.rs @@ -1,3 +1,4 @@ +#![allow(clippy::zero_prefixed_literal)] //! Enums representing the tactics and techniques from [Mitre ATT&CK](https://attack.mitre.org/) //! //! This file is auto-generated by `utilities/mitre`! Don't edit it directly! diff --git a/kraken/src/api/handler/aggregation_source/utils.rs b/kraken/src/api/handler/aggregation_source/utils.rs index 08d3d3248..5c5963b8b 100644 --- a/kraken/src/api/handler/aggregation_source/utils.rs +++ b/kraken/src/api/handler/aggregation_source/utils.rs @@ -370,8 +370,8 @@ impl FullAggregationSource { )) .stream(); while let Some(result) = stream.try_next().await? { - testssl.get_mut(result.attack.key()).unwrap().findings.push( - TestSSLFinding { + if let Some(slot) = testssl.get_mut(result.attack.key()) { + slot.findings.push(TestSSLFinding { section: result.section, id: result.key.to_string(), value: result.value, @@ -379,8 +379,8 @@ impl FullAggregationSource { cve: result.cve, cwe: result.cwe, issue: (), - }, - ); + }); + } } } } diff --git a/leech/src/modules/testssl/json_pretty.rs b/leech/src/modules/testssl/json_pretty.rs index a27a6aae8..591977e08 100644 --- a/leech/src/modules/testssl/json_pretty.rs +++ b/leech/src/modules/testssl/json_pretty.rs @@ -41,6 +41,7 @@ pub struct File { /// A service's scan results or an error #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] +#[allow(clippy::large_enum_variant)] // the error variant should be the cold path pub enum Service { /// A service's scan results Result(ScanResult), diff --git a/leech/src/modules/testssl/mitre.rs b/leech/src/modules/testssl/mitre.rs index bcf1a5e16..fa3580be0 100644 --- a/leech/src/modules/testssl/mitre.rs +++ b/leech/src/modules/testssl/mitre.rs @@ -13,6 +13,6 @@ pub fn categorize(finding: &Finding) -> Option { return None; } - let id = FindingId::from(finding.id.as_str()); + let _id = FindingId::from(finding.id.as_str()); None // TODO } diff --git a/utilities/mitre/main.py b/utilities/mitre/main.py index 89caa4741..e623fe09d 100644 --- a/utilities/mitre/main.py +++ b/utilities/mitre/main.py @@ -58,6 +58,7 @@ def main(): for tactic in data.get_tactics(True) ] + print("#![allow(clippy::zero_prefixed_literal)]") print("//! Enums representing the tactics and techniques from [Mitre ATT&CK](https://attack.mitre.org/)") print("//!") print("//! This file is auto-generated by `utilities/mitre`! Don't edit it directly!") From b4975f0eeb97792cae6af75872c3f13cee11e0a9 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Tue, 23 Jan 2024 17:15:53 +0100 Subject: [PATCH 18/37] Added testssl attack form --- kraken_frontend/src/api/api.ts | 2 + kraken_frontend/src/svg/attacks.tsx | 10 +- .../attacks/workspace-attacks-testssl.tsx | 182 ++++++++++++++++++ .../src/views/workspace/workspace-attacks.tsx | 8 + 4 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 kraken_frontend/src/views/workspace/attacks/workspace-attacks-testssl.tsx diff --git a/kraken_frontend/src/api/api.ts b/kraken_frontend/src/api/api.ts index 16282e127..7afbbbc8d 100644 --- a/kraken_frontend/src/api/api.ts +++ b/kraken_frontend/src/api/api.ts @@ -47,6 +47,7 @@ import { WordlistManagementApi, WorkspaceInvitationsApi, WorkspaceTagsApi, + TestSSLRequest, } from "./generated"; import { Configuration } from "./generated"; import { @@ -159,6 +160,7 @@ export const Api = { handleError(attacks.queryDehashed({ queryDehashedRequest: { workspaceUuid: uuid, query } })), dnsResolution: (attack: DnsResolutionRequest) => handleError(attacks.dnsResolution({ dnsResolutionRequest: attack })), + testssl: (attack: TestSSLRequest) => handleError(attacks.testssl({ testSSLRequest: attack })), all: () => handleError(attacks.getAllAttacks()), get: (uuid: UUID) => handleError(attacks.getAttack({ uuid })), delete: (uuid: UUID) => handleError(attacks.deleteAttack({ uuid })), diff --git a/kraken_frontend/src/svg/attacks.tsx b/kraken_frontend/src/svg/attacks.tsx index 10f935909..2432e2182 100644 --- a/kraken_frontend/src/svg/attacks.tsx +++ b/kraken_frontend/src/svg/attacks.tsx @@ -182,10 +182,13 @@ export default function AttacksIcon(params: AttacksParams) { } ${!disabled[AttackType.TcpCon] ? "kraken-attacks-clickable" : "kraken-attacks-hex-unavailable"}`} transform="matrix(.23193 0 0 .23193 55.05 14.824)" /> - {/* ports 2 */} + {/* testssl */} {/* ports 3 */} @@ -259,6 +262,9 @@ export default function AttacksIcon(params: AttacksParams) { {"HA"} + + {"TS"} + ); } diff --git a/kraken_frontend/src/views/workspace/attacks/workspace-attacks-testssl.tsx b/kraken_frontend/src/views/workspace/attacks/workspace-attacks-testssl.tsx new file mode 100644 index 000000000..79215b9ff --- /dev/null +++ b/kraken_frontend/src/views/workspace/attacks/workspace-attacks-testssl.tsx @@ -0,0 +1,182 @@ +import React from "react"; +import { Api, UUID } from "../../../api/api"; +import Input from "../../../components/input"; +import StartAttack from "../components/start-attack"; +import "../../../styling/workspace-attacks-host-alive.css"; +import { toast } from "react-toastify"; +import CollapseIcon from "../../../svg/collapse"; +import ExpandIcon from "../../../svg/expand"; +import { WORKSPACE_CONTEXT } from "../workspace"; +import { PrefilledAttackParams, TargetType } from "../workspace-attacks"; +import { handleApiError } from "../../../utils/helper"; +import { StartTLSProtocol } from "../../../api/generated"; +import Checkbox from "../../../components/checkbox"; +import Select, { SingleValue } from "react-select"; +import { selectStyles } from "../../../components/select-menu"; + +type WorkspaceAttacksTestsslProps = { prefilled: PrefilledAttackParams; targetType: TargetType | null }; +type WorkspaceAttacksTestsslState = { + domain: string; + host: string; + port: string; + showAdvanced: boolean; + basicAuth: boolean; + basicAuthUser: string; + basicAuthPass: string; + startTls: StartTLSProtocol | null; + connectTimeout: string; + opensslTimeout: string; +}; + +export default class WorkspaceAttacksTestssl extends React.Component< + WorkspaceAttacksTestsslProps, + WorkspaceAttacksTestsslState +> { + static contextType = WORKSPACE_CONTEXT; + declare context: React.ContextType; + + constructor(props: WorkspaceAttacksTestsslProps) { + super(props); + + this.state = { + domain: "", + host: "", + port: "443", + showAdvanced: false, + basicAuth: false, + basicAuthUser: "", + basicAuthPass: "", + startTls: null, + connectTimeout: "", + opensslTimeout: "", + }; + } + + componentDidUpdate(prevProps: Readonly) {} + + startAttack() { + const { + domain, + host, + port, + basicAuth, + basicAuthUser, + basicAuthPass, + startTls, + connectTimeout, + opensslTimeout, + } = this.state; + + const p = Number(port); + if (p === null || !Number.isSafeInteger(p) || (p <= 0 && p <= 65535)) { + toast.error("Port is invalid"); + return; + } + + const c = connectTimeout.length > 0 ? Number(connectTimeout) : null; + if (c !== null && (!Number.isSafeInteger(c) || c < 0)) { + toast.error("Connect timeout is invalid"); + return; + } + + const o = opensslTimeout.length > 0 ? Number(opensslTimeout) : null; + if (o !== null && (!Number.isSafeInteger(o) || o < 0)) { + toast.error("Openssl timeout is invalid"); + return; + } + + Api.attacks + .testssl({ + workspaceUuid: this.context.workspace.uuid, + uri: domain, + host: host, + port: p, + basicAuth: basicAuth ? [basicAuthUser, basicAuthPass] : null, + connectTimeout: c, + opensslTimeout: o, + + starttls: startTls, + }) + .then(handleApiError((_) => toast.success("Attack started"))); + } + + render() { + return ( +
{ + event.preventDefault(); + this.startAttack(); + }} + > +
+ + this.setState({ domain })} + /> + + this.setState({ host })} /> + + this.setState({ port })} /> + { + this.setState({ showAdvanced: !this.state.showAdvanced }); + }} + > + Advanced + {this.state.showAdvanced ? : } + +
+ + this.setState({ basicAuth })} /> + + this.setState({ basicAuthUser, basicAuth: true })} + /> + + this.setState({ basicAuthPass, basicAuth: true })} + /> + + this.setState({ connectTimeout })} + /> + + this.setState({ opensslTimeout })} + /> +
+
+ + + ); + } +} diff --git a/kraken_frontend/src/views/workspace/workspace-attacks.tsx b/kraken_frontend/src/views/workspace/workspace-attacks.tsx index 3d3ae2e8c..21b2e7377 100644 --- a/kraken_frontend/src/views/workspace/workspace-attacks.tsx +++ b/kraken_frontend/src/views/workspace/workspace-attacks.tsx @@ -15,6 +15,7 @@ import { handleApiError } from "../../utils/helper"; import CloseIcon from "../../svg/close"; import { ROUTES } from "../../routes"; import WorkspaceAttacksDnsResolution from "./attacks/workspace-attacks-dns-resolution"; +import WorkspaceAttacksTestssl from "./attacks/workspace-attacks-testssl"; export enum AttackCategory { Domains = "domains", @@ -34,6 +35,7 @@ export enum AttackType { BruteforceSubdomains = "bruteforce_subdomains", TcpCon = "tcp_con", DnsResolution = "dns_resolution", + TestSSL = "testssl", } const ATTACKS: Record< @@ -105,6 +107,12 @@ const ATTACKS: Record< category: AttackCategory.Other, form: WorkspaceAttacksDehashed, }, + testssl: { + name: "Testssl", + description: "Run testssl.sh to check a services tls configuration", + category: AttackCategory.Ports, + form: WorkspaceAttacksTestssl, + }, }; const TARGET_TYPE = ["domain", "host", "port", "service"] as const; From a17d8957abdfb1477c1484bd1502fc6a716dcde2 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Tue, 23 Jan 2024 19:26:19 +0100 Subject: [PATCH 19/37] Show raw testssl results in details panel --- .../src/styling/workspace-data-details.css | 47 +++++++++- kraken_frontend/src/utils/helper.tsx | 6 ++ .../workspace-data-details-results.tsx | 85 ++++++++++++++++++- 3 files changed, 132 insertions(+), 6 deletions(-) diff --git a/kraken_frontend/src/styling/workspace-data-details.css b/kraken_frontend/src/styling/workspace-data-details.css index 73132289c..d1a09be10 100644 --- a/kraken_frontend/src/styling/workspace-data-details.css +++ b/kraken_frontend/src/styling/workspace-data-details.css @@ -236,6 +236,49 @@ cursor: pointer; } -.workspace-data-details-link:active{ +.workspace-data-details-link:active { transform: translate(0.1em, 0.1em); -} \ No newline at end of file +} + +/* Base layout of testssl sections */ +.workspace-data-details-testssl-section { + display: grid; + grid-template-columns: min-content auto; + column-gap: 1em; + row-gap: 0.25em; +} +.workspace-data-details-testssl-section > h3 { + grid-column: 1 / 3; + margin: 0; +} + +/* Set handling of long text based on hover */ +.workspace-data-details-testssl-section > span:hover { + overflow-wrap: anywhere; + } +.workspace-data-details-testssl-section > span:not(:hover) { + white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; +} + +/* Set color based on testssl severity */ +.workspace-data-details-testssl-debug {} +.workspace-data-details-testssl-info {} +.workspace-data-details-testssl-warn {} +.workspace-data-details-testssl-fatal {} +.workspace-data-details-testssl-ok { + color: #008000; +} +.workspace-data-details-testssl-low { + color: #b4b434; +} +.workspace-data-details-testssl-medium { + color: #ff7a27; +} +.workspace-data-details-testssl-high { + color: #ff2828; +} +.workspace-data-details-testssl-critical { + color: #ff58ca; +} diff --git a/kraken_frontend/src/utils/helper.tsx b/kraken_frontend/src/utils/helper.tsx index 73c6f1fa1..bbba43bec 100644 --- a/kraken_frontend/src/utils/helper.tsx +++ b/kraken_frontend/src/utils/helper.tsx @@ -24,6 +24,12 @@ export namespace ObjectFns { return Object.entries(obj); } + /** {@link ObjectConstructor.fromEntries `Object.fromEntries`} which preserves the keys' type */ + export function fromEntries(arr: Array<[Key, Value]>): Record { + // @ts-ignore + return Object.fromEntries(arr); + } + export function isEmpty(obj: Record): boolean { for (const key in obj) { return false; diff --git a/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx b/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx index 5b7f5c4af..5dc72f663 100644 --- a/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx +++ b/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx @@ -3,8 +3,8 @@ import "../../../styling/workspace-data-details.css"; import CopyIcon from "../../../svg/copy"; import ArrowLeftIcon from "../../../svg/arrow-left"; import ArrowRightIcon from "../../../svg/arrow-right"; -import { SourceAttack } from "../../../api/generated"; -import { copyToClipboard } from "../../../utils/helper"; +import { SourceAttack, TestSSLFinding, TestSSLSection, TestSSLSeverity } from "../../../api/generated"; +import { copyToClipboard, ObjectFns } from "../../../utils/helper"; type WorkspaceDataDetailsResultsProps = { attack: SourceAttack; @@ -29,7 +29,7 @@ export default class WorkspaceDataDetailsResults extends React.Component< componentDidUpdate( prevProps: Readonly, prevState: Readonly, - snapshot?: any + snapshot?: any, ) { if (prevProps.attack.uuid !== this.props.attack.uuid || prevProps.uuid !== this.props.uuid) { this.setState({ page: 0 }); @@ -463,6 +463,58 @@ export default class WorkspaceDataDetailsResults extends React.Component< } else { return null; } + case "TestSSL": + const result = this.props.attack.results; + const sections = ObjectFns.fromEntries( + Object.values(TestSSLSection).map((s) => [ + s, + { worst: TestSSLSeverity.Info as TestSSLSeverity, findings: Array() }, + ]), + ); + for (const finding of result.findings) { + const section = sections[finding.section]; + if (rateSeverity(finding.severity) > rateSeverity(section.worst)) + section.worst = finding.severity; + section.findings.push(finding); + } + return ( +
+
+

TestSSL

+
+
+ Started by: + Created: + Finished: +
+
+ {a.startedBy.displayName} + {this.formateDate(a.createdAt)} + {this.formateDate(a.finishedAt)} +
+
+
+ {ObjectFns.entries(sections).map(([section, { worst, findings }]) => ( +
+
+

+ {section} +

+ {findings.map(({ id, value, severity }) => ( + <> + + {id} + + {value} + + ))} +
+
+ ))} +
+ ); case undefined: return "undefined"; default: @@ -470,7 +522,9 @@ export default class WorkspaceDataDetailsResults extends React.Component< } })(); console.log(this.state.page); - if (this.state.page < this.props.attack.results.length) { + if (!("length" in this.props.attack.results)) { + return
{attackElement}
; + } else if (this.state.page < this.props.attack.results.length) { let uuid = this.props.attack.results[this.state.page].uuid; return (
@@ -521,3 +575,26 @@ export default class WorkspaceDataDetailsResults extends React.Component< } } } + +function rateSeverity(severity: TestSSLSeverity): number { + switch (severity) { + case "Debug": + return -1; + case "Info": + return -1; + case "Warn": + return -1; + case "Fatal": + return -1; + case "Ok": + return 0; + case "Low": + return 1; + case "Medium": + return 2; + case "High": + return 3; + case "Critical": + return 4; + } +} From 0c05422a62ac3687efe1c269e79e897abc45d06e Mon Sep 17 00:00:00 2001 From: gammelalf Date: Wed, 24 Jan 2024 12:29:28 +0100 Subject: [PATCH 20/37] Made migrations work on production db --- kraken/migrations/0001_initial.toml | 2 + ...004_placeholder.toml => 0004_testssl.toml} | 83 +++---------------- 2 files changed, 12 insertions(+), 73 deletions(-) rename kraken/migrations/{0004_placeholder.toml => 0004_testssl.toml} (75%) diff --git a/kraken/migrations/0001_initial.toml b/kraken/migrations/0001_initial.toml index bdc30ab01..6ff6f0833 100644 --- a/kraken/migrations/0001_initial.toml +++ b/kraken/migrations/0001_initial.toml @@ -94,6 +94,7 @@ Value = [ "OSDetection", "VersionDetection", "AntiPortScanningDetection", + "TestSSL", ] [[Migration.Operations.Fields.Annotations]] @@ -1335,6 +1336,7 @@ Value = [ "OSDetection", "VersionDetection", "AntiPortScanningDetection", + "TestSSL", "ManualDomain", "ManualHost", "ManualPort", diff --git a/kraken/migrations/0004_placeholder.toml b/kraken/migrations/0004_testssl.toml similarity index 75% rename from kraken/migrations/0004_placeholder.toml rename to kraken/migrations/0004_testssl.toml index 37ba27ce9..a31264df0 100644 --- a/kraken/migrations/0004_placeholder.toml +++ b/kraken/migrations/0004_testssl.toml @@ -241,78 +241,15 @@ OnUpdate = "Cascade" Type = "not_null" [[Migration.Operations]] -Type = "DeleteField" -Model = "aggregationsource" -Name = "source_type" +Type = "RawSQL" +StructureSafe = true +SQLite = "only Postgres databases are supported right now" +MySQL = "only Postgres databases are supported right now" +Postgres = "ALTER TYPE _attack_attack_type ADD VALUE IF NOT EXISTS 'TestSSL' AFTER 'AntiPortScanningDetection';" [[Migration.Operations]] -Type = "CreateField" -Model = "aggregationsource" - -[Migration.Operations.Field] -Name = "source_type" -Type = "choices" - -[[Migration.Operations.Field.Annotations]] -Type = "choices" -Value = [ - "BruteforceSubdomains", - "TcpPortScan", - "QueryCertificateTransparency", - "QueryDehashed", - "HostAlive", - "ServiceDetection", - "UdpServiceDetection", - "DnsResolution", - "DnsTxtScan", - "UdpPortScan", - "ForcedBrowsing", - "OSDetection", - "VersionDetection", - "AntiPortScanningDetection", - "TestSSL", - "ManualDomain", - "ManualHost", - "ManualPort", - "ManualService", -] - -[[Migration.Operations.Field.Annotations]] -Type = "not_null" - -[[Migration.Operations]] -Type = "DeleteField" -Model = "attack" -Name = "attack_type" - -[[Migration.Operations]] -Type = "CreateField" -Model = "attack" - -[Migration.Operations.Field] -Name = "attack_type" -Type = "choices" - -[[Migration.Operations.Field.Annotations]] -Type = "choices" -Value = [ - "Undefined", - "BruteforceSubdomains", - "TcpPortScan", - "QueryCertificateTransparency", - "QueryUnhashed", - "HostAlive", - "ServiceDetection", - "UdpServiceDetection", - "DnsResolution", - "DnsTxtScan", - "UdpPortScan", - "ForcedBrowsing", - "OSDetection", - "VersionDetection", - "AntiPortScanningDetection", - "TestSSL", -] - -[[Migration.Operations.Field.Annotations]] -Type = "not_null" +Type = "RawSQL" +StructureSafe = true +SQLite = "only Postgres databases are supported right now" +MySQL = "only Postgres databases are supported right now" +Postgres = "ALTER TYPE _aggregationsource_source_type ADD VALUE IF NOT EXISTS 'TestSSL' AFTER 'AntiPortScanningDetection';" From 4de598f308fa6cac41f5b8cdec7031afe7564c05 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Wed, 24 Jan 2024 12:48:54 +0100 Subject: [PATCH 21/37] Fixed missing merge --- leech/src/rpc/attacks.rs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/leech/src/rpc/attacks.rs b/leech/src/rpc/attacks.rs index 381e94552..f32a5f701 100644 --- a/leech/src/rpc/attacks.rs +++ b/leech/src/rpc/attacks.rs @@ -14,25 +14,20 @@ use kraken_proto::req_attack_service_server::ReqAttackService; use kraken_proto::shared::dns_record::Record; use kraken_proto::shared::dns_txt_scan::Info; use kraken_proto::shared::{ - spf_directive, spf_part, Aaaa, Aaaa, Address, Address, AttackTechnique, CertEntry, CertEntry, - DnsRecord, DnsRecord, DnsTxtKnownEntry, DnsTxtScan, GenericRecord, GenericRecord, Net, - SpfDirective, SpfExplanationModifier, SpfInfo, SpfMechanismA, SpfMechanismAll, - SpfMechanismExists, SpfMechanismInclude, SpfMechanismIp, SpfMechanismMx, SpfMechanismPtr, - SpfPart, SpfQualifier, SpfRedirectModifier, SpfUnknownModifier, A, A, + spf_directive, spf_part, Aaaa, Address, AttackTechnique, CertEntry, DnsRecord, + DnsTxtKnownEntry, DnsTxtScan, GenericRecord, Net, SpfDirective, SpfExplanationModifier, + SpfInfo, SpfMechanismA, SpfMechanismAll, SpfMechanismExists, SpfMechanismInclude, + SpfMechanismIp, SpfMechanismMx, SpfMechanismPtr, SpfPart, SpfQualifier, SpfRedirectModifier, + SpfUnknownModifier, A, }; use kraken_proto::{ - any_attack_response, shared, shared, test_ssl_scans, test_ssl_service, - BruteforceSubdomainRequest, BruteforceSubdomainRequest, BruteforceSubdomainResponse, - BruteforceSubdomainResponse, CertificateTransparencyRequest, CertificateTransparencyRequest, - CertificateTransparencyResponse, CertificateTransparencyResponse, DnsResolutionRequest, - DnsResolutionRequest, DnsResolutionResponse, DnsResolutionResponse, DnsTxtScanRequest, - DnsTxtScanResponse, HostsAliveRequest, HostsAliveRequest, HostsAliveResponse, - HostsAliveResponse, ServiceCertainty, ServiceCertainty, ServiceDetectionRequest, - ServiceDetectionRequest, ServiceDetectionResponse, ServiceDetectionResponse, StartTlsProtocol, - TcpPortScanRequest, TcpPortScanRequest, TcpPortScanResponse, TcpPortScanResponse, + any_attack_response, shared, test_ssl_scans, test_ssl_service, BruteforceSubdomainRequest, + BruteforceSubdomainResponse, CertificateTransparencyRequest, CertificateTransparencyResponse, + DnsResolutionRequest, DnsResolutionResponse, DnsTxtScanRequest, DnsTxtScanResponse, + HostsAliveRequest, HostsAliveResponse, ServiceCertainty, ServiceDetectionRequest, + ServiceDetectionResponse, StartTlsProtocol, TcpPortScanRequest, TcpPortScanResponse, TestSslFinding, TestSslRequest, TestSslResponse, TestSslScanResult, TestSslService, - TestSslSeverity, UdpServiceDetectionRequest, UdpServiceDetectionRequest, - UdpServiceDetectionResponse, UdpServiceDetectionResponse, + TestSslSeverity, UdpServiceDetectionRequest, UdpServiceDetectionResponse, }; use log::error; use prost_types::Timestamp; From 437757982ccf62be27b1e3b6237332e519911e59 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Wed, 24 Jan 2024 12:55:56 +0100 Subject: [PATCH 22/37] Removed accedently commited files --- kraken/src/models/max_len_str.rs | 151 ------------------ leech/src/modules/service_detection/http2.rs | 103 ------------ .../src/modules/service_detection/netbios.rs | 35 ---- leech/src/modules/service_detection/smb.rs | 123 -------------- 4 files changed, 412 deletions(-) delete mode 100644 kraken/src/models/max_len_str.rs delete mode 100644 leech/src/modules/service_detection/http2.rs delete mode 100644 leech/src/modules/service_detection/netbios.rs delete mode 100644 leech/src/modules/service_detection/smb.rs diff --git a/kraken/src/models/max_len_str.rs b/kraken/src/models/max_len_str.rs deleted file mode 100644 index b0ec3e2b2..000000000 --- a/kraken/src/models/max_len_str.rs +++ /dev/null @@ -1,151 +0,0 @@ -use core::fmt; -use std::borrow::Cow; -use std::ops::Deref; - -use rorm::conditions::Value; -use rorm::fields::traits::FieldType; -use rorm::internal::field::Field; -use rorm::internal::hmr::AsImr; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] -pub struct MaxLenStr { - string: Str, - len_impl: Len, -} - -impl Deref for MaxLenStr -where - Str: Deref, -{ - type Target = Str; - - fn deref(&self) -> &Self::Target { - &self.string - } -} - -impl fmt::Display for MaxLenStr -where - Str: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.string.fmt(f) - } -} - -/* ======= CONSTRUCTOR BEGIN =======*/ -impl MaxLenStr -where - Str: Deref, - Len: LenImpl, -{ - pub fn new(string: Str) -> Result - where - Len: Default, - { - Self::with_impl(string, Default::default()) - } - - pub fn with_impl(string: Str, len_impl: Len) -> Result { - let len = len_impl.len(&string); - if len > MAX { - Err(MaxLenError { max: MAX, got: len }) - } else { - Ok(Self { string, len_impl }) - } - } -} -/* ======= CONSTRUCTOR END =======*/ - -/* ======= SERDE BEGIN =======*/ -impl Serialize for MaxLenStr -where - Str: Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.string.serialize(serializer) - } -} - -impl<'de, const MAX: usize, Str, Len> Deserialize<'de> for MaxLenStr -where - Str: Deserialize<'de> + Deref, - Len: Default + LenImpl, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - use serde::de::Error; - Str::deserialize(deserializer).and_then(|string| { - Self::new(string).map_err(|err| { - Error::custom(format_args!( - "String is too long: {} (max is {})", - err.got, err.max - )) - }) - }) - } -} -/* ======= SERDE END =======*/ - -/* ======= RORM END =======*/ -impl FieldType for MaxLenStr -where - Len: 'static, -{ - type Columns = [T; 1]; - - fn into_values(self) -> Self::Columns> { - [Value::String(Cow::Owned(self.string))] - } - - fn as_values(&self) -> Self::Columns> { - [Value::String(Cow::Borrowed(&self.string))] - } - - fn get_imr>() -> Self::Columns { - use rorm::imr::*; - [Field { - name: F::NAME.to_string(), - db_type: DbType::VarChar, - annotations: F::EFFECTIVE_ANNOTATIONS.unwrap_or_default().as_imr(), - source_defined_at: None, - }] - } - - type Decoder = (); - type AnnotationsModifier> = (); - type CheckModifier> = (); - type ColumnsFromName> = (); -} -/* ======= RORM END =======*/ - -pub struct MaxLenError { - pub max: usize, - pub got: usize, -} - -pub trait LenImpl { - fn len(&self, string: &str) -> usize; -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] -pub struct Bytes; -impl LenImpl for Bytes { - fn len(&self, string: &str) -> usize { - string.as_bytes().len() - } -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] -pub struct CodePoints; -impl LenImpl for CodePoints { - fn len(&self, string: &str) -> usize { - string.chars().count() - } -} diff --git a/leech/src/modules/service_detection/http2.rs b/leech/src/modules/service_detection/http2.rs deleted file mode 100644 index 476ac9f36..000000000 --- a/leech/src/modules/service_detection/http2.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! RFC for connection preface: -//! https://datatracker.ietf.org/doc/html/rfc9113 - -use std::net::SocketAddr; - -use log::{debug, log_enabled, trace}; - -use super::{probe_tcp, DynResult, LoggableBytes}; - -pub async fn probe(socket: SocketAddr) -> DynResult { - let mut payload = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".to_vec(); - Head { - length: 0, // we're sending no settings - r#type: 4, // SETTINGS frame - flags: 0, - stream_id: 0, // reserved id from general connection frames - } - .write(&mut payload); - - let data = probe_tcp(socket, &payload).await?; - trace!(target: "http2", "Got bytes: {:?}", LoggableBytes(&data)); - let Some((head, remaining)) = Head::parse(&data) else { - return Ok(false); - }; - trace!(target: "http2", "Parsed head: {:?}", LoggableBytes(&data)); - - // The server connection preface consists of a potentially empty SETTINGS frame - // that MUST be the first frame the server sends in the HTTP/2 connection. - if log_enabled!(target: "http2", log::Level::Debug) { - if head.r#type != 4 { - debug!(target: "http2", "Invalid frame type: {} (expected SETTINGS frame)", head.r#type); - return Ok(false); - } - if head.stream_id != 0 { - debug!(target: "http2", "Invalid stream id for SETTINGS frame: {}", head.stream_id); - return Ok(false); - } - if head.length % 6 != 0 { - debug!(target: "http2", "Invalid payload length for SETTINGS frame: {}", head.length); - return Ok(false); - } - if remaining.len() < head.length as usize { - debug!(target: "http2", "Got less payload bytes than promised (exp: {exp}, got: {got})", exp = head.length, got = remaining.len()); - return Ok(false); - } - Ok(true) - } else { - Ok(head.r#type == 4 - && head.stream_id == 0 - && head.length % 6 == 0 - && remaining.len() >= head.length as usize) - } -} - -/// http/2 frame head -#[derive(Debug, Copy, Clone)] -struct Head { - length: u32, - r#type: u8, - flags: u8, - stream_id: u32, -} - -impl Head { - const STREAM_ID_MASK: u32 = 1 << 31; - - /// Parse the http/2 frame head from the beginning of a byte slice - /// The remaining bytes will be returned next to the parsed head - fn parse(payload: &[u8]) -> Option<(Self, &[u8])> { - let (length, payload) = pop::<3>(payload)?; - let ([r#type], payload) = pop::<1>(payload)?; - let ([flags], payload) = pop::<1>(payload)?; - let (stream_id, payload) = pop::<4>(payload)?; - - let length = u32::from_be_bytes([0, length[0], length[1], length[2]]); - let stream_id = u32::from_be_bytes(stream_id) & !Self::STREAM_ID_MASK; - - Some(( - Head { - length, - r#type, - flags, - stream_id, - }, - payload, - )) - } - - /// Write the http/2 frame head to the end of a byte vec - fn write(self, bytes: &mut Vec) { - bytes.extend_from_slice(&(self.length.to_be_bytes())[1..]); - bytes.push(self.r#type); - bytes.push(self.flags); - bytes.extend((self.stream_id & !Self::STREAM_ID_MASK).to_be_bytes()); - } -} - -/// Pop `N` bytes from a slice and return them in an array as well as the remaining bytes -fn pop(slice: &[u8]) -> Option<([u8; N], &[u8])> { - let mut array = [0; N]; - array.copy_from_slice(slice.get(..N)?); - Some((array, slice.get(N..)?)) -} diff --git a/leech/src/modules/service_detection/netbios.rs b/leech/src/modules/service_detection/netbios.rs deleted file mode 100644 index 1b3070b0c..000000000 --- a/leech/src/modules/service_detection/netbios.rs +++ /dev/null @@ -1,35 +0,0 @@ -use itertools::Itertools; - -use super::{DetectServiceSettings, DynResult}; - -pub async fn probe(settings: &DetectServiceSettings) -> DynResult { - let response = settings.probe_tcp(b"anything").await?; -} - -pub struct SessionPacket<'b> { - r#type: u8, - flags: u8, - length: u16, - trailer: &'b [u8], -} - -impl<'b> SessionPacket<'b> { - pub fn parse(data: &'b [u8]) -> Option { - let (&r#type, data) = data.split_first()?; - let (&flags, data) = data.split_first()?; - let (&l1, data) = data.split_first()?; - let (&l2, data) = data.split_first()?; - let length = u16::from_le_bytes([l1, l2]); - (data.len() == length as usize).then_some(Self { - r#type, - flags, - length, - trailer: data, - }) - } - - /// Checks if type and flags are set correctly - pub fn is_valid(&self) -> bool { - [0x00, 0x81, 0x82, 0x83, 0x84, 0x85].contains(&self.r#type) && (self.flags >> 1) == 0 - } -} diff --git a/leech/src/modules/service_detection/smb.rs b/leech/src/modules/service_detection/smb.rs deleted file mode 100644 index 3777ef41a..000000000 --- a/leech/src/modules/service_detection/smb.rs +++ /dev/null @@ -1,123 +0,0 @@ -use std::borrow::Cow; - -pub fn create_connection_message() -> Vec { - let mut bytes = Vec::new(); - SMBMessage { - header: SMBHeader { - command: SMB_COM_NEGOTIATE, - status: SMBStatus::EMPTY, - flags_1: 0, - flags_2: 0, - security_features: [0; 8], - pid: 1, // arbitrary chosen - tid: 0, // uninit - uid: 0, // uninit - mid: 1, // arbitrary chosen - }, - params: Cow::Borrowed(&[]), - data: Cow::Borrowed(b""), // list of (\x02 + cstr) - } - .push(&mut bytes); - bytes -} - -struct SMBMessage<'a> { - header: SMBHeader, - - /// Must be an even number of bytes and less than 512 - params: Cow<'a, [u8]>, - - /// Must be less than 65536 - data: Cow<'a, [u8]>, -} -impl<'a> SMBMessage<'a> { - fn push(&self, bytes: &mut Vec) { - self.header.push(bytes); - - assert_eq!( - self.params.len() % 2, - 0, - "Parameters are counted in word i.e. two bytes" - ); - let word_count = self.params.len() / 2; - bytes.push(u8::try_from(word_count).expect("Word count is stored in a single byte")); - bytes.extend_from_slice(&self.params); - - bytes.extend_from_slice( - &u16::try_from(self.data.len()) - .expect("Byte count is stored in two bytes") - .to_le_bytes(), - ); - bytes.extend_from_slice(&self.data); - } - - fn parse(&self, bytes: &'a [u8]) -> Option { - None - } -} - -struct SMBHeader { - command: SMBCommand, // 72 - status: SMBStatus, // 0 - flags_1: u8, // 08 - flags_2: u16, // 01 40 - security_features: [u8; 8], // 0 - - /// Process identifier - /// - /// The PID is assigned by the client. - pid: u32, // 00 00 40 06 - - /// Tree identifier - /// - /// TIDs are generated on servers. - tid: u16, // 00 00 - - /// User identifier - /// - /// UIDs are generated on servers. - uid: u16, // 00 00 - - /// Multiplex identifier - /// - /// The MID is assigned by the client. - mid: u16, // 00 01 -} -impl SMBHeader { - fn push(&self, bytes: &mut Vec) { - let (pid_high, pid_low) = self.pid.to_le_bytes().split_at(2); - - bytes.extend_from_slice(b"\xffSMB"); // protocol - bytes.push(self.command); - self.status.push(bytes); - bytes.push(self.flags_1); - bytes.extend_from_slice(&self.flags_2.to_le_bytes()); - bytes.extend_from_slice(&self.pid.to_le_bytes()[..2]); - bytes.extend_from_slice(&self.security_features); - bytes.extend_from_slice(&[0, 0]); // reserved - bytes.extend_from_slice(&self.tid.to_le_bytes()); - bytes.extend_from_slice(&self.pid.to_le_bytes()[2..]); - bytes.extend_from_slice(&self.uid.to_le_bytes()); - bytes.extend_from_slice(&self.mid.to_le_bytes()); - } -} - -type SMBCommand = u8; -const SMB_COM_NEGOTIATE: SMBCommand = 0x72; - -struct SMBStatus { - error_class: u8, - error_code: u16, -} -impl SMBStatus { - const EMPTY: Self = Self { - error_class: 0, - error_code: 0, - }; - - fn push(&self, bytes: &mut Vec) { - bytes.push(self.error_class); - bytes.push(0); // reserved - bytes.extend_from_slice(&self.error_code.to_le_bytes()); - } -} From ce88f42520f5acdc33d08a5715fd05c4bd028ce6 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Wed, 24 Jan 2024 16:48:00 +0100 Subject: [PATCH 23/37] Removed mitre and applied other requested changes --- kraken-proto/build.rs | 3 + kraken-proto/proto/attacks.proto | 2 - kraken-proto/proto/attacks.shared.proto | 9 - kraken-proto/src/convert.rs | 8 - kraken-proto/src/lib.rs | 1 - kraken-proto/src/mitre.rs | 2705 ----------------- kraken/migrations/0004_testssl.toml | 27 +- .../api/handler/aggregation_source/utils.rs | 4 +- .../src/api/handler/attack_results/handler.rs | 4 +- .../src/api/handler/attack_results/schema.rs | 9 +- kraken/src/api/handler/attacks/handler.rs | 4 + kraken/src/api/handler/attacks/schema.rs | 2 +- kraken/src/models/attack/mod.rs | 29 +- kraken/src/models/attack/patches.rs | 6 +- kraken/src/modules/attacks/testssl.rs | 21 +- leech/src/modules/testssl/mitre.rs | 18 - leech/src/modules/testssl/mod.rs | 6 +- leech/src/rpc/attacks.rs | 11 +- utilities/mitre/README.md | 7 - utilities/mitre/main.py | 182 -- utilities/mitre/requirements.txt | 1 - 21 files changed, 39 insertions(+), 3020 deletions(-) delete mode 100644 kraken-proto/src/mitre.rs delete mode 100644 leech/src/modules/testssl/mitre.rs delete mode 100644 utilities/mitre/README.md delete mode 100644 utilities/mitre/main.py delete mode 100644 utilities/mitre/requirements.txt diff --git a/kraken-proto/build.rs b/kraken-proto/build.rs index 0be0c2d53..9df70c7c5 100644 --- a/kraken-proto/build.rs +++ b/kraken-proto/build.rs @@ -1,5 +1,8 @@ fn main() -> Result<(), Box> { tonic_build::configure() + // Required for protoc versions < 3.15 + // 3.15 stabilized the feature and enabled it by default + // This was relevant for the CI .protoc_arg("--experimental_allow_proto3_optional") .compile(&["./proto/attacks.proto"], &["./proto/"])?; Ok(()) diff --git a/kraken-proto/proto/attacks.proto b/kraken-proto/proto/attacks.proto index e2ea87097..fac11de25 100644 --- a/kraken-proto/proto/attacks.proto +++ b/kraken-proto/proto/attacks.proto @@ -444,8 +444,6 @@ message TestSSLFinding { optional string cve = 4; // The associated CWE optional string cwe = 5; - // The MITRE ATT&CK tactic and technique associated with this weakness - optional shared.AttackTechnique mitre = 6; } // A TestSSLFinding's severity diff --git a/kraken-proto/proto/attacks.shared.proto b/kraken-proto/proto/attacks.shared.proto index 4d5f51106..30afbd8f5 100644 --- a/kraken-proto/proto/attacks.shared.proto +++ b/kraken-proto/proto/attacks.shared.proto @@ -295,12 +295,3 @@ message CertEntry { // The serial number of the certificate string serial_number = 6; } - -// A mitre ATT&CK tactic and technique -message AttackTechnique { - // The tactic's id i.e. TA00xx - uint32 tactic = 1; - - // The technique's id i.e. Txxxx - uint32 technique = 2; -} \ No newline at end of file diff --git a/kraken-proto/src/convert.rs b/kraken-proto/src/convert.rs index 9f839a9e8..c4b4c8a73 100644 --- a/kraken-proto/src/convert.rs +++ b/kraken-proto/src/convert.rs @@ -44,14 +44,6 @@ pub enum InvalidArgumentError { /// Received an invalid value for a ipv4 network prefix #[error("Got invalid network prefix for v6: {}", .0)] InvalidV6Prefix(u32), - - /// Received an unknown mitre att&ck tactic - #[error("Got unknown mitre att&ck tactic: TA{:04}", .0)] - InvalidMitreTactic(u32), - - /// Received an unknown mitre att&ck technique - #[error("Got unknown mitre att&ck technique: T{:04} (for TA{:04})", .1, .0)] - InvalidMitreTechnique(u32, u32), } impl From for Status { fn from(value: InvalidArgumentError) -> Self { diff --git a/kraken-proto/src/lib.rs b/kraken-proto/src/lib.rs index fb636abd0..7abc91411 100644 --- a/kraken-proto/src/lib.rs +++ b/kraken-proto/src/lib.rs @@ -5,7 +5,6 @@ pub use convert::InvalidArgumentError; pub use generated::*; mod convert; -pub mod mitre; #[allow(clippy::unwrap_used, clippy::expect_used, clippy::large_enum_variant)] mod generated { diff --git a/kraken-proto/src/mitre.rs b/kraken-proto/src/mitre.rs deleted file mode 100644 index 3b6a483a1..000000000 --- a/kraken-proto/src/mitre.rs +++ /dev/null @@ -1,2705 +0,0 @@ -#![allow(clippy::zero_prefixed_literal)] -//! Enums representing the tactics and techniques from [Mitre ATT&CK](https://attack.mitre.org/) -//! -//! This file is auto-generated by `utilities/mitre`! Don't edit it directly! -use std::fmt; -use std::str::FromStr; -use crate::InvalidArgumentError; -use crate::shared::AttackTechnique; -/// An entry in the [Mitre ATT&CK table](https://attack.mitre.org/) -pub enum Tactic { - /// [Credential Access](https://attack.mitre.org/tactics/TA0006) - /// - /// The adversary is trying to steal account names and passwords. - CredentialAccess(CredentialAccess), - - /// [Execution](https://attack.mitre.org/tactics/TA0002) - /// - /// The adversary is trying to run malicious code. - Execution(Execution), - - /// [Impact](https://attack.mitre.org/tactics/TA0040) - /// - /// The adversary is trying to manipulate, interrupt, or destroy your systems and data. - Impact(Impact), - - /// [Persistence](https://attack.mitre.org/tactics/TA0003) - /// - /// The adversary is trying to maintain their foothold. - Persistence(Persistence), - - /// [Privilege Escalation](https://attack.mitre.org/tactics/TA0004) - /// - /// The adversary is trying to gain higher-level permissions. - PrivilegeEscalation(PrivilegeEscalation), - - /// [Lateral Movement](https://attack.mitre.org/tactics/TA0008) - /// - /// The adversary is trying to move through your environment. - LateralMovement(LateralMovement), - - /// [Defense Evasion](https://attack.mitre.org/tactics/TA0005) - /// - /// The adversary is trying to avoid being detected. - DefenseEvasion(DefenseEvasion), - - /// [Exfiltration](https://attack.mitre.org/tactics/TA0010) - /// - /// The adversary is trying to steal data. - Exfiltration(Exfiltration), - - /// [Discovery](https://attack.mitre.org/tactics/TA0007) - /// - /// The adversary is trying to figure out your environment. - Discovery(Discovery), - - /// [Collection](https://attack.mitre.org/tactics/TA0009) - /// - /// The adversary is trying to gather data of interest to their goal. - Collection(Collection), - - /// [Resource Development](https://attack.mitre.org/tactics/TA0042) - /// - /// The adversary is trying to establish resources they can use to support operations. - ResourceDevelopment(ResourceDevelopment), - - /// [Reconnaissance](https://attack.mitre.org/tactics/TA0043) - /// - /// The adversary is trying to gather information they can use to plan future operations. - Reconnaissance(Reconnaissance), - - /// [Command and Control](https://attack.mitre.org/tactics/TA0011) - /// - /// The adversary is trying to communicate with compromised systems to control them. - CommandAndControl(CommandAndControl), - - /// [Initial Access](https://attack.mitre.org/tactics/TA0001) - /// - /// The adversary is trying to get into your network. - InitialAccess(InitialAccess), - -} -/// [Credential Access](https://attack.mitre.org/tactics/TA0006)'s techniques -pub enum CredentialAccess { - /// [Adversary-in-the-Middle](https://attack.mitre.org/techniques/T1557) - /// - /// Adversaries may attempt to position themselves between two or more networked devices using an adversary-in-the-middle (AiTM) technique to support follow-on behaviors such as [Network Sniffing](https://attack.mitre.org/techniques/T1040), [Transmitted Data Manipulation](https://attack.mitre.org/techniques/T1565/002), or replay attacks ([Exploitation for Credential Access](https://attack.mitre.org/techniques/T1212)). By abusing features of common networking protocols that can determine the flow of network traffic (e.g. ARP, DNS, LLMNR, etc.), adversaries may force a device to communicate through an adversary controlled system so they can collect information or perform additional actions.(Citation: Rapid7 MiTM Basics) - AdversaryInTheMiddle, - - /// [OS Credential Dumping](https://attack.mitre.org/techniques/T1003) - /// - /// Adversaries may attempt to dump credentials to obtain account login and credential material, normally in the form of a hash or a clear text password, from the operating system and software. Credentials can then be used to perform [Lateral Movement](https://attack.mitre.org/tactics/TA0008) and access restricted information. - OsCredentialDumping, - - /// [Steal Web Session Cookie](https://attack.mitre.org/techniques/T1539) - /// - /// An adversary may steal web application or service session cookies and use them to gain access to web applications or Internet services as an authenticated user without needing credentials. Web applications and services often use session cookies as an authentication token after a user has authenticated to a website. - StealWebSessionCookie, - - /// [Network Sniffing](https://attack.mitre.org/techniques/T1040) - /// - /// Adversaries may sniff network traffic to capture information about an environment, including authentication material passed over the network. Network sniffing refers to using the network interface on a system to monitor or capture information sent over a wired or wireless connection. An adversary may place a network interface into promiscuous mode to passively access data in transit over the network, or use span ports to capture a larger amount of data. - NetworkSniffing, - - /// [Steal or Forge Kerberos Tickets](https://attack.mitre.org/techniques/T1558) - /// - /// Adversaries may attempt to subvert Kerberos authentication by stealing or forging Kerberos tickets to enable [Pass the Ticket](https://attack.mitre.org/techniques/T1550/003). Kerberos is an authentication protocol widely used in modern Windows domain environments. In Kerberos environments, referred to as “realms”, there are three basic participants: client, service, and Key Distribution Center (KDC).(Citation: ADSecurity Kerberos Ring Decoder) Clients request access to a service and through the exchange of Kerberos tickets, originating from KDC, they are granted access after having successfully authenticated. The KDC is responsible for both authentication and ticket granting. Adversaries may attempt to abuse Kerberos by stealing tickets or forging tickets to enable unauthorized access. - StealOrForgeKerberosTickets, - - /// [Credentials from Password Stores](https://attack.mitre.org/techniques/T1555) - /// - /// Adversaries may search for common password storage locations to obtain user credentials. Passwords are stored in several places on a system, depending on the operating system or application holding the credentials. There are also specific applications and services that store passwords to make them easier for users to manage and maintain, such as password managers and cloud secrets vaults. Once credentials are obtained, they can be used to perform lateral movement and access restricted information. - CredentialsFromPasswordStores, - - /// [Unsecured Credentials](https://attack.mitre.org/techniques/T1552) - /// - /// Adversaries may search compromised systems to find and obtain insecurely stored credentials. These credentials can be stored and/or misplaced in many locations on a system, including plaintext files (e.g. [Bash History](https://attack.mitre.org/techniques/T1552/003)), operating system or application-specific repositories (e.g. [Credentials in Registry](https://attack.mitre.org/techniques/T1552/002)), or other specialized files/artifacts (e.g. [Private Keys](https://attack.mitre.org/techniques/T1552/004)). - UnsecuredCredentials, - - /// [Steal or Forge Authentication Certificates](https://attack.mitre.org/techniques/T1649) - /// - /// Adversaries may steal or forge certificates used for authentication to access remote systems or resources. Digital certificates are often used to sign and encrypt messages and/or files. Certificates are also used as authentication material. For example, Azure AD device certificates and Active Directory Certificate Services (AD CS) certificates bind to an identity and can be used as credentials for domain accounts.(Citation: O365 Blog Azure AD Device IDs)(Citation: Microsoft AD CS Overview) - StealOrForgeAuthenticationCertificates, - - /// [Steal Application Access Token](https://attack.mitre.org/techniques/T1528) - /// - /// Adversaries can steal application access tokens as a means of acquiring credentials to access remote systems and resources. - StealApplicationAccessToken, - - /// [Forge Web Credentials](https://attack.mitre.org/techniques/T1606) - /// - /// Adversaries may forge credential materials that can be used to gain access to web applications or Internet services. Web applications and services (hosted in cloud SaaS environments or on-premise servers) often use session cookies, tokens, or other materials to authenticate and authorize user access. - ForgeWebCredentials, - - /// [Multi-Factor Authentication Request Generation](https://attack.mitre.org/techniques/T1621) - /// - /// Adversaries may attempt to bypass multi-factor authentication (MFA) mechanisms and gain access to accounts by generating MFA requests sent to users. - MultiFactorAuthenticationRequestGeneration, - - /// [Exploitation for Credential Access](https://attack.mitre.org/techniques/T1212) - /// - /// Adversaries may exploit software vulnerabilities in an attempt to collect credentials. Exploitation of a software vulnerability occurs when an adversary takes advantage of a programming error in a program, service, or within the operating system software or kernel itself to execute adversary-controlled code.  - ExploitationForCredentialAccess, - - /// [Brute Force](https://attack.mitre.org/techniques/T1110) - /// - /// Adversaries may use brute force techniques to gain access to accounts when passwords are unknown or when password hashes are obtained. Without knowledge of the password for an account or set of accounts, an adversary may systematically guess the password using a repetitive or iterative mechanism. Brute forcing passwords can take place via interaction with a service that will check the validity of those credentials or offline against previously acquired credential data, such as password hashes. - BruteForce, - - /// [Forced Authentication](https://attack.mitre.org/techniques/T1187) - /// - /// Adversaries may gather credential material by invoking or forcing a user to automatically provide authentication information through a mechanism in which they can intercept. - ForcedAuthentication, - - /// [Input Capture](https://attack.mitre.org/techniques/T1056) - /// - /// Adversaries may use methods of capturing user input to obtain credentials or collect information. During normal system usage, users often provide credentials to various different locations, such as login pages/portals or system dialog boxes. Input capture mechanisms may be transparent to the user (e.g. [Credential API Hooking](https://attack.mitre.org/techniques/T1056/004)) or rely on deceiving the user into providing input into what they believe to be a genuine service (e.g. [Web Portal Capture](https://attack.mitre.org/techniques/T1056/003)). - InputCapture, - - /// [Multi-Factor Authentication Interception](https://attack.mitre.org/techniques/T1111) - /// - /// Adversaries may target multi-factor authentication (MFA) mechanisms, (i.e., smart cards, token generators, etc.) to gain access to credentials that can be used to access systems, services, and network resources. Use of MFA is recommended and provides a higher level of security than usernames and passwords alone, but organizations should be aware of techniques that could be used to intercept and bypass these security mechanisms. - MultiFactorAuthenticationInterception, - - /// [Modify Authentication Process](https://attack.mitre.org/techniques/T1556) - /// - /// Adversaries may modify authentication mechanisms and processes to access user credentials or enable otherwise unwarranted access to accounts. The authentication process is handled by mechanisms, such as the Local Security Authentication Server (LSASS) process and the Security Accounts Manager (SAM) on Windows, pluggable authentication modules (PAM) on Unix-based systems, and authorization plugins on MacOS systems, responsible for gathering, storing, and validating credentials. By modifying an authentication process, an adversary may be able to authenticate to a service or system without using [Valid Accounts](https://attack.mitre.org/techniques/T1078). - ModifyAuthenticationProcess, - -} -/// [Execution](https://attack.mitre.org/tactics/TA0002)'s techniques -pub enum Execution { - /// [Windows Management Instrumentation](https://attack.mitre.org/techniques/T1047) - /// - /// Adversaries may abuse Windows Management Instrumentation (WMI) to execute malicious commands and payloads. WMI is an administration feature that provides a uniform environment to access Windows system components. The WMI service enables both local and remote access, though the latter is facilitated by [Remote Services](https://attack.mitre.org/techniques/T1021) such as [Distributed Component Object Model](https://attack.mitre.org/techniques/T1021/003) (DCOM) and [Windows Remote Management](https://attack.mitre.org/techniques/T1021/006) (WinRM).(Citation: MSDN WMI) Remote WMI over DCOM operates using port 135, whereas WMI over WinRM operates over port 5985 when using HTTP and 5986 for HTTPS.(Citation: MSDN WMI)(Citation: FireEye WMI 2015) - WindowsManagementInstrumentation, - - /// [Shared Modules](https://attack.mitre.org/techniques/T1129) - /// - /// Adversaries may execute malicious payloads via loading shared modules. Shared modules are executable files that are loaded into processes to provide access to reusable code, such as specific custom functions or invoking OS API functions (i.e., [Native API](https://attack.mitre.org/techniques/T1106)). - SharedModules, - - /// [Scheduled Task/Job](https://attack.mitre.org/techniques/T1053) - /// - /// Adversaries may abuse task scheduling functionality to facilitate initial or recurring execution of malicious code. Utilities exist within all major operating systems to schedule programs or scripts to be executed at a specified date and time. A task can also be scheduled on a remote system, provided the proper authentication is met (ex: RPC and file and printer sharing in Windows environments). Scheduling a task on a remote system typically may require being a member of an admin or otherwise privileged group on the remote system.(Citation: TechNet Task Scheduler Security) - ScheduledTaskJob, - - /// [Native API](https://attack.mitre.org/techniques/T1106) - /// - /// Adversaries may interact with the native OS application programming interface (API) to execute behaviors. Native APIs provide a controlled means of calling low-level OS services within the kernel, such as those involving hardware/devices, memory, and processes.(Citation: NT API Windows)(Citation: Linux Kernel API) These native APIs are leveraged by the OS during system boot (when other system components are not yet initialized) as well as carrying out tasks and requests during routine operations. - NativeApi, - - /// [Deploy Container](https://attack.mitre.org/techniques/T1610) - /// - /// Adversaries may deploy a container into an environment to facilitate execution or evade defenses. In some cases, adversaries may deploy a new container to execute processes associated with a particular image or deployment, such as processes that execute or download malware. In others, an adversary may deploy a new container configured without network rules, user limitations, etc. to bypass existing defenses within the environment. - DeployContainer, - - /// [Command and Scripting Interpreter](https://attack.mitre.org/techniques/T1059) - /// - /// Adversaries may abuse command and script interpreters to execute commands, scripts, or binaries. These interfaces and languages provide ways of interacting with computer systems and are a common feature across many different platforms. Most systems come with some built-in command-line interface and scripting capabilities, for example, macOS and Linux distributions include some flavor of [Unix Shell](https://attack.mitre.org/techniques/T1059/004) while Windows installations include the [Windows Command Shell](https://attack.mitre.org/techniques/T1059/003) and [PowerShell](https://attack.mitre.org/techniques/T1059/001). - CommandAndScriptingInterpreter, - - /// [Container Administration Command](https://attack.mitre.org/techniques/T1609) - /// - /// Adversaries may abuse a container administration service to execute commands within a container. A container administration service such as the Docker daemon, the Kubernetes API server, or the kubelet may allow remote management of containers within an environment.(Citation: Docker Daemon CLI)(Citation: Kubernetes API)(Citation: Kubernetes Kubelet) - ContainerAdministrationCommand, - - /// [User Execution](https://attack.mitre.org/techniques/T1204) - /// - /// An adversary may rely upon specific actions by a user in order to gain execution. Users may be subjected to social engineering to get them to execute malicious code by, for example, opening a malicious document file or link. These user actions will typically be observed as follow-on behavior from forms of [Phishing](https://attack.mitre.org/techniques/T1566). - UserExecution, - - /// [Software Deployment Tools](https://attack.mitre.org/techniques/T1072) - /// - /// Adversaries may gain access to and use third-party software suites installed within an enterprise network, such as administration, monitoring, and deployment systems, to move laterally through the network. Third-party applications and software deployment systems may be in use in the network environment for administration purposes (e.g., SCCM, HBSS, Altiris, etc.). - SoftwareDeploymentTools, - - /// [Inter-Process Communication](https://attack.mitre.org/techniques/T1559) - /// - /// Adversaries may abuse inter-process communication (IPC) mechanisms for local code or command execution. IPC is typically used by processes to share data, communicate with each other, or synchronize execution. IPC is also commonly used to avoid situations such as deadlocks, which occurs when processes are stuck in a cyclic waiting pattern. - InterProcessCommunication, - - /// [Exploitation for Client Execution](https://attack.mitre.org/techniques/T1203) - /// - /// Adversaries may exploit software vulnerabilities in client applications to execute code. Vulnerabilities can exist in software due to unsecure coding practices that can lead to unanticipated behavior. Adversaries can take advantage of certain vulnerabilities through targeted exploitation for the purpose of arbitrary code execution. Oftentimes the most valuable exploits to an offensive toolkit are those that can be used to obtain code execution on a remote system because they can be used to gain access to that system. Users will expect to see files related to the applications they commonly used to do work, so they are a useful target for exploit research and development because of their high utility. - ExploitationForClientExecution, - - /// [System Services](https://attack.mitre.org/techniques/T1569) - /// - /// Adversaries may abuse system services or daemons to execute commands or programs. Adversaries can execute malicious content by interacting with or creating services either locally or remotely. Many services are set to run at boot, which can aid in achieving persistence ([Create or Modify System Process](https://attack.mitre.org/techniques/T1543)), but adversaries can also abuse services for one-time or temporary execution. - SystemServices, - - /// [Cloud Administration Command](https://attack.mitre.org/techniques/T1651) - /// - /// Adversaries may abuse cloud management services to execute commands within virtual machines or hybrid-joined devices. Resources such as AWS Systems Manager, Azure RunCommand, and Runbooks allow users to remotely run scripts in virtual machines by leveraging installed virtual machine agents. Similarly, in Azure AD environments, Microsoft Endpoint Manager allows Global or Intune Administrators to run scripts as SYSTEM on on-premises devices joined to the Azure AD.(Citation: AWS Systems Manager Run Command)(Citation: Microsoft Run Command)(Citation: SpecterOps Lateral Movement from Azure to On-Prem AD 2020) - CloudAdministrationCommand, - - /// [Serverless Execution](https://attack.mitre.org/techniques/T1648) - /// - /// Adversaries may abuse serverless computing, integration, and automation services to execute arbitrary code in cloud environments. Many cloud providers offer a variety of serverless resources, including compute engines, application integration services, and web servers. - ServerlessExecution, - -} -/// [Impact](https://attack.mitre.org/tactics/TA0040)'s techniques -pub enum Impact { - /// [Disk Wipe](https://attack.mitre.org/techniques/T1561) - /// - /// Adversaries may wipe or corrupt raw disk data on specific systems or in large numbers in a network to interrupt availability to system and network resources. With direct write access to a disk, adversaries may attempt to overwrite portions of disk data. Adversaries may opt to wipe arbitrary portions of disk data and/or wipe disk structures like the master boot record (MBR). A complete wipe of all disk sectors may be attempted. - DiskWipe, - - /// [Service Stop](https://attack.mitre.org/techniques/T1489) - /// - /// Adversaries may stop or disable services on a system to render those services unavailable to legitimate users. Stopping critical services or processes can inhibit or stop response to an incident or aid in the adversary's overall objectives to cause damage to the environment.(Citation: Talos Olympic Destroyer 2018)(Citation: Novetta Blockbuster) - ServiceStop, - - /// [Defacement](https://attack.mitre.org/techniques/T1491) - /// - /// Adversaries may modify visual content available internally or externally to an enterprise network, thus affecting the integrity of the original content. Reasons for [Defacement](https://attack.mitre.org/techniques/T1491) include delivering messaging, intimidation, or claiming (possibly false) credit for an intrusion. Disturbing or offensive images may be used as a part of [Defacement](https://attack.mitre.org/techniques/T1491) in order to cause user discomfort, or to pressure compliance with accompanying messages. - Defacement, - - /// [Financial Theft](https://attack.mitre.org/techniques/T1657) - /// - /// Adversaries may steal monetary resources from targets through extortion, social engineering, technical theft, or other methods aimed at their own financial gain at the expense of the availability of these resources for victims. Financial theft is the ultimate objective of several popular campaign types including extortion by ransomware,(Citation: FBI-ransomware) business email compromise (BEC) and fraud,(Citation: FBI-BEC) "pig butchering,"(Citation: wired-pig butchering) bank hacking,(Citation: DOJ-DPRK Heist) and exploiting cryptocurrency networks.(Citation: BBC-Ronin) - FinancialTheft, - - /// [Data Manipulation](https://attack.mitre.org/techniques/T1565) - /// - /// Adversaries may insert, delete, or manipulate data in order to influence external outcomes or hide activity, thus threatening the integrity of the data. By manipulating data, adversaries may attempt to affect a business process, organizational understanding, or decision making. - DataManipulation, - - /// [Account Access Removal](https://attack.mitre.org/techniques/T1531) - /// - /// Adversaries may interrupt availability of system and network resources by inhibiting access to accounts utilized by legitimate users. Accounts may be deleted, locked, or manipulated (ex: changed credentials) to remove access to accounts. Adversaries may also subsequently log off and/or perform a [System Shutdown/Reboot](https://attack.mitre.org/techniques/T1529) to set malicious changes into place.(Citation: CarbonBlack LockerGoga 2019)(Citation: Unit42 LockerGoga 2019) - AccountAccessRemoval, - - /// [Data Encrypted for Impact](https://attack.mitre.org/techniques/T1486) - /// - /// Adversaries may encrypt data on target systems or on large numbers of systems in a network to interrupt availability to system and network resources. They can attempt to render stored data inaccessible by encrypting files or data on local and remote drives and withholding access to a decryption key. This may be done in order to extract monetary compensation from a victim in exchange for decryption or a decryption key (ransomware) or to render data permanently inaccessible in cases where the key is not saved or transmitted.(Citation: US-CERT Ransomware 2016)(Citation: FireEye WannaCry 2017)(Citation: US-CERT NotPetya 2017)(Citation: US-CERT SamSam 2018) - DataEncryptedForImpact, - - /// [Endpoint Denial of Service](https://attack.mitre.org/techniques/T1499) - /// - /// Adversaries may perform Endpoint Denial of Service (DoS) attacks to degrade or block the availability of services to users. Endpoint DoS can be performed by exhausting the system resources those services are hosted on or exploiting the system to cause a persistent crash condition. Example services include websites, email services, DNS, and web-based applications. Adversaries have been observed conducting DoS attacks for political purposes(Citation: FireEye OpPoisonedHandover February 2016) and to support other malicious activities, including distraction(Citation: FSISAC FraudNetDoS September 2012), hacktivism, and extortion.(Citation: Symantec DDoS October 2014) - EndpointDenialOfService, - - /// [Resource Hijacking](https://attack.mitre.org/techniques/T1496) - /// - /// Adversaries may leverage the resources of co-opted systems to complete resource-intensive tasks, which may impact system and/or hosted service availability. - ResourceHijacking, - - /// [Data Destruction](https://attack.mitre.org/techniques/T1485) - /// - /// Adversaries may destroy data and files on specific systems or in large numbers on a network to interrupt availability to systems, services, and network resources. Data destruction is likely to render stored data irrecoverable by forensic techniques through overwriting files or data on local and remote drives.(Citation: Symantec Shamoon 2012)(Citation: FireEye Shamoon Nov 2016)(Citation: Palo Alto Shamoon Nov 2016)(Citation: Kaspersky StoneDrill 2017)(Citation: Unit 42 Shamoon3 2018)(Citation: Talos Olympic Destroyer 2018) Common operating system file deletion commands such as del and rm often only remove pointers to files without wiping the contents of the files themselves, making the files recoverable by proper forensic methodology. This behavior is distinct from [Disk Content Wipe](https://attack.mitre.org/techniques/T1561/001) and [Disk Structure Wipe](https://attack.mitre.org/techniques/T1561/002) because individual files are destroyed rather than sections of a storage disk or the disk's logical structure. - DataDestruction, - - /// [Network Denial of Service](https://attack.mitre.org/techniques/T1498) - /// - /// Adversaries may perform Network Denial of Service (DoS) attacks to degrade or block the availability of targeted resources to users. Network DoS can be performed by exhausting the network bandwidth services rely on. Example resources include specific websites, email services, DNS, and web-based applications. Adversaries have been observed conducting network DoS attacks for political purposes(Citation: FireEye OpPoisonedHandover February 2016) and to support other malicious activities, including distraction(Citation: FSISAC FraudNetDoS September 2012), hacktivism, and extortion.(Citation: Symantec DDoS October 2014) - NetworkDenialOfService, - - /// [Firmware Corruption](https://attack.mitre.org/techniques/T1495) - /// - /// Adversaries may overwrite or corrupt the flash memory contents of system BIOS or other firmware in devices attached to a system in order to render them inoperable or unable to boot, thus denying the availability to use the devices and/or the system.(Citation: Symantec Chernobyl W95.CIH) Firmware is software that is loaded and executed from non-volatile memory on hardware devices in order to initialize and manage device functionality. These devices may include the motherboard, hard drive, or video cards. - FirmwareCorruption, - - /// [Inhibit System Recovery](https://attack.mitre.org/techniques/T1490) - /// - /// Adversaries may delete or remove built-in data and turn off services designed to aid in the recovery of a corrupted system to prevent recovery.(Citation: Talos Olympic Destroyer 2018)(Citation: FireEye WannaCry 2017) This may deny access to available backups and recovery options. - InhibitSystemRecovery, - - /// [System Shutdown/Reboot](https://attack.mitre.org/techniques/T1529) - /// - /// Adversaries may shutdown/reboot systems to interrupt access to, or aid in the destruction of, those systems. Operating systems may contain commands to initiate a shutdown/reboot of a machine or network device. In some cases, these commands may also be used to initiate a shutdown/reboot of a remote computer or network device via [Network Device CLI](https://attack.mitre.org/techniques/T1059/008) (e.g. reload).(Citation: Microsoft Shutdown Oct 2017)(Citation: alert_TA18_106A) - SystemShutdownReboot, - -} -/// [Persistence](https://attack.mitre.org/tactics/TA0003)'s techniques -pub enum Persistence { - /// [Boot or Logon Initialization Scripts](https://attack.mitre.org/techniques/T1037) - /// - /// Adversaries may use scripts automatically executed at boot or logon initialization to establish persistence. Initialization scripts can be used to perform administrative functions, which may often execute other programs or send information to an internal logging server. These scripts can vary based on operating system and whether applied locally or remotely. - BootOrLogonInitializationScripts, - - /// [Create or Modify System Process](https://attack.mitre.org/techniques/T1543) - /// - /// Adversaries may create or modify system-level processes to repeatedly execute malicious payloads as part of persistence. When operating systems boot up, they can start processes that perform background system functions. On Windows and Linux, these system processes are referred to as services.(Citation: TechNet Services) On macOS, launchd processes known as [Launch Daemon](https://attack.mitre.org/techniques/T1543/004) and [Launch Agent](https://attack.mitre.org/techniques/T1543/001) are run to finish system initialization and load user specific parameters.(Citation: AppleDocs Launch Agent Daemons) - CreateOrModifySystemProcess, - - /// [External Remote Services](https://attack.mitre.org/techniques/T1133) - /// - /// Adversaries may leverage external-facing remote services to initially access and/or persist within a network. Remote services such as VPNs, Citrix, and other access mechanisms allow users to connect to internal enterprise network resources from external locations. There are often remote service gateways that manage connections and credential authentication for these services. Services such as [Windows Remote Management](https://attack.mitre.org/techniques/T1021/006) and [VNC](https://attack.mitre.org/techniques/T1021/005) can also be used externally.(Citation: MacOS VNC software for Remote Desktop) - ExternalRemoteServices, - - /// [Boot or Logon Autostart Execution](https://attack.mitre.org/techniques/T1547) - /// - /// Adversaries may configure system settings to automatically execute a program during system boot or logon to maintain persistence or gain higher-level privileges on compromised systems. Operating systems may have mechanisms for automatically running a program on system boot or account logon.(Citation: Microsoft Run Key)(Citation: MSDN Authentication Packages)(Citation: Microsoft TimeProvider)(Citation: Cylance Reg Persistence Sept 2013)(Citation: Linux Kernel Programming) These mechanisms may include automatically executing programs that are placed in specially designated directories or are referenced by repositories that store configuration information, such as the Windows Registry. An adversary may achieve the same goal by modifying or extending features of the kernel. - BootOrLogonAutostartExecution, - - /// [Office Application Startup](https://attack.mitre.org/techniques/T1137) - /// - /// Adversaries may leverage Microsoft Office-based applications for persistence between startups. Microsoft Office is a fairly common application suite on Windows-based operating systems within an enterprise network. There are multiple mechanisms that can be used with Office for persistence when an Office-based application is started; this can include the use of Office Template Macros and add-ins. - OfficeApplicationStartup, - - /// [Scheduled Task/Job](https://attack.mitre.org/techniques/T1053) - /// - /// Adversaries may abuse task scheduling functionality to facilitate initial or recurring execution of malicious code. Utilities exist within all major operating systems to schedule programs or scripts to be executed at a specified date and time. A task can also be scheduled on a remote system, provided the proper authentication is met (ex: RPC and file and printer sharing in Windows environments). Scheduling a task on a remote system typically may require being a member of an admin or otherwise privileged group on the remote system.(Citation: TechNet Task Scheduler Security) - ScheduledTaskJob, - - /// [Browser Extensions](https://attack.mitre.org/techniques/T1176) - /// - /// Adversaries may abuse Internet browser extensions to establish persistent access to victim systems. Browser extensions or plugins are small programs that can add functionality and customize aspects of Internet browsers. They can be installed directly or through a browser's app store and generally have access and permissions to everything that the browser can access.(Citation: Wikipedia Browser Extension)(Citation: Chrome Extensions Definition) - BrowserExtensions, - - /// [Traffic Signaling](https://attack.mitre.org/techniques/T1205) - /// - /// Adversaries may use traffic signaling to hide open ports or other malicious functionality used for persistence or command and control. Traffic signaling involves the use of a magic value or sequence that must be sent to a system to trigger a special response, such as opening a closed port or executing a malicious task. This may take the form of sending a series of packets with certain characteristics before a port will be opened that the adversary can use for command and control. Usually this series of packets consists of attempted connections to a predefined sequence of closed ports (i.e. [Port Knocking](https://attack.mitre.org/techniques/T1205/001)), but can involve unusual flags, specific strings, or other unique characteristics. After the sequence is completed, opening a port may be accomplished by the host-based firewall, but could also be implemented by custom software. - TrafficSignaling, - - /// [Implant Internal Image](https://attack.mitre.org/techniques/T1525) - /// - /// Adversaries may implant cloud or container images with malicious code to establish persistence after gaining access to an environment. Amazon Web Services (AWS) Amazon Machine Images (AMIs), Google Cloud Platform (GCP) Images, and Azure Images as well as popular container runtimes such as Docker can be implanted or backdoored. Unlike [Upload Malware](https://attack.mitre.org/techniques/T1608/001), this technique focuses on adversaries implanting an image in a registry within a victim’s environment. Depending on how the infrastructure is provisioned, this could provide persistent access if the infrastructure provisioning tool is instructed to always use the latest image.(Citation: Rhino Labs Cloud Image Backdoor Technique Sept 2019) - ImplantInternalImage, - - /// [Pre-OS Boot](https://attack.mitre.org/techniques/T1542) - /// - /// Adversaries may abuse Pre-OS Boot mechanisms as a way to establish persistence on a system. During the booting process of a computer, firmware and various startup services are loaded before the operating system. These programs control flow of execution before the operating system takes control.(Citation: Wikipedia Booting) - PreOsBoot, - - /// [Compromise Client Software Binary](https://attack.mitre.org/techniques/T1554) - /// - /// Adversaries may modify client software binaries to establish persistent access to systems. Client software enables users to access services provided by a server. Common client software types are SSH clients, FTP clients, email clients, and web browsers. - CompromiseClientSoftwareBinary, - - /// [Account Manipulation](https://attack.mitre.org/techniques/T1098) - /// - /// Adversaries may manipulate accounts to maintain and/or elevate access to victim systems. Account manipulation may consist of any action that preserves or modifies adversary access to a compromised account, such as modifying credentials or permission groups. These actions could also include account activity designed to subvert security policies, such as performing iterative password updates to bypass password duration policies and preserve the life of compromised credentials. - AccountManipulation, - - /// [Hijack Execution Flow](https://attack.mitre.org/techniques/T1574) - /// - /// Adversaries may execute their own malicious payloads by hijacking the way operating systems run programs. Hijacking execution flow can be for the purposes of persistence, since this hijacked execution may reoccur over time. Adversaries may also use these mechanisms to elevate privileges or evade defenses, such as application control or other restrictions on execution. - HijackExecutionFlow, - - /// [Valid Accounts](https://attack.mitre.org/techniques/T1078) - /// - /// Adversaries may obtain and abuse credentials of existing accounts as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Compromised credentials may be used to bypass access controls placed on various resources on systems within the network and may even be used for persistent access to remote systems and externally available services, such as VPNs, Outlook Web Access, network devices, and remote desktop.(Citation: volexity_0day_sophos_FW) Compromised credentials may also grant an adversary increased privilege to specific systems or access to restricted areas of the network. Adversaries may choose not to use malware or tools in conjunction with the legitimate access those credentials provide to make it harder to detect their presence. - ValidAccounts, - - /// [Event Triggered Execution](https://attack.mitre.org/techniques/T1546) - /// - /// Adversaries may establish persistence and/or elevate privileges using system mechanisms that trigger execution based on specific events. Various operating systems have means to monitor and subscribe to events such as logons or other user activity such as running specific applications/binaries. Cloud environments may also support various functions and services that monitor and can be invoked in response to specific cloud events.(Citation: Backdooring an AWS account)(Citation: Varonis Power Automate Data Exfiltration)(Citation: Microsoft DART Case Report 001) - EventTriggeredExecution, - - /// [BITS Jobs](https://attack.mitre.org/techniques/T1197) - /// - /// Adversaries may abuse BITS jobs to persistently execute code and perform various background tasks. Windows Background Intelligent Transfer Service (BITS) is a low-bandwidth, asynchronous file transfer mechanism exposed through [Component Object Model](https://attack.mitre.org/techniques/T1559/001) (COM).(Citation: Microsoft COM)(Citation: Microsoft BITS) BITS is commonly used by updaters, messengers, and other applications preferred to operate in the background (using available idle bandwidth) without interrupting other networked applications. File transfer tasks are implemented as BITS jobs, which contain a queue of one or more file operations. - BitsJobs, - - /// [Server Software Component](https://attack.mitre.org/techniques/T1505) - /// - /// Adversaries may abuse legitimate extensible development features of servers to establish persistent access to systems. Enterprise server applications may include features that allow developers to write and install software or scripts to extend the functionality of the main application. Adversaries may install malicious components to extend and abuse server applications.(Citation: volexity_0day_sophos_FW) - ServerSoftwareComponent, - - /// [Create Account](https://attack.mitre.org/techniques/T1136) - /// - /// Adversaries may create an account to maintain access to victim systems. With a sufficient level of access, creating such accounts may be used to establish secondary credentialed access that do not require persistent remote access tools to be deployed on the system. - CreateAccount, - - /// [Power Settings](https://attack.mitre.org/techniques/T1653) - /// - /// Adversaries may impair a system's ability to hibernate, reboot, or shut down in order to extend access to infected machines. When a computer enters a dormant state, some or all software and hardware may cease to operate which can disrupt malicious activity.(Citation: Sleep, shut down, hibernate) - PowerSettings, - - /// [Modify Authentication Process](https://attack.mitre.org/techniques/T1556) - /// - /// Adversaries may modify authentication mechanisms and processes to access user credentials or enable otherwise unwarranted access to accounts. The authentication process is handled by mechanisms, such as the Local Security Authentication Server (LSASS) process and the Security Accounts Manager (SAM) on Windows, pluggable authentication modules (PAM) on Unix-based systems, and authorization plugins on MacOS systems, responsible for gathering, storing, and validating credentials. By modifying an authentication process, an adversary may be able to authenticate to a service or system without using [Valid Accounts](https://attack.mitre.org/techniques/T1078). - ModifyAuthenticationProcess, - -} -/// [Privilege Escalation](https://attack.mitre.org/tactics/TA0004)'s techniques -pub enum PrivilegeEscalation { - /// [Boot or Logon Initialization Scripts](https://attack.mitre.org/techniques/T1037) - /// - /// Adversaries may use scripts automatically executed at boot or logon initialization to establish persistence. Initialization scripts can be used to perform administrative functions, which may often execute other programs or send information to an internal logging server. These scripts can vary based on operating system and whether applied locally or remotely. - BootOrLogonInitializationScripts, - - /// [Create or Modify System Process](https://attack.mitre.org/techniques/T1543) - /// - /// Adversaries may create or modify system-level processes to repeatedly execute malicious payloads as part of persistence. When operating systems boot up, they can start processes that perform background system functions. On Windows and Linux, these system processes are referred to as services.(Citation: TechNet Services) On macOS, launchd processes known as [Launch Daemon](https://attack.mitre.org/techniques/T1543/004) and [Launch Agent](https://attack.mitre.org/techniques/T1543/001) are run to finish system initialization and load user specific parameters.(Citation: AppleDocs Launch Agent Daemons) - CreateOrModifySystemProcess, - - /// [Boot or Logon Autostart Execution](https://attack.mitre.org/techniques/T1547) - /// - /// Adversaries may configure system settings to automatically execute a program during system boot or logon to maintain persistence or gain higher-level privileges on compromised systems. Operating systems may have mechanisms for automatically running a program on system boot or account logon.(Citation: Microsoft Run Key)(Citation: MSDN Authentication Packages)(Citation: Microsoft TimeProvider)(Citation: Cylance Reg Persistence Sept 2013)(Citation: Linux Kernel Programming) These mechanisms may include automatically executing programs that are placed in specially designated directories or are referenced by repositories that store configuration information, such as the Windows Registry. An adversary may achieve the same goal by modifying or extending features of the kernel. - BootOrLogonAutostartExecution, - - /// [Scheduled Task/Job](https://attack.mitre.org/techniques/T1053) - /// - /// Adversaries may abuse task scheduling functionality to facilitate initial or recurring execution of malicious code. Utilities exist within all major operating systems to schedule programs or scripts to be executed at a specified date and time. A task can also be scheduled on a remote system, provided the proper authentication is met (ex: RPC and file and printer sharing in Windows environments). Scheduling a task on a remote system typically may require being a member of an admin or otherwise privileged group on the remote system.(Citation: TechNet Task Scheduler Security) - ScheduledTaskJob, - - /// [Process Injection](https://attack.mitre.org/techniques/T1055) - /// - /// Adversaries may inject code into processes in order to evade process-based defenses as well as possibly elevate privileges. Process injection is a method of executing arbitrary code in the address space of a separate live process. Running code in the context of another process may allow access to the process's memory, system/network resources, and possibly elevated privileges. Execution via process injection may also evade detection from security products since the execution is masked under a legitimate process. - ProcessInjection, - - /// [Escape to Host](https://attack.mitre.org/techniques/T1611) - /// - /// Adversaries may break out of a container to gain access to the underlying host. This can allow an adversary access to other containerized resources from the host level or to the host itself. In principle, containerized resources should provide a clear separation of application functionality and be isolated from the host environment.(Citation: Docker Overview) - EscapeToHost, - - /// [Abuse Elevation Control Mechanism](https://attack.mitre.org/techniques/T1548) - /// - /// Adversaries may circumvent mechanisms designed to control elevate privileges to gain higher-level permissions. Most modern systems contain native elevation control mechanisms that are intended to limit privileges that a user can perform on a machine. Authorization has to be granted to specific users in order to perform tasks that can be considered of higher risk. An adversary can perform several methods to take advantage of built-in control mechanisms in order to escalate privileges on a system. - AbuseElevationControlMechanism, - - /// [Account Manipulation](https://attack.mitre.org/techniques/T1098) - /// - /// Adversaries may manipulate accounts to maintain and/or elevate access to victim systems. Account manipulation may consist of any action that preserves or modifies adversary access to a compromised account, such as modifying credentials or permission groups. These actions could also include account activity designed to subvert security policies, such as performing iterative password updates to bypass password duration policies and preserve the life of compromised credentials. - AccountManipulation, - - /// [Hijack Execution Flow](https://attack.mitre.org/techniques/T1574) - /// - /// Adversaries may execute their own malicious payloads by hijacking the way operating systems run programs. Hijacking execution flow can be for the purposes of persistence, since this hijacked execution may reoccur over time. Adversaries may also use these mechanisms to elevate privileges or evade defenses, such as application control or other restrictions on execution. - HijackExecutionFlow, - - /// [Valid Accounts](https://attack.mitre.org/techniques/T1078) - /// - /// Adversaries may obtain and abuse credentials of existing accounts as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Compromised credentials may be used to bypass access controls placed on various resources on systems within the network and may even be used for persistent access to remote systems and externally available services, such as VPNs, Outlook Web Access, network devices, and remote desktop.(Citation: volexity_0day_sophos_FW) Compromised credentials may also grant an adversary increased privilege to specific systems or access to restricted areas of the network. Adversaries may choose not to use malware or tools in conjunction with the legitimate access those credentials provide to make it harder to detect their presence. - ValidAccounts, - - /// [Exploitation for Privilege Escalation](https://attack.mitre.org/techniques/T1068) - /// - /// Adversaries may exploit software vulnerabilities in an attempt to elevate privileges. Exploitation of a software vulnerability occurs when an adversary takes advantage of a programming error in a program, service, or within the operating system software or kernel itself to execute adversary-controlled code. Security constructs such as permission levels will often hinder access to information and use of certain techniques, so adversaries will likely need to perform privilege escalation to include use of software exploitation to circumvent those restrictions. - ExploitationForPrivilegeEscalation, - - /// [Event Triggered Execution](https://attack.mitre.org/techniques/T1546) - /// - /// Adversaries may establish persistence and/or elevate privileges using system mechanisms that trigger execution based on specific events. Various operating systems have means to monitor and subscribe to events such as logons or other user activity such as running specific applications/binaries. Cloud environments may also support various functions and services that monitor and can be invoked in response to specific cloud events.(Citation: Backdooring an AWS account)(Citation: Varonis Power Automate Data Exfiltration)(Citation: Microsoft DART Case Report 001) - EventTriggeredExecution, - - /// [Access Token Manipulation](https://attack.mitre.org/techniques/T1134) - /// - /// Adversaries may modify access tokens to operate under a different user or system security context to perform actions and bypass access controls. Windows uses access tokens to determine the ownership of a running process. A user can manipulate access tokens to make a running process appear as though it is the child of a different process or belongs to someone other than the user that started the process. When this occurs, the process also takes on the security context associated with the new token. - AccessTokenManipulation, - - /// [Domain Policy Modification](https://attack.mitre.org/techniques/T1484) - /// - /// Adversaries may modify the configuration settings of a domain to evade defenses and/or escalate privileges in domain environments. Domains provide a centralized means of managing how computer resources (ex: computers, user accounts) can act, and interact with each other, on a network. The policy of the domain also includes configuration settings that may apply between domains in a multi-domain/forest environment. Modifications to domain settings may include altering domain Group Policy Objects (GPOs) or changing trust settings for domains, including federation trusts. - DomainPolicyModification, - -} -/// [Lateral Movement](https://attack.mitre.org/tactics/TA0008)'s techniques -pub enum LateralMovement { - /// [Taint Shared Content](https://attack.mitre.org/techniques/T1080) - /// - /// - TaintSharedContent, - - /// [Replication Through Removable Media](https://attack.mitre.org/techniques/T1091) - /// - /// Adversaries may move onto systems, possibly those on disconnected or air-gapped networks, by copying malware to removable media and taking advantage of Autorun features when the media is inserted into a system and executes. In the case of Lateral Movement, this may occur through modification of executable files stored on removable media or by copying malware and renaming it to look like a legitimate file to trick users into executing it on a separate system. In the case of Initial Access, this may occur through manual manipulation of the media, modification of systems used to initially format the media, or modification to the media's firmware itself. - ReplicationThroughRemovableMedia, - - /// [Use Alternate Authentication Material](https://attack.mitre.org/techniques/T1550) - /// - /// Adversaries may use alternate authentication material, such as password hashes, Kerberos tickets, and application access tokens, in order to move laterally within an environment and bypass normal system access controls. - UseAlternateAuthenticationMaterial, - - /// [Remote Services](https://attack.mitre.org/techniques/T1021) - /// - /// Adversaries may use [Valid Accounts](https://attack.mitre.org/techniques/T1078) to log into a service that accepts remote connections, such as telnet, SSH, and VNC. The adversary may then perform actions as the logged-on user. - RemoteServices, - - /// [Remote Service Session Hijacking](https://attack.mitre.org/techniques/T1563) - /// - /// Adversaries may take control of preexisting sessions with remote services to move laterally in an environment. Users may use valid credentials to log into a service specifically designed to accept remote connections, such as telnet, SSH, and RDP. When a user logs into a service, a session will be established that will allow them to maintain a continuous interaction with that service. - RemoteServiceSessionHijacking, - - /// [Software Deployment Tools](https://attack.mitre.org/techniques/T1072) - /// - /// Adversaries may gain access to and use third-party software suites installed within an enterprise network, such as administration, monitoring, and deployment systems, to move laterally through the network. Third-party applications and software deployment systems may be in use in the network environment for administration purposes (e.g., SCCM, HBSS, Altiris, etc.). - SoftwareDeploymentTools, - - /// [Exploitation of Remote Services](https://attack.mitre.org/techniques/T1210) - /// - /// Adversaries may exploit remote services to gain unauthorized access to internal systems once inside of a network. Exploitation of a software vulnerability occurs when an adversary takes advantage of a programming error in a program, service, or within the operating system software or kernel itself to execute adversary-controlled code. A common goal for post-compromise exploitation of remote services is for lateral movement to enable access to a remote system. - ExploitationOfRemoteServices, - - /// [Internal Spearphishing](https://attack.mitre.org/techniques/T1534) - /// - /// Adversaries may use internal spearphishing to gain access to additional information or exploit other users within the same organization after they already have access to accounts or systems within the environment. Internal spearphishing is multi-staged campaign where an email account is owned either by controlling the user's device with previously installed malware or by compromising the account credentials of the user. Adversaries attempt to take advantage of a trusted internal account to increase the likelihood of tricking the target into falling for the phish attempt.(Citation: Trend Micro When Phishing Starts from the Inside 2017) - InternalSpearphishing, - - /// [Lateral Tool Transfer](https://attack.mitre.org/techniques/T1570) - /// - /// Adversaries may transfer tools or other files between systems in a compromised environment. Once brought into the victim environment (i.e., [Ingress Tool Transfer](https://attack.mitre.org/techniques/T1105)) files may then be copied from one system to another to stage adversary tools or other files over the course of an operation. - LateralToolTransfer, - -} -/// [Defense Evasion](https://attack.mitre.org/tactics/TA0005)'s techniques -pub enum DefenseEvasion { - /// [Direct Volume Access](https://attack.mitre.org/techniques/T1006) - /// - /// Adversaries may directly access a volume to bypass file access controls and file system monitoring. Windows allows programs to have direct access to logical volumes. Programs with direct access may read and write files directly from the drive by analyzing file system data structures. This technique may bypass Windows file access controls as well as file system monitoring tools. (Citation: Hakobyan 2009) - DirectVolumeAccess, - - /// [Rootkit](https://attack.mitre.org/techniques/T1014) - /// - /// Adversaries may use rootkits to hide the presence of programs, files, network connections, services, drivers, and other system components. Rootkits are programs that hide the existence of malware by intercepting/hooking and modifying operating system API calls that supply system information. (Citation: Symantec Windows Rootkits) - Rootkit, - - /// [Modify Cloud Compute Infrastructure](https://attack.mitre.org/techniques/T1578) - /// - /// An adversary may attempt to modify a cloud account's compute service infrastructure to evade defenses. A modification to the compute service infrastructure can include the creation, deletion, or modification of one or more components such as compute instances, virtual machines, and snapshots. - ModifyCloudComputeInfrastructure, - - /// [Weaken Encryption](https://attack.mitre.org/techniques/T1600) - /// - /// Adversaries may compromise a network device’s encryption capability in order to bypass encryption that would otherwise protect data communications. (Citation: Cisco Synful Knock Evolution) - WeakenEncryption, - - /// [Hide Artifacts](https://attack.mitre.org/techniques/T1564) - /// - /// Adversaries may attempt to hide artifacts associated with their behaviors to evade detection. Operating systems may have features to hide various artifacts, such as important system files and administrative task execution, to avoid disrupting user work environments and prevent users from changing files or features on the system. Adversaries may abuse these features to hide artifacts such as files, directories, user accounts, or other system activity to evade detection.(Citation: Sofacy Komplex Trojan)(Citation: Cybereason OSX Pirrit)(Citation: MalwareBytes ADS July 2015) - HideArtifacts, - - /// [Indirect Command Execution](https://attack.mitre.org/techniques/T1202) - /// - /// Adversaries may abuse utilities that allow for command execution to bypass security restrictions that limit the use of command-line interpreters. Various Windows utilities may be used to execute commands, possibly without invoking [cmd](https://attack.mitre.org/software/S0106). For example, [Forfiles](https://attack.mitre.org/software/S0193), the Program Compatibility Assistant (pcalua.exe), components of the Windows Subsystem for Linux (WSL), as well as other utilities may invoke the execution of programs and commands from a [Command and Scripting Interpreter](https://attack.mitre.org/techniques/T1059), Run window, or via scripts. (Citation: VectorSec ForFiles Aug 2017) (Citation: Evi1cg Forfiles Nov 2017) - IndirectCommandExecution, - - /// [Deobfuscate/Decode Files or Information](https://attack.mitre.org/techniques/T1140) - /// - /// Adversaries may use [Obfuscated Files or Information](https://attack.mitre.org/techniques/T1027) to hide artifacts of an intrusion from analysis. They may require separate mechanisms to decode or deobfuscate that information depending on how they intend to use it. Methods for doing that include built-in functionality of malware or by using utilities present on the system. - DeobfuscateDecodeFilesOrInformation, - - /// [Impair Defenses](https://attack.mitre.org/techniques/T1562) - /// - /// Adversaries may maliciously modify components of a victim environment in order to hinder or disable defensive mechanisms. This not only involves impairing preventative defenses, such as firewalls and anti-virus, but also detection capabilities that defenders can use to audit activity and identify malicious behavior. This may also span both native defenses as well as supplemental capabilities installed by users and administrators. - ImpairDefenses, - - /// [Masquerading](https://attack.mitre.org/techniques/T1036) - /// - /// Adversaries may attempt to manipulate features of their artifacts to make them appear legitimate or benign to users and/or security tools. Masquerading occurs when the name or location of an object, legitimate or malicious, is manipulated or abused for the sake of evading defenses and observation. This may include manipulating file metadata, tricking users into misidentifying the file type, and giving legitimate task or service names. - Masquerading, - - /// [Process Injection](https://attack.mitre.org/techniques/T1055) - /// - /// Adversaries may inject code into processes in order to evade process-based defenses as well as possibly elevate privileges. Process injection is a method of executing arbitrary code in the address space of a separate live process. Running code in the context of another process may allow access to the process's memory, system/network resources, and possibly elevated privileges. Execution via process injection may also evade detection from security products since the execution is masked under a legitimate process. - ProcessInjection, - - /// [Traffic Signaling](https://attack.mitre.org/techniques/T1205) - /// - /// Adversaries may use traffic signaling to hide open ports or other malicious functionality used for persistence or command and control. Traffic signaling involves the use of a magic value or sequence that must be sent to a system to trigger a special response, such as opening a closed port or executing a malicious task. This may take the form of sending a series of packets with certain characteristics before a port will be opened that the adversary can use for command and control. Usually this series of packets consists of attempted connections to a predefined sequence of closed ports (i.e. [Port Knocking](https://attack.mitre.org/techniques/T1205/001)), but can involve unusual flags, specific strings, or other unique characteristics. After the sequence is completed, opening a port may be accomplished by the host-based firewall, but could also be implemented by custom software. - TrafficSignaling, - - /// [System Binary Proxy Execution](https://attack.mitre.org/techniques/T1218) - /// - /// Adversaries may bypass process and/or signature-based defenses by proxying execution of malicious content with signed, or otherwise trusted, binaries. Binaries used in this technique are often Microsoft-signed files, indicating that they have been either downloaded from Microsoft or are already native in the operating system.(Citation: LOLBAS Project) Binaries signed with trusted digital certificates can typically execute on Windows systems protected by digital signature validation. Several Microsoft signed binaries that are default on Windows installations can be used to proxy execution of other files or commands. - SystemBinaryProxyExecution, - - /// [Reflective Code Loading](https://attack.mitre.org/techniques/T1620) - /// - /// Adversaries may reflectively load code into a process in order to conceal the execution of malicious payloads. Reflective loading involves allocating then executing payloads directly within the memory of the process, vice creating a thread or process backed by a file path on disk. Reflectively loaded payloads may be compiled binaries, anonymous files (only present in RAM), or just snubs of fileless executable code (ex: position-independent shellcode).(Citation: Introducing Donut)(Citation: S1 Custom Shellcode Tool)(Citation: Stuart ELF Memory)(Citation: 00sec Droppers)(Citation: Mandiant BYOL) - ReflectiveCodeLoading, - - /// [Use Alternate Authentication Material](https://attack.mitre.org/techniques/T1550) - /// - /// Adversaries may use alternate authentication material, such as password hashes, Kerberos tickets, and application access tokens, in order to move laterally within an environment and bypass normal system access controls. - UseAlternateAuthenticationMaterial, - - /// [Rogue Domain Controller](https://attack.mitre.org/techniques/T1207) - /// - /// Adversaries may register a rogue Domain Controller to enable manipulation of Active Directory data. DCShadow may be used to create a rogue Domain Controller (DC). DCShadow is a method of manipulating Active Directory (AD) data, including objects and schemas, by registering (or reusing an inactive registration) and simulating the behavior of a DC. (Citation: DCShadow Blog) Once registered, a rogue DC may be able to inject and replicate changes into AD infrastructure for any domain object, including credentials and keys. - RogueDomainController, - - /// [Deploy Container](https://attack.mitre.org/techniques/T1610) - /// - /// Adversaries may deploy a container into an environment to facilitate execution or evade defenses. In some cases, adversaries may deploy a new container to execute processes associated with a particular image or deployment, such as processes that execute or download malware. In others, an adversary may deploy a new container configured without network rules, user limitations, etc. to bypass existing defenses within the environment. - DeployContainer, - - /// [Modify Registry](https://attack.mitre.org/techniques/T1112) - /// - /// Adversaries may interact with the Windows Registry to hide configuration information within Registry keys, remove information as part of cleaning up, or as part of other techniques to aid in persistence and execution. - ModifyRegistry, - - /// [Unused/Unsupported Cloud Regions](https://attack.mitre.org/techniques/T1535) - /// - /// Adversaries may create cloud instances in unused geographic service regions in order to evade detection. Access is usually obtained through compromising accounts used to manage cloud infrastructure. - UnusedUnsupportedCloudRegions, - - /// [File and Directory Permissions Modification](https://attack.mitre.org/techniques/T1222) - /// - /// Adversaries may modify file or directory permissions/attributes to evade access control lists (ACLs) and access protected files.(Citation: Hybrid Analysis Icacls1 June 2018)(Citation: Hybrid Analysis Icacls2 May 2018) File and directory permissions are commonly managed by ACLs configured by the file or directory owner, or users with the appropriate permissions. File and directory ACL implementations vary by platform, but generally explicitly designate which users or groups can perform which actions (read, write, execute, etc.). - FileAndDirectoryPermissionsModification, - - /// [Abuse Elevation Control Mechanism](https://attack.mitre.org/techniques/T1548) - /// - /// Adversaries may circumvent mechanisms designed to control elevate privileges to gain higher-level permissions. Most modern systems contain native elevation control mechanisms that are intended to limit privileges that a user can perform on a machine. Authorization has to be granted to specific users in order to perform tasks that can be considered of higher risk. An adversary can perform several methods to take advantage of built-in control mechanisms in order to escalate privileges on a system. - AbuseElevationControlMechanism, - - /// [Indicator Removal](https://attack.mitre.org/techniques/T1070) - /// - /// Adversaries may delete or modify artifacts generated within systems to remove evidence of their presence or hinder defenses. Various artifacts may be created by an adversary or something that can be attributed to an adversary’s actions. Typically these artifacts are used as defensive indicators related to monitored events, such as strings from downloaded files, logs that are generated from user actions, and other data analyzed by defenders. Location, format, and type of artifact (such as command or login history) are often specific to each platform. - IndicatorRemoval, - - /// [Plist File Modification](https://attack.mitre.org/techniques/T1647) - /// - /// Adversaries may modify property list files (plist files) to enable other malicious activity, while also potentially evading and bypassing system defenses. macOS applications use plist files, such as the info.plist file, to store properties and configuration settings that inform the operating system how to handle the application at runtime. Plist files are structured metadata in key-value pairs formatted in XML based on Apple's Core Foundation DTD. Plist files can be saved in text or binary format.(Citation: fileinfo plist file description) - PlistFileModification, - - /// [Pre-OS Boot](https://attack.mitre.org/techniques/T1542) - /// - /// Adversaries may abuse Pre-OS Boot mechanisms as a way to establish persistence on a system. During the booting process of a computer, firmware and various startup services are loaded before the operating system. These programs control flow of execution before the operating system takes control.(Citation: Wikipedia Booting) - PreOsBoot, - - /// [Build Image on Host](https://attack.mitre.org/techniques/T1612) - /// - /// Adversaries may build a container image directly on a host to bypass defenses that monitor for the retrieval of malicious images from a public registry. A remote build request may be sent to the Docker API that includes a Dockerfile that pulls a vanilla base image, such as alpine, from a public or local registry and then builds a custom image upon it.(Citation: Docker Build Image) - BuildImageOnHost, - - /// [Virtualization/Sandbox Evasion](https://attack.mitre.org/techniques/T1497) - /// - /// Adversaries may employ various means to detect and avoid virtualization and analysis environments. This may include changing behaviors based on the results of checks for the presence of artifacts indicative of a virtual machine environment (VME) or sandbox. If the adversary detects a VME, they may alter their malware to disengage from the victim or conceal the core functions of the implant. They may also search for VME artifacts before dropping secondary or additional payloads. Adversaries may use the information learned from [Virtualization/Sandbox Evasion](https://attack.mitre.org/techniques/T1497) during automated discovery to shape follow-on behaviors.(Citation: Deloitte Environment Awareness) - VirtualizationSandboxEvasion, - - /// [Execution Guardrails](https://attack.mitre.org/techniques/T1480) - /// - /// Adversaries may use execution guardrails to constrain execution or actions based on adversary supplied and environment specific conditions that are expected to be present on the target. Guardrails ensure that a payload only executes against an intended target and reduces collateral damage from an adversary’s campaign.(Citation: FireEye Kevin Mandia Guardrails) Values an adversary can provide about a target system or environment to use as guardrails may include specific network share names, attached physical devices, files, joined Active Directory (AD) domains, and local/external IP addresses.(Citation: FireEye Outlook Dec 2019) - ExecutionGuardrails, - - /// [Modify System Image](https://attack.mitre.org/techniques/T1601) - /// - /// Adversaries may make changes to the operating system of embedded network devices to weaken defenses and provide new capabilities for themselves. On such devices, the operating systems are typically monolithic and most of the device functionality and capabilities are contained within a single file. - ModifySystemImage, - - /// [Hijack Execution Flow](https://attack.mitre.org/techniques/T1574) - /// - /// Adversaries may execute their own malicious payloads by hijacking the way operating systems run programs. Hijacking execution flow can be for the purposes of persistence, since this hijacked execution may reoccur over time. Adversaries may also use these mechanisms to elevate privileges or evade defenses, such as application control or other restrictions on execution. - HijackExecutionFlow, - - /// [Valid Accounts](https://attack.mitre.org/techniques/T1078) - /// - /// Adversaries may obtain and abuse credentials of existing accounts as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Compromised credentials may be used to bypass access controls placed on various resources on systems within the network and may even be used for persistent access to remote systems and externally available services, such as VPNs, Outlook Web Access, network devices, and remote desktop.(Citation: volexity_0day_sophos_FW) Compromised credentials may also grant an adversary increased privilege to specific systems or access to restricted areas of the network. Adversaries may choose not to use malware or tools in conjunction with the legitimate access those credentials provide to make it harder to detect their presence. - ValidAccounts, - - /// [Obfuscated Files or Information](https://attack.mitre.org/techniques/T1027) - /// - /// Adversaries may attempt to make an executable or file difficult to discover or analyze by encrypting, encoding, or otherwise obfuscating its contents on the system or in transit. This is common behavior that can be used across different platforms and the network to evade defenses. - ObfuscatedFilesOrInformation, - - /// [Network Boundary Bridging](https://attack.mitre.org/techniques/T1599) - /// - /// Adversaries may bridge network boundaries by compromising perimeter network devices or internal devices responsible for network segmentation. Breaching these devices may enable an adversary to bypass restrictions on traffic routing that otherwise separate trusted and untrusted networks. - NetworkBoundaryBridging, - - /// [Subvert Trust Controls](https://attack.mitre.org/techniques/T1553) - /// - /// Adversaries may undermine security controls that will either warn users of untrusted activity or prevent execution of untrusted programs. Operating systems and security products may contain mechanisms to identify programs or websites as possessing some level of trust. Examples of such features would include a program being allowed to run because it is signed by a valid code signing certificate, a program prompting the user with a warning because it has an attribute set from being downloaded from the Internet, or getting an indication that you are about to connect to an untrusted site. - SubvertTrustControls, - - /// [BITS Jobs](https://attack.mitre.org/techniques/T1197) - /// - /// Adversaries may abuse BITS jobs to persistently execute code and perform various background tasks. Windows Background Intelligent Transfer Service (BITS) is a low-bandwidth, asynchronous file transfer mechanism exposed through [Component Object Model](https://attack.mitre.org/techniques/T1559/001) (COM).(Citation: Microsoft COM)(Citation: Microsoft BITS) BITS is commonly used by updaters, messengers, and other applications preferred to operate in the background (using available idle bandwidth) without interrupting other networked applications. File transfer tasks are implemented as BITS jobs, which contain a queue of one or more file operations. - BitsJobs, - - /// [Impersonation](https://attack.mitre.org/techniques/T1656) - /// - /// Adversaries may impersonate a trusted person or organization in order to persuade and trick a target into performing some action on their behalf. For example, adversaries may communicate with victims (via [Phishing for Information](https://attack.mitre.org/techniques/T1598), [Phishing](https://attack.mitre.org/techniques/T1566), or [Internal Spearphishing](https://attack.mitre.org/techniques/T1534)) while impersonating a known sender such as an executive, colleague, or third-party vendor. Established trust can then be leveraged to accomplish an adversary’s ultimate goals, possibly against multiple victims. - Impersonation, - - /// [Template Injection](https://attack.mitre.org/techniques/T1221) - /// - /// Adversaries may create or modify references in user document templates to conceal malicious code or force authentication attempts. For example, Microsoft’s Office Open XML (OOXML) specification defines an XML-based format for Office documents (.docx, xlsx, .pptx) to replace older binary formats (.doc, .xls, .ppt). OOXML files are packed together ZIP archives compromised of various XML files, referred to as parts, containing properties that collectively define how a document is rendered.(Citation: Microsoft Open XML July 2017) - TemplateInjection, - - /// [Access Token Manipulation](https://attack.mitre.org/techniques/T1134) - /// - /// Adversaries may modify access tokens to operate under a different user or system security context to perform actions and bypass access controls. Windows uses access tokens to determine the ownership of a running process. A user can manipulate access tokens to make a running process appear as though it is the child of a different process or belongs to someone other than the user that started the process. When this occurs, the process also takes on the security context associated with the new token. - AccessTokenManipulation, - - /// [Debugger Evasion](https://attack.mitre.org/techniques/T1622) - /// - /// Adversaries may employ various means to detect and avoid debuggers. Debuggers are typically used by defenders to trace and/or analyze the execution of potential malware payloads.(Citation: ProcessHacker Github) - DebuggerEvasion, - - /// [Domain Policy Modification](https://attack.mitre.org/techniques/T1484) - /// - /// Adversaries may modify the configuration settings of a domain to evade defenses and/or escalate privileges in domain environments. Domains provide a centralized means of managing how computer resources (ex: computers, user accounts) can act, and interact with each other, on a network. The policy of the domain also includes configuration settings that may apply between domains in a multi-domain/forest environment. Modifications to domain settings may include altering domain Group Policy Objects (GPOs) or changing trust settings for domains, including federation trusts. - DomainPolicyModification, - - /// [XSL Script Processing](https://attack.mitre.org/techniques/T1220) - /// - /// Adversaries may bypass application control and obscure execution of code by embedding scripts inside XSL files. Extensible Stylesheet Language (XSL) files are commonly used to describe the processing and rendering of data within XML files. To support complex operations, the XSL standard includes support for embedded scripting in various languages. (Citation: Microsoft XSLT Script Mar 2017) - XslScriptProcessing, - - /// [Modify Authentication Process](https://attack.mitre.org/techniques/T1556) - /// - /// Adversaries may modify authentication mechanisms and processes to access user credentials or enable otherwise unwarranted access to accounts. The authentication process is handled by mechanisms, such as the Local Security Authentication Server (LSASS) process and the Security Accounts Manager (SAM) on Windows, pluggable authentication modules (PAM) on Unix-based systems, and authorization plugins on MacOS systems, responsible for gathering, storing, and validating credentials. By modifying an authentication process, an adversary may be able to authenticate to a service or system without using [Valid Accounts](https://attack.mitre.org/techniques/T1078). - ModifyAuthenticationProcess, - - /// [System Script Proxy Execution](https://attack.mitre.org/techniques/T1216) - /// - /// Adversaries may use trusted scripts, often signed with certificates, to proxy the execution of malicious files. Several Microsoft signed scripts that have been downloaded from Microsoft or are default on Windows installations can be used to proxy execution of other files.(Citation: LOLBAS Project) This behavior may be abused by adversaries to execute malicious files that could bypass application control and signature validation on systems.(Citation: GitHub Ultimate AppLocker Bypass List) - SystemScriptProxyExecution, - - /// [Exploitation for Defense Evasion](https://attack.mitre.org/techniques/T1211) - /// - /// Adversaries may exploit a system or application vulnerability to bypass security features. Exploitation of a vulnerability occurs when an adversary takes advantage of a programming error in a program, service, or within the operating system software or kernel itself to execute adversary-controlled code. Vulnerabilities may exist in defensive security software that can be used to disable or circumvent them. - ExploitationForDefenseEvasion, - - /// [Trusted Developer Utilities Proxy Execution](https://attack.mitre.org/techniques/T1127) - /// - /// Adversaries may take advantage of trusted developer utilities to proxy execution of malicious payloads. There are many utilities used for software development related tasks that can be used to execute code in various forms to assist in development, debugging, and reverse engineering.(Citation: engima0x3 DNX Bypass)(Citation: engima0x3 RCSI Bypass)(Citation: Exploit Monday WinDbg)(Citation: LOLBAS Tracker) These utilities may often be signed with legitimate certificates that allow them to execute on a system and proxy execution of malicious code through a trusted process that effectively bypasses application control solutions. - TrustedDeveloperUtilitiesProxyExecution, - -} -/// [Exfiltration](https://attack.mitre.org/tactics/TA0010)'s techniques -pub enum Exfiltration { - /// [Exfiltration Over Web Service](https://attack.mitre.org/techniques/T1567) - /// - /// Adversaries may use an existing, legitimate external Web service to exfiltrate data rather than their primary command and control channel. Popular Web services acting as an exfiltration mechanism may give a significant amount of cover due to the likelihood that hosts within a network are already communicating with them prior to compromise. Firewall rules may also already exist to permit traffic to these services. - ExfiltrationOverWebService, - - /// [Scheduled Transfer](https://attack.mitre.org/techniques/T1029) - /// - /// Adversaries may schedule data exfiltration to be performed only at certain times of day or at certain intervals. This could be done to blend traffic patterns with normal activity or availability. - ScheduledTransfer, - - /// [Exfiltration Over Other Network Medium](https://attack.mitre.org/techniques/T1011) - /// - /// Adversaries may attempt to exfiltrate data over a different network medium than the command and control channel. If the command and control network is a wired Internet connection, the exfiltration may occur, for example, over a WiFi connection, modem, cellular data connection, Bluetooth, or another radio frequency (RF) channel. - ExfiltrationOverOtherNetworkMedium, - - /// [Automated Exfiltration](https://attack.mitre.org/techniques/T1020) - /// - /// Adversaries may exfiltrate data, such as sensitive documents, through the use of automated processing after being gathered during Collection. - AutomatedExfiltration, - - /// [Exfiltration Over C2 Channel](https://attack.mitre.org/techniques/T1041) - /// - /// Adversaries may steal data by exfiltrating it over an existing command and control channel. Stolen data is encoded into the normal communications channel using the same protocol as command and control communications. - ExfiltrationOverC2Channel, - - /// [Exfiltration Over Alternative Protocol](https://attack.mitre.org/techniques/T1048) - /// - /// Adversaries may steal data by exfiltrating it over a different protocol than that of the existing command and control channel. The data may also be sent to an alternate network location from the main command and control server. - ExfiltrationOverAlternativeProtocol, - - /// [Data Transfer Size Limits](https://attack.mitre.org/techniques/T1030) - /// - /// An adversary may exfiltrate data in fixed size chunks instead of whole files or limit packet sizes below certain thresholds. This approach may be used to avoid triggering network data transfer threshold alerts. - DataTransferSizeLimits, - - /// [Transfer Data to Cloud Account](https://attack.mitre.org/techniques/T1537) - /// - /// Adversaries may exfiltrate data by transferring the data, including backups of cloud environments, to another cloud account they control on the same service to avoid typical file transfers/downloads and network-based exfiltration detection. - TransferDataToCloudAccount, - - /// [Exfiltration Over Physical Medium](https://attack.mitre.org/techniques/T1052) - /// - /// Adversaries may attempt to exfiltrate data via a physical medium, such as a removable drive. In certain circumstances, such as an air-gapped network compromise, exfiltration could occur via a physical medium or device introduced by a user. Such media could be an external hard drive, USB drive, cellular phone, MP3 player, or other removable storage and processing device. The physical medium or device could be used as the final exfiltration point or to hop between otherwise disconnected systems. - ExfiltrationOverPhysicalMedium, - -} -/// [Discovery](https://attack.mitre.org/tactics/TA0007)'s techniques -pub enum Discovery { - /// [System Owner/User Discovery](https://attack.mitre.org/techniques/T1033) - /// - /// Adversaries may attempt to identify the primary user, currently logged in user, set of users that commonly uses a system, or whether a user is actively using the system. They may do this, for example, by retrieving account usernames or by using [OS Credential Dumping](https://attack.mitre.org/techniques/T1003). The information may be collected in a number of different ways using other Discovery techniques, because user and username details are prevalent throughout a system and include running process ownership, file/directory ownership, session information, and system logs. Adversaries may use the information from [System Owner/User Discovery](https://attack.mitre.org/techniques/T1033) during automated discovery to shape follow-on behaviors, including whether or not the adversary fully infects the target and/or attempts specific actions. - SystemOwnerUserDiscovery, - - /// [Container and Resource Discovery](https://attack.mitre.org/techniques/T1613) - /// - /// Adversaries may attempt to discover containers and other resources that are available within a containers environment. Other resources may include images, deployments, pods, nodes, and other information such as the status of a cluster. - ContainerAndResourceDiscovery, - - /// [Permission Groups Discovery](https://attack.mitre.org/techniques/T1069) - /// - /// Adversaries may attempt to discover group and permission settings. This information can help adversaries determine which user accounts and groups are available, the membership of users in particular groups, and which users and groups have elevated permissions. - PermissionGroupsDiscovery, - - /// [Group Policy Discovery](https://attack.mitre.org/techniques/T1615) - /// - /// Adversaries may gather information on Group Policy settings to identify paths for privilege escalation, security measures applied within a domain, and to discover patterns in domain objects that can be manipulated or used to blend in the environment. Group Policy allows for centralized management of user and computer settings in Active Directory (AD). Group policy objects (GPOs) are containers for group policy settings made up of files stored within a predictable network path `\\SYSVOL\\Policies\`.(Citation: TechNet Group Policy Basics)(Citation: ADSecurity GPO Persistence 2016) - GroupPolicyDiscovery, - - /// [Device Driver Discovery](https://attack.mitre.org/techniques/T1652) - /// - /// Adversaries may attempt to enumerate local device drivers on a victim host. Information about device drivers may highlight various insights that shape follow-on behaviors, such as the function/purpose of the host, present security tools (i.e. [Security Software Discovery](https://attack.mitre.org/techniques/T1518/001)) or other defenses (e.g., [Virtualization/Sandbox Evasion](https://attack.mitre.org/techniques/T1497)), as well as potential exploitable vulnerabilities (e.g., [Exploitation for Privilege Escalation](https://attack.mitre.org/techniques/T1068)). - DeviceDriverDiscovery, - - /// [System Service Discovery](https://attack.mitre.org/techniques/T1007) - /// - /// Adversaries may try to gather information about registered local system services. Adversaries may obtain information about services using tools as well as OS utility commands such as sc query, tasklist /svc, systemctl --type=service, and net start. - SystemServiceDiscovery, - - /// [Network Sniffing](https://attack.mitre.org/techniques/T1040) - /// - /// Adversaries may sniff network traffic to capture information about an environment, including authentication material passed over the network. Network sniffing refers to using the network interface on a system to monitor or capture information sent over a wired or wireless connection. An adversary may place a network interface into promiscuous mode to passively access data in transit over the network, or use span ports to capture a larger amount of data. - NetworkSniffing, - - /// [Network Share Discovery](https://attack.mitre.org/techniques/T1135) - /// - /// Adversaries may look for folders and drives shared on remote systems as a means of identifying sources of information to gather as a precursor for Collection and to identify potential systems of interest for Lateral Movement. Networks often contain shared network drives and folders that enable users to access file directories on various systems across a network. - NetworkShareDiscovery, - - /// [Peripheral Device Discovery](https://attack.mitre.org/techniques/T1120) - /// - /// Adversaries may attempt to gather information about attached peripheral devices and components connected to a computer system.(Citation: Peripheral Discovery Linux)(Citation: Peripheral Discovery macOS) Peripheral devices could include auxiliary resources that support a variety of functionalities such as keyboards, printers, cameras, smart card readers, or removable storage. The information may be used to enhance their awareness of the system and network environment or may be used for further actions. - PeripheralDeviceDiscovery, - - /// [System Information Discovery](https://attack.mitre.org/techniques/T1082) - /// - /// An adversary may attempt to get detailed information about the operating system and hardware, including version, patches, hotfixes, service packs, and architecture. Adversaries may use the information from [System Information Discovery](https://attack.mitre.org/techniques/T1082) during automated discovery to shape follow-on behaviors, including whether or not the adversary fully infects the target and/or attempts specific actions. - SystemInformationDiscovery, - - /// [Application Window Discovery](https://attack.mitre.org/techniques/T1010) - /// - /// Adversaries may attempt to get a listing of open application windows. Window listings could convey information about how the system is used.(Citation: Prevailion DarkWatchman 2021) For example, information about application windows could be used identify potential data to collect as well as identifying security tooling ([Security Software Discovery](https://attack.mitre.org/techniques/T1518/001)) to evade.(Citation: ESET Grandoreiro April 2020) - ApplicationWindowDiscovery, - - /// [Cloud Infrastructure Discovery](https://attack.mitre.org/techniques/T1580) - /// - /// An adversary may attempt to discover infrastructure and resources that are available within an infrastructure-as-a-service (IaaS) environment. This includes compute service resources such as instances, virtual machines, and snapshots as well as resources of other services including the storage and database services. - CloudInfrastructureDiscovery, - - /// [Browser Information Discovery](https://attack.mitre.org/techniques/T1217) - /// - /// Adversaries may enumerate information about browsers to learn more about compromised environments. Data saved by browsers (such as bookmarks, accounts, and browsing history) may reveal a variety of personal information about users (e.g., banking sites, relationships/interests, social media, etc.) as well as details about internal network resources such as servers, tools/dashboards, or other related infrastructure.(Citation: Kaspersky Autofill) - BrowserInformationDiscovery, - - /// [System Network Configuration Discovery](https://attack.mitre.org/techniques/T1016) - /// - /// Adversaries may look for details about the network configuration and settings, such as IP and/or MAC addresses, of systems they access or through information discovery of remote systems. Several operating system administration utilities exist that can be used to gather this information. Examples include [Arp](https://attack.mitre.org/software/S0099), [ipconfig](https://attack.mitre.org/software/S0100)/[ifconfig](https://attack.mitre.org/software/S0101), [nbtstat](https://attack.mitre.org/software/S0102), and [route](https://attack.mitre.org/software/S0103). - SystemNetworkConfigurationDiscovery, - - /// [Account Discovery](https://attack.mitre.org/techniques/T1087) - /// - /// Adversaries may attempt to get a listing of valid accounts, usernames, or email addresses on a system or within a compromised environment. This information can help adversaries determine which accounts exist, which can aid in follow-on behavior such as brute-forcing, spear-phishing attacks, or account takeovers (e.g., [Valid Accounts](https://attack.mitre.org/techniques/T1078)). - AccountDiscovery, - - /// [Domain Trust Discovery](https://attack.mitre.org/techniques/T1482) - /// - /// Adversaries may attempt to gather information on domain trust relationships that may be used to identify lateral movement opportunities in Windows multi-domain/forest environments. Domain trusts provide a mechanism for a domain to allow access to resources based on the authentication procedures of another domain.(Citation: Microsoft Trusts) Domain trusts allow the users of the trusted domain to access resources in the trusting domain. The information discovered may help the adversary conduct [SID-History Injection](https://attack.mitre.org/techniques/T1134/005), [Pass the Ticket](https://attack.mitre.org/techniques/T1550/003), and [Kerberoasting](https://attack.mitre.org/techniques/T1558/003).(Citation: AdSecurity Forging Trust Tickets)(Citation: Harmj0y Domain Trusts) Domain trusts can be enumerated using the `DSEnumerateDomainTrusts()` Win32 API call, .NET methods, and LDAP.(Citation: Harmj0y Domain Trusts) The Windows utility [Nltest](https://attack.mitre.org/software/S0359) is known to be used by adversaries to enumerate domain trusts.(Citation: Microsoft Operation Wilysupply) - DomainTrustDiscovery, - - /// [File and Directory Discovery](https://attack.mitre.org/techniques/T1083) - /// - /// Adversaries may enumerate files and directories or may search in specific locations of a host or network share for certain information within a file system. Adversaries may use the information from [File and Directory Discovery](https://attack.mitre.org/techniques/T1083) during automated discovery to shape follow-on behaviors, including whether or not the adversary fully infects the target and/or attempts specific actions. - FileAndDirectoryDiscovery, - - /// [System Network Connections Discovery](https://attack.mitre.org/techniques/T1049) - /// - /// Adversaries may attempt to get a listing of network connections to or from the compromised system they are currently accessing or from remote systems by querying for information over the network. - SystemNetworkConnectionsDiscovery, - - /// [Virtualization/Sandbox Evasion](https://attack.mitre.org/techniques/T1497) - /// - /// Adversaries may employ various means to detect and avoid virtualization and analysis environments. This may include changing behaviors based on the results of checks for the presence of artifacts indicative of a virtual machine environment (VME) or sandbox. If the adversary detects a VME, they may alter their malware to disengage from the victim or conceal the core functions of the implant. They may also search for VME artifacts before dropping secondary or additional payloads. Adversaries may use the information learned from [Virtualization/Sandbox Evasion](https://attack.mitre.org/techniques/T1497) during automated discovery to shape follow-on behaviors.(Citation: Deloitte Environment Awareness) - VirtualizationSandboxEvasion, - - /// [Cloud Storage Object Discovery](https://attack.mitre.org/techniques/T1619) - /// - /// Adversaries may enumerate objects in cloud storage infrastructure. Adversaries may use this information during automated discovery to shape follow-on behaviors, including requesting all or specific objects from cloud storage. Similar to [File and Directory Discovery](https://attack.mitre.org/techniques/T1083) on a local host, after identifying available storage services (i.e. [Cloud Infrastructure Discovery](https://attack.mitre.org/techniques/T1580)) adversaries may access the contents/objects stored in cloud infrastructure. - CloudStorageObjectDiscovery, - - /// [Log Enumeration](https://attack.mitre.org/techniques/T1654) - /// - /// Adversaries may enumerate system and service logs to find useful data. These logs may highlight various types of valuable insights for an adversary, such as user authentication records ([Account Discovery](https://attack.mitre.org/techniques/T1087)), security or vulnerable software ([Software Discovery](https://attack.mitre.org/techniques/T1518)), or hosts within a compromised network ([Remote System Discovery](https://attack.mitre.org/techniques/T1018)). - LogEnumeration, - - /// [Process Discovery](https://attack.mitre.org/techniques/T1057) - /// - /// Adversaries may attempt to get information about running processes on a system. Information obtained could be used to gain an understanding of common software/applications running on systems within the network. Adversaries may use the information from [Process Discovery](https://attack.mitre.org/techniques/T1057) during automated discovery to shape follow-on behaviors, including whether or not the adversary fully infects the target and/or attempts specific actions. - ProcessDiscovery, - - /// [Password Policy Discovery](https://attack.mitre.org/techniques/T1201) - /// - /// Adversaries may attempt to access detailed information about the password policy used within an enterprise network or cloud environment. Password policies are a way to enforce complex passwords that are difficult to guess or crack through [Brute Force](https://attack.mitre.org/techniques/T1110). This information may help the adversary to create a list of common passwords and launch dictionary and/or brute force attacks which adheres to the policy (e.g. if the minimum password length should be 8, then not trying passwords such as 'pass123'; not checking for more than 3-4 passwords per account if the lockout is set to 6 as to not lock out accounts). - PasswordPolicyDiscovery, - - /// [Query Registry](https://attack.mitre.org/techniques/T1012) - /// - /// Adversaries may interact with the Windows Registry to gather information about the system, configuration, and installed software. - QueryRegistry, - - /// [System Location Discovery](https://attack.mitre.org/techniques/T1614) - /// - /// - SystemLocationDiscovery, - - /// [Cloud Service Discovery](https://attack.mitre.org/techniques/T1526) - /// - /// An adversary may attempt to enumerate the cloud services running on a system after gaining access. These methods can differ from platform-as-a-service (PaaS), to infrastructure-as-a-service (IaaS), or software-as-a-service (SaaS). Many services exist throughout the various cloud providers and can include Continuous Integration and Continuous Delivery (CI/CD), Lambda Functions, Azure AD, etc. They may also include security services, such as AWS GuardDuty and Microsoft Defender for Cloud, and logging services, such as AWS CloudTrail and Google Cloud Audit Logs. - CloudServiceDiscovery, - - /// [Remote System Discovery](https://attack.mitre.org/techniques/T1018) - /// - /// Adversaries may attempt to get a listing of other systems by IP address, hostname, or other logical identifier on a network that may be used for Lateral Movement from the current system. Functionality could exist within remote access tools to enable this, but utilities available on the operating system could also be used such as [Ping](https://attack.mitre.org/software/S0097) or net view using [Net](https://attack.mitre.org/software/S0039). - RemoteSystemDiscovery, - - /// [Network Service Discovery](https://attack.mitre.org/techniques/T1046) - /// - /// Adversaries may attempt to get a listing of services running on remote hosts and local network infrastructure devices, including those that may be vulnerable to remote software exploitation. Common methods to acquire this information include port and/or vulnerability scans using tools that are brought onto a system.(Citation: CISA AR21-126A FIVEHANDS May 2021) - NetworkServiceDiscovery, - - /// [Software Discovery](https://attack.mitre.org/techniques/T1518) - /// - /// Adversaries may attempt to get a listing of software and software versions that are installed on a system or in a cloud environment. Adversaries may use the information from [Software Discovery](https://attack.mitre.org/techniques/T1518) during automated discovery to shape follow-on behaviors, including whether or not the adversary fully infects the target and/or attempts specific actions. - SoftwareDiscovery, - - /// [Cloud Service Dashboard](https://attack.mitre.org/techniques/T1538) - /// - /// An adversary may use a cloud service dashboard GUI with stolen credentials to gain useful information from an operational cloud environment, such as specific services, resources, and features. For example, the GCP Command Center can be used to view all assets, findings of potential security risks, and to run additional queries, such as finding public IP addresses and open ports.(Citation: Google Command Center Dashboard) - CloudServiceDashboard, - - /// [Debugger Evasion](https://attack.mitre.org/techniques/T1622) - /// - /// Adversaries may employ various means to detect and avoid debuggers. Debuggers are typically used by defenders to trace and/or analyze the execution of potential malware payloads.(Citation: ProcessHacker Github) - DebuggerEvasion, - - /// [System Time Discovery](https://attack.mitre.org/techniques/T1124) - /// - /// An adversary may gather the system time and/or time zone from a local or remote system. The system time is set and stored by the Windows Time Service within a domain to maintain time synchronization between systems and services in an enterprise network. (Citation: MSDN System Time)(Citation: Technet Windows Time Service) - SystemTimeDiscovery, - -} -/// [Collection](https://attack.mitre.org/tactics/TA0009)'s techniques -pub enum Collection { - /// [Screen Capture](https://attack.mitre.org/techniques/T1113) - /// - /// Adversaries may attempt to take screen captures of the desktop to gather information over the course of an operation. Screen capturing functionality may be included as a feature of a remote access tool used in post-compromise operations. Taking a screenshot is also typically possible through native utilities or API calls, such as CopyFromScreen, xwd, or screencapture.(Citation: CopyFromScreen .NET)(Citation: Antiquated Mac Malware) - ScreenCapture, - - /// [Adversary-in-the-Middle](https://attack.mitre.org/techniques/T1557) - /// - /// Adversaries may attempt to position themselves between two or more networked devices using an adversary-in-the-middle (AiTM) technique to support follow-on behaviors such as [Network Sniffing](https://attack.mitre.org/techniques/T1040), [Transmitted Data Manipulation](https://attack.mitre.org/techniques/T1565/002), or replay attacks ([Exploitation for Credential Access](https://attack.mitre.org/techniques/T1212)). By abusing features of common networking protocols that can determine the flow of network traffic (e.g. ARP, DNS, LLMNR, etc.), adversaries may force a device to communicate through an adversary controlled system so they can collect information or perform additional actions.(Citation: Rapid7 MiTM Basics) - AdversaryInTheMiddle, - - /// [Data from Configuration Repository](https://attack.mitre.org/techniques/T1602) - /// - /// Adversaries may collect data related to managed devices from configuration repositories. Configuration repositories are used by management systems in order to configure, manage, and control data on remote systems. Configuration repositories may also facilitate remote access and administration of devices. - DataFromConfigurationRepository, - - /// [Audio Capture](https://attack.mitre.org/techniques/T1123) - /// - /// An adversary can leverage a computer's peripheral devices (e.g., microphones and webcams) or applications (e.g., voice and video call services) to capture audio recordings for the purpose of listening into sensitive conversations to gather information. - AudioCapture, - - /// [Email Collection](https://attack.mitre.org/techniques/T1114) - /// - /// Adversaries may target user email to collect sensitive information. Emails may contain sensitive data, including trade secrets or personal information, that can prove valuable to adversaries. Adversaries can collect or forward email from mail servers or clients. - EmailCollection, - - /// [Data from Removable Media](https://attack.mitre.org/techniques/T1025) - /// - /// Adversaries may search connected removable media on computers they have compromised to find files of interest. Sensitive data can be collected from any removable media (optical disk drive, USB memory, etc.) connected to the compromised system prior to Exfiltration. Interactive command shells may be in use, and common functionality within [cmd](https://attack.mitre.org/software/S0106) may be used to gather information. - DataFromRemovableMedia, - - /// [Automated Collection](https://attack.mitre.org/techniques/T1119) - /// - /// Once established within a system or network, an adversary may use automated techniques for collecting internal data. Methods for performing this technique could include use of a [Command and Scripting Interpreter](https://attack.mitre.org/techniques/T1059) to search for and copy information fitting set criteria such as file type, location, or name at specific time intervals. In cloud-based environments, adversaries may also use cloud APIs, command line interfaces, or extract, transform, and load (ETL) services to automatically collect data. This functionality could also be built into remote access tools. - AutomatedCollection, - - /// [Clipboard Data](https://attack.mitre.org/techniques/T1115) - /// - /// Adversaries may collect data stored in the clipboard from users copying information within or between applications. - ClipboardData, - - /// [Data from Cloud Storage](https://attack.mitre.org/techniques/T1530) - /// - /// Adversaries may access data from cloud storage. - DataFromCloudStorage, - - /// [Data from Local System](https://attack.mitre.org/techniques/T1005) - /// - /// Adversaries may search local system sources, such as file systems and configuration files or local databases, to find files of interest and sensitive data prior to Exfiltration. - DataFromLocalSystem, - - /// [Archive Collected Data](https://attack.mitre.org/techniques/T1560) - /// - /// An adversary may compress and/or encrypt data that is collected prior to exfiltration. Compressing the data can help to obfuscate the collected data and minimize the amount of data sent over the network. Encryption can be used to hide information that is being exfiltrated from detection or make exfiltration less conspicuous upon inspection by a defender. - ArchiveCollectedData, - - /// [Browser Session Hijacking](https://attack.mitre.org/techniques/T1185) - /// - /// Adversaries may take advantage of security vulnerabilities and inherent functionality in browser software to change content, modify user-behaviors, and intercept information as part of various browser session hijacking techniques.(Citation: Wikipedia Man in the Browser) - BrowserSessionHijacking, - - /// [Video Capture](https://attack.mitre.org/techniques/T1125) - /// - /// An adversary can leverage a computer's peripheral devices (e.g., integrated cameras or webcams) or applications (e.g., video call services) to capture video recordings for the purpose of gathering information. Images may also be captured from devices or applications, potentially in specified intervals, in lieu of video files. - VideoCapture, - - /// [Data Staged](https://attack.mitre.org/techniques/T1074) - /// - /// Adversaries may stage collected data in a central location or directory prior to Exfiltration. Data may be kept in separate files or combined into one file through techniques such as [Archive Collected Data](https://attack.mitre.org/techniques/T1560). Interactive command shells may be used, and common functionality within [cmd](https://attack.mitre.org/software/S0106) and bash may be used to copy data into a staging location.(Citation: PWC Cloud Hopper April 2017) - DataStaged, - - /// [Data from Network Shared Drive](https://attack.mitre.org/techniques/T1039) - /// - /// Adversaries may search network shares on computers they have compromised to find files of interest. Sensitive data can be collected from remote systems via shared network drives (host shared directory, network file server, etc.) that are accessible from the current system prior to Exfiltration. Interactive command shells may be in use, and common functionality within [cmd](https://attack.mitre.org/software/S0106) may be used to gather information. - DataFromNetworkSharedDrive, - - /// [Input Capture](https://attack.mitre.org/techniques/T1056) - /// - /// Adversaries may use methods of capturing user input to obtain credentials or collect information. During normal system usage, users often provide credentials to various different locations, such as login pages/portals or system dialog boxes. Input capture mechanisms may be transparent to the user (e.g. [Credential API Hooking](https://attack.mitre.org/techniques/T1056/004)) or rely on deceiving the user into providing input into what they believe to be a genuine service (e.g. [Web Portal Capture](https://attack.mitre.org/techniques/T1056/003)). - InputCapture, - - /// [Data from Information Repositories](https://attack.mitre.org/techniques/T1213) - /// - /// Adversaries may leverage information repositories to mine valuable information. Information repositories are tools that allow for storage of information, typically to facilitate collaboration or information sharing between users, and can store a wide variety of data that may aid adversaries in further objectives, or direct access to the target information. Adversaries may also abuse external sharing features to share sensitive documents with recipients outside of the organization. - DataFromInformationRepositories, - -} -/// [Resource Development](https://attack.mitre.org/tactics/TA0042)'s techniques -pub enum ResourceDevelopment { - /// [Acquire Infrastructure](https://attack.mitre.org/techniques/T1583) - /// - /// Adversaries may buy, lease, or rent infrastructure that can be used during targeting. A wide variety of infrastructure exists for hosting and orchestrating adversary operations. Infrastructure solutions include physical or cloud servers, domains, and third-party web services.(Citation: TrendmicroHideoutsLease) Additionally, botnets are available for rent or purchase. - AcquireInfrastructure, - - /// [Compromise Infrastructure](https://attack.mitre.org/techniques/T1584) - /// - /// Adversaries may compromise third-party infrastructure that can be used during targeting. Infrastructure solutions include physical or cloud servers, domains, and third-party web and DNS services. Instead of buying, leasing, or renting infrastructure an adversary may compromise infrastructure and use it during other phases of the adversary lifecycle.(Citation: Mandiant APT1)(Citation: ICANNDomainNameHijacking)(Citation: Talos DNSpionage Nov 2018)(Citation: FireEye EPS Awakens Part 2) Additionally, adversaries may compromise numerous machines to form a botnet they can leverage. - CompromiseInfrastructure, - - /// [Compromise Accounts](https://attack.mitre.org/techniques/T1586) - /// - /// Adversaries may compromise accounts with services that can be used during targeting. For operations incorporating social engineering, the utilization of an online persona may be important. Rather than creating and cultivating accounts (i.e. [Establish Accounts](https://attack.mitre.org/techniques/T1585)), adversaries may compromise existing accounts. Utilizing an existing persona may engender a level of trust in a potential victim if they have a relationship, or knowledge of, the compromised persona. - CompromiseAccounts, - - /// [Stage Capabilities](https://attack.mitre.org/techniques/T1608) - /// - /// Adversaries may upload, install, or otherwise set up capabilities that can be used during targeting. To support their operations, an adversary may need to take capabilities they developed ([Develop Capabilities](https://attack.mitre.org/techniques/T1587)) or obtained ([Obtain Capabilities](https://attack.mitre.org/techniques/T1588)) and stage them on infrastructure under their control. These capabilities may be staged on infrastructure that was previously purchased/rented by the adversary ([Acquire Infrastructure](https://attack.mitre.org/techniques/T1583)) or was otherwise compromised by them ([Compromise Infrastructure](https://attack.mitre.org/techniques/T1584)). Capabilities may also be staged on web services, such as GitHub or Pastebin, or on Platform-as-a-Service (PaaS) offerings that enable users to easily provision applications.(Citation: Volexity Ocean Lotus November 2020)(Citation: Dragos Heroku Watering Hole)(Citation: Malwarebytes Heroku Skimmers)(Citation: Netskope GCP Redirection)(Citation: Netskope Cloud Phishing) - StageCapabilities, - - /// [Establish Accounts](https://attack.mitre.org/techniques/T1585) - /// - /// Adversaries may create and cultivate accounts with services that can be used during targeting. Adversaries can create accounts that can be used to build a persona to further operations. Persona development consists of the development of public information, presence, history and appropriate affiliations. This development could be applied to social media, website, or other publicly available information that could be referenced and scrutinized for legitimacy over the course of an operation using that persona or identity.(Citation: NEWSCASTER2014)(Citation: BlackHatRobinSage) - EstablishAccounts, - - /// [Obtain Capabilities](https://attack.mitre.org/techniques/T1588) - /// - /// Adversaries may buy and/or steal capabilities that can be used during targeting. Rather than developing their own capabilities in-house, adversaries may purchase, freely download, or steal them. Activities may include the acquisition of malware, software (including licenses), exploits, certificates, and information relating to vulnerabilities. Adversaries may obtain capabilities to support their operations throughout numerous phases of the adversary lifecycle. - ObtainCapabilities, - - /// [Acquire Access](https://attack.mitre.org/techniques/T1650) - /// - /// Adversaries may purchase or otherwise acquire an existing access to a target system or network. A variety of online services and initial access broker networks are available to sell access to previously compromised systems.(Citation: Microsoft Ransomware as a Service)(Citation: CrowdStrike Access Brokers)(Citation: Krebs Access Brokers Fortune 500) In some cases, adversary groups may form partnerships to share compromised systems with each other.(Citation: CISA Karakurt 2022) - AcquireAccess, - - /// [Develop Capabilities](https://attack.mitre.org/techniques/T1587) - /// - /// Adversaries may build capabilities that can be used during targeting. Rather than purchasing, freely downloading, or stealing capabilities, adversaries may develop their own capabilities in-house. This is the process of identifying development requirements and building solutions such as malware, exploits, and self-signed certificates. Adversaries may develop capabilities to support their operations throughout numerous phases of the adversary lifecycle.(Citation: Mandiant APT1)(Citation: Kaspersky Sofacy)(Citation: Bitdefender StrongPity June 2020)(Citation: Talos Promethium June 2020) - DevelopCapabilities, - -} -/// [Reconnaissance](https://attack.mitre.org/tactics/TA0043)'s techniques -pub enum Reconnaissance { - /// [Gather Victim Host Information](https://attack.mitre.org/techniques/T1592) - /// - /// Adversaries may gather information about the victim's hosts that can be used during targeting. Information about hosts may include a variety of details, including administrative data (ex: name, assigned IP, functionality, etc.) as well as specifics regarding its configuration (ex: operating system, language, etc.). - GatherVictimHostInformation, - - /// [Search Victim-Owned Websites](https://attack.mitre.org/techniques/T1594) - /// - /// Adversaries may search websites owned by the victim for information that can be used during targeting. Victim-owned websites may contain a variety of details, including names of departments/divisions, physical locations, and data about key employees such as names, roles, and contact info (ex: [Email Addresses](https://attack.mitre.org/techniques/T1589/002)). These sites may also have details highlighting business operations and relationships.(Citation: Comparitech Leak) - SearchVictimOwnedWebsites, - - /// [Gather Victim Identity Information](https://attack.mitre.org/techniques/T1589) - /// - /// Adversaries may gather information about the victim's identity that can be used during targeting. Information about identities may include a variety of details, including personal data (ex: employee names, email addresses, etc.) as well as sensitive details such as credentials. - GatherVictimIdentityInformation, - - /// [Search Open Technical Databases](https://attack.mitre.org/techniques/T1596) - /// - /// Adversaries may search freely available technical databases for information about victims that can be used during targeting. Information about victims may be available in online databases and repositories, such as registrations of domains/certificates as well as public collections of network data/artifacts gathered from traffic and/or scans.(Citation: WHOIS)(Citation: DNS Dumpster)(Citation: Circl Passive DNS)(Citation: Medium SSL Cert)(Citation: SSLShopper Lookup)(Citation: DigitalShadows CDN)(Citation: Shodan) - SearchOpenTechnicalDatabases, - - /// [Active Scanning](https://attack.mitre.org/techniques/T1595) - /// - /// Adversaries may execute active reconnaissance scans to gather information that can be used during targeting. Active scans are those where the adversary probes victim infrastructure via network traffic, as opposed to other forms of reconnaissance that do not involve direct interaction. - ActiveScanning, - - /// [Gather Victim Org Information](https://attack.mitre.org/techniques/T1591) - /// - /// Adversaries may gather information about the victim's organization that can be used during targeting. Information about an organization may include a variety of details, including the names of divisions/departments, specifics of business operations, as well as the roles and responsibilities of key employees. - GatherVictimOrgInformation, - - /// [Gather Victim Network Information](https://attack.mitre.org/techniques/T1590) - /// - /// Adversaries may gather information about the victim's networks that can be used during targeting. Information about networks may include a variety of details, including administrative data (ex: IP ranges, domain names, etc.) as well as specifics regarding its topology and operations. - GatherVictimNetworkInformation, - - /// [Search Open Websites/Domains](https://attack.mitre.org/techniques/T1593) - /// - /// Adversaries may search freely available websites and/or domains for information about victims that can be used during targeting. Information about victims may be available in various online sites, such as social media, new sites, or those hosting information about business operations such as hiring or requested/rewarded contracts.(Citation: Cyware Social Media)(Citation: SecurityTrails Google Hacking)(Citation: ExploitDB GoogleHacking) - SearchOpenWebsitesDomains, - - /// [Search Closed Sources](https://attack.mitre.org/techniques/T1597) - /// - /// Adversaries may search and gather information about victims from closed sources that can be used during targeting. Information about victims may be available for purchase from reputable private sources and databases, such as paid subscriptions to feeds of technical/threat intelligence data.(Citation: D3Secutrity CTI Feeds) Adversaries may also purchase information from less-reputable sources such as dark web or cybercrime blackmarkets.(Citation: ZDNET Selling Data) - SearchClosedSources, - - /// [Phishing for Information](https://attack.mitre.org/techniques/T1598) - /// - /// Adversaries may send phishing messages to elicit sensitive information that can be used during targeting. Phishing for information is an attempt to trick targets into divulging information, frequently credentials or other actionable information. Phishing for information is different from [Phishing](https://attack.mitre.org/techniques/T1566) in that the objective is gathering data from the victim rather than executing malicious code. - PhishingForInformation, - -} -/// [Command and Control](https://attack.mitre.org/tactics/TA0011)'s techniques -pub enum CommandAndControl { - /// [Application Layer Protocol](https://attack.mitre.org/techniques/T1071) - /// - /// Adversaries may communicate using OSI application layer protocols to avoid detection/network filtering by blending in with existing traffic. Commands to the remote system, and often the results of those commands, will be embedded within the protocol traffic between the client and server. - ApplicationLayerProtocol, - - /// [Remote Access Software](https://attack.mitre.org/techniques/T1219) - /// - /// An adversary may use legitimate desktop support and remote access software to establish an interactive command and control channel to target systems within networks. These services, such as `VNC`, `Team Viewer`, `AnyDesk`, `ScreenConnect`, `LogMein`, `AmmyyAdmin`, and other remote monitoring and management (RMM) tools, are commonly used as legitimate technical support software and may be allowed by application control within a target environment.(Citation: Symantec Living off the Land)(Citation: CrowdStrike 2015 Global Threat Report)(Citation: CrySyS Blog TeamSpy) - RemoteAccessSoftware, - - /// [Content Injection](https://attack.mitre.org/techniques/T1659) - /// - /// Adversaries may gain access and continuously communicate with victims by injecting malicious content into systems through online network traffic. Rather than luring victims to malicious payloads hosted on a compromised website (i.e., [Drive-by Target](https://attack.mitre.org/techniques/T1608/004) followed by [Drive-by Compromise](https://attack.mitre.org/techniques/T1189)), adversaries may initially access victims through compromised data-transfer channels where they can manipulate traffic and/or inject their own content. These compromised online network channels may also be used to deliver additional payloads (i.e., [Ingress Tool Transfer](https://attack.mitre.org/techniques/T1105)) and other data to already compromised systems.(Citation: ESET MoustachedBouncer) - ContentInjection, - - /// [Traffic Signaling](https://attack.mitre.org/techniques/T1205) - /// - /// Adversaries may use traffic signaling to hide open ports or other malicious functionality used for persistence or command and control. Traffic signaling involves the use of a magic value or sequence that must be sent to a system to trigger a special response, such as opening a closed port or executing a malicious task. This may take the form of sending a series of packets with certain characteristics before a port will be opened that the adversary can use for command and control. Usually this series of packets consists of attempted connections to a predefined sequence of closed ports (i.e. [Port Knocking](https://attack.mitre.org/techniques/T1205/001)), but can involve unusual flags, specific strings, or other unique characteristics. After the sequence is completed, opening a port may be accomplished by the host-based firewall, but could also be implemented by custom software. - TrafficSignaling, - - /// [Protocol Tunneling](https://attack.mitre.org/techniques/T1572) - /// - /// Adversaries may tunnel network communications to and from a victim system within a separate protocol to avoid detection/network filtering and/or enable access to otherwise unreachable systems. Tunneling involves explicitly encapsulating a protocol within another. This behavior may conceal malicious traffic by blending in with existing traffic and/or provide an outer layer of encryption (similar to a VPN). Tunneling could also enable routing of network packets that would otherwise not reach their intended destination, such as SMB, RDP, or other traffic that would be filtered by network appliances or not routed over the Internet. - ProtocolTunneling, - - /// [Communication Through Removable Media](https://attack.mitre.org/techniques/T1092) - /// - /// Adversaries can perform command and control between compromised hosts on potentially disconnected networks using removable media to transfer commands from system to system. Both systems would need to be compromised, with the likelihood that an Internet-connected system was compromised first and the second through lateral movement by [Replication Through Removable Media](https://attack.mitre.org/techniques/T1091). Commands and files would be relayed from the disconnected system to the Internet-connected system to which the adversary has direct access. - CommunicationThroughRemovableMedia, - - /// [Proxy](https://attack.mitre.org/techniques/T1090) - /// - /// Adversaries may use a connection proxy to direct network traffic between systems or act as an intermediary for network communications to a command and control server to avoid direct connections to their infrastructure. Many tools exist that enable traffic redirection through proxies or port redirection, including [HTRAN](https://attack.mitre.org/software/S0040), ZXProxy, and ZXPortMap. (Citation: Trend Micro APT Attack Tools) Adversaries use these types of proxies to manage command and control communications, reduce the number of simultaneous outbound network connections, provide resiliency in the face of connection loss, or to ride over existing trusted communications paths between victims to avoid suspicion. Adversaries may chain together multiple proxies to further disguise the source of malicious traffic. - Proxy, - - /// [Dynamic Resolution](https://attack.mitre.org/techniques/T1568) - /// - /// Adversaries may dynamically establish connections to command and control infrastructure to evade common detections and remediations. This may be achieved by using malware that shares a common algorithm with the infrastructure the adversary uses to receive the malware's communications. These calculations can be used to dynamically adjust parameters such as the domain name, IP address, or port number the malware uses for command and control. - DynamicResolution, - - /// [Web Service](https://attack.mitre.org/techniques/T1102) - /// - /// Adversaries may use an existing, legitimate external Web service as a means for relaying data to/from a compromised system. Popular websites and social media acting as a mechanism for C2 may give a significant amount of cover due to the likelihood that hosts within a network are already communicating with them prior to a compromise. Using common services, such as those offered by Google or Twitter, makes it easier for adversaries to hide in expected noise. Web service providers commonly use SSL/TLS encryption, giving adversaries an added level of protection. - WebService, - - /// [Multi-Stage Channels](https://attack.mitre.org/techniques/T1104) - /// - /// Adversaries may create multiple stages for command and control that are employed under different conditions or for certain functions. Use of multiple stages may obfuscate the command and control channel to make detection more difficult. - MultiStageChannels, - - /// [Data Obfuscation](https://attack.mitre.org/techniques/T1001) - /// - /// Adversaries may obfuscate command and control traffic to make it more difficult to detect. Command and control (C2) communications are hidden (but not necessarily encrypted) in an attempt to make the content more difficult to discover or decipher and to make the communication less conspicuous and hide commands from being seen. This encompasses many methods, such as adding junk data to protocol traffic, using steganography, or impersonating legitimate protocols. - DataObfuscation, - - /// [Non-Standard Port](https://attack.mitre.org/techniques/T1571) - /// - /// Adversaries may communicate using a protocol and port pairing that are typically not associated. For example, HTTPS over port 8088(Citation: Symantec Elfin Mar 2019) or port 587(Citation: Fortinet Agent Tesla April 2018) as opposed to the traditional port 443. Adversaries may make changes to the standard port used by a protocol to bypass filtering or muddle analysis/parsing of network data. - NonStandardPort, - - /// [Encrypted Channel](https://attack.mitre.org/techniques/T1573) - /// - /// Adversaries may employ a known encryption algorithm to conceal command and control traffic rather than relying on any inherent protections provided by a communication protocol. Despite the use of a secure algorithm, these implementations may be vulnerable to reverse engineering if secret keys are encoded and/or generated within malware samples/configuration files. - EncryptedChannel, - - /// [Non-Application Layer Protocol](https://attack.mitre.org/techniques/T1095) - /// - /// Adversaries may use an OSI non-application layer protocol for communication between host and C2 server or among infected hosts within a network. The list of possible protocols is extensive.(Citation: Wikipedia OSI) Specific examples include use of network layer protocols, such as the Internet Control Message Protocol (ICMP), transport layer protocols, such as the User Datagram Protocol (UDP), session layer protocols, such as Socket Secure (SOCKS), as well as redirected/tunneled protocols, such as Serial over LAN (SOL). - NonApplicationLayerProtocol, - - /// [Data Encoding](https://attack.mitre.org/techniques/T1132) - /// - /// Adversaries may encode data to make the content of command and control traffic more difficult to detect. Command and control (C2) information can be encoded using a standard data encoding system. Use of data encoding may adhere to existing protocol specifications and includes use of ASCII, Unicode, Base64, MIME, or other binary-to-text and character encoding systems.(Citation: Wikipedia Binary-to-text Encoding) (Citation: Wikipedia Character Encoding) Some data encoding systems may also result in data compression, such as gzip. - DataEncoding, - - /// [Ingress Tool Transfer](https://attack.mitre.org/techniques/T1105) - /// - /// Adversaries may transfer tools or other files from an external system into a compromised environment. Tools or files may be copied from an external adversary-controlled system to the victim network through the command and control channel or through alternate protocols such as [ftp](https://attack.mitre.org/software/S0095). Once present, adversaries may also transfer/spread tools between victim devices within a compromised environment (i.e. [Lateral Tool Transfer](https://attack.mitre.org/techniques/T1570)). - IngressToolTransfer, - - /// [Fallback Channels](https://attack.mitre.org/techniques/T1008) - /// - /// Adversaries may use fallback or alternate communication channels if the primary channel is compromised or inaccessible in order to maintain reliable command and control and to avoid data transfer thresholds. - FallbackChannels, - -} -/// [Initial Access](https://attack.mitre.org/tactics/TA0001)'s techniques -pub enum InitialAccess { - /// [External Remote Services](https://attack.mitre.org/techniques/T1133) - /// - /// Adversaries may leverage external-facing remote services to initially access and/or persist within a network. Remote services such as VPNs, Citrix, and other access mechanisms allow users to connect to internal enterprise network resources from external locations. There are often remote service gateways that manage connections and credential authentication for these services. Services such as [Windows Remote Management](https://attack.mitre.org/techniques/T1021/006) and [VNC](https://attack.mitre.org/techniques/T1021/005) can also be used externally.(Citation: MacOS VNC software for Remote Desktop) - ExternalRemoteServices, - - /// [Replication Through Removable Media](https://attack.mitre.org/techniques/T1091) - /// - /// Adversaries may move onto systems, possibly those on disconnected or air-gapped networks, by copying malware to removable media and taking advantage of Autorun features when the media is inserted into a system and executes. In the case of Lateral Movement, this may occur through modification of executable files stored on removable media or by copying malware and renaming it to look like a legitimate file to trick users into executing it on a separate system. In the case of Initial Access, this may occur through manual manipulation of the media, modification of systems used to initially format the media, or modification to the media's firmware itself. - ReplicationThroughRemovableMedia, - - /// [Supply Chain Compromise](https://attack.mitre.org/techniques/T1195) - /// - /// Adversaries may manipulate products or product delivery mechanisms prior to receipt by a final consumer for the purpose of data or system compromise. - SupplyChainCompromise, - - /// [Exploit Public-Facing Application](https://attack.mitre.org/techniques/T1190) - /// - /// Adversaries may attempt to exploit a weakness in an Internet-facing host or system to initially access a network. The weakness in the system can be a software bug, a temporary glitch, or a misconfiguration. - ExploitPublicFacingApplication, - - /// [Content Injection](https://attack.mitre.org/techniques/T1659) - /// - /// Adversaries may gain access and continuously communicate with victims by injecting malicious content into systems through online network traffic. Rather than luring victims to malicious payloads hosted on a compromised website (i.e., [Drive-by Target](https://attack.mitre.org/techniques/T1608/004) followed by [Drive-by Compromise](https://attack.mitre.org/techniques/T1189)), adversaries may initially access victims through compromised data-transfer channels where they can manipulate traffic and/or inject their own content. These compromised online network channels may also be used to deliver additional payloads (i.e., [Ingress Tool Transfer](https://attack.mitre.org/techniques/T1105)) and other data to already compromised systems.(Citation: ESET MoustachedBouncer) - ContentInjection, - - /// [Trusted Relationship](https://attack.mitre.org/techniques/T1199) - /// - /// Adversaries may breach or otherwise leverage organizations who have access to intended victims. Access through trusted third party relationship abuses an existing connection that may not be protected or receives less scrutiny than standard mechanisms of gaining access to a network. - TrustedRelationship, - - /// [Phishing](https://attack.mitre.org/techniques/T1566) - /// - /// Adversaries may send phishing messages to gain access to victim systems. All forms of phishing are electronically delivered social engineering. Phishing can be targeted, known as spearphishing. In spearphishing, a specific individual, company, or industry will be targeted by the adversary. More generally, adversaries can conduct non-targeted phishing, such as in mass malware spam campaigns. - Phishing, - - /// [Valid Accounts](https://attack.mitre.org/techniques/T1078) - /// - /// Adversaries may obtain and abuse credentials of existing accounts as a means of gaining Initial Access, Persistence, Privilege Escalation, or Defense Evasion. Compromised credentials may be used to bypass access controls placed on various resources on systems within the network and may even be used for persistent access to remote systems and externally available services, such as VPNs, Outlook Web Access, network devices, and remote desktop.(Citation: volexity_0day_sophos_FW) Compromised credentials may also grant an adversary increased privilege to specific systems or access to restricted areas of the network. Adversaries may choose not to use malware or tools in conjunction with the legitimate access those credentials provide to make it harder to detect their presence. - ValidAccounts, - - /// [Hardware Additions](https://attack.mitre.org/techniques/T1200) - /// - /// Adversaries may introduce computer accessories, networking hardware, or other computing devices into a system or network that can be used as a vector to gain access. Rather than just connecting and distributing payloads via removable storage (i.e. [Replication Through Removable Media](https://attack.mitre.org/techniques/T1091)), more robust hardware additions can be used to introduce new functionalities and/or features into a system that can then be abused. - HardwareAdditions, - - /// [Drive-by Compromise](https://attack.mitre.org/techniques/T1189) - /// - /// Adversaries may gain access to a system through a user visiting a website over the normal course of browsing. With this technique, the user's web browser is typically targeted for exploitation, but adversaries may also use compromised websites for non-exploitation behavior such as acquiring [Application Access Token](https://attack.mitre.org/techniques/T1550/001). - DriveByCompromise, - -} -impl TryFrom for Tactic { - type Error = InvalidArgumentError; - fn try_from(value: AttackTechnique) -> Result { - let AttackTechnique { tactic, technique } = value; - Ok(match tactic { - 0006 => Self::CredentialAccess(CredentialAccess::try_from(technique)?), - 0002 => Self::Execution(Execution::try_from(technique)?), - 0040 => Self::Impact(Impact::try_from(technique)?), - 0003 => Self::Persistence(Persistence::try_from(technique)?), - 0004 => Self::PrivilegeEscalation(PrivilegeEscalation::try_from(technique)?), - 0008 => Self::LateralMovement(LateralMovement::try_from(technique)?), - 0005 => Self::DefenseEvasion(DefenseEvasion::try_from(technique)?), - 0010 => Self::Exfiltration(Exfiltration::try_from(technique)?), - 0007 => Self::Discovery(Discovery::try_from(technique)?), - 0009 => Self::Collection(Collection::try_from(technique)?), - 0042 => Self::ResourceDevelopment(ResourceDevelopment::try_from(technique)?), - 0043 => Self::Reconnaissance(Reconnaissance::try_from(technique)?), - 0011 => Self::CommandAndControl(CommandAndControl::try_from(technique)?), - 0001 => Self::InitialAccess(InitialAccess::try_from(technique)?), - _ => return Err(InvalidArgumentError::InvalidMitreTactic(tactic)), - }) - } -} -impl TryFrom for CredentialAccess { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1557 => Self::AdversaryInTheMiddle, - 1003 => Self::OsCredentialDumping, - 1539 => Self::StealWebSessionCookie, - 1040 => Self::NetworkSniffing, - 1558 => Self::StealOrForgeKerberosTickets, - 1555 => Self::CredentialsFromPasswordStores, - 1552 => Self::UnsecuredCredentials, - 1649 => Self::StealOrForgeAuthenticationCertificates, - 1528 => Self::StealApplicationAccessToken, - 1606 => Self::ForgeWebCredentials, - 1621 => Self::MultiFactorAuthenticationRequestGeneration, - 1212 => Self::ExploitationForCredentialAccess, - 1110 => Self::BruteForce, - 1187 => Self::ForcedAuthentication, - 1056 => Self::InputCapture, - 1111 => Self::MultiFactorAuthenticationInterception, - 1556 => Self::ModifyAuthenticationProcess, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0006, value)), - }) - } -} -impl TryFrom for Execution { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1047 => Self::WindowsManagementInstrumentation, - 1129 => Self::SharedModules, - 1053 => Self::ScheduledTaskJob, - 1106 => Self::NativeApi, - 1610 => Self::DeployContainer, - 1059 => Self::CommandAndScriptingInterpreter, - 1609 => Self::ContainerAdministrationCommand, - 1204 => Self::UserExecution, - 1072 => Self::SoftwareDeploymentTools, - 1559 => Self::InterProcessCommunication, - 1203 => Self::ExploitationForClientExecution, - 1569 => Self::SystemServices, - 1651 => Self::CloudAdministrationCommand, - 1648 => Self::ServerlessExecution, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0002, value)), - }) - } -} -impl TryFrom for Impact { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1561 => Self::DiskWipe, - 1489 => Self::ServiceStop, - 1491 => Self::Defacement, - 1657 => Self::FinancialTheft, - 1565 => Self::DataManipulation, - 1531 => Self::AccountAccessRemoval, - 1486 => Self::DataEncryptedForImpact, - 1499 => Self::EndpointDenialOfService, - 1496 => Self::ResourceHijacking, - 1485 => Self::DataDestruction, - 1498 => Self::NetworkDenialOfService, - 1495 => Self::FirmwareCorruption, - 1490 => Self::InhibitSystemRecovery, - 1529 => Self::SystemShutdownReboot, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0040, value)), - }) - } -} -impl TryFrom for Persistence { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1037 => Self::BootOrLogonInitializationScripts, - 1543 => Self::CreateOrModifySystemProcess, - 1133 => Self::ExternalRemoteServices, - 1547 => Self::BootOrLogonAutostartExecution, - 1137 => Self::OfficeApplicationStartup, - 1053 => Self::ScheduledTaskJob, - 1176 => Self::BrowserExtensions, - 1205 => Self::TrafficSignaling, - 1525 => Self::ImplantInternalImage, - 1542 => Self::PreOsBoot, - 1554 => Self::CompromiseClientSoftwareBinary, - 1098 => Self::AccountManipulation, - 1574 => Self::HijackExecutionFlow, - 1078 => Self::ValidAccounts, - 1546 => Self::EventTriggeredExecution, - 1197 => Self::BitsJobs, - 1505 => Self::ServerSoftwareComponent, - 1136 => Self::CreateAccount, - 1653 => Self::PowerSettings, - 1556 => Self::ModifyAuthenticationProcess, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0003, value)), - }) - } -} -impl TryFrom for PrivilegeEscalation { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1037 => Self::BootOrLogonInitializationScripts, - 1543 => Self::CreateOrModifySystemProcess, - 1547 => Self::BootOrLogonAutostartExecution, - 1053 => Self::ScheduledTaskJob, - 1055 => Self::ProcessInjection, - 1611 => Self::EscapeToHost, - 1548 => Self::AbuseElevationControlMechanism, - 1098 => Self::AccountManipulation, - 1574 => Self::HijackExecutionFlow, - 1078 => Self::ValidAccounts, - 1068 => Self::ExploitationForPrivilegeEscalation, - 1546 => Self::EventTriggeredExecution, - 1134 => Self::AccessTokenManipulation, - 1484 => Self::DomainPolicyModification, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0004, value)), - }) - } -} -impl TryFrom for LateralMovement { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1080 => Self::TaintSharedContent, - 1091 => Self::ReplicationThroughRemovableMedia, - 1550 => Self::UseAlternateAuthenticationMaterial, - 1021 => Self::RemoteServices, - 1563 => Self::RemoteServiceSessionHijacking, - 1072 => Self::SoftwareDeploymentTools, - 1210 => Self::ExploitationOfRemoteServices, - 1534 => Self::InternalSpearphishing, - 1570 => Self::LateralToolTransfer, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0008, value)), - }) - } -} -impl TryFrom for DefenseEvasion { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1006 => Self::DirectVolumeAccess, - 1014 => Self::Rootkit, - 1578 => Self::ModifyCloudComputeInfrastructure, - 1600 => Self::WeakenEncryption, - 1564 => Self::HideArtifacts, - 1202 => Self::IndirectCommandExecution, - 1140 => Self::DeobfuscateDecodeFilesOrInformation, - 1562 => Self::ImpairDefenses, - 1036 => Self::Masquerading, - 1055 => Self::ProcessInjection, - 1205 => Self::TrafficSignaling, - 1218 => Self::SystemBinaryProxyExecution, - 1620 => Self::ReflectiveCodeLoading, - 1550 => Self::UseAlternateAuthenticationMaterial, - 1207 => Self::RogueDomainController, - 1610 => Self::DeployContainer, - 1112 => Self::ModifyRegistry, - 1535 => Self::UnusedUnsupportedCloudRegions, - 1222 => Self::FileAndDirectoryPermissionsModification, - 1548 => Self::AbuseElevationControlMechanism, - 1070 => Self::IndicatorRemoval, - 1647 => Self::PlistFileModification, - 1542 => Self::PreOsBoot, - 1612 => Self::BuildImageOnHost, - 1497 => Self::VirtualizationSandboxEvasion, - 1480 => Self::ExecutionGuardrails, - 1601 => Self::ModifySystemImage, - 1574 => Self::HijackExecutionFlow, - 1078 => Self::ValidAccounts, - 1027 => Self::ObfuscatedFilesOrInformation, - 1599 => Self::NetworkBoundaryBridging, - 1553 => Self::SubvertTrustControls, - 1197 => Self::BitsJobs, - 1656 => Self::Impersonation, - 1221 => Self::TemplateInjection, - 1134 => Self::AccessTokenManipulation, - 1622 => Self::DebuggerEvasion, - 1484 => Self::DomainPolicyModification, - 1220 => Self::XslScriptProcessing, - 1556 => Self::ModifyAuthenticationProcess, - 1216 => Self::SystemScriptProxyExecution, - 1211 => Self::ExploitationForDefenseEvasion, - 1127 => Self::TrustedDeveloperUtilitiesProxyExecution, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0005, value)), - }) - } -} -impl TryFrom for Exfiltration { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1567 => Self::ExfiltrationOverWebService, - 1029 => Self::ScheduledTransfer, - 1011 => Self::ExfiltrationOverOtherNetworkMedium, - 1020 => Self::AutomatedExfiltration, - 1041 => Self::ExfiltrationOverC2Channel, - 1048 => Self::ExfiltrationOverAlternativeProtocol, - 1030 => Self::DataTransferSizeLimits, - 1537 => Self::TransferDataToCloudAccount, - 1052 => Self::ExfiltrationOverPhysicalMedium, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0010, value)), - }) - } -} -impl TryFrom for Discovery { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1033 => Self::SystemOwnerUserDiscovery, - 1613 => Self::ContainerAndResourceDiscovery, - 1069 => Self::PermissionGroupsDiscovery, - 1615 => Self::GroupPolicyDiscovery, - 1652 => Self::DeviceDriverDiscovery, - 1007 => Self::SystemServiceDiscovery, - 1040 => Self::NetworkSniffing, - 1135 => Self::NetworkShareDiscovery, - 1120 => Self::PeripheralDeviceDiscovery, - 1082 => Self::SystemInformationDiscovery, - 1010 => Self::ApplicationWindowDiscovery, - 1580 => Self::CloudInfrastructureDiscovery, - 1217 => Self::BrowserInformationDiscovery, - 1016 => Self::SystemNetworkConfigurationDiscovery, - 1087 => Self::AccountDiscovery, - 1482 => Self::DomainTrustDiscovery, - 1083 => Self::FileAndDirectoryDiscovery, - 1049 => Self::SystemNetworkConnectionsDiscovery, - 1497 => Self::VirtualizationSandboxEvasion, - 1619 => Self::CloudStorageObjectDiscovery, - 1654 => Self::LogEnumeration, - 1057 => Self::ProcessDiscovery, - 1201 => Self::PasswordPolicyDiscovery, - 1012 => Self::QueryRegistry, - 1614 => Self::SystemLocationDiscovery, - 1526 => Self::CloudServiceDiscovery, - 1018 => Self::RemoteSystemDiscovery, - 1046 => Self::NetworkServiceDiscovery, - 1518 => Self::SoftwareDiscovery, - 1538 => Self::CloudServiceDashboard, - 1622 => Self::DebuggerEvasion, - 1124 => Self::SystemTimeDiscovery, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0007, value)), - }) - } -} -impl TryFrom for Collection { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1113 => Self::ScreenCapture, - 1557 => Self::AdversaryInTheMiddle, - 1602 => Self::DataFromConfigurationRepository, - 1123 => Self::AudioCapture, - 1114 => Self::EmailCollection, - 1025 => Self::DataFromRemovableMedia, - 1119 => Self::AutomatedCollection, - 1115 => Self::ClipboardData, - 1530 => Self::DataFromCloudStorage, - 1005 => Self::DataFromLocalSystem, - 1560 => Self::ArchiveCollectedData, - 1185 => Self::BrowserSessionHijacking, - 1125 => Self::VideoCapture, - 1074 => Self::DataStaged, - 1039 => Self::DataFromNetworkSharedDrive, - 1056 => Self::InputCapture, - 1213 => Self::DataFromInformationRepositories, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0009, value)), - }) - } -} -impl TryFrom for ResourceDevelopment { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1583 => Self::AcquireInfrastructure, - 1584 => Self::CompromiseInfrastructure, - 1586 => Self::CompromiseAccounts, - 1608 => Self::StageCapabilities, - 1585 => Self::EstablishAccounts, - 1588 => Self::ObtainCapabilities, - 1650 => Self::AcquireAccess, - 1587 => Self::DevelopCapabilities, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0042, value)), - }) - } -} -impl TryFrom for Reconnaissance { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1592 => Self::GatherVictimHostInformation, - 1594 => Self::SearchVictimOwnedWebsites, - 1589 => Self::GatherVictimIdentityInformation, - 1596 => Self::SearchOpenTechnicalDatabases, - 1595 => Self::ActiveScanning, - 1591 => Self::GatherVictimOrgInformation, - 1590 => Self::GatherVictimNetworkInformation, - 1593 => Self::SearchOpenWebsitesDomains, - 1597 => Self::SearchClosedSources, - 1598 => Self::PhishingForInformation, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0043, value)), - }) - } -} -impl TryFrom for CommandAndControl { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1071 => Self::ApplicationLayerProtocol, - 1219 => Self::RemoteAccessSoftware, - 1659 => Self::ContentInjection, - 1205 => Self::TrafficSignaling, - 1572 => Self::ProtocolTunneling, - 1092 => Self::CommunicationThroughRemovableMedia, - 1090 => Self::Proxy, - 1568 => Self::DynamicResolution, - 1102 => Self::WebService, - 1104 => Self::MultiStageChannels, - 1001 => Self::DataObfuscation, - 1571 => Self::NonStandardPort, - 1573 => Self::EncryptedChannel, - 1095 => Self::NonApplicationLayerProtocol, - 1132 => Self::DataEncoding, - 1105 => Self::IngressToolTransfer, - 1008 => Self::FallbackChannels, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0011, value)), - }) - } -} -impl TryFrom for InitialAccess { - type Error = InvalidArgumentError; - fn try_from(value: u32) -> Result { - Ok(match value { - 1133 => Self::ExternalRemoteServices, - 1091 => Self::ReplicationThroughRemovableMedia, - 1195 => Self::SupplyChainCompromise, - 1190 => Self::ExploitPublicFacingApplication, - 1659 => Self::ContentInjection, - 1199 => Self::TrustedRelationship, - 1566 => Self::Phishing, - 1078 => Self::ValidAccounts, - 1200 => Self::HardwareAdditions, - 1189 => Self::DriveByCompromise, - _ => return Err(InvalidArgumentError::InvalidMitreTechnique(0001, value)), - }) - } -} -impl From for AttackTechnique { - fn from(value: Tactic) -> Self { - let (tactic, technique) = match value { - Tactic::CredentialAccess(technique) => (0006, technique.into()), - Tactic::Execution(technique) => (0002, technique.into()), - Tactic::Impact(technique) => (0040, technique.into()), - Tactic::Persistence(technique) => (0003, technique.into()), - Tactic::PrivilegeEscalation(technique) => (0004, technique.into()), - Tactic::LateralMovement(technique) => (0008, technique.into()), - Tactic::DefenseEvasion(technique) => (0005, technique.into()), - Tactic::Exfiltration(technique) => (0010, technique.into()), - Tactic::Discovery(technique) => (0007, technique.into()), - Tactic::Collection(technique) => (0009, technique.into()), - Tactic::ResourceDevelopment(technique) => (0042, technique.into()), - Tactic::Reconnaissance(technique) => (0043, technique.into()), - Tactic::CommandAndControl(technique) => (0011, technique.into()), - Tactic::InitialAccess(technique) => (0001, technique.into()), - }; - AttackTechnique { tactic, technique } - } -} -impl From for u32 { - fn from(value: CredentialAccess) -> Self { - match value { - CredentialAccess::AdversaryInTheMiddle => 1557, - CredentialAccess::OsCredentialDumping => 1003, - CredentialAccess::StealWebSessionCookie => 1539, - CredentialAccess::NetworkSniffing => 1040, - CredentialAccess::StealOrForgeKerberosTickets => 1558, - CredentialAccess::CredentialsFromPasswordStores => 1555, - CredentialAccess::UnsecuredCredentials => 1552, - CredentialAccess::StealOrForgeAuthenticationCertificates => 1649, - CredentialAccess::StealApplicationAccessToken => 1528, - CredentialAccess::ForgeWebCredentials => 1606, - CredentialAccess::MultiFactorAuthenticationRequestGeneration => 1621, - CredentialAccess::ExploitationForCredentialAccess => 1212, - CredentialAccess::BruteForce => 1110, - CredentialAccess::ForcedAuthentication => 1187, - CredentialAccess::InputCapture => 1056, - CredentialAccess::MultiFactorAuthenticationInterception => 1111, - CredentialAccess::ModifyAuthenticationProcess => 1556, - } - } -} -impl From for u32 { - fn from(value: Execution) -> Self { - match value { - Execution::WindowsManagementInstrumentation => 1047, - Execution::SharedModules => 1129, - Execution::ScheduledTaskJob => 1053, - Execution::NativeApi => 1106, - Execution::DeployContainer => 1610, - Execution::CommandAndScriptingInterpreter => 1059, - Execution::ContainerAdministrationCommand => 1609, - Execution::UserExecution => 1204, - Execution::SoftwareDeploymentTools => 1072, - Execution::InterProcessCommunication => 1559, - Execution::ExploitationForClientExecution => 1203, - Execution::SystemServices => 1569, - Execution::CloudAdministrationCommand => 1651, - Execution::ServerlessExecution => 1648, - } - } -} -impl From for u32 { - fn from(value: Impact) -> Self { - match value { - Impact::DiskWipe => 1561, - Impact::ServiceStop => 1489, - Impact::Defacement => 1491, - Impact::FinancialTheft => 1657, - Impact::DataManipulation => 1565, - Impact::AccountAccessRemoval => 1531, - Impact::DataEncryptedForImpact => 1486, - Impact::EndpointDenialOfService => 1499, - Impact::ResourceHijacking => 1496, - Impact::DataDestruction => 1485, - Impact::NetworkDenialOfService => 1498, - Impact::FirmwareCorruption => 1495, - Impact::InhibitSystemRecovery => 1490, - Impact::SystemShutdownReboot => 1529, - } - } -} -impl From for u32 { - fn from(value: Persistence) -> Self { - match value { - Persistence::BootOrLogonInitializationScripts => 1037, - Persistence::CreateOrModifySystemProcess => 1543, - Persistence::ExternalRemoteServices => 1133, - Persistence::BootOrLogonAutostartExecution => 1547, - Persistence::OfficeApplicationStartup => 1137, - Persistence::ScheduledTaskJob => 1053, - Persistence::BrowserExtensions => 1176, - Persistence::TrafficSignaling => 1205, - Persistence::ImplantInternalImage => 1525, - Persistence::PreOsBoot => 1542, - Persistence::CompromiseClientSoftwareBinary => 1554, - Persistence::AccountManipulation => 1098, - Persistence::HijackExecutionFlow => 1574, - Persistence::ValidAccounts => 1078, - Persistence::EventTriggeredExecution => 1546, - Persistence::BitsJobs => 1197, - Persistence::ServerSoftwareComponent => 1505, - Persistence::CreateAccount => 1136, - Persistence::PowerSettings => 1653, - Persistence::ModifyAuthenticationProcess => 1556, - } - } -} -impl From for u32 { - fn from(value: PrivilegeEscalation) -> Self { - match value { - PrivilegeEscalation::BootOrLogonInitializationScripts => 1037, - PrivilegeEscalation::CreateOrModifySystemProcess => 1543, - PrivilegeEscalation::BootOrLogonAutostartExecution => 1547, - PrivilegeEscalation::ScheduledTaskJob => 1053, - PrivilegeEscalation::ProcessInjection => 1055, - PrivilegeEscalation::EscapeToHost => 1611, - PrivilegeEscalation::AbuseElevationControlMechanism => 1548, - PrivilegeEscalation::AccountManipulation => 1098, - PrivilegeEscalation::HijackExecutionFlow => 1574, - PrivilegeEscalation::ValidAccounts => 1078, - PrivilegeEscalation::ExploitationForPrivilegeEscalation => 1068, - PrivilegeEscalation::EventTriggeredExecution => 1546, - PrivilegeEscalation::AccessTokenManipulation => 1134, - PrivilegeEscalation::DomainPolicyModification => 1484, - } - } -} -impl From for u32 { - fn from(value: LateralMovement) -> Self { - match value { - LateralMovement::TaintSharedContent => 1080, - LateralMovement::ReplicationThroughRemovableMedia => 1091, - LateralMovement::UseAlternateAuthenticationMaterial => 1550, - LateralMovement::RemoteServices => 1021, - LateralMovement::RemoteServiceSessionHijacking => 1563, - LateralMovement::SoftwareDeploymentTools => 1072, - LateralMovement::ExploitationOfRemoteServices => 1210, - LateralMovement::InternalSpearphishing => 1534, - LateralMovement::LateralToolTransfer => 1570, - } - } -} -impl From for u32 { - fn from(value: DefenseEvasion) -> Self { - match value { - DefenseEvasion::DirectVolumeAccess => 1006, - DefenseEvasion::Rootkit => 1014, - DefenseEvasion::ModifyCloudComputeInfrastructure => 1578, - DefenseEvasion::WeakenEncryption => 1600, - DefenseEvasion::HideArtifacts => 1564, - DefenseEvasion::IndirectCommandExecution => 1202, - DefenseEvasion::DeobfuscateDecodeFilesOrInformation => 1140, - DefenseEvasion::ImpairDefenses => 1562, - DefenseEvasion::Masquerading => 1036, - DefenseEvasion::ProcessInjection => 1055, - DefenseEvasion::TrafficSignaling => 1205, - DefenseEvasion::SystemBinaryProxyExecution => 1218, - DefenseEvasion::ReflectiveCodeLoading => 1620, - DefenseEvasion::UseAlternateAuthenticationMaterial => 1550, - DefenseEvasion::RogueDomainController => 1207, - DefenseEvasion::DeployContainer => 1610, - DefenseEvasion::ModifyRegistry => 1112, - DefenseEvasion::UnusedUnsupportedCloudRegions => 1535, - DefenseEvasion::FileAndDirectoryPermissionsModification => 1222, - DefenseEvasion::AbuseElevationControlMechanism => 1548, - DefenseEvasion::IndicatorRemoval => 1070, - DefenseEvasion::PlistFileModification => 1647, - DefenseEvasion::PreOsBoot => 1542, - DefenseEvasion::BuildImageOnHost => 1612, - DefenseEvasion::VirtualizationSandboxEvasion => 1497, - DefenseEvasion::ExecutionGuardrails => 1480, - DefenseEvasion::ModifySystemImage => 1601, - DefenseEvasion::HijackExecutionFlow => 1574, - DefenseEvasion::ValidAccounts => 1078, - DefenseEvasion::ObfuscatedFilesOrInformation => 1027, - DefenseEvasion::NetworkBoundaryBridging => 1599, - DefenseEvasion::SubvertTrustControls => 1553, - DefenseEvasion::BitsJobs => 1197, - DefenseEvasion::Impersonation => 1656, - DefenseEvasion::TemplateInjection => 1221, - DefenseEvasion::AccessTokenManipulation => 1134, - DefenseEvasion::DebuggerEvasion => 1622, - DefenseEvasion::DomainPolicyModification => 1484, - DefenseEvasion::XslScriptProcessing => 1220, - DefenseEvasion::ModifyAuthenticationProcess => 1556, - DefenseEvasion::SystemScriptProxyExecution => 1216, - DefenseEvasion::ExploitationForDefenseEvasion => 1211, - DefenseEvasion::TrustedDeveloperUtilitiesProxyExecution => 1127, - } - } -} -impl From for u32 { - fn from(value: Exfiltration) -> Self { - match value { - Exfiltration::ExfiltrationOverWebService => 1567, - Exfiltration::ScheduledTransfer => 1029, - Exfiltration::ExfiltrationOverOtherNetworkMedium => 1011, - Exfiltration::AutomatedExfiltration => 1020, - Exfiltration::ExfiltrationOverC2Channel => 1041, - Exfiltration::ExfiltrationOverAlternativeProtocol => 1048, - Exfiltration::DataTransferSizeLimits => 1030, - Exfiltration::TransferDataToCloudAccount => 1537, - Exfiltration::ExfiltrationOverPhysicalMedium => 1052, - } - } -} -impl From for u32 { - fn from(value: Discovery) -> Self { - match value { - Discovery::SystemOwnerUserDiscovery => 1033, - Discovery::ContainerAndResourceDiscovery => 1613, - Discovery::PermissionGroupsDiscovery => 1069, - Discovery::GroupPolicyDiscovery => 1615, - Discovery::DeviceDriverDiscovery => 1652, - Discovery::SystemServiceDiscovery => 1007, - Discovery::NetworkSniffing => 1040, - Discovery::NetworkShareDiscovery => 1135, - Discovery::PeripheralDeviceDiscovery => 1120, - Discovery::SystemInformationDiscovery => 1082, - Discovery::ApplicationWindowDiscovery => 1010, - Discovery::CloudInfrastructureDiscovery => 1580, - Discovery::BrowserInformationDiscovery => 1217, - Discovery::SystemNetworkConfigurationDiscovery => 1016, - Discovery::AccountDiscovery => 1087, - Discovery::DomainTrustDiscovery => 1482, - Discovery::FileAndDirectoryDiscovery => 1083, - Discovery::SystemNetworkConnectionsDiscovery => 1049, - Discovery::VirtualizationSandboxEvasion => 1497, - Discovery::CloudStorageObjectDiscovery => 1619, - Discovery::LogEnumeration => 1654, - Discovery::ProcessDiscovery => 1057, - Discovery::PasswordPolicyDiscovery => 1201, - Discovery::QueryRegistry => 1012, - Discovery::SystemLocationDiscovery => 1614, - Discovery::CloudServiceDiscovery => 1526, - Discovery::RemoteSystemDiscovery => 1018, - Discovery::NetworkServiceDiscovery => 1046, - Discovery::SoftwareDiscovery => 1518, - Discovery::CloudServiceDashboard => 1538, - Discovery::DebuggerEvasion => 1622, - Discovery::SystemTimeDiscovery => 1124, - } - } -} -impl From for u32 { - fn from(value: Collection) -> Self { - match value { - Collection::ScreenCapture => 1113, - Collection::AdversaryInTheMiddle => 1557, - Collection::DataFromConfigurationRepository => 1602, - Collection::AudioCapture => 1123, - Collection::EmailCollection => 1114, - Collection::DataFromRemovableMedia => 1025, - Collection::AutomatedCollection => 1119, - Collection::ClipboardData => 1115, - Collection::DataFromCloudStorage => 1530, - Collection::DataFromLocalSystem => 1005, - Collection::ArchiveCollectedData => 1560, - Collection::BrowserSessionHijacking => 1185, - Collection::VideoCapture => 1125, - Collection::DataStaged => 1074, - Collection::DataFromNetworkSharedDrive => 1039, - Collection::InputCapture => 1056, - Collection::DataFromInformationRepositories => 1213, - } - } -} -impl From for u32 { - fn from(value: ResourceDevelopment) -> Self { - match value { - ResourceDevelopment::AcquireInfrastructure => 1583, - ResourceDevelopment::CompromiseInfrastructure => 1584, - ResourceDevelopment::CompromiseAccounts => 1586, - ResourceDevelopment::StageCapabilities => 1608, - ResourceDevelopment::EstablishAccounts => 1585, - ResourceDevelopment::ObtainCapabilities => 1588, - ResourceDevelopment::AcquireAccess => 1650, - ResourceDevelopment::DevelopCapabilities => 1587, - } - } -} -impl From for u32 { - fn from(value: Reconnaissance) -> Self { - match value { - Reconnaissance::GatherVictimHostInformation => 1592, - Reconnaissance::SearchVictimOwnedWebsites => 1594, - Reconnaissance::GatherVictimIdentityInformation => 1589, - Reconnaissance::SearchOpenTechnicalDatabases => 1596, - Reconnaissance::ActiveScanning => 1595, - Reconnaissance::GatherVictimOrgInformation => 1591, - Reconnaissance::GatherVictimNetworkInformation => 1590, - Reconnaissance::SearchOpenWebsitesDomains => 1593, - Reconnaissance::SearchClosedSources => 1597, - Reconnaissance::PhishingForInformation => 1598, - } - } -} -impl From for u32 { - fn from(value: CommandAndControl) -> Self { - match value { - CommandAndControl::ApplicationLayerProtocol => 1071, - CommandAndControl::RemoteAccessSoftware => 1219, - CommandAndControl::ContentInjection => 1659, - CommandAndControl::TrafficSignaling => 1205, - CommandAndControl::ProtocolTunneling => 1572, - CommandAndControl::CommunicationThroughRemovableMedia => 1092, - CommandAndControl::Proxy => 1090, - CommandAndControl::DynamicResolution => 1568, - CommandAndControl::WebService => 1102, - CommandAndControl::MultiStageChannels => 1104, - CommandAndControl::DataObfuscation => 1001, - CommandAndControl::NonStandardPort => 1571, - CommandAndControl::EncryptedChannel => 1573, - CommandAndControl::NonApplicationLayerProtocol => 1095, - CommandAndControl::DataEncoding => 1132, - CommandAndControl::IngressToolTransfer => 1105, - CommandAndControl::FallbackChannels => 1008, - } - } -} -impl From for u32 { - fn from(value: InitialAccess) -> Self { - match value { - InitialAccess::ExternalRemoteServices => 1133, - InitialAccess::ReplicationThroughRemovableMedia => 1091, - InitialAccess::SupplyChainCompromise => 1195, - InitialAccess::ExploitPublicFacingApplication => 1190, - InitialAccess::ContentInjection => 1659, - InitialAccess::TrustedRelationship => 1199, - InitialAccess::Phishing => 1566, - InitialAccess::ValidAccounts => 1078, - InitialAccess::HardwareAdditions => 1200, - InitialAccess::DriveByCompromise => 1189, - } - } -} -impl fmt::Display for Tactic { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Tactic::CredentialAccess(technique) => technique.fmt(f), - Tactic::Execution(technique) => technique.fmt(f), - Tactic::Impact(technique) => technique.fmt(f), - Tactic::Persistence(technique) => technique.fmt(f), - Tactic::PrivilegeEscalation(technique) => technique.fmt(f), - Tactic::LateralMovement(technique) => technique.fmt(f), - Tactic::DefenseEvasion(technique) => technique.fmt(f), - Tactic::Exfiltration(technique) => technique.fmt(f), - Tactic::Discovery(technique) => technique.fmt(f), - Tactic::Collection(technique) => technique.fmt(f), - Tactic::ResourceDevelopment(technique) => technique.fmt(f), - Tactic::Reconnaissance(technique) => technique.fmt(f), - Tactic::CommandAndControl(technique) => technique.fmt(f), - Tactic::InitialAccess(technique) => technique.fmt(f), - } - } -} -impl fmt::Display for CredentialAccess { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - CredentialAccess::AdversaryInTheMiddle => "Adversary-in-the-Middle", - CredentialAccess::OsCredentialDumping => "OS Credential Dumping", - CredentialAccess::StealWebSessionCookie => "Steal Web Session Cookie", - CredentialAccess::NetworkSniffing => "Network Sniffing", - CredentialAccess::StealOrForgeKerberosTickets => "Steal or Forge Kerberos Tickets", - CredentialAccess::CredentialsFromPasswordStores => "Credentials from Password Stores", - CredentialAccess::UnsecuredCredentials => "Unsecured Credentials", - CredentialAccess::StealOrForgeAuthenticationCertificates => "Steal or Forge Authentication Certificates", - CredentialAccess::StealApplicationAccessToken => "Steal Application Access Token", - CredentialAccess::ForgeWebCredentials => "Forge Web Credentials", - CredentialAccess::MultiFactorAuthenticationRequestGeneration => "Multi-Factor Authentication Request Generation", - CredentialAccess::ExploitationForCredentialAccess => "Exploitation for Credential Access", - CredentialAccess::BruteForce => "Brute Force", - CredentialAccess::ForcedAuthentication => "Forced Authentication", - CredentialAccess::InputCapture => "Input Capture", - CredentialAccess::MultiFactorAuthenticationInterception => "Multi-Factor Authentication Interception", - CredentialAccess::ModifyAuthenticationProcess => "Modify Authentication Process", - }) - } -} -impl fmt::Display for Execution { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Execution::WindowsManagementInstrumentation => "Windows Management Instrumentation", - Execution::SharedModules => "Shared Modules", - Execution::ScheduledTaskJob => "Scheduled Task/Job", - Execution::NativeApi => "Native API", - Execution::DeployContainer => "Deploy Container", - Execution::CommandAndScriptingInterpreter => "Command and Scripting Interpreter", - Execution::ContainerAdministrationCommand => "Container Administration Command", - Execution::UserExecution => "User Execution", - Execution::SoftwareDeploymentTools => "Software Deployment Tools", - Execution::InterProcessCommunication => "Inter-Process Communication", - Execution::ExploitationForClientExecution => "Exploitation for Client Execution", - Execution::SystemServices => "System Services", - Execution::CloudAdministrationCommand => "Cloud Administration Command", - Execution::ServerlessExecution => "Serverless Execution", - }) - } -} -impl fmt::Display for Impact { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Impact::DiskWipe => "Disk Wipe", - Impact::ServiceStop => "Service Stop", - Impact::Defacement => "Defacement", - Impact::FinancialTheft => "Financial Theft", - Impact::DataManipulation => "Data Manipulation", - Impact::AccountAccessRemoval => "Account Access Removal", - Impact::DataEncryptedForImpact => "Data Encrypted for Impact", - Impact::EndpointDenialOfService => "Endpoint Denial of Service", - Impact::ResourceHijacking => "Resource Hijacking", - Impact::DataDestruction => "Data Destruction", - Impact::NetworkDenialOfService => "Network Denial of Service", - Impact::FirmwareCorruption => "Firmware Corruption", - Impact::InhibitSystemRecovery => "Inhibit System Recovery", - Impact::SystemShutdownReboot => "System Shutdown/Reboot", - }) - } -} -impl fmt::Display for Persistence { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Persistence::BootOrLogonInitializationScripts => "Boot or Logon Initialization Scripts", - Persistence::CreateOrModifySystemProcess => "Create or Modify System Process", - Persistence::ExternalRemoteServices => "External Remote Services", - Persistence::BootOrLogonAutostartExecution => "Boot or Logon Autostart Execution", - Persistence::OfficeApplicationStartup => "Office Application Startup", - Persistence::ScheduledTaskJob => "Scheduled Task/Job", - Persistence::BrowserExtensions => "Browser Extensions", - Persistence::TrafficSignaling => "Traffic Signaling", - Persistence::ImplantInternalImage => "Implant Internal Image", - Persistence::PreOsBoot => "Pre-OS Boot", - Persistence::CompromiseClientSoftwareBinary => "Compromise Client Software Binary", - Persistence::AccountManipulation => "Account Manipulation", - Persistence::HijackExecutionFlow => "Hijack Execution Flow", - Persistence::ValidAccounts => "Valid Accounts", - Persistence::EventTriggeredExecution => "Event Triggered Execution", - Persistence::BitsJobs => "BITS Jobs", - Persistence::ServerSoftwareComponent => "Server Software Component", - Persistence::CreateAccount => "Create Account", - Persistence::PowerSettings => "Power Settings", - Persistence::ModifyAuthenticationProcess => "Modify Authentication Process", - }) - } -} -impl fmt::Display for PrivilegeEscalation { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - PrivilegeEscalation::BootOrLogonInitializationScripts => "Boot or Logon Initialization Scripts", - PrivilegeEscalation::CreateOrModifySystemProcess => "Create or Modify System Process", - PrivilegeEscalation::BootOrLogonAutostartExecution => "Boot or Logon Autostart Execution", - PrivilegeEscalation::ScheduledTaskJob => "Scheduled Task/Job", - PrivilegeEscalation::ProcessInjection => "Process Injection", - PrivilegeEscalation::EscapeToHost => "Escape to Host", - PrivilegeEscalation::AbuseElevationControlMechanism => "Abuse Elevation Control Mechanism", - PrivilegeEscalation::AccountManipulation => "Account Manipulation", - PrivilegeEscalation::HijackExecutionFlow => "Hijack Execution Flow", - PrivilegeEscalation::ValidAccounts => "Valid Accounts", - PrivilegeEscalation::ExploitationForPrivilegeEscalation => "Exploitation for Privilege Escalation", - PrivilegeEscalation::EventTriggeredExecution => "Event Triggered Execution", - PrivilegeEscalation::AccessTokenManipulation => "Access Token Manipulation", - PrivilegeEscalation::DomainPolicyModification => "Domain Policy Modification", - }) - } -} -impl fmt::Display for LateralMovement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - LateralMovement::TaintSharedContent => "Taint Shared Content", - LateralMovement::ReplicationThroughRemovableMedia => "Replication Through Removable Media", - LateralMovement::UseAlternateAuthenticationMaterial => "Use Alternate Authentication Material", - LateralMovement::RemoteServices => "Remote Services", - LateralMovement::RemoteServiceSessionHijacking => "Remote Service Session Hijacking", - LateralMovement::SoftwareDeploymentTools => "Software Deployment Tools", - LateralMovement::ExploitationOfRemoteServices => "Exploitation of Remote Services", - LateralMovement::InternalSpearphishing => "Internal Spearphishing", - LateralMovement::LateralToolTransfer => "Lateral Tool Transfer", - }) - } -} -impl fmt::Display for DefenseEvasion { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - DefenseEvasion::DirectVolumeAccess => "Direct Volume Access", - DefenseEvasion::Rootkit => "Rootkit", - DefenseEvasion::ModifyCloudComputeInfrastructure => "Modify Cloud Compute Infrastructure", - DefenseEvasion::WeakenEncryption => "Weaken Encryption", - DefenseEvasion::HideArtifacts => "Hide Artifacts", - DefenseEvasion::IndirectCommandExecution => "Indirect Command Execution", - DefenseEvasion::DeobfuscateDecodeFilesOrInformation => "Deobfuscate/Decode Files or Information", - DefenseEvasion::ImpairDefenses => "Impair Defenses", - DefenseEvasion::Masquerading => "Masquerading", - DefenseEvasion::ProcessInjection => "Process Injection", - DefenseEvasion::TrafficSignaling => "Traffic Signaling", - DefenseEvasion::SystemBinaryProxyExecution => "System Binary Proxy Execution", - DefenseEvasion::ReflectiveCodeLoading => "Reflective Code Loading", - DefenseEvasion::UseAlternateAuthenticationMaterial => "Use Alternate Authentication Material", - DefenseEvasion::RogueDomainController => "Rogue Domain Controller", - DefenseEvasion::DeployContainer => "Deploy Container", - DefenseEvasion::ModifyRegistry => "Modify Registry", - DefenseEvasion::UnusedUnsupportedCloudRegions => "Unused/Unsupported Cloud Regions", - DefenseEvasion::FileAndDirectoryPermissionsModification => "File and Directory Permissions Modification", - DefenseEvasion::AbuseElevationControlMechanism => "Abuse Elevation Control Mechanism", - DefenseEvasion::IndicatorRemoval => "Indicator Removal", - DefenseEvasion::PlistFileModification => "Plist File Modification", - DefenseEvasion::PreOsBoot => "Pre-OS Boot", - DefenseEvasion::BuildImageOnHost => "Build Image on Host", - DefenseEvasion::VirtualizationSandboxEvasion => "Virtualization/Sandbox Evasion", - DefenseEvasion::ExecutionGuardrails => "Execution Guardrails", - DefenseEvasion::ModifySystemImage => "Modify System Image", - DefenseEvasion::HijackExecutionFlow => "Hijack Execution Flow", - DefenseEvasion::ValidAccounts => "Valid Accounts", - DefenseEvasion::ObfuscatedFilesOrInformation => "Obfuscated Files or Information", - DefenseEvasion::NetworkBoundaryBridging => "Network Boundary Bridging", - DefenseEvasion::SubvertTrustControls => "Subvert Trust Controls", - DefenseEvasion::BitsJobs => "BITS Jobs", - DefenseEvasion::Impersonation => "Impersonation", - DefenseEvasion::TemplateInjection => "Template Injection", - DefenseEvasion::AccessTokenManipulation => "Access Token Manipulation", - DefenseEvasion::DebuggerEvasion => "Debugger Evasion", - DefenseEvasion::DomainPolicyModification => "Domain Policy Modification", - DefenseEvasion::XslScriptProcessing => "XSL Script Processing", - DefenseEvasion::ModifyAuthenticationProcess => "Modify Authentication Process", - DefenseEvasion::SystemScriptProxyExecution => "System Script Proxy Execution", - DefenseEvasion::ExploitationForDefenseEvasion => "Exploitation for Defense Evasion", - DefenseEvasion::TrustedDeveloperUtilitiesProxyExecution => "Trusted Developer Utilities Proxy Execution", - }) - } -} -impl fmt::Display for Exfiltration { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Exfiltration::ExfiltrationOverWebService => "Exfiltration Over Web Service", - Exfiltration::ScheduledTransfer => "Scheduled Transfer", - Exfiltration::ExfiltrationOverOtherNetworkMedium => "Exfiltration Over Other Network Medium", - Exfiltration::AutomatedExfiltration => "Automated Exfiltration", - Exfiltration::ExfiltrationOverC2Channel => "Exfiltration Over C2 Channel", - Exfiltration::ExfiltrationOverAlternativeProtocol => "Exfiltration Over Alternative Protocol", - Exfiltration::DataTransferSizeLimits => "Data Transfer Size Limits", - Exfiltration::TransferDataToCloudAccount => "Transfer Data to Cloud Account", - Exfiltration::ExfiltrationOverPhysicalMedium => "Exfiltration Over Physical Medium", - }) - } -} -impl fmt::Display for Discovery { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Discovery::SystemOwnerUserDiscovery => "System Owner/User Discovery", - Discovery::ContainerAndResourceDiscovery => "Container and Resource Discovery", - Discovery::PermissionGroupsDiscovery => "Permission Groups Discovery", - Discovery::GroupPolicyDiscovery => "Group Policy Discovery", - Discovery::DeviceDriverDiscovery => "Device Driver Discovery", - Discovery::SystemServiceDiscovery => "System Service Discovery", - Discovery::NetworkSniffing => "Network Sniffing", - Discovery::NetworkShareDiscovery => "Network Share Discovery", - Discovery::PeripheralDeviceDiscovery => "Peripheral Device Discovery", - Discovery::SystemInformationDiscovery => "System Information Discovery", - Discovery::ApplicationWindowDiscovery => "Application Window Discovery", - Discovery::CloudInfrastructureDiscovery => "Cloud Infrastructure Discovery", - Discovery::BrowserInformationDiscovery => "Browser Information Discovery", - Discovery::SystemNetworkConfigurationDiscovery => "System Network Configuration Discovery", - Discovery::AccountDiscovery => "Account Discovery", - Discovery::DomainTrustDiscovery => "Domain Trust Discovery", - Discovery::FileAndDirectoryDiscovery => "File and Directory Discovery", - Discovery::SystemNetworkConnectionsDiscovery => "System Network Connections Discovery", - Discovery::VirtualizationSandboxEvasion => "Virtualization/Sandbox Evasion", - Discovery::CloudStorageObjectDiscovery => "Cloud Storage Object Discovery", - Discovery::LogEnumeration => "Log Enumeration", - Discovery::ProcessDiscovery => "Process Discovery", - Discovery::PasswordPolicyDiscovery => "Password Policy Discovery", - Discovery::QueryRegistry => "Query Registry", - Discovery::SystemLocationDiscovery => "System Location Discovery", - Discovery::CloudServiceDiscovery => "Cloud Service Discovery", - Discovery::RemoteSystemDiscovery => "Remote System Discovery", - Discovery::NetworkServiceDiscovery => "Network Service Discovery", - Discovery::SoftwareDiscovery => "Software Discovery", - Discovery::CloudServiceDashboard => "Cloud Service Dashboard", - Discovery::DebuggerEvasion => "Debugger Evasion", - Discovery::SystemTimeDiscovery => "System Time Discovery", - }) - } -} -impl fmt::Display for Collection { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Collection::ScreenCapture => "Screen Capture", - Collection::AdversaryInTheMiddle => "Adversary-in-the-Middle", - Collection::DataFromConfigurationRepository => "Data from Configuration Repository", - Collection::AudioCapture => "Audio Capture", - Collection::EmailCollection => "Email Collection", - Collection::DataFromRemovableMedia => "Data from Removable Media", - Collection::AutomatedCollection => "Automated Collection", - Collection::ClipboardData => "Clipboard Data", - Collection::DataFromCloudStorage => "Data from Cloud Storage", - Collection::DataFromLocalSystem => "Data from Local System", - Collection::ArchiveCollectedData => "Archive Collected Data", - Collection::BrowserSessionHijacking => "Browser Session Hijacking", - Collection::VideoCapture => "Video Capture", - Collection::DataStaged => "Data Staged", - Collection::DataFromNetworkSharedDrive => "Data from Network Shared Drive", - Collection::InputCapture => "Input Capture", - Collection::DataFromInformationRepositories => "Data from Information Repositories", - }) - } -} -impl fmt::Display for ResourceDevelopment { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - ResourceDevelopment::AcquireInfrastructure => "Acquire Infrastructure", - ResourceDevelopment::CompromiseInfrastructure => "Compromise Infrastructure", - ResourceDevelopment::CompromiseAccounts => "Compromise Accounts", - ResourceDevelopment::StageCapabilities => "Stage Capabilities", - ResourceDevelopment::EstablishAccounts => "Establish Accounts", - ResourceDevelopment::ObtainCapabilities => "Obtain Capabilities", - ResourceDevelopment::AcquireAccess => "Acquire Access", - ResourceDevelopment::DevelopCapabilities => "Develop Capabilities", - }) - } -} -impl fmt::Display for Reconnaissance { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - Reconnaissance::GatherVictimHostInformation => "Gather Victim Host Information", - Reconnaissance::SearchVictimOwnedWebsites => "Search Victim-Owned Websites", - Reconnaissance::GatherVictimIdentityInformation => "Gather Victim Identity Information", - Reconnaissance::SearchOpenTechnicalDatabases => "Search Open Technical Databases", - Reconnaissance::ActiveScanning => "Active Scanning", - Reconnaissance::GatherVictimOrgInformation => "Gather Victim Org Information", - Reconnaissance::GatherVictimNetworkInformation => "Gather Victim Network Information", - Reconnaissance::SearchOpenWebsitesDomains => "Search Open Websites/Domains", - Reconnaissance::SearchClosedSources => "Search Closed Sources", - Reconnaissance::PhishingForInformation => "Phishing for Information", - }) - } -} -impl fmt::Display for CommandAndControl { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - CommandAndControl::ApplicationLayerProtocol => "Application Layer Protocol", - CommandAndControl::RemoteAccessSoftware => "Remote Access Software", - CommandAndControl::ContentInjection => "Content Injection", - CommandAndControl::TrafficSignaling => "Traffic Signaling", - CommandAndControl::ProtocolTunneling => "Protocol Tunneling", - CommandAndControl::CommunicationThroughRemovableMedia => "Communication Through Removable Media", - CommandAndControl::Proxy => "Proxy", - CommandAndControl::DynamicResolution => "Dynamic Resolution", - CommandAndControl::WebService => "Web Service", - CommandAndControl::MultiStageChannels => "Multi-Stage Channels", - CommandAndControl::DataObfuscation => "Data Obfuscation", - CommandAndControl::NonStandardPort => "Non-Standard Port", - CommandAndControl::EncryptedChannel => "Encrypted Channel", - CommandAndControl::NonApplicationLayerProtocol => "Non-Application Layer Protocol", - CommandAndControl::DataEncoding => "Data Encoding", - CommandAndControl::IngressToolTransfer => "Ingress Tool Transfer", - CommandAndControl::FallbackChannels => "Fallback Channels", - }) - } -} -impl fmt::Display for InitialAccess { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match self { - InitialAccess::ExternalRemoteServices => "External Remote Services", - InitialAccess::ReplicationThroughRemovableMedia => "Replication Through Removable Media", - InitialAccess::SupplyChainCompromise => "Supply Chain Compromise", - InitialAccess::ExploitPublicFacingApplication => "Exploit Public-Facing Application", - InitialAccess::ContentInjection => "Content Injection", - InitialAccess::TrustedRelationship => "Trusted Relationship", - InitialAccess::Phishing => "Phishing", - InitialAccess::ValidAccounts => "Valid Accounts", - InitialAccess::HardwareAdditions => "Hardware Additions", - InitialAccess::DriveByCompromise => "Drive-by Compromise", - }) - } -} -impl FromStr for Tactic { - type Err = (); - fn from_str(s: &str) -> Result { - Err(()) - .or_else(|_| CredentialAccess::from_str(s).map(Tactic::CredentialAccess)) - .or_else(|_| Execution::from_str(s).map(Tactic::Execution)) - .or_else(|_| Impact::from_str(s).map(Tactic::Impact)) - .or_else(|_| Persistence::from_str(s).map(Tactic::Persistence)) - .or_else(|_| PrivilegeEscalation::from_str(s).map(Tactic::PrivilegeEscalation)) - .or_else(|_| LateralMovement::from_str(s).map(Tactic::LateralMovement)) - .or_else(|_| DefenseEvasion::from_str(s).map(Tactic::DefenseEvasion)) - .or_else(|_| Exfiltration::from_str(s).map(Tactic::Exfiltration)) - .or_else(|_| Discovery::from_str(s).map(Tactic::Discovery)) - .or_else(|_| Collection::from_str(s).map(Tactic::Collection)) - .or_else(|_| ResourceDevelopment::from_str(s).map(Tactic::ResourceDevelopment)) - .or_else(|_| Reconnaissance::from_str(s).map(Tactic::Reconnaissance)) - .or_else(|_| CommandAndControl::from_str(s).map(Tactic::CommandAndControl)) - .or_else(|_| InitialAccess::from_str(s).map(Tactic::InitialAccess)) - } -} -impl FromStr for CredentialAccess { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Adversary-in-the-Middle" => Ok(CredentialAccess::AdversaryInTheMiddle), - "OS Credential Dumping" => Ok(CredentialAccess::OsCredentialDumping), - "Steal Web Session Cookie" => Ok(CredentialAccess::StealWebSessionCookie), - "Network Sniffing" => Ok(CredentialAccess::NetworkSniffing), - "Steal or Forge Kerberos Tickets" => Ok(CredentialAccess::StealOrForgeKerberosTickets), - "Credentials from Password Stores" => Ok(CredentialAccess::CredentialsFromPasswordStores), - "Unsecured Credentials" => Ok(CredentialAccess::UnsecuredCredentials), - "Steal or Forge Authentication Certificates" => Ok(CredentialAccess::StealOrForgeAuthenticationCertificates), - "Steal Application Access Token" => Ok(CredentialAccess::StealApplicationAccessToken), - "Forge Web Credentials" => Ok(CredentialAccess::ForgeWebCredentials), - "Multi-Factor Authentication Request Generation" => Ok(CredentialAccess::MultiFactorAuthenticationRequestGeneration), - "Exploitation for Credential Access" => Ok(CredentialAccess::ExploitationForCredentialAccess), - "Brute Force" => Ok(CredentialAccess::BruteForce), - "Forced Authentication" => Ok(CredentialAccess::ForcedAuthentication), - "Input Capture" => Ok(CredentialAccess::InputCapture), - "Multi-Factor Authentication Interception" => Ok(CredentialAccess::MultiFactorAuthenticationInterception), - "Modify Authentication Process" => Ok(CredentialAccess::ModifyAuthenticationProcess), - _ => Err(()), - } - } -} -impl FromStr for Execution { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Windows Management Instrumentation" => Ok(Execution::WindowsManagementInstrumentation), - "Shared Modules" => Ok(Execution::SharedModules), - "Scheduled Task/Job" => Ok(Execution::ScheduledTaskJob), - "Native API" => Ok(Execution::NativeApi), - "Deploy Container" => Ok(Execution::DeployContainer), - "Command and Scripting Interpreter" => Ok(Execution::CommandAndScriptingInterpreter), - "Container Administration Command" => Ok(Execution::ContainerAdministrationCommand), - "User Execution" => Ok(Execution::UserExecution), - "Software Deployment Tools" => Ok(Execution::SoftwareDeploymentTools), - "Inter-Process Communication" => Ok(Execution::InterProcessCommunication), - "Exploitation for Client Execution" => Ok(Execution::ExploitationForClientExecution), - "System Services" => Ok(Execution::SystemServices), - "Cloud Administration Command" => Ok(Execution::CloudAdministrationCommand), - "Serverless Execution" => Ok(Execution::ServerlessExecution), - _ => Err(()), - } - } -} -impl FromStr for Impact { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Disk Wipe" => Ok(Impact::DiskWipe), - "Service Stop" => Ok(Impact::ServiceStop), - "Defacement" => Ok(Impact::Defacement), - "Financial Theft" => Ok(Impact::FinancialTheft), - "Data Manipulation" => Ok(Impact::DataManipulation), - "Account Access Removal" => Ok(Impact::AccountAccessRemoval), - "Data Encrypted for Impact" => Ok(Impact::DataEncryptedForImpact), - "Endpoint Denial of Service" => Ok(Impact::EndpointDenialOfService), - "Resource Hijacking" => Ok(Impact::ResourceHijacking), - "Data Destruction" => Ok(Impact::DataDestruction), - "Network Denial of Service" => Ok(Impact::NetworkDenialOfService), - "Firmware Corruption" => Ok(Impact::FirmwareCorruption), - "Inhibit System Recovery" => Ok(Impact::InhibitSystemRecovery), - "System Shutdown/Reboot" => Ok(Impact::SystemShutdownReboot), - _ => Err(()), - } - } -} -impl FromStr for Persistence { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Boot or Logon Initialization Scripts" => Ok(Persistence::BootOrLogonInitializationScripts), - "Create or Modify System Process" => Ok(Persistence::CreateOrModifySystemProcess), - "External Remote Services" => Ok(Persistence::ExternalRemoteServices), - "Boot or Logon Autostart Execution" => Ok(Persistence::BootOrLogonAutostartExecution), - "Office Application Startup" => Ok(Persistence::OfficeApplicationStartup), - "Scheduled Task/Job" => Ok(Persistence::ScheduledTaskJob), - "Browser Extensions" => Ok(Persistence::BrowserExtensions), - "Traffic Signaling" => Ok(Persistence::TrafficSignaling), - "Implant Internal Image" => Ok(Persistence::ImplantInternalImage), - "Pre-OS Boot" => Ok(Persistence::PreOsBoot), - "Compromise Client Software Binary" => Ok(Persistence::CompromiseClientSoftwareBinary), - "Account Manipulation" => Ok(Persistence::AccountManipulation), - "Hijack Execution Flow" => Ok(Persistence::HijackExecutionFlow), - "Valid Accounts" => Ok(Persistence::ValidAccounts), - "Event Triggered Execution" => Ok(Persistence::EventTriggeredExecution), - "BITS Jobs" => Ok(Persistence::BitsJobs), - "Server Software Component" => Ok(Persistence::ServerSoftwareComponent), - "Create Account" => Ok(Persistence::CreateAccount), - "Power Settings" => Ok(Persistence::PowerSettings), - "Modify Authentication Process" => Ok(Persistence::ModifyAuthenticationProcess), - _ => Err(()), - } - } -} -impl FromStr for PrivilegeEscalation { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Boot or Logon Initialization Scripts" => Ok(PrivilegeEscalation::BootOrLogonInitializationScripts), - "Create or Modify System Process" => Ok(PrivilegeEscalation::CreateOrModifySystemProcess), - "Boot or Logon Autostart Execution" => Ok(PrivilegeEscalation::BootOrLogonAutostartExecution), - "Scheduled Task/Job" => Ok(PrivilegeEscalation::ScheduledTaskJob), - "Process Injection" => Ok(PrivilegeEscalation::ProcessInjection), - "Escape to Host" => Ok(PrivilegeEscalation::EscapeToHost), - "Abuse Elevation Control Mechanism" => Ok(PrivilegeEscalation::AbuseElevationControlMechanism), - "Account Manipulation" => Ok(PrivilegeEscalation::AccountManipulation), - "Hijack Execution Flow" => Ok(PrivilegeEscalation::HijackExecutionFlow), - "Valid Accounts" => Ok(PrivilegeEscalation::ValidAccounts), - "Exploitation for Privilege Escalation" => Ok(PrivilegeEscalation::ExploitationForPrivilegeEscalation), - "Event Triggered Execution" => Ok(PrivilegeEscalation::EventTriggeredExecution), - "Access Token Manipulation" => Ok(PrivilegeEscalation::AccessTokenManipulation), - "Domain Policy Modification" => Ok(PrivilegeEscalation::DomainPolicyModification), - _ => Err(()), - } - } -} -impl FromStr for LateralMovement { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Taint Shared Content" => Ok(LateralMovement::TaintSharedContent), - "Replication Through Removable Media" => Ok(LateralMovement::ReplicationThroughRemovableMedia), - "Use Alternate Authentication Material" => Ok(LateralMovement::UseAlternateAuthenticationMaterial), - "Remote Services" => Ok(LateralMovement::RemoteServices), - "Remote Service Session Hijacking" => Ok(LateralMovement::RemoteServiceSessionHijacking), - "Software Deployment Tools" => Ok(LateralMovement::SoftwareDeploymentTools), - "Exploitation of Remote Services" => Ok(LateralMovement::ExploitationOfRemoteServices), - "Internal Spearphishing" => Ok(LateralMovement::InternalSpearphishing), - "Lateral Tool Transfer" => Ok(LateralMovement::LateralToolTransfer), - _ => Err(()), - } - } -} -impl FromStr for DefenseEvasion { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Direct Volume Access" => Ok(DefenseEvasion::DirectVolumeAccess), - "Rootkit" => Ok(DefenseEvasion::Rootkit), - "Modify Cloud Compute Infrastructure" => Ok(DefenseEvasion::ModifyCloudComputeInfrastructure), - "Weaken Encryption" => Ok(DefenseEvasion::WeakenEncryption), - "Hide Artifacts" => Ok(DefenseEvasion::HideArtifacts), - "Indirect Command Execution" => Ok(DefenseEvasion::IndirectCommandExecution), - "Deobfuscate/Decode Files or Information" => Ok(DefenseEvasion::DeobfuscateDecodeFilesOrInformation), - "Impair Defenses" => Ok(DefenseEvasion::ImpairDefenses), - "Masquerading" => Ok(DefenseEvasion::Masquerading), - "Process Injection" => Ok(DefenseEvasion::ProcessInjection), - "Traffic Signaling" => Ok(DefenseEvasion::TrafficSignaling), - "System Binary Proxy Execution" => Ok(DefenseEvasion::SystemBinaryProxyExecution), - "Reflective Code Loading" => Ok(DefenseEvasion::ReflectiveCodeLoading), - "Use Alternate Authentication Material" => Ok(DefenseEvasion::UseAlternateAuthenticationMaterial), - "Rogue Domain Controller" => Ok(DefenseEvasion::RogueDomainController), - "Deploy Container" => Ok(DefenseEvasion::DeployContainer), - "Modify Registry" => Ok(DefenseEvasion::ModifyRegistry), - "Unused/Unsupported Cloud Regions" => Ok(DefenseEvasion::UnusedUnsupportedCloudRegions), - "File and Directory Permissions Modification" => Ok(DefenseEvasion::FileAndDirectoryPermissionsModification), - "Abuse Elevation Control Mechanism" => Ok(DefenseEvasion::AbuseElevationControlMechanism), - "Indicator Removal" => Ok(DefenseEvasion::IndicatorRemoval), - "Plist File Modification" => Ok(DefenseEvasion::PlistFileModification), - "Pre-OS Boot" => Ok(DefenseEvasion::PreOsBoot), - "Build Image on Host" => Ok(DefenseEvasion::BuildImageOnHost), - "Virtualization/Sandbox Evasion" => Ok(DefenseEvasion::VirtualizationSandboxEvasion), - "Execution Guardrails" => Ok(DefenseEvasion::ExecutionGuardrails), - "Modify System Image" => Ok(DefenseEvasion::ModifySystemImage), - "Hijack Execution Flow" => Ok(DefenseEvasion::HijackExecutionFlow), - "Valid Accounts" => Ok(DefenseEvasion::ValidAccounts), - "Obfuscated Files or Information" => Ok(DefenseEvasion::ObfuscatedFilesOrInformation), - "Network Boundary Bridging" => Ok(DefenseEvasion::NetworkBoundaryBridging), - "Subvert Trust Controls" => Ok(DefenseEvasion::SubvertTrustControls), - "BITS Jobs" => Ok(DefenseEvasion::BitsJobs), - "Impersonation" => Ok(DefenseEvasion::Impersonation), - "Template Injection" => Ok(DefenseEvasion::TemplateInjection), - "Access Token Manipulation" => Ok(DefenseEvasion::AccessTokenManipulation), - "Debugger Evasion" => Ok(DefenseEvasion::DebuggerEvasion), - "Domain Policy Modification" => Ok(DefenseEvasion::DomainPolicyModification), - "XSL Script Processing" => Ok(DefenseEvasion::XslScriptProcessing), - "Modify Authentication Process" => Ok(DefenseEvasion::ModifyAuthenticationProcess), - "System Script Proxy Execution" => Ok(DefenseEvasion::SystemScriptProxyExecution), - "Exploitation for Defense Evasion" => Ok(DefenseEvasion::ExploitationForDefenseEvasion), - "Trusted Developer Utilities Proxy Execution" => Ok(DefenseEvasion::TrustedDeveloperUtilitiesProxyExecution), - _ => Err(()), - } - } -} -impl FromStr for Exfiltration { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Exfiltration Over Web Service" => Ok(Exfiltration::ExfiltrationOverWebService), - "Scheduled Transfer" => Ok(Exfiltration::ScheduledTransfer), - "Exfiltration Over Other Network Medium" => Ok(Exfiltration::ExfiltrationOverOtherNetworkMedium), - "Automated Exfiltration" => Ok(Exfiltration::AutomatedExfiltration), - "Exfiltration Over C2 Channel" => Ok(Exfiltration::ExfiltrationOverC2Channel), - "Exfiltration Over Alternative Protocol" => Ok(Exfiltration::ExfiltrationOverAlternativeProtocol), - "Data Transfer Size Limits" => Ok(Exfiltration::DataTransferSizeLimits), - "Transfer Data to Cloud Account" => Ok(Exfiltration::TransferDataToCloudAccount), - "Exfiltration Over Physical Medium" => Ok(Exfiltration::ExfiltrationOverPhysicalMedium), - _ => Err(()), - } - } -} -impl FromStr for Discovery { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "System Owner/User Discovery" => Ok(Discovery::SystemOwnerUserDiscovery), - "Container and Resource Discovery" => Ok(Discovery::ContainerAndResourceDiscovery), - "Permission Groups Discovery" => Ok(Discovery::PermissionGroupsDiscovery), - "Group Policy Discovery" => Ok(Discovery::GroupPolicyDiscovery), - "Device Driver Discovery" => Ok(Discovery::DeviceDriverDiscovery), - "System Service Discovery" => Ok(Discovery::SystemServiceDiscovery), - "Network Sniffing" => Ok(Discovery::NetworkSniffing), - "Network Share Discovery" => Ok(Discovery::NetworkShareDiscovery), - "Peripheral Device Discovery" => Ok(Discovery::PeripheralDeviceDiscovery), - "System Information Discovery" => Ok(Discovery::SystemInformationDiscovery), - "Application Window Discovery" => Ok(Discovery::ApplicationWindowDiscovery), - "Cloud Infrastructure Discovery" => Ok(Discovery::CloudInfrastructureDiscovery), - "Browser Information Discovery" => Ok(Discovery::BrowserInformationDiscovery), - "System Network Configuration Discovery" => Ok(Discovery::SystemNetworkConfigurationDiscovery), - "Account Discovery" => Ok(Discovery::AccountDiscovery), - "Domain Trust Discovery" => Ok(Discovery::DomainTrustDiscovery), - "File and Directory Discovery" => Ok(Discovery::FileAndDirectoryDiscovery), - "System Network Connections Discovery" => Ok(Discovery::SystemNetworkConnectionsDiscovery), - "Virtualization/Sandbox Evasion" => Ok(Discovery::VirtualizationSandboxEvasion), - "Cloud Storage Object Discovery" => Ok(Discovery::CloudStorageObjectDiscovery), - "Log Enumeration" => Ok(Discovery::LogEnumeration), - "Process Discovery" => Ok(Discovery::ProcessDiscovery), - "Password Policy Discovery" => Ok(Discovery::PasswordPolicyDiscovery), - "Query Registry" => Ok(Discovery::QueryRegistry), - "System Location Discovery" => Ok(Discovery::SystemLocationDiscovery), - "Cloud Service Discovery" => Ok(Discovery::CloudServiceDiscovery), - "Remote System Discovery" => Ok(Discovery::RemoteSystemDiscovery), - "Network Service Discovery" => Ok(Discovery::NetworkServiceDiscovery), - "Software Discovery" => Ok(Discovery::SoftwareDiscovery), - "Cloud Service Dashboard" => Ok(Discovery::CloudServiceDashboard), - "Debugger Evasion" => Ok(Discovery::DebuggerEvasion), - "System Time Discovery" => Ok(Discovery::SystemTimeDiscovery), - _ => Err(()), - } - } -} -impl FromStr for Collection { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Screen Capture" => Ok(Collection::ScreenCapture), - "Adversary-in-the-Middle" => Ok(Collection::AdversaryInTheMiddle), - "Data from Configuration Repository" => Ok(Collection::DataFromConfigurationRepository), - "Audio Capture" => Ok(Collection::AudioCapture), - "Email Collection" => Ok(Collection::EmailCollection), - "Data from Removable Media" => Ok(Collection::DataFromRemovableMedia), - "Automated Collection" => Ok(Collection::AutomatedCollection), - "Clipboard Data" => Ok(Collection::ClipboardData), - "Data from Cloud Storage" => Ok(Collection::DataFromCloudStorage), - "Data from Local System" => Ok(Collection::DataFromLocalSystem), - "Archive Collected Data" => Ok(Collection::ArchiveCollectedData), - "Browser Session Hijacking" => Ok(Collection::BrowserSessionHijacking), - "Video Capture" => Ok(Collection::VideoCapture), - "Data Staged" => Ok(Collection::DataStaged), - "Data from Network Shared Drive" => Ok(Collection::DataFromNetworkSharedDrive), - "Input Capture" => Ok(Collection::InputCapture), - "Data from Information Repositories" => Ok(Collection::DataFromInformationRepositories), - _ => Err(()), - } - } -} -impl FromStr for ResourceDevelopment { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Acquire Infrastructure" => Ok(ResourceDevelopment::AcquireInfrastructure), - "Compromise Infrastructure" => Ok(ResourceDevelopment::CompromiseInfrastructure), - "Compromise Accounts" => Ok(ResourceDevelopment::CompromiseAccounts), - "Stage Capabilities" => Ok(ResourceDevelopment::StageCapabilities), - "Establish Accounts" => Ok(ResourceDevelopment::EstablishAccounts), - "Obtain Capabilities" => Ok(ResourceDevelopment::ObtainCapabilities), - "Acquire Access" => Ok(ResourceDevelopment::AcquireAccess), - "Develop Capabilities" => Ok(ResourceDevelopment::DevelopCapabilities), - _ => Err(()), - } - } -} -impl FromStr for Reconnaissance { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Gather Victim Host Information" => Ok(Reconnaissance::GatherVictimHostInformation), - "Search Victim-Owned Websites" => Ok(Reconnaissance::SearchVictimOwnedWebsites), - "Gather Victim Identity Information" => Ok(Reconnaissance::GatherVictimIdentityInformation), - "Search Open Technical Databases" => Ok(Reconnaissance::SearchOpenTechnicalDatabases), - "Active Scanning" => Ok(Reconnaissance::ActiveScanning), - "Gather Victim Org Information" => Ok(Reconnaissance::GatherVictimOrgInformation), - "Gather Victim Network Information" => Ok(Reconnaissance::GatherVictimNetworkInformation), - "Search Open Websites/Domains" => Ok(Reconnaissance::SearchOpenWebsitesDomains), - "Search Closed Sources" => Ok(Reconnaissance::SearchClosedSources), - "Phishing for Information" => Ok(Reconnaissance::PhishingForInformation), - _ => Err(()), - } - } -} -impl FromStr for CommandAndControl { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "Application Layer Protocol" => Ok(CommandAndControl::ApplicationLayerProtocol), - "Remote Access Software" => Ok(CommandAndControl::RemoteAccessSoftware), - "Content Injection" => Ok(CommandAndControl::ContentInjection), - "Traffic Signaling" => Ok(CommandAndControl::TrafficSignaling), - "Protocol Tunneling" => Ok(CommandAndControl::ProtocolTunneling), - "Communication Through Removable Media" => Ok(CommandAndControl::CommunicationThroughRemovableMedia), - "Proxy" => Ok(CommandAndControl::Proxy), - "Dynamic Resolution" => Ok(CommandAndControl::DynamicResolution), - "Web Service" => Ok(CommandAndControl::WebService), - "Multi-Stage Channels" => Ok(CommandAndControl::MultiStageChannels), - "Data Obfuscation" => Ok(CommandAndControl::DataObfuscation), - "Non-Standard Port" => Ok(CommandAndControl::NonStandardPort), - "Encrypted Channel" => Ok(CommandAndControl::EncryptedChannel), - "Non-Application Layer Protocol" => Ok(CommandAndControl::NonApplicationLayerProtocol), - "Data Encoding" => Ok(CommandAndControl::DataEncoding), - "Ingress Tool Transfer" => Ok(CommandAndControl::IngressToolTransfer), - "Fallback Channels" => Ok(CommandAndControl::FallbackChannels), - _ => Err(()), - } - } -} -impl FromStr for InitialAccess { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "External Remote Services" => Ok(InitialAccess::ExternalRemoteServices), - "Replication Through Removable Media" => Ok(InitialAccess::ReplicationThroughRemovableMedia), - "Supply Chain Compromise" => Ok(InitialAccess::SupplyChainCompromise), - "Exploit Public-Facing Application" => Ok(InitialAccess::ExploitPublicFacingApplication), - "Content Injection" => Ok(InitialAccess::ContentInjection), - "Trusted Relationship" => Ok(InitialAccess::TrustedRelationship), - "Phishing" => Ok(InitialAccess::Phishing), - "Valid Accounts" => Ok(InitialAccess::ValidAccounts), - "Hardware Additions" => Ok(InitialAccess::HardwareAdditions), - "Drive-by Compromise" => Ok(InitialAccess::DriveByCompromise), - _ => Err(()), - } - } -} diff --git a/kraken/migrations/0004_testssl.toml b/kraken/migrations/0004_testssl.toml index a31264df0..82c141966 100644 --- a/kraken/migrations/0004_testssl.toml +++ b/kraken/migrations/0004_testssl.toml @@ -26,7 +26,7 @@ Type = "auto_create_time" Type = "not_null" [[Migration.Operations.Fields]] -Name = "target_host" +Name = "domain" Type = "varchar" [[Migration.Operations.Fields.Annotations]] @@ -175,31 +175,6 @@ Type = "varchar" Type = "max_length" Value = 255 -[[Migration.Operations.Fields]] -Name = "mitre" -Type = "varchar" - -[[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 - -[[Migration.Operations.Fields]] -Name = "severity" -Type = "choices" - -[[Migration.Operations.Fields.Annotations]] -Type = "choices" -Value = [ - "None", - "Low", - "Medium", - "High", - "Critical", -] - -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" - [[Migration.Operations]] Type = "CreateField" Model = "testsslresultheader" diff --git a/kraken/src/api/handler/aggregation_source/utils.rs b/kraken/src/api/handler/aggregation_source/utils.rs index 1a6513317..41d37f51c 100644 --- a/kraken/src/api/handler/aggregation_source/utils.rs +++ b/kraken/src/api/handler/aggregation_source/utils.rs @@ -447,8 +447,8 @@ impl FullAggregationSource { uuid: result.uuid, attack: *result.attack.key(), created_at: result.created_at, - target_host: result.target_host, - ip: result.ip.ip().to_string(), + domain: result.domain, + ip: result.ip.ip(), port: result.port as u16, rdns: result.rdns, service: result.service, diff --git a/kraken/src/api/handler/attack_results/handler.rs b/kraken/src/api/handler/attack_results/handler.rs index d1c5d830b..349bc1c04 100644 --- a/kraken/src/api/handler/attack_results/handler.rs +++ b/kraken/src/api/handler/attack_results/handler.rs @@ -752,8 +752,8 @@ pub async fn get_testssl_results( uuid: header.uuid, attack: attack_uuid, created_at: header.created_at, - target_host: header.target_host, - ip: header.ip.ip().to_string(), + domain: header.domain, + ip: header.ip.ip(), port: header.port as u16, rdns: header.rdns, service: header.service, diff --git a/kraken/src/api/handler/attack_results/schema.rs b/kraken/src/api/handler/attack_results/schema.rs index 0595c1695..f6ecb8669 100644 --- a/kraken/src/api/handler/attack_results/schema.rs +++ b/kraken/src/api/handler/attack_results/schema.rs @@ -1,3 +1,5 @@ +use std::net::IpAddr; + use chrono::{DateTime, Utc}; use ipnetwork::IpNetwork; use serde::{Deserialize, Serialize}; @@ -323,11 +325,12 @@ pub struct FullTestSSLResult { /// The point in time, this result was produced pub created_at: DateTime, - /// The original user target this result belongs to - pub target_host: String, + /// The domain which was used for SNI and certificate verification + pub domain: String, /// The scanned ip address - pub ip: String, + #[schema(value_type = String, example = "127.0.0.1")] + pub ip: IpAddr, /// The scanned port pub port: u16, diff --git a/kraken/src/api/handler/attacks/handler.rs b/kraken/src/api/handler/attacks/handler.rs index cd2449da7..0c460c96e 100644 --- a/kraken/src/api/handler/attacks/handler.rs +++ b/kraken/src/api/handler/attacks/handler.rs @@ -511,6 +511,10 @@ pub async fn testssl( starttls, } = req.into_inner(); + if port == 0 { + return Err(ApiError::InvalidPort); + } + let client = if let Some(leech_uuid) = leech_uuid { GLOBAL.leeches.get_leech(&leech_uuid)? } else { diff --git a/kraken/src/api/handler/attacks/schema.rs b/kraken/src/api/handler/attacks/schema.rs index 0279eeca9..6f7b7c166 100644 --- a/kraken/src/api/handler/attacks/schema.rs +++ b/kraken/src/api/handler/attacks/schema.rs @@ -276,7 +276,7 @@ pub struct TestSSLRequest { pub uri: String, /// The host to scan - #[schema(value_type = String)] + #[schema(value_type = String, example = "127.0.0.1")] pub host: IpAddr, /// The port to scan diff --git a/kraken/src/models/attack/mod.rs b/kraken/src/models/attack/mod.rs index d78d62dd4..da4e2607d 100644 --- a/kraken/src/models/attack/mod.rs +++ b/kraken/src/models/attack/mod.rs @@ -546,9 +546,10 @@ pub struct TestSSLResultHeader { /// The point in time, this result was produced #[rorm(auto_create_time)] pub created_at: DateTime, - /// The original user target this result belongs to + + /// The domain which was used for SNI and certificate verification #[rorm(max_length = 255)] - pub target_host: String, + pub domain: String, /// The scanned ip address pub ip: IpNetwork, @@ -603,13 +604,6 @@ pub struct TestSSLResultFinding { /// An associated cwe category #[rorm(max_length = 255)] pub cwe: Option, - - /// An associated mitre ATT&CK technique - #[rorm(max_length = 255)] - pub mitre: Option, - - /// An associated severity - pub severity: Severity, } /// A [`TestSSLResultFinding`]'s section @@ -677,20 +671,3 @@ pub enum TestSSLSeverity { /// The test's result pose a critical priority issue Critical, } - -/// A generic attack result's severity -#[derive( - Copy, Clone, Debug, DbEnum, Deserialize, Serialize, ToSchema, Ord, PartialOrd, Eq, PartialEq, -)] -pub enum Severity { - /// No issue - None = 0, - /// The test's result pose a low priority issue - Low = 1, - /// The test's result pose a medium priority issue - Medium = 2, - /// The test's result pose a high priority issue - High = 3, - /// The test's result pose a critical priority issue - Critical = 4, -} diff --git a/kraken/src/models/attack/patches.rs b/kraken/src/models/attack/patches.rs index d9f3ba02d..f63247efe 100644 --- a/kraken/src/models/attack/patches.rs +++ b/kraken/src/models/attack/patches.rs @@ -7,7 +7,7 @@ use crate::models::{ Attack, CertificateTransparencyResult, CertificateTransparencyValueName, DehashedQueryResult, DnsRecordResult, DnsRecordType, DnsTxtScanAttackResult, DnsTxtScanServiceHintEntry, DnsTxtScanServiceHintType, DnsTxtScanSpfEntry, DnsTxtScanSpfType, DnsTxtScanSummaryType, - HostAliveResult, ServiceCertainty, ServiceDetectionResult, Severity, TcpPortScanResult, + HostAliveResult, ServiceCertainty, ServiceDetectionResult, TcpPortScanResult, TestSSLResultFinding, TestSSLResultHeader, TestSSLSection, TestSSLSeverity, UdpServiceDetectionResult, }; @@ -136,7 +136,7 @@ pub(crate) struct UdpServiceDetectionResultInsert { pub(crate) struct TestSSLResultHeaderInsert { pub(crate) uuid: Uuid, pub(crate) attack: ForeignModel, - pub(crate) target_host: String, + pub(crate) domain: String, pub(crate) ip: IpNetwork, pub(crate) port: i32, pub(crate) rdns: String, @@ -154,6 +154,4 @@ pub(crate) struct TestSSLResultFindingInsert { pub(crate) testssl_severity: TestSSLSeverity, pub(crate) cve: Option, pub(crate) cwe: Option, - pub(crate) mitre: Option, - pub(crate) severity: Severity, } diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index 758bbeeaf..22ce3bfc6 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -3,8 +3,8 @@ use std::str::FromStr; use ipnetwork::IpNetwork; use kraken_proto::shared::Address; use kraken_proto::{ - mitre, test_ssl_scans, test_ssl_service, BasicAuth, StartTlsProtocol, TestSslRequest, - TestSslResponse, TestSslScanResult, TestSslScans, TestSslSeverity, + test_ssl_scans, test_ssl_service, BasicAuth, StartTlsProtocol, TestSslRequest, TestSslResponse, + TestSslScanResult, TestSslScans, TestSslSeverity, }; use log::error; use rorm::insert; @@ -16,7 +16,7 @@ use crate::chan::global::GLOBAL; use crate::chan::leech_manager::LeechClient; use crate::models::{ AggregationSource, AggregationTable, DomainCertainty, HostCertainty, PortCertainty, - PortProtocol, Severity, SourceType, TestSSLResultFinding, TestSSLResultFindingInsert, + PortProtocol, SourceType, TestSSLResultFinding, TestSSLResultFindingInsert, TestSSLResultHeader, TestSSLResultHeaderInsert, TestSSLSection, TestSSLSeverity, }; use crate::modules::attacks::{AttackContext, AttackError, HandleAttackResponse, TestSSLParams}; @@ -99,7 +99,11 @@ impl HandleAttackResponse for AttackContext { }; let port = match u16::from_str(&port) { - Ok(port) => port, + Ok(port) if port > 0 => port, + Ok(port) => { + error!("Testssl didn't return a valid port: {port}"); + return Ok(()); + } Err(err) => { error!("Testssl didn't return a valid port: {err}"); return Ok(()); @@ -151,13 +155,6 @@ impl HandleAttackResponse for AttackContext { }, cve: finding.cve, cwe: finding.cwe, - mitre: finding - .mitre - .map(mitre::Tactic::try_from) - .transpose()? - .as_ref() - .map(ToString::to_string), - severity: Severity::None, }) }) }) @@ -194,7 +191,7 @@ impl HandleAttackResponse for AttackContext { .single(&TestSSLResultHeaderInsert { uuid: Uuid::new_v4(), attack: ForeignModelByField::Key(self.attack_uuid), - target_host, + domain: target_host, ip, port: port as i32, rdns, diff --git a/leech/src/modules/testssl/mitre.rs b/leech/src/modules/testssl/mitre.rs deleted file mode 100644 index fa3580be0..000000000 --- a/leech/src/modules/testssl/mitre.rs +++ /dev/null @@ -1,18 +0,0 @@ -use kraken_proto::mitre::Tactic; - -use crate::modules::testssl::finding_id::FindingId; -use crate::modules::testssl::{Finding, Severity}; - -/// Categorize a finding into a tactic and technique from Mitre ATT&CK -pub fn categorize(finding: &Finding) -> Option { - // Only categorize actual problems - if matches!( - &finding.severity, - Severity::Debug | Severity::Info | Severity::Warn | Severity::Fatal | Severity::Ok - ) { - return None; - } - - let _id = FindingId::from(finding.id.as_str()); - None // TODO -} diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index ea3cc37c1..69bfa93cd 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -13,9 +13,7 @@ use tokio::process::Command; pub mod finding_id; mod json; mod json_pretty; -mod mitre; pub use self::json_pretty::*; -pub use self::mitre::categorize; /// The settings of a `testssl.sh` invocation #[derive(Debug)] @@ -281,11 +279,11 @@ pub async fn run_testssl(settings: TestSSLSettings) -> Result TestSslFinding { - let mitre = testssl::categorize(&finding); TestSslFinding { id: finding.id, severity: match finding.severity { @@ -688,7 +686,6 @@ impl ReqAttackService for Attacks { finding: finding.finding, cve: finding.cve, cwe: finding.cwe, - mitre: mitre.map(AttackTechnique::from), } } fn conv_findings(findings: Vec) -> Vec { diff --git a/utilities/mitre/README.md b/utilities/mitre/README.md deleted file mode 100644 index 89dbe2b3f..000000000 --- a/utilities/mitre/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# [Mitre](https://attack.mitre.org/) enum generator - -This python script generates `kraken-proto/src/mitre.rs`. - -It takes no arguments and writes the rust code to `stdout`. - -The json is takes its data from, is downloaded from [github](https://github.com/mitre/cti/blob/230f6c26b1554d90993e59cb60e0aeefef530147/enterprise-attack/enterprise-attack.json) and cached in `/tmp/`. \ No newline at end of file diff --git a/utilities/mitre/main.py b/utilities/mitre/main.py deleted file mode 100644 index e623fe09d..000000000 --- a/utilities/mitre/main.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python3 - -import os -import typing -import urllib.request -from dataclasses import dataclass - -from mitreattack.stix20 import MitreAttackData - - -FILE = "/tmp/enterprise-attack.json" -URL = "https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json" - - -@dataclass -class Technique: - name: str - ident: str - id: str - url: str - description: str - - -@dataclass -class Tactic: - name: str - ident: str - id: str - url: str - description: str - techniques: list[Technique] - - -def main(): - if not os.path.isfile(FILE): - urllib.request.urlretrieve(URL, FILE) - data = MitreAttackData(FILE) - - tactics = [ - Tactic( - tactic["name"], - to_camel_case(tactic["name"]), - tactic["external_references"][0]["external_id"][2:], - tactic["external_references"][0]["url"], - tactic["description"].splitlines()[0], - [ - Technique( - technique["name"], - to_camel_case(technique["name"]), - technique["external_references"][0]["external_id"][1:], - technique["external_references"][0]["url"], - technique["description"].splitlines()[0] - ) - for technique in data.get_techniques_by_tactic(tactic["x_mitre_shortname"], "enterprise-attack", True) - if not technique["x_mitre_is_subtechnique"] - ], - ) - for tactic in data.get_tactics(True) - ] - - print("#![allow(clippy::zero_prefixed_literal)]") - print("//! Enums representing the tactics and techniques from [Mitre ATT&CK](https://attack.mitre.org/)") - print("//!") - print("//! This file is auto-generated by `utilities/mitre`! Don't edit it directly!") - print("use std::fmt;") - print("use std::str::FromStr;") - print("use crate::InvalidArgumentError;") - print("use crate::shared::AttackTechnique;") - print("/// An entry in the [Mitre ATT&CK table](https://attack.mitre.org/)") - print("pub enum Tactic {") - for tactic in tactics: - print(f" /// [{tactic.name}]({tactic.url})") - print(f" ///") - print(f" /// {tactic.description}") - print(f" {tactic.ident}({tactic.ident}),") - print("") - print("}") - - for tactic in tactics: - print(f"/// [{tactic.name}]({tactic.url})'s techniques") - print(f"pub enum {tactic.ident} {{") - for technique in tactic.techniques: - print(f" /// [{technique.name}]({technique.url})") - print(f" ///") - print(f" /// {technique.description}") - print(f" {technique.ident},") - print("") - print("}") - - print("impl TryFrom for Tactic {") - print(" type Error = InvalidArgumentError;") - print(" fn try_from(value: AttackTechnique) -> Result {") - print(" let AttackTechnique { tactic, technique } = value;") - print(" Ok(match tactic {") - for tactic in tactics: - print(f" {tactic.id} => Self::{tactic.ident}({tactic.ident}::try_from(technique)?),") - print(" _ => return Err(InvalidArgumentError::InvalidMitreTactic(tactic)),") - print(" })") - print(" }") - print("}") - - for tactic in tactics: - print(f"impl TryFrom for {tactic.ident} {{") - print(" type Error = InvalidArgumentError;") - print(" fn try_from(value: u32) -> Result {") - print(" Ok(match value {") - for technique in tactic.techniques: - print(f" {technique.id} => Self::{technique.ident},") - print(f" _ => return Err(InvalidArgumentError::InvalidMitreTechnique({tactic.id}, value)),") - print(" })") - print(" }") - print("}") - - print("impl From for AttackTechnique {") - print(" fn from(value: Tactic) -> Self {") - print(" let (tactic, technique) = match value {") - for tactic in tactics: - print(f" Tactic::{tactic.ident}(technique) => ({tactic.id}, technique.into()),") - print(" };") - print(" AttackTechnique { tactic, technique }") - print(" }") - print("}") - - for tactic in tactics: - print(f"impl From<{tactic.ident}> for u32 {{") - print(f" fn from(value: {tactic.ident}) -> Self {{") - print(" match value {") - for technique in tactic.techniques: - print(f" {tactic.ident}::{technique.ident} => {technique.id},") - print(" }") - print(" }") - print("}") - - print("impl fmt::Display for Tactic {") - print(" fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {") - print(" match self {") - for tactic in tactics: - print(f" Tactic::{tactic.ident}(technique) => technique.fmt(f),") - print(" }") - print(" }") - print("}") - - for tactic in tactics: - print(f"impl fmt::Display for {tactic.ident} {{") - print(" fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {") - print(" f.write_str(match self {") - for technique in tactic.techniques: - print(f" {tactic.ident}::{technique.ident} => \"{technique.name}\",") - print(" })") - print(" }") - print("}") - - print("impl FromStr for Tactic {") - print(" type Err = ();") - print(" fn from_str(s: &str) -> Result {") - print(" Err(())") - for tactic in tactics: - print(f" .or_else(|_| {tactic.ident}::from_str(s).map(Tactic::{tactic.ident}))") - print(" }") - print("}") - - for tactic in tactics: - print(f"impl FromStr for {tactic.ident} {{") - print(" type Err = ();") - print(" fn from_str(s: &str) -> Result {") - print(" match s {") - for technique in tactic.techniques: - print(f" \"{technique.name}\" => Ok({tactic.ident}::{technique.ident}),") - print(" _ => Err(()),") - print(" }") - print(" }") - print("}") - - -def to_camel_case(name: str) -> str: - import re - return "".join((part.capitalize() for part in re.split("[-/_ ]", name))) - - -if __name__ == "__main__": - main() - diff --git a/utilities/mitre/requirements.txt b/utilities/mitre/requirements.txt deleted file mode 100644 index 00394d798..000000000 --- a/utilities/mitre/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -mitreattack-python==3.0.2 From 497c5de0388621072a9dc49afff0cd6f4516cedb Mon Sep 17 00:00:00 2001 From: gammelalf Date: Tue, 27 Aug 2024 15:09:25 +0200 Subject: [PATCH 24/37] Fixed attacking http services --- .../src/views/workspace/workspace-attacks.tsx | 345 +++++++++--------- 1 file changed, 165 insertions(+), 180 deletions(-) diff --git a/kraken_frontend/src/views/workspace/workspace-attacks.tsx b/kraken_frontend/src/views/workspace/workspace-attacks.tsx index 47e5a462a..c0530028d 100644 --- a/kraken_frontend/src/views/workspace/workspace-attacks.tsx +++ b/kraken_frontend/src/views/workspace/workspace-attacks.tsx @@ -1,6 +1,5 @@ import React from "react"; import { Api } from "../../api/api"; -import { ApiError } from "../../api/error"; import { AttacksApi, BruteforceSubdomainsRequest, @@ -16,17 +15,16 @@ import { PortProtocol, QueryCertificateTransparencyRequest, QueryDehashedRequest, - ServiceDetectionRequest, TestSSLRequest, - UdpServiceDetectionRequest + ServiceDetectionRequest, + TestSSLRequest, + UdpServiceDetectionRequest, } from "../../api/generated"; import { ROUTES } from "../../routes"; import "../../styling/workspace-attacks.css"; import AttacksIcon from "../../svg/attacks"; import CloseIcon from "../../svg/close"; -import CONSOLE from "../../utils/console"; import { ObjectFns, handleApiError } from "../../utils/helper"; import { buildHttpServiceURL } from "../../utils/http-services"; -import { Result } from "../../utils/result"; import { AttackInputProps, BooleanAttackInput, @@ -36,7 +34,7 @@ import { NumberAttackInput, PortListInput, StringAttackInput, - WordlistAttackInput + WordlistAttackInput, } from "./attacks/attack-input"; import GenericAttackForm from "./attacks/generic-attack-form"; import { WORKSPACE_CONTEXT } from "./workspace"; @@ -160,10 +158,10 @@ export type AttackInputs = { jsonKey: string; inputs: { [T in Exclude]: - | (AttackRequestTypes[ReqType][T] extends readonly (infer ElementType)[] - ? AttackInput - : AttackInput) - | { fixed: AttackRequestTypes[ReqType][T] }; + | (AttackRequestTypes[ReqType][T] extends readonly (infer ElementType)[] + ? AttackInput + : AttackInput) + | { fixed: AttackRequestTypes[ReqType][T] }; }; }; @@ -195,11 +193,11 @@ export interface IAttackDescr { [index: string]: | IAttackInput | { - /** - * always a fixed value that is sent to the API without being able to be edited by the user. - */ - fixed: AnyApiValue; - }; + /** + * always a fixed value that is sent to the API without being able to be edited by the user. + */ + fixed: AnyApiValue; + }; }; }; } @@ -236,14 +234,14 @@ const ATTACKS: AllAttackDescr = { required: true, defaultValue: "", prefill: ["domain"], - type: StringAttackInput + type: StringAttackInput, }, wordlistUuid: { label: "Wordlist", multi: false, required: true, defaultValue: "", - type: WordlistAttackInput + type: WordlistAttackInput, }, concurrentLimit: { label: "Concurrency Limit", @@ -251,10 +249,10 @@ const ATTACKS: AllAttackDescr = { defaultValue: 100, required: true, type: NumberAttackInput, - group: "Advanced" - } - } - } + group: "Advanced", + }, + }, + }, }, certificate_transparency: { name: "Certificate Transparency", @@ -271,13 +269,13 @@ const ATTACKS: AllAttackDescr = { defaultValue: "", required: true, prefill: ["domain"], - type: StringAttackInput + type: StringAttackInput, }, includeExpired: { label: "Include expired certificates", multi: false, defaultValue: false, - type: BooleanAttackInput + type: BooleanAttackInput, }, maxRetries: { label: "Max. no. of retries", @@ -285,7 +283,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 3, required: true, type: NumberAttackInput, - group: "Advanced" + group: "Advanced", }, retryInterval: { label: "Retry interval", @@ -293,10 +291,10 @@ const ATTACKS: AllAttackDescr = { defaultValue: 500, required: true, type: DurationAttackInput, - group: "Advanced" - } - } - } + group: "Advanced", + }, + }, + }, }, dns_resolution: { name: "Dns Resolution", @@ -307,7 +305,7 @@ const ATTACKS: AllAttackDescr = { jsonKey: "dnsResolutionRequest", inputs: { concurrentLimit: { - fixed: 1 + fixed: 1, }, targets: { label: "Domain", @@ -315,10 +313,10 @@ const ATTACKS: AllAttackDescr = { defaultValue: undefined, type: StringAttackInput, prefill: ["domain"], - required: true - } - } - } + required: true, + }, + }, + }, }, dns_txt_scan: { name: "DNS TXT Scan", @@ -334,10 +332,10 @@ const ATTACKS: AllAttackDescr = { defaultValue: undefined, type: StringAttackInput, prefill: ["domain"], - required: true - } - } - } + required: true, + }, + }, + }, }, host_alive: { name: "Host alive", @@ -353,7 +351,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: undefined, prefill: ["domain", "ipAddr"], type: StringAttackInput, - required: true + required: true, }, timeout: { label: "Timeout (in ms)", @@ -361,7 +359,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 1000, type: DurationAttackInput, required: true, - group: "Advanced" + group: "Advanced", }, concurrentLimit: { label: "Concurrency Limit", @@ -369,10 +367,10 @@ const ATTACKS: AllAttackDescr = { defaultValue: 50, type: NumberAttackInput, required: true, - group: "Advanced" - } - } - } + group: "Advanced", + }, + }, + }, }, service_detection: { name: "Service Detection", @@ -389,7 +387,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: undefined, prefill: ["domain", "ipAddr"], type: StringAttackInput, - required: true + required: true, }, ports: { label: "Ports", @@ -399,7 +397,7 @@ const ATTACKS: AllAttackDescr = { prefill: ["port[Tcp]"], type: PortListInput, // eslint-disable-next-line jsdoc/require-jsdoc - preprocess: (v) => (typeof v == "number" ? [v] : v) + preprocess: (v) => (typeof v == "number" ? [v] : v), }, connectTimeout: { label: "Connect Timeout (in ms)", @@ -407,7 +405,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 1000, required: true, type: DurationAttackInput, - group: "Advanced" + group: "Advanced", }, receiveTimeout: { label: "Receive Timeout (in ms)", @@ -415,7 +413,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 500, type: DurationAttackInput, required: true, - group: "Advanced" + group: "Advanced", }, maxRetries: { label: "Max. no. of retries", @@ -423,7 +421,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 6, required: true, type: NumberAttackInput, - group: "Advanced" + group: "Advanced", }, retryInterval: { label: "Retry interval", @@ -431,7 +429,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 100, required: true, type: DurationAttackInput, - group: "Advanced" + group: "Advanced", }, concurrentLimit: { label: "Concurrency Limit", @@ -439,16 +437,16 @@ const ATTACKS: AllAttackDescr = { defaultValue: 500, required: true, type: NumberAttackInput, - group: "Advanced" + group: "Advanced", }, skipIcmpCheck: { label: "Skip icmp check", multi: false, defaultValue: true, - type: BooleanAttackInput - } - } - } + type: BooleanAttackInput, + }, + }, + }, }, udp_service_detection: { name: "UDP Service Detection", @@ -464,7 +462,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: undefined, prefill: ["domain", "ipAddr"], type: StringAttackInput, - required: true + required: true, }, ports: { label: "Ports", @@ -474,7 +472,7 @@ const ATTACKS: AllAttackDescr = { prefill: ["port[Udp]"], type: PortListInput, // eslint-disable-next-line jsdoc/require-jsdoc - preprocess: (v) => (typeof v == "number" ? [v] : v) + preprocess: (v) => (typeof v == "number" ? [v] : v), }, timeout: { label: "Timeout (in ms)", @@ -482,7 +480,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 1000, type: DurationAttackInput, group: "Advanced", - required: true + required: true, }, maxRetries: { label: "Max. no. of retries", @@ -490,7 +488,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 5, type: NumberAttackInput, group: "Advanced", - required: true + required: true, }, retryInterval: { label: "Retry interval", @@ -498,7 +496,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 1000, type: DurationAttackInput, group: "Advanced", - required: true + required: true, }, concurrentLimit: { label: "Concurrency Limit", @@ -506,10 +504,10 @@ const ATTACKS: AllAttackDescr = { defaultValue: 1024, type: NumberAttackInput, group: "Advanced", - required: true - } - } - } + required: true, + }, + }, + }, }, dehashed: { name: "Dehashed", @@ -535,10 +533,10 @@ const ATTACKS: AllAttackDescr = { if (v.port) return { ipAddress: { simple: v.port.host.ipAddr } }; if (v.service) return { ipAddress: { simple: v.service.host.ipAddr } }; return undefined; - } - } - } - } + }, + }, + }, + }, }, os_detection: { name: "OS detection", @@ -554,7 +552,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: undefined, prefill: ["domain", "ipAddr"], type: StringAttackInput, - required: true + required: true, }, sshPort: { defaultValue: 22, @@ -562,7 +560,7 @@ const ATTACKS: AllAttackDescr = { prefill: ["service[ssh].port"], multi: false, type: NullNumberAttackInput, - required: false + required: false, }, fingerprintPort: { defaultValue: undefined, @@ -570,7 +568,7 @@ const ATTACKS: AllAttackDescr = { label: "TCP Fingerprint Port", type: NullNumberAttackInput, multi: false, - required: false + required: false, }, fingerprintTimeout: { group: "TCP fingerprint task", @@ -578,7 +576,7 @@ const ATTACKS: AllAttackDescr = { label: "Timeout", type: DurationAttackInput, required: true, - multi: false + multi: false, }, sshTimeout: { group: "SSH task", @@ -586,7 +584,7 @@ const ATTACKS: AllAttackDescr = { label: "Timeout", type: DurationAttackInput, required: true, - multi: false + multi: false, }, sshConnectTimeout: { group: "SSH task", @@ -594,7 +592,7 @@ const ATTACKS: AllAttackDescr = { label: "Connection timeout", type: DurationAttackInput, required: true, - multi: false + multi: false, }, portAckTimeout: { group: "TCP SYN port test", @@ -602,7 +600,7 @@ const ATTACKS: AllAttackDescr = { label: "ACK timeout", type: DurationAttackInput, required: true, - multi: false + multi: false, }, portParallelSyns: { group: "TCP SYN port test", @@ -610,7 +608,7 @@ const ATTACKS: AllAttackDescr = { label: "Max parallel requests", type: NumberAttackInput, required: true, - multi: false + multi: false, }, concurrentLimit: { label: "Concurrency Limit", @@ -618,24 +616,26 @@ const ATTACKS: AllAttackDescr = { defaultValue: 32, required: true, type: NumberAttackInput, - group: "Advanced" - } - } - } + group: "Advanced", + }, + }, + }, }, testssl: { name: "Testssl", description: "Run testssl.sh to check a services tls configuration", category: AttackCategory.Ports, inputs: { - endpoint: "testssl", jsonKey: "testSSLRequest", inputs: { + endpoint: "testssl", + jsonKey: "testSSLRequest", + inputs: { uri: { label: "Domain", multi: false, defaultValue: "", required: true, prefill: ["domain"], - type: StringAttackInput + type: StringAttackInput, }, host: { label: "IP", @@ -643,7 +643,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: "", prefill: ["ipAddr"], type: StringAttackInput, - required: true + required: true, }, port: { label: "Port", @@ -651,7 +651,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 443, prefill: ["port[Tcp]"], type: NumberAttackInput, - required: true + required: true, }, connectTimeout: { label: "Connect Timeout (in s)", @@ -659,7 +659,7 @@ const ATTACKS: AllAttackDescr = { defaultValue: 5, type: NullNumberAttackInput, group: "Advanced", - required: true + required: true, }, opensslTimeout: { label: "OpenSSL Timeout (in s)", @@ -667,13 +667,13 @@ const ATTACKS: AllAttackDescr = { defaultValue: 5, type: NullNumberAttackInput, group: "Advanced", - required: true + required: true, }, basicAuth: { fixed: undefined }, - starttls: { fixed: undefined } - } - } - } + starttls: { fixed: undefined }, + }, + }, + }, }; const TARGET_TYPE = ["domain", "host", "port", "service", "httpService"] as const; @@ -730,21 +730,21 @@ export type PrefillType = */ type WorkspaceAttacksProps = | { - targetType?: never; - targetUuid?: never; -} + targetType?: never; + targetUuid?: never; + } | { - targetType: TargetType; - targetUuid: string; -} + targetType: TargetType; + targetUuid: string; + } | { - targetType: "selection"; - domains: string[]; - hosts: string[]; - ports: string[]; - services: string[]; - httpServices: string[]; -}; + targetType: "selection"; + domains: string[]; + hosts: string[]; + ports: string[]; + services: string[]; + httpServices: string[]; + }; /** * The full workspace attacks page, includes attack selector, description and @@ -752,67 +752,16 @@ type WorkspaceAttacksProps = */ export default function WorkspaceAttacks(props: WorkspaceAttacksProps) { const { - workspace: { uuid: workspace } + workspace: { uuid: workspace }, } = React.useContext(WORKSPACE_CONTEXT); const [selectedAttack, setSelectedAttack] = React.useState(null); const [hoverAttack, setHoverAttack] = React.useState(null); const [target, setTarget] = React.useState<{ name: string; selection: RawSelectionData[] }>({ name: "Loading...", - selection: [] + selection: [], }); - async function updateSelection() { - if (props.targetType != "selection") throw new Error("invalid state"); - - const workspaceUuid = workspace; - - function fetchAll( - api: { get: (workspaceUuid: string, thingUuid: string) => Promise> }, - list: string[] - ): Promise { - return new Promise((resolve, reject) => { - const res: T[] = []; - - /** `resolve(res)` once `res` has a value for each `list` input */ - function checkDone() { - if (res.length == list.length) { - resolve(res); - } - } - - checkDone(); - list.forEach((item) => { - api.get(workspaceUuid, item) - .then( - handleApiError((v) => { - res.push(v); - checkDone(); - }) - ) - .catch((v) => { - CONSOLE.error(v); - reject("failed looking up item " + item); - }); - }); - }); - } - - const inputs: { [group: string]: RawSelectionData[] } = { - hosts: (await fetchAll(Api.workspaces.hosts, props.hosts)).map((v) => ({ host: v })), - ports: (await fetchAll(Api.workspaces.ports, props.ports)).map((v) => ({ port: v })), - domains: (await fetchAll(Api.workspaces.domains, props.domains)).map((v) => ({ domain: v })), - services: (await fetchAll(Api.workspaces.services, props.services)).map((v) => ({ service: v })) - }; - - const selection: RawSelectionData[] = Object.keys(inputs).flatMap((k) => inputs[k]); - - setTarget((target) => ({ - name: target.name, - selection: selection - })); - } - function loadTarget() { switch (props.targetType) { case "domain": @@ -820,9 +769,9 @@ export default function WorkspaceAttacks(props: WorkspaceAttacksProps) { handleApiError((domain) => setTarget({ name: domain.domain, - selection: [{ domain }] - }) - ) + selection: [{ domain }], + }), + ), ); break; case "host": @@ -830,9 +779,9 @@ export default function WorkspaceAttacks(props: WorkspaceAttacksProps) { handleApiError((host) => setTarget({ name: host.ipAddr, - selection: [{ host }] - }) - ) + selection: [{ host }], + }), + ), ); break; case "port": @@ -840,9 +789,9 @@ export default function WorkspaceAttacks(props: WorkspaceAttacksProps) { handleApiError((port) => setTarget({ name: `${port.host.ipAddr}'s port ${port.port}`, - selection: [{ port }] - }) - ) + selection: [{ port }], + }), + ), ); break; case "service": @@ -853,9 +802,9 @@ export default function WorkspaceAttacks(props: WorkspaceAttacksProps) { name: port ? `${host.ipAddr}'s service ${name} on port ${port.port}` : `${host.ipAddr}'s service ${name}`, - selection: [{ service }] + selection: [{ service }], }); - }) + }), ); break; case "httpService": @@ -864,9 +813,9 @@ export default function WorkspaceAttacks(props: WorkspaceAttacksProps) { const { name } = httpService; setTarget({ name: `HTTP service ${name} on ${buildHttpServiceURL(httpService)}`, - selection: [{ httpService }] + selection: [{ httpService }], }); - }) + }), ); break; case "selection": @@ -875,13 +824,48 @@ export default function WorkspaceAttacks(props: WorkspaceAttacksProps) { `${props.hosts.length} hosts`, `${props.ports.length} ports`, `${props.domains.length} domains`, - `${props.services.length} services` + `${props.services.length} services`, + `${props.httpServices.length} http services`, ] .filter((s) => !s.startsWith("0 ")) .join(", "), - selection: [] + selection: [], }); - updateSelection(); + + const selection: RawSelectionData[] = []; + Promise.all([ + ...props.hosts.map((itemUuid) => + Api.workspaces.hosts + .get(workspace, itemUuid) + .then(handleApiError((host) => selection.push({ host }))), + ), + ...props.ports.map((itemUuid) => + Api.workspaces.ports + .get(workspace, itemUuid) + .then(handleApiError((port) => selection.push({ port }))), + ), + ...props.domains.map((itemUuid) => + Api.workspaces.domains + .get(workspace, itemUuid) + .then(handleApiError((domain) => selection.push({ domain }))), + ), + ...props.services.map((itemUuid) => + Api.workspaces.services + .get(workspace, itemUuid) + .then(handleApiError((service) => selection.push({ service }))), + ), + ...props.httpServices.map((itemUuid) => + Api.workspaces.httpServices + .get(workspace, itemUuid) + .then(handleApiError((httpService) => selection.push({ httpService }))), + ), + ]).then(() => + setTarget((target) => ({ + name: target.name, + selection: selection, + })), + ); + break; default: setTarget({ name: "Loading...", selection: [] }); @@ -897,7 +881,8 @@ export default function WorkspaceAttacks(props: WorkspaceAttacksProps) { "hosts" in props ? props.hosts : undefined, "ports" in props ? props.ports : undefined, "services" in props ? props.services : undefined, - props.targetType + "httpServices" in props ? props.httpServices : undefined, + props.targetType, ]); function renderSelection() { @@ -920,11 +905,11 @@ export default function WorkspaceAttacks(props: WorkspaceAttacksProps) {

Selection

- - {columnLabels.map((label) => ( - - ))} - + + {columnLabels.map((label) => ( + + ))} + {rows}
{label}
{label}
@@ -1001,8 +986,8 @@ function generateDisabled(prefill: RawSelectionData[]): Record [ v, prefill.length && - Object.values(generateAttackPrefill(v as AttackType, prefill)).every((v) => v.length == 0) - ]) + Object.values(generateAttackPrefill(v as AttackType, prefill)).every((v) => v.length == 0), + ]), ) as { [T in keyof typeof ATTACKS]: boolean }; } @@ -1040,7 +1025,7 @@ function generateAttackPrefill(attack: AttackType, prefill: RawSelectionData[]): // and remove rows that have missing required values values = values.filter( (row) => - !row.some((v, i) => v === undefined && (ATTACKS[attack].inputs.inputs as AnyAttackInput)[keys[i]].required) + !row.some((v, i) => v === undefined && (ATTACKS[attack].inputs.inputs as AnyAttackInput)[keys[i]].required), ); values = ObjectFns.transpose2D(values); if (keys.length != values.length) throw new Error("logic error"); From 822f03b6536b02e1c4b68f3f47faed2797795751 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Tue, 27 Aug 2024 16:45:50 +0200 Subject: [PATCH 25/37] Updated formatting of imports in testssl code --- kraken/src/models/attack/patches.rs | 2 +- kraken/src/modules/attacks/testssl.rs | 36 +++++++++++++++++------- leech/src/modules/testssl/finding_id.rs | 17 +++++++---- leech/src/modules/testssl/json.rs | 3 +- leech/src/modules/testssl/json_pretty.rs | 3 +- leech/src/modules/testssl/mod.rs | 4 ++- 6 files changed, 46 insertions(+), 19 deletions(-) diff --git a/kraken/src/models/attack/patches.rs b/kraken/src/models/attack/patches.rs index 8e49bc64b..0f100b4fd 100644 --- a/kraken/src/models/attack/patches.rs +++ b/kraken/src/models/attack/patches.rs @@ -21,11 +21,11 @@ use crate::models::OsDetectionResult; use crate::models::OsType; use crate::models::ServiceCertainty; use crate::models::ServiceDetectionResult; -use crate::models::UdpServiceDetectionResult; use crate::models::TestSSLResultFinding; use crate::models::TestSSLResultHeader; use crate::models::TestSSLSection; use crate::models::TestSSLSeverity; +use crate::models::UdpServiceDetectionResult; pub(crate) type BruteforceSubdomainsResultInsert = DnsRecordResultInsert; pub(crate) type DnsResolutionResultInsert = DnsRecordResultInsert; diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index 22ce3bfc6..90eded5ef 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -2,10 +2,15 @@ use std::str::FromStr; use ipnetwork::IpNetwork; use kraken_proto::shared::Address; -use kraken_proto::{ - test_ssl_scans, test_ssl_service, BasicAuth, StartTlsProtocol, TestSslRequest, TestSslResponse, - TestSslScanResult, TestSslScans, TestSslSeverity, -}; +use kraken_proto::test_ssl_scans; +use kraken_proto::test_ssl_service; +use kraken_proto::BasicAuth; +use kraken_proto::StartTlsProtocol; +use kraken_proto::TestSslRequest; +use kraken_proto::TestSslResponse; +use kraken_proto::TestSslScanResult; +use kraken_proto::TestSslScans; +use kraken_proto::TestSslSeverity; use log::error; use rorm::insert; use rorm::prelude::ForeignModelByField; @@ -14,12 +19,23 @@ use uuid::Uuid; use crate::api::handler::attacks::schema::StartTLSProtocol; use crate::chan::global::GLOBAL; use crate::chan::leech_manager::LeechClient; -use crate::models::{ - AggregationSource, AggregationTable, DomainCertainty, HostCertainty, PortCertainty, - PortProtocol, SourceType, TestSSLResultFinding, TestSSLResultFindingInsert, - TestSSLResultHeader, TestSSLResultHeaderInsert, TestSSLSection, TestSSLSeverity, -}; -use crate::modules::attacks::{AttackContext, AttackError, HandleAttackResponse, TestSSLParams}; +use crate::models::AggregationSource; +use crate::models::AggregationTable; +use crate::models::DomainCertainty; +use crate::models::HostCertainty; +use crate::models::PortCertainty; +use crate::models::PortProtocol; +use crate::models::SourceType; +use crate::models::TestSSLResultFinding; +use crate::models::TestSSLResultFindingInsert; +use crate::models::TestSSLResultHeader; +use crate::models::TestSSLResultHeaderInsert; +use crate::models::TestSSLSection; +use crate::models::TestSSLSeverity; +use crate::modules::attacks::AttackContext; +use crate::modules::attacks::AttackError; +use crate::modules::attacks::HandleAttackResponse; +use crate::modules::attacks::TestSSLParams; impl AttackContext { /// Executes the "testssl" attack diff --git a/leech/src/modules/testssl/finding_id.rs b/leech/src/modules/testssl/finding_id.rs index f79fb1251..48ec4389f 100644 --- a/leech/src/modules/testssl/finding_id.rs +++ b/leech/src/modules/testssl/finding_id.rs @@ -416,11 +416,18 @@ pub enum ScanIssues { impl From<&str> for FindingId { fn from(s: &str) -> Self { - use FindingId::{ - Certificate as crt, CipherList as cl, CipherOrder as co, Cookie as c, Hpkp as kp, - Hsts as ts, HttpHeader as hh, Logging as l, Pfs as pfs, Protocol as p, - ScanIssues as si, Vulnerabilities as v, - }; + use FindingId::Certificate as crt; + use FindingId::CipherList as cl; + use FindingId::CipherOrder as co; + use FindingId::Cookie as c; + use FindingId::Hpkp as kp; + use FindingId::Hsts as ts; + use FindingId::HttpHeader as hh; + use FindingId::Logging as l; + use FindingId::Pfs as pfs; + use FindingId::Protocol as p; + use FindingId::ScanIssues as si; + use FindingId::Vulnerabilities as v; const T: bool = true; const F: bool = false; diff --git a/leech/src/modules/testssl/json.rs b/leech/src/modules/testssl/json.rs index be7bd93ac..98045d24a 100644 --- a/leech/src/modules/testssl/json.rs +++ b/leech/src/modules/testssl/json.rs @@ -1,6 +1,7 @@ //! Struct defining `testssl.sh`'s `--json` output -use serde::{Deserialize, Serialize}; +use serde::Deserialize; +use serde::Serialize; /// The entire output file #[allow(dead_code)] diff --git a/leech/src/modules/testssl/json_pretty.rs b/leech/src/modules/testssl/json_pretty.rs index 591977e08..d9f1bc0e5 100644 --- a/leech/src/modules/testssl/json_pretty.rs +++ b/leech/src/modules/testssl/json_pretty.rs @@ -2,7 +2,8 @@ use std::num::NonZeroU64; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; +use serde::Serialize; /// The entire output file /// diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index 69bfa93cd..82bf63a8b 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -3,7 +3,9 @@ use std::io; use std::net::IpAddr; -use log::{debug, error, trace}; +use log::debug; +use log::error; +use log::trace; use tempfile::NamedTempFile; use thiserror::Error; use tokio::fs::File as TokioFile; From 0cca13d98125eff06a7a40cc3c26c9de97198998 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Tue, 27 Aug 2024 17:28:57 +0200 Subject: [PATCH 26/37] Added StartTLS to frontend --- .../src/styling/workspace-data-details.css | 15 ++++++++----- .../views/workspace/attacks/attack-input.tsx | 22 +++++++++++++++++-- .../src/views/workspace/workspace-attacks.tsx | 10 ++++++++- .../workspace-data-details-results.tsx | 11 +++++----- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/kraken_frontend/src/styling/workspace-data-details.css b/kraken_frontend/src/styling/workspace-data-details.css index 852e39967..00da07281 100644 --- a/kraken_frontend/src/styling/workspace-data-details.css +++ b/kraken_frontend/src/styling/workspace-data-details.css @@ -295,7 +295,6 @@ max-width: 30em; } - /* Base layout of testssl sections */ .workspace-data-details-testssl-section { display: grid; @@ -311,7 +310,7 @@ /* Set handling of long text based on hover */ .workspace-data-details-testssl-section > span:hover { overflow-wrap: anywhere; - } +} .workspace-data-details-testssl-section > span:not(:hover) { white-space: nowrap; overflow-x: hidden; @@ -319,10 +318,14 @@ } /* Set color based on testssl severity */ -.workspace-data-details-testssl-debug {} -.workspace-data-details-testssl-info {} -.workspace-data-details-testssl-warn {} -.workspace-data-details-testssl-fatal {} +.workspace-data-details-testssl-debug { +} +.workspace-data-details-testssl-info { +} +.workspace-data-details-testssl-warn { +} +.workspace-data-details-testssl-fatal { +} .workspace-data-details-testssl-ok { color: #008000; } diff --git a/kraken_frontend/src/views/workspace/attacks/attack-input.tsx b/kraken_frontend/src/views/workspace/attacks/attack-input.tsx index 77c0f364d..7fd911463 100644 --- a/kraken_frontend/src/views/workspace/attacks/attack-input.tsx +++ b/kraken_frontend/src/views/workspace/attacks/attack-input.tsx @@ -1,10 +1,10 @@ import React, { forwardRef, useEffect, useRef, useState } from "react"; import Select from "react-select"; import { Api } from "../../../api/api"; -import { PortOrRange, Query, SearchType } from "../../../api/generated"; +import { PortOrRange, Query, SearchType, StartTLSProtocol } from "../../../api/generated"; import Checkbox from "../../../components/checkbox"; import Input from "../../../components/input"; -import { selectStyles } from "../../../components/select-menu"; +import { SelectPrimitive, selectStyles } from "../../../components/select-menu"; import { handleApiError } from "../../../utils/helper"; import { parseUserPorts } from "../../../utils/ports"; @@ -300,6 +300,24 @@ export const WordlistAttackInput = forwardRef>((pr ); }); +/** + * A dropdown select input where you can select a whether to use StartTLS and which variant of it. + */ +export const StartTLSAttackInput = forwardRef>((props, ref) => { + const { value, label, valueKey, onUpdate } = props; + return ( + + + onUpdate(v)} + isClearable + /> + + ); +}); + /** * Dehashed query type as defined by the kraken dehashed API. The strings here * correspond to the object keys for each different variant type. diff --git a/kraken_frontend/src/views/workspace/workspace-attacks.tsx b/kraken_frontend/src/views/workspace/workspace-attacks.tsx index c0530028d..a3f5cbb5e 100644 --- a/kraken_frontend/src/views/workspace/workspace-attacks.tsx +++ b/kraken_frontend/src/views/workspace/workspace-attacks.tsx @@ -33,6 +33,7 @@ import { NullNumberAttackInput, NumberAttackInput, PortListInput, + StartTLSAttackInput, StringAttackInput, WordlistAttackInput, } from "./attacks/attack-input"; @@ -670,7 +671,14 @@ const ATTACKS: AllAttackDescr = { required: true, }, basicAuth: { fixed: undefined }, - starttls: { fixed: undefined }, + starttls: { + label: "StartTLS Protocol", + multi: false, + defaultValue: undefined, + type: StartTLSAttackInput, + group: "Advanced", + required: false, + }, }, }, }, diff --git a/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx b/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx index 5f957e3b6..69fc4ef28 100644 --- a/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx +++ b/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx @@ -1,11 +1,11 @@ import React from "react"; +import { SourceAttack, TestSSLFinding, TestSSLSection, TestSSLSeverity } from "../../../api/generated"; import OsIcon from "../../../components/os-icon"; import "../../../styling/workspace-data-details.css"; import ArrowLeftIcon from "../../../svg/arrow-left"; import ArrowRightIcon from "../../../svg/arrow-right"; -import { SourceAttack, TestSSLFinding, TestSSLSection, TestSSLSeverity } from "../../../api/generated"; -import { copyToClipboard, ObjectFns } from "../../../utils/helper"; import CopyIcon from "../../../svg/copy"; +import { ObjectFns, copyToClipboard } from "../../../utils/helper"; type WorkspaceDataDetailsResultsProps = { attacks: Array; @@ -500,13 +500,12 @@ export default function WorkspaceDataDetailsResults(props: WorkspaceDataDetailsR const sections = ObjectFns.fromEntries( Object.values(TestSSLSection).map((s) => [ s, - { worst: TestSSLSeverity.Info as TestSSLSeverity, findings: Array() } - ]) + { worst: TestSSLSeverity.Info as TestSSLSeverity, findings: Array() }, + ]), ); for (const finding of tsResult.findings) { const section = sections[finding.section]; - if (rateSeverity(finding.severity) > rateSeverity(section.worst)) - section.worst = finding.severity; + if (rateSeverity(finding.severity) > rateSeverity(section.worst)) section.worst = finding.severity; section.findings.push(finding); } return ( From 59a352b10a4206b82d0a1a38a3e8d1ae71079c0a Mon Sep 17 00:00:00 2001 From: gammelalf Date: Wed, 28 Aug 2024 12:08:44 +0200 Subject: [PATCH 27/37] Attach testssl results to services without creating them --- kraken/src/modules/attacks/testssl.rs | 90 +++++++++++++++++++-------- 1 file changed, 64 insertions(+), 26 deletions(-) diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index 90eded5ef..a479f0767 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -1,5 +1,6 @@ use std::str::FromStr; +use futures::TryStreamExt; use ipnetwork::IpNetwork; use kraken_proto::shared::Address; use kraken_proto::test_ssl_scans; @@ -12,11 +13,16 @@ use kraken_proto::TestSslScanResult; use kraken_proto::TestSslScans; use kraken_proto::TestSslSeverity; use log::error; +use rorm::and; use rorm::insert; use rorm::prelude::ForeignModelByField; +use rorm::query; +use rorm::FieldAccess; +use rorm::Model; use uuid::Uuid; use crate::api::handler::attacks::schema::StartTLSProtocol; +use crate::api::handler::services::schema::ServiceProtocols; use crate::chan::global::GLOBAL; use crate::chan::leech_manager::LeechClient; use crate::models::AggregationSource; @@ -25,6 +31,7 @@ use crate::models::DomainCertainty; use crate::models::HostCertainty; use crate::models::PortCertainty; use crate::models::PortProtocol; +use crate::models::Service; use crate::models::SourceType; use crate::models::TestSSLResultFinding; use crate::models::TestSSLResultFindingInsert; @@ -202,6 +209,24 @@ impl HandleAttackResponse for AttackContext { ) .await?; + // testssl didn't gather the information to aggregate a service, but it should attach to an existing one + let service_uuids = query!(&GLOBAL.db, (Service::F.uuid, Service::F.protocols)) + .condition(and![ + Service::F.workspace.equals(self.workspace.uuid), + Service::F.host.equals(host_uuid), + Service::F.port.equals(port_uuid), + ]) + .stream() + .try_filter_map(|(uuid, protocols)| async move { + Ok(matches!( + PortProtocol::Tcp.decode_service(protocols), + ServiceProtocols::Tcp { tls: true, .. } + ) + .then_some(uuid)) + }) + .try_collect::>() + .await?; + let source_uuid = insert!(&mut tx, TestSSLResultHeader) .return_primary_key() .single(&TestSSLResultHeaderInsert { @@ -222,32 +247,45 @@ impl HandleAttackResponse for AttackContext { insert!(&mut tx, AggregationSource) .return_nothing() - .bulk([ - AggregationSource { - uuid: Uuid::new_v4(), - workspace: ForeignModelByField::Key(self.workspace.uuid), - source_type: SourceType::TestSSL, - source_uuid, - aggregated_table: AggregationTable::Domain, - aggregated_uuid: domain_uuid, - }, - AggregationSource { - uuid: Uuid::new_v4(), - workspace: ForeignModelByField::Key(self.workspace.uuid), - source_type: SourceType::TestSSL, - source_uuid, - aggregated_table: AggregationTable::Host, - aggregated_uuid: host_uuid, - }, - AggregationSource { - uuid: Uuid::new_v4(), - workspace: ForeignModelByField::Key(self.workspace.uuid), - source_type: SourceType::TestSSL, - source_uuid, - aggregated_table: AggregationTable::Port, - aggregated_uuid: port_uuid, - }, - ]) + .bulk( + [ + AggregationSource { + uuid: Uuid::new_v4(), + workspace: ForeignModelByField::Key(self.workspace.uuid), + source_type: SourceType::TestSSL, + source_uuid, + aggregated_table: AggregationTable::Domain, + aggregated_uuid: domain_uuid, + }, + AggregationSource { + uuid: Uuid::new_v4(), + workspace: ForeignModelByField::Key(self.workspace.uuid), + source_type: SourceType::TestSSL, + source_uuid, + aggregated_table: AggregationTable::Host, + aggregated_uuid: host_uuid, + }, + AggregationSource { + uuid: Uuid::new_v4(), + workspace: ForeignModelByField::Key(self.workspace.uuid), + source_type: SourceType::TestSSL, + source_uuid, + aggregated_table: AggregationTable::Port, + aggregated_uuid: port_uuid, + }, + ] + .into_iter() + .chain(service_uuids.into_iter().map(|aggregated_uuid| { + AggregationSource { + uuid: Uuid::new_v4(), + workspace: ForeignModelByField::Key(self.workspace.uuid), + source_type: SourceType::TestSSL, + source_uuid, + aggregated_table: AggregationTable::Service, + aggregated_uuid, + } + })), + ) .await?; tx.commit().await?; From e08d441e93ba01c007c837f5c9bf29cbfe3d64fa Mon Sep 17 00:00:00 2001 From: gammelalf Date: Wed, 28 Aug 2024 12:26:34 +0200 Subject: [PATCH 28/37] Made domain optional in testssl attacks --- kraken-proto/proto/attacks.proto | 34 +++++++++---------- kraken/migrations/0020_testssl.toml | 3 -- .../src/api/handler/attack_results/schema.rs | 2 +- kraken/src/api/handler/attacks/handler.rs | 4 +-- kraken/src/api/handler/attacks/schema.rs | 2 +- kraken/src/models/attack/mod.rs | 2 +- kraken/src/models/attack/patches.rs | 2 +- kraken/src/modules/attacks/mod.rs | 2 +- kraken/src/modules/attacks/testssl.rs | 4 +-- kraken_frontend/openapi.json | 10 +++--- .../api/generated/models/FullTestSSLResult.ts | 5 ++- .../api/generated/models/TestSSLRequest.ts | 7 ++-- .../views/workspace/attacks/attack-input.tsx | 20 +++++++++++ .../src/views/workspace/workspace-attacks.tsx | 17 +++++----- leech/src/main.rs | 10 +++--- leech/src/modules/testssl/mod.rs | 14 +++++--- leech/src/rpc/attacks.rs | 4 +-- 17 files changed, 82 insertions(+), 60 deletions(-) diff --git a/kraken-proto/proto/attacks.proto b/kraken-proto/proto/attacks.proto index 3fff3e494..168048f7b 100644 --- a/kraken-proto/proto/attacks.proto +++ b/kraken-proto/proto/attacks.proto @@ -282,7 +282,7 @@ message TestSSLRequest { // A unique id that identifier the attack string attack_uuid = 1; // The domain used for SNI and cert validity check - string uri = 2; + optional string domain = 2; // The ip address to scan shared.Address ip = 3; // The port to scan @@ -312,23 +312,23 @@ message BasicAuth { // Protocols to select from when using `testssl.sh`'s `--starttls` option enum StartTLSProtocol { // FTP - FTP = 0; + FTP = 0; // SMTP - SMTP = 1; + SMTP = 1; // POP3 - POP3 = 2; + POP3 = 2; // IMAP - IMAP = 3; + IMAP = 3; // XMPP - XMPP = 4; + XMPP = 4; // LMTP - LMTP = 5; + LMTP = 5; // NNTP - NNTP = 6; + NNTP = 6; // Postgres Postgres = 7; // MySQL - MySQL = 8; + MySQL = 8; } /// Config option which scans `testssl.sh` should run @@ -474,22 +474,22 @@ message TestSSLFinding { // A TestSSLFinding's severity enum TestSSLSeverity { // A debug level log message - Debug = 0; + Debug = 0; // An info level log message - Info = 1; + Info = 1; // A warning level log message - Warn = 2; + Warn = 2; // An error level log message - Fatal = 3; + Fatal = 3; // The test's result doesn't pose an issue - Ok = 4; + Ok = 4; // The test's result pose a low priority issue - Low = 5; + Low = 5; // The test's result pose a medium priority issue - Medium = 6; + Medium = 6; // The test's result pose a high priority issue - High = 7; + High = 7; // The test's result pose a critical priority issue Critical = 8; } diff --git a/kraken/migrations/0020_testssl.toml b/kraken/migrations/0020_testssl.toml index a3d5eb7de..4a5caa434 100644 --- a/kraken/migrations/0020_testssl.toml +++ b/kraken/migrations/0020_testssl.toml @@ -33,9 +33,6 @@ Type = "varchar" Type = "max_length" Value = 255 -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" - [[Migration.Operations.Fields]] Name = "ip" Type = "ipnetwork" diff --git a/kraken/src/api/handler/attack_results/schema.rs b/kraken/src/api/handler/attack_results/schema.rs index 96ea7d031..2051f8285 100644 --- a/kraken/src/api/handler/attack_results/schema.rs +++ b/kraken/src/api/handler/attack_results/schema.rs @@ -427,7 +427,7 @@ pub struct FullTestSSLResult { pub created_at: DateTime, /// The domain which was used for SNI and certificate verification - pub domain: String, + pub domain: Option, /// The scanned ip address #[schema(value_type = String, example = "127.0.0.1")] diff --git a/kraken/src/api/handler/attacks/handler.rs b/kraken/src/api/handler/attacks/handler.rs index e17d1df52..0ee2f24ac 100644 --- a/kraken/src/api/handler/attacks/handler.rs +++ b/kraken/src/api/handler/attacks/handler.rs @@ -540,7 +540,7 @@ pub async fn testssl( let TestSSLRequest { leech_uuid, workspace_uuid, - uri, + domain, host, port, connect_timeout, @@ -564,7 +564,7 @@ pub async fn testssl( user_uuid, client, TestSSLParams { - uri, + domain, ip: host, port, connect_timeout, diff --git a/kraken/src/api/handler/attacks/schema.rs b/kraken/src/api/handler/attacks/schema.rs index b840135ac..217d940e6 100644 --- a/kraken/src/api/handler/attacks/schema.rs +++ b/kraken/src/api/handler/attacks/schema.rs @@ -302,7 +302,7 @@ pub struct TestSSLRequest { pub workspace_uuid: Uuid, /// The domain to scan - pub uri: String, + pub domain: Option, /// The host to scan #[schema(value_type = String, example = "127.0.0.1")] diff --git a/kraken/src/models/attack/mod.rs b/kraken/src/models/attack/mod.rs index 84d5af044..7cbb60ade 100644 --- a/kraken/src/models/attack/mod.rs +++ b/kraken/src/models/attack/mod.rs @@ -534,7 +534,7 @@ pub struct TestSSLResultHeader { /// The domain which was used for SNI and certificate verification #[rorm(max_length = 255)] - pub domain: String, + pub domain: Option, /// The scanned ip address pub ip: IpNetwork, diff --git a/kraken/src/models/attack/patches.rs b/kraken/src/models/attack/patches.rs index 0f100b4fd..e56610ed1 100644 --- a/kraken/src/models/attack/patches.rs +++ b/kraken/src/models/attack/patches.rs @@ -153,7 +153,7 @@ pub(crate) struct OsDetectionResultInsert { pub(crate) struct TestSSLResultHeaderInsert { pub(crate) uuid: Uuid, pub(crate) attack: ForeignModel, - pub(crate) domain: String, + pub(crate) domain: Option, pub(crate) ip: IpNetwork, pub(crate) port: i32, pub(crate) rdns: String, diff --git a/kraken/src/modules/attacks/mod.rs b/kraken/src/modules/attacks/mod.rs index 32b3ff08e..33a40bf1f 100644 --- a/kraken/src/modules/attacks/mod.rs +++ b/kraken/src/modules/attacks/mod.rs @@ -359,7 +359,7 @@ pub async fn start_udp_service_detection( /// The parameters of a "testssl" attack pub struct TestSSLParams { /// The domain to use for sni and cert validation - pub uri: String, + pub domain: Option, /// The ip to scan pub ip: IpAddr, diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index a479f0767..df541defb 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -53,7 +53,7 @@ impl AttackContext { ) -> Result<(), AttackError> { let request = TestSslRequest { attack_uuid: self.attack_uuid.to_string(), - uri: params.uri, + domain: params.domain, ip: Some(Address::from(params.ip)), port: params.port as u32, connect_timeout: params.connect_timeout, @@ -232,7 +232,7 @@ impl HandleAttackResponse for AttackContext { .single(&TestSSLResultHeaderInsert { uuid: Uuid::new_v4(), attack: ForeignModelByField::Key(self.attack_uuid), - domain: target_host, + domain: (ip.to_string() != target_host).then_some(target_host), ip, port: port as i32, rdns, diff --git a/kraken_frontend/openapi.json b/kraken_frontend/openapi.json index cd58ed74b..041416315 100644 --- a/kraken_frontend/openapi.json +++ b/kraken_frontend/openapi.json @@ -12362,7 +12362,6 @@ "uuid", "attack", "created_at", - "domain", "ip", "port", "rdns", @@ -12387,7 +12386,8 @@ }, "domain": { "type": "string", - "description": "The domain which was used for SNI and certificate verification" + "description": "The domain which was used for SNI and certificate verification", + "nullable": true }, "ip": { "type": "string", @@ -16243,7 +16243,6 @@ "description": "Request to run testssl", "required": [ "workspace_uuid", - "uri", "host", "port" ], @@ -16259,9 +16258,10 @@ "format": "uuid", "description": "The workspace to execute the attack in" }, - "uri": { + "domain": { "type": "string", - "description": "The domain to scan" + "description": "The domain to scan", + "nullable": true }, "host": { "type": "string", diff --git a/kraken_frontend/src/api/generated/models/FullTestSSLResult.ts b/kraken_frontend/src/api/generated/models/FullTestSSLResult.ts index ee9df1620..316fe8891 100644 --- a/kraken_frontend/src/api/generated/models/FullTestSSLResult.ts +++ b/kraken_frontend/src/api/generated/models/FullTestSSLResult.ts @@ -49,7 +49,7 @@ export interface FullTestSSLResult { * @type {string} * @memberof FullTestSSLResult */ - domain: string; + domain?: string | null; /** * The scanned ip address * @type {string} @@ -92,7 +92,6 @@ export function instanceOfFullTestSSLResult(value: object): boolean { isInstance = isInstance && "uuid" in value; isInstance = isInstance && "attack" in value; isInstance = isInstance && "createdAt" in value; - isInstance = isInstance && "domain" in value; isInstance = isInstance && "ip" in value; isInstance = isInstance && "port" in value; isInstance = isInstance && "rdns" in value; @@ -115,7 +114,7 @@ export function FullTestSSLResultFromJSONTyped(json: any, ignoreDiscriminator: b 'uuid': json['uuid'], 'attack': json['attack'], 'createdAt': (new Date(json['created_at'])), - 'domain': json['domain'], + 'domain': !exists(json, 'domain') ? undefined : json['domain'], 'ip': json['ip'], 'port': json['port'], 'rdns': json['rdns'], diff --git a/kraken_frontend/src/api/generated/models/TestSSLRequest.ts b/kraken_frontend/src/api/generated/models/TestSSLRequest.ts index 29ebed737..1d1797908 100644 --- a/kraken_frontend/src/api/generated/models/TestSSLRequest.ts +++ b/kraken_frontend/src/api/generated/models/TestSSLRequest.ts @@ -45,7 +45,7 @@ export interface TestSSLRequest { * @type {string} * @memberof TestSSLRequest */ - uri: string; + domain?: string | null; /** * The host to scan * @type {string} @@ -90,7 +90,6 @@ export interface TestSSLRequest { export function instanceOfTestSSLRequest(value: object): boolean { let isInstance = true; isInstance = isInstance && "workspaceUuid" in value; - isInstance = isInstance && "uri" in value; isInstance = isInstance && "host" in value; isInstance = isInstance && "port" in value; @@ -109,7 +108,7 @@ export function TestSSLRequestFromJSONTyped(json: any, ignoreDiscriminator: bool 'leechUuid': !exists(json, 'leech_uuid') ? undefined : json['leech_uuid'], 'workspaceUuid': json['workspace_uuid'], - 'uri': json['uri'], + 'domain': !exists(json, 'domain') ? undefined : json['domain'], 'host': json['host'], 'port': json['port'], 'connectTimeout': !exists(json, 'connect_timeout') ? undefined : json['connect_timeout'], @@ -130,7 +129,7 @@ export function TestSSLRequestToJSON(value?: TestSSLRequest | null): any { 'leech_uuid': value.leechUuid, 'workspace_uuid': value.workspaceUuid, - 'uri': value.uri, + 'domain': value.domain, 'host': value.host, 'port': value.port, 'connect_timeout': value.connectTimeout, diff --git a/kraken_frontend/src/views/workspace/attacks/attack-input.tsx b/kraken_frontend/src/views/workspace/attacks/attack-input.tsx index 7fd911463..243b0305e 100644 --- a/kraken_frontend/src/views/workspace/attacks/attack-input.tsx +++ b/kraken_frontend/src/views/workspace/attacks/attack-input.tsx @@ -47,6 +47,26 @@ export const StringAttackInput = forwardRef>((props, ref) => { + const { value, label, valueKey, onUpdate, ...htmlProps } = props; + + return ( + + + onUpdate(v || null)} + {...htmlProps} + /> + + ); +}); + /** * Input component to manipulate an attack input on string basis, with a * `deserialize` & `serialize` callback for any custom types. diff --git a/kraken_frontend/src/views/workspace/workspace-attacks.tsx b/kraken_frontend/src/views/workspace/workspace-attacks.tsx index a3f5cbb5e..c9ab09a84 100644 --- a/kraken_frontend/src/views/workspace/workspace-attacks.tsx +++ b/kraken_frontend/src/views/workspace/workspace-attacks.tsx @@ -31,6 +31,7 @@ import { DehashedAttackInput, DurationAttackInput, NullNumberAttackInput, + NullStringAttackInput, NumberAttackInput, PortListInput, StartTLSAttackInput, @@ -630,14 +631,6 @@ const ATTACKS: AllAttackDescr = { endpoint: "testssl", jsonKey: "testSSLRequest", inputs: { - uri: { - label: "Domain", - multi: false, - defaultValue: "", - required: true, - prefill: ["domain"], - type: StringAttackInput, - }, host: { label: "IP", multi: false, @@ -654,6 +647,14 @@ const ATTACKS: AllAttackDescr = { type: NumberAttackInput, required: true, }, + domain: { + label: "Domain", + multi: false, + defaultValue: null, + required: false, + prefill: ["domain"], + type: NullStringAttackInput, + }, connectTimeout: { label: "Connect Timeout (in s)", multi: false, diff --git a/leech/src/main.rs b/leech/src/main.rs index 84b564dbe..dab25296a 100644 --- a/leech/src/main.rs +++ b/leech/src/main.rs @@ -284,15 +284,15 @@ pub enum RunCommand { /// Run `testssl.sh` TestSSL { - /// Domain to scan - uri: String, - /// The ip address to scan ip: IpAddr, /// The port to scan #[clap(default_value_t = 443)] port: u16, + + /// Domain to scan + domain: Option, }, } @@ -760,9 +760,9 @@ async fn main() -> Result<(), Box> { } } } - RunCommand::TestSSL { uri, ip, port } => { + RunCommand::TestSSL { domain, ip, port } => { let json = testssl::run_testssl(TestSSLSettings { - uri, + domain, ip, port, ..Default::default() diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index 82bf63a8b..6b06b5733 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -21,7 +21,7 @@ pub use self::json_pretty::*; #[derive(Debug)] pub struct TestSSLSettings { /// The domain to scan - pub uri: String, + pub domain: Option, /// The ip address to scan pub ip: IpAddr, @@ -50,7 +50,7 @@ pub struct TestSSLSettings { impl Default for TestSSLSettings { fn default() -> Self { Self { - uri: "localhost".to_string(), + domain: Some("localhost".to_string()), ip: IpAddr::from([127, 0, 0, 1]), port: 443, connect_timeout: None, @@ -133,7 +133,7 @@ pub enum TestSSLScans { /// Run `testssl.sh` and parse its output pub async fn run_testssl(settings: TestSSLSettings) -> Result { let TestSSLSettings { - uri, + domain, ip, port, connect_timeout, @@ -247,7 +247,13 @@ pub async fn run_testssl(settings: TestSSLSettings) -> Result Result, Status> { let TestSslRequest { attack_uuid: _, - uri, + domain, ip, port, connect_timeout, @@ -826,7 +826,7 @@ impl ReqAttackService for Attacks { scans, } = request.into_inner(); let settings = testssl::TestSSLSettings { - uri, + domain, ip: IpAddr::try_from(ip.ok_or(Status::invalid_argument("Missing ip"))?)?, port: port as u16, connect_timeout, From 4751727dae3e43835039fabb819f68daf609abd5 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Wed, 28 Aug 2024 12:37:31 +0200 Subject: [PATCH 29/37] Display attack parameters in results page --- .../workspace-data/workspace-data-details-results.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx b/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx index 69fc4ef28..b355165b4 100644 --- a/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx +++ b/kraken_frontend/src/views/workspace/workspace-data/workspace-data-details-results.tsx @@ -514,11 +514,17 @@ export default function WorkspaceDataDetailsResults(props: WorkspaceDataDetailsR

TestSSL

+ IP: + Port: + Domain: Started by: Created: Finished:
+ {tsResult.ip} + {tsResult.port} + {tsResult.domain || ""} {attack.startedBy.displayName} {formatDate(attack.createdAt)} {formatDate(attack.finishedAt)} From bedde037283c55704371228d3405c7f8d59cf197 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Thu, 29 Aug 2024 15:40:59 +0200 Subject: [PATCH 30/37] Aggregate testssl into services and their targets' domain --- kraken/src/modules/attacks/testssl.rs | 165 +++++++++++++------------- 1 file changed, 83 insertions(+), 82 deletions(-) diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index df541defb..734bcf1f8 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -1,6 +1,5 @@ use std::str::FromStr; -use futures::TryStreamExt; use ipnetwork::IpNetwork; use kraken_proto::shared::Address; use kraken_proto::test_ssl_scans; @@ -13,12 +12,8 @@ use kraken_proto::TestSslScanResult; use kraken_proto::TestSslScans; use kraken_proto::TestSslSeverity; use log::error; -use rorm::and; use rorm::insert; use rorm::prelude::ForeignModelByField; -use rorm::query; -use rorm::FieldAccess; -use rorm::Model; use uuid::Uuid; use crate::api::handler::attacks::schema::StartTLSProtocol; @@ -31,7 +26,7 @@ use crate::models::DomainCertainty; use crate::models::HostCertainty; use crate::models::PortCertainty; use crate::models::PortProtocol; -use crate::models::Service; +use crate::models::ServiceCertainty; use crate::models::SourceType; use crate::models::TestSSLResultFinding; use crate::models::TestSSLResultFindingInsert; @@ -113,6 +108,17 @@ impl HandleAttackResponse for AttackContext { browser_simulations, } = result; + let domain = if target_host == ip { + None + } else { + Some(target_host) + }; + + let mut reverse_domain = rdns.clone(); + if reverse_domain.ends_with('.') { + reverse_domain.pop(); + } + let ip = match IpNetwork::from_str(&ip) { Ok(ip) => ip, Err(err) => { @@ -133,11 +139,6 @@ impl HandleAttackResponse for AttackContext { } }; - let mut domain = rdns.clone(); - if domain.ends_with('.') { - domain.pop(); - } - let findings = [ (pretest, TestSSLSection::Pretest), (protocols, TestSSLSection::Protocols), @@ -183,11 +184,45 @@ impl HandleAttackResponse for AttackContext { }) .collect::, AttackError>>()?; - let domain_uuid = GLOBAL + let source_uuid = insert!(&mut tx, TestSSLResultHeader) + .return_primary_key() + .single(&TestSSLResultHeaderInsert { + uuid: Uuid::new_v4(), + attack: ForeignModelByField::Key(self.attack_uuid), + domain: domain.clone(), + ip, + port: port as i32, + rdns, + service: service.clone(), + }) + .await?; + + insert!(&mut tx, TestSSLResultFinding) + .return_nothing() + .bulk(&findings) + .await?; + + let domain_uuid = if let Some(domain) = domain.as_deref() { + Some( + GLOBAL + .aggregator + .aggregate_domain( + self.workspace.uuid, + domain, + DomainCertainty::Unverified, + self.user.uuid, + ) + .await?, + ) + } else { + None + }; + + let reverse_domain_uuid = GLOBAL .aggregator .aggregate_domain( self.workspace.uuid, - &domain, + &reverse_domain, DomainCertainty::Unverified, self.user.uuid, ) @@ -209,82 +244,48 @@ impl HandleAttackResponse for AttackContext { ) .await?; - // testssl didn't gather the information to aggregate a service, but it should attach to an existing one - let service_uuids = query!(&GLOBAL.db, (Service::F.uuid, Service::F.protocols)) - .condition(and![ - Service::F.workspace.equals(self.workspace.uuid), - Service::F.host.equals(host_uuid), - Service::F.port.equals(port_uuid), - ]) - .stream() - .try_filter_map(|(uuid, protocols)| async move { - Ok(matches!( - PortProtocol::Tcp.decode_service(protocols), - ServiceProtocols::Tcp { tls: true, .. } - ) - .then_some(uuid)) - }) - .try_collect::>() - .await?; - - let source_uuid = insert!(&mut tx, TestSSLResultHeader) - .return_primary_key() - .single(&TestSSLResultHeaderInsert { - uuid: Uuid::new_v4(), - attack: ForeignModelByField::Key(self.attack_uuid), - domain: (ip.to_string() != target_host).then_some(target_host), - ip, - port: port as i32, - rdns, - service, - }) - .await?; - - insert!(&mut tx, TestSSLResultFinding) - .return_nothing() - .bulk(&findings) - .await?; + // TODO: extend this check to services verified through STARTTLS + let service_uuid = if service == "HTTP" { + Some( + GLOBAL + .aggregator + .aggregate_service( + self.workspace.uuid, + host_uuid, + Some(port_uuid), + Some(ServiceProtocols::Tcp { + tls: true, + raw: false, + }), + "http", + ServiceCertainty::DefinitelyVerified, + ) + .await?, + ) + } else { + None + }; insert!(&mut tx, AggregationSource) .return_nothing() .bulk( [ - AggregationSource { - uuid: Uuid::new_v4(), - workspace: ForeignModelByField::Key(self.workspace.uuid), - source_type: SourceType::TestSSL, - source_uuid, - aggregated_table: AggregationTable::Domain, - aggregated_uuid: domain_uuid, - }, - AggregationSource { - uuid: Uuid::new_v4(), - workspace: ForeignModelByField::Key(self.workspace.uuid), - source_type: SourceType::TestSSL, - source_uuid, - aggregated_table: AggregationTable::Host, - aggregated_uuid: host_uuid, - }, - AggregationSource { - uuid: Uuid::new_v4(), - workspace: ForeignModelByField::Key(self.workspace.uuid), - source_type: SourceType::TestSSL, - source_uuid, - aggregated_table: AggregationTable::Port, - aggregated_uuid: port_uuid, - }, + (AggregationTable::Domain, domain_uuid), + (AggregationTable::Domain, Some(reverse_domain_uuid)), + (AggregationTable::Host, Some(host_uuid)), + (AggregationTable::Port, Some(port_uuid)), + (AggregationTable::Service, service_uuid), ] .into_iter() - .chain(service_uuids.into_iter().map(|aggregated_uuid| { - AggregationSource { - uuid: Uuid::new_v4(), - workspace: ForeignModelByField::Key(self.workspace.uuid), - source_type: SourceType::TestSSL, - source_uuid, - aggregated_table: AggregationTable::Service, - aggregated_uuid, - } - })), + .filter_map(|(table, uuid)| uuid.map(|uuid| (table, uuid))) + .map(|(aggregated_table, aggregated_uuid)| AggregationSource { + uuid: Uuid::new_v4(), + workspace: ForeignModelByField::Key(self.workspace.uuid), + source_type: SourceType::TestSSL, + source_uuid, + aggregated_table, + aggregated_uuid, + }), ) .await?; From 85b183d34324d56ea00621266a994a3e5fe3acb4 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Thu, 5 Sep 2024 11:21:51 +0200 Subject: [PATCH 31/37] Fixed broken join --- kraken/src/api/handler/finding_factory/handler_admin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kraken/src/api/handler/finding_factory/handler_admin.rs b/kraken/src/api/handler/finding_factory/handler_admin.rs index 99d8354cc..0beb6561e 100644 --- a/kraken/src/api/handler/finding_factory/handler_admin.rs +++ b/kraken/src/api/handler/finding_factory/handler_admin.rs @@ -53,8 +53,8 @@ pub async fn get_finding_factory_entries() -> ApiResult Date: Thu, 5 Sep 2024 11:22:16 +0200 Subject: [PATCH 32/37] Renamed hexagon; Re-enabled "Ports" hexagon --- kraken_frontend/src/svg/attacks.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kraken_frontend/src/svg/attacks.tsx b/kraken_frontend/src/svg/attacks.tsx index eba919769..32aab5e74 100644 --- a/kraken_frontend/src/svg/attacks.tsx +++ b/kraken_frontend/src/svg/attacks.tsx @@ -96,7 +96,7 @@ export default function AttacksIcon(params: AttacksParams) { scale={2} padding={12} text="Ports" - className={`category-text kraken-attacks-hex-unavailable`} + className="category-text" categoryType={AttackCategory.Ports} /> Date: Thu, 5 Sep 2024 13:40:54 +0200 Subject: [PATCH 33/37] Re-added accidentially deleted raw migration --- kraken/migrations/0021_testssl.toml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/kraken/migrations/0021_testssl.toml b/kraken/migrations/0021_testssl.toml index e2e3b9455..71631b74a 100644 --- a/kraken/migrations/0021_testssl.toml +++ b/kraken/migrations/0021_testssl.toml @@ -211,3 +211,17 @@ OnUpdate = "Cascade" [[Migration.Operations.Field.Annotations]] Type = "not_null" + +[[Migration.Operations]] +Type = "RawSQL" +StructureSafe = true +SQLite = "only Postgres databases are supported right now" +MySQL = "only Postgres databases are supported right now" +Postgres = "ALTER TYPE _attack_attack_type ADD VALUE IF NOT EXISTS 'TestSSL' AFTER 'AntiPortScanningDetection';" + +[[Migration.Operations]] +Type = "RawSQL" +StructureSafe = true +SQLite = "only Postgres databases are supported right now" +MySQL = "only Postgres databases are supported right now" +Postgres = "ALTER TYPE _aggregationsource_source_type ADD VALUE IF NOT EXISTS 'TestSSL' AFTER 'AntiPortScanningDetection';" \ No newline at end of file From 4b5f395e7954c0108081b3f226ba7d2504394bda Mon Sep 17 00:00:00 2001 From: gammelalf Date: Thu, 5 Sep 2024 18:01:10 +0200 Subject: [PATCH 34/37] Forced testssl to not perform any dns on its own rDNS had to be removed as a result --- kraken-proto/proto/attacks.proto | 3 --- kraken/migrations/0022_placeholder.toml | 10 ++++++++++ .../api/handler/aggregation_source/utils.rs | 1 - .../src/api/handler/attack_results/handler.rs | 1 - .../src/api/handler/attack_results/schema.rs | 3 --- kraken/src/models/attack/mod.rs | 4 ---- kraken/src/models/attack/patches.rs | 1 - kraken/src/modules/attacks/testssl.rs | 18 ------------------ leech/src/modules/testssl/json_pretty.rs | 9 ++++----- leech/src/modules/testssl/mod.rs | 5 ++++- leech/src/rpc/attacks.rs | 1 - 11 files changed, 18 insertions(+), 38 deletions(-) create mode 100644 kraken/migrations/0022_placeholder.toml diff --git a/kraken-proto/proto/attacks.proto b/kraken-proto/proto/attacks.proto index 168048f7b..1a0caf634 100644 --- a/kraken-proto/proto/attacks.proto +++ b/kraken-proto/proto/attacks.proto @@ -410,9 +410,6 @@ message TestSSLScanResult { // The scanned port string port = 3; - // The ip address' rDNS name - string rdns = 4; - // The detected service string service = 5; diff --git a/kraken/migrations/0022_placeholder.toml b/kraken/migrations/0022_placeholder.toml new file mode 100644 index 000000000..18f444c02 --- /dev/null +++ b/kraken/migrations/0022_placeholder.toml @@ -0,0 +1,10 @@ +[Migration] +Hash = "1457786132841928709" +Initial = false +Dependency = 21 +Replaces = [] + +[[Migration.Operations]] +Type = "DeleteField" +Model = "testsslresultheader" +Name = "rdns" diff --git a/kraken/src/api/handler/aggregation_source/utils.rs b/kraken/src/api/handler/aggregation_source/utils.rs index 227664552..e286df488 100644 --- a/kraken/src/api/handler/aggregation_source/utils.rs +++ b/kraken/src/api/handler/aggregation_source/utils.rs @@ -485,7 +485,6 @@ impl FullAggregationSource { domain: result.domain, ip: result.ip.ip(), port: result.port as u16, - rdns: result.rdns, service: result.service, findings: Vec::new(), }, diff --git a/kraken/src/api/handler/attack_results/handler.rs b/kraken/src/api/handler/attack_results/handler.rs index 6085572ef..8b5332c28 100644 --- a/kraken/src/api/handler/attack_results/handler.rs +++ b/kraken/src/api/handler/attack_results/handler.rs @@ -787,7 +787,6 @@ pub async fn get_testssl_results( domain: header.domain, ip: header.ip.ip(), port: header.port as u16, - rdns: header.rdns, service: header.service, findings: query!(&mut tx, TestSSLResultFinding) .condition(TestSSLResultFinding::F.attack.equals(attack_uuid)) diff --git a/kraken/src/api/handler/attack_results/schema.rs b/kraken/src/api/handler/attack_results/schema.rs index 2051f8285..80b9dab28 100644 --- a/kraken/src/api/handler/attack_results/schema.rs +++ b/kraken/src/api/handler/attack_results/schema.rs @@ -436,9 +436,6 @@ pub struct FullTestSSLResult { /// The scanned port pub port: u16, - /// The ip address' rDNS name - pub rdns: String, - /// The detected service pub service: String, diff --git a/kraken/src/models/attack/mod.rs b/kraken/src/models/attack/mod.rs index 7cbb60ade..97e75e04c 100644 --- a/kraken/src/models/attack/mod.rs +++ b/kraken/src/models/attack/mod.rs @@ -542,10 +542,6 @@ pub struct TestSSLResultHeader { /// The scanned port pub port: i32, - /// The ip address' rDNS name - #[rorm(max_length = 255)] - pub rdns: String, - /// The detected service #[rorm(max_length = 255)] pub service: String, diff --git a/kraken/src/models/attack/patches.rs b/kraken/src/models/attack/patches.rs index e56610ed1..628f59afa 100644 --- a/kraken/src/models/attack/patches.rs +++ b/kraken/src/models/attack/patches.rs @@ -156,7 +156,6 @@ pub(crate) struct TestSSLResultHeaderInsert { pub(crate) domain: Option, pub(crate) ip: IpNetwork, pub(crate) port: i32, - pub(crate) rdns: String, pub(crate) service: String, } diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index ac61a4bee..8ea67455d 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -95,7 +95,6 @@ impl HandleAttackResponse for AttackContext { target_host, ip, port, - rdns, service, pretest, protocols, @@ -116,11 +115,6 @@ impl HandleAttackResponse for AttackContext { Some(target_host) }; - let mut reverse_domain = rdns.clone(); - if reverse_domain.ends_with('.') { - reverse_domain.pop(); - } - let ip = match IpNetwork::from_str(&ip) { Ok(ip) => ip, Err(err) => { @@ -194,7 +188,6 @@ impl HandleAttackResponse for AttackContext { domain: domain.clone(), ip, port: port as i32, - rdns, service: service.clone(), }) .await?; @@ -220,16 +213,6 @@ impl HandleAttackResponse for AttackContext { None }; - let reverse_domain_uuid = GLOBAL - .aggregator - .aggregate_domain( - self.workspace.uuid, - &reverse_domain, - DomainCertainty::Unverified, - self.user.uuid, - ) - .await?; - let host_uuid = GLOBAL .aggregator .aggregate_host(self.workspace.uuid, ip, HostCertainty::Verified) @@ -273,7 +256,6 @@ impl HandleAttackResponse for AttackContext { .bulk( [ (AggregationTable::Domain, domain_uuid), - (AggregationTable::Domain, Some(reverse_domain_uuid)), (AggregationTable::Host, Some(host_uuid)), (AggregationTable::Port, Some(port_uuid)), (AggregationTable::Service, service_uuid), diff --git a/leech/src/modules/testssl/json_pretty.rs b/leech/src/modules/testssl/json_pretty.rs index d9f1bc0e5..bfdd36cc3 100644 --- a/leech/src/modules/testssl/json_pretty.rs +++ b/leech/src/modules/testssl/json_pretty.rs @@ -67,10 +67,10 @@ pub struct ScanResult { /// The scanned port pub port: String, - /// The ip address' rDNS name - #[serde(rename = "rDNS")] - pub rdns: String, - + // /// The ip address' rDNS name + // #[serde(rename = "rDNS")] + // pub rdns: String, + // /// The detected service pub service: String, @@ -138,7 +138,6 @@ impl ScanResult { target_host: _, ip: _, port: _, - rdns: _, service: _, hostname: _, pretest, diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index 6b06b5733..9703bcf54 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -155,6 +155,9 @@ pub async fn run_testssl(settings: TestSSLSettings) -> Result` still performs DNS lookups and uses those ips except the first one? + cmd.arg("--nodns").arg("none"); + // Add timeouts if let Some(seconds) = connect_timeout { cmd.arg("--connect-timeout").arg(&seconds.to_string()); @@ -221,7 +224,7 @@ pub async fn run_testssl(settings: TestSSLSettings) -> Result Date: Fri, 6 Sep 2024 10:15:38 +0200 Subject: [PATCH 35/37] Fixed starttls --- kraken/src/modules/attacks/testssl.rs | 17 +++++++-- leech/src/modules/testssl/mod.rs | 53 ++++++++++++++++----------- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index 8ea67455d..42784f7cf 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -229,8 +229,19 @@ impl HandleAttackResponse for AttackContext { ) .await?; - // TODO: extend this check to services verified through STARTTLS - let service_uuid = if service == "HTTP" { + let service_uuid = if let Some(service_name) = match service.as_str() { + "HTTP" => Some("http"), + "ftp" => Some("ftp"), + "smtp" => Some("smtp"), + "pop3" => Some("pop3"), + "imap" => Some("imap"), + "xmpp" => Some("xmpp"), + "lmtp" => Some("lmtp"), + "nntp" => Some("nntp"), + "postgres" => Some("postgres"), + "mysql" => Some("mysql"), + _ => None, + } { Some( GLOBAL .aggregator @@ -242,7 +253,7 @@ impl HandleAttackResponse for AttackContext { tls: true, raw: false, }), - "http", + service_name, ServiceCertainty::DefinitelyVerified, ) .await?, diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index 9703bcf54..61d41ce09 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -6,6 +6,7 @@ use std::net::IpAddr; use log::debug; use log::error; use log::trace; +use log::warn; use tempfile::NamedTempFile; use thiserror::Error; use tokio::fs::File as TokioFile; @@ -259,29 +260,37 @@ pub async fn run_testssl(settings: TestSSLSettings) -> Result Ok(json_result?), + 1..50 => { + warn!("testssl.sh reported {exit_code} \"ambiguous situations or errors\""); + Ok(json_result?) + } + 242 | 244..256 => { + error!("testssl.sh returned error code {exit_code}"); + Err(TestSSLError::NonZeroExitStatus) + } + _ => { + warn!("testssl.sh returned undocumented exit code: {exit_code}"); + Ok(json_result?) + } + } } else { - error!( - "testssl.sh exited with [{}]", - output - .status - .code() - .expect("No one should have send this process a signal") - ); - trace!( - "Testssl's stdout: \n{}", - String::from_utf8_lossy(&output.stdout) - ); - trace!( - "Testssl's stderr: \n{}", - String::from_utf8_lossy(&output.stderr) - ); - + error!("testssl.sh exited without code"); Err(TestSSLError::NonZeroExitStatus) } } From c573a98e18a7b2193afcc511548a57a2113347fc Mon Sep 17 00:00:00 2001 From: gammelalf Date: Fri, 6 Sep 2024 11:06:25 +0200 Subject: [PATCH 36/37] Fixed clippy lints --- .../handler/finding_factory/handler_admin.rs | 23 +- .../src/modules/attacks/service_detection.rs | 2 +- kraken/src/modules/cache/editor.rs | 253 +++++++++--------- kraken/src/modules/editor/mod.rs | 1 + kraken/src/modules/finding_factory/factory.rs | 6 +- leech/src/modules/testssl/mod.rs | 7 +- sdk/rust-kraken-sdk/src/sdk/auth.rs | 2 +- sdk/rust-kraken-sdk/src/sdk/domains.rs | 2 +- 8 files changed, 144 insertions(+), 152 deletions(-) diff --git a/kraken/src/api/handler/finding_factory/handler_admin.rs b/kraken/src/api/handler/finding_factory/handler_admin.rs index 0beb6561e..6dcdb3c82 100644 --- a/kraken/src/api/handler/finding_factory/handler_admin.rs +++ b/kraken/src/api/handler/finding_factory/handler_admin.rs @@ -58,16 +58,19 @@ pub async fn get_finding_factory_entries() -> ApiResult>::new(), + |mut map, (definition, category)| { + map.entry(definition) + .or_default() + .push(SimpleFindingCategory { + uuid: category.uuid, + name: category.name, + color: Color::from_db(category.color), + }); + async move { Ok(map) } + }, + ) .await?; let entries: HashMap<_, _> = query!( diff --git a/kraken/src/modules/attacks/service_detection.rs b/kraken/src/modules/attacks/service_detection.rs index fb9bb70c8..b578c4b2a 100644 --- a/kraken/src/modules/attacks/service_detection.rs +++ b/kraken/src/modules/attacks/service_detection.rs @@ -173,7 +173,7 @@ impl HandleAttackResponse for AttackContext { raw: *raw, tls: *tls, }), - &name, + name, *certainty, ) .await?; diff --git a/kraken/src/modules/cache/editor.rs b/kraken/src/modules/cache/editor.rs index 73d4d0d87..198c0e5aa 100644 --- a/kraken/src/modules/cache/editor.rs +++ b/kraken/src/modules/cache/editor.rs @@ -633,6 +633,7 @@ impl EditorCacheImpl for WsNotes { // Implementation details // -------------- +#[allow(clippy::type_complexity)] pub struct EditorCache { /// HashMap used to store cached entries /// @@ -709,41 +710,38 @@ impl EditorCache { /// Retrieve an item through a key /// /// The option marks the availability of the key in the database. - pub fn get( + pub async fn get( &self, key: Impl::Key, - ) -> impl Future, rorm::Error>> + Send + '_ - { - async move { - let cache_item = self.read_cache().get(&key).cloned(); + ) -> Result, rorm::Error> { + let cache_item = self.read_cache().get(&key).cloned(); - // Check if ws notes have already been queried once - return if let Some(item) = cache_item { - Ok(item.map(|x| (x.data, x.workspace))) - } else { - // Query the db to populate the cache - let notes = Impl::query_db(key).await?; + // Check if ws notes have already been queried once + return if let Some(item) = cache_item { + Ok(item.map(|x| (x.data, x.workspace))) + } else { + // Query the db to populate the cache + let notes = Impl::query_db(key).await?; - let Some((notes, workspace)) = notes else { - // Update cache so it knows that there's no DB entry - self.write_cache().insert(key, None); - return Ok(None); - }; + let Some((notes, workspace)) = notes else { + // Update cache so it knows that there's no DB entry + self.write_cache().insert(key, None); + return Ok(None); + }; - // If the workspace was found, insert it into the cache + // If the workspace was found, insert it into the cache - self.write_cache().insert( - key, - Some(InnerItem { - changed: true, - data: notes.clone(), - workspace, - }), - ); + self.write_cache().insert( + key, + Some(InnerItem { + changed: true, + data: notes.clone(), + workspace, + }), + ); - Ok(Some((notes, workspace))) - }; - } + Ok(Some((notes, workspace))) + }; } /// Invalidates everything marked as "Not found in DB" @@ -765,53 +763,46 @@ impl EditorCache { } /// Update an item in the cache - pub fn update( - &self, - key: Impl::Key, - value: String, - ) -> impl Future> + Send + '_ { - async move { - // Check if ws notes have already been queried once - let item = self.read_cache().get(&key).cloned(); + pub async fn update(&self, key: Impl::Key, value: String) -> Result<(), CacheError> { + // Check if ws notes have already been queried once + let item = self.read_cache().get(&key).cloned(); + + match item { + None => { + let (_, workspace) = Impl::query_db(key).await?.ok_or(CacheError::ItemNotFound)?; + + // If the item was found, insert the update in the cache + self.write_cache().insert( + key, + Some(InnerItem { + changed: true, + data: value, + workspace, + }), + ); - match item { - None => { + Ok(()) + } + Some(old) => { + let item = if let Some(data) = old { + InnerItem { + changed: true, + data: value, + workspace: data.workspace, + } + } else { let (_, workspace) = Impl::query_db(key).await?.ok_or(CacheError::ItemNotFound)?; + InnerItem { + changed: true, + data: value, + workspace, + } + }; - // If the item was found, insert the update in the cache - self.write_cache().insert( - key, - Some(InnerItem { - changed: true, - data: value, - workspace, - }), - ); - - Ok(()) - } - Some(old) => { - let item = if let Some(data) = old { - InnerItem { - changed: true, - data: value, - workspace: data.workspace, - } - } else { - let (_, workspace) = - Impl::query_db(key).await?.ok_or(CacheError::ItemNotFound)?; - InnerItem { - changed: true, - data: value, - workspace, - } - }; - - self.write_cache().insert(key, Some(item)); + self.write_cache().insert(key, Some(item)); - Ok(()) - } + Ok(()) } } } @@ -819,85 +810,84 @@ impl EditorCache { /// Saves the cache in regular intervals to the database /// /// This is an infinite loop and should be run as background task - pub fn run_cache_save(self) -> impl Future + Send + pub async fn run_cache_save(self) -> Never where Self: Sized, { - async move { - let mut timer = tokio::time::interval(Duration::from_secs(30)); - - let dir_path = Path::new("/var/lib/kraken/editor_cache_failures/"); - if fs::try_exists(dir_path).await.is_err() { - if let Err(err) = async { - fs::create_dir_all(dir_path).await?; - fs::set_permissions(dir_path, Permissions::from_mode(0o700)).await - } - .await - { - error!("{err}"); - } + let mut timer = tokio::time::interval(Duration::from_secs(30)); + + let dir_path = Path::new("/var/lib/kraken/editor_cache_failures/"); + if fs::try_exists(dir_path).await.is_err() { + if let Err(err) = async { + fs::create_dir_all(dir_path).await?; + fs::set_permissions(dir_path, Permissions::from_mode(0o700)).await + } + .await + { + error!("{err}"); } + } - loop { - timer.tick().await; + loop { + timer.tick().await; - if !GLOBAL.is_initialized() { - trace!("Skipping cache save run as GLOBAL isn't initialized yet"); - continue; - } + if !GLOBAL.is_initialized() { + trace!("Skipping cache save run as GLOBAL isn't initialized yet"); + continue; + } - // Get all changed records - let data: Vec<(Impl::Key, String)> = self - .read_cache() - .iter() - .filter_map(|(uuid, inner)| match inner { - Some(inner) if inner.changed => Some((*uuid, inner.data.clone())), - _ => None, - }) - .collect(); - - let mut update_failed = vec![]; - let mut update_success = vec![]; - for (uuid, value) in data { - let res = Impl::save_to_db(uuid, value.clone()).await; - - if let Err(err) = res { - error!("DB error when updating workspace notes: {err}"); - update_failed.push((uuid, value)) - } else { - update_success.push((uuid, value)); - } + // Get all changed records + let data: Vec<(Impl::Key, String)> = self + .read_cache() + .iter() + .filter_map(|(uuid, inner)| match inner { + Some(inner) if inner.changed => Some((*uuid, inner.data.clone())), + _ => None, + }) + .collect(); + + let mut update_failed = vec![]; + let mut update_success = vec![]; + for (uuid, value) in data { + let res = Impl::save_to_db(uuid, value.clone()).await; + + if let Err(err) = res { + error!("DB error when updating workspace notes: {err}"); + update_failed.push((uuid, value)) + } else { + update_success.push((uuid, value)); } + } - { - let mut guard = self.write_cache(); - for (key, value) in update_success { - guard.get_mut(&key).and_then(|opt| { - opt.as_mut().map(|inner| { - // If the data was changed in the meantime, we shouldn't set - // changed to false - if inner.data == value { - inner.changed = false - } - }) - }); - } + { + let mut guard = self.write_cache(); + for (key, value) in update_success { + guard.get_mut(&key).and_then(|opt| { + opt.as_mut().map(|inner| { + // If the data was changed in the meantime, we shouldn't set + // changed to false + if inner.data == value { + inner.changed = false + } + }) + }); } + } - for (key, value) in update_failed { - match fs::File::create(dir_path.join(Impl::file_name(key))).await { - Ok(mut file) => { - if let Err(err) = file.write_all(value.as_bytes()).await { - error!("{err}"); - } + for (key, value) in update_failed { + match fs::File::create(dir_path.join(Impl::file_name(key))).await { + Ok(mut file) => { + if let Err(err) = file.write_all(value.as_bytes()).await { + error!("{err}"); } - Err(err) => error!("{err}"), } + Err(err) => error!("{err}"), } } } } + #[allow(clippy::type_complexity)] fn read_cache( &self, ) -> RwLockReadGuard<'_, HashMap>>> { @@ -905,6 +895,7 @@ impl EditorCache { self.inner.read().expect(EXPECT_MSG) } + #[allow(clippy::type_complexity)] fn write_cache( &self, ) -> RwLockWriteGuard<'_, HashMap>>> { diff --git a/kraken/src/modules/editor/mod.rs b/kraken/src/modules/editor/mod.rs index 61f9d6363..b65eccde6 100644 --- a/kraken/src/modules/editor/mod.rs +++ b/kraken/src/modules/editor/mod.rs @@ -29,6 +29,7 @@ use crate::models::FindingDefinition; /// Sync editor #[derive(Clone)] +#[allow(clippy::type_complexity)] pub struct EditorSync { ws_notes_tx: Arc>, finding_definition_tx: Arc>, diff --git a/kraken/src/modules/finding_factory/factory.rs b/kraken/src/modules/finding_factory/factory.rs index 1cb11de55..3a772f769 100644 --- a/kraken/src/modules/finding_factory/factory.rs +++ b/kraken/src/modules/finding_factory/factory.rs @@ -33,7 +33,7 @@ use crate::modules::finding_factory::schema::FindingFactoryIdentifier; /// /// The finding factory's API uses an enum [`FindingFactoryIdentifier`] instead of [`FindingDefinition`] uuids /// to allow code to hard code them while being dynamically configurable at runtime. -#[derive(Debug)] +#[derive(Debug, Default)] pub struct FindingFactory { issues: HashMap>, } @@ -41,9 +41,7 @@ pub struct FindingFactory { impl FindingFactory { /// Constructs a new empty `FindingFactory` pub fn new() -> Self { - FindingFactory { - issues: HashMap::new(), - } + Self::default() } /// Adds an aggregated model and its issue to the factory diff --git a/leech/src/modules/testssl/mod.rs b/leech/src/modules/testssl/mod.rs index 61d41ce09..879eea162 100644 --- a/leech/src/modules/testssl/mod.rs +++ b/leech/src/modules/testssl/mod.rs @@ -161,10 +161,10 @@ pub async fn run_testssl(settings: TestSSLSettings) -> Result Result() .await?; info!("Logged in successfully"); diff --git a/sdk/rust-kraken-sdk/src/sdk/domains.rs b/sdk/rust-kraken-sdk/src/sdk/domains.rs index 149317bbb..70b31ed1a 100644 --- a/sdk/rust-kraken-sdk/src/sdk/domains.rs +++ b/sdk/rust-kraken-sdk/src/sdk/domains.rs @@ -59,7 +59,7 @@ impl KrakenClient { /// Delete a domain pub async fn delete_domain(&self, workspace: Uuid, domain: Uuid) -> KrakenResult<()> { self.delete(&format!("api/v1/workspaces/{workspace}/domains/{domain}")) - .send() + .send::<()>() .await?; Ok(()) From 3fb92b34c0e0a473fd521b0b3844a112d4e64d61 Mon Sep 17 00:00:00 2001 From: gammelalf Date: Fri, 6 Sep 2024 15:52:44 +0200 Subject: [PATCH 37/37] Made TestSSLResultFinding point to TestSSLResultHeader instead of Attack --- kraken/migrations/0021_testssl.toml | 17 +--- kraken/migrations/0022_placeholder.toml | 10 --- .../api/handler/aggregation_source/utils.rs | 77 +++++++++---------- .../src/api/handler/attack_results/handler.rs | 2 +- kraken/src/models/attack/mod.rs | 5 +- kraken/src/models/attack/patches.rs | 2 +- kraken/src/modules/attacks/testssl.rs | 28 ++++--- kraken_frontend/src/api/api.ts | 2 +- 8 files changed, 58 insertions(+), 85 deletions(-) delete mode 100644 kraken/migrations/0022_placeholder.toml diff --git a/kraken/migrations/0021_testssl.toml b/kraken/migrations/0021_testssl.toml index 71631b74a..6b77acc66 100644 --- a/kraken/migrations/0021_testssl.toml +++ b/kraken/migrations/0021_testssl.toml @@ -1,5 +1,5 @@ [Migration] -Hash = "17574876020326552698" +Hash = "4024405889827429141" Initial = false Dependency = 20 Replaces = [] @@ -47,17 +47,6 @@ Type = "int32" [[Migration.Operations.Fields.Annotations]] Type = "not_null" -[[Migration.Operations.Fields]] -Name = "rdns" -Type = "varchar" - -[[Migration.Operations.Fields.Annotations]] -Type = "max_length" -Value = 255 - -[[Migration.Operations.Fields.Annotations]] -Type = "not_null" - [[Migration.Operations.Fields]] Name = "service" Type = "varchar" @@ -177,14 +166,14 @@ Type = "CreateField" Model = "testsslresultfinding" [Migration.Operations.Field] -Name = "attack" +Name = "header" Type = "uuid" [[Migration.Operations.Field.Annotations]] Type = "foreign_key" [Migration.Operations.Field.Annotations.Value] -TableName = "attack" +TableName = "testsslresultheader" ColumnName = "uuid" OnDelete = "Cascade" OnUpdate = "Cascade" diff --git a/kraken/migrations/0022_placeholder.toml b/kraken/migrations/0022_placeholder.toml deleted file mode 100644 index 18f444c02..000000000 --- a/kraken/migrations/0022_placeholder.toml +++ /dev/null @@ -1,10 +0,0 @@ -[Migration] -Hash = "1457786132841928709" -Initial = false -Dependency = 21 -Replaces = [] - -[[Migration.Operations]] -Type = "DeleteField" -Model = "testsslresultheader" -Name = "rdns" diff --git a/kraken/src/api/handler/aggregation_source/utils.rs b/kraken/src/api/handler/aggregation_source/utils.rs index e286df488..10f2e3ef6 100644 --- a/kraken/src/api/handler/aggregation_source/utils.rs +++ b/kraken/src/api/handler/aggregation_source/utils.rs @@ -472,49 +472,46 @@ impl FullAggregationSource { } } SourceType::TestSSL => { - { - let mut stream = query!(&mut *tx, TestSSLResultHeader) - .condition(field_in(TestSSLResultHeader::F.uuid, uuids)) - .stream(); - while let Some(result) = stream.try_next().await? { - testssl.entry(*result.attack.key()).or_default().push( + let mut findings = query!(&mut *tx, TestSSLResultFinding) + .condition(field_in( + TestSSLResultFinding::F.header, + uuids.iter().copied(), + )) + .stream() + .try_fold(HashMap::<_, Vec<_>>::new(), |mut map, finding| { + map.entry(*finding.header.key()) + .or_default() + .push(TestSSLFinding { + section: FromDb::from_db(finding.section), + id: finding.key.to_string(), + value: finding.value, + severity: FromDb::from_db(finding.testssl_severity), + cve: finding.cve, + cwe: finding.cwe, + issue: (), + }); + async move { Ok(map) } + }) + .await?; + query!(&mut *tx, TestSSLResultHeader) + .condition(field_in(TestSSLResultHeader::F.uuid, uuids)) + .stream() + .try_for_each(|header| { + testssl.entry(*header.attack.key()).or_default().push( FullTestSSLResult { - uuid: result.uuid, - attack: *result.attack.key(), - created_at: result.created_at, - domain: result.domain, - ip: result.ip.ip(), - port: result.port as u16, - service: result.service, - findings: Vec::new(), + uuid: header.uuid, + attack: *header.attack.key(), + created_at: header.created_at, + domain: header.domain, + ip: header.ip.ip(), + port: header.port as u16, + service: header.service, + findings: findings.remove(&header.uuid).unwrap_or_default(), }, ); - } - } - { - let mut stream = query!(&mut *tx, TestSSLResultFinding) - .condition(field_in( - TestSSLResultFinding::F.attack, - testssl.keys().copied(), - )) - .stream(); - while let Some(result) = stream.try_next().await? { - if let Some(slot) = testssl - .get_mut(result.attack.key()) - .and_then(|v| v.last_mut()) - { - slot.findings.push(TestSSLFinding { - section: FromDb::from_db(result.section), - id: result.key.to_string(), - value: result.value, - severity: FromDb::from_db(result.testssl_severity), - cve: result.cve, - cwe: result.cwe, - issue: (), - }); - } - } - } + async move { Ok(()) } + }) + .await?; } SourceType::UdpPortScan | SourceType::ForcedBrowsing diff --git a/kraken/src/api/handler/attack_results/handler.rs b/kraken/src/api/handler/attack_results/handler.rs index 8b5332c28..9c8690908 100644 --- a/kraken/src/api/handler/attack_results/handler.rs +++ b/kraken/src/api/handler/attack_results/handler.rs @@ -789,7 +789,7 @@ pub async fn get_testssl_results( port: header.port as u16, service: header.service, findings: query!(&mut tx, TestSSLResultFinding) - .condition(TestSSLResultFinding::F.attack.equals(attack_uuid)) + .condition(TestSSLResultFinding::F.header.equals(header.uuid)) .stream() .map_ok(|x| TestSSLFinding { section: FromDb::from_db(x.section), diff --git a/kraken/src/models/attack/mod.rs b/kraken/src/models/attack/mod.rs index 97e75e04c..23de72a62 100644 --- a/kraken/src/models/attack/mod.rs +++ b/kraken/src/models/attack/mod.rs @@ -556,10 +556,9 @@ pub struct TestSSLResultFinding { #[rorm(primary_key)] pub uuid: Uuid, - // TODO: shouldn't this be associated with the header? - /// The [attack](Attack) which produced this result + /// The [`TestSSLResultHeader`] this finding belongs to #[rorm(on_delete = "Cascade", on_update = "Cascade")] - pub attack: ForeignModel, + pub header: ForeignModel, /// The point in time, this result was produced #[rorm(auto_create_time)] diff --git a/kraken/src/models/attack/patches.rs b/kraken/src/models/attack/patches.rs index 628f59afa..563404560 100644 --- a/kraken/src/models/attack/patches.rs +++ b/kraken/src/models/attack/patches.rs @@ -163,7 +163,7 @@ pub(crate) struct TestSSLResultHeaderInsert { #[rorm(model = "TestSSLResultFinding")] pub(crate) struct TestSSLResultFindingInsert { pub(crate) uuid: Uuid, - pub(crate) attack: ForeignModel, + pub(crate) header: ForeignModel, pub(crate) section: TestSSLSection, pub(crate) key: String, pub(crate) value: String, diff --git a/kraken/src/modules/attacks/testssl.rs b/kraken/src/modules/attacks/testssl.rs index 42784f7cf..115b3f9ff 100644 --- a/kraken/src/modules/attacks/testssl.rs +++ b/kraken/src/modules/attacks/testssl.rs @@ -84,8 +84,6 @@ impl AttackContext { impl HandleAttackResponse for AttackContext { async fn handle_response(&mut self, response: TestSslResponse) -> Result<(), AttackError> { - let attack_uuid = self.attack_uuid; - for service in response.services { if let Some(test_ssl_service::TestsslService::Result(result)) = service.testssl_service { @@ -135,6 +133,18 @@ impl HandleAttackResponse for AttackContext { } }; + let source_uuid = insert!(&mut tx, TestSSLResultHeader) + .return_primary_key() + .single(&TestSSLResultHeaderInsert { + uuid: Uuid::new_v4(), + attack: ForeignModelByField::Key(self.attack_uuid), + domain: domain.clone(), + ip, + port: port as i32, + service: service.clone(), + }) + .await?; + let findings = [ (pretest, TestSSLSection::Pretest), (protocols, TestSSLSection::Protocols), @@ -156,7 +166,7 @@ impl HandleAttackResponse for AttackContext { .map(move |finding| { Ok(TestSSLResultFindingInsert { uuid: Uuid::new_v4(), - attack: ForeignModelByField::Key(attack_uuid), + header: ForeignModelByField::Key(source_uuid), section, key: finding.id, value: finding.finding, @@ -180,18 +190,6 @@ impl HandleAttackResponse for AttackContext { }) .collect::, AttackError>>()?; - let source_uuid = insert!(&mut tx, TestSSLResultHeader) - .return_primary_key() - .single(&TestSSLResultHeaderInsert { - uuid: Uuid::new_v4(), - attack: ForeignModelByField::Key(self.attack_uuid), - domain: domain.clone(), - ip, - port: port as i32, - service: service.clone(), - }) - .await?; - insert!(&mut tx, TestSSLResultFinding) .return_nothing() .bulk(&findings) diff --git a/kraken_frontend/src/api/api.ts b/kraken_frontend/src/api/api.ts index 1e5d0eccf..ecafe5454 100644 --- a/kraken_frontend/src/api/api.ts +++ b/kraken_frontend/src/api/api.ts @@ -173,7 +173,7 @@ export const Api = { }, }, attacks: { - impl: attacks, // TODO add testssl + impl: attacks, all: () => handleError(attacks.getAllAttacks()), get: (uuid: UUID) => handleError(attacks.getAttack({ uuid })), delete: (uuid: UUID) => handleError(attacks.deleteAttack({ uuid })),