Top Level Namespace

Defined Under Namespace

Modules: Terminal, Typhoeus, URI Classes: Array, Browser, CacheFileStore, CheckerPlugin, CheckerSpelling, CustomOptionParser, DbUpdater, Numeric, Plugin, Plugins, StatsPlugin, TyphoeusCache, VersionCompare, Vulnerabilities, Vulnerability, WebSite, WpItem, WpItems, WpPlugin, WpPlugins, WpTarget, WpTheme, WpThemes, WpTimthumb, WpTimthumbs, WpUser, WpUsers, WpVersion, WpscanOptions

Constant Summary collapse

LIB_DIR =
File.expand_path(File.join(File.dirname(__FILE__), '..'))
ROOT_DIR =

expand_path is used to get “wpscan/” instead of “wpscan/lib/../”

File.expand_path(File.join(LIB_DIR, '..'))
DATA_DIR =
File.join(ROOT_DIR, 'data')
CONF_DIR =
File.join(ROOT_DIR, 'conf')
CACHE_DIR =
File.join(ROOT_DIR, 'cache')
WPSCAN_LIB_DIR =
File.join(LIB_DIR, 'wpscan')
WPSTOOLS_LIB_DIR =
File.join(LIB_DIR, 'wpstools')
UPDATER_LIB_DIR =
File.join(LIB_DIR, 'updater')
COMMON_LIB_DIR =
File.join(LIB_DIR, 'common')
MODELS_LIB_DIR =
File.join(COMMON_LIB_DIR, 'models')
COLLECTIONS_LIB_DIR =
File.join(COMMON_LIB_DIR, 'collections')
LOG_FILE =
File.join(ROOT_DIR, 'log.txt')
COMMON_PLUGINS_DIR =

Plugins directories

File.join(COMMON_LIB_DIR, 'plugins')
WPSCAN_PLUGINS_DIR =

Not used ATM

File.join(WPSCAN_LIB_DIR, 'plugins')
WPSTOOLS_PLUGINS_DIR =
File.join(WPSTOOLS_LIB_DIR, 'plugins')
PLUGINS_FILE =

Data files

File.join(DATA_DIR, 'plugins.txt')
PLUGINS_FULL_FILE =
File.join(DATA_DIR, 'plugins_full.txt')
PLUGINS_VULNS_FILE =
File.join(DATA_DIR, 'plugin_vulns.json')
THEMES_FILE =
File.join(DATA_DIR, 'themes.txt')
THEMES_FULL_FILE =
File.join(DATA_DIR, 'themes_full.txt')
THEMES_VULNS_FILE =
File.join(DATA_DIR, 'theme_vulns.json')
WP_VULNS_FILE =
File.join(DATA_DIR, 'wp_vulns.json')
WP_VERSIONS_FILE =
File.join(DATA_DIR, 'wp_versions.xml')
LOCAL_FILES_FILE =
File.join(DATA_DIR, 'local_vulnerable_files.xml')
WP_VERSIONS_XSD =

VULNS_XSD = File.join(DATA_DIR, 'vuln.xsd')

File.join(DATA_DIR, 'wp_versions.xsd')
LOCAL_FILES_XSD =
File.join(DATA_DIR, 'local_vulnerable_files.xsd')
USER_AGENTS_FILE =
File.join(DATA_DIR, 'user-agents.txt')
WPSCAN_VERSION =
'2.6'

Instance Method Summary collapse

Instance Method Details

#add_http_protocol(url) ⇒ Object

Add protocol


68
69
70
# File 'lib/common/common_helper.rb', line 68

def add_http_protocol(url)
  url =~ /^https?:/ ? url : "http://#{url}"
end

#add_trailing_slash(url) ⇒ Object


72
73
74
# File 'lib/common/common_helper.rb', line 72

def add_trailing_slash(url)
  url =~ /\/$/ ? url : "#{url}/"
end

#amber(text) ⇒ Object


104
105
106
# File 'lib/common/common_helper.rb', line 104

def amber(text)
  colorize(text, 33)
end

our 1337 banner


129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/common/common_helper.rb', line 129

