moby.rb 1.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,134 @@
1
+ # test/Moby/Configuration_test.rb
2
+
3
+ require_relative '../test_helper'
4
+
5
+ describe Moby::Configuration do
6
+ let(:url){'https://phishing.example.com/login'}
7
+
8
+ describe "defaults" do
9
+ let(:config){Moby::Configuration.new(url: url)}
10
+
11
+ it "keeps the url" do
12
+ _(config.url).must_equal(url)
13
+ end
14
+
15
+ it "defaults the backend to mechanize" do
16
+ _(config.backend).must_equal(:mechanize)
17
+ _(config.mechanize?).must_equal(true)
18
+ _(config.selenium?).must_equal(false)
19
+ end
20
+
21
+ it "defaults the browser to chrome" do
22
+ _(config.browser).must_equal(:chrome)
23
+ end
24
+
25
+ it "defaults form_number to 0" do
26
+ _(config.form_number).must_equal(0)
27
+ end
28
+
29
+ it "defaults the field names to username and password" do
30
+ _(config.username_field_name).must_equal('username')
31
+ _(config.password_field_name).must_equal('password')
32
+ end
33
+
34
+ it "defaults the field numbers to 0 and 1" do
35
+ _(config.username_field_number).must_equal(0)
36
+ _(config.password_field_number).must_equal(1)
37
+ end
38
+
39
+ it "runs indefinitely by default" do
40
+ _(config.iterations).must_be_nil
41
+ _(config.fixed_number_of_submissions?).must_equal(false)
42
+ end
43
+
44
+ it "defaults the delay to 0" do
45
+ _(config.delay).must_equal(0)
46
+ end
47
+
48
+ it "is not prefilled, email, verbose or debug by default" do
49
+ _(config.username_prefilled?).must_equal(false)
50
+ _(config.username_is_email_address?).must_equal(false)
51
+ _(config.verbose?).must_equal(false)
52
+ _(config.debug?).must_equal(false)
53
+ end
54
+ end
55
+
56
+ describe "backend and browser selection" do
57
+ it "selects selenium" do
58
+ _(Moby::Configuration.new(url: url, backend: :selenium).selenium?).must_equal(true)
59
+ end
60
+
61
+ it "coerces a string backend to a symbol" do
62
+ _(Moby::Configuration.new(url: url, backend: 'selenium').backend).must_equal(:selenium)
63
+ end
64
+
65
+ it "falls back to mechanize when the backend is nil" do
66
+ _(Moby::Configuration.new(url: url, backend: nil).backend).must_equal(:mechanize)
67
+ end
68
+
69
+ it "falls back to chrome when the browser is nil" do
70
+ _(Moby::Configuration.new(url: url, browser: nil).browser).must_equal(:chrome)
71
+ end
72
+ end
73
+
74
+ describe "coercion of string inputs" do
75
+ let(:config) do
76
+ Moby::Configuration.new(
77
+ url: url,
78
+ form_number: '2',
79
+ username_field_number: '3',
80
+ password_field_number: '4',
81
+ delay: '5',
82
+ iterations: '6'
83
+ )
84
+ end
85
+
86
+ it "coerces the numeric switches to integers" do
87
+ _(config.form_number).must_equal(2)
88
+ _(config.username_field_number).must_equal(3)
89
+ _(config.password_field_number).must_equal(4)
90
+ _(config.delay).must_equal(5)
91
+ _(config.iterations).must_equal(6)
92
+ end
93
+
94
+ it "treats a given iterations count as a fixed number of submissions" do
95
+ _(config.fixed_number_of_submissions?).must_equal(true)
96
+ end
97
+ end
98
+
99
+ describe "#username_is_email_address?" do
100
+ it "is true when set explicitly" do
101
+ _(Moby::Configuration.new(url: url, username_is_email_address: true).username_is_email_address?).must_equal(true)
102
+ end
103
+
104
+ it "is truthy when a username hostname is given" do
105
+ _(Moby::Configuration.new(url: url, username_hostname: 'example.com').username_is_email_address?).wont_equal(false)
106
+ end
107
+
108
+ it "is truthy when the username field is named email" do
109
+ _(Moby::Configuration.new(url: url, username_field_name: 'email').username_is_email_address?).wont_equal(false)
110
+ end
111
+ end
112
+
113
+ describe "#user_agent" do
114
+ it "returns a random agent when not set" do
115
+ agent = Moby::Configuration.new(url: url).user_agent
116
+ _(agent).must_be_kind_of(String)
117
+ _(agent).wont_equal('Mechanize')
118
+ end
119
+
120
+ it "returns the set agent" do
121
+ _(Moby::Configuration.new(url: url, user_agent: 'CustomAgent').user_agent).must_equal('CustomAgent')
122
+ end
123
+ end
124
+
125
+ describe "#using_form_name?" do
126
+ it "is false without a form name" do
127
+ _(Moby::Configuration.new(url: url).using_form_name?).must_equal(false)
128
+ end
129
+
130
+ it "is true with a form name" do
131
+ _(Moby::Configuration.new(url: url, form_name: 'login').using_form_name?).must_equal(true)
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,37 @@
1
+ # test/Moby/RandomInputGenerator_test.rb
2
+
3
+ require_relative '../test_helper'
4
+
5
+ describe Moby::RandomInputGenerator do
6
+ let(:word_list_path){TestFixtures::WORD_LIST_PATH}
7
+
8
+ def generator(**args)
9
+ Moby::RandomInputGenerator.new(word_list_path: word_list_path, **args)
10
+ end
11
+
12
+ describe "#random_username" do
13
+ it "returns a word from the list by default" do
14
+ _(TestFixtures::WORDS).must_include(generator.random_username)
15
+ end
16
+
17
+ it "returns an email address when username_is_email_address is true" do
18
+ _(generator(username_is_email_address: true).random_username).must_match(/\A[^@]+@[^@]+\z/)
19
+ end
20
+
21
+ it "uses the given hostname for the email address" do
22
+ username = generator(username_hostname: 'example.com', username_is_email_address: true).random_username
23
+ _(username).must_match(/@example\.com\z/)
24
+ end
25
+
26
+ it "generates more than one distinct username" do
27
+ usernames = 20.times.map{generator.random_username}
28
+ _(usernames.uniq.length).must_be(:>, 1)
29
+ end
30
+ end
31
+
32
+ describe "#random_password" do
33
+ it "returns a word from the list" do
34
+ _(TestFixtures::WORDS).must_include(generator.random_password)
35
+ end
36
+ end
37
+ end
@@ -16,8 +16,8 @@ describe Moby do
16
16
  _(Moby::VERSION).must_match(/\d+\.\d+\.\d+/)
