def adminCreateNewUser(): userName = current_user.name isAdmin = db.isUserAdmin(userName) if isAdmin: postValuesAsDict = request.values.to_dict(flat=False) newUserName = postValuesAsDict["username"][0] newPassword = postValuesAsDict["password"][0] newAdmin = (postValuesAsDict["isAdmin"][0] == "true") users = db.getUsers() userList = list(map(lambda uR: uR["userName"], users)) if not (newUserName in userList): try: db.insertUser(newUserName, newPassword, isAdmin=newAdmin) except: return "Error adding user" if newAdmin: uStr = "(admin)" else: uStr = "(normal)" db.addInteraction( userName, "", "ADD-USER", "Added new " + uStr + " user " + str(newUserName), "", getClientIPAddress()) return "OK" else: return "User already exists!" else: return genericError
def logout(): userName = current_user.name logout_user() db.addInteraction(userName, "", "LOGOUT", "", "", getClientIPAddress()) db.createNewSession( userName) # this effectively invalidates the previous session return render_template("logout.html")
def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] sessionID = db.verifyUserPassword(username, password) if None != sessionID: user = db.createNewSession(username) login_user(user) db.addInteraction(username, "", "LOGIN", "", "", getClientIPAddress()) return redirect(request.args.get("next")) else: return render_template("login.html", message="Error while logging in") else: return render_template("login.html", message="")
def adminChangeUserPassword(): userName = current_user.name isAdmin = db.isUserAdmin(userName) if isAdmin: postValuesAsDict = request.values.to_dict(flat=False) theUserID = postValuesAsDict["userid"][0] theUserPass = postValuesAsDict["newpassword"][0] try: db.updateUserIDPassword(theUserID, theUserPass) except: return genericError db.addInteraction(userName, "", "PW-USER", "Changed password of user with id " + str(theUserID), "", getClientIPAddress()) return "OK" else: return genericError
def sendInputFile(chalID): try: if not (chalID in challenges.idToKey): db.addInteraction(userName, chalID, "OOPS", "challenge not found", "", getClientIPAddress()) return "Not Found!" else: chalKey = challenges.idToKey[chalID] chalPath = challenges.allChallenges[chalKey]["directory"] chalFile = challenges.allChallenges[chalKey]["input_file"] #print("Send Input File: "+chalFile+" from "+chalPath) return send_from_directory(directory=chalPath, filename=chalFile) except: db.addInteraction(userName, chalID, "OOPS", "error loading challenge input file", "", getClientIPAddress()) return "Error loading challenge input file"
def adminDeleteUser(): userName = current_user.name isAdmin = db.isUserAdmin(userName) if isAdmin: postValuesAsDict = request.values.to_dict(flat=False) delUserName = postValuesAsDict["username"][0] delUserID = postValuesAsDict["userid"][0] try: print(delUserName, delUserID) db.deleteUserID(delUserID) except: return "Error while deleting user" db.addInteraction(userName, "", "DEL-USER", "Deleted user " + str(delUserName), "", getClientIPAddress()) return "OK" else: return genericError
def challengeRoot(chalID): userName = current_user.name ipAddress = getClientIPAddress() #db.addChalCache(userName,chalID,"xxx") if chalID in challenges.idToKey: cfg = challenges.getChalConfig(chalID) rootFile = cfg["root_file"] db.unlockChallenge(userName, chalID, ipAddress) db.addInteraction(userName, chalID, "ENTRY", "visit challenge", "", ipAddress) if cfg["root"] == "template": # programming challenges isAdmin = db.isUserAdmin(userName) return render_template(rootFile, cfg=cfg, hbTimer=heartBeat, isAdmin=isAdmin) elif cfg["root"] == "challenge": # multiple choice questions chalDir = cfg["directory"] tplFile = os.path.join(chalDir, rootFile) tpl = open(tplFile, "r").read() t = Template(tpl) isAdmin = db.isUserAdmin(userName) return t.render({ "cfg": cfg, "hbTimer": heartBeat, "chalID": chalID, "isAdmin": isAdmin }) else: return genericError else: p(chalID) p(challenges.idToKey) db.addInteraction(userName, chalID, "ENTRY", "unkown challenge", "", ipAddress) return genericError
def postSend(chalID): if not (chalID in challenges.idToKey): return {"results": "Challenge not found!"} userName = current_user.name userIP = getClientIPAddress() db.unlockChallenge(userName, chalID, userIP) cfg = copy.deepcopy(challenges.getChalConfig(chalID)) mainFileContent = request.values["usercontent"] #print("----mainFileContent----------------------") #print(mainFileContent) #print("-----------------------------------------") inputFileContent = "" try: inputFileContent = request.values["inputfile"] #print("~~~~inputFileContent~~~~~~~~~~~~~~~~~~~~~") #print(inputFileContent) #print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~") except: pass (result, d, tcDir) = challenges.evalChalFromString(userName, chalID, mainFileContent, inputFileContent) chalLogLines = challenges.collectChallengeEvalLogs(tcDir) chalLog = [] for s in chalLogLines: chalLog.append(escape(s)) chalLog = "<br>".join(chalLog) failMsg = None failPrio = None tag = None if result == False: try: for e in d: if d[e]["pass"] == "FAIL": newPrio = int(d[e]["nr"]) if None == failPrio: failPrio = newPrio failMsg = d[e]["msg"] tag = d[e]["x"] else: if newPrio < failPrio: failPrio = newPrio failMsg = d[e]["msg"] tag = d[e]["x"] if failMsg: hintHtml = "" if tag in challenges.allTags: myTag = challenges.allTags[tag] tagDesc = myTag["description"] hintHtml = tagDesc.format(**myTag) db.addHintTag(userName, chalID, tag, hintHtml, getClientIPAddress()) if False: # Toggle this to test a new tag myTag = challenges.allTags["TEST_TAG"] tagDesc = myTag["description"] hintHtml = tagDesc.format(**myTag) #print("HINT:",hintHtml) db.addHintTag(userName, chalID, "TEST_TAG", hintHtml, getClientIPAddress()) db.addInteraction(userName, chalID, "FAIL", failMsg, tcDir, getClientIPAddress()) return {"results": failMsg, "log-results": chalLog} else: msg = "Oops! please contact one of the coaches" db.addInteraction(userName, chalID, "OOPS", msg, tcDir, getClientIPAddress()) return {"results": msg, "log-results": chalLog} except: pass #p(d) msg = "Oops! - where did the failed result go to?" db.addInteraction(userName, chalID, "OOPS", msg, tcDir, getClientIPAddress()) return {"results": msg, "log-results": chalLog} else: flag = str(cfg["flag"]) db.addInteraction(userName, chalID, "SOLVE", flag, tcDir, getClientIPAddress()) return { "results": "Well done, here is your flag: " + flag, "log-results": chalLog }
def sendFile(chalID): userName = current_user.name ipAddress = getClientIPAddress() try: resetChal = False try: resetChal = request.values["reset"] == "true" except: pass if not (chalID in challenges.idToKey): db.addInteraction(userName, chalID, "OOPS", "challenge not found", "", ipAddress) return "Not Found!" else: chalKey = challenges.idToKey[chalID] chalPath = challenges.allChallenges[chalKey]["directory"] allChalDir = db.getCacheDir(userName) chalDir = allChalDir.get(chalID, None) cacheFiles = False if None != chalDir: # We have already a Cache... use it... #print("GET Cache: for user", userName) srcDir = chalDir else: # We do not have a Cache... we will create it... newUUID = str(uuid.uuid4()) # Generate new random UUID cacheDir = "upload/cache/" + newUUID srcDir = chalPath cacheFiles = True os.mkdir(cacheDir) db.addChalCache(userName, chalID, cacheDir) #print("GEN Cache:",cacheDir," for chalID",chalID," for user", userName) #print("Send Challenge Directory") cfg = challenges.getChalConfig(chalID) files = cfg.get("files", "") filesToSend = [] if not (files == ""): filesToSend = cfg.get("files", "").split(",") firstFile = filesToSend[0] if firstFile[:2] != "./": firstFile = "./" + firstFile # Make sure that each file starts with "./" allFiles = [] for f in filesToSend: if f[:2] != "./": allFiles.append("./" + f) else: allFiles.append(f) filesToSend = sorted(allFiles) fContent = {} #print("filesToSend: ",filesToSend) for f in filesToSend: if resetChal: # this time we need to create a cache for the files _srcFile = os.path.join(chalPath, f) _dstFile = os.path.join(srcDir, f) #print("FROM: "+_srcFile+" TO: "+_dstFile) utils.copyWithFullPath(_srcFile, _dstFile) if cacheFiles: # this time we need to create a cache for the files _srcFile = os.path.join(srcDir, f) _dstFile = os.path.join(cacheDir, f) #print("FROM: "+_srcFile+" TO: "+_dstFile) utils.copyWithFullPath(_srcFile, _dstFile) fContent[f] = utils.fileContents(os.path.join(srcDir, f)) jstree = utils.jstreeJSON(filesToSend) r = { "fcontent": fContent, "dirstruct": jstree, "workFile": firstFile } #print("Send Files (r):") #p(r) return r except Exception as e: userName = current_user.name db.addInteraction(userName, chalID, "OOPS", "error loading main challenge file", "", ipAddress) print("ERROR:", str(e)) return "Error loading main challenge file"
def challengeFile(chalID, fileName): userName = current_user.name if chalID in challenges.idToKey: cfg = copy.deepcopy(challenges.getChalConfig(chalID)) else: return genericError if request.method == 'GET': #print("Try allow_get...") try: allowHtml = cfg["allow_get"] except: allowHtml = "" allowHtml = allowHtml.split(",") #print("allow: ",allowHtml) if fileName in allowHtml: chalDir = cfg["directory"] fileName = os.path.join(chalDir, fileName) return send_file(fileName) else: return genericError _postValuesAsDict = request.values.to_dict(flat=False) postValuesAsDict = {} # ugly hack... for k in _postValuesAsDict: newK = "".join("_".join(k.split("[")).split("]")) postValuesAsDict[newK] = _postValuesAsDict[k] postValuesAsDict = utils.processPost(postValuesAsDict) limitFile = int(cfg["limitFile"]) if ("limitFile" in cfg) else 0 db.unlockChallenge(userName, chalID, getClientIPAddress()) if limitFile > 0: n = db.getChalNrTimes(userName, chalID) if (n >= limitFile): return "Limit exceeded" db.incChalNrTimes(userName, chalID, getClientIPAddress()) allowPost = "" try: allowPost = cfg["allow_post"] except: allowPost = "" allowPost = allowPost.split(",") #print("Try allow_post...") if fileName in allowPost: chalDir = cfg["directory"] tplFile = os.path.join(chalDir, fileName) tpl = open(tplFile, "r").read() t = Template(tpl) try: cfg["unlock_codes"] = cfg["unlock_codes"].split(",") except Exception as e: cfg["unlock_codes"] = [] html = t.render({ "post": postValuesAsDict, "cfg": cfg, "chalID": chalID }) #print("Rendered HTML") #print(html) #print("") # if we can find the flag in the HTML code, then the challenge was solved if re.search(cfg["flag"], html): db.addInteraction(userName, chalID, "SOLVE", "", "", getClientIPAddress()) # if we can find this comment in the code, it means that we have failed the challenge if re.search("<!-- FAIL -->", html): db.addInteraction(userName, chalID, "FAIL", "", "", getClientIPAddress()) return html #print("Try unlock_post...") allowPostUnlock = "" try: allowPostUnlock = cfg["unlock_post"].split(",") except: allowPostUnlock = [] try: unlockCodes = cfg["unlock_codes"].split(",") except: unlockCodes = [] if not (len(allowPostUnlock) == len(unlockCodes)): return "Inconsistent length of unlock codes" postUnlock = dict(zip(allowPostUnlock, unlockCodes)) if fileName in allowPostUnlock: chalUnlocks = db.getChallengeUnlockFiles(userName) flagFound = False for u in chalUnlocks: if (u["chalID"] == chalID) and (u["unlockCode"] == postUnlock[fileName]): #print("FOUND") chalDir = cfg["directory"] tplFile = os.path.join(chalDir, fileName) tpl = open(tplFile, "r").read() t = Template(tpl) try: cfg["unlock_codes"] = cfg["unlock_codes"].split(",") except Exception as e: cfg["unlock_codes"] = [] p(postValuesAsDict) html = t.render({ "post": postValuesAsDict, "cfg": cfg, "chalID": chalID }) #print("Rendered HTML") #print(html) #print("") # if we can find the flag in the HTML code, then the challenge was solved if re.search(cfg["flag"], html): db.addInteraction(userName, chalID, "SOLVE", "", "", getClientIPAddress()) # if we can find this comment in the code, it means that we have failed the challenge if re.search("<!-- FAIL -->", html): db.addInteraction(userName, chalID, "FAIL", "", "", getClientIPAddress()) return html return "ERROR: a team of highly trained monkeys was just dispatched to ignore your request" else: return genericError
def evalChalFromDirStruct( userName, userIP, chalID, chalFiles, testing=False, chalBaseFolder=".", pathRoot='.', origDir=None, testwip=False # flag for testiomaker ): _result = "FAIL: error while processing the challenge" _logger = "" tmpPath = "" try: nrHeader = 0 # remember the nr of header lines added if not (chalID in idToKey): return { "result": "Challenge not found", "logger": _logger, "solve": "false" } cfg = getChalConfig(chalID) # fetch the challenge configuration if not testing: newUUID = str(uuid.uuid4()) # Generate new random UUID tmpPath = os.path.join(pathRoot, 'upload', newUUID) else: tmpPath = pathRoot # NOTE: I take directly the "root path" pathRoot #print("TMP Challenge Path: ",tmpPath) copyFrom = os.path.join(chalBaseFolder, cfg["directory"]) #print("Copy from",copyFrom," to ",tmpPath) if not testwip: # (testbuilding happens elsewhere) shutil.copytree(copyFrom, tmpPath) # Recursively copy all files if not testing: #print("Copied files from",cfg["directory"]) for f in chalFiles: # save all user files to temp folder fullPath = os.path.normpath(os.path.join(tmpPath, f)) with open(fullPath, "w+") as o: # make sure we overwrite the file o.write(chalFiles[f]) # write the user content to the file uHints = db.getUserHints(userName, chalID) # load used hints by the user fNH = os.path.join( tmpPath, "used_hints") # generate path of dest. file name with open(fNH, "w+") as f: f.write(json.dumps(uHints)) # write used hints to file try: fName = os.path.join(tmpPath, "chal_info.json") #print("CHAL_INFO: "+fName) with open(fName, "w+") as f: f.write(json.dumps({"chal_id": cfg["chal_id"]})) except Exception as e: print("ERROR in evalChalFromDirStruct: " + str(e)) else: # just copy / override the regresion input files utils.copyTree(origDir, tmpPath) #print("Running", tmpPath) checkFile = cfg["run"] # retrieve command to evaluate challenge result = utils.executeOS(tmpPath, checkFile) # ... and run that command if not testing: AIr = loadAIResult( tmpPath, nrHeader) # load the result from the AI machinery _l1 = collectChallengeEvalLogs( tmpPath ) # collect the challenge log from logger to _l1 temp var _l2 = [] # _l2: temp var containing all lines for s in _l1: # loop through all logger lines _l2.append(escape(s)) # escape the text (prevent XSS) _logger = "<br>".join(_l2) # add HTML code for new line if (None == AIr): # if the AI engine did not return any result... _result = "FAIL: no results were found" # bail out with an error message tha no results are found if not testing: db.addInteraction(userName, chalID, "FAIL", _result, tmpPath, userIP) return { "result": _result, "logger": _logger, "tmpDir": tmpPath, "regression": "none", "solve": "false" } tag = AIr["tag"] # retrieve the AI tag for hints #print("AI Result:") # debugging output. to be removed #pprint.pprint(AIr) # debugging output. to be removed if tag in allTags: # does the tag match any known tag? myTag = allTags[tag] # retrieve the dictionary (from YAML) tagDesc = myTag[ "description"] # required key = description (main tag) hintHtml = tagDesc.format( **myTag ) # perform string interpolation to generate HTML code if not testing: db.addHintTag(userName, chalID, tag, hintHtml, userIP) # add hint to database if False: # this is only for testing purposes myTag = allTags[ "TEST_TAG"] # the YAML file can contain a TEST_TAG for simple tests tagDesc = myTag["description"] hintHtml = tagDesc.format(**myTag) if not testing: db.addHintTag(userName, chalID, "TEST_TAG", hintHtml, userIP) if AIr["result"] == "OK": # if the AI engine states that all TCs have passed, then give the flag flag = str( cfg.get("flag", "!!! HELP !!! UNDEFINED !!! HELP !!!") ) # has the flag been defined in the YAML file? _result = "Well done, here is your flag: " + flag if cfg.get("unlocks", False): next_challenge = str(cfg.get("unlocks", "")) _result += " You have unlocked a new <a href='/challenge/" + next_challenge + "' target='_blank'>challenge</a>" # TODO: consider adding the flag as an hint! if not testing: db.addInteraction(userName, chalID, "SOLVE", _result, tmpPath, userIP) return { "result": _result, "logger": _logger, "tmpDir": tmpPath, "regression": "none", "solve": "true" } # return the flag to the user; this is where the function exists in case of OK else: # the user failed the challenge... _result = "FAIL: " + AIr[ "msg"] # give back the user message from the AI engine if not testing: db.addInteraction(userName, chalID, "FAIL", _result, tmpPath, userIP) return { "result": _result, "logger": _logger, "tmpDir": tmpPath, "regression": "none", "solve": "false" } # return FAIL to the user. this is where the function exists in case of FAIL else: return {"regression": "done"} except Exception as e: _result = "UGLY ERROR: " + str( e) # something very wrong happen, if we are here! print("UGLY ERROR: " + str(e)) sys.exit(0) if not testing: db.addInteraction(userName, chalID, "FAIL", _result, tmpPath, userIP) return { "result": _result, "logger": _logger, "tmpDir": tmpPath, "regression": "fail", "solve": "false" } # the function should normally not exit here!