任意文件下载漏洞
漏洞原理
许多web应用程序因业务需要,提供文件下载功能,但是没有对用户下载的文件做限制,导致恶意用户能够下载敏感文件。
产生原因
文件下载功能在很多web系统上都会出现,一般我们当点击下载链接,便会向后台发送一个下载请求,一般这个请求会包含一个需要下载的文件名称,后台在收到请求后 会开始执行下载代码,将该文件名对应的文件响应(response)给浏览器,从而完成下载。 如果后台在收到请求的文件名后,将其直接拼进下载文件的路径中而不对其进行安全判断,则可能会引发不安全的文件下载漏洞。
利用位置
url中有以下这类关键词的一般形式:
download.php?path=
download.php?file=
down.php?file=
readfife.php?file=
read.php?filename=
包含参数:
&Src=
&Inputfile=
&Filepath=
&Path=
&Data=
漏洞示例
网址:http://172.28.25.41/pikachu/vul/unsafedownload/execdownload.php?filename=kb.png
看到网址中?filename=kb.png,可以想到更改文件名是否可以下载这个文件名的文件呢。
看一下这个目录中都有什么文件
将kb.png 更改为 ai.png 看效果,ai.png被成功下载
结合目录穿越漏洞下载index.php文件
将kb.png更改为../../../../index.php 看效果,index.php被成功下载
更改后网址:
http://172.28.25.41/pikachu/vul/unsafedownload/execdownload.php?filename=../../../../index.php
绕过思路
1、url编码绕过
使用 %2e 代替 . | ?name=%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd |
使用 %2f 代替 / | ?name=..%2f..%2f..%2f..%2f..%2fetc%2fpasswd |
使用 %2e%2e%2f 代替 ../ | ?name=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd |
常用绕过一般是后两种,点一般不会被过滤,因为文件名中间也会存在一个 .
2、二次编码绕过
使用 %25%32%65 代替 . | ?name=%252e%252e/%252e%252e/%252e%252e/%252e%252e/etc/passwd |
使用 %25%32%66 代替 / | ?name=..%252f..%252f..%252f..%252f..%252fetc%252fpasswd |
使用 %25%32%65%25%32%65%25%32%66<br><br>代替 ../ | ?name=%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252fetc%252fpasswd |
3、将 / 替换为 \ 绕过
4、%00混淆绕过
?name=.%00./.%00./.%00./.%00./etc/passwd
5、双写绕过
有些代码会进行过滤,会把 ../ 替换为空,利用 ....// 代替 ../ ,利用 ..// 代替 /
漏洞利用
- 下载常规的配置文件
- 下载各种日志文件
- 下载web应用程序文件
linux系统常见利用文件:
/root/.ssh/ - 这是root用户的SSH密钥目录。
authorized_keys - 包含允许通过SSH登录到系统的公钥。
id_rsa - 用户的私钥。
id_rsa.keystore - 这似乎是一个错误或拼写错误,通常应该是id_rsa。如果是密钥存储文件,它可能包含私钥的加密版本。
known_hosts - 包含已知的主机公钥,用于SSH连接时的主机验证。
/etc/passwd - 用户账户信息数据库,包含系统上所有用户的列表。
/etc/shadow - 加密的用户密码数据库。
/etc/issue - 登录提示信息文件,当用户登录时显示。
/etc/fstab - 文件系统挂载信息文件,定义了系统启动时哪些文件系统需要挂载以及挂载的选项。
/etc/host.conf - 定义主机名解析的行为。
/var/log/xferlog - 记录FTP传输的日志文件。
/var/log/cron - 记录cron守护进程的日志。
/etc/(cron.d/|crontab) - cron的配置文件和目录,用于定时任务。
/var/log/secure - 记录与安全相关的日志文件,如SSH登录尝试。
/etc/rc.local - 系统启动时执行的脚本。
/etc/motd - 消息 of the day,用户登录时显示的信息。
/etc/sysctl.conf - 内核参数配置文件,用于调整系统内核的行为。
/var/log/syslog - 系统日志文件的汇总。
/etc/environment - 系统环境变量设置。
/etc/inputrc - readline库的配置文件,影响命令行编辑。
/etc/default/useradd - 用户添加时的默认配置。
/etc/login.defs - 登录系统的默认设置。
/etc/skel/ - 用户创建新账户时,此目录下的文件会被复制到新用户的家目录中。
/sbin/nologin - 当系统不希望用户登录时,显示的消息。
/var/log/message - 旧的syslog日志文件位置(现代系统可能使用/var/log/syslog)。
/etc/httpd/conf/httpd.conf - Apache HTTP服务器的配置文件。
/etc/mtab - 当前挂载的文件系统列表。
/etc/ld.so.conf - 动态链接器配置,定义了程序运行时查找共享库的路径。
/etc/my.cnf - MySQL数据库的配置文件。
/proc/mounts - 当前挂载的文件系统的信息,与/etc/mtab相似,但通常用于程序读取。
/proc/config.gz - 内核配置文件的压缩版本。
/var/lib/mlocate/mlocate.db - mlocate数据库文件,用于快速查找文件。
/proc/self/cmdline - 当前进程的命令行参数。
tomcat/ - Tomcat服务器相关的文件和目录。
conf/server.xml - Tomcat的主要配置文件。
webapps/ROOT/WEB-INF/classes/database.properties - 应用程序的数据库连接属性文件。
conf/tomcat-users.xml - Tomcat的用户管理配置文件。
windows系统常见利用文件:
C:\windows\system32\config\SAM
SAM是Windows系统中存储本地用户账户安全信息的数据库文件
C:\boot.ini
这个文件是Windows XP及更早版本中的启动配置文件。它包含了系统启动时需要的信息,如启动哪个操作系统、启动参数等。在Windows Vista及更高版本中,这个功能被BCD(Boot Configuration Data)所替代,该文件通常位于C:\Boot\BCD。
C:\Windows\System32\inetsrv\MetaBase.xml
这个文件是Internet Information Services (IIS) 元数据库的一个备份。IIS元数据库存储了IIS服务器配置的所有信息,包括网站、应用程序池、虚拟目录等的设置。MetaBase.xml文件通常在IIS配置更改时自动更新。
C:\Program Files\mysql\my.ini
这是MySQL数据库的配置文件。它包含了MySQL服务器启动和运行所需的配置信息,如端口号、日志文件位置、内存分配等。
C:\Program Files\mysql\data\mysql\user.MYD
这是MySQL数据库中的一个数据文件,通常存储用户账户信息。它是MySQL的系统数据库mysql中的一部分,用于存储用户账户、权限等信息。MYD文件是MyISAM存储引擎的数据文件。
C:\Windows\php.ini
这是PHP的配置文件。它包含了PHP解释器运行时的配置信息,如内存限制、错误报告设置、扩展模块加载等。
C:\Windows\my.ini
在某些情况下,这可能是另一个MySQL配置文件。然而,通常MySQL的配置文件会放在C:\Program Files\mysql\目录下。如果C:\Windows\my.ini存在,它可能是为特定应用或特定环境定制的MySQL配置。
漏洞防御
- 过滤特殊字符点 ".",屏蔽目录穿越。
- 严格判断用户输入的参数格式
- 开启路径访问限制(php语言开启open_basedir配置)
任意文件上传漏洞
漏洞原理
服务端对用户上传的文件没有进行严格的过滤,导致可以上传任意文件,含恶意脚本(.exe\.php\.jsp\.asp)的文件,导致任意文件上传漏洞。
文件上传功能在web应用系统很常见,比如很多网站注册的时候需要上传头像、上传附件等等。当用户点击上传按钮后,后台会对上传的文件进行判断 比如是否是指定的类型、后缀名、大小等等,然后将其按照设计的格式进行重命名后存储在指定的目录。 如果说后台对上传的文件没有进行任何的安全判断或者判断条件不够严谨,则攻击着可能会上传一些恶意的文件,比如一句话木马,从而导致后台服务器被webshell。
前端JS绕过
通过前端js代码对上传的文件进行效验。
漏洞示例1
我们上传一个非图片格式的文件,如下图所示,被限制了。
谷歌浏览器直接删除οnchange="checkFileExt(this.value)"没有效果,还是弹框无法绕过js,
单击小齿轮图标进入设置
找到停止js脚本选项,将其启用,下图所示位置
再次上传可以直接上传
访问上传文件3.php效果
火狐浏览器直接删除οnchange="checkFileExt(this.value)"可以直接绕过。
漏洞示例2
第一步:将要上传的文件(我这里用4.php举例)的扩展名更改为符合上传规则的图片格式(4.jpg)。
第二步:选择4.jpg文件
第三步:开启Burp抓包工具 ,单击开始上传,抓取数据包。
第四步:放包,成功绕过前端js效验,文件上传成功
第五步:访问一下刚上传的文件
upload-labs pass-01
直接上传webshell被拦截
查看代码 、前端js效验
谷歌浏览器设置停止js脚本运行,成功绕过效验。
成功拿到webshell
服务端绕过
通过后端代码对上传文件进行效验。
upload-labs示例演示
pass-02 白名单 mime类型
直接上传webshell,提示文件类型不正确。
利用purp抓个包,将application/octet-stream更改为image/jpeg 后放包
成功上传webshell,复制图片地址,在新窗口打开
成功拿到webshell
pass-03 黑名单 phtml、php3、php5
直接上传webshell,提示:不允许上传.asp,.aspx,.php,.jsp后缀文件!
更改文件后缀名为php3或php5
成功上传webshell.php3
右键复制图片地址,在新窗口打开,看看是否能够解析webshell.php3
执行php3、php5前提条件,修改Apache 配置文件
重启服务器,重新访问看效果
pass-04 黑名单 .htaccess
简单了解一下.htaccess文件
.htaccess文件是apache服务器中的一个配置文件,允许在运行时覆盖Apache服务器的默认配置。
创建.htaccess文件,里面写三行代码。
<FilesMatch "">
SetHandler application/x-httpd-php
</FilesMatch>
创建.htaccess文件时,用notepad++工具创建
上传webshell.php3文件,被拒绝。
上传更改后缀名的webshell.jpg文件,成功上传,复制图片地址,在新窗口访问效果。
上传.htaccess文件,成功上传
再次访问webshell.jpg文件,看效果。
pass-05 黑名单 大小写混合
将文件后缀名大小写混合比如.php 更改为.pHp 或 phP
上传正常后缀名结尾的php文件被拒绝
.php更改文件后缀名为.pHP后,再次上传,成功绕过,复制图片地址,在新窗口打开,看效果。
pass-06 黑名单 空格和点配合
利用windows系统特性,上传文件利用burp抓包,将文件名后加上空格和点,在上传的服务端保存时,windows文件系统会自动去掉点和空格,保存为正常后缀名的文件(1.php . 上传后 1.php)
选择要上传的文件,打开burp抓包工具,抓取数据包
pass-07 黑名单 点和空格绕过
pass-07原理同pass-06,操作方式也一样,都是抓取数据包,文件后缀名后加点和空格(1.php更改后1.php. )。这里就不演示了
pass-08 黑名单 文件流特性::$DATA
在windows系统中,会把::$DATA之后的数据当成文件流处理,不会检测后缀名,而且保留::$DATA之前的文件名,目的就是绕过检查上传文件的后缀名。
Burp抓包,发送到reperter重放器,修改数据包"webshell.php"更改为"webshell.php::$DATA" 发送数据包。
在响应数据包中找到img 标签src= 文件名,复制文件名,拼接网址到新窗口访问。
pass-09 黑名单 点空格点绕过
pass-09同理pass-06,操作方式也一样,都是抓取数据包,文件后缀名后加点和空格和点(1.php更改后1.php. .)。这里就不演示了
pass-10 黑名单 双写绕过
选择要上传的文件
1、抓包,将"webshell.php"更改为"webshell.pphphp"
2、发送数据包
3、在响应中找到img标签中src属性"../upload/webshell.php"这就是上传到服务器中的文件。
4、拼接网址“http://172.28.25.41/upload/upload/webshell.php”直接访问。
pass-11 白名单 %00截断
php低版本出现的漏洞,版本小于5.3.4
选择上传文件“webshell.php”
抓包发送到重放器,改包 将“../upload/”更改为“../upload/webshell.php%00” 将“webshell.php”更改为“webshell.jpg” 发送数据包
pass-12 白名单 0x00绕过
选择上传文件"webshell.php"
burp抓包,发送到重放器,修改数据包。
利用Hex 将php后的空格20改为00
发送数据包,看到响应效果
<img src="../upload/webshell.php /1620240328213955.jpg">
拼接网址直接访问,拿到webshell
pass-13 检查内容 文件头部检查
图片的格式在防护中通常是不会使用后缀进行判断过滤,文件头是文件开头的一段二进制码,不同类型的图片也就会有不同的二进制头。用记事本打开gif图片可以看到(GIF89a)
在图片末尾添加php探针语句,准备gif图片,含有php探针语句的php文件,放到一个文件夹中,cmd进入到文件所在目录,执行下方命令:
>copy 1.gif /b + 4.php /a info.gif
上传刚制作好的图片马
右键图片,复制图片地址,在浏览器中访问,正常显示图片,添加的代码没有被解析执行
制作好的图片马想要解析出来这个图片,还得有文件包含漏洞。
构造下方地址,访问刚上传的图片
http://172.28.25.41/upload/include.php?file=upload/8520240329081406.gif
pass-14 检查内容 image_type_to_extension()
image_type_to_extension() 函数用于获取图片后缀
分析代码
function isImage($filename){
$types = '.jpeg|.png|.gif';
if(file_exists($filename)){
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);
if(stripos($types,$ext)>=0){
return $ext;
}else{
return false;
}
}else{
return false;
}
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
getimagesize() 函数用于获取图像尺寸及相关信息 。索引 2 给出的是图像的类型,返回值是数字
1 = GIF | 2 = JPG | 3 = PNG | 4 = SWF | 5 = PSD |
6 = BMP | 7 = TIFF(intel byte order) | 8 = TIFF(motorola byte order) | 9 = JPC | 10 = JP2 |
11 = JPX | 12 = JB2 | 13 = SWC | 14 = IFF | 15 = WBMP |
16 = XBM |
测试方法和pass-13是一样的,前提都需要存在相关的漏洞,这里就不演示了。
pass-15 检查内容 exif_imagetype()
exif_imagetype () 用来判断一个图像的类型
分析代码
function isImage($filename){
//需要开启php_exif模块
$image_type = exif_imagetype($filename);
switch ($image_type) {
case IMAGETYPE_GIF:
return "gif";
break;
case IMAGETYPE_JPEG:
return "jpg";
break;
case IMAGETYPE_PNG:
return "png";
break;
default:
return false;
break;
}
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
pass-16 检查内容 二次渲染
将用户上传过来的文件数据重新读取保存到另外一个文件中,那么在读取写入的过程中,将特
殊的数据剔除掉了。
分析代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
$filename = $_FILES['upload_file']['name'];
$filetype = $_FILES['upload_file']['type'];
$tmpname = $_FILES['upload_file']['tmp_name'];
$target_path=UPLOAD_PATH.'/'.basename($filename);
// 获得上传文件的扩展名
$fileext= substr(strrchr($filename,"."),1);
//判断文件后缀与类型,合法才进行上传操作
if(($fileext == "jpg") && ($filetype=="image/jpeg")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromjpeg($target_path);
if($im == false){
$msg = "该文件不是jpg格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".jpg";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagejpeg($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else if(($fileext == "png") && ($filetype=="image/png")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefrompng($target_path);
if($im == false){
$msg = "该文件不是png格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".png";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagepng($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else if(($fileext == "gif") && ($filetype=="image/gif")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromgif($target_path);
if($im == false){
$msg = "该文件不是gif格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".gif";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagegif($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else{
$msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
}
}
对比上传前图片内容,上传后的图片内容
将一个正常显示的图片,上传到服务器。寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传。具体实现需要自己编写Python程序,人工尝试基本是不可能构造出能绕过渲染函数的图片webshell的。
pass-17 条件竞争 时间竞争
利用条件竞争删除文件时间差绕过。服务器先把文件保存 然后再检查上传的文件是否合法 不合法再进行删除操作。
分析代码
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_name = $_FILES['upload_file']['name'];
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_ext = substr($file_name,strrpos($file_name,".")+1);
$upload_file = UPLOAD_PATH . '/' . $file_name;
if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
}else{
$msg = '上传出错!';
}
}
上传一个符合规则的图片,上传成功后,右键图片复制图片地址,获取到图片地址
http://172.28.25.41/upload-labs/upload/5720240329193332.gif
选择webshell文件,利用burp抓包、发送到攻击器
生成3000个数据包
上传文件的数据包已经设置完毕,接着再抓一个访问上传文件的数据包,步骤同上。
开启(点击开始攻击)上传文件攻击器,接着开启(点击开始攻击)访问文件攻击器。
批量上传,让程序处理不过来,接着就访问,如果被访问到文件被占用就无法删除。
pass-18 条件竞争 重命名
pass-18同理pass-17,快速批量上传上千个文件,让程序来不及重命名。
pass-19 0x00绕过
pass-19同理pass-12
pass-20
Pass-20来源于CTF,请审计代码!这是代码审计出来的漏洞,直接渗透测试其实很难发现的。
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
//检查MIME
$allow_type = array('image/jpeg','image/png','image/gif');
if(!in_array($_FILES['upload_file']['type'],$allow_type)){
$msg = "禁止上传该类型文件!";
}else{
//检查文件名
$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
if (!is_array($file)) {
$file = explode('.', strtolower($file));
}
$ext = end($file);
$allow_suffix = array('jpg','png','gif');
if (!in_array($ext, $allow_suffix)) {
$msg = "禁止上传该后缀文件!";
}else{
$file_name = reset($file) . '.' . $file[count($file) - 1];
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' .$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$msg = "文件上传成功!";
$is_upload = true;
} else {
$msg = "文件上传失败!";
}
}
}
}else{
$msg = "请选择要上传的文件!";
}
双文件上传绕过
准备含有一句话木马的文件(4.php),复制4.php文件,后缀名更改为.jpg
选择要上传的文件(4.jpg),利用burp抓包
修改数据包
放包后,服务端效果。
访问刚上传的4.php文件效果