Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security] debops.pki does not validate CSRs allowing certificate mis-issuance by compromised remote host #106

Open
ypid opened this issue Apr 23, 2017 · 0 comments

Comments

@ypid
Copy link
Member

ypid commented Apr 23, 2017

The vulnerability goes in the same direction as other vulns on https://www.ansible.com/security which are compromised remote hosts exploiting the Ansible controller.

Steps to reproduce:

pki_ca_domain: 'example.org'
pki_ca_organization: 'example'
pki_default_authority: 'example-issuing-ca'

pki_authorities:

  - name: 'example-root-ca'
    domain: '{{ network__public_dns_fqdn }}'
    subdomain: 'root-ca'
    subject: [ 'o=example Internal Root CA' ]
    key_size: '{{ pki_ca_root_key_size }}'

  - name: 'example-issuing-ca'
    domain: '{{ network__public_dns_fqdn }}'
    subdomain: 'issuing-ca'
    subject: [ 'o=example', 'ou=example Internal Issuing CA' ]
    issuer_name: 'example-root-ca'
    key_size: '{{ pki_ca_domain_key_size }}'

# What the Ansible controller expects:
pki_host_realms:

  - name: 'good.{{ pki_ca_domain }}'

# That is what the remote host will give us (the Ansible controller):
pki_evil_host_realms:

  - name: 'good.{{ pki_ca_domain }}'
    domains:
      - 'evil.{{ pki_ca_domain }}'

Then simply replace all:

  with_flattened:
    - '{{ pki_realms }}'
    - '{{ pki_group_realms }}'
    - '{{ pki_host_realms }}'
    - '{{ pki_default_realms }}'
    - '{{ pki_dependent_realms }}'

with:

  with_flattened:
    - '{{ pki_evil_host_realms }}'

in tasks where pki-realm is called on the remote host (which can be spoofed by the remote host to their liking).

Then run the role. The remote host gets this cert issued:

Certificate:
    Data:
        Version: 3 (0x2)
    Signature Algorithm: sha256WithRSAEncryption
        Subject: CN=good.example.org
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:evil.example.org

The above is just my way of demonstrating/reproducing it.

Basically, the pki-realms script is always executed by the remote host, so the input and output of the script could be controlled by an attacker if the remote host got compromised. That is basically what I simulated here. I defined a second variable in the inventory on the controller pki_evil_host_realms representing the input by which pki-realms gets called despite the fact that the controller sends pki_host_realms. I could have done it manually on the remote host but, oh well, automation.

pki-authority must validate pki_*realms and check if the admin actually authorized the CSR generated by that particular (untrusted) remote host.

Unfortunately, DebOps does not have a patch for this and it is currently not clear when one will be available as it might end in a rewrite of pki-authority. For transparency reasons, we therefore decided to make this public to not leave users in the dark. Technically, DebOps is not yet recommended for production.

@drybjed Already wrote how this can be solved. It is probably best when he pastes that in himself.

My idea was:
pki-authority could just get all pki_*realms of the current Ansible run, encoded as JSON, build Subject and SANs for each realm. Then subject and SANs (and possibly other interesting parts of the CSR) get extracted from the CSR the remote host provided, sorted and compared. Python would make that a bit easier.

Timeline:

  • 2017-04-17: Internal discussion with @drybjed
  • 2017-04-23: Decision that the vulnerability can/should be made public.
@ypid ypid changed the title debops.pki does not validate CSRs allowing certificate mis-issuance by compromised remote host [Security] debops.pki does not validate CSRs allowing certificate mis-issuance by compromised remote host Jul 23, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant