八十三.CTF夺旗-Python考点SSTI&反序列化&字符串
2023年 01月 22 日

BIGFISH

在这里插入图片描述

在这里插入图片描述

必备知识点:

  • 在大量的比赛真题复现中,将涉及到渗透测试的题库进行了语言区分,主要以 Python, PHP,Java为主,本章节将各个语言的常考点进行真题复现讲解。

CTF各大题型简介

  • MISC(安全杂项):全称Miscellaneous。题目涉及流量分析、电子取证、人肉搜索、数据分析、大数据统计等等,覆盖面比较广。我们平时看到的社工类题目;给你一个流量包让你分析的题目;取证分析题目;都属于这类题目。主要考查参赛选手的各种基础综合知识,考察范围比较广。

  • PPC(编程类):全称Professionally Program Coder。题目涉及到程序编写、编程算法实现。算法的逆向编写,批量处理等,有时候用编程去处理问题,会方便的多。当然PPC相比ACM来说,还是较为容易的。至于编程语言嘛,推荐使用Python来尝试。这部分主要考察选手的快速编程能力。

  • CRYPTO(密码学):全称Cryptography。题目考察各种加解密技术,包括古典加密技术、现代加密技术甚至出题者自创加密技术。实验吧“角斗场”中,这样的题目汇集的最多。这部分主要考查参赛选手密码学相关知识点。

  • REVERSE(逆向):全称reverse。题目涉及到软件逆向、破解技术等,要求有较强的反汇编、反编译扎实功底。需要掌握汇编,堆栈、寄存器方面的知识。有好的逻辑思维能力。主要考查参赛选手的逆向分析能力。此类题目也是线下比赛的考察重点。

  • STEGA(隐写):全称Steganography。隐写术是我开始接触CTF觉得比较神奇的一类,知道这个东西的时候感觉好神奇啊,黑客们真是聪明。题目的Flag会隐藏到图片、音频、视频等各类数据载体中供参赛选手获取。载体就是图片、音频、视频等,可能是修改了这些载体来隐藏flag,也可能将flaq隐藏在这些载体的二进制空白位置。有时候需要你侦探精神足够的强,才能发现。此类题目主要考察参赛选手对各种隐写工具、隐写算法的熟悉程度。实验吧“角斗场”的隐写题目在我看来是比较全的,以上说到的都有涵盖。新手盆友们可以去了解下。

  • PWN(溢出):PWN在黑客俚语中代表着攻破,取得权限,在CTF比赛中它代表着溢出类的题目,其中常见类型溢出漏洞有栈溢出、堆溢出。在CTF比赛中,线上比赛会有,但是比例不会太重,进入线下比赛,逆向和溢出则是战队实力的关健。主要考察参与选手漏洞挖掘和利用能力。

  • WEB(wob类):WEB应用在今天越来越广泛,也是CTF夺旗竞赛中的主要题型,题目涉及到常见的Web漏洞,诸如注入、XSS、文件包含、代码审计、上传等漏洞。这些题目都不是简单的注入、上传题目,至少会有一层的安全过滤,需要选手想办法绕过。且Web题目是国内比较多也是大家比较喜欢的题目。因为大多数人开始安全都是从web开始的。

案例演示:

  • 案例1:CTF夺旗-Python-支付逻辑&JWT&反序列化

  • 案例2:CTF夺旗-Python-Flask&jinja2&SSTI模版注入

  • 案例3:CTF夺旗-Python-格式化字符串漏洞&读取对象

案例1:CTF夺旗-Python-支付逻辑&JWT&反序列化

真题:2019 CISCN华北赛区Day1 Web2 WriteUp (全国大学生信息安全竞赛)

