PHP 文件包含与文件读取

PHP 文件包含与文件读取

1.basic

1.1 php文件读取(File-open)

光是文件读取并没什么特别的,如果读取的文件名是我们可以控制的参数,那就会造成任意文件读取漏洞,这样我们就可以进一步的渗透,可以试着的文件我下面稍微整理了下

  • 配置文件

    • /etc/php/7.1/apache2/php.ini
    • robots.txt
    • .htaccess
  • session文件

    • /tmp/sess_[your phpsessid value]
    • /var/lib/php/sessions/
  • 日志文件

    • /var/log/apache/access.log
  • 其他系统文件

    • /proc/net/arp

    • /proc/self/fd/4

    • /proc/self/environ

      this requires PHP to be run as CGI on a
      system that has the /proc pseudo-filesystem and PHP script is required to
      have access to the aforementioned pseudo-file

    • /var/lib/locate.db

    • /var/lib/mlocate/mlocate.db
  • 伪协议

    • php://filter/read=convert.base64-encode/resource=index.php
    • php://input + POST代码

1.2 php文件包含(File-Inclusion)

  • 把要包含的文件打开

    可以理解为先进行文件读取

  • 解析在PHP tags中的php代码

    可以理解为再进行一次代码执行

  • 把整个文件的内容返回

    包括tags内解析后的内容,也包括PHP tags外的内容,不过不会被解析而是会直接返回。

这里我们可以看到文件读取文件包含的子集!不同于文件读取(仅仅读取内容),如果读取的文件的内容是我们可控的,那么就造成了任意代码执行漏洞。那么可以控制内容的文件有哪些呢,首先这个得依据情况而定,比较通用的方法是

  • 利用伪协议,可以做一些绕过

  • 包含上传临时文件

  • 包含 session

    一些 session 变量可能名字或值可能可控,比如上传进度Session

1.3 漏洞函数

File Inclusion

include, include_once, require, require_once

File open

有些读取函数有特别的用处,比如显示源码,会对文件内容有一个操作,这样有时只能有信息泄露了

1
highlight_file,show_source,readfile,file_get_contents ,fopen,file,......

1.4 相关配置

  • allow_url_fopen

    default: On

    针对fopen等读取文件的函数,一般该配置是开启的,读取的URI可控的话可以造成SSRF,不过只能是以 GET 请求的方式,如果请求的报文中还能有可控的部分,那SSRF可以进一步渗透了。而且由于文件读取函数读取URI的操作curl插件php内置的http解析方式(如parse_url)不太一样,可以构造 URI 来进行一些绕过解析!(详见orange blackhat 2017 的ppt – A new Era of SSRF)

  • allow_url_include

    default: Off

    对打开的URL作为文件处理(Off 默认),php://input 伪协议也需要它开启才可用。

两个如果都开启的话LFI开启则升级为RFI,如果包含了我们自己VPS上的构造好的文件,那就可以 getshell 了。而且 allow_url_fopen 一般会打开,所以 allow_url_include 一般不会打开的,

另外,data:// 伪协议需要两个都开启

1.5 出现场景比较

File Inclusion, SSRF, CRLF, 命令注入 出现的场景很像,可以都尝试,分析清后台调用的函数。

  • SSRF是Server Side再发起一个http(默认)请求 curl等
  • include和require不可省略协议名(如http)
  • 在 curl 中可以用0代表127.0.0.1,在include/require中即使开启了 allow_url_include 也不可以用 http://0/

2. Tecnique

2.1 php://filter 伪协议读取源码

上面刚说过,如果文件里有PHP tags的时候,包含过程会自动解析其中的php代码,但如果我们想获取源码的话,就不能直接包含了,php://filter/read在我们包含前可以先将读取的内容做一次 base64 加密,这样就不可能由php tags了,拿到后,我们再解析回来就行了

1
php://filter/read=convert.base64-encode/resource=index.php

2.2 php://input 伪协议 POST 构造代码执行漏洞

需要开启 allow_url_include

php://input 返回的就是 post 一个请求时,post的数据。我们可以 post 一行命令来写shell

2.3 open_basedir绕过

在 php.ini中设置可被访问的目录
绕过

2.4 后缀名截断

  • %00截断(magic_quotes_gpc=off,PHP小于5.3.4)
    %00截断目录遍历:/var/www/%00 (magic_quotes_gpc=off,unix文件系统)

  • 构造长目录截断在Windows下256字节、Linux下4096字节时达到最大值

    ././././././././././././././././passwd
    ////////////////////////passwd

  • 点号截断
    ?file=../../../../../../../../../boot.ini/………[…]…………

  • RFI可以用?,#等截断

2.5 Windows下,未知文件名利用FindFirstFile特性

FindFirstFile特性,类似于linux中的通配符,同样符合匹配模式的,windows指挥返回按后序字符ascii码排序的第一个文件,不过linux的通配符在include语句中不能用

windows linux
多个字符 >> *
单个字符 < ?

2.6 zip或phar 伪协议+上传伪造图片

部分山传场景中,只能上传图片,同时又有 LFI 。那么我们可以上传一个实际上是phar或zip压缩文件的假图片,zip:// 和 phar:// 伪协议可以读取这种压缩文件里的文件,在进行一次包含的话,就巧妙地 getshell 了

1
2
3
4
5
6
# zip
/include.php?file=zip://./images/vin.jpg%23shell.php

# phar 5.3.0+
# phar文件也可以用zip来打包,上传后再用 phar 包含,访问内部文件直接用斜杠
/include.php?file=phar://./images/vin.jpg/shell.php

类似的还有compress.zlib 伪协议,不过不能直接访问到里面的文件

2.7 上传进度Session

配置 session.upload_progress.enabled = On

首先,post一个文件时,带上PHPSESSID,同时在表单中带上一个名为 PHP_SESSION_UPLOAD_PROGRESS 的变量,值为任意,在上传临时文件被删除前,如果,那就会产生一个上传进度session变量,这个 session 变量的名字为:

1
2
3
# session.upload_progress.prefix + PHP_SESSION_UPLOAD_PROGRESS
upload_progress_123123
upload_progress_<?php echo md5('1');?>

PHP_SESSION_UPLOAD_PROGRESS 的值我们是可控的,如果像上面写为 php 代码,抢在删除前包含后就可以被执行了。下面的链接里有以脚本可以用来测试能不能执行。

php伪协议实现命令执行的七种姿势

文件包含漏洞小结

zip或phar协议包含文件