pwn 0.5.426 → 0.5.428
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/README.md +3 -3
- data/lib/pwn/plugins/repl.rb +48 -51
- data/lib/pwn/plugins/vault.rb +29 -39
- data/lib/pwn/reports/sast.rb +10 -3
- data/lib/pwn/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb4a896d76b2eff5600f7e7464227b6223a4287e4cd4e6fba7a60df29d40bc64
|
4
|
+
data.tar.gz: 93dbd97045e6ac60c4a46446bb8c681629ab462186092657e4f75bdb975eb7c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50aaa55f8d403788d10610c52a877bc99494678c0606b9d83fcdf623470faae899bfa6e095e0de4114832575184308d5a9303d0b5f1f15d0038f3e13b5c9e1b1
|
7
|
+
data.tar.gz: fdc901980719c87ac59a14e247f352074271ed8b43572bdbd446462fb621e772db5cb065c117c07b55c68caee5bd559094e536c5316c958af8fcab1f5f7ad602
|
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.428]: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.428]: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.428]: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/plugins/repl.rb
CHANGED
@@ -18,7 +18,11 @@ module PWN
|
|
18
18
|
mode = opts[:mode]
|
19
19
|
|
20
20
|
proc do |_target_self, _nest_level, pi|
|
21
|
-
|
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_for_repl(opts)
|
25
|
+
end
|
22
26
|
|
23
27
|
pi.config.pwn_repl_line += 1
|
24
28
|
line_pad = format(
|
@@ -34,8 +38,8 @@ module PWN
|
|
34
38
|
dchars = "\001\e[33m\002***\001\e[0m\002" if mode == :splat
|
35
39
|
|
36
40
|
if pi.config.pwn_asm
|
37
|
-
arch = pi.config.
|
38
|
-
endian = pi.config.
|
41
|
+
arch = pi.config.pwn[:asm][:arch] ||= PWN::Plugins::DetectOS.arch
|
42
|
+
endian = pi.config.pwn[:asm][:endian] ||= PWN::Plugins::DetectOS.endian
|
39
43
|
|
40
44
|
pi.config.prompt_name = "pwn.asm:#{arch}/#{endian}"
|
41
45
|
name = "\001\e[1m\002\001\e[37m\002#{pi.config.prompt_name}\001\e[0m\002"
|
@@ -44,10 +48,10 @@ module PWN
|
|
44
48
|
end
|
45
49
|
|
46
50
|
if pi.config.pwn_ai
|
47
|
-
ai_engine = pi.config.
|
48
|
-
model = pi.config.
|
49
|
-
system_role_content = pi.config.
|
50
|
-
temp = pi.config.
|
51
|
+
ai_engine = pi.config.pwn[:ai_engine]
|
52
|
+
model = pi.config.pwn[ai_engine][:model]
|
53
|
+
system_role_content = pi.config.pwn[ai_engine][:system_role_content]
|
54
|
+
temp = pi.config.pwn[ai_engine][:temp]
|
51
55
|
pname = "pwn.ai:#{ai_engine}"
|
52
56
|
pname = "pwn.ai:#{ai_engine}/#{model}" if model
|
53
57
|
pname = "pwn.ai:#{ai_engine}/#{model}.SPEAK" if pi.config.pwn_ai_speak
|
@@ -173,10 +177,10 @@ module PWN
|
|
173
177
|
|
174
178
|
reply = nil
|
175
179
|
response_history = nil
|
176
|
-
shared_chan = pi.config.
|
180
|
+
shared_chan = pi.config.pwn[:irc][:shared_chan]
|
177
181
|
mem_chan = '#mem'
|
178
|
-
ai_agents = pi.config.
|
179
|
-
ai_agents_arr = pi.config.
|
182
|
+
ai_agents = pi.config.pwn[:irc][:ai_agent_nicks]
|
183
|
+
ai_agents_arr = pi.config.pwn[:irc][:ai_agent_nicks].keys
|
180
184
|
total_ai_agents = ai_agents_arr.length
|
181
185
|
mutex = Mutex.new
|
182
186
|
PWN::Plugins::ThreadPool.fill(
|
@@ -302,15 +306,12 @@ module PWN
|
|
302
306
|
next unless dm_agent == nick
|
303
307
|
|
304
308
|
response_history = ai_agents[dm_agent.to_sym][:response_history]
|
305
|
-
ai_engine = pi.config.
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
model = pi.config.pwn_ai_model
|
312
|
-
system_role_content = pi.config.pwn_ai_system_role_content
|
313
|
-
temp = pi.config.pwn_ai_temp
|
309
|
+
ai_engine = pi.config.pwn[:ai_engine]
|
310
|
+
base_uri = pi.config.pwn[ai_engine][:base_uri]
|
311
|
+
key = pi.config.pwn[ai_engine][:key] ||= ''
|
312
|
+
temp = pi.config.pwn[ai_engine][:temp]
|
313
|
+
model = pi.config.pwn[ai_engine][:model]
|
314
|
+
system_role_content = pi.config.pwn[ai_engine][:system_role_content]
|
314
315
|
|
315
316
|
users_in_chan = PWN::Plugins::IRC.names(
|
316
317
|
irc_obj: irc_obj,
|
@@ -344,10 +345,10 @@ module PWN
|
|
344
345
|
case ai_engine
|
345
346
|
when :grok
|
346
347
|
response = PWN::AI::Grok.chat(
|
347
|
-
base_uri:
|
348
|
-
token:
|
348
|
+
base_uri: base_uri,
|
349
|
+
token: key,
|
349
350
|
model: model,
|
350
|
-
temp:
|
351
|
+
temp: temp,
|
351
352
|
system_role_content: system_role_content,
|
352
353
|
request: request,
|
353
354
|
response_history: response_history,
|
@@ -355,10 +356,10 @@ module PWN
|
|
355
356
|
)
|
356
357
|
when :ollama
|
357
358
|
response = PWN::AI::Ollama.chat(
|
358
|
-
base_uri:
|
359
|
-
token:
|
359
|
+
base_uri: base_uri,
|
360
|
+
token: key,
|
360
361
|
model: model,
|
361
|
-
temp:
|
362
|
+
temp: temp,
|
362
363
|
system_role_content: system_role_content,
|
363
364
|
request: request,
|
364
365
|
response_history: response_history,
|
@@ -366,10 +367,10 @@ module PWN
|
|
366
367
|
)
|
367
368
|
when :openai
|
368
369
|
response = PWN::AI::OpenAI.chat(
|
369
|
-
base_uri:
|
370
|
-
token:
|
370
|
+
base_uri: base_uri,
|
371
|
+
token: key,
|
371
372
|
model: model,
|
372
|
-
temp:
|
373
|
+
temp: temp,
|
373
374
|
system_role_content: system_role_content,
|
374
375
|
request: request,
|
375
376
|
response_history: response_history,
|
@@ -434,7 +435,7 @@ module PWN
|
|
434
435
|
|
435
436
|
# TODO: Use TLS for IRC Connections
|
436
437
|
# Use an IRC nCurses CLI Client
|
437
|
-
ui_nick = pi.config.
|
438
|
+
ui_nick = pi.config.pwn[:irc][:ui_nick]
|
438
439
|
join_channels = ai_agents_arr.map { |ai_chan| "##{ai_chan}" }.join(',')
|
439
440
|
|
440
441
|
cmd0 = "/server add pwn #{host}/#{port} -notls"
|
@@ -538,10 +539,8 @@ module PWN
|
|
538
539
|
|
539
540
|
# Initialize pwn.yaml Configuration using :before_session Hook
|
540
541
|
Pry.config.hooks.add_hook(:before_session, :init_opts) do |_output, _binding, pi|
|
542
|
+
# puts "Refreshing PWN env via #{opts[:yaml_config_path]}"
|
541
543
|
opts[:pi] = pi
|
542
|
-
Pry.config.yaml_config_path = opts[:yaml_config_path]
|
543
|
-
Pry.config.yaml_decryptor_path = opts[:yaml_decryptor_path]
|
544
|
-
|
545
544
|
PWN::Plugins::Vault.refresh_config_for_repl(opts)
|
546
545
|
end
|
547
546
|
|
@@ -549,8 +548,8 @@ module PWN
|
|
549
548
|
if pi.config.pwn_asm && !request.chomp.empty?
|
550
549
|
request = pi.input.line_buffer
|
551
550
|
|
552
|
-
arch = pi.config.
|
553
|
-
endian = pi.config.
|
551
|
+
arch = pi.config.pwn[:asm][:arch]
|
552
|
+
endian = pi.config.pwn[:asm][:endian]
|
554
553
|
|
555
554
|
# Analyze request to determine if it should be processed as opcodes or asm.
|
556
555
|
straight_hex = /^[a-fA-F0-9\s]+$/
|
@@ -586,29 +585,27 @@ module PWN
|
|
586
585
|
if pi.config.pwn_ai && !request.chomp.empty?
|
587
586
|
request = pi.input.line_buffer.to_s
|
588
587
|
debug = pi.config.pwn_ai_debug
|
589
|
-
ai_engine = pi.config.
|
590
|
-
|
591
|
-
|
592
|
-
if
|
593
|
-
|
588
|
+
ai_engine = pi.config.pwn[:ai_engine]
|
589
|
+
base_uri = pi.config.pwn[ai_engine][:base_uri]
|
590
|
+
key = pi.config.pwn[ai_engine][:key] ||= ''
|
591
|
+
if key.empty?
|
592
|
+
key = PWN::Plugins::AuthenticationHelper.mask_password(
|
594
593
|
prompt: 'pwn-ai Key'
|
595
594
|
)
|
596
|
-
pi.config.
|
595
|
+
pi.config.pwn[ai_engine][:key] = key
|
597
596
|
end
|
598
597
|
|
599
598
|
response_history = pi.config.pwn_ai_response_history
|
600
599
|
speak_answer = pi.config.pwn_ai_speak
|
601
|
-
model = pi.config.
|
602
|
-
system_role_content = pi.config.
|
603
|
-
temp = pi.config.
|
604
|
-
|
605
|
-
ai_base_uri = pi.config.pwn_ai_base_uri
|
600
|
+
model = pi.config.pwn[ai_engine][:model]
|
601
|
+
system_role_content = pi.config.pwn[ai_engine][:system_role_content]
|
602
|
+
temp = pi.config.pwn[ai_engine][:temp]
|
606
603
|
|
607
604
|
case ai_engine
|
608
605
|
when :grok
|
609
606
|
response = PWN::AI::Grok.chat(
|
610
|
-
base_uri:
|
611
|
-
token:
|
607
|
+
base_uri: base_uri,
|
608
|
+
token: key,
|
612
609
|
model: model,
|
613
610
|
system_role_content: system_role_content,
|
614
611
|
temp: temp,
|
@@ -619,8 +616,8 @@ module PWN
|
|
619
616
|
)
|
620
617
|
when :ollama
|
621
618
|
response = PWN::AI::Ollama.chat(
|
622
|
-
base_uri:
|
623
|
-
token:
|
619
|
+
base_uri: base_uri,
|
620
|
+
token: key,
|
624
621
|
model: model,
|
625
622
|
system_role_content: system_role_content,
|
626
623
|
temp: temp,
|
@@ -631,8 +628,8 @@ module PWN
|
|
631
628
|
)
|
632
629
|
when :openai
|
633
630
|
response = PWN::AI::OpenAI.chat(
|
634
|
-
base_uri:
|
635
|
-
token:
|
631
|
+
base_uri: base_uri,
|
632
|
+
token: key,
|
636
633
|
model: model,
|
637
634
|
system_role_content: system_role_content,
|
638
635
|
temp: temp,
|
data/lib/pwn/plugins/vault.rb
CHANGED
@@ -173,7 +173,7 @@ module PWN
|
|
173
173
|
system(relative_editor, file)
|
174
174
|
|
175
175
|
# If the Pry object exists, set refresh_config to true
|
176
|
-
Pry.config.
|
176
|
+
Pry.config.refresh = true if defined?(Pry)
|
177
177
|
|
178
178
|
encrypt(
|
179
179
|
file: file,
|
@@ -245,7 +245,8 @@ module PWN
|
|
245
245
|
|
246
246
|
return false unless File.exist?(yaml_config_path)
|
247
247
|
|
248
|
-
pi = opts[:pi]
|
248
|
+
pi = opts[:pi]
|
249
|
+
raise 'ERROR: Pry instance is required.' if pi.nil?
|
249
250
|
|
250
251
|
is_encrypted = PWN::Plugins::Vault.file_encrypted?(file: yaml_config_path)
|
251
252
|
|
@@ -270,52 +271,41 @@ module PWN
|
|
270
271
|
else
|
271
272
|
yaml_config = YAML.load_file(yaml_config_path, symbolize_names: true)
|
272
273
|
end
|
273
|
-
pi.config.p = yaml_config
|
274
|
-
Pry.config.p = yaml_config
|
275
274
|
|
276
275
|
valid_ai_engines = %i[
|
277
276
|
grok
|
278
277
|
openai
|
279
278
|
ollama
|
280
279
|
]
|
281
|
-
ai_engine = yaml_config[:ai_engine].to_s.downcase.to_sym
|
282
280
|
|
281
|
+
# Convert ai_engine to symbol and downcase to ensure stability
|
282
|
+
yaml_config[:ai_engine] = yaml_config[:ai_engine].to_s.downcase.to_sym
|
283
|
+
pi.config.pwn = yaml_config
|
284
|
+
ai_engine = pi.config.pwn[:ai_engine]
|
283
285
|
raise "ERROR: Unsupported AI Engine: #{ai_engine} in #{yaml_config_path}. Supported AI Engines:\n#{valid_ai_engines.inspect}" unless valid_ai_engines.include?(ai_engine)
|
284
286
|
|
285
|
-
pi.config.
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
pi.config.
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
Pry.config.pwn_asm_endian = pi.config.pwn_asm_endian
|
308
|
-
|
309
|
-
pi.config.pwn_irc = pi.config.p[:irc]
|
310
|
-
Pry.config.pwn_irc = pi.config.pwn_irc
|
311
|
-
|
312
|
-
pi.config.pwn_hunter = pi.config.p[:hunter][:api_key]
|
313
|
-
Pry.config.pwn_hunter = pi.config.pwn_hunter
|
314
|
-
|
315
|
-
pi.config.pwn_shodan = pi.config.p[:shodan][:api_key]
|
316
|
-
Pry.config.pwn_shodan = pi.config.pwn_shodan
|
317
|
-
|
318
|
-
Pry.config.refresh_config = false
|
287
|
+
model = pi.config.pwn[ai_engine][:model]
|
288
|
+
system_role_content = pi.config.pwn[ai_engine][:system_role_content]
|
289
|
+
|
290
|
+
# Reset the ai response history for new configurations
|
291
|
+
pi.config.pwn_ai_response_history = {
|
292
|
+
id: '',
|
293
|
+
object: '',
|
294
|
+
model: model,
|
295
|
+
usage: {},
|
296
|
+
choices: [
|
297
|
+
{
|
298
|
+
role: 'system',
|
299
|
+
content: system_role_content
|
300
|
+
}
|
301
|
+
]
|
302
|
+
}
|
303
|
+
|
304
|
+
# These two lines should be immutable for the session
|
305
|
+
pi.config.pwn[:yaml_config_path] = yaml_config_path
|
306
|
+
pi.config.pwn[:yaml_decryptor_path] = yaml_decryptor_path if is_encrypted
|
307
|
+
|
308
|
+
Pry.config.refresh = false
|
319
309
|
|
320
310
|
true
|
321
311
|
rescue StandardError => e
|
data/lib/pwn/reports/sast.rb
CHANGED
@@ -44,7 +44,7 @@ module PWN
|
|
44
44
|
raise 'ERROR: AI Model is required for AI engine ollama.' if ai_engine == :ollama && ai_model.nil?
|
45
45
|
|
46
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] ||= '
|
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
48
|
ai_temp = opts[:ai_temp] ||= 0.1
|
49
49
|
|
50
50
|
puts "Analyzing source code using AI engine: #{ai_engine}\nModel: #{ai_model}\nSystem Role Content: #{ai_system_role_content}\nTemperature: #{ai_temp}"
|
@@ -64,12 +64,19 @@ module PWN
|
|
64
64
|
spin.auto_spin
|
65
65
|
|
66
66
|
results_hash[:data].each do |hash_line|
|
67
|
+
git_repo_root_uri = hash_line[:filename][:git_repo_root_uri]
|
68
|
+
filename = hash_line[:filename][:entry]
|
67
69
|
hash_line[:line_no_and_contents].each do |src_detail|
|
68
70
|
entry_count += 1
|
69
71
|
percent_complete = (entry_count.to_f / total_entries * 100).round(2)
|
70
|
-
request = src_detail[:contents]
|
71
|
-
response = nil
|
72
72
|
line_no = src_detail[:line_no]
|
73
|
+
source_code_snippet = src_detail[:contents]
|
74
|
+
request = {
|
75
|
+
scm_uri: "#{git_repo_root_uri}/#{filename}",
|
76
|
+
line: line_no,
|
77
|
+
source_code_snippet: source_code_snippet
|
78
|
+
}.to_json
|
79
|
+
response = nil
|
73
80
|
author = src_detail[:author].to_s.scrub.chomp.strip
|
74
81
|
|
75
82
|
case ai_engine
|
data/lib/pwn/version.rb
CHANGED