打开后通过提示 -> 寻找LV6 -> 购买修改支付逻辑 -> 绕过admin限制需修改jwt值 -> 爆破jwt密匙 -> 重组jwt值成为admin -> 购买进入会员中心 -> 源码找到文件压缩源码 -> Python代码审计反序列化 -> 构造读取flag代码进行序列化打印 -> 提交获取

  • <1>打开页面如下



    • img

  • <2>根据提示:暴破、一定要买到LV6。写一个脚本,找到LV6。如下图所示,在181页。



    • img

  • <3>打开181页,找到LV6的购买链接。



    • img

  • <4>点击购买,发现价格太高,而余额太少,不够。



    • img

    • img

  • <5>发现购买时有一个优惠券,尝试在前端修改优惠券折扣,点击结算,提示“该页面只允许admin访问”。



    • img

    • img

  • <6>由于目前我们登录的是普通用户,此时可以尝试垂直越权。观察数据包,发现会话使用的JWT,尝试使用c-jwt-cracker工具爆破JWT秘钥,成功得到秘钥。



    • img

    • img

  • <7>将username值改为admin,使用秘钥重新生成JWT,成功登录admin账户。



    • img

    • img

  • <8>查看网页源代码,找到新提示。



    • img

  • <9>下载www.zip,解压缩,打开文件,发现是python源码。



    • img

  • <10>使用idea工具打开源码,全局搜索漏洞关键字。发现反序列化关键字pickle,猜测这里有反序列化漏洞。



  • <11>利用漏洞,编写脚本,生成payload



    • img

  • <12>由于become输入框是个隐藏框,可以F12删除隐藏属性,显示输入框,输入payload,点击“一键成为大会员”。



    • img

  • <13>成功得到flag。



    • img

案例2:CTF夺旗-Python-Flask&jinja2&SSTI模版注入

(1)ssti模版注入原理解释

  • 一个安全的代码应该如下:

  • #/www
    from flask import Flask,request,render_template
    from jinja2 import Template
    app = Flask(__name__)
    app.config['SECRET'] = "root:password"
     
    @app.route('/')
    @app.route('/index')
    def index():
    return render_template("index.html",title='SSTI_TEST',name=request.args.get("name"))
     
    if __name__ == "__main__":
    app.run()
  • <!--/www/templates/index.html-->
    <html>
    <head>
    <title>{{title}} - cl4y</title>
    </head>
    <body>
    <h1>Hello, {{name}} !</h1>
    </body>
    </html>
  • 可以看到,我们在index.html里面构造了两个渲染模板,用户通过传递name参数可以控制回显的内容:



    • img

  • 即使用户输入渲染模板,更改语法结构,也不会造成SSTI注入:



    • img

  • 原因是:服务端先将index.html渲染,然后读取用户输入的参数,模板其实已经固定,用户的输入不会更改模板的语法结构。

  • 而如果有程序员为了图省事,将代码这样写:

  • from flask import Flask,request
    from jinja2 import Template
    app = Flask(__name__)
    app.config['SECRET_KEY'] = "password:123456789"
    @app.route("/")
    def index():
    name = request.args.get('name', 'guest')
    t = Template('''
    <html>
    <head>
    <title>SSTI_TEST - cl4y</title>
    </head>
    <body>
    <h1>Hello, %s !</h1>
    </body>
    </html>
    '''% (name))
    return t.render()
    if __name__ == "__main__":
    app.run()
  • 我们再进行测试:可以看到,我们输入的内容被服务器渲染然后输出,形成SSTI模板注入漏洞。



    • img

(2)如何确定Python-ssti模版注入:中间件,返回页面,关键文字提示等

  • 中间件:可通过请求响应头server值判断,比如 Server:Werkzeug/0.11.15 python/3.7.0,说明后台使用python脚本编写,应该想到测试是否有SSTI漏洞。

  • 返回页面:比如返回Opos!That page doesnt exist.

  • 关键字提示:比如flask、inja2、mako等

(3)如何正确利用ssti注入获取Flag:人工&工具

a . 人工:判断版本-找利用类-构造Payload-绕过滤等

