简单php代码审计与文件包含漏洞介绍 – 作者:ATL安全团队

近日刚刚入门CTF,在攻防世界作了一些WEB方向的题,在高手进阶区发现多数涉及到文件包含漏洞的题都会给出源代码,让我们先进行审计再利用漏洞。很多题都是乍一看以为很难,仔细观察后发现难度并不高。

0x01 读懂PHP代码

我们就以攻防世界WEB方向高手进阶区的web2为例:通过这道题可以接触到一些PHP函数,和一些简单的逆向思路,很适合新手入门。那么我就来带大家一同了解一下解题的思路。

题目的描述就只有解密,于是我们首先来看题目源码:

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";

function encode($str){
    $_o=strrev($str);
    // echo $_o;
        
    for($_0=0;$_0<strlen($_o);$_0++){
       
        $_c=substr($_o,$_0,1);
        $__=ord($_c)+1;
        $_c=chr($__);
        $_=$_.$_c;   
    } 
    return str_rot13(strrev(base64_encode($_)));
}

highlight_file(__FILE__);
/*
   逆向加密算法,解密$miwen就是flag
*/
?> 

这里还有高亮的版本方便大家查看:图片[1]-简单php代码审计与文件包含漏洞介绍 – 作者:ATL安全团队-安全小百科

接下来是解题的思路:

首先要明白各个函数的作用:

函数:strrev([字符串])

作用:翻转字符串

示例:strrev(“abc”) 输出:cba

函数:substr([字符串],[从几位开始],[截取多少位])

作用:返回字符串的一部分

示例:substr(“abcdef”,3,2) 输出:de

函数:ord([字符串])

作用:返回字符串首个字符的ASCII值

示例:ord(“S”) 输出:83

ord(“Shanghai”) 输出:83

函数:chr([ASCII值])

作用:从指定的ASCII值返回字符,可以被指定为十进制、八进制、或16进制

八进制值被定义为带前置0,十六进制被指定为带前置0x

示例:chr(61)  // 十进制 输出:=

chr(061)  // 八进制值 输出:1

chr(0x61)  // 十六进制值 输出:a

函数: str_rot13([字符串])

作用:对字符串执行ROT13编码。

ROT13编码:把每一个字母在字母表中向前移动 13 个字母。数字和非字母字符保持不变。

注释:编码和解码都是由相同函数完成的,如果把已编码的字符再次编码,则会解码。

示例:str_rot13(“I love Shanghai”)  输出:V ybir Funatunv

str_rot13(“V ybir Funatunv”)  输出:I love Shanghai

函数:base64_encode([字符串])和base64_decode([字符串])

作用:对字符串进行base64编码和解码。

明白各个函数的作用之后阅读代码,简单梳理就可以明白代码作用:

整个加密的流程就是:

  1. 将字符串翻转
  2. 循环取出每个字符的ASCII值+1后再转换回字符
  3. 之后对字符串进行base64编码,然后再翻转回来,最后进行ROT13编码。

于是我们解密的思路就很清晰了:

整个解密的流程就是:

  1. 对密文进行ROT13编码先将ROT13编码还原。
  2. 然后将字符串翻转,然后进行base64解码。
  3. 取出每个字符的ASCII值-1后在转换回字符。
  4. 最后对字符串再次翻转就可以的到最后解密的明文。

编写PHP代码如下:

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws"; 
$_="";
$a= base64_decode(strrev(str_rot13($miwen))); 
for($_0=0;$_0<strlen($a);$_0++){   
        $_c=substr($a,$_0,1);
        $__=ord($_c)-1;
        $_c=chr($__);
        $_=$_.$_c;   
} 
$_o=strrev($_);
echo $_o."</br>";
highlight_file(__FILE__);
?>

运行之后即可得到明文:

运行结果:

图片[2]-简单php代码审计与文件包含漏洞介绍 – 作者:ATL安全团队-安全小百科

做完了这一道题,我们知道了如何去读懂PHP代码,并且能够分析出代码的作用。接下来让我们再来看一看文件包含漏洞。

0x02 什么是文件包含漏洞

在程序开发时,开发人员希望代码更加灵活,所以通常会把被包含的文件设置为变量,这样方便进行动态调用,但是如果动态包含的文件路径的参数可以从客户端修改,那么通过修改动态调用的参数,就可以从客户端调用任意文件,从而造成文件包含漏洞。

漏洞产生原因:

网页中实现了动态文件包含(包含的文件路径为一个变量);

动态包含的文件路径参数在客户端可以修改(通过POST或GET等方式从客户端获取);

文件包含的特点

无视文件后缀名读取文件:

在包含文件时,PHP会直接读取文件的源码,不会去考虑文件的类型,就算是包含图片文件时,也会直接读取图片的源码。

无条件解析代码:

文件包含在读取文件源码的同时,如果遇到了符合PHP语法规范的代码,也会去执行。这样我们将一个PHP文件不管后缀名改成什么,在包含时都会正常解析。

文件包含类型:

文件包含可以分为:本地文件包含和远程文件包含。

本地文件包含就是可以读取和打开本地文件。