def banner
  puts '_______________________________________________________________'
  puts '        __          _______   _____                  '
  puts '        \\ \\        / /  __ \\ / ____|                 '
  puts '         \\ \\  /\\  / /| |__) | (___   ___  __ _ _ __  '
  puts '          \\ \\/  \\/ / |  ___/ \\___ \\ / __|/ _` | \'_ \\ '
  puts '           \\  /\\  /  | |     ____) | (__| (_| | | | |'
  puts '            \\/  \\/   |_|    |_____/ \\___|\\__,_|_| |_|'
  puts
  puts '        WordPress Security Scanner by the WPScan Team '
  puts "                       Version #{WPSCAN_VERSION}"
  puts '          Sponsored by Sucuri - https://sucuri.net'
  puts '   @_WPScan_, @ethicalhack3r, @erwan_lr, pvdl, @_FireFart_'
  puts '_______________________________________________________________'
  puts
end

#blue(text) ⇒ Object


108
109
110
# File 'lib/common/common_helper.rb', line 108

def blue(text)
  colorize(text, 34)
end

#bold(text) ⇒ Object


92
93
94
# File 'lib/common/common_helper.rb', line 92

def bold(text)
  colorize(text, 1)
end

#colorize(text, color_code) ⇒ Object

Define colors


84
85
86
87
88
89
90
# File 'lib/common/common_helper.rb', line 84

def colorize(text, color_code)
  if $COLORSWITCH
    "#{text}"
  else
    "\e[#{color_code}m#{text}\e[0m"
  end
end

#count_file_lines(file) ⇒ Integer

Use the wc system command to count the number of lines in the file instead of using File.open which will use to much memory for large file (10 times the size of the file)

Returns:

  • (Integer)

    The number of lines in the given file


211
212
213
# File 'lib/common/common_helper.rb', line 211

def count_file_lines(file)
  `wc -l #{file.shellescape}`.split[0].to_i
end

#critical(text) ⇒ Object


112
113
114
# File 'lib/common/common_helper.rb', line 112

def critical(text)
  red(text)
end

#directory_listing_enabled?(url) ⇒ Boolean

Directory listing enabled on url?

Returns:

  • (Boolean)

243
244
245
# File 'lib/common/common_helper.rb', line 243

def directory_listing_enabled?(url)
  Browser.get(url.to_s).body[%r{<title>Index of}] ? true : false
end

#get_equal_string_end(stringarray = ['']) ⇒ Object

Gets the string all elements in stringarray ends with


169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/common/common_helper.rb', line 169

def get_equal_string_end(stringarray = [''])
  already_found = ''
  looping = true
  counter = -1
  # remove nils (# Issue #232)
  stringarray = stringarray.compact
  if stringarray.kind_of? Array and stringarray.length > 1
    base = stringarray.first
    while looping
      character = base[counter, 1]
      stringarray.each do |s|
        if s[counter, 1] != character
          looping = false
          break
        end
      end
      if looping == false or (counter * -1) > base.length
        break
      end
      already_found = "#{character if character}#{already_found}"
      counter -= 1
    end
  end
  already_found
end

#get_memory_usageInteger

Returns The memory of the current process in Bytes

Returns:

  • (Integer)

    The memory of the current process in Bytes


203
204
205
# File 'lib/common/common_helper.rb', line 203

def get_memory_usage
  `ps -o rss= -p #{Process.pid}`.to_i * 1024 # ps returns the value in KB
end

#get_random_user_agentString

Gets a random User-Agent

Returns:

  • (String)

    A random user-agent from data/user-agents.txt


227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/common/common_helper.rb', line 227

