txt2stix 1.0.8__tar.gz → 1.0.10__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 (261) hide show
  1. {txt2stix-1.0.8 → txt2stix-1.0.10}/PKG-INFO +1 -1
  2. {txt2stix-1.0.8 → txt2stix-1.0.10}/pyproject.toml +1 -1
  3. txt2stix-1.0.10/requirements.txt +233 -0
  4. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/attack_flow_demo.txt +3 -1
  5. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/manual-tests/cases-standard-tests.md +18 -0
  6. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/test_attack_flow.py +76 -26
  7. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/ai_extractor/openai.py +6 -1
  8. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/attack_flow.py +16 -5
  9. txt2stix-1.0.8/requirements.txt +0 -377
  10. {txt2stix-1.0.8 → txt2stix-1.0.10}/.env.example +0 -0
  11. {txt2stix-1.0.8 → txt2stix-1.0.10}/.env.markdown +0 -0
  12. {txt2stix-1.0.8 → txt2stix-1.0.10}/.github/workflows/create-release.yml +0 -0
  13. {txt2stix-1.0.8 → txt2stix-1.0.10}/.github/workflows/run-tests.yml +0 -0
  14. {txt2stix-1.0.8 → txt2stix-1.0.10}/.gitignore +0 -0
  15. {txt2stix-1.0.8 → txt2stix-1.0.10}/LICENSE +0 -0
  16. {txt2stix-1.0.8 → txt2stix-1.0.10}/README.md +0 -0
  17. {txt2stix-1.0.8 → txt2stix-1.0.10}/docs/README.md +0 -0
  18. {txt2stix-1.0.8 → txt2stix-1.0.10}/docs/stix-mapping.md +0 -0
  19. {txt2stix-1.0.8 → txt2stix-1.0.10}/docs/txt2stix.png +0 -0
  20. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/__init__.py +0 -0
  21. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/extractions/ai/config.yaml +0 -0
  22. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/extractions/lookup/config.yaml +0 -0
  23. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/extractions/pattern/config.yaml +0 -0
  24. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/helpers/mimetype_filename_extension_list.csv +0 -0
  25. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/helpers/stix_relationship_types.txt +0 -0
  26. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/helpers/tlds.txt +0 -0
  27. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/helpers/windows_registry_key_prefix.txt +0 -0
  28. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/_README.md +0 -0
  29. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/_generate_lookups.py +0 -0
  30. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/attack_pattern.txt +0 -0
  31. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/campaign.txt +0 -0
  32. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/country_iso3166_alpha2.txt +0 -0
  33. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/course_of_action.txt +0 -0
  34. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/disarm_id_v1_5.txt +0 -0
  35. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/disarm_name_v1_5.txt +0 -0
  36. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/extensions.txt +0 -0
  37. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/identity.txt +0 -0
  38. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/infrastructure.txt +0 -0
  39. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/intrusion_set.txt +0 -0
  40. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/malware.txt +0 -0
  41. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_atlas_id_v4_5_2.txt +0 -0
  42. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_atlas_name_v4_5_2.txt +0 -0
  43. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_attack_enterprise_aliases_v16_0.txt +0 -0
  44. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_attack_enterprise_id_v16_0.txt +0 -0
  45. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_attack_enterprise_name_v16_0.txt +0 -0
  46. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_attack_ics_aliases_v16_0.txt +0 -0
  47. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_attack_ics_id_v16_0.txt +0 -0
  48. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_attack_ics_name_v16_0.txt +0 -0
  49. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_attack_mobile_aliases_v16_0.txt +0 -0
  50. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_attack_mobile_id_v16_0.txt +0 -0
  51. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_attack_mobile_name_v16_0.txt +0 -0
  52. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_capec_id_v3_9.txt +0 -0
  53. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_capec_name_v3_9.txt +0 -0
  54. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_cwe_id_v4_15.txt +0 -0
  55. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/mitre_cwe_name_v4_15.txt +0 -0
  56. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/threat_actor.txt +0 -0
  57. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/tld.txt +0 -0
  58. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/lookups/tool.txt +0 -0
  59. {txt2stix-1.0.8 → txt2stix-1.0.10}/includes/tests/test_cases.yaml +0 -0
  60. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/README.md +0 -0
  61. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/ai_country.txt +0 -0
  62. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/ai_mitre_attack_enterprise.txt +0 -0
  63. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/ai_mitre_attack_ics.txt +0 -0
  64. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/ai_mitre_attack_mobile.txt +0 -0
  65. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/ai_mitre_capec.txt +0 -0
  66. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/ai_mitre_cwe.txt +0 -0
  67. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/all_cases.txt +0 -0
  68. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_autonomous_system_number.txt +0 -0
  69. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_bank_card_all.txt +0 -0
  70. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_bank_card_amex.txt +0 -0
  71. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_bank_card_diners.txt +0 -0
  72. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_bank_card_discover.txt +0 -0
  73. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_bank_card_jcb.txt +0 -0
  74. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_bank_card_mastercard.txt +0 -0
  75. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_bank_card_union_pay.txt +0 -0
  76. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_bank_card_visa.txt +0 -0
  77. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_country_alpha2.txt +0 -0
  78. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_cpe_uri.txt +0 -0
  79. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_cryptocurrency_btc_transaction.txt +0 -0
  80. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_cryptocurrency_btc_wallet.txt +0 -0
  81. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_cryptocurrency_eth_transaction.txt +0 -0
  82. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_cryptocurrency_eth_wallet.txt +0 -0
  83. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_cryptocurrency_xmr_transaction.txt +0 -0
  84. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_cryptocurrency_xmr_wallet.txt +0 -0
  85. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_cve_id.txt +0 -0
  86. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_directory_unix.txt +0 -0
  87. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_directory_unix_file.txt +0 -0
  88. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_directory_windows.txt +0 -0
  89. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_directory_windows_with_file.txt +0 -0
  90. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_disarm.txt +0 -0
  91. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_disarm_name.txt +0 -0
  92. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_domain_name_only.txt +0 -0
  93. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_domain_name_subdomain.txt +0 -0
  94. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_email_address.txt +0 -0
  95. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_file_hash_md5.txt +0 -0
  96. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_file_hash_sha_1.txt +0 -0
  97. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_file_hash_sha_224.txt +0 -0
  98. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_file_hash_sha_256.txt +0 -0
  99. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_file_hash_sha_384.txt +0 -0
  100. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_file_hash_sha_512.txt +0 -0
  101. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_file_name.txt +0 -0
  102. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_host_name.txt +0 -0
  103. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_host_name_file.txt +0 -0
  104. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_host_name_path.txt +0 -0
  105. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_host_name_subdomain.txt +0 -0
  106. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_host_name_url.txt +0 -0
  107. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_iban_number.txt +0 -0
  108. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_ipv4_address_cidr.txt +0 -0
  109. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_ipv4_address_only.txt +0 -0
  110. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_ipv4_address_port.txt +0 -0
  111. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_ipv6_address_cidr.txt +0 -0
  112. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_ipv6_address_only.txt +0 -0
  113. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_ipv6_address_port.txt +0 -0
  114. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mac_address.txt +0 -0
  115. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_atlas.txt +0 -0
  116. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_atlas_name.txt +0 -0
  117. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_attack_enterprise.txt +0 -0
  118. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_attack_enterprise_aliases.txt +0 -0
  119. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_attack_enterprise_name.txt +0 -0
  120. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_attack_ics.txt +0 -0
  121. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_attack_ics_aliases.txt +0 -0
  122. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_attack_ics_name.txt +0 -0
  123. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_attack_mobile.txt +0 -0
  124. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_attack_mobile_aliases.txt +0 -0
  125. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_attack_mobile_name.txt +0 -0
  126. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_capec.txt +0 -0
  127. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_capec_name.txt +0 -0
  128. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_cwe.txt +0 -0
  129. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_mitre_cwe_name.txt +0 -0
  130. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_phone_number.txt +0 -0
  131. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_url.txt +0 -0
  132. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_url_file.txt +0 -0
  133. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_url_path.txt +0 -0
  134. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_user_agent.txt +0 -0
  135. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/generic_windows_registry_key.txt +0 -0
  136. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/lookup_attack_pattern.txt +0 -0
  137. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/lookup_campaign.txt +0 -0
  138. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/lookup_course_of_action.txt +0 -0
  139. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/lookup_identity.txt +0 -0
  140. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/lookup_infrastructure.txt +0 -0
  141. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/lookup_intrusion_set.txt +0 -0
  142. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/lookup_malware.txt +0 -0
  143. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/lookup_threat_actor.txt +0 -0
  144. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/extraction_types/lookup_tool.txt +0 -0
  145. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/attack_navigator_demo.txt +0 -0
  146. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/basic_relationship.txt +0 -0
  147. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/char_length_too_long.txt +0 -0
  148. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/descriptive_for_ai_relationships_1.txt +0 -0
  149. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/disarm_demo.txt +0 -0
  150. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/embedded_img_ignore.txt +0 -0
  151. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/embedded_link_ignore.txt +0 -0
  152. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/ip1.txt +0 -0
  153. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/ip2.txt +0 -0
  154. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/known_whitelist_match.txt +0 -0
  155. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/mitre_attack_enterprise_ai_demo.txt +0 -0
  156. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/mitre_attack_enterprise_lookup_demo.txt +0 -0
  157. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/mixed_extractions.txt +0 -0
  158. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/not_security_content.txt +0 -0
  159. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/test_ai_hash_error_with_stix2_lib.txt +0 -0
  160. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/test_aliases.txt +0 -0
  161. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/test_extraction_boundary.txt +0 -0
  162. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/manually_generated_reports/test_extraction_escapes.txt +0 -0
  163. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/real_intel_reports/APT28-Center-of-Storm-2017.txt +0 -0
  164. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/real_intel_reports/Bitdefender-Labs-Report-X-creat6958-en-EN.txt +0 -0
  165. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/real_intel_reports/FireEyeAPT39.txt +0 -0
  166. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/real_intel_reports/France_CERT_APT31_Pakdoor_TLPWHITE.txt +0 -0
  167. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/real_intel_reports/Group-IB_Ransomware_Uncovered_whitepaper_eng.txt +0 -0
  168. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/real_intel_reports/JOINT_CSA_HUNTING_RU_INTEL_SNAKE_MALWARE_20230509.txt +0 -0
  169. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/real_intel_reports/TA22-0126-QAKBOT-analysis-TLP-GREEN.txt +0 -0
  170. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/real_intel_reports/dinners_card.txt +0 -0
  171. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/real_intel_reports/mandiant-apt1.txt +0 -0
  172. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/data/real_intel_reports/mykings_report_final.txt +0 -0
  173. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/manual-tests/cases-ai-relationships.md +0 -0
  174. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/manual-tests/cases-extraction-type-ai.md +0 -0
  175. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/manual-tests/cases-extraction-type-lookup.md +0 -0
  176. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/manual-tests/cases-extraction-type-pattern.md +0 -0
  177. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/scripts/generate_simple_extraction_test_cases_txt_files.py +0 -0
  178. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/__init__.py +0 -0
  179. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/test_bundler.py +0 -0
  180. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/test_extractors.py +0 -0
  181. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/test_indicator.py +0 -0
  182. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/test_lookups.py +0 -0
  183. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/test_main.py +0 -0
  184. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/test_retriever.py +0 -0
  185. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/test_run_txt2stix.py +0 -0
  186. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/test_utils.py +0 -0
  187. {txt2stix-1.0.8 → txt2stix-1.0.10}/tests/src/utils.py +0 -0
  188. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/__init__.py +0 -0
  189. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/ai_extractor/__init__.py +0 -0
  190. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/ai_extractor/anthropic.py +0 -0
  191. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/ai_extractor/base.py +0 -0
  192. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/ai_extractor/deepseek.py +0 -0
  193. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/ai_extractor/gemini.py +0 -0
  194. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/ai_extractor/openrouter.py +0 -0
  195. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/ai_extractor/prompts.py +0 -0
  196. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/ai_extractor/utils.py +0 -0
  197. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/bundler.py +0 -0
  198. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/common.py +0 -0
  199. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/credential_checker.py +0 -0
  200. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/extractions.py +0 -0
  201. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/indicator.py +0 -0
  202. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/lookups.py +0 -0
  203. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/__init__.py +0 -0
  204. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/__init__.py +0 -0
  205. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/base_extractor.py +0 -0
  206. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/card/README.md +0 -0
  207. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/card/__init__.py +0 -0
  208. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/card/amex_card_extractor.py +0 -0
  209. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/card/diners_card_extractor.py +0 -0
  210. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/card/discover_card_extractor.py +0 -0
  211. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/card/jcb_card_extractor.py +0 -0
  212. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/card/master_card_extractor.py +0 -0
  213. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/card/union_card_extractor.py +0 -0
  214. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/card/visa_card_extractor.py +0 -0
  215. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/crypto/__init__.py +0 -0
  216. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/crypto/btc_extractor.py +0 -0
  217. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/directory/__init__.py +0 -0
  218. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/directory/unix_directory_extractor.py +0 -0
  219. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/directory/unix_file_path_extractor.py +0 -0
  220. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/directory/windows_directory_path_extractor.py +0 -0
  221. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/directory/windows_file_path_extractor.py +0 -0
  222. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/domain/__init__.py +0 -0
  223. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/domain/domain_extractor.py +0 -0
  224. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/domain/hostname_extractor.py +0 -0
  225. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/domain/sub_domain_extractor.py +0 -0
  226. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/hashes/__init__.py +0 -0
  227. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/hashes/md5_extractor.py +0 -0
  228. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/hashes/sha1_extractor.py +0 -0
  229. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/hashes/sha224_extractor.py +0 -0
  230. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/hashes/sha2_256_exactor.py +0 -0
  231. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/hashes/sha2_512_exactor.py +0 -0
  232. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/hashes/sha3_256_exactor.py +0 -0
  233. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/hashes/sha3_512_exactor.py +0 -0
  234. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/helper.py +0 -0
  235. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/ip/__init__.py +0 -0
  236. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/ip/ipv4_cidr_extractor.py +0 -0
  237. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/ip/ipv4_extractor.py +0 -0
  238. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/ip/ipv4_port_extractor.py +0 -0
  239. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/ip/ipv6_cidr_extractor.py +0 -0
  240. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/ip/ipv6_extractor.py +0 -0
  241. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/ip/ipv6_port_extractor.py +0 -0
  242. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/__init__.py +0 -0
  243. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/asn_extractor.py +0 -0
  244. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/cpe_extractor.py +0 -0
  245. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/cve_extractor.py +0 -0
  246. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/email_extractor.py +0 -0
  247. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/filename_extractor.py +0 -0
  248. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/iban_extractor.py +0 -0
  249. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/mac_address_extractor.py +0 -0
  250. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/phonenumber_extractor.py +0 -0
  251. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/user_agent_extractor.py +0 -0
  252. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/others/windows_registry_key_extractor.py +0 -0
  253. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/url/__init__.py +0 -0
  254. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/url/url_extractor.py +0 -0
  255. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/url/url_file_extractor.py +0 -0
  256. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/pattern/extractors/url/url_path_extractor.py +0 -0
  257. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/retriever.py +0 -0
  258. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/stix.py +0 -0
  259. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/txt2stix.py +0 -0
  260. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix/utils.py +0 -0
  261. {txt2stix-1.0.8 → txt2stix-1.0.10}/txt2stix.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: txt2stix
