txt2stix 1.0.2__tar.gz → 1.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. {txt2stix-1.0.2 → txt2stix-1.0.4}/PKG-INFO +1 -1
  2. {txt2stix-1.0.2 → txt2stix-1.0.4}/pyproject.toml +1 -1
  3. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/src/test_attack_flow.py +151 -48
  4. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/src/test_main.py +15 -1
  5. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/attack_flow.py +28 -11
  6. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/txt2stix.py +2 -2
  7. {txt2stix-1.0.2 → txt2stix-1.0.4}/.env.example +0 -0
  8. {txt2stix-1.0.2 → txt2stix-1.0.4}/.env.markdown +0 -0
  9. {txt2stix-1.0.2 → txt2stix-1.0.4}/.github/workflows/create-release.yml +0 -0
  10. {txt2stix-1.0.2 → txt2stix-1.0.4}/.github/workflows/run-tests.yml +0 -0
  11. {txt2stix-1.0.2 → txt2stix-1.0.4}/.gitignore +0 -0
  12. {txt2stix-1.0.2 → txt2stix-1.0.4}/LICENSE +0 -0
  13. {txt2stix-1.0.2 → txt2stix-1.0.4}/README.md +0 -0
  14. {txt2stix-1.0.2 → txt2stix-1.0.4}/docs/README.md +0 -0
  15. {txt2stix-1.0.2 → txt2stix-1.0.4}/docs/stix-mapping.md +0 -0
  16. {txt2stix-1.0.2 → txt2stix-1.0.4}/docs/txt2stix.png +0 -0
  17. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/__init__.py +0 -0
  18. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/extractions/ai/config.yaml +0 -0
  19. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/extractions/lookup/config.yaml +0 -0
  20. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/extractions/pattern/config.yaml +0 -0
  21. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/helpers/mimetype_filename_extension_list.csv +0 -0
  22. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/helpers/stix_relationship_types.txt +0 -0
  23. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/helpers/tlds.txt +0 -0
  24. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/helpers/windows_registry_key_prefix.txt +0 -0
  25. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/_README.md +0 -0
  26. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/_generate_lookups.py +0 -0
  27. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/attack_pattern.txt +0 -0
  28. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/campaign.txt +0 -0
  29. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/country_iso3166_alpha2.txt +0 -0
  30. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/course_of_action.txt +0 -0
  31. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/disarm_id_v1_5.txt +0 -0
  32. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/disarm_name_v1_5.txt +0 -0
  33. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/extensions.txt +0 -0
  34. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/identity.txt +0 -0
  35. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/infrastructure.txt +0 -0
  36. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/intrusion_set.txt +0 -0
  37. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/malware.txt +0 -0
  38. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_atlas_id_v4_5_2.txt +0 -0
  39. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_atlas_name_v4_5_2.txt +0 -0
  40. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_attack_enterprise_aliases_v16_0.txt +0 -0
  41. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_attack_enterprise_id_v16_0.txt +0 -0
  42. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_attack_enterprise_name_v16_0.txt +0 -0
  43. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_attack_ics_aliases_v16_0.txt +0 -0
  44. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_attack_ics_id_v16_0.txt +0 -0
  45. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_attack_ics_name_v16_0.txt +0 -0
  46. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_attack_mobile_aliases_v16_0.txt +0 -0
  47. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_attack_mobile_id_v16_0.txt +0 -0
  48. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_attack_mobile_name_v16_0.txt +0 -0
  49. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_capec_id_v3_9.txt +0 -0
  50. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_capec_name_v3_9.txt +0 -0
  51. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_cwe_id_v4_15.txt +0 -0
  52. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/mitre_cwe_name_v4_15.txt +0 -0
  53. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/threat_actor.txt +0 -0
  54. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/tld.txt +0 -0
  55. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/lookups/tool.txt +0 -0
  56. {txt2stix-1.0.2 → txt2stix-1.0.4}/includes/tests/test_cases.yaml +0 -0
  57. {txt2stix-1.0.2 → txt2stix-1.0.4}/requirements.txt +0 -0
  58. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/README.md +0 -0
  59. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/ai_country.txt +0 -0
  60. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/ai_mitre_attack_enterprise.txt +0 -0
  61. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/ai_mitre_attack_ics.txt +0 -0
  62. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/ai_mitre_attack_mobile.txt +0 -0
  63. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/ai_mitre_capec.txt +0 -0
  64. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/ai_mitre_cwe.txt +0 -0
  65. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/all_cases.txt +0 -0
  66. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_autonomous_system_number.txt +0 -0
  67. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_bank_card_all.txt +0 -0
  68. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_bank_card_amex.txt +0 -0
  69. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_bank_card_diners.txt +0 -0
  70. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_bank_card_discover.txt +0 -0
  71. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_bank_card_jcb.txt +0 -0
  72. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_bank_card_mastercard.txt +0 -0
  73. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_bank_card_union_pay.txt +0 -0
  74. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_bank_card_visa.txt +0 -0
  75. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_country_alpha2.txt +0 -0
  76. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_cpe_uri.txt +0 -0
  77. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_cryptocurrency_btc_transaction.txt +0 -0
  78. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_cryptocurrency_btc_wallet.txt +0 -0
  79. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_cryptocurrency_eth_transaction.txt +0 -0
  80. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_cryptocurrency_eth_wallet.txt +0 -0
  81. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_cryptocurrency_xmr_transaction.txt +0 -0
  82. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_cryptocurrency_xmr_wallet.txt +0 -0
  83. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_cve_id.txt +0 -0
  84. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_directory_unix.txt +0 -0
  85. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_directory_unix_file.txt +0 -0
  86. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_directory_windows.txt +0 -0
  87. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_directory_windows_with_file.txt +0 -0
  88. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_disarm.txt +0 -0
  89. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_disarm_name.txt +0 -0
  90. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_domain_name_only.txt +0 -0
  91. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_domain_name_subdomain.txt +0 -0
  92. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_email_address.txt +0 -0
  93. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_file_hash_md5.txt +0 -0
  94. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_file_hash_sha_1.txt +0 -0
  95. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_file_hash_sha_224.txt +0 -0
  96. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_file_hash_sha_256.txt +0 -0
  97. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_file_hash_sha_384.txt +0 -0
  98. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_file_hash_sha_512.txt +0 -0
  99. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_file_name.txt +0 -0
  100. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_host_name.txt +0 -0
  101. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_host_name_file.txt +0 -0
  102. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_host_name_path.txt +0 -0
  103. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_host_name_subdomain.txt +0 -0
  104. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_host_name_url.txt +0 -0
  105. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_iban_number.txt +0 -0
  106. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_ipv4_address_cidr.txt +0 -0
  107. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_ipv4_address_only.txt +0 -0
  108. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_ipv4_address_port.txt +0 -0
  109. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_ipv6_address_cidr.txt +0 -0
  110. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_ipv6_address_only.txt +0 -0
  111. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_ipv6_address_port.txt +0 -0
  112. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mac_address.txt +0 -0
  113. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_atlas.txt +0 -0
  114. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_atlas_name.txt +0 -0
  115. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_attack_enterprise.txt +0 -0
  116. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_attack_enterprise_aliases.txt +0 -0
  117. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_attack_enterprise_name.txt +0 -0
  118. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_attack_ics.txt +0 -0
  119. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_attack_ics_aliases.txt +0 -0
  120. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_attack_ics_name.txt +0 -0
  121. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_attack_mobile.txt +0 -0
  122. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_attack_mobile_aliases.txt +0 -0
  123. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_attack_mobile_name.txt +0 -0
  124. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_capec.txt +0 -0
  125. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_capec_name.txt +0 -0
  126. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_cwe.txt +0 -0
  127. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_mitre_cwe_name.txt +0 -0
  128. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_phone_number.txt +0 -0
  129. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_url.txt +0 -0
  130. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_url_file.txt +0 -0
  131. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_url_path.txt +0 -0
  132. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_user_agent.txt +0 -0
  133. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/generic_windows_registry_key.txt +0 -0
  134. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/lookup_attack_pattern.txt +0 -0
  135. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/lookup_campaign.txt +0 -0
  136. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/lookup_course_of_action.txt +0 -0
  137. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/lookup_identity.txt +0 -0
  138. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/lookup_infrastructure.txt +0 -0
  139. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/lookup_intrusion_set.txt +0 -0
  140. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/lookup_malware.txt +0 -0
  141. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/lookup_threat_actor.txt +0 -0
  142. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/extraction_types/lookup_tool.txt +0 -0
  143. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/attack_flow_demo.txt +0 -0
  144. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/attack_navigator_demo.txt +0 -0
  145. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/basic_relationship.txt +0 -0
  146. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/char_length_too_long.txt +0 -0
  147. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/descriptive_for_ai_relationships_1.txt +0 -0
  148. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/disarm_demo.txt +0 -0
  149. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/embedded_img_ignore.txt +0 -0
  150. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/embedded_link_ignore.txt +0 -0
  151. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/ip1.txt +0 -0
  152. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/ip2.txt +0 -0
  153. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/known_whitelist_match.txt +0 -0
  154. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/mitre_attack_enterprise_ai_demo.txt +0 -0
  155. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/mitre_attack_enterprise_lookup_demo.txt +0 -0
  156. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/mixed_extractions.txt +0 -0
  157. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/not_security_content.txt +0 -0
  158. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/test_ai_hash_error_with_stix2_lib.txt +0 -0
  159. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/test_aliases.txt +0 -0
  160. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/test_extraction_boundary.txt +0 -0
  161. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/manually_generated_reports/test_extraction_escapes.txt +0 -0
  162. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/real_intel_reports/APT28-Center-of-Storm-2017.txt +0 -0
  163. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/real_intel_reports/Bitdefender-Labs-Report-X-creat6958-en-EN.txt +0 -0
  164. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/real_intel_reports/FireEyeAPT39.txt +0 -0
  165. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/real_intel_reports/France_CERT_APT31_Pakdoor_TLPWHITE.txt +0 -0
  166. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/real_intel_reports/Group-IB_Ransomware_Uncovered_whitepaper_eng.txt +0 -0
  167. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/real_intel_reports/JOINT_CSA_HUNTING_RU_INTEL_SNAKE_MALWARE_20230509.txt +0 -0
  168. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/real_intel_reports/TA22-0126-QAKBOT-analysis-TLP-GREEN.txt +0 -0
  169. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/real_intel_reports/dinners_card.txt +0 -0
  170. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/real_intel_reports/mandiant-apt1.txt +0 -0
  171. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/data/real_intel_reports/mykings_report_final.txt +0 -0
  172. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/manual-tests/cases-ai-relationships.md +0 -0
  173. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/manual-tests/cases-extraction-type-ai.md +0 -0
  174. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/manual-tests/cases-extraction-type-lookup.md +0 -0
  175. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/manual-tests/cases-extraction-type-pattern.md +0 -0
  176. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/manual-tests/cases-standard-tests.md +0 -0
  177. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/scripts/generate_simple_extraction_test_cases_txt_files.py +0 -0
  178. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/src/__init__.py +0 -0
  179. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/src/test_bundler.py +0 -0
  180. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/src/test_extractors.py +0 -0
  181. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/src/test_indicator.py +0 -0
  182. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/src/test_lookups.py +0 -0
  183. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/src/test_run_txt2stix.py +0 -0
  184. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/src/test_utils.py +0 -0
  185. {txt2stix-1.0.2 → txt2stix-1.0.4}/tests/src/utils.py +0 -0
  186. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/__init__.py +0 -0
  187. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/ai_extractor/__init__.py +0 -0
  188. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/ai_extractor/anthropic.py +0 -0
  189. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/ai_extractor/base.py +0 -0
  190. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/ai_extractor/deepseek.py +0 -0
  191. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/ai_extractor/gemini.py +0 -0
  192. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/ai_extractor/openai.py +0 -0
  193. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/ai_extractor/openrouter.py +0 -0
  194. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/ai_extractor/prompts.py +0 -0
  195. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/ai_extractor/utils.py +0 -0
  196. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/bundler.py +0 -0
  197. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/common.py +0 -0
  198. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/extractions.py +0 -0
  199. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/indicator.py +0 -0
  200. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/lookups.py +0 -0
  201. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/__init__.py +0 -0
  202. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/__init__.py +0 -0
  203. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/base_extractor.py +0 -0
  204. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/card/README.md +0 -0
  205. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/card/__init__.py +0 -0
  206. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/card/amex_card_extractor.py +0 -0
  207. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/card/diners_card_extractor.py +0 -0
  208. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/card/discover_card_extractor.py +0 -0
  209. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/card/jcb_card_extractor.py +0 -0
  210. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/card/master_card_extractor.py +0 -0
  211. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/card/union_card_extractor.py +0 -0
  212. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/card/visa_card_extractor.py +0 -0
  213. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/crypto/__init__.py +0 -0
  214. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/crypto/btc_extractor.py +0 -0
  215. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/directory/__init__.py +0 -0
  216. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/directory/unix_directory_extractor.py +0 -0
  217. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/directory/unix_file_path_extractor.py +0 -0
  218. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/directory/windows_directory_path_extractor.py +0 -0
  219. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/directory/windows_file_path_extractor.py +0 -0
  220. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/domain/__init__.py +0 -0
  221. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/domain/domain_extractor.py +0 -0
  222. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/domain/hostname_extractor.py +0 -0
  223. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/domain/sub_domain_extractor.py +0 -0
  224. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/hashes/__init__.py +0 -0
  225. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/hashes/md5_extractor.py +0 -0
  226. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/hashes/sha1_extractor.py +0 -0
  227. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/hashes/sha224_extractor.py +0 -0
  228. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/hashes/sha2_256_exactor.py +0 -0
  229. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/hashes/sha2_512_exactor.py +0 -0
  230. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/hashes/sha3_256_exactor.py +0 -0
  231. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/hashes/sha3_512_exactor.py +0 -0
  232. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/helper.py +0 -0
  233. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/ip/__init__.py +0 -0
  234. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/ip/ipv4_cidr_extractor.py +0 -0
  235. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/ip/ipv4_extractor.py +0 -0
  236. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/ip/ipv4_port_extractor.py +0 -0
  237. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/ip/ipv6_cidr_extractor.py +0 -0
  238. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/ip/ipv6_extractor.py +0 -0
  239. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/ip/ipv6_port_extractor.py +0 -0
  240. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/__init__.py +0 -0
  241. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/asn_extractor.py +0 -0
  242. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/cpe_extractor.py +0 -0
  243. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/cve_extractor.py +0 -0
  244. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/email_extractor.py +0 -0
  245. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/filename_extractor.py +0 -0
  246. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/iban_extractor.py +0 -0
  247. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/mac_address_extractor.py +0 -0
  248. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/phonenumber_extractor.py +0 -0
  249. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/user_agent_extractor.py +0 -0
  250. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/others/windows_registry_key_extractor.py +0 -0
  251. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/url/__init__.py +0 -0
  252. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/url/url_extractor.py +0 -0
  253. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/url/url_file_extractor.py +0 -0
  254. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/pattern/extractors/url/url_path_extractor.py +0 -0
  255. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/retriever.py +0 -0
  256. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/stix.py +0 -0
  257. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix/utils.py +0 -0
  258. {txt2stix-1.0.2 → txt2stix-1.0.4}/txt2stix.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: txt2stix
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: txt2stix is a Python script that is designed to identify and extract IoCs and TTPs from text files, identify the relationships between them, convert them to STIX 2.1 objects, and output as a STIX 2.1 bundle.
5
5
  Project-URL: Homepage, https://github.com/muchdogesec/txt2stix
