Ruby eval函数代码执行注入失败求助:反引号内命令未执行
先帮你拆解下当前的问题:你要注入的目标代码是eval "\"Hello "+params['username']+"\"",这段代码其实是把用户输入的username拼接进一个字符串字面量里,然后让Ruby去执行这个字符串。比如正常输入alice,eval执行的就是"Hello alice",本质上只是返回一个字符串,不会触发任何代码执行——所以你得先跳出这个字符串字面量,让eval去执行额外的Ruby代码才行。
你现在用的注入代码myuser"%2B[system('uname')]%2B",解码后是myuser"+[system('uname')]+",这里有两个关键问题:
- 反引号的用法错了:Ruby里的反引号
`是用来执行shell命令的,不是执行Ruby代码。你在反引号里写[system('uname')],shell会把它当成shell命令去解析,这显然不是有效的shell指令,自然不会执行你想要的system('uname')(这是Ruby方法)。 - 多余的方括号:就算你想在反引号里执行shell命令,
[system('uname')]也不对,直接写uname就行,比如`uname`,这样会返回shell命令uname的输出结果。
正确的注入方式
要让eval执行你的Ruby代码,得先跳出原来的字符串字面量。举两个可行的例子:
方法1:用分号分隔代码
把username设置为:"; system('uname'); "(URL编码后是%22%3B+system%28%27uname%27%29%3B+%22)
拼接后eval执行的内容就变成:
"Hello "; system('uname'); ""
这样eval会依次执行:
- 解析第一个字符串
"Hello "(无实际输出) - 执行Ruby的
system('uname')方法,这个方法会直接在终端输出系统名称(比如Linux/macOS) - 解析空字符串
""(无实际输出)
方法2:用字符串拼接插入代码
把username设置为:"+ system('uname'); "(URL编码后是%22%2B+system%28%27uname%27%29%3B+%22)
拼接后eval执行的内容是:
"Hello "+ system('uname'); ""
这里system('uname')会先执行,输出系统名,然后"Hello "和system的返回值(成功的话是true)拼接,最终eval返回"Hello true",但你要的命令执行已经完成了。
如果想用反引号获取命令输出,也可以写成:"+ uname +"(URL编码后是%22%2B+%60uname%60+%2B%22),拼接后eval执行:
"Hello "+`uname`+""
这时候eval会返回"Hello Linux"(假设系统是Linux),同时uname命令也会执行(不过反引号会捕获命令输出作为返回值,不会直接打印到终端,除非你特意输出它)。
为什么你原来的注入没生效?
你原来的反引号里写的[system('uname')],shell会尝试执行这个命令——shell里的[是test命令的别名,它会把system('uname')当成参数,但这显然不符合test命令的语法,所以shell会执行失败,但这个错误不会反馈到Ruby的eval层面,所以你看不到错误,也看不到预期的系统名称输出。
内容的提问来源于stack exchange,提问作者Ashwin Gopalakrishnan




