├── .gitignore ├── README.md ├── app ├── app.py ├── bot │ └── bot.py ├── challenges │ ├── csrf1 │ │ ├── csrf1.py │ │ ├── static │ │ │ ├── css │ │ │ │ ├── bootstrap.min.css │ │ │ │ └── style.css │ │ │ └── js │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── jquery.min.js │ │ │ │ ├── main.js │ │ │ │ └── popper.js │ │ └── templates │ │ │ ├── board.html │ │ │ ├── changepw.html │ │ │ ├── login.html │ │ │ ├── register.html │ │ │ ├── view.html │ │ │ └── write.html │ ├── csrf2 │ │ ├── csrf2.py │ │ ├── static │ │ │ ├── css │ │ │ │ ├── bootstrap.min.css │ │ │ │ └── style.css │ │ │ └── js │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── jquery.min.js │ │ │ │ ├── main.js │ │ │ │ └── popper.js │ │ └── templates │ │ │ ├── board.html │ │ │ ├── changepw.html │ │ │ ├── login.html │ │ │ ├── register.html │ │ │ ├── view.html │ │ │ └── write.html │ ├── xsleak │ │ ├── static │ │ │ ├── css │ │ │ │ ├── bootstrap.min.css │ │ │ │ └── style.css │ │ │ └── js │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── jquery.min.js │ │ │ │ ├── main.js │ │ │ │ └── popper.js │ │ ├── templates │ │ │ ├── board.html │ │ │ ├── login.html │ │ │ ├── register.html │ │ │ ├── view.html │ │ │ └── write.html │ │ └── xsleak.py │ ├── xss1 │ │ ├── static │ │ │ ├── css │ │ │ │ ├── bootstrap.min.css │ │ │ │ └── style.css │ │ │ └── js │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── jquery.min.js │ │ │ │ ├── main.js │ │ │ │ └── popper.js │ │ ├── templates │ │ │ ├── board.html │ │ │ ├── login.html │ │ │ ├── register.html │ │ │ ├── view.html │ │ │ └── write.html │ │ └── xss1.py │ ├── xss2 │ │ ├── static │ │ │ ├── css │ │ │ │ ├── bootstrap.min.css │ │ │ │ └── style.css │ │ │ └── js │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── jquery.min.js │ │ │ │ ├── main.js │ │ │ │ └── popper.js │ │ ├── templates │ │ │ ├── board.html │ │ │ ├── login.html │ │ │ ├── register.html │ │ │ ├── view.html │ │ │ └── write.html │ │ └── xss2.py │ └── xss3 │ │ ├── static │ │ ├── css │ │ │ ├── bootstrap.min.css │ │ │ └── style.css │ │ └── js │ │ │ ├── bootstrap.min.js │ │ │ ├── jquery.min.js │ │ │ ├── main.js │ │ │ └── popper.js │ │ ├── templates │ │ ├── board.html │ │ ├── login.html │ │ ├── register.html │ │ ├── view.html │ │ └── write.html │ │ └── xss3.py ├── entrypoint.sh ├── flags.json ├── static │ ├── css │ │ ├── bootstrap.min.css │ │ └── style.css │ └── js │ │ ├── bootstrap.min.js │ │ ├── jquery.min.js │ │ ├── main.js │ │ └── popper.js ├── templates │ ├── board.html │ ├── login.html │ ├── main.html │ ├── ranking.html │ └── register.html └── users.json ├── app2 ├── 000-default.conf ├── entrypoint.sh ├── html │ ├── dbconn.php │ ├── domclobbering.php │ ├── index.php │ ├── prototype_pollution.php │ ├── sqli1.php │ ├── sqli2.php │ └── sqli3.php └── ports.conf ├── app3 ├── 000-default.conf ├── entrypoint.sh ├── html │ ├── index.php │ ├── lfi1.php │ ├── lfi2.php │ └── lfiflag.php └── ports.conf ├── app4 ├── app.py └── entrypoint.sh ├── app5 ├── app.py └── entrypoint.sh ├── docker-compose.yml ├── docker ├── flask │ └── Dockerfile ├── flask2 │ ├── Dockerfile │ └── flags │ │ └── command_injection_flag.txt ├── flask3 │ ├── Dockerfile │ └── flags │ │ └── ssti_flag.txt ├── mysql │ └── Dockerfile ├── php │ ├── Dockerfile │ └── flags │ │ ├── domclobbering_flag.txt │ │ ├── pp_flag.txt │ │ ├── sqli1_flag.txt │ │ └── sqli2_flag.txt └── php2 │ ├── Dockerfile │ └── flags │ └── readflag.c └── mysql └── init.sql /.gitignore: -------------------------------------------------------------------------------- 1 | *core.* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # web-ctf-edu-challs 2 | 3 | ### challserver & xss1\~3, csrf1\~2, xsleak 4 | related directories : `./app/` , `./docker/flask/` 5 | 6 | ### domclobbering, sqli1~3, prototype pollution 7 | `./app2/` , `./docker/php/` , `./docker/mysql/` , `./mysql/` 8 | 9 | ### lfi1~2 10 | `./app3/`, `./docker/php2/` 11 | 12 | ### command injection 13 | `./app4/`, `./docker/flask2/` 14 | 15 | ### ssti 16 | `./app5/`, `./docker/flask3/` -------------------------------------------------------------------------------- /app/app.py: -------------------------------------------------------------------------------- 1 | #-*-coding:utf-8-*- 2 | import flask 3 | import os, pymysql, re, hashlib, time, base64, io, requests, json 4 | import logging, traceback 5 | logging.basicConfig(level=logging.INFO) 6 | logging.getLogger('werkzeug').setLevel(level=logging.WARNING) 7 | 8 | app = flask.Flask(__name__) 9 | app.secret_key = os.urandom(16) 10 | app.config['MAX_CONTENT_LENGTH'] = 80 * 1024 * 1024 11 | 12 | ids = {} 13 | def load_user(): 14 | global ids 15 | if os.path.exists("users.json"): 16 | with open("users.json","r") as f: 17 | ids = json.loads(f.read()) 18 | for i in ids.keys(): 19 | ids[i]['solved'] = list(set(ids[i]['solved'])) 20 | else: 21 | ids = { 22 | "arang":{ 23 | "password": "123123", 24 | "solved": [], 25 | "lastsolved":0 26 | } 27 | } 28 | load_user() 29 | 30 | 31 | challenges = [ 32 | { 33 | "seq": 1, 34 | "challenge": "xss1 - default", 35 | "link": "http://arang_client:9001/" 36 | }, 37 | { 38 | "seq": 2, 39 | "challenge": "xss2 - bypass", 40 | "link": "http://arang_client:9002/" 41 | }, 42 | { 43 | "seq": 3, 44 | "challenge": "xss3 - read article", 45 | "link": "http://arang_client:9003/" 46 | }, 47 | { 48 | "seq": 4, 49 | "challenge": "domclobbering", 50 | "link": "http://arang_client:9200/domclobbering.php" 51 | }, 52 | { 53 | "seq": 5, 54 | "challenge": "csrf1 - change admin password1", 55 | "link": "http://arang_client:9004/" 56 | }, 57 | { 58 | "seq": 6, 59 | "challenge": "csrf2 - change admin password2", 60 | "link": "http://arang_client:9005/" 61 | }, 62 | { 63 | "seq": 7, 64 | "challenge": "xsleak - get secret value of admin", 65 | "link": "http://arang_client:9006/" 66 | }, 67 | { 68 | "seq": 8, 69 | "challenge": "sqli1 - basic", 70 | "link": "http://arang_client:9200/sqli1.php" 71 | }, 72 | { 73 | "seq": 9, 74 | "challenge": "sqli2 - bypass filtering", 75 | "link": "http://arang_client:9200/sqli2.php" 76 | }, 77 | { 78 | "seq": 10, 79 | "challenge": "sqli3 - blind sqli + bypass filtering", 80 | "link": "http://arang_client:9200/sqli3.php" 81 | }, 82 | { 83 | "seq": 11, 84 | "challenge": "lif1 - basic", 85 | "link": "http://arang_client:9201/lfi1.php" 86 | }, 87 | { 88 | "seq": 12, 89 | "challenge": "lfi2 - get the shell", 90 | "link": "http://arang_client:9201/lfi2.php" 91 | }, 92 | { 93 | "seq": 13, 94 | "challenge": "command injection - blind", 95 | "link": "http://arang_client:9301/" 96 | }, 97 | { 98 | "seq": 14, 99 | "challenge": "ssti - get the shell", 100 | "link": "http://arang_client:9302/" 101 | }, 102 | { 103 | "seq": 15, 104 | "challenge": "prototype - eval js code", 105 | "link": "http://arang_client:9200/prototype_pollution.php" 106 | }, 107 | 108 | ] 109 | 110 | def sessionCheck(loginCheck=False): 111 | if loginCheck: 112 | if "isLogin" not in flask.session: 113 | return False 114 | else: 115 | return True 116 | 117 | if "isLogin" in flask.session: 118 | return True 119 | 120 | return False 121 | 122 | 123 | @app.route("/") 124 | def index(): 125 | if sessionCheck(loginCheck=True): 126 | return flask.redirect(flask.url_for("main")) 127 | 128 | return flask.redirect(flask.url_for("login")) 129 | 130 | @app.route("/main") 131 | def main(): 132 | global ids 133 | if not sessionCheck(loginCheck=True): 134 | return flask.redirect(flask.url_for("login")) 135 | 136 | load_user() 137 | t=[] 138 | for i in range(len(challenges)): 139 | if i in ids[flask.session["userid"]]["solved"]: 140 | tt = challenges[i] 141 | tt["solved"] = True 142 | else: 143 | tt = challenges[i] 144 | tt["solved"] = False 145 | t.append(tt) 146 | 147 | return flask.render_template("main.html", c=t) 148 | 149 | 150 | @app.route("/ranking") 151 | def ranking(): 152 | load_user() 153 | t = [] 154 | sorted_dict = dict(sorted(ids.items(), key=lambda item: (-len(item[1]["solved"]), item[1]["lastsolved"]))) 155 | print(sorted_dict) 156 | for i in sorted_dict.keys(): 157 | if not sorted_dict[i]["solved"]: 158 | continue 159 | t.append({i:sorted_dict[i]}) 160 | print(t) 161 | return flask.render_template("ranking.html", ids=t) 162 | 163 | 164 | @app.route("/login", methods=["GET","POST"]) 165 | def login(): 166 | if flask.request.method == "GET": 167 | if sessionCheck(loginCheck=True): 168 | return flask.redirect(flask.url_for("main")) 169 | 170 | return flask.render_template("login.html", msg="false") 171 | else: 172 | if sessionCheck(): 173 | return flask.redirect(flask.url_for("main")) 174 | 175 | userid = flask.request.form["userid"] 176 | userpw = flask.request.form["userpw"] 177 | 178 | if userid in ids: 179 | if ids[userid]["password"] == hashlib.sha256(userpw.encode()).hexdigest(): 180 | flask.session["userid"] = userid 181 | flask.session["isLogin"] = True 182 | 183 | resp = flask.make_response(flask.redirect(flask.url_for("main"))) 184 | resp.set_cookie('userid', flask.session["userid"]) 185 | return resp 186 | else: 187 | return flask.render_template("login.html", msg="login fail") 188 | else: 189 | return flask.render_template("login.html", msg="login fail") 190 | 191 | 192 | @app.route("/register", methods=["GET","POST"]) 193 | def register(): 194 | if flask.request.method == "GET": 195 | if sessionCheck(loginCheck=True): 196 | return flask.redirect(flask.url_for("main")) 197 | 198 | return flask.render_template("register.html", msg="false") 199 | else: 200 | if sessionCheck(): 201 | return flask.redirect(flask.url_for("main")) 202 | 203 | userid = flask.request.form["userid"] 204 | userpw = hashlib.sha256(flask.request.form["userpw"].encode()).hexdigest() 205 | 206 | if userid not in ids: 207 | ids[userid] = { 208 | "password": userpw, 209 | "solved": [], 210 | "lastsolved": 0 211 | } 212 | with open("users.json", "w") as f: 213 | f.write(json.dumps(ids, indent=4)) 214 | return flask.render_template("login.html", msg="false") 215 | else: 216 | return flask.render_template("register.html", msg="already registered id") 217 | 218 | @app.route("/logout") 219 | def logout(): 220 | flask.session.pop('isLogin', False) 221 | resp = flask.make_response(flask.redirect(flask.url_for("login"))) 222 | resp.set_cookie('userid', expires=0) 223 | return resp 224 | 225 | @app.route("/checkflag", methods=["GET", "POST"]) 226 | def report(): 227 | if flask.request.method == "GET": 228 | if not sessionCheck(loginCheck=True): 229 | return flask.redirect(flask.url_for("login")) 230 | else: 231 | return ''' 232 |
233 | 234 | 235 |
236 | ''' 237 | elif flask.request.method == "POST": 238 | if not sessionCheck(loginCheck=True): 239 | return flask.redirect(flask.url_for("login")) 240 | 241 | flag = flask.request.form['flag'] 242 | with open("/app/flags.json", "r") as f: 243 | flags = json.loads(f.read()) 244 | 245 | if flag in list(flags.values()): 246 | i = list(flags.values()).index(flag) 247 | ids[flask.session["userid"]]["solved"].append(i) 248 | ids[flask.session["userid"]]["lastsolved"] = time.time() 249 | with open("users.json", "w") as f: 250 | f.write(json.dumps(ids, indent=4)) 251 | return "" 252 | else: 253 | return "" 254 | 255 | 256 | if __name__ == "__main__": 257 | try: 258 | app.run(host="0.0.0.0", port=9091, debug=True) 259 | except Exception as ex: 260 | logging.info(str(ex)) 261 | pass 262 | -------------------------------------------------------------------------------- /app/bot/bot.py: -------------------------------------------------------------------------------- 1 | #-*-coding: utf-8-*- 2 | from selenium import webdriver 3 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 4 | from selenium.webdriver.support.ui import WebDriverWait 5 | from selenium.webdriver.support import expected_conditions as EC 6 | from selenium.webdriver.common.by import By 7 | from selenium.webdriver.chrome.service import Service 8 | from selenium.common.exceptions import TimeoutException 9 | from selenium.webdriver.remote.remote_connection import LOGGER 10 | from webdriver_manager.chrome import ChromeDriverManager 11 | import flask 12 | import traceback, os, time 13 | 14 | app = flask.Flask(__name__) 15 | app.secret_key = os.urandom(16) 16 | app.config['MAX_CONTENT_LENGTH'] = 80 * 1024 * 1024 17 | 18 | ADMIN_ID = "admin" 19 | ADMIN_PASS = os.getenv("admin_password") 20 | 21 | server1_challs = { 22 | "xss1": "9001", 23 | "xss2": "9002", 24 | "xss3": "9003", 25 | "csrf1": "9004", 26 | "csrf2": "9005", 27 | "xsleak": "9006", 28 | } 29 | 30 | def interceptor(request): 31 | pass 32 | 33 | class Crawler: 34 | def __init__(self): 35 | options = webdriver.ChromeOptions() 36 | options.add_argument('--headless') 37 | options.add_argument('--no-sandbox') 38 | options.add_experimental_option("excludeSwitches", ["enable-automation"]) 39 | options.add_experimental_option("useAutomationExtension", False) 40 | 41 | self.driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options) 42 | self.driver.request_interceptor = interceptor 43 | self.driver.implicitly_wait(3) 44 | self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") 45 | self.driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': 'navigator.'}) 46 | self.driver.set_page_load_timeout(3) 47 | 48 | def req(self, url): 49 | try: 50 | print(f"[+] doing crawler req {url}") 51 | self.driver.get(url) 52 | except: 53 | print(f"[x] crawler driver req fail - {url}") 54 | print(traceback.format_exc()) 55 | return False 56 | 57 | return self.driver 58 | 59 | def doCrawl_server1(chal, url): 60 | crawler = Crawler() 61 | driver = crawler.driver 62 | try: 63 | crawler.req(f'http://arang_client:{server1_challs[chal]}/login') 64 | 65 | driver.find_element(By.ID,"userid").send_keys(ADMIN_ID) 66 | driver.find_element(By.ID,"userpw").send_keys(ADMIN_PASS) 67 | driver.find_element(By.ID,"submit-login").click() 68 | 69 | time.sleep(1) 70 | 71 | if crawler.req(url): 72 | time.sleep(2) 73 | 74 | driver.quit() 75 | except: 76 | driver.quit() 77 | print(f"[x] error...") 78 | print(traceback.format_exc()) 79 | 80 | def doCrawl_server2(url): 81 | crawler = Crawler() 82 | driver = crawler.driver 83 | try: 84 | if crawler.req(url): 85 | time.sleep(10) 86 | 87 | driver.quit() 88 | except: 89 | driver.quit() 90 | print(f"[x] error...") 91 | print(traceback.format_exc()) 92 | 93 | 94 | @app.route("/run", methods=["POST"]) 95 | def run(): 96 | url = flask.request.form['url'] 97 | if 'chal' in flask.request.form: 98 | chal = flask.request.form['chal'] 99 | print(f"[+] bot run arang_client:{chal} - {url}") 100 | doCrawl_server1(chal, url) 101 | else: 102 | print(url) 103 | doCrawl_server2(url) 104 | 105 | return "" 106 | 107 | 108 | if __name__ == "__main__": 109 | try: 110 | app.run(host="0.0.0.0", port=9000, debug=True) 111 | except Exception as ex: 112 | logging.info(str(ex)) 113 | pass -------------------------------------------------------------------------------- /app/challenges/csrf1/csrf1.py: -------------------------------------------------------------------------------- 1 | #-*-coding:utf-8-*- 2 | import flask 3 | import os, pymysql, re, hashlib, time, base64, io, requests, socket 4 | import logging, traceback 5 | logging.basicConfig(level=logging.INFO) 6 | logging.getLogger('werkzeug').setLevel(level=logging.WARNING) 7 | 8 | app = flask.Flask(__name__) 9 | app.secret_key = os.urandom(16) 10 | app.config['MAX_CONTENT_LENGTH'] = 80 * 1024 * 1024 11 | 12 | ids = { 13 | "admin":os.getenv("admin_password") 14 | } 15 | 16 | articles = [{ 17 | "seq":0, 18 | "subject":"flag is here!", 19 | "author":"admin", 20 | "content": os.getenv("csrf1_flag") 21 | }] 22 | 23 | def sessionCheck(loginCheck=False): 24 | if loginCheck: 25 | if "isLogin" not in flask.session: 26 | return False 27 | else: 28 | return True 29 | 30 | if "isLogin" in flask.session: 31 | return True 32 | 33 | return False 34 | 35 | def xsscheck(content): 36 | content = content.lower() 37 | vulns = ["javascript", "frame", "object", "on", "data", "embed", "&#", "base","\\u","alert","fetch","XMLHttpRequest","eval","constructor"] 38 | vulns += list("'\"") 39 | for char in vulns: 40 | if char in content: 41 | return True 42 | 43 | return False 44 | 45 | 46 | @app.route("/") 47 | def index(): 48 | if sessionCheck(loginCheck=True): 49 | return flask.redirect(flask.url_for("board")) 50 | 51 | return flask.redirect(flask.url_for("login")) 52 | 53 | 54 | 55 | @app.route("/login", methods=["GET","POST"]) 56 | def login(): 57 | if flask.request.method == "GET": 58 | if sessionCheck(loginCheck=True): 59 | return flask.redirect(flask.url_for("board")) 60 | 61 | return flask.render_template("login.html", msg="false") 62 | else: 63 | if sessionCheck(): 64 | return flask.redirect(flask.url_for("board")) 65 | 66 | userid = flask.request.form["userid"] 67 | userpw = flask.request.form["userpw"] 68 | 69 | if userid in ids: 70 | if ids[userid] == userpw or (userid=="admin" and userpw==os.getenv("admin_password")): 71 | flask.session["userid"] = userid 72 | flask.session["isLogin"] = True 73 | 74 | resp = flask.make_response(flask.redirect(flask.url_for("board"))) 75 | resp.set_cookie('userid', flask.session["userid"]) 76 | return resp 77 | else: 78 | return flask.render_template("login.html", msg="login fail") 79 | else: 80 | return flask.render_template("login.html", msg="login fail") 81 | 82 | 83 | @app.route("/register", methods=["GET","POST"]) 84 | def register(): 85 | if flask.request.method == "GET": 86 | if sessionCheck(loginCheck=True): 87 | return flask.redirect(flask.url_for("board")) 88 | 89 | return flask.render_template("register.html", msg="false") 90 | else: 91 | if sessionCheck(): 92 | return flask.redirect(flask.url_for("board")) 93 | 94 | userid = flask.request.form["userid"] 95 | userpw = flask.request.form["userpw"] 96 | 97 | if userid not in ids: 98 | ids[userid] = userpw 99 | return flask.render_template("login.html", msg="false") 100 | else: 101 | return flask.render_template("register.html", msg="already registered id") 102 | 103 | @app.route("/changepw", methods=["GET"]) 104 | def changepw(): 105 | if "userid" not in flask.request.args or "userpw" not in flask.request.args: 106 | return flask.render_template("changepw.html", msg="false") 107 | else: 108 | userid = flask.request.args["userid"] 109 | userpw = flask.request.args["userpw"] 110 | 111 | if userid == "admin": 112 | if flask.request.remote_addr != socket.gethostbyname("arang_client"): 113 | return flask.render_template("changepw.html", msg="admin password is only changed at internal network") 114 | 115 | if userid in ids: 116 | ids[userid] = userpw 117 | return flask.redirect(flask.url_for("login")) 118 | else: 119 | return flask.render_template("changepw.html", msg="user doesn't exist") 120 | 121 | 122 | 123 | @app.route("/logout") 124 | def logout(): 125 | flask.session.pop('isLogin', False) 126 | resp = flask.make_response(flask.redirect(flask.url_for("login"))) 127 | resp.set_cookie('userid', expires=0) 128 | return resp 129 | 130 | 131 | @app.route("/board", methods=["GET"]) 132 | def board(): 133 | if not sessionCheck(loginCheck=True): 134 | return flask.redirect(flask.url_for("login")) 135 | results = [] 136 | for i in articles: 137 | if i["author"] == flask.session["userid"] or flask.session["userid"] == "admin" or i["author"] == "admin": 138 | results.append(i) 139 | return flask.render_template("board.html", articles=results) 140 | 141 | 142 | @app.route("/board/") 143 | def viewboard(seq): 144 | if not sessionCheck(loginCheck=True): 145 | return flask.redirect(flask.url_for("login")) 146 | 147 | article = articles[int(seq)] 148 | if article["author"] == flask.session["userid"] or flask.session["userid"] == "admin": 149 | return flask.render_template("view.html", articles=article) 150 | else: 151 | return "" 152 | 153 | @app.route("/write", methods=["GET", "POST"]) 154 | def write(): 155 | if not sessionCheck(loginCheck=True): 156 | return flask.redirect(flask.url_for("login")) 157 | 158 | if flask.request.method == "GET": 159 | return flask.render_template("write.html", loginid=flask.session["userid"]) 160 | 161 | elif flask.request.method == "POST": 162 | subject = flask.request.form["subject"] 163 | author = flask.request.form["author"] 164 | content = flask.request.form["content"] 165 | 166 | if not xsscheck(content): 167 | # substitute markdown image refference to html image tag 168 | content = re.sub(r"!\[(.*?)\]\((.*?)\)",r'',content.replace('"','')) 169 | 170 | req = { 171 | 'seq':len(articles), 172 | 'subject':subject, 173 | 'author':flask.session['userid'], 174 | 'content':content, 175 | } 176 | 177 | articles.append(req) 178 | 179 | return flask.redirect(flask.url_for("board")) 180 | else: 181 | return '' 182 | 183 | 184 | @app.route("/report", methods=["GET", "POST"]) 185 | def report(): 186 | if flask.request.method == "GET": 187 | return ''' 188 |
189 | 190 | 191 |
192 | ''' 193 | elif flask.request.method == "POST": 194 | url = flask.request.form['url'] 195 | requests.post(f"http://arang_client:9000/run", data=f"url={url}&chal=csrf1", headers={"Content-Type":"application/x-www-form-urlencoded", "Content-Length":"1"}) 196 | return "" 197 | 198 | 199 | if __name__ == "__main__": 200 | try: 201 | app.run(host="0.0.0.0", port=9004, debug=True) 202 | except Exception as ex: 203 | logging.info(str(ex)) 204 | pass 205 | -------------------------------------------------------------------------------- /app/challenges/csrf1/static/js/main.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | "use strict"; 4 | 5 | 6 | })(jQuery); 7 | -------------------------------------------------------------------------------- /app/challenges/csrf1/templates/board.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-CSRF1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-CSRF1

25 |
26 |
27 |
28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% for i in articles %} 40 | 41 | 42 | 43 | 44 | 45 | {% endfor %} 46 | 47 |
번호제목작성자
{{i['seq']}}{{i['subject']}}{{i['author']}}
48 |
49 | 55 |
56 |
57 |
58 |
59 |
60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /app/challenges/csrf1/templates/changepw.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF CHANGEPW-CSRF1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

Mini CTF CHANGEPW-CSRF1

26 |
27 |
28 |
29 |
30 | 47 |
48 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/challenges/csrf1/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF LOGIN-CSRF1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

LOGIN-CSRF1

26 |
27 |
28 |
29 |
30 | 54 |
55 |
56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/challenges/csrf1/templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF REGISTER-CSRF1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

Mini CTF REGISTER-CSRF1

26 |
27 |
28 |
29 |
30 | 47 |
48 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/challenges/csrf1/templates/view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-CSRF1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 |
19 |
20 |

Mini CTF BOARD-CSRF1

21 |
22 |
23 | 24 |
25 |
26 |
27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 42 | 43 | 44 | 49 | 50 | 51 |
제목{{articles['subject']}}
글쓴이 38 | 40 | {{articles['author']}} 41 |
45 | 46 |

{{articles['content']|safe}}

47 | 48 |
52 | 53 | 54 | 55 | 56 | 62 | 63 | 64 |
57 | 58 | 59 | 60 | 61 |
65 |
66 |
67 |
68 |
69 |
70 | 71 | 72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/challenges/csrf1/templates/write.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-CSRF1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-CSRF1

25 |
26 |
27 |
28 |
29 |
30 |
31 |

글쓰기

32 |
33 |
34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 |
47 | 48 | 49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/challenges/csrf2/csrf2.py: -------------------------------------------------------------------------------- 1 | #-*-coding:utf-8-*- 2 | import flask 3 | import os, pymysql, re, hashlib, time, base64, io, requests, binascii, socket 4 | import logging, traceback 5 | logging.basicConfig(level=logging.INFO) 6 | logging.getLogger('werkzeug').setLevel(level=logging.WARNING) 7 | 8 | app = flask.Flask(__name__) 9 | app.secret_key = os.urandom(16) 10 | app.config['MAX_CONTENT_LENGTH'] = 80 * 1024 * 1024 11 | 12 | ids = { 13 | "admin":os.getenv("admin_password") 14 | } 15 | 16 | articles = [{ 17 | "seq":0, 18 | "subject":"flag is here!", 19 | "author":"admin", 20 | "content": os.getenv("csrf2_flag") 21 | }] 22 | 23 | def sessionCheck(loginCheck=False): 24 | if loginCheck: 25 | if "isLogin" not in flask.session: 26 | return False 27 | else: 28 | return True 29 | 30 | if "isLogin" in flask.session: 31 | return True 32 | 33 | return False 34 | 35 | def xsscheck(content): 36 | content = content.lower() 37 | vulns = ["javascript", "frame", "object", "on", "data", "base","\\u", "embed", "&#", "alert","fetch","XMLHttpRequest","eval","constructor"] 38 | vulns += list("'\"") 39 | for char in vulns: 40 | if char in content: 41 | return True 42 | 43 | return False 44 | 45 | 46 | @app.route("/") 47 | def index(): 48 | if sessionCheck(loginCheck=True): 49 | return flask.redirect(flask.url_for("board")) 50 | 51 | return flask.redirect(flask.url_for("login")) 52 | 53 | 54 | 55 | @app.route("/login", methods=["GET","POST"]) 56 | def login(): 57 | if flask.request.method == "GET": 58 | if sessionCheck(loginCheck=True): 59 | return flask.redirect(flask.url_for("board")) 60 | 61 | return flask.render_template("login.html", msg="false") 62 | else: 63 | if sessionCheck(): 64 | return flask.redirect(flask.url_for("board")) 65 | 66 | userid = flask.request.form["userid"] 67 | userpw = flask.request.form["userpw"] 68 | 69 | if userid in ids: 70 | if ids[userid] == userpw or (userid=="admin" and userpw==os.getenv("admin_password")): 71 | flask.session["userid"] = userid 72 | flask.session["isLogin"] = True 73 | 74 | resp = flask.make_response(flask.redirect(flask.url_for("board"))) 75 | resp.set_cookie('userid', flask.session["userid"]) 76 | return resp 77 | else: 78 | return flask.render_template("login.html", msg="login fail") 79 | else: 80 | return flask.render_template("login.html", msg="login fail") 81 | 82 | 83 | @app.route("/register", methods=["GET","POST"]) 84 | def register(): 85 | if flask.request.method == "GET": 86 | if sessionCheck(loginCheck=True): 87 | return flask.redirect(flask.url_for("board")) 88 | 89 | return flask.render_template("register.html", msg="false") 90 | else: 91 | if sessionCheck(): 92 | return flask.redirect(flask.url_for("board")) 93 | 94 | userid = flask.request.form["userid"] 95 | userpw = flask.request.form["userpw"] 96 | 97 | if userid not in ids: 98 | ids[userid] = userpw 99 | return flask.render_template("login.html", msg="false") 100 | else: 101 | return flask.render_template("register.html", msg="already registered id") 102 | 103 | @app.route("/changepw", methods=["GET"]) 104 | def changepw(): 105 | if "userid" not in flask.request.args or "userpw" not in flask.request.args: 106 | flask.session["csrf_token"] = binascii.hexlify(os.urandom(16)).decode() 107 | return flask.render_template("changepw.html", msg="false", csrf_token=flask.session["csrf_token"]) 108 | else: 109 | if "csrf_token" not in flask.request.args: 110 | return flask.render_template("changepw.html", msg="please input csrf token") 111 | 112 | 113 | if flask.request.args["csrf_token"] != flask.session["csrf_token"]: 114 | return flask.render_template("changepw.html", msg="csrf token not match!") 115 | 116 | userid = flask.request.args["userid"] 117 | userpw = flask.request.args["userpw"] 118 | 119 | if userid == "admin": 120 | if flask.request.remote_addr != socket.gethostbyname("arang_client"): 121 | return flask.render_template("changepw.html", msg="admin password is only changed at internal network") 122 | 123 | if userid in ids: 124 | ids[userid] = userpw 125 | return flask.redirect(flask.url_for("login")) 126 | else: 127 | return flask.render_template("changepw.html", msg="user doesn't exist") 128 | 129 | 130 | 131 | @app.route("/logout") 132 | def logout(): 133 | flask.session.pop('isLogin', False) 134 | resp = flask.make_response(flask.redirect(flask.url_for("login"))) 135 | resp.set_cookie('userid', expires=0) 136 | return resp 137 | 138 | 139 | @app.route("/board", methods=["GET"]) 140 | def board(): 141 | if not sessionCheck(loginCheck=True): 142 | return flask.redirect(flask.url_for("login")) 143 | results = [] 144 | for i in articles: 145 | if i["author"] == flask.session["userid"] or flask.session["userid"] == "admin" or i["author"] == "admin": 146 | results.append(i) 147 | return flask.render_template("board.html", articles=results) 148 | 149 | 150 | @app.route("/board/") 151 | def viewboard(seq): 152 | if not sessionCheck(loginCheck=True): 153 | return flask.redirect(flask.url_for("login")) 154 | 155 | article = articles[int(seq)] 156 | if article["author"] == flask.session["userid"] or flask.session["userid"] == "admin": 157 | return flask.render_template("view.html", articles=article) 158 | else: 159 | return "" 160 | 161 | @app.route("/write", methods=["GET", "POST"]) 162 | def write(): 163 | if not sessionCheck(loginCheck=True): 164 | return flask.redirect(flask.url_for("login")) 165 | 166 | if flask.request.method == "GET": 167 | return flask.render_template("write.html", loginid=flask.session["userid"]) 168 | 169 | elif flask.request.method == "POST": 170 | subject = flask.request.form["subject"] 171 | author = flask.request.form["author"] 172 | content = flask.request.form["content"] 173 | 174 | if not xsscheck(content): 175 | # substitute markdown image refference to html image tag 176 | content = re.sub(r"!\[(.*?)\]\((.*?)\)",r'',content.replace('"','')) 177 | 178 | req = { 179 | 'seq':len(articles), 180 | 'subject':subject, 181 | 'author':flask.session['userid'], 182 | 'content':content, 183 | } 184 | 185 | articles.append(req) 186 | 187 | return flask.redirect(flask.url_for("board")) 188 | else: 189 | return '' 190 | 191 | 192 | @app.route("/report", methods=["GET", "POST"]) 193 | def report(): 194 | if flask.request.method == "GET": 195 | return ''' 196 |
197 | 198 | 199 |
200 | ''' 201 | elif flask.request.method == "POST": 202 | url = flask.request.form['url'] 203 | requests.post(f"http://arang_client:9000/run", data=f"url={url}&chal=csrf2", headers={"Content-Type":"application/x-www-form-urlencoded", "Content-Length":"1"}) 204 | return "" 205 | 206 | 207 | if __name__ == "__main__": 208 | try: 209 | app.run(host="0.0.0.0", port=9005, debug=True) 210 | except Exception as ex: 211 | logging.info(str(ex)) 212 | pass 213 | -------------------------------------------------------------------------------- /app/challenges/csrf2/static/js/main.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | "use strict"; 4 | 5 | 6 | })(jQuery); 7 | -------------------------------------------------------------------------------- /app/challenges/csrf2/templates/board.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-CSRF2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-CSRF2

25 |
26 |
27 |
28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% for i in articles %} 40 | 41 | 42 | 43 | 44 | 45 | {% endfor %} 46 | 47 |
번호제목작성자
{{i['seq']}}{{i['subject']}}{{i['author']}}
48 |
49 | 55 |
56 |
57 |
58 |
59 |
60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /app/challenges/csrf2/templates/changepw.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF CHANGEPW-CSRF2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

Mini CTF CHANGEPW-CSRF2

26 |
27 |
28 |
29 |
30 | 48 |
49 |
50 |
51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /app/challenges/csrf2/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF LOGIN-CSRF2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

LOGIN-CSRF2

26 |
27 |
28 |
29 |
30 | 54 |
55 |
56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/challenges/csrf2/templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF REGISTER-CSRF2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

Mini CTF REGISTER-CSRF2

26 |
27 |
28 |
29 |
30 | 47 |
48 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/challenges/csrf2/templates/view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-CSRF2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 |
19 |
20 |

Mini CTF BOARD-CSRF2

21 |
22 |
23 | 24 |
25 |
26 |
27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 42 | 43 | 44 | 49 | 50 | 51 |
제목{{articles['subject']}}
글쓴이 38 | 40 | {{articles['author']}} 41 |
45 | 46 |

{{articles['content']|safe}}

47 | 48 |
52 | 53 | 54 | 55 | 56 | 62 | 63 | 64 |
57 | 58 | 59 | 60 | 61 |
65 |
66 |
67 |
68 |
69 |
70 | 71 | 72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/challenges/csrf2/templates/write.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-CSRF2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-CSRF2

25 |
26 |
27 |
28 |
29 |
30 |
31 |

글쓰기

32 |
33 |
34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 |
47 | 48 | 49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/challenges/xsleak/static/js/main.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | "use strict"; 4 | 5 | 6 | })(jQuery); 7 | -------------------------------------------------------------------------------- /app/challenges/xsleak/templates/board.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSLEAK 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-XSLEAK

25 |
26 |
27 |
28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% for i in articles %} 40 | 41 | 42 | 43 | 44 | 45 | {% endfor %} 46 | 47 |
번호제목작성자
{{i['seq']}}{{i['subject']}}{{i['author']}}
48 |
49 | 54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/challenges/xsleak/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF LOGIN-XSLEAK 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

LOGIN-XSLEAK

26 |
27 |
28 |
29 |
30 | 54 |
55 |
56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/challenges/xsleak/templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF REGISTER-XSLEAK 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

Mini CTF REGISTER-XSLEAK

26 |
27 |
28 |
29 |
30 | 47 |
48 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/challenges/xsleak/templates/view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSLEAK 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 |
19 |
20 |
21 |

Mini CTF BOARD-XSLEAK

22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 43 | 44 | 45 | 50 | 51 | 52 |
제목{{articles['subject']}}
글쓴이 39 | 41 | {{articles['author']}} 42 |
46 | 47 |

{{articles['content']|safe}}

48 | flag! 49 |
53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 |
58 | 59 | 60 | 61 | 62 |
66 |
67 |
68 |
69 |
70 |
71 | 72 | 73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/challenges/xsleak/templates/write.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSLEAK 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-XSLEAK

25 |
26 |
27 |
28 |
29 |
30 |
31 |

글쓰기

32 |
33 |
34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 |
47 | 48 | 49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/challenges/xsleak/xsleak.py: -------------------------------------------------------------------------------- 1 | #-*-coding:utf-8-*- 2 | import flask 3 | import os, pymysql, re, hashlib, time, base64, io, requests 4 | import logging, traceback 5 | logging.basicConfig(level=logging.INFO) 6 | logging.getLogger('werkzeug').setLevel(level=logging.WARNING) 7 | 8 | app = flask.Flask(__name__) 9 | app.secret_key = os.urandom(16) 10 | app.config['MAX_CONTENT_LENGTH'] = 80 * 1024 * 1024 11 | 12 | ids = { 13 | "admin":os.getenv("admin_password") 14 | } 15 | 16 | articles = [] 17 | 18 | def sessionCheck(loginCheck=False): 19 | if loginCheck: 20 | if "isLogin" not in flask.session: 21 | return False 22 | else: 23 | return True 24 | 25 | if "isLogin" in flask.session: 26 | return True 27 | 28 | return False 29 | 30 | def xsscheck(content): 31 | content = content.lower() 32 | vulns = ["javascript", "script", "frame", "object", "embed", "on", "data", "base", "\\u", "&#", "alert", "fetch", "XMLHttpRequest", "eval", "constructor"] 33 | for char in vulns: 34 | if char in content: 35 | return True 36 | 37 | return False 38 | 39 | 40 | @app.route("/") 41 | def index(): 42 | if sessionCheck(loginCheck=True): 43 | return flask.redirect(flask.url_for("board")) 44 | 45 | return flask.redirect(flask.url_for("login")) 46 | 47 | 48 | 49 | @app.route("/login", methods=["GET","POST"]) 50 | def login(): 51 | if flask.request.method == "GET": 52 | if sessionCheck(loginCheck=True): 53 | return flask.redirect(flask.url_for("board")) 54 | 55 | return flask.render_template("login.html", msg="false") 56 | else: 57 | if sessionCheck(): 58 | return flask.redirect(flask.url_for("board")) 59 | 60 | userid = flask.request.form["userid"] 61 | userpw = flask.request.form["userpw"] 62 | 63 | if userid in ids: 64 | if ids[userid] == userpw: 65 | flask.session["userid"] = userid 66 | flask.session["isLogin"] = True 67 | 68 | resp = flask.make_response(flask.redirect(flask.url_for("board"))) 69 | resp.set_cookie('userid', flask.session["userid"]) 70 | return resp 71 | else: 72 | return flask.render_template("login.html", msg="login fail") 73 | else: 74 | return flask.render_template("login.html", msg="login fail") 75 | 76 | 77 | @app.route("/register", methods=["GET","POST"]) 78 | def register(): 79 | if flask.request.method == "GET": 80 | if sessionCheck(loginCheck=True): 81 | return flask.redirect(flask.url_for("board")) 82 | 83 | return flask.render_template("register.html", msg="false") 84 | else: 85 | if sessionCheck(): 86 | return flask.redirect(flask.url_for("board")) 87 | 88 | userid = flask.request.form["userid"] 89 | userpw = flask.request.form["userpw"] 90 | 91 | if userid not in ids: 92 | ids[userid] = userpw 93 | return flask.render_template("login.html", msg="false") 94 | else: 95 | return flask.render_template("register.html", msg="already registered id") 96 | 97 | 98 | @app.route("/logout") 99 | def logout(): 100 | flask.session.pop('isLogin', False) 101 | resp = flask.make_response(flask.redirect(flask.url_for("login"))) 102 | resp.set_cookie('userid', expires=0) 103 | return resp 104 | 105 | 106 | @app.route("/board", methods=["GET"]) 107 | def board(): 108 | if not sessionCheck(loginCheck=True): 109 | return flask.redirect(flask.url_for("login")) 110 | results = [] 111 | for i in articles: 112 | if i["author"] == flask.session["userid"] or flask.session["userid"] == "admin" or i["author"] == "admin": 113 | results.append(i) 114 | return flask.render_template("board.html", articles=results) 115 | 116 | 117 | @app.route("/board/") 118 | def viewboard(seq): 119 | if not sessionCheck(loginCheck=True): 120 | return flask.redirect(flask.url_for("login")) 121 | 122 | article = articles[int(seq)] 123 | if article["author"] == flask.session["userid"] or flask.session["userid"] == "admin": 124 | article["flag"] = os.getenv("xsleak_flag") if flask.session["userid"] == "admin" else "no flag to user" 125 | return flask.render_template("view.html", articles=article) 126 | else: 127 | return "" 128 | 129 | 130 | @app.route("/write", methods=["GET", "POST"]) 131 | def write(): 132 | if not sessionCheck(loginCheck=True): 133 | return flask.redirect(flask.url_for("login")) 134 | 135 | if flask.request.method == "GET": 136 | return flask.render_template("write.html", loginid=flask.session["userid"]) 137 | 138 | elif flask.request.method == "POST": 139 | subject = flask.request.form["subject"] 140 | author = flask.request.form["author"] 141 | content = flask.request.form["content"] 142 | 143 | if not xsscheck(content): 144 | req = { 145 | 'seq':len(articles), 146 | 'subject':subject, 147 | 'author':flask.session['userid'], 148 | 'content':content 149 | } 150 | 151 | articles.append(req) 152 | 153 | return flask.redirect(flask.url_for("board")) 154 | else: 155 | return '' 156 | 157 | 158 | @app.route("/report", methods=["GET", "POST"]) 159 | def report(): 160 | if flask.request.method == "GET": 161 | return ''' 162 |
163 | 164 | 165 |
166 | ''' 167 | elif flask.request.method == "POST": 168 | url = flask.request.form['url'] 169 | requests.post(f"http://arang_client:9000/run", data=f"chal=xsleak&url={url}", headers={"Content-Type":"application/x-www-form-urlencoded", "Content-Length":"1"}) 170 | return "" 171 | 172 | 173 | if __name__ == "__main__": 174 | try: 175 | app.run(host="0.0.0.0", port=9006, debug=True) 176 | except Exception as ex: 177 | logging.info(str(ex)) 178 | pass 179 | -------------------------------------------------------------------------------- /app/challenges/xss1/static/js/main.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | "use strict"; 4 | 5 | 6 | })(jQuery); 7 | -------------------------------------------------------------------------------- /app/challenges/xss1/static/js/popper.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) Federico Zivolo 2019 3 | Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). 4 | */(function(e,t){'object'==typeof exports&&'undefined'!=typeof module?module.exports=t():'function'==typeof define&&define.amd?define(t):e.Popper=t()})(this,function(){'use strict';function e(e){return e&&'[object Function]'==={}.toString.call(e)}function t(e,t){if(1!==e.nodeType)return[];var o=e.ownerDocument.defaultView,n=o.getComputedStyle(e,null);return t?n[t]:n}function o(e){return'HTML'===e.nodeName?e:e.parentNode||e.host}function n(e){if(!e)return document.body;switch(e.nodeName){case'HTML':case'BODY':return e.ownerDocument.body;case'#document':return e.body;}var i=t(e),r=i.overflow,p=i.overflowX,s=i.overflowY;return /(auto|scroll|overlay)/.test(r+s+p)?e:n(o(e))}function r(e){return 11===e?pe:10===e?se:pe||se}function p(e){if(!e)return document.documentElement;for(var o=r(10)?document.body:null,n=e.offsetParent||null;n===o&&e.nextElementSibling;)n=(e=e.nextElementSibling).offsetParent;var i=n&&n.nodeName;return i&&'BODY'!==i&&'HTML'!==i?-1!==['TH','TD','TABLE'].indexOf(n.nodeName)&&'static'===t(n,'position')?p(n):n:e?e.ownerDocument.documentElement:document.documentElement}function s(e){var t=e.nodeName;return'BODY'!==t&&('HTML'===t||p(e.firstElementChild)===e)}function d(e){return null===e.parentNode?e:d(e.parentNode)}function a(e,t){if(!e||!e.nodeType||!t||!t.nodeType)return document.documentElement;var o=e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING,n=o?e:t,i=o?t:e,r=document.createRange();r.setStart(n,0),r.setEnd(i,0);var l=r.commonAncestorContainer;if(e!==l&&t!==l||n.contains(i))return s(l)?l:p(l);var f=d(e);return f.host?a(f.host,t):a(e,d(t).host)}function l(e){var t=1=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),le({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=fe({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f],10),E=parseFloat(w['border'+f+'Width'],10),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},le(n,m,$(v)),le(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ge.FLIP:p=[n,i];break;case ge.CLOCKWISE:p=G(n);break;case ge.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u);(m||b||y)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),y&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=fe({},e.offsets.popper,D(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport'},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=C(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!me),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=H('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=fe({},E,e.attributes),e.styles=fe({},m,e.styles),e.arrowStyles=fe({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return j(e.instance.popper,e.styles),V(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&j(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),j(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ue}); 5 | //# sourceMappingURL=popper.min.js.map -------------------------------------------------------------------------------- /app/challenges/xss1/templates/board.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSS1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-XSS1

25 |
26 |
27 |
28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% for i in articles %} 40 | 41 | 42 | 43 | 44 | 45 | {% endfor %} 46 | 47 |
번호제목작성자
{{i['seq']}}{{i['subject']}}{{i['author']}}
48 |
49 | 54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/challenges/xss1/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF LOGIN-XSS1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

LOGIN-XSS1

26 |
27 |
28 |
29 |
30 | 54 |
55 |
56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/challenges/xss1/templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF REGISTER-XSS1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

Mini CTF REGISTER-XSS1

26 |
27 |
28 |
29 |
30 | 47 |
48 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/challenges/xss1/templates/view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSS1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 |
19 |
20 |

Mini CTF BOARD-XSS1

21 |
22 |
23 | 24 |
25 |
26 |
27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 42 | 43 | 44 | 49 | 50 | 51 |
제목{{articles['subject']}}
글쓴이 38 | 40 | {{articles['author']}} 41 |
45 | 46 |

{{articles['content']|safe}}

47 | 48 |
52 | 53 | 54 | 55 | 56 | 62 | 63 | 64 |
57 | 58 | 59 | 60 | 61 |
65 |
66 |
67 |
68 |
69 |
70 | 71 | 72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/challenges/xss1/templates/write.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-XSS1

25 |
26 |
27 |
28 |
29 |
30 |
31 |

글쓰기

32 |
33 |
34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 |
47 | 48 | 49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/challenges/xss1/xss1.py: -------------------------------------------------------------------------------- 1 | #-*-coding:utf-8-*- 2 | import flask 3 | import os, pymysql, re, hashlib, time, base64, io, requests 4 | import logging, traceback 5 | logging.basicConfig(level=logging.INFO) 6 | logging.getLogger('werkzeug').setLevel(level=logging.WARNING) 7 | 8 | app = flask.Flask(__name__) 9 | app.secret_key = os.urandom(16) 10 | app.config['MAX_CONTENT_LENGTH'] = 80 * 1024 * 1024 11 | 12 | ids = { 13 | "admin":os.getenv("admin_password") 14 | } 15 | 16 | articles = [] 17 | 18 | def sessionCheck(loginCheck=False): 19 | if loginCheck: 20 | if "isLogin" not in flask.session: 21 | return False 22 | else: 23 | return True 24 | 25 | if "isLogin" in flask.session: 26 | return True 27 | 28 | return False 29 | 30 | 31 | @app.route("/") 32 | def index(): 33 | if sessionCheck(loginCheck=True): 34 | return flask.redirect(flask.url_for("board")) 35 | 36 | return flask.redirect(flask.url_for("login")) 37 | 38 | 39 | 40 | @app.route("/login", methods=["GET","POST"]) 41 | def login(): 42 | if flask.request.method == "GET": 43 | if sessionCheck(loginCheck=True): 44 | return flask.redirect(flask.url_for("board")) 45 | 46 | return flask.render_template("login.html", msg="false") 47 | else: 48 | if sessionCheck(): 49 | return flask.redirect(flask.url_for("board")) 50 | 51 | userid = flask.request.form["userid"] 52 | userpw = flask.request.form["userpw"] 53 | 54 | if userid in ids: 55 | if ids[userid] == userpw: 56 | flask.session["userid"] = userid 57 | flask.session["isLogin"] = True 58 | 59 | resp = flask.make_response(flask.redirect(flask.url_for("board"))) 60 | resp.set_cookie('userid', flask.session["userid"]) 61 | if userid == "admin": 62 | resp.set_cookie('flag', os.getenv("xss1_flag")) 63 | return resp 64 | else: 65 | return flask.render_template("login.html", msg="login fail") 66 | else: 67 | return flask.render_template("login.html", msg="login fail") 68 | 69 | 70 | @app.route("/register", methods=["GET","POST"]) 71 | def register(): 72 | if flask.request.method == "GET": 73 | if sessionCheck(loginCheck=True): 74 | return flask.redirect(flask.url_for("board")) 75 | 76 | return flask.render_template("register.html", msg="false") 77 | else: 78 | if sessionCheck(): 79 | return flask.redirect(flask.url_for("board")) 80 | 81 | userid = flask.request.form["userid"] 82 | userpw = flask.request.form["userpw"] 83 | 84 | if userid not in ids: 85 | ids[userid] = userpw 86 | return flask.render_template("login.html", msg="false") 87 | else: 88 | return flask.render_template("register.html", msg="already registered id") 89 | 90 | @app.route("/logout") 91 | def logout(): 92 | flask.session.pop('isLogin', False) 93 | resp = flask.make_response(flask.redirect(flask.url_for("login"))) 94 | resp.set_cookie('userid', expires=0) 95 | return resp 96 | 97 | @app.route("/board", methods=["GET"]) 98 | def board(): 99 | if not sessionCheck(loginCheck=True): 100 | return flask.redirect(flask.url_for("login")) 101 | results = [] 102 | for i in articles: 103 | if i["author"] == flask.session["userid"] or flask.session["userid"] == "admin": 104 | results.append(i) 105 | return flask.render_template("board.html", articles=results) 106 | 107 | 108 | @app.route("/board/") 109 | def viewboard(seq): 110 | if not sessionCheck(loginCheck=True): 111 | return flask.redirect(flask.url_for("login")) 112 | 113 | article = articles[int(seq)] 114 | if article["author"] == flask.session["userid"] or flask.session["userid"] == "admin": 115 | return flask.render_template("view.html", articles=article) 116 | else: 117 | return "" 118 | 119 | 120 | @app.route("/write", methods=["GET", "POST"]) 121 | def write(): 122 | if not sessionCheck(loginCheck=True): 123 | return flask.redirect(flask.url_for("login")) 124 | 125 | if flask.request.method == "GET": 126 | return flask.render_template("write.html", loginid=flask.session["userid"]) 127 | 128 | elif flask.request.method == "POST": 129 | subject = flask.request.form["subject"] 130 | author = flask.request.form["author"] 131 | content = flask.request.form["content"] 132 | 133 | req = { 134 | 'seq':len(articles), 135 | 'subject':subject, 136 | 'author':flask.session['userid'], 137 | 'content':content, 138 | } 139 | 140 | articles.append(req) 141 | 142 | return flask.redirect(flask.url_for("board")) 143 | 144 | 145 | @app.route("/report", methods=["GET", "POST"]) 146 | def report(): 147 | if flask.request.method == "GET": 148 | return ''' 149 |
150 | 151 | 152 |
153 | ''' 154 | elif flask.request.method == "POST": 155 | url = flask.request.form['url'] 156 | requests.post(f"http://arang_client:9000/run", data=f"chal=xss1&url={url}", headers={"Content-Type":"application/x-www-form-urlencoded", "Content-Length":"1"}) 157 | return "" 158 | 159 | 160 | if __name__ == "__main__": 161 | try: 162 | app.run(host="0.0.0.0", port=9001, debug=True) 163 | except Exception as ex: 164 | logging.info(str(ex)) 165 | pass 166 | -------------------------------------------------------------------------------- /app/challenges/xss2/static/js/main.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | "use strict"; 4 | 5 | 6 | })(jQuery); 7 | -------------------------------------------------------------------------------- /app/challenges/xss2/templates/board.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSS2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-XSS2

25 |
26 |
27 |
28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% for i in articles %} 40 | 41 | 42 | 43 | 44 | 45 | {% endfor %} 46 | 47 |
번호제목작성자
{{i['seq']}}{{i['subject']}}{{i['author']}}
48 |
49 | 54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/challenges/xss2/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF LOGIN-XSS2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

LOGIN-XSS2

26 |
27 |
28 |
29 |
30 | 54 |
55 |
56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/challenges/xss2/templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF REGISTER-XSS2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

Mini CTF REGISTER-XSS2

26 |
27 |
28 |
29 |
30 | 47 |
48 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/challenges/xss2/templates/view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSS2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 |
19 |
20 |

Mini CTF BOARD-XSS2

21 |
22 |
23 | 24 |
25 |
26 |
27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 42 | 43 | 44 | 49 | 50 | 51 |
제목{{articles['subject']}}
글쓴이 38 | 40 | {{articles['author']}} 41 |
45 | 46 |

{{articles['content']|safe}}

47 | 48 |
52 | 53 | 54 | 55 | 56 | 62 | 63 | 64 |
57 | 58 | 59 | 60 | 61 |
65 |
66 |
67 |
68 |
69 |
70 | 71 | 72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/challenges/xss2/templates/write.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSS2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-XSS2

25 |
26 |
27 |
28 |
29 |
30 |
31 |

글쓰기

32 |
33 |
34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 |
47 | 48 | 49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/challenges/xss2/xss2.py: -------------------------------------------------------------------------------- 1 | #-*-coding:utf-8-*- 2 | import flask 3 | import os, pymysql, re, hashlib, time, base64, io, requests 4 | import logging, traceback 5 | logging.basicConfig(level=logging.INFO) 6 | logging.getLogger('werkzeug').setLevel(level=logging.WARNING) 7 | 8 | app = flask.Flask(__name__) 9 | app.secret_key = os.urandom(16) 10 | app.config['MAX_CONTENT_LENGTH'] = 80 * 1024 * 1024 11 | 12 | ids = { 13 | "admin":os.getenv("admin_password") 14 | } 15 | 16 | articles = [] 17 | 18 | def sessionCheck(loginCheck=False): 19 | if loginCheck: 20 | if "isLogin" not in flask.session: 21 | return False 22 | else: 23 | return True 24 | 25 | if "isLogin" in flask.session: 26 | return True 27 | 28 | return False 29 | 30 | 31 | def xsscheck(content): 32 | content = content.lower() 33 | vulns = ["javascript", "script", "on", "data", "base", "(", ")", "'"] 34 | vulns += [chr(x) for x in range(0x20)] 35 | for char in vulns: 36 | if char in content: 37 | return True 38 | 39 | return False 40 | 41 | 42 | @app.route("/") 43 | def index(): 44 | if sessionCheck(loginCheck=True): 45 | return flask.redirect(flask.url_for("board")) 46 | 47 | return flask.redirect(flask.url_for("login")) 48 | 49 | 50 | 51 | @app.route("/login", methods=["GET","POST"]) 52 | def login(): 53 | if flask.request.method == "GET": 54 | if sessionCheck(loginCheck=True): 55 | return flask.redirect(flask.url_for("board")) 56 | 57 | return flask.render_template("login.html", msg="false") 58 | else: 59 | if sessionCheck(): 60 | return flask.redirect(flask.url_for("board")) 61 | 62 | userid = flask.request.form["userid"] 63 | userpw = flask.request.form["userpw"] 64 | 65 | if userid in ids: 66 | if ids[userid] == userpw: 67 | flask.session["userid"] = userid 68 | flask.session["isLogin"] = True 69 | 70 | resp = flask.make_response(flask.redirect(flask.url_for("board"))) 71 | resp.set_cookie('userid', flask.session["userid"]) 72 | if userid == "admin": 73 | resp.set_cookie('flag', os.getenv("xss2_flag")) 74 | return resp 75 | else: 76 | return flask.render_template("login.html", msg="login fail") 77 | else: 78 | return flask.render_template("login.html", msg="login fail") 79 | 80 | 81 | @app.route("/register", methods=["GET","POST"]) 82 | def register(): 83 | if flask.request.method == "GET": 84 | if sessionCheck(loginCheck=True): 85 | return flask.redirect(flask.url_for("board")) 86 | 87 | return flask.render_template("register.html", msg="false") 88 | else: 89 | if sessionCheck(): 90 | return flask.redirect(flask.url_for("board")) 91 | 92 | userid = flask.request.form["userid"] 93 | userpw = flask.request.form["userpw"] 94 | 95 | if userid not in ids: 96 | ids[userid] = userpw 97 | return flask.render_template("login.html", msg="false") 98 | else: 99 | return flask.render_template("register.html", msg="already registered id") 100 | 101 | @app.route("/logout") 102 | def logout(): 103 | flask.session.pop('isLogin', False) 104 | resp = flask.make_response(flask.redirect(flask.url_for("login"))) 105 | resp.set_cookie('userid', expires=0) 106 | return resp 107 | 108 | 109 | @app.route("/board", methods=["GET"]) 110 | def board(): 111 | if not sessionCheck(loginCheck=True): 112 | return flask.redirect(flask.url_for("login")) 113 | results = [] 114 | for i in articles: 115 | if i["author"] == flask.session["userid"] or flask.session["userid"] == "admin": 116 | results.append(i) 117 | return flask.render_template("board.html", articles=results) 118 | 119 | 120 | @app.route("/board/") 121 | def viewboard(seq): 122 | if not sessionCheck(loginCheck=True): 123 | return flask.redirect(flask.url_for("login")) 124 | 125 | article = articles[int(seq)] 126 | if article["author"] == flask.session["userid"] or flask.session["userid"] == "admin": 127 | return flask.render_template("view.html", articles=article) 128 | else: 129 | return "" 130 | 131 | @app.route("/write", methods=["GET", "POST"]) 132 | def write(): 133 | if not sessionCheck(loginCheck=True): 134 | return flask.redirect(flask.url_for("login")) 135 | 136 | if flask.request.method == "GET": 137 | return flask.render_template("write.html", loginid=flask.session["userid"]) 138 | 139 | elif flask.request.method == "POST": 140 | subject = flask.request.form["subject"] 141 | author = flask.request.form["author"] 142 | content = flask.request.form["content"] 143 | 144 | if not xsscheck(content): 145 | req = { 146 | 'seq':len(articles), 147 | 'subject':subject, 148 | 'author':flask.session['userid'], 149 | 'content':content, 150 | } 151 | 152 | articles.append(req) 153 | 154 | return flask.redirect(flask.url_for("board")) 155 | else: 156 | return '' 157 | 158 | 159 | @app.route("/report", methods=["GET", "POST"]) 160 | def report(): 161 | if flask.request.method == "GET": 162 | return ''' 163 |
164 | 165 | 166 |
167 | ''' 168 | elif flask.request.method == "POST": 169 | url = flask.request.form['url'] 170 | requests.post(f"http://arang_client:9000/run", data=f"chal=xss2&url={url}", headers={"Content-Type":"application/x-www-form-urlencoded", "Content-Length":"1"}) 171 | return "" 172 | 173 | 174 | if __name__ == "__main__": 175 | try: 176 | app.run(host="0.0.0.0", port=9002, debug=True) 177 | except Exception as ex: 178 | logging.info(str(ex)) 179 | pass 180 | -------------------------------------------------------------------------------- /app/challenges/xss3/static/js/main.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | "use strict"; 4 | 5 | 6 | })(jQuery); 7 | -------------------------------------------------------------------------------- /app/challenges/xss3/templates/board.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSS3 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-XSS3

25 |
26 |
27 |
28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% for i in articles %} 40 | 41 | 42 | 43 | 44 | 45 | {% endfor %} 46 | 47 |
번호제목작성자
{{i['seq']}}{{i['subject']}}{{i['author']}}
48 |
49 | 54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/challenges/xss3/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF LOGIN-XSS3 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

LOGIN-XSS3

26 |
27 |
28 |
29 |
30 | 54 |
55 |
56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/challenges/xss3/templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF REGISTER-XSS3 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

Mini CTF REGISTER-XSS3

26 |
27 |
28 |
29 |
30 | 47 |
48 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/challenges/xss3/templates/view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSS3 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 |
19 |
20 |

Mini CTF BOARD-XSS3

21 |
22 |
23 | 24 |
25 |
26 |
27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 42 | 43 | 44 | 49 | 50 | 51 |
제목{{articles['subject']}}
글쓴이 38 | 40 | {{articles['author']}} 41 |
45 | 46 |

{{articles['content']|safe}}

47 | 48 |
52 | 53 | 54 | 55 | 56 | 62 | 63 | 64 |
57 | 58 | 59 | 60 | 61 |
65 |
66 |
67 |
68 |
69 |
70 | 71 | 72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/challenges/xss3/templates/write.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD-XSS3 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

Mini CTF BOARD-XSS3

25 |
26 |
27 |
28 |
29 |
30 |
31 |

글쓰기

32 |
33 |
34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 |
47 | 48 | 49 |
50 |
51 | 52 | 53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/challenges/xss3/xss3.py: -------------------------------------------------------------------------------- 1 | #-*-coding:utf-8-*- 2 | import flask 3 | import os, pymysql, re, hashlib, time, base64, io, requests 4 | import logging, traceback 5 | logging.basicConfig(level=logging.INFO) 6 | logging.getLogger('werkzeug').setLevel(level=logging.WARNING) 7 | 8 | app = flask.Flask(__name__) 9 | app.secret_key = os.urandom(16) 10 | app.config['MAX_CONTENT_LENGTH'] = 80 * 1024 * 1024 11 | 12 | ids = { 13 | "admin":os.getenv("admin_password") 14 | } 15 | 16 | articles = [{ 17 | "seq":0, 18 | "subject":"flag is here!", 19 | "author":"admin", 20 | "content": os.getenv("xss3_flag") 21 | }] 22 | 23 | def sessionCheck(loginCheck=False): 24 | if loginCheck: 25 | if "isLogin" not in flask.session: 26 | return False 27 | else: 28 | return True 29 | 30 | if "isLogin" in flask.session: 31 | return True 32 | 33 | return False 34 | 35 | def xsscheck(content): 36 | content = content.lower() 37 | vulns = ["javascript", "frame", "object", "on", "data", "base","\\u","alert","fetch","XMLHttpRequest","eval","constructor"] 38 | vulns += list("()'\"") 39 | for char in vulns: 40 | if char in content: 41 | return True 42 | 43 | return False 44 | 45 | 46 | @app.route("/") 47 | def index(): 48 | if sessionCheck(loginCheck=True): 49 | return flask.redirect(flask.url_for("board")) 50 | 51 | return flask.redirect(flask.url_for("login")) 52 | 53 | 54 | 55 | @app.route("/login", methods=["GET","POST"]) 56 | def login(): 57 | if flask.request.method == "GET": 58 | if sessionCheck(loginCheck=True): 59 | return flask.redirect(flask.url_for("board")) 60 | 61 | return flask.render_template("login.html", msg="false") 62 | else: 63 | if sessionCheck(): 64 | return flask.redirect(flask.url_for("board")) 65 | 66 | userid = flask.request.form["userid"] 67 | userpw = flask.request.form["userpw"] 68 | 69 | if userid in ids: 70 | if ids[userid] == userpw: 71 | flask.session["userid"] = userid 72 | flask.session["isLogin"] = True 73 | 74 | resp = flask.make_response(flask.redirect(flask.url_for("board"))) 75 | resp.set_cookie('userid', flask.session["userid"]) 76 | return resp 77 | else: 78 | return flask.render_template("login.html", msg="login fail") 79 | else: 80 | return flask.render_template("login.html", msg="login fail") 81 | 82 | 83 | @app.route("/register", methods=["GET","POST"]) 84 | def register(): 85 | if flask.request.method == "GET": 86 | if sessionCheck(loginCheck=True): 87 | return flask.redirect(flask.url_for("board")) 88 | 89 | return flask.render_template("register.html", msg="false") 90 | else: 91 | if sessionCheck(): 92 | return flask.redirect(flask.url_for("board")) 93 | 94 | userid = flask.request.form["userid"] 95 | userpw = flask.request.form["userpw"] 96 | 97 | if userid not in ids: 98 | ids[userid] = userpw 99 | return flask.render_template("login.html", msg="false") 100 | else: 101 | return flask.render_template("register.html", msg="already registered id") 102 | 103 | @app.route("/logout") 104 | def logout(): 105 | flask.session.pop('isLogin', False) 106 | resp = flask.make_response(flask.redirect(flask.url_for("login"))) 107 | resp.set_cookie('userid', expires=0) 108 | return resp 109 | 110 | 111 | @app.route("/board", methods=["GET"]) 112 | def board(): 113 | if not sessionCheck(loginCheck=True): 114 | return flask.redirect(flask.url_for("login")) 115 | results = [] 116 | for i in articles: 117 | if i["author"] == flask.session["userid"] or flask.session["userid"] == "admin" or i["author"] == "admin": 118 | results.append(i) 119 | return flask.render_template("board.html", articles=results) 120 | 121 | 122 | @app.route("/board/") 123 | def viewboard(seq): 124 | if not sessionCheck(loginCheck=True): 125 | return flask.redirect(flask.url_for("login")) 126 | 127 | article = articles[int(seq)] 128 | if article["author"] == flask.session["userid"] or flask.session["userid"] == "admin": 129 | return flask.render_template("view.html", articles=article) 130 | else: 131 | return "" 132 | 133 | @app.route("/write", methods=["GET", "POST"]) 134 | def write(): 135 | if not sessionCheck(loginCheck=True): 136 | return flask.redirect(flask.url_for("login")) 137 | 138 | if flask.request.method == "GET": 139 | return flask.render_template("write.html", loginid=flask.session["userid"]) 140 | 141 | elif flask.request.method == "POST": 142 | subject = flask.request.form["subject"] 143 | author = flask.request.form["author"] 144 | content = flask.request.form["content"] 145 | 146 | if not xsscheck(content): 147 | req = { 148 | 'seq':len(articles), 149 | 'subject':subject, 150 | 'author':flask.session['userid'], 151 | 'content':content, 152 | } 153 | 154 | articles.append(req) 155 | 156 | return flask.redirect(flask.url_for("board")) 157 | else: 158 | return '' 159 | 160 | 161 | @app.route("/report", methods=["GET", "POST"]) 162 | def report(): 163 | if flask.request.method == "GET": 164 | return ''' 165 |
166 | 167 | 168 |
169 | ''' 170 | elif flask.request.method == "POST": 171 | url = flask.request.form['url'] 172 | requests.post(f"http://arang_client:9000/run", data=f"chal=xss3&url={url}", headers={"Content-Type":"application/x-www-form-urlencoded", "Content-Length":"1"}) 173 | return "" 174 | 175 | 176 | if __name__ == "__main__": 177 | try: 178 | app.run(host="0.0.0.0", port=9003, debug=True) 179 | except Exception as ex: 180 | logging.info(str(ex)) 181 | pass 182 | -------------------------------------------------------------------------------- /app/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 /app/app.py& 3 | python3 /app/bot/bot.py& 4 | python3 /app/challenges/xss1/xss1.py& 5 | python3 /app/challenges/xss2/xss2.py& 6 | python3 /app/challenges/xss3/xss3.py& 7 | python3 /app/challenges/csrf1/csrf1.py& 8 | python3 /app/challenges/csrf2/csrf2.py& 9 | python3 /app/challenges/xsleak/xsleak.py& -------------------------------------------------------------------------------- /app/flags.json: -------------------------------------------------------------------------------- 1 | { 2 | "xss1":"flag{[REDACTED]}", 3 | "xss2":"flag{[REDACTED]}", 4 | "xss3":"flag{[REDACTED]}", 5 | "dom clobbering":"flag{[REDACTED]}", 6 | "csrf1":"flag{[REDACTED]}", 7 | "csrf2":"flag{[REDACTED]}", 8 | "xsleak":"flag{[REDACTED]}", 9 | "sqli1":"flag{[REDACTED]}", 10 | "sqli2":"flag{[REDACTED]}", 11 | "sqli3":"flag{[REDACTED]}", 12 | "lfi1":"flag{[REDACTED]}", 13 | "lfi2":"flag{[REDACTED]}", 14 | "command injection":"flag{[REDACTED]}", 15 | "ssti":"flag{[REDACTED]}", 16 | "prototype pollution":"flag{[REDACTED]}" 17 | } -------------------------------------------------------------------------------- /app/static/js/main.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | "use strict"; 4 | 5 | 6 | })(jQuery); 7 | -------------------------------------------------------------------------------- /app/static/js/popper.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) Federico Zivolo 2019 3 | Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). 4 | */(function(e,t){'object'==typeof exports&&'undefined'!=typeof module?module.exports=t():'function'==typeof define&&define.amd?define(t):e.Popper=t()})(this,function(){'use strict';function e(e){return e&&'[object Function]'==={}.toString.call(e)}function t(e,t){if(1!==e.nodeType)return[];var o=e.ownerDocument.defaultView,n=o.getComputedStyle(e,null);return t?n[t]:n}function o(e){return'HTML'===e.nodeName?e:e.parentNode||e.host}function n(e){if(!e)return document.body;switch(e.nodeName){case'HTML':case'BODY':return e.ownerDocument.body;case'#document':return e.body;}var i=t(e),r=i.overflow,p=i.overflowX,s=i.overflowY;return /(auto|scroll|overlay)/.test(r+s+p)?e:n(o(e))}function r(e){return 11===e?pe:10===e?se:pe||se}function p(e){if(!e)return document.documentElement;for(var o=r(10)?document.body:null,n=e.offsetParent||null;n===o&&e.nextElementSibling;)n=(e=e.nextElementSibling).offsetParent;var i=n&&n.nodeName;return i&&'BODY'!==i&&'HTML'!==i?-1!==['TH','TD','TABLE'].indexOf(n.nodeName)&&'static'===t(n,'position')?p(n):n:e?e.ownerDocument.documentElement:document.documentElement}function s(e){var t=e.nodeName;return'BODY'!==t&&('HTML'===t||p(e.firstElementChild)===e)}function d(e){return null===e.parentNode?e:d(e.parentNode)}function a(e,t){if(!e||!e.nodeType||!t||!t.nodeType)return document.documentElement;var o=e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING,n=o?e:t,i=o?t:e,r=document.createRange();r.setStart(n,0),r.setEnd(i,0);var l=r.commonAncestorContainer;if(e!==l&&t!==l||n.contains(i))return s(l)?l:p(l);var f=d(e);return f.host?a(f.host,t):a(e,d(t).host)}function l(e){var t=1=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),le({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=fe({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f],10),E=parseFloat(w['border'+f+'Width'],10),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},le(n,m,$(v)),le(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ge.FLIP:p=[n,i];break;case ge.CLOCKWISE:p=G(n);break;case ge.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u);(m||b||y)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),y&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=fe({},e.offsets.popper,D(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport'},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=C(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.rightwindow.devicePixelRatio||!me),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=H('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=fe({},E,e.attributes),e.styles=fe({},m,e.styles),e.arrowStyles=fe({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return j(e.instance.popper,e.styles),V(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&j(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),j(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ue}); 5 | //# sourceMappingURL=popper.min.js.map -------------------------------------------------------------------------------- /app/templates/board.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF BOARD 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |

WHS1 Mini CTF BOARD

25 |
26 |
27 |
28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% for i in results %} 40 | 41 | 42 | 43 | 44 | 45 | {% endfor %} 46 | 47 |
번호제목작성자
{{i['seq']}}{{i['subject']}}{{i['author']}}
48 |
49 | 54 |
55 |
56 |
57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF LOGIN 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

LOGIN

26 |
27 |
28 |
29 |
30 | 54 |
55 |
56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/templates/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 26 | 27 | 28 |
29 |
30 |
31 |
32 |

Mini CTF

33 |
34 |
35 |
36 |
37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | {% for i in c %} 49 | 50 | 51 | 52 | 53 | {% if i['solved'] == True %} 54 | 55 | {% else %} 56 | 57 | {% endif %} 58 | 59 | {% endfor %} 60 | 61 |
번호문제링크
풀이여부
{{i['seq']}}{{i['challenge']}}{{i['link']}}
62 |
63 |
64 | 플래그제출 65 | 랭킹 66 | 로그아웃 67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/templates/ranking.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |

Mini CTF

21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | {% for item in ids %} 36 | 37 | 38 | 39 | 40 | 41 | {% endfor %} 42 | 43 |
순위아이디푼 문제
{{ loop.index }}{{ item.keys()|first }}{{ (item.values()|first)['solved']|join(', ') }}
44 |
45 |
46 | 메인 47 | 로그아웃 48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /app/templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mini CTF REGISTER 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 |
22 |
23 |
24 |
25 |

Mini CTF REGISTER

26 |
27 |
28 |
29 |
30 | 47 |
48 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/users.json: -------------------------------------------------------------------------------- 1 | { 2 | "arang": { 3 | "password": "123123", 4 | "solved": [], 5 | "lastsolved": 1797214493 6 | } 7 | } -------------------------------------------------------------------------------- /app2/000-default.conf: -------------------------------------------------------------------------------- 1 | 2 | # The ServerName directive sets the request scheme, hostname and port that 3 | # the server uses to identify itself. This is used when creating 4 | # redirection URLs. In the context of virtual hosts, the ServerName 5 | # specifies what hostname must appear in the request's Host: header to 6 | # match this virtual host. For the default virtual host (this file) this 7 | # value is not decisive as it is used as a last resort host regardless. 8 | # However, you must set it for any further virtual host explicitly. 9 | #ServerName www.example.com 10 | 11 | ServerAdmin webmaster@localhost 12 | DocumentRoot /var/www/html 13 | 14 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, 15 | # error, crit, alert, emerg. 16 | # It is also possible to configure the loglevel for particular 17 | # modules, e.g. 18 | #LogLevel info ssl:warn 19 | 20 | ErrorLog ${APACHE_LOG_DIR}/error.log 21 | CustomLog ${APACHE_LOG_DIR}/access.log combined 22 | 23 | # For most configuration files from conf-available/, which are 24 | # enabled or disabled at a global level, it is possible to 25 | # include a line for only one particular virtual host. For example the 26 | # following line enables the CGI configuration for this host only 27 | # after it has been globally disabled with "a2disconf". 28 | #Include conf-available/serve-cgi-bin.conf 29 | 30 | 31 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet -------------------------------------------------------------------------------- /app2/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | service apache2 start 3 | -------------------------------------------------------------------------------- /app2/html/dbconn.php: -------------------------------------------------------------------------------- 1 | 26 | 27 | 28 | Dom Clobbering Simple Chall! 29 | 43 | 44 | 45 |
46 | 47 | 48 |
49 | 56 |

57 |
58 | 64 |
65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /app2/html/index.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app2/html/prototype_pollution.php: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | Prototype Pollution Simple Chall! 21 | 55 | 56 | 57 |
58 | 59 | 60 |
61 |
62 |
63 | 64 |
65 | 71 |
72 |

73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /app2/html/sqli1.php: -------------------------------------------------------------------------------- 1 | connect_error) { 8 | die("connection fail:" . $mysqli->connect_error); 9 | } 10 | 11 | $query = "SELECT userid FROM sqli1_table where userid='$_GET[userid]' and userpw='$_GET[userpw]'"; 12 | $result = $mysqli->query($query); 13 | $userid = ""; 14 | 15 | if ($result->num_rows > 0) { 16 | while ($row = $result->fetch_assoc()) { 17 | $userid = $row['userid']; 18 | } 19 | } 20 | $mysqli->close(); 21 | 22 | if($userid == "admin"){ 23 | echo file_get_contents('/sqli1_flag.txt'); 24 | } else { 25 | echo $userid; 26 | } 27 | } 28 | ?> 29 |

30 | 31 | -------------------------------------------------------------------------------- /app2/html/sqli2.php: -------------------------------------------------------------------------------- 1 | connect_error) { 17 | die("connection fail:" . $mysqli->connect_error); 18 | } 19 | 20 | $uid = waf($_GET["userid"]); 21 | $upw = waf($_GET["userpw"]); 22 | 23 | $query = "SELECT userid FROM sqli2_table where userid='$uid' and userpw='$upw'"; 24 | $result = $mysqli->query($query); 25 | $userid = ""; 26 | 27 | if ($result->num_rows > 0) { 28 | while ($row = $result->fetch_assoc()) { 29 | $userid = $row['userid']; 30 | break; 31 | } 32 | } 33 | $mysqli->close(); 34 | 35 | if($userid == "admin"){ 36 | echo file_get_contents('/sqli2_flag.txt'); 37 | } else { 38 | echo $userid; 39 | } 40 | } 41 | ?> 42 |

43 | 44 | -------------------------------------------------------------------------------- /app2/html/sqli3.php: -------------------------------------------------------------------------------- 1 | connect_error) { 17 | die("connection fail:" . $mysqli->connect_error); 18 | } 19 | 20 | $uid = waf($_GET["userid"]); 21 | $upw = waf($_GET["userpw"]); 22 | 23 | $query = "SELECT userid FROM sqli3_table where userid='$uid' and userpw='$upw'"; 24 | $result = $mysqli->query($query); 25 | $userid = ""; 26 | 27 | if ($result->num_rows > 0) { 28 | while ($row = $result->fetch_assoc()) { 29 | $userid = $row['userid']; 30 | break; 31 | } 32 | } 33 | $mysqli->close(); 34 | 35 | if($userid == "admin"){ 36 | echo "Hello admin"; 37 | } else { 38 | echo $userid; 39 | } 40 | } 41 | ?> 42 |

43 | 44 | -------------------------------------------------------------------------------- /app2/ports.conf: -------------------------------------------------------------------------------- 1 | # If you just change the port or add more ports here, you will likely also 2 | # have to change the VirtualHost statement in 3 | # /etc/apache2/sites-enabled/000-default.conf 4 | 5 | Listen 9200 6 | 7 | 8 | Listen 443 9 | 10 | 11 | 12 | Listen 443 13 | 14 | 15 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet -------------------------------------------------------------------------------- /app3/000-default.conf: -------------------------------------------------------------------------------- 1 | 2 | # The ServerName directive sets the request scheme, hostname and port that 3 | # the server uses to identify itself. This is used when creating 4 | # redirection URLs. In the context of virtual hosts, the ServerName 5 | # specifies what hostname must appear in the request's Host: header to 6 | # match this virtual host. For the default virtual host (this file) this 7 | # value is not decisive as it is used as a last resort host regardless. 8 | # However, you must set it for any further virtual host explicitly. 9 | #ServerName www.example.com 10 | 11 | ServerAdmin webmaster@localhost 12 | DocumentRoot /var/www/html 13 | 14 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, 15 | # error, crit, alert, emerg. 16 | # It is also possible to configure the loglevel for particular 17 | # modules, e.g. 18 | #LogLevel info ssl:warn 19 | 20 | ErrorLog ${APACHE_LOG_DIR}/error.log 21 | CustomLog ${APACHE_LOG_DIR}/access.log combined 22 | 23 | # For most configuration files from conf-available/, which are 24 | # enabled or disabled at a global level, it is possible to 25 | # include a line for only one particular virtual host. For example the 26 | # following line enables the CGI configuration for this host only 27 | # after it has been globally disabled with "a2disconf". 28 | #Include conf-available/serve-cgi-bin.conf 29 | 30 | 31 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet -------------------------------------------------------------------------------- /app3/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | service apache2 start -------------------------------------------------------------------------------- /app3/html/index.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app3/html/lfi1.php: -------------------------------------------------------------------------------- 1 | 9 |

10 | 11 | -------------------------------------------------------------------------------- /app3/html/lfi2.php: -------------------------------------------------------------------------------- 1 | 11 |

12 | 13 | -------------------------------------------------------------------------------- /app3/html/lfiflag.php: -------------------------------------------------------------------------------- 1 | 8 | Listen 443 9 | 10 | 11 | 12 | Listen 443 13 | 14 | 15 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet -------------------------------------------------------------------------------- /app4/app.py: -------------------------------------------------------------------------------- 1 | #-*-coding:utf-8-*- 2 | import flask 3 | import os, subprocess 4 | 5 | app = flask.Flask(__name__) 6 | app.secret_key = os.urandom(16) 7 | app.config['MAX_CONTENT_LENGTH'] = 80 * 1024 * 1024 8 | 9 | @app.route("/") 10 | def index(): 11 | if "cmd" not in flask.request.args: 12 | with open("app.py","r") as f: 13 | content = f.read() 14 | return content 15 | else: 16 | cmd = flask.request.args["cmd"] 17 | p = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, text=True) 18 | return "!" 19 | 20 | 21 | if __name__ == "__main__": 22 | try: 23 | app.run(host="0.0.0.0", port=9301, debug=True) 24 | except Exception as ex: 25 | logging.info(str(ex)) 26 | pass 27 | -------------------------------------------------------------------------------- /app4/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 /app4/app.py& -------------------------------------------------------------------------------- /app5/app.py: -------------------------------------------------------------------------------- 1 | #-*-coding:utf-8-*- 2 | import flask 3 | import os, subprocess 4 | 5 | app = flask.Flask(__name__) 6 | app.secret_key = os.urandom(16) 7 | app.config['MAX_CONTENT_LENGTH'] = 80 * 1024 * 1024 8 | 9 | @app.route("/") 10 | def index(): 11 | if "name" in flask.request.args: 12 | template =f''' 13 |

