diff --git a/changelogs/fragments/dont_template_passwords_from_prompt.yml b/changelogs/fragments/dont_template_passwords_from_prompt.yml new file mode 100644 index 0000000000..86a0e6122f --- /dev/null +++ b/changelogs/fragments/dont_template_passwords_from_prompt.yml @@ -0,0 +1,2 @@ +bugfixes: + - resolves CVE-2019-10206, by avoiding templating passwords from prompt as it is probable they have special characters. diff --git a/lib/ansible/cli/__init__.py b/lib/ansible/cli/__init__.py index 380ddc4e2a..76d652f7c8 100644 --- a/lib/ansible/cli/__init__.py +++ b/lib/ansible/cli/__init__.py @@ -42,6 +42,7 @@ from ansible.parsing.dataloader import DataLoader from ansible.release import __version__ from ansible.utils.path import unfrackpath from ansible.utils.vars import load_extra_vars, load_options_vars +from ansible.utils.unsafe_proxy import AnsibleUnsafeBytes from ansible.vars.manager import VariableManager from ansible.parsing.vault import PromptVaultSecret, get_file_vault_secret @@ -342,6 +343,13 @@ class CLI(with_metaclass(ABCMeta, object)): except EOFError: pass + # we 'wrap' the passwords to prevent templating as + # they can contain special chars and trigger it incorrectly + if sshpass: + sshpass = AnsibleUnsafeBytes(sshpass) + if becomepass: + becomepass = AnsibleUnsafeBytes(becomepass) + return (sshpass, becomepass) def normalize_become_options(self): diff --git a/lib/ansible/utils/unsafe_proxy.py b/lib/ansible/utils/unsafe_proxy.py index 963798a087..6221e73393 100644 --- a/lib/ansible/utils/unsafe_proxy.py +++ b/lib/ansible/utils/unsafe_proxy.py @@ -55,7 +55,7 @@ __metaclass__ = type from collections import Mapping, MutableSequence, Set -from ansible.module_utils.six import string_types, text_type +from ansible.module_utils.six import string_types, text_type, binary_type from ansible.module_utils._text import to_text @@ -70,15 +70,24 @@ class AnsibleUnsafeText(text_type, AnsibleUnsafe): pass +class AnsibleUnsafeBytes(binary_type, AnsibleUnsafe): + pass + + class UnsafeProxy(object): def __new__(cls, obj, *args, **kwargs): + if isinstance(obj, AnsibleUnsafe): + # Already marked unsafe + return obj + # In our usage we should only receive unicode strings. # This conditional and conversion exists to sanity check the values # we're given but we may want to take it out for testing and sanitize # our input instead. + # Note that this does the wrong thing if we're *intentionall* passing a byte string to this + # function. if isinstance(obj, string_types): - obj = to_text(obj, errors='surrogate_or_strict') - return AnsibleUnsafeText(obj) + obj = AnsibleUnsafeText(to_text(obj, errors='surrogate_or_strict')) return obj