Module: Aikido::Zen::Sinks::File
- Defined in:
- lib/aikido/zen/sinks/file.rb
Defined Under Namespace
Modules: Helpers
Constant Summary collapse
- SINK =
Sinks.add("File", scanners: [Scanners::PathTraversalScanner])
Class Method Summary collapse
Class Method Details
.load_sinks! ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/aikido/zen/sinks/file.rb', line 17 def self.load_sinks! ::File.singleton_class.class_eval do extend Sinks::DSL # Create a copy of the original methods for internal use only to prevent # recursion in PathTraversalScanner. # # IMPORTANT: The aliases must be created before the method is overridden. alias_method :expand_path__internal_for_aikido_zen, :expand_path alias_method :join__internal_for_aikido_zen, :join sink_before :open do |path| Helpers.scan(path, "open") end sink_before :read do |path| Helpers.scan(path, "read") end sink_before :write do |path| Helpers.scan(path, "write") end sink_before :truncate do |file_name| Helpers.scan(file_name, "truncate") end sink_before :rename do |old_name, new_name| Helpers.scan(old_name, "rename") Helpers.scan(new_name, "rename") end sink_before :unlink do |*file_names| file_names.each do |file_name| Helpers.scan(file_name, "unlink") end end sink_before :delete do |*file_names| file_names.each do |file_name| Helpers.scan(file_name, "delete") end end sink_before :symlink do |old_name, new_name| Helpers.scan(old_name, "symlink") Helpers.scan(new_name, "symlink") end sink_before :chmod do |_mode_int, *file_names| file_names.each do |file_name| Helpers.scan(file_name, "chmod") end end sink_before :chown do |_owner_int, group_int, *file_names| file_names.each do |file_name| Helpers.scan(file_name, "chown") end end sink_before :utime do |_atime, _mtime, *file_names| file_names.each do |file_name| Helpers.scan(file_name, "utime") end end def join(*args, **kwargs, &blk) if Aikido::Zen.config.harden? # IMPORTANT: THE BEHAVIOR OF THIS METHOD IS CHANGED! # # File.join has undocumented behavior: # # File.join recursively joins nested string arrays. # # This prevents path traversal detection when an array originates # from user input that was assumed to be a string. # # This undocumented behavior has been restricted to support path # traversal detection. # # File.join no longer joins nested string arrays, but still accepts # a single string array argument. # File.join is often incorrectly called with a single array argument. # # i.e. # # File.join(["prefix", "filename"]) # # This is considered acceptable. # # Calling File.join with a single string argument returns the string # argument itself, having no practical effect. Therefore, it can be # presumed that if File.join is called with a single array argument # then this was its intended usage, and the array did not originate # from user input that was assumed to be a string. strings = args strings = args.first if args.size == 1 && args.first.is_a?(Array) strings.each do |string| raise TypeError.new("Zen prevented implicit conversion of Array to String in hardened method. Visit https://github.com/AikidoSec/firewall-ruby for more information.") if string.is_a?(Array) end end result = join__internal_for_aikido_zen(*args, **kwargs, &blk) Sinks::DSL.safe do Helpers.scan(result, "join") end result end sink_before :expand_path do |file_name| Helpers.scan(file_name, "expand_path") end sink_before :realpath do |file_name| Helpers.scan(file_name, "realpath") end sink_before :realdirpath do |file_name| Helpers.scan(file_name, "realdirpath") end end ::File.class_eval do extend Sinks::DSL sink_before :initialize do |path| Helpers.scan(path, "new") end end end |