ronin-web 1.0.2 → 2.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +3 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +5 -0
- data/ChangeLog.md +46 -1
- data/Gemfile +25 -12
- data/README.md +257 -51
- data/Rakefile +9 -0
- data/data/completions/ronin-web +203 -0
- data/gemspec.yml +18 -5
- data/lib/ronin/web/cli/browser_options.rb +92 -0
- data/lib/ronin/web/cli/browser_shell.rb +448 -0
- data/lib/ronin/web/cli/command.rb +1 -1
- data/lib/ronin/web/cli/commands/browser.rb +373 -0
- data/lib/ronin/web/cli/commands/completion.rb +63 -0
- data/lib/ronin/web/cli/commands/diff.rb +60 -8
- data/lib/ronin/web/cli/commands/html.rb +21 -33
- data/lib/ronin/web/cli/commands/irb.rb +1 -1
- data/lib/ronin/web/cli/commands/new/{webapp.rb → app.rb} +8 -8
- data/lib/ronin/web/cli/commands/new/nokogiri.rb +4 -4
- data/lib/ronin/web/cli/commands/new/server.rb +1 -1
- data/lib/ronin/web/cli/commands/new/spider.rb +1 -1
- data/lib/ronin/web/cli/commands/new.rb +5 -3
- data/lib/ronin/web/cli/commands/reverse_proxy.rb +1 -1
- data/lib/ronin/web/cli/commands/screenshot.rb +186 -0
- data/lib/ronin/web/cli/commands/server.rb +1 -1
- data/lib/ronin/web/cli/commands/session_cookie.rb +265 -0
- data/lib/ronin/web/cli/commands/spider.rb +61 -467
- data/lib/ronin/web/cli/commands/user_agent.rb +177 -0
- data/lib/ronin/web/cli/commands/vulns.rb +463 -0
- data/lib/ronin/web/cli/commands/wordlist.rb +484 -0
- data/lib/ronin/web/cli/commands/xml.rb +149 -0
- data/lib/ronin/web/cli/js_shell.rb +69 -0
- data/lib/ronin/web/cli/ruby_shell.rb +1 -1
- data/lib/ronin/web/cli/spider_options.rb +919 -0
- data/lib/ronin/web/cli.rb +3 -1
- data/lib/ronin/web/html.rb +1 -1
- data/lib/ronin/web/root.rb +1 -1
- data/lib/ronin/web/version.rb +2 -2
- data/lib/ronin/web/xml.rb +1 -1
- data/lib/ronin/web.rb +4 -364
- data/man/ronin-web-browser.1 +92 -0
- data/man/ronin-web-browser.1.md +96 -0
- data/man/ronin-web-completion.1 +76 -0
- data/man/ronin-web-completion.1.md +78 -0
- data/man/ronin-web-diff.1 +14 -21
- data/man/ronin-web-diff.1.md +13 -6
- data/man/ronin-web-html.1 +30 -46
- data/man/ronin-web-html.1.md +27 -17
- data/man/ronin-web-irb.1 +9 -16
- data/man/ronin-web-irb.1.md +6 -2
- data/man/ronin-web-new-app.1.md +39 -0
- data/man/ronin-web-new-nokogiri.1 +9 -20
- data/man/ronin-web-new-nokogiri.1.md +5 -5
- data/man/ronin-web-new-server.1 +11 -23
- data/man/ronin-web-new-server.1.md +5 -5
- data/man/ronin-web-new-spider.1 +44 -88
- data/man/ronin-web-new-spider.1.md +37 -37
- data/man/ronin-web-new.1 +18 -30
- data/man/ronin-web-new.1.md +15 -11
- data/man/ronin-web-reverse-proxy.1 +33 -38
- data/man/ronin-web-reverse-proxy.1.md +20 -14
- data/man/ronin-web-screenshot.1 +56 -0
- data/man/ronin-web-screenshot.1.md +56 -0
- data/man/ronin-web-server.1 +15 -29
- data/man/ronin-web-server.1.md +13 -9
- data/man/ronin-web-session-cookie.1 +38 -0
- data/man/ronin-web-session-cookie.1.md +41 -0
- data/man/ronin-web-spider.1 +121 -130
- data/man/ronin-web-spider.1.md +115 -66
- data/man/ronin-web-user-agent.1 +44 -0
- data/man/ronin-web-user-agent.1.md +46 -0
- data/man/ronin-web-vulns.1 +175 -0
- data/man/ronin-web-vulns.1.md +177 -0
- data/man/ronin-web-wordlist.1 +258 -0
- data/man/ronin-web-wordlist.1.md +263 -0
- data/man/ronin-web-xml.1 +43 -0
- data/man/ronin-web-xml.1.md +46 -0
- data/man/ronin-web.1 +67 -18
- data/man/ronin-web.1.md +55 -4
- data/scripts/setup +58 -0
- metadata +122 -31
- data/lib/ronin/web/mechanize.rb +0 -84
- data/man/ronin-web-new-webapp.1.md +0 -39
- /data/data/new/{webapp → app}/.gitignore +0 -0
- /data/data/new/{webapp → app}/.ruby-version.erb +0 -0
- /data/data/new/{webapp → app}/Dockerfile.erb +0 -0
- /data/data/new/{webapp → app}/Gemfile +0 -0
- /data/data/new/{webapp → app}/app.rb.erb +0 -0
- /data/data/new/{webapp → app}/config.ru +0 -0
- /data/data/new/{webapp → app}/docker-compose.yml.erb +0 -0
@@ -0,0 +1,373 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-web - A collection of useful web helper methods and commands.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-web is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-web is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with ronin-web. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/web/cli/command'
|
22
|
+
require 'ronin/web/cli/browser_options'
|
23
|
+
require 'ronin/web/cli/browser_shell'
|
24
|
+
require 'ronin/web/cli/js_shell'
|
25
|
+
|
26
|
+
require 'command_kit/colors'
|
27
|
+
|
28
|
+
module Ronin
|
29
|
+
module Web
|
30
|
+
class CLI
|
31
|
+
module Commands
|
32
|
+
#
|
33
|
+
# Screenshots one or more URLs.
|
34
|
+
#
|
35
|
+
# ## Usage
|
36
|
+
#
|
37
|
+
# ronin-web browser [options] [URL]
|
38
|
+
#
|
39
|
+
# ## Options
|
40
|
+
#
|
41
|
+
# -B, --browser NAME|PATH The browser name or path to execute
|
42
|
+
# -W, --width WIDTH Sets the width of the browser viewport (Default: 1024)
|
43
|
+
# -H, --height HEIGHT Sets the height of the browser viewport (Default: 768)
|
44
|
+
# --headless Run the browser in headless mode
|
45
|
+
# --visible Open a visible browser
|
46
|
+
# -x, --x INT Sets the position of the browser X coordinate
|
47
|
+
# -y, --y INT Sets the position of the browser Y coordinate
|
48
|
+
# --inject-js JS Injects JavaScript into every page
|
49
|
+
# --inject-js-file FILE Injects a JavaScript file into every page
|
50
|
+
# --bypass-csp Enables bypassing CSP
|
51
|
+
# --print-urls Print all requested URLs
|
52
|
+
# --print-status Print the status of all requested URLs
|
53
|
+
# --print-requests Print all requests sent by the browser
|
54
|
+
# --print-responses Print responses to all requests
|
55
|
+
# --print-traffic Print requests and responses
|
56
|
+
# --print-headers Print headers of requests/responses
|
57
|
+
# --print-body Print request/response bodies
|
58
|
+
# --shell Starts an interactive shell
|
59
|
+
# --js-shell Starts an interactive JavaScript shell
|
60
|
+
# -h, --help Print help information
|
61
|
+
#
|
62
|
+
# ## Arguments
|
63
|
+
#
|
64
|
+
# [URL] The initial URL to visit
|
65
|
+
#
|
66
|
+
# @since 2.0.0
|
67
|
+
#
|
68
|
+
class Browser < Command
|
69
|
+
|
70
|
+
include BrowserOptions
|
71
|
+
include CommandKit::Colors
|
72
|
+
|
73
|
+
usage '[options] [URL]'
|
74
|
+
|
75
|
+
option :headless, desc: 'Run the browser in headless mode' do
|
76
|
+
@mode = :headless
|
77
|
+
end
|
78
|
+
|
79
|
+
option :visible, desc: 'Open a visible browser' do
|
80
|
+
@mode = :visible
|
81
|
+
end
|
82
|
+
|
83
|
+
option :x, short: '-x',
|
84
|
+
value: {
|
85
|
+
type: Integer
|
86
|
+
},
|
87
|
+
desc: "Sets the position of the browser X coordinate"
|
88
|
+
|
89
|
+
option :y, short: '-y',
|
90
|
+
value: {
|
91
|
+
type: Integer
|
92
|
+
},
|
93
|
+
desc: "Sets the position of the browser Y coordinate"
|
94
|
+
|
95
|
+
option :inject_js, value: {
|
96
|
+
type: String,
|
97
|
+
usage: 'JS'
|
98
|
+
},
|
99
|
+
desc: 'Injects JavaScript into every page'
|
100
|
+
|
101
|
+
option :inject_js_file, value: {
|
102
|
+
type: String,
|
103
|
+
usage: 'FILE'
|
104
|
+
},
|
105
|
+
desc: 'Injects a JavaScript file into every page'
|
106
|
+
|
107
|
+
option :bypass_csp, desc: 'Enables bypassing CSP'
|
108
|
+
|
109
|
+
option :print_urls, desc: 'Print all requested URLs'
|
110
|
+
|
111
|
+
option :print_status, desc: 'Print the status of all requested URLs'
|
112
|
+
|
113
|
+
option :print_requests, desc: 'Print all requests sent by the browser'
|
114
|
+
|
115
|
+
option :print_responses, desc: 'Print responses to all requests'
|
116
|
+
|
117
|
+
option :print_traffic, desc: 'Print requests and responses'
|
118
|
+
|
119
|
+
option :print_headers, desc: 'Print headers of requests/responses'
|
120
|
+
|
121
|
+
option :print_cookies, desc: 'Print Set-Cookie headers from all responses'
|
122
|
+
|
123
|
+
option :print_body, desc: 'Print request/response bodies'
|
124
|
+
|
125
|
+
option :shell, desc: 'Starts an interactive shell'
|
126
|
+
|
127
|
+
option :js_shell, desc: 'Starts an interactive JavaScript shell'
|
128
|
+
|
129
|
+
argument :url, required: false,
|
130
|
+
desc: 'The initial URL to visit'
|
131
|
+
|
132
|
+
description "Automates a web browser"
|
133
|
+
|
134
|
+
man_page 'ronin-web-browser.1'
|
135
|
+
|
136
|
+
#
|
137
|
+
# Initializes the `ronin-web browser` command.
|
138
|
+
#
|
139
|
+
# @param [Hash{Symbol => Object}] kwargs
|
140
|
+
# Additional keywords for the command.
|
141
|
+
#
|
142
|
+
def initialize(**kwargs)
|
143
|
+
super(**kwargs)
|
144
|
+
|
145
|
+
@mode = if stdout.tty? then :visible
|
146
|
+
else :headless
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
#
|
151
|
+
# Runs the `ronin-web browser` command.
|
152
|
+
#
|
153
|
+
# @param [String, nil] url
|
154
|
+
# The optional URL to visit.
|
155
|
+
#
|
156
|
+
def run(url=nil)
|
157
|
+
unless (url || options[:shell] || options[:js_shell])
|
158
|
+
print_error "must specify a URL or --shell / --js-shell"
|
159
|
+
exit(-1)
|
160
|
+
end
|
161
|
+
|
162
|
+
configure_browser
|
163
|
+
open_browser(url)
|
164
|
+
|
165
|
+
if options[:shell] || options[:js_shell]
|
166
|
+
start_shell
|
167
|
+
else
|
168
|
+
wait_until_closed
|
169
|
+
end
|
170
|
+
|
171
|
+
close_browser
|
172
|
+
end
|
173
|
+
|
174
|
+
#
|
175
|
+
# Configures the browser and registers callbacks.
|
176
|
+
#
|
177
|
+
def configure_browser
|
178
|
+
if options[:x] || options[:y]
|
179
|
+
browser.position = {
|
180
|
+
left: options.fetch(:x,0),
|
181
|
+
top: options.fetch(:y,0)
|
182
|
+
}
|
183
|
+
end
|
184
|
+
|
185
|
+
browser.bypass_csp = true if options[:bypass_csp]
|
186
|
+
|
187
|
+
if options[:inject_js_file]
|
188
|
+
browser.inject_js(File.read(options[:inject_js_file]))
|
189
|
+
elsif options[:inject_js]
|
190
|
+
browser.inject_js(options[:inject_js])
|
191
|
+
end
|
192
|
+
|
193
|
+
if options[:print_status]
|
194
|
+
browser.every_response(&method(:print_url_status))
|
195
|
+
elsif options[:print_cookies]
|
196
|
+
browser.every_response(&method(:print_cookies))
|
197
|
+
elsif options[:print_urls]
|
198
|
+
browser.every_url(&method(:puts))
|
199
|
+
elsif options[:print_traffic]
|
200
|
+
browser.every_request(&method(:print_request))
|
201
|
+
browser.every_response(&method(:print_response))
|
202
|
+
else
|
203
|
+
browser.every_request(&method(:print_request)) if options[:print_requests]
|
204
|
+
browser.every_response(&method(:print_response)) if options[:print_responses]
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
#
|
209
|
+
# Open the browser window.
|
210
|
+
#
|
211
|
+
# @param [String, nil] url
|
212
|
+
# The optional URL to visit.
|
213
|
+
#
|
214
|
+
def open_browser(url=nil)
|
215
|
+
browser.goto(url) if url
|
216
|
+
end
|
217
|
+
|
218
|
+
#
|
219
|
+
# Starts an interactive browser shell.
|
220
|
+
#
|
221
|
+
def start_shell
|
222
|
+
# start the shell then immediately quit the browser once exited
|
223
|
+
if options[:js_shell]
|
224
|
+
JSShell.start(browser)
|
225
|
+
elsif options[:shell]
|
226
|
+
BrowserShell.start(browser)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
#
|
231
|
+
# Waits until the browser is done or if the user exits the command.
|
232
|
+
#
|
233
|
+
def wait_until_closed
|
234
|
+
if @mode == :visible
|
235
|
+
# wait for the browser window to be closed
|
236
|
+
browser.wait_until_closed
|
237
|
+
else
|
238
|
+
# wait until there's no network traffic
|
239
|
+
browser.network.wait_for_idle { browser.quit }
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
#
|
244
|
+
# Close the browser.
|
245
|
+
#
|
246
|
+
def close_browser
|
247
|
+
browser.quit
|
248
|
+
end
|
249
|
+
|
250
|
+
#
|
251
|
+
# Additional keyword arguments for `Ronin::Web::Browser.new`.
|
252
|
+
#
|
253
|
+
# @return [Hash{Symbol => Object}]
|
254
|
+
#
|
255
|
+
def browser_kwargs
|
256
|
+
kwargs = super()
|
257
|
+
|
258
|
+
case @mode
|
259
|
+
when :headless then kwargs[:headless] = true
|
260
|
+
when :visible then kwargs[:visible] = true
|
261
|
+
end
|
262
|
+
|
263
|
+
return kwargs
|
264
|
+
end
|
265
|
+
|
266
|
+
#
|
267
|
+
# Prints the status and URL of a response.
|
268
|
+
#
|
269
|
+
# @param [Ferrum::Network::Response] response
|
270
|
+
# The respones object.
|
271
|
+
#
|
272
|
+
def print_url_status(response)
|
273
|
+
if response.status < 300
|
274
|
+
puts "#{colors.bright_green(response.status)} #{colors.green(response.url)}"
|
275
|
+
elsif response.status < 400
|
276
|
+
puts "#{colors.bright_yellow(response.status)} #{colors.yellow(response.url)}"
|
277
|
+
elsif response.status < 500
|
278
|
+
puts "#{colors.bright_red(response.status)} #{colors.red(response.url)}"
|
279
|
+
else
|
280
|
+
puts "#{colors.bold(colors.bright_red(response.status))} #{colors.bold(colors.red(response.url))}"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
#
|
285
|
+
# Prints a request from the browser.
|
286
|
+
#
|
287
|
+
# @param [Ferrum::Network::InterceptedRequest] request
|
288
|
+
#
|
289
|
+
def print_request(request)
|
290
|
+
sigil = colors.bold(colors.bright_white('>'))
|
291
|
+
|
292
|
+
puts "#{sigil} #{colors.bold(colors.bright_cyan(request.method))} #{colors.cyan(request.url)}"
|
293
|
+
|
294
|
+
if options[:print_headers]
|
295
|
+
print_headers(sigil,request.headers)
|
296
|
+
end
|
297
|
+
|
298
|
+
if options[:print_body] && (body = request.body)
|
299
|
+
print_body(sigil,body)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
#
|
304
|
+
# Prints a response.
|
305
|
+
#
|
306
|
+
# @param [Ferrum::Network::Response] response
|
307
|
+
# The respones object.
|
308
|
+
#
|
309
|
+
def print_response(response)
|
310
|
+
sigil = colors.bold(colors.bright_white('<'))
|
311
|
+
|
312
|
+
print "#{sigil} "
|
313
|
+
print_url_status(response)
|
314
|
+
|
315
|
+
if options[:print_headers]
|
316
|
+
print_headers(sigil,response.headers)
|
317
|
+
end
|
318
|
+
|
319
|
+
if options[:print_body]
|
320
|
+
print_body(sigil,response.body)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
#
|
325
|
+
# Prints headers.
|
326
|
+
#
|
327
|
+
# @param [String] sigil
|
328
|
+
# The "sigil" representing either a request (`>`) or
|
329
|
+
# a response (`<`).
|
330
|
+
#
|
331
|
+
# @param [Hash{String => String}] headers
|
332
|
+
# The header names and values.
|
333
|
+
#
|
334
|
+
def print_headers(sigil,headers)
|
335
|
+
headers.each do |name,value|
|
336
|
+
puts "#{sigil} #{colors.bright_white(name)}: #{value}"
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
#
|
341
|
+
# Prints the request or response body.
|
342
|
+
#
|
343
|
+
# @param [String] sigil
|
344
|
+
# The "sigil" representing either a request (`>`) or
|
345
|
+
# a response (`<`).
|
346
|
+
#
|
347
|
+
# @param [String] body
|
348
|
+
# the request or response body.
|
349
|
+
#
|
350
|
+
def print_body(sigil,body)
|
351
|
+
puts sigil
|
352
|
+
response.body.each_line do |line|
|
353
|
+
puts "#{sigil} #{line}"
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
#
|
358
|
+
# Prints the `Set-Cookie` header for each HTTP response.
|
359
|
+
#
|
360
|
+
# @param [Ferrum::Network::Response] response
|
361
|
+
# A response from the browser.
|
362
|
+
#
|
363
|
+
def print_cookies(response)
|
364
|
+
if (set_cookie = respones.headers['set-cookie'])
|
365
|
+
puts set_cookie
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-web - A collection of useful web helper methods and commands.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-web is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-web is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with ronin-web. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/web/root'
|
22
|
+
require 'ronin/core/cli/completion_command'
|
23
|
+
|
24
|
+
module Ronin
|
25
|
+
module Web
|
26
|
+
class CLI
|
27
|
+
module Commands
|
28
|
+
#
|
29
|
+
# Manages the shell completion rules for `ronin-web`.
|
30
|
+
#
|
31
|
+
# ## Usage
|
32
|
+
#
|
33
|
+
# ronin-web completion [options]
|
34
|
+
#
|
35
|
+
# ## Options
|
36
|
+
#
|
37
|
+
# --print Prints the shell completion file
|
38
|
+
# --install Installs the shell completion file
|
39
|
+
# --uninstall Uninstalls the shell completion file
|
40
|
+
# -h, --help Print help information
|
41
|
+
#
|
42
|
+
# ## Examples
|
43
|
+
#
|
44
|
+
# ronin-web completion --print
|
45
|
+
# ronin-web completion --install
|
46
|
+
# ronin-web completion --uninstall
|
47
|
+
#
|
48
|
+
# @since 2.0.0
|
49
|
+
#
|
50
|
+
class Completion < Core::CLI::CompletionCommand
|
51
|
+
|
52
|
+
completion_file File.join(ROOT,'data','completions','ronin-web')
|
53
|
+
|
54
|
+
man_dir File.join(ROOT,'man')
|
55
|
+
man_page 'ronin-web-completion.1'
|
56
|
+
|
57
|
+
description 'Manages the shell completion rules for ronin-web'
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-web - A collection of useful web helper methods and commands.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2006-
|
5
|
+
# Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-web is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU General Public License as published by
|
@@ -21,7 +21,7 @@
|
|
21
21
|
require 'ronin/web/cli/command'
|
22
22
|
require 'ronin/support/network/http'
|
23
23
|
|
24
|
-
require 'command_kit/
|
24
|
+
require 'command_kit/colors'
|
25
25
|
require 'nokogiri/diff'
|
26
26
|
|
27
27
|
module Ronin
|
@@ -43,10 +43,11 @@ module Ronin
|
|
43
43
|
# ## Options
|
44
44
|
#
|
45
45
|
# -h, --help Print help information
|
46
|
+
# -f, --format Pass the format of the URL or files. Supported formats are html and xml. (Default: html)
|
46
47
|
#
|
47
48
|
class Diff < Command
|
48
49
|
|
49
|
-
include CommandKit::
|
50
|
+
include CommandKit::Colors
|
50
51
|
|
51
52
|
usage '[options] {URL | FILE} {URL | FILE}'
|
52
53
|
|
@@ -58,7 +59,14 @@ module Ronin
|
|
58
59
|
usage: 'URL | FILE',
|
59
60
|
desc: 'The modified URL or file'
|
60
61
|
|
61
|
-
|
62
|
+
option :format, short: '-f',
|
63
|
+
value: {
|
64
|
+
type: [:html, :xml],
|
65
|
+
default: :html
|
66
|
+
},
|
67
|
+
desc: 'The format of the web pages'
|
68
|
+
|
69
|
+
description 'Diffs two web pages'
|
62
70
|
|
63
71
|
man_page 'ronin-web-diff.1'
|
64
72
|
|
@@ -72,16 +80,41 @@ module Ronin
|
|
72
80
|
# The URL or file path of the modified page.
|
73
81
|
#
|
74
82
|
def run(page1,page2)
|
75
|
-
doc1 =
|
76
|
-
doc2 =
|
83
|
+
doc1 = parse_doc(page1)
|
84
|
+
doc2 = parse_doc(page2)
|
77
85
|
|
78
86
|
doc1.diff(doc2) do |change,node|
|
79
|
-
unless change == ' '
|
80
|
-
|
87
|
+
unless change == ' ' # ignroe unchanged nodes
|
88
|
+
print_change(change,node)
|
81
89
|
end
|
82
90
|
end
|
83
91
|
end
|
84
92
|
|
93
|
+
#
|
94
|
+
# Prints a change to the document.
|
95
|
+
#
|
96
|
+
# @param ["+", "-"] change
|
97
|
+
# The type of change.
|
98
|
+
#
|
99
|
+
# * `+` - indicates an added node.
|
100
|
+
# * `-` - indicates a removed node.
|
101
|
+
#
|
102
|
+
# @param [Nokogiri::HTML::Node, Nokogiri::HTML::Node] node
|
103
|
+
# The node that was changed.
|
104
|
+
#
|
105
|
+
def print_change(change,node)
|
106
|
+
color = case change
|
107
|
+
when '+' then colors.method(:green)
|
108
|
+
when '-' then colors.method(:red)
|
109
|
+
end
|
110
|
+
|
111
|
+
content = node.to_s
|
112
|
+
|
113
|
+
content.each_line(chomp: true) do |line|
|
114
|
+
puts color.call("#{change} #{line}")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
85
118
|
#
|
86
119
|
# Reads a web page.
|
87
120
|
#
|
@@ -100,6 +133,25 @@ module Ronin
|
|
100
133
|
end
|
101
134
|
end
|
102
135
|
|
136
|
+
#
|
137
|
+
# Loads the given html or xml sources
|
138
|
+
#
|
139
|
+
# @param [String] page
|
140
|
+
# The URL or file path of the original page.
|
141
|
+
#
|
142
|
+
# @return [Nokogiri::HTML::Document, Nokogiri::XML::Document]
|
143
|
+
# html or xml document depends upon --format option
|
144
|
+
#
|
145
|
+
def parse_doc(page)
|
146
|
+
case options[:format]
|
147
|
+
when :html
|
148
|
+
Nokogiri::HTML(read(page))
|
149
|
+
when :xml
|
150
|
+
Nokogiri::XML(read(page))
|
151
|
+
else
|
152
|
+
raise(NotImplementedError,"unsupported format: #{options[:format].inspect}")
|
153
|
+
end
|
154
|
+
end
|
103
155
|
end
|
104
156
|
end
|
105
157
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-web - A collection of useful web helper methods and commands.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2006-
|
5
|
+
# Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-web is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU General Public License as published by
|
@@ -18,7 +18,7 @@
|
|
18
18
|
# along with ronin-web. If not, see <https://www.gnu.org/licenses/>.
|
19
19
|
#
|
20
20
|
|
21
|
-
require 'ronin/web/cli/
|
21
|
+
require 'ronin/web/cli/commands/xml'
|
22
22
|
require 'ronin/support/network/http'
|
23
23
|
|
24
24
|
require 'nokogiri'
|
@@ -38,6 +38,7 @@ module Ronin
|
|
38
38
|
#
|
39
39
|
# -X, --xpath XPATH XPath query
|
40
40
|
# -C, --css-path CSSPath CSS-path query
|
41
|
+
# -t, --text Prints the inner-text
|
41
42
|
# -M, --meta-tags Searches for all <meta ...> tags
|
42
43
|
# -l, --links Searches for all <a href="..."> URLs
|
43
44
|
# -S, --style Dumps all <style> tags
|
@@ -54,18 +55,15 @@ module Ronin
|
|
54
55
|
# URL | FILE The URL or FILE to search
|
55
56
|
# [XPATH | CSS-path] The XPath or CSS-path query
|
56
57
|
#
|
57
|
-
class Html <
|
58
|
+
class Html < Xml
|
58
59
|
|
59
60
|
usage '[options] {URL | FILE} [XPATH | CSS-path]'
|
60
61
|
|
61
|
-
option :xpath, short: '-X',
|
62
|
-
value: {type: String, usage: 'XPATH'},
|
63
|
-
desc: 'XPath query' do |xpath|
|
64
|
-
@query = xpath
|
65
|
-
end
|
66
|
-
|
67
62
|
option :css_path, short: '-C',
|
68
|
-
value: {
|
63
|
+
value: {
|
64
|
+
type: String,
|
65
|
+
usage: 'CSSPath'
|
66
|
+
},
|
69
67
|
desc: 'CSS-path query' do |css_path|
|
70
68
|
@query = css_path
|
71
69
|
end
|
@@ -110,9 +108,6 @@ module Ronin
|
|
110
108
|
@query = '//a/@href | //link/@href | //script/@src | //form/@action'
|
111
109
|
end
|
112
110
|
|
113
|
-
option :first, short: '-F',
|
114
|
-
desc: 'Only print the first match'
|
115
|
-
|
116
111
|
argument :source, required: true,
|
117
112
|
usage: 'URL | FILE',
|
118
113
|
desc: 'The URL or FILE to search'
|
@@ -125,6 +120,11 @@ module Ronin
|
|
125
120
|
|
126
121
|
man_page 'ronin-web-html.1'
|
127
122
|
|
123
|
+
# The XPath or CSS-path query.
|
124
|
+
#
|
125
|
+
# @return [String, nil]
|
126
|
+
attr_reader :query
|
127
|
+
|
128
128
|
#
|
129
129
|
# Runs the `ronin-web xpath` command.
|
130
130
|
#
|
@@ -140,32 +140,20 @@ module Ronin
|
|
140
140
|
exit(-1)
|
141
141
|
end
|
142
142
|
|
143
|
-
|
144
|
-
nodes = if options[:first] then [doc.at(query)]
|
145
|
-
else doc.search(query)
|
146
|
-
end
|
147
|
-
|
148
|
-
nodes.each do |node|
|
149
|
-
puts node
|
150
|
-
end
|
143
|
+
super(source,query)
|
151
144
|
end
|
152
145
|
|
153
146
|
#
|
154
|
-
#
|
147
|
+
# Parses the HTML source code.
|
155
148
|
#
|
156
|
-
# @param [String]
|
157
|
-
# The
|
149
|
+
# @param [String] html
|
150
|
+
# The raw unparsed HTML.
|
158
151
|
#
|
159
|
-
# @return [
|
160
|
-
# The
|
152
|
+
# @return [Nokogiri::HTML::Document]
|
153
|
+
# The parsed HTML document.
|
161
154
|
#
|
162
|
-
def
|
163
|
-
|
164
|
-
source.start_with?('http://')
|
165
|
-
Support::Network::HTTP.get_body(source)
|
166
|
-
else
|
167
|
-
File.new(source)
|
168
|
-
end
|
155
|
+
def parse(html)
|
156
|
+
Nokogiri::HTML(html)
|
169
157
|
end
|
170
158
|
|
171
159
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# ronin-web - A collection of useful web helper methods and commands.
|
4
4
|
#
|
5
|
-
# Copyright (c) 2006-
|
5
|
+
# Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
6
|
#
|
7
7
|
# ronin-web is free software: you can redistribute it and/or modify
|
8
8
|
# it under the terms of the GNU General Public License as published by
|