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的名字一样。