Home page logo

nmap-dev logo Nmap Development mailing list archives

Re: [NSE] Several changes to mssql.lua and SQL Server scripts
From: Patrik Karlsson <patrik () cqure net>
Date: Fri, 11 Feb 2011 08:05:14 +0100

On Feb 11, 2011, at 07:51 , Chris Woodbury wrote:

I have a significant set of changes to the NSE's SQL Server
functionality that I would like to propose. I started out with some
small-ish changes to the ms-sql-info script to improve the version
detection, but that turned into a bigger project.

When I sent in my initial changes to ms-sql-info, Patrik pointed out
that one of the nice "features" of the existing script (which I had
callously removed) was that, in the course of discovering SQL Server
instances and detecting their versions, it would also check to see if
there was a blank password for the "sa" account. Although this
functionality was already available in the ms-sql-empty-password
script, getting it to run against all of the discovered instances is a
cumbersome process wherein you must run an Nmap scan with ms-sql-info
to discover instances, then parse out all of the random ports their
listening on, and then run another Nmap scan with
ms-sql-empty-password against all of those ports on all of the hosts,
waiting for Nmap to properly identify them as SQL Servers. These
hindrances are also in place if you wish to run any of the other very
useful ms-sql-* scripts against instances running on non-standard
ports (as is the norm with SQL Server).

My proposed solution is to perform the two-step process within a
single scan, I accomplish this with a new ms-sql-discover script,
which discovers instances and stores their information in the Nmap
registry, where they can be accessed by the other ms-sql-* scripts. In
order to get around the problem of running scripts against ports that
may not have been in the Nmap scan, the scripts run as host-scripts
against all of the host's instances at once (they can also run as
port-scripts in the traditional manner).

I think that this is the most significant change, but the following
bullets sum everything up:
- Created stand-alone ms-sql-discover script, which discovers SQL
Server instances using the SQL Server Browser (1434/udp), the default
SQL Server port (1433/tcp) and default named pipe names (if SMB is
- Updated ms-sql-* scripts to also function as hostscripts, using
discovered SQL Server instances from ms-sql-discover.
- Added support for communicating with SQL Server via Windows named
pipes. (Note that this depends on the namedpipe.lua library and patch
to smb.lua in http://seclists.org/nmap-dev/2011/q1/501)
- Updated ms-sql-info to use a safer (no login attempt), more accurate
and more reliable method of version detection. The script's output has
also been expanded to break out the product, service pack level and
patch status of the target.
- Updated ms-sql-brute and ms-sql-empty-password to store valid
credentials on a per-instance basis, instead of globally. Updated
other ms-sql-* scripts to use these credentials.
- Updated ms-sql-brute to recognize different login error codes and to
stop brute-forcing an instance if an account is locked out.
- Moved handling of mssql.username and mssql.password into mssql.lua
- Factored some common code into mssql.lua
- mssql.lua changes:
* Added SSRP class for communicating with SQL Server Browser service (1434/udp)
* Implemented TDS PreLogin packet, ReturnStatus token, login error codes
* Implemented TDS token type 0x79 (ReturnStatus - returned by EXEC
calls). This was causing some existing scripts to not recognize that
they were getting results.
* Expanded handling of login errors to also recognize locked-out
accounts and expired passwords
* Added SqlServerInstanceInfo and SqlServerVersionInfo classes to
handle that data in a unified and easier manner.
* Added Helper.GetDiscoveredInstances() and
Helper.AddOrMergeInstance() to interact with the discovered instances.
* Removed Util.DecodeBrowserVersion. This is now handled in
ms-sql-info, and the results are persisted in nmap.registry.instances[
IP ][ # ].version, which is a SqlServerVersionInfo object.

Wow! This is some *really* impressive work! 

That said, I'm attaching the whole scripts instead of patches, since I
think diff makes it harder to understand these changes. This is
particularly the case in the ms-sql-* scripts, where I grafted the
pre-discovery/hostscript functionality onto the existing logic. The
original functionality is essentially the same, although it may not
appear that way at first glance (one change I made frequently was to
replace short-circuit returns with a way to log the error and move on
with processing the rest of the instances). I also made changes
throughout mssql.TDSStream in order to accomodate named pipes.

I have tested these fairly thoroughly on my own environment, but I
would love it if other people could test this out and let me know if
there are any problems or any comments people have. Additionally,
since this is probably quite a bit to digest at once, I'd be happy to
have some dialogue on why I made certain changes and whatnot. Or why I
introduced bugs into previously good code ;).

I'll look into it during the next few days and will be able to do some testing.

And, lastly, I should say that most of any credit should go to Patrik,
who developed these scripts and the mssql library in the first place!

Thanks, but these additions bring the scripts and library to another dimension :)

Sent through the nmap-dev mailing list
Archived at http://seclists.org/nmap-dev/

Patrik Karlsson

Sent through the nmap-dev mailing list
Archived at http://seclists.org/nmap-dev/

  By Date           By Thread  

Current thread:
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]