12
12
13
13
CHECK_OLD_RUBIES = !!ENV [ 'MSF_CHECK_OLD_RUBIES' ]
14
14
SUPPRESS_INFO_MESSAGES = !!ENV [ 'MSF_SUPPRESS_INFO_MESSAGES' ]
15
- ENCODING_REGEX = /^# (?:\- \* \- )?encoding:\s *(\S +)/
16
15
17
16
if CHECK_OLD_RUBIES
18
17
require 'rvm'
@@ -48,11 +47,16 @@ class Msftidy
48
47
WARNINGS = 0x10
49
48
ERRORS = 0x20
50
49
50
+ # Some compiles regexes
51
+ REGEX_MSF_EXPLOIT = / \< Msf::Exploit/
52
+ REGEX_IS_BLANK_OR_END = /^\s *end\s *$/
53
+
51
54
attr_reader :full_filepath , :source , :stat , :name , :status
52
55
53
56
def initialize ( source_file )
54
57
@full_filepath = source_file
55
58
@source = load_file ( source_file )
59
+ @lines = @source . lines # returns an enumerator
56
60
@status = OK
57
61
@name = File . basename ( source_file )
58
62
end
@@ -110,29 +114,8 @@ def check_mode
110
114
end
111
115
end
112
116
113
- # Check that modules don't have any encoding comment and that
114
- # non-modules have an explicity binary encoding comment
115
- def check_encoding
116
- # coding/encoding lines must be the first or second line if present
117
- encoding_lines = @source . lines . to_a [ 0 , 2 ] . select { |l | l =~ ENCODING_REGEX }
118
- if @full_filepath =~ /(?:^|\/ )modules\/ /
119
- warn ( 'Modules do not need an encoding comment' ) unless encoding_lines . empty?
120
- else
121
- if encoding_lines . empty?
122
- warn ( 'Non-modules must have an encoding comment' )
123
- else
124
- encoding_line = encoding_lines . first
125
- encoding_line =~ ENCODING_REGEX
126
- encoding_type = Regexp . last_match ( 1 )
127
- unless encoding_type == 'binary'
128
- warn ( "Non-modules must have a binary encoding comment, not #{ encoding_type } " )
129
- end
130
- end
131
- end
132
- end
133
-
134
117
def check_shebang
135
- if @source . lines . first =~ /^#!/
118
+ if @lines . first =~ /^#!/
136
119
warn ( "Module should not have a #! line" )
137
120
end
138
121
end
@@ -148,7 +131,7 @@ def check_nokogiri
148
131
msg = "Using Nokogiri in modules can be risky, use REXML instead."
149
132
has_nokogiri = false
150
133
has_nokogiri_xml_parser = false
151
- @source . each_line do |line |
134
+ @lines . each do |line |
152
135
if has_nokogiri
153
136
if line =~ /Nokogiri::XML\. parse/ or line =~ /Nokogiri::XML::Reader/
154
137
has_nokogiri_xml_parser = true
@@ -165,7 +148,7 @@ def check_ref_identifiers
165
148
in_super = false
166
149
in_refs = false
167
150
168
- @source . each_line do |line |
151
+ @lines . each do |line |
169
152
if !in_super and line =~ /\s +super\( /
170
153
in_super = true
171
154
elsif in_super and line =~ /[[:space:]]*def \w +[\( \w +\) ]*/
@@ -225,7 +208,7 @@ def check_ref_identifiers
225
208
# warn if so. Since Ruby 1.9 this has not been necessary and
226
209
# the framework only suports 1.9+
227
210
def check_rubygems
228
- @source . each_line do |line |
211
+ @lines . each do |line |
229
212
if line_has_require? ( line , 'rubygems' )
230
213
warn ( "Explicitly requiring/loading rubygems is not necessary" )
231
214
break
@@ -256,7 +239,7 @@ def check_old_keywords
256
239
max_count = 10
257
240
counter = 0
258
241
if @source =~ /^##/
259
- @source . each_line do |line |
242
+ @lines . each do |line |
260
243
# If exists, the $Id$ keyword should appear at the top of the code.
261
244
# If not (within the first 10 lines), then we assume there's no
262
245
# $Id$, and then bail.
@@ -288,7 +271,7 @@ def check_badchars
288
271
in_super = false
289
272
in_author = false
290
273
291
- @source . each_line do |line |
274
+ @lines . each do |line |
292
275
#
293
276
# Mark our "super" code block
294
277
#
@@ -366,8 +349,37 @@ def check_old_rubies
366
349
error ( "Fails alternate Ruby version check" ) if rubies . size != res . size
367
350
end
368
351
352
+ def is_exploit_module?
353
+ ret = false
354
+ if @source =~ REGEX_MSF_EXPLOIT
355
+ # having Msf::Exploit is good indicator, but will false positive on
356
+ # specs and other files containing the string, but not really acting
357
+ # as exploit modules, so here we check the file for some actual contents
358
+ # this could be done in a simpler way, but this let's us add more later
359
+ msf_exploit_line_no = nil
360
+ @lines . each_with_index do |line , idx |
361
+ if line = REGEX_MSF_EXPLOIT
362
+ # note the line number
363
+ msf_exploit_line_no = idx
364
+ elsif msf_exploit_line_no
365
+ # check there is anything but empty space between here and the next end
366
+ # something more complex could be added here
367
+ if line !~ REGEX_IS_BLANK_OR_END
368
+ # if the line is not 'end' and is not blank, prolly exploit module
369
+ ret = true
370
+ break
371
+ else
372
+ # then keep checking in case there are more than one Msf::Exploit
373
+ msf_exploit_line_no = nil
374
+ end
375
+ end
376
+ end
377
+ end
378
+ ret
379
+ end
380
+
369
381
def check_ranking
370
- return if @source !~ / \< Msf::Exploit/
382
+ return unless is_exploit_module?
371
383
372
384
available_ranks = [
373
385
'ManualRanking' ,
@@ -406,7 +418,7 @@ def check_disclosure_date
406
418
error ( 'Incorrect disclosure date format' )
407
419
end
408
420
else
409
- error ( 'Exploit is missing a disclosure date' ) if @source =~ / \< Msf::Exploit/
421
+ error ( 'Exploit is missing a disclosure date' ) if is_exploit_module?
410
422
end
411
423
end
412
424
@@ -462,7 +474,7 @@ def check_lines
462
474
src_ended = false
463
475
idx = 0
464
476
465
- @source . each_line { |ln |
477
+ @lines . each do |ln |
466
478
idx += 1
467
479
468
480
# block comment awareness
@@ -541,7 +553,7 @@ def check_lines
541
553
if ln =~ /^\s *Rank\s *=\s */ and @source =~ /<\s Msf::Auxiliary/
542
554
warn ( "Auxiliary modules have no 'Rank': #{ ln } " , idx )
543
555
end
544
- }
556
+ end
545
557
end
546
558
547
559
def check_vuln_codes
@@ -605,7 +617,6 @@ def run_checks(full_filepath)
605
617
tidy = Msftidy . new ( full_filepath )
606
618
tidy . check_mode
607
619
tidy . check_shebang
608
- tidy . check_encoding
609
620
tidy . check_nokogiri
610
621
tidy . check_rubygems
611
622
tidy . check_ref_identifiers
0 commit comments