b . 工具:自动化检测工具tplmap使用

  • https://github.com/epinna/tplmap

  • https://www.cnblogs.com/f0rsaken/p/14610425.htmlTplmap-20211015

  • Usage: python tplmap.py [options]
     
    选项:
    -h, --help          显示帮助并退出
     
    目标:
    -u URL, --url=URL   目标 URL
    -X REQUEST, --re..  强制使用给定的HTTP方法 (e.g. PUT)
     
    请求:
    -d DATA, --data=..  通过POST发送的数据字符串 它必须作为查询字符串: param1=value1&param2=value2
    -H HEADERS, --he..  附加消息头 (e.g. 'Header1: Value1') 多次使用以添加新的消息头
    -c COOKIES, --co..  Cookies (e.g. 'Field1=Value1') 多次使用以添加新的Cookie
    -A USER_AGENT, -..  HTTP User-Agent 消息头的值
    --proxy=PROXY       使用代理连接到目标URL
     
    检测:
    --level=LEVEL       要执行的代码上下文转义级别 (1-5, Default: 1)
    -e ENGINE, --eng..  强制将后端模板引擎设置为此值
    -t TECHNIQUE, --..  技术 R:渲染 T:基于时间的盲注 Default: RT
     
    操作系统访问:
    --os-cmd=OS_CMD     执行操作系统命令
    --os-shell          提示交互式操作系统Shell
    --upload=UPLOAD     上传本地文件到远程主机
    --force-overwrite   上传时强制覆盖文件
    --download=DOWNL..  下载远程文件到本地主机
    --bind-shell=BIN..  在目标的TCP端口上生成系统Shell并连接到它
    --reverse-shell=..  运行系统Shell并反向连接到本地主机端口
     
    模板检查:
    --tpl-shell         在模板引擎上提示交互式Shell
    --tpl-code=TPL_C..  在模板引擎中注入代码
     
    常规:
    --force-level=FO..  强制将测试级别设置为此值
    --injection-tag=..  使用字符串作为注入标签 (default '*')
  • 举例



c . 案例演示

  • 靶场地址:https://buuoj.cn/challenges#[WesternCTF2018]shrine

  • 打开发现给出源码-pytho&flask&ssti-代码分析访问参数,flag位置,过滤等-不能进行正常的路径符合-采用内置函数读取-读取代码中的存储FLAG

  • <1>页面打开如下,直接给出源代码。



    • img

    • 代码格式化如下

    • import flask
      import os
       
      app = flask.Flask(__name__)
      app.config['FLAG'] = os.environ.pop('FLAG')
       
      @app.route('/')
      def index():
      return open(__file__).read()
       
      @app.route('/shrine/')
      def shrine(shrine):
      
      def safe_jinja(s):
      s = s.replace('(', '').replace(')', '')
      blacklist = ['config', 'self']
      return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
      
      return flask.render_template_string(safe_jinja(shrine))
      
      if __name__ == '__main__':
      app.run(debug=True)
  • <2>看到flask,想到模板注入。



  • <3>看源码app.config['FLAG'] = os.environ.pop('FLAG'),推测{undefined{config}}可查看所有app.config内容,但是这题设了黑名单[‘config’,‘self’]并且过滤了括号。不过python还有一些内置函数,比如url_for和get_flashed_messages。



    • url_for查看全局变量:/shrine/{{url_for.globals}}

    • img

    • current_app意思应该是当前app,那我们就看当前app下的config:/shrine/{{url_for.globals['current_app'].config}},成功拿到flag。

    • img

  • <4>get_flashed_message同理:



    • /shrine/{{get_flashed_messages.globals['current_app'].config['FLAG']}}

    • img

案例3:CTF夺旗-Python-格式化字符串漏洞&读取对象

格式化字符串漏洞原理

  • 第一种:%操作符

  • 第二种:string.Template

  • 第三种:调用Format方法

  • 第四种:f-Strings

参考:https:/xz.aliyun.com/t/3569

漏洞代码举例

  • <1>调用Format方法。如下图所示,name后面的值可控,我们就可以传参获取当前脚本的核心变量flag值。



    • img

  • <2>f-Strings。这是python3函数式的新增一种字符串,其功能强大,可以执行字符串中包含的python表达式。



    • img

涉及资源:

