PHP代码审计 18 实战 MetInfo 变量覆盖漏洞

本文记录 PHP 代码审计的学习过程,教程为暗月 2015 版的 PHP 代码审计课程

PHP 代码审计博客目录

参考文章链接

1. 简介

  1. 变量覆盖漏洞

    变量覆盖漏洞大多数由函数使用不当导致,经常引发变量覆盖漏洞的函数有:extract(),parse_str()和import_request_variables()

  2. metinfo

    MetInfo 5.3.17 版本 PC6 下载链接

2. 实战

  1. 用户请求数据处理代码

    C:\wamp\www\metinfo\include\common.inc.php

     foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
     	foreach($$_request as $_key => $_value) {
     		$_key{0} != '_' && $$_key = daddslashes($_value,0,0,1);
     		$_M['form'][$_key] = daddslashes($_value,0,0,1);
     	}
     }
    

    代码中使用 $_request 来获取用户信息

    代码主要是用于遍历初始化变量,所以很有可能会出现变量覆盖。

    代码判断了 key 的第一个字符是不是“_”来避免覆盖系统全局变量,以及使用自定义函数 daddslashes() 对变量值进行处理。

  2. 代码中查找 daddslashes() 函数

     /*POST变量转换*/
     function daddslashes($string, $force = 0 ,$sql_injection =0,$url =0){
     	!defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
     	if(!MAGIC_QUOTES_GPC || $force) {
     		if(is_array($string)) {
     			foreach($string as $key => $val) {
     				$string[$key] = daddslashes($val, $force);
     			}
     		} else {
     			$string = addslashes($string);
     		}
     	}
     	if(is_array($string)){
     		if($url){
     			//$string='';
     			foreach($string as $key => $val) {
     				$string[$key] = daddslashes($val, $force);
     			}
     		}else{
     			foreach($string as $key => $val) {
     				$string[$key] = daddslashes($val, $force);
     			}
     		}
     	}
     
     	return $string;
     }
    

    可以看到,该函数先判断有没有开启magic_quotes_gpc即魔法引号,若没有则调用addslashes()函数对通过POST方法提交的内容进行转义过滤。也就是说,并没有对GET方法提交的内容进行过滤。

  3. 关于页面

    接着来看/about/页面的信息,查看\about\index.php文件,这里存在两个比较可疑的变量、一个是fmodule变量、另一个是module变量,其中还有require_once()函数,可能存在文件包含漏洞:

    \about\index.php:

     
    

    以上代码中的 $module 变量未赋值

    先来输出一下看看 $module 变量的值是什么

     
    

    浏览器执行 http://127.0.0.1/metinfo/about/index.php

    PHP代码审计 18 实战 MetInfo 变量覆盖漏洞_第1张图片

    可以看到 $module 的值是 show.php

    浏览器执行 http://127.0.0.1/metinfo/about/index.php?module=123456

    PHP代码审计 18 实战 MetInfo 变量覆盖漏洞_第2张图片

    $module 的值并没有覆盖掉

    分析 require_once ‘…/include/module.php’;

     if(!defined('IN_MET'))require_once 'common.inc.php';
    

    看到包含了 common.inc.php 文件

    也就是说 \about\index.php 文件中的 $fmodule 变量可以通过包含 /include/module.php 包含 common.inc.php 然后接收 $_request 来接受 $_GET 方法传递过来的新的 fmodule 值来导致原 fmodule 变量的值被覆盖,输出尝试一下:

     
    

    浏览器执行 http://127.0.0.1/metinfo/about/index.php?module=123&fmodule=test

    PHP代码审计 18 实战 MetInfo 变量覆盖漏洞_第3张图片

  4. fmodule变量和module变量之间的关系

    因为需要利用到require_once()函数来实现文件包含漏洞的利用,接着找fmodule变量和module变量之间的关系,回到module.php来跟踪module变量,可以看到在最后的判断语句中存在该变量:

     if($fmodule!=7){
     	if($mdle==100)$mdle=3;
     	if($mdle==101)$mdle=5;
     	$module = $modulefname[$mdle][$mdtp];
     	if($module==NULL){okinfo('../404.html');exit();}
     	if($mdle==2||$mdle==3||$mdle==4||$mdle==5||$mdle==6){
     		if($fmodule==$mdle){
     			$module = $modulefname[$mdle][$mdtp];
     		}
     		else{
     			okinfo('../404.html');exit();
     		}
     	}
     	else{
     		if($list){
     			okinfo('../404.html');exit();
     		}
     		else{
     			$module = $modulefname[$mdle][$mdtp];
     		}
     	}
     	if($mdle==8){
     	if(!$id)$id=$class1;
     	$module = '../feedback/index.php';
     	}
     }
     ?>
    

    先在结尾输出一下看看能不能进行覆盖:

     .........
     .........
     	if($mdle==8){
     	if(!$id)$id=$class1;
     	$module = '../feedback/index.php';
     	}
     }
     echo $module;
     ?>
    

    浏览器执行 http://127.0.0.1/metinfo/about/index.php?module=123&fmodule=test

    当fmodule不为7时,不覆盖;fmodule为7时,覆盖:

    浏览器执行 http://127.0.0.1/metinfo/about/index.php?module=123&fmodule=7

    即存在变量覆盖漏洞,可以进行文件包含漏洞的利用。

  5. 漏洞利用

    下面就是利用的示例,包含上传的小马文件xiaoma.txt:

     
    

    浏览器执行 http://127.0.0.1/metinfo/about/index.php?fmodule=7&module=../upload/xiaoma.txt

  6. 防御方法

    最简单的防御实现就是,直接在\about\index.php中判断module变量的值是否等于“show.php”,若是则包含指定的文件,否则不进行任何操作:

    \about\index.php:

     
    
  7. 这里提一下PHP文件包含漏洞正常的防御方法:

    1、严格判断包含中的参数是否外部可控。

    2、路径限制,限制被包含的文件只能在某一个文件夹内,特别是一定要禁止目录跳转字符,如:“…/”。

    3、基于白名单的包含文件验证,验证被包含的文件是否在白名单中。

    4、尽量不要使用动态包含,可以在需要包含的页面固定写好,如:“include(“head.php”)”。

    5、可以通过调用str_replace()函数实现相关敏感字符的过滤,一定程度上防御了远程文件包含。

你可能感兴趣的:(代码审计)