ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SQLi-Labs靶场搭建实战:PHP版本、数据库初始化与启动排错

SQLi-Labs靶场搭建实战:PHP版本、数据库初始化与启动排错 很多人学 Web 安全的第一个门槛不是注入思路而是靶场根本跑不起来。DVWA 点两下就能进Pikachu 装完就能打可轮到 SQLi-Labs一堆人卡在页面白屏数据库连接失败Call to undefined function mysql_connect这几行报错上折腾一整晚最后放弃。SQLi-Labs 这套靶场本身不复杂它是 Audi-1 开源的一套 PHP MySQL 注入练习平台从 Less-1 到 Less-65几乎把联合查询、报错注入、布尔盲注、时间盲注、堆叠查询、POST 型、Cookie 型、HTTP 头注入这些经典场景都覆盖了一遍是练手 SQL 注入最系统的一套环境。但它有个老的毛病——代码年代久远对 PHP 版本和数据库配置相当挑剔。这篇就把搭建过程从环境选型、源码落位、数据库初始化到启动失败排查完整走一遍适合刚入门想搭本地环境的新手也适合装了半天没装上的朋友对症下药。1. 搭之前先搞清楚SQLi-Labs 到底解决什么问题1.1 它和 DVWA、Pikachu 的定位差异同样叫靶场DVWA、Pikachu、SQLi-Labs 的定位其实完全不同。DVWA 是综合性靶场一个功能模块对应多种漏洞类型适合建立漏洞全景的认知Pikachu 偏教学化每个漏洞都配了说明和提示适合当教材对照着做而 SQLi-Labs 是垂直深度型它把SQL 注入这一件事拆成了 65 个关卡每一关考察的注入点和防护思路都不一样。这个差异直接决定了你搭建时的心态。DVWA 装不上你换个整合包就完事了SQLi-Labs 装不上你没法用别的靶场替代它的练习量——因为它是目前单点覆盖最全的注入练习环境。所以搭建这件事值得认真对待不要用随便找个一键包糊上去的思路去糊它后面关卡里一旦涉及字符集、HTTP 头、编码转换这些细节环境本来就不干净会让你分不清是靶场问题还是自己思路问题。另外提一句网上还有不少同类环境可以搭配使用DVWA 适合练完综合漏洞后回头做对比Vulnstack 和红日系列偏内网渗透场景vulhub 偏容器化的漏洞复现。它们和 SQLi-Labs 不是替代关系是不同阶段的配套。你现在的目标很明确——先把这套注入练习环境稳稳跑起来。1.2 学习路径上的实际作用我见过不少人问sqli-labs 通关有没有意义。说实话单纯背 payload 通关没意义但把它当作手写注入语句的肌肉记忆训练场就很有价值。第一到第十关让你把联合查询的字段数判断、回显位确定、库表字段枚举这一整条链路走顺后面的盲注关卡逼着你用二分法和条件判断去猜数据这种没有回显还得拿数据的思维在真实测试场景里出现频率极高。还有一点常被忽略SQLi-Labs 是练工具配合的好地方。手工通了之后再拿 Burp Suite 去抓包改包、挂字典批量跑你会明显感受到工具替你省下了哪些重复劳动。但前提还是那句——环境得先干净、稳定、能复现否则你连这一关到底是盲注还是报错注入都没法稳定验证。1.3 搭建前必须有的心理准备SQLi-Labs 的源码最后一个大版本更新已经是很久以前的事了那个年代的 PHP 还在用mysql_*系列函数而这类函数在 PHP 7.0 就被标记废弃、PHP 7.0 之后正式移除。所以你会看到很多教程让你装 PHP 5.6 或者 PHP 7.0这不是他们偷懒是这套代码真的跑不了高版本。同时它对magic_quotes_gpc这个早已被移除的配置项有依赖某些关卡的行为会受它影响。理解了这一点你就明白搭建的核心矛盾在哪现代环境默认的 PHP 版本太高而靶场代码太老。解决办法无非两条路——要么把环境降到靶场能接受的版本要么给靶场代码打补丁。前者省事但影响你本机其它项目后者干净但需要动源码。下面会分别说清楚。2. 环境选型三条部署路线怎么选2.1 三种路线的取舍对比搭建 SQLi-Labs本质上只需要三样东西Web 服务器Apache 或 Nginx、PHP 运行环境、MySQL 数据库。区别只在于你怎么把它们凑齐。目前主流是三条路路线代表方案优点缺点适合谁集成面板phpstudy、XAMPP、宝塔面板版本可切换、图形化、装完即用面板本身占资源、配置被封装不易理解新手首选手工编译/包管理Linux 下 apt 装 LAMP环境透明、可控性最高配置项多、排错要懂原理想搞懂底层的人容器化Docker 拉现成镜像秒级部署、环境隔离、可反复重建需要懂 Docker 基本操作有容器基础的人新手我一般直接推荐集成面板尤其是 phpstudy因为它能一键切换 PHP 版本正好解决上面说的PHP 版本太高这个死结。你不需要懂 Apache 的虚拟主机配置也不需要手动去改 php.ini点几下就能把环境调成靶场能接受的版本。2.2 PHP 版本是这套靶场的生死线这是整个搭建过程里最关键的一个决策点单独拎出来讲。SQLi-Labs 官方代码依赖mysql_connect()、mysql_query()、mysql_error()这一系列函数理论上最舒服的版本是PHP 5.4 到 5.6。如果你装的是 PHP 7.4 或者 PHP 8.x访问首页就会出现致命错误页面直接白掉或抛出未定义函数的异常。所以在集成面板里第一件事就是把 PHP 版本切到 5.6。操作路径通常是打开面板的软件管理或网站页面找到 PHP 版本切换选项选中 5.6 并应用。切换之后重启一下 Web 服务。如果你因为其它项目必须留在 PHP 8 环境那就得走打补丁这条路。核心思路是把所有mysql_*函数替换成mysqli_*或者 PDO 的等价写法。这个工作量不小因为涉及sql-connections目录下多个文件以及每一关的入口文件。社区里有人做过兼容补丁思路基本是// 原始写法PHP 5 可用PHP 7 报错 $con mysql_connect($host, $user, $pass); // 兼容写法 $con mysqli_connect($host, $user, $pass, $dbname);提示如果你只是单纯想学注入别跟自己较劲去改源码。装个 PHP 5.6 的独立环境成本远低于改造整个靶场。改源码看似干净实际容易出现某几关行为不一致的隐性坑。2.3 Docker 路线的具体操作如果你本机已经有 Docker这条路线其实最省心因为它把 PHP 版本、MySQL、Apache 全部打包好了不用你操心依赖。常见做法是拉取社区维护的 SQLi-Labs 镜像然后把 80 端口映射出来# 拉取镜像 docker pull acgpiano/sqli-labs # 启动容器映射到本机 8888 端口避免和已有服务冲突 docker run -dt --name sqli-labs -p 8888:80 acgpiano/sqli-labs # 查看容器状态 docker ps启动后浏览器访问http://localhost:8888就能看到靶场首页。容器的好处是就算你把数据库搞乱了删掉容器重新docker run一遍几十秒就能回到干净状态。练盲注类关卡时数据库会被你反复写脏这个一键重置能力很实用。但 Docker 路线也有个小坑容器内 MySQL 的认证方式、字符集可能和手工搭建的不一样某些依赖特定字符集的关卡表现会有差异。如果你追求和教程完全一致的行为还是集成面板更稳妥。3. 源码落位与配置文件的对应关系3.1 目录结构先看明白再动手源码从代码托管平台搜索 SQLi-Labs 就能找到作者是 Audi-1。下载解压后先别急着往 Web 根目录扔花两分钟看下目录结构后面排错能省一半时间。核心目录大致是这样根目录下是Less-1、Less-2一直到Less-65的文件夹每一关是独立入口这是它和 DVWA 最大的结构差异。sql-connections目录是整套系统的公共心脏数据库连接参数、建表建库脚本、公共函数都在这。index.html和index.php是首页导航里面有初始化数据库的按钮。理解这一点很重要靶场不是一个站点 多个路由而是几十个独立小站点共享一套数据库配置。所以数据库连不上是全部 65 关同时挂掉如果只有个别关卡报错那问题多半出在那一关的代码上跟环境无关。这个判断能帮你快速缩小排查范围。3.2 db-creds.inc 与数据库账号的对应关系这是搭建过程中最容易出错的地方。sql-connections目录下有个db-creds.inc文件整套靶场靠它连接数据库内容大致是这几行?php $host localhost; $dbuser root; $dbpass root; $dbname security; ?你需要做的就是让这里的$dbuser和$dbpass与你本机 MySQL 的实际账号密码完全一致。很多人装完之后页面能开但初始化报错八成就是这里没对上——比如面板里 MySQL 密码是root123文件里还是默认的root。我的建议是别去改 MySQL 的密码来迁就文件直接改文件更安全。因为改数据库密码可能影响本机其它项目而改一个靶场专用的配置文件风险为零。改完之后保存别漏了分号和引号PHP 配置文件语法错误会导致整个连接逻辑失效。另外$dbname这一项要留意不同版本源码里的默认库名可能不一样有的是security有的是security加别的后缀。这个值不是随便填的它必须和建库脚本里创建的库名对应。稳妥的做法是先打开sql-connections里的建库 SQL 文件看一眼库名再回头核对配置文件。3.3 站点根目录与访问路径设置把解压出来的整个 SQLi-Labs 文件夹放到 Web 服务器的站点根目录下。集成面板的话站点根目录通常是面板安装目录下的WWW或wwwrootApache 手工装的话一般是/var/www/html。放好之后访问地址就取决于你的端口和目录名。假设面板用的 80 端口文件夹名叫sqli-labs那么地址就是http://localhost/sqli-labs/。如果访问后是目录列表而不是靶场首页说明默认文档顺序有问题检查一下目录下是否有index.php且服务器允许它作为默认页。还有一种情况是首页能开但点任何一个 Less 都跳转到http://localhost/Less-1/这种丢了子目录的地址。这通常是源码里用了相对根路径的跳转解决办法是把文件夹直接放在站点根目录下、不要嵌套额外层级或者配置一个指向该文件夹的虚拟主机让它的根路径就是靶场目录。4. 数据库初始化setup-db 在背后做了什么4.1 正确的首次访问顺序SQLi-Labs 第一次访问不能直接点关卡得先初始化数据库。打开首页index.php页面顶部通常会有一个入口写着类似 Setup/reset Database for labs 的链接点击它会执行sql-connections下的初始化脚本。这个脚本干的事情其实很明确创建security数据库建好几张表users、emails、uagents等然后把预设的测试数据插进去。你后面所有关卡的注入目标都是往这几张表里查数据。所以这一步没跑成功后面 65 关全部是空的查询会返回表不存在。点击之后如果看到一排绿色的成功提示说明环境通了。如果看到红色的报错先别慌报错信息本身就是最好的线索下一节专门讲怎么读这些报错。4.2 手动导入的兜底做法有时候图形化初始化会因为权限或字符集问题失败这时候可以走命令行兜底。思路是直接用数据库客户端连上去手动执行建库脚本# 登录 MySQL mysql -u root -p # 创建数据库并指定字符集 CREATE DATABASE security DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; # 切换数据库 USE security; # 导入建表脚本 source /path/to/sqli-labs/sql-connections/db-schema.sql;这种方式的好处是完全绕开了 PHP 层的报错能让你确认到底是数据库权限问题还是 PHP 连接问题。如果手动导入成功、图形化初始化失败那问题就在 PHP 连接配置上如果手动导入也失败那就是数据库账号或者脚本本身的问题。这个二分法在实际排错里非常好用。手动导入完还要记得把配置文件里的$dbname核对一遍确保指向security。有些版本的建库脚本会用不同的库名别想当然。5. 启动失败排查一条从表象到根因的链路5.1 页面白屏但 HTTP 返回 200这是最让人头大的一类问题——浏览器一片空白但看网络面板状态码是 200说明请求成功、服务正常问题出在 PHP 执行阶段。白屏几乎必然是致命错误被display_errors关掉了。第一步打开php.ini把这两个开关打开display_errors On error_reporting E_ALL改完重启 Web 服务再访问一次白屏就会变成带具体文件行号的错误信息。这一步是所有排错的前提看不到错误信息就是在盲猜。打开之后最常见的两种报错一种是Call to undefined function mysql_connect()这就是前面说的 PHP 版本过高问题回到第 2.2 节切换版本即可。另一种是Access denied for user rootlocalhost这是数据库账号密码不匹配回到 3.2 节核对配置文件。5.2 数据库连接类报错的逐层定位数据库连不上可能是四层原因从外到内依次排查账号密码不对。用命令行mysql -u root -p手动登录一次确认密码正确。这一步能排除 90% 的问题。数据库服务没启动。面板里看 MySQL 服务状态绿色才是运行中。有时候是端口冲突导致启动失败。权限问题。如果用的是非 root 账号要确认它有没有security库的读写权限。图形化面板一般用 root问题不大。连接地址问题。配置文件里写的是localhost如果你改成了 IP而 MySQL 只监听本地回环就会连不上。这种情况要么改回localhost要么给 MySQL 开放对应主机的访问。排查顺序千万别乱从最简单的手动登录开始。我见过有人一上来就怀疑源码有 bug改了半天发现是数据库密码填错了。5.3 PHP 8 环境下的函数缺失与字符集坑如果你铁了心要在 PHP 8 上跑除了mysql_*函数还要注意magic_quotes_gpc这个配置项在 PHP 8 里已经不存在了。靶场里有些代码会调用get_magic_quotes_gpc()来判断是否需要转义这个函数在新版本里也没了会直接报错。处理方式是在公共函数文件里加一层兜底if (!function_exists(get_magic_quotes_gpc)) { function get_magic_quotes_gpc() { return false; } }字符集也是个隐形坑。PHP 5.6 和 PHP 8 默认的连接字符集不同某些依赖宽字节的关卡在两种环境下表现会不一样。如果你发现某个关卡的手工注入结果和教程对不上先别怀疑自己的 payload去确认一下连接的字符集设置。这也是我为什么反复推荐用 PHP 5.6——和绝大多数教程的环境一致减少变量。5.4 端口占用与访问不通还有一类看起来像靶场问题其实不是的情况端口被占。比如你本机已经跑了别的 Web 服务占了 80面板起不来但没报明显错误。排查方式很简单命令行看端口监听# Linux / macOS netstat -tlnp | grep 80 # Windows netstat -ano | findstr :80如果 80 被占把靶场改到 8080 或者 8888 之类不冲突的端口就行。改完记得访问地址也要跟着变。另外就是防火墙。本地访问一般不受影响但如果你是在虚拟机或服务器上搭外部访问不通要先看防火墙规则放没放行对应端口。这个和靶场本身没关系但确实卡住过不少人。6. 环境跑通之后Less-1 到 Less-65 怎么练才有效6.1 关卡分组与知识对应关系环境通了接下来才是真正的学习。65 关不用一关一关硬啃按类型分组练效率高得多。大致可以这样分关卡区间主要考察点练习重点Less 1-10基础注入联合查询、报错注入、布尔盲注、时间盲注Less 11-20POST 型注入表单提交、Burp 抓包改包Less 21-38进阶场景Cookie 注入、Base64 编码、HTTP 头注入Less 39-45堆叠查询分号多语句执行Less 46-53Order By 注入排序参数点的利用Less 54-65挑战关综合场景、二次注入、宽字节按这个顺序推进每一组内部再横向对比不同注入手法比机械地1、2、3往下刷有效得多。重点不是通关数量是每一关你都清楚它为什么能被注入防护为什么没拦住。6.2 工具配合与练习记录手工练完前二十关之后建议引入 Burp Suite 做抓包练习。它的价值在于把请求参数可视化你能直接在同一个请求上做参数变形测试而不用反复在浏览器地址栏里改 URL。对于 POST 型注入和 HTTP 头注入抓包几乎是必用的手段。更重要的习惯是记录。每一关我都会记三件事注入点在哪、判断注入类型的依据是什么、最终用的 payload 为什么能生效。这个记录不是为了给别人看是为了让你在遇到真实测试场景时能快速判断这个参数像哪种注入点。很多人的问题不是不会用工具是拿到一个真实参数完全不知道该从哪下手原因就是练习时只记了 payload 没记判断逻辑。7. 几个容易被忽略但很影响体验的细节7.1 数据库被写脏后的清理方式练盲注和堆叠查询的时候很容易往users表里插数据或者更新数据练着练着库就乱了某些关卡的结果会对不上。这时候最省事的做法不是逐条删而是重新跑一遍初始化脚本把库重置回干净状态。容器化部署的话直接重启容器更彻底。养成练完一批就重置一次的习惯比每次手动修数据省太多时间。这一点我在练时间盲注的时候吃过亏——数据库里残留了脏数据导致某关的判断条件永远为真卡了很久才发现是环境的问题。7.2 为什么不要在公网暴露这套环境SQLi-Labs 从设计之初就是故意不设防的它的所有关卡都在主动接受注入请求没有任何防护逻辑。放在本机或者隔离的内网环境自学完全没问题但千万不要把它挂到公网可访问的位置。原因很直接它不只是一套练习代码还是个真实运行的 PHP 应用配置里带着数据库账号密码一旦被外部扫描到风险是实打实的。这条不是危言耸听是搭建靶场时最基本的安全意识。学习环境就让它安安静静待在本地需要多人共享时用虚拟机加内网隔离。7.3 备份一份干净的环境这是个很小但很省事的建议环境跑通、数据库初始化成功之后把整个目录和数据库导出来备份一份。之后不管你怎么折腾搞坏了恢复一下就是几分钟的事。集成面板的话把整个靶场文件夹压缩存一份数据库用面板自带的导出功能导成 sql 文件。我自己就吃过没备份的亏有一次调字符集把配置文件改乱了忘记原始值翻教程找默认配置找了半天。从那之后每次环境一跑通第一件事就是备份。7.4 PHP 错误日志比浏览器报错信息更全浏览器上看到的那一行报错往往只是冰山一角真正有用的调用栈在 PHP 错误日志里。集成面板一般都提供日志查看入口手工环境的话看php.ini里error_log指向的路径。遇到 Fatal error 这类问题去日志里搜对应文件和时间点能看到完整调用链定位速度快很多。顺便说一句display_errors打开只是临时排错用的环境稳定之后建议关掉否则报错信息会暴露路径和结构这在真实项目里是安全隐患在靶场里虽然无所谓但养成排错时开、上线时关的习惯没坏处。最后分享一个我自己的做法每次重构或迁移环境时我会先在隔离的目录里把 SQLi-Labs 单独跑一遍最小验证——首页能开、数据库能初始化、Less-1 能正常回显这三步过了再往下堆其它东西。这样一旦出问题能立刻判断是新装的部分引入了冲突还是靶场本身的问题。搭建这种事变量越少排查越省心。
返回列表