
Command execution on Ansible controller from host - robin_reala
https://www.computest.nl/advisories/CT-2017-0109_Ansible.txt
======
cperciva
If only we had some form of superluminal communication, it might be possible
to patch all the affected systems before they get exploited.

~~~
vog
Not sure what you are trying to say. Are you trying say that the CVS
publication happened too early? If so, the timeline tells a different story:

    
    
        2016-12-08	First contact with Ansible security team
        2016-12-09	First contact with Redhat security team (secalert@redhat.com)
        2016-12-09	Submitted PoC and description to security@ansible.com
        2016-12-13	Ansible confirms issue and severity
        2016-12-15	Ansible informs us of intent to disclose after holidays
        2017-01-05	Ansible informs us of disclosure date and fix versions
        2017-01-09	Ansible issues fixed version

~~~
cperciva
It was a joke about the name:
[https://en.wikipedia.org/wiki/Ansible](https://en.wikipedia.org/wiki/Ansible)

(Well, that plus the fact that this seems like the sort of scary bug which
will get exploited very quickly.)

~~~
vog
I see. This is really astonishing.

I always preferred using plain SSH and Shell for automatically configuring
servers.

That's why I had a look at Ansible, but despite this simple concept, it seemed
too bloated to me: too many layers around this simple idea. But I had never
thought to be proven right, let alone that this complexity actually translates
into 6 scary security holes in a row.

To propose an alternative, this is how I'm currently doing it. I'd love to
hear what others think about it, or whether others have tried similar things:

 _Note: This works best of a relatively small and /or heterogenous set of
servers/VMs. So it's not really the full-blown Ansible use case. But then, how
many people really do have billions of users and a large set of homogenous
servers at their hands? I bet the "long tail" of web applications doesn't need
more than a few servers. Or, if your hardware is strong enough, just two
servers, where the first one takes all the load, and the second one is a
failover system on stand-by._

Use a plain shell and plain shell commands, which has the advantage that you
can quickly try these interactively in any VM. Use "set -eu" so it halts on
error, instead of blindly executing all following commands. Use appropriate
commands, e.g. "install" instead of "cat+chmod+chown". Use
"\--backup=numbered" to keep backups of previous versions of files, if you
want. Use only idempotent commands, i.e. commands that you can run multiple
times without changing anything of significance. Prefer portable commands, but
use distro-specific code as needed. The time you switch to another distro
you'll have a new script, anyway, because you'll have a different system with
different requirements. Write everything down in the style of a "copy&paste"
documentation (Does this count as "literate programming"?), but put all your
remarks in shell commands. Then automate the "paste" part by making it
executable.

Example file (executable file "myserver_config"):

    
    
        #!/bin/sh
        tail -n +3 "$0" | ssh -p 1234 root@myserver_ip ; exit
        set -eu
    
        # Install packages
        ...
    
        # Configure Foo
        ...
    
        # Configure Bar
        ...
    
        # Configure Nginx
        #
        # Configure Nginx so that the foo fits into the bar
        # and boggles the foobar.
    
        install --backup=numbered -o root -g root -m 600 /dev/stdin /etc/nginx/nginx.conf <<'EOF'
        error_log /var/log/nginx/error.log;
        events {
          ...
        }
        http {
          access_log /var/log/nginx/access.log;
          ...
        }
        EOF
    
        # Do more stuff
        ...
    

Edit this file and redeploy by simply executing it:

    
    
        ./myserver_config
    

The script may seem hard to read, but with syntax highlighting it is a breeze.
And you can easily convert this to HTML, AsciiDoc or Markdown if you need a
"real" documentation for your customer or other project members. It's just a
few lines of code in Python, or whatever language you prefer.

~~~
oskarth
I prefer simple and portable shell scripts too. While I use _here documents_ a
bunch too this is the first time I've seen this idiom:

    
    
        #!/bin/sh
        tail -n +3 <current-filename> | ssh -p 1234 root@myserver_ip  ; exit
        set -eu
        ...
    

Clever.

When you write `install`, is this another script that you have installed on
the server beforehand or is it a function/alias or something? [EDIT: Duh,
didn't realize this was actually a standalone program (standard but non-POSIX
AFAICT) I haven't used.]

~~~
vog
_> While I use here documents a bunch too this is the first time I've seen
this idiom_

I came up with this trick to avoid _nested_ here documents, which would make
syntax highlighting unusable.

 _> When you write `install`, is this another script that you have installed
on the server beforehand or is it a function/alias or something?_

The "install" tool is very common on almost all Unix systems. It is usually
called by a Makefile on "make install", but of course can be used by anyone.

------
estefan
Am I the only one who finds it pretty unprofessional to release the exploits
when the fixed version hasn't been released yet (and anyway was only scheduled
to have been released 48 hours beforehand)?

I'm all for disclosure, but seriously - if RH want Ansible to be used in
enterprise they can't expect patches at this rate. The researchers releasing
the exact exploits so quickly is just irresponsible IMO.

~~~
knocte
But to be a victim of this vulnerability you need to have one of the hosts
already compromised AFAIU, so I don't think it's that severe.

~~~
brianwawok
Any exploit that turns a 1 host hack into hack entire data enter with root
access seems worth a patch....

