def create(): # ---------Level Initialization--------- # Create randomized bucket name to avoid namespace conflict nonce = str(random.randint(100000000000, 999999999999)) bucket_name = f'{RESOURCE_PREFIX}-bucket-{nonce}' # -------------------------------------- # ---------Deployment Insertion--------- # Insert deployment config_template_args = {'nonce': nonce} template_files = ['core/framework/templates/bucket_acl.jinja'] deployments.insert(LEVEL_PATH, template_files=template_files, config_template_args=config_template_args) # -------------------------------------- # --------------Level Setup------------- print("Level setup started for: " + LEVEL_PATH) # Insert secret into bucket storage_client = storage.Client() bucket = storage_client.get_bucket(bucket_name) secret_blob = storage.Blob('secret.txt', bucket) secret = levels.make_secret(LEVEL_PATH) secret_blob.upload_from_string(secret) # Print complete message and print/save start info print( f'Level creation complete for: {LEVEL_PATH}\n' f'Instruction for the level can be accessed at thunder-ctf.cloud/thunder/{LEVEL_PATH}.html' ) start_message = f'The secret for this level can be found in the Google Cloud Storage (GCS) bucket {bucket_name}' levels.write_start_info(LEVEL_PATH, start_message)
def create(second_deploy=True): # Create randomized bucket name to avoid namespace conflict nonce = str(random.randint(100000000000, 999999999999)) bucket_name = f'{RESOURCE_PREFIX}-bucket-{nonce}' # Set role of default cloud function account credentials, project_id = google.auth.default() func_upload_url = cloudfunctions.upload_cloud_function( f'core/levels/{LEVEL_PATH}/function', FUNCTION_LOCATION) print("Level initialization finished for: " + LEVEL_PATH) # Insert deployment config_template_args = {'nonce': nonce, 'func_upload_url': func_upload_url} template_files = [ 'core/framework/templates/service_account.jinja', 'core/framework/templates/cloud_function.jinja', 'core/framework/templates/iam_policy.jinja', 'core/framework/templates/bucket_acl.jinja'] if second_deploy: deployments.insert(LEVEL_PATH, template_files=template_files, config_template_args=config_template_args, second_deploy=True) else: deployments.insert(LEVEL_PATH, template_files=template_files, config_template_args=config_template_args) try: print("Level setup started for: " + LEVEL_PATH) # Allow player to use cloud function's service account iam_api = discovery.build('iam', 'v1', credentials=credentials) policy_body = {"policy": { "bindings": [{ "members": [f"serviceAccount:a5-access@{project_id}.iam.gserviceaccount.com"], "role": "roles/iam.serviceAccountUser"}]}} iam_api.projects().serviceAccounts().setIamPolicy( resource=f'projects/{project_id}/serviceAccounts/a5-func-{nonce}-sa@{project_id}.iam.gserviceaccount.com', body=policy_body).execute() # Insert secret into bucket storage_client = storage.Client() bucket = storage_client.get_bucket(bucket_name) secret_blob = storage.Blob('secret.txt', bucket) secret = levels.make_secret(LEVEL_PATH) secret_blob.upload_from_string(secret) # Create service account key file sa_key = iam.generate_service_account_key(f'{RESOURCE_PREFIX}-access') print(f'Level creation complete for: {LEVEL_PATH}') start_message = ( f'Use the compromised service account credentials stored in {RESOURCE_PREFIX}-access.json to find the secret, ' 'which is located in a file called secret.txt in a private bucket on the project.') levels.write_start_info( LEVEL_PATH, start_message, file_name=f'{RESOURCE_PREFIX}-access.json', file_content=sa_key) print( f'Instruction for the level can be accessed at thunder-ctf.cloud/thunder/{LEVEL_PATH}.html') except Exception as e: exit()
def create(): print("Level initialization started for: " + LEVEL_PATH) # Create randomized nonce name to avoid namespace conflicts nonce = str(random.randint(100000000000, 999999999999)) bucket_name = f'{RESOURCE_PREFIX}-bucket-{nonce}' print("Level initialization finished for: " + LEVEL_PATH) # Insert deployment config_template_args = {'nonce': nonce} template_files = [ 'core/framework/templates/bucket_acl.jinja', 'core/framework/templates/service_account.jinja', 'core/framework/templates/iam_policy.jinja', 'core/framework/templates/container_vm.jinja' ] deployments.insert(LEVEL_PATH, template_files=template_files, config_template_args=config_template_args) print("Level setup started for: " + LEVEL_PATH) # Insert secret into bucket storage_client = storage.Client() bucket = storage_client.get_bucket(bucket_name) secret_blob = storage.Blob('secret.txt', bucket) secret = levels.make_secret(LEVEL_PATH) secret_blob.upload_from_string(secret) # Create service account key file sa_key = iam.generate_service_account_key(f'{RESOURCE_PREFIX}-access') print(f'Level creation complete for: {LEVEL_PATH}') start_message = ( f'Use the compromised service account credentials stored in {RESOURCE_PREFIX}-access.json to find the secret, ' 'which is located in a file called secret.txt in a private bucket on the project.' ) levels.write_start_info(LEVEL_PATH, start_message, file_name=f'{RESOURCE_PREFIX}-access.json', file_content=sa_key) print( f'Instruction for the level can be accessed at thunder-ctf.cloud/thunder/{LEVEL_PATH}.html' )
def create_logs(): # Load list of framework names with open(f'core/levels/{LEVEL_PATH}/first-names.txt') as f: first_names = f.read().split('\n') with open(f'core/levels/{LEVEL_PATH}/last-names.txt') as f: last_names = f.read().split('\n') # Randomly determine a name associated with the secret secret_name = (first_names[random.randint(0, 199)] + '_' + last_names[random.randint(0, 299)]) # Randomly determine an index of logging of the secret transaction secret_position = random.randint(0, 99) logger = glogging.Client().logger(LOG_NAME) for i in range(0, 100): # On secret index, log the transaction with the secret as the credit card number of the struct if i == secret_position: logger.log_struct({ 'name': secret_name, 'transaction-total': f'${random.randint(1,300)}.{random.randint(0,9)}{random.randint(0,9)}', 'credit-card-number': levels.make_secret(LEVEL_PATH, 16) }) else: # For the other entities, determine a random name name = (first_names[random.randint(0, 199)] + '_' + last_names[random.randint(0, 299)]) # If the name is not equal to the secret name, log the transaction with a random credit card number if not name == secret_name: logger.log_struct({ 'name': name, 'transaction-total': f'${random.randint(1,150)}.{random.randint(1,99)}', 'credit-card-number': str(random.randint(1000000000000000, 9999999999999999)) }) return secret_name.replace('_', ' ')
def create(second_deploy=True): # Create randomized bucket name to avoid namespace conflict nonce = str(random.randint(100000000000, 999999999999)) nonce_file = f'core/levels/{LEVEL_PATH}/nonce.txt' #write key file in function directory with open(nonce_file, 'w') as f: f.write(nonce) os.chmod(nonce_file, 0o700) print(f'Nonce {nonce} has been written to {nonce_file}') # Set role of default cloud function account credentials, project_id = google.auth.default() print("Level initialization finished for: " + LEVEL_PATH) # Insert deployment config_template_args = {'nonce': nonce} template_files = [ 'core/framework/templates/service_account.jinja', 'core/framework/templates/iam_policy.jinja', 'core/framework/templates/bucket_acl.jinja', 'core/framework/templates/ubuntu_vm.jinja', 'core/framework/templates/cloud_function.jinja' ] print("Level setup started for: " + LEVEL_PATH) start_message = ' Use function entrypoints below to access levels \n\n' for RESOURCE_PREFIX in LEVEL_NAMES: LEVEL_NAME = LEVEL_NAMES[RESOURCE_PREFIX] fvar = FARS[RESOURCE_PREFIX] func_patha = f'core/levels/{LEVEL_PATH}/{RESOURCE_PREFIX}/functionaccess' func_pathc = f'core/levels/{LEVEL_PATH}/{RESOURCE_PREFIX}/functioncheck' #Generate function urls func_template_argc = {'fvar': fvar} func_upload_urla = cloudfunctions.upload_cloud_function( func_patha, FUNCTION_LOCATION) func_upload_urlc = cloudfunctions.upload_cloud_function( func_pathc, FUNCTION_LOCATION, template_args=func_template_argc) #Update deployment with functions config_template_args_patch = { f'funca_upload_url_{RESOURCE_PREFIX}': func_upload_urla, f'funcc_upload_url_{RESOURCE_PREFIX}': func_upload_urlc, f'level_name_{RESOURCE_PREFIX}': LEVEL_NAME, f'resource_prefix_{RESOURCE_PREFIX}': RESOURCE_PREFIX } config_template_args.update(config_template_args_patch) msg = f'https://{FUNCTION_LOCATION}-{project_id}.cloudfunctions.net/{RESOURCE_PREFIX}-f-access-{nonce} {LEVEL_NAMES[RESOURCE_PREFIX]}' start_message += msg + '\n' # scores funciton func_pathsc = f'core/levels/{LEVEL_PATH}/scores' #Generate scores function urls func_template_arg = {'anws': FARS, 'level_names': LEVEL_NAMES} func_upload_urlsc = cloudfunctions.upload_cloud_function( func_pathsc, FUNCTION_LOCATION, template_args=func_template_arg) login_user = os.environ.get('USER', 'USER is not set.') #Update deployment with functions config_template_args_patch = { 'funcc_upload_url_scores': func_upload_urlsc, 'login_user': login_user } config_template_args.update(config_template_args_patch) msg = f'https://{FUNCTION_LOCATION}-{project_id}.cloudfunctions.net/scores-f-{nonce}' start_message += '\n Or access levels through Score Board: \n' + msg + '\n' if second_deploy: deployments.insert(LEVEL_PATH, template_files=template_files, config_template_args=config_template_args, second_deploy=True) else: deployments.insert(LEVEL_PATH, template_files=template_files, config_template_args=config_template_args) try: # Insert secret into bucket storage_client = storage.Client() for b in BUCKETS: bucket_name = f'{b}-bucket-{nonce}' secret = levels.make_secret(LEVEL_PATH) bucket = storage_client.get_bucket(bucket_name) secret_blob = storage.Blob(f'secret_{b}.txt', bucket) secret_blob.upload_from_string(secret) # Create and insert data in datastore for k in KINDS: entities = [{ 'name': f'admin-{k}', 'password': '******', 'active': True }, { 'name': f'editor-{k}', 'password': '******', 'active': True }] kind = f'{k}-{nonce}-{project_id}' client = datastore.Client(project_id) for entity in entities: entity_key = client.key(kind) task = datastore.Entity(key=entity_key) task.update(entity) client.put(task) #print(f'Datastore {kind} created') levels.write_start_info(LEVEL_PATH, start_message) except Exception as e: exit()
def create(second_deploy=True): print("Level initialization started for: " + LEVEL_PATH) # Create randomized nonce name to avoid namespace conflicts nonce = str(random.randint(100000000000, 999999999999)) bucket_name = f'{RESOURCE_PREFIX}-bucket-{nonce}' # Create random function password func_xor_password = str(random.randint(100000000000, 999999999999)) xor_factor = str(random.randint(100000000000, 999999999999)) func_template_args = {'bucket_name': bucket_name, 'xor_factor': xor_factor} # Upload function and get upload url func_upload_url = cloudfunctions.upload_cloud_function( f'core/levels/{LEVEL_PATH}/function', FUNCTION_LOCATION, template_args=func_template_args) print("Level initialization finished for: " + LEVEL_PATH) # Insert deployment config_template_args = { 'nonce': nonce, 'func_xor_password': func_xor_password, 'func_upload_url': func_upload_url } template_files = [ 'core/framework/templates/bucket_acl.jinja', 'core/framework/templates/cloud_function.jinja', 'core/framework/templates/service_account.jinja', 'core/framework/templates/iam_policy.jinja' ] if second_deploy: deployments.insert(LEVEL_PATH, template_files=template_files, config_template_args=config_template_args, second_deploy=True) else: deployments.insert(LEVEL_PATH, template_files=template_files, config_template_args=config_template_args) try: print("Level setup started for: " + LEVEL_PATH) # Insert secret into bucket storage_client = storage.Client() bucket = storage_client.get_bucket(bucket_name) secret_blob = storage.Blob('secret.txt', bucket) secret = levels.make_secret(LEVEL_PATH) secret_blob.upload_from_string(secret) # Create service account key file sa_key = iam.generate_service_account_key(f'{RESOURCE_PREFIX}-access') print(f'Level creation complete for: {LEVEL_PATH}') start_message = ( f'Use the given compromised credentials to find the secret hidden in the level.' ) levels.write_start_info(LEVEL_PATH, start_message, file_name=f'{RESOURCE_PREFIX}-access.json', file_content=sa_key) print( f'Instruction for the level can be accessed at thunder-ctf.cloud/thunder/{LEVEL_PATH}.html' ) except Exception as e: exit()
def create(second_deploy=True): print("Level initialization started for: " + LEVEL_PATH) # Create randomized nonce name to avoid namespace conflicts nonce = str(random.randint(100000000000, 999999999999)) bucket_name = f'{RESOURCE_PREFIX}-bucket-{nonce}' func_template_args = {'bucket_name': bucket_name} # Upload function and get upload url func_upload_url = cloudfunctions.upload_cloud_function( f'core/levels/{LEVEL_PATH}/function', FUNCTION_LOCATION, template_args=func_template_args) print("Level initialization finished for: " + LEVEL_PATH) secret = levels.make_secret(LEVEL_PATH) # Insert deployment config_template_args = { 'nonce': nonce, 'secret': secret, 'func_upload_url': func_upload_url } template_files = [ 'core/framework/templates/bucket_acl.jinja', 'core/framework/templates/cloud_function.jinja', 'core/framework/templates/service_account.jinja', 'core/framework/templates/iam_policy.jinja', 'core/framework/templates/ubuntu_vm.jinja' ] if second_deploy: deployments.insert(LEVEL_PATH, template_files=template_files, config_template_args=config_template_args, second_deploy=True) else: deployments.insert(LEVEL_PATH, template_files=template_files, config_template_args=config_template_args) try: print("Level setup started for: " + LEVEL_PATH) # Insert dummy files into bucket gcstorage.upload_directory_recursive( f'core/levels/{LEVEL_PATH}/bucket', bucket_name) # Delete startup script that contains secret from instance metadata credentials, project_id = google.auth.default() compute_api = discovery.build('compute', 'v1', credentials=credentials) instance_info = compute_api.instances().get( project=project_id, zone=INSTANCE_ZONE, instance=f'{RESOURCE_PREFIX}-instance').execute() metadata_fingerprint = instance_info['metadata']['fingerprint'] set_metadata_body = {'fingerprint': metadata_fingerprint, 'items': []} compute_api.instances().setMetadata( project=project_id, zone=INSTANCE_ZONE, instance=f'{RESOURCE_PREFIX}-instance', body=set_metadata_body).execute() # Create service account key file sa_key = iam.generate_service_account_key(f'{RESOURCE_PREFIX}-access') print(f'Level creation complete for: {LEVEL_PATH}') start_message = ( f'In this level, look for a file named "secret.txt," which is owned by "secretuser." ' 'Use the given compromised credentials to find it.') levels.write_start_info(LEVEL_PATH, start_message, file_name=f'{RESOURCE_PREFIX}-access.json', file_content=sa_key) print( f'Instruction for the level can be accessed at thunder-ctf.cloud/thunder/{LEVEL_PATH}.html' ) except Exception as e: exit()