Skip to content

Commit dcf0d74

Browse files
committed
Adding module to scan for Octopus Deploy server
This module tries to log into one or more Octopus Deploy servers. More information about Octopus Deploy: https://octopus.com
1 parent 0f30d3a commit dcf0d74

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
require 'metasploit/framework/login_scanner/http'
2+
require 'json'
3+
4+
module Metasploit
5+
module Framework
6+
module LoginScanner
7+
8+
# Octopus Deploy login scanner
9+
class OctopusDeploy < HTTP
10+
11+
# Inherit LIKELY_PORTS,LIKELY_SERVICE_NAMES, and REALM_KEY from HTTP
12+
CAN_GET_SESSION = true
13+
DEFAULT_PORT = 80
14+
PRIVATE_TYPES = [ :password ]
15+
16+
# (see Base#set_sane_defaults)
17+
def set_sane_defaults
18+
uri = '/api/users/login' if uri.nil?
19+
method = 'POST' if method.nil?
20+
21+
super
22+
end
23+
24+
def attempt_login(credential)
25+
result_opts = {
26+
credential: credential,
27+
host: host,
28+
port: port,
29+
protocol: 'tcp'
30+
}
31+
if ssl
32+
result_opts[:service_name] = 'https'
33+
else
34+
result_opts[:service_name] = 'http'
35+
end
36+
begin
37+
json_post_data = JSON.pretty_generate({ Username: credential.public, Password: credential.private })
38+
cli = Rex::Proto::Http::Client.new(host, port, { 'Msf' => framework, 'MsfExploit' => framework_module }, ssl, ssl_version, http_username, http_password)
39+
configure_http_client(cli)
40+
cli.connect
41+
req = cli.request_cgi(
42+
'method' => 'POST',
43+
'uri' => uri,
44+
'ctype' => 'application/json',
45+
'data' => json_post_data
46+
)
47+
res = cli.send_recv(req)
48+
body = JSON.parse(res.body)
49+
if res && res.code == 200 && body.key?('IsActive') && body['IsActive']
50+
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.body)
51+
else
52+
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res)
53+
end
54+
rescue ::JSON::ParserError
55+
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res.body)
56+
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
57+
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
58+
end
59+
Result.new(result_opts)
60+
end
61+
end
62+
end
63+
end
64+
end
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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/octopusdeploy'
9+
10+
class MetasploitModule < Msf::Auxiliary
11+
12+
include Msf::Exploit::Remote::HttpClient
13+
include Msf::Auxiliary::Report
14+
include Msf::Auxiliary::AuthBrute
15+
include Msf::Auxiliary::Scanner
16+
17+
def initialize
18+
super(
19+
'Name' => 'Octopus Deploy Login Utility',
20+
'Description' => %q{
21+
This module simply attempts to login to a Octopus Deploy server using a specific
22+
username and password. It has been confirmed to work on version 3.4.4
23+
},
24+
'Author' => [ 'James Otten <jamesotten1[at]gmail.com>' ],
25+
'License' => MSF_LICENSE
26+
)
27+
28+
register_options(
29+
[
30+
Opt::RPORT(80),
31+
OptString.new('TARGETURI', [true, 'URI for login. Default is /api/users/login', '/api/users/login'])
32+
], self.class)
33+
end
34+
35+
def run_host(ip)
36+
cred_collection = Metasploit::Framework::CredentialCollection.new(
37+
blank_passwords: datastore['BLANK_PASSWORDS'],
38+
pass_file: datastore['PASS_FILE'],
39+
password: datastore['PASSWORD'],
40+
user_file: datastore['USER_FILE'],
41+
userpass_file: datastore['USERPASS_FILE'],
42+
username: datastore['USERNAME'],
43+
user_as_pass: datastore['USER_AS_PASS']
44+
)
45+
46+
scanner = Metasploit::Framework::LoginScanner::OctopusDeploy.new(
47+
configure_http_login_scanner(
48+
cred_details: cred_collection,
49+
stop_on_success: datastore['STOP_ON_SUCCESS'],
50+
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
51+
connection_timeout: 10,
52+
http_username: datastore['HttpUsername'],
53+
http_password: datastore['HttpPassword'],
54+
uri: datastore['TARGETURI']
55+
)
56+
)
57+
58+
scanner.scan! do |result|
59+
credential_data = result.to_h
60+
credential_data.merge!(
61+
module_fullname: fullname,
62+
workspace_id: myworkspace_id
63+
)
64+
65+
if result.success?
66+
credential_core = create_credential(credential_data)
67+
credential_data[:core] = credential_core
68+
create_credential_login(credential_data)
69+
70+
print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential}"
71+
else
72+
invalidate_login(credential_data)
73+
print_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential} (#{result.status})"
74+
end
75+
end
76+
end
77+
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/octopusdeploy'
3+
4+
RSpec.describe Metasploit::Framework::LoginScanner::OctopusDeploy 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)