# .htaccess 文件的利用
自动生成.htaccess 的网站
分布式配置文件,它里面存放着 apache 服务器配置相关命令,提供了针对目录改变配置的方法,作用范围是当前目录及其子目录
使用前,首先要启用 htacces,将 AllowOveride 的配置改为 all
AllowOverride 从字面上解释是允许覆盖的意思,即 Apache 允许另一配置文件覆盖现有配置文件。
在 AllowOverride 设置为 None 时, .htaccess 文件将被完全忽略。当此指令设置为 All 时,所有具有 “.htaccess” 作用域的指令都允许出现在 .htaccess 文件中。
# 问题点一
PHPStudy 中 AddType application/x-httpd-php 等 Apache 命令之所以在 Apache 的设置文件中设置后未实现目标效果是由于 PHP 的版本不符导致的,但注意这里的 PHP 版本并不是指 PHP7.3.0、PHP7.4.0 这种版本号,也不是适用于 32 位的 PHP、适用于 64 位的 PHP 这种不同机型的版本,而是 PHP 的 NTS (Non Thread Safe) 与 TS (Thread Safe) 的这种不同版本导致的。
PHP For Windows: Binaries and sources Releases
- ts(Thread-Safety) 即线程安全,多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。
- nts(None-Thread Safe) 即非线程安全,就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的是 脏数据 php 以 fast cgi 方式运行的时候选择这个版本,具有更好的性能;
# 解决办法
安装 TS 版本的 php,在 apache 配置中设置好
在 php 文件夹中将 php.ini-development 文件复制一份命名为 php.ini
新下载的 php 本来没有现成的 php.ini 文件。只是给了
php.ini-development (开发环境用)与 php.ini-production(生产环境用)两个建议。
而 php 去加载 php.ini 作为配置文件的。我们更喜欢哪个建议,就把它备份,然后重命名为 php.ini 然后加入自己个性化的配置即可。
打开 php.ini,找到 extension_dir,并把前面的 ";" 符号删掉 (在 php.ini 相当于注释符),其值改为 "PHP 文件的路径 /ext"。
他是放 php 扩展的目录,保存后,我们 PHP 就设置完成了,接下来要设置 Apache。
来到 PHPStudy 安装 Apache 的目录下,打开 Apache 的配置文件 httpd.conf, 搜索 LoadModule,找到有很多 LoadModule 语句的地方。( LoadModule:加载特定的 DSO 模块。)
在末尾加上 LoadModule php7_module "PHP 文件的路径 /php7apache2_4.dll" 和 PHPIniDir "PHP 文件的路径"。
再加上一句 AddType application/x-httpd-php .php,配置就完成了
# 利用
# 文件解析
首先还是先说文件上传中常用的利用方式
(8.* 无法使用)
在 htaccess 文件中写入如下内容,上传到服务端后再上传一个其他任意后缀的文件,都会被当作 php 文件解析
<FilesMatch “.png”>
SetHandler application/x-httpd-php
</FilesMatch>
#匹配文件中有haha存在
SetHandler application/x-httpd-php
#SetHandler强制所有匹配的文件由指定处理程序处理
AddType application/x-httpd-php .txt
#AddType将给定的文件扩展名映射到指定的内容类型
接着聊一聊别的利用方式
# 源码泄露
当使用 PHP 作为 Apache 模块时,也可以用 Apache 的配置文件(例如 httpd.conf)和 .htaccess 文件中的指令来修改 php 的配置设定
我们可以通过 .htaccess 文件的 php_value 指令对 PHP 的 engine 配置选项进行设定,当把 engine 的值设为 off(或 0)时可以禁用一个本目录和子目录中的 PHP 解析,此时将会造成源码泄露:
在 htaccess 文件中写入
php_value engine 0
# 文件包含
htaccess 文件中同样有两个配置 auto_prepend_file 和 auto_append_file,我们可以通过 php_value 来设置,条件是同级目录下有 php 文件
php_value auto_append_file /etc/passwd
# 防御
最直接的就是过滤 htaccess 后缀
对文件重命名(htaccess 文件命名固定)
# user.ini 的利用
php.ini 是 php 的全局配置文件,只要是以 fastcgi 运行的 php 都可以用这个方法,对整个 web 环境起作用
user.ini 是用户自定义的 php.ini,如果在文件上传中没有对其进行限制,那么我们就可以修改 php.ini 的配置,既然是用户自定义,那么肯定要提到权限问题。
官方文档提到只有在这两种模式的 ini 设置可以被识别,那么就不得不提到什么是 PHP_INI_* 模式
这些模式决定着一个 PHP 的指令在何时何地,是否能够被设定。手册中的每个指令都有其所属的模式。例如有些指令可以在 PHP 脚本中用 ini_set () 来设定,而有些则只能在 php.ini 或 httpd.conf 中。(上面表格中没有提到的 PHP_INI_PERDIR 也可以在.user.ini 中设置),user_ini.cache_ttl 控制着重新读取用户 INI 文件的间隔时间。默认是 300 秒(5 分钟)。
PHP ini_set用来设置php.ini的值,在函数执行的时候生效,脚本结束后,设置失效。无需打开php.ini文件,就能修改配置
也就是说我们想利用.user.ini 需要在 PHP_INI_USER 模式(PHP_INI_ALL 模式)中,那么哪些配置可以在 .user.ini 中设定呢?
php.ini 配置选项列表(http://php.net/manual/zh/ini.list.php )
# 利用
.user.ini 中两个中的配置就是 auto_prepend_file 和 auto_append_file。这两个配置的意思就是:我们指定一个文件(如 1.jpg,对后缀名没有太多要求),那么该文件就会被包含在要执行的 php 文件,相当于在 php 文件中中插入一句:require (./1.jpg)。这两个设置的区别只是在于 auto_prepend_file 是在文件前插入,auto_append_file 在文件最后插入 (文件后插入如果程序以 exit () 结束就无法利用)。
demo:
经过测试 php 版本从 5.3 开始到 7.4 都是可用的,php8.* 的没有成功
# 防御
利用条件:
服务器脚本语言为PHP 服务器使用CGI
FastCGI模式
上传目录下要有可执行的php文件
上面提到有 php8.* 是不可用的,那么可使用 php8.* 可用从根源解决问题
user.ini 使用这两条条配置也有限制说了是在同目录下的其他.php 文件中包含配置中所指定的文件,也就是说需要该目录下存在.php 文件,不要将文件上传路径设置成为本目录下,存放上传文件的地方不要存有 php 文件(通常在文件上传中,一般是专门有一个目录用来存在图片,可能小概率会存在.php 文件。但是有时可以使用 ../
来将文件上传到其他目录,达到一个利用的效果。)严格限制文件上传的路径
再者结束对 ini 扩展名的过滤,对文件内容 auto_prepend_file、auto_append_file 的过滤
# 补充
了解什么是 FastCGI,首先应该知道什么是 cgi
全称是 “通用网关接口”,是一种让客户端(web 浏览器)与 Web 服务器(apache,nginx 等)程序进行通信(数据传输)的协议。
# CGI 工作流程
- 每次当 web server 收到 index.php 这种类型的动态请求后,会启动对应的 CGI 程序 - PHP 的解析器;
- PHP 解析器会解析 php.ini 配置文件,初始化运行环境,然后处理请求,处理完成后将数据按照 CGI 规定的格式返回给 web server 然后退出进程;
- 最后 web server 再把结果返回给浏览器。
高并发时的性能较差:
CGI 程序的每一次 web 请求都会有启动和退出过程 —— 每次 HTTP 服务器遇到动态请求时都需要重新启动脚本解析器来解析 php.ini,重新载入全部 DLL 扩展并重初始化全部数据结构,然后把结果返回给 HTTP 服务器
# FastCGI
因 CGI 高并发时性能差,未解决这一问题产生了 FastCGI
# FastCGI 工作流程
- Web Server 启动同时,加载 FastCGI 进程管理器
- FastCGI 进程管理器读取 php.ini 配置文件,对自身进行初始化,启动多个 CGI 解释器进程 (php-cgi),等待来自 Web Server 的连接。
- 当 Web Server 接收到客户端请求时,FastCGI 进程管理器选择并连接到一个 CGI 解释器。Web server 会将相关环境变量和标准输入发送到 FastCGI 子进程 php-cgi 进行处理
- FastCGI 子进程完成处理后将数据按照 CGI 规定的格式返回给 Web Server,然后关闭 FastCGI 子进程或者等待下一次请求。
# FastCGI 解决方案
Master-Worker 模式
Fastcgi 会先启一个 master,解析配置文件,初始化执行环境,然后再启动多个 worker。当请求过来时,master 会传递给一个 worker,然后立即可以接受下一个请求。这样就避免了重复的劳动,效率自然提高。而且当 worker 不够用时,master 可以根据配置预先启动几个 worker 等着;当然空闲 worker 太多时,也会停掉一些,这样就提高了性能,也节约了资源。这就是 fastcgi 的对进程的管理。