代码执行
eval
php中可以执行代码的方式还是很多的,最普通的就是eval()这个字符串,
需要注意一下
(1)一般情况下双引号中的内容可以被替换和解释,单引号的内容是不能变化的
(2)在eval中申请的变量,所有PHP代码都可访问到
eval() assert() system() exec() shell_exec() passthru() escapeshellcmd() pcntl_exec()
include
文件包含漏洞,如果开启了远程包含,很容易就会转变为代码执行漏洞。
之前做过整理
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
phpinfo()';
preg_replace("/(.*?)<\/tag>/e", '$1', $var);
?>
但是一般的利用情况是不会有E选项的,我们可以通过%00截断等方式来添加e这个选项
phpinfo()';
preg_replace("/(.*?)$regexp<\/tag>/", '\\1', $var);
?>
重音符
这个php会把重音符中的字符串当做代码来执行,这里是执行系统命令而不是php代码
大括号
php中会吧大括号中的值当做一个变量,这里我们可以使用${`dir`}这种形式来执行变量,但是不会有回显
一般情况下,花括号里面的第一个字符如果是某些特殊字符,后面字符串就可以被执行
http://www.yunsec.net/plus/view.php?aid=11894
ob_start
这个函数可以设定一个回调函数,来进行代码执行,不过貌似只能返回命令执行的最后一行
array_map
这个函数也是可以设定一个回调函数,对一个数组中的元素做处理,并返回处理后的数组
__destruct
值个函数执行的时候,会触发原类中的__destruct函数,用户构造一个比较蛋疼的提交的话,就会导致代码执行,但是这种情况也是比较苛刻的
当然也有很多前面带下划线的函数会执行,destruct只是其中一个,__wakeup也会被调用
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以后默认关闭。
第二种是人为注册成为全局变量
变量注册
$_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 overwrites
foreach(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开启的情况下,可以用来引入反斜杠,不过条件比较苛刻。