Skip to content

Replace mssql_cbt with mssql_epa for full Extended Protection enforcement check#1209

Open
NoahDSJP wants to merge 2 commits into
Pennyw0rth:mainfrom
NoahDSJP:merge-mssql-cbt-into-mssql-epa
Open

Replace mssql_cbt with mssql_epa for full Extended Protection enforcement check#1209
NoahDSJP wants to merge 2 commits into
Pennyw0rth:mainfrom
NoahDSJP:merge-mssql-cbt-into-mssql-epa

Conversation

@NoahDSJP
Copy link
Copy Markdown

@NoahDSJP NoahDSJP commented Apr 19, 2026

Description

This PR description and any comments are written by me in Japanese
and translated to English using a translation tool (Google Translation).

This PR is a continuation of #1206.

Following @Dfte's suggestion to merge mssql_cbt and mssql_epa into a single module (and using mssql_epa as the name).

The purpose of this PR is to remove mssql_cbt and add the mssql_epa module, which performs more comprehensive EPA checks.

mssql_cbt only detects whether CBT is required.
mssql_epa is more comprehensive, distinguishing between three EPA enforcement levels (Off/Allowed/Required) and also covering SPN-based paths that apply when mandatory encryption is disabled. This cannot be checked with mssql_cbt.

mssql_epa functionality:

  • If Force Encryption is set to On, it tests the EPA setting by sending a fake Channel Binding Token (CBT) and empty CBT.
  • If Force Encryption is set to Off, it tests the EPA setting by sending a fake SPN and an empty SPN.

Detect EPA enforcement:

  • Off — server does not validate CBT/SPN (NTLM relay possible)
  • Allowed — validated only when client provides CBT/SPN (partial protection)
  • Required — server enforces CBT/SPN (NTLM relay blocked)

The tool this module is based on:
https://github.com/NoahDSJP/mssql_epa_check

Notes

  • mssql_epa uses NTLM authentication, so it will be skipped if run with --local-auth or Kerberos authentication.
  • Because NetExec's MSSQL protocol invokes modules only after a successful MSSQL login, this module currently requires an account that can log in to MSSQL. However, the underlying technique operates purely at the NTLM authentication layer to verify EPA settings, so EPA can be verified with any domain user's authentication information. In the future, if a mechanism for handling "modules that do not require MSSQL login" is added to the NetExec framework, this limitation can be resolved.

Wiki updates will be submitted separately to https://github.com/Pennyw0rth/NetExec-Wiki

AI Assistance Disclosure

Developed using Claude Code (Anthropic, Opus 4.7).
All code has been manually reviewed and tested by me.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Deprecation of feature or functionality
  • This change requires a documentation update
  • This requires a third party update (such as Impacket, Dploot, lsassy, etc)
  • This PR was created with the assistance of AI (list what type of assistance, tool(s)/model(s) in the description)

Setup guide for the review

  • Client: Linux, Python 3.10+, NetExec from main
  • Target: Windows Server with MSSQL Server, AD-joined
  • Force Encryption/Extended Protection can be toggled in SQL Server Configuration Manager
  • No additional software required, no GPO changes required

Reproduce:

nxc mssql <target> -u <user> -p <password> -d <domain> -M mssql_epa

Expected output (one of):

  • Extended Protection: Off - NTLM relay POSSIBLE (Vulnerable) (red)
  • Extended Protection: Allowed - ... (Partially Vulnerable) (yellow)
  • Extended Protection: Required - CBT enforced, ... (Secure) (green)
  • Extended Protection: Required - SPN enforced, ... (Secure) (green)

Screenshots (if appropriate):

  • Force Encryption : No / Extended Protection : Off
2026-04-20_08h15_39
  • Force Encryption : No / Extended Protection : Allowed
2026-04-20_08h20_43
  • Force Encryption : No / Extended Protection : Required
2026-04-20_08h22_08
  • Force Encryption : Yes / Extended Protection : Off
2026-04-20_08h23_29
  • Force Encryption : Yes / Extended Protection : Allowed
2026-04-20_08h24_33
  • Force Encryption : Yes / Extended Protection : Required
2026-04-20_08h25_45

