pwn 0.5.429 → 0.5.431

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d62d95361763fc4363d172024859e5fc8cc9ea1b96b2765a37c679b468c9a22f
4
- data.tar.gz: 8def884e714ec444f10fae2c952087acb64fc4c5f06bef088f19e3f0a39fc157
3
+ metadata.gz: 94c2a5850f2c76a8702121a4b2bb47e1f89b0b41dc63246483a650ff55f39c10
4
+ data.tar.gz: 6d0addc08b3aec4a592e5cac6dbd13e761d3516573313755364289e7b1b4676a
5
5
  SHA512:
6
- metadata.gz: d46e4790ac2a3023a6210d77641c530226127429000c3994919750fcefa3a4610b0bf7390d4790be85081a9a7846c88e1bfa6ebda334375922276678239066cc
7
- data.tar.gz: 2f96f89617d314c6f1b9094580890b67a9b722fd9a58ee8e05642ba7c8bdd51e8f598f3e7c2cc3df267da05ba77efebbb23e29e15ccd684414b385531cad122c
6
+ metadata.gz: 3e8106f5103be1f4c1a447929b8f36440c3a37786374f50fcb7b2176d4fb089dc0b2809ba854fb43d0d516a6dd52be8f5d32339da3c4896074e229d278da4ca0
7
+ data.tar.gz: f5fdf5bbeb05fb798450829d9d2bd09637b4b71c2590f015707d57c9671ea9bbf8f0782f01e7dd5e32382c1a5c8d125f66824bbb3b51e6cd53e9b0057e256332
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.429]:001 >>> PWN.help
40
+ pwn[v0.5.431]:001 >>> PWN.help
41
41
  ```
42
42
 
43
43
  [![Installing the pwn Security Automation Framework](https://raw.githubusercontent.com/0dayInc/pwn/master/documentation/pwn_install.png)](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.429]:001 >>> PWN.help
55
+ pwn[v0.5.431]: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.429]:001 >>> PWN.help
65
+ pwn[v0.5.431]: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/bin/pwn CHANGED
@@ -10,12 +10,12 @@ OptionParser.new do |options|
10
10
  #{File.basename($PROGRAM_NAME)} [opts]
11
11
  "
12
12
 
13
- options.on('-cPATH', '--yaml-config=PATH', '<Optional - PWN YAML File>') do |p|
14
- opts[:yaml_config_path] = p
13
+ options.on('-YPATH', '--pwn-config=PATH', '<Optional - PWN YAML File>') do |p|
14
+ opts[:pwn_config_path] = p
15
15
  end
16
16
 
17
- options.on('-dPATH', '--yaml-decryptor=PATH', '<Optional - Out-of-Band YAML File with :key && :iv>') do |d|
18
- opts[:yaml_decryptor_path] = d
17
+ options.on('-ZPATH', '--pwn-decryptor=PATH', '<Optional - Out-of-Band YAML File with :key && :iv>') do |d|
18
+ opts[:pwn_decryptor_path] = d
19
19
  end
20
20
  end.parse!
21
21
 
data/bin/pwn_sast CHANGED
@@ -11,6 +11,15 @@ OptionParser.new do |options|
11
11
  #{File.basename($PROGRAM_NAME)} [opts]
12
12
  "
13
13
 
14
+ # TODO: HOW TO LOAD THE pwn.yaml CONFIGURATION FILE FOR EVERYTHING UNLESS OVERRIDDEN???
15
+ options.on('-YPATH', '--pwn-config=PATH', '<Optional - PWN YAML File>') do |p|
16
+ opts[:pwn_config_path] = p
17
+ end
18
+
19
+ options.on('-ZPATH', '--pwn-decryptor=PATH', '<Optional - Out-of-Band YAML File with :key && :iv>') do |d|
20
+ opts[:pwn_decryptor_path] = d
21
+ end
22
+
14
23
  options.on('-uGITURI', '--uri-source-root=GITURI', '<Required - HTTP URI of Git Repo Scanned e.g. https://github.com/0dayInc/pwn/tree/master>') do |u|
15
24
  opts[:uri_source_root] = u
16
25
  end
@@ -35,30 +44,6 @@ OptionParser.new do |options|
35
44
  opts[:report_name] = n
36
45
  end
37
46
 
38
- options.on('-aENGINE', '--ai-engine=ENGINE', '<Optional AI Engine to Analyze Results (grok, ollama, openai) [WARNING: CAN DRAMATICALLY INCREASE AI USAGE COSTS AND/OR SCAN DURATIONS]>') do |a|
39
- opts[:ai_engine] = a
40
- end
41
-
42
- options.on('-bURI', '--ai-base-uri=URI', '<Optional AI Base API URI (Only Required for "ollama" AI Engine. Supported by other LLMs when hosted privately)>') do |b|
43
- opts[:ai_base_uri] = b
44
- end
45
-
46
- options.on('-mMODEL', '--ai-model=MODEL', '<Optional AI Model to Use for Respective AI Engine (e.g., grok-4-0709, grok-3-mini-fast, gpt5-chat-latest, chargpt-4o-latest, llama-3.1, etc.)>') do |m|
47
- opts[:ai_model] = m
48
- end
49
-
50
- options.on('-kTOKEN', '--ai-key=TOKEN', '<Optional AI Key/Token for Respective AI Engine>') do |k|
51
- opts[:ai_key] = k
52
- end
53
-
54
- options.on('-SCONTENT', '--ai-system-content=CONTENT', '<Optional AI System Role Content for Respective AI Engine (Defaults to, "Confidence score of 0-10 this is vulnerable (0 being not vulnerable, moving upwards in confidence of exploitation). Provide additional context to assist penetration tester assessment.")>') do |s|
55
- opts[:ai_system_role_content] = s
56
- end
57
-
58
- options.on('-FTEMP', '--ai-temp=TEMP', '<Optional AI Temperature for Respective AI Engine (Default 0.9)>') do |t|
59
- opts[:ai_temp] = t
60
- end
61
-
62
47
  options.on('-s', '--[no-]start-reporting-server', '<Optional - Start Simple HTTP Server for Reporting>') do |s|
63
48
  opts[:start_reporting_server] = s
64
49
  end
@@ -71,6 +56,16 @@ end
71
56
 
72
57
  begin
73
58
  timestamp = Time.now.strftime('%Y-%m-%d_%H:%M:%S%z')
59
+
60
+ pwn_config_path = opts[:pwn_config_path]
61
+ pwn_decryptor_path = opts[:pwn_decryptor_path]
62
+ if pwn_config_path
63
+ PWN::Config.refresh(
64
+ pwn_config_path: pwn_config_path,
65
+ pwn_decryptor_path: pwn_decryptor_path
66
+ )
67
+ end
68
+
74
69
  previous_dir = Dir.pwd
75
70
 
76
71
  pwn_provider = 'ruby-gem'
@@ -95,23 +90,6 @@ begin
95
90
  report_name ||= "#{File.basename(Dir.pwd)}-#{timestamp}" if dir_path == '.'
96
91
  report_name ||= "#{File.basename(dir_path)}-#{timestamp}" unless dir_path == '.'
97
92
 
98
- ai_engine = opts[:ai_engine]
99
- if ai_engine
100
- ai_engine = ai_engine.to_s.to_sym
101
- valid_ai_engines = %i[grok ollama openai]
102
- raise "ERROR: Invalid AI Engine. Valid options are: #{valid_ai_engines.join(', ')}" unless valid_ai_engines.include?(ai_engine)
103
-
104
- ai_base_uri = opts[:ai_base_uri]
105
- raise 'ERROR: --base-uri Parameter for Ollama AI engine is required.' if ai_engine == :ollama && ai_base_uri.nil?
106
-
107
- ai_model = opts[:ai_model]
108
- raise 'ERROR: AI Model is required for AI engine ollama.' if ai_engine == :ollama && ai_model.nil?
109
-
110
- ai_key = opts[:ai_key] ||= PWN::Plugins::AuthenticationHelper.mask_password(prompt: "#{ai_engine} Token")
111
- ai_system_role_content = opts[:ai_system_role_content]
112
- ai_temp = opts[:ai_temp]
113
- end
114
-
115
93
  start_reporting_server = opts[:start_reporting_server]
116
94
 
117
95
  # Define Test Cases to Run & Start Thread Pool
@@ -202,13 +180,7 @@ begin
202
180
  PWN::Reports::SAST.generate(
203
181
  dir_path: dir_path,
204
182
  results_hash: results_hash,
205
- report_name: report_name,
206
- ai_engine: ai_engine,
207
- ai_model: ai_model,
208
- ai_key: ai_key,
209
- ai_base_uri: ai_base_uri,
210
- ai_system_role_content: ai_system_role_content,
211
- ai_temp: ai_temp
183
+ report_name: report_name
212
184
  )
213
185
  puts 'complete.'
214
186
 
data/etc/pwn.yaml.EXAMPLE CHANGED
@@ -2,6 +2,9 @@
2
2
  # Use PWN::Plugins::Vault.create(file: 'pwn.yaml') to encrypt this file
3
3
 
4
4
  # ai_engine: 'openai' || 'ollama'
5
+ # WARNING::
6
+ # If PWN::CONFIG[:ai][:instrospection] = true, the active ai agent will be used
7
+ # wherever possible throughout pwn. Proceeds with caution, as this may incur additional costs
5
8
  ai:
6
9
  active: 'grok'
7
10
  introspection: false
data/lib/pwn/ai/grok.rb CHANGED
@@ -25,6 +25,13 @@ module PWN
25
25
 
26
26
  private_class_method def self.grok_rest_call(opts = {})
27
27
  token = opts[:token]
28
+ if token.nil?
29
+ PWN::Plugins::AuthenticationHelper.mask_password(
30
+ prompt: 'Grok Key'
31
+ )
32
+ PWN::CONFIG[:ai][:grok][:key] = token
33
+ end
34
+
28
35
  http_method = if opts[:http_method].nil?
29
36
  :get
30
37
  else
data/lib/pwn/ai/ollama.rb CHANGED
@@ -27,6 +27,13 @@ module PWN
27
27
  private_class_method def self.ollama_rest_call(opts = {})
28
28
  base_uri = opts[:base_uri]
29
29
  token = opts[:token]
30
+ if token.nil?
31
+ PWN::Plugins::AuthenticationHelper.mask_password(
32
+ prompt: 'Ollama Key'
33
+ )
34
+ PWN::CONFIG[:ai][:ollama][:key] = token
35
+ end
36
+
30
37
  http_method = if opts[:http_method].nil?
31
38
  :get
32
39
  else
@@ -26,6 +26,13 @@ module PWN
26
26
 
27
27
  private_class_method def self.open_ai_rest_call(opts = {})
28
28
  token = opts[:token]
29
+ if token.nil?
30
+ PWN::Plugins::AuthenticationHelper.mask_password(
31
+ prompt: 'OpenAI Key'
32
+ )
33
+ PWN::CONFIG[:ai][:openai][:key] = token
34
+ end
35
+
29
36
  http_method = if opts[:http_method].nil?
30
37
  :get
31
38
  else
data/lib/pwn/config.rb ADDED
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'yaml'
5
+
6
+ module PWN
7
+ # Used to manage PWN configuration settings within PWN drivers.
8
+ module Config
9
+ # Supported Method Parameters::
10
+ # PWN::Config.refresh(
11
+ # pwn_config_path: 'optional - Path to pwn.yaml file. Defaults to ~/.pwn/pwn.yaml',
12
+ # pwn_decryptor_path: 'optional - Path to pwn.decryptor.yaml file. Defaults to ~/.pwn/pwn.decryptor.yaml'
13
+ # )
14
+
15
+ public_class_method def self.refresh(opts = {})
16
+ pwn_config_root = "#{Dir.home}/.pwn"
17
+ FileUtils.mkdir_p(pwn_config_root)
18
+
19
+ pwn_config_path = opts[:pwn_config_path] ||= "#{pwn_config_root}/pwn.yaml"
20
+ return unless File.exist?(pwn_config_path)
21
+
22
+ is_encrypted = PWN::Plugins::Vault.file_encrypted?(file: pwn_config_path)
23
+
24
+ if is_encrypted
25
+ pwn_decryptor_path = opts[:pwn_decryptor_path] ||= "#{pwn_config_root}/pwn.decryptor.yaml"
26
+ raise "PWN Decryptor (#{pwn_decryptor_path}) does not exist!" unless File.exist?(pwn_decryptor_path)
27
+
28
+ pwn_decryptor = YAML.load_file(pwn_decryptor_path, symbolize_names: true)
29
+
30
+ key = opts[:key] ||= pwn_decryptor[:key] ||= ENV.fetch('PWN_DECRYPTOR_KEY')
31
+ key = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption Key') if key.nil?
32
+
33
+ iv = opts[:iv] ||= pwn_decryptor[:iv] ||= ENV.fetch('PWN_DECRYPTOR_IV')
34
+ iv = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption IV') if iv.nil?
35
+
36
+ config = PWN::Plugins::Vault.dump(
37
+ file: pwn_config_path,
38
+ key: key,
39
+ iv: iv
40
+ )
41
+ else
42
+ config = YAML.load_file(pwn_config_path, symbolize_names: true)
43
+ end
44
+
45
+ valid_ai_engines = %i[
46
+ grok
47
+ openai
48
+ ollama
49
+ ]
50
+
51
+ engine = config[:ai][:active].to_s.downcase.to_sym
52
+ raise "ERROR: Unsupported AI Engine: #{engine} in #{pwn_config_path}. Supported AI Engines:\n#{valid_ai_engines.inspect}" unless valid_ai_engines.include?(engine)
53
+
54
+ model = config[:ai][engine][:model]
55
+ system_role_content = config[:ai][engine][:system_role_content]
56
+
57
+ # Reset the ai response history on config refresh
58
+ config[:ai][engine][:response_history] = {
59
+ id: '',
60
+ object: '',
61
+ model: model,
62
+ usage: {},
63
+ choices: [
64
+ {
65
+ role: 'system',
66
+ content: system_role_content
67
+ }
68
+ ]
69
+ }
70
+
71
+ # These two lines should be immutable for the session
72
+ config[:pwn_config_path] = pwn_config_path
73
+ config[:pwn_decryptor_path] = pwn_decryptor_path if is_encrypted
74
+
75
+ Pry.config.refresh = false if defined?(Pry)
76
+
77
+ PWN.send(:remove_const, :CONFIG) if PWN.const_defined?(:CONFIG)
78
+ PWN.const_set(:CONFIG, config)
79
+ end
80
+ end
81
+ end
@@ -18,11 +18,7 @@ module PWN
18
18
  mode = opts[:mode]
19
19
 
20
20
  proc do |_target_self, _nest_level, pi|
21
- if Pry.config.refresh
22
- # puts "Refreshing PWN env via #{opts[:yaml_config_path]}"
23
- opts[:pi] = pi
24
- PWN::Plugins::Vault.refresh_config(opts)
25
- end
21
+ pi.config.pwn = PWN::Config.refresh(opts) if Pry.config.refresh
26
22
 
27
23
  pi.config.pwn_repl_line += 1
28
24
  line_pad = format(
@@ -464,24 +460,24 @@ module PWN
464
460
 
465
461
  def process
466
462
  pi = pry_instance
467
- yaml_config_path = pi.config.yaml_config_path ||= "#{Dir.home}/.pwn/pwn.yaml"
468
- unless File.exist?(yaml_config_path)
469
- puts "ERROR: pwn.yaml not found: #{yaml_config_path}"
463
+ pwn_config_path = pi.config.pwn_config_path ||= "#{Dir.home}/.pwn/pwn.yaml"
464
+ unless File.exist?(pwn_config_path)
465
+ puts "ERROR: pwn.yaml not found: #{pwn_config_path}"
470
466
  return
471
467
  end
472
468
 
473
- yaml_decryptor_path = pi.config.yaml_decryptor_path ||= "#{Dir.home}/.pwn/pwn.decryptor.yaml"
474
- unless File.exist?(yaml_decryptor_path)
475
- puts "ERROR: pwn.decryptor.yaml not found: #{yaml_decryptor_path}"
469
+ pwn_decryptor_path = pi.config.pwn_decryptor_path ||= "#{Dir.home}/.pwn/pwn.decryptor.yaml"
470
+ unless File.exist?(pwn_decryptor_path)
471
+ puts "ERROR: pwn.decryptor.yaml not found: #{pwn_decryptor_path}"
476
472
  return
477
473
  end
478
474
 
479
- decryptor = YAML.load_file(yaml_decryptor_path, symbolize_names: true)
475
+ decryptor = YAML.load_file(pwn_decryptor_path, symbolize_names: true)
480
476
  key = decryptor[:key]
481
477
  iv = decryptor[:iv]
482
478
 
483
479
  PWN::Plugins::Vault.edit(
484
- file: yaml_config_path,
480
+ file: pwn_config_path,
485
481
  key: key,
486
482
  iv: iv
487
483
  )
@@ -539,9 +535,7 @@ module PWN
539
535
 
540
536
  # Initialize pwn.yaml Configuration using :before_session Hook
541
537
  Pry.config.hooks.add_hook(:before_session, :init_opts) do |_output, _binding, pi|
542
- # puts "Refreshing PWN env via #{opts[:yaml_config_path]}"
543
- opts[:pi] = pi
544
- PWN::Plugins::Vault.refresh_config(opts)
538
+ pi.config.pwn = PWN::Config.refresh(opts)
545
539
  end
546
540
 
547
541
  Pry.config.hooks.add_hook(:after_read, :pwn_asm_hook) do |request, pi|
@@ -588,13 +582,6 @@ module PWN
588
582
  engine = pi.config.pwn[:ai][:active].to_s.downcase.to_sym
589
583
  base_uri = pi.config.pwn[:ai][engine][:base_uri]
590
584
  key = pi.config.pwn[:ai][engine][:key] ||= ''
591
- if key.empty?
592
- key = PWN::Plugins::AuthenticationHelper.mask_password(
593
- prompt: 'pwn-ai Key'
594
- )
595
- pi.config.pwn[:ai][engine][:key] = key
596
- end
597
-
598
585
  response_history = pi.config.pwn[:ai][engine][:response_history]
599
586
  speak_answer = pi.config.pwn_ai_speak
600
587
  model = pi.config.pwn[:ai][engine][:model]
@@ -683,16 +670,10 @@ module PWN
683
670
  public_class_method def self.start(opts = {})
684
671
  # Monkey Patch Pry, add commands, && hooks
685
672
  PWN::Plugins::MonkeyPatch.pry
686
- add_commands
687
-
688
673
  pwn_config_root = "#{Dir.home}/.pwn"
689
- FileUtils.mkdir_p(pwn_config_root)
690
-
691
674
  Pry.config.history_file = "#{pwn_config_root}/pwn_history"
692
675
 
693
- opts[:yaml_config_path] ||= "#{pwn_config_root}/pwn.yaml"
694
- opts[:yaml_decryptor_path] ||= "#{pwn_config_root}/pwn.decryptor.yaml"
695
-
676
+ add_commands
696
677
  add_hooks(opts)
697
678
 
698
679
  # Define PS1 Prompt
@@ -15,7 +15,7 @@ module PWN
15
15
  # iv: 'required - iv to decrypt'
16
16
  # )
17
17
 
18
- def self.refresh_encryption_secrets(opts = {})
18
+ public_class_method def self.refresh_encryption_secrets(opts = {})
19
19
  file = opts[:file].to_s.scrub if File.exist?(opts[:file].to_s.scrub)
20
20
  key = opts[:key]
21
21
  iv = opts[:iv]
@@ -234,83 +234,6 @@ module PWN
234
234
  raise e
235
235
  end
236
236
 
237
- # Supported Method Parameters::
238
- # PWN::Plugins::Vault.refresh_config(
239
- # yaml_config_path: 'required - full path to pwn.yaml file',
240
- # pi: 'optional - Pry instance (default: Pry)',
241
- # yaml_decryptor_path: 'optional - full path to decryption YAML file'
242
- # )
243
- public_class_method def self.refresh_config(opts = {})
244
- yaml_config_path = opts[:yaml_config_path]
245
-
246
- return false unless File.exist?(yaml_config_path)
247
-
248
- pi = opts[:pi]
249
- raise 'ERROR: Pry instance is required.' if pi.nil?
250
-
251
- is_encrypted = PWN::Plugins::Vault.file_encrypted?(file: yaml_config_path)
252
-
253
- if is_encrypted
254
- # TODO: Implement "something you know, something you have, && something you are?"
255
- yaml_decryptor_path = opts[:yaml_decryptor_path] ||= "#{Dir.home}/.pwn/pwn.decryptor.yaml"
256
- raise "ERROR: #{yaml_decryptor_path} does not exist." unless File.exist?(yaml_decryptor_path)
257
-
258
- yaml_decryptor = YAML.load_file(yaml_decryptor_path, symbolize_names: true)
259
-
260
- key = opts[:key] ||= yaml_decryptor[:key] ||= ENV.fetch('PWN_DECRYPTOR_KEY')
261
- key = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption Key') if key.nil?
262
-
263
- iv = opts[:iv] ||= yaml_decryptor[:iv] ||= ENV.fetch('PWN_DECRYPTOR_IV')
264
- iv = PWN::Plugins::AuthenticationHelper.mask_password(prompt: 'Decryption IV') if iv.nil?
265
-
266
- yaml_config = PWN::Plugins::Vault.dump(
267
- file: yaml_config_path,
268
- key: key,
269
- iv: iv
270
- )
271
- else
272
- yaml_config = YAML.load_file(yaml_config_path, symbolize_names: true)
273
- end
274
-
275
- valid_ai_engines = %i[
276
- grok
277
- openai
278
- ollama
279
- ]
280
-
281
- # Convert ai_engine to symbol and downcase to ensure stability
282
- pi.config.pwn = yaml_config
283
- engine = pi.config.pwn[:ai][:active].to_s.downcase.to_sym
284
- raise "ERROR: Unsupported AI Engine: #{engine} in #{yaml_config_path}. Supported AI Engines:\n#{valid_ai_engines.inspect}" unless valid_ai_engines.include?(engine)
285
-
286
- model = pi.config.pwn[:ai][engine][:model]
287
- system_role_content = pi.config.pwn[:ai][engine][:system_role_content]
288
-
289
- # Reset the ai response history on config refresh
290
- pi.config.pwn[:ai][engine][:response_history] = {
291
- id: '',
292
- object: '',
293
- model: model,
294
- usage: {},
295
- choices: [
296
- {
297
- role: 'system',
298
- content: system_role_content
299
- }
300
- ]
301
- }
302
-
303
- # These two lines should be immutable for the session
304
- pi.config.pwn[:yaml_config_path] = yaml_config_path
305
- pi.config.pwn[:yaml_decryptor_path] = yaml_decryptor_path if is_encrypted
306
-
307
- Pry.config.refresh = false
308
-
309
- true
310
- rescue StandardError => e
311
- raise e
312
- end
313
-
314
237
  # Author(s):: 0day Inc. <support@0dayinc.com>
315
238
 
316
239
  public_class_method def self.authors
@@ -363,12 +286,6 @@ module PWN
363
286
  file: 'required - file to check if encrypted'
364
287
  )
365
288
 
366
- #{self}.refresh_config(
367
- yaml_config_path: 'required - full path to pwn.yaml file',
368
- pi: 'optional - Pry instance (default: Pry)',
369
- yaml_decryptor_path: 'optional - full path to decryption YAML file'
370
- )
371
-
372
289
  #{self}.authors
373
290
  "
374
291
  end
@@ -14,13 +14,7 @@ module PWN
14
14
  # PWN::Reports::SAST.generate(
15
15
  # dir_path: 'optional - Directory path to save the report (defaults to .)',
16
16
  # results_hash: 'optional - Hash containing the results of the SAST analysis (defaults to empty hash structure)',
17
- # report_name: 'optional - Name of the report file (defaults to current directory name)',
18
- # ai_engine: 'optional - AI engine to use for analysis (:grok, :ollama, or :openai)',
19
- # ai_model: 'optionnal - AI Model to Use for Respective AI Engine (e.g., grok-4i-0709, chargpt-4o-latest, llama-3.1, etc.)',
20
- # ai_key: 'optional - AI Key/Token for Respective AI Engine',
21
- # ai_base_uri: 'optional - AI FQDN (Only Required for "ollama" AI Engine)',
22
- # ai_system_role_content: 'optional - AI System Role Content (Defaults to "Confidence score of 0-10 this is vulnerable (0 being not vulnerable, moving upwards in confidence of exploitation). Provide additional context to assist penetration tester assessment.")',
23
- # ai_temp: 'optional - AI Temperature (Defaults to 0.1)'
17
+ # report_name: 'optional - Name of the report file (defaults to current directory name)'
24
18
  # )
25
19
 
26
20
  public_class_method def self.generate(opts = {})
@@ -31,28 +25,21 @@ module PWN
31
25
  }
32
26
  report_name = opts[:report_name] ||= File.basename(Dir.pwd)
33
27
 
34
- ai_engine = opts[:ai_engine]
35
- if ai_engine
36
- ai_engine = ai_engine.to_s.to_sym
37
- valid_ai_engines = %i[grok ollama openai]
38
- raise "ERROR: Invalid AI Engine. Valid options are: #{valid_ai_engines.join(', ')}" unless valid_ai_engines.include?(ai_engine)
28
+ ai_instrospection = PWN::CONFIG[:ai][:introspection]
29
+ if ai_instrospection
30
+ engine = PWN::CONFIG[:ai][:active].to_s.downcase.to_sym
31
+ base_uri = PWN::CONFIG[:ai][engine][:base_uri]
32
+ model = PWN::CONFIG[:ai][engine][:model]
33
+ key = PWN::CONFIG[:ai][engine][:key]
34
+ system_role_content = PWN::CONFIG[:ai][engine][:system_role_content]
35
+ temp = PWN::CONFIG[:ai][engine][:temp]
39
36
 
40
- ai_base_uri = opts[:ai_base_uri]
41
- raise 'ERROR: FQDN for Ollama AI engine is required.' if ai_engine == :ollama && ai_base_uri.nil?
42
-
43
- ai_model = opts[:ai_model]
44
- raise 'ERROR: AI Model is required for AI engine ollama.' if ai_engine == :ollama && ai_model.nil?
45
-
46
- ai_key = opts[:ai_key] ||= PWN::Plugins::AuthenticationHelper.mask_password(prompt: "#{ai_engine} Token")
47
- ai_system_role_content = opts[:ai_system_role_content] ||= 'Your sole purpose is to analyze source code snippets and generate an Exploit Prediction Scoring System (EPSS) score between 0% - 100%. Just generate a score unless score is higher than 75% in which a code fic should also be included.'
48
- ai_temp = opts[:ai_temp] ||= 0.1
49
-
50
- puts "Analyzing source code using AI engine: #{ai_engine}\nModel: #{ai_model}\nSystem Role Content: #{ai_system_role_content}\nTemperature: #{ai_temp}"
37
+ puts "Analyzing source code using AI engine: #{engine}\nModel: #{model}\nSystem Role Content: #{system_role_content}\nTemperature: #{temp}"
51
38
  end
52
39
 
53
40
  # Calculate percentage of AI analysis based on the number of entries
54
41
  total_entries = results_hash[:data].sum { |entry| entry[:line_no_and_contents].size }
55
- puts "Total entries to analyze: #{total_entries}" if ai_engine
42
+ puts "Total entries to analyze: #{total_entries}" if engine
56
43
 
57
44
  percent_complete = 0.0
58
45
  entry_count = 0
@@ -79,37 +66,39 @@ module PWN
79
66
  response = nil
80
67
  author = src_detail[:author].to_s.scrub.chomp.strip
81
68
 
82
- case ai_engine
83
- when :grok
84
- response = PWN::AI::Grok.chat(
85
- base_uri: ai_base_uri,
86
- token: ai_key,
87
- model: ai_model,
88
- system_role_content: ai_system_role_content,
89
- temp: ai_temp,
90
- request: request.chomp,
91
- spinner: false
92
- )
93
- when :ollama
94
- response = PWN::AI::Ollama.chat(
95
- base_uri: ai_base_uri,
96
- token: ai_key,
97
- model: ai_model,
98
- system_role_content: ai_system_role_content,
99
- temp: ai_temp,
100
- request: request.chomp,
101
- spinner: false
102
- )
103
- when :openai
104
- response = PWN::AI::OpenAI.chat(
105
- base_uri: ai_base_uri,
106
- token: ai_key,
107
- model: ai_model,
108
- system_role_content: ai_system_role_content,
109
- temp: ai_temp,
110
- request: request.chomp,
111
- spinner: false
112
- )
69
+ if ai_instrospection
70
+ case engine
71
+ when :grok
72
+ response = PWN::AI::Grok.chat(
73
+ base_uri: base_uri,
74
+ token: key,
75
+ model: model,
76
+ system_role_content: system_role_content,
77
+ temp: temp,
78
+ request: request.chomp,
79
+ spinner: false
80
+ )
81
+ when :ollama
82
+ response = PWN::AI::Ollama.chat(
83
+ base_uri: base_uri,
84
+ token: key,
85
+ model: model,
86
+ system_role_content: system_role_content,
87
+ temp: temp,
88
+ request: request.chomp,
89
+ spinner: false
90
+ )
91
+ when :openai
92
+ response = PWN::AI::OpenAI.chat(
93
+ base_uri: base_uri,
94
+ token: key,
95
+ model: model,
96
+ system_role_content: system_role_content,
97
+ temp: temp,
98
+ request: request.chomp,
99
+ spinner: false
100
+ )
101
+ end
113
102
  end
114
103
 
115
104
  ai_analysis = nil
@@ -118,6 +107,7 @@ module PWN
118
107
  ai_analysis = response[:choices].last[:content] if response[:choices].last.keys.include?(:content)
119
108
  # puts "AI Analysis Progress: #{percent_complete}% Line: #{line_no} | Author: #{author} | AI Analysis: #{ai_analysis}\n\n\n" if ai_analysis
120
109
  end
110
+ # TODO: Make results prettier in the HTML report
121
111
  src_detail[:ai_analysis] = ai_analysis.to_s.scrub.chomp.strip
122
112
 
123
113
  spin.update(
data/lib/pwn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PWN
4
- VERSION = '0.5.429'
4
+ VERSION = '0.5.431'
5
5
  end
data/lib/pwn.rb CHANGED
@@ -12,19 +12,22 @@ module PWN
12
12
  autoload :AWS, 'pwn/aws'
13
13
  autoload :Banner, 'pwn/banner'
14
14
  autoload :Blockchain, 'pwn/blockchain'
15
+ autoload :Config, 'pwn/config'
15
16
  autoload :FFI, 'pwn/ffi'
16
17
  autoload :Plugins, 'pwn/plugins'
17
18
  autoload :Reports, 'pwn/reports'
18
19
  autoload :SAST, 'pwn/sast'
19
20
  autoload :WWW, 'pwn/www'
20
- # TODO: If pwn.yaml is present, attempt to decrypt it, and initialize the YAML config
21
- # Do this within PWN::Plugins::AuthenticationHelper?
22
21
 
23
22
  # Display a List of Every PWN Module
24
23
 
25
24
  public_class_method def self.help
26
25
  constants.sort
27
26
  end
27
+
28
+ # Initialize PWN configuration file
29
+ # PWN::CONFIG is the constant that stores the configuration data
30
+ PWN::Config.refresh
28
31
  rescue StandardError => e
29
32
  puts e.backtrace
30
33
  raise e
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe PWN::Config do
6
+ it 'should return data for refresh method' do
7
+ config_response = PWN::Config.refresh
8
+ expect(config_response).not_to be_nil
9
+ end
10
+ end
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.429
4
+ version: 0.5.431
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.
@@ -1832,6 +1832,7 @@ files:
1832
1832
  - lib/pwn/blockchain.rb
1833
1833
  - lib/pwn/blockchain/btc.rb
1834
1834
  - lib/pwn/blockchain/eth.rb
1835
+ - lib/pwn/config.rb
1835
1836
  - lib/pwn/ffi.rb
1836
1837
  - lib/pwn/ffi/stdio.rb
1837
1838
  - lib/pwn/plugins.rb
@@ -2180,6 +2181,7 @@ files:
2180
2181
  - spec/lib/pwn/blockchain/btc_spec.rb
2181
2182
  - spec/lib/pwn/blockchain/eth_spec.rb
2182
2183
  - spec/lib/pwn/blockchain_spec.rb
2184
+ - spec/lib/pwn/config_spec.rb
2183
2185
  - spec/lib/pwn/ffi/stdio_spec.rb
2184
2186
  - spec/lib/pwn/ffi_spec.rb
2185
2187
  - spec/lib/pwn/plugins/android_spec.rb