Securely running scripts via ansible on Windows/false positives

Hi Guys,

The antivirus I have installed on some of my test windows hosts are causing scripts to be flagged as malicious and thus they are failing when run. I don’t think that the code is malicious, it’s a simple ping via the win_shell module . Will you please review my results/playbook and give suggestions? How do I prevent this from happening to other non-malicious code?

I should also ask, what is the safe way to allow ansible to execute PowerShell code?
Right now I have the ExecutionPolicy set as unrestricted. My ansible control node connects to my windows hosts via WinrM and certificate based authentication. Your thoughts are welcome.

mramanan@hgiclprint1:/etc/ansible$ ansible-playbook -i Inventory/macoya_inventory.ini Playbooks/win_ping.yml 

PLAY [Test Windows Host Connectivity] *****************************************************************************************************************************************************************************

TASK [Ping Windows Hosts] *****************************************************************************************************************************************************************************************
fatal: [dell3070-carlho]: FAILED! => {"changed": false, "module_stderr": "At line:1 char:1\r\n+ begin {\r\n+ ~~~~~~~\r\nThis script contains malicious content and has been blocked by your antivirus software.\r\n    + CategoryInfo          : ParserError: (:) [], ParseException\r\n    + FullyQualifiedErrorId : ScriptContainedMaliciousContent\r\n ", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
fatal: [Dellopt9020pos1]: UNREACHABLE! => {"changed": false, "msg": "certificate: the specified credentials were rejected by the server", "unreachable": true}
fatal: [dell3070-ashley]: FAILED! => {"changed": false, "module_stderr": "At line:1 char:1\r\n+ begin {\r\n+ ~~~~~~~\r\nThis script contains malicious content and has been blocked by your antivirus software.\r\n    + CategoryInfo          : ParserError: (:) [], ParseException\r\n    + FullyQualifiedErrorId : ScriptContainedMaliciousContent\r\n ", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
ok: [11sgdell1]
fatal: [Len710tuna1]: FAILED! => {"changed": false, "module_stderr": "At line:1 char:1\r\n+ begin {\r\n+ ~~~~~~~\r\nThis script contains malicious content and has been blocked by your antivirus software.\r\n    + CategoryInfo          : ParserError: (:) [], ParseException\r\n    + FullyQualifiedErrorId : ScriptContainedMaliciousContent\r\n ", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
fatal: [claims-tuna2]: UNREACHABLE! => {"changed": false, "msg": "certificate: HTTPSConnectionPool(host='172.22.248.210', port=5986): Max retries exceeded with url: /wsman (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x7fa9776e3220>, 'Connection to 172.22.248.210 timed out. (connect timeout=30)'))", "unreachable": true}
fatal: [hgicl-pc-kamille]: FAILED! => {"changed": false, "module_stderr": "At line:1 char:1\r\n+ begin {\r\n+ ~~~~~~~\r\nThis script contains malicious content and has been blocked by your antivirus software.\r\n    + CategoryInfo          : ParserError: (:) [], ParseException\r\n    + FullyQualifiedErrorId : ScriptContainedMaliciousContent\r\n ", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
fatal: [3060MKTTUN1MELISSA]: UNREACHABLE! => {"changed": false, "msg": "certificate: HTTPSConnectionPool(host='172.22.248.201', port=5986): Max retries exceeded with url: /wsman (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x7fa9776f3b20>, 'Connection to 172.22.248.201 timed out. (connect timeout=30)'))", "unreachable": true}

PLAY RECAP ********************************************************************************************************************************************************************************************************
11sgdell1                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
3060MKTTUN1MELISSA         : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   
Dellopt9020pos1            : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   
Len710tuna1                : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
claims-tuna2               : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   
dell3070-ashley            : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
dell3070-carlho            : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
hgicl-pc-kamille           : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

mramanan@hgiclprint1:/etc/ansible$ cat Playbooks/win_ping.yml 
---
- name: Test Windows Host Connectivity
  hosts: windows
  gather_facts: no
  tasks:
    - name: Ping Windows Hosts
      win_ping:
mramanan@hgiclprint1:/etc/ansible$ 

The ping module or in this case the win_ping module is actually NOT an ICMP ping. In retrospect… years later… we should have called this something else… It is a simple module, but it actually does connect.

The module will connect to the windows host using the provided credentials, it copies over module code, in your case its copying over the win_ping powershell code (literally this powershell script .ps1 file https://github.com/ansible-collections/ansible.windows/blob/main/plugins/modules/win_ping.ps1) and then it executes it. It then will return a JSON payload indicating how the module returned, then the default behavior is to remove itself (there is ways to debug and leave modules on managed nodes).

Usually… (not always) users will create a service account for machines, for the use-case of automation. This allows them to know “who” (or in this case what :rofl:) changed something in the logs. This is where I would make the changes to your antivirus or whatever is causing them to be flagged as malicious.

What is actually flagging them as malicious and what are the options for an allow list?

1 Like

Hi Sean.
Thank you for your response
I have Vipre EDR that is blocking scripts executed via WinRM on Windows machines. In another case, my code just copies a file (Executable) from a server and runs a command on the client machine to run the exe. This is being blocked.
The file is safe. The code is safe.
Therefore this is perhaps behaviour based blocking by the EDR.
I have written to the vendor for advice on how can these behaviour based EDRs/Antivirus systems be configured to allow vetted scripts to run on client machines.

My ansible setup is certificate based authentication that connects to winrm. The certificate is tied to a user created just for ansible tasks , named “ansiblerunner”.
I know you advised on making changes to the AV.

I want to make minimal changes as possible. Disabling behaviour scanning is not an option in today’s threat landscape. (even temporarily)

Therefore, the question I am pondering from the ansible side is, what are the best practices where I can use my scripts or executing win_shell scripts via ansible through WinRM, in a manner that promotes us making as minimal changes to AV as possible.

You also asked what options I have for an allow list.
It would be specifying:
-file (specifying filename, filepath or folder)
-Domain
-process (eg process.exe)
-hash( eg SHA256)

That being said, I did mention earlier that I excluded filepaths:
MODIFIED BY
Filepaths:
C:\Windows\System32\winrm.cmd
C:\Windows\SysWOW64\winrm.cmd
C:\Windows\System32\WindowsPowerShell\v1.0\winrm.cmd

However, same issue.

Suggestions welcome