3
- Version: 1.0.8
3
+ Version: 1.0.10
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.8"
7
+ version = "1.0.10"
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."
@@ -0,0 +1,233 @@
1
+ #
2
+ # This file is autogenerated by pip-compile with Python 3.13
3
+ # by the following command:
4
+ #
5
+ # pip-compile --output-file=requirements.txt pyproject.toml
6
+ #
7
+ aiohappyeyeballs==2.6.1
8
+ # via aiohttp
9
+ aiohttp==3.12.15
10
+ # via llama-index-core
11
+ aiosignal==1.4.0
12
+ # via aiohttp
13
+ aiosqlite==0.21.0
14
+ # via llama-index-core
15
+ annotated-types==0.7.0
16
+ # via pydantic
17
+ antlr4-python3-runtime==4.9.3
18
+ # via stix2-patterns
19
+ anyio==4.10.0
20
+ # via
21
+ # httpx
22
+ # openai
23
+ attrs==25.3.0
24
+ # via aiohttp
25
+ banks==2.2.0
26
+ # via llama-index-core
27
+ base58==2.1.1
28
+ # via txt2stix (pyproject.toml)
29
+ beautifulsoup4==4.13.5
30
+ # via txt2stix (pyproject.toml)
31
+ certifi==2025.8.3
32
+ # via
33
+ # httpcore
34
+ # httpx
35
+ # requests
36
+ charset-normalizer==3.4.3
37
+ # via requests
38
+ click==8.2.1
39
+ # via nltk
40
+ colorama==0.4.6
41
+ # via griffe
42
+ dataclasses-json==0.6.7
43
+ # via llama-index-core
44
+ deprecated==1.2.18
45
+ # via
46
+ # banks
47
+ # llama-index-core
48
+ # llama-index-instrumentation
49
+ dirtyjson==1.0.8
50
+ # via llama-index-core
51
+ distro==1.9.0
52
+ # via openai
53
+ filelock==3.19.1
54
+ # via tldextract
55
+ filetype==1.2.0
56
+ # via llama-index-core
57
+ frozenlist==1.7.0
58
+ # via
59
+ # aiohttp
60
+ # aiosignal
61
+ fsspec==2025.7.0
62
+ # via llama-index-core
63
+ greenlet==3.2.4
64
+ # via sqlalchemy
65
+ griffe==1.13.0
66
+ # via banks
67
+ h11==0.16.0
68
+ # via httpcore
69
+ httpcore==1.0.9
70
+ # via httpx
71
+ httpx==0.28.1
72
+ # via
73
+ # llama-index-core
74
+ # openai
75
+ idna==3.10
76
+ # via
77
+ # anyio
78
+ # httpx
79
+ # requests
80
+ # tldextract
81
+ # yarl
82
+ jinja2==3.1.6
83
+ # via banks
84
+ jiter==0.10.0
85
+ # via openai
86
+ joblib==1.5.1
87
+ # via nltk
88
+ llama-index-core==0.13.3
89
+ # via
90
+ # llama-index-llms-openai
91
+ # txt2stix (pyproject.toml)
92
+ llama-index-instrumentation==0.4.0
93
+ # via llama-index-workflows
94
+ llama-index-llms-openai==0.5.4
95
+ # via txt2stix (pyproject.toml)
96
+ llama-index-workflows==1.3.0
97
+ # via llama-index-core
98
+ markupsafe==3.0.2
99
+ # via jinja2
100
+ marshmallow==3.26.1
101
+ # via dataclasses-json
102
+ mistune==3.1.3
103
+ # via txt2stix (pyproject.toml)
104
+ multidict==6.6.4
105
+ # via
106
+ # aiohttp
107
+ # yarl
108
+ mypy-extensions==1.1.0
109
+ # via typing-inspect
110
+ nest-asyncio==1.6.0
111
+ # via llama-index-core
112
+ networkx==3.5
113
+ # via llama-index-core
114
+ nltk==3.9.1
115
+ # via llama-index-core
116
+ numpy==2.3.2
117
+ # via llama-index-core
118
+ openai==1.101.0
119
+ # via llama-index-llms-openai
120
+ packaging==25.0
121
+ # via marshmallow
122
+ pathvalidate==3.3.1
123
+ # via txt2stix (pyproject.toml)
124
+ phonenumbers==9.0.12
125
+ # via txt2stix (pyproject.toml)
126
+ pillow==11.3.0
127
+ # via llama-index-core
128
+ platformdirs==4.3.8
129
+ # via
130
+ # banks
131
+ # llama-index-core
132
+ propcache==0.3.2
133
+ # via
134
+ # aiohttp
135
+ # yarl
136
+ pycountry==24.6.1
137
+ # via schwifty
138
+ pydantic==2.11.7
139
+ # via
140
+ # banks
141
+ # llama-index-core
142
+ # llama-index-instrumentation
143
+ # llama-index-workflows
144
+ # openai
145
+ pydantic-core==2.33.2
146
+ # via pydantic
147
+ python-dotenv==1.1.1
148
+ # via txt2stix (pyproject.toml)
149
+ pytz==2025.2
150
+ # via stix2
151
+ pyyaml==6.0.2
152
+ # via llama-index-core
153
+ regex==2025.7.34
154
+ # via
155
+ # nltk
156
+ # tiktoken
157
+ requests==2.32.5
158
+ # via
159
+ # llama-index-core
160
+ # requests-file
161
+ # stix2
162
+ # stix2extensions
163
+ # tiktoken
164
+ # tldextract
165
+ # txt2stix (pyproject.toml)
166
+ requests-file==2.1.0
167
+ # via tldextract
168
+ rstr==3.2.2
169
+ # via schwifty
170
+ schwifty==2025.7.0
171
+ # via txt2stix (pyproject.toml)
172
+ simplejson==3.20.1
173
+ # via stix2
174
+ six==1.17.0
175
+ # via stix2-patterns
176
+ sniffio==1.3.1
177
+ # via
178
+ # anyio
179
+ # openai
180
+ soupsieve==2.7
181
+ # via beautifulsoup4
182
+ sqlalchemy[asyncio]==2.0.43
183
+ # via llama-index-core
184
+ stix2==3.0.1
185
+ # via stix2extensions
186
+ stix2-patterns==2.0.0
187
+ # via stix2
188
+ stix2extensions==1.1.1
189
+ # via txt2stix (pyproject.toml)
190
+ tenacity==9.1.2
191
+ # via llama-index-core
192
+ tiktoken==0.11.0
193
+ # via llama-index-core
194
+ tld==0.13.1
195
+ # via txt2stix (pyproject.toml)
196
+ tldextract==5.3.0
197
+ # via txt2stix (pyproject.toml)
198
+ tqdm==4.67.1
199
+ # via
200
+ # llama-index-core
201
+ # nltk
202
+ # openai
203
+ typing-extensions==4.15.0
204
+ # via
205
+ # aiosqlite
206
+ # beautifulsoup4
207
+ # llama-index-core
208
+ # llama-index-workflows
209
+ # openai
210
+ # pydantic
211
+ # pydantic-core
212
+ # sqlalchemy
213
+ # typing-inspect
214
+ # typing-inspection
215
+ typing-inspect==0.9.0
216
+ # via
217
+ # dataclasses-json
218
+ # llama-index-core
219
+ typing-inspection==0.4.1
220
+ # via pydantic
221
+ urllib3==2.5.0
222
+ # via requests
223
+ validators==0.35.0
224
+ # via txt2stix (pyproject.toml)
225
+ wrapt==1.17.3
226
+ # via
227
+ # deprecated
228
+ # llama-index-core
229
+ yarl==1.20.1
230
+ # via aiohttp
231
+
232
+ # The following packages are considered to be unsafe in a requirements file:
233
+ # setuptools
@@ -4,4 +4,6 @@ Due to password protection, the zip files are able to bypass some AV detections.
4
4
 
