read

Leveraging ansible and powershell together for remote management.

Install

sudo yum install -y python3 python3-pip
sudo alternatives --set python /usr/bin/python3
pip3 install ansible --user

Test PS-Remoting

$pwd = ConvertTo-SecureString -String 'P@@@ssword54321' -AsPlainText -Force
$psCredential = New-Object System.Management.Automation.PSCredential('jmpesp\administrator',$pwd)

Test-WSMan -ComputerName "file4.jmpesp.xyz" -Credential $psCredential -Authentication Negotiate

Configure Ansible Client on the Remote Host

$winHostSession = New-PSSession "file4.jmpesp.xyz" -Credential $psCredential

$scriptBlock = {
      $url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
      $file = "$env:temp\ConfigureRemotingForAnsible.ps1"
      (New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)
      & $file
      winrm set winrm/config/service '@{AllowUnencrypted="true"}'
}
Invoke-Command -Session $winHostSession -ScriptBlock $scriptBlock

Configure Ansible Server

Configure the hosts file:

sudo mkdir /etc/ansible && cd /etc/ansible
sudo touch hosts

Add hosts in this format:

[windows]
file4.jmpesp.xyz

Add configuration for windows connections to hosts in this format (windows is the group name shown in the previous example)

[windows:vars]
ansible_user=administrator@JMPESP.XYZ
ansible_password=P@ssw0rd123
ansible_connection=winrm
ansible_winrm_transport=kerberos
ansible_port=5985

You might need the kerberos client

yum -y install python-devel krb5-devel krb5-libs krb5-workstation

And if you do, you’ll also need to add the python-kerberos wrapper for ansible

pip install pywinrm[kerberos]

Some things you might need if the above errors out:

sudo yum install gcc
sudo yum install python3-devel
sudo yum install krb5-devel

Test with

ansible windows -m win_ping

where “windows” is the group name from above and win_ping is an ansible module that does what you’d expect.

If it fails with:

file4=10.0.0.150 | FAILED! => {
    "msg": "winrm or requests is not installed: No module named 'winrm'"
}

You probably need to install the winrm module using: sudo pip install pywinrm

Then you should see:

file4.jmpesp.xyz | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Execute PowerShell on hosts via Ansible

Example:

ansible windows -m win_shell -a "get-Service"

Where “windows” is the group name i specified above.

Or, create a scripts folder

sudo mkdir scripts
sudo chown scripts/

Create a simple script for testing on windows admin machine:

Set-Content script1.ps1 -Value 'Get-Service -Name wuauserv | Start-Service'

Copy it to the ansible host:

