[De1CTF 2019]SSRF Me

考点:代码审计,关于flask框架的应用,python读写文件

目录

解题过程

代码审计:

1. /De1ta和/geneSign

2. Task类

3. python文件操控

4. 得到flag的大致思路有了

构造payload的步骤:

1. 首先需要绕过self.checkSign()

2. 将flag.txt中的数据读入result.txt,然后读取result.txt

payload2:如下,注意修改cookie中参数action和参数sign的值

总结

解题过程

打开题目,就是进行代码审计

#! /usr/bin/env python
#encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')

app = Flask(__name__)

secert_key = os.urandom(16)

class Task:
    def __init__(self, action, param, sign, ip):        #是一个简单的赋值函数
        self.action = action
        self.param = param
        self.sign = sign
        self.sandbox = md5(ip)
        if(not os.path.exists(self.sandbox)):       #如果没有该文件夹,则创立一个文件夹
            os.mkdir(self.sandbox)

    def Exec(self):
        result = {}
        result['code'] = 500
        if (self.checkSign()):
            if "scan" in self.action:
                tmpfile = open("./%s/result.txt" % self.sandbox, 'w')   #注意w,可以对result.txt文件进行修改
                resp = scan(self.param)
                if (resp == "Connection Timeout"):
                    result['data'] = resp
                else:
                    print resp
                    tmpfile.write(resp) #这个将resp中的数据写入result.txt中,可以利用为将flag.txt中的数据放进result.txt中
                    tmpfile.close()
                result['code'] = 200
            if "read" in self.action:
                f = open("./%s/result.txt" % self.sandbox, 'r') #打开方式为只读
                result['code'] = 200
                result['data'] = f.read()   #读取result.txt中的数据
            if result['code'] == 500:
                result['data'] = "Action Error"
        else:
            result['code'] = 500
            result['msg'] = "Sign Error"
        return result

    def checkSign(self):
        if (getSign(self.action, self.param) == self.sign):
            return True
        else:
            return False

@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
    param = urllib.unquote(request.args.get("param", ""))
    action = "scan"
    return getSign(action, param)

@app.route('/De1ta',methods=['GET','POST'])     #注意这个绑定,接下来的几个函数都很重要,这个相当于c语言里面的主函数,接下来是调用其他函数的过程
def challenge():
    action = urllib.unquote(request.cookies.get("action"))      #cookie传递action参数,对应不同的处理方式
    param = urllib.unquote(request.args.get("param", ""))       #传递get方式的参数param
    sign = urllib.unquote(request.cookies.get("sign"))          #cookie传递sign参数sign
    ip = request.remote_addr                #获取请求端的ip地址
    if(waf(param)):         #调用waf函数进行过滤
        return "No Hacker!!!!"
    task = Task(action, param, sign, ip)            #创建Task类对象
    return json.dumps(task.Exec())          #以json的形式返回到客户端

@app.route('/')
def index():
    return open("code.txt","r").read()

def scan(param):
    socket.setdefaulttimeout(1)
    try:
        return urllib.urlopen(param).read()[:50]        #这个可以利用为访问flag.txt。读取然后为下一步将flag.txt文件中的东西放到result.txt中做铺垫
    except:
        return "Connection Timeout"

def getSign(action, param):             #getSign的作用是拼接secret_key,param,action,然后返回拼接后的字符串的md5加密值
    return hashlib.md5(secert_key + param + action).hexdigest()

def md5(content):           #将传入的字符串进行md5加密
    return hashlib.md5(content).hexdigest()

def waf(param):                     #防火墙的作用是判断开头的几个字母是否是gopher 或者是file  如果是的话,返回true
    check=param.strip().lower()
    if check.startswith("gopher") or check.startswith("file"):
        return True
    else:
        return False
if __name__ == '__main__':
    app.debug = False
    app.run(host='0.0.0.0',port=9999)

代码审计:

一个flask框架,先说一些需要注意的地方

1. /De1ta和/geneSign

分别绑定不同的函数,具有不同的功能,接下俩会具体分析。

2. Task类

这个类中有不同的参数action,对应不同的函数执行,但是需要注意到

if "scan" in self.action:
if "read" in self.action:

