69,【1】BUUCTF WEB ssrf [De1CTF 2019]SSRF Me

进入靶场

这是段python的flask代码

python 复制代码
#! /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__) 
# 生成一个 16 字节的随机密钥,可能用于后续的签名验证等操作
secert_key = os.urandom(16) 

class Task: 
    def __init__(self, action, param, sign, ip): 
        # 存储操作类型,例如 "scan" 或 "read"
        self.action = action 
        # 存储请求的参数
        self.param = param 
        # 存储签名,用于验证请求的合法性
        self.sign = sign 
        # 根据 IP 地址的 MD5 值创建沙箱目录,用于存储操作结果
        self.sandbox = md5(ip) 
        if(not os.path.exists(self.sandbox)):  # SandBox For Remote_Addr 
            # 如果沙箱目录不存在,则创建该目录
            os.mkdir(self.sandbox) 
    def Exec(self): 
        # 存储执行结果的字典,初始状态码为 500
        result = {} 
        result['code'] = 500 
        # 检查签名是否合法
        if (self.checkSign()): 
            # 如果操作是 "scan"
            if "scan" in self.action: 
                # 打开沙箱目录下的 result.txt 文件,以写入模式
                tmpfile = open("./%s/result.txt" % self.sandbox, 'w') 
                # 调用 scan 函数扫描请求参数
                resp = scan(self.param) 
                if (resp == "Connection Timeout"): 
                    # 如果扫描超时,将结果存储在结果字典中
                    result['data'] = resp 
                else: 
                    # 打印扫描结果(可能是调试用,可考虑删除)
                    print resp 
                    # 将扫描结果写入文件
                    tmpfile.write(resp) 
                    tmpfile.close() 
                    # 操作成功,更新状态码为 200
                    result['code'] = 200 
            # 如果操作是 "read"
            if "read" in self.action: 
                # 打开沙箱目录下的 result.txt 文件,以读取模式
                f = open("./%s/result.txt" % self.sandbox, 'r') 
                # 操作成功,更新状态码为 200
                result['code'] = 200 
                # 读取文件内容存储在结果字典中
                result['data'] = f.read() 
        # 如果状态码仍为 500,可能是操作错误或签名错误
        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 

# generate Sign For Action Scan. 
@app.route("/geneSign", methods=['GET', 'POST']) 
def geneSign(): 
    # 从请求参数中获取 param 参数
    param = urllib.unquote(request.args.get("param", "")) 
    # 设定操作类型为 scan
    action = "scan" 
    # 调用 getSign 函数生成签名
    return getSign(action, param) 

@app.route('/De1ta',methods=['GET','POST']) 
def challenge(): 
    # 从请求的 cookie 中获取操作类型
    action = urllib.unquote(request.cookies.get("action")) 
    # 从请求参数中获取参数
    param = urllib.unquote(request.args.get("param", "")) 
    # 从请求的 cookie 中获取签名
    sign = urllib.unquote(request.cookies.get("sign")) 
    # 获取请求的远程 IP 地址
    ip = request.remote_addr 
    # 调用 waf 函数检查参数是否安全
    if(waf(param)): 
        return "No Hacker!!!!" 
    # 创建 Task 对象并执行相应操作
    task = Task(action, param, sign, ip) 
    # 将执行结果以 JSON 格式返回
    return json.dumps(task.Exec()) 

@app.route('/') 
def index(): 
    # 读取 code.txt 文件的内容并返回
    return open("code.txt","r").read() 

def scan(param): 
    # 设置 socket 超时为 1 秒
    socket.setdefaulttimeout(1) 
    try: 
        # 打开请求的 URL 并读取前 50 个字符
        return urllib.urlopen(param).read()[:50] 
    except: 
        # 如果超时或发生异常,返回超时信息
        return "Connection Timeout" 

def getSign(action, param): 
    # 结合密钥、参数和操作类型生成 MD5 签名
    return hashlib.md5(secert_key + param + action).hexdigest() 

def md5(content): 
    # 计算输入内容的 MD5 哈希值
    return hashlib.md5(content).hexdigest() 

def waf(param): 
    # 将参数去除前后空格并转为小写
    check=param.strip().lower() 
    # 如果参数以 gopher 或 file 开头,认为不安全
    if check.startswith("gopher") or check.startswith("file"): 
        return True 
    else: 
        return False 

if __name__ == '__main__': 
    # 关闭调试模式
    app.debug = False 
    # 运行 Flask 应用,监听 0.0.0.0 地址的 80 端口
    app.run(host='0.0.0.0',port=80)

看了他人的wp知道flag在flag.txt 文件里

不知道我的buuctf为什么不提醒我

不过不能直接访问flag.txt文件,没有路由

根据靶场代码中的这段代码,知道要在url处做文章

根据箭头指的这两行代码,知道我们要将字符串存在self.action就能正确

所以readscan和scanread都可以

根据以上代码param写为flag.txt

由此代码知action默认为scan

由以上图片知 getSign 函数会将 secert_keyparamaction 拼接在一起,计算其 MD5 哈希值。

所以访问/geneSign?param=flag.txtread即可

以上是错误示范

获取sign为a82acc908a59e0f4a2664f70e9f5f80a

根据以上代码,构造cookie请求头Cookie:action=readscan;sign=a82acc908a59e0f4a2664f70e9f5f80a

和访问文件/De1ta?param=flag.txt

添加cookie后再加 /De1ta?param=flag.txt

flag{773868ea-57f3-4721-b91a-797273226f28}

相关推荐
echo haha10 分钟前
第7章 :面向对象
笔记
Chef_Chen11 分钟前
从0开始学习R语言--Day18--分类变量关联性检验
学习
njsgcs15 分钟前
chili3d 笔记16 emscripten配置 |用cnpm i 安装 |hello world 编译
笔记
键盘敲没电28 分钟前
【IOS】GCD学习
学习·ios·objective-c·xcode
海的诗篇_1 小时前
前端开发面试题总结-JavaScript篇(一)
开发语言·前端·javascript·学习·面试
AgilityBaby1 小时前
UE5 2D角色PaperZD插件动画状态机学习笔记
笔记·学习·ue5
AgilityBaby1 小时前
UE5 创建2D角色帧动画学习笔记
笔记·学习·ue5
武昌库里写JAVA3 小时前
iview Switch Tabs TabPane 使用提示Maximum call stack size exceeded堆栈溢出
java·开发语言·spring boot·学习·课程设计
一弓虽4 小时前
git 学习
git·学习
冷凌爱5 小时前
总结HTML中的文本标签
前端·笔记·html