[De1CTF 2019]SSRF Me

python格式美化一下
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)

首先看这个路由:

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

创建了一个Task类,action、sign的值是由cookie得到的,而param的值就是直接通过GET方法传递param参数的值得到,ip就是自己的ip地址。接着参数param会经过一个waf,然后执行task类中的Exec()方法

waf

def waf(param): 
    check = param.strip().lower() 
    if check.startswith("gopher") or check.startswith("file"):
    	return True
	else :
        return False

要求参数param不是以gopher和file开头,就是过滤了两个协议,是我们不能通过协议读取文件。

接着是task类中的Exec()方法:

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 

如果self.checkSign()为真,则参数param进入scan方法,

scan():

def scan(param):
    socket.setdefaulttimeout(1) 
    try: 
        return urllib.urlopen(param).read()[: 50] 
    except: 
        return"Connection Timeout"

通过我们构造的param参数发现达到进行任意文件读取的效果,所以我们现在要做的就是如何使self.checkSign为真,跟进:

def checkSign(self): 
    if(getSign(self.action, self.param) ==self.sign):
        return True
    else:
        return False
 
def getSign(action, param): 
    return hashlib.md5(secert_key+param+action).hexdigest() 

只要我们在cookie中传入的sign==getSign(cookie传入的aaction,Get传入的param)就能返回True

我们不知道secert_key的值,从而无法得到getSign返回的值,发现:

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

这里能得到getSign('scan',Get传递的param),也是我们唯一能利用的地方,这里参数param的值很明确,就是flag.txt,我们通过genSIgn的sign的值是md5(secert_key+param+'scan'),而最后我们在/De1ta?param=的值一定是flag.txt,而且要满足:

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

我们可以在/geneSignparam参数传入flag.txtread,这样我们得到的sign就是md5(secret_key+flag.txtreadscan),而访问/De1ta?param传入的值为flag.txt,且通过cookie传入的action的值为readscan,这样

geySign(self.action,self.param) == getSign(flag.txtreadscan)==md5(secret_key+flag.txtread.scan)

得到sign

得到flag

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值