源码
#! /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')
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", "")) #接收参数param
action = "scan"
return getSign(action, param)
@app.route('/De1ta',methods=['GET','POST'])
def challenge():
action = urllib.unquote(request.cookies.get("action")) #读取cookie值
param = urllib.unquote(request.args.get("param", "")) #读取GET值
sign = urllib.unquote(request.cookies.get("sign")) #读取cookie值
ip = request.remote_addr
if(waf(param)):
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]
except:
return "Connection Timeout"
def getSign(action, param):
return hashlib.md5(secert_key + param + action).hexdigest() #把密钥与传入的param和action拼接经过md5加密后返回,注意运行代码后这里密钥是唯一的,因为没有再次生成新的,所以不用管secert_key。
def md5(content):
return hashlib.md5(content).hexdigest()
def waf(param):
check=param.strip().lower() #删除首尾空格并且转换小写
if check.startswith("gopher") or check.startswith("file"): #字符串开头,把gopher和file协议禁用
return True
else:
return False
if __name__ == '__main__':
app.debug = False
app.run(host='0.0.0.0',port=9999)
wp
flask框架,先找到三个路由
@app.route("/geneSign", methods=['GET', 'POST'])
输入/geneSign会执行下面的函数geneSign(),methods表示接收的方法是GET和POST,接收参数param,返回getSign()函数。
@app.route('/De1ta',methods=['GET','POST'])
输入/De1ta会执行下面的函数challenge(),methods表示接收的方法是GET和POST,获取GET的param和cookie的action和sign,waf()过滤函数,实例化Task并调用方法Exec(),返回对象的json格式。
@app.route('/')
返回源代码
首先看第二个路由,接收三个主要参数,并且waf()过滤了两个伪协议。接下来实例化类并调用Exec()函数。我们来看下Exec()。
if语句中调用了checkSign(),又调用了getSign(),
getSign():将刚开始生成的随机数与param和action拼接并生成md5返回。
如果getSign()的返回值与我们需要传入的cookie里的sign相等就返回true。
接下来有两个if语句
第一个,只需'scan'在action中,然后以写入方式打开result.txt,调用scan()读取param文件(param=flag.txt)的前50个字符,然后写入result.txt文件。
第二个,只需'read'在action中,然后读取result.txt内容返回作为result字典中data的值。
从代码中来看,如果未通过第二个if的read,则输出的resp如下(即未写入之前的result.txt,此时result字典里只有code的值)
因此我们也需要获取data里的内容,这里的两个if语句中都是使用了'in'来判断,而不是通过'='来判断,因此如果action=readscan或者scanread的话,两个if语句都会被执行。这样既可以将flag.txt写入results.txt,又能读取写入后的results.txt内容。
接下来我们回到checkSign()函数,要让它返回true我们就要得到sign的值,sign我们可以通过geneSign()来获取。由于这里的action已经是scan,而我们想要的是action='readscan'
或者'action=scanread'
,因此需要想办法让action是我们想要的值。由于getSign()函数是使用拼接的方式(secert_key + param + action)进行md5加密,因此我们可以使 param=flag.txtread
,那么此时返回的是 secert_key+'flag.txtread'+'scan'
的md5加密的密文。当我们使用路由De1ta时,只需要让param='flag.txt',sign为geneSign()返回后的值,action='readscan',这样checkSign()就能够返回true,成功执行接下来的两个if语句写入后读取获得flag。
获取sign
添加Cookie到请求包,添加sign以及action,最后获取flag。
标签:审计,ssrfme,return,flask,self,param,sign,result,action From: https://www.cnblogs.com/p0n9/p/16844204.html