远程文件包含则是可以远程加载文件。(通过HTPP、FTP、PHP 伪协议)

想要远程文件包含,需要在php.ini中开启远程文件包含。(allow_url_include = on)

0x03 相关函数

在PHP中提供了四个文件包含的函数,他们之间有略微的区别:

函数

区别

include( )

文件包含失败时,会产生警告,但是脚本会继续运行。

include_once( )

与include( )作用是一样的,只是文件只会被包含一次。

require( )

文件包含失败时,会产生错误,会直接结束脚本执行。

require_once( )

与require( )作用是一样的,只是文件只会被包含一次。

0x04 利用方式

文件包含漏洞的利用方式有以下几种。

读取敏感文件:

我们可以利用文件包含文件读取系统中的任意文件,来查看系统的配置、日志等信息。

直接包含木马文件:

可以配合网站的上传功能,上传一个图片木马等文件,然后利用包含漏洞包含图片木马就可以正常解析。

PHP封装协议:

通过PHP的file协议访问本地系统文件:

?[参数名]=file://[文件路径]

传输PHP文件:

?[参数名]=php://filter/read=convert.base64-encod/resource=[php文件]

之后将得到的字符进行base64解码即可。

执行PHP命令:

?[参数名]=php://input

执行的PHP代码需要通过POST方式上传。

实战演示:

这里我们再以攻防世界中的另一道题:Web_php_include,来演示漏洞的利用。

这道题没有什么描述,那么我们直接进入试验场景。

题目源码如下:

<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
    $page=str_replace("php://", "", $page);
}
include($page);
?>

这里同样有高亮的版本供大家查看:

图片[3]-简单php代码审计与文件包含漏洞介绍 – 作者:ATL安全团队-安全小百科

上来就是一串php代码,代码很简单,我们就先看看这段代码是什么意思。

首先我们要知道这中间用到的函数的作用:

函数:strstr([被查找的字符串],[要查找的字符串])

作用:寻找某字符串在另一字符串中第一次出现的位置,并返回查找到字符串的位置之后的全部字符串。

示例:strstr(“Helloworld!”,”world”) 返回:world!

备注:当没有查找到符合的字符串时,strstr函数会返回 FALSE(布尔值)。

此函数还有一个可选参数。默认值为 “false” 的布尔值。如果设置为 “true”,它将返回要查找字符串第一次出现之前的字符串部分。如:strstr(“Helloworld!”,”world”,true) 返回:Hello

同时此函数对大小写敏感,如需进行大小写不敏感的搜索,可以使用 stristr()。

如果只是要査找某字符串是否存在于另一字符串中,则建议使用 strpos这个函数, strpos函数执行的速度会比 strstr快,而且使用更少的内存。

函数:str_replace([查找的字符串],[替换的字符串],[被查找的字符串])

作用:替换字符串中的一些字符

示例:str_replace(“world”,”Peter”,”Hello world!”) 返回:Hello Peter!

备注:该函数是区分大小写的。可以使用 str_ireplace() 函数执行不区分大小写的搜索。

同时该函数还有一个可选参数,为一个变量,作用是对替换数进行计数。

明白各个函数的作用之后阅读代码,就可以明白代码作用:

获取hello参数中的值,显示在页面中。

获取page参数中的值,检测其中是否有“php://”如果有就将“php://”替换为“”(相当于删除字符串中的“php://”)

然后包含page参数中的文件。

分析题目的本意应是阻止我们使用php伪协议去包含任意文件。

比较简单的解决方法就是strstr和str_replace都是区分大小写的,只需要将php大写,变为PHP://即可绕过代码的过滤。

但是在这里我们使用一种比较巧妙的方法:

首先经过测试我们看到传入的hello参数会回显到页面中:图片[4]-简单php代码审计与文件包含漏洞介绍 – 作者:ATL安全团队-安全小百科

然后我们尝试直接传入php代码结果发下代码会直接被注释掉,并不会执行:

图片[5]-简单php代码审计与文件包含漏洞介绍 – 作者:ATL安全团队-安全小百科

这时我们可以通过http协议直接包含自身,并向包含的文件中传入php代码,来使php代码执行。

构造URL:

http://220.249.52.133:43238/?page=http://127.0.0.1/?hello=<?system(‘ls’)?>

这时我们的php代码就会运行:图片[6]-简单php代码审计与文件包含漏洞介绍 – 作者:ATL安全团队-安全小百科

可以看到目录下有三个php文件,其中fl4gisisish3r3.php十分可疑,我们直接来看一下他的内容:

http://220.249.52.133:43238/?page=http://127.0.0.1/?hello=<?show_source(“fl4gisisish3r3.php”)?>

图片[7]-简单php代码审计与文件包含漏洞介绍 – 作者:ATL安全团队-安全小百科

这样我们就得到了我们需要的flag:

ctf{876a5fca-96c6-4cbd-9075-46f0c89475d2}

我们就成功利用文件包含漏洞解出了这一道题。

来源:freebuf.com 2020-11-12 14:06:34 by: ATL安全团队

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论