Module: PWN::Plugins::AISandbox
- Defined in:
- lib/pwn/plugins/ai_sandbox.rb
Overview
Forked worker for model-authored shell/Ruby with Landlock/seccomp profiles.
Constant Summary collapse
- WRITE_RX =
%r{\b(?:rm|rmdir|unlink|shred|truncate)\b|FileUtils\.rm|File\.(?:delete|unlink)|Pathname.*rmtree|>\s*/}- NET_RX =
/\b(?:curl|wget|nc|ncat|ssh|scp|ftp|telnet)\b|TCPSocket|UDPSocket|Net::HTTP|Socket\.(?:tcp|udp)/- PATH_RX =
%r{FileUtils\.\w+\(\s*['"]([^'"]+)['"]|(?:^|\s)(?:rm|rmdir)\s+(?:-[a-zA-Z]+\s+)*([^\s;|&]+)|['"](/(?:[^'"]+))['"]}
Class Method Summary collapse
- .authors ⇒ Object
-
.classify(opts = {}) ⇒ Object
Classify payload as read, write, or network for profile selection.
-
.exec(opts = {}) ⇒ Object
Run shell or Ruby in a forked worker under the selected profile.
- .help ⇒ Object
-
.mode(opts = {}) ⇒ Object
Read the ai_sandbox key as strict, permissive, or off.
- .required_bins ⇒ Object
-
.wrap_ruby(opts = {}) ⇒ Object
Intercept pwn_eval when ai_sandbox is not off; nil means in-process eval.
-
.wrap_shell(opts = {}) ⇒ Object
Intercept shell when ai_sandbox is not off; nil means the caller runs host Open3.
Class Method Details
.authors ⇒ Object
64 65 66 |
# File 'lib/pwn/plugins/ai_sandbox.rb', line 64 public_class_method def self. "AUTHOR(S):\n 0day Inc. <[email protected]>\n" end |
.classify(opts = {}) ⇒ Object
Classify payload as read, write, or network for profile selection.
30 31 32 33 34 35 36 37 |
# File 'lib/pwn/plugins/ai_sandbox.rb', line 30 public_class_method def self.classify(opts = {}) text = (opts[:payload] || opts[:command] || opts[:code]).to_s return (opts[:side_effect] || opts[:class]).to_sym if opts[:side_effect] || opts[:class] return :write if text.match?(WRITE_RX) return :network if text.match?(NET_RX) :read end |
.exec(opts = {}) ⇒ Object
Run shell or Ruby in a forked worker under the selected profile.
40 41 42 43 44 45 46 47 48 |
# File 'lib/pwn/plugins/ai_sandbox.rb', line 40 public_class_method def self.exec(opts = {}) kind = (opts[:kind] || :shell).to_s.to_sym payload = (opts[:payload] || opts[:command] || opts[:code]).to_s profile = classify(opts.merge(payload: payload)) denied = preflight(opts.merge(payload: payload, profile: profile)) return denied if denied run_worker(opts.merge(kind: kind, payload: payload, profile: profile)) end |
.help ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/pwn/plugins/ai_sandbox.rb', line 68 public_class_method def self.help puts "USAGE: # List host binaries this module expects to be installed. #{self}.required_bins # Read the ai_sandbox key as strict, permissive, or off. #{self}.mode( mode: 'optional - strict, permissive, or off overlay', ai_sandbox: 'optional - alias for mode' ) # Classify payload as read, write, or network for profile selection. #{self}.classify( payload: 'optional - shell command or Ruby source', command: 'optional - alias for payload', code: 'optional - alias for payload', side_effect: 'optional - declared class read, write, or network', class: 'optional - alias for side_effect' ) # Run shell or Ruby in a forked worker under the selected profile. #{self}.exec( kind: 'optional - shell or ruby (defaults to shell)', payload: 'optional - command or Ruby source', command: 'optional - alias for payload', code: 'optional - alias for payload', mode: 'optional - strict, permissive, or off overlay', timeout: 'optional - worker seconds budget', side_effect: 'optional - declared class read, write, or network', scope: 'optional - Array of hostnames allowed for network egress' ) # Intercept shell when ai_sandbox is not off; nil means the caller runs host Open3. #{self}.wrap_shell( command: 'optional - shell command to sandbox', payload: 'optional - alias for command', mode: 'optional - strict, permissive, or off overlay', timeout: 'optional - worker seconds budget' ) # Intercept pwn_eval when ai_sandbox is not off; nil means in-process eval. #{self}.wrap_ruby( code: 'optional - Ruby source to sandbox', payload: 'optional - alias for code', mode: 'optional - strict, permissive, or off overlay', timeout: 'optional - worker seconds budget' ) # Print the AUTHOR(S) string for this module. #{self}.authors " constants.sort end |
.mode(opts = {}) ⇒ Object
Read the ai_sandbox key as strict, permissive, or off.
22 23 24 25 26 27 |
# File 'lib/pwn/plugins/ai_sandbox.rb', line 22 public_class_method def self.mode(opts = {}) raw = opts[:mode] || opts[:ai_sandbox] raw = env_mode if raw.nil? value = raw.to_s.downcase %w[strict permissive off].include?(value) ? value.to_sym : :off end |
.required_bins ⇒ Object
17 18 19 |
# File 'lib/pwn/plugins/ai_sandbox.rb', line 17 public_class_method def self.required_bins [] end |
.wrap_ruby(opts = {}) ⇒ Object
Intercept pwn_eval when ai_sandbox is not off; nil means in-process eval.
58 59 60 61 62 |
# File 'lib/pwn/plugins/ai_sandbox.rb', line 58 public_class_method def self.wrap_ruby(opts = {}) return nil if mode(opts) == :off exec(opts.merge(kind: :ruby, payload: opts[:code] || opts[:payload])) end |
.wrap_shell(opts = {}) ⇒ Object
Intercept shell when ai_sandbox is not off; nil means the caller runs host Open3.
51 52 53 54 55 |
# File 'lib/pwn/plugins/ai_sandbox.rb', line 51 public_class_method def self.wrap_shell(opts = {}) return nil if mode(opts) == :off exec(opts.merge(kind: :shell, payload: opts[:command] || opts[:payload])) end |