------
jorrizza
The fixed version does not seem to be released yet on pypi or their launchpad
PPA. The only (official) place where a fixed release is available seems to be
[https://releases.ansible.com/ansible/](https://releases.ansible.com/ansible/)

------
romanr
Can anyone explain in simple terms what is this about? Exploit found in
Ansible? Should we all update asap?

I couldn't understand from article or discussion.

~~~
grey-area
Ansible sends commands to servers, but asks them for certain data first
(facts).

If one of your servers is compromised, this is a vulnerability in the ansible
client that lets that bad server take over your local computer _and_ your
other servers when you connect to it by sending you bad facts.

So it's pretty serious.

~~~
mverwijs
Puppet uses facter and chef ohai to achieve te same thing. Could they be
exploited in similar fashion?

------
ensignavenger
I'm just starting to use Ansible for a major deployment at work, so I am not
an expert- can anyone who knows more explain why "ansible_connection" exists
as a host definable fact? The controller already knows what host it is
connecting to when it retrieves the fact, so why can the host change it?

~~~
bcoca
it is not a host definable fact, it is a 'host variable' which you normally
define in inventory.

~~~
ensignavenger
From the advisory:

When Ansible runs on a host, a JSON object with Facts is returned to the
Controller. The Controller uses these facts for various housekeeping purposes.
Some facts have special meaning, like the fact "ansible_python_interpreter"
and "ansible_connection".

So while you may normally define it in the inventory, it sounds like, from the
advisory, it can also be defined by the host.

------
mdeeks
No fix for 1.9? We are stuck on 1.9 because 2.X does not support connecting to
more than a couple hundred hosts. This ticket has been open for about a year
now:
[https://github.com/ansible/ansible/issues/14143#issuecomment...](https://github.com/ansible/ansible/issues/14143#issuecomment-264455619)

~~~
scrollaway
Have you considered working on it to fix that issue?

------
bcoca
disclaimer: I'm one of the maintainers

I'll try to answer several questions so this might get long.

First, the procedure for disclosing the CVE is something we discussed
internally (including security professionals), as all over the internet there
are 2 or more views on this. The decision arrived at doesn't please everyone
(I doubt one that would exists), but it is a recognized way of dealing with
security issues, so it is what we followed.

The CVE can be dense explaining how the exploits work. The simple version: it
is a rehash of an old problem which we had thought solved, the researchers
proved us wrong by finding ways around our filtering. The vulnerability is
pretty hard to trigger and requires both a compromised system to intercept the
Ansible calls and return faulty data and intimate knowledge of the existing
playbooks and systems used to force the arbitrary execution.

All software has flaws, this is not an excuse, it is a fact. Not all software
or flaws have the same scope though. As a automation tool that is often used
to manage things with high levels of privilege, we take these things very
seriously and we do our best to prevent it in the first place or remediate it
as soon as possible. As an OSS project we appreciate the eyes and efforts many
put into finding these flaws which end up making the software better (and me a
better programmer).

Ansible is not idempotent, it is declarative, which does help the user create
idempotent plays. True idempotency depends on many things, the modules used,
the problem addressed and how the playbooks are written, etc. Both of the
following are valid ansible tasks, but the implications are very different
even if the result ends up being the same.

\- shell: usermod -G user bcoca

\- user: state=present name=bcoca groups=user

I hope this helps,

~~~
rarrrrrr
Odd. I reported this very same form of vulnerability to the Ansible team in
the 1.5.4 series in 2014, where the code basically eval'd the "facts"
discovered from a system under management.

There was this "safe_eval" function which filtered input in a way quite
inconsistent with its name. The Ansible team was responsive and pleasant to
work with!

[https://groups.google.com/forum/#!topic/ansible-
project/MUQx...](https://groups.google.com/forum/#!topic/ansible-
project/MUQxiKwSQDc)

But I suspect lots of remote control and monitoring software products might
have security bugs like this where they assume that the returned information
from systems under management are trustworthy.

Edit to add: Here's the patch made to safe_eval in 2014. I had suggested using
literal_eval instead but I guess a Python 2.6+ requirement wouldn't work.
[https://github.com/ansible/ansible/commit/998793fd0ab55705d5...](https://github.com/ansible/ansible/commit/998793fd0ab55705d57527a38cee5e83f535974c)

Edit again: Ansible is a pretty great product, and IMO one of the first of
such tools to seriously improve the UX for sysadmins. Thanks for maintaining
it!

------
ivank
[https://www.computest.nl/advisories/CT-2017-0109_Ansible.txt](https://www.computest.nl/advisories/CT-2017-0109_Ansible.txt)
has the bug details

Edit: LWN link was changed to this one

~~~
wvh
Thanks! Some of those are somewhat embarrassing, especially for something
that's meant to be software used in secure environments. Why does a client
need to specify an interpreter to run on the master host? Or changing the
template brackets to escape quoting? I'm also thinking that maybe Python might
be a bit too dynamic – allowing anything by design – bringing its own share of
problems to developing security-conscious software.

~~~
icebraining
_Why does a client need to specify an interpreter to run on the master host?_

No, the client specifies the interpreter to use inside itself.

~~~
mkesper
But why? I think a dedicated interpreter at a fixed address would do.

~~~
evolvedlight
Imagine you're in a large enterprise environment, and need to deploy something
to lots of different servers that were created by lots of different people
(your company bought 3 others and each used different software/linux
versions/servers). Some have python in the path, some have different pythons
in the path, etc. You can't immediately throw away all these servers and
rebuild them - some probably have 10 year old bits of software on them where
the original author has moved away. Ansible might be one of the tools you use
to start fixing this chaotic situation, and having per-host configurations for
things like python path is essential.

~~~
mkesper
Step 1: Install the expected, dedicated Python interpreter as
/usr/bin/ansible_python.

~~~
holmb
Python is not just a single executable. It takes a little more work than one
would want. And for what gain? Would you be fine with other software also
requiring a custom interpreter to function? It gets cumbersome.

~~~
mkesper
If you rely on the system-wide Python you'll need to cover different versions
and you need to make sure not to use any 3rd party modules.

~~~
icebraining
Ansible ships its own libraries, generally.

