Skip to content

Commit a535d23

Browse files
committed
Land rapid7#3947, login scanner for jenkins by @nstarke
2 parents 3305b1e + 6ea5309 commit a535d23

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
require 'metasploit/framework/login_scanner/http'
2+
3+
module Metasploit
4+
module Framework
5+
module LoginScanner
6+
7+
# Jenkins login scanner
8+
class Jenkins < HTTP
9+
10+
# Inherit LIKELY_PORTS,LIKELY_SERVICE_NAMES, and REALM_KEY from HTTP
11+
CAN_GET_SESSION = true
12+
DEFAULT_PORT = 8080
13+
PRIVATE_TYPES = [ :password ]
14+
15+
# (see Base#set_sane_defaults)
16+
def set_sane_defaults
17+
self.uri = "/j_acegi_security_check" if self.uri.nil?
18+
self.method = "POST" if self.method.nil?
19+
20+
super
21+
end
22+
23+
def attempt_login(credential)
24+
result_opts = {
25+
credential: credential,
26+
host: host,
27+
port: port,
28+
protocol: 'tcp'
29+
}
30+
if ssl
31+
result_opts[:service_name] = 'https'
32+
else
33+
result_opts[:service_name] = 'http'
34+
end
35+
begin
36+
cli = Rex::Proto::Http::Client.new(host, port, {}, ssl, ssl_version)
37+
cli.connect
38+
req = cli.request_cgi({
39+
'method'=>'POST',
40+
'uri'=>'/j_acegi_security_check',
41+
'vars_post'=> {
42+
'j_username' => credential.public,
43+
'j_password'=>credential.private
44+
}
45+
})
46+
res = cli.send_recv(req)
47+
if res && !res.headers['location'].include?('loginError')
48+
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.headers)
49+
else
50+
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res)
51+
end
52+
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
53+
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
54+
end
55+
Result.new(result_opts)
56+
end
57+
end
58+
end
59+
end
60+
end
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
##
2+
# This module requires Metasploit: http//metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
require 'metasploit/framework/credential_collection'
8+
require 'metasploit/framework/login_scanner/jenkins'
9+
10+
class Metasploit3 < Msf::Auxiliary
11+
include Msf::Auxiliary::Scanner
12+
include Msf::Exploit::Remote::HttpClient
13+
include Msf::Auxiliary::Report
14+
include Msf::Auxiliary::AuthBrute
15+
16+
def initialize
17+
super(
18+
'Name' => 'Jenkins-CI Login Utility',
19+
'Description' => 'This module simply attempts to login to a Jenkins-CI instance using a specific user/pass.',
20+
'Author' => [ 'Nicholas Starke <starke.nicholas[at]gmail.com>' ],
21+
'License' => MSF_LICENSE
22+
)
23+
24+
register_options(
25+
[
26+
Opt::RPORT(8080)
27+
], self.class)
28+
29+
register_autofilter_ports([ 80, 443, 8080, 8081, 8000 ])
30+
31+
deregister_options('RHOST')
32+
end
33+
34+
def run_host(ip)
35+
cred_collection = Metasploit::Framework::CredentialCollection.new(
36+
blank_passwords: datastore['BLANK_PASSWORDS'],
37+
pass_file: datastore['PASS_FILE'],
38+
password: datastore['PASSWORD'],
39+
user_file: datastore['USER_FILE'],
40+
userpass_file: datastore['USERPASS_FILE'],
41+
username: datastore['USERNAME'],
42+
user_as_pass: datastore['USER_AS_PASS']
43+
)
44+
45+
scanner = Metasploit::Framework::LoginScanner::Jenkins.new(
46+
host: ip,
47+
port: rport,
48+
proxies: datastore['PROXIES'],
49+
cred_details: cred_collection,
50+
stop_on_success: datastore['STOP_ON_SUCCESS'],
51+
connection_timeout: 10,
52+
user_agent: datastore['UserAgent'],
53+
vhost: datastore['VHOST']
54+
)
55+
56+
scanner.scan! do |result|
57+
credential_data = result.to_h
58+
credential_data.merge!(
59+
module_fullname: fullname,
60+
workspace_id: myworkspace_id
61+
)
62+
if result.success?
63+
credential_core = create_credential(credential_data)
64+
credential_data[:core] = credential_core
65+
create_credential_login(credential_data)
66+
67+
print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}"
68+
else
69+
invalidate_login(credential_data)
70+
print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status})"
71+
end
72+
end
73+
end
74+
end
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
require 'spec_helper'
2+
require 'metasploit/framework/login_scanner/jenkins'
3+
4+
describe Metasploit::Framework::LoginScanner::Jenkins do
5+
6+
it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: false
7+
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
8+
it_behaves_like 'Metasploit::Framework::LoginScanner::HTTP'
9+
10+
end

0 commit comments

Comments
 (0)