前言

PHP文件包含漏洞的产生原因是在通过PHP的函数引入文件时,由于传入的文件名没有经过合理的校验,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入。最常见的就属于本地文件包含(Local File Inclusion)漏洞了。

常见漏洞代码

if ($_GET['method']) {include $_GET['method'];} else {include 'index.php';}

一般情况下,程序的执行过程是当用户提交url为 https://xianzhi.aliyun.com/sth.php?method=search.php 时,调用search.php里面的样式内容和功能。直接访问 https://xianzhi.aliyun.com/search.php 则会包含默认的index.php里面的样式内容和功能。那么问题来了,如果我们提交),且1.jpg是由黑客上传到服务器上的一个图片,并在图片的末尾添加了恶意的php代码,那么恶意的代码就会被当前文件执行,以此触发本地文件包含漏洞。

有趣的发现

我和我的好朋友Mike Brooks一直致力于对一些开源的Web框架进行代码审计工作,在对这些Web开源框架代码审计的过程中,我们找到了一种将本地文件包含漏洞(LFI)转换为远程文件包含漏洞(RFI)的方法。并且依赖于我们驻留在Web服务器上的JAR包文件,我们发现了一个能够执行任意代码的方法。通常情况下,当以特定方式配置Web应用程序时,它将能够加载Web服务器上的JAR包文件并在文件中搜索实现的java类。有意思的是,在Java类中,我们可以在正在被执行的java类上定义一个静态代码块,具体如下所示:

public class LoadRunner {static {System.out.println("Load runner'ed");}public static void main(String[] args) {}
}

我们首先编译这个java类,然后在代码中加载它,具体实现如下图所示:

现在,我们已经有了两个有趣的发现:一个是可以在加载的JAR文件中插入执行代码,另一个是在Web服务器上找到一个合适的文件路径来加载JAR包文件。因此,我们现在必须找到的一种方式来让应用程序以某种方式引用我们驻留在服务器上的JAR包文件。在这个探索的过程中,我们尝试了很多的方法,包括去查看应用程序中的所有请求处理程序以确定能否进行文件上传;甚至尝试寻找可以在服务器上毒化文件的方法,以便将其转化为JAR包文件,但是这些方法却都没有能够奏效。尽管这样,我们仍然没有放弃去研究和探索,最终Mike Brooks想出了一个好主意。

文件描述符

