├── .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 |
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 |
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 |
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 |
31 |
32 |
33 |
34 |
Change Password
35 |
46 |
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 |
31 |
32 |
33 |
34 |
Sign In
35 |
53 |
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 |
31 |
32 |
33 |
34 |
Register
35 |
46 |
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 | {{articles['subject']}}
33 |
34 |
35 |
36 |
37 | 글쓴이
38 |
39 |
40 | {{articles['author']}}
41 |
42 |
43 |
44 |
45 |
46 | {{articles['content']|safe}}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | 목록
59 | 글쓰기
60 |
61 |
62 |
63 |
64 |
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 |
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 | {{i['seq']}}
42 | {{i['subject']}}
43 | {{i['author']}}
44 |
45 | {% endfor %}
46 |
47 |
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 |
31 |
32 |
33 |
34 |
Change Password
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Change Password
44 |
45 |
46 |
47 |
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 |
31 |
32 |
33 |
34 |
Sign In
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Login
44 |
45 |
52 |
53 |
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 |
31 |
32 |
33 |
34 |
Register
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Register
44 |
45 |
46 |
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 | {{articles['subject']}}
33 |
34 |
35 |
36 |
37 | 글쓴이
38 |
39 |
40 | {{articles['author']}}
41 |
42 |
43 |
44 |
45 |
46 | {{articles['content']|safe}}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | 목록
59 | 글쓰기
60 |
61 |
62 |
63 |
64 |
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 |
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 | {{i['seq']}}
42 | {{i['subject']}}
43 | {{i['author']}}
44 |
45 | {% endfor %}
46 |
47 |
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 |
31 |
32 |
33 |
34 |
Sign In
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Login
44 |
45 |
52 |
53 |
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 |
31 |
32 |
33 |
34 |
Register
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Register
44 |
45 |
46 |
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 | {{articles['subject']}}
34 |
35 |
36 |
37 |
38 | 글쓴이
39 |
40 |
41 | {{articles['author']}}
42 |
43 |
44 |
45 |
46 |
47 | {{articles['content']|safe}}
48 | flag!
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | 목록
60 | 글쓰기
61 |
62 |
63 |
64 |
65 |
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 |
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 | {{i['seq']}}
42 | {{i['subject']}}
43 | {{i['author']}}
44 |
45 | {% endfor %}
46 |
47 |
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 |
31 |
32 |
33 |
34 |
Sign In
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Login
44 |
45 |
52 |
53 |
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 |
31 |
32 |
33 |
34 |
Register
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Register
44 |
45 |
46 |
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 | {{articles['subject']}}
33 |
34 |
35 |
36 |
37 | 글쓴이
38 |
39 |
40 | {{articles['author']}}
41 |
42 |
43 |
44 |
45 |
46 | {{articles['content']|safe}}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | 목록
59 | 글쓰기
60 |
61 |
62 |
63 |
64 |
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 |
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 | {{i['seq']}}
42 | {{i['subject']}}
43 | {{i['author']}}
44 |
45 | {% endfor %}
46 |
47 |
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 |
31 |
32 |
33 |
34 |
Sign In
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Login
44 |
45 |
52 |
53 |
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 |
31 |
32 |
33 |
34 |
Register
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Register
44 |
45 |
46 |
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 | {{articles['subject']}}
33 |
34 |
35 |
36 |
37 | 글쓴이
38 |
39 |
40 | {{articles['author']}}
41 |
42 |
43 |
44 |
45 |
46 | {{articles['content']|safe}}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | 목록
59 | 글쓰기
60 |
61 |
62 |
63 |
64 |
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 |
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 | {{i['seq']}}
42 | {{i['subject']}}
43 | {{i['author']}}
44 |
45 | {% endfor %}
46 |
47 |
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 |
31 |
32 |
33 |
34 |
Sign In
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Login
44 |
45 |
52 |
53 |
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 |
31 |
32 |
33 |
34 |
Register
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Register
44 |
45 |
46 |
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 | {{articles['subject']}}
33 |
34 |
35 |
36 |
37 | 글쓴이
38 |
39 |
40 | {{articles['author']}}
41 |
42 |
43 |
44 |
45 |
46 | {{articles['content']|safe}}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | 목록
59 | 글쓰기
60 |
61 |
62 |
63 |
64 |
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 |
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 | {{i['seq']}}
42 | {{i['subject']}}
43 | {{i['author']}}
44 |
45 | {% endfor %}
46 |
47 |
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 |
31 |
32 |
33 |
34 |
Sign In
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Login
44 |
45 |
52 |
53 |
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 | {{i['seq']}}
51 | {{i['challenge']}}
52 | {{i['link']}}
53 | {% if i['solved'] == True %}
54 | ✅
55 | {% else %}
56 | ❌
57 | {% endif %}
58 |
59 | {% endfor %}
60 |
61 |
62 |
63 |
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 | {{ loop.index }}
38 | {{ item.keys()|first }}
39 | {{ (item.values()|first)['solved']|join(', ') }}
40 |
41 | {% endfor %}
42 |
43 |
44 |
45 |
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 |
31 |
32 |
33 |
34 |
Register
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Register
44 |
45 |
46 |
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;
--------------------------------------------------------------------------------