Example #1
0
def create():
    # Don't deploy the template. Delete this line when you implement your level.
    exit('This is a template file. It is not meant to be deployed.')

    # ---------Level Initialization---------
    # Put code here that generates anything passed to the configuration template,
    # sets up the project before deployment, or does anything else that happens
    # before the deployment gets inserted.

    # --------------------------------------

    # ---------Deployment Insertion---------
    # Insert the deployment, filling out labels, config template arguments,
    # and the deployment manager template imports.
    config_template_args = {}
    labels = {}
    template_files = []
    deployments.insert(LEVEL_PATH,
                       config_template_args=config_template_args,
                       labels=labels,
                       template_files=template_files)
    # --------------------------------------

    # --------------Level Setup-------------
    # Put code here that does anything that needs to happen after the deployment.
    # This includes usings APIs to modify deployed resources or anything else.

    # 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 '
          f'thunder-ctf.cloud/levels/{LEVEL_PATH}.html')
    start_message = '--Put the start message here.--'
    levels.write_start_info(LEVEL_PATH, start_message)
Example #2
0
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)
Example #3
0
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}'

    # Create ssh key
    ssh_private_key, ssh_public_key = ssh_keys.generate_ssh_keypair()
    ssh_username = "******"

    try:
        # Construct git repo
        repo_path = os.path.dirname(os.getcwd()) + "/temp-repository-" + nonce
        create_repo_files(repo_path, ssh_private_key)
        print("Level initialization finished for: " + LEVEL_PATH)

        # Insert deployment
        config_template_args = {
            'nonce': nonce,
            'ssh_public_key': ssh_public_key,
            'ssh_username': ssh_username
        }
        template_files = [
            'core/framework/templates/bucket_acl.jinja',
            'core/framework/templates/ubuntu_vm.jinja',
            'core/framework/templates/service_account.jinja',
            'core/framework/templates/iam_policy.jinja'
        ]
        deployments.insert(LEVEL_PATH,
                           template_files=template_files,
                           config_template_args=config_template_args)

        print("Level setup started for: " + LEVEL_PATH)
        # Upload repository to bucket
        gcstorage.upload_directory_recursive(repo_path, bucket_name)

        # Create logs
        secret_name = create_logs()

        # 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 credit card number of {secret_name}, '
            'which is hidden somewhere in the GCP 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'
        )
    finally:
        # If there is an error, make sure to delete the temporary repository before exiting
        if os.path.exists(repo_path):
            shutil.rmtree(repo_path)
Example #4
0
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()
Example #5
0
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'
    )
Example #6
0
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()
Example #7
0
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()
Example #8
0
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()
Example #9
0
def create(second_deploy=True):
    bar = ProgBar()
    print("\nLevel initialization started for: " + LEVEL_PATH)

    nonce = str(random.randint(100000000000, 999999999999))
    credentials, project_id = google.auth.default()

    #the cloud function may need to know information about the vm in order to hit our API. put that info here.
    func_template_args = {}

    func_upload_url = cloudfunctions.upload_cloud_function(
        f'core/levels/{LEVEL_PATH}/resources/rmUser',
        FUNCTION_LOCATION,
        template_args=func_template_args)

    # Create database password value
    db_secret_value = ''
    for _ in range(0, 64):
        db_secret_value += random.choice(string.ascii_letters + string.digits)
    create_secret(DB_SECRET_ID, db_secret_value)

    config_template_args = {
        'nonce': nonce,
        'root_password': db_secret_value,
        'func_upload_url': func_upload_url
    }

    template_files = [
        'core/framework/templates/service_account.jinja',
        'core/framework/templates/iam_policy.jinja',
        'core/framework/templates/sql_db.jinja',
        'core/framework/templates/container_vm.jinja',
        'core/framework/templates/bucket_acl.jinja',
        'core/framework/templates/cloud_function.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)

    print("\nLevel setup started for: " + LEVEL_PATH)

    bar.tick('Creating database tables')
    create_tables(db_secret_value)

    dev_key = iam.generate_service_account_key('dev-account')
    dev_sa = service_account.Credentials.from_service_account_info(
        json.loads(dev_key))
    compute_admin_key = iam.generate_service_account_key('compute-admin')
    logging_key = iam.generate_service_account_key('log-viewer')

    # add vm files to bucket
    bar.tick('Uploading container source to bucket')
    storage_client = storage.Client()
    vm_image_bucket = storage_client.get_bucket(f'vm-image-bucket-{nonce}')
    gcstorage.upload_directory_recursive(
        f'core/levels/{LEVEL_PATH}/resources/api-engine',
        f'vm-image-bucket-{nonce}')
    storage_blob = storage.Blob('compute-admin.json', vm_image_bucket)
    storage_blob.upload_from_string(compute_admin_key)

    bar.tick('Creating developer logs')
    #os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'start/dev-account.json'
    url = "http://us-central1-" + project_id + ".cloudfunctions.net/rm-user-" + nonce

    req = google.auth.transport.requests.Request()
    id_token = google.oauth2.id_token.fetch_id_token(req, url)
    headers = {'Authorization': f"Bearer {id_token}"}
    data = {'name': 'Robert Caldwell', 'authentication': dev_key}
    resp = req(url, method='POST', body=data, headers=headers)

    bar.tick('Starting exploit script')
    hostname = exploit(nonce, logging_key, bar)
    hack(hostname)
    bar.tick('Exploit complete')

    print(f'\nLevel creation complete for: {LEVEL_PATH}')
    start_message = (
        'Nefarious statuses are being posted by accounts without the owner\'s knowledge. Find out how this is happening. \nInstructions for each level can be found at: https://asokamoto.github.io/CloudAuditCTFs/'
    )
    levels.write_start_info(LEVEL_PATH, start_message)