17
17
  end
18
18
 
19
- it "version is 1.0.1" do
20
- _(Moby::VERSION).must_equal('1.0.1')
19
+ it "version is 2.0.0" do
20
+ _(Moby::VERSION).must_equal('2.0.0')
21
21
  end
22
22
  end
23
23
  end
data/test/moby_test.rb CHANGED
@@ -4,292 +4,16 @@ require_relative './test_helper'
4
4
 
5
5
  describe Moby do
6
6
  let(:url){'https://phishing.example.com/login'}
7
- let(:moby){Moby.new(url: url)}
8
7
 
9
- before do
10
- WebMock.disable_net_connect!
11
-
12
- # Stub the login page
13
- stub_request(:get, url)
14
- .to_return(
15
- status: 200,
16
- body: TestFixtures::SIMPLE_LOGIN_FORM,
17
- headers: {'Content-Type' => 'text/html'}
18
- )
19
-
20
- # Stub form submission
21
- stub_request(:post, 'https://phishing.example.com/login')
22
- .to_return(status: 200, body: 'Success')
23
- end
24
-
25
- after do
26
- WebMock.reset!
27
- WebMock.allow_net_connect!
28
- end
29
-
30
- describe "initialization" do
31
- it "accepts url parameter" do
32
- _(moby.url).must_equal(url)
33
- end
34
-
35
- it "sets default form_number to 0" do
36
- _(moby.form_number).must_equal(0)
37
- end
38
-
39
- it "sets default username_field_name to 'username'" do
40
- _(moby.username_field_name).must_equal('username')
41
- end
42
-
43
- it "sets default password_field_name to 'password'" do
44
- _(moby.password_field_name).must_equal('password')
45
- end
46
-
47
- it "sets default username_field_number to 0" do
48
- _(moby.username_field_number).must_equal(0)
49
- end
50
-
51
- it "sets default password_field_number to 1" do
52
- _(moby.password_field_number).must_equal(1)
53
- end
54
-
55
- it "accepts form_name parameter" do
56
- m = Moby.new(url: url, form_name: 'login')
57
-
58
- _(m.form_name).must_equal('login')
59
- end
60
-
61
- it "accepts username_hostname parameter" do
62
- m = Moby.new(url: url, username_hostname: 'example.com')
63
-
64
- _(m.username_hostname).must_equal('example.com')
65
- end
66
-
67
- it "accepts username_is_email_address parameter" do
68
- m = Moby.new(url: url, username_is_email_address: true)
69
-
70
- _(m.username_is_email_address).must_equal(true)
71
- end
72
- end
73
-
74
- describe "mechanize setup" do
75
- it "creates Mechanize instance lazily" do
76
- mech = moby.instance_variable_get(:@mechanize)
77
-
78
- _(mech).must_be_nil
79
-
80
- moby.send(:mechanize)
81
- mech = moby.instance_variable_get(:@mechanize)
82
-
83
- _(mech).must_be_instance_of(Mechanize)
84
- end
85
-
86
- it "reuses same mechanize instance" do
87
- mech1 = moby.send(:mechanize)
88
- mech2 = moby.send(:mechanize)
89
-
90
- _(mech1).must_be_same_as(mech2)
91
- end
92
- end
93
-
94
- describe "page loading" do
95
- it "loads the target URL" do
96
- page = moby.send(:page)
97
-
98
- _(page).must_be_instance_of(Mechanize::Page)
99
- assert_requested(:get, url, times: 1)
100
- end
101
-
102
- it "reuses loaded page" do
103
- page1 = moby.send(:page)
104
- page2 = moby.send(:page)
105
-
106
- _(page1).must_be_same_as(page2)
107
- assert_requested(:get, url, times: 1)
108
- end
109
-
110
- it "handles meta refresh redirects" do
111
- redirect_body = '<html><head><meta http-equiv="Refresh" content="0; url=https://phishing.example.com/real-login"></head></html>'
112
-
113
- stub_request(:get, url)
114
- .to_return(status: 200, body: redirect_body, headers: {'Content-Type' => 'text/html'})
115
-
116
- stub_request(:get, 'https://phishing.example.com/real-login')
117
- .to_return(status: 200, body: TestFixtures::SIMPLE_LOGIN_FORM, headers: {'Content-Type' => 'text/html'})
118
-
119
- m = Moby.new(url: url)
120
- page = m.send(:page)
121
-
122
- assert_requested(:get, url, times: 1)
123
- assert_requested(:get, 'https://phishing.example.com/real-login', times: 1)
124
- end
125
- end
126
-
127
- describe "form finding" do
128
- describe "finding by name" do
129
- let(:moby) do
130
- Moby.new(url: url, form_name: 'login')
131
- end
132
-
133
- it "finds form by name when form_name is set" do
134
- moby.send(:page)
135
- form = moby.send(:form)
136
-
137
- _(form).must_be_instance_of(Mechanize::Form)
138
- _(form.name).must_equal('login')
139
- end
140
- end
141
-
142
- describe "finding by number" do
143
- let(:moby) do
144
- Moby.new(url: 'https://multi.example.com/page', form_number: 1)
145
- end
146
-
147
- it "finds form by number when form_number is set" do
148
- stub_request(:get, 'https://multi.example.com/page')
149
- .to_return(
150
- status: 200,
151
- body: TestFixtures::MULTIPLE_FORMS,
152
- headers: {'Content-Type' => 'text/html'}
153
- )
154
- moby.send(:page)
155
- form = moby.send(:form)
156
-
157
- _(form).must_be_instance_of(Mechanize::Form)
158
- _(form.node['id']).must_equal('login_form')
159
- end
160
- end
161
-
162
- describe "deafult form" do
163
- it "defaults to first form" do
164
- moby.send(:page)
165
- form = moby.send(:form)
166
-
167
- _(form).must_be_instance_of(Mechanize::Form)
168
- end
169
- end
170
- end
171
-
172
- describe "field finding" do
173
- describe "finding by name" do
174
- let(:moby) do
175
- Moby.new(url: url, form_name: 'login', username_field_name: 'username', password_field_name: 'password')
176
- end
177
-
178
- it "finds username field by name" do
179
- moby.send(:page)
180
- moby.send(:form)
181
- field = moby.send(:username_field)
182
-
183
- _(field.name).must_equal('username')
184
- end
185
-
186
- it "finds password field by name" do
187
- moby.send(:page)
188
- moby.send(:form)
189
- field = moby.send(:password_field)
190
-
191
- _(field.name).must_equal('password')
192
- end
193
- end
194
-
195
- describe "finding by number" do
196
- let(:moby) do
197
- Moby.new(url: url, username_field_number: 0, password_field_number: 1)
198
- end
199
-
200
- it "finds username field by number" do
201
- moby.send(:page)
202
- moby.send(:form)
203
- field = moby.send(:username_field)
204
-
205
- _(field).wont_be_nil
206
- end
207
-
208
- it "finds password field by number" do
209
- moby.send(:page)
210
- moby.send(:form)
211
- field = moby.send(:password_field)
212
-
213
- _(field).wont_be_nil
214
- end
215
- end
216
- end
217
-
218
- describe "#username" do
219
- it "generates random username" do
220
- username = moby.send(:username)
221
-
222
- _(username).must_be_kind_of(String)
223
- _(username.length).must_be(:>, 0)
224
- end
225
-
226
- it "generates email address when username_is_email_address is true" do
227
- m = Moby.new(url: url, username_is_email_address: true)
228
- username = m.send(:username)
229
-
230
- _(username).must_match(/@/)
231
- end
232
-
233
- it "generates email with custom hostname" do
234
- m = Moby.new(url: url, username_hostname: 'example.com')
235
- username = m.send(:username)
236
-
237
- _(username).must_match(/@example\.com$/)
238
- end
239
-
240
-
241
- it "generates different usernames" do
242
- usernames = 10.times.map{moby.send(:username)}
243
-
244
- _(usernames.uniq.length).must_be(:>, 1)
245
- end
8
+ it "selects the mechanize backend by default" do
9
+ _(Moby.new(url: url).send(:backend)).must_be_instance_of(Moby::Backends::MechanizeBackend)
246
10
  end
