howler-api 2.13.0.dev329__py3-none-any.whl

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.

Potentially problematic release.


This version of howler-api might be problematic. Click here for more details.

Files changed (200) hide show
  1. howler/__init__.py +0 -0
  2. howler/actions/__init__.py +167 -0
  3. howler/actions/add_label.py +111 -0
  4. howler/actions/add_to_bundle.py +159 -0
  5. howler/actions/change_field.py +76 -0
  6. howler/actions/demote.py +160 -0
  7. howler/actions/example_plugin.py +104 -0
  8. howler/actions/prioritization.py +93 -0
  9. howler/actions/promote.py +147 -0
  10. howler/actions/remove_from_bundle.py +133 -0
  11. howler/actions/remove_label.py +111 -0
  12. howler/actions/transition.py +200 -0
  13. howler/api/__init__.py +249 -0
  14. howler/api/base.py +88 -0
  15. howler/api/socket.py +114 -0
  16. howler/api/v1/__init__.py +97 -0
  17. howler/api/v1/action.py +372 -0
  18. howler/api/v1/analytic.py +748 -0
  19. howler/api/v1/auth.py +382 -0
  20. howler/api/v1/borealis.py +101 -0
  21. howler/api/v1/configs.py +55 -0
  22. howler/api/v1/dossier.py +222 -0
  23. howler/api/v1/help.py +28 -0
  24. howler/api/v1/hit.py +1181 -0
  25. howler/api/v1/notebook.py +82 -0
  26. howler/api/v1/overview.py +191 -0
  27. howler/api/v1/search.py +715 -0
  28. howler/api/v1/template.py +206 -0
  29. howler/api/v1/tool.py +183 -0
  30. howler/api/v1/user.py +414 -0
  31. howler/api/v1/utils/__init__.py +0 -0
  32. howler/api/v1/utils/etag.py +84 -0
  33. howler/api/v1/view.py +288 -0
  34. howler/app.py +235 -0
  35. howler/common/README.md +144 -0
  36. howler/common/__init__.py +0 -0
  37. howler/common/classification.py +979 -0
  38. howler/common/classification.yml +107 -0
  39. howler/common/exceptions.py +167 -0
  40. howler/common/hexdump.py +48 -0
  41. howler/common/iprange.py +171 -0
  42. howler/common/loader.py +154 -0
  43. howler/common/logging/__init__.py +241 -0
  44. howler/common/logging/audit.py +138 -0
  45. howler/common/logging/format.py +38 -0
  46. howler/common/net.py +79 -0
  47. howler/common/net_static.py +1494 -0
  48. howler/common/random_user.py +316 -0
  49. howler/common/swagger.py +117 -0
  50. howler/config.py +64 -0
  51. howler/cronjobs/__init__.py +29 -0
  52. howler/cronjobs/retention.py +61 -0
  53. howler/cronjobs/rules.py +274 -0
  54. howler/cronjobs/view_cleanup.py +88 -0
  55. howler/datastore/README.md +112 -0
  56. howler/datastore/__init__.py +0 -0
  57. howler/datastore/bulk.py +72 -0
  58. howler/datastore/collection.py +2327 -0
  59. howler/datastore/constants.py +117 -0
  60. howler/datastore/exceptions.py +41 -0
  61. howler/datastore/howler_store.py +105 -0
  62. howler/datastore/migrations/fix_process.py +41 -0
  63. howler/datastore/operations.py +130 -0
  64. howler/datastore/schemas.py +90 -0
  65. howler/datastore/store.py +231 -0
  66. howler/datastore/support/__init__.py +0 -0
  67. howler/datastore/support/build.py +214 -0
  68. howler/datastore/support/schemas.py +90 -0
  69. howler/datastore/types.py +22 -0
  70. howler/error.py +91 -0
  71. howler/external/__init__.py +0 -0
  72. howler/external/generate_mitre.py +96 -0
  73. howler/external/generate_sigma_rules.py +31 -0
  74. howler/external/generate_tlds.py +47 -0
  75. howler/external/reindex_data.py +46 -0
  76. howler/external/wipe_databases.py +58 -0
  77. howler/gunicorn_config.py +25 -0
  78. howler/healthz.py +47 -0
  79. howler/helper/__init__.py +0 -0
  80. howler/helper/azure.py +50 -0
  81. howler/helper/discover.py +59 -0
  82. howler/helper/hit.py +236 -0
  83. howler/helper/oauth.py +247 -0
  84. howler/helper/search.py +92 -0
  85. howler/helper/workflow.py +110 -0
  86. howler/helper/ws.py +378 -0
  87. howler/odm/README.md +102 -0
  88. howler/odm/__init__.py +1 -0
  89. howler/odm/base.py +1504 -0
  90. howler/odm/charter.txt +146 -0
  91. howler/odm/helper.py +416 -0
  92. howler/odm/howler_enum.py +25 -0
  93. howler/odm/models/__init__.py +0 -0
  94. howler/odm/models/action.py +33 -0
  95. howler/odm/models/analytic.py +90 -0
  96. howler/odm/models/assemblyline.py +48 -0
  97. howler/odm/models/aws.py +23 -0
  98. howler/odm/models/azure.py +16 -0
  99. howler/odm/models/cbs.py +44 -0
  100. howler/odm/models/config.py +558 -0
  101. howler/odm/models/dossier.py +33 -0
  102. howler/odm/models/ecs/__init__.py +0 -0
  103. howler/odm/models/ecs/agent.py +17 -0
  104. howler/odm/models/ecs/autonomous_system.py +16 -0
  105. howler/odm/models/ecs/client.py +149 -0
  106. howler/odm/models/ecs/cloud.py +141 -0
  107. howler/odm/models/ecs/code_signature.py +27 -0
  108. howler/odm/models/ecs/container.py +32 -0
  109. howler/odm/models/ecs/dns.py +62 -0
  110. howler/odm/models/ecs/egress.py +10 -0
  111. howler/odm/models/ecs/elf.py +74 -0
  112. howler/odm/models/ecs/email.py +122 -0
  113. howler/odm/models/ecs/error.py +14 -0
  114. howler/odm/models/ecs/event.py +140 -0
  115. howler/odm/models/ecs/faas.py +24 -0
  116. howler/odm/models/ecs/file.py +84 -0
  117. howler/odm/models/ecs/geo.py +30 -0
  118. howler/odm/models/ecs/group.py +18 -0
  119. howler/odm/models/ecs/hash.py +16 -0
  120. howler/odm/models/ecs/host.py +17 -0
  121. howler/odm/models/ecs/http.py +37 -0
  122. howler/odm/models/ecs/ingress.py +12 -0
  123. howler/odm/models/ecs/interface.py +21 -0
  124. howler/odm/models/ecs/network.py +30 -0
  125. howler/odm/models/ecs/observer.py +45 -0
  126. howler/odm/models/ecs/organization.py +12 -0
  127. howler/odm/models/ecs/os.py +21 -0
  128. howler/odm/models/ecs/pe.py +17 -0
  129. howler/odm/models/ecs/process.py +216 -0
  130. howler/odm/models/ecs/registry.py +26 -0
  131. howler/odm/models/ecs/related.py +45 -0
  132. howler/odm/models/ecs/rule.py +51 -0
  133. howler/odm/models/ecs/server.py +24 -0
  134. howler/odm/models/ecs/threat.py +247 -0
  135. howler/odm/models/ecs/tls.py +58 -0
  136. howler/odm/models/ecs/url.py +51 -0
  137. howler/odm/models/ecs/user.py +57 -0
  138. howler/odm/models/ecs/user_agent.py +20 -0
  139. howler/odm/models/ecs/vulnerability.py +41 -0
  140. howler/odm/models/gcp.py +16 -0
  141. howler/odm/models/hit.py +356 -0
  142. howler/odm/models/howler_data.py +328 -0
  143. howler/odm/models/lead.py +33 -0
  144. howler/odm/models/localized_label.py +13 -0
  145. howler/odm/models/overview.py +16 -0
  146. howler/odm/models/pivot.py +40 -0
  147. howler/odm/models/template.py +24 -0
  148. howler/odm/models/user.py +83 -0
  149. howler/odm/models/view.py +34 -0
  150. howler/odm/random_data.py +888 -0
  151. howler/odm/randomizer.py +606 -0
  152. howler/patched.py +5 -0
  153. howler/plugins/__init__.py +25 -0
  154. howler/plugins/config.py +123 -0
  155. howler/remote/__init__.py +0 -0
  156. howler/remote/datatypes/README.md +355 -0
  157. howler/remote/datatypes/__init__.py +98 -0
  158. howler/remote/datatypes/counters.py +63 -0
  159. howler/remote/datatypes/events.py +66 -0
  160. howler/remote/datatypes/hash.py +206 -0
  161. howler/remote/datatypes/lock.py +42 -0
  162. howler/remote/datatypes/queues/__init__.py +0 -0
  163. howler/remote/datatypes/queues/comms.py +59 -0
  164. howler/remote/datatypes/queues/multi.py +32 -0
  165. howler/remote/datatypes/queues/named.py +93 -0
  166. howler/remote/datatypes/queues/priority.py +215 -0
  167. howler/remote/datatypes/set.py +118 -0
  168. howler/remote/datatypes/user_quota_tracker.py +54 -0
  169. howler/security/__init__.py +253 -0
  170. howler/security/socket.py +108 -0
  171. howler/security/utils.py +185 -0
  172. howler/services/__init__.py +0 -0
  173. howler/services/action_service.py +111 -0
  174. howler/services/analytic_service.py +128 -0
  175. howler/services/auth_service.py +323 -0
  176. howler/services/config_service.py +128 -0
  177. howler/services/dossier_service.py +252 -0
  178. howler/services/event_service.py +93 -0
  179. howler/services/hit_service.py +893 -0
  180. howler/services/jwt_service.py +158 -0
  181. howler/services/lucene_service.py +286 -0
  182. howler/services/notebook_service.py +119 -0
  183. howler/services/overview_service.py +44 -0
  184. howler/services/template_service.py +45 -0
  185. howler/services/user_service.py +330 -0
  186. howler/utils/__init__.py +0 -0
  187. howler/utils/annotations.py +28 -0
  188. howler/utils/chunk.py +38 -0
  189. howler/utils/dict_utils.py +200 -0
  190. howler/utils/isotime.py +17 -0
  191. howler/utils/list_utils.py +11 -0
  192. howler/utils/lucene.py +77 -0
  193. howler/utils/path.py +27 -0
  194. howler/utils/socket_utils.py +61 -0
  195. howler/utils/str_utils.py +256 -0
  196. howler/utils/uid.py +47 -0
  197. howler_api-2.13.0.dev329.dist-info/METADATA +71 -0
  198. howler_api-2.13.0.dev329.dist-info/RECORD +200 -0
  199. howler_api-2.13.0.dev329.dist-info/WHEEL +4 -0
  200. howler_api-2.13.0.dev329.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,216 @@
