一些基础的东西
序列化:serialize()函数
所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。通俗来说,就是把一个对象变成可以传输的字符串。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字
一个大佬总结的不错
对于对象,序列化后的格式为:
其他类型的数据序列化后的格式为:
反序列化 :unserialize()函数
就是把被序列化的字符串还原为对象,转换为php的值,然后在接下来的代码中继续使用。
魔术方法:自动触发的函数。【满足条件自动触发】
code review1
代码如下:/
hlight_file(__FILE__);
class BUU {
public $correct = "";
public $input = "";
public function __destruct() {
try {
$this->correct = base64_encode(uniqid());
if($this->correct === $this->input) {
echo file_get_contents("/flag");
}
} catch (Exception $e) {
}
}
}
if($_GET['pleaseget'] === '1') {
if($_POST['pleasepost'] === '2') {
if(md5($_POST['md51']) == md5($_POST['md52']) && $_POST['md51'] != $_POST['md52']) {
unserialize($_POST['obj']);
}
}
}
这个题涉及到php弱类型,百度看一下相关的知识点:
该函数用于打印显示,一个变量的内容与结构,以及类型的信息。
该函数有一个参数,第一个参数(必填).第二个参数(选填参数,N)可以多个参数。
案例1:
输出部分:
array(4) { [0]=> int(1) [1]=> int(2) [2]=> int(3) [3]=> array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" } }
案例2:
输出部分:
string(3) "php" float(3.1) bool(true) int(15) array(2) { [0]=> int(1) [1]=> int(2) } object(Admin\Controller\test)#2 (0) { }
严格比较就是说两个参数,不仅类型要相同,值也要相同,上面这个表就很直观地反映了出来。
至于松散比较,两个参数类型就没必要相同,因为类型不同会自动转换,然后再进行比较。
然后开始分析题目的源码,浅分析一下:
先是创建一个名为buu的类,然后创建两个对象。对经过base64编码后的uniqid值赋给correct
然后,通过get和post传参。
然后看一下wp:需要序列化对象:
<?php class BUU{
public $correct = "";
public $input = ""; }
$a = new BUU();
$a->input = &$a->correct;
echo serialize($a);
结果
O:3:"BUU":2:{s:7:"correct";s:0:"";s:5:"input";R:2;}
[HCTF 2018]WarmUp
一个诡异的笑脸,
访问source.php,得到源码
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
is_string():检测变量是否是字符串
isset():检测变量是否已设置并且非 NULL
in_array(要搜索的值,要搜索的数组):搜索数组中是否存在指定的值
mb_substr($page,n,m):返回page中从第n位开始,到n+m位字符串的值
mb_strpos():查找字符串在另一个字符串中首次出现的位置
urldecode():将url编码后的字符串还原成未编码的样子
分析: 代码审计下来能看到是要我们输入一个file的参数,只要这个参数不是非空、为字符串类型和能通过自定义的checkFile函数就能直接包含这个文件。
仔细看一下checkFile这个函数,是一个类似白名单的判断的函数。一开始设立了一个白名单,包括两个文件名source.php和hint.php。然后会进行3次白名单的判断,只要成功一次算通过白名单。
第一次判断,没有进行任何操作,直接拿输入的值来进行白名单判断。
又出现了一次同样的界面。
第二次判断,是取输入的值第一个?号前面的字符串来