pedrobento988 commited on
Commit
8b2adc4
·
verified ·
1 Parent(s): 9320ddd

add_mitre_attack_information_retrieval (#7)

Browse files

- feat: add stix object retrieval for an attack id (8e93ae4498ecb4cdd0db9728e834c9e7446fe841)
- Merge branch 'main' of https://huggingface.co/spaces/Agents-MCP-Hackathon/TDAgentTools (c59ae19eb829e398b16e5091760a9b6c99e9e480)
- fix: update requirements files and add missing dependency (b1c435fae63c7e8efa1cef272312cfdb163dfee9)
- fix: rodrigo's laziness second try (dd8af64b17133f1a7d87725c06ebbbfe6760ede6)
- feat: add cache to mittre retrieval (b0da92f1a0715fc63217c181f7323cf3fa3a2cd7)

app.py CHANGED
@@ -15,6 +15,7 @@ from tdagent.tools.lookup_company_cloud_account_information import (
15
  )
16
  from tdagent.tools.query_abuse_ip_db import gr_query_abuseipdb
17
  from tdagent.tools.rdap import gr_query_rdap
 
18
  from tdagent.tools.send_email import gr_send_email
19
  from tdagent.tools.virus_total import gr_virus_total_url_info
20
 
@@ -43,6 +44,7 @@ TOOLS = (
43
  ToolInfo("DNS Enumerator", dns_enumeration_tool),
44
  ToolInfo("Subdomain Retriever", scrap_subdomains_tool),
45
  ToolInfo("Extractor of IoCs", extractor_of_ioc_from_threatfox_tool),
 
46
  ## Fake tools
47
  ToolInfo("Fake company directory", gr_internal_company),
48
  ToolInfo(
 
15
  )
16
  from tdagent.tools.query_abuse_ip_db import gr_query_abuseipdb
17
  from tdagent.tools.rdap import gr_query_rdap
18
+ from tdagent.tools.retrieve_from_mitre_attack import gr_get_stix_of_attack_id
19
  from tdagent.tools.send_email import gr_send_email
20
  from tdagent.tools.virus_total import gr_virus_total_url_info
21
 
 
44
  ToolInfo("DNS Enumerator", dns_enumeration_tool),
45
  ToolInfo("Subdomain Retriever", scrap_subdomains_tool),
46
  ToolInfo("Extractor of IoCs", extractor_of_ioc_from_threatfox_tool),
47
+ ToolInfo("ATT&CK STIX information", gr_get_stix_of_attack_id),
48
  ## Fake tools
49
  ToolInfo("Fake company directory", gr_internal_company),
50
  ToolInfo(
pyproject.toml CHANGED
@@ -13,6 +13,9 @@ requires-python = ">=3.10,<4"
13
  readme = "README.md"
14
  license = ""
15
  dependencies = [
 
 
 
16
  "cachetools>=6.0.0",
17
  "dnspython>=2.7.0",
18
  "gradio[mcp]>=5.32.1",
 
13
  readme = "README.md"
14
  license = ""
15
  dependencies = [
16
+ "attackcti>=0.5.4",
17
+ "audioop-lts>=0.2.1 ; python_full_version >= '3.13'",
18
+ "black>=25.1.0",
19
  "cachetools>=6.0.0",
20
  "dnspython>=2.7.0",
21
  "gradio[mcp]>=5.32.1",
requirements-dev.txt CHANGED
@@ -1,17 +1,19 @@
1
  # This file was autogenerated by uv via the following command:
2
- # uv export --format requirements-txt --no-hashes --group dev --group test -o requirements-dev.txt
3
  aiofiles==24.1.0
4
  # via
5
  # gradio
6
  # vt-py
7
  aiohappyeyeballs==2.6.1
8
  # via aiohttp
9
- aiohttp==3.12.8
10
  # via vt-py
11
  aiosignal==1.3.2
12
  # via aiohttp
13
  annotated-types==0.7.0
14
  # via pydantic
 
 
15
  anyio==4.9.0
16
  # via
17
  # gradio
@@ -21,10 +23,16 @@ anyio==4.9.0
21
  # starlette
22
  async-timeout==5.0.1 ; python_full_version < '3.11'
23
  # via aiohttp
 
 
24
  attrs==25.3.0
25
  # via aiohttp
26
  audioop-lts==0.2.1 ; python_full_version >= '3.13'
27
- # via gradio
 
 
 
 
28
  boolean-py==5.0
29
  # via license-expression
30
  cachecontrol==0.14.3
@@ -40,8 +48,9 @@ cfgv==3.4.0
40
  # via pre-commit
41
  charset-normalizer==3.4.2
42
  # via requests
43
- click==8.2.1 ; sys_platform != 'emscripten'
44
  # via
 
45
  # typer
46
  # uvicorn
47
  colorama==0.4.6 ; sys_platform == 'win32'
@@ -80,7 +89,7 @@ fsspec==2025.5.1
80
  # via
81
  # gradio-client
82
  # huggingface-hub
83
- gradio==5.32.1
84
  # via tdagent
85
  gradio-client==1.10.2
86
  # via gradio
@@ -90,7 +99,7 @@ h11==0.16.0
90
  # via
91
  # httpcore
92
  # uvicorn
93
- hf-xet==1.1.2 ; platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'
94
  # via huggingface-hub
95
  httpcore==1.0.9
96
  # via httpx
@@ -138,7 +147,9 @@ multidict==6.4.4
138
  # yarl
139
  mypy==1.16.0
140
  mypy-extensions==1.1.0
141
- # via mypy
 
 
142
  nodeenv==1.9.1
143
  # via pre-commit
144
  numpy==2.2.6
@@ -147,20 +158,23 @@ numpy==2.2.6
147
  # pandas
148
  orjson==3.10.18
149
  # via gradio
150
- packageurl-python==0.16.0
151
  # via cyclonedx-python-lib
152
  packaging==25.0
153
  # via
 
154
  # gradio
155
  # gradio-client
156
  # huggingface-hub
157
  # pip-audit
158
  # pip-requirements-parser
159
  # pytest
160
- pandas==2.2.3
161
  # via gradio
162
  pathspec==0.12.1
163
- # via mypy
 
 
164
  pillow==11.2.1
165
  # via gradio
166
  pip==25.1.1
@@ -172,6 +186,7 @@ pip-requirements-parser==32.0.1
172
  # via pip-audit
173
  platformdirs==4.3.8
174
  # via
 
175
  # pip-audit
176
  # virtualenv
177
  pluggy==1.6.0
@@ -185,6 +200,7 @@ py-serializable==2.0.0
185
  # via cyclonedx-python-lib
186
  pydantic==2.11.5
187
  # via
 
188
  # fastapi
189
  # gradio
190
  # mcp
@@ -218,7 +234,10 @@ python-multipart==0.0.20
218
  python-whois==0.9.5
219
  # via tdagent
220
  pytz==2025.2
221
- # via pandas
 
 
 
222
  pyyaml==6.0.2
223
  # via
224
  # gradio
@@ -229,6 +248,8 @@ requests==2.32.3
229
  # cachecontrol
230
  # huggingface-hub
231
  # pip-audit
 
 
232
  # tdagent
233
  rich==14.0.0
234
  # via
@@ -242,8 +263,13 @@ semantic-version==2.10.0
242
  # via gradio
243
  shellingham==1.5.4 ; sys_platform != 'emscripten'
244
  # via typer
 
 
245
  six==1.17.0
246
- # via python-dateutil
 
 
 
247
  sniffio==1.3.1
248
  # via anyio
249
  sortedcontainers==2.4.0
@@ -255,14 +281,21 @@ starlette==0.46.2
255
  # fastapi
256
  # gradio
257
  # mcp
 
 
 
 
 
 
258
  toml==0.10.2
259
  # via pip-audit
260
  tomli==2.2.1 ; python_full_version <= '3.11'
261
  # via
 
262
  # coverage
263
  # mypy
264
  # pytest
265
- tomlkit==0.13.2
266
  # via gradio
267
  tqdm==4.67.1
268
  # via huggingface-hub
@@ -271,6 +304,7 @@ typer==0.16.0 ; sys_platform != 'emscripten'
271
  typing-extensions==4.14.0
272
  # via
273
  # anyio
 
274
  # exceptiongroup
275
  # fastapi
276
  # gradio
 
1
  # This file was autogenerated by uv via the following command:
2
+ # uv export --format requirements.txt --no-hashes --group dev --group test -o requirements-dev.txt
3
  aiofiles==24.1.0
4
  # via
5
  # gradio
6
  # vt-py
7
  aiohappyeyeballs==2.6.1
8
  # via aiohttp
9
+ aiohttp==3.12.9
10
  # via vt-py
11
  aiosignal==1.3.2
12
  # via aiohttp
13
  annotated-types==0.7.0
14
  # via pydantic
15
+ antlr4-python3-runtime==4.9.3
16
+ # via stix2-patterns
17
  anyio==4.9.0
18
  # via
19
  # gradio
 
23
  # starlette
24
  async-timeout==5.0.1 ; python_full_version < '3.11'
25
  # via aiohttp
26
+ attackcti==0.5.4
27
+ # via tdagent
28
  attrs==25.3.0
29
  # via aiohttp
30
  audioop-lts==0.2.1 ; python_full_version >= '3.13'
31
+ # via
32
+ # gradio
33
+ # tdagent
34
+ black==25.1.0
35
+ # via tdagent
36
  boolean-py==5.0
37
  # via license-expression
38
  cachecontrol==0.14.3
 
48
  # via pre-commit
49
  charset-normalizer==3.4.2
50
  # via requests
51
+ click==8.2.1
52
  # via
53
+ # black
54
  # typer
55
  # uvicorn
56
  colorama==0.4.6 ; sys_platform == 'win32'
 
89
  # via
90
  # gradio-client
91
  # huggingface-hub
92
+ gradio==5.33.0
93
  # via tdagent
94
  gradio-client==1.10.2
95
  # via gradio
 
99
  # via
100
  # httpcore
101
  # uvicorn
102
+ hf-xet==1.1.3 ; platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'
103
  # via huggingface-hub
104
  httpcore==1.0.9
105
  # via httpx
 
147
  # yarl
148
  mypy==1.16.0
149
  mypy-extensions==1.1.0
150
+ # via
151
+ # black
152
+ # mypy
153
  nodeenv==1.9.1
154
  # via pre-commit
155
  numpy==2.2.6
 
158
  # pandas
159
  orjson==3.10.18
160
  # via gradio
161
+ packageurl-python==0.17.0
162
  # via cyclonedx-python-lib
163
  packaging==25.0
164
  # via
165
+ # black
166
  # gradio
167
  # gradio-client
168
  # huggingface-hub
169
  # pip-audit
170
  # pip-requirements-parser
171
  # pytest
172
+ pandas==2.3.0
173
  # via gradio
174
  pathspec==0.12.1
175
+ # via
176
+ # black
177
+ # mypy
178
  pillow==11.2.1
179
  # via gradio
180
  pip==25.1.1
 
186
  # via pip-audit
187
  platformdirs==4.3.8
188
  # via
189
+ # black
190
  # pip-audit
191
  # virtualenv
192
  pluggy==1.6.0
 
200
  # via cyclonedx-python-lib
201
  pydantic==2.11.5
202
  # via
203
+ # attackcti
204
  # fastapi
205
  # gradio
206
  # mcp
 
234
  python-whois==0.9.5
235
  # via tdagent
236
  pytz==2025.2
237
+ # via
238
+ # pandas
239
+ # stix2
240
+ # taxii2-client
241
  pyyaml==6.0.2
242
  # via
243
  # gradio
 
248
  # cachecontrol
249
  # huggingface-hub
250
  # pip-audit
251
+ # stix2
252
+ # taxii2-client
253
  # tdagent
254
  rich==14.0.0
255
  # via
 
263
  # via gradio
264
  shellingham==1.5.4 ; sys_platform != 'emscripten'
265
  # via typer
266
+ simplejson==3.20.1
267
+ # via stix2
268
  six==1.17.0
269
+ # via
270
+ # python-dateutil
271
+ # stix2-patterns
272
+ # taxii2-client
273
  sniffio==1.3.1
274
  # via anyio
275
  sortedcontainers==2.4.0
 
281
  # fastapi
282
  # gradio
283
  # mcp
284
+ stix2==3.0.1
285
+ # via attackcti
286
+ stix2-patterns==2.0.0
287
+ # via stix2
288
+ taxii2-client==2.3.0
289
+ # via attackcti
290
  toml==0.10.2
291
  # via pip-audit
292
  tomli==2.2.1 ; python_full_version <= '3.11'
293
  # via
294
+ # black
295
  # coverage
296
  # mypy
297
  # pytest
298
+ tomlkit==0.13.3
299
  # via gradio
300
  tqdm==4.67.1
301
  # via huggingface-hub
 
304
  typing-extensions==4.14.0
305
  # via
306
  # anyio
307
+ # black
308
  # exceptiongroup
309
  # fastapi
310
  # gradio
requirements.txt CHANGED
@@ -1,17 +1,19 @@
1
  # This file was autogenerated by uv via the following command:
2
- # uv pip compile pyproject.toml -o requirements.txt
3
  aiofiles==24.1.0
4
  # via
5
  # gradio
6
  # vt-py
7
  aiohappyeyeballs==2.6.1
8
  # via aiohttp
9
- aiohttp==3.12.8
10
  # via vt-py
11
  aiosignal==1.3.2
12
  # via aiohttp
13
  annotated-types==0.7.0
14
  # via pydantic
 
 
15
  anyio==4.9.0
16
  # via
17
  # gradio
@@ -19,12 +21,20 @@ anyio==4.9.0
19
  # mcp
20
  # sse-starlette
21
  # starlette
 
 
 
 
22
  attrs==25.3.0
23
  # via aiohttp
24
- audioop-lts==0.2.1
25
- # via gradio
 
 
 
 
26
  cachetools==6.0.0
27
- # via tdagent (pyproject.toml)
28
  certifi==2025.4.26
29
  # via
30
  # httpcore
@@ -34,10 +44,22 @@ charset-normalizer==3.4.2
34
  # via requests
35
  click==8.2.1
36
  # via
 
37
  # typer
38
  # uvicorn
 
 
 
 
 
 
 
39
  dnspython==2.7.0
40
- # via tdagent (pyproject.toml)
 
 
 
 
41
  fastapi==0.115.12
42
  # via gradio
43
  ffmpy==0.6.0
@@ -52,8 +74,8 @@ fsspec==2025.5.1
52
  # via
53
  # gradio-client
54
  # huggingface-hub
55
- gradio==5.32.1
56
- # via tdagent (pyproject.toml)
57
  gradio-client==1.10.2
58
  # via gradio
59
  groovy==0.1.2
@@ -62,7 +84,7 @@ h11==0.16.0
62
  # via
63
  # httpcore
64
  # uvicorn
65
- hf-xet==1.1.2
66
  # via huggingface-hub
67
  httpcore==1.0.9
68
  # via httpx
@@ -84,9 +106,11 @@ idna==3.10
84
  # httpx
85
  # requests
86
  # yarl
 
 
87
  jinja2==3.1.6
88
  # via gradio
89
- markdown-it-py==3.0.0
90
  # via rich
91
  markupsafe==3.0.2
92
  # via
@@ -94,12 +118,14 @@ markupsafe==3.0.2
94
  # jinja2
95
  mcp==1.9.0
96
  # via gradio
97
- mdurl==0.1.2
98
  # via markdown-it-py
99
  multidict==6.4.4
100
  # via
101
  # aiohttp
102
  # yarl
 
 
103
  numpy==2.2.6
104
  # via
105
  # gradio
@@ -108,19 +134,28 @@ orjson==3.10.18
108
  # via gradio
109
  packaging==25.0
110
  # via
 
111
  # gradio
112
  # gradio-client
113
  # huggingface-hub
114
- pandas==2.2.3
 
115
  # via gradio
 
 
116
  pillow==11.2.1
117
  # via gradio
 
 
 
 
118
  propcache==0.3.1
119
  # via
120
  # aiohttp
121
  # yarl
122
  pydantic==2.11.5
123
  # via
 
124
  # fastapi
125
  # gradio
126
  # mcp
@@ -131,8 +166,14 @@ pydantic-settings==2.9.1
131
  # via mcp
132
  pydub==0.25.1
133
  # via gradio
134
- pygments==2.19.1
135
  # via rich
 
 
 
 
 
 
136
  python-dateutil==2.9.0.post0
137
  # via
138
  # pandas
@@ -144,29 +185,39 @@ python-multipart==0.0.20
144
  # gradio
145
  # mcp
146
  python-whois==0.9.5
147
- # via tdagent (pyproject.toml)
148
  pytz==2025.2
149
- # via pandas
 
 
 
150
  pyyaml==6.0.2
151
  # via
152
  # gradio
153
  # huggingface-hub
154
  requests==2.32.3
155
  # via
156
- # tdagent (pyproject.toml)
157
  # huggingface-hub
158
- rich==14.0.0
 
 
 
159
  # via typer
160
- ruff==0.11.12
161
  # via gradio
162
  safehttpx==0.1.6
163
  # via gradio
164
  semantic-version==2.10.0
165
  # via gradio
166
- shellingham==1.5.4
167
  # via typer
 
 
168
  six==1.17.0
169
- # via python-dateutil
 
 
 
170
  sniffio==1.3.1
171
  # via anyio
172
  sse-starlette==2.3.6
@@ -176,22 +227,39 @@ starlette==0.46.2
176
  # fastapi
177
  # gradio
178
  # mcp
179
- tomlkit==0.13.2
 
 
 
 
 
 
 
 
 
 
 
180
  # via gradio
181
  tqdm==4.67.1
182
  # via huggingface-hub
183
- typer==0.16.0
184
  # via gradio
185
  typing-extensions==4.14.0
186
  # via
 
 
 
187
  # fastapi
188
  # gradio
189
  # gradio-client
190
  # huggingface-hub
 
191
  # pydantic
192
  # pydantic-core
 
193
  # typer
194
  # typing-inspection
 
195
  typing-inspection==0.4.1
196
  # via
197
  # pydantic
@@ -199,14 +267,17 @@ typing-inspection==0.4.1
199
  tzdata==2025.2
200
  # via pandas
201
  urllib3==2.4.0
202
- # via requests
203
- uvicorn==0.34.3
 
 
204
  # via
205
  # gradio
206
  # mcp
207
  vt-py==0.21.0
208
- # via tdagent (pyproject.toml)
209
  websockets==15.0.1
210
  # via gradio-client
 
211
  yarl==1.20.0
212
  # via aiohttp
 
1
  # This file was autogenerated by uv via the following command:
2
+ # uv export --format requirements.txt --no-hashes --no-dev -o requirements.txt
3
  aiofiles==24.1.0
4
  # via
5
  # gradio
6
  # vt-py
7
  aiohappyeyeballs==2.6.1
8
  # via aiohttp
9
+ aiohttp==3.12.9
10
  # via vt-py
11
  aiosignal==1.3.2
12
  # via aiohttp
13
  annotated-types==0.7.0
14
  # via pydantic
15
+ antlr4-python3-runtime==4.9.3
16
+ # via stix2-patterns
17
  anyio==4.9.0
18
  # via
19
  # gradio
 
21
  # mcp
22
  # sse-starlette
23
  # starlette
24
+ async-timeout==5.0.1 ; python_full_version < '3.11'
25
+ # via aiohttp
26
+ attackcti==0.5.4
27
+ # via tdagent
28
  attrs==25.3.0
29
  # via aiohttp
30
+ audioop-lts==0.2.1 ; python_full_version >= '3.13'
31
+ # via
32
+ # gradio
33
+ # tdagent
34
+ black==25.1.0
35
+ # via tdagent
36
  cachetools==6.0.0
37
+ # via tdagent
38
  certifi==2025.4.26
39
  # via
40
  # httpcore
 
44
  # via requests
45
  click==8.2.1
46
  # via
47
+ # black
48
  # typer
49
  # uvicorn
50
+ colorama==0.4.6 ; sys_platform == 'win32'
51
+ # via
52
+ # click
53
+ # pytest
54
+ # tqdm
55
+ coverage==7.8.2
56
+ # via pytest-cov
57
  dnspython==2.7.0
58
+ # via tdagent
59
+ exceptiongroup==1.3.0 ; python_full_version < '3.11'
60
+ # via
61
+ # anyio
62
+ # pytest
63
  fastapi==0.115.12
64
  # via gradio
65
  ffmpy==0.6.0
 
74
  # via
75
  # gradio-client
76
  # huggingface-hub
77
+ gradio==5.33.0
78
+ # via tdagent
79
  gradio-client==1.10.2
80
  # via gradio
81
  groovy==0.1.2
 
84
  # via
85
  # httpcore
86
  # uvicorn
87
+ hf-xet==1.1.3 ; platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'
88
  # via huggingface-hub
89
  httpcore==1.0.9
90
  # via httpx
 
106
  # httpx
107
  # requests
108
  # yarl
109
+ iniconfig==2.1.0
110
+ # via pytest
111
  jinja2==3.1.6
112
  # via gradio
113
+ markdown-it-py==3.0.0 ; sys_platform != 'emscripten'
114
  # via rich
115
  markupsafe==3.0.2
116
  # via
 
118
  # jinja2
119
  mcp==1.9.0
120
  # via gradio
121
+ mdurl==0.1.2 ; sys_platform != 'emscripten'
122
  # via markdown-it-py
123
  multidict==6.4.4
124
  # via
125
  # aiohttp
126
  # yarl
127
+ mypy-extensions==1.1.0
128
+ # via black
129
  numpy==2.2.6
130
  # via
131
  # gradio
 
134
  # via gradio
135
  packaging==25.0
136
  # via
137
+ # black
138
  # gradio
139
  # gradio-client
140
  # huggingface-hub
141
+ # pytest
142
+ pandas==2.3.0
143
  # via gradio
144
+ pathspec==0.12.1
145
+ # via black
146
  pillow==11.2.1
147
  # via gradio
148
+ platformdirs==4.3.8
149
+ # via black
150
+ pluggy==1.6.0
151
+ # via pytest
152
  propcache==0.3.1
153
  # via
154
  # aiohttp
155
  # yarl
156
  pydantic==2.11.5
157
  # via
158
+ # attackcti
159
  # fastapi
160
  # gradio
161
  # mcp
 
166
  # via mcp
167
  pydub==0.25.1
168
  # via gradio
169
+ pygments==2.19.1 ; sys_platform != 'emscripten'
170
  # via rich
171
+ pytest==7.4.4
172
+ # via
173
+ # pytest-cov
174
+ # pytest-randomly
175
+ pytest-cov==4.1.0
176
+ pytest-randomly==3.16.0
177
  python-dateutil==2.9.0.post0
178
  # via
179
  # pandas
 
185
  # gradio
186
  # mcp
187
  python-whois==0.9.5
188
+ # via tdagent
189
  pytz==2025.2
190
+ # via
191
+ # pandas
192
+ # stix2
193
+ # taxii2-client
194
  pyyaml==6.0.2
195
  # via
196
  # gradio
197
  # huggingface-hub
198
  requests==2.32.3
199
  # via
 
200
  # huggingface-hub
201
+ # stix2
202
+ # taxii2-client
203
+ # tdagent
204
+ rich==14.0.0 ; sys_platform != 'emscripten'
205
  # via typer
206
+ ruff==0.11.12 ; sys_platform != 'emscripten'
207
  # via gradio
208
  safehttpx==0.1.6
209
  # via gradio
210
  semantic-version==2.10.0
211
  # via gradio
212
+ shellingham==1.5.4 ; sys_platform != 'emscripten'
213
  # via typer
214
+ simplejson==3.20.1
215
+ # via stix2
216
  six==1.17.0
217
+ # via
218
+ # python-dateutil
219
+ # stix2-patterns
220
+ # taxii2-client
221
  sniffio==1.3.1
222
  # via anyio
223
  sse-starlette==2.3.6
 
227
  # fastapi
228
  # gradio
229
  # mcp
230
+ stix2==3.0.1
231
+ # via attackcti
232
+ stix2-patterns==2.0.0
233
+ # via stix2
234
+ taxii2-client==2.3.0
235
+ # via attackcti
236
+ tomli==2.2.1 ; python_full_version <= '3.11'
237
+ # via
238
+ # black
239
+ # coverage
240
+ # pytest
241
+ tomlkit==0.13.3
242
  # via gradio
243
  tqdm==4.67.1
244
  # via huggingface-hub
245
+ typer==0.16.0 ; sys_platform != 'emscripten'
246
  # via gradio
247
  typing-extensions==4.14.0
248
  # via
249
+ # anyio
250
+ # black
251
+ # exceptiongroup
252
  # fastapi
253
  # gradio
254
  # gradio-client
255
  # huggingface-hub
256
+ # multidict
257
  # pydantic
258
  # pydantic-core
259
+ # rich
260
  # typer
261
  # typing-inspection
262
+ # uvicorn
263
  typing-inspection==0.4.1
264
  # via
265
  # pydantic
 
267
  tzdata==2025.2
268
  # via pandas
269
  urllib3==2.4.0
270
+ # via
271
+ # gradio
272
+ # requests
273
+ uvicorn==0.34.3 ; sys_platform != 'emscripten'
274
  # via
275
  # gradio
276
  # mcp
277
  vt-py==0.21.0
278
+ # via tdagent
279
  websockets==15.0.1
280
  # via gradio-client
281
+ xdoctest==1.2.0
282
  yarl==1.20.0
283
  # via aiohttp
tdagent/tools/get_domain_information.py CHANGED
@@ -10,7 +10,7 @@ import urllib3
10
  from dns import message
11
 
12
 
13
- _DNS_SERVER = "https://dns.google/dns-query" # can use others
14
  _DNS_RECORD_TYPES = [
15
  "A",
16
  "AAAA",
@@ -71,7 +71,7 @@ def get_geolocation(ip: str) -> dict[str, Any] | str:
71
  return str(e)
72
 
73
 
74
- def _request_dns_record(domain: str, record_type: str) -> str:
75
  """Utility to build dns resolve requests that do not use port 53.
76
 
77
  Args:
@@ -95,6 +95,7 @@ def _request_dns_record(domain: str, record_type: str) -> str:
95
  dns_message = message.from_wire(response.content)
96
  return [str(rdata) for rdata in dns_message.answer[0]] if dns_message.answer else []
97
 
 
98
  # see: https://thepythoncode.com/article/dns-enumeration-with-python
99
  # https://dnspython.readthedocs.io
100
  def enumerate_dns(domain_name: str) -> dict[str, Any] | None:
@@ -163,9 +164,10 @@ def enumerate_dns(domain_name: str) -> dict[str, Any] | None:
163
  if record:
164
  enumeration[record_type] = record
165
  except Exception as e: # noqa: BLE001, PERF203
166
- enumeration[record_type] = str(e)
167
  return enumeration if enumeration else None
168
 
 
169
  def resolve_subdomain_ipv4(domain: str) -> str | None:
170
  """Resolve the IPv4 address of a domain.
171
 
@@ -225,6 +227,7 @@ def scrap_subdomains_for_domain(domain_name: str) -> list[str]:
225
  results = executor.map(resolve_subdomain_ipv4, potential_subdomains)
226
  return [domain for domain in results if domain]
227
 
 
228
  def retrieve_ioc_from_threatfox(potentially_ioc: str) -> str:
229
  r"""Retrieves information about a potential IoC from ThreatFox.
230
 
 
10
  from dns import message
11
 
12
 
13
+ _DNS_SERVER = "https://dns.google/dns-query" # can use others
14
  _DNS_RECORD_TYPES = [
15
  "A",
16
  "AAAA",
 
71
  return str(e)
72
 
73
 
74
+ def _request_dns_record(domain: str, record_type: str) -> list[str]:
75
  """Utility to build dns resolve requests that do not use port 53.
76
 
77
  Args:
 
95
  dns_message = message.from_wire(response.content)
96
  return [str(rdata) for rdata in dns_message.answer[0]] if dns_message.answer else []
97
 
98
+
99
  # see: https://thepythoncode.com/article/dns-enumeration-with-python
100
  # https://dnspython.readthedocs.io
101
  def enumerate_dns(domain_name: str) -> dict[str, Any] | None:
 
164
  if record:
165
  enumeration[record_type] = record
166
  except Exception as e: # noqa: BLE001, PERF203
167
+ enumeration[record_type] = [str(e)]
168
  return enumeration if enumeration else None
169
 
170
+
171
  def resolve_subdomain_ipv4(domain: str) -> str | None:
172
  """Resolve the IPv4 address of a domain.
173
 
 
227
  results = executor.map(resolve_subdomain_ipv4, potential_subdomains)
228
  return [domain for domain in results if domain]
229
 
230
+
231
  def retrieve_ioc_from_threatfox(potentially_ioc: str) -> str:
232
  r"""Retrieves information about a potential IoC from ThreatFox.
233
 
tdagent/tools/retrieve_from_mitre_attack.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+
3
+ import cachetools
4
+ import gradio as gr
5
+ from attackcti import attack_client
6
+
7
+
8
+ _CACHE_MAX_SIZE = 4096
9
+ _CACHE_TTL_SECONDS = 3600
10
+
11
+
12
+ @cachetools.cached(
13
+ cache=cachetools.TTLCache(maxsize=_CACHE_MAX_SIZE, ttl=_CACHE_TTL_SECONDS),
14
+ )
15
+ def get_stix_object_of_attack_id(
16
+ attack_id: str,
17
+ object_type: str = "attack-pattern",
18
+ ) -> dict[str, Any]:
19
+ """Retrieves a STIX object identified by an ATT&CK ID in all ATT&CK matrices.
20
+
21
+ Args:
22
+ attack_id (str): The ATT&CK ID (e.g., 'T1234') of the STIX object to retrieve.
23
+ object_type (str): The type of STIX object to retrieve, such as
24
+ 'attack-pattern', 'course-of-action', 'intrusion-set',
25
+ 'malware', 'tool', or 'x-mitre-data-component'. Default is 'attack-pattern'
26
+
27
+ Returns:
28
+ A list containing the matched STIX object, either in its raw STIX format
29
+ or as a custom dictionary following the structure defined by the relevant
30
+ Pydantic model, depending on the 'stix_format' flag.
31
+ """
32
+ lift = attack_client()
33
+ return lift.get_object_by_attack_id(
34
+ object_type=object_type,
35
+ attack_id=attack_id,
36
+ stix_format=False,
37
+ )[0]
38
+
39
+
40
+ gr_get_stix_of_attack_id = gr.Interface(
41
+ fn=get_stix_object_of_attack_id,
42
+ inputs=["text", "text"],
43
+ outputs="json",
44
+ title="MITRE ATT&CK STIX information",
45
+ description=(
46
+ "Retrieves a specific STIX object identified by an ATT&CK ID across all ATT&CK"
47
+ " matrices"
48
+ ),
49
+ )
uv.lock CHANGED
The diff for this file is too large to render. See raw diff