5
5
  The zip files are extracted and usually contain a malicious document, such as a .doc, .pdf, or .xls. Some examples are malware.pdf and bad.com
6
6
 
7
- The extracted files contain malicious macros that connect to a C2 server 1.1.1.1
7
+ The extracted files contain malicious macros that connect to a C2 server 1.1.1.1
8
+
9
+ And here is a mobile ID to test behaviour of multiple matrices T1630.001
@@ -486,6 +486,24 @@ python3 txt2stix.py \
486
486
  --report_id 3b160a8d-12dd-4e7c-aee8-5af6e371b425
487
487
  ```
488
488
 
489
+ with two domains
490
+
491
+ no indicators
492
+
493
+ ```shell
494
+ python3 txt2stix.py \
495
+ --relationship_mode ai \
496
+ --ai_settings_relationships openai:gpt-5 \
497
+ --input_file tests/data/manually_generated_reports/attack_flow_demo.txt \
498
+ --name 'Test MITRE ATT&CK Flow demo' \
499
+ --tlp_level clear \
500
+ --confidence 100 \
501
+ --use_extractions 'ai_mitre_attack_*' \
502
+ --ai_settings_extractions openai:gpt-5 \
503
+ --ai_create_attack_flow \
504
+ --report_id ccc8c844-6a89-4762-b4e7-77c918fa4b8f
505
+ ```
506
+
489
507
  ### attack navigator demo
490
508
 
491
509
  ```shell
