motioneye icon indicating copy to clipboard operation
motioneye copied to clipboard

Admin password in SHA1, normal password in plain text

Open SuMaPa opened this issue 1 month ago • 11 comments

Hi Sha1 is a little better than plaintext. So I changed the normal password to SHA1 in the config.py file. Works perfectly. I haven't been able to switch to >SHA1 yet. Password generation works, but the login doesn't. I was able to gather some insights. However, a bypass solution will then be needed.

SuMaPa avatar Nov 17 '25 14:11 SuMaPa

When touching this, we'd need to keep supporting the old hashing algorithm for reading the password, but we may want to force users to set/change it once, to have it stored in new format ASAP. However, does not make much sense to use insecure SHA1. At best we switch to Argon2ID, or minimum bcrypt.

MichaIng avatar Nov 17 '25 14:11 MichaIng

Btw, regarding normal/surveillance user password, AFAIK the reason to store it in plain text was that it is reused as direct motion camera password, also used by motionEye to access those streams. Hence storing it hashed would break access. Not an awesome implementation, but I have no other great idea how to do better: motionEye could use some internal-only random password to access motion, that is independent of the surveillance user password used to authenticate at motionEye. But that would break direct access to those streams for users, bypassing motionEye interface. The idea surely was to keep it simple, having one surveillance user password to access motionEye read-only, as well as access motion camera streams directly. And AFAIK there is no way to have two passwords for a motion cam, to allow access via surveillance user password, while motionEye uses an own internal one that is not exposed in any UI.

MichaIng avatar Nov 17 '25 15:11 MichaIng

When touching this, we'd need to keep supporting the old hashing algorithm for reading the password

Different hash algorithms produce hashes of different lengths (and have even distinctly recognisable formats, see examples in Hashcat docs), so this shouldn't be too difficult 🤔

motionEye could use some internal-only random password to access motion, that is independent of the surveillance user password used to authenticate at motionEye. But that would break direct access to those streams for users, bypassing motionEye interface.

Yeah, not to mention that the password for accessing Motion (be it only used internally by ME or not) needs to be stored in plaintext anyway, so having a more secure read-only access to ME UI might not make much sense 🤔 I mean, if someone could read the surveillance user password from ME config, that same attacker could just as fine read the password from Motion config and anyway access Motion directly. The original design of Motion wasn't done with much regard for security, and that was pretty normal back then I guess so I'm not blaming anyone here. I guess it just is one of those things that needs to be guarded from outside access by all means and on all levels if security is a requirement.

zagrim avatar Nov 17 '25 18:11 zagrim

I'm not sure if I understand you correctly. In the config.py file, I changed the user to sha1. The SHA1 password was created in the motion.conf file. All other passwords continue to be stored in plain text. I can't find any restrictions. Unfortunately, I haven't made any further progress. The SHA256 string is being saved correctly, but it's not being recognized upon login. There might be a hidden character limit somewhere that I haven't found yet.

:( ...postponed until next week

SuMaPa avatar Nov 17 '25 22:11 SuMaPa

Image Image

user (anyway) and admin name can be changed, possibly a little more security??

SuMaPa avatar Nov 19 '25 12:11 SuMaPa

I'm too stupid for that.

SuMaPa avatar Nov 27 '25 16:11 SuMaPa

Sorry for the late reply. So you applied hashing in config.py here, but you could not login afterwards? Did you also implement support for the hash at the authentication part? Here I mean: https://github.com/motioneye-project/motioneye/blob/main/motioneye/handlers/base.py#L115-L135

Although, it seems to allow both already:

  • Assuming normal_password is a hash
  • normal_password in (up['password'], hashlib.sha1(up['password'].encode('utf-8')).hexdigest()) is true as it matches the 2nd entry: the hashed password header.
  • If it is in plain text, it machtes the 1st entry: the plain password header.
  • Alone the fact that this code is identical for admin and "normal" users means that a hash for the normal user should not cause any issue, as the same works for the admin.

If this does not work, and authentication fails there, it would need some debug code to find out why.

And yes, the usernames are variables internally already, but in many places of the code they are still hardcoded. Should not be too hard to find and adjust those places, and turn the currently read-only fields in the settings into read-write fields, to change those usernames.

I found the reason why this password is not hashed right now:

  • https://motion-project.github.io/motion_config.html#stream_authentication
  • https://github.com/search?q=repo%3Amotioneye-project%2Fmotioneye+stream_authentication
  • So direct camera stream authentication can be enabled in which case the "normal" user credentials are used for simplicity. So this would break when hashing the password, as one would then need to enter the hash itself for viewing the direct camera stream.

motion also has a webcontrol authentication option, but that is not currently used by motionEye:

  • https://motion-project.github.io/motion_config.html#webcontrol_auth_method
  • An open request about it: #1671
  • But that one would not necessarily interfere with password hashing: What could be done there is generating a long random password exclusively for this motion control port, and storing that separately, as digest or plain does not really matter, and using that for internal motion control API requests. It does not need to be visible in the GUI anywhere. So this would be just to protect the control port for attackers with access to that port, but cannot help against attackers with read-access to the motion or motionEye configs.

MichaIng avatar Nov 27 '25 17:11 MichaIng

Please do not test on your live system. It's easy to make the adminusername/ "admin" changeable. templates/main.html

search: id="adminUsernameEntry" readonly="readonly"
remove: readonly="readonly"

It is also easy to encrypt the user password using SHA1. config.py

search:     if ui.get('normal_password') is not None:
remove:     data['@normal_password'] = ui['normal_password']
paste:
        if ui['normal_password']:
            data['@normal_password'] = hashlib.sha1(
                ui['normal_password'].encode('utf-8')
            ).hexdigest()
        else:
            data['@normal_password'] = ''

I tested this on several test installations, and it works very well under Debian (12&13). Please do not test on your live system.

Anything higher than SHA1 doesn't work.

Passwords are generated correctly (config.py).

Queries are apparently made via utils/init.py (on restart) and handlers/base.py.

Right now I'm just annoyed. Once I've calmed down, I'll add debug code. Maybe.

@MichaIng Everything's fine, we all have work to do.

SuMaPa avatar Nov 27 '25 19:11 SuMaPa

Anything higher than SHA1 doesn't work.

That makes sense unless you replace the algorithm everywhere it is used, i.e. in the base.py handler I linked above.

See here about updating the algorithm: #2467

MichaIng avatar Nov 27 '25 20:11 MichaIng

SHA1 user password works with video streaming. Video streaming works even when it's switched off. :(

Image

SuMaPa avatar Nov 28 '25 17:11 SuMaPa

Oh, that is odd. And indeed the code looks like it would just allow everything, hash, plain, or no authentication for normal/surveillance user. But that the direct stream cannot even be disabled raises the severance of that issue.

The [stream_auth_method[https://motion-project.github.io/motion_config.html#stream_auth_method] allows at least MD5 digest authentication, which hence would allow the normal user password to be stored this way, without breaking double-use of it. Not awesome, but better than plain text. However, inside the motion config, it seems to be still needed in plain text, needs testing.

Let me re-open this issue. This whole normal user and direct stream authentication needs some require at least.

MichaIng avatar Nov 29 '25 14:11 MichaIng