SQL注入 手工注入

前言

开始 SQL 注入 。推荐使用 sqli-labs 靶场,因为它涵盖了丰富的 SQL 注入相关内容。靶场的具体搭建方法可以自行百度查找。

实操流程

  • 本次选择的是 sqli-labs 的 less 2 数字型注入作为起点。
  • 进入靶场后,首先看到如下网页界面:
  • 可以通过插件了解该网站的开发语言:
  • 该网站是用 PHP 编写的,因此后续解题需要结合 PHP 代码进行分析。
  • 通过 F12 开发者工具可以发现这是一个 GET 请求 页面。下面介绍一下 GET 和 POST 请求的区别。

一、基础概念:浏览器向服务器提交数据的两种方式

1. GET 提交

  • 提交位置:数据直接嵌套在 URL(网址)中,比如 xxx.com?id=1,参数会直接显示在地址栏。
  • 核心特点
    • 数据长度有限制:约 2KB(2048 字节),无法提交大量数据。
    • 安全性低:参数明文可见,敏感信息(如账号、密码)会直接暴露在地址栏。
    • 速度快:请求处理效率高于 POST。
  • 适用场景:适用于数据不敏感、无高安全要求、数据量小的场景(如商品列表查询、文章ID查询)。

2. POST 提交

  • 提交位置:数据放在 HTTP 请求体中,地址栏不会显示参数。
  • 核心特点
    • 安全性更高:参数不直接暴露在地址栏,普通用户无法直接看到提交的数据。
    • 数据量大:没有 GET 的长度限制,可以提交大量数据(如表单、文件上传)。
  • 适用场景:绝大多数网站/APP的主流提交方式,适用于登录、注册、表单提交、文件上传等涉及敏感数据或大数据量的场景。

OK,那我们回到正题,我这边要填写什么猜能过关呢,我先直接写出来:

bash 复制代码
http://sqli-labs-1202/Less-2/index.php?id=1


为什么可以这样写呢?我们去找一下源码看一下。
不需要每行代码都看得十分明白,只需要知道它是怎么用的就行。

可以看出来,我们的 id=1 被这个 GET 指令接收了,然后这个 GET 指令再向下执行到 SELECT 引导的搜索函数。当然,id 不一样的话,数据也是会发生变化的,这边不做过多演示。

三、手工注入完整流程(数字型 + 回显注入)

步骤 1:判断是否存在注入点

核心逻辑:看后端是否将用户输入的参数直接拼接到 SQL 语句中执行,未做过滤则存在注入点。

  • 测试方法:在 URL 参数后拼接逻辑判断语句
  1. 正常请求:id=1 → 页面显示对应数据
  2. 测试语句 1:id=1 and 1=1 → 页面正常(条件成立,SQL 执行成功)

    这边说一下,这个%20 其实就是空格的意思
  3. 测试语句 2:id=1 and 1=2 → 页面异常(条件不成立,SQL 执行失败)
  4. 简单粗暴法:直接输入 id=abc 等非数字内容,页面报错则说明存在注入点
  • 原理:后端 SQL 语句为 select * from users where id = 输入的参数,拼接后会执行完整逻辑

步骤 2:用 order by 判断字段数量

核心逻辑:order by 是排序语句,后跟数字表示按第 N 个字段排序,若数字超过实际字段数则报错,以此推断字段总数。

  • 测试流程
  1. 输入 id=1 order by 1 → 正常(存在第 1 个字段)
  2. 输入 id=1 order by 2 → 正常(存在第 2 个字段)
  3. 输入 id=1 order by 3 → 正常(存在第 3 个字段)
  4. 输入 id=1 order by 4 → 报错(无第 4 个字段)
  • 结论 :该表共有 3 个字段
  • 补充:URL 中空格可用 %20 代替,避免被过滤

步骤 3:用 union select 判断回显点

核心逻辑 :union select 用于联合查询,要求前后两条查询语句的字段数一致;构造第一条查询无结果,第二条查询的内容就会显示在页面上,显示的位置就是 回显点

  • 测试方法
  1. 构造无结果的第一条查询:id=-1(一般无负 ID 数据)
  2. 拼接联合查询:id=-1 union select 1,2,3
  3. 页面显示 2 和 3 → 说明第 2、3 个字段是回显点(后续可在这两个位置查询数据)
  • 关键特性:union select 前后字段数必须一致;第一条查询无结果时,才会显示第二条查询的内容

步骤 4:信息收集(数据库版本、库名等)

核心逻辑:利用 MySQL 内置函数,在回显点位置查询数据库基础信息,为后续注入铺路。

  • 常用函数

    • version():查询数据库版本(如 5.7.26),判断高低版本(5.0 以上为高版本,有系统库 information_schema)
    • database():查询当前数据库名(如 security)
  • 测试语句

    bash 复制代码
    id=-1 union select 1,version(),database()
    • 页面回显:数据库版本 + 当前库名,确认是高版本后,可借助系统库查询表名、字段名

    步骤 5:查询数据库中的表名

    核心逻辑:高版本 MySQL 的 information_schema.tables 表存储了所有表的信息,通过条件筛选当前库的表名。

    • 核心语句

      bash 复制代码
      id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()
      • 关键说明
      1. group_concat():将多个表名合并成一行显示,避免页面只显示单个结果
      2. table_schema=database():筛选出当前数据库下的所有表
      • 页面回显:当前库的所有表名(如 users、emails 等),其中 users 表大概率存储账号密码

      步骤 6:查询目标表的字段名

      核心逻辑:information_schema.columns 表存储了所有字段的信息,筛选目标表的字段名。

      • 核心语句

        bash 复制代码
        id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users'
        • 补充:若直接写表名报错,可将 users 转为 16 进制(如 0x7573657273),避免引号被过滤
        • 页面回显:users 表的字段名(如 id、username、password)

        步骤 7:查询目标字段的具体数据

        核心逻辑:直接查询 users 表中 username 和 password 字段的内容,拿到账号密码。

        • 核心语句

          bash 复制代码
          id=-1 union select 1,group_concat(username),group_concat(password) from users
相关推荐
盟接之桥1 小时前
盟接之桥®制造业EDI软件:专注制造,为制造业服务,让全球供应链协同更有底气
网络·安全·低代码·汽车·制造
eam0511232 小时前
简单园区网
网络
dishugj2 小时前
psql-客户端工具日常使用命令整理
数据库·postgresql
m0_737539372 小时前
数据库主从复制和读写分离
数据库·oracle
y = xⁿ2 小时前
MySQL学习日记:关于MVCC及一些八股总结
数据库·学习·mysql
Cat_Rocky2 小时前
网络技术基础一点点
运维·服务器·网络
Lyyaoo.2 小时前
【JAVA网络面经】应用层协议
java·开发语言·网络
m0_737539372 小时前
SQL语言续2
数据库·sql
下地种菜小叶2 小时前
订单中心怎么设计?一次讲清订单主链路、状态流转、拆单模型与核心边界
安全·缓存·rabbitmq