247
11
 
248
- describe "#password" do
249
- it "generates random password" do
250
- password = moby.send(:password)
251
-
252
- _(password).must_be_kind_of(String)
253
- _(password.length).must_be(:>, 0)
254
- end
12
+ it "selects the selenium backend when configured" do
13
+ _(Moby.new(url: url, backend: :selenium).send(:backend)).must_be_instance_of(Moby::Backends::SeleniumBackend)
255
14
  end
256
15
 
257
- describe "#user_agent" do
258
- it "returns random user agent when not set" do
259
- agent = moby.send(:user_agent)
260
-
261
- _(agent).must_be_kind_of(String)
262
- _(agent).wont_equal('Mechanize')
263
- end
264
-
265
- it "returns set user agent when provided" do
266
- m = Moby.new(url: url, user_agent: 'CustomAgent')
267
-
268
- _(m.send(:user_agent)).must_equal('CustomAgent')
269
- end
270
-
271
- it "generates different random agents" do
272
- agents = 10.times.map{Moby.new(url: url).send(:user_agent)}
273
-
274
- _(agents.uniq.length).must_be(:>, 1)
275
- end
276
- end
277
-
278
- describe "#username_is_email_address?" do
279
- it "returns true when username_is_email_address is set" do
280
- m = Moby.new(url: url, username_is_email_address: true)
281
-
282
- _(m.send(:username_is_email_address?)).must_equal(true)
283
- end
284
-
285
- it "returns true when username_hostname is set" do
286
- m = Moby.new(url: url, username_hostname: 'example.com')
287
-
288
- _(m.send(:username_is_email_address?)).wont_be_nil
289
- end
290
-
291
- it "returns false by default" do
292
- _(moby.send(:username_field_name)).must_equal('username')
293
- end
16
+ it "responds to counter_phish" do
17
+ _(Moby.new(url: url)).must_respond_to(:counter_phish)
294
18
  end
