NetExec icon indicating copy to clipboard operation
NetExec copied to clipboard

SQL Browser detection for MSSQL protocol

Open mrsheepsheep opened this issue 6 months ago • 13 comments

Description

Adds support for SQL Browser detection and automatic fallback to the dynamic SQL server port if only one instance is running.

This slows down the scan a bit but can detect MSSQL servers without a detailed port scan on each

I chose to add SQL Browser detection by default and added a blacklit flag --no-sqlbrowser, but it can easily be changed to --sqlbrowser if it's more appropriate.

When using --port with a non-default port, the fallback will be ignored. When multiple instances are detected, no fallback happens.

We could also remove the port fallback part and simply report it and let the user rerun with --port. Let me know what's best.

Type of change

  • [ ] Bug fix (non-breaking change which fixes an issue)
  • [x] New feature (non-breaking change which adds functionality)
  • [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • [x] This change requires a documentation update
  • [ ] This requires a third party update (such as Impacket, Dploot, lsassy, etc)

Setup guide for the review

OS : Windows Server 2022 with SQL Server Express installed

Expose the SQL server to the network : Open SQL Server Network Configuration > Protocols for INSTANCENAME

  • Click TCP/IP protocol
  • Set Enabled to true and ensure Listen All is set to Yes

Enable the SQL Browser service : Open SQL Server Services

  • Right-click SQL Server Browser > Properties > Service : Start-Mode = Automatic
  • Start the service

Disable the Windows Firewall if you're lazy (SQL Server rules are not added by default, this is for testing purposes only).

Restart the SQL Server service.

Note down the dynamic port used by SQL server :

image

You can now run a set of tests targeted at a single SQL server instance.

To add more instances, run SQL Server 2022 Installation Center, Installation, click New SQL Server Standalone installation or..., select This PC > C: > SQL2022 > Express_ENU and follow instructions. Once the instance is installed, repeat the steps above for the new instance.

Screenshots

Running on a /21 without --no-sqlbrowser (slower)

image

Running on a /21 with --no-sqlbrowser (faster) yields no results

image

The fallback works as expected when running other modules like command execution :

image

--port has priority and works as expected

image

image

Multiple instances setup

image

Checklist:

  • [x] I have ran Ruff against my changes (via poetry: poetry run python -m ruff check . --preview, use --fix to automatically fix what it can)
  • [x] I have added or updated the tests/e2e_commands.txt file if necessary
  • [x] New and existing e2e tests pass locally with my changes
  • All tests related to MSSQL pass, except --rid-brute because test server was not domain-joined
  • [x] If reliant on changes of third party dependencies, such as Impacket, dploot, lsassy, etc, I have linked the relevant PRs in those projects
  • [x] I have performed a self-review of my own code
  • [x] 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)
    • Waiting for approval on the args / automatic fallback before sending PR

mrsheepsheep avatar Jun 11 '25 22:06 mrsheepsheep

Man that is a fantastic update! I wasn't aware of this MSSQL Browser thing!!

Dfte avatar Jun 12 '25 08:06 Dfte

Man that is a fantastic update! I wasn't aware of this MSSQL Browser thing!!

Thanks ! SQL Browser is not enabled by default and requires a bit of setup, and I haven't been able to test it outside of the lab yet to assess the efficiency of scanning an additional UDP port by default.

I usually blind spray mssql for initial access, and I'm sure I missed some instances because I didn't know about the dynamic port until yesterday...

The SQL server can still run on a random port even if the SQL browser is disabled, so it's not a 100% guaranteed hit, but it will certainly improve automatic discovery.

mrsheepsheep avatar Jun 12 '25 09:06 mrsheepsheep

Yeah don't worry about the testing, I'm actually finishing integrating encryption and channel binding on Impacket, and then on NXC, myself so I have got a lab on which I can test your PR as well! Will look ASAP :)

Dfte avatar Jun 12 '25 09:06 Dfte

Very interesting, thanks for the PR! Do you have any resources about that topic that you could share?

NeffIsBack avatar Jun 12 '25 10:06 NeffIsBack

Very interesting, thanks for the PR! Do you have any resources about that topic that you could share?

Not so much, I just learned about it 😅

SQL Browser uses the TDS protocol on UDP 1434 : https://learn.microsoft.com/en-us/sql/relational-databases/security/networking/tds-8?view=sql-server-ver17

So in reality, the protocol is TDS. Yet MS states it uses SQL Server Resolution Protocol (SSRP)... Confusing.

Impacket already implements TDS behind the scenes. I'm unsure if there's more setup required for encrypted connections or if it works out of the box.

Instances can be hidden from SQL Browser, meaning the service can run but not list any instances. There's probably a way to try catch getInstances to detect whether the service actually runs THEN enumerating instances, rather than only relying on the array size. But I don't think that makes a huge operational difference.

MSDOCS for SQL Browser : https://learn.microsoft.com/en-us/sql/tools/configuration-manager/sql-server-browser-service?view=sql-server-ver16

I'll see what I can do to move the detection to enum_host_info !

mrsheepsheep avatar Jun 12 '25 11:06 mrsheepsheep

Oh wait there's something about DAC that we could definitely look into : https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/diagnostic-connection-for-database-administrators?view=sql-server-ver16

It runs on the same 1434 port and potentially gives access to the database even when it's not directly exposed.

I'll try to look into it later today.

mrsheepsheep avatar Jun 12 '25 11:06 mrsheepsheep

It's getting more complicated than I thought !

SQL browser also lists named-pipe SQL instances ! (which is great)

For now I'll only fallback to TCP until I understand how we can fallback to named pipes without breaking other modules.

mrsheepsheep avatar Jun 13 '25 09:06 mrsheepsheep

image

mrsheepsheep avatar Jun 13 '25 09:06 mrsheepsheep

Hey man! I think I missed something in the SQL browser configuration cause I can't seem to have a dynamic port here:

image

Althought I have followed you setup instructions. Is there something else you might have configured ?

Dfte avatar Jun 30 '25 15:06 Dfte

Hey man! I think I missed something in the SQL browser configuration cause I can't seem to have a dynamic port here:

image

Althought I have followed you setup instructions. Is there something else you might have configured ?

Hey ;) Remove the static port value from IPAll and restart the service, that should be enough.

Leaving this here just in case : https://learn.microsoft.com/en-us/sql/tools/configuration-manager/tcp-ip-properties-ip-addresses-tab?view=sql-server-ver17#static-vs-dynamic-ports

mrsheepsheep avatar Jul 02 '25 03:07 mrsheepsheep

I'll be looking into this one that week mate! Sorry for the long delay but I had to implement the CBT thing before ahah!

Dfte avatar Sep 28 '25 16:09 Dfte

There is something I don't get:

image

Which is produced by that code:

# Get number of mssql instance
self.mssql_instances = self.conn.getInstances()
print(self.mssql_instances)

You mentionned there is another way of finding the correct value of instances ?

Dfte avatar Sep 30 '25 12:09 Dfte

There is something I don't get:

image Which is produced by that code:
# Get number of mssql instance
self.mssql_instances = self.conn.getInstances()
print(self.mssql_instances)

You mentionned there is another way of finding the correct value of instances ?

Sorry for the delay, I haven't checked my GitHub inbox in a while.

There's no output when you don't specify any --port, that's expected when the SQL browser service is not detected. The service is not mandatory to use dynamic ports, it's just here to advertise.

Is the SQL browser service actually running ?

mrsheepsheep avatar Oct 12 '25 15:10 mrsheepsheep