Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Samba Advisory #1802

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions vulnerabilities/importers/__init__.py
Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@
from vulnerabilities.pipelines import nvd_importer
from vulnerabilities.pipelines import pypa_importer
from vulnerabilities.pipelines import pysec_importer
from vulnerabilities.pipelines import samba_importer

IMPORTERS_REGISTRY = [
openssl.OpensslImporter,
@@ -78,6 +79,7 @@
nvd_importer.NVDImporterPipeline,
pysec_importer.PyPIImporterPipeline,
alpine_linux_importer.AlpineLinuxImporterPipeline,
samba_importer.SambaImporterPipeline,
]

IMPORTERS_REGISTRY = {
335 changes: 335 additions & 0 deletions vulnerabilities/pipelines/samba_importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# VulnerableCode is a trademark of nexB Inc.
# SPDX-License-Identifier: Apache-2.0
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
# See https://aboutcode.org for more information about nexB OSS projects.
#

import html
import logging
import re
from datetime import datetime
from traceback import format_exc as traceback_format_exc
from typing import Dict
from typing import Iterable
from typing import List
from typing import Optional

import pytz
import requests
from bs4 import BeautifulSoup
from dateutil import parser as dateparser
from packageurl import PackageURL

from vulnerabilities.importer import AdvisoryData
from vulnerabilities.importer import AffectedPackage
from vulnerabilities.importer import Reference
from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipeline
from vulnerabilities.utils import build_description
from vulnerabilities.utils import get_cwe_id


class SambaImporterPipeline(VulnerableCodeBaseImporterPipeline):
pipeline_id = "samba_importer"
spdx_license_expression = "GPL-3.0-only"
license_url = "https://www.samba.org/samba/ms_license.html"
url = "https://www.samba.org/samba/history/security.html"
importer_name = "Samba Importer"

@classmethod
def steps(cls):
return (cls.fetch, cls.collect_and_store_advisories, cls.import_new_advisories)

def fetch(self):
self.log(f"Fetching `{self.url}`")
try:
response = requests.get(self.url)
response.raise_for_status()
self.advisory_data = response.text
self.advisory_details_cache = {}
except requests.exceptions.HTTPError as http_err:
self.log(
f"Failed to fetch Samba security data: {self.url} with error {http_err!r}:\n{traceback_format_exc()}",
level=logging.ERROR,
)
raise

def advisories_count(self):
if not hasattr(self, "advisory_data"):
return 0

soup = BeautifulSoup(self.advisory_data, "html.parser")
security_table = soup.find("table", {"class": "security_table"})
return 0 if not security_table else len(security_table.find_all("tr")) - 1

def collect_advisories(self):
soup = BeautifulSoup(self.advisory_data, "html.parser")
security_table = soup.find("table", {"class": "security_table"})

if not security_table:
self.log("Security table not found in HTML content", level=logging.ERROR)
return

rows = security_table.find_all("tr")[1:]
for row in rows:
try:
advisory = self.parse_advisory_row(row)
if advisory:
yield advisory
except Exception as e:
self.log(
f"Error parsing advisory row: {e!r}:\n{traceback_format_exc()}",
level=logging.ERROR,
)

def get_advisory_details(self, cve_id):
if cve_id in self.advisory_details_cache:
return self.advisory_details_cache[cve_id]

detail_url = f"https://www.samba.org/samba/security/{cve_id}.html"

try:
response = requests.get(detail_url)
response.raise_for_status()

soup = BeautifulSoup(response.text, "html.parser")
pre_tag = soup.find("pre")
if not pre_tag:
self.log(f"No detailed information found for {cve_id}", level=logging.WARNING)
return {}

announcement_text = html.unescape(pre_tag.get_text())
details = parse_announcement_text(announcement_text)
details["url"] = detail_url

self.advisory_details_cache[cve_id] = details
return details
except requests.exceptions.RequestException as e:
self.log(f"Error fetching advisory details for {cve_id}: {e}", level=logging.WARNING)
return {}
except Exception as e:
self.log(f"Error processing advisory details for {cve_id}: {e!r}", level=logging.ERROR)
return {}

def parse_advisory_row(self, row):
cells = row.find_all("td")
if len(cells) != 6:
self.log(
f"Expected 6 cells in security table row, got {len(cells)}", level=logging.WARNING
)
return None

date_issued = cells[0].get_text().strip()
patch_links = []

for link in cells[1].find_all("a"):
href = link.get("href", "")
if href:
if not href.startswith(("http://", "https://")):
href = f"https://www.samba.org{href}"
patch_links.append(href)

issue_desc = cells[2].get_text().strip()
affected_releases = cells[3].get_text().strip()

cve_ids = []
for link in cells[4].find_all("a"):
cve_id = link.get_text().strip()
if re.match(r"CVE-\d{4}-\d{4,}", cve_id):
cve_ids.append(cve_id)

date_published = None
try:
if date_issued:
date_obj = dateparser.parse(date_issued)
if date_obj:
date_published = date_obj.replace(tzinfo=pytz.UTC)
except Exception as e:
self.log(f"Error parsing date {date_issued}: {e!r}", level=logging.WARNING)

fixed_versions = self.extract_versions_from_patch_links(patch_links)
affected_packages = []

if fixed_versions:
base_purl = PackageURL(type="generic", name="samba")
for version in fixed_versions:
affected_packages.append(AffectedPackage(package=base_purl, fixed_version=version))
elif affected_releases and affected_releases != "Please refer to the advisories.":
base_purl = PackageURL(type="generic", name="samba")
version_match = re.search(r"(?:Samba|samba)\s+(\d+\.\d+\.\d+)", affected_releases)

if version_match:
affected_packages.append(
AffectedPackage(
package=base_purl, fixed_version=f"{version_match.group(1)}-fixed"
)
)
else:
affected_packages.append(
AffectedPackage(package=base_purl, fixed_version="unknown")
)

if not cve_ids and issue_desc:
synthetic_id = (
f"SAMBA-VULN-{date_issued.replace(' ', '-') if date_issued else 'UNKNOWN'}"
)
cve_ids.append(synthetic_id)

detailed_summary = issue_desc

for cve_id in cve_ids:
details = self.get_advisory_details(cve_id)
if not details:
continue

if details.get("summary"):
detailed_summary = details["summary"]

if details.get("description"):
detailed_summary = f"{detailed_summary}\n\n{details['description']}"

if details.get("affected_versions"):
versions_details = details.get("affected_versions")
fixed_vers = details.get("fixed_versions", [])

for pkg in self.extract_affected_packages_from_detail(versions_details, fixed_vers):
affected_packages.append(pkg)

if details.get("mitigation"):
detailed_summary = f"{detailed_summary}\n\nMitigation: {details['mitigation']}"

references = []
for link in cells[5].find_all("a"):
announcement_text = link.get_text().strip()
announcement_url = link.get("href")
if announcement_url:
if not announcement_url.startswith(("http://", "https://")):
announcement_url = f"https://www.samba.org{announcement_url}"

reference_id = None
for cve_id in cve_ids:
if cve_id in announcement_url:
reference_id = cve_id
break

if not reference_id:
reference_id = announcement_text

references.append(Reference(url=announcement_url, reference_id=reference_id))

for patch_url in patch_links:
patch_filename = patch_url.split("/")[-1]
references.append(Reference(url=patch_url, reference_id=f"Patch: {patch_filename}"))

return AdvisoryData(
aliases=cve_ids,
summary=build_description(
summary=detailed_summary, description=f"Affected versions: {affected_releases}"
),
references=references,
affected_packages=affected_packages,
date_published=date_published,
url="https://www.samba.org/samba/history/security.html",
)

def extract_affected_packages_from_detail(self, affected_versions, fixed_versions=None):
affected_packages = []
fixed_versions = fixed_versions or []
base_purl = PackageURL(type="generic", name="samba")

if fixed_versions:
for version in fixed_versions:
affected_packages.append(AffectedPackage(package=base_purl, fixed_version=version))
elif affected_versions:
version_match = re.search(r"(?:Samba|samba)\s+(\d+\.\d+\.\d+)", affected_versions)
if version_match:
affected_packages.append(
AffectedPackage(
package=base_purl, fixed_version=f"{version_match.group(1)}-fixed"
)
)
else:
affected_packages.append(
AffectedPackage(package=base_purl, fixed_version="unknown")
)

return affected_packages

def extract_versions_from_patch_links(self, patch_links):
versions = []
for link in patch_links:
match = re.search(r"samba-(\d+\.\d+\.\d+(?:\.\d+)?)", link)
if match:
version = match.group(1)
if version not in versions:
versions.append(version)
return versions


def extract_cwe_ids(issue_desc):
cwe_ids = []
for cwe_match in re.findall(r"CWE-(\d+)", issue_desc):
try:
cwe_ids.append(int(cwe_match))
except ValueError:
pass
return cwe_ids


def parse_announcement_text(text):
result = {
"subject": None,
"cve_id": None,
"affected_versions": None,
"summary": None,
"description": None,
"patches": None,
"mitigation": None,
"credits": None,
"fixed_versions": [],
}

cve_match = re.search(r"CVE ID#:\s*(CVE-\d+-\d+)", text, re.IGNORECASE)
if cve_match:
result["cve_id"] = cve_match.group(1)

subject_match = re.search(r"== Subject:\s*(.*?)(?=\n==\nCVE|\n==\n==)", text, re.DOTALL)
if subject_match:
subject = subject_match.group(1).strip()
subject = re.sub(r"\n==\s*", " ", subject)
subject = re.sub(r"\s+", " ", subject)
result["subject"] = subject

versions_match = re.search(r"Versions:\s*(.*?)(?=\n\n|\n==|\n[A-Za-z]+:)", text, re.DOTALL)
if versions_match:
result["affected_versions"] = versions_match.group(1).strip()

summary_match = re.search(r"Summary:\s*(.*?)(?=\n\n|\n==|\n[A-Za-z]+:)", text, re.DOTALL)
if summary_match:
summary = summary_match.group(1).strip()
summary = re.sub(r"\n==\s*", " ", summary)
summary = re.sub(r"\s*==\s*", " ", summary)
result["summary"] = summary

sections = re.split(r"={2,}\n([A-Za-z ]+)\n={2,}", text)[1:]

for i in range(0, len(sections), 2):
if i + 1 < len(sections):
section_name = sections[i].strip().lower()
section_content = sections[i + 1].strip()

if section_name == "description":
result["description"] = section_content
elif section_name == "patch availability":
result["patches"] = section_content
fixed_versions = re.findall(r"Samba\s+(\d+\.\d+\.\d+(?:\.\d+)?)", section_content)
if fixed_versions:
result["fixed_versions"] = fixed_versions
elif section_name == "workaround and mitigating factors":
result["mitigation"] = section_content
elif section_name == "credits":
result["credits"] = section_content

return result
206 changes: 206 additions & 0 deletions vulnerabilities/tests/pipelines/test_samba_importer_pipeline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# VulnerableCode is a trademark of nexB Inc.
# SPDX-License-Identifier: Apache-2.0
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
# See https://aboutcode.org for more information about nexB OSS projects.
#

import os
from pathlib import Path
from unittest import mock

import pytest
from bs4 import BeautifulSoup
from packageurl import PackageURL

from vulnerabilities.importer import AdvisoryData
from vulnerabilities.importer import AffectedPackage
from vulnerabilities.importer import Reference
from vulnerabilities.pipelines.samba_importer import SambaImporterPipeline
from vulnerabilities.pipelines.samba_importer import parse_announcement_text
from vulnerabilities.tests import util_tests

TEST_DATA = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "test_data", "samba"
)


