Example #1
0
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
Example #2
0
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")
Example #3
0
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="")
Example #4
0
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
Example #5
0
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"
Example #6
0
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
Example #7
0
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
Example #8
0
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
        }
Example #9
0
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"
Example #10
0
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
Example #11
0
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!