​    一般情况下,大多数Web开源框架都会将上传的文件落地到服务器的某个磁盘上,但文件的路径是不可猜测的(通常使用GUID或其他随机标识符来表示),如果我们不知道文件路径,那又该如何去访问上传的文件呢?在Linux中,当一个进程有一个文件被打开时,它将在其 /proc/ 目录中打开一个指向该文件的文件描述符。因此,如果我们有一个PID为1234的进程,并且该进程打开了磁盘上的某个文件,那么我们可以通过**/proc/1234/fd/***文件描述符来访问该文件。这意味着,我们不需要猜测GUID或其他随机值,我们只需要猜测HTTP请求处理程序的PID和上传文件的文件描述符即可。因而用于访问上传文件的搜索空间就会大幅减少。不仅如此,如果我们已经有了LFI,加上磁盘上那些经常出现的、可以预测的PID(Web服务器上HTTP请求处理程序的PID)文件,因此获取PID和文件描述符编号要比想象中简单得多。

加载文件描述符

​    为了实现上面的方法,我们首先需要在程序中找到那些处理文件上传的请求,之后尝试通过Web开源框架中的LFI漏洞来查看所有PID文件描述符,并通过文件描述符来访问我们在Web服务器上上传的文件。在我们测试过的Web框架中,当访问FILES字典时,这些文件描述符总是被缓慢加载,而Flask Web框架直接在HTTP GET请求填充了FILES字典字段,以下是超简单的Flask应用程序:

# -*- coding: utf-8 -*-
import osfrom flask import Flask, requestUPLOAD_FOLDER = "/tmp"app = Flask(__name__)
app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER@app.route("/", methods=["GET"])
def show_me_the_money():x = requestimport codecode.interact(local=locals())if __name__ == "__main__":app.run()

在这个应用程序中,我们有一个单一的处理程序,该处理程序允许在URL上挂载HTTP GET请求。然后我们在Ubuntu VM中运行这个程序,并通过HTTP GET请求将文件上传到该服务器上。对于以前没有使用过 import code 技巧的人来说,这是一个很好的方法来调试Python代码和库,因为在 code.interact 被调用时你将进入到python的REPL环境中去。

以下是通过HTTP GET请求上传文件的简单脚本:

# -*- coding: utf-8 -*-
import requestsresponse = requests.get("http://127.0.0.1:5000/",files={"upload_file": open("/tmp/hullo", "rb"),},
)

而在 /tmp/hullo 的文件中,我们可以看到很多的“Hello World”:

然后,我们首先运行服务器,之后上传文件,并进入Flask请求处理程序上下文中的python REPL环境,具体如下图所示:

通过使用请求处理程序的PID,我们可以查看到磁盘上打开的文件描述符:

然后我们返回到REPL并访问上传的文件:

现在该文件已经在Web服务器中被访问过了,此刻我们回到 /proc 目录,看看是否可以找到上传文件的内容:

果然,我们找到了上传的文件!因此,对于我们正在评估的Web应用程序来说,我们确认通过这种上传和引用文件的方法可以正常访问到我们驻留在Web服务器中的JAR包文件!

我们可以通过 多次上传相同的文件 来进一步减少文件路径搜索空间,因此我修改了文件上传的代码使得可以上传相同的九个文件:

# -*- coding: utf-8 -*-
import requestsresponse = requests.get("http://127.0.0.1:5000/",files={"upload_file": open("/tmp/hullo", "rb"),"upload_file2": open("/tmp/hullo", "rb"),"upload_file3": open("/tmp/hullo", "rb"),"upload_file4": open("/tmp/hullo", "rb"),"upload_file5": open("/tmp/hullo", "rb"),"upload_file6": open("/tmp/hullo", "rb"),"upload_file7": open("/tmp/hullo", "rb"),"upload_file8": open("/tmp/hullo", "rb"),},
)

运行此脚本后,访问处理程序中的 FILES 字典,并查看请求处理程序PID目录中的 fd 目录内容,我们看到所有上传的文件都有打开的文件描述符:

因此,通过使用这种方法,我们可以保证具有特定号码的文件描述符终将会指向我们上传的文件。如果我们提交100个上传文件的请求,可能文件描述符50指向的就是我们的文件!反过来,我们现在需要猜测的唯一值就是PID。

如何实施攻击利用?

​    总而言之,为了引用上传文件以达到攻击的目的,这是一种大大减少搜索空间的方法,这在许多情况下可以使LFI成为RFI。如果你要使用此方法进行攻击利用,请考虑以下事项:

  1. 通过我们对多个Web框架(Django和Flask)的分析发现,当访问FILE字典时框架会延迟加载文件引用。因此,我们必须定位 访问FILES字典的 请求处理程序 。一旦请求处理程序访问了FILES字典,文件描述符将在请求处理期间一直保持打开状态。

  2. 默认情况下,其他框架可能会填充这些文件描述符,而这正是我们下一步将要研究的内容。

  3. 当处理请求体中上传的文件时,有些框架不区分不同的请求方式,这在一定程度上说明这种攻击方法不仅限于非幂等的HTTP verbs。

  4. PID并不意味着随机化。无论我们的目标是什么(Ubuntu上的Apache,Fedora上的Nginx等),如果我们希望将其转化为漏洞,那么我们可以创建一个本地设置,并查看与Web服务器和请求处理程序相关联的PID。一般来说,当我们将服务安装到*nix时,它们将在机器重新启动时以类似的顺序启动。由于PID也按顺序分配,这意味着我们可以大大减少PID搜索空间。

  5. 请求处理程序需要访问 所有要处理的上传文件 的FILES字典 。这就是说,如果处理程序中的功能期望上传的文件是PDF,以执行请求处理程序的中代码,而此时我们也准备上传一个JAR包文件,那么只要同时上传这两个文件即可,它们都将被赋予文件描述符。

  6. 尝试找到加载文件描述符的请求处理程序,为了我们的代码审计工作能够顺利进行,我们发现有一个处理程序会逐行处理一个文件的全部内容,所以我们上传了一个巨大的文件,该巨大的文件中当然也包含了我们想要执行的JAR包文件。

  7. 请注意,如果您上传的文件较小,则可能只读入内存,并且不会打开任何文件描述符。当对Flask Web框架进行测试时,我们发现1MB以下的文件会被直接加载到内存中,而1MB以上的文件则放在磁盘上。因此,我们需要在JAR包文件中额外填充任何可供攻击利用的有效载荷。

后续更新

​    后续我们对多个框架缓慢加载文件描述符这一问题进行了深入的研究和分析。最后我们发现对于Flask和Django来说,并不是FILES 被缓慢加载,而是请求体的内容只有在被访问时才会被处理。因此,根据这个结论我们可以轻松定位那些访问HTTP请求体数据的任何请求处理程序。一旦请求处理程序访问了包含在请求体中的数据,文件描述符就会被填充。

Django框架中访问请求体数据代码如下所示:

通过此访问请求填充的文件描述符如下所示:

Flask Web框架中访问请求体数据的代码如下所示:

通过此访问请求填充的文件描述符如下所示:

本文作者:佚名

来源:51CTO

应对安全漏洞:如何将LFI变为RFI相关推荐

  1. 文件包含漏洞(LFI、RFI)(require()、include()函数)

    文章目录 一.文件包含漏洞分类 二.文件包含漏洞原理 三.文件包含函数 四.测试是否存在本地文件包含(LFI)漏洞 五.文件包含漏洞实例 "百度杯"CTF比赛 2017 二月场in ...

  2. 如何应对安全漏洞的修复

    在大多数企业和公司,并没有专门的信息安全部和安全工程师,所以安全漏洞的修复责任就落到了运维部门的工程师头上,那么当你拿到了一份安全评估报告后,该如何应对安全漏洞的修复呢? 首先明确风险的类型和确定等级 ...

  3. 【PHP渗透技巧拓展】————3、LFI、RFI、PHP封装协议安全问题学习

    本文希望分享一些本地文件包含.远程文件包含.PHP的封装协议(伪协议)中可能包含的漏洞 目录 1. 文件包含的基本概念 2. LFI(Local File Include) 3. RFI(Remote ...

  4. LFI、RFI、PHP封装协议安全问题学习

    本文希望分享一些本地文件包含.远程文件包含.PHP的封装协议(伪协议)中可能包含的漏洞 相关学习资料 http://www.ibm.com/developerworks/cn/java/j-lo-lo ...

  5. 欧盟正研究用三种标准技术应对DNS漏洞

    欧洲网网络与信息安全局(ENISA)正在研究用三种不同方法增强网络地址系统的安全,应对最近发现的互联网域名系统中的安全漏洞. 互联网域名系统中的安全漏洞是研究人员Dan Kaminsky首先发现了.这 ...

  6. php本地文件包含漏洞,本地文件包含漏洞详解---LFI

    1 概述 文件包含(Local File Include)是php脚本的一大特色,程序员们为了开发的方便,常常会用到包含.比如把一系列功能函数都写进fuction.php中,之后当某个文件需要调用的时 ...

  7. 版本帝 GitLab 连发五版,应对 XSS 漏洞

    GitLab 8.17.0-rc2 .8.16.5.8.15.6.8.14.9 和 8.17.0-rc3 发布了.GitLab 是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托 ...

  8. 阿里云帮助云上用户应对Struts2高危漏洞

    2017年3月6日,Apache Struts2被曝存在远程命令执行漏洞,漏洞编号:S2-045,CVE编号:CVE-2017-5638,官方评级为高危,该漏洞是由于在使用基于Jakarta插件的文件 ...

  9. 代码审计中的文件包含漏洞

    0x00 背景 文件包含漏洞是php语言的一大特性.文件包含的意思是,服务器在执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码并执行,这会为开发者节省大量的时间.而文件包含漏洞的出现 ...

最新文章

  1. ​西湖大学EMBLab诚聘环境工程学、生物信息学、分子生态学科研助理
  2. 6.Spring Security Session 管理
  3. Xamarin Essentials教程振动Vibration
  4. 矢量旋度的散度恒为零
  5. struts2 去掉或修改后缀名
  6. tiger4444/rabbit4444后缀勒索病毒怎么删除 能否百分百恢复
  7. 雷林鹏分享:CSS Id 和 Class
  8. 每日一测5(关于继承)
  9. Oracle-索引分裂研究
  10. 经典Python面试题之Python基础篇
  11. 设置居中_安卓手机时间怎么显示在中间 时间居中设置教程
  12. 解决办法:atoi不能将CString 转化为char *
  13. [转载] 民兵葛二蛋——第7集
  14. FS FT DTFT DFT关系及频谱分析总结
  15. 故障树分析法MATLAB,故障树分析(FTA)方法及其基于VC的软件设计的研究
  16. 神舟电脑怎么重装系统 神舟电脑重装系统步骤
  17. 还在傻傻的数star、数fork吗?3秒钟教会你如何查看GitHub项目活跃度,是死是活一眼便知
  18. jsp、html通过添加注册表打开本地应用
  19. Java中Calendar基本使用--Comparator.comparing比较排序
  20. 艾永亮:B站破壁出圈,同是弹幕视频网站,为什么倒下的是A站?

热门文章

  1. MATLAB - 三维图绘制
  2. loj #3086. 「GXOI / GZOI2019」逼死强迫症
  3. 祝愿所有兄弟姐妹们新春身体健康,阖家欢乐
  4. LeetCode笔记:526. Beautiful Arrangement
  5. FME支持的Autodesk Revit 格式概要
  6. 大数据信息资料采集:武志红公众号心理学历史文章采集评论搜集
  7. VIEWGOOD(远古)P2P流媒体直播系统的设计与实现
  8. 嘉兴碧桂园云栖里土拍价格_奥山深耕嘉兴,再下一城!以总价5.73亿元竞得王店镇宅地...
  9. 牛客wannafly27 C 树形dp
  10. Win7使用技巧(持续更新...)