17

I've created a user ... but forgotten the password

mysql> create user 'blayo'@'%' identified by 'right';

Which Linux command line tool can encrypt the password the same way mysql 5.5 does ?

mysql> select Password,User from mysql.user
------------------------------------------+-------+
*920018161824B14A1067A69626595E68CB8284CB | blayo |

...to be sure I use the right one

$ tool right
*920018161824B14A1067A69626595E68CB8284CB
Philippe Blayo
  • 1,949
  • 4
  • 18
  • 23
  • 2
    Why can't you just login as an administrator and define a new password for `blayo`? That's definitively faster than running through trillions of possible character combinations to find the right one. – nohillside Aug 06 '12 at 20:10
  • Please [do not post the same question to multiple Stack Exchange sites](http://meta.stackexchange.com/questions/64068/is-it-possible-to-post-questions-across-a-couple-of-the-sites-because-its-debata/64073#64073). [The DBA version](http://dba.stackexchange.com/questions/22067/tool-to-match-mysql-password-encryption) has been answered as well, which is a waste of effort. – Gilles 'SO- stop being evil' Aug 06 '12 at 23:57

9 Answers9

17

Some one-liners:

MySQL (may require you add -u(user) -p):

mysql -NBe "select password('right')"

Python:

python -c 'from hashlib import sha1; print "*" + sha1(sha1("right").digest()).hexdigest().upper()'

Perl:

perl -MDigest::SHA1=sha1_hex -MDigest::SHA1=sha1 -le 'print "*". uc sha1_hex(sha1("right"))'

PHP:

php -r 'echo "*" . strtoupper(sha1(sha1("right", TRUE))). "\n";'

Ruby:

ruby -e 'require "digest/sha1"; puts "*" + Digest::SHA1.hexdigest(Digest::SHA1.digest("right")).upcase'

All output:

*920018161824B14A1067A69626595E68CB8284CB

7yl4r
  • 163
  • 7
alexjhart
  • 171
  • 1
  • 3
16

Well, the trivial (perhaps cheating) way would be to run:

mysql -NBe "select password('right')"

This will produce a password using whatever password hashing scheme your version of mysql uses. [EDIT: added -NB, which gets rid of the column names and ascii table art.]

jsbillings
  • 24,006
  • 6
  • 56
  • 58
  • 6
    And, handily, this will store your shiny new password in clear text both in your MySQL log and in your bash account history log. – Craig Tullis Sep 14 '14 at 18:16
  • @Craig To prevent both you can prepend a ' ' (space) right before the `mysql` to hide it from the bash history and you can use `SET sql_log_off=ON;` right before the `SELECT ...` to hide it from the MySQL log. – Murmel Mar 13 '19 at 09:54
  • 1
    @Murmel thanks for the update! Off course, it should default to not logging passwords. Security should always be the default setting. – Craig Tullis Mar 13 '19 at 17:23
  • @Craig To be fair, this is already done by mysql (v5.7, the last version this function exists, got removed with [v8.0.11](https://dev.mysql.com/doc/refman/8.0/en/encryption-functions.html#function_password))) on the: 1. clientside (affecting `.mysql_history`) ignoring all statements matching `*PASSWORD*` and 2. serverside for several stmts (except `SELECT`). See: [MySQL 5.7 Manual - Passwords and Logging](https://dev.mysql.com/doc/refman/5.7/en/password-logging.html) and [MySQL 5.7 - Manual - mysql Client Logging](https://dev.mysql.com/doc/refman/5.7/en/mysql-logging.html) – Murmel Mar 14 '19 at 08:31
  • That's good feedback! Unfortunately, there are still quite a few people who for various reasons (myself included) are still stuck using mysql versions older than 5.7. – Craig Tullis Apr 22 '19 at 05:38
7

One more using the shell:

echo -n 'right' | sha1sum | xxd -r -p |\
sha1sum | tr '[a-z]' '[A-Z]' | awk '{printf "*%s", $1}'

Explanation:

  1. echo -n print without linebreak
  2. sha1sum first SHA1
  3. xxd -r -p unhex the hash
  4. sha1sum second SHA1
  5. tr '[a-z]' '[A-Z]' convert to uppercase
  6. awk '{print "*" $1}' add leading *

More details:

Between 2. and 3. an optional awk '{printf "%s", $1}' step could be insterted for newline- and hyphen-removal. But xxd will ignore them anyway (Thanks to dave_thompson_085).

Furthermore step 5 and 6 could be done at once by replacing them with {print "*" toupper($1)} (Thanks to dave_thompson_085).

Murmel
  • 206
  • 2
  • 7
  • 2
    `awk` can do the uppercase, and outputting an incomplete (last) line to terminal is incovenient: `.. | sha1sum | awk '{print "*" toupper($1)}'`. And you don't need to worry about the NL and even the hyphen on the `xxd -r -p`, they're ignored. – dave_thompson_085 Dec 06 '15 at 02:54
6

It still kind of blows my mind that MySQL doesn't bother obfuscating passwords on the command line and in logs. And that's the only reason I'm adding an answer rather than just commenting on @Gilles answer.

So, of course, you could just log into MySQL as an admin and set a new password for your blayo user, as @patrix suggested.

However, the standard way to do that is by using MySQL's password() function, which takes a plaintext password as an argument (seriously?).

If you do that, you leave the plaintext version of your MySQL user's password sitting around in your bash history and in your MySQL logs, for easy retrieval later on by whoever manages to get access to those log files.

Wouldn't it be better to have a little utility that would prompt for the password, without echoing it to the screen or to your logs, then provide you with the resulting MySQL-compatible hash?

So, modifying @Gilles's answer just a bit, how about a little shell script that uses Python, like the following. You could easily modify this to run a SQL statement against your MySQL database to set the password all at once. But even without going that far, just copy and paste the resulting hash into a SQL statement to update the users table:

#!/bin/bash

mysqlpwd=$(/usr/bin/python -c 'from hashlib import sha1; import getpass; print "*" + sha1(sha1(getpass.getpass("New MySQL Password:")).digest()).hexdigest()')

echo $mysqlpwd
Craig Tullis
  • 171
  • 1
  • 4
4

The hash is sha1(sha1(password)). Since there is no salt (which is a grave security flaw), you can look up the hash in a table.

With just POSIX tools plus sha1sum from GNU coreutils or BusyBox, sha1(sha1(password)) is annoying to compute because the sha1sum command prints out the digest in hexadecimal and there is no standard tool to convert to binary.

awk "$(printf %s 'right' | sha1sum |
       sed -e 's/ .*//' -e 's/../, 0x&/g' \
           -e 's/^/BEGIN {printf "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"/' \
           -e 's/$/; exit}/')" | sha1sum

Python has standard digests in its standard libraries, so it's a simple one-liner.

printf %s 'right' |
python -c 'from hashlib import sha1; import sys; print sha1(sha1(sys.stdin.read()).digest()).hexdigest()'

Or with the password inside the one-liner:

python -c 'from hashlib import sha1; print sha1(sha1("right").digest()).hexdigest()'
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
  • I love this answer in spirit, but it isn't quite working. When I hit the enter key, it still wants to keep reading input instead of moving on. Also, the input echos back to the screen, which might not be desirable. How about something like this, though? http://unix.stackexchange.com/a/155583/37401 – Craig Tullis Sep 14 '14 at 19:33
  • @Craig How to read interactive input is beyond the scopre of the question. I assume that the script already has the password; usually it's stored in a file, it's rare to type a database password interactively. If you want to read interactive input, you can use the `read` shell builtin to read a line; run `stty echo` first if you want to turn off echo and `ssty +echo` to turn it back on. In Python, you can use the `getpass` module. – Gilles 'SO- stop being evil' Sep 14 '14 at 19:49
  • Yeah, I know... and fair enough! I just hate horrible security the further down the road I go, and MySQL security is pretty horrible in general, so I have this knee-jerk tendency to want to inject a little security insight wherever I get a chance. ;-) – Craig Tullis Sep 14 '14 at 20:42
2

Another using the shell

echo -n 'right' | openssl sha1 -binary | openssl sha1 -hex | \
    sed 's/^.* //' | \
    awk '{print "*"toupper($0)}'

...which outputs:

*920018161824B14A1067A69626595E68CB8284CB
  • 1
    It prints `*(STDIN)= 920018161824B14A1067A69626595E68CB8284CB` in Debian bash. But +1 for an intuitive alternative way. – o.v Dec 23 '20 at 10:33
  • @o.v thanks for commenting that issue - fixed above with the `sed` command – Chris Martin Jan 03 '21 at 20:15
1

If you crated a user and forgotten the password this is what you should do and it's easier.

This also happened to me a dozen times while I was doing 10 billion things at once. The best way that I recovered my password was:

stopped the mysql server completely first

issued mysqld_safe --skip-grant-tables &

then I logged in as root without issuing a password, just mysql -u mysql-user (it lets you in after the mysqld_safe)

then go to the mysql > user table and update the password for the user

then go back and restart mysql

see if that works and let us know.

unixmiah
  • 348
  • 1
  • 12
  • This seems like it would be more for the case that you can't log in *at all*, rather than just as a specific user. – mwfearnley Jun 26 '17 at 13:41
0

MySQL 4.1+ uses double SHA1

> SELECT PASSWORD("right")
*920018161824B14A1067A69626595E68CB8284CB

> SELECT SHA1(UNHEX(SHA1("right")))
920018161824B14A1067A69626595E68CB8284CB

sh-3.2# php -r 'echo "*" . sha1(sha1("right", TRUE)). "\n";'
*920018161824b14a1067a69626595e68cb8284cb

This algorithm can be easily ported to other languages​​. A difference is that password hashes in the "select password" always begin with a “*” character.

0

Python3 one liner, in case it's useful to anyone:

python3 -c 'from hashlib import sha1; print(f"""*{sha1(sha1("right".encode()).digest()).hexdigest().upper()}""")'

*920018161824B14A1067A69626595E68CB8284CB