0

Consider a UNIX account jdoe. I want to update jdoe's password using python script running as root. Currently, I am using:

cmd = 'echo "' + username + ":" + new_pass + '" | chpasswd '
os.system(cmd)

However, that is an unsafe method. If someone were to enter new_pass as pass"; rm -rf / #, that would be disasterous.

Is there a safe and secure way to do it?

2 Answers 2

1

If you're concerned about untrusted input, it's better to avoid using os.system, since that invokes the shell, and in general, you don't want the shell anywhere near untrusted input. In addition, you typically want to avoid putting secrets into command-line arguments since they can be read by other users, although since echo is usually a built-in, this isn't strictly a concern here.

To do this securely, you can use subprocess.Popen instead, like so:

import subprocess

proc = subprocess.Popen(['chpasswd'], stdin=subprocess.PIPE)
proc.stdin.write(b"username:password")

Note that if you need to pass additional arguments to chpasswd, you'd do that by adding arguments to the array:

proc = subprocess.Popen(['chpasswd', '-c', 'SHA512'], stdin=subprocess.PIPE)
Sign up to request clarification or add additional context in comments.

4 Comments

This seems to be working with new_pass = pass"; rm -rf / #. I hope I am not overlooking something.
It should indeed work with an arbitrary password, including a password that contains a shell injection. That's just a part of the password in that case, not a security vulnerability.
Surprisingly, this does not work with flask, I can't figure out why.
Ah, replaceing proc.stdin.write(...) with proc.communicate(input=...) fixed the problem.
1

I'd modify it so the entered password gets hashed (sha512 is standard on modern Linux systems) and then pass the hashes value to your cmd.

cmd = 'echo "' + username + ":" + new_pass + '" | chpasswd -e'
os.system(cmd)

Note the -e after chpasswd

Fleshing the above suggestion out a little more:

import crypt
entered_password = 'pass"; rm -rf / #'
new_password = crypt.crypt(entered_password, '$6$' + 'salt1234')

1 Comment

I am doing cmd = 'echo "' + username + ":" + sha512(new_pass) + '" | chpasswd -e', os.system(cmd), but when I try logging in, new_pass is not valid. What is the default hash for chpasswd -e? It does not appear to be sha256.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.