Bug 998223 (CVE-2013-4259) - CVE-2013-4259 ansible: insecure location for ssh ControlMaster socket
Summary: CVE-2013-4259 ansible: insecure location for ssh ControlMaster socket
Alias: CVE-2013-4259
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: Unspecified
OS: Unspecified
Target Milestone: ---
Assignee: Red Hat Product Security
QA Contact:
Depends On: 999621 1001454
Blocks: 998712
TreeView+ depends on / blocked
Reported: 2013-08-18 11:40 UTC by Michael S.
Modified: 2023-05-12 19:15 UTC (History)
7 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Last Closed: 2017-05-12 07:04:19 UTC

Attachments (Terms of Use)
better patch (2.05 KB, patch)
2013-08-18 14:24 UTC, Michael S.
no flags Details | Diff

Description Michael S. 2013-08-18 11:40:22 UTC
by default, ansible try to create a ControlMaster file in a predictible location in /tmp. This is vulnerable to a ssh socket injection attack like this :

~ $ sudo ln -s /tmp/ansible-ssh-elspeth.example.org-22-misc /tmp/ansible-ssh-sisay.example.org-22-misc

~ $ ansible -i 'elspeth.example.org,sisay.example.org' all -m shell -u misc -a hostname
elspeth.example.org | success | rc=0 >>

sisay.example.org | success | rc=0 >>

I also did a test without using root, that's the same.
Based on this attack, someone could divert the ssh connexion to another server, make it connect to a server under the control of attacker, and steal configuration file ( with passwords ), or steal password with a fake sudo ( since ansible can also use sudo )

Please note that you need to :
- disable selinux
# setenforce 0

- disable latest protection from the kernel 

# sysctl -w fs.protected_symlinks=0
# sysctl -w fs.protected_hardlinks=0

to make sure this work.
I didn't found how/where ssh control the socket file for suitability, maybe it should

I am not sure what could be a good fix. I do have a patch that put the socket in $XDG_RUNTIME_DIR but it is a very weak mitigation technique that do not work on older platform such as RHEL 6. 

Another solution would be to make sure the socket is created in specific temporary directory, but this could make the software much slower.

And checking if the socket exist first is prone to race condition.

Upstream was not contacted yet, and plan to release 1.3 around 2 weeks. Issue is not public ( but quite easy to spot )

Comment 1 Michael S. 2013-08-18 11:45:04 UTC
The issue is in https://github.com/ansible/ansible/blob/devel/lib/ansible/runner/connection_plugins/ssh.py#L59

Possible fix :

commit d06eaae5fa32ae24e8076f846bdf3f04e6090384
Author: Michael Scherer <misc>
Date:   Sun Aug 18 13:19:01 2013 +0200

    Try to mitigate symlink attacks on newer platform
    A attacker could pre create a socket in /tmp and so divert
    the ssh connexion to another server. However, newer platform
    are protected against this since kernel 3.10 and surely with
    a proper selinux policy.

diff --git a/lib/ansible/runner/connection_plugins/ssh.py b/lib/ansible/runner/connection_plugins/ssh.py
index abbffcf..be8289e 100644
--- a/lib/ansible/runner/connection_plugins/ssh.py
+++ b/lib/ansible/runner/connection_plugins/ssh.py
@@ -51,12 +51,15 @@ class Connection(object):
         self.common_args = []
         extra_args = C.ANSIBLE_SSH_ARGS
+        control_path_dir = '/tmp'
+        if 'XDG_RUNTIME_DIR' in os.environ:
+            control_path_dir = os.environ['XDG_RUNTIME_DIR']
         if extra_args is not None:
             self.common_args += shlex.split(extra_args)
             self.common_args += ["-o", "ControlMaster=auto",
                                  "-o", "ControlPersist=60s",
-                                 "-o", "ControlPath=/tmp/ansible-ssh-%h-%p-%r"]
+                                 "-o", "ControlPath=%s/ansible-ssh-%%h-%%p-%%r" % control_path_dir]
         if not C.HOST_KEY_CHECKING:
             self.common_args += ["-o", "StrictHostKeyChecking=no"]

Comment 2 Michael S. 2013-08-18 14:24:40 UTC
Created attachment 787788 [details]
better patch

So here is a proper patch, using a temporary directory shared during the playbook run. 

However, it could be written more cleanly without using global, and using proper object lifecycle, but I consider that being minor when compared to the security fix.

Comment 3 Vincent Danen 2013-08-19 20:12:46 UTC
Hi, Michael.  The best thing to do here would be to alert upstream to this.  We can assign a CVE for this that you can pass along as well, and then we can open this bug up and get fixes into Fedora and EPEL6 once the issue is fixed upstream.

Comment 4 Vincent Danen 2013-08-19 20:28:31 UTC

Red Hat would like to thank Michael Scherer for reporting this issue.

Comment 5 Vincent Danen 2013-08-19 20:29:09 UTC
Michael, when you report this to upstream can you also note that it was assigned CVE-2013-4259?


Comment 6 Michael S. 2013-08-19 21:35:39 UTC
Yep, will do. I keep you in CC to see how we organize the embargo, if upstream want one.

Comment 7 Vincent Danen 2013-08-21 17:58:33 UTC
Created ansible tracking bugs for this issue:

Affects: fedora-all [bug 999621]

Comment 8 Vincent Danen 2013-08-21 18:01:10 UTC
This is public now:


Comment 9 Vincent Danen 2013-08-27 05:51:32 UTC
Created ansible tracking bugs for this issue:

Affects: epel-6 [bug 1001454]

Comment 10 Fedora Update System 2013-08-28 16:43:55 UTC
ansible-1.2.3-2.el6 has been pushed to the Fedora EPEL 6 stable repository.  If problems still persist, please make note of it in this bug report.

Comment 11 Fedora Update System 2013-08-30 22:58:23 UTC
ansible-1.2.3-2.fc18 has been pushed to the Fedora 18 stable repository.  If problems still persist, please make note of it in this bug report.

Comment 12 Fedora Update System 2013-08-30 23:03:27 UTC
ansible-1.2.3-2.fc19 has been pushed to the Fedora 19 stable repository.  If problems still persist, please make note of it in this bug report.

Note You need to log in before you can comment on or make changes to this bug.