jruby_sandbox 0.2.2-java → 0.2.3-java
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/.gitignore +2 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/README.md +37 -26
- data/ext/java/sandbox/BoxedClass.java +10 -0
- data/ext/java/sandbox/SandboxFull.java +16 -11
- data/ext/java/sandbox/SandboxModule.java +23 -0
- data/ext/java/sandbox/SandboxService.java +1 -17
- data/jruby_sandbox.gemspec +18 -17
- data/lib/sandbox.rb +4 -397
- data/lib/sandbox/safe.rb +399 -0
- data/lib/sandbox/version.rb +1 -1
- data/spec/exploits_spec.rb +56 -49
- data/spec/sandbox_spec.rb +75 -75
- metadata +6 -4
- data/.rvmrc +0 -47
- data/Gemfile.lock +0 -40
data/lib/sandbox/safe.rb
ADDED
@@ -0,0 +1,399 @@
|
|
1
|
+
require "fakefs/safe"
|
2
|
+
|
3
|
+
module Sandbox
|
4
|
+
TimeoutError = Class.new(Exception)
|
5
|
+
|
6
|
+
class Safe < Full
|
7
|
+
def activate!
|
8
|
+
activate_fakefs
|
9
|
+
|
10
|
+
keep_singleton_methods(:Kernel, KERNEL_S_METHODS)
|
11
|
+
keep_singleton_methods(:Symbol, SYMBOL_S_METHODS)
|
12
|
+
keep_singleton_methods(:String, STRING_S_METHODS)
|
13
|
+
keep_singleton_methods(:IO, IO_S_METHODS)
|
14
|
+
|
15
|
+
keep_methods(:Kernel, KERNEL_METHODS)
|
16
|
+
keep_methods(:NilClass, NILCLASS_METHODS)
|
17
|
+
keep_methods(:Symbol, SYMBOL_METHODS)
|
18
|
+
keep_methods(:TrueClass, TRUECLASS_METHODS)
|
19
|
+
keep_methods(:FalseClass, FALSECLASS_METHODS)
|
20
|
+
keep_methods(:Enumerable, ENUMERABLE_METHODS)
|
21
|
+
keep_methods(:String, STRING_METHODS)
|
22
|
+
|
23
|
+
# FIXME: Blacklisting Object methods is not a scalable solution.
|
24
|
+
# Whitelisting using #keep_methods is safer.
|
25
|
+
remove_method(:Object, :java_import)
|
26
|
+
|
27
|
+
Kernel.class_eval do
|
28
|
+
def `(*args)
|
29
|
+
raise NoMethodError, "` is unavailable"
|
30
|
+
end
|
31
|
+
|
32
|
+
def system(*args)
|
33
|
+
raise NoMethodError, "system is unavailable"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def activate_fakefs
|
39
|
+
require "fileutils"
|
40
|
+
|
41
|
+
# unfortunately, the authors of FakeFS used `extend self` in FileUtils, instead of `module_function`.
|
42
|
+
# I fixed it for them
|
43
|
+
(FakeFS::FileUtils.methods - Module.methods - Kernel.methods).each do |module_method_name|
|
44
|
+
FakeFS::FileUtils.send(:module_function, module_method_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
import FakeFS
|
48
|
+
ref FakeFS::Dir
|
49
|
+
ref FakeFS::File
|
50
|
+
ref FakeFS::FileTest
|
51
|
+
import FakeFS::FileUtils #import FileUtils because it is a module
|
52
|
+
|
53
|
+
# this is basically what FakeFS.activate! does, but we want to do it in the sandbox
|
54
|
+
# so we have to live with this:
|
55
|
+
eval <<-RUBY
|
56
|
+
Object.class_eval do
|
57
|
+
remove_const(:Dir)
|
58
|
+
remove_const(:File)
|
59
|
+
remove_const(:FileTest)
|
60
|
+
remove_const(:FileUtils)
|
61
|
+
|
62
|
+
const_set(:Dir, FakeFS::Dir)
|
63
|
+
const_set(:File, FakeFS::File)
|
64
|
+
const_set(:FileUtils, FakeFS::FileUtils)
|
65
|
+
const_set(:FileTest, FakeFS::FileTest)
|
66
|
+
end
|
67
|
+
|
68
|
+
[Dir, File, FileUtils, FileTest].each do |fake_class|
|
69
|
+
fake_class.class_eval do
|
70
|
+
def self.class_eval
|
71
|
+
raise NoMethodError, "class_eval is unavailable"
|
72
|
+
end
|
73
|
+
def self.instance_eval
|
74
|
+
raise NoMethodError, "instance_eval is unavailable"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
RUBY
|
79
|
+
|
80
|
+
FakeFS::FileSystem.clear
|
81
|
+
end
|
82
|
+
|
83
|
+
def eval(code, options={})
|
84
|
+
if seconds = options[:timeout]
|
85
|
+
sandbox_timeout(code, seconds) do
|
86
|
+
super code
|
87
|
+
end
|
88
|
+
else
|
89
|
+
super code
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def sandbox_timeout(name, seconds)
|
96
|
+
val, exc = nil
|
97
|
+
|
98
|
+
thread = Thread.start(name) do
|
99
|
+
begin
|
100
|
+
val = yield
|
101
|
+
rescue Exception => exc
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
thread.join(seconds)
|
106
|
+
|
107
|
+
if thread.alive?
|
108
|
+
if thread.respond_to? :kill!
|
109
|
+
thread.kill!
|
110
|
+
else
|
111
|
+
thread.kill
|
112
|
+
end
|
113
|
+
|
114
|
+
timed_out = true
|
115
|
+
end
|
116
|
+
|
117
|
+
if timed_out
|
118
|
+
raise TimeoutError, "#{self.class} timed out"
|
119
|
+
elsif exc
|
120
|
+
raise exc
|
121
|
+
else
|
122
|
+
val
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
IO_S_METHODS = %w[
|
127
|
+
new
|
128
|
+
foreach
|
129
|
+
open
|
130
|
+
]
|
131
|
+
|
132
|
+
KERNEL_S_METHODS = %w[
|
133
|
+
Array
|
134
|
+
binding
|
135
|
+
block_given?
|
136
|
+
catch
|
137
|
+
chomp
|
138
|
+
chomp!
|
139
|
+
chop
|
140
|
+
chop!
|
141
|
+
eval
|
142
|
+
fail
|
143
|
+
Float
|
144
|
+
format
|
145
|
+
global_variables
|
146
|
+
gsub
|
147
|
+
gsub!
|
148
|
+
Integer
|
149
|
+
iterator?
|
150
|
+
lambda
|
151
|
+
local_variables
|
152
|
+
loop
|
153
|
+
method_missing
|
154
|
+
proc
|
155
|
+
raise
|
156
|
+
scan
|
157
|
+
split
|
158
|
+
sprintf
|
159
|
+
String
|
160
|
+
sub
|
161
|
+
sub!
|
162
|
+
throw
|
163
|
+
].freeze
|
164
|
+
|
165
|
+
SYMBOL_S_METHODS = %w[
|
166
|
+
all_symbols
|
167
|
+
].freeze
|
168
|
+
|
169
|
+
STRING_S_METHODS = %w[
|
170
|
+
new
|
171
|
+
].freeze
|
172
|
+
|
173
|
+
KERNEL_METHODS = %w[
|
174
|
+
==
|
175
|
+
===
|
176
|
+
=~
|
177
|
+
Array
|
178
|
+
binding
|
179
|
+
block_given?
|
180
|
+
catch
|
181
|
+
chomp
|
182
|
+
chomp!
|
183
|
+
chop
|
184
|
+
chop!
|
185
|
+
class
|
186
|
+
clone
|
187
|
+
dup
|
188
|
+
eql?
|
189
|
+
equal?
|
190
|
+
eval
|
191
|
+
fail
|
192
|
+
Float
|
193
|
+
format
|
194
|
+
freeze
|
195
|
+
frozen?
|
196
|
+
global_variables
|
197
|
+
gsub
|
198
|
+
gsub!
|
199
|
+
hash
|
200
|
+
id
|
201
|
+
initialize_copy
|
202
|
+
inspect
|
203
|
+
instance_eval
|
204
|
+
instance_of?
|
205
|
+
instance_variables
|
206
|
+
instance_variable_get
|
207
|
+
instance_variable_set
|
208
|
+
instance_variable_defined?
|
209
|
+
Integer
|
210
|
+
is_a?
|
211
|
+
iterator?
|
212
|
+
kind_of?
|
213
|
+
lambda
|
214
|
+
local_variables
|
215
|
+
loop
|
216
|
+
methods
|
217
|
+
method_missing
|
218
|
+
nil?
|
219
|
+
private_methods
|
220
|
+
print
|
221
|
+
proc
|
222
|
+
protected_methods
|
223
|
+
public_methods
|
224
|
+
raise
|
225
|
+
remove_instance_variable
|
226
|
+
respond_to?
|
227
|
+
respond_to_missing?
|
228
|
+
scan
|
229
|
+
send
|
230
|
+
singleton_methods
|
231
|
+
singleton_method_added
|
232
|
+
singleton_method_removed
|
233
|
+
singleton_method_undefined
|
234
|
+
split
|
235
|
+
sprintf
|
236
|
+
String
|
237
|
+
sub
|
238
|
+
sub!
|
239
|
+
taint
|
240
|
+
tainted?
|
241
|
+
throw
|
242
|
+
to_a
|
243
|
+
to_s
|
244
|
+
type
|
245
|
+
untaint
|
246
|
+
__send__
|
247
|
+
].freeze
|
248
|
+
|
249
|
+
NILCLASS_METHODS = %w[
|
250
|
+
&
|
251
|
+
inspect
|
252
|
+
nil?
|
253
|
+
to_a
|
254
|
+
to_f
|
255
|
+
to_i
|
256
|
+
to_s
|
257
|
+
^
|
258
|
+
|
|
259
|
+
].freeze
|
260
|
+
|
261
|
+
SYMBOL_METHODS = %w[
|
262
|
+
===
|
263
|
+
id2name
|
264
|
+
inspect
|
265
|
+
to_i
|
266
|
+
to_int
|
267
|
+
to_s
|
268
|
+
to_sym
|
269
|
+
].freeze
|
270
|
+
|
271
|
+
TRUECLASS_METHODS = %w[
|
272
|
+
&
|
273
|
+
to_s
|
274
|
+
^
|
275
|
+
|
|
276
|
+
].freeze
|
277
|
+
|
278
|
+
FALSECLASS_METHODS = %w[
|
279
|
+
&
|
280
|
+
to_s
|
281
|
+
^
|
282
|
+
|
|
283
|
+
].freeze
|
284
|
+
|
285
|
+
ENUMERABLE_METHODS = %w[
|
286
|
+
all?
|
287
|
+
any?
|
288
|
+
collect
|
289
|
+
detect
|
290
|
+
each_with_index
|
291
|
+
entries
|
292
|
+
find
|
293
|
+
find_all
|
294
|
+
grep
|
295
|
+
include?
|
296
|
+
inject
|
297
|
+
map
|
298
|
+
max
|
299
|
+
member?
|
300
|
+
min
|
301
|
+
partition
|
302
|
+
reject
|
303
|
+
select
|
304
|
+
sort
|
305
|
+
sort_by
|
306
|
+
to_a
|
307
|
+
zip
|
308
|
+
].freeze
|
309
|
+
|
310
|
+
STRING_METHODS = %w[
|
311
|
+
%
|
312
|
+
*
|
313
|
+
+
|
314
|
+
<<
|
315
|
+
<=>
|
316
|
+
==
|
317
|
+
=~
|
318
|
+
capitalize
|
319
|
+
capitalize!
|
320
|
+
casecmp
|
321
|
+
center
|
322
|
+
chomp
|
323
|
+
chomp!
|
324
|
+
chop
|
325
|
+
chop!
|
326
|
+
concat
|
327
|
+
count
|
328
|
+
crypt
|
329
|
+
delete
|
330
|
+
delete!
|
331
|
+
downcase
|
332
|
+
downcase!
|
333
|
+
dump
|
334
|
+
each
|
335
|
+
each_byte
|
336
|
+
each_line
|
337
|
+
empty?
|
338
|
+
eql?
|
339
|
+
gsub
|
340
|
+
gsub!
|
341
|
+
hash
|
342
|
+
hex
|
343
|
+
include?
|
344
|
+
index
|
345
|
+
initialize
|
346
|
+
initialize_copy
|
347
|
+
insert
|
348
|
+
inspect
|
349
|
+
intern
|
350
|
+
length
|
351
|
+
ljust
|
352
|
+
lines
|
353
|
+
lstrip
|
354
|
+
lstrip!
|
355
|
+
match
|
356
|
+
next
|
357
|
+
next!
|
358
|
+
oct
|
359
|
+
replace
|
360
|
+
reverse
|
361
|
+
reverse!
|
362
|
+
rindex
|
363
|
+
rjust
|
364
|
+
rstrip
|
365
|
+
rstrip!
|
366
|
+
scan
|
367
|
+
size
|
368
|
+
slice
|
369
|
+
slice!
|
370
|
+
split
|
371
|
+
squeeze
|
372
|
+
squeeze!
|
373
|
+
strip
|
374
|
+
strip!
|
375
|
+
start_with?
|
376
|
+
sub
|
377
|
+
sub!
|
378
|
+
succ
|
379
|
+
succ!
|
380
|
+
sum
|
381
|
+
swapcase
|
382
|
+
swapcase!
|
383
|
+
to_f
|
384
|
+
to_i
|
385
|
+
to_s
|
386
|
+
to_str
|
387
|
+
to_sym
|
388
|
+
tr
|
389
|
+
tr!
|
390
|
+
tr_s
|
391
|
+
tr_s!
|
392
|
+
upcase
|
393
|
+
upcase!
|
394
|
+
upto
|
395
|
+
[]
|
396
|
+
[]=
|
397
|
+
].freeze
|
398
|
+
end
|
399
|
+
end
|
data/lib/sandbox/version.rb
CHANGED
data/spec/exploits_spec.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "rspec"
|
2
|
+
require "sandbox"
|
3
|
+
require "tempfile"
|
3
4
|
|
4
5
|
class OutsideFoo
|
5
|
-
def self.bar;
|
6
|
+
def self.bar; "bar"; end
|
6
7
|
end
|
7
8
|
|
8
9
|
describe "Sandbox exploits" do
|
@@ -12,166 +13,162 @@ describe "Sandbox exploits" do
|
|
12
13
|
subject.activate!
|
13
14
|
end
|
14
15
|
|
15
|
-
it
|
16
|
+
it "should not allow access to the filesystem using backticks" do
|
16
17
|
expect {
|
17
|
-
subject.eval(
|
18
|
+
subject.eval(%|`cat spec/support/foo.txt`|)
|
18
19
|
}.to raise_error(Sandbox::SandboxException)
|
19
20
|
end
|
20
21
|
|
21
22
|
it "should not allow running system commands using system" do
|
22
23
|
expect {
|
23
|
-
subject.eval
|
24
|
+
subject.eval(%|system("ls")|)
|
24
25
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
25
26
|
end
|
26
27
|
|
27
28
|
it "should not allow running system commands through File.class_eval" do
|
28
29
|
expect {
|
29
|
-
subject.eval
|
30
|
+
subject.eval(%|File.class_eval { `echo Hello` }|)
|
30
31
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
31
32
|
|
32
33
|
expect {
|
33
|
-
subject.eval
|
34
|
+
subject.eval(%|FileUtils.class_eval { `echo Hello` }|)
|
34
35
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
35
36
|
|
36
37
|
expect {
|
37
|
-
subject.eval
|
38
|
+
subject.eval(%|Dir.class_eval { `echo Hello` }|)
|
38
39
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
39
40
|
|
40
41
|
expect {
|
41
|
-
subject.eval
|
42
|
+
subject.eval(%|FileTest.class_eval { `echo Hello` }|)
|
42
43
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
43
44
|
end
|
44
45
|
|
45
46
|
it "should not allow running system commands through File.eval" do
|
46
47
|
expect {
|
47
|
-
subject.eval
|
48
|
+
subject.eval(%|File.eval "`echo Hello`"|)
|
48
49
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
49
50
|
|
50
51
|
expect {
|
51
|
-
subject.eval
|
52
|
+
subject.eval(%|FileUtils.eval "`echo Hello`"|)
|
52
53
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
53
54
|
|
54
55
|
expect {
|
55
|
-
subject.eval
|
56
|
+
subject.eval(%|Dir.eval "`echo Hello`"|)
|
56
57
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
57
58
|
|
58
59
|
expect {
|
59
|
-
subject.eval
|
60
|
+
subject.eval(%|FileTest.eval "`echo Hello`"|)
|
60
61
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
61
62
|
end
|
62
63
|
|
63
64
|
it "should not allow running system commands through File.instance_eval" do
|
64
65
|
expect {
|
65
|
-
subject.eval
|
66
|
+
subject.eval(%|File.instance_eval { `echo Hello` }|)
|
66
67
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
67
68
|
|
68
69
|
expect {
|
69
|
-
subject.eval
|
70
|
+
subject.eval(%|FileUtils.instance_eval { `echo Hello` }|)
|
70
71
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
71
72
|
|
72
73
|
expect {
|
73
|
-
subject.eval
|
74
|
+
subject.eval(%|Dir.instance_eval { `echo Hello` }|)
|
74
75
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
75
76
|
|
76
77
|
expect {
|
77
|
-
subject.eval
|
78
|
+
subject.eval(%|FileTest.instance_eval { `echo Hello` }|)
|
78
79
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
79
80
|
end
|
80
81
|
|
81
82
|
it "should not allow running any commands or reading files using IO" do
|
82
83
|
expect {
|
83
|
-
subject.eval
|
84
|
+
subject.eval(%|f=IO.popen("uname"); f.readlines; f.close|)
|
84
85
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
85
86
|
|
86
87
|
expect {
|
87
|
-
subject.eval
|
88
|
+
subject.eval(%|IO.binread("/etc/passwd")|)
|
88
89
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
89
90
|
|
90
91
|
expect {
|
91
|
-
subject.eval
|
92
|
+
subject.eval(%|IO.read("/etc/passwd")|)
|
92
93
|
}.to raise_error(Sandbox::SandboxException, /NoMethodError/)
|
93
94
|
end
|
94
95
|
|
95
96
|
it "should not pass through methods added to Kernel" do
|
96
|
-
k = subject.eval(
|
97
|
+
k = subject.eval(%|Kernel|)
|
97
98
|
def k.crack
|
98
99
|
open("/etc/passwd")
|
99
100
|
end
|
100
101
|
|
101
102
|
Kernel.should respond_to(:crack)
|
102
|
-
subject.eval(
|
103
|
+
subject.eval(%|Kernel.respond_to?(:crack)|).should == false
|
103
104
|
end
|
104
105
|
|
105
106
|
it "should not allow calling fork on Kernel, even through eval" do
|
106
|
-
subject.eval(
|
107
|
+
subject.eval(%|eval("Kernel").respond_to?(:fork)|).should == false
|
107
108
|
end
|
108
109
|
|
109
110
|
it "should not get access to outside the box objects by using eval and TOPLEVEL_BINDING" do
|
110
111
|
expect {
|
111
|
-
subject.eval(%{eval(
|
112
|
+
subject.eval(%{eval("OutsideFoo.bar", TOPLEVEL_BINDING)})
|
112
113
|
}.to raise_error(Sandbox::SandboxException, /NameError/)
|
113
114
|
end
|
114
115
|
|
115
116
|
it "should not get access to the outside eval through a ref'd object" do
|
116
|
-
subject.ref
|
117
|
-
subject.eval
|
118
|
-
subject.eval(
|
119
|
-
subject.eval(
|
117
|
+
subject.ref(OutsideFoo)
|
118
|
+
subject.eval(%|obj = OutsideFoo.new|)
|
119
|
+
subject.eval(%|(obj.methods.grep /^eval/).empty?|).should == true
|
120
|
+
subject.eval(%|obj.respond_to?(:eval)|).should == false
|
120
121
|
end
|
121
122
|
|
122
123
|
it "should not allow file access, even through a ref hack" do
|
123
|
-
unsafe_open = %{File.open('/etc/passwd').read}
|
124
|
-
|
125
124
|
expect {
|
126
|
-
subject.eval(
|
125
|
+
subject.eval(%|File.open("/etc/passwd").read|)
|
127
126
|
}.to raise_error(Sandbox::SandboxException)
|
128
127
|
|
129
|
-
subject.ref
|
130
|
-
subject.eval
|
131
|
-
|
132
|
-
unsafe_open_hack = %{obj.eval "#{unsafe_open}"}
|
128
|
+
subject.ref(OutsideFoo)
|
129
|
+
subject.eval(%|obj = OutsideFoo.new|)
|
133
130
|
|
134
131
|
pending "gotta figure out how to lock down ref'd objects eval" do
|
135
132
|
expect {
|
136
|
-
subject.eval(
|
133
|
+
subject.eval(%|obj.eval("File.open(\\"/etc/passwd\\").read")|)
|
137
134
|
}.to raise_error(Sandbox::SandboxException)
|
138
135
|
end
|
139
136
|
end
|
140
137
|
|
141
138
|
it "should have safe globals" do
|
142
|
-
subject.eval(
|
139
|
+
subject.eval(%|$0|).should == "(sandbox)"
|
143
140
|
/(.)(.)(.)/.match("abc")
|
144
|
-
subject.eval(
|
145
|
-
subject.eval(
|
141
|
+
subject.eval(%|$TEST = "TEST"; $TEST|).should == "TEST"
|
142
|
+
subject.eval(%|/(.)(.)(.)/.match("def"); $2|).should == "e"
|
146
143
|
$2.should == "b"
|
147
|
-
subject.eval(
|
148
|
-
subject.eval(
|
144
|
+
subject.eval(%|$TEST|).should == "TEST"
|
145
|
+
subject.eval(%|$2|).should == "e"
|
149
146
|
end
|
150
147
|
|
151
148
|
it "should not keep Kernel.fork" do
|
152
149
|
expect {
|
153
|
-
subject.eval(
|
150
|
+
subject.eval(%|Kernel.fork|)
|
154
151
|
}.to raise_error(Sandbox::SandboxException)
|
155
152
|
|
156
153
|
expect {
|
157
|
-
subject.eval(
|
154
|
+
subject.eval(%|fork|)
|
158
155
|
}.to raise_error(Sandbox::SandboxException)
|
159
156
|
end
|
160
157
|
|
161
158
|
it "should not allow the sandbox to get back to Kernel through ancestors" do
|
162
|
-
subject.eval(
|
159
|
+
subject.eval(%|$0.class.ancestors[3].respond_to?(:fork)|).should == false
|
163
160
|
end
|
164
161
|
|
165
162
|
it "should not pass through block scope" do
|
166
163
|
1.times do |i|
|
167
|
-
subject.eval(
|
164
|
+
subject.eval(%|local_variables|).should == []
|
168
165
|
end
|
169
166
|
end
|
170
167
|
|
171
168
|
it "should not allow exploits through match data" do
|
172
|
-
subject.eval(
|
169
|
+
subject.eval(%|begin; /(.+)/.match("FreakyFreaky").instance_eval { open("/etc/passwd") }; rescue NameError; :NameError; end|).should == :NameError
|
173
170
|
|
174
|
-
subject.eval(
|
171
|
+
subject.eval(%|begin;(begin;Regexp.new("(");rescue e;e;end).instance_eval{ open("/etc/passwd") }; rescue NameError; :NameError; end|).should == :NameError
|
175
172
|
end
|
176
173
|
|
177
174
|
it "should not be able to access outside box Kernel through exceptions" do
|
@@ -184,6 +181,16 @@ describe "Sandbox exploits" do
|
|
184
181
|
RUBY
|
185
182
|
subject.eval(exception_code)
|
186
183
|
|
187
|
-
subject.eval(
|
184
|
+
subject.eval(%|obj.class.ancestors[4].respond_to?(:fork)|).should == false
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should not allow access to Java classes" do
|
188
|
+
tempfile = Tempfile.new("sandbox")
|
189
|
+
expect {
|
190
|
+
subject.eval("Object.send(:java_import, 'java.lang.ProcessBuilder')")
|
191
|
+
subject.eval("Java::java.lang.ProcessBuilder.new('sh', '-c', 'echo pwned > #{tempfile.path}').start; nil")
|
192
|
+
}.to raise_error(Sandbox::SandboxException)
|
193
|
+
tempfile.size.should == 0
|
194
|
+
tempfile.close
|
188
195
|
end
|
189
196
|
end
|