def test_parse_announcement_text():
with open(os.path.join(TEST_DATA, "CVE-2023-4154.html.txt")) as f:
announcement_text = f.read()

result = parse_announcement_text(announcement_text)

assert result["cve_id"] is not None
assert "CVE-2023-4154" in result["cve_id"]
assert result["subject"] is not None and "password exposure" in result["subject"].lower()
assert (
result["affected_versions"] is not None and "samba" in result["affected_versions"].lower()
)


def test_extract_versions_from_patch_links():
importer = SambaImporterPipeline()

patch_links = [
"https://www.samba.org/samba/ftp/patches/security/samba-4.19.1-security-2023-10-10.patch",
"https://www.samba.org/samba/ftp/patches/security/samba-4.18.8-security-2023-10-10.patch",
"https://www.samba.org/samba/ftp/patches/security/samba-4.17.12-security-2023-10-10.patch",
]

extracted_versions = importer.extract_versions_from_patch_links(patch_links)

assert len(extracted_versions) == 3
assert all(isinstance(v, str) for v in extracted_versions)
assert all(v.count(".") >= 2 for v in extracted_versions)


def test_extract_affected_packages_from_detail():
importer = SambaImporterPipeline()
importer.log = lambda msg, level=None: None

fixed_versions = ["4.19.1", "4.18.8", "4.17.12"]
affected_versions = "All versions since Samba 4.0.0"

