Class: Codesake::Dawn::Sinatra

Inherits:
Object
  • Object
show all
Includes:
Engine
Defined in:
lib/codesake/dawn/sinatra.rb

Instance Attribute Summary collapse

Attributes included from Engine

#applied_checks, #checks, #connected_gems, #controllers, #debug, #engine_error, #force, #gemfile_lock, #mitigated_issues, #models, #mvc_version, #name, #reflected_xss, #ruby_version, #scan_start, #scan_stop, #skipped_checks, #target, #views, #vulnerabilities

Instance Method Summary collapse

Methods included from Engine

#apply, #apply_all, #build_view_array, #can_apply?, #count_vulnerabilities, #detect_controllers, #detect_models, #error!, #error?, #find_vulnerability_by_name, #get_mvc_version, #get_ruby_version, #has_gemfile_lock?, #has_reflected_xss?, #is_applied?, #is_good_mvc?, #is_vulnerable_to?, #load_knowledge_base, #scan_time, #set_mvc_version, #set_target, #target_is_dir?

Methods included from Utils

#__debug_me_and_return, #debug_me, #debug_me_and_return_false, #debug_me_and_return_true

Constructor Details

#initialize(dir = nil, mp = nil) ⇒ Sinatra

Returns a new instance of Sinatra.



16
17
18
19
20
21
22
23
24
# File 'lib/codesake/dawn/sinatra.rb', line 16

def initialize(dir=nil, mp=nil)
  super(dir, "sinatra")
  @appname = detect_appname(self.target)
  error! if self.appname == ""
  @views = detect_views
  @sinks = detect_sinks(self.appname) unless self.appname == ""
  @reflected_xss = detect_reflected_xss unless self.appname == "" || !@views
  @mount_point = (mp.nil?)? "" : mp
end

Instance Attribute Details

#appnameObject (readonly)

Returns the value of attribute appname.



10
11
12
# File 'lib/codesake/dawn/sinatra.rb', line 10

def appname
  @appname
end

#mount_pointObject (readonly)

mount_point is the mounting point for this Sinatra application. It’s filled up only in padrino engines



14
15
16
# File 'lib/codesake/dawn/sinatra.rb', line 14

def mount_point
  @mount_point
end

#sinksObject (readonly)

Returns the value of attribute sinks.



9
10
11
# File 'lib/codesake/dawn/sinatra.rb', line 9

def sinks
  @sinks
end

Instance Method Details

#detect_appname(target) ⇒ Object

TODO: appname should be hopefully autodetect from config.ru



27
28
29
30
31
32
33
# File 'lib/codesake/dawn/sinatra.rb', line 27

def detect_appname(target)
  return "app.rb" if File.exist?(File.join(self.target, "app.rb"))
  return "application.rb" if File.exist?(File.join(self.target, "application.rb"))
  file_array = Dir.glob(File.join("#{target}", "*.rb"))
  return file_array[0] if ! file_array.nil? and file_array.count == 1
  return "" # gracefully failure
end

#detect_reflected_xssObject



35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/codesake/dawn/sinatra.rb', line 35

def detect_reflected_xss
  ret = []
  @views.each do |v|
    view_content = File.read(v[:filename])
    @sinks.each do |sink|
      if view_content.match(sink[:sink_name])
        sink[:sink_view] = v[:filename]
        ret << sink
      end
    end
  end
  ret
end

#detect_sinks(appname = nil) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/codesake/dawn/sinatra.rb', line 49

def detect_sinks(appname=nil)
  ret = []
  appname = "app.rb" if appname.nil? and self.appname == ""
  app_rb = File.readlines(File.join(self.target, appname)) if File.exist?(File.join(self.target, appname))
  return [] if app_rb.nil?

  parser = RubyParser.new

  app_rb.each_with_index do |line, i|
    line = line.chomp

    unless line.match(/params/).nil?

      begin
        t = parser.parse(line)

        # a[1] = params["foo"]
        #
        if (! t.nil? and t.sexp_type == :attrasgn)
          body = t.sexp_body.to_a

          if is_assignement_from_params?(body, :attrasgn)

            if body[0][0] == :call
              sink_name=body[0][2].to_s unless body[1].to_s == "[]=" 
              sink_name="#{body[2].to_a[1].to_s}" if body[1].to_s == "[]=" # the sink is assigned to an Array

              sink_source = "#{body[3].to_a[1][2].to_s}[#{body[3].to_a[3][1].to_s}]"

              ret << {:sink_name=>sink_name, :sink_kind=>:params, :sink_line=>i+1, :sink_source=>sink_source, :sink_file=>appname, :sink_evidence=>line}
            end
            if body[0][0] == :ivar
              sink_name=body[0][1].to_s
              sink_pos=body[2][1].to_i
              sink_source=body[3][3][1]

              ret << {:sink_name=>sink_name, :sink_kind=>:params, :sink_line=>i+1, :sink_source=>sink_source, :sink_file=>appname, :sink_evidence=>line}
            end

          end
        end

        # a = params["foo"]
        if (! t.nil? and t.sexp_type == :iasgn)
          body = t.sexp_body.to_a
          if is_assignement_from_params?(body, :iasgn)
            sink_name = body[0].to_s
            sink_source = "#{body[1][3][1].to_s}"
            ret << {:sink_name=>sink_name, :sink_kind=>:params, :sink_line=>i+1, :sink_source=>sink_source, :sink_file=>appname, :sink_evidence=>line}
          end
        end
      rescue Racc::ParseError => e
        # TODO: we must pass logger instance to engines if we want some error message
        # For now... silently discard parse errors
        return []
      end
    end

  end

  ret
end

#detect_viewsObject



118
119
120
121
# File 'lib/codesake/dawn/sinatra.rb', line 118

def detect_views
  return build_view_array(File.join(self.target, "views")) if File.exist?(File.join(self.target, "views"))
  []
end

#is_assignement_from_params?(body, kind) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
116
# File 'lib/codesake/dawn/sinatra.rb', line 113

def is_assignement_from_params?(body, kind)
  return ( ! body[3].nil? and body[3].to_a[1][2].to_s == "params") if kind == :attrasgn
  return ( ! body[1].nil? and ! body[1][1].nil? and body[1][1][2].to_s == "params") if kind == :iasgn
end