Covering Tracks

Once an attacker has broken into a SQL Server, his efforts will turn to both ensuring that his intrusion is not detected and to making future attacks easier. The first goal is achieved by deleting access log entries and minimizing obvious changes to data; the second is commonly accomplished by means of subtle changes to the database software and structure that remove security checks, known as backdoors. This section describes techniques used to compromise a SQL Server's security controls and also details detection and defense methods .

Three-Byte Patch

Perhaps the subtlest of SQL Server backdoors is the three-byte patch as described by Chris Anley in his whitepaper "Violating Database-Enforced Security Mechanisms" ( http://www.ngssoftware.com/papers/violating_database_security.pdf ).

This method utilizes an existing attack vector, such as a buffer overflow exploit, to patch the SQL Server process in memory ”an approach known as runtime patching. When patching bytes in memory the Windows SDK function VirtualProtect() must first be called on the region in order to mark it as writable. To determine the bytes to patch, a debugger, such as the one included with Microsoft Visual C++ .NET, is attached to the sqlservr .exe process. After logging on to the SQL Server as a low-privileged user using Microsoft Query Analyzer, a query attempting to access a prohibited table is executed:

 select * from sysxlogins 

By default only members of the dbo database administrators group can view this table, which contains usernames and password hashes for all database users. Running this query causes the SQL Server process to throw a C++ exception in the debugger; after allowing execution to continue the expected message is produced in Query Analyzer:

 SELECT permission denied on object 'sysxlogins', database 'master', owner 'dbo'. 

Logging into the server as the sa user, which does have select permission on the table, and running the query displays the table and does not produce the C++ exception. Clearly the access control mechanism throws an exception when access is denied to a table. A great help when debugging SQL Server is the symbols file (sqlservr.pdb), which is provided by Microsoft in the MSSQL\Binn\exe directory. This provides the original function names to the debugger and allows inference of the general purpose of large chunks of assembler. A case in point here is the function FHasObjPermissions, which after setting breakpoints on all functions containing the word "permission" is executed after the original select query is run. A static disassembly of the main SQL Server binary using DataRescue's excellent IDA Pro ( http://www.datarescue.com/idabase ) can be used to divine the behavior of this function. In this case the function is called from within the CheckPermissions function:

 0087F9C0        call FHasObjPermissions 0087F9C5        add esp, 14h 0087F9C8        test eax, eax 0087F9CA        jnz short loc_87F9DC 0087F9CC        push 17h 0087F9CE        push 19h 0087F9D0        push 2 0087F9D2        push 24h 0087F9D4        call ex_raise 

FHasObjPermissions is called, and after it returns, the stack-pointer (esp) is increased by 0x14 to remove the arguments that were passed to the function. The eax register is then compared with itself using the test operator; the effect of this operation is to set the CPU's zero flag only if eax is zero. So if eax is set to zero by FhasObjPermission, the following jnz (jump if not zero) operator will not cause a jump and execution will continue on to the call to ex_raise. To avoid the exception being raised, the jump to the code that carries out the query should always occur. A quick way to achieve this would be to patch the conditional jump (jnz) to a non-conditional jump (jmp), however this may not bypass further checks; if the code is investigated further a neater patch can be found.

Looking at the code for FHasObjPermissions, an interesting section is

 004262BB    call ExecutionContext::Uid(void) 004262C0    cmp ax, 1 004262C4    jnz loc_616F76 

The call to the Uid method in the ExecutionContext object places the current user's uid into the ax register (the 16-bit version of the eax register, effectively the lower 16 bits of this 32-bit register). SQL Server uids (user IDs) are listed in the sysxlogins table, and the uid with a value of 1 is associated with the database administrators group dbo. Because the code is comparing the uid returned by the Uid() call to 1, the best approach would be to patch ExecutionContext::Uid() to always return 1. Examining the function, the assignment takes place at the end, just before it returns:

 00413A97    mov ax, [eax+2] 00413A9B    pop esi 00413A9C    retn 

Changing the mov ax, [eax+2] assignment to mov ax, 1 requires patching three bytes. The bytes 66 8B 40 02 should be changed to 66 B8 01 00.

Any user now has permissions on all objects in the database and any user can view the password hashes in sysxlogins. Attempting to execute the stored procedure xp_cmdshell as a non-admin user, however, results in

 Msg 50001, Level 1, State 50001 xpsql.cpp: Error 183 from GetProxyAccount on line 604 

This is because of a security feature in SQL Server that prevents non-administrators from executing commands unless a proxy account is specified. SQL Server is attempting to retrieve this proxy information and failing because it is not set by default. Loading up SQL Server's Enterprise Manager, and selecting the Job System tab under SQL Server Agent properties, invalid proxy account information was entered. The error now produced when xp_cmdshell is run with low privileges is

 Msg 50001, Level 1, State 50001 xpsql.cpp: Error 1326 from LogonUserW on line 488 

Using APISpy32 ( http://www.internals.com ) to watch for calls to the Windows API function LogonUserW(PWSTR, PWSTR, PWSTR, DWORD, DWORD, PDWORD) when xp_cmdshell is executed, the output shows the function being called from within xplog70.dll. This DLL can be debugged by launching the sqlservr.exe process from within a debugger such as Microsoft's WinDbg ( http://www.microsoft.com/whdc/devtools/debugging/default.mspx ) or from IDA's internal debugger. After setting multiple breakpoints in the code and stepping through the code- path taken when xp_cmdshell is successfully and unsuccessfully executed, the divergence point can be established. This point on SQL Server 2000 with no service packs turns out to be a conditional jump (jnz):

 42EA56D3      add esp, 0Ch 42EA56D6      push eax 42EA56D7      call strcmp 42EA56DC      add esp, 8 42EA56DF      test eax, eax 42EA56E1      jnz loc_42EA5A98 

Patching the 2-byte op-code for jnz (0F 85) to the 2-byte op-code for a non-conditional jump jmp (90 E9) results in execution of xp_cmdshell being allowed for all users. Both this patch and Chris Anley's original patch require existing attack vectors for deployment such as a buffer overflow vulnerability. The decision on whether to patch bytes in memory (run-time patching) or to patch the actual SQL Server system files on the hard-drive depends on two factors; if the target is running software that offers file baselining features such as TripWire ( http://www.tripwire.com/products/servers/index.cfm ), and the SQL Server binaries are patched, this will be detected. However, if the SQL Server code is patched in memory, any backdoors will be removed on reboot of the server. A call to the function VirtualProtect() is needed first in order to make the code segment writable.

XSTATUS Backdoor

Another tactic, known as the xstatus backdoor, uses a modification to the xstatus column of the master.dbo.sysxlogins table to permit users to login with system administrator privileges and no password. The xstatus column contains a smallint (2 byte) value that describes the user's role memberships together with the method of authentication to use. If the third bit of the number is set to zero, this denotes that the account authenticates using SQL Server's native authentication; a 1 means that Windows authentication is used. The default SQL Server account used with Windows authentication (BUILTIN\Administrators) has a null password, which becomes a problem if the xstatus bit is changed to zero, giving an effective denary value of 18. This results in allowing anyone to log on to the server using native authentication, a username of BUILTIN\Administrators, and a blank password.

The Windows .NET Server adds the NT AUTHORITY\NETWORK SERVICE group as a SQL login and this account is also prone to xstatus changes in the same way as BUILTIN\Administrators.

Start-Up Procedures

If the SQL Server is set up to use replication, the stored procedure sp_MSRepl_startup will be executed every time the server is restarted, in the security context of the SQL Server process. This makes it a target for Trojanning ”all procedures that are run automatically should be examined for malicious instructions. The presence of the stored procedures sp_addlogin, sp_addrolemember, sp_addsrvrolemember, or xp_cmdshell in startup procedures may indicate that the server has been attacked and should be investigated.



Database Hacker's Handbook. Defending Database Servers
The Database Hackers Handbook: Defending Database Servers
ISBN: 0764578014
EAN: 2147483647
Year: 2003
Pages: 156

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net