Skip to content

Commit 3664c3e

Browse files
committed
Merge keshav-space:gitlab_datasource branch
Signed-off-by: Philippe Ombredanne <[email protected]>
2 parents edc4047 + 55fc8a8 commit 3664c3e

File tree

10 files changed

+442
-0
lines changed

10 files changed

+442
-0
lines changed

vulntotal/datasources/gitlab.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# http://nexb.com and https://github.com/nexB/vulnerablecode/
4+
# The VulnTotal software is licensed under the Apache License version 2.0.
5+
# Data generated with VulnTotal require an acknowledgment.
6+
#
7+
# You may not use this software except in compliance with the License.
8+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
9+
# Unless required by applicable law or agreed to in writing, software distributed
10+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
# specific language governing permissions and limitations under the License.
13+
#
14+
# When you publish or redistribute any data created with VulnTotal or any VulnTotal
15+
# derivative work, you must accompany this data with the following acknowledgment:
16+
#
17+
# Generated with VulnTotal and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
18+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
19+
# VulnTotal should be considered or used as legal advice. Consult an Attorney
20+
# for any legal advice.
21+
# VulnTotal is a free software tool from nexB Inc. and others.
22+
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
23+
24+
25+
import json
26+
import logging
27+
import os
28+
import shutil
29+
import tarfile
30+
from pathlib import Path
31+
from typing import Iterable
32+
33+
import requests
34+
import saneyaml
35+
from fetchcode import fetch
36+
from packageurl import PackageURL
37+
38+
from vulntotal.validator import DataSource
39+
from vulntotal.validator import VendorData
40+
from vulntotal.vulntotal_utils import gitlab_constraints_satisfied
41+
42+
logger = logging.getLogger(__name__)
43+
44+
45+
class GitlabDataSource(DataSource):
46+
spdx_license_expression = "TODO"
47+
license_url = "TODO"
48+
49+
def datasource_advisory(self, purl) -> Iterable[VendorData]:
50+
package_slug = get_package_slug(purl)
51+
location = download_subtree(package_slug, speculative_execution=True)
52+
if not location:
53+
clear_download(location)
54+
path = self.supported_ecosystem()[purl.type]
55+
casesensitive_package_slug = get_casesensitive_slug(path, package_slug)
56+
location = download_subtree(casesensitive_package_slug)
57+
if location:
58+
interesting_advisories = parse_interesting_advisories(location, purl.version, delete_download=True)
59+
return interesting_advisories
60+
clear_download(location)
61+
62+
@classmethod
63+
def supported_ecosystem(cls):
64+
return {
65+
"composer": "packagist",
66+
"conan": "conan",
67+
"gem": "gem",
68+
"golang": "go",
69+
"maven": "maven",
70+
"npm": "npm",
71+
"nuget": "nuget",
72+
"pypi": "pypi",
73+
}
74+
75+
76+
def get_package_slug(purl):
77+
supported_ecosystem = GitlabDataSource.supported_ecosystem()
78+
79+
if purl.type not in supported_ecosystem:
80+
return
81+
82+
ecosystem = supported_ecosystem[purl.type]
83+
package_name = purl.name
84+
85+
if purl.type in ("maven", "composer", "golang"):
86+
package_name = f"{purl.namespace}/{purl.name}"
87+
88+
return f"{ecosystem}/{package_name}"
89+
90+
91+
def download_subtree(package_slug: str, speculative_execution=False):
92+
url = f"https://gitlab.com/gitlab-org/security-products/gemnasium-db/-/archive/master/gemnasium-db-master.tar.gz?path={package_slug}"
93+
response = fetch(url)
94+
if os.path.getsize(response.location) > 0:
95+
extracted_location = Path(response.location).parent.joinpath(
96+
"temp_vulntotal_gitlab_datasource"
97+
)
98+
with tarfile.open(response.location, "r") as file_obj:
99+
file_obj.extractall(extracted_location)
100+
os.remove(response.location)
101+
return extracted_location
102+
if not speculative_execution:
103+
logger.error(f"{package_slug} doesn't exist")
104+
os.remove(response.location)
105+
106+
107+
def clear_download(location):
108+
if location:
109+
shutil.rmtree(location)
110+
111+
112+
def get_casesensitive_slug(path, package_slug):
113+
payload = [
114+
{
115+
"operationName": "getPaginatedTree",
116+
"variables": {
117+
"projectPath": "gitlab-org/security-products/gemnasium-db",
118+
"ref": "master",
119+
"path": path,
120+
"nextPageCursor": "",
121+
"pageSize": 100,
122+
},
123+
"query": """
124+
fragment TreeEntry on Entry {
125+
flatPath
126+
}
127+
query getPaginatedTree($projectPath: ID!, $path: String, $ref: String!, $nextPageCursor: String) {
128+
project(fullPath: $projectPath) {
129+
repository {
130+
paginatedTree(path: $path, ref: $ref, after: $nextPageCursor) {
131+
pageInfo {
132+
endCursor
133+
startCursor
134+
hasNextPage
135+
}
136+
nodes {
137+
trees {
138+
nodes {
139+
...TreeEntry
140+
}
141+
}
142+
}
143+
}
144+
}
145+
}
146+
} """,
147+
}
148+
]
149+
url = "https://gitlab.com/api/graphql"
150+
hasnext = True
151+
152+
while hasnext:
153+
response = requests.post(url, json=payload).json()
154+
paginated_tree = response[0]["data"]["project"]["repository"]["paginatedTree"]
155+
156+
for slug in paginated_tree["nodes"][0]["trees"]["nodes"]:
157+
if slug["flatPath"].lower() == package_slug.lower():
158+
return slug["flatPath"]
159+
160+
# If the namespace/subfolder contains multiple packages, then progressive transverse through folders tree
161+
if package_slug.lower().startswith(slug["flatPath"].lower()):
162+
return get_gitlab_style_slug(slug["flatPath"], package_slug)
163+
164+
payload[0]["variables"]["nextPageCursor"] = paginated_tree["pageInfo"]["endCursor"]
165+
hasnext = paginated_tree["pageInfo"]["hasNextPage"]
166+
167+
168+
def parse_interesting_advisories(location, version, delete_download=False) -> Iterable[VendorData]:
169+
path = Path(location)
170+
glob = "**/*.yml"
171+
files = (p for p in path.glob(glob) if p.is_file())
172+
for file in sorted(files):
173+
with open(file) as f:
174+
gitlab_advisory = saneyaml.load(f)
175+
if gitlab_constraints_satisfied(gitlab_advisory["affected_range"], version):
176+
yield VendorData(
177+
aliases=gitlab_advisory["identifiers"],
178+
affected_versions=[gitlab_advisory["affected_range"]],
179+
fixed_versions=gitlab_advisory["fixed_versions"],
180+
)
181+
if delete_download:
182+
clear_download(location)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
"pypi/jinja2",
3+
"maven/org.apache.tomcat/tomcat",
4+
"npm/semver-regex",
5+
"go/github.com/mattermost/mattermost-server/v6/api4",
6+
"packagist/bolt/core",
7+
"nuget/moment.js"
8+
]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[
2+
{
3+
"affected_versions": [
4+
"<=2.7.1"
5+
],
6+
"fixed_versions": [
7+
"2.7.2"
8+
],
9+
"aliases": [
10+
"CVE-2014-1402"
11+
]
12+
},
13+
{
14+
"affected_versions": [
15+
"<2.8.1"
16+
],
17+
"fixed_versions": [
18+
"2.8.1"
19+
],
20+
"aliases": [
21+
"GHSA-hj2j-77xm-mc5v",
22+
"CVE-2016-10745"
23+
]
24+
},
25+
{
26+
"affected_versions": [
27+
"<2.10.1"
28+
],
29+
"fixed_versions": [
30+
"2.10.1"
31+
],
32+
"aliases": [
33+
"CVE-2019-10906"
34+
]
35+
},
36+
{
37+
"affected_versions": [
38+
"<2.11.3"
39+
],
40+
"fixed_versions": [
41+
"2.11.3"
42+
],
43+
"aliases": [
44+
"CVE-2020-28493"
45+
]
46+
}
47+
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
pkg:maven/org.apache.tomcat/[email protected]
3+
4+
pkg:golang/github.com/mattermost/mattermost-server/v6/[email protected]
5+
pkg:composer/bolt/[email protected]
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
identifier: "CVE-2014-1402"
3+
package_slug: "pypi/Jinja2"
4+
title: "Incorrect Default Permissions"
5+
description: "The default configuration for `bccache.FileSystemBytecodeCache` in Jinja2
6+
before does not properly create temporary files, which allows local users to gain
7+
privileges via a crafted `.cache` file with a name starting with `__jinja2_` in
8+
`/tmp`."
9+
date: "2017-12-21"
10+
pubdate: "2014-05-19"
11+
affected_range: "<=2.7.1"
12+
fixed_versions:
13+
- "2.7.2"
14+
affected_versions: "All versions up to 2.7.1"
15+
not_impacted: "All versions after 2.7.1"
16+
solution: "Upgrade to version 2.7.2 or above."
17+
urls:
18+
- "https://bugzilla.redhat.com/CVE-2014-1402"
19+
- "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=734747"
20+
- "https://github.com/mitsuhiko/jinja2/commit/acb672b6"
21+
cvss_v2: "AV:L/AC:M/Au:N/C:P/I:P/A:P"
22+
uuid: "73933300-77cd-49dd-8e3d-671763767b99"
23+
cwe_ids:
24+
- "CWE-1035"
25+
- "CWE-264"
26+
- "CWE-937"
27+
identifiers:
28+
- "CVE-2014-1402"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
identifier: "CVE-2016-10745"
3+
identifiers:
4+
- "GHSA-hj2j-77xm-mc5v"
5+
- "CVE-2016-10745"
6+
package_slug: "pypi/Jinja2"
7+
title: "Use of Externally-Controlled Format String"
8+
description: "In Pallets Jinja before 2.8.1, str.format allows a sandbox escape."
9+
date: "2021-09-14"
10+
pubdate: "2019-04-10"
11+
affected_range: "<2.8.1"
12+
fixed_versions:
13+
- "2.8.1"
14+
affected_versions: "All versions before 2.8.1"
15+
not_impacted: "All versions starting from 2.8.1"
16+
solution: "Upgrade to version 2.8.1 or above."
17+
urls:
18+
- "https://nvd.nist.gov/vuln/detail/CVE-2016-10745"
19+
- "https://github.com/pallets/jinja/commit/9b53045c34e61013dc8f09b7e52a555fa16bed16"
20+
- "https://access.redhat.com/errata/RHSA-2019:1022"
21+
- "https://access.redhat.com/errata/RHSA-2019:1237"
22+
- "https://access.redhat.com/errata/RHSA-2019:1260"
23+
- "https://access.redhat.com/errata/RHSA-2019:3964"
24+
- "https://access.redhat.com/errata/RHSA-2019:4062"
25+
- "https://github.com/advisories/GHSA-hj2j-77xm-mc5v"
26+
- "https://palletsprojects.com/blog/jinja-281-released/"
27+
- "https://usn.ubuntu.com/4011-1/"
28+
- "https://usn.ubuntu.com/4011-2/"
29+
- "http://lists.opensuse.org/opensuse-security-announce/2019-05/msg00030.html"
30+
- "http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00064.html"
31+
cvss_v2: "AV:N/AC:L/Au:N/C:P/I:N/A:N"
32+
cvss_v3: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N"
33+
uuid: "db196e91-7fc4-4b94-93b3-e0c0dc01bcbe"
34+
cwe_ids:
35+
- "CWE-1035"
36+
- "CWE-134"
37+
- "CWE-937"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
identifier: "CVE-2019-10906"
3+
package_slug: "pypi/Jinja2"
4+
title: "Sandbox Escape"
5+
description: "In Pallets Jinja, str.format_map allows a sandbox escape."
6+
date: "2019-06-06"
7+
pubdate: "2019-04-06"
8+
affected_range: "<2.10.1"
9+
fixed_versions:
10+
- "2.10.1"
11+
affected_versions: "All versions before 2.10.1"
12+
not_impacted: "All versions starting from 2.10.1"
13+
solution: "Upgrade to version 2.10.1 or above."
14+
urls:
15+
- "https://nvd.nist.gov/vuln/detail/CVE-2019-10906"
16+
- "https://palletsprojects.com/blog/jinja-2-10-1-released"
17+
cvss_v2: "AV:N/AC:L/Au:N/C:P/I:N/A:N"
18+
cvss_v3: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N"
19+
uuid: "b2d59abd-b748-4d93-bb21-55f9e9aecea2"
20+
cwe_ids:
21+
- "CWE-1035"
22+
- "CWE-937"
23+
identifiers:
24+
- "CVE-2019-10906"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
identifier: "CVE-2019-8341"
3+
package_slug: "pypi/Jinja2"
4+
title: "Code Injection"
5+
description: "The `from_string` function is prone to Server Side Template Injection
6+
(SSTI) where it takes the `source` parameter as a template object, renders it, and
7+
then returns it. The attacker can exploit it with `{{INJECTION COMMANDS}}` in a
8+
URI."
9+
date: "2019-08-06"
10+
pubdate: "2019-02-15"
11+
affected_range: "==2.10"
12+
fixed_versions:
13+
- "2.10.1"
14+
affected_versions: "Version 2.10"
15+
not_impacted: "All versions before 2.10, all versions after 2.10"
16+
solution: "Upgrade to version 2.10.1 or above."
17+
urls:
18+
- "https://nvd.nist.gov/vuln/detail/CVE-2019-8341"
19+
- "https://www.exploit-db.com/exploits/46386/"
20+
cvss_v2: "AV:N/AC:L/Au:N/C:P/I:P/A:P"
21+
cvss_v3: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
22+
uuid: "6b00a76b-aac8-4ce1-b7b2-122a73f22985"
23+
cwe_ids:
24+
- "CWE-1035"
25+
- "CWE-937"
26+
- "CWE-94"
27+
identifiers:
28+
- "CVE-2019-8341"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
identifier: "CVE-2020-28493"
3+
package_slug: "pypi/Jinja2"
4+
title: "Regular Expression Denial of Service"
5+
description: "The ReDOS vulnerability of the regex is mainly due to the sub-pattern
6+
`[a-zA-Z0-9._-]+.[a-zA-Z0-9._-]+` This issue can be mitigated by Markdown to format
7+
user content instead of the urlize filter, or by implementing request timeouts and
8+
limiting process memory."
9+
date: "2021-07-21"
10+
pubdate: "2021-02-01"
11+
affected_range: "<2.11.3"
12+
fixed_versions:
13+
- "2.11.3"
14+
affected_versions: "All versions before 2.11.3"
15+
not_impacted: "All versions starting from 2.11.3"
16+
solution: "Upgrade to version 2.11.3 or above."
17+
urls:
18+
- "https://nvd.nist.gov/vuln/detail/CVE-2020-28493"
19+
cvss_v2: "AV:N/AC:L/Au:N/C:N/I:N/A:P"
20+
cvss_v3: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L"
21+
uuid: "17c4602a-c0ae-48d0-96f6-08c84d55d0cb"
22+
cwe_ids:
23+
- "CWE-1035"
24+
- "CWE-937"
25+
identifiers:
26+
- "CVE-2020-28493"

0 commit comments

Comments
 (0)