6
6
  Project-URL: Issues, https://github.com/muchdogesec/txt2stix/issues
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "txt2stix"
7
- version = "1.0.2"
7
+ version = "1.0.4"
8
8
  authors = [{ name = "dogesec" }]
9
9
  maintainers = [{ name = "dogesec" }]
10
10
  description = "txt2stix is a Python script that is designed to identify and extract IoCs and TTPs from text files, identify the relationships between them, convert them to STIX 2.1 objects, and output as a STIX 2.1 bundle."
@@ -3,9 +3,7 @@ import pytest
3
3
  from unittest.mock import MagicMock, patch
4
4
  from stix2extensions._extensions import attack_flow_ExtensionDefinitionSMO
5
5
 
6
- from txt2stix.ai_extractor.utils import (
7
- AttackFlowList,
8
- )
6
+ from txt2stix.ai_extractor.utils import AttackFlowList, AttackFlowItem
9
7
  from txt2stix.attack_flow import (
10
8
  create_navigator_layer,
11
9
  get_all_tactics,
@@ -55,6 +53,7 @@ def test_parse_flow__no_success(dummy_report):
55
53
  success=False,
56
54
  matrix="enterprise",
57
55
  items=[],
56
+ tactic_selection=[],
58
57
  ),
59
58
  None,
