pwn 0.5.721 → 0.5.722
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/etc/default_skills/pwn/ai/agent/learning/SKILL.md +2 -0
- data/etc/default_skills/pwn/ai/agent/metrics/SKILL.md +1 -0
- data/etc/default_skills/pwn/ai/agent/mistakes/SKILL.md +2 -0
- data/etc/default_skills/pwn/plugins/exploit_dev/SKILL.md +1 -0
- data/etc/default_skills/pwn/plugins/gdb/SKILL.md +1 -0
- data/etc/default_skills/pwn/plugins/jobs/SKILL.md +1 -0
- data/lib/pwn/ai/agent/dispatch.rb +9 -0
- data/lib/pwn/ai/agent/learning.rb +35 -0
- data/lib/pwn/ai/agent/loop.rb +11 -1
- data/lib/pwn/ai/agent/metrics.rb +18 -0
- data/lib/pwn/ai/agent/mistakes.rb +67 -1
- data/lib/pwn/ai/agent/reward.rb +11 -7
- data/lib/pwn/ai/agent/tools/artifacts.rb +8 -3
- data/lib/pwn/plugins/artifact_registry.rb +27 -11
- data/lib/pwn/plugins/binary_parser.rb +4 -1
- data/lib/pwn/plugins/exploit_dev.rb +15 -0
- data/lib/pwn/plugins/gdb.rb +17 -0
- data/lib/pwn/plugins/jobs.rb +19 -0
- data/lib/pwn/plugins/repl.rb +6 -1
- data/lib/pwn/version.rb +1 -1
- data/spec/lib/pwn/ai/agent/mistakes_spec.rb +10 -0
- data/spec/lib/pwn/ai/agent/reward_spec.rb +12 -0
- data/spec/lib/pwn/plugins/artifact_registry_spec.rb +9 -0
- data/third_party/pwn_rdoc.jsonl +9 -0
- 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: 31f54d1cd6a7bfbc4cef3bcc989650930b1b31bbf2bbc47654b20d6f20158775
|
|
4
|
+
data.tar.gz: 50bfda31eecd4b99d17324a8c4c548f14b8df10561c183f27bc9e7157c8f88bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3a43118f36da1f9712dbfb908b5f0c9d4650d3bfde63239240d7c9cefcc50d29d78468e14e9cd9bf44f9fdba5df971b48659b348619dc79a7e17667028930025
|
|
7
|
+
data.tar.gz: 867d72ec34f85caaf18fa5abeb38b466d5663c1361becf17cb4af87115dd0d45411527b0f5616dd54874c241544416fb0b9427f16476248ed38a864b3951daef
|
|
@@ -37,6 +37,7 @@ PWN::AI::Agent::Mistakes.load(opts)
|
|
|
37
37
|
- `save`
|
|
38
38
|
- `signature`
|
|
39
39
|
- `error_class`
|
|
40
|
+
- `family`
|
|
40
41
|
- `find`
|
|
41
42
|
- `for_tool`
|
|
42
43
|
- `record`
|
|
@@ -48,6 +49,7 @@ PWN::AI::Agent::Mistakes.load(opts)
|
|
|
48
49
|
- `operator_inbox`
|
|
49
50
|
- `to_context`
|
|
50
51
|
- `correction_hint`
|
|
52
|
+
- `note_hint_outcome`
|
|
51
53
|
- `correction`
|
|
52
54
|
- `check_user_correction`
|
|
53
55
|
- `lean`
|
|
@@ -72,6 +72,15 @@ module PWN
|
|
|
72
72
|
error: 'refused: memory_remember/skills_update text copied from last tool output'
|
|
73
73
|
)
|
|
74
74
|
end
|
|
75
|
+
if blob.match?(/open_sockraw|sockraw/) && defined?(PWN::Plugins::PreflightChecker) &&
|
|
76
|
+
PWN::Plugins::PreflightChecker.respond_to?(:cap_net_raw?) && !PWN::Plugins::PreflightChecker.cap_net_raw?
|
|
77
|
+
return JSON.generate(
|
|
78
|
+
success: false,
|
|
79
|
+
error: 'capability missing CAP_NET_RAW',
|
|
80
|
+
substitute: 'PWN::Plugins::Packet.tcp_connect_scan',
|
|
81
|
+
code: 'CAP_DENY'
|
|
82
|
+
)
|
|
83
|
+
end
|
|
75
84
|
result = entry.handler.call(args)
|
|
76
85
|
result = ToolGuard.quarantine_output(text: result) if defined?(ToolGuard) && result.is_a?(String) && ToolGuard.respond_to?(:quarantine_output)
|
|
77
86
|
note_taint(text: result)
|
|
@@ -26,6 +26,7 @@ module PWN
|
|
|
26
26
|
# restarts and is shared by every future session.
|
|
27
27
|
module Learning
|
|
28
28
|
LEARNING_FILE = File.join(Dir.home, '.pwn', 'learning.jsonl')
|
|
29
|
+
DISPUTED_FILE = File.join(Dir.home, '.pwn', 'learning', 'disputed.jsonl')
|
|
29
30
|
LESSONS_FILE = File.join(Dir.home, '.pwn', 'lessons.json')
|
|
30
31
|
FINETUNE_DIR = File.join(Dir.home, '.pwn', 'finetune')
|
|
31
32
|
# P0 — post-answer introspect must not train "stop early" while
|
|
@@ -138,6 +139,12 @@ module PWN
|
|
|
138
139
|
entry[:success] = true
|
|
139
140
|
success = true
|
|
140
141
|
end
|
|
142
|
+
check = consistency_check(details: details, success: success, rationale: opts[:rationale])
|
|
143
|
+
if check == :disputed
|
|
144
|
+
entry[:status] = 'disputed'
|
|
145
|
+
disputed_save(entry: entry)
|
|
146
|
+
return entry
|
|
147
|
+
end
|
|
141
148
|
FileUtils.mkdir_p(File.dirname(LEARNING_FILE))
|
|
142
149
|
File.open(LEARNING_FILE, 'a') { |f| f.puts(JSON.generate(entry)) }
|
|
143
150
|
maybe_prune_outcomes!
|
|
@@ -159,6 +166,22 @@ module PWN
|
|
|
159
166
|
entry
|
|
160
167
|
end
|
|
161
168
|
|
|
169
|
+
public_class_method def self.consistency_check(opts = {})
|
|
170
|
+
details = "#{opts[:details]} #{opts[:rationale]}"
|
|
171
|
+
success = opts[:success]
|
|
172
|
+
return :disputed if details.match?(/\bPASS\b/) && success == false
|
|
173
|
+
return :disputed if details.match?(/\bFAIL\b/) && success == true && !details.match?(/\bPASS\b/)
|
|
174
|
+
|
|
175
|
+
:ok
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
public_class_method def self.disputed_save(opts = {})
|
|
179
|
+
entry = opts[:entry] || {}
|
|
180
|
+
FileUtils.mkdir_p(File.dirname(DISPUTED_FILE))
|
|
181
|
+
File.open(DISPUTED_FILE, 'a') { |f| f.puts(JSON.generate(entry)) }
|
|
182
|
+
entry
|
|
183
|
+
end
|
|
184
|
+
|
|
162
185
|
# Supported Method Parameters::
|
|
163
186
|
# rows = PWN::AI::Agent::Learning.outcomes(
|
|
164
187
|
# limit: 'optional - max entries returned newest-first (default 50)',
|
|
@@ -2081,6 +2104,18 @@ module PWN
|
|
|
2081
2104
|
include_demoted: 'optional - include demoted lessons (defaults to false)'
|
|
2082
2105
|
)
|
|
2083
2106
|
|
|
2107
|
+
# Refuse PASS+success:false rows; they go to the disputed queue.
|
|
2108
|
+
#{self}.consistency_check(
|
|
2109
|
+
details: 'optional - details string that may contain PASS/FAIL',
|
|
2110
|
+
rationale: 'optional - judge rationale text',
|
|
2111
|
+
success: 'required - boolean success flag'
|
|
2112
|
+
)
|
|
2113
|
+
|
|
2114
|
+
# Append a disputed outcome to ~/.pwn/learning/disputed.jsonl.
|
|
2115
|
+
#{self}.disputed_save(
|
|
2116
|
+
entry: 'required - Hash of the disputed learning row'
|
|
2117
|
+
)
|
|
2118
|
+
|
|
2084
2119
|
# Print the AUTHOR(S) string for this module.
|
|
2085
2120
|
#{self}.authors
|
|
2086
2121
|
"
|
data/lib/pwn/ai/agent/loop.rb
CHANGED
|
@@ -1176,6 +1176,16 @@ module PWN
|
|
|
1176
1176
|
false
|
|
1177
1177
|
end
|
|
1178
1178
|
|
|
1179
|
+
private_class_method def self.session_tool_budget(opts = {})
|
|
1180
|
+
name = opts[:name].to_s
|
|
1181
|
+
result = opts[:result].to_s
|
|
1182
|
+
return 16_384 if name.match?(/decompile|binary_triage|artifact_read|exploitdev/)
|
|
1183
|
+
return 16_384 if name == 'pwn_eval' && result.match?(/r2 |objdump|xxd |pdf\b|afl-/)
|
|
1184
|
+
return 16_384 if name == 'shell' && result.match?(/objdump|xxd|radare|r2 |disassembl/)
|
|
1185
|
+
|
|
1186
|
+
1_024
|
|
1187
|
+
end
|
|
1188
|
+
|
|
1179
1189
|
# E1 — did the environment change under this tool? If Metrics CUSUM
|
|
1180
1190
|
# tripped for it in the last hour AND Extrospection.drift shows a
|
|
1181
1191
|
# toolchain/net/repo change, blame the WORLD not the AGENT.
|
|
@@ -3126,7 +3136,7 @@ module PWN
|
|
|
3126
3136
|
append_session(
|
|
3127
3137
|
session_id: session_id,
|
|
3128
3138
|
role: 'tool',
|
|
3129
|
-
content: "#{name} → #{result[0,
|
|
3139
|
+
content: "#{name} → #{result[0, session_tool_budget(name: name, result: result)]}"
|
|
3130
3140
|
)
|
|
3131
3141
|
end
|
|
3132
3142
|
|
data/lib/pwn/ai/agent/metrics.rb
CHANGED
|
@@ -156,6 +156,19 @@ module PWN
|
|
|
156
156
|
.sort_by { |r| [-r[:calls], -r[:success_rate]] }.first(limit)
|
|
157
157
|
end
|
|
158
158
|
|
|
159
|
+
public_class_method def self.snapshot(opts = {})
|
|
160
|
+
_day = opts[:day]
|
|
161
|
+
learn = defined?(Learning) ? Learning.stats : {}
|
|
162
|
+
{
|
|
163
|
+
success_rate: learn[:success_rate],
|
|
164
|
+
success_rate_orm: learn[:success_rate_orm],
|
|
165
|
+
success_rate_heur: learn[:success_rate_heur],
|
|
166
|
+
brier: (learn.dig(:calibration, :brier) if learn.is_a?(Hash)),
|
|
167
|
+
proxy_distrust: learn[:proxy_distrust],
|
|
168
|
+
tools: summary(limit: 8)
|
|
169
|
+
}
|
|
170
|
+
end
|
|
171
|
+
|
|
159
172
|
# Supported Method Parameters::
|
|
160
173
|
# ctx = PWN::AI::Agent::Metrics.to_context(
|
|
161
174
|
# limit: 'optional - cap number of tools included (default 8)',
|
|
@@ -814,6 +827,11 @@ module PWN
|
|
|
814
827
|
# Run reset and return its result
|
|
815
828
|
#{self}.reset
|
|
816
829
|
|
|
830
|
+
# Snapshot success rates per judge source for the LEARNING block.
|
|
831
|
+
#{self}.snapshot(
|
|
832
|
+
day: 'optional - reserved day key for rotation'
|
|
833
|
+
)
|
|
834
|
+
|
|
817
835
|
# Print the AUTHOR(S) string for this module.
|
|
818
836
|
#{self}.authors
|
|
819
837
|
"
|
|
@@ -127,6 +127,31 @@ module PWN
|
|
|
127
127
|
'other'
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
+
public_class_method def self.family(opts = {})
|
|
131
|
+
klass = error_class(opts)
|
|
132
|
+
case klass
|
|
133
|
+
when 'docker_registry_auth', 'auth_denied' then 'auth_denied'
|
|
134
|
+
when 'name_conflict' then 'name_conflict'
|
|
135
|
+
when 'parse_error' then 'parse_error'
|
|
136
|
+
when 'missing_path', 'enoent' then 'missing_path'
|
|
137
|
+
when 'perm_denied', 'socket_perm', 'eacces' then 'permission_capability'
|
|
138
|
+
when 'net_unreach' then 'network_unreachable'
|
|
139
|
+
when 'timeout' then 'timeout'
|
|
140
|
+
else 'other'
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
FAMILY_FIXES = {
|
|
145
|
+
'auth_denied' => 'check registry credentials / image name; do NOT ls paths',
|
|
146
|
+
'name_conflict' => 'rename the resource or remove the existing name; do NOT ls paths',
|
|
147
|
+
'parse_error' => 'fix template/JSON syntax; do NOT ls paths',
|
|
148
|
+
'missing_path' => 'Path missing. ls/test -e the parent first, then run. Do not retry the same missing path.',
|
|
149
|
+
'permission_capability' => 'Raw sockets need CAP_NET_RAW. Do not retry open_sockraw. Use connect-scan or Sock.',
|
|
150
|
+
'network_unreachable' => 'network unreachable; check routing/VPN, do not ls paths',
|
|
151
|
+
'timeout' => 'deadline too short; retry same payload with timeout += 180',
|
|
152
|
+
'other' => 'inspect the exact error class before retrying'
|
|
153
|
+
}.freeze
|
|
154
|
+
|
|
130
155
|
# Supported Method Parameters::
|
|
131
156
|
# entry = PWN::AI::Agent::Mistakes.find(
|
|
132
157
|
# signature: 'optional - exact signature to fetch',
|
|
@@ -630,10 +655,38 @@ module PWN
|
|
|
630
655
|
|
|
631
656
|
parts = ["seen #{m[:count]}× across #{Array(m[:sessions]).length} session(s), sig=#{m[:signature]}"]
|
|
632
657
|
parts << 'REGRESSED (previous fix did not hold)' if m[:regressed]
|
|
633
|
-
|
|
658
|
+
fam = family(error: opts[:error] || m[:error])
|
|
659
|
+
fam_fix = FAMILY_FIXES[fam]
|
|
660
|
+
stored = m[:fix].to_s.strip
|
|
661
|
+
stored = '' if stored.match?(%r{ls/test -e the parent}) && fam != 'missing_path'
|
|
662
|
+
stored = '' if m[:hint_confidence].to_f.negative?
|
|
663
|
+
stored = '' if stored.include?('[UNVERIFIED]')
|
|
664
|
+
hint = stored.empty? ? fam_fix : stored
|
|
665
|
+
parts << "KNOWN FIX: #{hint}" unless hint.to_s.empty?
|
|
634
666
|
"[pwn-ai/mistakes] #{parts.join(' | ')}"
|
|
635
667
|
end
|
|
636
668
|
|
|
669
|
+
public_class_method def self.note_hint_outcome(opts = {})
|
|
670
|
+
sig = (opts[:signature] || signature(tool: opts[:tool], error: opts[:error])).to_s
|
|
671
|
+
return nil if sig.empty?
|
|
672
|
+
|
|
673
|
+
store = load
|
|
674
|
+
m = store[sig.to_sym]
|
|
675
|
+
return nil unless m
|
|
676
|
+
|
|
677
|
+
m[:hint_outcomes] = m[:hint_outcomes].to_i + 1
|
|
678
|
+
unless opts[:helped]
|
|
679
|
+
m[:hint_misses] = m[:hint_misses].to_i + 1
|
|
680
|
+
if m[:hint_misses].to_i >= 3
|
|
681
|
+
m[:fix] = "[UNVERIFIED] #{m[:fix]}"
|
|
682
|
+
m[:hint_confidence] = -1.0
|
|
683
|
+
end
|
|
684
|
+
end
|
|
685
|
+
store[sig.to_sym] = m
|
|
686
|
+
save(store: store)
|
|
687
|
+
m
|
|
688
|
+
end
|
|
689
|
+
|
|
637
690
|
# Supported Method Parameters::
|
|
638
691
|
# bool = PWN::AI::Agent::Mistakes.correction?(request: user_text)
|
|
639
692
|
|
|
@@ -988,6 +1041,19 @@ module PWN
|
|
|
988
1041
|
signature: 'optional - signature value consumed by #effective_count'
|
|
989
1042
|
)
|
|
990
1043
|
|
|
1044
|
+
# Map an error string onto a coarse family (auth vs path vs parse).
|
|
1045
|
+
#{self}.family(
|
|
1046
|
+
error: 'required - raw error text'
|
|
1047
|
+
)
|
|
1048
|
+
|
|
1049
|
+
# Record whether an injected KNOWN FIX helped; demote after 3 misses.
|
|
1050
|
+
#{self}.note_hint_outcome(
|
|
1051
|
+
tool: 'optional - tool name',
|
|
1052
|
+
error: 'optional - raw error text',
|
|
1053
|
+
signature: 'optional - explicit signature',
|
|
1054
|
+
helped: 'optional - true when the hint resolved the failure'
|
|
1055
|
+
)
|
|
1056
|
+
|
|
991
1057
|
# Print the AUTHOR(S) string for this module.
|
|
992
1058
|
#{self}.authors
|
|
993
1059
|
"
|
data/lib/pwn/ai/agent/reward.rb
CHANGED
|
@@ -143,17 +143,21 @@ module PWN
|
|
|
143
143
|
# confidence handles that in the bandit blend.
|
|
144
144
|
eng = (PWN::Env.dig(:ai, :active) if defined?(PWN::Env)).to_s.downcase
|
|
145
145
|
local = eng == 'ollama' || eng.empty?
|
|
146
|
-
if v[:source].to_s == 'heuristic'
|
|
147
|
-
|
|
146
|
+
if v[:source].to_s == 'heuristic' || v[:source].to_s.start_with?('heuristic')
|
|
147
|
+
toolbacked = Array(trace).any?
|
|
148
|
+
v[:heuristic_class] = toolbacked ? :toolbacked : :textual
|
|
149
|
+
v[:source] = :heuristic
|
|
150
|
+
v[:confidence] = if toolbacked
|
|
151
|
+
local ? 0.55 : 0.7
|
|
152
|
+
else
|
|
153
|
+
local ? 0.35 : 0.5
|
|
154
|
+
end
|
|
148
155
|
raw = v[:score].to_f
|
|
149
156
|
v[:score_raw] = raw
|
|
150
|
-
|
|
151
|
-
# and pass-through non-capped heuristics via the default arm.
|
|
152
|
-
if local && raw > 0.15 && trace.empty? && raw >= 0.6 && final.length < 400
|
|
157
|
+
if !toolbacked && local && raw > 0.15 && trace.empty? && raw >= 0.6 && final.length < 400
|
|
153
158
|
v[:score] = [raw, 0.45].min
|
|
154
159
|
v[:rationale] = "#{v[:rationale]} | P1:local_no_trace_cap"
|
|
155
|
-
elsif local && raw > 0.15 && trace.length < 2 && raw >= 0.85
|
|
156
|
-
# thin-evidence local highs: mild shrink toward 0.5
|
|
160
|
+
elsif !toolbacked && local && raw > 0.15 && trace.length < 2 && raw >= 0.85
|
|
157
161
|
v[:score] = (0.5 + ((raw - 0.5) * 0.7)).round(3).clamp(0.0, 1.0)
|
|
158
162
|
else
|
|
159
163
|
v[:score] = raw
|
|
@@ -45,17 +45,22 @@ PWN::AI::Agent::Registry.register(
|
|
|
45
45
|
path: { type: 'string' },
|
|
46
46
|
offset: { type: 'integer' },
|
|
47
47
|
length: { type: 'integer' },
|
|
48
|
-
mode: { type: 'string', description: 'text|hex|base64' }
|
|
48
|
+
mode: { type: 'string', description: 'text|hex|base64' },
|
|
49
|
+
grep: { type: 'string' },
|
|
50
|
+
ref: { type: 'string' },
|
|
51
|
+
sha256: { type: 'string' }
|
|
49
52
|
},
|
|
50
53
|
required: %w[path]
|
|
51
54
|
}
|
|
52
55
|
},
|
|
53
56
|
handler: lambda { |args|
|
|
54
57
|
PWN::Plugins::ArtifactRegistry.read_page(
|
|
55
|
-
path: args[:path] || args['path'],
|
|
58
|
+
path: args[:path] || args['path'] || args[:ref] || args['ref'],
|
|
56
59
|
offset: args[:offset] || args['offset'],
|
|
57
60
|
length: args[:length] || args['length'],
|
|
58
|
-
mode: args[:mode] || args['mode']
|
|
61
|
+
mode: args[:mode] || args['mode'],
|
|
62
|
+
grep: args[:grep] || args['grep'],
|
|
63
|
+
sha256: args[:sha256] || args['sha256']
|
|
59
64
|
)
|
|
60
65
|
}
|
|
61
66
|
)
|
|
@@ -51,13 +51,26 @@ module PWN
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
public_class_method def self.read_page(opts = {})
|
|
54
|
-
path = opts[:path].to_s
|
|
54
|
+
path = (opts[:path] || opts[:ref]).to_s
|
|
55
55
|
raise 'ERROR: path is required' if path.empty?
|
|
56
56
|
raise "ERROR: file not found: #{path}" unless File.file?(path)
|
|
57
57
|
|
|
58
|
+
raise 'ERROR: sha256 mismatch' if opts[:sha256].to_s != '' && Digest::SHA256.file(path).hexdigest != opts[:sha256].to_s
|
|
59
|
+
|
|
60
|
+
grep = opts[:grep].to_s
|
|
61
|
+
unless grep.empty?
|
|
62
|
+
rx = Regexp.new(grep, Regexp::IGNORECASE)
|
|
63
|
+
hits = []
|
|
64
|
+
File.foreach(path).with_index(1) do |ln, i|
|
|
65
|
+
hits << { line: i, text: ln.chomp } if ln.match?(rx)
|
|
66
|
+
break if hits.length >= 50
|
|
67
|
+
end
|
|
68
|
+
return { path: path, grep: grep, matches: hits }
|
|
69
|
+
end
|
|
70
|
+
|
|
58
71
|
offset = opts[:offset].to_i
|
|
59
|
-
length = (opts[:length] ||
|
|
60
|
-
length =
|
|
72
|
+
length = (opts[:length] || 16_384).to_i
|
|
73
|
+
length = 16_384 if length <= 0
|
|
61
74
|
mode = (opts[:mode] || 'text').to_s
|
|
62
75
|
data = File.binread(path, length, offset).to_s
|
|
63
76
|
case mode
|
|
@@ -117,14 +130,6 @@ module PWN
|
|
|
117
130
|
path: 'required - filesystem path of a registered artifact'
|
|
118
131
|
)
|
|
119
132
|
|
|
120
|
-
# Page an artifact as text, hex, or base64 from an offset.
|
|
121
|
-
#{self}.read_page(
|
|
122
|
-
path: 'required - filesystem path of the artifact',
|
|
123
|
-
offset: 'optional - byte offset (defaults to 0)',
|
|
124
|
-
length: 'optional - byte count (defaults to 4096)',
|
|
125
|
-
mode: 'optional - text, hex, or base64 (defaults to text)'
|
|
126
|
-
)
|
|
127
|
-
|
|
128
133
|
# Store bytes under artifacts/sha256/<h2>/<hash> and append manifest.jsonl.
|
|
129
134
|
#{self}.put(
|
|
130
135
|
bytes: 'optional - raw bytes to store',
|
|
@@ -134,6 +139,17 @@ module PWN
|
|
|
134
139
|
kind: 'optional - artifact kind'
|
|
135
140
|
)
|
|
136
141
|
|
|
142
|
+
# Page an artifact; grep: searches lines, ref: alias for path.
|
|
143
|
+
#{self}.read_page(
|
|
144
|
+
path: 'required - filesystem path of the artifact',
|
|
145
|
+
ref: 'optional - alias for path',
|
|
146
|
+
offset: 'optional - byte offset (defaults to 0)',
|
|
147
|
+
length: 'optional - byte count (defaults to 16384)',
|
|
148
|
+
mode: 'optional - text, hex, or base64 (defaults to text)',
|
|
149
|
+
grep: 'optional - regex to search instead of paging',
|
|
150
|
+
sha256: 'optional - expected sha256 of the file'
|
|
151
|
+
)
|
|
152
|
+
|
|
137
153
|
# Print the AUTHOR(S) string for this module.
|
|
138
154
|
#{self}.authors
|
|
139
155
|
"
|
|
@@ -120,7 +120,10 @@ module PWN
|
|
|
120
120
|
end
|
|
121
121
|
body = summary.merge(path: path, sha256: sha)
|
|
122
122
|
File.write(art, JSON.pretty_generate(body))
|
|
123
|
-
|
|
123
|
+
facts_dir = File.join(Dir.home, '.pwn', 'engagements', 'default', 'binaries', sha)
|
|
124
|
+
FileUtils.mkdir_p(facts_dir)
|
|
125
|
+
File.write(File.join(facts_dir, 'facts.json'), JSON.pretty_generate(body))
|
|
126
|
+
body.merge(artifact: art, cached: false, facts: File.join(facts_dir, 'facts.json'))
|
|
124
127
|
end
|
|
125
128
|
|
|
126
129
|
public_class_method def self.diff(opts = {})
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'open3'
|
|
4
4
|
require 'fileutils'
|
|
5
|
+
require 'json'
|
|
5
6
|
|
|
6
7
|
module PWN
|
|
7
8
|
module Plugins
|
|
@@ -197,6 +198,14 @@ module PWN
|
|
|
197
198
|
{ path: out, triage: triage, gadgets: gadgets.first(8) }
|
|
198
199
|
end
|
|
199
200
|
|
|
201
|
+
public_class_method def self.from_crash(opts = {})
|
|
202
|
+
path = (opts[:path] || opts[:from_crash]).to_s
|
|
203
|
+
raise 'ERROR: path is required' if path.empty?
|
|
204
|
+
raise "ERROR: file not found: #{path}" unless File.file?(path)
|
|
205
|
+
|
|
206
|
+
JSON.parse(File.read(path), symbolize_names: true)
|
|
207
|
+
end
|
|
208
|
+
|
|
200
209
|
public_class_method def self.authors
|
|
201
210
|
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n"
|
|
202
211
|
end
|
|
@@ -344,6 +353,12 @@ module PWN
|
|
|
344
353
|
names: 'optional - Array of symbol names (defaults to system, execve, __libc_start_main)'
|
|
345
354
|
)
|
|
346
355
|
|
|
356
|
+
# Load a crash.json produced by a fuzz campaign.
|
|
357
|
+
#{self}.from_crash(
|
|
358
|
+
path: 'required - filesystem path of crash.json',
|
|
359
|
+
from_crash: 'optional - alias for path'
|
|
360
|
+
)
|
|
361
|
+
|
|
347
362
|
# Print the AUTHOR(S) string for this module.
|
|
348
363
|
#{self}.authors
|
|
349
364
|
"
|
data/lib/pwn/plugins/gdb.rb
CHANGED
|
@@ -90,6 +90,18 @@ module PWN
|
|
|
90
90
|
crash_info(opts.merge(commands: script))
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
+
public_class_method def self.ptrace_preflight(opts = {})
|
|
94
|
+
_target = opts[:target]
|
|
95
|
+
scope = 0
|
|
96
|
+
path = '/proc/sys/kernel/yama/ptrace_scope'
|
|
97
|
+
scope = File.read(path).to_i if File.file?(path)
|
|
98
|
+
{
|
|
99
|
+
ptrace_scope: scope,
|
|
100
|
+
attach_ok: scope.zero?,
|
|
101
|
+
hint: scope.positive? ? 'spawn instead of attach' : 'ok'
|
|
102
|
+
}
|
|
103
|
+
end
|
|
104
|
+
|
|
93
105
|
public_class_method def self.authors
|
|
94
106
|
"AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n"
|
|
95
107
|
end
|
|
@@ -147,6 +159,11 @@ module PWN
|
|
|
147
159
|
script: 'optional - Array of gdb/MI commands'
|
|
148
160
|
)
|
|
149
161
|
|
|
162
|
+
# Probe yama ptrace_scope before gdb/frida attach.
|
|
163
|
+
#{self}.ptrace_preflight(
|
|
164
|
+
target: 'optional - pid or binary path being attached'
|
|
165
|
+
)
|
|
166
|
+
|
|
150
167
|
# Print the AUTHOR(S) string for this module.
|
|
151
168
|
#{self}.authors
|
|
152
169
|
"
|
data/lib/pwn/plugins/jobs.rb
CHANGED
|
@@ -40,6 +40,19 @@ module PWN
|
|
|
40
40
|
row
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
public_class_method def self.watch(opts = {})
|
|
44
|
+
row = load_job(opts)
|
|
45
|
+
pattern = opts[:pattern].to_s
|
|
46
|
+
raise 'ERROR: pattern is required' if pattern.empty?
|
|
47
|
+
|
|
48
|
+
log = row[:log].to_s
|
|
49
|
+
return { id: row[:id], hits: [] } unless File.file?(log)
|
|
50
|
+
|
|
51
|
+
rx = Regexp.new(pattern)
|
|
52
|
+
hits = File.readlines(log).grep(rx).last(20)
|
|
53
|
+
{ id: row[:id], hits: hits.map(&:chomp), pattern: pattern }
|
|
54
|
+
end
|
|
55
|
+
|
|
43
56
|
public_class_method def self.status(opts = {})
|
|
44
57
|
row = load_job(opts)
|
|
45
58
|
alive = begin
|
|
@@ -144,6 +157,12 @@ module PWN
|
|
|
144
157
|
# Run stop and return its result
|
|
145
158
|
#{self}.stop
|
|
146
159
|
|
|
160
|
+
# Tail a job log for a regex (AFL new-crash lines).
|
|
161
|
+
#{self}.watch(
|
|
162
|
+
id: 'required - job id from #start',
|
|
163
|
+
pattern: 'required - regex to match in the job log'
|
|
164
|
+
)
|
|
165
|
+
|
|
147
166
|
# Print the AUTHOR(S) string for this module.
|
|
148
167
|
#{self}.authors
|
|
149
168
|
"
|
data/lib/pwn/plugins/repl.rb
CHANGED
|
@@ -494,7 +494,12 @@ module PWN
|
|
|
494
494
|
puts '[*] TAB menus: leading `/` = commands (/cron /skills /sessions …); `/` later = host paths; otherwise Ruby completion (same as the pwn REPL).'
|
|
495
495
|
puts "[*] tmux + terminator users: Ensure ~/.tmux.conf has 'set -s extended-keys on' and 'set -g xterm-keys on', then restart tmux. Use TERM=xterm-256color."
|
|
496
496
|
tag = pi.config.pwn_ai_session_id.to_s.empty? ? '<SESSION_ID>' : pi.config.pwn_ai_session_id
|
|
497
|
-
|
|
497
|
+
|
|
498
|
+
dbg_lvl = ''
|
|
499
|
+
dbg_lvl = 'trace' if pi.config.pwn_ai_trace
|
|
500
|
+
dbg_lvl = 'debug' if pi.config.pwn_ai_debug && !pi.config.pwn_ai_trace
|
|
501
|
+
|
|
502
|
+
puts "\n\n\npwn-ai #{dbg_lvl} ON → ~/.pwn/logs/pwn-ai-DEBUG-#{tag}-R<REQUEST_NUMBER>.log" unless dbg_lvl.empty?
|
|
498
503
|
end
|
|
499
504
|
end
|
|
500
505
|
|
data/lib/pwn/version.rb
CHANGED
|
@@ -216,4 +216,14 @@ describe PWN::AI::Agent::Mistakes do
|
|
|
216
216
|
expect(classes).to eq(rows.map { |r| r['class'] })
|
|
217
217
|
expect(classes.uniq.length).to eq(3)
|
|
218
218
|
end
|
|
219
|
+
|
|
220
|
+
it 'gives pull-access-denied an auth family hint, never ls-the-parent' do
|
|
221
|
+
stub_const('PWN::AI::Agent::Mistakes::MISTAKES_FILE', File.join(Dir.mktmpdir, 'mistakes.json'))
|
|
222
|
+
described_class.reset
|
|
223
|
+
described_class.record(tool: 'shell', error: 'pull access denied for library/foo')
|
|
224
|
+
hint = described_class.correction_hint(tool: 'shell', error: 'pull access denied for library/foo')
|
|
225
|
+
expect(hint).to match(/credential|registry/i)
|
|
226
|
+
expect(hint).not_to match(%r{ls/test -e the parent})
|
|
227
|
+
expect(described_class.family(error: 'pull access denied')).to eq('auth_denied')
|
|
228
|
+
end
|
|
219
229
|
end
|
|
@@ -438,4 +438,16 @@ describe 'PWN::AI::Agent::Reward vs TUI plan' do
|
|
|
438
438
|
expect(v[:verifier_verdict]).to eq(:pass)
|
|
439
439
|
expect(v[:judge_score]).to be < 0.6
|
|
440
440
|
end
|
|
441
|
+
|
|
442
|
+
it 'tags tool-backed heuristics so they are not haircut' do
|
|
443
|
+
allow(PWN::AI::Agent::Reward).to receive(:llm_judge).and_return(nil)
|
|
444
|
+
v = PWN::AI::Agent::Reward.judge(
|
|
445
|
+
request: 'write /tmp/x and verify',
|
|
446
|
+
final: 'PASS file exists',
|
|
447
|
+
trace: ['{"success":true,"result":{"exit":0}}'],
|
|
448
|
+
commit: false
|
|
449
|
+
)
|
|
450
|
+
expect(v[:heuristic_class].to_s).to eq('toolbacked')
|
|
451
|
+
expect(v[:score]).to be >= 0.6
|
|
452
|
+
end
|
|
441
453
|
end
|
|
@@ -22,4 +22,13 @@ describe PWN::Plugins::ArtifactRegistry do
|
|
|
22
22
|
expect(rows.first[:kind]).to eq('loot')
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
it 'greps an artifact by regex' do
|
|
27
|
+
Dir.mktmpdir do |dir|
|
|
28
|
+
src = File.join(dir, 'dump.txt')
|
|
29
|
+
File.write(src, "nop\ncall system\nret\n")
|
|
30
|
+
hits = described_class.read_page(path: src, grep: 'call.*system')
|
|
31
|
+
expect(hits[:matches].first[:text]).to include('call system')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
25
34
|
end
|
data/third_party/pwn_rdoc.jsonl
CHANGED
|
@@ -280,9 +280,11 @@
|
|
|
280
280
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.compact! Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.compact!`: "}]}
|
|
281
281
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.compress_exemplar Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.compress_exemplar`: "}]}
|
|
282
282
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.compress_finetune_trace Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.compress_finetune_trace`: "}]}
|
|
283
|
+
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.consistency_check Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.consistency_check`: "}]}
|
|
283
284
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.consolidate Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.consolidate`: Supported Method Parameters\n\nremoved = PWN::AI::Agent::Learning.consolidate(\n\nmax_entries: 'optional - hard cap on PWN::Memory size (default MAX_MEMORY_ENTRIES)'\n\n)\n\nDeduplicates near-identical lesson values and prunes the oldest entries once the cap is exceeded so the injected MEMORY block stays high-signal.\n"}]}
|
|
284
285
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.discount_success_rate Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.discount_success_rate`: "}]}
|
|
285
286
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.display_task Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.display_task`: "}]}
|
|
287
|
+
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.disputed_save Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.disputed_save`: "}]}
|
|
286
288
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.distill_skill Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.distill_skill`: Supported Method Parameters\n\nskill = PWN::AI::Agent::Learning.distill_skill(\n\nname: 'required - snake_case name for the new skill',\nsession_id: 'optional - PWN::Sessions id to mine (uses its transcript)',\ncontent: 'optional - explicit markdown body; overrides transcript mining',\nreferences: 'optional - Array of reference URLs / CWE / CVE / ATT&CK ids'\n\n)\n"}]}
|
|
287
289
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.exemplars_for Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.exemplars_for`: Supported Method Parameters\n\nmsgs = PWN::AI::Agent::Learning.exemplars_for(\n\nrequest: 'required - current user request',\nlimit: 'optional - max exemplar traces to return (default 1)',\nmax_msgs: 'optional - cap on messages per exemplar (default 6)'\n\n)\n\nRetrieval-augmented BEHAVIOUR: keyword-matches request against prior successful outcomes in learning.jsonl, loads the matching session, and compresses its (user, tool, assistant) trace into a short few-shot exemplar Loop.run splices between system and user. Local models are dramatically better with 1 concrete example than with 25 abstract lessons.\n"}]}
|
|
288
290
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Learning.export_finetune Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Learning.export_finetune`: "}]}
|
|
@@ -419,6 +421,7 @@
|
|
|
419
421
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Loop.run Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Loop.run`: Supported Method Parameters\n\nfinal = PWN::AI::Agent::Loop.run(\n\nrequest: 'required - what the human typed',\nsession_id: 'optional - PWN::Sessions id (transcript is appended to it)',\nenabled_toolsets: 'optional - subset of Registry.toolsets, or nil for all',\non_tool: 'optional - ->(name, args, result) callback for live UI',\nsystem_role_content: 'optional - override default system prompt (built from session_id if not provided)'\n\n)\n"}]}
|
|
420
422
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Loop.session_chat_history Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Loop.session_chat_history`: "}]}
|
|
421
423
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Loop.session_files Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Loop.session_files`: "}]}
|
|
424
|
+
{"messages":[{"role":"user","content":"PWN::AI::Agent::Loop.session_tool_budget Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Loop.session_tool_budget`: "}]}
|
|
422
425
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Loop.should_auto_introspect? Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Loop.should_auto_introspect?`: "}]}
|
|
423
426
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Loop.spill_tool_body Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Loop.spill_tool_body`: "}]}
|
|
424
427
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Loop.spill_tool_history! Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Loop.spill_tool_history!`: "}]}
|
|
@@ -467,6 +470,7 @@
|
|
|
467
470
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Metrics.save Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Metrics.save`: Supported Method Parameters\n\nPWN::AI::Agent::Metrics.save(\n\nmetrics: 'required - Hash returned by .load / mutated in place'\n\n)\n"}]}
|
|
468
471
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Metrics.scale_prediction Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Metrics.scale_prediction`: "}]}
|
|
469
472
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Metrics.scoreboard Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Metrics.scoreboard`: "}]}
|
|
473
|
+
{"messages":[{"role":"user","content":"PWN::AI::Agent::Metrics.snapshot Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Metrics.snapshot`: "}]}
|
|
470
474
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Metrics.summary Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Metrics.summary`: Supported Method Parameters\n\nrows = PWN::AI::Agent::Metrics.summary(\n\nlimit: 'optional - cap number of tools returned (default 25)',\nengine: 'optional - only that engine\\'s sub-bucket (falls back to global when absent)'\n\n)\n"}]}
|
|
471
475
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Metrics.thompson Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Metrics.thompson`: Supported Method Parameters\n\np = PWN::AI::Agent::Metrics.thompson(name: ‘shell’)\n\nC1 — Thompson sample from Beta(ok+1, fail+1). Naturally balances exploit/explore; used by Registry.rank as the tie-breaker.\n"}]}
|
|
472
476
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Metrics.to_context Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Metrics.to_context`: Supported Method Parameters\n\nctx = PWN::AI::Agent::Metrics.to_context(\n\nlimit: 'optional - cap number of tools included (default 8)',\nengine: 'optional - restrict to one engine\\'s telemetry'\n\n)\n"}]}
|
|
@@ -481,6 +485,7 @@
|
|
|
481
485
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.error_class Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.error_class`: "}]}
|
|
482
486
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.extinguish! Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.extinguish!`: "}]}
|
|
483
487
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.extinguish_parked! Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.extinguish_parked!`: "}]}
|
|
488
|
+
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.family Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.family`: "}]}
|
|
484
489
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.find Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.find`: Supported Method Parameters\n\nentry = PWN::AI::Agent::Mistakes.find(\n\nsignature: 'optional - exact signature to fetch',\ntool: 'optional - with error:, compute signature and fetch',\nerror: 'optional - raw error text (used with tool:)'\n\n)\n"}]}
|
|
485
490
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.for_tool Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.for_tool`: Supported Method Parameters\n\nrows = PWN::AI::Agent::Mistakes.for_tool(\n\ntool: 'required - tool name',\nunresolved_only: 'optional - default false'\n\n)\n"}]}
|
|
486
491
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.help Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.help`: "}]}
|
|
@@ -488,6 +493,7 @@
|
|
|
488
493
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.lean! Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.lean!`: Supported Method Parameters\n\nresult = PWN::AI::Agent::Mistakes.lean!(\n\ndry_run: 'optional - Boolean (default false)',\nmax_resolved_kept: 'optional - cap on resolved-with-fix records',\nresolved_min_age_days: 'optional - age before resolved count=1 may drop'\n\n)\n\nCompact text fields on every record. Never drops unresolved, regressed, or high-count repeaters. Aged resolved-once fixes may drop after Memory already holds mistake_fix_<sig>.\n"}]}
|
|
489
494
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.load Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.load`: Supported Method Parameters\n\nstore = PWN::AI::Agent::Mistakes.load\n"}]}
|
|
490
495
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.normalize_error Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.normalize_error`: "}]}
|
|
496
|
+
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.note_hint_outcome Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.note_hint_outcome`: "}]}
|
|
491
497
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.operator_inbox Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.operator_inbox`: "}]}
|
|
492
498
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.park Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.park`: "}]}
|
|
493
499
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::Mistakes.previous_assistant Usage"},{"role":"assistant","content":"`PWN::AI::Agent::Mistakes.previous_assistant`: "}]}
|
|
@@ -2068,6 +2074,7 @@
|
|
|
2068
2074
|
{"messages":[{"role":"user","content":"PWN::Plugins::ExploitDev.flat Usage"},{"role":"assistant","content":"`PWN::Plugins::ExploitDev.flat`: "}]}
|
|
2069
2075
|
{"messages":[{"role":"user","content":"PWN::Plugins::ExploitDev.fmt_writes Usage"},{"role":"assistant","content":"`PWN::Plugins::ExploitDev.fmt_writes`: "}]}
|
|
2070
2076
|
{"messages":[{"role":"user","content":"PWN::Plugins::ExploitDev.fmtstr Usage"},{"role":"assistant","content":"`PWN::Plugins::ExploitDev.fmtstr`: "}]}
|
|
2077
|
+
{"messages":[{"role":"user","content":"PWN::Plugins::ExploitDev.from_crash Usage"},{"role":"assistant","content":"`PWN::Plugins::ExploitDev.from_crash`: "}]}
|
|
2071
2078
|
{"messages":[{"role":"user","content":"PWN::Plugins::ExploitDev.gadgets Usage"},{"role":"assistant","content":"`PWN::Plugins::ExploitDev.gadgets`: "}]}
|
|
2072
2079
|
{"messages":[{"role":"user","content":"PWN::Plugins::ExploitDev.help Usage"},{"role":"assistant","content":"`PWN::Plugins::ExploitDev.help`: "}]}
|
|
2073
2080
|
{"messages":[{"role":"user","content":"PWN::Plugins::ExploitDev.io Usage"},{"role":"assistant","content":"`PWN::Plugins::ExploitDev.io`: "}]}
|
|
@@ -2121,6 +2128,7 @@
|
|
|
2121
2128
|
{"messages":[{"role":"user","content":"PWN::Plugins::GDB.debug_session Usage"},{"role":"assistant","content":"`PWN::Plugins::GDB.debug_session`: "}]}
|
|
2122
2129
|
{"messages":[{"role":"user","content":"PWN::Plugins::GDB.help Usage"},{"role":"assistant","content":"`PWN::Plugins::GDB.help`: "}]}
|
|
2123
2130
|
{"messages":[{"role":"user","content":"PWN::Plugins::GDB.mitigations Usage"},{"role":"assistant","content":"`PWN::Plugins::GDB.mitigations`: "}]}
|
|
2131
|
+
{"messages":[{"role":"user","content":"PWN::Plugins::GDB.ptrace_preflight Usage"},{"role":"assistant","content":"`PWN::Plugins::GDB.ptrace_preflight`: "}]}
|
|
2124
2132
|
{"messages":[{"role":"user","content":"PWN::Plugins::GDB.registers Usage"},{"role":"assistant","content":"`PWN::Plugins::GDB.registers`: "}]}
|
|
2125
2133
|
{"messages":[{"role":"user","content":"PWN::Plugins::GDB.required_bins Usage"},{"role":"assistant","content":"`PWN::Plugins::GDB.required_bins`: "}]}
|
|
2126
2134
|
{"messages":[{"role":"user","content":"PWN::Plugins::GDB.run_to_crash Usage"},{"role":"assistant","content":"`PWN::Plugins::GDB.run_to_crash`: "}]}
|
|
@@ -2293,6 +2301,7 @@
|
|
|
2293
2301
|
{"messages":[{"role":"user","content":"PWN::Plugins::Jobs.status Usage"},{"role":"assistant","content":"`PWN::Plugins::Jobs.status`: "}]}
|
|
2294
2302
|
{"messages":[{"role":"user","content":"PWN::Plugins::Jobs.stop Usage"},{"role":"assistant","content":"`PWN::Plugins::Jobs.stop`: "}]}
|
|
2295
2303
|
{"messages":[{"role":"user","content":"PWN::Plugins::Jobs.tail Usage"},{"role":"assistant","content":"`PWN::Plugins::Jobs.tail`: "}]}
|
|
2304
|
+
{"messages":[{"role":"user","content":"PWN::Plugins::Jobs.watch Usage"},{"role":"assistant","content":"`PWN::Plugins::Jobs.watch`: "}]}
|
|
2296
2305
|
{"messages":[{"role":"user","content":"PWN::Plugins::K8s.authors Usage"},{"role":"assistant","content":"`PWN::Plugins::K8s.authors`: "}]}
|
|
2297
2306
|
{"messages":[{"role":"user","content":"PWN::Plugins::K8s.docker_socket? Usage"},{"role":"assistant","content":"`PWN::Plugins::K8s.docker_socket?`: "}]}
|
|
2298
2307
|
{"messages":[{"role":"user","content":"PWN::Plugins::K8s.help Usage"},{"role":"assistant","content":"`PWN::Plugins::K8s.help`: "}]}
|