pwn 0.5.493 → 0.5.495
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/.rubocop.yml +3 -3
- data/Gemfile +7 -7
- data/README.md +3 -3
- data/lib/pwn/ai/introspection.rb +7 -4
- data/lib/pwn/ai/open_ai.rb +4 -8
- data/lib/pwn/config.rb +1 -0
- data/lib/pwn/plugins/burp_suite.rb +62 -29
- data/lib/pwn/plugins/transparent_browser.rb +226 -117
- data/lib/pwn/version.rb +1 -1
- data/lib/pwn/www/hacker_one.rb +29 -0
- metadata +15 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 60c64fa5b4751ee72882a87e666c22ca826bb94bab63f0dca925a92520241afd
|
|
4
|
+
data.tar.gz: 6ddf3436eca29081e4d53f81183555d80daaf847ebab4b9f6174114372bcde63
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 25a82f578e16c23fbf958e353381c39f0ec9126a6d254c51849620b42d68012024f987cacbbf79790889bd282936f13c8ae8fba060b39b3bd2738e44270f76f7
|
|
7
|
+
data.tar.gz: 378c9b00d02d832aa820c4cf53cb09c01949d3a1ff2e7f4fd2d6e17833d84266d9a6be6a1fb5f2e792335a90b21ae88e42c574f2fb152d8b0bf74b56ab672112
|
data/.rubocop.yml
CHANGED
|
@@ -14,13 +14,13 @@ Metrics/BlockNesting:
|
|
|
14
14
|
Metrics/ClassLength:
|
|
15
15
|
Max: 134
|
|
16
16
|
Metrics/CyclomaticComplexity:
|
|
17
|
-
Max:
|
|
17
|
+
Max: 158
|
|
18
18
|
Metrics/MethodLength:
|
|
19
19
|
Max: 565
|
|
20
20
|
Metrics/ModuleLength:
|
|
21
|
-
Max:
|
|
21
|
+
Max: 1133
|
|
22
22
|
Metrics/PerceivedComplexity:
|
|
23
|
-
Max:
|
|
23
|
+
Max: 157
|
|
24
24
|
Style/HashEachMethods:
|
|
25
25
|
Enabled: true
|
|
26
26
|
Style/HashSyntax:
|
data/Gemfile
CHANGED
|
@@ -11,14 +11,14 @@ gemspec
|
|
|
11
11
|
# In some circumstances custom flags are passed to gems in order
|
|
12
12
|
# to build appropriately. Defer to ./reinstall_pwn_gemset.sh
|
|
13
13
|
# to review these custom flags (e.g. pg, serialport, etc).
|
|
14
|
-
gem 'activesupport', '<8.1.
|
|
14
|
+
gem 'activesupport', '<8.1.1'
|
|
15
15
|
gem 'anemone', '0.7.2'
|
|
16
16
|
gem 'authy', '3.0.1'
|
|
17
17
|
gem 'aws-sdk', '3.3.0'
|
|
18
18
|
gem 'barby', '0.7.0'
|
|
19
19
|
gem 'base32', '0.3.4'
|
|
20
20
|
gem 'bitcoin-ruby', '0.0.20'
|
|
21
|
-
gem 'brakeman', '7.1.
|
|
21
|
+
gem 'brakeman', '7.1.1'
|
|
22
22
|
gem 'bson', '5.2.0'
|
|
23
23
|
gem 'bundler', '>=2.7.2'
|
|
24
24
|
gem 'bundler-audit', '0.9.2'
|
|
@@ -70,17 +70,17 @@ gem 'pdf-reader', '2.15.0'
|
|
|
70
70
|
gem 'pg', '1.6.2'
|
|
71
71
|
gem 'pry', '0.15.2'
|
|
72
72
|
gem 'pry-doc', '1.6.0'
|
|
73
|
-
gem 'rake', '13.3.
|
|
73
|
+
gem 'rake', '13.3.1'
|
|
74
74
|
gem 'rb-readline', '0.5.5'
|
|
75
75
|
gem 'rbvmomi2', '3.8.0'
|
|
76
|
-
gem 'rdoc', '6.15.
|
|
76
|
+
gem 'rdoc', '6.15.1'
|
|
77
77
|
gem 'rest-client', '2.1.0'
|
|
78
78
|
gem 'rex', '2.0.13'
|
|
79
79
|
gem 'rmagick', '6.1.4'
|
|
80
80
|
gem 'rqrcode', '3.1.0'
|
|
81
81
|
gem 'rspec', '3.13.2'
|
|
82
82
|
gem 'rtesseract', '3.1.4'
|
|
83
|
-
gem 'rubocop', '1.81.
|
|
83
|
+
gem 'rubocop', '1.81.7'
|
|
84
84
|
gem 'rubocop-rake', '0.7.1'
|
|
85
85
|
gem 'rubocop-rspec', '3.7.0'
|
|
86
86
|
gem 'ruby-audio', '1.6.1'
|
|
@@ -88,8 +88,8 @@ gem 'ruby-nmap', '1.0.3'
|
|
|
88
88
|
gem 'ruby-saml', '1.18.1'
|
|
89
89
|
gem 'rvm', '1.11.3.9'
|
|
90
90
|
gem 'savon', '2.15.1'
|
|
91
|
-
gem 'selenium-devtools', '0.
|
|
92
|
-
gem 'selenium-webdriver', '4.
|
|
91
|
+
gem 'selenium-devtools', '0.142.0'
|
|
92
|
+
gem 'selenium-webdriver', '4.38.0'
|
|
93
93
|
gem 'slack-ruby-client', '3.0.0'
|
|
94
94
|
gem 'socksify', '1.8.1'
|
|
95
95
|
gem 'spreadsheet', '1.3.4'
|
data/README.md
CHANGED
|
@@ -37,7 +37,7 @@ $ cd /opt/pwn
|
|
|
37
37
|
$ ./install.sh
|
|
38
38
|
$ ./install.sh ruby-gem
|
|
39
39
|
$ pwn
|
|
40
|
-
pwn[v0.5.
|
|
40
|
+
pwn[v0.5.495]:001 >>> PWN.help
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
[](https://youtu.be/G7iLUY4FzsI)
|
|
@@ -52,7 +52,7 @@ $ rvm use ruby-3.4.4@pwn
|
|
|
52
52
|
$ gem uninstall --all --executables pwn
|
|
53
53
|
$ gem install --verbose pwn
|
|
54
54
|
$ pwn
|
|
55
|
-
pwn[v0.5.
|
|
55
|
+
pwn[v0.5.495]:001 >>> PWN.help
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
If you're using a multi-user install of RVM do:
|
|
@@ -62,7 +62,7 @@ $ rvm use ruby-3.4.4@pwn
|
|
|
62
62
|
$ rvmsudo gem uninstall --all --executables pwn
|
|
63
63
|
$ rvmsudo gem install --verbose pwn
|
|
64
64
|
$ pwn
|
|
65
|
-
pwn[v0.5.
|
|
65
|
+
pwn[v0.5.495]:001 >>> PWN.help
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
PWN periodically upgrades to the latest version of Ruby which is reflected in `/opt/pwn/.ruby-version`. The easiest way to upgrade to the latest version of Ruby from a previous PWN installation is to run the following script:
|
data/lib/pwn/ai/introspection.rb
CHANGED
|
@@ -11,7 +11,8 @@ module PWN
|
|
|
11
11
|
# Supported Method Parameters::
|
|
12
12
|
# response = PWN::AI::Introspection.reflect_on(
|
|
13
13
|
# request: 'required - String - What you want the AI to reflect on',
|
|
14
|
-
# system_role_content: 'optional - context to set up the model behavior for reflection'
|
|
14
|
+
# system_role_content: 'optional - context to set up the model behavior for reflection',
|
|
15
|
+
# spinner: 'optional - Boolean - Display spinner during operation (default: false)'
|
|
15
16
|
# )
|
|
16
17
|
|
|
17
18
|
public_class_method def self.reflect_on(opts = {})
|
|
@@ -20,6 +21,8 @@ module PWN
|
|
|
20
21
|
|
|
21
22
|
system_role_content = opts[:system_role_content]
|
|
22
23
|
|
|
24
|
+
spinner = opts[:spinner] || false
|
|
25
|
+
|
|
23
26
|
response = nil
|
|
24
27
|
|
|
25
28
|
ai_introspection = PWN::Env[:ai][:introspection]
|
|
@@ -34,7 +37,7 @@ module PWN
|
|
|
34
37
|
response = PWN::AI::Grok.chat(
|
|
35
38
|
request: request.chomp,
|
|
36
39
|
system_role_content: system_role_content,
|
|
37
|
-
spinner:
|
|
40
|
+
spinner: spinner
|
|
38
41
|
)
|
|
39
42
|
response = response[:choices].last[:content] if response.is_a?(Hash) &&
|
|
40
43
|
response.key?(:choices) &&
|
|
@@ -43,7 +46,7 @@ module PWN
|
|
|
43
46
|
response = PWN::AI::Ollama.chat(
|
|
44
47
|
request: request.chomp,
|
|
45
48
|
system_role_content: system_role_content,
|
|
46
|
-
spinner:
|
|
49
|
+
spinner: spinner
|
|
47
50
|
)
|
|
48
51
|
response = response[:choices].last[:content] if response.is_a?(Hash) &&
|
|
49
52
|
response.key?(:choices) &&
|
|
@@ -52,7 +55,7 @@ module PWN
|
|
|
52
55
|
response = PWN::AI::OpenAI.chat(
|
|
53
56
|
request: request.chomp,
|
|
54
57
|
system_role_content: system_role_content,
|
|
55
|
-
spinner:
|
|
58
|
+
spinner: spinner
|
|
56
59
|
)
|
|
57
60
|
if response.is_a?(Hash) && response.key?(:choices)
|
|
58
61
|
response = response[:choices].last[:text] if response[:choices].last.keys.include?(:text)
|
data/lib/pwn/ai/open_ai.rb
CHANGED
|
@@ -158,16 +158,12 @@ module PWN
|
|
|
158
158
|
case model
|
|
159
159
|
when 'gpt-3.5-turbo', 'gpt-3.5-turbo-0125', 'gpt-3.5-turbo-1106', 'gpt-3.5-turbo-instruct',
|
|
160
160
|
'gpt-4-turbo', 'gpt-4-turbo-2024-04-09', 'gpt-4-turbo-preview', 'gpt-4-0125-preview', 'gpt-4-1106-preview'
|
|
161
|
-
max_completion_tokens = 4_096
|
|
161
|
+
max_completion_tokens = 4_096
|
|
162
162
|
when 'gpt-4', 'gpt-4-0613', 'gpt-4-0314',
|
|
163
163
|
'gpt-4o', 'gpt-4o-2024-05-13'
|
|
164
|
-
max_completion_tokens = 8_192
|
|
165
|
-
|
|
166
|
-
max_completion_tokens = 16_384
|
|
167
|
-
when 'o1-preview', 'o1-preview-2024-09-12'
|
|
168
|
-
max_completion_tokens = 32_768 - (request.to_s.length / 4)
|
|
169
|
-
when 'o1-mini', 'o1-mini-2024-09-12'
|
|
170
|
-
max_completion_tokens = 65_536 - (request.to_s.length / 4)
|
|
164
|
+
max_completion_tokens = 8_192
|
|
165
|
+
else
|
|
166
|
+
max_completion_tokens = 16_384
|
|
171
167
|
end
|
|
172
168
|
|
|
173
169
|
response_history = opts[:response_history]
|
data/lib/pwn/config.rb
CHANGED
|
@@ -108,12 +108,20 @@ module PWN
|
|
|
108
108
|
next
|
|
109
109
|
end
|
|
110
110
|
|
|
111
|
-
#
|
|
112
|
-
|
|
111
|
+
# Delete existing proxy listener and add new one
|
|
112
|
+
# in favor of weird update behavior in event the port is alread in use
|
|
113
|
+
# by another application which refuses to enable the listener even when
|
|
114
|
+
# the port is changed via the update method.
|
|
115
|
+
delete_proxy_listener(
|
|
113
116
|
burp_obj: burp_obj,
|
|
114
|
-
id:
|
|
115
|
-
|
|
116
|
-
|
|
117
|
+
id: 0
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
add_proxy_listener(
|
|
121
|
+
burp_obj: burp_obj,
|
|
122
|
+
bindAddress: burp_ip,
|
|
123
|
+
port: burp_port,
|
|
124
|
+
enabled: true
|
|
117
125
|
)
|
|
118
126
|
|
|
119
127
|
burp_obj
|
|
@@ -270,7 +278,7 @@ module PWN
|
|
|
270
278
|
# Supported Method Parameters::
|
|
271
279
|
# json_proxy_listener = PWN::Plugins::BurpSuite.add_proxy_listener(
|
|
272
280
|
# burp_obj: 'required - burp_obj returned by #start method',
|
|
273
|
-
#
|
|
281
|
+
# bindAddress: 'required - bind address for the proxy listener (e.g., "127.0.0.1")',
|
|
274
282
|
# port: 'required - port for the proxy listener (e.g., 8081)',
|
|
275
283
|
# enabled: 'optional - enable the listener (defaults to true)'
|
|
276
284
|
# )
|
|
@@ -279,8 +287,8 @@ module PWN
|
|
|
279
287
|
burp_obj = opts[:burp_obj]
|
|
280
288
|
rest_browser = burp_obj[:rest_browser]
|
|
281
289
|
mitm_rest_api = burp_obj[:mitm_rest_api]
|
|
282
|
-
bind_address = opts[:
|
|
283
|
-
raise 'ERROR:
|
|
290
|
+
bind_address = opts[:bindAddress]
|
|
291
|
+
raise 'ERROR: bindAddress parameter is required' if bind_address.nil?
|
|
284
292
|
|
|
285
293
|
port = opts[:port]
|
|
286
294
|
raise 'ERROR: port parameter is required' if port.nil?
|
|
@@ -288,12 +296,14 @@ module PWN
|
|
|
288
296
|
enabled = opts[:enabled] != false # Default to true if not specified
|
|
289
297
|
|
|
290
298
|
proxy_listeners = get_proxy_listeners(burp_obj: burp_obj)
|
|
291
|
-
|
|
299
|
+
puts "Proxy Listeners: #{proxy_listeners.inspect}"
|
|
300
|
+
last_known_proxy_id = 0
|
|
301
|
+
last_known_proxy_id = proxy_listeners.last[:id].to_i if proxy_listeners.any?
|
|
292
302
|
next_id = last_known_proxy_id + 1
|
|
293
303
|
|
|
294
304
|
post_body = {
|
|
295
305
|
id: next_id.to_s,
|
|
296
|
-
|
|
306
|
+
bindAddress: bind_address,
|
|
297
307
|
port: port,
|
|
298
308
|
enabled: enabled
|
|
299
309
|
}.to_json
|
|
@@ -308,24 +318,29 @@ module PWN
|
|
|
308
318
|
# Supported Method Parameters::
|
|
309
319
|
# json_proxy_listener = PWN::Plugins::BurpSuite.update_proxy_listener(
|
|
310
320
|
# burp_obj: 'required - burp_obj returned by #start method',
|
|
311
|
-
# id: 'optional - ID of the proxy listener (defaults to
|
|
312
|
-
#
|
|
313
|
-
# port: 'optional - port for the proxy listener (defaults to
|
|
314
|
-
# enabled: 'optional - enable or disable the listener (defaults to
|
|
321
|
+
# id: 'optional - ID of the proxy listener (defaults to 0)',
|
|
322
|
+
# bindAddress: 'optional - bind address for the proxy listener (defaults to value of existing listener)',
|
|
323
|
+
# port: 'optional - port for the proxy listener (defaults to value of existing listener)',
|
|
324
|
+
# enabled: 'optional - enable or disable the listener (defaults to value of existing listener)'
|
|
315
325
|
# )
|
|
316
326
|
|
|
317
327
|
public_class_method def self.update_proxy_listener(opts = {})
|
|
318
328
|
burp_obj = opts[:burp_obj]
|
|
319
329
|
rest_browser = burp_obj[:rest_browser]
|
|
320
330
|
mitm_rest_api = burp_obj[:mitm_rest_api]
|
|
321
|
-
id = opts[:id] ||=
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
331
|
+
id = opts[:id] ||= 0
|
|
332
|
+
|
|
333
|
+
proxy_listeners = get_proxy_listeners(burp_obj: burp_obj)
|
|
334
|
+
listener_by_id = proxy_listeners.find { |listener| listener[:id].to_i == id.to_i }
|
|
335
|
+
raise "ERROR: No proxy listener found with ID #{id}" if listener_by_id.nil?
|
|
336
|
+
|
|
337
|
+
bind_address = opts[:bindAddress] ||= listener_by_id[:bindAddress]
|
|
338
|
+
port = opts[:port] ||= listener_by_id[:port]
|
|
339
|
+
enabled = opts[:enabled] ||= listener_by_id[:enabled]
|
|
325
340
|
|
|
326
341
|
post_body = {
|
|
327
|
-
id: id,
|
|
328
|
-
|
|
342
|
+
id: id.to_s,
|
|
343
|
+
bindAddress: bind_address,
|
|
329
344
|
port: port,
|
|
330
345
|
enabled: enabled
|
|
331
346
|
}.to_json
|
|
@@ -340,15 +355,17 @@ module PWN
|
|
|
340
355
|
# Supported Method Parameters::
|
|
341
356
|
# PWN::Plugins::BurpSuite.delete_proxy_listener(
|
|
342
357
|
# burp_obj: 'required - burp_obj returned by #start method',
|
|
343
|
-
# id: '
|
|
358
|
+
# id: 'optional - ID of the proxy listener (defaults to 0)'
|
|
344
359
|
# )
|
|
345
360
|
|
|
346
361
|
public_class_method def self.delete_proxy_listener(opts = {})
|
|
347
362
|
burp_obj = opts[:burp_obj]
|
|
348
363
|
rest_browser = burp_obj[:rest_browser]
|
|
349
364
|
mitm_rest_api = burp_obj[:mitm_rest_api]
|
|
350
|
-
id = opts[:id] ||=
|
|
351
|
-
|
|
365
|
+
id = opts[:id] ||= 0
|
|
366
|
+
proxy_listeners = get_proxy_listeners(burp_obj: burp_obj)
|
|
367
|
+
listener_by_id = proxy_listeners.find { |listener| listener[:id].to_i == id.to_i }
|
|
368
|
+
raise "ERROR: No proxy listener found with ID #{id}" if listener_by_id.nil?
|
|
352
369
|
|
|
353
370
|
rest_browser.delete("http://#{mitm_rest_api}/proxy/listeners/#{id}")
|
|
354
371
|
true # Return true to indicate successful deletion (or error if API fails)
|
|
@@ -567,6 +584,22 @@ module PWN
|
|
|
567
584
|
sitemap = opts[:sitemap] ||= {}
|
|
568
585
|
debug = opts[:debug] || false
|
|
569
586
|
|
|
587
|
+
decoded_sitemap = {
|
|
588
|
+
request: Base64.strict_decode64(sitemap[:request]),
|
|
589
|
+
http_service: {
|
|
590
|
+
host: sitemap[:http_service][:host],
|
|
591
|
+
port: sitemap[:http_service][:port],
|
|
592
|
+
protocol: sitemap[:http_service][:protocol]
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
system_role_content = 'Your sole purpose is to analyze each `protocol`, `host`, `port`, and `request` and generate an Exploit Prediction Scoring System (EPSS) score from 0%-100%. Just generate a score unless the score is >= 75% in which a PoC should also be generated to communicate the threat. You can always generate an score - provide the score at _the beggining of your analysis_. Be concise and to the point.'
|
|
596
|
+
ai_analysis = PWN::AI::Introspection.reflect_on(
|
|
597
|
+
system_role_content: system_role_content,
|
|
598
|
+
request: decoded_sitemap.to_json,
|
|
599
|
+
spinner: true
|
|
600
|
+
)
|
|
601
|
+
sitemap[:comment] = ai_analysis unless ai_analysis.nil?
|
|
602
|
+
|
|
570
603
|
rest_client = rest_browser::Request
|
|
571
604
|
response = rest_client.execute(
|
|
572
605
|
method: :post,
|
|
@@ -1484,22 +1517,22 @@ module PWN
|
|
|
1484
1517
|
|
|
1485
1518
|
json_proxy_listener = #{self}.add_proxy_listener(
|
|
1486
1519
|
burp_obj: 'required - burp_obj returned by #start method',
|
|
1487
|
-
|
|
1520
|
+
bindAddress: 'required - bind address for the proxy listener (e.g., \"127.0.0.1\")',
|
|
1488
1521
|
port: 'required - port for the proxy listener (e.g., 8081)',
|
|
1489
1522
|
enabled: 'optional - enable the listener (defaults to true)'
|
|
1490
1523
|
)
|
|
1491
1524
|
|
|
1492
1525
|
json_proxy_listener = #{self}.update_proxy_listener(
|
|
1493
1526
|
burp_obj: 'required - burp_obj returned by #start method',
|
|
1494
|
-
id: 'optional - ID of the proxy listener (defaults to
|
|
1495
|
-
|
|
1496
|
-
port: '
|
|
1497
|
-
enabled: 'optional - enable the listener (defaults to
|
|
1527
|
+
id: 'optional - ID of the proxy listener (defaults to 0)',
|
|
1528
|
+
bindAddress: 'optional - bind address for the proxy listener (defaults to value of existing listener)',
|
|
1529
|
+
port: 'optional - port for the proxy listener (defaults to value of existing listener)',
|
|
1530
|
+
enabled: 'optional - enable the listener (defaults to value of existing listener)'
|
|
1498
1531
|
)
|
|
1499
1532
|
|
|
1500
1533
|
#{self}.delete_proxy_listener(
|
|
1501
1534
|
burp_obj: 'required - burp_obj returned by #start method',
|
|
1502
|
-
id: '
|
|
1535
|
+
id: 'optional - ID of the proxy listener (defaults to 0)'
|
|
1503
1536
|
)
|
|
1504
1537
|
|
|
1505
1538
|
json_sitemap = #{self}.get_sitemap(
|
|
@@ -190,11 +190,6 @@ module PWN
|
|
|
190
190
|
args.push("--proxy-server=#{proxy}")
|
|
191
191
|
end
|
|
192
192
|
|
|
193
|
-
if devtools
|
|
194
|
-
args.push('--auto-open-devtools-for-tabs')
|
|
195
|
-
args.push('--disable-hang-monitor')
|
|
196
|
-
end
|
|
197
|
-
|
|
198
193
|
# Incognito browsing mode
|
|
199
194
|
args.push('--incognito')
|
|
200
195
|
options = Selenium::WebDriver::Chrome::Options.new(
|
|
@@ -202,6 +197,13 @@ module PWN
|
|
|
202
197
|
accept_insecure_certs: true
|
|
203
198
|
)
|
|
204
199
|
|
|
200
|
+
if devtools
|
|
201
|
+
args.push('--auto-open-devtools-for-tabs')
|
|
202
|
+
args.push('--disable-hang-monitor')
|
|
203
|
+
options.add_preference('devtools.preferences.enable-ignore-listing', false)
|
|
204
|
+
options.add_preference('devtools.preferences.default-indentation', '2 spaces')
|
|
205
|
+
end
|
|
206
|
+
|
|
205
207
|
# This is required for BiDi support
|
|
206
208
|
options.web_socket_url = true
|
|
207
209
|
options.add_preference('remote.active-protocols', 3)
|
|
@@ -1148,52 +1150,150 @@ module PWN
|
|
|
1148
1150
|
raise 'ERROR: action parameter must be :enable|:pause|:resume|:disable' unless valid_actions.include?(action)
|
|
1149
1151
|
|
|
1150
1152
|
devtools = browser_obj[:devtools]
|
|
1151
|
-
debugger_state = devtools.instance_variable_get(:@debugger_state)
|
|
1153
|
+
debugger_state = devtools.instance_variable_get(:@debugger_state) || {}
|
|
1154
|
+
breakpoint_arr = debugger_state[:breakpoints] || []
|
|
1152
1155
|
|
|
1156
|
+
method = nil
|
|
1153
1157
|
case action
|
|
1154
1158
|
when :enable
|
|
1155
|
-
|
|
1156
|
-
debugger_state = devtools.instance_variable_get(:@debugger_state)
|
|
1157
|
-
devtools.remove_instance_variable(:@debugger_state) if debugger_state.is_a?(Hash)
|
|
1158
|
-
devtools.debugger.disable
|
|
1159
|
-
end
|
|
1160
|
-
debugger_state = {}
|
|
1161
|
-
breakpoint_arr = []
|
|
1162
|
-
|
|
1163
|
-
# breakpoint = devtools.debugger.set_instrumentation_breakpoint(instrumentation: 'beforeScriptExecution')
|
|
1164
|
-
bcmd = 'EventBreakpoints.setInstrumentationBreakpoint'
|
|
1165
|
-
event = 'load'
|
|
1166
|
-
breakpoint = devtools.send_cmd(bcmd, eventName: event)
|
|
1167
|
-
breakpoint['result']['breakpointId'] = "#{bcmd}.#{event}.#{SecureRandom.uuid}"
|
|
1168
|
-
breakpoint_arr.push(breakpoint)
|
|
1169
|
-
debugger_state[:breakpoints] = breakpoint_arr
|
|
1170
|
-
|
|
1171
|
-
devtools.runtime.disable
|
|
1159
|
+
devtools.dom.enable
|
|
1172
1160
|
devtools.log.disable
|
|
1173
1161
|
devtools.network.disable
|
|
1174
1162
|
devtools.page.disable
|
|
1175
|
-
devtools.
|
|
1163
|
+
devtools.runtime.disable
|
|
1164
|
+
|
|
1165
|
+
method = 'Debugger.scriptParsed'
|
|
1166
|
+
callbacks_to_delete = devtools.callbacks.keys.reject { |k| k == 'Target.atta`chedToTarget' }
|
|
1167
|
+
# until devtools.callbacks.keys.include?(method) && breakpoint_arr.any?
|
|
1168
|
+
until breakpoint_arr.any?
|
|
1169
|
+
callbacks_to_delete.each { |method| devtools.callbacks.delete(method) }
|
|
1170
|
+
breakpoint_set = false
|
|
1171
|
+
# devtools.dom.disable
|
|
1172
|
+
devtools.debugger.disable
|
|
1173
|
+
devtools.debugger.on(:script_parsed) do |params|
|
|
1174
|
+
url = params['url']
|
|
1175
|
+
next if breakpoint_set || url.include?('devtools://') || url.empty?
|
|
1176
|
+
|
|
1177
|
+
breakpoint_set = true
|
|
1178
|
+
puts url
|
|
1179
|
+
bcmd = 'Debugger.setBreakpoint'
|
|
1180
|
+
script_id = params['scriptId']
|
|
1181
|
+
line = params['startLine']
|
|
1182
|
+
column = params['startColumn']
|
|
1183
|
+
location = { scriptId: script_id, lineNumber: line, columnNumber: column }
|
|
1184
|
+
breakpoint = devtools.send_cmd(bcmd, location: location)
|
|
1185
|
+
breakpoint['result']['breakpointId'] = "#{bcmd}.#{script_id}.#{line}.#{column}.#{SecureRandom.uuid}"
|
|
1186
|
+
breakpoint['id'] = breakpoint['id'].to_s
|
|
1187
|
+
breakpoint['url'] = url
|
|
1188
|
+
breakpoint['caught'] = false
|
|
1189
|
+
breakpoint_arr.push(breakpoint)
|
|
1190
|
+
debugger_state[:breakpoints] = breakpoint_arr
|
|
1191
|
+
devtools.instance_variable_set(:@debugger_state, debugger_state)
|
|
1192
|
+
|
|
1193
|
+
puts "Breakpoint set in #{url} at line #{line}, column #{column}: #{breakpoint}"
|
|
1194
|
+
puts params.inspect
|
|
1195
|
+
end
|
|
1196
|
+
devtools.debugger.enable
|
|
1197
|
+
end
|
|
1198
|
+
devtools.callbacks.delete(method)
|
|
1199
|
+
method = 'Debugger.enabled'
|
|
1176
1200
|
when :pause
|
|
1177
|
-
|
|
1178
|
-
|
|
1201
|
+
method = 'Debugger.paused'
|
|
1202
|
+
callbacks_to_delete = devtools.callbacks.keys.reject { |k| k == 'Target.attachedToTarget' }
|
|
1203
|
+
Timeout.timeout(30) { browser_obj[:browser].refresh }
|
|
1204
|
+
until devtools.callbacks.keys.include?(method) && breakpoint_arr.any? { |bp| bp['caught'] == true }
|
|
1205
|
+
callbacks_to_delete.each { |method| devtools.callbacks.delete(method) }
|
|
1206
|
+
devtools.debugger.on(:paused) do |params|
|
|
1207
|
+
breakpoint_id_caught = params['callFrames'].first['location']['scriptId']
|
|
1208
|
+
breakpoint_arr.each_with_index do |bp, idx|
|
|
1209
|
+
next unless bp['id'] == breakpoint_id_caught
|
|
1210
|
+
|
|
1211
|
+
bp['caught'] = true
|
|
1212
|
+
breakpoint_arr[idx] = bp
|
|
1213
|
+
debugger_state[:breakpoints] = breakpoint_arr
|
|
1214
|
+
devtools.instance_variable_set(:@debugger_state, debugger_state)
|
|
1215
|
+
end
|
|
1216
|
+
puts "TARGET BREAKPOINTS: #{breakpoint_arr.inspect}"
|
|
1217
|
+
puts "PARAMS Observerd: #{params.inspect}"
|
|
1218
|
+
end
|
|
1219
|
+
devtools.debugger.pause
|
|
1220
|
+
# browser_obj[:browser].refresh
|
|
1221
|
+
debugger_state = devtools.instance_variable_get(:@debugger_state)
|
|
1222
|
+
breakpoint_arr = debugger_state[:breakpoints]
|
|
1223
|
+
end
|
|
1224
|
+
devtools.callbacks.delete(method)
|
|
1179
1225
|
when :resume
|
|
1180
|
-
|
|
1226
|
+
method = 'Debugger.resumed'
|
|
1227
|
+
callbacks_to_delete = devtools.callbacks.keys.reject { |k| k == 'Target.attachedToTarget' }
|
|
1228
|
+
callbacks_to_delete.each { |method| devtools.callbacks.delete(method) }
|
|
1229
|
+
devtools.debugger.resume until devtools.callbacks.keys.include?(method)
|
|
1181
1230
|
when :disable
|
|
1182
|
-
|
|
1183
|
-
|
|
1231
|
+
callbacks_to_delete = devtools.callbacks.keys.reject { |k| k == 'Target.attachedToTarget' }
|
|
1232
|
+
callbacks_to_delete.each { |method| devtools.callbacks.delete(method) }
|
|
1184
1233
|
devtools.debugger.disable
|
|
1234
|
+
method = 'Debugger.disabled'
|
|
1185
1235
|
end
|
|
1186
1236
|
|
|
1187
|
-
devtools_websocket_messages = devtools_websocket_messages(browser_obj: browser_obj)
|
|
1188
|
-
debugger_state[:method] = devtools_websocket_messages['method']
|
|
1189
|
-
devtools.instance_variable_set(:@debugger_state, debugger_state)
|
|
1190
|
-
devtools
|
|
1191
|
-
rescue Timeout::Error
|
|
1192
1237
|
devtools
|
|
1193
1238
|
rescue Selenium::WebDriver::Error::WebDriverError => e
|
|
1194
1239
|
puts e.message
|
|
1195
1240
|
rescue StandardError => e
|
|
1196
1241
|
raise e
|
|
1242
|
+
ensure
|
|
1243
|
+
debugger_state[:method] = method
|
|
1244
|
+
devtools.instance_variable_set(:@debugger_state, debugger_state) if debugger_state.is_a?(Hash)
|
|
1245
|
+
end
|
|
1246
|
+
|
|
1247
|
+
# Supported Method Parameters::
|
|
1248
|
+
# page_state_arr = PWN::Plugins::TransparentBrowser.get_targets(
|
|
1249
|
+
# browser_obj: 'required - browser_obj returned from #open method)'
|
|
1250
|
+
# )
|
|
1251
|
+
|
|
1252
|
+
public_class_method def self.get_targets(opts = {})
|
|
1253
|
+
browser_obj = opts[:browser_obj]
|
|
1254
|
+
supported = %i[chrome headless_chrome]
|
|
1255
|
+
verified = verify_devtools_browser(browser_obj: browser_obj, supported: supported)
|
|
1256
|
+
puts 'This browser is not supported for DevTools operations.' unless verified
|
|
1257
|
+
return unless verified
|
|
1258
|
+
|
|
1259
|
+
devtools = browser_obj[:devtools]
|
|
1260
|
+
bcmd = 'Target.getTargets'
|
|
1261
|
+
devtools.send_cmd(bcmd)
|
|
1262
|
+
rescue StandardError => e
|
|
1263
|
+
raise e
|
|
1264
|
+
end
|
|
1265
|
+
|
|
1266
|
+
# Supported Method Parameters::
|
|
1267
|
+
# page_state_arr = PWN::Plugins::TransparentBrowser.breakpoint_locations(
|
|
1268
|
+
# browser_obj: 'required - browser_obj returned from #open method)'
|
|
1269
|
+
# )
|
|
1270
|
+
|
|
1271
|
+
public_class_method def self.breakpoint_locations(opts = {})
|
|
1272
|
+
browser_obj = opts[:browser_obj]
|
|
1273
|
+
supported = %i[chrome headless_chrome]
|
|
1274
|
+
verified = verify_devtools_browser(browser_obj: browser_obj, supported: supported)
|
|
1275
|
+
puts 'This browser is not supported for DevTools operations.' unless verified
|
|
1276
|
+
return unless verified
|
|
1277
|
+
|
|
1278
|
+
valid_methods = %w[Debugger.scriptParsed Debugger.paused Debugger.resumed]
|
|
1279
|
+
devtools = browser_obj[:devtools]
|
|
1280
|
+
ws_msg = devtools_websocket_messages(browser_obj: browser_obj)
|
|
1281
|
+
method = ws_msg['method']
|
|
1282
|
+
raise "ERROR: Unsupported method: #{method}" unless valid_methods.include?(method)
|
|
1283
|
+
|
|
1284
|
+
case method
|
|
1285
|
+
when 'Debugger.resumed', 'Debugger.paused'
|
|
1286
|
+
script_id = ws_msg['params']['callFrames'].first['location']['scriptId'].to_s
|
|
1287
|
+
when 'Debugger.scriptParsed'
|
|
1288
|
+
script_id = ws_msg['params']['scriptId'].to_s
|
|
1289
|
+
end
|
|
1290
|
+
|
|
1291
|
+
puts "Method: #{method}"
|
|
1292
|
+
puts "Fetching possible breakpoints for script ID: #{script_id}..."
|
|
1293
|
+
bcmd = 'Debugger.getPossibleBreakpoints'
|
|
1294
|
+
devtools.send_cmd(bcmd, start: { scriptId: script_id, lineNumber: 0, columnNumber: 0 })
|
|
1295
|
+
rescue StandardError => e
|
|
1296
|
+
raise e
|
|
1197
1297
|
end
|
|
1198
1298
|
|
|
1199
1299
|
# Supported Method Parameters::
|
|
@@ -1219,107 +1319,116 @@ module PWN
|
|
|
1219
1319
|
steps = 1 if steps.zero? || steps.negative?
|
|
1220
1320
|
|
|
1221
1321
|
devtools = browser_obj[:devtools]
|
|
1322
|
+
ws_msg = devtools_websocket_messages(browser_obj: browser_obj)
|
|
1323
|
+
method = ws_msg['method']
|
|
1324
|
+
|
|
1222
1325
|
debugger_state = devtools.instance_variable_get(:@debugger_state)
|
|
1223
|
-
method =
|
|
1224
|
-
|
|
1225
|
-
puts 'The debugger must be paused before stepping. Pausing now...'
|
|
1226
|
-
return devtools
|
|
1227
|
-
end
|
|
1326
|
+
debugger_state[:method] = method
|
|
1327
|
+
devtools.instance_variable_set(:@debugger_state, debugger_state)
|
|
1228
1328
|
|
|
1229
|
-
|
|
1329
|
+
valid_methods = %w[Debugger.scriptParsed Debugger.paused Debugger.resumed]
|
|
1330
|
+
devtools = browser_obj[:devtools]
|
|
1331
|
+
ws_msg = devtools_websocket_messages(browser_obj: browser_obj)
|
|
1332
|
+
method = ws_msg['method']
|
|
1333
|
+
raise "ERROR: Unsupported method: #{method}" unless valid_methods.include?(method)
|
|
1334
|
+
|
|
1335
|
+
steps_arr = []
|
|
1336
|
+
cursor_termination_chars = %w[; , . ( ) { } = |]
|
|
1230
1337
|
steps.times do |s|
|
|
1231
1338
|
step_num = s + 1
|
|
1232
1339
|
puts "Stepping #{action} (step #{step_num}/#{steps})..."
|
|
1233
1340
|
|
|
1234
|
-
|
|
1235
|
-
# puts before.inspect
|
|
1236
|
-
before = devtools_websocket_messages(browser_obj: browser_obj)
|
|
1237
|
-
method = before['method']
|
|
1238
|
-
# puts before
|
|
1239
|
-
puts "\n"
|
|
1240
|
-
|
|
1241
|
-
if method == 'Debugger.paused'
|
|
1242
|
-
before_location = before['params']['callFrames'].first['location']
|
|
1243
|
-
start_location = before['params']['callFrames'].first['scopeChain'].first['startLocation']
|
|
1244
|
-
before_script_id = start_location['scriptId']
|
|
1245
|
-
from_line_num = start_location['lineNumber']
|
|
1246
|
-
from_column_num = start_location['columnNumber']
|
|
1247
|
-
|
|
1248
|
-
end_location = before['params']['callFrames'].first['scopeChain'].first['endLocation']
|
|
1249
|
-
to_line_num = end_location['lineNumber']
|
|
1250
|
-
to_column_num = end_location['columnNumber']
|
|
1251
|
-
|
|
1252
|
-
source_obj = devtools.debugger.get_script_source(script_id: before_script_id)
|
|
1253
|
-
source_code = source_obj['result']['scriptSource']
|
|
1254
|
-
# puts source_code
|
|
1255
|
-
# gets
|
|
1256
|
-
|
|
1257
|
-
source_lines = source_code.split("\n")
|
|
1258
|
-
source_lines_str = source_lines[from_line_num..to_line_num].join("\n")
|
|
1259
|
-
source_to_review = source_lines_str[from_column_num..to_column_num]
|
|
1260
|
-
|
|
1261
|
-
puts source_to_review
|
|
1262
|
-
request = source_lines_str[from_column_num..to_column_num]
|
|
1263
|
-
ai_analysis = PWN::AI::Introspection.reflect_on(request: request)
|
|
1264
|
-
puts "^^^ #{ai_analysis}" unless ai_analysis.nil?
|
|
1265
|
-
# gets
|
|
1266
|
-
end
|
|
1267
|
-
|
|
1341
|
+
method = 'Debugger.resumed'
|
|
1268
1342
|
case action
|
|
1269
1343
|
when :into
|
|
1270
|
-
devtools.debugger.step_into
|
|
1344
|
+
devtools.debugger.step_into until devtools.callbacks.keys.include?(method)
|
|
1271
1345
|
when :out
|
|
1272
|
-
devtools.debugger.step_out
|
|
1346
|
+
devtools.debugger.step_out until devtools.callbacks.keys.include?(method)
|
|
1273
1347
|
when :over
|
|
1274
|
-
devtools.debugger.step_over
|
|
1348
|
+
devtools.debugger.step_over until devtools.callbacks.keys.include?(method)
|
|
1349
|
+
end
|
|
1350
|
+
devtools.callbacks.delete(method)
|
|
1351
|
+
|
|
1352
|
+
method = 'Debugger.paused'
|
|
1353
|
+
devtools.debugger.pause until devtools.callbacks.keys.include?(method)
|
|
1354
|
+
devtools.callbacks.delete(method)
|
|
1355
|
+
|
|
1356
|
+
ws_msg = devtools_websocket_messages(browser_obj: browser_obj)
|
|
1357
|
+
ws_msg_params = ws_msg['params']
|
|
1358
|
+
ws_msg_call_frames = ws_msg_params['callFrames'].first
|
|
1359
|
+
ws_msg_scope_chain_local = ws_msg_call_frames['scopeChain'].find { |scope| scope['type'] == 'local' }
|
|
1360
|
+
next unless ws_msg_scope_chain_local.is_a?(Hash)
|
|
1361
|
+
|
|
1362
|
+
ws_msg_scope_chain_block = ws_msg_call_frames['scopeChain'].find { |scope| scope['type'] == 'block' }
|
|
1363
|
+
|
|
1364
|
+
cursor_location = ws_msg_call_frames['location']
|
|
1365
|
+
cursor_line_num = cursor_location['lineNumber']
|
|
1366
|
+
cursor_column_num = cursor_location['columnNumber']
|
|
1367
|
+
|
|
1368
|
+
script_id = cursor_location['scriptId']
|
|
1369
|
+
|
|
1370
|
+
start_location = ws_msg_scope_chain_local['startLocation']
|
|
1371
|
+
start_line_num = start_location['lineNumber']
|
|
1372
|
+
start_column_num = start_location['columnNumber']
|
|
1373
|
+
|
|
1374
|
+
end_location = ws_msg_scope_chain_local['endLocation']
|
|
1375
|
+
# end_location_block = ws_msg_scope_chain_block['endLocation']
|
|
1376
|
+
# puts "TEST: #{end_location - end_location_block}"
|
|
1377
|
+
end_line_num = end_location['lineNumber']
|
|
1378
|
+
end_column_num = end_location['columnNumber']
|
|
1379
|
+
|
|
1380
|
+
source_obj = devtools.debugger.get_script_source(script_id: script_id)
|
|
1381
|
+
full_source_code = source_obj['result']['scriptSource']
|
|
1382
|
+
|
|
1383
|
+
source_lines = full_source_code.split("\n")
|
|
1384
|
+
# puts source_lines.inspect
|
|
1385
|
+
source_lines_range = source_lines[start_line_num..end_line_num]
|
|
1386
|
+
next if source_lines_range.nil?
|
|
1387
|
+
|
|
1388
|
+
source_lines_str = source_lines_range.join("\n")
|
|
1389
|
+
source_to_review = source_lines_str[start_column_num..end_column_num]
|
|
1390
|
+
current_step = source_lines_str[cursor_column_num..end_column_num]
|
|
1391
|
+
|
|
1392
|
+
# TODO: leverage ANSI escape codes to highlight current_step to red
|
|
1393
|
+
# puts ws_msg.inspect
|
|
1394
|
+
# puts "\n"
|
|
1395
|
+
# puts ws_msg_call_frames['scopeChain'].inspect
|
|
1396
|
+
# puts "\n"
|
|
1397
|
+
cursor_terminated = false
|
|
1398
|
+
source_to_review.each_char.with_index do |char, idx|
|
|
1399
|
+
cursor_start_offset = cursor_column_num - start_column_num
|
|
1400
|
+
cursor_end_offset = end_column_num - start_column_num
|
|
1401
|
+
|
|
1402
|
+
if idx >= cursor_start_offset && !cursor_terminated
|
|
1403
|
+
cursor_terminated = true if cursor_termination_chars.include?(char)
|
|
1404
|
+
print char if cursor_terminated
|
|
1405
|
+
print "\001\e[31m\002#{char}\001\e[0m\002" unless cursor_terminated
|
|
1406
|
+
else
|
|
1407
|
+
print char
|
|
1408
|
+
end
|
|
1275
1409
|
end
|
|
1276
1410
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
after_location = after['params']['callFrames'].first['scopeChain'].first['object']
|
|
1285
|
-
start_location = after['params']['callFrames'].first['scopeChain'].first['startLocation']
|
|
1286
|
-
after_script_id = start_location['scriptId']
|
|
1287
|
-
from_line_num = start_location['lineNumber']
|
|
1288
|
-
from_column_num = start_location['columnNumber']
|
|
1289
|
-
|
|
1290
|
-
end_location = after['params']['callFrames'].first['scopeChain'].first['endLocation']
|
|
1291
|
-
to_line_num = end_location['lineNumber']
|
|
1292
|
-
to_column_num = end_location['columnNumber']
|
|
1293
|
-
|
|
1294
|
-
source_obj = devtools.debugger.get_script_source(script_id: after_script_id)
|
|
1295
|
-
source_code = source_obj['result']['scriptSource']
|
|
1296
|
-
# puts source_code
|
|
1297
|
-
# gets
|
|
1298
|
-
|
|
1299
|
-
source_lines = source_code.split("\n")
|
|
1300
|
-
source_lines_str = source_lines[from_line_num..to_line_num].join("\n")
|
|
1301
|
-
source_to_review = source_lines_str[from_column_num..to_column_num]
|
|
1302
|
-
|
|
1303
|
-
puts source_to_review
|
|
1304
|
-
request = source_lines_str[from_column_num..to_column_num]
|
|
1305
|
-
ai_analysis = PWN::AI::Introspection.reflect_on(request: request)
|
|
1411
|
+
if current_step.length.positive?
|
|
1412
|
+
system_role_content = "Being an expert penetration tester skilled in code analysis, debugging, and exploitation while stepping through JavaScript in a Chrome DevTools debugging session: 1. Your sole purpose is to analyze each JavaScript step and generate an Exploit Prediction Scoring System (EPSS) score between 0% - 100%. The step currently resides in this block of JavaScript:\n```\n#{source_to_review}\n```\n2. If the score is >= 75%, generate a JavaScript proof-of-concept that would allow a threat actor to directly exploit or target a user for exploitation (i.e. no self-exploit). 3. If the EPSS score is >= 75% also provide a code fix. *** If the EPSS score is < 75%, no explanations or summaries - just the EPSS score."
|
|
1413
|
+
|
|
1414
|
+
ai_analysis = PWN::AI::Introspection.reflect_on(
|
|
1415
|
+
system_role_content: system_role_content,
|
|
1416
|
+
request: current_step
|
|
1417
|
+
)
|
|
1306
1418
|
puts "^^^ #{ai_analysis}" unless ai_analysis.nil?
|
|
1307
|
-
# gets
|
|
1308
1419
|
end
|
|
1309
|
-
puts "\n" *
|
|
1420
|
+
puts "\n" * 3
|
|
1310
1421
|
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
# diff: diff.to_s(:text)
|
|
1317
|
-
# }
|
|
1422
|
+
step_hash = {
|
|
1423
|
+
step: step_num,
|
|
1424
|
+
action: action,
|
|
1425
|
+
source: current_step
|
|
1426
|
+
}
|
|
1318
1427
|
|
|
1319
|
-
|
|
1428
|
+
steps_arr.push(step_hash)
|
|
1320
1429
|
end
|
|
1321
1430
|
|
|
1322
|
-
|
|
1431
|
+
steps_arr
|
|
1323
1432
|
rescue Selenium::WebDriver::Error::WebDriverError
|
|
1324
1433
|
devtools
|
|
1325
1434
|
rescue StandardError => e
|
data/lib/pwn/version.rb
CHANGED
data/lib/pwn/www/hacker_one.rb
CHANGED
|
@@ -131,9 +131,18 @@ module PWN
|
|
|
131
131
|
cursor = page_info[:endCursor]
|
|
132
132
|
break unless page_info[:hasNextPage]
|
|
133
133
|
end
|
|
134
|
+
puts "\n"
|
|
134
135
|
|
|
135
136
|
programs_arr.sort_by! { |p| -p[:min_payout].gsub('$', '').gsub(',', '').to_f }
|
|
136
137
|
|
|
138
|
+
system_role_content = 'Suggest an optimal bug bounty program to target on HackerOne to maximize potential earnings based on values within `min_payout` and publicly known vulnerabilities that have surfaced for the `name` of the program.'
|
|
139
|
+
ai_analysis = PWN::AI::Introspection.reflect_on(
|
|
140
|
+
request: programs_arr.to_json,
|
|
141
|
+
system_role_content: system_role_content,
|
|
142
|
+
spinner: true
|
|
143
|
+
)
|
|
144
|
+
puts "\n\n#{ai_analysis}" unless ai_analysis.nil?
|
|
145
|
+
|
|
137
146
|
programs_arr
|
|
138
147
|
rescue RestClient::ExceptionWithResponse => e
|
|
139
148
|
if e.response
|
|
@@ -270,6 +279,16 @@ module PWN
|
|
|
270
279
|
name: program_name,
|
|
271
280
|
scope_details: json_resp_hash
|
|
272
281
|
}
|
|
282
|
+
|
|
283
|
+
system_role_content = 'Analyze the scope details for the given bug bounty program on HackerOne. Identify key areas of interest, potential vulnerabilities, and any patterns that could inform a targeted security assessment based on the provided scope information.'
|
|
284
|
+
ai_analysis = PWN::AI::Introspection.reflect_on(
|
|
285
|
+
request: json_resp.to_json,
|
|
286
|
+
system_role_content: system_role_content,
|
|
287
|
+
spinner: true
|
|
288
|
+
)
|
|
289
|
+
puts "\n\n#{ai_analysis}" unless ai_analysis.nil?
|
|
290
|
+
|
|
291
|
+
json_resp
|
|
273
292
|
rescue RestClient::ExceptionWithResponse => e
|
|
274
293
|
if e.response
|
|
275
294
|
puts "HTTP RESPONSE CODE: #{e.response.code}"
|
|
@@ -408,6 +427,16 @@ module PWN
|
|
|
408
427
|
name: program_name,
|
|
409
428
|
hacktivity: json_resp_hash
|
|
410
429
|
}
|
|
430
|
+
|
|
431
|
+
system_role_content = 'Analyze the hacktivity details for the given bug bounty program on HackerOne. Identify significant disclosed reports, common vulnerability types, and any trends that could inform future security assessments based on the provided hacktivity information.'
|
|
432
|
+
ai_analysis = PWN::AI::Introspection.reflect_on(
|
|
433
|
+
request: json_resp.to_json,
|
|
434
|
+
system_role_content: system_role_content,
|
|
435
|
+
spinner: true
|
|
436
|
+
)
|
|
437
|
+
puts "\n\n#{ai_analysis}" unless ai_analysis.nil?
|
|
438
|
+
|
|
439
|
+
json_resp
|
|
411
440
|
rescue RestClient::ExceptionWithResponse => e
|
|
412
441
|
if e.response
|
|
413
442
|
puts "HTTP RESPONSE CODE: #{e.response.code}"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pwn
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.495
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- 0day Inc.
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "<"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 8.1.
|
|
18
|
+
version: 8.1.1
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "<"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 8.1.
|
|
25
|
+
version: 8.1.1
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: anemone
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -113,14 +113,14 @@ dependencies:
|
|
|
113
113
|
requirements:
|
|
114
114
|
- - '='
|
|
115
115
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: 7.1.
|
|
116
|
+
version: 7.1.1
|
|
117
117
|
type: :runtime
|
|
118
118
|
prerelease: false
|
|
119
119
|
version_requirements: !ruby/object:Gem::Requirement
|
|
120
120
|
requirements:
|
|
121
121
|
- - '='
|
|
122
122
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: 7.1.
|
|
123
|
+
version: 7.1.1
|
|
124
124
|
- !ruby/object:Gem::Dependency
|
|
125
125
|
name: bson
|
|
126
126
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -827,14 +827,14 @@ dependencies:
|
|
|
827
827
|
requirements:
|
|
828
828
|
- - '='
|
|
829
829
|
- !ruby/object:Gem::Version
|
|
830
|
-
version: 13.3.
|
|
830
|
+
version: 13.3.1
|
|
831
831
|
type: :development
|
|
832
832
|
prerelease: false
|
|
833
833
|
version_requirements: !ruby/object:Gem::Requirement
|
|
834
834
|
requirements:
|
|
835
835
|
- - '='
|
|
836
836
|
- !ruby/object:Gem::Version
|
|
837
|
-
version: 13.3.
|
|
837
|
+
version: 13.3.1
|
|
838
838
|
- !ruby/object:Gem::Dependency
|
|
839
839
|
name: rb-readline
|
|
840
840
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -869,14 +869,14 @@ dependencies:
|
|
|
869
869
|
requirements:
|
|
870
870
|
- - '='
|
|
871
871
|
- !ruby/object:Gem::Version
|
|
872
|
-
version: 6.15.
|
|
872
|
+
version: 6.15.1
|
|
873
873
|
type: :development
|
|
874
874
|
prerelease: false
|
|
875
875
|
version_requirements: !ruby/object:Gem::Requirement
|
|
876
876
|
requirements:
|
|
877
877
|
- - '='
|
|
878
878
|
- !ruby/object:Gem::Version
|
|
879
|
-
version: 6.15.
|
|
879
|
+
version: 6.15.1
|
|
880
880
|
- !ruby/object:Gem::Dependency
|
|
881
881
|
name: rest-client
|
|
882
882
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -967,14 +967,14 @@ dependencies:
|
|
|
967
967
|
requirements:
|
|
968
968
|
- - '='
|
|
969
969
|
- !ruby/object:Gem::Version
|
|
970
|
-
version: 1.81.
|
|
970
|
+
version: 1.81.7
|
|
971
971
|
type: :runtime
|
|
972
972
|
prerelease: false
|
|
973
973
|
version_requirements: !ruby/object:Gem::Requirement
|
|
974
974
|
requirements:
|
|
975
975
|
- - '='
|
|
976
976
|
- !ruby/object:Gem::Version
|
|
977
|
-
version: 1.81.
|
|
977
|
+
version: 1.81.7
|
|
978
978
|
- !ruby/object:Gem::Dependency
|
|
979
979
|
name: rubocop-rake
|
|
980
980
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -1079,28 +1079,28 @@ dependencies:
|
|
|
1079
1079
|
requirements:
|
|
1080
1080
|
- - '='
|
|
1081
1081
|
- !ruby/object:Gem::Version
|
|
1082
|
-
version: 0.
|
|
1082
|
+
version: 0.142.0
|
|
1083
1083
|
type: :runtime
|
|
1084
1084
|
prerelease: false
|
|
1085
1085
|
version_requirements: !ruby/object:Gem::Requirement
|
|
1086
1086
|
requirements:
|
|
1087
1087
|
- - '='
|
|
1088
1088
|
- !ruby/object:Gem::Version
|
|
1089
|
-
version: 0.
|
|
1089
|
+
version: 0.142.0
|
|
1090
1090
|
- !ruby/object:Gem::Dependency
|
|
1091
1091
|
name: selenium-webdriver
|
|
1092
1092
|
requirement: !ruby/object:Gem::Requirement
|
|
1093
1093
|
requirements:
|
|
1094
1094
|
- - '='
|
|
1095
1095
|
- !ruby/object:Gem::Version
|
|
1096
|
-
version: 4.
|
|
1096
|
+
version: 4.38.0
|
|
1097
1097
|
type: :runtime
|
|
1098
1098
|
prerelease: false
|
|
1099
1099
|
version_requirements: !ruby/object:Gem::Requirement
|
|
1100
1100
|
requirements:
|
|
1101
1101
|
- - '='
|
|
1102
1102
|
- !ruby/object:Gem::Version
|
|
1103
|
-
version: 4.
|
|
1103
|
+
version: 4.38.0
|
|
1104
1104
|
- !ruby/object:Gem::Dependency
|
|
1105
1105
|
name: slack-ruby-client
|
|
1106
1106
|
requirement: !ruby/object:Gem::Requirement
|