@@ -8,6 +8,7 @@ from txt2stix.attack_flow import (
8
8
  create_navigator_layer,
9
9
  get_all_tactics,
10
10
  get_techniques_from_extracted_objects,
11
+ parse_domain_flow,
11
12
  parse_flow,
12
13
  extract_attack_flow_and_navigator,
13
14
  )
@@ -21,31 +22,30 @@ def test_parse_flow(dummy_report, dummy_objects, dummy_flow):
21
22
  techniques = get_techniques_from_extracted_objects(dummy_objects, tactics)
22
23
  flow = dummy_flow
23
24
  report = dummy_report
24
- expected_ids = set(
25
- [
26
- "report--9c88fbcb-8c0d-4124-868b-3dcb1e9b696c",
27
- "extension-definition--fb9c968a-745b-4ade-9b25-c324172197f4",
28
- "attack-flow--9c88fbcb-8c0d-4124-868b-3dcb1e9b696c",
29
- "relationship--6346ead9-49cc-5ede-89e2-449f1c22ed13",
30
- "x-mitre-tactic--696af733-728e-49d7-8261-75fdc590f453",
31
- "attack-pattern--0fe075d5-beac-4d02-b93e-0f874997db72",
32
- "attack-action--51dc1572-cb10-581b-b9ef-9e589615ecaa",
33
- "x-mitre-tactic--5bc1d813-693e-4823-9961-abf9af4b0e92",
34
- "attack-pattern--f9e9365a-9ca2-4d9c-8e7c-050d73d1101a",
35
- "attack-action--e03c89ba-a476-5509-ac0a-049b61514be7",
36
- "x-mitre-tactic--298fe907-7931-4fd2-8131-2814dd493134",
37
- "attack-pattern--1b22b676-9347-4c55-9a35-ef0dc653db5b",
38
- "attack-action--1fd63972-ef98-5da5-81f5-4090c7dfa585",
39
- "x-mitre-tactic--2558fd61-8c75-4730-94c4-11926db2a263",
40
- "attack-pattern--1a80d097-54df-41d8-9d33-34e755ec5e72",
41
- "attack-action--c7e06b10-252d-520d-82eb-e32314bbec34",
42
- ]
43
- )
25
+ expected_ids = {
26
+ "attack-pattern--1b22b676-9347-4c55-9a35-ef0dc653db5b",
27
+ "x-mitre-tactic--298fe907-7931-4fd2-8131-2814dd493134",
28
+ "attack-action--1fd63972-ef98-5da5-81f5-4090c7dfa585",
29
+ "extension-definition--fb9c968a-745b-4ade-9b25-c324172197f4",
30
+ "attack-pattern--1a80d097-54df-41d8-9d33-34e755ec5e72",
31
+ "report--9c88fbcb-8c0d-4124-868b-3dcb1e9b696c",
32
+ "attack-flow--bb21585c-5f82-55cf-b73d-89b5217ef092",
33
+ "relationship--22e97298-819a-55ac-b57b-2185ffb72c62",
34
+ "x-mitre-tactic--2558fd61-8c75-4730-94c4-11926db2a263",
35
+ "attack-action--c7e06b10-252d-520d-82eb-e32314bbec34",
36
+ "x-mitre-tactic--696af733-728e-49d7-8261-75fdc590f453",
37
+ "x-mitre-tactic--5bc1d813-693e-4823-9961-abf9af4b0e92",
38
+ "attack-pattern--f9e9365a-9ca2-4d9c-8e7c-050d73d1101a",
39
+ "attack-action--51dc1572-cb10-581b-b9ef-9e589615ecaa",
40
+ "relationship--931f6b0d-5136-534a-93bc-8cce065e04dc",
41
+ "attack-pattern--0fe075d5-beac-4d02-b93e-0f874997db72",
42
+ "attack-flow--b48ec5d9-407c-5e4a-a6d0-fe851cd4ea0e",
43
+ "attack-action--e03c89ba-a476-5509-ac0a-049b61514be7",
44
+ }
44
45
 