八十三.CTF夺旗-Python考点SSTI&反序列化&字符串

在这里插入图片描述

在这里插入图片描述

必备知识点:

  • 在大量的比赛真题复现中,将涉及到渗透测试的题库进行了语言区分,主要以 Python, PHP,Java为主,本章节将各个语言的常考点进行真题复现讲解。

CTF各大题型简介

  • MISC(安全杂项):全称Miscellaneous。题目涉及流量分析、电子取证、人肉搜索、数据分析、大数据统计等等,覆盖面比较广。我们平时看到的社工类题目;给你一个流量包让你分析的题目;取证分析题目;都属于这类题目。主要考查参赛选手的各种基础综合知识,考察范围比较广。

  • PPC(编程类):全称Professionally Program Coder。题目涉及到程序编写、编程算法实现。算法的逆向编写,批量处理等,有时候用编程去处理问题,会方便的多。当然PPC相比ACM来说,还是较为容易的。至于编程语言嘛,推荐使用Python来尝试。这部分主要考察选手的快速编程能力。

  • CRYPTO(密码学):全称Cryptography。题目考察各种加解密技术,包括古典加密技术、现代加密技术甚至出题者自创加密技术。实验吧“角斗场”中,这样的题目汇集的最多。这部分主要考查参赛选手密码学相关知识点。

  • REVERSE(逆向):全称reverse。题目涉及到软件逆向、破解技术等,要求有较强的反汇编、反编译扎实功底。需要掌握汇编,堆栈、寄存器方面的知识。有好的逻辑思维能力。主要考查参赛选手的逆向分析能力。此类题目也是线下比赛的考察重点。

  • STEGA(隐写):全称Steganography。隐写术是我开始接触CTF觉得比较神奇的一类,知道这个东西的时候感觉好神奇啊,黑客们真是聪明。题目的Flag会隐藏到图片、音频、视频等各类数据载体中供参赛选手获取。载体就是图片、音频、视频等,可能是修改了这些载体来隐藏flag,也可能将flaq隐藏在这些载体的二进制空白位置。有时候需要你侦探精神足够的强,才能发现。此类题目主要考察参赛选手对各种隐写工具、隐写算法的熟悉程度。实验吧“角斗场”的隐写题目在我看来是比较全的,以上说到的都有涵盖。新手盆友们可以去了解下。

  • PWN(溢出):PWN在黑客俚语中代表着攻破,取得权限,在CTF比赛中它代表着溢出类的题目,其中常见类型溢出漏洞有栈溢出、堆溢出。在CTF比赛中,线上比赛会有,但是比例不会太重,进入线下比赛,逆向和溢出则是战队实力的关健。主要考察参与选手漏洞挖掘和利用能力。

  • WEB(wob类):WEB应用在今天越来越广泛,也是CTF夺旗竞赛中的主要题型,题目涉及到常见的Web漏洞,诸如注入、XSS、文件包含、代码审计、上传等漏洞。这些题目都不是简单的注入、上传题目,至少会有一层的安全过滤,需要选手想办法绕过。且Web题目是国内比较多也是大家比较喜欢的题目。因为大多数人开始安全都是从web开始的。

案例演示:

  • 案例1:CTF夺旗-Python-支付逻辑&JWT&反序列化

  • 案例2:CTF夺旗-Python-Flask&jinja2&SSTI模版注入

  • 案例3:CTF夺旗-Python-格式化字符串漏洞&读取对象

案例1:CTF夺旗-Python-支付逻辑&JWT&反序列化

真题:2019 CISCN华北赛区Day1 Web2 WriteUp (全国大学生信息安全竞赛)

