pwn 0.5.657 → 0.5.658
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/shell.rb +83 -8
- data/lib/pwn/banner/white_rabbit.rb +1 -1
- 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: 84155e448029c5d41ebd8dda5e4c00147a3283ebf8258c42f2fdf7cb3f159616
|
|
4
|
+
data.tar.gz: ceecb743a07ddf4d0a2f45434f1b7816e859754762d60f8932f9dd1f4a83d80a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5cb1bf7948fa027253fa5e2aeb2204d917bf51ab4ebf2710073b8ca3c4fa07f53012a3e8f98e5db5f3dabda050b405119dadf78b7a5583476da35fd11af5c5c7
|
|
7
|
+
data.tar.gz: 07e6832ea6946949d3042f62b03930d5e6f882dd8f246449f314c994459b4f16ce4e32700ab4467b55d44e01f5ba35dbc3788f742d44a7fd79b36026b2d61ccf
|
|
@@ -6,6 +6,13 @@ require 'pwn/ai/agent/registry'
|
|
|
6
6
|
|
|
7
7
|
# Run a shell command on the pwn host. Lifted from the bash branch of the
|
|
8
8
|
# legacy :pwn_ai_hook (repl.rb).
|
|
9
|
+
#
|
|
10
|
+
# Timeout path must NOT leave Open3's pipe-reader threads racing a closed
|
|
11
|
+
# pipe — that surfaces as noisy:
|
|
12
|
+
# #<Thread:0x... open3.rb:664 run> terminated with exception
|
|
13
|
+
# (report_on_exception is true): IOError stream closed in another thread
|
|
14
|
+
# Fix: own the popen3 lifecycle, process-group kill on timeout, and silence
|
|
15
|
+
# report_on_exception on the reader threads before closing pipes.
|
|
9
16
|
PWN::AI::Agent::Registry.register(
|
|
10
17
|
name: 'shell',
|
|
11
18
|
toolset: 'terminal',
|
|
@@ -29,16 +36,84 @@ PWN::AI::Agent::Registry.register(
|
|
|
29
36
|
timeout = (args[:timeout] || 120).to_i
|
|
30
37
|
raise ArgumentError, 'command is required' if cmd.strip.empty?
|
|
31
38
|
|
|
32
|
-
stdout =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
stdout = +''
|
|
40
|
+
stderr = +''
|
|
41
|
+
exitstatus = nil
|
|
42
|
+
timed_out = false
|
|
43
|
+
|
|
44
|
+
# pgroup: true => child is session/process-group leader; kill(-pid)
|
|
45
|
+
# reaps the whole tree (shell + grandchildren) on timeout.
|
|
46
|
+
Open3.popen3(cmd, pgroup: true) do |stdin, out_io, err_io, wait_thr|
|
|
47
|
+
stdin.close
|
|
48
|
+
pid = wait_thr.pid
|
|
49
|
+
|
|
50
|
+
out_reader = Thread.new { out_io.read.to_s }
|
|
51
|
+
err_reader = Thread.new { err_io.read.to_s }
|
|
52
|
+
# Prevent Ruby from dumping IOError to $stderr when we close pipes
|
|
53
|
+
# out from under these readers on the timeout path.
|
|
54
|
+
out_reader.report_on_exception = false
|
|
55
|
+
err_reader.report_on_exception = false
|
|
56
|
+
|
|
57
|
+
begin
|
|
58
|
+
Timeout.timeout(timeout) do
|
|
59
|
+
# Wait for the child; readers drain pipes concurrently.
|
|
60
|
+
wait_thr.value
|
|
61
|
+
end
|
|
62
|
+
rescue Timeout::Error
|
|
63
|
+
timed_out = true
|
|
64
|
+
begin
|
|
65
|
+
Process.kill('TERM', -pid)
|
|
66
|
+
rescue Errno::ESRCH, Errno::EPERM
|
|
67
|
+
nil
|
|
68
|
+
end
|
|
69
|
+
# Brief grace, then hard kill the process group.
|
|
70
|
+
sleep 0.2
|
|
71
|
+
begin
|
|
72
|
+
Process.kill('KILL', -pid)
|
|
73
|
+
rescue Errno::ESRCH, Errno::EPERM
|
|
74
|
+
nil
|
|
75
|
+
end
|
|
76
|
+
begin
|
|
77
|
+
wait_thr.value
|
|
78
|
+
rescue StandardError
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Ensure pipes are closed so readers unblock even if the child
|
|
84
|
+
# ignored signals or left descendants holding fds.
|
|
85
|
+
begin
|
|
86
|
+
out_io.close unless out_io.closed?
|
|
87
|
+
rescue StandardError
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
begin
|
|
91
|
+
err_io.close unless err_io.closed?
|
|
92
|
+
rescue StandardError
|
|
93
|
+
nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Join readers; swallow the IOError that arrives when the pipe was
|
|
97
|
+
# closed mid-read (timeout path). report_on_exception is already off.
|
|
98
|
+
begin
|
|
99
|
+
stdout = out_reader.value.to_s
|
|
100
|
+
rescue StandardError
|
|
101
|
+
stdout = +''
|
|
102
|
+
end
|
|
103
|
+
begin
|
|
104
|
+
stderr = err_reader.value.to_s
|
|
105
|
+
rescue StandardError
|
|
106
|
+
stderr = +''
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
unless timed_out
|
|
110
|
+
status = wait_thr.value
|
|
111
|
+
exitstatus = status&.exitstatus
|
|
37
112
|
end
|
|
38
|
-
rescue Timeout::Error
|
|
39
|
-
return { stdout: stdout, stderr: stderr, exit: nil, error: "timeout after #{timeout}s" }
|
|
40
113
|
end
|
|
41
114
|
|
|
42
|
-
{ stdout: stdout, stderr: stderr, exit:
|
|
115
|
+
return { stdout: stdout, stderr: stderr, exit: nil, error: "timeout after #{timeout}s" } if timed_out
|
|
116
|
+
|
|
117
|
+
{ stdout: stdout, stderr: stderr, exit: exitstatus }
|
|
43
118
|
}
|
|
44
119
|
)
|
data/lib/pwn/version.rb
CHANGED