60
59
  None,
@@ -71,28 +70,28 @@ def test_get_techniques_from_extracted_objects(dummy_objects):
71
70
  "T0814": {
72
71
  "domain": "ics-attack",
73
72
  "name": "Denial of Service",
74
- "possible_tactics": {"TA0107": "inhibit-response-function"},
73
+ "possible_tactics": {"inhibit-response-function": "TA0107"},
75
74
  "id": "T0814",
76
75
  "platforms": [],
77
76
  },
78
77
  "T0887": {
79
78
  "domain": "ics-attack",
80
79
  "name": "Wireless Sniffing",
81
- "possible_tactics": {"TA0102": "discovery" , "TA0100": "collection"},
80
+ "possible_tactics": {"discovery": "TA0102", "collection": "TA0100"},
82
81
  "id": "T0887",
83
82
  "platforms": [],
84
83
  },
85
84
  "T1505.001": {
86
85
  "domain": "enterprise-attack",
87
86
  "name": "SQL Stored Procedures",
88
- "possible_tactics": {"TA0003":"persistence"},
87
+ "possible_tactics": {"persistence": "TA0003"},
89
88
  "id": "T1505.001",
90
89
  "platforms": ["Windows", "Linux"],
91
90
  },
92
91
  "T1555.002": {
93
92
  "domain": "enterprise-attack",
94
93
  "name": "Securityd Memory",
95
- "possible_tactics": {"TA0006": "credential-access"},
94
+ "possible_tactics": {"credential-access": "TA0006"},
96
95
  "id": "T1555.002",
97
96
  "platforms": ["Linux", "macOS"],
98
97
  },
