Skip to content

Added --impersonate flag on mssql protocol#1067

Open
T1erno wants to merge 1 commit intoPennyw0rth:mainfrom
T1erno:mssql-impersonate
Open

Added --impersonate flag on mssql protocol#1067
T1erno wants to merge 1 commit intoPennyw0rth:mainfrom
T1erno:mssql-impersonate

Conversation

@T1erno
Copy link
Contributor

@T1erno T1erno commented Jan 9, 2026

Description

The --impersonate flag has been introduced in the MSSQL protocol, adding a first-level protocol-level way to set EXECUTE AS before executing any command arguments or modules
The mssql_priv module is not included in the impersonation flow; this recovers direct impersonation so that users can execute queries/modules with another login/user without additional module modifications

A module-only approach would be limited to module execution, and arbitrary arguments cannot be combined with modules. A protocol-level flag is applied universally and consistently across all CLI actions and modules, without the need to change each module or overload its options

This might be better than modifying the actual modules, which would only affect the internal logic of that module and still not change the session context for other actions. --impersonate sets the session context once, so all subsequent operations are executed under the intended login/user, in a more predictable and reusable way

As you can see in the image, the modules and queries are executed in the context of the impersonated user

Type of change

Insert an "x" inside the brackets for relevant items (do not delete options)

  • 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)

Screenshots (if appropriate):

imagen

Checklist:

Insert an "x" inside the brackets for completed and relevant items (do not delete options)

  • I have ran Ruff against my changes (via poetry: poetry run python -m ruff check . --preview, 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)
  • New and existing e2e tests pass locally with my changes
  • 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 performed a self-review of my own code
  • 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)

@mpgn
Copy link
Collaborator

mpgn commented Jan 10, 2026

ok for me ✅

@NeffIsBack
Copy link
Member

NeffIsBack commented Jan 11, 2026

ok for me ✅

Sounds good, from my side as well. However the argument/module calling is done in the connection.py and should not be reimplemented here.

Thanks for the PR!

@Marshall-Hallenbeck
Copy link
Collaborator

Marshall-Hallenbeck commented Feb 5, 2026

@T1erno please add this new flag to the e2e tests

Copy link
Member

@NeffIsBack NeffIsBack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really cool technique :)

One thought: Do we want to continue execution even if impersonation fails? My intuition would be no (and I think that is also the way it is currently implemented?), but let's discuss it. If we don't, we should just exit().

Comment on lines +160 to +174
def call_cmd_args(self):
if getattr(self.args, "impersonate", None) and not self.impersonation_applied and not self.impersonate():
return
for attr, value in vars(self.args).items():
if attr == "impersonate":
continue
if hasattr(self, attr) and callable(getattr(self, attr)) and value is not False and value is not None:
self.logger.debug(f"Calling {attr}()")
getattr(self, attr)()

def call_modules(self):
if getattr(self.args, "impersonate", None) and not self.impersonation_applied and not self.impersonate():
return
super().call_modules()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please modify the logic in connection.py, so that args are called regardless of modules being specified and before these are executed.

Comment on lines +296 to +298
if not target:
self.logger.error("No impersonation target specified")
return False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That can be enforced via argparse with nargs=1

Comment on lines +301 to +302
raw_target = str(target)
lowered = raw_target.lower()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argparse will always return strings (type=str), so no need to manually cast it. Besides, please do all the string manipulation in one line, e.g. target =args.impersonate.lower()

Comment on lines +323 to +325
if self.args.debug:
res = self.conn.sql_query("SELECT SYSTEM_USER, SUSER_SNAME();")
self.logger.debug(f"Impersonated context: {res}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just always execute this logic. Debug logs will be filtered anyway if the arg is not specified

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.

4 participants