packages = importer.extract_affected_packages_from_detail(affected_versions, fixed_versions)

assert len(packages) == 3
assert all(pkg.package.type == "generic" and pkg.package.name == "samba" for pkg in packages)
assert all(pkg.fixed_version in fixed_versions for pkg in packages)

packages = importer.extract_affected_packages_from_detail("Samba 4.0.0", [])

assert len(packages) == 1
assert packages[0].package.type == "generic"
assert packages[0].package.name == "samba"


@mock.patch("requests.get")
def test_get_advisory_details(mock_get):
mock_response = mock.Mock()
mock_response.raise_for_status.return_value = None

with open(os.path.join(TEST_DATA, "CVE-2023-4154.html")) as f:
mock_response.text = f.read()

mock_get.return_value = mock_response

importer = SambaImporterPipeline()
importer.log = lambda msg, level=None: None
importer.advisory_details_cache = {}

details = importer.get_advisory_details("CVE-2023-4154")

assert "cve_id" in details
assert "CVE-2023-4154" in details["cve_id"]
assert "subject" in details
assert "affected_versions" in details
assert "url" in details

mock_get.reset_mock()
importer.get_advisory_details("CVE-2023-4154")
mock_get.assert_not_called()


@mock.patch("requests.get")
def test_parse_advisory_row(mock_get):
mock_response = mock.Mock()
mock_response.raise_for_status.return_value = None

