资讯动态

SQL注入实战入门:从sqli-labs Less-1通关到Web安全基础

发布时间:2026/8/11 14:49:32 来源:尧图企业网站定制
1. 靶场初探为什么从SQL注入开始如果你刚接触网络安全或者想从CTF、渗透测试的实战中找点感觉那么SQL注入SQL Injection绝对是你绕不开的第一个“老朋友”。它不像缓冲区溢出那样需要深厚的底层知识也不像逻辑漏洞那样考验天马行空的思维。SQL注入的原理直白、危害巨大且至今仍是Web应用中最常见、最危险的漏洞之一。而sqli-labs这个开源靶场就是无数安全从业者梦开始的地方。它由印度安全研究员Audi-1搭建通过一系列精心设计的关卡Lessons由浅入深地带你领略SQL注入的“十八般武艺”。今天要聊的Less-1就是这个庞大迷宫的第一扇门。别看它编号靠前就以为简单。恰恰相反Less-1是基于错误的字符型注入的经典教学案例。它模拟了一个非常常见的场景一个使用GET方法传递参数、并且后端代码对用户输入未做任何过滤的登录查询。通关它你不仅能理解最基本的注入原理更能掌握一套适用于后续绝大多数关卡的核心方法论——如何观察、如何测试、如何构造Payload、如何获取数据。很多人在后续关卡卡壳问题往往就出在对第一关的基础理解不够扎实。所以咱们不追求速度而是扎扎实实地把每一步的原理和操作都掰开揉碎让你真正“通关”而不仅仅是“通过”。2. 环境准备与靶场搭建你的专属“黑客实验室”工欲善其事必先利其器。在开始“黑”之前我们得先有个安全的、合法的环境来练手。直接在网上找现成的在线靶场当然方便但为了学习过程的完整性和可控性我强烈建议你在本地搭建一套。这样你不仅可以随意测试、查看源码还能深入数据库亲眼看到你的注入语句是如何被执行的。2.1 本地环境搭建方案对于新手最省心的方案是使用集成环境包比如XAMPP、PHPStudy或WAMP。它们把ApacheWeb服务器、MySQL数据库、PHP后端语言打包在一起一键安装即可。以PHPStudy为例下载安装去官网下载对应你操作系统Windows的版本安装过程基本就是一路“下一步”。启动服务安装完成后打开PHPStudy你会看到界面。点击“启动”按钮它会同时启动Apache和MySQL服务。当Apache和MySQL旁边的图标都变成绿色就表示服务运行正常了。部署靶场去GitHub上搜索“sqli-labs”找到Audi-1的官方仓库下载ZIP包并解压。将解压后的整个文件夹通常叫sqli-labs或sqli-labs-master复制到PHPStudy的网站根目录下。这个根目录的路径通常是phpstudy_pro/WWW/具体路径取决于你的安装位置。访问靶场打开浏览器在地址栏输入http://localhost/sqli-labs/如果你的文件夹名不同请相应修改。如果一切顺利你会看到sqli-labs的首页点击“Setup/reset Database for labs”链接来初始化数据库。页面提示“Congratulations”等字样就表示数据库和表结构创建成功了。注意如果初始化失败最常见的原因是MySQL的密码问题。PHPStudy的MySQL默认密码可能是root或空。你需要打开sqli-labs文件夹下的sql-connections目录编辑db-creds.inc文件确保里面的数据库用户名和密码与你本地MySQL的配置一致。2.2 核心工具你的“瑞士军刀”有了靶场我们还需要几件趁手的工具。对于SQL注入浏览器和一款专业的HTTP代理工具就足够了。浏览器推荐Chrome或Firefox现代浏览器的开发者工具F12打开是神器。我们主要用它的“网络”Network标签页可以查看每个请求的详细信息包括URL、参数、响应头、响应体。在“控制台”Console标签页我们还可以快速执行一些JavaScript代码来编码或解码数据非常方便。Burp Suite Community必备这是安全测试的行业标准工具社区版对个人学习完全免费。它的核心功能是代理拦截和重放。简单说它能让你看到浏览器发送给服务器的所有请求并且允许你暂停请求、修改其中的任何部分比如参数值然后再发送出去。这对于我们手动构造和测试复杂的注入Payload至关重要。安装与配置从PortSwigger官网下载安装。启动后你需要将浏览器的代理设置为Burp Suite监听的地址默认是127.0.0.1:8080。Burp Suite有详细的入门教程跟着做一遍就能掌握基础用法。为什么不用HackBar之类的浏览器插件插件固然方便但功能有限且不利于你理解HTTP请求的本质。Burp Suite能给你更全局的视角和更强大的操控能力是走向专业的必经之路。3. Less-1 通关全流程深度解析好了实验室和工具都齐了让我们正式进入Less-1。访问http://localhost/sqli-labs/Less-1/你会看到一个简单的页面上面有一个输入框提示你输入ID作为参数。3.1 第一步信息收集与漏洞探测任何一次有效的攻击都始于充分的信息收集。我们的目标是搞清楚这个页面是如何工作的。观察正常行为在输入框里输入数字1然后提交。页面显示了一个用户的ID、用户名和密码。URL变成了http://localhost/sqli-labs/Less-1/?id1。这告诉我们几个关键信息参数使用GET方法参数名是id。功能看起来是根据ID从数据库中查询用户信息。SQL语句猜测后端很可能执行了一条类似SELECT * FROM users WHERE id$id的查询。触发错误确认注入点与数据库类型这是最关键的一步。我们故意输入一些“不正常”的数据看服务器返回什么错误。输入一个单引号然后提交。页面返回了类似下面的错误信息You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 1 LIMIT 0,1 at line 1分析错误信息明确指出了是“MySQL server”。这太好了我们不仅确认了存在SQL注入漏洞因为我们的输入改变了SQL语法结构还知道了后端数据库是MySQL。错误信息中near 1这部分揭示了后端代码拼接SQL语句的方式它很可能是SELECT ... WHERE id$id LIMIT 0,1。我们输入后语句变成了SELECT ... WHERE id LIMIT 0,1多出的单引号破坏了语法。判断注入类型我们尝试输入1 and 11和1 and 12。输入1 and 11页面正常返回了ID为1的用户信息。因为拼接后的SQL是... WHERE id1 and 11 LIMIT 0,1这是一个永真条件所以查询成功。输入1 and 12页面没有返回用户信息可能是空白或报错。因为拼接后的SQL是... WHERE id1 and 12 LIMIT 0,1这是一个永假条件查询不到结果。结论这是一个基于布尔Boolean的真假条件注入并且是字符型因为参数值被单引号包裹。3.2 第二步利用联合查询UNION获取数据结构知道了是字符型注入并且有错误回显我们可以使用最强大的工具之一UNION SELECT。它的作用是将我们自定义的查询结果拼接到原始查询的结果后面显示出来。但使用它有两个前提原始查询与我们注入的查询列的数目必须相同。列的数据类型需要兼容。所以我们的首要任务是判断原始查询返回了多少列。使用ORDER BY测列数ORDER BY子句用于根据列索引排序。如果指定的列索引超过了实际列数数据库就会报错。我们利用这一点来探测。输入1 order by 1--页面正常。--是MySQL中的单行注释符--后面要跟一个空格在URL中常被编码为空格它注释掉了原SQL语句中后面的单引号和LIMIT确保语法正确。语句相当于SELECT ... WHERE id1 order by 1-- LIMIT 0,1。输入1 order by 2--页面正常。输入1 order by 3--页面正常。输入1 order by 4--页面报错语法错误或空白。结论原始查询返回了3 列。因为order by 3成功而order by 4失败。确定显示位知道了有3列我们需要找出哪几列的内容会显示在网页上。这样我们才能把想要的数据“投射”到这些位置上。输入1 union select 1,2,3--观察页面。你会发现原本显示“用户名”和“密码”的地方变成了数字2和3。结论第2列和第3列是显示位。这意味着我们后续可以通过union select将数据库名、表名、字段名等信息放在2和3的位置上它们就会在页面中显示出来。3.3 第三步逐步获取数据库信息现在我们可以开始系统地“翻阅”数据库了。MySQL有一个名为information_schema的系统数据库它就像数据库的“户口本”存储了所有其他数据库、表、列的结构信息。这是我们注入攻击的“地图”。获取当前数据库名输入1 union select 1, database(), 3--database()是MySQL的函数返回当前连接使用的数据库名称。执行后你会在显示位2的位置看到数据库名通常是security。获取数据库中的所有表名输入1 union select 1, group_concat(table_name), 3 from information_schema.tables where table_schemadatabase()--拆解information_schema.tables系统表存放所有表的信息。table_schemadatabase()条件限制只取当前数据库security下的表。group_concat(table_name)将查询到的所有表名合并成一个字符串用逗号分隔。因为union select通常只返回一行用group_concat可以一次性看到所有结果。执行后你可能会看到类似emails,referers,uagents,users这样的结果。显然users表最有可能存放用户凭证。获取目标表users的所有列名输入1 union select 1, group_concat(column_name), 3 from information_schema.columns where table_schemadatabase() and table_nameusers--拆解information_schema.columns系统表存放所有列的信息。table_nameusers条件限制只取users表的列。执行后你会看到类似id,username,password的列名。3.4 第四步最终目标——拖取数据拿到了数据库名、表名、列名最后一步就是提取数据了。输入1 union select 1, group_concat(username), group_concat(password) from users--这个查询直接从security.users表中将所有用户名和密码分别合并后查询出来。执行后你会在页面看到所有用户的用户名和密码格式类似Dumb,Angelina,Dummy,...和Dumb,I-kill-you,pssword,...。至此Less-1的通关核心步骤就全部完成了。你已经成功地利用一个简单的ID参数逐步获取了整个数据库的关键信息。4. 核心原理与Payload构造心法通关步骤看似线性但背后每一步都蕴含着对SQL语法和Web交互的深刻理解。这里我分享一些教科书上不会细讲的“心法”。4.1 为什么单引号能导致注入这是最本质的问题。假设后端PHP代码是这样的$id $_GET[id]; $sql SELECT * FROM users WHERE id$id LIMIT 0,1; $result mysqli_query($conn, $sql);当你传入id1时SQL语句是SELECT * FROM users WHERE id1 LIMIT 0,1完全正确。 当你传入id1时语句变成了SELECT * FROM users WHERE id1 LIMIT 0,1。数据库引擎解析到第二个单引号时认为字符串1结束了但后面又多了一个单引号它不知道这个多出来的引号该和谁配对于是抛出语法错误。你通过输入改变了SQL语句的原始结构这就是注入。4.2 注释符-- #的妙用与差异在注入中注释符用于“吃掉”原SQL语句中我们无法控制的后半部分比如闭合的单引号、LIMIT子句等确保我们注入的语句语法完整。--双减号加空格是SQL标准注释符。在URL中空格需要编码为或%20所以常写为--。Burp Suite里直接写--带空格即可。#是MySQL的注释符。在URL中#被称为片段标识符浏览器不会将其发送到服务器。所以如果你想在URL中直接使用#需要对其进行URL编码写成%23。例如1 union select 1,2,3%23。实操心得在浏览器地址栏手动测试时用--最稳妥。在Burp Suite的Repeater模块里修改请求时直接写--注意有空格或#都可以因为Burp会帮你处理编码。务必注意这个差异很多新手在这里卡住。4.3UNION与ORDER BY的协同与取舍ORDER BY测列数和UNION SELECT确定显示位是两个相辅相成的步骤。为什么先ORDER BY因为它更“温和”。ORDER BY 10如果报错只是说明列数不够不会暴露我们想联合查询的意图。如果一上来就用UNION SELECT 1,2,3,4,5...去盲猜一旦列数不对就会报错且错误信息可能不同在某些配置下可能更显眼。UNION查询的数据类型问题我们用了select 1,2,3这里的数字是整数。如果显示位原本是字符串类型比如用户名MySQL会进行隐式转换通常能正常显示。但更严谨的做法是用null代替数字因为null可以匹配任何数据类型。例如union select null,null,null。4.4group_concat()与数据截断group_concat()函数非常实用但它有一个默认的长度限制group_concat_max_len变量默认1024字节。如果某个表的数据量非常大group_concat()的结果可能会被截断导致你无法看到完整数据。解决方案在注入语句中临时修改这个设置1 union select 1, (select group_concat(username) from users), 3--可以改为先设置长度。但更通用的方法是分次查询。使用limit子句分页查询1 union select 1, username, password from users limit 0,1--一次只查一行然后通过改变limit的参数limit 1,1limit 2,1...来遍历所有数据。虽然麻烦但绝对可靠。5. 常见问题、调试技巧与防御思考即使跟着步骤做你也可能会遇到各种“坑”。这里记录一些我踩过的雷和解决方法。5.1 常见问题速查表问题现象可能原因解决方案页面空白无任何输出1. 数据库查询出错但PHP错误显示被关闭。2.union前后查询列数不一致。3. 注释符使用错误导致语法错误。1. 打开Burp Suite查看原始HTTP响应尾部可能有错误信息。2. 用order by重新确认列数。3. 检查注释符在Burp中尝试--、#、--或%23。输入后不报错1. 靶场环境配置了通用错误页面屏蔽了详细错误。2. 可能存在过滤但被转义或处理了。1. 尝试布尔盲注测试1 and 11--与1 and 12--看页面是否不同。2. 查看网页源代码CtrlU有时错误信息藏在HTML注释里。union select后数字不显示显示位判断错误。可能页面内容来自多行结果默认只显示第一行。让原始查询结果为空使得union的结果成为第一行。将ID改为一个不存在的值如-1 union select 1,2,3--。group_concat结果不完整被group_concat_max_len限制截断。使用limit分页查询或注入语句中执行set group_concat_max_len1000000;需支持堆叠查询。使用%23(#) 仍然失败可能服务器端或中间件对URL解码有特殊处理。优先使用--。在Burp Suite里直接修改请求体使用#或--空格更直接。5.2 高级调试技巧让数据库“说话”当注入不顺利时你需要更深入地了解到底发生了什么。利用错误信息提取数据Less-1本身就是错误回显型。但有时错误信息会更直接。例如你可以尝试1 and extractvalue(1, concat(0x7e, (select database()), 0x7e))--。extractvalue()是XML函数如果第二个参数不是合法XPath格式它会将查询结果连同错误一起爆出来。0x7e是波浪号~的十六进制用于分隔。时间盲注作为备用方案如果页面无论输入什么外观都完全一样无错误、无内容差异那就可能是盲注。你可以用sleep()函数测试1 and sleep(5)--。如果页面响应延迟了大约5秒说明注入存在且被执行了。Less-1不是盲注但这是重要的思维拓展。查看靶场源码这是学习的最佳途径。找到sqli-labs/Less-1目录下的index.php文件打开它。你会看到类似下面的代码$id$_GET[id]; $sqlSELECT * FROM users WHERE id$id LIMIT 0,1; $resultmysql_query($sql);亲眼看到漏洞是如何产生的理解会深刻十倍。你还可以修改源码比如加上mysql_error()函数打印错误或者尝试添加一些简单的过滤看看你的Payload如何被拦截从而理解防御原理。5.3 从攻击者视角看防御通过这次通关你应该深刻理解了一点防御SQL注入核心就是不要让用户输入的数据被当作SQL代码来执行。所有防御手段都围绕这个核心。预处理语句参数化查询这是最有效、最根本的解决方案。它让SQL语句的“结构”和“数据”分离。数据库先编译带占位符的SQL模板如SELECT * FROM users WHERE id?然后再将用户输入的id值作为纯数据绑定上去。这样即使用户输入1 OR 11它也会被整体当作一个字符串值去查询ID字段等于这个字符串的记录而不会破坏SQL结构。PHP中使用PDO或MySQLi扩展即可实现。输入验证与过滤对输入进行严格的“白名单”验证。比如如果ID应该是数字就用intval()或is_numeric()函数强制转换为整数。对于字符串可以定义允许的字符集。但注意过滤是辅助手段容易被绕过不能单独依赖。最小权限原则连接数据库的Web应用账号不应该拥有DROP,CREATE,FILE等高危权限。只赋予其完成业务所必需的SELECT,INSERT,UPDATE权限。这样即使被注入破坏力也有限。关闭错误回显像Less-1这样详细的错误信息是攻击者的指路明灯。在生产环境中应关闭PHP的display_errors设置将错误记录到日志文件而不是展示给用户。通关Less-1你收获的不仅仅是一个Payload。你建立了一套完整的SQL注入测试思维模型探测 - 确认 - 查列 - 定位 - 取信息 - 拿数据。这套模型在后续的字符型、数字型、搜索型、盲注等关卡中万变不离其宗。真正的挑战在于后续关卡会加入各种过滤、转义、编码你需要像解谜一样思考如何绕过这些限制。而这正是sqli-labs这个靶场最迷人的地方。它告诉你漏洞的原理更逼迫你思考攻击的演化。当你用自己的方法绕过层层防御最终拿到数据时那种成就感就是安全研究的乐趣所在。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价