@@ -128,7 +127,7 @@ def test_extract_attack_flow_and_navigator(dummy_objects, dummy_report):
128
127
  "txt2stix.attack_flow.create_navigator_layer"
129
128
  ) as mock_create_navigator_layer,
130
129
  ):
131
- ## Both flow and navigator
130
+ # ================= Both flow and navigator ===================
132
131
  flow, nav = extract_attack_flow_and_navigator(
133
132
  bundler, text, True, True, ai_extractor
134
133
  )
@@ -151,7 +150,7 @@ def test_extract_attack_flow_and_navigator(dummy_objects, dummy_report):
151
150
  mock_create_navigator_layer.reset_mock()
152
151
  mock_extract_flow.reset_mock()
153
152
 
154
- ## only flow
153
+ # ================= only flow ===================
155
154
  flow, nav = extract_attack_flow_and_navigator(
156
155
  bundler, text, True, False, ai_extractor
157
156
  )
@@ -169,7 +168,7 @@ def test_extract_attack_flow_and_navigator(dummy_objects, dummy_report):
169
168
  mock_create_navigator_layer.reset_mock()
170
169
  mock_extract_flow.reset_mock()
171
170
 
172
- ## only navigator
171
+ # ================= only navigator ===================
173
172
  flow, nav = extract_attack_flow_and_navigator(
174
173
  bundler, text, False, True, ai_extractor
175
174
  )