scp script1.ps1 chad@centos`:/etc/ansible/scripts

On the ansible host, use win_copy module to deploy the script:

[chad@localhost ~]$ ansible windows -m win_copy -a "src=/etc/ansible/scripts/script1.ps1 dest=c:\script.ps1"
file4.jmpesp.xyz | CHANGED => {
    "changed": true,
    "checksum": "e7117f64e52ee17063f9339c4aab9d7ef4ad77f8",
    "dest": "c:\\script.ps1",
    "operation": "file_copy",
    "original_basename": "script1.ps1",
    "size": 44,
    "src": "/etc/ansible/scripts/script1.ps1"
}

Run it:

[chad@localhost ~]$ ansible windows -m win_command -a "powershell.exe -ExecutionPolicy bypass -file c:\script.ps1"
file4.jmpesp.xyz | CHANGED | rc=0 >>

Runbook

The real power of ansible.

We create a playbooks folder in the ansible directory on the ansible host to store the playbooks, then use SCP to copy it from our administrative machine to the ansible host.

Sample:

- name: IIS
  hosts: windows
  tasks:
  - name: create folder
    win_file:
      path: C:\iis
      state: directory

  - name: create html page
    win_copy:
      content: |
        <html>
        <head><title>Ansible Test</title></head>
        <body>Some Things</body>
        </html>
      dest: C:\iis\index.html

  - name: install IIS features
    win_feature:
      name: Web-Server
      state: present
      include_sub_features: yes
      include_management_tools: no

  - name: remove default website
    win_iis_website:
      name: Default Web Site
      state: absent

  - name: create new IIS website
    win_iis_website:
      name: IIS Demo
      state: started
      port: 8080
      physical_path: C:\iis
  
  - name: Copy PowerShell scripts
    win_copy:
      src: /etc/ansible/scripts/iissetup.ps1
      dest: 'C:\'
      remote_src: no

  - name: Execute PowerShell script
    win_command: powershell.exe -ExecutionPolicy Bypass -File C:\iissetup.ps1

We execute the playbook with:

ansible-playbook iissetup.yml -vv

On the client side:

You see processes created as children of a winrshost.exe (winrm) parent.

ansible1

They’ll be sent over as encoded strings

ansible1

The full command was:

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand JgBjAGgAYwBwAC4AYwBvAG0AIAA2ADUAMAAwADEAIAA+ACAAJABuAHUAbABsAAoAJABlAHgAZQBjAF8AdwByAGEAcABwAGUAcgBfAHMAdAByACAAPQAgACQAaQBuAHAAdQB0ACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcACgAkAHMAcABsAGkAdABfAHAAYQByAHQAcwAgAD0AIAAkAGUAeABlAGMAXwB3AHIAYQBwAHAAZQByAF8AcwB0AHIALgBTAHAAbABpAHQAKABAACgAIgBgADAAYAAwAGAAMABgADAAIgApACwAIAAyACwAIABbAFMAdAByAGkAbgBnAFMAcABsAGkAdABPAHAAdABpAG8AbgBzAF0AOgA6AFIAZQBtAG8AdgBlAEUAbQBwAHQAeQBFAG4AdAByAGkAZQBzACkACgBJAGYAIAAoAC0AbgBvAHQAIAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwAuAEwAZQBuAGcAdABoACAALQBlAHEAIAAyACkAIAB7ACAAdABoAHIAbwB3ACAAIgBpAG4AdgBhAGwAaQBkACAAcABhAHkAbABvAGEAZAAiACAAfQAKAFMAZQB0AC0AVgBhAHIAaQBhAGIAbABlACAALQBOAGEAbQBlACAAagBzAG8AbgBfAHIAYQB3ACAALQBWAGEAbAB1AGUAIAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwBbADEAXQAKACQAZQB4AGUAYwBfAHcAcgBhAHAAcABlAHIAIAA9ACAAWwBTAGMAcgBpAHAAdABCAGwAbwBjAGsAXQA6ADoAQwByAGUAYQB0AGUAKAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwBbADAAXQApAAoAJgAkAGUAeABlAGMAXwB3AHIAYQBwAHAAZQByAA==

The encoded part comes to:

&chcp.com 65001 > $null
$exec_wrapper_str = $input | Out-String
$split_parts = $exec_wrapper_str.Split(@("`0`0`0`0"), 2, [StringSplitOptions]::RemoveEmptyEntries)
If (-not $split_parts.Length -eq 2) { throw "invalid payload" }
Set-Variable -Name json_raw -Value $split_parts[1]
$exec_wrapper = [ScriptBlock]::Create($split_parts[0])
&$exec_wrapper

Add custom Powershell to the Ansible Runbook

The example runbook above demonstrated this at the bottom, but its important so here we go again. We copy the script to the target machine, then we execute the script:

  - name: Copy PowerShell scripts
    win_copy:
      src: /etc/ansible/scripts/iissetup.ps1
      dest: 'C:\'
      remote_src: no

  - name: Execute PowerShell script
    win_command: powershell.exe -ExecutionPolicy Bypass -File C:\iissetup.ps1
Blog Logo

Chad Duffey


Published

Image

Chad Duffey

Blue Team -> Exploit Development & things in-between

Back to Overview