lib/wwmd/page.rb in miketracy-wwmd-0.2.16 vs lib/wwmd/page.rb in miketracy-wwmd-0.2.17

- old
+ new

@@ -1,245 +1,3 @@ -module WWMD - attr_accessor :curl_object - attr_accessor :body_data - attr_accessor :post_data - attr_accessor :header_data - attr_accessor :use_referer - attr_reader :forms - attr_reader :last_error - attr_reader :links # array of links (urls) - attr_reader :jlinks # array of included javascript files - attr_reader :spider # spider object - attr_reader :scrape # scrape object - attr_reader :urlparse # urlparse object - attr_reader :comments - - attr_accessor :base_url # needed to properly munge relative urls into fq urls - attr_accessor :logged_in # are we logged in? - - attr_accessor :opts - attr_accessor :inputs - - # WWMD::Page is an extension of a Curl::Easy object which provides methods to - # enhance and ease the performance of web application penetration testing. - class Page - - def initialize(opts={}) - @opts = opts.clone - DEFAULTS.each { |k,v| @opts[k] = v if not opts[k] } - @spider = Spider.new(opts) - @scrape = Scrape.new - @base_url ||= opts[:base_url] - @scrape.warn = opts[:scrape_warn] if !opts[:scrape_warn].nil? - if opts.empty? - putw "Page initialized without opts" - @scrape.warn = false - end - @urlparse = URLParse.new() - @inputs = Inputs.new(self) - @logged_in = false - @body_data = "" - @post_data = "" - @comments = [] - @header_data = FormArray.new - - @curl_object = Curl::Easy.new - @opts.each do |k,v| - next if !(@curl_object.methods.include?("#{k}=")) - next if k == :proxy_url - @curl_object.send("#{k}=",v) - end - @curl_object.on_body { |data| self._body_cb(data) } - @curl_object.on_header { |data| self._header_cb(data) } - - # cookies? - @curl_object.enable_cookies = @opts[:enable_cookies] - if @curl_object.enable_cookies? - @curl_object.cookiejar = @opts[:cookiejar] || "./__cookiejar" - end - - #proxy? - @curl_object.proxy_url = @opts[:proxy_url] if @opts[:use_proxy] - end - -#:section: Heavy Lifting - - # set reporting data for the page - # - # Scan for comments, anchors, links and javascript includes and - # set page flags. The heavy lifting for parsing is done in the - # scrape class. - # - # returns: <tt>array [ code, page_status, body_data.size ]</tt> - def set_data - # reset scrape and inputs object - # transparently gunzip - begin - io = StringIO.new(self.body_data) - gz = Zlib::GzipReader.new(io) - self.body_data.replace(gz.read) - rescue => e - end - @scrape.reset(self.body_data) - @inputs.set - - @comments = @scrape.for_comments - # remove comments that are css selectors for IE silliness - @comments.reject! do |c| - c =~ /\[if IE\]/ || - c =~ /\[if IE \d/ || - c =~ /\[if lt IE \d/ - end - @links = @scrape.for_links.map do |url| - @urlparse.parse(self.last_effective_url,url).to_s - end - @jlinks = @scrape.for_javascript_links - @forms = [] - self.search("//form").each { |f| @forms << Form.new(f) } - @spider.add(self.last_effective_url,@links) - return [self.code,self.page_status,self.body_data.size] - end - - # clear self.body_data and self.header_data - def clear_data - return false if self.opts[:parse] = false - @body_data = "" - @header_data.clear - @last_error = nil - end - - # override Curl::Easy.perform to perform page actions, - # call <tt>self.set_data</tt> - # - # returns: <tt>array [ code, page_status, body_data.size ]</tt> - # - # don't call this directly if we are in console mode - # use get and submit respectively for GET and POST - def perform - self.clear_data - self.headers["Referer"] = self.cur if self.use_referer - begin - @curl_object.perform - rescue => e - @last_error = e - putw "WARN: #{e.class}" if e.class =~ /Curl::Err/ -# self.logged_in = false - end - self.set_data - return [self.code,self.page_status,self.body_data.size] - end - - # replacement for Curl::Easy.http_post - # - # post the form attempting to remove curl supplied headers (Expect, X-Forwarded-For - # call <tt>self.set_data</tt> - # - # if passed a regexp, escape values in the form using regexp before submitting - # if passed nil for the regexp arg, the form will not be escaped - # default: WWMD::ESCAPE[:url] - # - # returns: <tt>array [ code, body_data.size ]</tt> - def submit(iform=nil,reg=WWMD::ESCAPE[:default]) -##### this is just getting worse and worse - if iform.class == "Symbol" - reg = iform - iform = nil - end - self.clear_data - ["Expect","X-Forwarded-For","Content-length"].each { |s| self.clear_header(s) } - self.headers["Referer"] = self.cur if self.use_referer - if iform == nil - if not self.form.empty? - sform = self.form.clone - else - return "no form provided" - end - else - sform = iform.clone # clone the form so that we don't change the original - end - sform.escape_all!(reg) - if sform.empty? - self.http_post('') - else - self.http_post(self.post_data = sform.to_post) - end - begin - self.set_data - rescue => e - STDERR.puts "FATAL: could not parse page" - end - return [self.code, self.body_data.size] - end - - # submit a form using POST string - def submit_string(post_string) - self.clear_data - self.http_post(post_string) - self.set_data - if self.ntlm? - putw "WARN: this page requires NTLM Authentication" - putw "WARN: use ntlm_get instead of get" - end - return [self.code, self.body_data.size] - end - - # override for Curl::Easy.perform - # - # if the passed url string doesn't contain an fully qualified - # path, we'll guess and prepend opts[:base_url] - # - # returns: <tt>array [ code, body_data.size ]</tt> - def get(url=nil,parse=true) - if !(url =~ /[a-z]+:\/\//) && parse - self.url = @urlparse.parse(self.opts[:base_url],url).to_s if url - elsif url - self.url = url - end - self.perform - if self.ntlm? - putw "WARN: this page requires NTLM Authentication" - putw "use ntlm_get instead of get" - end - self.set_data - return [self.code, self.body_data.size] - end - - # GET with params and POST it as a form - def post(url=nil) - ep = url.clip - self.url = @urlparse.parse(self.opts[:base_url],ep).to_s if ep - form = url.clop.to_form - self.submit(form) - end - - # send arbitrary verb (only works with patch to taf2-curb - def verb(verb) - return false if !@curl_object.respond_to?(:http_verb) - self.clear_data - self.headers["Referer"] = self.cur if self.use_referer - self.http_verb(verb) - self.set_data - return [self.code, self.body_data.size] - end - -#:section: Data callbacks and method_missing - - # callback for <tt>self.on_body</tt> - def _body_cb(data) - @body_data << data if data - return data.length.to_i - end - - # callback for <tt>self.on_header</tt> - def _header_cb(data) - myArr = Array.new(data.split(":",2)) - @header_data.extend! myArr[0].to_s.strip,myArr[1].to_s.strip - return data.length.to_i - end - - # send methods not defined here to <tt>@curl_object</tt> - def method_missing(methodname, *args) - @curl_object.send(methodname, *args) - end - - end -end +require 'wwmd/wwmd_utils' +require 'wwmd/wwmd_config' +require 'wwmd/page/page'