@@ -185,6 +184,21 @@ def test_extract_attack_flow_and_navigator(dummy_objects, dummy_report):
185
184
  bundler.report, bundler.summary, mock_extract_flow.return_value, techniques
186
185
  )
187
186
 
187
+ ### reset mocks
188
+ mock_parse_flow.reset_mock()
189
+ mock_create_navigator_layer.reset_mock()
190
+ mock_extract_flow.reset_mock()
191
+ # ============ no technique object ============
192
+ bundler.bundle.objects = []
193
+ flow, nav = extract_attack_flow_and_navigator(
194
+ bundler, text, True, True, ai_extractor
195
+ )
196
+ mock_extract_flow.assert_not_called()
197
+ assert (flow, nav) == (None, None)
198
+ mock_parse_flow.assert_not_called()
199
+
200
+ mock_create_navigator_layer.assert_not_called()
201
+
188
202
 
189
203
  def test_create_navigator_layer(dummy_report):
190
204
  summary = "this is a summary"
@@ -202,15 +216,36 @@ def test_create_navigator_layer(dummy_report):
202
216
  "TA91": "exfiltration",
203
217
  }
204
218
  flow.items = [
205
- SimpleNamespace(attack_technique_id="T0001", attack_tactic_id="TA01"),
206
- SimpleNamespace(attack_technique_id="T0002", attack_tactic_id="TA02"),
207
- SimpleNamespace(attack_technique_id="T0003", attack_tactic_id="TA03"),
208
- SimpleNamespace(attack_technique_id="T1001", attack_tactic_id="TA11"),
209
- SimpleNamespace(attack_technique_id="T1002", attack_tactic_id="TA12"),
210
- SimpleNamespace(attack_technique_id="T1003", attack_tactic_id="TA25"),
211
- SimpleNamespace(attack_technique_id="T2001", attack_tactic_id="TA11"),
212
- SimpleNamespace(attack_technique_id="T2002", attack_tactic_id="TA123"),
213
- SimpleNamespace(attack_technique_id="T2003", attack_tactic_id="TA91"),
219
+ SimpleNamespace(
220
+ attack_technique_id="T0001",
221
+ attack_tactic_id="TA01",
222
+ description="description 1",
223
+ ),
224
+ SimpleNamespace(
225
+ attack_technique_id="T0003",
226
+ attack_tactic_id="TA03",
227
+ description="description 2",
228
+ ),
229
+ SimpleNamespace(
230
+ attack_technique_id="T1001",
231
+ attack_tactic_id="TA11",
232
+ description="description 3",
233
+ ),
234
+ SimpleNamespace(
235
+ attack_technique_id="T1002",
236
+ attack_tactic_id="TA12",
237
+ description="description 4",
238
+ ),
239
+ SimpleNamespace(
240
+ attack_technique_id="T2001",
241
+ attack_tactic_id="TA11",
242
+ description="description 28jhsjhs",
243
+ ),
244
+ SimpleNamespace(
245
+ attack_technique_id="T2003",
246
+ attack_tactic_id="TA91",
247
+ description="description sasa",
248
+ ),
214
249
  ]
