Ruby On Rails 路径穿越漏洞(CVE-2018-3760)
前言:
这个漏洞作为路径穿越的典型例子,比较经典,18年跟着文档分析了一遍,最近又重新理了一遍,捎带着写了一遍源码跟踪分析的过程,个人感觉整个跟入调用的思想还是比较清晰的,分析的过程写的比较详细,有兴趣的萌新们也可以跟着分析一遍。
背景:
prockets中存在信息泄露漏洞。 受影响的版本:4.0.0.beta7及更低版本,3.7.1及更低版本,2.12.4及更低版本。 在生产中使用Sprockets服务器时,可以使用特制的请求来访问存在于应用程序根目录之外的文件系统上的文件。 运行受影响版本的所有用户应立即升级或使用其中一种解决方法。
前方高能预警,前文别被各种调用绕晕了~
## 漏洞分析: 先看一下漏洞爆出以后打的补丁![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/eb755f8ff420fedd9fbed6097158096f.png)
Test_server在测试环境下使用,这里不去关注,着重看看server.rb(下图是已经patch过的)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/9a44bf68376b5e2906afa74d79c14374.png)
Forbidden_request是在哪儿被调用的呢?
往前找
可以看到是在call函数中被调用
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d231804221f93575960e7233d431129b.png)
Forbidden_request返回forbidden_response(env)信息后会进入find_asset
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b5224e69e727624be4cb0ce5f3bce15f.png)
跟进去
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/cf879f693606653a475a8ac9081b7656.png)
在find_asset中又跟入load()
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e5afb6f25f76ba4946593a47548c38b5.png)
传入的url此时已经被自动解码过一次,这是第一次
跟入unloadedasset.new
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/842cad3ac0238f7f69813182fd76a04d.png)
在其中可以看到访问filename时会调用load_file_params
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/3e89c7d636ab2e9e6f0bf23630569610.png)
继续跟进去
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ecb3b9c5a6da195b262b5f068f6b1205.png)
跟入URIUtils找到parse_asset_uri
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e81cee74cedac4720b3a11ccbf0be56b.png)
跟入split_file_uri
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/c8638df36d9f4f69e0048a4063376e5d.png)
第48行进行了第二次解码
至此,便完成了从get获得的路径到主机路径的解析流程
根据“在find_asset中又跟入load()”这一步的代码逻辑,解析完成后调用load_from_unloaded
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/662916b1934e85b952f02448c450a725.png)
由两个raise可以看出,函数主要功能是检查文件是否存在和文件是否在指定路径下
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d29d75d4fbed351548370f47fc6962a4.png)
以利用漏洞读取/etc/passwd为例,文件是一定存在的,关键是判断文件是否在指定路径下
影响这个判断的关键的地方在上图的第114行,跟入path_split
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6af323331387d072652fbc31d855a6db.png)
然后跟入split_subpath
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/9e3323a592596e519a4c485c4e1c7119.png)
165行的判断看出如果是以path开头,则检查通过
这儿检查通过之后,还是回到load_from_unloaded进行后续的读取操作。
这么一个判断本身是没有什么问题的,但是在这一系列的调用过程中,不知不觉间将传入的路径进行了二次解码,所以作为攻击做就可以利用%2525%252e即…/…/穿越到根目录再读取任意文件,接下来的复现中的第三步利用成功最关键的地方也在这儿。
复现:
环境搭好后的主界面
构造payload尝试目录穿越
http://your-ip:3000/assets/file:///etc/passwd
其中将//URL编码为%2f
http://your-ip:3000/assets/file:%2F%2F/etc/passwd
此时会报错
因为/etc/passwd不在允许的目录中
但是在报错页面中给出了允许的目录列表,随意选中一个,然后使用…/…/的办法向上跳转,最后读取/etc/passwd
这里…/…/需url编码为%2e,然后二次编码为%252e
最后得payload:
http://111.230.225.189:3000/assets/file:%2F%2F/usr/src/blog/app/assets/images/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
参考:
1.https://seclists.org/oss-sec/2018/q2/210
2.https://medium.com/@Bakku1505/ruby-start-with-end-with-vs-regular-expressions-59728be0859e
3.https://xz.aliyun.com/t/25421
4.https://github.com/vulhub/vulhub/blob/master/rails/CVE-2018-3760/README.zh-cn.md