1
+ from typing import Optional
2
+
3
+ from howler import odm
4
+ from howler.odm.models.ecs.code_signature import CodeSignature
5
+ from howler.odm.models.ecs.hash import Hashes
6
+ from howler.odm.models.ecs.pe import PE
7
+ from howler.odm.models.ecs.user import ShortUser
8
+
9
+
10
+ @odm.model(index=True, store=True, description="Information about the char device.")
11
+ class CharDevice(odm.Model):
12
+ major = odm.Optional(odm.Integer(description="The major number identifies the driver associated with the device."))
13
+ minor = odm.Optional(
14
+ odm.Integer(
15
+ description="The minor number is used only by the driver specified by the major number; other parts of "
16
+ "the kernel don't use it, and merely pass it along to the driver."
17
+ )
18
+ )
19
+
20
+
21
+ @odm.model(index=True, store=True, description="Information about the controlling TTY device.")
22
+ class TTY(odm.Model):
23
+ char_device = odm.Optional(odm.Compound(CharDevice, description="Information about the char device."))
24
+
25
+
26
+ @odm.model(index=True, store=True, description="Thread Information.")
27
+ class Thread(odm.Model):
28
+ id: Optional[int] = odm.Optional(odm.Integer(description="Thread ID."))
29
+ name: Optional[str] = odm.Optional(odm.Keyword(description="Thread name."))
30
+
31
+
32
+ @odm.model(index=True, store=True, description="Entry Meta-Information.")
33
+ class EntryMeta(odm.Model):
34
+ type: Optional[str] = odm.Keyword(description="SESSIONNAME from Process Environment Variable", optional=True)
35
+
36
+
37
+ @odm.model(
38
+ index=True,
39
+ store=True,
40
+ description="These fields contain information about a process.",
41
+ )
42
+ class ParentParentProcess(odm.Model):
43
+ args = odm.Optional(
44
+ odm.List(
45
+ odm.Keyword(),
46
+ description="Array of process arguments, starting with the absolute path to the executable.",
47
+ )
48
+ )
49
+ args_count = odm.Optional(odm.Integer(description="Length of the process.args array."))
50
+ code_signature = odm.Optional(
51
+ odm.Compound(CodeSignature),
52
+ description="Information about binary code signatures.",
53
+ )
54
+ command_line = odm.Optional(
55
+ odm.Keyword(
56
+ description="Full command line that started the process, including the absolute path to the "
57
+ "executable, and all arguments."
58
+ )
59
+ )
60
+ end = odm.Optional(odm.Date(description="The time the process ended."))
61
+ entity_id = odm.Optional(odm.Keyword(description="OID Hash of the process."))
62
+ entry_meta: Optional[EntryMeta] = odm.Optional(
63
+ odm.Compound(EntryMeta),
64
+ description="Process Meta Information.",
65
+ )
66
+ env_vars = odm.Optional(
67
+ odm.Mapping(
68
+ odm.Keyword(),
69
+ description="Environment variables (env_vars) set at the time of the event. May be filtered to "
70
+ "protect sensitive information.",
71
+ )
72
+ )
73
+ executable = odm.Optional(odm.Keyword(description="Absolute path to the process executable."))
74
+ exit_code = odm.Optional(odm.Integer(description="The exit code of the process, if this is a termination event."))
75
+ hash = odm.Optional(odm.Compound(Hashes), description="Hashes, usually file hashes")
76
+ interactive = odm.Optional(odm.Boolean(description="Whether the process is connected to an interactive shell."))
77
+ name = odm.Optional(odm.Keyword(description="Process name."))
78
+ pe = odm.Optional(
79
+ odm.Compound(PE),
80
+ description="Windows Portable Executable (PE) metadata.",
81
+ )
82
+ pid = odm.Optional(odm.Integer(description="Process id."))
83
+ same_as_process = odm.Optional(
84
+ odm.Boolean(
85
+ description="This boolean is used to identify if a leader process is the same as the top level process."
86
+ )
87
+ )
88
+ start = odm.Optional(odm.Date(description="The time the process started."))
89
+ title = odm.Optional(odm.Keyword(description="Process title."))
90
+ uptime = odm.Optional(odm.Integer(description="Seconds the process has been up."))
91
+ user = odm.Optional(odm.Compound(ShortUser, description="The effective user (euid)."))
92
+ working_directory = odm.Optional(odm.Keyword(description="The working directory of the process."))
93
+
94
+
95
+ @odm.model(
96
+ index=True,
97
+ store=True,
98
+ description="These fields contain information about a process.",
99
+ )
100
+ class ParentProcess(odm.Model):
101
+ args = odm.Optional(
102
+ odm.List(
103
+ odm.Keyword(),
104
+ description="Array of process arguments, starting with the absolute path to the executable.",
105
+ )
106
+ )
107
+ args_count = odm.Optional(odm.Integer(description="Length of the process.args array."))
108
+ code_signature = odm.Optional(
109
+ odm.Compound(CodeSignature),
110
+ description="Information about binary code signatures.",
111
+ )
112
+ command_line = odm.Optional(
113
+ odm.Keyword(
114
+ description="Full command line that started the process, including the absolute path to the "
115
+ "executable, and all arguments."
116
+ )
117
+ )
118
+ end = odm.Optional(odm.Date(description="The time the process ended."))
119
+ entity_id = odm.Optional(odm.Keyword(description="OID Hash of the process."))
120
+ entry_meta: Optional[EntryMeta] = odm.Optional(
121
+ odm.Compound(EntryMeta),
122
+ description="Process Meta Information.",
123
+ )
124
+ env_vars = odm.Optional(
125
+ odm.Mapping(
126
+ odm.Keyword(),
127
+ description="Environment variables (env_vars) set at the time of the event. May be filtered to "
128
+ "protect sensitive information.",
129
+ )
130
+ )
131
+ executable = odm.Optional(odm.Keyword(description="Absolute path to the process executable."))
132
+ exit_code = odm.Optional(odm.Integer(description="The exit code of the process, if this is a termination event."))
133
+ hash = odm.Optional(odm.Compound(Hashes), description="Hashes, usually file hashes")
134
+ interactive = odm.Optional(odm.Boolean(description="Whether the process is connected to an interactive shell."))
135
+ name = odm.Optional(odm.Keyword(description="Process name."))
136
+ parent = odm.Optional(
137
+ odm.Compound(ParentParentProcess),
138
+ description="Information about the parent process.",
139
+ )
140
+ pe = odm.Optional(
141
+ odm.Compound(PE),
142
+ description="Windows Portable Executable (PE) metadata.",
143
+ )
144
+ pid = odm.Optional(odm.Integer(description="Process id."))
145
+ same_as_process = odm.Optional(
146
+ odm.Boolean(
147
+ description="This boolean is used to identify if a leader process is the same as the top level process."
148
+ )
149
+ )
150
+ start = odm.Optional(odm.Date(description="The time the process started."))
151
+ title = odm.Optional(odm.Keyword(description="Process title."))
152
+ uptime = odm.Optional(odm.Integer(description="Seconds the process has been up."))
153
+ user = odm.Optional(odm.Compound(ShortUser, description="The effective user (euid)."))
154
+ working_directory = odm.Optional(odm.Keyword(description="The working directory of the process."))
155
+
156
+
157
+ @odm.model(
158
+ index=True,
159
+ store=True,
160
+ description="These fields contain information about a process.",
161
+ )
162
+ class Process(odm.Model):
163
+ args = odm.Optional(
164
+ odm.List(
165
+ odm.Keyword(),
166
+ description="Array of process arguments, starting with the absolute path to the executable.",
167
+ )
168
+ )
169
+ args_count = odm.Optional(odm.Integer(description="Length of the process.args array."))
170
+ code_signature = odm.Optional(
171
+ odm.Compound(CodeSignature),
172
+ description="Information about binary code signatures.",
173
+ )
174
+ command_line = odm.Optional(
175
+ odm.Keyword(
176
+ description="Full command line that started the process, including the absolute path to the "
177
+ "executable, and all arguments."
178
+ )
179
+ )
180
+ end = odm.Optional(odm.Date(description="The time the process ended."))
181
+ entity_id = odm.Optional(odm.Keyword(description="OID Hash of the process."))
182
+ entry_meta: Optional[EntryMeta] = odm.Optional(
183
+ odm.Compound(EntryMeta),
184
+ description="Process Meta Information.",
185
+ )
186
+ env_vars = odm.Optional(
187
+ odm.Mapping(
188
+ odm.Keyword(),
189
+ description="Environment variables (env_vars) set at the time of the event. May be filtered to "
190
+ "protect sensitive information.",
191
+ )
192
+ )
193
+ executable = odm.Optional(odm.Keyword(description="Absolute path to the process executable."))
194
+ exit_code = odm.Optional(odm.Integer(description="The exit code of the process, if this is a termination event."))
195
+ hash = odm.Optional(odm.Compound(Hashes), description="Hashes, usually file hashes")
196
+ interactive = odm.Optional(odm.Boolean(description="Whether the process is connected to an interactive shell."))
197
+ name = odm.Optional(odm.Keyword(description="Process name."))
198
+ parent = odm.Optional(
199
+ odm.Compound(ParentProcess),
200
+ description="Information about the parent process.",
201
+ )
202
+ pe = odm.Optional(
203
+ odm.Compound(PE),
204
+ description="Windows Portable Executable (PE) metadata.",
205
+ )
206
+ pid = odm.Optional(odm.Integer(description="Process id."))
207
+ same_as_process = odm.Optional(
208
+ odm.Boolean(
209
+ description="This boolean is used to identify if a leader process is the same as the top level process."
210
+ )
211
+ )
212
+ start = odm.Optional(odm.Date(description="The time the process started."))
213
+ title = odm.Optional(odm.Keyword(description="Process title."))
214
+ uptime = odm.Optional(odm.Integer(description="Seconds the process has been up."))
215
+ user = odm.Optional(odm.Compound(ShortUser, description="The effective user (euid)."))
216
+ working_directory = odm.Optional(odm.Keyword(description="The working directory of the process."))
@@ -0,0 +1,26 @@
1
+ from howler import odm
2
+
3
+
4
+ @odm.model(
5
+ index=True,
6
+ store=True,
7
+ description="Fields related to data written to Windows Registry.",
8
+ )
9
+ class RegistryData(odm.Model):
10
+ bytes = odm.Optional(odm.Keyword(description="Original bytes written with base64 encoding."))
11
+ strings = odm.Optional(odm.List(odm.Keyword(), description="Content when writing string types."))
12
+ type = odm.Optional(odm.Keyword(description="Standard registry type for encoding contents."))
13
+
14
+
15
+ @odm.model(index=True, store=True, description="Fields related to Windows Registry operations.")
16
+ class Registry(odm.Model):
17
+ data = odm.Optional(
18
+ odm.Compound(
19
+ RegistryData,
20
+ description="Fields related to data written to Windows Registry.",
21
+ )
22
+ )
23
+ hive = odm.Optional(odm.Keyword(description="Abbreviated name for the hive."))
24
+ key = odm.Optional(odm.Keyword(description="Hive-relative path of keys."))
25
+ path = odm.Optional(odm.Keyword(description="Full path, including hive, key and value."))
26
+ value = odm.Optional(odm.Keyword(description="Name of the value written."))
@@ -0,0 +1,45 @@
1
+ from howler import odm
2
+
3
+
4
+ @odm.model(
5
+ index=True,
6
+ store=True,
7
+ description="This field set is meant to facilitate pivoting around a piece of data.",
8
+ )
9
+ class Related(odm.Model):
10
+ hash: list[str] = odm.List(
11
+ odm.Keyword(),
12
+ description="All the hashes seen on your event. Populating this field, then using it to search "
13
+ "for hashes can help in situations where you're unsure what the hash algorithm is "
14
+ "(and therefore which key name to search).",
15
+ default=[],
16
+ )
17
+ hosts: list[str] = odm.List(
18
+ odm.Keyword(),
19
+ description="All hostnames or other host identifiers seen on your event. Example identifiers "
20
+ "include FQDNs, domain names, workstation names, or aliases.",
21
+ default=[],
22
+ )
23
+ ip: list[str] = odm.List(odm.IP(), description="All of the IPs seen on your event.", default=[])
24
+ user: list[str] = odm.List(
25
+ odm.Keyword(),
26
+ description="All the user names or other user identifiers seen on the event.",
27
+ default=[],
28
+ )
29
+ ids: list[str] = odm.List(
30
+ odm.Keyword(),
31
+ description="Any identifier that doesn't fit in other related fields like a GUID.",
32
+ default=[],
33
+ )
34
+
35
+ # Extra fields not defined in ECS but added for outline purposes
36
+ id = odm.Optional(odm.Keyword(description="The id related to the event."))
37
+
38
+ uri = odm.Optional(odm.List(odm.URI(), description="All of the URIs related to the event."))
39
+
40
+ signature = odm.Optional(
41
+ odm.List(
42
+ odm.Keyword(),
43
+ description="All the signatures/rules that were triggered by the event.",
44
+ )
45
+ )
@@ -0,0 +1,51 @@
1
+ from howler import odm
2
+
3
+
4
+ @odm.model(
5
+ index=True,
6
+ store=True,
7
+ description="Rule fields are used to capture the specifics of any observer or agent "
8
+ "rules that generate alerts or other notable events.",
9
+ )
10
+ class Rule(odm.Model):
11
+ author = odm.Optional(
12
+ odm.Keyword(
13
+ description="Name, organization, or pseudonym of the author or authors who "
14
+ "created the rule used to generate this event."
15
+ )
16
+ )
17
+ category = odm.Optional(
18
+ odm.Keyword(
19
+ description="A categorization value keyword used by the entity using the "
20
+ "rule for detection of this event."
21
+ )
22
+ )
23
+ description = odm.Optional(odm.Keyword(description="The description of the rule generating the event."))
24
+ id = odm.Optional(
25
+ odm.Keyword(
26
+ description="A rule ID that is unique within the scope of an agent, observer, "
27
+ "or other entity using the rule for detection of this event."
28
+ )
29
+ )
30
+ license = odm.Optional(
31
+ odm.Keyword(
32
+ description="Name of the license under which the rule used to generate this event is made available."
33
+ )
34
+ )
35
+ name = odm.Optional(odm.Keyword(description="The name of the rule or signature generating the event."))
36
+ reference = odm.Optional(
37
+ odm.Keyword(description="Reference URL to additional information about the rule used to generate this event.")
38
+ )
39
+ ruleset = odm.Optional(
40
+ odm.Keyword(
41
+ description="Name of the ruleset, policy, group, or parent category in which the "
42
+ "rule used to generate this event is a member."
43
+ )
44
+ )
45
+ uuid = odm.Optional(
46
+ odm.Keyword(
47
+ description="A rule ID that is unique within the scope of a set or group of agents, observers, "
48
+ "or other entities using the rule for detection of this event."
49
+ )
50
+ )
51
+ version = odm.Optional(odm.Keyword(description="The version / revision of the rule being used for analysis."))
@@ -0,0 +1,24 @@
1
+ from typing import Optional
2
+
3
+ from howler import odm
4
+
5
+
6
+ @odm.model(
7
+ index=True,
8
+ store=True,
9
+ description=(
10
+ "A Server is defined as the responder in a network connection for events regarding sessions, "
11
+ "connections, or bidirectional flow records."
12
+ ),
13
+ )
14
+ class Server(odm.Model):
15
+ ip: Optional[str] = odm.Optional(odm.IP(description="IP address of the server (IPv4 or IPv6)."))
16
+ address: Optional[str] = odm.Optional(
17
+ odm.Keyword(
18
+ description=(
19
+ "Some event server addresses are defined ambiguously. The event will sometimes list an IP, a "
20
+ "domain or a unix socket. You should always store the raw address in the .address field."
21
+ )
22
+ )
23
+ )
24
+ domain: Optional[str] = odm.Optional(odm.Keyword(description="The domain name of the server system."))
@@ -0,0 +1,247 @@
1
+ from typing import Optional
2
+
3
+ from howler import odm
4
+ from howler.odm.models.ecs.file import File
5
+
6
+
7
+ @odm.model(
8
+ index=True,
9
+ store=True,
10
+ description="Information about the subtechnique used by this threat.",
11
+ )
12
+ class Email(odm.Model):
13
+ address: Optional[str] = odm.Optional(
14
+ odm.Keyword(),
15
+ description="Identifies a threat indicator as an email address (irrespective of direction).",
16
+ )
17
+
18
+
19
+ @odm.model(
20
+ index=True,
21
+ store=True,
22
+ description="Information about the subtechnique used by this threat.",
23
+ )
24
+ class SubTechnique(odm.Model):
25
+ id = odm.Optional(odm.Keyword(description="The id of subtechnique used by this threat."))
26
+ name = odm.Optional(odm.Keyword(description="Name of the type of subtechnique used by this threat."))
27
+ reference = odm.Optional(odm.Keyword(description="The reference url of subtechnique used by this threat."))
28
+
29
+
30
+ @odm.model(
31
+ index=True,
32
+ store=True,
33
+ description="Information about the technique used by this threat.",
34
+ )
35
+ class Technique(odm.Model):
36
+ id = odm.Optional(odm.Keyword(description="The id of technique used by this threat."))
37
+ name = odm.Optional(odm.Keyword(description="Name of the type of technique used by this threat."))
38
+ reference = odm.Optional(odm.Keyword(description="The reference url of technique used by this threat."))
39
+ subtechnique = odm.Optional(
40
+ odm.Compound(
41
+ SubTechnique,
42
+ description="Information about the subtechnique used by this threat.",
43
+ )
44
+ )
45
+
46
+
47
+ @odm.model(
48
+ index=True,
49
+ store=True,
50
+ description="Information about the tactic used by this threat.",
51
+ )
52
+ class Tactic(odm.Model):
53
+ id = odm.Optional(odm.Keyword(description="The id of tactic used by this threat."))
54
+ name = odm.Optional(odm.Keyword(description="Name of the type of tactic used by this threat."))
55
+ reference = odm.Optional(odm.Keyword(description="The reference url of tactic used by this threat."))
56
+
57
+
58
+ @odm.model(
59
+ index=True,
60
+ store=True,
61
+ description="Information about the software used by this threat.",
62
+ )
63
+ class Software(odm.Model):
64
+ alias = odm.Optional(
65
+ odm.List(
66
+ odm.Keyword(),
67
+ description="The alias(es) of the software for a set of related intrusion activity that are "
68
+ "tracked by a common name in the security community.",
69
+ )
70
+ )
71
+ id = odm.Optional(
72
+ odm.Keyword(
73
+ description="The id of the software used by this threat to conduct behavior commonly modeled "
74
+ "using MITRE ATT&CK®."
75
+ )
76
+ )
77
+ name = odm.Optional(
78
+ odm.Keyword(
79
+ description="The name of the software used by this threat to conduct behavior commonly modeled "
80
+ "using MITRE ATT&CK®."
81
+ )
82
+ )
83
+ platform = odm.Optional(
84
+ odm.List(
85
+ odm.Keyword(),
86
+ description="The platforms of the software used by this threat to conduct behavior commonly "
87
+ "modeled using MITRE ATT&CK®.",
88
+ )
89
+ )
90
+ reference = odm.Optional(
91
+ odm.Keyword(
92
+ description="The reference URL of the software used by this threat to conduct behavior commonly "
93
+ "modeled using MITRE ATT&CK®."
94
+ )
95
+ )
96
+ type = odm.Optional(
97
+ odm.Keyword(
98
+ description="The type of software used by this threat to conduct behavior commonly modeled "
99
+ "using MITRE ATT&CK®."
100
+ )
101
+ )
102
+
103
+
104
+ @odm.model(
105
+ index=True,
106
+ store=True,
107
+ description="Information about the group related to this threat.",
108
+ )
109
+ class Group(odm.Model):
110
+ alias = odm.Optional(
111
+ odm.List(
112
+ odm.Keyword(),
113
+ description="The alias(es) of the group for a set of related intrusion activity that are tracked by "
114
+ "a common name in the security community.",
115
+ )
116
+ )
117
+ id = odm.Optional(
118
+ odm.Keyword(
119
+ description="The id of the group for a set of related intrusion activity that are tracked by a common "
120
+ "name in the security community."
121
+ )
122
+ )
123
+ name = odm.Optional(
124
+ odm.Keyword(
125
+ description="The name of the group for a set of related intrusion activity that are tracked by a common "
126
+ "name in the security community."
127
+ )
128
+ )
129
+ reference = odm.Optional(
130
+ odm.Keyword(
131
+ description="The reference URL of the group for a set of related intrusion activity that are tracked "
132
+ "by a common name in the security community."
133
+ )
134
+ )
135
+
136
+
137
+ @odm.model(index=True, store=True, description="Threat feed information.")
138
+ class Feed(odm.Model):
139
+ dashboard_id = odm.Optional(
140
+ odm.Keyword(
141
+ description="The saved object ID of the dashboard belonging to the threat feed for "
142
+ "displaying dashboard links to threat feeds in Kibana."
143
+ )
144
+ )
145
+ description = odm.Optional(odm.Keyword(description="Description of the threat feed in a UI friendly format."))
146
+ name = odm.Optional(odm.Keyword(description="The name of the threat feed in UI friendly format."))
147
+ reference = odm.Optional(
148
+ odm.Keyword(description="Reference information for the threat feed in a UI friendly format.")
149
+ )
150
+
151
+
152
+ @odm.model(
153
+ index=True,
154
+ store=True,
155
+ description="Object containing associated indicators enriching the event.",
156
+ )
157
+ class Indicator(odm.Model):
158
+ confidence = odm.Optional(
159
+ odm.Keyword(
160
+ description="Identifies the vendor-neutral confidence rating using the None/Low/Medium/High scale defined "
161
+ "in Appendix A of the STIX 2.1 framework. Vendor-specific confidence scales may be added as custom fields."
162
+ )
163
+ )
164
+ description = odm.Optional(odm.Text(description="Describes the type of action conducted by the threat."))
165
+ email: Email = odm.Optional(odm.Compound(Email))
166
+ file: File = odm.Optional(odm.Compound(File))
167
+ provider = odm.Optional(odm.Keyword(description="The name of the indicator’s provider."))
168
+ reference = odm.Optional(
169
+ odm.Keyword(description="Reference URL linking to additional information about this indicator.")
170
+ )
171
+ scanner_stats = odm.Integer(
172
+ description="Count of AV/EDR vendors that successfully detected malicious file or URL.", optional=True
173
+ )
174
+
175
+ sightings = odm.Integer(
176
+ description="Number of times this indicator was observed conducting threat activity.", optional=True
177
+ )
178
+
179
+ ip: Optional[str] = odm.Optional(
180
+ odm.IP(description="Identifies a threat indicator as an IP address (irrespective of direction).")
181
+ )
182
+ type: Optional[str] = odm.Optional(
183
+ odm.Keyword(description="Type of indicator as represented by Cyber Observable in STIX 2.0.")
184
+ )
185
+ first_seen: Optional[str] = odm.Optional(
186
+ odm.Date(description="The date and time when intelligence source first reported sighting this indicator.")
187
+ )
188
+ last_seen: Optional[str] = odm.Optional(
189
+ odm.Date(description="The date and time when intelligence source last reported sighting this indicator.")
190
+ )
191
+ port: Optional[int] = odm.Integer(description="Identifies a threat indicator as a port number", optional=True)
192
+
193
+
194
+ @odm.model(
195
+ index=True,
196
+ store=True,
197
+ )
198
+ class Matched(odm.Model):
199
+ atomic: Optional[str] = odm.Optional(
200
+ odm.Keyword(
201
+ description="Identifies the atomic indicator value that matched a extended local envirnment endpoint or network event" # noqa: E501
202
+ )
203
+ )
204
+
205
+
206
+ @odm.model(
207
+ index=True,
208
+ store=True,
209
+ description="List of enrichments",
210
+ )
211
+ class Enrichments(odm.Model):
212
+ indicator = odm.Optional(odm.Compound(Indicator))
213
+ matched = odm.Optional(odm.Compound(Matched))
214
+
215
+
216
+ @odm.model(
217
+ index=True,
218
+ store=True,
219
+ description="Fields to classify events and alerts according to a threat "
220
+ "taxonomy such as the MITRE ATT&CK® framework.",
221
+ )
222
+ class Threat(odm.Model):
223
+ enrichments = odm.Optional(
224
+ odm.List(odm.Compound(Enrichments, description="List of enrichments marked threats from indicator."))
225
+ )
226
+ feed = odm.Optional(odm.Compound(Feed, description="Threat feed information."))
227
+ framework = odm.Optional(
228
+ odm.Keyword(
229
+ description="Name of the threat framework used to further categorize and classify the tactic and "
230
+ "technique of the reported threat."
231
+ )
232
+ )
233
+ group = odm.Optional(odm.Compound(Group, description="Information about the group related to this threat."))
234
+ indicator = odm.Optional(
235
+ odm.Compound(
236
+ Indicator,
237
+ description="Object containing associated indicators enriching the event.",
238
+ )
239
+ )
240
+ software = odm.Optional(odm.Compound(Software, description="Information about the software used by this threat."))
241
+ tactic: Tactic = odm.Optional(odm.Compound(Tactic, description="Information about the tactic used by this threat."))
242
+ technique: Tactic = odm.Optional(
243
+ odm.Compound(
244
+ Tactic,
245
+ description="Information about the technique used by this threat.",
246
+ )
247
+ )
@@ -0,0 +1,58 @@
1
+ from typing import Optional
2
+
3
+ from howler import odm
4
+
5
+
6
+ @odm.model(
7
+ index=True,
8
+ store=True,
9
+ description=(
10
+ "A Server is defined as the responder in a network connection for events regarding sessions, "
11
+ "connections, or bidirectional flow records."
12
+ ),
13
+ )
14
+ class Server(odm.Model):
15
+ ja3s: Optional[str] = odm.Optional(
16
+ odm.Keyword(description="A hash that identifies servers based on how they perform an SSL/TLS handshake.")
17
+ )
18
+
19
+
20
+ @odm.model(
21
+ index=True,
22
+ store=True,
23
+ description=(
24
+ "A Server is defined as the responder in a network connection for events regarding sessions, "
25
+ "connections, or bidirectional flow records."
26
+ ),
27
+ )
28
+ class Client(odm.Model):
29
+ server_name: Optional[str] = odm.Optional(
30
+ odm.Keyword(
31
+ description=(
32
+ "Also called an SNI, this tells the server which hostname to which the client is "
33
+ "attempting to connect to. When this value is available, it should get copied to destination.domain."
34
+ )
35
+ )
36
+ )
37
+ ja3: Optional[str] = odm.Optional(
38
+ odm.Keyword(description="A hash that identifies clients based on how they perform an SSL/TLS handshake.")
39
+ )
40
+
41
+
42
+ @odm.model(
43
+ index=True,
44
+ store=True,
45
+ description=(
46
+ "A Server is defined as the responder in a network connection for events regarding sessions, "
47
+ "connections, or bidirectional flow records."
48
+ ),
49
+ )
50
+ class TLS(odm.Model):
51
+ version: Optional[str] = odm.Optional(
52
+ odm.Keyword(description="Numeric part of the version parsed from the original string.")
53
+ )
54
+ version_protocol: Optional[str] = odm.Optional(
55
+ odm.Keyword(description="Normalized lowercase protocol name parsed from original string.")
56
+ )
57
+ client: Client = odm.Optional(odm.Compound(Client))
58
+ server: Server = odm.Optional(odm.Compound(Server))