215
250
  techniques = {
216
251
  "T0001": dict(
@@ -232,25 +267,31 @@ def test_create_navigator_layer(dummy_report):
232
267
 
233
268
  retval = create_navigator_layer(dummy_report, summary, flow, techniques)
234
269
  assert len(retval) == 3
235
- print(retval)
236
270
  assert retval == [
237
271
  {
238
272
  "version": "4.5",
239
273
  "name": "some markdown document",
240
274
  "domain": "enterprise-attack",
241
275
  "description": "this is a summary",
242
- "techniques": [
243
- {"techniqueID": "T0001", "tactic": "initial-access"},
244
- {"techniqueID": "T0002", "tactic": "lateral-movement"},
245
- {"techniqueID": "T0003", "tactic": "command-and-control"},
246
- ],
276
+ "techniques": [],
247
277
  "gradient": {
248
278
  "colors": ["#ffffff", "#ff6666"],
249
279
  "minValue": 0,
250
280
  "maxValue": 100,
251
281
  },
252
282
  "legendItems": [],
253
- "metadata": [],
283
+ "metadata": [
284
+ {
285
+ "name": "report_id",
286
+ "value": "report--9c88fbcb-8c0d-4124-868b-3dcb1e9b696c",
287
+ }
288
+ ],
289
+ "links": [
290
+ {
291
+ "label": "Generated using txt2stix",
292
+ "url": "https://github.com/muchdogesec/txt2stix/",
293
+ }
294
+ ],
254
295
  "layout": {"layout": "side"},
255
296
  },
256
297
  {
@@ -258,18 +299,25 @@ def test_create_navigator_layer(dummy_report):
258
299
  "name": "some markdown document",
259
300
  "domain": "ics-attack",
260
301
  "description": "this is a summary",
261
- "techniques": [
262
- {"techniqueID": "T1001", "tactic": "initial-access"},
263
- {"techniqueID": "T1002", "tactic": "lateral-movement"},
264
- {"techniqueID": "T1003", "tactic": "command-and-control"},
265
- ],
302
+ "techniques": [],
266
303
  "gradient": {
267
304
  "colors": ["#ffffff", "#ff6666"],
268
305
  "minValue": 0,
269
306
  "maxValue": 100,
270
307
  },
271
308
  "legendItems": [],
272
- "metadata": [],
309
+ "metadata": [
310
+ {
311
+ "name": "report_id",
312
+ "value": "report--9c88fbcb-8c0d-4124-868b-3dcb1e9b696c",
313
+ }
314
+ ],
315
+ "links": [
316
+ {
317
+ "label": "Generated using txt2stix",
318
+ "url": "https://github.com/muchdogesec/txt2stix/",
319
+ }
320
+ ],
273
321
  "layout": {"layout": "side"},
274
322
  },
275
323
  {
@@ -277,18 +325,25 @@ def test_create_navigator_layer(dummy_report):
277
325
  "name": "some markdown document",
278
326
  "domain": "mobile-attack",
279
327
  "description": "this is a summary",
280
- "techniques": [
281
- {"techniqueID": "T2001", "tactic": "initial-access"},
282
- {"techniqueID": "T2002", "tactic": "persistence"},
283
- {"techniqueID": "T2003", "tactic": "exfiltration"},
284
- ],
328
+ "techniques": [],
285
329
  "gradient": {
286
330
  "colors": ["#ffffff", "#ff6666"],
287
331
  "minValue": 0,
288
332
  "maxValue": 100,
289
333
  },
290
334
  "legendItems": [],
291
- "metadata": [],
335
+ "metadata": [
336
+ {
337
+ "name": "report_id",
338
+ "value": "report--9c88fbcb-8c0d-4124-868b-3dcb1e9b696c",
339
+ }
340
+ ],
341
+ "links": [
342
+ {
343
+ "label": "Generated using txt2stix",
344
+ "url": "https://github.com/muchdogesec/txt2stix/",
345
+ }
346
+ ],
292
347
  "layout": {"layout": "side"},
293
348
  },
294
349
  ]
@@ -307,8 +362,20 @@ def test_create_navigator_layer__real_flow(dummy_report, dummy_flow, dummy_objec
307
362
  "domain": "ics-attack",
308
363
  "description": "a summary",
309
364
  "techniques": [
310
- {"techniqueID": "T0814", "tactic": "inhibit-response-function"},
311
- {"techniqueID": "T0887", "tactic": "discovery"},
365
+ {
366
+ "techniqueID": "T0814",
367
+ "tactic": "inhibit-response-function",
368
+ "score": 100,
369
+ "showSubtechniques": True,
370
+ "comment": "The SQL injection requests lead to a denial of service condition, disrupting the availability of the targeted service.",
371
+ },
372
+ {
373
+ "techniqueID": "T0887",
374
+ "tactic": "discovery",
375
+ "score": 100,
376
+ "showSubtechniques": True,
377
+ "comment": "The attack begins by using Wireshark to sniff network packets with a specific source, indicating a reconnaissance or discovery phase to gather information about the network traffic.",
378
+ },
312
379
  ],
313
380
  "gradient": {
314
381
  "colors": ["#ffffff", "#ff6666"],
@@ -316,7 +383,18 @@ def test_create_navigator_layer__real_flow(dummy_report, dummy_flow, dummy_objec
316
383
  "maxValue": 100,
317
384
  },
318
385
  "legendItems": [],
319
- "metadata": [],
386
+ "metadata": [
387
+ {
388
+ "name": "report_id",
389
+ "value": "report--9c88fbcb-8c0d-4124-868b-3dcb1e9b696c",
390
+ }
391
+ ],
392
+ "links": [
393
+ {
394
+ "label": "Generated using txt2stix",
395
+ "url": "https://github.com/muchdogesec/txt2stix/",
396
+ }
397
+ ],
320
398
  "layout": {"layout": "side"},
321
399
  },
322
400
  {
@@ -325,8 +403,20 @@ def test_create_navigator_layer__real_flow(dummy_report, dummy_flow, dummy_objec
325
403
  "domain": "enterprise-attack",
326
404
  "description": "a summary",
327
405
  "techniques": [
328
- {"techniqueID": "T1505.001", "tactic": "persistence"},
329
- {"techniqueID": "T1555.002", "tactic": "credential-access"},
406
+ {
407
+ "techniqueID": "T1505.001",
408
+ "tactic": "persistence",
409
+ "score": 100,
410
+ "showSubtechniques": True,
411
+ "comment": "A series of SQL injection requests are sent to a specific port, potentially to establish persistence or manipulate database operations.",
412
+ },
413
+ {
414
+ "techniqueID": "T1555.002",
415
+ "tactic": "credential-access",
416
+ "score": 100,
417
+ "showSubtechniques": True,
418
+ "comment": "An additional method is employed to bypass Securityd, likely to gain unauthorized access to credentials or sensitive information.",
419
+ },
330
420
  ],
331
421
  "gradient": {
332
422
  "colors": ["#ffffff", "#ff6666"],
@@ -334,7 +424,18 @@ def test_create_navigator_layer__real_flow(dummy_report, dummy_flow, dummy_objec
334
424
  "maxValue": 100,
335
425
  },
336
426
  "legendItems": [],
337
- "metadata": [],
427
+ "metadata": [
428
+ {
429
+ "name": "report_id",
430
+ "value": "report--9c88fbcb-8c0d-4124-868b-3dcb1e9b696c",
431
+ }
432
+ ],
433
+ "links": [
434
+ {
435
+ "label": "Generated using txt2stix",
436
+ "url": "https://github.com/muchdogesec/txt2stix/",
437
+ }
438
+ ],
338
439
  "layout": {"layout": "side"},
339
440
  },
340
441
  ]
@@ -623,33 +724,35 @@ def dummy_flow():
623
724
  "items": [
624
725
  {
625
726
  "position": 0,
626
- "attack_tactic_id": "TA0102",
627
727
  "attack_technique_id": "T0887",
628
728
  "name": "Packet Sniffing with Wireshark",
629
729
  "description": "The attack begins by using Wireshark to sniff network packets with a specific source, indicating a reconnaissance or discovery phase to gather information about the network traffic.",
630
730
  },
631
731
  {
632
732
  "position": 1,
633
- "attack_tactic_id": "TA0003",
634
733
  "attack_technique_id": "T1505.001",
635
734
  "name": "SQL Injection for Persistence",
636
735
  "description": "A series of SQL injection requests are sent to a specific port, potentially to establish persistence or manipulate database operations.",
637
736
  },
638
737
  {
639
738
  "position": 2,
640
- "attack_tactic_id": "TA0107",
641
739
  "attack_technique_id": "T0814",
642
740
  "name": "Denial of Service via SQLi",
643
741
  "description": "The SQL injection requests lead to a denial of service condition, disrupting the availability of the targeted service.",
644
742
  },
645
743
  {
646
744
  "position": 3,
647
- "attack_tactic_id": "TA0006",
648
745
  "attack_technique_id": "T1555.002",
649
746
  "name": "Bypassing Securityd",
650
747
  "description": "An additional method is employed to bypass Securityd, likely to gain unauthorized access to credentials or sensitive information.",
651
748
  },
652
749
  ],
653
750
  "success": True,
751
+ "tactic_selection": [
752
+ ("T0887", "discovery"),
753
+ ("T1505.001", "persistence"),
754
+ ("T0814", "inhibit-response-function"),
755
+ ("T1555.002", "credential-access"),
756
+ ],
654
757
  }
655
758
  )
@@ -146,7 +146,21 @@ def test_parse_args_fails(monkeypatch):
146
146
  "standard",
147
147
  "--ai_create_attack_flow",
148
148
  ])
