CTF Web安全

Xctf Final

Posted on 2020-01-02,3 min read

一题关于回调函数和session+lfi的题目

有三个文件。分别是
function.php(用来过滤危险函数)

<?php
function filters($data){
	foreach($data as $key=>$value){
		if(preg_match('/eval|assert|exec|passthru|glob|system|popen/i',$value)){
			die('Do not hack me!');
		}
	}
}
?

index.php(此文件限制了用户的操作目录。回调函数参数可控)

<?php
highlight_file(__FILE__);
error_reporting(0);
ini_set('open_basedir','/var/www/html:/tmp');
$file='function.php';
$func=$_GET['function'];
call_user_func($func,$_GET);
include($file);
session_start();
$_SESSION['name']=$_POST['name'];
if($_SESSION['name']=='admin'){
	header("location:admin.php");
}
?>

admin.php

hello admin
<?php
if(empty($_SESSION['name'])){
	session_start();
	#echo 'hello ' + $_SESSION['name'];
}else{
	die('you must login with admin');
}
?>

总览代码。应该就是利用call_user_func回调函数。来造成代码执行。但是过滤危险函数。
call_user_func可以使用extract进行变量覆盖。第二个参数$_GET;就会将GET传参的所有参数和值注册为全局变量。
当我们传入
function=extract&file=php://filter/read=convert.base64-encode/resouce=function.php

代码就成了call_user_func(extract,$_GET),也就是extract($_GET);
而我们传入的file就会将原先的$file给覆盖掉。变成了php://filter......,后面include即可读取php文件
读取了文件之后呢。我们目的是getshell。因为不知道flag在哪。

查看PHP手册。发现PHP7.0后。session_start()函数有了变化
Session_start()函数支持options选项了。而options选项。可以传入一个关联数组。配置session的保存位置。名字。httponly等属性。

也就是说。我们可以通过call_user_func函数。去调用session_start,然后GET传参save_path=/tmp
代码就成了session_start(array('save_path'=>'/tmp'))
将session保存到tmp目录,因为前面配置了open_basedir的缘故。我们只能访问web目录和tmp目录
我们试着改下session文件的内容

更改了文件名。但是。并不能更改其内容。这里就有其他的办法了。比如session.upload_progress,但是比较麻烦。
在index.php中。session['name']==_POST['name'],试下修改session文件内容
控制了文件内容。那还不好办吗。老套路,覆盖 POST['name ′],试下修改session文件内容
控制了文件内容。那还不好办吗。老套路,覆盖file,包含session文件。就能getshell

下一篇: PHP Bypass open_basedir→