Skip to content

Commit 8452ac1

Browse files
dmaloney-r7dmaloney-r7
authored andcommitted
Merge pull request #14 from jvazquez-r7/review_3699
Add specs for #attempt_login
2 parents 2ac15f2 + 9e21cc8 commit 8452ac1

File tree

2 files changed

+126
-8
lines changed

2 files changed

+126
-8
lines changed

lib/metasploit/framework/login_scanner/ipboard.rb

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,22 @@ def attempt_login(credential)
4646
base_uri = uri
4747
end
4848

49-
auth_uri = "#{base_uri}/index.php?app=core&module=global&section=login&do=process"
49+
auth_uri = "#{base_uri}/index.php"
5050

5151
request = http_client.request_cgi(
52-
'uri' => auth_uri,
53-
'method' => 'POST',
54-
'vars_post' => {
55-
'auth_key' => server_nonce,
56-
'ips_username' => credential.public,
57-
'ips_password' => credential.private
58-
},
52+
'uri' => auth_uri,
53+
'method' => 'POST',
54+
'vars_get' => {
55+
'app' => 'core',
56+
'module' => 'global',
57+
'section' => 'login',
58+
'do' => 'process'
59+
},
60+
'vars_post' => {
61+
'auth_key' => server_nonce,
62+
'ips_username' => credential.public,
63+
'ips_password' => credential.private
64+
}
5965
)
6066

6167
response = http_client.send_recv(request)

spec/lib/metasploit/framework/login_scanner/ipboard_spec.rb

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,120 @@
33

44
describe Metasploit::Framework::LoginScanner::IPBoard do
55

6+
subject { described_class.new }
7+
68
it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: false
79
it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket'
810
it_behaves_like 'Metasploit::Framework::LoginScanner::HTTP'
911

12+
context "#attempt_login" do
13+
14+
let(:username) { 'admin' }
15+
let(:password) { 'password' }
16+
let(:server_nonce) { 'nonce' }
17+
18+
let(:creds) do
19+
Metasploit::Framework::Credential.new(
20+
paired: true,
21+
public: username,
22+
private: password
23+
)
24+
end
25+
26+
let(:invalid_creds) do
27+
Metasploit::Framework::Credential.new(
28+
paired: true,
29+
public: 'username',
30+
private: 'novalid'
31+
)
32+
end
33+
34+
context "when Rex::Proto::Http::Client#connect raises Rex::ConnectionError" do
35+
it 'returns status Metasploit::Model::Login::Status::UNABLE_TO_CONNECT' do
36+
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:connect).and_raise(Rex::ConnectionError)
37+
expect(subject.attempt_login(creds).status).to eq(Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
38+
end
39+
end
40+
41+
context "when Rex::Proto::Http::Client#connect raises Timeout::Error" do
42+
it 'returns status Metasploit::Model::Login::Status::UNABLE_TO_CONNECT' do
43+
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:connect).and_raise(Timeout::Error)
44+
expect(subject.attempt_login(creds).status).to eq(Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
45+
end
46+
end
47+
48+
context "when Rex::Proto::Http::Client#connect raises EOFError" do
49+
it 'returns status Metasploit::Model::Login::Status::UNABLE_TO_CONNECT' do
50+
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:connect).and_raise(EOFError)
51+
expect(subject.attempt_login(creds).status).to eq(Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
52+
end
53+
end
54+
55+
context "when invalid IPBoard application" do
56+
let(:not_found_warning) { 'Server nonce not present, potentially not an IP Board install or bad URI.' }
57+
before :each do
58+
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:send_recv) do |cli, req|
59+
Rex::Proto::Http::Response.new(200)
60+
end
61+
end
62+
63+
it 'returns status Metasploit::Model::Login::Status::UNABLE_TO_CONNECT' do
64+
expect(subject.attempt_login(creds).status).to eq(Metasploit::Model::Login::Status::UNABLE_TO_CONNECT)
65+
end
66+
67+
it 'returns proof warning about nonce not found' do
68+
expect(subject.attempt_login(creds).proof).to eq(not_found_warning)
69+
end
70+
end
71+
72+
context "when valid IPBoard application" do
73+
before :each do
74+
allow_any_instance_of(Rex::Proto::Http::Client).to receive(:send_recv) do |cli, req|
75+
76+
if req.opts['uri'] && req.opts['uri'].include?('index.php') &&
77+
req.opts['vars_get'] &&
78+
req.opts['vars_get']['app'] &&
79+
req.opts['vars_get']['app'] == 'core' &&
80+
req.opts['vars_get']['module'] &&
81+
req.opts['vars_get']['module'] == 'global' &&
82+
req.opts['vars_get']['section'] &&
83+
req.opts['vars_get']['section'] == 'login' &&
84+
req.opts['vars_get']['do'] &&
85+
req.opts['vars_get']['do'] == 'process' &&
86+
req.opts['vars_post'] &&
87+
req.opts['vars_post']['auth_key'] &&
88+
req.opts['vars_post']['auth_key'] == server_nonce &&
89+
req.opts['vars_post']['ips_username'] &&
90+
req.opts['vars_post']['ips_username'] == username &&
91+
req.opts['vars_post']['ips_password'] &&
92+
req.opts['vars_post']['ips_password'] == password
93+
res = Rex::Proto::Http::Response.new(200)
94+
res.headers['Set-Cookie'] = 'ipsconnect=ipsconnect_value;Path=/;,coppa=coppa_value;Path=/;'
95+
elsif req.opts['uri'] && req.opts['uri'].include?('index.php') && req.opts['method'] == 'POST'
96+
res = Rex::Proto::Http::Response.new(404)
97+
else
98+
res = Rex::Proto::Http::Response.new(200)
99+
res.body = "name='auth_key' value='#{server_nonce}'"
100+
end
101+
102+
res
103+
end
104+
end
105+
106+
context "when valid login" do
107+
it 'returns status Metasploit::Model::Login::Status::SUCCESSFUL' do
108+
expect(subject.attempt_login(creds).status).to eq(Metasploit::Model::Login::Status::SUCCESSFUL)
109+
end
110+
end
111+
112+
context "when invalid login" do
113+
it 'returns status Metasploit::Model::Login::Status::INCORRECT' do
114+
expect(subject.attempt_login(invalid_creds).status).to eq(Metasploit::Model::Login::Status::INCORRECT)
115+
end
116+
end
117+
118+
end
119+
end
120+
121+
10122
end

0 commit comments

Comments
 (0)