45
46
  flow_objects = parse_flow(report, flow, techniques, tactics)
46
47
  assert {obj["id"] for obj in flow_objects} == expected_ids
47
48
 
48
-
49
49
  def test_parse_flow__no_success(dummy_report):
50
50
  flow_objects = parse_flow(
51
51
  dummy_report,
@@ -61,6 +61,48 @@ def test_parse_flow__no_success(dummy_report):
61
61
  assert len(flow_objects) == 0
62
62
 
63
63
 
64
+ @pytest.mark.parametrize(
65
+ ["domain", "expected_ids"],
66
+ [
67
+ ("mobile-attack", set()),
68
+ [
69
+ "ics-attack",
70
+ {
71
+ "x-mitre-tactic--298fe907-7931-4fd2-8131-2814dd493134",
72
+ "x-mitre-tactic--696af733-728e-49d7-8261-75fdc590f453",
73
+ "attack-pattern--1b22b676-9347-4c55-9a35-ef0dc653db5b",
74
+ "relationship--22e97298-819a-55ac-b57b-2185ffb72c62",
75
+ "attack-action--1fd63972-ef98-5da5-81f5-4090c7dfa585",
76
+ "attack-pattern--0fe075d5-beac-4d02-b93e-0f874997db72",
77
+ "attack-flow--bb21585c-5f82-55cf-b73d-89b5217ef092",
78
+ "attack-action--51dc1572-cb10-581b-b9ef-9e589615ecaa",
79
+ },
80
+ ],
81
+ [
82
+ "enterprise-attack",
83
+ {
84
+ "attack-action--e03c89ba-a476-5509-ac0a-049b61514be7",
85
+ "relationship--931f6b0d-5136-534a-93bc-8cce065e04dc",
86
+ "attack-flow--b48ec5d9-407c-5e4a-a6d0-fe851cd4ea0e",
87
+ "attack-pattern--f9e9365a-9ca2-4d9c-8e7c-050d73d1101a",
88
+ "x-mitre-tactic--2558fd61-8c75-4730-94c4-11926db2a263",
89
+ "attack-pattern--1a80d097-54df-41d8-9d33-34e755ec5e72",
90
+ "x-mitre-tactic--5bc1d813-693e-4823-9961-abf9af4b0e92",
91
+ "attack-action--c7e06b10-252d-520d-82eb-e32314bbec34",
92
+ },
93
+ ],
94
+ ],
95
+ )
96
+ def test_parse_domain_flow(dummy_report, dummy_objects, dummy_flow, domain, expected_ids):
97
+ tactics = get_all_tactics()
98
+ techniques = get_techniques_from_extracted_objects(dummy_objects, tactics)
99
+ flow = dummy_flow
100
+ report = dummy_report
101
+ flow_objects = parse_domain_flow(report, flow, techniques, tactics, domain)
102
+ print([domain, {obj["id"] for obj in flow_objects}], ",")
103
+ assert {obj["id"] for obj in flow_objects} == expected_ids
104
+
105
+
64
106
  def test_get_techniques_from_extracted_objects(dummy_objects):
65
107
  tactics = get_all_tactics()
66
108
  techniques = get_techniques_from_extracted_objects(dummy_objects, tactics)
@@ -142,7 +184,11 @@ def test_extract_attack_flow_and_navigator(dummy_objects, dummy_report):
142
184
  mock_extract_flow.assert_called_once_with(text, techniques)
143
185
 
144
186
  mock_create_navigator_layer.assert_called_once_with(
145
- bundler.report, bundler.summary, mock_extract_flow.return_value, techniques, tactics
187
+ bundler.report,
188
+ bundler.summary,
189
+ mock_extract_flow.return_value,
190
+ techniques,
191
+ tactics,
146
192
  )
147
193
 
148
194
  ### reset mocks
@@ -181,7 +227,11 @@ def test_extract_attack_flow_and_navigator(dummy_objects, dummy_report):
181
227
  mock_parse_flow.assert_not_called()
182
228
 
183
229
  mock_create_navigator_layer.assert_called_once_with(
184
- bundler.report, bundler.summary, mock_extract_flow.return_value, techniques, tactics
230
+ bundler.report,
231
+ bundler.summary,
232
+ mock_extract_flow.return_value,
233
+ techniques,
234
+ tactics,
185
235
  )
186
236
 
187
237
  ### reset mocks
@@ -281,7 +331,7 @@ def test_create_navigator_layer(dummy_report):
281
331
  {
282
332
  "versions": {
283
333
  "layer": "4.5",
284
- "attack": '16.1',
334
+ "attack": "16.1",
285
335
  "navigator": "5.1.0",
286
336
  },
287
337
  "name": "some markdown document",
@@ -311,7 +361,7 @@ def test_create_navigator_layer(dummy_report):
311
361
  {
312
362
  "versions": {
313
363
  "layer": "4.5",
314
- "attack": '17.0',
364
+ "attack": "17.0",
315
365
  "navigator": "5.1.0",
316
366
  },
317
367
  "name": "some markdown document",
@@ -341,7 +391,7 @@ def test_create_navigator_layer(dummy_report):
341
391
  {
342
392
  "versions": {
343
393
  "layer": "4.5",
344
- "attack": '13.1',
394
+ "attack": "13.1",
345
395
  "navigator": "5.1.0",
346
396
  },
347
397
  "name": "some markdown document",
@@ -1,4 +1,5 @@
1
1
 
2
+ import logging
2
3
  import os
3
4
  from txt2stix.ai_extractor.base import BaseAIExtractor
4
5
  from llama_index.llms.openai import OpenAI
@@ -11,5 +12,9 @@ class OpenAIExtractor(BaseAIExtractor, provider="openai"):
11
12
  super().__init__()
12
13
 
13
14
  def count_tokens(self, text):
14
- return len(self.llm._tokenizer.encode(text))
15
+ try:
16
+ return len(self.llm._tokenizer.encode(text))
17
+ except Exception as e:
18
+ logging.warning(e)
19
+ return super().count_tokens(text)
15
20
 
@@ -16,15 +16,26 @@ def parse_flow(report, flow: AttackFlowList, techniques, tactics):
16
16
  logging.info(f"flow.success = {flow.success}")
17
17
  if not flow.success:
18
18
  return []
19
- flow_objects = [report, attack_flow_ExtensionDefinitionSMO]
19
+ objects = [report, attack_flow_ExtensionDefinitionSMO]
20
+ for domain in ["enterprise-attack", "mobile-attack", "ics-attack"]:
21
+ flow_objects = parse_domain_flow(report, flow, techniques, tactics, domain)
22
+ objects.extend(flow_objects)
23
+ return objects
24
+
25
+ def parse_domain_flow(report, flow: AttackFlowList, techniques, tactics, domain):
26
+ flow_objects = []
27
+ flow_obj = None
20
28
  last_action = None
21
29
  for i, item in enumerate(flow.items):
22
30
  try:
23
31
  technique = techniques[item.attack_technique_id]
32
+ if technique["domain"] != domain:
33
+ continue
24
34
  tactic_id = technique["possible_tactics"][
25
35
  flow.tactic_mapping[item.attack_technique_id]
26
36
  ]
27
37
  technique_obj = technique["stix_obj"]
38
+
28
39
  tactic_obj = tactics[technique["domain"]][tactic_id]
29
40
  action_obj = AttackAction(
30
41
  **{
@@ -40,16 +51,16 @@ def parse_flow(report, flow: AttackFlowList, techniques, tactics):
40
51
  allow_custom=True,
41
52
  )
42
53
  action_obj.effect_refs.clear()
43
- if i == 0:
54
+ if not flow_obj:
44
55
  flow_obj = {
45
56
  "type": "attack-flow",
46
- "id": report.id.replace("report", "attack-flow"),
57
+ "id": "attack-flow--"+str(uuid.uuid5(UUID_NAMESPACE, f"attack-flow+{domain}+{report.id}")),
47
58
  "spec_version": "2.1",
48
59
  "created": report.created,
49
60
  "modified": report.modified,
50
61
  "created_by_ref": report.created_by_ref,
51
62
  "start_refs": [action_obj["id"]],
52
- "name": report.name,
63
+ "name": f"[{domain.split('-')[0].upper()}] {report.name}",
53
64
  "description": report.description,
54
65
  "scope": "malware",
55
66
  "external_references": report.external_references,
@@ -61,7 +72,7 @@ def parse_flow(report, flow: AttackFlowList, techniques, tactics):
61
72
  type="relationship",
62
73
  spec_version="2.1",
63
74
  id="relationship--"
64
- + str(uuid.uuid5(UUID_NAMESPACE, f"attack-flow+{report.id}")),
75
+ + str(uuid.uuid5(UUID_NAMESPACE, f"attack-flow+{report.id}+{flow_obj['id']}")),
65
76
  created_by_ref=report.created_by_ref,
66
77
  created=report.created,
67
78
  modified=report.modified,