forked from WhitewidowScanner/whitewidow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
whitewidow.rb
executable file
·188 lines (184 loc) · 10 KB
/
whitewidow.rb
1
2
3
4
5
6
7
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
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#!/usr/local/env ruby
require_relative 'lib/imports/constants_and_requires'
#
# Options banner
#
def banner_message
[
"USAGE: ruby #{$0} -[SHORT-OPTS] [ARGS] --[LONG-OPTS] [ARGS]".cyan.bold,
"Mandatory options : -[d|f|s] FILE|URL --[default|file|spider] FILE|URL".cyan.bold,
"Enumeration options: -[x] NUM --[dry-run|batch|run-x] NUM".cyan.bold,
"Anomity options : -[p] IP:PORT --[rand-agent|proxy] IP:PORT".cyan.bold,
"Processing options : -[D|c] DORK|NAME --[sqlmap|dork|column] DORK|NAME".cyan.bold,
"Misc options : -[l|b|u] --[legal|banner|beep|update]".cyan.bold,
"Dev options : --[test]".cyan.bold,
" " # Blank line for nice formatting
].join("\n")
end
#
# Usage page, basic help page for commands
#
def usage_page
FORMAT.info("Check the README.md file for a list of flags and further information or go here: #{FUNCTION_PAGE_LINK}\n")
end
#
# Append into the OPTIONS constant so that we can call the flag from the constant instead of a class
#
ARGV << '-h' if ARGV.empty? # Display help dialog if no flags are passed
OptionParser.new do |opt|
opt.banner = banner_message
opt.on('-f FILE', '--file FILE', 'Pass a filename to scan for vulnerabilities') { |o| OPTIONS[:file] = o }
opt.on('-s URL', '--spider URL', 'Spider a web page and save all the URLS') { |o| OPTIONS[:spider] = o }
opt.on('-p IP:PORT', '--proxy IP:PORT', 'Configure to run with a proxy, must use ":"') { |o| OPTIONS[:proxy] = o }
opt.on('-x NUM', '--run-x NUM', 'Run the specified amount of dry runs') { |o| OPTIONS[:run] = o }
opt.on('-D DORK', '--dork DORK', 'Use your own dork to do the searching') { |o| OPTIONS[:dork] = o } # Issue #32 https://github.com/WhitewidowScanner/whitewidow/issues/32
opt.on('-d', '--default', 'Run in default mode, scrape Google') { |o| OPTIONS[:default] = o }
opt.on('-l', '--legal', 'Show the legal information and the TOS') { |o| OPTIONS[:legal] = o }
opt.on('-b', '--banner', 'Hide the banner') { |o| OPTIONS[:banner] = o }
opt.on('-v', '--version', 'Display the version number and exit') { |o| OPTIONS[:version] = o }
opt.on('-u', '--update', 'Update whitewidow with the newest version') { |o| OPTIONS[:update] = o }
opt.on('-S', '--search-engine', 'Configure whitewidow to use a random search engine') { |o| OPTIONS[:searchengine] = o }
opt.on('--dry-run', 'Run a dry run (no checking for vulnerability with prompt)') { |o| OPTIONS[:dry] = o }
opt.on('--batch', 'No prompts, used in conjunction with the dry run') { |o| OPTIONS[:batch] = o }
opt.on('--beep', 'Make a beep when the program finds a vulnerability') { |o| OPTIONS[:beep] = o }
opt.on('--rand-agent', 'Use a random user agent') { |o| OPTIONS[:agent] = o }
opt.on('--sqlmap', 'Run sqlmap through the SQL_VULN.LOG file as a bulk file') { |o| OPTIONS[:sqlmap] = o }
opt.on('--test', 'Used mostly for development use') { |o| OPTIONS[:test] = o }
opt.on('-h', '--help', 'Display this help dialog and exit') do
hidden = "--search-engine"
usage_page
puts opt.to_s.split("\n").delete_if { |line| line =~ /#{hidden}/ }.join("\n")
end
end.parse!
# This case statement has to be empty or the program won't read the options constants
begin
case
when OPTIONS[:default]
begin
SETTINGS.hide_banner?
SETTINGS.show_legal?
Whitewidow::Scanner.get_urls(OPTIONS[:proxy])
if File.size("#{SITES_TO_CHECK_PATH}") == 0
FORMAT.warning("No sites found for search query: #{SEARCH_QUERY}. Adding query to blacklist so it won't be run again.") # Add the query to the blacklist # File.open("#{QUERY_BLACKLIST_PATH}", "a+") { |query| query.puts(SEARCH_QUERY) }
FORMAT.info("Query added to blacklist and will not be run again, exiting..")
exit(1)
elsif OPTIONS[:dry]
#if OPTIONS[:dry]
dry = FORMAT.prompt('Run the sites[Y/N]') unless OPTIONS[:batch]
dry = 'N' if OPTIONS[:batch]
if dry.upcase == 'N'
FORMAT.info('Sites saved to file, will not run scan now..')
exit(0)
else
Whitewidow::Scanner.vulnerability_check(file_mode: false)
end
else
Whitewidow::Scanner.vulnerability_check(file_mode: false)
end
File.open("#{ERROR_LOG_PATH}", 'a+') {
|s| s.puts("No sites found with search query #{DEFAULT_SEARCH_QUERY}")
} if File.size("#{SITES_TO_CHECK_PATH}") == 0
File.truncate("#{SITES_TO_CHECK_PATH}", 0)
FORMAT.info("I'm truncating SQL_sites_to_check file back to #{File.size("#{SITES_TO_CHECK_PATH}")}")
FileUtils.copy(TEMP_VULN_LOG, SQL_VULN_SITES_LOG)
File.truncate("#{TEMP_VULN_LOG}", 0)
FORMAT.info("I've run all my tests and queries, and logged all important information into #{SQL_VULN_SITES_LOG}")
rescue *FATAL_ERRORS => e
File.open(ERROR_LOG_PATH, 'a+') { |error| error.puts("#{Date.today}\n#{e.backtrace}\n---") }
FORMAT.fatal("Issue template has been generated for this error, create a new issue named: #{SETTINGS.random_issue_name} #{e}")
FORMAT.info("An issue template has been generated for you and is located in #{ISSUE_TEMPLATE_PATH}")
SETTINGS.create_issue_page("Getting error: #{e}", e, "Run with #{OPTIONS}",
OPTIONS[:dork] == nil ? DEFAULT_SEARCH_QUERY : OPTIONS[:dork])
end
when OPTIONS[:file]
begin
SETTINGS.hide_banner?
SETTINGS.show_legal?
FORMAT.info('Formatting file')
Whitewidow::Scanner.format_file(OPTIONS[:file])
Whitewidow::Scanner.vulnerability_check(file_mode: true)
File.truncate("#{SITES_TO_CHECK_PATH}", 0)
FORMAT.info("I'm truncating SQL_sites_to_check file back to #{File.size("#{SITES_TO_CHECK_PATH}")}")
FileUtils.copy(TEMP_VULN_LOG, SQL_VULN_SITES_LOG)
File.truncate("#{TEMP_VULN_LOG}", 0)
FORMAT.info(
"I've run all my tests and queries, and logged all important information into #{SQL_VULN_SITES_LOG}"
) unless File.size("#{SQL_VULN_SITES_LOG}") == 0
rescue *FATAL_ERRORS => e
File.open(ERROR_LOG_PATH, 'a+') { |error| error.puts("#{Date.today}\n#{e.backtrace}\n---") }
FORMAT.fatal("Issue template has been generated for this error, create a new issue named: #{SETTINGS.random_issue_name} #{e}")
FORMAT.info("An issue template has been generated for you and is located in #{ISSUE_TEMPLATE_PATH}")
SETTINGS.create_issue_page("Getting error: #{e}", e, "Run with #{OPTIONS}",
OPTIONS[:dork] == nil ? DEFAULT_SEARCH_QUERY : OPTIONS[:dork])
end
when OPTIONS[:legal]
SETTINGS.show_legal?
when OPTIONS[:run]
OPTIONS[:run].to_i.times do
system('ruby whitewidow.rb -d --dry-run --batch --banner')
end
FORMAT.info("#{OPTIONS[:run]} runs completed successfully.")
when OPTIONS[:sqlmap]
FORMAT.info("Launching sqlmap..")
if SETTINGS.sqlmap_config
system("#{File.read(SQLMAP_CONFIG_PATH)}")
else
system("#{File.read(SQLMAP_LAST_REQUEST_FILE)}")
File.open(SQLMAP_LAST_REQUEST_FILE, "a+").truncate(0)
end
when OPTIONS[:spider]
begin
if URI(OPTIONS[:spider]).query
arr = SPIDER_BOT.pull_links(OPTIONS[:spider])
SPIDER_BOT.follow_links(arr)
FORMAT.info("Found a total of #{File.open(BLACKWIDOW_LOG).readlines.size} links. Running them as file..")
system("ruby whitewidow.rb --banner -f #{BLACKWIDOW_LOG}")
File.truncate("tmp/blackwidow_log.txt", 0)
else
FORMAT.err("No valid query parameter found for: #{OPTIONS[:spider]}.")
FORMAT.err("URL should contain a query parameter. I.E. http://fakesite.com/php?id=2")
end
rescue *SPIDER_ERRORS => e
File.size(BLACKWIDOW_LOG) == 0 ? FORMAT.fatal("No sites obtained for #{OPTIONS[:spider]}, failed with #{e}") :
FORMAT.err("#{OPTIONS[:spider]} encountered an error and cannot continue. Running sites obtained so far")
system("ruby whitewidow.rb --banner -f #{BLACKWIDOW_LOG}") if File.size(BLACKWIDOW_LOG) != 0
end
when OPTIONS[:version]
FORMAT.info("Currently version: #{VERSION}")
exit
when OPTIONS[:update]
FORMAT.info("Updating to newest version..")
SETTINGS.update!
when OPTIONS[:test]
system('rspec')
else
exit(1)
end
rescue => e
FORMAT.err("Failed with error code #{e}")
if e.inspect =~ /OpenSSL::SSL::SSLError/
FORMAT.warning("Your user agent is bad, make an issue with the user agent")
FORMAT.info("Trying again with a different user agent") # Temp fix until I can fix the user agents.
begin
system("ruby whitewidow.rb -d --banner --rand-agent")
rescue OpenSSL::SSL::SSLError
FORMAT.fatal("User agent failed to load for the second time, running as default..")
system("ruby whitewidow.rb -d --banner")
end
elsif e.inspect =~ /tIDENTIFIER/
FORMAT.fatal("What we have here is a P.I.C.N.I.C. To run this program you need a Ruby version >=2.3.0.")
FORMAT.fatal("Your current ruby version: #{RUBY_VERSION}")
FORMAT.fatal("Download the latest Ruby by#{SETTINGS.ruby_download_link}")
exit(1)
else
FORMAT.fatal("Program failed with error code: #{e}, error saved to error_log.txt")
File.open(ERROR_LOG_PATH, 'a+') { |error| error.puts("#{Date.today}\n---\n#{e.backtrace}\n#{e.backtrace_locations}\n---\n") }
FORMAT.fatal("Issue template is being generated for this error, create a new issue named: #{SETTINGS.random_issue_name} #{e}")
SETTINGS.create_issue_page("Getting error: #{e}", e, "Run with #{OPTIONS}",
OPTIONS[:dork] == nil ? DEFAULT_SEARCH_QUERY : OPTIONS[:dork])
FORMAT.info("An issue template has been generated for you and is located in #{ISSUE_TEMPLATE_PATH}")
end
rescue Interrupt
FORMAT.err("User aborted scanning.")
exit(1)
end