295
19
  end
data/test/test_helper.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'minitest/autorun'
4
4
  require 'minitest-spec-context'
5
5
  require 'webmock/minitest'
6
+ require 'tempfile'
6
7
 
7
8
  require_relative '../lib/moby'
8
9
 
@@ -33,4 +34,18 @@ module TestFixtures
33
34
  </body>
34
35
  </html>
35
36
  HTML
37
+
38
+ WORDS = %w{
39
+ alpha bravo charlie delta echo foxtrot golf hotel india juliet
40
+ kilo lima mike november oscar papa quebec romeo sierra tango
41
+ uniform victor whiskey xray yankee zulu apple banana cherry date
42
+ elder fig grape honey iris jasmine kiwi lemon mango nutmeg
43
+ }.freeze
44
+
45
+ WORD_LIST_FILE = Tempfile.new('moby_words').tap do |file|
46
+ file.write(WORDS.join("\n") << "\n")
47
+ file.flush
48
+ end
49
+
50
+ WORD_LIST_PATH = WORD_LIST_FILE.path
36
51
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moby.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: selenium-webdriver
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '4'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '4'
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: switches.rb
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -108,11 +122,23 @@ files:
108
122
  - README.md
109
123
  - Rakefile
110
124
  - bin/moby
111
- - lib/File/self.collect.rb
112
125
  - lib/Moby.rb
