- Audit the source code and add some comments
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", ""))
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')
- A brief summary of the code after auditing
- There are three routes under the Flask framework
/geneSign:
The returned test page is encrypted by md5secert_key + param + action
/De1ta:
The core part of the topic
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
task = Task(action, param, sign, ip)
return json.dumps(task.Exec())
- Get a series of data, param filters gopher and file, generate Task object, call Exec() command execution function to read the file
/:
Return to the source code, no use problem gave the download place
- In the first step of executing the Exec() function, there is a
if(self.checkSign())
def checkSign(self):
if (getSign(self.action, self.param) == self.sign):
return True
else:
eturn False
def getSign(action, param):
return hashlib.md5(secert_key + param + action).hexdigest()
- So the sign we passed in should be consistent with the sign generated by getSign()
- So we visit the
/geneSign
route get upload? param=flag.txtread
adf80ee5dfe9c60c8575ebd2c8baacf1
Page back
- This is the md5 encrypted value returned by the page when action=readscan param=flag.txt
- Because the action is fixed to scan when it is generated, only param=readscan is required
def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)