pwn 0.5.745 → 0.5.746
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/lib/pwn/ai/agent/tools/exploitdev.rb +2 -1
- data/lib/pwn/plugins/exploit_dev.rb +3 -1
- data/lib/pwn/plugins/process_tube.rb +2 -0
- data/lib/pwn/plugins/sbom.rb +4 -9
- data/lib/pwn/version.rb +1 -1
- data/spec/lib/pwn/ai/agent/tools/exploitdev_spec.rb +13 -3
- data/spec/lib/pwn/plugins/jobs_spec.rb +3 -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: aacb6a992222f92a5a198def002962a7f92105b68489ae2a9dd01fb9207332f9
|
|
4
|
+
data.tar.gz: d48b7f1c97a7a18bba283685075d887d9e539280abe3cc41064a88374e9bf355
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 614149c9170c27dad853ec23b90f3990ae9182001bd6d2b7e4b919095a003bc2b85b949946c834e32052e37ba0f4b785c59adbaeb127a1f90298025ec657cfe6
|
|
7
|
+
data.tar.gz: 40f3119856e9a6965b5977494fcb1afb4ea8ef13f226a7044353232be87a46dda4bd4970b6806677d327e18e53af6bb328852bd170fd4c9095821b8947222a5f
|
|
@@ -22,6 +22,7 @@ PWN::AI::Agent::Registry.register(
|
|
|
22
22
|
arch: { type: 'string' },
|
|
23
23
|
offset: { type: 'integer' },
|
|
24
24
|
extra: { type: 'string' },
|
|
25
|
+
pad: { type: 'integer' },
|
|
25
26
|
cmd: { type: 'string' },
|
|
26
27
|
host: { type: 'string' },
|
|
27
28
|
port: { type: 'integer' },
|
|
@@ -55,7 +56,7 @@ PWN::AI::Agent::Registry.register(
|
|
|
55
56
|
when 'io'
|
|
56
57
|
PWN::Plugins::ExploitDev.io(kind: args[:kind] || 'process', cmd: args[:cmd] || args[:path], host: args[:host], port: args[:port])
|
|
57
58
|
when 'ret2libc'
|
|
58
|
-
PWN::Plugins::ExploitDev.ret2libc(path: args[:path], offset: args[:offset], extra: args[:extra])
|
|
59
|
+
PWN::Plugins::ExploitDev.ret2libc(path: args[:path], offset: args[:offset], extra: args[:extra], pad: args[:pad])
|
|
59
60
|
when 'checksec'
|
|
60
61
|
PWN::Plugins::GDB.mitigations(binary: args[:path])
|
|
61
62
|
else
|
|
@@ -231,7 +231,9 @@ module PWN
|
|
|
231
231
|
offset = (opts[:offset] || 72).to_i
|
|
232
232
|
raise 'ERROR: missing pop rdi, system, or argument address' unless pop && system && arg
|
|
233
233
|
|
|
234
|
-
align = opts[:ret]
|
|
234
|
+
align = opts[:ret]
|
|
235
|
+
align ||= pop + 1 if pop && Array(gadgets[:gadgets]).any? { |row| row[:address] == pop && row[:gadget].to_s.match?(/pop rdi; ret/i) }
|
|
236
|
+
align ||= Array(gadgets[:gadgets]).find { |row| row[:gadget].to_s == 'ret' && row[:address] != pop }&.fetch(:address, nil)
|
|
235
237
|
packed = [pop, arg]
|
|
236
238
|
packed << align if align && align != pop
|
|
237
239
|
packed << system
|
data/lib/pwn/plugins/sbom.rb
CHANGED
|
@@ -81,21 +81,16 @@ module PWN
|
|
|
81
81
|
|
|
82
82
|
private_class_method def self.run!(opts = {})
|
|
83
83
|
argv = opts[:argv]
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
raise IOError, "#{argv.first} failed: #{err}" unless st.success? || opts[:allow_nonzero] == true
|
|
84
|
+
out, st = Open3.capture2(*argv)
|
|
85
|
+
raise IOError, "#{argv.first} failed" unless st.success? || opts[:allow_nonzero] == true
|
|
87
86
|
|
|
88
|
-
else
|
|
89
|
-
out, = Open3.capture2(*argv)
|
|
90
|
-
end
|
|
91
|
-
out
|
|
92
|
-
rescue Errno::ENOENT
|
|
93
|
-
out, = Open3.capture2(*opts[:argv])
|
|
94
87
|
out
|
|
95
88
|
end
|
|
96
89
|
|
|
97
90
|
private_class_method def self.parse_grype(opts = {})
|
|
98
91
|
out = run!(argv: ['grype', '-o', 'json', opts[:target]], allow_nonzero: true)
|
|
92
|
+
raise IOError, 'grype returned no JSON' if out.to_s.strip.empty?
|
|
93
|
+
|
|
99
94
|
json = JSON.parse(out)
|
|
100
95
|
Array(json['matches']).map do |row|
|
|
101
96
|
art = row['artifact'] || {}
|
data/lib/pwn/version.rb
CHANGED
|
@@ -27,25 +27,35 @@ describe 'PWN::AI::Agent::Tools exploitdev' do
|
|
|
27
27
|
void keep(void) { __asm__ volatile("pop %rdi; ret"); }
|
|
28
28
|
int main(int argc, char **argv) {
|
|
29
29
|
char buf[64];
|
|
30
|
+
void *frame = __builtin_frame_address(0);
|
|
30
31
|
(void)argv;
|
|
31
32
|
if (argc > 100) { system(cmd); keep(); }
|
|
33
|
+
char line[32];
|
|
34
|
+
snprintf(line, sizeof(line), "%ld", (long)((char *)frame + sizeof(void *) - buf));
|
|
35
|
+
puts(line);
|
|
36
|
+
fflush(stdout);
|
|
32
37
|
read(0, buf, 256);
|
|
33
38
|
return 0;
|
|
34
39
|
}
|
|
35
40
|
C
|
|
36
|
-
out, status = Open3.capture2e('cc', '-O0', '-fno-stack-protector', '-no-pie', '-o', bin, src)
|
|
41
|
+
out, status = Open3.capture2e('cc', '-O0', '-fno-stack-protector', '-fno-pie', '-no-pie', '-o', bin, src)
|
|
37
42
|
expect(status.success?).to eq(true), out
|
|
43
|
+
elf = File.binread(bin)
|
|
44
|
+
expect(elf[16, 2].unpack1('v')).to eq(2), 'cc produced a PIE binary; file addresses would not be the runtime addresses'
|
|
45
|
+
io = PWN::Plugins::ExploitDev.io(cmd: [bin], pty: false)
|
|
46
|
+
offset = PWN::Plugins::ProcessTube.recvuntil(id: io[:id], until: "\n", timeout: 3).to_i
|
|
47
|
+
expect(offset).to be > 64
|
|
38
48
|
raw = PWN::AI::Agent::Dispatch.call(
|
|
39
|
-
tool_call: { function: { name: 'exploitdev', arguments: JSON.generate(action: 'ret2libc', path: bin, offset:
|
|
49
|
+
tool_call: { function: { name: 'exploitdev', arguments: JSON.generate(action: 'ret2libc', path: bin, offset: offset, extra: 'cmd') } },
|
|
40
50
|
scope_path: File.join(dir, 'absent.yaml')
|
|
41
51
|
)
|
|
42
52
|
row = JSON.parse(raw, symbolize_names: true).fetch(:result)
|
|
53
|
+
row = JSON.parse(File.binread(row[:artifact][:path]), symbolize_names: true) if row[:artifact]
|
|
43
54
|
expect(row[:payload]).not_to be_empty
|
|
44
55
|
expect(row[:plt].keys.map(&:to_s)).to include('system')
|
|
45
56
|
expect(row[:pop_rdi]).to be_a(Integer)
|
|
46
57
|
packed = [row[:payload_hex] || row['payload_hex']].pack('H*')
|
|
47
58
|
packed = row[:payload].to_s if packed.empty?
|
|
48
|
-
io = PWN::Plugins::ExploitDev.io(cmd: [bin], pty: false)
|
|
49
59
|
PWN::Plugins::ProcessTube.send_raw(id: io[:id], bytes: packed)
|
|
50
60
|
out = PWN::Plugins::ProcessTube.recvuntil(id: io[:id], until: 'RET2LIBC_OK', timeout: 3)
|
|
51
61
|
expect(out.to_s).to include('RET2LIBC_OK')
|
|
@@ -32,12 +32,14 @@ describe PWN::Plugins::Jobs do
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
it 'survives an exited creator and records completion in a fresh session' do
|
|
35
|
-
|
|
35
|
+
gate = File.join(@root, 'release')
|
|
36
|
+
row = fresh("puts JSON.generate(PWN::Plugins::Jobs.start(command: 'while [ ! -f #{gate} ]; do sleep 0.05; done; printf durable', max_runtime: 21600, session_id: 'old'))")
|
|
36
37
|
expect(row[:status]).to eq('RUNNING')
|
|
37
38
|
expect(row[:worker_pid]).to be_a(Integer)
|
|
38
39
|
expect(row[:worker_identity]).not_to be_nil
|
|
39
40
|
worker_session = Process.getsid(row[:worker_pid])
|
|
40
41
|
expect(fresh("puts JSON.generate(PWN::Plugins::Jobs.status(id: '#{row[:id]}'))")[:status]).to eq('RUNNING')
|
|
42
|
+
File.write(gate, '1')
|
|
41
43
|
done = finished(row[:id])
|
|
42
44
|
expect(worker_session).to eq(row[:worker_pid])
|
|
43
45
|
expect(done).to include(status: 'COMPLETED', exit_code: 0, max_runtime: 21_600, session_id: 'old')
|