Module: Watobo::Utils
- Defined in:
- lib/watobo/utils.rb,
lib/watobo/utils/url.rb,
lib/watobo/utils/strings.rb,
lib/watobo/utils/hexprint.rb,
lib/watobo/utils/load_chat.rb,
lib/watobo/utils/load_icon.rb,
lib/watobo/utils/export_xml.rb,
lib/watobo/utils/check_regex.rb,
lib/watobo/utils/copy_object.rb,
lib/watobo/utils/secure_eval.rb,
lib/watobo/utils/expand_range.rb,
lib/watobo/utils/text2request.rb,
lib/watobo/utils/response_hash.rb,
lib/watobo/utils/file_management.rb,
lib/watobo/utils/response_builder.rb
Overview
:nodoc: all
Defined Under Namespace
Modules: URL
Class Method Summary collapse
- .ascii_regex(s) ⇒ Object
- .camelcase(string) ⇒ Object
- .chat2xml(chat, xml) ⇒ Object
- .checkRegex(pattern) ⇒ Object
- .copyObject(object) ⇒ Object
-
.expand_range(pattern) ⇒ Object
expand range creates an array out of.
- .exportXML(*prefs) ⇒ Object
- .finding2xml(finding, xml) ⇒ Object
- .hexprint(data) ⇒ Object
- .load_settings(file) ⇒ Object
- .loadChat(path, id, request_pattern, response_pattern) ⇒ Object
- .loadChatMarshal(file) ⇒ Object
-
.loadChatYAML(file) ⇒ Object
loadChat returns a chat object imported from a yaml file.
- .loadFindingMarshal(file) ⇒ Object
- .loadFindingYAML(file) ⇒ Object
- .remove_string(data, remove) ⇒ Object
- .responseHash(request, response) ⇒ Object
-
.save_settings(file, settings) ⇒ Object
e.g, save_settings(“test-settings.test”, 0, “@saved_settings”, @saved_settings).
- .saveChat(chat, filename) ⇒ Object
- .secure_eval(exp) ⇒ Object
-
.smartHash(orig_request, request, response) ⇒ Object
smart hashes are necessary for blind sql injections tests SmartHash means that all dynamic information is removed from the response before creating the hash value.
- .snakecase(string) ⇒ Object
- .string2response(text, opts = {}) ⇒ Object
- .text2request(text) ⇒ Object
Instance Method Summary collapse
Class Method Details
.ascii_regex(s) ⇒ Object
16 17 18 19 |
# File 'lib/watobo/utils/response_hash.rb', line 16 def self.ascii_regex(s) s.encode!('ASCII', :invalid => :replace, :undef => :replace) Regexp.quote s.unpack("C*").pack("C*") end |
.camelcase(string) ⇒ Object
13 14 15 |
# File 'lib/watobo/utils/strings.rb', line 13 def self.camelcase(string) string.strip.gsub(/[^[a-zA-Z\-_]]/,"").gsub( "-" , "_").split("_").map{ |s| s.downcase.capitalize }.join end |
.chat2xml(chat, xml) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/watobo/utils/export_xml.rb', line 34 def self.chat2xml(chat,xml) fnode = Nokogiri::XML::Node.new("Chat", xml) dnode = Nokogiri::XML::Node.new("Request", xml) dnode.content = Base64.strict_encode64( chat.request.join ) fnode << dnode dnode = Nokogiri::XML::Node.new("Response", xml) dnode.content = Base64.strict_encode64 chat.response.join fnode << dnode dnode = Nokogiri::XML::Node.new("Details", xml) chat.settings.each do |k,v| d = Nokogiri::XML::Node.new(k.to_s, xml) d.content = v dnode << d end fnode << dnode fnode end |
.checkRegex(pattern) ⇒ Object
13 14 15 16 17 18 19 20 21 22 |
# File 'lib/watobo/utils/check_regex.rb', line 13 def Utils.checkRegex(pattern) begin # use nice string to test pattern ;) "watobo rocks!!!" =~ /#{pattern}/i return true rescue => bang # puts bang return false, bang end end |
.copyObject(object) ⇒ Object
13 14 15 16 |
# File 'lib/watobo/utils/copy_object.rb', line 13 def Utils.copyObject(object) copy = secure_eval(YAML.load(YAML.dump(object.inspect))) return copy end |
.expand_range(pattern) ⇒ Object
expand range creates an array out of
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/watobo/utils/expand_range.rb', line 14 def self.(pattern) vals = pattern.split(",") result = [] vals.each do |v| v.strip! if v =~ /^(\d+)$/ then result.push $1.to_i elsif v =~ /^(\d+)-(\d+)$/ start = $1 stop = $2 dummy = (start..stop).to_a result.concat dummy end end result.uniq! return result end |
.exportXML(*prefs) ⇒ Object
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 |
# File 'lib/watobo/utils/export_xml.rb', line 56 def self.exportXML(*prefs) # prefs ||= [] xml = Nokogiri::XML("") env = Nokogiri::XML::Node.new("WatoboExportv1", xml) xml << env if prefs.include? :export_findings findings = Nokogiri::XML::Node.new("Findings", xml) env << findings Watobo::Findings.each do |fid, finding| if prefs.include? :scope_only if Watobo::Scope.match_site?(finding.request.site) if prefs.include? :ignore_fps unless finding.false_positive? findings << finding2xml(finding, xml) end else findings << finding2xml(finding, xml) end end else if prefs.include? :ignore_fps unless finding.false_positive? findings << finding2xml(finding, xml) end else findings << finding2xml(finding, xml) end end end end chats = Nokogiri::XML::Node.new("Chats", xml) env << chats if prefs.include? :export_chats Watobo::Chats.each do |chat| if prefs.include? :scope_only if Watobo::Scope.match_site?(chat.request.site) chats << chat2xml(chat, xml) end else chats << chat2xml(chat, xml) end end end xml end |
.finding2xml(finding, xml) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/watobo/utils/export_xml.rb', line 12 def self.finding2xml(finding,xml) fnode = Nokogiri::XML::Node.new("Finding", xml) dnode = Nokogiri::XML::Node.new("Request", xml) dnode.content = Base64.strict_encode64( finding.request.join ) fnode << dnode dnode = Nokogiri::XML::Node.new("Response", xml) dnode.content = Base64.strict_encode64 finding.response.join fnode << dnode dnode = Nokogiri::XML::Node.new("Details", xml) finding.details.each do |k,v| d = Nokogiri::XML::Node.new(k.to_s, xml) d.content = v dnode << d end fnode << dnode fnode end |
.hexprint(data) ⇒ Object
13 14 15 16 17 18 |
# File 'lib/watobo/utils/hexprint.rb', line 13 def self.hexprint(data) data.length.times do |i| print "%02X" % data[i].ord puts if data[i] == "\n" end end |
.load_settings(file) ⇒ Object
32 33 34 35 36 37 38 |
# File 'lib/watobo/utils/file_management.rb', line 32 def Utils.load_settings(file) settings = nil if File.exists?(file) then settings = YAML.load_file(file) end return settings end |
.loadChat(path, id, request_pattern, response_pattern) ⇒ Object
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/watobo/utils/load_chat.rb', line 173 def Utils.loadChat(path, id, request_pattern, response_pattern) chat = nil req_file = File.join(path, "#{id}#{request_pattern}") res_file = File.join(path, "#{id}#{response_pattern}") # puts "* load chat (request): #{req_file}" # puts "* load chat (response): #{res_file}" request = [] if File.exists?(req_file) then fh = File.open(req_file,"rb") fh.each do |line| request.push line end else # puts "!! File not found (#{req_file})" return nil,nil end response = [] # print "." # first only read header as array content_length = 0 response_is_gzipped = false content_is_chunked = false max_response_size = 50000 if File.exists?(res_file) then begin resFH = open(res_file, "rb") loop do l = resFH.readline if l =~ /Content-Length.* (\d*)/ then content_length = $1.to_i #puts "Content-Length is #{content_length}" end if l =~ /Content-Encoding.*gzip/ then response_is_gzipped = true end if l=~ /Transfer-Encoding.*chunked/i then content_is_chunked = true end response.push(l) # break if l.length < 3 # end of header break if l =~ /^\r\n$/ # end of header end if content_is_chunked then # read rest of file response.push "\r\n" response.push resFH.read #content_length = dummy.chomp.hex return request, response end rescue => bang puts "Could not read Header from file #{res_file}" end # now read response body begin if response_is_gzipped and content_length > 0 then gziped = resFH.read(content_length) begin gz = Zlib::GzipReader.new( StringIO.new( gziped ) ) data = gz.read if data.length > max_response_size then data = data[0..max_response_size] puts "!!! chat file (#{res_file}: Response too long" # puts data end response.push data rescue => bang puts "ERROR: GZIP with file #{res_file}" puts bang #resFH.each do |l| # response.push(l) if response.join.length < @max_response_size #end end return request, response end #resFH.each do |l| # response.push(l) if response.join.length < max_response_size #end rest = resFH.read response.push(rest) return request, response rescue EOFError => bang return request, response rescue => bang puts "!!! Error: Could not read response file #{res_file}" puts bang end end end |
.loadChatMarshal(file) ⇒ Object
14 15 16 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 |
# File 'lib/watobo/utils/load_chat.rb', line 14 def Utils.loadChatMarshal(file) begin request = [] response = [] if File.exists?(file) then puts "LoadChatMarshal: #{file}" if $DEBUG settings = {} File.open(file,"rb") { |fh| settings = Marshal::load(fh.read) request = settings[:request] response = settings[:response] settings.delete(:response) settings.delete(:request) } chat = Watobo::Chat.new(request, response, settings) chat.file = file return chat else puts "* file #{file} not found" return nil end rescue Psych::SyntaxError puts "!!! Malformed File #{file}" rescue => bang puts "! could not load chat from file #{file}" puts bang puts bang.backtrace #puts cdata #puts bang #puts bang.backtrace if $DEBUG end end |
.loadChatYAML(file) ⇒ Object
loadChat returns a chat object imported from a yaml file
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 |
# File 'lib/watobo/utils/load_chat.rb', line 53 def Utils.loadChatYAML(file) begin if File.exists?(file) then puts "LoadChatYAML: #{file}" if $DEBUG cdata = YAML.load(File.open(file,"rb").read) return nil unless cdata # need to restore CRLF cdata[:request].map!{|l| if l =~ /^\"/ then x = secure_eval(l) else x = l.strip + "\r\n" x = l if l == cdata[:request].last end x } cdata[:response].map!{|l| if l =~ /^\"/ then x = secure_eval(l) else x = l.strip + "\r\n" x = l if l == cdata[:response].last end x } # puts cdata # puts cdata.class settings = Hash.new settings.update cdata settings.delete(:response) settings.delete(:request) chat = Watobo::Chat.new(cdata[:request], cdata[:response], settings) chat.file = file return chat else puts "* file #{file} not found" return nil end rescue Psych::SyntaxError puts "!!! Malformed File #{file}" rescue => bang puts "! could not load chat from file #{file}" #puts cdata #puts bang #puts bang.backtrace if $DEBUG end end |
.loadFindingMarshal(file) ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/watobo/utils/load_chat.rb', line 109 def Utils.loadFindingMarshal(file) puts "LoadFindingMarshal: #{file}" if $DEBUG if File.exists?(file) then begin fdata = nil File.open(file,"rb") {|f| fdata = Marshal::load(f.read) } finding = Watobo::Finding.new(fdata[:request], fdata[:response], fdata[:details]) return finding rescue => bang puts bang puts "could not load finding #{file}" return nil end else # puts "* file #{file} not found" return nil end end |
.loadFindingYAML(file) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/watobo/utils/load_chat.rb', line 133 def Utils.loadFindingYAML(file) puts "LoadFindingYAML: #{file}" if $DEBUG if File.exists?(file) then begin fdata = YAML.load(File.open(file,"rb").read) # need to restore CRLF return nil unless fdata fdata[:request].map!{|l| if l =~ /^\"/ then x = secure_eval(l) else x = l.strip + "\r\n" x = l if l == fdata[:request].last end x } fdata[:response].map!{|l| if l =~ /^\"/ then x = secure_eval(l) else x = l.strip + "\r\n" x = l if l == fdata[:response].last end x } finding = Watobo::Finding.new(fdata[:request], fdata[:response], fdata[:details]) return finding rescue => bang puts bang puts "could not load finding #{file}" return nil end else # puts "* file #{file} not found" return nil end end |
.remove_string(data, remove) ⇒ Object
56 57 58 59 60 61 |
# File 'lib/watobo/utils/response_hash.rb', line 56 def Utils.remove_string(data, remove) plain = "#{remove}" data.gsub!(/#{Regexp.quote(remove)}/, '') cgi_esc = CGI::unescape(p) data.gsub!(/#{Regexp.quote(cgi_esc)}/, '') end |
.responseHash(request, response) ⇒ Object
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 |
# File 'lib/watobo/utils/response_hash.rb', line 21 def self.responseHash(request, response) begin if request.body and response.body then body = response.body.dup # remove all parm/value pairs request.get_parm_names.each do |p| body.gsub!(/#{ascii_regex(p)}/, '') body.gsub!(/#{ascii_regex(request.get_parm_value(p))}/, '') end request.post_parm_names.each do |p| body.gsub!(/#{Regexp.quote(p)}/, '') val = request.post_parm_value(p) body.gsub!(/#{Regexp.quote(val)}/, '') end # remove date format 01.02.2009 body.gsub!(/\d{1,2}\.\d{1,2}.\d{2,4}/, "") # remove date format 02/2009 body.gsub!(/\d{1,2}(.\|\/)d{2,4}/, "") #remove time body.gsub!(/\d{1,2}:\d{1,2}(:\d{1,2})?/, '') return body, Digest::MD5.hexdigest(body) elsif response.body then return body, Digest::MD5.hexdigest(response.body) end rescue => bang puts bang puts bang.backtrace if $DEBUG end return nil end |
.save_settings(file, settings) ⇒ Object
e.g, save_settings(“test-settings.test”, 0, “@saved_settings”, @saved_settings)
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/watobo/utils/file_management.rb', line 15 def Utils.save_settings(file, settings) begin if settings.is_a? Hash File.open(file, "w") { |fh| YAML.dump(settings, fh) } return true else return false end rescue => bang puts bang puts bang.backtrace if $DEBUG end return false end |
.saveChat(chat, filename) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/watobo/utils/file_management.rb', line 40 def Utils.saveChat(chat, filename) return false if filename.nil? return false if chat.nil? chat_data = { :request => chat.request.map{|x| x.inspect}, :response => chat.response.map{|x| x.inspect}, } chat_data.update(chat.settings) if File.exists?(filename) then puts "Updating #{filename}" File.open(filename, "w") { |fh| YAML.dump(chat_data, fh) } chat.file = filename end end |
.secure_eval(exp) ⇒ Object
14 15 16 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 |
# File 'lib/watobo/utils/secure_eval.rb', line 14 def Utils.secure_eval(exp) result = nil t = Thread.new(exp) { |e| e.untaint $SAFE = 3 # $SAFE = 4 # no longer supported since ruby 2.1.x begin result = eval(e) rescue SyntaxError => bang puts bang puts bang.backtrace if $DEBUG rescue LocalJumpError => bang puts bang puts bang.backtrace if $DEBUG rescue SecurityError => bang puts "WARNING: Desired functionality forbidden. it may harm your system!" puts bang.backtrace if $DEBUG rescue => bang puts bang puts bang.backtrace if $DEBUG end } t.join return result end |
.smartHash(orig_request, request, response) ⇒ Object
smart hashes are necessary for blind sql injections tests SmartHash means that all dynamic information is removed from the response before creating the hash value. Dynamic information could be date&time as well as parameter names and theire valuse.
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 |
# File 'lib/watobo/utils/response_hash.rb', line 66 def Utils.smartHash(orig_request, request, response) min_length = 4 begin if request and response.body then # puts response.content_type # puts charset body = response.body.dup #body.gsub!(/\P{ASCII}/, '') charset = response.charset unless charset.nil? begin body.encode!(charset, :invalid => :replace, :undef => :replace, :replace => '') rescue body = response.body.dup end end #body.encode!('ASCII', :invalid => :replace, :undef => :replace, :replace => '') #body.encode!('ISO-8859-1', :invalid => :replace, :undef => :replace, :replace => '') # remove possible chunk values body.gsub!(/\r\n[0-9a-fA-F]+\r\n/,'') # remove date format 01.02.2009 body.gsub!(/\d{1,2}\.\d{1,2}.\d{2,4}/, "") # remove date format 02/2009 body.gsub!(/\d{1,2}(.\|\/)d{2,4}/, "") #remove time body.gsub!(/\d{1,2}:\d{1,2}(:\d{1,2})?/, '') # remove all non-printables body.gsub!(/[^[:print:]]/,'') replace_items = [] request.get_parm_names.each do |p| replace_items << p if p.length >= min_length val = request.get_parm_value(p) replace_items << val if val.length >= min_length end request.post_parm_names.each do |p| replace_items << p if p.length >= min_length val = request.post_parm_value(p) replace_items << val if val.length >= min_length end orig_request.get_parm_names.each do |p| replace_items << p if ( p.length >= min_length ) val = orig_request.get_parm_value(p) replace_items << val if ( val.length >= min_length ) end orig_request.post_parm_names.each do |p| replace_items << p if p.length >= min_length val = orig_request.post_parm_value(p) replace_items << val if val.length >= min_length end replace_items.uniq.sort.each do |p| body.gsub!(/#{ascii_regex(p)}/, '') body.gsub!(/#{ascii_regex(CGI::unescape(p))}/, '') end md5 = Digest::MD5.hexdigest(body) #puts md5 return body, md5 else # no response body. create hash from header unless response.respond_to? :removeHeader Watobo::Response.create response end response.removeHeader("Date") response.removeHeader("Set-Cookie") return response, Digest::MD5.hexdigest(response.join) end rescue => bang # puts "VAL_CGI_Q: #{val_cgi_q}" # return some random hash in case of an error puts bang if $DEBUG puts bang.backtrace if $DEBUG return body, Digest::MD5.hexdigest(Time.now.to_f.to_s + rand(10000).to_s ) end end |
.snakecase(string) ⇒ Object
17 18 19 |
# File 'lib/watobo/utils/strings.rb', line 17 def self.snakecase(string) string.gsub(/([A-Z])([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').tr("-","_").downcase end |
.string2response(text, opts = {}) ⇒ Object
13 14 15 16 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 |
# File 'lib/watobo/utils/response_builder.rb', line 13 def self.string2response( text, opts = {} ) = { :update_content_length => false } .update opts begin hb_sep = "\r\n\r\n" eoh = text.index(hb_sep) if eoh.nil? hb_sep = "\n\n" eoh = text.index(hb_sep) end unless eoh.nil? raw_header = text[0..eoh-1] raw_body = text[eoh+hb_sep.length..-1] puts ">> RawBody: #{raw_body}" else raw_header = text raw_body = nil end response = raw_header.split("\n") response.map!{|r| "#{r.strip}\r\n" } # Watobo::Response.create response unless raw_body.nil? response << "\r\n" response << raw_body unless raw_body.strip.empty? end #return response return Watobo::Response.new(response) rescue => bang puts bang puts bang.backtrace end return nil end |
.text2request(text) ⇒ Object
13 14 15 16 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 |
# File 'lib/watobo/utils/text2request.rb', line 13 def Utils.text2request(text) result = [] return result if text.strip.empty? # UTF-8 CleanUp text = text.unpack("C*").pack("C*") if text =~ /\n\n/ dummy = text.split(/\n\n/) header = dummy.shift.split(/\n/) body = dummy.join("\n\n") else header = text.split(/\n/) body = nil end header.each do |h| result.push "#{h}\r\n" end result = Watobo::Request.new result ct = result.content_type # last line is without "\r\n" if text has a body if ct =~ /multipart\/form/ and body then #Content-Type: multipart/form-data; boundary=---------------------------3035221901842 if ct =~ /boundary=([\-\w]+)/ boundary = $1.strip chunks = body.split(boundary) e = chunks.pop # remove "--" new_body = [] chunks.each do |c| new_chunk = '' c.gsub!(/[\-]+$/,'') next if c.nil? next if c.strip.empty? c.strip! if c =~ /\n\n/ ctmp = c.split(/\n\n/) cheader = ctmp.shift.split(/\n/) cbody = ctmp.join("\n\n") else cheader = c.split(/\n/) cbody = nil end new_chunk = cheader.join("\r\n") new_chunk += "\r\n\r\n" new_chunk += cbody.strip + "\r\n" if cbody # puts cbody new_body.push new_chunk end body = "--#{boundary}\r\n" body += new_body.join("--#{boundary}\r\n") body += "--#{boundary}--" end # body.gsub!(/\n/, "\r\n") if body end if body then result.push "\r\n" result.push body.strip end return result end |
Instance Method Details
#loadIcon(app, filename) ⇒ Object
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/watobo/utils/load_icon.rb', line 13 def loadIcon(app, filename) begin icon = nil File.open(filename, "rb") do |f| if filename.strip =~ /\.ico$/ then icon = FXICOIcon.new(app, f.read) #icon = FXICOIcon.new(getApp(), f.read) elsif filename.strip =~ /\.png$/ then icon = FXPNGIcon.new(app, f.read) elsif filename.strip =~ /\.gif$/ then icon = FXGIFIcon.new(app, f.read) end icon.create end icon rescue => bang puts "Couldn't load icon: #{filename}" puts bang end end |