Checklist:

  • I have ran Ruff against my changes (poetry: poetry run ruff check ., use --fix to automatically fix what it can)
  • I have added or updated the tests/e2e_commands.txt file if necessary (new modules or features are required to be added to the e2e tests)
  • If reliant on changes of third party dependencies, such as Impacket, dploot, lsassy, etc, I have linked the relevant PRs in those projects
  • I have linked relevant sources that describes the added technique (blog posts, documentation, etc)
  • I have performed a self-review of my own code (not an AI review)
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (PR here: https://github.com/Pennyw0rth/NetExec-Wiki)

@NeffIsBack NeffIsBack added the enhancement New feature or request label Apr 20, 2026
@NeffIsBack
Copy link
Copy Markdown
Member

Thanks for the PR!

@Dfte
Copy link
Copy Markdown
Contributor

Dfte commented Apr 29, 2026

Alright thanks for the PR! So here is the thing:

  • You mention that it only works with NTLM althought it should be the same for Kerberos. It cannot work on local auth for obvious reason.
  • You mention it is possible to enumerate these settings without authenticating ? If this is the case then we should remove the module and add these as default checks in the host_enum_function in mssql.py.

Let me know :)

- Add Kerberos auth path using impacket's kerberosLogin with cbt_fake_value
- Force Encryption ON: test CBT (bogus + missing) like NTLM CBT case
- Force Encryption OFF + Kerberos: report N/A (MSSQL does not validate
  Kerberos channel bindings without TLS, and Kerberos has no service-binding
  equivalent of NTLM's MsvAvTargetName)
- Credit @Dfte (mssql_cbt author) in module docstring
@NoahDSJP
Copy link
Copy Markdown
Author

NoahDSJP commented May 2, 2026

@Dfte
I apologize if the English is unclear, as it was translated using Google Translate.

Thank you for your question.
Let me report on the Kerberos support you mentioned in your first question.
I implemented logic to insert an arbitrary value into the cksum["Bnd"] field of the Kerberos AP-REQ. When Force Encryption is On, the EPA level (Off/Allowed/Required) is determined by testing with dummy data and 16 bytes of zeros in cksum["Bnd"]. When Force Encryption is Off and Kerberos authentication is used, the Kerberos CBT cannot be verified without TLS, and since Kerberos authentication does not have a Service Binding equivalent to NTLM authentication's MsvAvTargetName, the EPA cannot be determined, so I have made it output to indicate this.

Regarding the second question, my explanation might have been a little confusing, so let me clarify.

Originally, MSSQL's EPA can be verified with the authentication credentials of any domain user. Without authentication, the EPA cannot be enumerated.
However, login privileges to MSSQL are not required. This is because the EPA check logic is performed at the NTLM/Kerberos layer and is determined before the SQL Server DB login.
However, the current NetExec MSSQL protocol only executes the module after a successful login to MSSQL. As a result, this module (mssql_epa) also requires authentication credentials that allow login to MSSQL. Fixing this issue requires a modification to the NetExec framework, so it is not included in this PR.

For the reasons above, it is difficult to incorporate the EPA check into host_enum_function (enum_host_info), which does not have an authentication flow, and I believe it is appropriate to leave it as a separate module.

Force Encryption : No(Kerberos Authentication)
2026-05-02_09h58_57

Force Encryption : Yes / Extended Protection : Off(Kerberos Authentication)
2026-05-02_10h14_54

Force Encryption : Yes / Extended Protection : Allowed(Kerberos Authentication)
2026-05-02_10h28_48

Force Encryption : Yes / Extended Protection : Required(Kerberos Authentication)
2026-05-02_10h31_36

@NeffIsBack
Copy link
Copy Markdown
Member

Thanks for the detailed explanation and no worries about the english, that is perfectly fine.

Regarding the second paragraph, so this basically means you need to have valid Domain credentials to be able to determine a valid NTLM authentication in combination with the service binding, but it does not need access to the MSSQL service itself right? Then we indeed need valid (domain) credentials and I agree, that should then be a module and not incorporated into the NetExec enumeration part.

@NoahDSJP
Copy link
Copy Markdown
Author

NoahDSJP commented May 2, 2026

Yes, that understanding is completely correct.

To be precise:

  • Valid domain credentials are required (to construct the NTLM/Kerberos authentication message)
  • Access permissions to MSSQL (SQL Login) are not required
  • EPA verification is completed at the NTLM/Kerberos layer and is determined before reaching the SQL Login authorization step

The NetExec module only executes after a successful SQL Login, so the need for SQL Login is a consequence of that; it's not a technical constraint.

Thank you for agreeing to keep this as a module.
I would appreciate it if you could proceed with the review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants