Skip to content

Commit a39f7b9

Browse files
committed
Land rapid7#3684 - IP Board Login Scanner
2 parents c20b4dc + 302e402 commit a39f7b9

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
2+
require 'msf/core'
3+
4+
class Metasploit3 < Msf::Auxiliary
5+
6+
include Msf::Exploit::Remote::HttpClient
7+
include Msf::Auxiliary::Report
8+
include Msf::Auxiliary::AuthBrute
9+
include Msf::Auxiliary::Scanner
10+
11+
def initialize
12+
super(
13+
'Name' => 'IP Board Login Auxiliary Module',
14+
'Description' => %q{
15+
This module attempts to validate user provided credentials against
16+
an IP Board web application.
17+
},
18+
'Author' => 'Christopher Truncer [email protected]',
19+
'License' => MSF_LICENSE
20+
)
21+
22+
register_options([
23+
OptString.new('TARGETURI', [true, "The directory of the IP Board install", "/forum/"]),
24+
], self.class)
25+
end
26+
27+
def run_host(ip)
28+
connect
29+
30+
each_user_pass do |user, pass|
31+
do_login(user, pass, ip)
32+
end
33+
end
34+
35+
def do_login(user, pass, ip)
36+
begin
37+
print_status "Connecting to target, searching for IP Board server nonce..."
38+
39+
# Perform the initial request and find the server nonce, which is required to log
40+
# into IP Board
41+
res = send_request_cgi({
42+
'uri' => normalize_uri(target_uri.path),
43+
'method' => 'GET'
44+
}, 10)
45+
46+
unless res
47+
print_error "No response when trying to connect to #{vhost}"
48+
return :connection_error
49+
end
50+
51+
# Grab the key from within the body, or alert that it can't be found and exit out
52+
if res.body =~ /name='auth_key'\s+value='.*?((?:[a-z0-9]*))'/i
53+
server_nonce = $1
54+
print_status "Server nonce found, attempting to log in..."
55+
else
56+
print_error "Server nonce not present, potentially not an IP Board install or bad URI."
57+
print_error "Skipping #{vhost}.."
58+
return :abort
59+
end
60+
61+
# With the server nonce found, try to log into IP Board with the user provided creds
62+
res2 = send_request_cgi({
63+
'uri' => normalize_uri(target_uri.path, "index.php?app=core&module=global&section=login&do=process"),
64+
'method' => 'POST',
65+
'vars_post' => {
66+
'auth_key' => server_nonce,
67+
'ips_username' => user,
68+
'ips_password' => pass
69+
}
70+
})
71+
72+
# Default value of no creds found
73+
valid_creds = false
74+
75+
# Iterate over header response. If the server is setting the ipsconnect and coppa cookie
76+
# then we were able to log in successfully. If they are not set, invalid credentials were
77+
# provided.
78+
79+
if res2.get_cookies.include?('ipsconnect') && res2.get_cookies.include?('coppa')
80+
valid_creds = true
81+
end
82+
83+
# Inform the user if the user supplied credentials were valid or not
84+
if valid_creds
85+
print_good "Username: #{user} and Password: #{pass} are valid credentials!"
86+
register_creds(user, pass, ip)
87+
return :next_user
88+
else
89+
vprint_error "Username: #{user} and Password: #{pass} are invalid credentials!"
90+
return nil
91+
end
92+
93+
rescue ::Timeout::Error
94+
print_error "Connection timed out while attempting to reach #{vhost}!"
95+
return :connection_error
96+
97+
rescue ::Errno::EPIPE
98+
print_error "Broken pipe error when connecting to #{vhost}!"
99+
return :connection_error
100+
end
101+
end
102+
103+
def register_creds(username, password, ipaddr)
104+
# Build service information
105+
service_data = {
106+
address: ipaddr,
107+
port: datastore['RPORT'],
108+
service_name: 'http',
109+
protocol: 'tcp',
110+
workspace_id: myworkspace_id
111+
}
112+
113+
# Build credential information
114+
credential_data = {
115+
origin_type: :service,
116+
module_fullname: self.fullname,
117+
private_data: password,
118+
private_type: :password,
119+
username: username,
120+
workspace_id: myworkspace_id
121+
}
122+
123+
credential_data.merge!(service_data)
124+
credential_core = create_credential(credential_data)
125+
126+
# Assemble the options hash for creating the Metasploit::Credential::Login object
127+
login_data = {
128+
access_level: "user",
129+
core: credential_core,
130+
last_attempted_at: DateTime.now,
131+
status: Metasploit::Model::Login::Status::SUCCESSFUL,
132+
workspace_id: myworkspace_id
133+
}
134+
135+
login_data.merge!(service_data)
136+
create_credential_login(login_data)
137+
end
138+
139+
end

0 commit comments

Comments
 (0)