scanny 0.1.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.
- data/.gitignore +5 -0
- data/Gemfile +11 -0
- data/LICENSE +23 -0
- data/README.md +185 -0
- data/Rakefile +5 -0
- data/bin/scanny +61 -0
- data/lib/scanny.rb +12 -0
- data/lib/scanny/checks/access_control_check.rb +52 -0
- data/lib/scanny/checks/backticks_check.rb +18 -0
- data/lib/scanny/checks/before_filters_check.rb +35 -0
- data/lib/scanny/checks/check.rb +33 -0
- data/lib/scanny/checks/csrf_check.rb +19 -0
- data/lib/scanny/checks/denial_of_service_check.rb +42 -0
- data/lib/scanny/checks/file_open_check.rb +46 -0
- data/lib/scanny/checks/frameworks_check.rb +24 -0
- data/lib/scanny/checks/helpers.rb +28 -0
- data/lib/scanny/checks/http_basic_auth_check.rb +39 -0
- data/lib/scanny/checks/http_header/header_injection_check.rb +38 -0
- data/lib/scanny/checks/http_redirect_check.rb +37 -0
- data/lib/scanny/checks/http_request_check.rb +74 -0
- data/lib/scanny/checks/http_usage_check.rb +31 -0
- data/lib/scanny/checks/information_leak_check.rb +55 -0
- data/lib/scanny/checks/input_filtering_check.rb +39 -0
- data/lib/scanny/checks/insecure_config/set_rails_env_check.rb +24 -0
- data/lib/scanny/checks/insecure_config/set_secret_check.rb +25 -0
- data/lib/scanny/checks/insecure_config/set_session_key_check.rb +23 -0
- data/lib/scanny/checks/insecure_method/eval_method_check.rb +26 -0
- data/lib/scanny/checks/insecure_method/marshal_check.rb +33 -0
- data/lib/scanny/checks/insecure_method/system_method_check.rb +46 -0
- data/lib/scanny/checks/mass_assignment_check.rb +48 -0
- data/lib/scanny/checks/random_numbers_check.rb +54 -0
- data/lib/scanny/checks/redirect_with_params_check.rb +48 -0
- data/lib/scanny/checks/regexp_check.rb +23 -0
- data/lib/scanny/checks/reset_session_check.rb +24 -0
- data/lib/scanny/checks/session/access_to_session_check.rb +49 -0
- data/lib/scanny/checks/session/session_secure_check.rb +47 -0
- data/lib/scanny/checks/shell_expanding_methods_check.rb +54 -0
- data/lib/scanny/checks/skip_before_filters_check.rb +41 -0
- data/lib/scanny/checks/sql_injection/find_method_check.rb +81 -0
- data/lib/scanny/checks/sql_injection/find_method_with_dynamic_string_check.rb +43 -0
- data/lib/scanny/checks/sql_injection/find_method_with_params_check.rb +80 -0
- data/lib/scanny/checks/sql_injection/sanitize_sql_check.rb +25 -0
- data/lib/scanny/checks/sql_injection/sql_check.rb +14 -0
- data/lib/scanny/checks/sql_injection/string_interpolation_with_params_check.rb +39 -0
- data/lib/scanny/checks/ssl/verify_check.rb +53 -0
- data/lib/scanny/checks/ssl/verify_peer_check.rb +37 -0
- data/lib/scanny/checks/system_tools/gpg_usage_check.rb +51 -0
- data/lib/scanny/checks/system_tools/sudo_check.rb +24 -0
- data/lib/scanny/checks/system_tools/tar_check.rb +24 -0
- data/lib/scanny/checks/system_tools/tar_commands_check.rb +27 -0
- data/lib/scanny/checks/system_tools/unzip_check.rb +30 -0
- data/lib/scanny/checks/temp_file_open_check.rb +57 -0
- data/lib/scanny/checks/user_find_check.rb +40 -0
- data/lib/scanny/checks/validates_check.rb +32 -0
- data/lib/scanny/checks/verify_check.rb +44 -0
- data/lib/scanny/checks/xss/xss_flash_check.rb +70 -0
- data/lib/scanny/checks/xss/xss_logger_check.rb +78 -0
- data/lib/scanny/checks/xss/xss_mark_check.rb +48 -0
- data/lib/scanny/checks/xss/xss_send_check.rb +70 -0
- data/lib/scanny/cli.rb +47 -0
- data/lib/scanny/issue.rb +28 -0
- data/lib/scanny/rake_task.rb +56 -0
- data/lib/scanny/reporters.rb +3 -0
- data/lib/scanny/reporters/reporter.rb +22 -0
- data/lib/scanny/reporters/simple_reporter.rb +19 -0
- data/lib/scanny/reporters/xml_reporter.rb +64 -0
- data/lib/scanny/ruby_version_check.rb +15 -0
- data/lib/scanny/runner.rb +90 -0
- data/scanny.gemspec +22 -0
- data/spec/scanny/check_spec.rb +22 -0
- data/spec/scanny/checks/access_control_check_spec.rb +43 -0
- data/spec/scanny/checks/backticks_check_spec.rb +22 -0
- data/spec/scanny/checks/before_filters_check_spec.rb +45 -0
- data/spec/scanny/checks/csrf_check_spec.rb +16 -0
- data/spec/scanny/checks/denial_of_service_check_spec.rb +28 -0
- data/spec/scanny/checks/file_open_check_spec.rb +22 -0
- data/spec/scanny/checks/frameworks_check_spec.rb +16 -0
- data/spec/scanny/checks/http_basic_auth_check_spec.rb +20 -0
- data/spec/scanny/checks/http_header/header_injection_check_spec.rb +21 -0
- data/spec/scanny/checks/http_redirect_check_spec.rb +15 -0
- data/spec/scanny/checks/http_request_check_spec.rb +37 -0
- data/spec/scanny/checks/http_usage_check_spec.rb +20 -0
- data/spec/scanny/checks/information_leak_check_spec.rb +32 -0
- data/spec/scanny/checks/input_filtering_check_spec.rb +19 -0
- data/spec/scanny/checks/insecure_config/set_rails_env_check_spec.rb +17 -0
- data/spec/scanny/checks/insecure_config/set_secret_check_spec.rb +22 -0
- data/spec/scanny/checks/insecure_config/set_session_key_check_spec.rb +21 -0
- data/spec/scanny/checks/insecure_method/eval_method_check_spec.rb +22 -0
- data/spec/scanny/checks/insecure_method/marshal_check_spec.rb +26 -0
- data/spec/scanny/checks/insecure_method/system_method_check_spec.rb +33 -0
- data/spec/scanny/checks/mass_assignment_check_spec.rb +30 -0
- data/spec/scanny/checks/random_numbers_check_spec.rb +41 -0
- data/spec/scanny/checks/redirect_with_params_check_spec.rb +24 -0
- data/spec/scanny/checks/regexp_check_spec.rb +22 -0
- data/spec/scanny/checks/reset_session_check_spec.rb +15 -0
- data/spec/scanny/checks/session/access_to_session_check_spec.rb +29 -0
- data/spec/scanny/checks/session/session_secure_check_spec.rb +22 -0
- data/spec/scanny/checks/shell_expanding_methods_check_spec.rb +67 -0
- data/spec/scanny/checks/skip_before_filters_check_spec.rb +81 -0
- data/spec/scanny/checks/sql_injection/find_method_check_spec.rb +62 -0
- data/spec/scanny/checks/sql_injection/find_method_with_dynamic_string_check_spec.rb +27 -0
- data/spec/scanny/checks/sql_injection/find_method_with_params_check_spec.rb +93 -0
- data/spec/scanny/checks/sql_injection/sanitize_sql_check_spec.rb +16 -0
- data/spec/scanny/checks/sql_injection/string_interpolation_with_params_check_spec.rb +18 -0
- data/spec/scanny/checks/ssl/verify_check_spec.rb +25 -0
- data/spec/scanny/checks/ssl/verify_peer_check_spec.rb +17 -0
- data/spec/scanny/checks/system_tools/gpg_usage_check_spec.rb +43 -0
- data/spec/scanny/checks/system_tools/sudo_check_spec.rb +24 -0
- data/spec/scanny/checks/system_tools/tar_check_spec.rb +20 -0
- data/spec/scanny/checks/system_tools/tar_commands_check_spec.rb +41 -0
- data/spec/scanny/checks/system_tools/unizp_check_spec.rb +29 -0
- data/spec/scanny/checks/temp_file_open_check_spec.rb +22 -0
- data/spec/scanny/checks/user_find_check_spec.rb +22 -0
- data/spec/scanny/checks/validates_check_spec.rb +19 -0
- data/spec/scanny/checks/verify_check_spec.rb +27 -0
- data/spec/scanny/checks/xss/xss_flash_check_spec.rb +22 -0
- data/spec/scanny/checks/xss/xss_logger_check_spec.rb +24 -0
- data/spec/scanny/checks/xss/xss_mark_check_spec.rb +31 -0
- data/spec/scanny/checks/xss/xss_send_check_spec.rb +34 -0
- data/spec/scanny/cli_spec.rb +167 -0
- data/spec/scanny/issue_spec.rb +82 -0
- data/spec/scanny/rake_taks_spec.rb +82 -0
- data/spec/scanny/reporters/reporter_spec.rb +24 -0
- data/spec/scanny/reporters/simple_reporter_spec.rb +48 -0
- data/spec/scanny/reporters/xml_reporter_spec.rb +52 -0
- data/spec/scanny/ruby_version_check_spec.rb +24 -0
- data/spec/scanny/runner_spec.rb +128 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/aruba.rb +4 -0
- data/spec/support/check_spec_helpers.rb +5 -0
- data/spec/support/checks/extend_test_check.rb +11 -0
- data/spec/support/checks/test_check.rb +15 -0
- data/spec/support/checks/test_strict_check.rb +17 -0
- data/spec/support/const_spec_helpers.rb +36 -0
- data/spec/support/matchers/check_matcher.rb +43 -0
- data/spec/support/matchers/xpath_matcher.rb +30 -0
- data/spec/support/mock_task.rb +43 -0
- metadata +242 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Copyright (c) 2011 SUSE
|
|
2
|
+
Copyright (c) 2008 Marty Andrews
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person
|
|
5
|
+
obtaining a copy of this software and associated documentation
|
|
6
|
+
files (the "Software"), to deal in the Software without
|
|
7
|
+
restriction, including without limitation the rights to use,
|
|
8
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the
|
|
10
|
+
Software is furnished to do so, subject to the following
|
|
11
|
+
conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
18
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
20
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
21
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
22
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
23
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Scanny
|
|
2
|
+
======
|
|
3
|
+
|
|
4
|
+
Scanny is a Ruby on Rails security scanner. It parses Ruby files, looks for various suspicious patterns in them (by traversing the AST) and produces a report. Scanny aims to be simple (it does one thing well) and extensible (it is easy to define new patterns).
|
|
5
|
+
|
|
6
|
+
**This is currently work in progress and it's probably not useful yet.**
|
|
7
|
+
|
|
8
|
+
Installation
|
|
9
|
+
------------
|
|
10
|
+
|
|
11
|
+
You need to install the current development version of [Rubinius](http://rubini.us/) first. You can then install Scanny:
|
|
12
|
+
|
|
13
|
+
$ gem install scanny
|
|
14
|
+
|
|
15
|
+
Usage
|
|
16
|
+
-----
|
|
17
|
+
|
|
18
|
+
To scan one or more Ruby file, use the `scanny` command and pass the files to scan as arguments. Scanny will check the files and print a nice report:
|
|
19
|
+
|
|
20
|
+
$ cat bad.rb
|
|
21
|
+
`ls #{ARGV[1]}`
|
|
22
|
+
$ scanny bad.rb
|
|
23
|
+
bad.rb [2 checks done | 2 nodes inspected | 1 issues]
|
|
24
|
+
- [high] bad.rb:1: Backticks and %x{...} pass the executed command through shell expansion. (CWE-88, CWE-78)
|
|
25
|
+
|
|
26
|
+
Found 1 issues.
|
|
27
|
+
|
|
28
|
+
Rake task
|
|
29
|
+
---------
|
|
30
|
+
|
|
31
|
+
To create scanny rake task you need to edit Rakefile.
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
require "scanny/rake_task"
|
|
35
|
+
|
|
36
|
+
Scanny::RakeTask.new do |t|
|
|
37
|
+
t.name = "scanny" # name of rake-task
|
|
38
|
+
t.include = "./custom/checks" # directory with custom checks
|
|
39
|
+
t.disable = "HTTPRedirectCheck" # checks to disable
|
|
40
|
+
t.format = :stdout # output format
|
|
41
|
+
t.strict = true # scanny strict mode
|
|
42
|
+
t.path = "./custom/app" # path to scan
|
|
43
|
+
t.fail_on_error = true # raise exception on error
|
|
44
|
+
t.ruby_mode = "18" # ruby parser mode (default 19)
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
CI (Continuous Integration)
|
|
49
|
+
---------------------------
|
|
50
|
+
|
|
51
|
+
### Common for all CLI
|
|
52
|
+
|
|
53
|
+
* Add to ```Gemfile``` scanny gem
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
gem 'scanny'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
* Create [Rake task](https://github.com/openSUSE/scanny#rake-task).
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
Scanny::RakeTask.new do |t|
|
|
63
|
+
t.format = :stdout # you will see output on travis website
|
|
64
|
+
t.fail_on_error = false # security errors should not break build
|
|
65
|
+
end
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Travis
|
|
69
|
+
|
|
70
|
+
* Update your ```.travis.yml``` file. You need add ```before_script``` section.
|
|
71
|
+
|
|
72
|
+
```yaml
|
|
73
|
+
before_script:
|
|
74
|
+
- test -s "$HOME/.rvm/scripts/rvm" && source "$HOME/.rvm/scripts/rvm"
|
|
75
|
+
- rvm rbx-19mode
|
|
76
|
+
- bundle install
|
|
77
|
+
- bundle exec rake scanny
|
|
78
|
+
- rvm $TRAVIS_RUBY_VERSION
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Jenkins
|
|
82
|
+
|
|
83
|
+
* Add build step
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
bash -l -c '
|
|
87
|
+
rvm rbx-head &&
|
|
88
|
+
rvm gemset create scanny &&
|
|
89
|
+
rvm gemset use scanny &&
|
|
90
|
+
bundle install &&
|
|
91
|
+
bundle exec rake scanny'
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
* Install [Log Parser Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Log+Parser+Plugin) for Jenkins
|
|
95
|
+
* Create rules file
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
# /var/lib/jenkins/rules
|
|
99
|
+
|
|
100
|
+
info /- \[info\]/
|
|
101
|
+
warning /- \[low\]/
|
|
102
|
+
error /- \[(medium|high)\]/
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
* Go to ```Manage Jenkins > Configure System > Console Output Parsing```.
|
|
106
|
+
Add path to rules with in **Parsing Rules File** field
|
|
107
|
+
|
|
108
|
+
* Go to and check ```[Project] > Configure > Console output (build log) parsing```
|
|
109
|
+
* Select proper **Select Parsing Rules**
|
|
110
|
+
* Warnings you can find in ```[Build] > Parsed Console Output```
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
Writing New Checks
|
|
114
|
+
------------------
|
|
115
|
+
Internally, Scanny consists of multiple *checks*, each responsible for finding and reporting one suspicious pattern in the code. You can easily extend Scanny by writing new checks.
|
|
116
|
+
|
|
117
|
+
The checks are loaded automatically from files in the `lib/scanny/checks` directory. Let's look how a simple check may look like:
|
|
118
|
+
|
|
119
|
+
module Scanny
|
|
120
|
+
module Checks
|
|
121
|
+
# Finds all invocations of "boo" and "moo" methods.
|
|
122
|
+
class BooMooCheck < Check
|
|
123
|
+
def pattern
|
|
124
|
+
'Send<name = :boo | :moo> | SendWithArguments<name = :boo | :moo>'
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def check(node)
|
|
128
|
+
issue :high, "The \"#{node.name}\" method indicates wandering cows in the code.",
|
|
129
|
+
:cwe => 999
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
Checks are subclasses of the `Scanny::Checks::Check` class and they implement two methods: `pattern` and `check`.
|
|
136
|
+
|
|
137
|
+
### The `pattern` method
|
|
138
|
+
|
|
139
|
+
The `pattern` method returns a [Machete](https://github.com/openSUSE/machete) pattern describing Rubinius AST nodes this check is interested in. See [Machete documentation](https://github.com/openSUSE/machete/blob/master/README.md) to learn about the pattern syntax.
|
|
140
|
+
|
|
141
|
+
**Tip:** When creating a check pattern it's often useful to inspect how Rubinius transforms some Ruby constructs into AST nodes. You can do this using the `to_ast` method:
|
|
142
|
+
|
|
143
|
+
'42'.to_ast # => #<Rubinius::AST::FixnumLiteral:0x36fc @value=42 @line=1>
|
|
144
|
+
|
|
145
|
+
### The `check` method
|
|
146
|
+
|
|
147
|
+
The `check` method will be called on all AST nodes in the scanned files matched by the pattern returned by the `pattern` method. It will be passed the suspicious node. It can perform additional checks on it and report an issue if the node really is problematic.
|
|
148
|
+
|
|
149
|
+
Issues are reported using the `issue` method. As its arguments it accepts issue impact level (`:info`, `:low`, `:medium` or `:high`) and a message for the user, optionally followed by an options hash. The only currently implemented option is `:cwe`, which allows associating the issue with a [CWE number](http://www.cvedetails.com/cwe-definitions.php) (or multiple numbers if you pass an array).
|
|
150
|
+
|
|
151
|
+
### Tests
|
|
152
|
+
|
|
153
|
+
Each check should be tested. The tests are written in RSpec and they are stored in the `spec/scanny/checks` directory. This is how a test for our sample check may look like:
|
|
154
|
+
|
|
155
|
+
require "spec_helper"
|
|
156
|
+
|
|
157
|
+
module Scanny::Checks
|
|
158
|
+
describe BooMooCheck do
|
|
159
|
+
it "reports \"boo\" correctly" do
|
|
160
|
+
@runner.should check('boo').with_issue(
|
|
161
|
+
issue(:high, "The \"boo\" method indicates wandering cows in the code.", 999)
|
|
162
|
+
)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it "reports \"moo\" correctly" do
|
|
166
|
+
@runner.should check('moo').with_issue(
|
|
167
|
+
issue(:high, "The \"moo\" method indicates wandering cows in the code.", 999)
|
|
168
|
+
)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
Aim to create as simple test cases as possible. Also test different kinds of issues separately. See the existing tests to learn how more complex checks are tested.
|
|
174
|
+
|
|
175
|
+
Compatibility
|
|
176
|
+
-------------
|
|
177
|
+
|
|
178
|
+
Scanny requires Rubinius 1.9 mode to run.
|
|
179
|
+
|
|
180
|
+
Acknowledgement
|
|
181
|
+
---------------
|
|
182
|
+
|
|
183
|
+
The tool was written as a replacement of Thomas Biege's [Ruby on Rails scanner](http://gitorious.org/code-scanner/ror-sec-scanner/) which was used internally at [SUSE](http://www.suse.com/). This tool needed replacement because it look for suspicious patterns using just regular expressions, which is very rough and has expressivity problems with more complex patterns.
|
|
184
|
+
|
|
185
|
+
The original AST parsing and checking code was copied and adapted from [Roodi](http://roodi.rubyforge.org/), a tool for detecting Ruby code design issues.
|
data/Rakefile
ADDED
data/bin/scanny
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "docopt"
|
|
4
|
+
require_relative "../lib/scanny"
|
|
5
|
+
include Scanny::CLI
|
|
6
|
+
|
|
7
|
+
doc = "Scanny RoR secutiry scanner
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
scanny [options] <files_or_dirs>...
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
-h, --help Show this screen.
|
|
14
|
+
-i <check>, --include <check> Include check to scanning process (file or directory).
|
|
15
|
+
-d <check>, --disable <check> Disable check class from scanning process.
|
|
16
|
+
-f <format>, --format <format> Output format (stdout, html, xml) [default: stdout].
|
|
17
|
+
-s, --strict Enable strict mode (for security guys) [default: false].
|
|
18
|
+
-m <mode>, --mode <mode> Ruby parser mode (18 or 19) [default: 19]"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
options = Docopt(doc)
|
|
22
|
+
|
|
23
|
+
require_checks(options[:include])
|
|
24
|
+
|
|
25
|
+
runner = Scanny::Runner.new(:parser => use_parser(options[:mode]))
|
|
26
|
+
|
|
27
|
+
runner_with_custom_checks(runner, options[:disable], options[:strict])
|
|
28
|
+
issues = 0
|
|
29
|
+
|
|
30
|
+
files = build_paths.map { |arg| Dir[arg].to_a }.flatten
|
|
31
|
+
|
|
32
|
+
begin
|
|
33
|
+
runner.run(*files)
|
|
34
|
+
rescue SyntaxError => e
|
|
35
|
+
$stderr.puts "Can't parse #{runner.file} as Ruby file.",
|
|
36
|
+
"Parser currently is working in #{options[:mode]} mode.",
|
|
37
|
+
"It is possible that your project works with another version of ruby",
|
|
38
|
+
"You can change parser mode with '-m' flag"
|
|
39
|
+
exit 2
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
runner.checks_data.each do |check_data|
|
|
43
|
+
case options[:format]
|
|
44
|
+
when 'xml'
|
|
45
|
+
Scanny::Reporters::XMLReporter.new(check_data).report
|
|
46
|
+
when 'stdout'
|
|
47
|
+
Scanny::Reporters::SimpleReporter.new(check_data).report
|
|
48
|
+
else
|
|
49
|
+
raise "Format #{options[:format]} is not supported"
|
|
50
|
+
end
|
|
51
|
+
issues += check_data[:issues].size
|
|
52
|
+
end
|
|
53
|
+
puts
|
|
54
|
+
|
|
55
|
+
if issues == 0
|
|
56
|
+
puts "Found no issues."
|
|
57
|
+
exit 0
|
|
58
|
+
else
|
|
59
|
+
puts "Found #{issues} issues."
|
|
60
|
+
exit 1
|
|
61
|
+
end
|
data/lib/scanny.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require_relative "scanny/ruby_version_check"
|
|
2
|
+
require_relative "scanny/cli"
|
|
3
|
+
require_relative "scanny/issue"
|
|
4
|
+
require_relative "scanny/reporters"
|
|
5
|
+
require_relative "scanny/runner"
|
|
6
|
+
require_relative "scanny/checks/check"
|
|
7
|
+
require_relative "scanny/checks/helpers"
|
|
8
|
+
require_relative "scanny/rake_task"
|
|
9
|
+
|
|
10
|
+
Dir[File.dirname(__FILE__) + "/scanny/checks/**/*_check.rb"].each do |file|
|
|
11
|
+
require file
|
|
12
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Scanny
|
|
2
|
+
module Checks
|
|
3
|
+
# Checks for use of "params[:id]" in parameters of certain methods that
|
|
4
|
+
# requires authorizaton checks.
|
|
5
|
+
class AccessControlCheck < Check
|
|
6
|
+
# User.new(params[:id])
|
|
7
|
+
def pattern
|
|
8
|
+
<<-EOT
|
|
9
|
+
SendWithArguments<
|
|
10
|
+
name = :new | :create,
|
|
11
|
+
arguments = ActualArguments<
|
|
12
|
+
array = [
|
|
13
|
+
HashLiteral<
|
|
14
|
+
array = [
|
|
15
|
+
any{odd},
|
|
16
|
+
SendWithArguments<
|
|
17
|
+
receiver = Send<name = :params>,
|
|
18
|
+
name = :[],
|
|
19
|
+
arguments = ActualArguments<array = [SymbolLiteral<value = :id>]>
|
|
20
|
+
>,
|
|
21
|
+
any{even}
|
|
22
|
+
]
|
|
23
|
+
>
|
|
24
|
+
]
|
|
25
|
+
>
|
|
26
|
+
>
|
|
27
|
+
|
|
|
28
|
+
SendWithArguments<
|
|
29
|
+
name = :delete | :destroy,
|
|
30
|
+
arguments = ActualArguments<
|
|
31
|
+
array = [
|
|
32
|
+
any*,
|
|
33
|
+
SendWithArguments<
|
|
34
|
+
receiver = Send<name = :params>,
|
|
35
|
+
name = :[],
|
|
36
|
+
arguments = ActualArguments<array = [SymbolLiteral<value = :id>]>
|
|
37
|
+
>,
|
|
38
|
+
any*
|
|
39
|
+
]
|
|
40
|
+
>
|
|
41
|
+
>
|
|
42
|
+
EOT
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def check(node)
|
|
46
|
+
issue :medium,
|
|
47
|
+
"Using \"params[:id]\" requires proper authorization check.",
|
|
48
|
+
:cwe => 285
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Scanny
|
|
2
|
+
module Checks
|
|
3
|
+
# Checks for backticks and %x{...} that pass the command through shell
|
|
4
|
+
# expansion. This can cause unwanted code execution if the command includes
|
|
5
|
+
# unescaped input.
|
|
6
|
+
class BackticksCheck < Check
|
|
7
|
+
# `command`
|
|
8
|
+
def pattern
|
|
9
|
+
'ExecuteString | DynamicExecuteString'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def check(node)
|
|
13
|
+
issue :high, "Backticks and %x{...} pass the executed command through shell expansion.",
|
|
14
|
+
:cwe => [88, 78]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Scanny
|
|
2
|
+
module Checks
|
|
3
|
+
# Checks for use of the "before_filter" method with certain filters.
|
|
4
|
+
class BeforeFiltersCheck < Check
|
|
5
|
+
FILTERS = [:login_required, :admin_required]
|
|
6
|
+
|
|
7
|
+
# before_filter :login_required
|
|
8
|
+
def pattern
|
|
9
|
+
<<-EOT
|
|
10
|
+
SendWithArguments<
|
|
11
|
+
receiver = Self,
|
|
12
|
+
name = :before_filter,
|
|
13
|
+
arguments = ActualArguments<
|
|
14
|
+
array = [
|
|
15
|
+
any*,
|
|
16
|
+
SymbolLiteral<value = #{FILTERS.map(&:inspect).join(' | ')}>,
|
|
17
|
+
any*
|
|
18
|
+
]
|
|
19
|
+
>
|
|
20
|
+
>
|
|
21
|
+
EOT
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def check(node)
|
|
25
|
+
filter_node = node.arguments.array.find do |argument|
|
|
26
|
+
argument.is_a?(Rubinius::AST::SymbolLiteral) &&
|
|
27
|
+
FILTERS.include?(argument.value)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
issue :info,
|
|
31
|
+
"The \"before_filter\" method with :#{filter_node.value} filter is used."
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Scanny
|
|
2
|
+
module Checks
|
|
3
|
+
class Check
|
|
4
|
+
def visit(file, node)
|
|
5
|
+
@file = file
|
|
6
|
+
@line = node.line
|
|
7
|
+
@issues = []
|
|
8
|
+
|
|
9
|
+
check(node)
|
|
10
|
+
|
|
11
|
+
@issues
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @return [String] pattern used to find relevant nodes. It must respect Machete's syntax.
|
|
15
|
+
def pattern
|
|
16
|
+
raise "The Check class requires its childrens to provide an "\
|
|
17
|
+
"implementation of the 'pattern' method."
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def issue(impact, message, options = {})
|
|
21
|
+
@issues << Issue.new(@file, @line, impact, message, options[:cwe])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def strict?
|
|
25
|
+
false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def compiled_pattern
|
|
29
|
+
@compiled_pattern ||= Machete::Parser.new.parse(pattern)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|