diff --git a/lib/wpscan/wp_item.rb b/lib/wpscan/wp_item.rb index 82910fdf..5b560e71 100644 --- a/lib/wpscan/wp_item.rb +++ b/lib/wpscan/wp_item.rb @@ -161,6 +161,20 @@ class WpItem < Vulnerable get_url_without_filename.merge('changelog.txt') end + def error_log_url + get_url_without_filename.merge('error_log') + end + + # Discover any error_log files created by WordPress + # These are created by the WordPress error_log() function + # They are normally found in the /plugins/ directory, + # however can also be found in their specific plugin dir. + # http://www.exploit-db.com/ghdb/3714/ + def error_log? + response_body = Browser.instance.get(error_log_url, headers: {'range' => 'bytes=0-700'}).body + response_body[%r{PHP Fatal error}i] ? true : false + end + # readme.txt present? def has_readme? unless @readme diff --git a/lib/wpscan/wp_plugin.rb b/lib/wpscan/wp_plugin.rb index 605dce43..961d5f60 100644 --- a/lib/wpscan/wp_plugin.rb +++ b/lib/wpscan/wp_plugin.rb @@ -29,18 +29,4 @@ class WpPlugin < WpItem super(options) end - - # Discover any error_log files created by WordPress - # These are created by the WordPress error_log() function - # They are normally found in the /plugins/ directory, - # however can also be found in their specific plugin dir. - # http://www.exploit-db.com/ghdb/3714/ - def error_log? - response_body = Browser.instance.get(error_log_url(), headers: {'range' => 'bytes=0-700'}).body - response_body[%r{PHP Fatal error}i] ? true : false - end - - def error_log_url - get_full_url.merge('error_log').to_s - end end diff --git a/spec/lib/wpscan/wp_item_spec.rb b/spec/lib/wpscan/wp_item_spec.rb index d1f78bc9..3b8bc2a7 100644 --- a/spec/lib/wpscan/wp_item_spec.rb +++ b/spec/lib/wpscan/wp_item_spec.rb @@ -539,4 +539,49 @@ describe WpPlugin do end end + describe '#error_log_url' do + it 'should return a correct url' do + temp = WpItem.new( + base_url: 'http://sub.example.com/path/to/wordpress/', + path: 'name/asdf.php', + vulns_file: 'XXX.xml', + name: 'name', + vulns_xpath: 'XX', + type: 'plugins') + temp.error_log_url.to_s.should == 'http://sub.example.com/path/to/wordpress/wp-content/plugins/name/error_log' + end + end + + describe '#error_log?' do + before :each do + @temp = WpItem.new( + base_url: 'http://sub.example.com/path/to/wordpress/', + path: 'test/asdf.php', + vulns_file: 'XXX.xml', + name: 'name', + vulns_xpath: 'XX', + type: 'plugins') + end + + it 'should return true' do + stub_request(:get, @temp.error_log_url.to_s).to_return(status: 200, body: 'PHP Fatal error') + @temp.error_log?.should be true + end + + it 'should return false' do + stub_request(:get, @temp.error_log_url.to_s).to_return(status: 500, body: 'Access denied') + @temp.error_log?.should be false + end + + it 'should return true' do + fixtures_dir = SPEC_FIXTURES_WPSCAN_WP_PLUGIN_DIR + '/error_log' + stub_request(:get, @temp.error_log_url.to_s).to_return( + status: 200, + body: File.new(fixtures_dir + '/error_log') + ) + + @temp.error_log?.should be true + end + end + end diff --git a/spec/lib/wpscan/wp_plugin_spec.rb b/spec/lib/wpscan/wp_plugin_spec.rb index 2f78779a..9d8cd9ae 100644 --- a/spec/lib/wpscan/wp_plugin_spec.rb +++ b/spec/lib/wpscan/wp_plugin_spec.rb @@ -41,42 +41,4 @@ describe WpPlugin do expect { WpPlugin.new(base_url: 'url', path: 'path', wp_content_dir: 'dir') }.to raise_error end end - - describe '#error_log_url' do - it 'should return a correct url' do - temp = WpPlugin.new( - base_url: 'http://wordpress.com', - path: 'test/asdf.php' - ) - temp.error_log_url.to_s.should == 'http://wordpress.com/wp-content/plugins/test/error_log' - end - end - - describe '#error_log?' do - before :each do - @temp = WpPlugin.new( - base_url: 'http://wordpress.com', - path: 'test/asdf.php') - end - - it 'should return true' do - stub_request(:get, @temp.error_log_url.to_s).to_return(status: 200, body: 'PHP Fatal error') - @temp.error_log?.should be true - end - - it 'should return false' do - stub_request(:get, @temp.error_log_url.to_s).to_return(status: 500, body: 'Access denied') - @temp.error_log?.should be false - end - - it 'should return true' do - fixtures_dir = SPEC_FIXTURES_WPSCAN_WP_PLUGIN_DIR + '/error_log' - stub_request(:get, @temp.error_log_url.to_s).to_return( - status: 200, - body: File.new(fixtures_dir + '/error_log') - ) - - @temp.error_log?.should be true - end - end end diff --git a/wpscan.rb b/wpscan.rb index 5e4e7bca..7b3eb94b 100755 --- a/wpscan.rb +++ b/wpscan.rb @@ -35,6 +35,22 @@ def output_vulnerabilities(vulns) end end +def output_item_details(item) + puts + puts " | Name: #{item}" #this will also output the version number if detected + puts " | Location: #{item.get_url_without_filename}" + puts " | WordPress: #{item.wp_org_url}" if item.wp_org_item? + puts ' | Directory listing enabled: Yes' if item.directory_listing? + puts " | Readme: #{item.readme_url}" if item.has_readme? + puts " | Changelog: #{item.changelog_url}" if item.has_changelog? + + output_vulnerabilities(item.vulnerabilities) + + if item.error_log? + puts ' | ' + red('[!]') + " A WordPress error_log file has been found : #{item.error_log_url}" + end +end + # delete old logfile, check if it is a symlink first. File.delete(LOG_FILE) if File.exist?(LOG_FILE) and !File.symlink?(LOG_FILE) @@ -136,19 +152,7 @@ begin if wp_theme # Theme version is handled in wp_item.to_s puts green('[+]') + " The WordPress theme in use is #{wp_theme}" - puts - puts " | Name: #{wp_theme}" #this will also output the version number if detected - puts " | Location: #{wp_theme.get_url_without_filename}" - puts " | WordPress: #{wp_theme.wp_org_url}" if wp_theme.wp_org_item? - puts ' | Directory listing enabled: Yes' if wp_theme.directory_listing? - puts " | Readme: #{wp_theme.readme_url}" if wp_theme.has_readme? - puts " | Changelog: #{wp_theme.changelog_url}" if wp_theme.has_changelog? - - theme_vulnerabilities = wp_theme.vulnerabilities - unless theme_vulnerabilities.empty? - puts red('[!]') + " We have identified #{theme_vulnerabilities.size} vulnerabilities for this theme :" - output_vulnerabilities(theme_vulnerabilities) - end + output_item_details(wp_theme) puts end @@ -218,15 +222,10 @@ begin plugins = wp_target.plugins_from_passive_detection(base_url: wp_target.uri, wp_content_dir: wp_target.wp_content_dir) if !plugins.empty? - puts "#{plugins.size} found :" + puts "#{plugins.size} plugins found :" plugins.each do |plugin| - puts - puts " | Name: #{plugin}" - puts " | Location: #{plugin.get_full_url}" - puts " | WordPress: #{plugin.wp_org_url}" if plugin.wp_org_item? - - output_vulnerabilities(plugin.vulnerabilities) + output_item_details(plugin) end else puts 'No plugins found :(' @@ -258,19 +257,7 @@ begin puts green('[+]') + " We found #{plugins.size.to_s} plugins:" plugins.each do |plugin| - puts - puts " | Name: #{plugin}" #this will also output the version number if detected - puts " | Location: #{plugin.get_url_without_filename}" - puts " | WordPress: #{plugin.wp_org_url}" if plugin.wp_org_item? - puts ' | Directory listing enabled: Yes' if plugin.directory_listing? - puts " | Readme: #{plugin.readme_url}" if plugin.has_readme? - puts " | Changelog: #{plugin.changelog_url}" if plugin.has_changelog? - - output_vulnerabilities(plugin.vulnerabilities) - - if plugin.error_log? - puts ' | ' + red('[!]') + " A WordPress error_log file has been found : #{plugin.error_log_url}" - end + output_item_details(plugin) end else puts @@ -302,15 +289,7 @@ begin puts green('[+]') + " We found #{themes.size.to_s} themes:" themes.each do |theme| - puts - puts " | Name: #{theme}" #this will also output the version number if detected - puts " | Location: #{theme.get_url_without_filename}" - puts " | WordPress: #{theme.wp_org_url}" if theme.wp_org_item? - puts ' | Directory listing enabled: Yes' if theme.directory_listing? - puts " | Readme: #{theme.readme_url}" if theme.has_readme? - puts " | Changelog: #{theme.changelog_url}" if theme.has_changelog? - - output_vulnerabilities(theme.vulnerabilities) + output_item_details(theme) end else puts