打开后通过提示 -> 寻找LV6 -> 购买修改支付逻辑 -> 绕过admin限制需修改jwt值 -> 爆破jwt密匙 -> 重组jwt值成为admin -> 购买进入会员中心 -> 源码找到文件压缩源码 -> Python代码审计反序列化 -> 构造读取flag代码进行序列化打印 -> 提交获取

  • <1>打开页面如下



    • img

  • <2>根据提示:暴破、一定要买到LV6。写一个脚本,找到LV6。如下图所示,在181页。



    • img

  • <3>打开181页,找到LV6的购买链接。



    • img

  • <4>点击购买,发现价格太高,而余额太少,不够。



    • img

    • img

  • <5>发现购买时有一个优惠券,尝试在前端修改优惠券折扣,点击结算,提示“该页面只允许admin访问”。



    • img

    • img

  • <6>由于目前我们登录的是普通用户,此时可以尝试垂直越权。观察数据包,发现会话使用的JWT,尝试使用c-jwt-cracker工具爆破JWT秘钥,成功得到秘钥。



    • img

    • img

  • <7>将username值改为admin,使用秘钥重新生成JWT,成功登录admin账户。



    • img

    • img

  • <8>查看网页源代码,找到新提示。



    • img

  • <9>下载www.zip,解压缩,打开文件,发现是python源码。



    • img

  • <10>使用idea工具打开源码,全局搜索漏洞关键字。发现反序列化关键字pickle,猜测这里有反序列化漏洞。



  • <11>利用漏洞,编写脚本,生成payload



    • img

  • <12>由于become输入框是个隐藏框,可以F12删除隐藏属性,显示输入框,输入payload,点击“一键成为大会员”。



    • img

  • <13>成功得到flag。



    • img

案例2:CTF夺旗-Python-Flask&jinja2&SSTI模版注入

(1)ssti模版注入原理解释

  • 一个安全的代码应该如下:

  • #/www
    from flask import Flask,request,render_template
    from jinja2 import Template
    app = Flask(__name__)
    app.config['SECRET'] = "root:password"
     
    @app.route('/')
    @app.route('/index')
    def index():
    return render_template("index.html",title='SSTI_TEST',name=request.args.get("name"))
     
    if __name__ == "__main__":
    app.run()
  • <!--/www/templates/index.html-->
    <html>
    <head>
    <title>{{title}} - cl4y</title>
    </head>
    <body>
    <h1>Hello, {{name}} !</h1>
    </body>
    </html>
  • 可以看到,我们在index.html里面构造了两个渲染模板,用户通过传递name参数可以控制回显的内容:



    • img

  • 即使用户输入渲染模板,更改语法结构,也不会造成SSTI注入:



    • img

  • 原因是:服务端先将index.html渲染,然后读取用户输入的参数,模板其实已经固定,用户的输入不会更改模板的语法结构。

  • 而如果有程序员为了图省事,将代码这样写:

  • from flask import Flask,request
    from jinja2 import Template
    app = Flask(__name__)
    app.config['SECRET_KEY'] = "password:123456789"
    @app.route("/")
    def index():
    name = request.args.get('name', 'guest')
    t = Template('''
    <html>
    <head>
    <title>SSTI_TEST - cl4y</title>
    </head>
    <body>
    <h1>Hello, %s !</h1>
    </body>
    </html>
    '''% (name))
    return t.render()
    if __name__ == "__main__":
    app.run()
  • 我们再进行测试:可以看到,我们输入的内容被服务器渲染然后输出,形成SSTI模板注入漏洞。



    • img

(2)如何确定Python-ssti模版注入:中间件,返回页面,关键文字提示等

  • 中间件:可通过请求响应头server值判断,比如 Server:Werkzeug/0.11.15 python/3.7.0,说明后台使用python脚本编写,应该想到测试是否有SSTI漏洞。

  • 返回页面:比如返回Opos!That page doesnt exist.

  • 关键字提示:比如flask、inja2、mako等

(3)如何正确利用ssti注入获取Flag:人工&工具

a . 人工:判断版本-找利用类-构造Payload-绕过滤等

