The need for this tool raised a day when I was debugging a login procedure from
a web site I was developing.
A SQL Profiler was monitoring queries on a SQL Server 2000 with SP 4 installed,
and, when I tried to login to the web site I saw a strange message instead of my
original
Stored Procedure call.
So I started googling trying to find a way to remove security check and continue
my work. I was unable to find a solution to my problem, even if it seems many developers
are in my same situation. So I decided I had to figure out how that was implemented
and eventually try to remove limitation.
In the meantime I was forced to change my stored procedure parameter name from "password"
to "pwd" to been able to debug it.
In a few hours of binary seeking among SQL Server files I was able to find a good
place where a list of words seems to be hidden.
Figuring out this was a bit hard, cause "password" is a so common string inside
all those DLL and EXE.
Anyway, at last I found all "reserved" words (or should I say blacklisted ones)
deep inside
sqlservr.exe (which is SQL Server main executable). They are
encryption, sp_setapprole and
password.
This means when you use one of them (not necessarily as a standalone word) in a
SQL script, you are unable to see them using a SQL Profiler.
For example if you try this query (even if this is not working on current database)
on a SQL Query Analyzer:
select EncryptedPassword from Users
monitoring it, you get this message in SQL Profiler
-- 'password' was found in the text of this event.
-- The text has been replaced with this comment for security reasons.
Previous message will be in your SQL Server installation language cause it's contained
in
pfclnt80.rll resources-DLL in localized strings.
The hard part is done, if you know the basics of executable patching: you know strings
and you have to remove them.
This is done putting a "00" byte on their first char.
Cause those strings are ASCIIZ (strings with zero termination byte), you simply
say they are zero-lenght.
My next step was to code a tool to do same steps in an automatic way:
- Find if SQL Server 2000 is installed and if upgraded to SP 4
- Locate main executable file ("sqlservr.exe")
- Check to see if SQL Server service is running and eventually stop it (and related
services like SQL Server Agent)
- Load executable file in memory, using memory-mapped files
- Seek for byte patterns and patch it if found
- Restore service situation previous to patching
Memory-mapped files operation is my preferred approach in this case.
MMF Win32 APIs are well documented in many books, even if I prefer
Jeffrey Richter
"Advanced Windows" one.
Using them from C# and .Net in general is easily done with the excellent work by
René Grob ("argee"). You can find his library on GotDotNet:
Managed wrapper classes for memory mapped
files and unmanaged memory access.
This approach allows us to seek byte patterns in memory like a big array.
This lead to the fact the byte pattern is the same one on every SQL Server culture
(I tried it successfully on English and Italian localization), even if patching
offset is different in each file.
Other interesting stuff inside here is about retrieving SQL Server installation
path and version from Registry. Only SP4 SQL Servers can be patched, so, we must
be sure we have something to do.
Stopping and restarting windows services related to SQL Server is done using
ServiceController
class.
Sometimes, on very large servers, stopping SQL Server service can take a real long
time. In that case, stop it manually and apply patch, or you would get file locked
problems.
I would not support using this tool or patching critical SQL Server instances in
production environments.
I tried and used this tool on many SQL Server instances I have access to, never
finding problems about it. Anyway, using it is at your own risk.
Every problem should be easily solved simply stopping SQL Server and restoring previously
backupped executable.
Keep in mind executable signature is changing applying this patch, so an antivirus
or similar software monitoring files CRC can badly react to it.
I believe this behavior introduced with Service Pack 4 by Microsoft is a good security
idea (even the fact it cannot be disabled in any way).
It is implemented on server side, not on client side, so password and critical data
would not travel unencrypted around the network.
This is definitely a valid idea in my opinion.