hello {flask.request.args['name']}!

14 | ''' 15 | return flask.render_template_string(template) 16 | else: 17 | template = ''' 18 |

hello noname............

19 | ''' 20 | return flask.render_template_string(template) 21 | 22 | 23 | if __name__ == "__main__": 24 | try: 25 | app.run(host="0.0.0.0", port=9302, debug=True) 26 | except Exception as ex: 27 | logging.info(str(ex)) 28 | pass 29 | -------------------------------------------------------------------------------- /app5/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 /app5/app.py& -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | arang_client: 4 | build: ./docker/flask/ 5 | container_name: arang_client 6 | volumes: 7 | - ./app:/app 8 | stdin_open: true 9 | environment: 10 | LC_ALL: C.UTF-8 11 | tty: true 12 | ports: 13 | - "9001-9100:9001-9100" 14 | 15 | arang_client2: 16 | build: ./docker/php/ 17 | container_name: arang_client2 18 | volumes: 19 | - ./app2/:/app2 20 | - ./app2/html/:/var/www/html/ 21 | - ./app2/ports.conf:/etc/apache2/ports.conf 22 | - ./app2/000-default.conf:/etc/apache2/sites-enabled/000-default.conf 23 | stdin_open: true 24 | environment: 25 | LC_ALL: C.UTF-8 26 | tty: true 27 | ports: 28 | - "9200:9200" 29 | 30 | arang_client3: 31 | build: ./docker/php2/ 32 | container_name: arang_client3 33 | volumes: 34 | - ./app3/:/app3 35 | - ./app3/html/:/var/www/html/ 36 | - ./app3/ports.conf:/etc/apache2/ports.conf 37 | - ./app3/000-default.conf:/etc/apache2/sites-enabled/000-default.conf 38 | stdin_open: true 39 | environment: 40 | LC_ALL: C.UTF-8 41 | tty: true 42 | ports: 43 | - "9201:9201" 44 | 45 | arang_client4: 46 | build: ./docker/flask2/ 47 | container_name: arang_client4 48 | volumes: 49 | - ./app4/:/app4 50 | stdin_open: true 51 | environment: 52 | LC_ALL: C.UTF-8 53 | tty: true 54 | ports: 55 | - "9301:9301" 56 | 57 | arang_client5: 58 | build: ./docker/flask3/ 59 | container_name: arang_client5 60 | volumes: 61 | - ./app5/:/app5 62 | stdin_open: true 63 | environment: 64 | LC_ALL: C.UTF-8 65 | tty: true 66 | ports: 67 | - "9302:9302" 68 | 69 | db: 70 | build: ./docker/mysql 71 | container_name: mysql-db 72 | environment: 73 | MYSQL_ROOT_PASSWORD: "mysq1_r00t_p4ssw0rd_d0_n0t_cr4ck_th1s" 74 | volumes: 75 | - "./mysql/:/docker-entrypoint-initdb.d/" 76 | command: mysqld --innodb-buffer-pool-size=16M --character-set-server=utf8 --collation-server=utf8_general_ci -------------------------------------------------------------------------------- /docker/flask/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | WORKDIR /app 3 | RUN apt-get update -y 4 | RUN apt-get install -y curl unzip gnupg xvfb libxi6 libgconf-2-4 default-jdk wget software-properties-common 5 | RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - 6 | RUN echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list 7 | RUN apt-get update -y && apt-get install -y google-chrome-stable 8 | RUN apt-get install -y python3-pip python3-dev build-essential libcurl4-openssl-dev libssl-dev git 9 | RUN apt-get install -y net-tools 10 | RUN apt-get install -y procps 11 | RUN pip3 install pycurl pymysql flask requests selenium 12 | RUN pip3 install git+https://github.com/SergeyPirogov/webdriver_manager 13 | 14 | ENV admin_password [redacted] 15 | 16 | ENV xss1_flag flag{[redacted]} 17 | ENV xss2_flag flag{[redacted]} 18 | ENV xss3_flag flag{[redacted]} 19 | ENV csrf1_flag flag{[redacted]} 20 | ENV csrf2_flag flag{[redacted]} 21 | ENV xsleak_flag flag{[redacted]} 22 | 23 | 24 | ENTRYPOINT /app/entrypoint.sh && /bin/bash 25 | CMD ["true"] 26 | -------------------------------------------------------------------------------- /docker/flask2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | WORKDIR /app4 3 | RUN apt-get update -y 4 | RUN apt-get install -y curl unzip gnupg xvfb libxi6 libgconf-2-4 default-jdk wget software-properties-common 5 | RUN apt-get install -y python3-pip python3-dev build-essential libcurl4-openssl-dev libssl-dev 6 | RUN apt-get install -y net-tools vim procps 7 | RUN pip3 install pycurl flask requests 8 | 9 | COPY flags/command_injection_flag.txt /command_injection_flag.txt 10 | RUN chmod 444 /command_injection_flag.txt 11 | 12 | RUN groupadd -g 999 user 13 | RUN useradd -r -u 999 -g user user 14 | USER user 15 | RUN python3 /app4/app.py& 16 | 17 | ENTRYPOINT /app4/entrypoint.sh && /bin/bash 18 | CMD ["true"] 19 | -------------------------------------------------------------------------------- /docker/flask2/flags/command_injection_flag.txt: -------------------------------------------------------------------------------- 1 | flag{[REDACTED]} -------------------------------------------------------------------------------- /docker/flask3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | WORKDIR /app5 3 | RUN apt-get update -y 4 | RUN apt-get install -y curl unzip gnupg xvfb libxi6 libgconf-2-4 default-jdk wget software-properties-common 5 | RUN apt-get install -y python3-pip python3-dev build-essential libcurl4-openssl-dev libssl-dev 6 | RUN apt-get install -y net-tools vim procps 7 | RUN pip3 install pycurl flask requests 8 | 9 | COPY flags/ssti_flag.txt /ssti_flag.txt 10 | RUN chmod 444 /ssti_flag.txt 11 | 12 | RUN groupadd -g 999 user 13 | RUN useradd -r -u 999 -g user user 14 | USER user 15 | RUN python3 /app5/app.py& 16 | 17 | ENTRYPOINT /app5/entrypoint.sh && /bin/bash 18 | CMD ["true"] 19 | -------------------------------------------------------------------------------- /docker/flask3/flags/ssti_flag.txt: -------------------------------------------------------------------------------- 1 | flag{[REDACTED]} -------------------------------------------------------------------------------- /docker/mysql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mysql:5.7 -------------------------------------------------------------------------------- /docker/php/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.2-apache-bullseye 2 | WORKDIR /app2 3 | RUN apt-get update -y 4 | RUN apt-get install -y curl unzip gnupg xvfb libxi6 libgconf-2-4 default-jdk wget software-properties-common 5 | RUN apt-get install -y python3-pip python3-dev build-essential libcurl4-openssl-dev libssl-dev git 6 | RUN apt-get install -y net-tools 7 | RUN apt-get install -y procps 8 | RUN docker-php-ext-install mysqli 9 | 10 | COPY flags/domclobbering_flag.txt /domclobbering_flag.txt 11 | RUN chmod 444 /domclobbering_flag.txt 12 | 13 | COPY flags/sqli1_flag.txt /sqli1_flag.txt 14 | RUN chmod 444 /sqli1_flag.txt 15 | 16 | COPY flags/sqli2_flag.txt /sqli2_flag.txt 17 | RUN chmod 444 /sqli2_flag.txt 18 | 19 | COPY flags/pp_flag.txt /pp_flag.txt 20 | RUN chmod 444 /pp_flag.txt 21 | 22 | RUN groupadd -g 999 user 23 | RUN useradd -r -u 999 -g user user 24 | USER user 25 | 26 | ENTRYPOINT /app2/entrypoint.sh && /bin/bash 27 | CMD ["true"] 28 | -------------------------------------------------------------------------------- /docker/php/flags/domclobbering_flag.txt: -------------------------------------------------------------------------------- 1 | flag{[REDACTED]} 2 | -------------------------------------------------------------------------------- /docker/php/flags/pp_flag.txt: -------------------------------------------------------------------------------- 1 | flag{[REDACTED]} -------------------------------------------------------------------------------- /docker/php/flags/sqli1_flag.txt: -------------------------------------------------------------------------------- 1 | flag{[REDACTED]} 2 | -------------------------------------------------------------------------------- /docker/php/flags/sqli2_flag.txt: -------------------------------------------------------------------------------- 1 | flag{[REDACTED]} 2 | -------------------------------------------------------------------------------- /docker/php2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.2-apache-bullseye 2 | WORKDIR /app3 3 | RUN apt-get update -y 4 | RUN apt-get install -y curl unzip gnupg xvfb libxi6 libgconf-2-4 default-jdk wget software-properties-common 5 | RUN apt-get install -y python3-pip python3-dev build-essential libcurl4-openssl-dev libssl-dev git gcc 6 | RUN apt-get install -y net-tools procps vim 7 | COPY flags/readflag.c /app3/readflag.c 8 | RUN gcc -o /readflag /app3/readflag.c 9 | RUN chmod 111 /readflag 10 | 11 | RUN groupadd -g 999 user 12 | RUN useradd -r -u 999 -g user user 13 | USER user 14 | 15 | ENTRYPOINT /app3/entrypoint.sh && /bin/bash 16 | CMD ["true"] 17 | -------------------------------------------------------------------------------- /docker/php2/flags/readflag.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]){ 5 | puts("flag{[REDACTED]}"); 6 | } -------------------------------------------------------------------------------- /mysql/init.sql: -------------------------------------------------------------------------------- 1 | SET collation_connection = 'utf8_general_ci'; 2 | 3 | #drop database fsi; 4 | create database fsi; 5 | ALTER DATABASE fsi CHARACTER SET utf8 COLLATE utf8_general_ci; 6 | 7 | use fsi; 8 | 9 | #drop table sqli1_table; 10 | 11 | create user 'sqli1'@'%' identified by '[REDACTED]'; 12 | create user 'sqli2'@'%' identified by '[REDACTED]'; 13 | create user 'sqli3'@'%' identified by '[REDACTED]'; 14 | 15 | create table sqli1_table( 16 | userseq int not null auto_increment primary key, 17 | userid varchar(50) not null, 18 | userpw varchar(255) not null 19 | ); 20 | 21 | create table sqli2_table( 22 | userseq int not null auto_increment primary key, 23 | userid varchar(50) not null, 24 | userpw varchar(255) not null 25 | ); 26 | 27 | create table sqli3_table( 28 | userseq int not null auto_increment primary key, 29 | userid varchar(50) not null, 30 | userpw varchar(255) not null 31 | ); 32 | 33 | 34 | ALTER TABLE sqli1_table CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; 35 | ALTER TABLE sqli2_table CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; 36 | ALTER TABLE sqli3_table CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; 37 | 38 | insert into sqli1_table (userid, userpw) values ("guest","guest"), ("admin", "[REDACTED]"); 39 | insert into sqli2_table (userid, userpw) values ("guest","guest"), ("admin", "[REDACTED]"); 40 | insert into sqli3_table (userid, userpw) values ("guest","guest"), ("admin", "flag{[REDACTED]}"); 41 | 42 | grant select on fsi.sqli1_table to 'sqli1'@'%'; 43 | grant select on fsi.sqli2_table to 'sqli2'@'%'; 44 | grant select on fsi.sqli3_table to 'sqli3'@'%'; 45 | 46 | 47 | flush privileges; --------------------------------------------------------------------------------