149
- with pytest.raises(argparse.ArgumentError, match="--ai_create_attack_flow requires --ai_settings_relationships"):
149
+ with pytest.raises(argparse.ArgumentError, match="argument --ai_create_attack_flow: --ai_settings_relationships must be set"):
150
+ parse_args()
151
+
152
+
153
+ monkeypatch.setattr(sys, 'argv', [
154
+ "program",
155
+ "--input-file",
156
+ tmp.name,
157
+ "--name",
158
+ "a",
159
+ "--relationship_mode",
160
+ "standard",
161
+ "--ai_create_attack_navigator_layer",
162
+ ])
163
+ with pytest.raises(argparse.ArgumentError, match="argument --ai_create_attack_navigator_layer: --ai_settings_relationships must be set"):
150
164
  parse_args()
151
165
 
152
166
  monkeypatch.setattr(sys, 'argv', [
@@ -21,14 +21,14 @@ def parse_flow(report, flow: AttackFlowList, techniques, tactics):
21
21
  for i, item in enumerate(flow.items):
22
22
  try:
23
23
  technique = techniques[item.attack_technique_id]
24
- tactic_id = technique['possible_tactics'][flow.tactic_mapping[item.attack_technique_id]]
24
+ tactic_id = technique["possible_tactics"][
25
+ flow.tactic_mapping[item.attack_technique_id]
26
+ ]
25
27
  technique_obj = technique["stix_obj"]
26
28
  tactic_obj = tactics[technique["domain"]][tactic_id]
27
29
  action_obj = AttackAction(
28
30
  **{
29
- "id": flow_id(
30
- report["id"], item.attack_technique_id, tactic_id
31
- ),
31
+ "id": flow_id(report["id"], item.attack_technique_id, tactic_id),
32
32
  "effect_refs": [f"attack-action--{str(uuid.uuid4())}"],
33
33
  "technique_id": item.attack_technique_id,
34
34
  "technique_ref": technique_obj["id"],
@@ -149,14 +149,21 @@ def get_techniques_from_extracted_objects(objects: dict, tactics: dict):
149
149
 
150
150
  def create_navigator_layer(report, summary, flow: AttackFlowList, techniques):
151
151
  domains = {}
152
+ comments = {item.attack_technique_id: item.description for item in flow.items}
152
153
  for technique in techniques.values():
153
154
  domain_techniques = domains.setdefault(technique["domain"], [])
154
155
  technique_id = technique["id"]
155
156
  if technique_id not in flow.tactic_mapping:
156
157
  continue
157
- domain_techniques.append(
158
- dict(techniqueID=technique_id, tactic=flow.tactic_mapping[technique_id])
158
+ technique_item = dict(
159
+ techniqueID=technique_id,
160
+ tactic=flow.tactic_mapping[technique_id],
161
+ score=100,
162
+ showSubtechniques=True,
159
163
  )
164
+ if comment := comments.get(technique_id):
165
+ technique_item["comment"] = comment
166
+ domain_techniques.append(technique_item)
160
167
 
161
168
  retval = []
162
169
 
@@ -174,7 +181,13 @@ def create_navigator_layer(report, summary, flow: AttackFlowList, techniques):
174
181
  "maxValue": 100,
175
182
  },
176
183
  "legendItems": [],
177
- "metadata": [],
184
+ "metadata": [{"name": "report_id", "value": report.id}],
185
+ "links": [
186
+ {
187
+ "label": "Generated using txt2stix",
188
+ "url": "https://github.com/muchdogesec/txt2stix/",
189
+ }
190
+ ],
178
191
  "layout": {"layout": "side"},
179
192
  }
180
193
  )
@@ -191,10 +204,12 @@ def extract_attack_flow_and_navigator(
191
204
  ex: BaseAIExtractor = ai_settings_relationships
192
205
  tactics = get_all_tactics()
193
206
  techniques = get_techniques_from_extracted_objects(bundler.bundle.objects, tactics)
207
+ if not techniques:
208
+ return None, None
209
+
194
210
  logged_techniques = [
195
- {k: v for k, v in t.items() if k != "stix_obj"}
196
- for t in techniques.values()
197
- ]
211
+ {k: v for k, v in t.items() if k != "stix_obj"} for t in techniques.values()
212
+ ]
198
213
  logging.debug(f"parsed techniques: {json.dumps(logged_techniques, indent=4)}")
199
214
 
200
215
  flow = ex.extract_attack_flow(preprocessed_text, techniques)
@@ -204,5 +219,7 @@ def extract_attack_flow_and_navigator(
204
219
  bundler.flow_objects = parse_flow(bundler.report, flow, techniques, tactics)
205
220
 
206
221
  if ai_create_attack_navigator_layer:
207
- navigator = create_navigator_layer(bundler.report, bundler.summary, flow, techniques)
222
+ navigator = create_navigator_layer(
223
+ bundler.report, bundler.summary, flow, techniques
224
+ )
208
225
  return flow, navigator
@@ -440,11 +440,11 @@ def main():
440
440
  output_path = output_dir/f"{bundler.bundle.id}.json"
441
441
  output_path.write_text(out)
442
442
  logger.info(f"Wrote bundle output to `{output_path}`")
443
- data_path = output_dir/"data.json"
443
+ data_path = output_dir/f"data--{args.report_id}.json"
444
444
  data_path.write_text(data.model_dump_json(indent=4))
445
445
  logger.info(f"Wrote data output to `{data_path}`")
446
446
  for nav_layer in data.navigator_layer or []:
447
- nav_path = output_dir/f"navigator-{nav_layer['domain']}.json"
447
+ nav_path = output_dir/f"navigator-{nav_layer['domain']}----{args.report_id}.json"
448
448
  nav_path.write_text(json.dumps(nav_layer, indent=4))
449
449
  logger.info(f"Wrote navigator output to `{nav_path}`")
450
450
  except argparse.ArgumentError as e:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes