SQL注入实战:科学计数法绕过与Sqli-labs靶场通关指南

发布时间:2026/7/5 23:17:14
SQL注入实战:科学计数法绕过与Sqli-labs靶场通关指南 1. 项目概述为什么Sqli-labs是Web安全入门的必修课如果你刚接触Web安全或者想系统性地提升SQL注入实战能力那么Sqli-labs这个靶场绝对是你绕不开的“新手村”和“训练场”。我第一次接触它的时候感觉就像拿到了一张藏宝图里面布满了精心设计的谜题每一关都对应着一种或多种SQL注入的典型场景。这个靶场之所以经典是因为它几乎涵盖了SQL注入的所有基础类型从最简单的字符型、数字型注入到需要层层绕过的盲注、报错注入再到需要组合拳的堆叠注入和二次注入。它不只是一个让你“打点”的工具更是一个让你理解数据库、应用程序和后端代码如何交互的绝佳沙盒。很多新手会问网上那么多靶场为什么偏偏是Sqli-labs我的体会是它的设计非常“教学化”。它的代码是开源的你可以直接看到每一关的后端PHP源码理解漏洞是如何产生的以及开发者或者说出题人在哪些地方设置了过滤又留下了哪些“后门”。这种“上帝视角”对于建立完整的攻击者思维至关重要。你不会只停留在“这个payload能用”的层面而是会去思考“为什么这个payload能用”以及“开发者为什么会犯这个错”。理解了漏洞的根源你才能在未来自己开发或审计代码时有效地避免同类问题。这次我们要聊的不仅仅是按部就班地通关而是聚焦于一个实战中非常有趣且实用的技巧利用科学计数法绕过过滤。在不少CTF比赛和真实世界的WAFWeb应用防火墙规则中单纯的数字或字符串拼接可能会被拦截但像1e1表示10这样的科学计数法表示却常常成为规则盲区。掌握这个技巧相当于在你的注入武器库里又多了一把轻巧而锋利的“手术刀”。2. 环境搭建与靶场初探不只是启动一个Docker工欲善其事必先利其器。搭建一个稳定、可反复“破坏”的实验环境是第一步。虽然网上有很多一键Docker的教程但我建议尤其是初学者最好能手动从GitHub拉取源码在本地配置一个LAMPLinux Apache MySQL PHP或WAMP环境。这个过程本身就能让你熟悉Web应用的基本运行架构。2.1 手动部署Sqli-labs的细节与避坑直接从GitHub克隆项目是最稳妥的方式git clone https://github.com/Audi-1/sqli-labs.git将克隆下来的sqli-labs文件夹整个放到你的Web服务器根目录例如Apache的/var/www/html/或 XAMPP 的htdocs。接下来是关键的一步数据库初始化。很多新手卡在这里因为README里的说明可能不够详细。修改数据库配置文件找到sqli-labs/sql-connections目录下的db-creds.inc文件。用文本编辑器打开你会看到类似下面的内容?php //give your mysql connection username and password $dbuser root; $dbpass ; $dbname security; $host localhost; $dbname1 challenges; ?你需要根据自己本地MySQL的实际情况修改$dbpass你的MySQL root密码和$host通常是localhost。创建数据库并导入数据通过phpMyAdmin或者命令行登录MySQL然后顺序执行以下操作-- 创建名为 security 的数据库 CREATE DATABASE security; -- 使用这个数据库 USE security; -- 导入 sqli-labs 目录下的 SQL 文件来创建数据表 -- 你需要找到 sql-lab 目录下的 .sql 文件例如 SOURCE /你的路径/sqli-labs/sql-lab/less-1.sql;注意Sqli-labs的SQL文件可能分散在多个地方主要的数据表结构通常在sql-lab目录下。如果导入失败检查文件路径和MySQL用户的权限。一个常见的坑是Windows系统下的文件路径需要使用反斜杠或双斜杠。访问安装页面在浏览器中输入http://localhost/sqli-labs/具体路径根据你的放置位置调整点击页面上的链接进行安装。如果一切顺利你会看到所有关卡Less-1, Less-2...的链接列表。2.2 核心工具链Burp Suite与浏览器的协同对于SQL注入实战Burp Suite不是可选项而是必需品。它不仅仅是一个抓包工具更是你观察HTTP请求与响应、修改参数、进行自动化测试的“作战指挥中心”。Burp Suite配置确保你的浏览器代理设置正确指向Burp默认127.0.0.1:8080并在Burp中安装好CA证书以拦截HTTPS流量。对于Sqli-labs这类本地HTTP靶场HTTP流量就足够了。浏览器开发者工具与Burp互补。我习惯用开发者工具的“网络Network”标签页实时查看请求响应用“控制台Console”执行一些简单的JavaScript来辅助测试比如快速生成一个长字符串。两者结合能让你对数据流有立体的感知。搭建好环境你的“黑客实验室”就准备就绪了。接下来我们将从最基础的关卡开始逐步深入并最终亮出“科学计数法绕过”这个绝招。3. 从Less-1到Less-4理解注入的基本类型与闭合Sqli-labs的前几关是精心设计的入门教程它们分别代表了不同的注入点类型和SQL语句闭合方式。理解这些是写出有效payload的前提。3.1 Less-1基于错误的字符型注入与单引号闭合打开Less-1页面通常有一个输入框让你输入ID。随便输入一个数字比如1页面会返回对应的用户信息。我们的第一步永远是探测。探测注入点输入一个单引号‘。如果页面返回了数据库错误信息如“You have an error in your SQL syntax...”那么这里很可能存在SQL注入漏洞并且原始SQL语句使用了单引号来包裹用户输入。判断列数使用ORDER BY子句。在Burp中拦截请求将ID参数修改为1‘ ORDER BY 3 --。--是注释符在URL中号代表空格用于注释掉原SQL语句中后续的部分。逐渐增加ORDER BY后面的数字4,5...直到页面报错或返回异常。如果ORDER BY 3正常而ORDER BY 4报错说明当前查询结果有3列。确定回显点使用UNION SELECT语句。将payload修改为-1‘ UNION SELECT 1,2,3 --。这里ID设为-1或一个不存在的值是为了让原查询结果为空从而确保页面显示的是我们UNION查询的结果。观察页面看数字“1”、“2”、“3”哪个位置被显示了出来。假设数字2和3的位置被显示那它们就是我们可以用来回显数据库信息的“回显点”。获取信息利用回显点。将payload修改为-1‘ UNION SELECT 1, database(), user() --。这样我们就能在页面上直接看到当前数据库名和数据库用户名了。后续可以进一步查询表名、列名和数据。实操心得--里的在Burp的Repeater模块中发送时有时需要手动编码为%2b或者直接使用--后面跟一个空格。也可以使用#注释但在URL中需要编码为%23。多试试几种确保注释生效。3.2 Less-2数字型注入的简洁性Less-2的页面和Less-1看起来一样但输入单引号‘可能不报错。这时可以尝试输入1 and 12。如果页面正常返回ID1的数据说明and 12这个假条件没起作用可能不是数字型。但如果页面返回空或错误则可能是数字型注入。对于数字型注入闭合方式更简单通常不需要单引号。探测列数的payload直接就是1 ORDER BY 3UNION注入的payload是-1 UNION SELECT 1,2,3。少了引号的纠缠整个过程更加直接。这一关的核心是让你意识到并非所有注入点都需要处理引号闭合这取决于后端代码如何处理输入参数。如果代码是$id $_GET[‘id‘]; $sql “SELECT ... FROM ... WHERE id$id”;那么就是数字型。3.3 Less-3与Less-4单引号括号与双引号括号闭合这两关提升了难度引入了括号()进行闭合。Less-3输入单引号‘报错信息可能是...near ‘‘‘)‘ LIMIT 0,1‘。这提示我们原始SQL语句的格式可能是SELECT ... WHERE id(‘$id‘)。所以我们的闭合需要构造为1‘) --先闭合单引号再闭合括号。完整的探测payload例如1‘) ORDER BY 3 --。Less-4输入单引号不报错试试双引号“。报错信息可能包含““)说明格式是SELECT ... WHERE id(“$id“)。闭合方式则为1“) --。这两关的训练价值在于让你学会仔细阅读数据库的错误信息。错误信息是极好的调试工具它常常会“泄露”出原始SQL语句的结构片段。通过观察错误信息中引号和括号的位置你可以反推出正确的闭合方式。关卡注入类型推测SQL结构测试Payload探测关键技巧Less-1字符型单引号...WHERE id‘$id‘ LIMIT 0,11‘ and ‘1‘‘1利用单引号闭合注意注释符使用Less-2数字型...WHERE id$id LIMIT 0,11 and 12无需处理引号直接拼接逻辑语句Less-3字符型单引号括号...WHERE id(‘$id‘) LIMIT 0,11‘) and (‘1‘)‘1需同时闭合单引号和括号Less-4字符型双引号括号...WHERE id(“$id“) LIMIT 0,11“) and (“1“)“1需同时闭合双引号和括号4. 中级挑战盲注、报错注入与堆叠注入闯过基础关卡后你会遇到一些不再直接回显查询结果的挑战。这时候就需要更高级的技巧。4.1 布尔盲注与时间盲注当页面“沉默”时在Less-5和Less-6等关卡无论输入什么页面都只返回一种固定的提示如“You are in…”不会显示数据库数据也不会直接报错。这就是盲注Blind Injection。布尔盲注页面虽然不显示数据但会根据SQL查询语句的真假返回不同的内容比如一条简单的“存在”或“不存在”的信息。我们可以通过and连接条件像猜谜一样逐位判断。例如猜解数据库名的第一个字母1‘ and ascii(substr(database(),1,1))100 --。如果页面返回“存在”的状态说明ASCII码大于100然后我们再用二分法不断缩小范围150, 125...直到确定准确的ASCII码值再转换为字符。这个过程极其繁琐必须借助自动化工具。时间盲注页面返回内容完全一样无法通过内容区分真假。这时我们利用SLEEP()函数。payload如1‘ and if(ascii(substr(database(),1,1))100, sleep(5), 0) --。如果第一个字符的ASCII码大于100页面会延迟5秒响应否则立即返回。通过观察响应时间同样可以逐位猜解。注意事项手工进行盲注是低效且痛苦的。实战中一定会使用工具如SQLmap。但理解其原理至关重要。你可以用Python写一个简单的脚本自动化发送请求和判断逻辑这是很好的练习。4.2 报错注入让数据库自己“说”出来在Less-11等关卡页面会显示数据库的错误信息。我们可以故意构造一个会让数据库报错的语句并让错误信息中包含我们想窃取的数据。这就是报错注入。常用的函数有updatexml()、extractvalue()和floor(rand()*2)结合count()产生的重复键错误。updatexml()示例1‘ and updatexml(1, concat(0x7e, (select database()), 0x7e), 1) --。concat(0x7e, ..., 0x7e)中的0x7e是波浪号~的十六进制用于在报错信息中凸显我们的数据。执行后错误信息会提示“XPATH syntax error: ‘~database_name~‘”从而泄露数据库名。原理updatexml()函数用于更新XML文档第二个参数需要是合法的XPATH路径。我们传入一个由concat()拼接的非法路径以~开头数据库执行时会报错并将这个非法字符串即我们拼接的数据一起显示在错误信息中。报错注入的优点是一次性能提取较长的数据效率高于盲注的逐位猜解。4.3 堆叠注入执行“多条语句”的威力从Less-38开始你会接触到堆叠注入Stacked Injection。它的原理是利用;分隔在一次数据库调用中执行多条SQL语句。这赋予了攻击者更大的破坏力。例如一个可能的payload是1‘; DROP TABLE users --。如果后端使用了支持多语句查询的数据库驱动如PHP中的mysqli_multi_query那么这条语句不仅会执行原查询还会执行删除users表的操作。重要警告在自家靶场可以随便玩但在任何授权测试之外的真实环境绝对禁止使用DROP、DELETE、UPDATE等破坏性语句。堆叠注入常被用于在注入后创建新的数据表、插入后门用户等持久化操作。在Sqli-labs中你可以安全地尝试1‘; CREATE TABLE test (id int); --来验证漏洞存在。5. 高阶技巧科学计数法绕过的原理与实战现在让我们聚焦到标题中提到的“科学计数法绕过”。这个技巧在过滤了某些字符但未过滤e或E的场景下特别有效。5.1 科学计数法在SQL中的本质在MySQL、MariaDB等数据库中科学计数法是一种合法的数字表示形式。1e1等于102.5e2等于2501e0等于1。关键在于数据库引擎在解析SQL时会将科学计数法字符串先计算成对应的数字值。假设后端代码对用户输入进行了过滤比如将“空格”替换为空或者过滤了“and”、“or”等关键字但允许数字和字母e通过。这时传统的1 and 11可能会被拦截。5.2 绕过场景实战解析场景一绕过空格过滤有些WAF或简单的过滤函数会删除或拦截空格。我们可以用科学计数法来替代某些数字有时可以避免使用空格。原始Payload1‘ and ‘1‘‘1如果空格被过滤可能变成1‘and‘1‘‘1这可能导致语法错误。尝试利用科学计数法构造1‘and‘1e0‘‘1e0。这里1e0就是数字1。虽然看起来还有空格实际上在and前后但重点是如果过滤规则是删除空格这个payload被处理后会变成1‘and‘1e0‘‘1e0在SQL中1e0是一个合法的数值令牌整个语句可能依然能被正确解析。更常见的用法是结合其他无空格技巧如用括号()、注释/**/代替空格。场景二作为数字参与运算绕过特定字符检测这是更常见的用途。在一些盲注或条件判断中我们需要用到数字比较。假设我们需要判断数据库名的长度是否大于101‘ and length(database())10 --如果符号被过滤了怎么办我们可以利用科学计数法和等式判断。length(database())11可以写成length(database())1e1。但如何判断“大于”呢一个技巧是使用减法1‘ and length(database())-1e10 --。如果被过滤这个思路可能受阻。更巧妙的绕过利用between ... and ...语句。1‘ and length(database()) between 1e1 and 2e1 --。这个语句判断长度是否在10到20之间。between和and是SQL关键字1e1和2e1是数字整个payload可能绕过对、等比较符的过滤。场景三在报错注入中构造数字参数某些报错注入函数需要数字参数。例如exp()函数当参数过大709时会产生溢出错误。我们可以构造exp(~(select * from (select user())x))来报错输出用户信息。其中~是按位取反会产生一个很大的数字。如果某些符号被过滤我们可以尝试用科学计数法构造这个大数但通常exp()配合~的方式已经足够。5.3 一个综合案例Less-的绕过实战假设某一关我们可以设想一个场景过滤了空格和and关键字但我们可以使用代替and在MySQL中是逻辑与的另一种写法。同时它允许字母e通过。 我们的目标是判断一个条件的真假。正常逻辑1‘ length(database())10 --如果被过滤我们可以尝试用like或rlike。但比较数字时可以尝试用科学计数法配合运算1‘ length(database())-1e10 --。这里1e1是10如果长度等于10减法的结果就是0。如果-和也被过滤假设过滤得很奇怪我们可以利用in关键字。1‘ length(database()) in (1e1) --。in用于判断一个值是否在列表中这里列表只有一个值1e1即10。这个案例想说明的是科学计数法1e1作为一个整体性的“数字令牌”可以替代纯数字10出现在SQL语句的数值位置。当一些针对数字10的简单过滤规则比如正则表达式\b10\b生效时1e1可能因为不符合该模式而成功绕过。它的价值在于提供了另一种数字表示形式增加了payload的变体与注释符、编码、等价函数替换等技巧组合使用能有效提高绕过成功率。6. 工具辅助与自动化测试SQLmap的正确打开方式手工注入是理解原理的必经之路但实战中效率至上。SQLmap是每个Web安全工程师的必备神器。然而直接sqlmap -u “url” --batch往往不是最优解。6.1 针对Sqli-labs的SQLmap精细化使用指定注入点和参数sqlmap -u “http://localhost/sqli-labs/Less-1/?id1“ -p id-p id指定只测试id这个参数节省时间。指定数据库类型sqlmap -u “...” --dbmsmysqlSqli-labs用的是MySQL直接指定可以跳过自动探测加快速度。设置级别和风险sqlmap -u “...” --level2 --risk2--level越高测试的payload越多越全面也会更慢。--risk越高会使用风险更高的payload如OR布尔注入可能造成大量数据返回。对于靶场level2, risk2是个不错的起点。获取数据获取所有数据库--dbs获取当前数据库--current-db获取指定数据库的所有表-D security --tables获取指定表的所有列-D security -T users --columnsdump表数据-D security -T users -C username,password --dump6.2 结合Burp Suite进行高效测试我更推荐的工作流是用浏览器和Burp Suite手工测试确定存在注入点、类型和闭合方式。将Burp中拦截到的含有注入点的请求右键保存到文件例如request.txt。使用SQLmap直接加载这个文件进行自动化测试sqlmap -r request.txt这种方式会自动识别所有参数、Cookie等信息最贴近真实请求成功率很高。实操心得SQLmap的--tamper参数是绕过WAF的利器。它内置了很多脚本可以对payload进行混淆、编码。例如--tamperspace2comment会把空格替换成/**/。你可以针对靶场的过滤规则编写或选择合适的tamper脚本。对于科学计数法绕过如果SQLmap没有现成脚本你可以通过观察手工成功的payload用--tamper自定义一个简单的替换脚本例如把特定的数字10替换成1e1但这需要一定的Python基础。7. 防御视角从攻击中学习如何编写安全代码通过Sqli-labs的实战我们站在攻击者的角度看到了各种漏洞的成因。现在切换回开发者视角如何防御预处理语句参数化查询这是最根本、最有效的防御手段。使用像PDOPHP或MyBatisJava这样的数据库接口它们会将SQL语句的结构SELECT * FROM users WHERE id ?与数据用户输入的id值分开处理。数据库引擎会先编译语句结构再将数据作为参数传入从根本上杜绝了数据被解释为代码的可能性。这是绝对的首选方案。输入验证与过滤如果因为某些历史原因无法使用预处理则必须进行严格的输入验证。对于数字型参数使用intval()、ctype_digit()等函数确保输入是合法的整数。对于字符型定义严格的白名单只允许特定字符集而非黑名单。黑名单永远会被绕过科学计数法绕过就是一个例子——如果你只过滤了数字和空格但没考虑到e就可能被绕过。最小权限原则连接数据库的应用程序账号不应该拥有DROP、CREATE TABLE、FILE等高危权限。只赋予其完成业务所必需的最小权限通常是SELECT、INSERT、UPDATE、DELETE这样即使发生注入危害也能被限制。错误信息处理切勿将详细的数据库错误信息直接返回给前端用户。应使用自定义的、模糊的错误页面。这能增加攻击者进行报错注入和盲注的难度。使用Web应用防火墙WAFWAF可以作为一道额外的防线基于规则拦截常见的攻击payload。但切记WAF是“缓兵之计”不能替代安全的代码编写。攻击者会不断研究新的绕过技巧就像科学计数法绕过一样规则总有滞后的可能。玩转Sqli-labs靶场特别是深入理解像科学计数法绕过这样的技巧最终目的不是为了“黑”掉什么而是为了在脑海中建立起一道坚固的防线。当你再看到自己写的SQL语句时你会本能地思考这里有没有拼接用户输入我该怎么用参数化查询来重写它这种从攻击者思维转化而来的防御意识才是安全实战训练带给你的最宝贵的财富。