Lucene search

K
seebugRootSSV:5112
HistoryApr 25, 2009 - 12:00 a.m.

CVE-2009-1285: phpMyAdmin Code Injection

2009-04-2500:00:00
Root
www.seebug.org
25

EPSS

0.029

Percentile

90.9%

Well, I usually don’t blog about these bugs but phpMyAdmin is a project that is used almost everywhere and this is a quick and dirty way to get code execution. This issue affects phpMyAdmin 3.x before 3.1.3.2 and it was disclosed on 14 April 2009. The bug is present at setup/lib/ConfigFile.class.php file. Here is an outline of that file from 3.1.3.1 release:

1 <?php

10 class ConfigFile
11 {
12 /**
13 * Stores default PMA config from config.default.php
14 * @var array
15 /
16 private $cfg;

259 /
*
260 * Creates config file
261 *
262 * @return string
263 /
264 public function getConfigFile()
265 {
266 $crlf = (isset($_SESSION[‘eol’]) && $_SESSION[‘eol’] == ‘win’) ? "\r\n" : "\n";
267 $c = $_SESSION[‘ConfigFile’];
268
269 // header
270 $ret = ‘<?php’ . $crlf

279 // servers
280 if ($this->getServerCount() > 0) {
281 $ret .= "/
Servers configuration /$crlf$i = 0;" . $crlf . $crlf;
282 foreach ($c[‘Servers’] as $id => $server) {
283 $ret .= '/
Server: ’ . $this->getServerName($id) . " [$id] /" . $crlf
284 . ‘$i++;’ . $crlf;
285 foreach ($server as $k => $v) {
286 $ret .= "$cfg[‘Servers’][$i][‘$k’] = "
287 . var_export($v, true) . ‘;’ . $crlf;
288 }
289 $ret .= $crlf;
290 }
291 $ret .= '/
End of servers configuration */’ . $crlf . $crlf;
292 }

So… function getConfigFile() retrieves various information. Here it constructs a configuration file and $ret includes the PHP code. At line 281 it starts the file with comment:

/* Servers configuration */

Then, as you can clearly see at line 283 the configuration will have a new comment which is:

/* Server: <getServerName()> "id" */

However, $id is completely user controlled since it’s derived from the session variable ConfigFile at line 267. For example, if a user specifies an $id of:

bleh / <?php echo date(); ?> /

He will end up with a configuration file that includes this:

/* Server: <getServerName()> bleh / <?php echo date(); ?> / */

This simple code injection was patched by limiting the user input using preg_replace() function like this:

         foreach ($c['Servers'] as $id =&gt; $server) {
  •            $k = preg_replace('/[^A-Za-z0-9_]/', '_', $k);
               $ret .= '/* Server: ' . $this-&gt;getServerName($id) . &quot; [$id] */&quot; . $crlf
    

Which replaces any matches of /[^A-Za-z0-9_]/ with _ and moves on with the next element. The same bug was also in the following code of the same function:

296 // other settings
297 $persistKeys = $this->persistKeys;
298 foreach ($c as $k => $v) {
299 $ret .= "$cfg[‘$k’] = " . var_export($v, true) . ‘;’ . $crlf;
300 if (isset($persistKeys[$k])) {
301 unset($persistKeys[$k]);
302 }
303 }

Where the exact same logic applies and also the same patch :-P

     foreach ($c as $k =&gt; $v) {
  •        $k = preg_replace('/[^A-Za-z0-9_]/', '_', $k);
           $ret .= &quot;\$cfg['$k'] = &quot; . var_export($v, true) . ';' . $crlf;
    

There was another instance of that bug at the last loop of that function which was this:

305 // keep 1d array keys which are present in $persist_keys (config_info.inc.php)
306 foreach (array_keys($persistKeys) as $k) {
307 if (strpos($k, ‘/’) === false) {
308 $ret .= "$cfg[‘$k’] = " . var_export($this->getDefault($k), true) . ‘;’ . $crlf;
309 }
310 }
311 $ret .= ‘?>’;
312
313 return $ret;
314 }
315 }
316 ?>

Again, the concept is the same in the foreach() loop at line 306 and the patch was of course:

         if (strpos($k, '/') === false) {
  •            $k = preg_replace('/[^A-Za-z0-9_]/', '_', $k);
               $ret .= &quot;\$cfg['$k'] = &quot; . var_export($this-&gt;getDefault($k), true) . ';' . $crlf;
    

The evil auditors among us would have caught that the bug is still there ;-)

phpMyAdmin 3.1.3.2
暂无
<a href=“http://www.phpmyadmin.net/home_page/security/PMASA-2009-4.php” target=“_blank”>http://www.phpmyadmin.net/home_page/security/PMASA-2009-4.php</a>
<a href=“http://www.phpmyadmin.net/home_page/index.php” target=“_blank”>http://www.phpmyadmin.net/home_page/index.php</a>