Post

Important Considerations for Injecting Groovy Memory Shell using CVE-2024-45507

This article discusses key considerations when injecting a Groovy memory shell using the CVE-2024-45507 vulnerability. It covers script formatting, package name settings, use of the main function, relationship between class name and file name, and how to handle and replace special keywords in Groovy scripts. The article also provides code examples demonstrating how to convert Java code to Groovy script to avoid specific keywords and syntax restrictions.

Important Considerations for Injecting Groovy Memory Shell using CVE-2024-45507

Reference

Groovy reserved keywords and unsupported functions (oracle.com)

Preface

While exploiting CVE-2024-45507 to inject a Groovy memory shell, I discovered several points that require attention. I’m documenting these here for future reference.

Key Considerations

Formatting

Through testing, I found that compressing the entire Groovy script into a single line renders it ineffective.

Package Name

Although I haven’t tested it extensively, it’s possible to execute the script file normally without setting a package name. Therefore, it’s recommended not to set a package name for the Groovy script file.

Main Function

Although the constructor is automatically executed when running the script, I still recommend setting a main function in the Groovy script. This reduces one warning about the missing main function.

1
2
3
public static void main(String[] args) {
    new testofbiz();
}

Class Name

During testing, I noticed that the Groovy script can still run even if the class name doesn’t match the file name.

Handling and Replacing Keywords

In theory, you could directly write a normal Tomcat memory shell in the Groovy file. However, to avoid Groovy script keywords and account for differences from Java code, some parts of the code need to be modified.

Keyword $

Java code:

1
HashMap childrenMap = (HashMap)getFV(getFV(getFV(thread, "target"), "this$0"), "children");

Groovy script:

1
HashMap childrenMap = (HashMap)getFV(getFV(getFV(thread, "target"), "this${'$'}0"), "children");

Keyword in

Java code:

1
GZIPInputStream ungzip = new GZIPInputStream(in);

Groovy script:

1
GZIPInputStream ungzip = new GZIPInputStream(inputStream);

Keyword new

Java code:

1
2
new Class[]{Object.class}
new Class[]{Object[].class}

Groovy script:

1
2
[Object] as Class[]
[Object[]] as Class[]

This transformation in Groovy script leverages Groovy’s syntactic sugar and type inference capabilities to make the code more concise and readable. This Groovy syntax utilizes several features:

  1. List literal: [Object] in Groovy creates a list containing a single element Object.
  2. as operator: This is Groovy’s type conversion operator, used to convert the expression on the left to the type specified on the right.
  3. Type inference: Groovy can infer that Object and Object[] are class objects without explicitly writing .class.

Memory Shell

Reference: CVE-2024-45507_Behinder_Webshell (github.com)

image-20240913173818314

This post is licensed under CC BY 4.0 by the author.