判断action中的值的时候,用的是in,而不是==,所以如果action中是scanread或者是reanscan的话,if语句同时满足,相应的代码都执行。

3. python文件操控

有许多关于python的文件操控的代码,所以在本地进行了复现

#因为是在windows系统下复现,所以文件路径和源码中有些不同,但是原理一样,都是将flag.txt中的文件放在result.txt中
#! /usr/bin/env python
#encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json

f = open("D:/phpstudy_pro/WWW/test/result.txt",'w')     #注意切换为写的功能
resp = open("D:/phpstudy_pro/WWW/test/flag.txt").read()
f.write(resp)

4. 得到flag的大致思路有了

首先绕过self.checkSign(),并且传入的action需要同时包含scan和read,然后if “scan” in self.action:执行将flag.txt中的数据写入result.txt中,继续if “read” in self.action:执行读取result.txt中的数据,并且放在 result[‘data’] 中 , return json.dumps(task.Exec()) 接着返回以json的形式返回到客户端。

构造payload的步骤:

1. 首先需要绕过 self.checkSign()

分析一下相关源码,源码分别截取,方便分析

@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
    param = urllib.unquote(request.args.get("param", ""))
    action = "scan"
    return getSign(action, param)

def checkSign(self):
        if (getSign(self.action, self.param) == self.sign):
            return True
        else:
            return False

def getSign(action, param):             #getSign的作用是拼接secret_key,param,action,然后返回拼接后的字符串的md5加密值
    return hashlib.md5(secert_key + param + action).hexdigest()

需要满足self.checkSign(),

就需要getSign(self.action, self.param) == self.sign,(而sign值通过cookie传值)

就需要hashlib.md5(secert_key + param + action).hexdigest() == self.sign,

说白了也就是hashlib.md5(secert_key + ‘flag.txt’ + ‘readscan’).hexdigest() == self.sign,即我们需要得到

secert_key + ‘flag.txtreadscan’的哈希值

@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
    param = urllib.unquote(request.args.get("param", ""))
    action = "scan"
    return getSign(action, param)

但是我们不知道secret_key的值是多少,它只存在于服务端,但是我们可以通过上面截取的源码中/geneSign,来返回我们所需要的编码之后的哈希值

注意到/geneSign中已经将action定为 scan,所以我们传入的param可以为flag.txtread,这样的话还是会拼接为 secert_key + ‘flag.txtreadscan’

payload1:

/geneSign?param=flag.txtread

返回哈希值

[De1CTF 2019]SSRF Me

2. 将flag.txt中的数据读入result.txt,然后读取result.txt

  if "scan" in self.action:
                tmpfile = open("./%s/result.txt" % self.sandbox, 'w')   #注意w,可以对result.txt文件进行修改
                resp = scan(self.param)
                if (resp == "Connection Timeout"):
                    result['data'] = resp
                else:
                    print resp
                    tmpfile.write(resp) #这个将resp中的数据写入result.txt中,可以利用为将flag.txt中的数据放进result.txt中
                    tmpfile.close()
                result['code'] = 200
            if "read" in self.action:
                f = open("./%s/result.txt" % self.sandbox, 'r') #打开方式为只读
                result['code'] = 200
                result['data'] = f.read()   #读取result.txt中的数据
            if result['code'] == 500:
                result['data'] = "Action Error"

payload2:如下,注意修改cookie中参数action和参数sign的值

[De1CTF 2019]SSRF Me

然后得到flag.

总结

本题我感觉还是主要考察代码审计能力,只要肯下功夫,仔细研读,会有帮助。

主要参考的博客:

[De1CTF 2019]SSRF Me之愚见

