diff --git a/.ruby-version b/.ruby-version index 8c50098..be94e6f 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.1 +3.2.2 diff --git a/Changelog.md b/Changelog.md index 225e39a..7e36df5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -16,6 +16,10 @@ _latest update: Mon 17 Apr 2023, 18:07:04, CEST_ It makes sense to integrate cvss gem within the project. * Fixed issue #260. Removed old codesake-dawn named rake tasks. dawn is not intended to be run via rake anymore. +* Issue #268. As part of the Hackweek (https://t.ly/epoSZ), dawn must be able + to parse a Sinatra application to spot vulnerabilities. As Sinatra code can + be also self contained in a single file, this must be allowed as a valid + target. ## Version 2.2.0 (2023-04-17) diff --git a/dawnscanner.gemspec b/dawnscanner.gemspec index c8ae121..2745931 100644 --- a/dawnscanner.gemspec +++ b/dawnscanner.gemspec @@ -31,6 +31,8 @@ Gem::Specification.new do |gem| # For CLI we will use thor gem.add_dependency 'thor' + gem.add_dependency 'parser' + # gem.add_dependency 'sqlite3' # gem.add_dependency 'datamapper' # gem.add_dependency 'dm-sqlite-adapter' diff --git a/lib/dawn/core.rb b/lib/dawn/core.rb index 05dc424..4a4ba47 100644 --- a/lib/dawn/core.rb +++ b/lib/dawn/core.rb @@ -1,4 +1,5 @@ require "yaml" +require 'parser/current' module Dawn class Core @@ -79,8 +80,34 @@ def self.guess_mvc(gemfile_lock) end + ## + # detect_mvc_from_file is a method to check if a ruby script is a self + # contained web application, most likely if it is a Sinatra web application + # or a simple script. + # + # TODO: this method has a known bug. It relies only on the presence of a + # "require 'sinatra'" statement to detect a sinatra app. In case of a + # malformed ruby script, requiring sinatra gem but not defining a real + # sinatra app, dawnscanner will be fooled. + # + # @param target [String] the target filename + # @return [Object] a Dawn::Sinatra instance or nil in case of error + def self.detect_mvc_from_file(target) + code = File.read(target) + parsed_code = Parser::CurrentRuby.parse(code) + ast = Dawn::Processor::Require.new + ast.process_all(parsed_code) + + return Dawn::Sinatra.new(target) if ast.is_sinatra + + return nil + end + def self.detect_mvc(target) + # Issue#268 + return detect_mvc_from_file(target) if (File.file?(target) and File.extname(target) == ".rb") + raise ArgumentError.new("you must set target directory") if target.nil? my_dir = Dir.pwd diff --git a/lib/dawn/processor/require.rb b/lib/dawn/processor/require.rb new file mode 100644 index 0000000..804efca --- /dev/null +++ b/lib/dawn/processor/require.rb @@ -0,0 +1,20 @@ +module Dawn + module Processor + class Require < AST::Processor + attr_reader :is_sinatra + + def initialize() + @is_sinatra = false + super() + end + + def on_send(node) + if (node.children[1].to_s == "require") + if node.children[2].children[0].to_s == "sinatra" + @is_sinatra = true + end + end + end + end + end +end diff --git a/lib/dawnscanner.rb b/lib/dawnscanner.rb index 27c7b02..b5b1d20 100644 --- a/lib/dawnscanner.rb +++ b/lib/dawnscanner.rb @@ -9,7 +9,8 @@ require "dawn/cli/dawn_cli" -# KB +require "dawn/processor/require" +# KB require "dawn/knowledge_base" # General purpose utilities diff --git a/spec/lib/dawn/issue_268_spec.rb b/spec/lib/dawn/issue_268_spec.rb new file mode 100644 index 0000000..1f10aa1 --- /dev/null +++ b/spec/lib/dawn/issue_268_spec.rb @@ -0,0 +1,14 @@ +require "spec_helper" + +describe "A single ruby file with a Sinatra application " do + before (:all) do + @engine = Dawn::Core.detect_mvc("./spec/support/sinatra_hello_app.rb") + end + it "is a good target too" do + expect(@engine).not_to be_nil + end + + it "is recognized as a Sinatra app" do + expect(@engine).to be_a Dawn::Sinatra + end +end