实战演练:看我是如何将LFI变为RFI的
前言
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里面的样式内容和功能。那么问题来了,如果我们提交https://xianzhi.aliyun.com/search.php?method=upload/1.jpg ,且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 os

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