Original: https://blog.csdn.net/RABCDXB/article/details/115412359
Author: Sk1y
Title: [De1CTF 2019]SSRF Me

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/749021/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • flask-sqlalchemy操作mysql

    文章目录 1、简介 2、mysql连接设置 3、模型类字段类型 4、ORM使用方式 * 4.1、先创建模型类,再迁移到数据库 4.2、用原生SQL创建数据库表,再编写模型类作映射 …

    Python 2023年8月13日
    057
  • matplotlib:基本柱状图绘制

    matplotlib.pyplot.bar(x,height,width: float=0.8,bottom=None,align:str=’center’…

    Python 2023年9月3日
    061
  • 数据挖掘与分析——关联规则模型

    1.打开csv打分表,并指出数据存在的问题,给出相应的解决方案; 打分表中,前五行数据为空白或不在统计范围内的数据,第六行数据为列名,因此需要从第七行开始进行存储。在列名中,存在许…

    Python 2023年8月7日
    068
  • 手把手教你DouZero项目的环境配置及运行,使用注意事项(否则会退出)

    新手小白,即使啥都不懂,也完全可以成功(因为我也是小白)。Ai斗地主未经训练,胜率可能比较低。训练方法目前还不会,有兴趣的小伙伴,大家可以去查找资料。 代码来自GitHub 源码在…

    Python 2023年8月3日
    0700
  • 计算空间物体包围球的两种算法实现

    概述 在进行二维空间几何运算的之前,往往会用包围盒进行快速碰撞检测,从而筛掉一些无法碰撞到的可能。而在三维中,比较常用的就是包围球了。当然,如何计算包围球是一个问题。 详论 2.1…

    Python 2023年10月20日
    047
  • Anaconda的升级、配置及使用

    1、安装:通过腾讯电脑管家软件管理安装 2、处理源: 以管理员身份,运行Anaconda Prompt 输入 conda –version 如果正常输出了 co…

    Python 2023年8月2日
    0104
  • 旅游可视化系统flask+pyecharts

    旅游可视化系统flask+pyecharts 1、先上效果图吧 ; 2、关于环境问题 pyecharts 1.8.1,Flask 1.1.2 3、思想步骤,首先我们是先用pyech…

    Python 2023年8月14日
    048
  • 【pandas】dataframe高级用法三

    上一篇: DataFrame数据筛选(二) DataFrame数据处理(一) 文章目录 一、筛选数据 – 1. 布尔值筛选法 2.删除满足条件的行 3. datafra…

    Python 2023年8月7日
    065
  • 解决jupyter notebook操作中终端出现Bad file descriptor (C:cizeromq_1616055400030worksrcepoll.cpp:100)问题

    在学习jupyter notebook时,我在Jupyter Notebook的界面新建了一个文档,如下所示 当我点进去对文档就行重命名操作,出现error信息,我发现在终端里出现…

    Python 2023年8月2日
    065
  • Html制作表格

    啊哦~你想找的内容离你而去了哦 内容不存在,可能为如下原因导致: ① 内容还在审核中 ② 内容以前存在,但是由于不符合新 的规定而被删除 ③ 内容地址错误 ④ 作者删除了内容。 可…

    Python 2023年11月8日
    035
  • Django项目实战学习笔记

    前言: 一、创建项目: 二、创建数据库:osdb 三、项目框架构建: 3.1 创建项目应用: 3.2 创建项目模板目录—templates和静态文件目录—static 3.3 3个…

    Python 2023年8月4日
    056
  • Java学习路线图,看这一篇就够了!

    主要分为三阶段 | 耗废1024根秀发,Java学习路线图来了,整合了自己所学的所有技术整理出来的2022最新版Java学习路线图,适合于初、中级别的Java程序员。可以按照这个序…

    Python 2023年9月16日
    053
  • 【视觉SLAM14讲】【汇总】

    抵扣说明: 1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。 Original: https://blo…

    Python 2023年9月29日
    030
  • Springboot内置的工具类之CollectionUtils

    前言 实际业务开发中,集合的判断和操作也是经常用到的,Spring也针对集合的判断和操作封装了一些方法,但是最令我惊讶的是,我在梳理这些内容的过程中发现了一些有趣的现象,我的第一反…

    Python 2023年9月26日
    047
  • 【Django框架】——04 创建Django项目子应用

    文章目录 * – + 创建Django项目子应用 + * 1.创建⼦应⽤ * 2.⼦应⽤⽬录说明 * 3.注册安装⼦应⽤ * 4.设置PyCharm的环境 创建Djan…

    Python 2023年8月6日
    061
  • Scrapy 框架架构

    Scrapy 框架架构 目录 Scrapy 框架架构 前言 一、核心组成 二、数据流 三、项目结构 总结 前言 Scrapy (/ˈskreɪpaɪ/) 是一个用于抓取网站和提取结…

    Python 2023年10月1日
    033
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球