def get_random_user_agent
  user_agents = []
  f = File.open(USER_AGENTS_FILE, 'r')
  f.each_line do |line|
    # ignore comments
    next if line.empty? or line =~ /^\s*(#|\/\/)/
    user_agents << line.strip
  end
  f.close
  # return ransom user-agent
  user_agents.sample
end

#green(text) ⇒ Object


100
101
102
# File 'lib/common/common_helper.rb', line 100

def green(text)
  colorize(text, 32)
end

#helpObject

command help


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
# File 'lib/wpscan/wpscan_helper.rb', line 60

def help
  puts 'Help :'
  puts
  puts 'Some values are settable in a config file, see the example.conf.json'
  puts
  puts '--update                            Update to the database to the latest version.'
  puts '--url       | -u <target url>       The WordPress URL/domain to scan.'
  puts '--force     | -f                    Forces WPScan to not check if the remote site is running WordPress.'
  puts '--enumerate | -e [option(s)]        Enumeration.'
  puts '  option :'
  puts '    u        usernames from id 1 to 10'
  puts '    u[10-20] usernames from id 10 to 20 (you must write [] chars)'
  puts '    p        plugins'
  puts '    vp       only vulnerable plugins'
  puts '    ap       all plugins (can take a long time)'
  puts '    tt       timthumbs'
  puts '    t        themes'
  puts '    vt       only vulnerable themes'
  puts '    at       all themes (can take a long time)'
  puts '  Multiple values are allowed : "-e tt,p" will enumerate timthumbs and plugins'
  puts '  If no option is supplied, the default is "vt,tt,u,vp"'
  puts
  puts '--exclude-content-based "<regexp or string>"'
  puts '                                    Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied.'
  puts '                                    You do not need to provide the regexp delimiters, but you must write the quotes (simple or double).'
  puts '--config-file  | -c <config file>   Use the specified config file, see the example.conf.json.'
  puts '--user-agent   | -a <User-Agent>    Use the specified User-Agent.'
  puts '--cookie <String>                   String to read cookies from.'
  puts '--random-agent | -r                 Use a random User-Agent.'
  puts '--follow-redirection                If the target url has a redirection, it will be followed without asking if you wanted to do so or not'
  puts '--batch                             Never ask for user input, use the default behaviour.'
  puts '--no-color                          Do not use colors in the output.'
  puts '--wp-content-dir <wp content dir>   WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specified it.'
  puts '                                    Subdirectories are allowed.'
  puts '--wp-plugins-dir <wp plugins dir>   Same thing than --wp-content-dir but for the plugins directory.'
  puts '                                    If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed'
  puts '--proxy <[protocol://]host:port>    Supply a proxy. HTTP, SOCKS4 SOCKS4A and SOCKS5 are supported.'
  puts '                                    If no protocol is given (format host:port), HTTP will be used.'
  puts '--proxy-auth <username:password>    Supply the proxy login credentials.'
  puts '--basic-auth <username:password>    Set the HTTP Basic authentication.'
  puts '--wordlist | -w <wordlist>          Supply a wordlist for the password brute forcer.'
  puts '--username | -U <username>          Only brute force the supplied username.'
  puts '--usernames     <path-to-file>      Only brute force the usernames from the file.'
  puts '--threads  | -t <number of threads> The number of threads to use when multi-threading requests.'
  puts '--cache-ttl       <cache-ttl>       Typhoeus cache TTL.'
  puts '--request-timeout <request-timeout> Request Timeout.'
  puts '--connect-timeout <connect-timeout> Connect Timeout.'
  puts '--max-threads     <max-threads>     Maximum Threads.'
  puts '--help     | -h                     This help screen.'
  puts '--verbose  | -v                     Verbose output.'
  puts '--version                           Output the current version and exit.'
  puts
end

#info(text) ⇒ Object


120
121
122
# File 'lib/common/common_helper.rb', line 120

def info(text)
  green(text)
end

#json(file) ⇒ Object


152
153
154
155
156
157
158
159
160
161
# File 'lib/common/common_helper.rb', line 152

def json(file)
  content = File.open(file).read

  begin
    JSON.parse(content)
  rescue => e
    puts "[ERROR] In JSON file parsing #{file} #{e}"
    raise
  end
end

#kali_linux?Boolean

Returns:

  • (Boolean)

43
44
45
46
47
48
49
# File 'lib/common/common_helper.rb', line 43

def kali_linux?
  begin
    File.readlines("/etc/debian_version").grep(/^kali/i).any?
  rescue
    false
  end
end

#missing_db_file?Boolean

Returns:

  • (Boolean)

76
77
78
79
80
81
# File 'lib/common/common_helper.rb', line 76

def missing_db_file?
  DbUpdater::FILES.each do |db_file|
    return true unless File.exist?(File.join(DATA_DIR, db_file))
  end
  false
end

#notice(text) ⇒ Object


124
125
126
# File 'lib/common/common_helper.rb', line 124

def notice(text)
  blue(text)
end

#puts(o = '') ⇒ Object

Override for puts to enable logging


51
52
53
54
55
56
57
58
# File 'lib/common/hacks.rb', line 51

def puts(o = '')
  if $log && o.respond_to?(:gsub)
    temp = o.gsub(/\e\[\d+m/, '') # remove color for logging
    File.open(LOG_FILE, 'a+') { |f| f.puts(temp) }
  end
  
  super(o)
end

#red(text) ⇒ Object


96
97
98
# File 'lib/common/common_helper.rb', line 96

def red(text)
  colorize(text, 31)
end

#redefine_constant(constant, value) ⇒ Object


163
164
165
166
# File 'lib/common/common_helper.rb', line 163

def redefine_constant(constant, value)
  Object.send(:remove_const, constant)
  Object.const_set(constant, value)
end

#remove_base64_images_from_html(html) ⇒ Object


195
196
197
198
199
200
# File 'lib/common/common_helper.rb', line 195

def remove_base64_images_from_html(html)
  # remove data:image/png;base64, images
  base64regex = %r{(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?}
  imageregex = %r{data\s*:\s*image/[^\s;]+\s*;\s*base64\s*,\s*}
  html.gsub(/["']\s*#{imageregex}#{base64regex}\s*["']/, '""')
end

#require_files_from_directory(absolute_dir_path, files_pattern = '*.rb') ⇒ Object

TODO : add an exclude pattern ?


54
55
56
57
58
59
60
61
62
63
# File 'lib/common/common_helper.rb', line 54

def require_files_from_directory(absolute_dir_path, files_pattern = '*.rb')
  files = Dir[File.join(absolute_dir_path, files_pattern)]

  # Files in the root dir are loaded first, then those in the subdirectories
  files.sort_by { |file| [file.count("/"), file] }.each do |f|
    f = File.expand_path(f)
    #puts "require #{f}" # Used for debug
    require f
  end
end

#truncate(input, size, trailing = '...') ⇒ Object

Truncates a string to a specific length and adds … at the end


216
217
218
219
220
221
222
# File 'lib/common/common_helper.rb', line 216

def truncate(input, size, trailing = '...')
  size = size.to_i
  trailing ||= ''
  return input if input.nil? or size <= 0 or input.length <= size or
      trailing.length >= input.length or size-trailing.length-1 >= input.length
  return "#{input[0..size-trailing.length-1]}#{trailing}"
end

#usageObject

wpscan usage


8
9
10
11
12
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
# File 'lib/wpscan/wpscan_helper.rb', line 8

def usage
  script_name = $0
  puts
  puts 'Examples :'
  puts
  puts '-Further help ...'
  puts "ruby #{script_name} --help"
  puts
  puts "-Do 'non-intrusive' checks ..."
  puts "ruby #{script_name} --url www.example.com"
  puts
  puts '-Do wordlist password brute force on enumerated users using 50 threads ...'
  puts "ruby #{script_name} --url www.example.com --wordlist darkc0de.lst --threads 50"
  puts
  puts "-Do wordlist password brute force on the 'admin' username only ..."
  puts "ruby #{script_name} --url www.example.com --wordlist darkc0de.lst --username admin"
  puts
  puts '-Enumerate installed plugins ...'
  puts "ruby #{script_name} --url www.example.com --enumerate p"
  puts
  puts '-Enumerate installed themes ...'
  puts "ruby #{script_name} --url www.example.com --enumerate t"
  puts
  puts '-Enumerate users ...'
  puts "ruby #{script_name} --url www.example.com --enumerate u"
  puts
  puts '-Enumerate installed timthumbs ...'
  puts "ruby #{script_name} --url www.example.com --enumerate tt"
  puts
  puts '-Use a HTTP proxy ...'
  puts "ruby #{script_name} --url www.example.com --proxy 127.0.0.1:8118"
  puts
  puts '-Use a SOCKS5 proxy ... (cURL >= v7.21.7 needed)'
  puts "ruby #{script_name} --url www.example.com --proxy socks5://127.0.0.1:9000"
  puts
  puts '-Use custom content directory ...'
  puts "ruby #{script_name} -u www.example.com --wp-content-dir custom-content"
  puts
  puts '-Use custom plugins directory ...'
  puts "ruby #{script_name} -u www.example.com --wp-plugins-dir wp-content/custom-plugins"
  puts
  puts '-Update the DB ...'
  puts "ruby #{script_name} --update"
  puts
  puts '-Debug output ...'
  puts "ruby #{script_name} --url www.example.com --debug-output 2>debug.log"
  puts
  puts 'See README for further information.'
  puts
end

#warning(text) ⇒ Object


116
117
118
# File 'lib/common/common_helper.rb', line 116

def warning(text)
  amber(text)
end

#xml(file) ⇒ Object


146
147
148
149
150
# File 'lib/common/common_helper.rb', line 146

def xml(file)
  Nokogiri::XML(File.open(file)) do |config|
    config.noblanks
  end
end