VulnTrain 0.1.0__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.
vulntrain-0.1.0/COPYING
ADDED
|
File without changes
|
vulntrain-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: VulnTrain
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generate datasets amd models based on vulnerabilities descriptions from Vulnerability-Lookup.
|
|
5
|
+
License: GPL-3.0-or-later
|
|
6
|
+
Author: Cédric Bonhomme
|
|
7
|
+
Author-email: cedric.bonhomme@circl.lu
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Security
|
|
21
|
+
Requires-Dist: datasets (>=3.3.1,<4.0.0)
|
|
22
|
+
Requires-Dist: nltk (>=3.9.1,<4.0.0)
|
|
23
|
+
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
|
24
|
+
Requires-Dist: valkey (>=6.1.0,<7.0.0)
|
|
25
|
+
Project-URL: Homepage, https://github.com/vulnerability-lookup/VulnTrain
|
|
26
|
+
Project-URL: Repository, https://github.com/vulnerability-lookup/VulnTrain
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# VulnTrain
|
|
30
|
+
|
|
31
|
+
Generate datasets amd models based on vulnerabilities descriptions from Vulnerability-Lookup.
|
|
32
|
+
|
|
33
|
+
Uses data from the ``vulnerability-lookup:meta`` container such as vulnrichment and FKIE.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Generate datasets
|
|
39
|
+
|
|
40
|
+
Authenticate to HuggingFace:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
huggingface-cli login
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Creation of datasets:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
$ pipx install VulnTrain
|
|
50
|
+
|
|
51
|
+
$ vulntrain-create-dataset
|
|
52
|
+
DatasetDict({
|
|
53
|
+
train: Dataset({
|
|
54
|
+
features: ['id', 'title', 'description'],
|
|
55
|
+
num_rows: 4
|
|
56
|
+
})
|
|
57
|
+
test: Dataset({
|
|
58
|
+
features: ['id', 'title', 'description'],
|
|
59
|
+
num_rows: 1
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
Creating parquet from Arrow format: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1317.72ba/s]
|
|
63
|
+
Uploading the dataset shards: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1.16it/s]
|
|
64
|
+
Creating parquet from Arrow format: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2233.39ba/s]
|
|
65
|
+
Uploading the dataset shards: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1.39it/s]
|
|
66
|
+
README.md: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 428/428 [00:00<00:00, 1.70MB/s]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
Train:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
$ vulntrain-train-dataset
|
|
74
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# VulnTrain
|
|
2
|
+
|
|
3
|
+
Generate datasets amd models based on vulnerabilities descriptions from Vulnerability-Lookup.
|
|
4
|
+
|
|
5
|
+
Uses data from the ``vulnerability-lookup:meta`` container such as vulnrichment and FKIE.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
### Generate datasets
|
|
11
|
+
|
|
12
|
+
Authenticate to HuggingFace:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
huggingface-cli login
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Creation of datasets:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
$ pipx install VulnTrain
|
|
22
|
+
|
|
23
|
+
$ vulntrain-create-dataset
|
|
24
|
+
DatasetDict({
|
|
25
|
+
train: Dataset({
|
|
26
|
+
features: ['id', 'title', 'description'],
|
|
27
|
+
num_rows: 4
|
|
28
|
+
})
|
|
29
|
+
test: Dataset({
|
|
30
|
+
features: ['id', 'title', 'description'],
|
|
31
|
+
num_rows: 1
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
Creating parquet from Arrow format: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1317.72ba/s]
|
|
35
|
+
Uploading the dataset shards: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1.16it/s]
|
|
36
|
+
Creating parquet from Arrow format: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2233.39ba/s]
|
|
37
|
+
Uploading the dataset shards: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 1.39it/s]
|
|
38
|
+
README.md: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 428/428 [00:00<00:00, 1.70MB/s]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
Train:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
$ vulntrain-train-dataset
|
|
46
|
+
```
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
3
|
+
build-backend = "poetry.core.masonry.api"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "VulnTrain"
|
|
8
|
+
version = "0.1.0"
|
|
9
|
+
description = "Generate datasets amd models based on vulnerabilities descriptions from Vulnerability-Lookup."
|
|
10
|
+
authors = [
|
|
11
|
+
{name = "Cédric Bonhomme",email = "cedric.bonhomme@circl.lu"}
|
|
12
|
+
]
|
|
13
|
+
license = "GPL-3.0-or-later"
|
|
14
|
+
readme = "README.md"
|
|
15
|
+
|
|
16
|
+
dynamic = ["classifiers"]
|
|
17
|
+
|
|
18
|
+
requires-python = ">=3.10,<4.0"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://github.com/vulnerability-lookup/VulnTrain"
|
|
23
|
+
Repository = "https://github.com/vulnerability-lookup/VulnTrain"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
vulntrain-create-dataset = "vulntrain.create_dataset:main"
|
|
28
|
+
# vulntrain-train-dataset = "vulntrain.train:main"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
[tool.poetry]
|
|
32
|
+
requires-poetry = ">=2.0"
|
|
33
|
+
classifiers = [
|
|
34
|
+
"Development Status :: 5 - Production/Stable",
|
|
35
|
+
"Environment :: Console",
|
|
36
|
+
"Intended Audience :: Developers",
|
|
37
|
+
"Intended Audience :: Science/Research",
|
|
38
|
+
"Topic :: Security",
|
|
39
|
+
"Operating System :: POSIX :: Linux",
|
|
40
|
+
"Programming Language :: Python :: 3.10",
|
|
41
|
+
"Programming Language :: Python :: 3.11",
|
|
42
|
+
"Programming Language :: Python :: 3.12",
|
|
43
|
+
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)"
|
|
44
|
+
]
|
|
45
|
+
include = [
|
|
46
|
+
"README.md",
|
|
47
|
+
"COPYING",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[tool.poetry.dependencies]
|
|
51
|
+
nltk = "^3.9.1"
|
|
52
|
+
pandas = "^2.2.3"
|
|
53
|
+
datasets = "^3.3.1"
|
|
54
|
+
valkey = "^6.1.0"
|
|
File without changes
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Creates a text/description dataset using vulnerabilities description from Vulnerability-Lookup.
|
|
3
|
+
|
|
4
|
+
Author: Cédric Bonhomme / CIRCL
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
import json
|
|
8
|
+
from typing import Any, Generator
|
|
9
|
+
|
|
10
|
+
import valkey
|
|
11
|
+
from datasets import Dataset, DatasetDict
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class VulnExtractor:
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.valkey_client = valkey.Valkey(
|
|
17
|
+
host="127.0.0.1",
|
|
18
|
+
port=10002,
|
|
19
|
+
decode_responses=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_vulnerability_meta(self, vulnerability_id: str) -> dict[str, str | dict[str, Any]]:
|
|
24
|
+
_vid = vulnerability_id.lower()
|
|
25
|
+
to_return: dict[str, str | dict[str, Any]] = {}
|
|
26
|
+
for meta_name, meta_uuid in self.valkey_client.hgetall(f'{_vid}:meta').items():
|
|
27
|
+
if self.valkey_client.exists(f'{meta_name}:{meta_uuid}'):
|
|
28
|
+
if self.valkey_client.type(f'{meta_name}:{meta_uuid}') == 'string': # type: ignore[no-untyped-call] # noqa
|
|
29
|
+
if _meta_str := self.valkey_client.get(f'{meta_name}:{meta_uuid}'):
|
|
30
|
+
to_return[meta_name] = _meta_str
|
|
31
|
+
elif self.valkey_client.type(f'{meta_name}:{meta_uuid}') == 'hash': # type: ignore[no-untyped-call] # noqa
|
|
32
|
+
if _meta_hash := self.valkey_client.hgetall(f'{meta_name}:{meta_uuid}'):
|
|
33
|
+
to_return[meta_name] = _meta_hash
|
|
34
|
+
else:
|
|
35
|
+
print(f'Unable to find meta {meta_uuid} for {meta_name}')
|
|
36
|
+
return to_return
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_vulnerability(self, vulnerability_id: str,
|
|
40
|
+
*, with_meta: bool | None=False) -> dict[str, Any] | None:
|
|
41
|
+
_vid = vulnerability_id.lower()
|
|
42
|
+
_vuln = self.valkey_client.get(_vid)
|
|
43
|
+
if not _vuln:
|
|
44
|
+
return None
|
|
45
|
+
vuln = json.loads(_vuln)
|
|
46
|
+
if with_meta:
|
|
47
|
+
if meta := self.get_vulnerability_meta(_vid):
|
|
48
|
+
vuln['vulnerability-lookup:meta'] = meta
|
|
49
|
+
return vuln
|
|
50
|
+
|
|
51
|
+
def get_all(self, source: str = "", /, with_meta: bool=False) -> Generator[dict[str, Any], None, None]:
|
|
52
|
+
"""This method will scan a complete source and yield the vulnerabilities.
|
|
53
|
+
It is up to the caller to handle the yielded entries as it will be a lot"""
|
|
54
|
+
if source:
|
|
55
|
+
key = f'index:{source}'
|
|
56
|
+
else:
|
|
57
|
+
key = 'index'
|
|
58
|
+
for vuln_id, _ in self.valkey_client.zscan_iter(key):
|
|
59
|
+
if vuln := self.get_vulnerability(vuln_id, with_meta=with_meta):
|
|
60
|
+
yield vuln
|
|
61
|
+
|
|
62
|
+
def __call__(self):
|
|
63
|
+
count = 0
|
|
64
|
+
for vuln in self.get_all("nvd", True):
|
|
65
|
+
count += 1
|
|
66
|
+
if count == 10000:
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
vuln_cpes = []
|
|
70
|
+
if vulnrichment := vuln["vulnerability-lookup:meta"].get("vulnrichment", False):
|
|
71
|
+
containers = json.loads(vulnrichment["containers"])
|
|
72
|
+
|
|
73
|
+
# Check ADP section
|
|
74
|
+
if "adp" in containers:
|
|
75
|
+
for entry in containers["adp"]:
|
|
76
|
+
if "affected" in entry:
|
|
77
|
+
for affected in entry["affected"]:
|
|
78
|
+
if "cpes" in affected:
|
|
79
|
+
vuln_cpes.extend(affected["cpes"])
|
|
80
|
+
|
|
81
|
+
# Check CNA section
|
|
82
|
+
if "cna" in containers and "affected" in containers["cna"]:
|
|
83
|
+
for affected in containers["cna"]["affected"]:
|
|
84
|
+
if "cpes" in affected:
|
|
85
|
+
vuln_cpes.extend(affected["cpes"])
|
|
86
|
+
|
|
87
|
+
# for elem in vulnrichment["containers"]["adp"]["affected"]:
|
|
88
|
+
# if "cpes" in elem:
|
|
89
|
+
# print(elem)
|
|
90
|
+
# vuln_cpes = elem["cpes"]
|
|
91
|
+
# break
|
|
92
|
+
# else:
|
|
93
|
+
# vuln_cpes = []
|
|
94
|
+
|
|
95
|
+
vuln_id = vuln["cveMetadata"]["cveId"]
|
|
96
|
+
|
|
97
|
+
vuln_title = vuln["containers"]["cna"].get("title", "")
|
|
98
|
+
|
|
99
|
+
for description in vuln["containers"]["cna"].get("descriptions", []):
|
|
100
|
+
if description["lang"].lower() in ["en", "en-sn", "en-us"]:
|
|
101
|
+
vuln_description = description["value"]
|
|
102
|
+
break
|
|
103
|
+
else:
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
# if not vuln_cpes:
|
|
107
|
+
# for elem in vuln["containers"]["cna"]["affected"]:
|
|
108
|
+
# if "cpes" in elem:
|
|
109
|
+
# vuln_cpes = elem["cpes"]
|
|
110
|
+
# break
|
|
111
|
+
# else:
|
|
112
|
+
# vuln_cpes = []
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# print(vuln_cpes)
|
|
117
|
+
|
|
118
|
+
vuln_data = {
|
|
119
|
+
"id": vuln_id,
|
|
120
|
+
"title": vuln_title,
|
|
121
|
+
"description": vuln_description,
|
|
122
|
+
"cpes": vuln_cpes,
|
|
123
|
+
}
|
|
124
|
+
yield vuln_data
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def main():
|
|
131
|
+
extractor = VulnExtractor()
|
|
132
|
+
|
|
133
|
+
vulns = list(extractor())
|
|
134
|
+
|
|
135
|
+
def gen():
|
|
136
|
+
for vuln in vulns:
|
|
137
|
+
yield vuln
|
|
138
|
+
|
|
139
|
+
dataset = Dataset.from_generator(gen)
|
|
140
|
+
train_test_split = dataset.train_test_split(test_size=0.1)
|
|
141
|
+
dataset_dict = DatasetDict(
|
|
142
|
+
{"train": train_test_split["train"], "test": train_test_split["test"]}
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
print(dataset_dict)
|
|
146
|
+
# dataset_dict.push_to_hub("cedricbonhomme/vulnerability-descriptions")
|
|
147
|
+
dataset_dict.push_to_hub("circl/vulnerability-dataset")
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
if __name__ == "__main__":
|
|
151
|
+
main()
|