代码审计典型语法结构

来源:互联网 发布:淘宝不发货 自动退款 编辑:程序博客网 时间:2024/05/16 14:10

代码执行

eval

php中可以执行代码的方式还是很多的,最普通的就是eval()这个字符串,
需要注意一下
(1)一般情况下双引号中的内容可以被替换和解释,单引号的内容是不能变化的
(2)在eval中申请的变量,所有PHP代码都可访问到
<?php$foobar = "xxx";eval("echo $foobar;");eval('echo $foobar;');?>
类似的函数还有
eval() assert() system() exec() shell_exec() passthru() escapeshellcmd() pcntl_exec()

include

文件包含漏洞,如果开启了远程包含,很容易就会转变为代码执行漏洞。

<?php$to_include = $_GET['file'];require_once($to_include . '.html');?>
之前做过整理
http://blog.csdn.net/wangyi_lin/article/details/9837257#t19
类似的函数还有
nclude() include_once() require() require_once() spl_autoload()

preg_replace

比较常用的正则表达式,也可以引发代码执行,源于PCRE (Perl Compatible Regular Expressions) 中的e(PREG_REPLACE_EVAL)选项,
这个选项会吧replacement中的内容当做PHP代码执行,并取返回结果的值,其中后项引用可以$1 也可以 \\1
<?php$var = '<tag>phpinfo()</tag>';preg_replace("/<tag>(.*?)<\/tag>/e", '$1', $var);?>
但是一般的利用情况是不会有E选项的,我们可以通过%00截断等方式来添加e这个选项
<?php$regexp = $_GET['re'];$var = '<tag>phpinfo()</tag>';preg_replace("/<tag>(.*?)$regexp<\/tag>/", '\\1', $var);?>

重音符

这个php会把重音符中的字符串当做代码来执行,这里是执行系统命令而不是php代码
<?phpecho `dir`;?>

大括号


php中会吧大括号中的值当做一个变量,这里我们可以使用${`dir`}这种形式来执行变量,但是不会有回显

<?php$year = "10";echo "That was 20${year}-th year.";$foobar = 'phpinfo';${foobar}();?>

这里也可以使用大括号来执行php语句
<?php$k = "{${phpinfo()}}";?>

一般情况下,花括号里面的第一个字符如果是某些特殊字符,后面字符串就可以被执行
http://www.yunsec.net/plus/view.php?aid=11894


ob_start

这个函数可以设定一个回调函数,来进行代码执行,不过貌似只能返回命令执行的最后一行
<?php$foobar = 'system';ob_start($foobar);echo 'dir';ob_end_flush();?>


array_map

这个函数也是可以设定一个回调函数,对一个数组中的元素做处理,并返回处理后的数组
<?php$evil_callback = $_GET['callback'];$some_array = array(0, 1, 2, 3);$new_array = array_map($evil_callback, $some_array);?>

unserialize / serialize

__destruct

值个函数执行的时候,会触发原类中的__destruct函数,用户构造一个比较蛋疼的提交的话,就会导致代码执行,但是这种情况也是比较苛刻的
当然也有很多前面带下划线的函数会执行,destruct只是其中一个,__wakeup也会被调用
<?phpclass Example {var $var = '';function __destruct() {eval($this->var);}}unserialize($_GET['saved_code']);?>
像这样构造提交
http://127.0.0.1/test.php?saved_code=O:7:"Example":1:{s:3:"var";s:10:"phpinfo();";}

__toString

这个函数,会在serialize调用这个函数,这个函数会返回一个字符串决定serialize的值,重载这个函数会影响这个值
比如下面这个代码就会产生文件包含
class just4fun {        public $filename;         function __toString() {            return @file_get_contents($this->filename);        }    }

绕过方法

有一些程序中会判断用户输入是不是一个序列化的数据,常见的代码如下
$token = $data[0];switch ( $token ) {    case 's' :        if ( '"' !== $data[$length-2] )            return false;    case 'a' :    case 'O' :        return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );    case 'b' :    case 'i' :    case 'd' :        return (bool) preg_match( "/^{$token}:[0-9.E-]+;\$/", $data );
这个可以用+来绕过,这也属于PHP的一种特性
O:+4:"test":1:{s:1:"a";s:3:"aaa";} 
当然还有很多类似的绕过方法
$str1 = 's:8:"ryatsyne";';$str2 = 's:8:"ryatsyne"t';$str3 = 'S:8:"\72\79\61\74\73\79\6e\65"';



其他容易导致问题的函数

array_map()usort(), uasort(), uksort()array_filter()array_reduce()array_diff_uassoc(), array_diff_ukey()array_udiff(), array_udiff_assoc(), array_udiff_uassoc()array_intersect_assoc(), array_intersect_uassoc()array_uintersect(), array_uintersect_assoc(), array_uintersect_uassoc()array_walk(), array_walk_recursive()xml_set_character_data_handler()xml_set_default_handler()xml_set_element_handler()xml_set_end_namespace_decl_handler()xml_set_external_entity_ref_handler()xml_set_notation_decl_handler()xml_set_processing_instruction_handler()xml_set_start_namespace_decl_handler()xml_set_unparsed_entity_decl_handler()stream_filter_register()set_error_handler()register_shutdown_function()register_tick_function()


文件包含

http://blog.csdn.net/wangyi_lin/article/details/9837257#t19 



变量覆盖

变量覆盖漏洞产生的原因有两种
第一种是register_globals为on的情况,PHP4默认开启,PHP5以后默认关闭。
第二种是人为注册成为全局变量

变量注册

<?php       foreach(Array('_GET','_POST','_COOKIE') as $_request)        {              foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);        }?>
这里如果我们构造这样的提交,便可以修改GLOBALS中的变量
http://127.0.0.1/test.php?_POST[GLOBALS][XXX]=wyl
程序会通过$_GET注册了$_POST,通过$_POST注册了$GLOBALS! 

变量销毁

有的时候为了防止全局变量覆盖,会出现这样的代码
//if register globals = on, undo var overwritesforeach(array('_GET','_POST','_REQUEST','_COOKIE') as $method){     foreach($$method as $key=>$value){          unset($$key);     }}
这样很容易导致一些关键变量被销毁

$_REQUEST

这个数组保存了Get  Post传递的变量,不过在变量名相同的情况下post中的变量会覆盖get中的变量
比如如下的代码,用来检测变量中是否有数组存在
foreach($_REQUEST as $request) {    if(is_array($request)) {        die("Can not use Array in request!");    }}
当提交  GET:LanLan[xxxxx]=xxxxx   POST:LanLan=1  便可绕过这个检测 

其他导致变量覆盖的函数

还有一些函数的使用可能导致变量覆盖
parse_str   mb_parse_str  import_request_variables

随机函数

PHP中一般使用随机函数来生成session

Rand()

此函数生曾的最大随机数是32767,很容易被暴力破解。



字符串

offset

这是php字符串的一个特性,下面的两条echo都会输出L,PHP对字符串大括号中的变量,进行类型转换'hi'转换成整形之后的值为0
$xigr = 'LanLan';echo $xigr[0];echo $xigr['hi'];
这种特性会引发一些漏洞,比如这样的情况,如果admin被变量覆盖成了字符串型,那么就可以绕过下面的check判断
$admin['check'] = "0";$admin['pass']  = "angel"; ......if($admin['check'] == "1") {....}
总的来说就是把一个原本是数组型的变量,被覆盖成字符串型,但是根据PHP的特性,程序依然可以继续执行~但是会给各种不法分子提供做坏事的机会。
这种特性在GPC开启的情况下,可以用来引入反斜杠,不过条件比较苛刻。