with open(os.path.join(TEST_DATA, "CVE-2023-4154.html")) as f:
mock_response.text = f.read()

mock_get.return_value = mock_response

row_html = """
<tr>
<td>October 10, 2023</td>
<td>
<a href="/samba/ftp/patches/security/samba-4.19.1-security-2023-10-10.patch">4.19.1</a>
<a href="/samba/ftp/patches/security/samba-4.18.8-security-2023-10-10.patch">4.18.8</a>
<a href="/samba/ftp/patches/security/samba-4.17.12-security-2023-10-10.patch">4.17.12</a>
</td>
<td>Password exposure to privileged users and RODCs</td>
<td>All versions since Samba 4.0.0</td>
<td><a href="/samba/security/CVE-2023-4154.html">CVE-2023-4154</a></td>
<td><a href="/samba/security/CVE-2023-4154.html">Announcement</a></td>
</tr>
"""

soup = BeautifulSoup(row_html, "html.parser")
row = soup.find("tr")

importer = SambaImporterPipeline()
importer.log = lambda msg, level=None: None
importer.advisory_details_cache = {}

advisory = importer.parse_advisory_row(row)

assert advisory is not None
assert "CVE-2023-4154" in advisory.aliases
assert len(advisory.affected_packages) > 0
assert len(advisory.references) >= 3
assert any(ref.reference_id == "CVE-2023-4154" for ref in advisory.references)
assert any("Patch:" in ref.reference_id for ref in advisory.references)


@mock.patch("requests.get")
def test_fetch(mock_get):
mock_response = mock.Mock()
mock_response.raise_for_status.return_value = None

with open(os.path.join(TEST_DATA, "security_advisories.html")) as f:
mock_response.text = f.read()

mock_get.return_value = mock_response

importer = SambaImporterPipeline()
importer.log = lambda msg, level=None: None

importer.fetch()

mock_get.assert_called_once_with("https://www.samba.org/samba/history/security.html")
assert hasattr(importer, "advisory_data")
assert hasattr(importer, "advisory_details_cache")


class MockResponse:
def __init__(self, text, url):
self.text = text
self.url = url

def raise_for_status(self):
return None


@mock.patch("requests.get")
def test_full_pipeline_execution(mock_get):
def mock_get_response(url):
if url == "https://www.samba.org/samba/history/security.html":
with open(os.path.join(TEST_DATA, "security_advisories.html")) as f:
return MockResponse(f.read(), url)
elif "CVE-2023-4154" in url:
with open(os.path.join(TEST_DATA, "CVE-2023-4154.html")) as f:
return MockResponse(f.read(), url)
else:
with open(os.path.join(TEST_DATA, "CVE-2023-4154.html")) as f:
return MockResponse(f.read(), url)

mock_get.side_effect = mock_get_response

importer = SambaImporterPipeline()
importer.log = lambda msg, level=None: None

importer.fetch()