126
+ - lib/Moby/Backends.rb
127
+ - lib/Moby/Backends/MechanizeBackend.rb
128
+ - lib/Moby/Backends/SeleniumBackend.rb
129
+ - lib/Moby/Configuration.rb
130
+ - lib/Moby/RandomInputGenerator.rb
113
131
  - lib/Moby/VERSION.rb
114
- - lib/Thoran/File/SelfCollect/self.collect.rb
132
+ - lib/Selenium/WebDriver/Driver/Attempt/attempt.rb
133
+ - lib/Selenium/WebDriver/SearchContext/ElementPresentQ/element_presentQ.rb
134
+ - lib/Thoran/Selenium/WebDriver/Driver/Attempt/attempt.rb
135
+ - lib/Thoran/Selenium/WebDriver/SearchContext/ElementPresentQ/element_presentQ.rb
115
136
  - moby.rb.gemspec
137
+ - test/Moby/Backends/MechanizeBackend_test.rb
138
+ - test/Moby/Backends/SeleniumBackend_test.rb
139
+ - test/Moby/Backends_test.rb
140
+ - test/Moby/Configuration_test.rb
141
+ - test/Moby/RandomInputGenerator_test.rb
116
142
  - test/Moby/VERSION_test.rb
117
143
  - test/moby_test.rb
118
144
  - test/test_helper.rb
@@ -131,14 +157,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
131
157
  requirements:
132
158
  - - ">="
133
159
  - !ruby/object:Gem::Version
134
- version: 2.5.0
160
+ version: 3.3.0
135
161
  required_rubygems_version: !ruby/object:Gem::Requirement
136
162
  requirements:
137
163
  - - ">="
138
164
  - !ruby/object:Gem::Version
139
165
  version: '0'
140
166
  requirements: []
141
- rubygems_version: 4.0.17
167
+ rubygems_version: 4.0.18
142
168
  specification_version: 4
143
169
  summary: Moby is a credentials poisoning tool which floods phishing forms with fake
144
170
  credentials.
@@ -1,10 +0,0 @@
1
- # File/self.collect.rb
2
- # File.collect
3
-
4
- # 20200111
5
- # 0.2.1
6
-
7
- # Changes:
8
- # 1. + Thoran::File::SelfCollect namespace.
9
-
10
- require 'Thoran/File/SelfCollect/self.collect.rb'
@@ -1,22 +0,0 @@
1
- # Thoran/File/SelfCollect/self.collect.rb
2
- # Thoran::File::SelfCollect.collect.rb
3
-
4
- # 20190821
5
- # 0.2.0
6
-
7
- # Changes:
8
- # 1. + Thoran::File::SelfCollect namespace.
9
-
10
- module Thoran
11
- module File
12
- module SelfCollect
13
-
14
- def collect(filename, &block)
15
- open(filename, 'r').collect(&block)
16
- end
17
-
18
- end
19
- end
20
- end
21
-
22
- File.extend(Thoran::File::SelfCollect)