0%

SQL注入题型总结

SQL架构

我们可以认为SQL有四层,自顶向下为:数据库,数据库中所含的表,表中的列,列中储存的内容。

一个数据库中有多个表,每一个表由若干行和列组成,列储存的是属性名称,而行储存的是内容。

基础知识

  • version()在一些支持的数据库发行版下可以拿到相关版本号,对于搜索历代CVE拿来打很有用处。
  • database()获取当前在查询的数据库名称。
  • information_schema是一个在版本大于5.0后默认存在的数据库,在我们利用的时候提供了非常大的用处。
  • group_concat是一个把多个字符合成一个字符的方法,毕竟泄露的时候一般只能从一个字符的位置泄露出来。

利用思路

  1. database()获知当前数据库名称
  2. group_concat(table_name) from information_schema.tables where table_schema=database()获取当前数据库中所有的表的名称
  3. group_concat(column_name) from information_schema.columns where table_name='your_table_name'获取一个表中所有列的名称
  4. 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的名字一样。