count = importer.advisories_count()
assert count > 0

advisories = list(importer.collect_advisories())
assert len(advisories) > 0

assert all(len(advisory.aliases) > 0 for advisory in advisories)
assert all(advisory.affected_packages for advisory in advisories)
assert all(advisory.references for advisory in advisories)
122 changes: 122 additions & 0 deletions vulnerabilities/tests/test_data/samba/CVE-2023-4154.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<title>Samba - Security Announcement Archive</title>
</head>

<body>

<H2>CVE-2023-4154.html:</H2>

<p>
<pre>
===========================================================
== Subject: Samba AD DC password exposure to privileged
== users and RODCs
==
== CVE ID#: CVE-2023-4154
==
== Versions: All versions since Samba 4.0.0
==
== Summary: An RODC and a user with the GET_CHANGES
== right can view all attributes, including
== secrets and passwords.
==
== Additionally, the access check fails open
== on error conditions.
===========================================================

===========
Description
===========

In normal operation, passwords and (most) secrets are never disclosed
over LDAP in Active Directory.

However, due to a design flaw in Samba&#x27;s implementation of the DirSync
control, Active Directory accounts authorized to do some replication,
but not to replicate sensitive attributes, can instead replicate
critical domain passwords and secrets.

In a default installation, this means that RODC DC accounts (which
should only be permitted to replicate some passwords) can instead
obtain all domain secrets, including the core AD secret: the krbtgt
password.

RODCs are given this permission as part of their installation for DRS
replication. This vulnerability removes the RODC / DC distinction.

Secondly, and just as problematically, the access check for this
functionality did not account for error conditions - errors like
out of memory were regarded as success. This is sometimes described
as &quot;fail open&quot;. In these error conditions, some of which (eg out of
memory) may be influenced by a low-privileged attacker, access to the
secret attributes could be obtained!


==================
Patch Availability
==================

Patches addressing both these issues have been posted to:

https://www.samba.org/samba/security/

Additionally, Samba 4.19.1, 4.18.8 and 4.17.12 have been issued
as security releases to correct the defect. Samba administrators are
advised to upgrade to these releases or apply the patch as soon
as possible.

==================
CVSSv3 calculation
==================

For password disclosure to RODCs and other privileged accounts:
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H (7.2)

For the fail open on the DirSync access check:
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H (7.5)

=================================
Workaround and mitigating factors
=================================

If no RODC accounts are in use in the domain, and DirSync users set
LDAP_DIRSYNC_OBJECT_SECURITY then there is no need to give this right
to any users. If only privileged accounts have this right, only the
error path vulnerability exists.

Since Windows 2003 and in all versions of Samba, it has not been
required to assign accounts this &quot;Get Changes&quot; / GUID_DRS_GET_CHANGES
right to use LDAP DirSync, provided that the
LDAP_DIRSYNC_OBJECT_SECURITY it set in the control.

If any unprivileged accounts do have this right, and either no longer
use DirSync or use LDAP_DIRSYNC_OBJECT_SECURITY, this should be
removed.

GUID_DRS_GET_CHANGES / 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2 is an
extended right set in the ntSecurityDescriptor on the NC root (the DN
at the top of each partition). These are for example the domain DN,
configuration DN etc. The domain DN is the most important.

=======
Credits
=======

Originally reported by Andrew Bartlett of Catalyst and the Samba Team
during routine code review.

Patches provided by Andrew Bartlett of Catalyst and the Samba team.

==========================================================
== Our Code, Our Bugs, Our Responsibility.
== The Samba Team
==========================================================


</pre>
</body>
</html>
103 changes: 103 additions & 0 deletions vulnerabilities/tests/test_data/samba/CVE-2023-4154.html.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
===========================================================
== Subject: Samba AD DC password exposure to privileged
== users and RODCs
==
== CVE ID#: CVE-2023-4154
==
== Versions: All versions since Samba 4.0.0
==
== Summary: An RODC and a user with the GET_CHANGES
== right can view all attributes, including
== secrets and passwords.
==
== Additionally, the access check fails open
== on error conditions.
===========================================================

===========
Description
===========

In normal operation, passwords and (most) secrets are never disclosed
over LDAP in Active Directory.

However, due to a design flaw in Samba's implementation of the DirSync
control, Active Directory accounts authorized to do some replication,
but not to replicate sensitive attributes, can instead replicate
critical domain passwords and secrets.