b . 工具:自动化检测工具tplmap使用

  • https://github.com/epinna/tplmap

  • https://www.cnblogs.com/f0rsaken/p/14610425.htmlTplmap-20211015

  • Usage: python tplmap.py [options]
     
    选项:
    -h, --help          显示帮助并退出
     
    目标:
    -u URL, --url=URL   目标 URL
    -X REQUEST, --re..  强制使用给定的HTTP方法 (e.g. PUT)
     
    请求:
    -d DATA, --data=..  通过POST发送的数据字符串 它必须作为查询字符串: param1=value1&param2=value2
    -H HEADERS, --he..  附加消息头 (e.g. 'Header1: Value1') 多次使用以添加新的消息头
    -c COOKIES, --co..  Cookies (e.g. 'Field1=Value1') 多次使用以添加新的Cookie
    -A USER_AGENT, -..  HTTP User-Agent 消息头的值
    --proxy=PROXY       使用代理连接到目标URL
     
    检测:
    --level=LEVEL       要执行的代码上下文转义级别 (1-5, Default: 1)
    -e ENGINE, --eng..  强制将后端模板引擎设置为此值
    -t TECHNIQUE, --..  技术 R:渲染 T:基于时间的盲注 Default: RT
     
    操作系统访问:
    --os-cmd=OS_CMD     执行操作系统命令
    --os-shell          提示交互式操作系统Shell
    --upload=UPLOAD     上传本地文件到远程主机
    --force-overwrite   上传时强制覆盖文件
    --download=DOWNL..  下载远程文件到本地主机
    --bind-shell=BIN..  在目标的TCP端口上生成系统Shell并连接到它
    --reverse-shell=..  运行系统Shell并反向连接到本地主机端口
     
    模板检查:
    --tpl-shell         在模板引擎上提示交互式Shell
    --tpl-code=TPL_C..  在模板引擎中注入代码
     
    常规:
    --force-level=FO..  强制将测试级别设置为此值
    --injection-tag=..  使用字符串作为注入标签 (default '*')
  • 举例



c . 案例演示

  • 靶场地址:https://buuoj.cn/challenges#[WesternCTF2018]shrine

  • 打开发现给出源码-pytho&flask&ssti-代码分析访问参数,flag位置,过滤等-不能进行正常的路径符合-采用内置函数读取-读取代码中的存储FLAG

  • <1>页面打开如下,直接给出源代码。



    • img

    • 代码格式化如下

    • import flask
      import os
       
      app = flask.Flask(__name__)
      app.config['FLAG'] = os.environ.pop('FLAG')
       
      @app.route('/')
      def index():
      return open(__file__).read()
       
      @app.route('/shrine/')
      def shrine(shrine):
      
      def safe_jinja(s):
      s = s.replace('(', '').replace(')', '')
      blacklist = ['config', 'self']
      return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
      
      return flask.render_template_string(safe_jinja(shrine))
      
      if __name__ == '__main__':
      app.run(debug=True)
  • <2>看到flask,想到模板注入。



  • <3>看源码app.config['FLAG'] = os.environ.pop('FLAG'),推测{undefined{config}}可查看所有app.config内容,但是这题设了黑名单[‘config’,‘self’]并且过滤了括号。不过python还有一些内置函数,比如url_for和get_flashed_messages。



    • url_for查看全局变量:/shrine/{{url_for.globals}}

    • img

    • current_app意思应该是当前app,那我们就看当前app下的config:/shrine/{{url_for.globals['current_app'].config}},成功拿到flag。

    • img

  • <4>get_flashed_message同理:



    • /shrine/{{get_flashed_messages.globals['current_app'].config['FLAG']}}

    • img

案例3:CTF夺旗-Python-格式化字符串漏洞&读取对象

格式化字符串漏洞原理

  • 第一种:%操作符

  • 第二种:string.Template

  • 第三种:调用Format方法

  • 第四种:f-Strings

参考:https:/xz.aliyun.com/t/3569

漏洞代码举例

  • <1>调用Format方法。如下图所示,name后面的值可控,我们就可以传参获取当前脚本的核心变量flag值。



    • img

  • <2>f-Strings。这是python3函数式的新增一种字符串,其功能强大,可以执行字符串中包含的python表达式。



    • img

涉及资源:

赞 (0)

猜您想看

评论区(暂无评论)

这里空空如也,快来评论吧~

我要评论