In a default installation, this means that RODC DC accounts (which
should only be permitted to replicate some passwords) can instead
obtain all domain secrets, including the core AD secret: the krbtgt
password.

RODCs are given this permission as part of their installation for DRS
replication. This vulnerability removes the RODC / DC distinction.

Secondly, and just as problematically, the access check for this
functionality did not account for error conditions - errors like
out of memory were regarded as success. This is sometimes described
as "fail open". In these error conditions, some of which (eg out of
memory) may be influenced by a low-privileged attacker, access to the
secret attributes could be obtained!


==================
Patch Availability
==================

Patches addressing both these issues have been posted to:

https://www.samba.org/samba/security/

Additionally, Samba 4.19.1, 4.18.8 and 4.17.12 have been issued
as security releases to correct the defect. Samba administrators are
advised to upgrade to these releases or apply the patch as soon
as possible.

==================
CVSSv3 calculation
==================

For password disclosure to RODCs and other privileged accounts:
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H (7.2)

For the fail open on the DirSync access check:
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H (7.5)

=================================
Workaround and mitigating factors
=================================

If no RODC accounts are in use in the domain, and DirSync users set
LDAP_DIRSYNC_OBJECT_SECURITY then there is no need to give this right
to any users. If only privileged accounts have this right, only the
error path vulnerability exists.

Since Windows 2003 and in all versions of Samba, it has not been
required to assign accounts this "Get Changes" / GUID_DRS_GET_CHANGES
right to use LDAP DirSync, provided that the
LDAP_DIRSYNC_OBJECT_SECURITY it set in the control.

If any unprivileged accounts do have this right, and either no longer
use DirSync or use LDAP_DIRSYNC_OBJECT_SECURITY, this should be
removed.

GUID_DRS_GET_CHANGES / 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2 is an
extended right set in the ntSecurityDescriptor on the NC root (the DN
at the top of each partition). These are for example the domain DN,
configuration DN etc. The domain DN is the most important.

=======
Credits
=======

Originally reported by Andrew Bartlett of Catalyst and the Samba Team
during routine code review.

Patches provided by Andrew Bartlett of Catalyst and the Samba team.

==========================================================
== Our Code, Our Bugs, Our Responsibility.
== The Samba Team
==========================================================
53 changes: 53 additions & 0 deletions vulnerabilities/tests/test_data/samba/security_advisories.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<title>Samba - Security Announcement Archive</title>
</head>

<body>

<table class="security_table">
<tr>
<th>Date issued</th>
<th>Patch links</th>
<th>Issue description</th>
<th>Affected releases</th>
<th>CVE ID</th>
<th>Announcement</th>
</tr>
<tr>
<td>October 10, 2023</td>
<td>
<a href="/samba/ftp/patches/security/samba-4.19.1-security-2023-10-10.patch">4.19.1</a>
<a href="/samba/ftp/patches/security/samba-4.18.8-security-2023-10-10.patch">4.18.8</a>
<a href="/samba/ftp/patches/security/samba-4.17.12-security-2023-10-10.patch">4.17.12</a>
</td>
<td>Password exposure to privileged users and RODCs</td>
<td>All versions since Samba 4.0.0</td>
<td><a href="/samba/security/CVE-2023-4154.html">CVE-2023-4154</a></td>
<td><a href="/samba/security/CVE-2023-4154.html">Announcement</a></td>
</tr>
<tr>
<td>August 8, 2023</td>
<td>
<a href="/samba/ftp/patches/security/samba-4.19.0-security-2023-08-08.patch">4.19.0</a>
<a href="/samba/ftp/patches/security/samba-4.18.6-security-2023-08-08.patch">4.18.6</a>
<a href="/samba/ftp/patches/security/samba-4.17.10-security-2023-08-08.patch">4.17.10</a>
</td>
<td>Multiple security flaws in Samba Active Directory</td>
<td>All versions of Samba prior to 4.17.10, 4.18.6, and 4.19.0</td>
<td>
<a href="/samba/security/CVE-2023-3961.html">CVE-2023-3961</a>
<a href="/samba/security/CVE-2023-3962.html">CVE-2023-3962</a>
</td>
<td>
<a href="/samba/security/CVE-2023-3961.html">Announcement</a>
<a href="/samba/security/CVE-2023-3962.html">Announcement</a>
</td>
</tr>
</table>

</body>
</html>