Bug #3284 Multiple tmpfile/symlink vulnerabilities in 'mysqlbug'
Submitted: 24 Mar 2004 9:03 Modified: 8 Apr 2004 0:38
Reporter: Shaun Colley Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Command-line Clients Severity:S3 (Non-critical)
Version:Ver 12.22 Distrib 4.0.18, for portbld-fr OS:FreeBSD (FreeBSD (very likely others))
Assigned to: Sergei Golubchik

[24 Mar 2004 9:03] Shaun Colley
Description:
'mysqlbug' is vulnerable to multiple tmpfile/symlink bugs, all of which can pose a threat to system security and file integrity, particuarly if root invokes 'mysqlbug'.

1) The variable $TEMP is defined with a fairly insecure tmpfile name.

--
# Try to create a secure tmpfile
umask 077
TEMPDIR=/tmp/mysqlbug-$$
mkdir $TEMPDIR || (echo "can not create directory in /tmp, aborting"; exit 1;)
TEMP=${TEMPDIR}/mysqlbug
--

The file is written to insecurely (and blindly, i.e no file checks) using commands such as:

--
cat > $TEMP <<EOF
--

Variations of the $TEMP file are also written to, such as this:

--
cp $TEMP $TEMP.x
--

And $TEMP.tmp is also written to using blind 'echo' invokations and sed, etc...

2) Another, less obvious (slightly less obvious) is how the script handles a user simply exiting the text editor without changing the bug report.  When this happens, the mysqlbug script does the following:

--
if cmp -s $TEMP $TEMP.x
then
  echo "File not changed, no bug report submitted."
  cp $TEMP /tmp/failed-mysql-bugreport
  echo "The raw bug report exists in /tmp/failed-mysql-bugreport"
  echo "If you use this remember that the first lines of the report now is a lie
.."
  exit 1
fi
--

As can be seen, this time a tmpfile isn't even attempted to be created securely, just a quick 'cp' to an unchecked file (/tmp/failed-mysql-bugreport).  This could be bad if a root user had invoked mysqlbug, and then decided that they wanted to gather more info on their potential bug, so exited the text editor (and meanwhile the attacker had symlinked /tmp/failed-mysql-bugreport to /etc/nologin or somewhere...).

How to repeat:
1) This one is a little harder to repeat - this one is more of a race condition, and an attacker would need to have at least done a little preparation to pull of an attack.

--
attacker$ ls -al /nologin
ls: /etc/nologin: No such file or directory

[...]

root# /usr/local/bin/mysqlbug

[attacker VERY quickly does this:]

attacker$ ln -s /etc/nologin /tmp/mysqlbug-<pid>/mysqlbug

[...]

attacker$ ls -al /nologin
-rw-r--r--    1 root     root            0 Mar 24 16:50 /etc/nologin
--

Although I haven't tested, it is possible that when the user is writing the bug report in the fired up text editor, an attacker might be able to delete the tmpfile, and then symlink it somewhere else.  The race condition might be made easier because of the time it takes for a user to type a bug report.  I haven't confirmed this, though.

2) This one is relatively easy, but requires that mysqlbug is started, then when the text editor is fired up by 'mysqlbug', the user decides the exit it.  At this, the script copies the email template rather insecurely into an unverified /tmp file (/tmp/failed-mysql-bugreport).

--
attacker$ ls -al /nologin
ls: /etc/nologin: No such file or directory
attacker$ ln -s /etc/nologin /tmp/failed-mysql-bugreport

[...]

root# mysqlbug

[root decides to exit the text editor that mysqlbug started, because he wants to get more info on his discovered bug]

attacker$ ls -al /nologin
-rw-r--r--    1 root     root            0 Mar 24 16:50 /etc/nologin
---

Suggested fix:
1) I reckon that 'mktemp' could be used to more securely create tempfiles.  I.e

--
mktemp /tmp/temp.XXXXXX
--

Or, more ideally,

--
mktemp -d /tmp/temp.XXXXXX
--

which creates a directory.  From there, we could define $TEMP as mysqlbug.$$, or continue to use 'mktemp' to generate a more secure tmpfile name.  

2) The same workaround as above could be used, or, just don't dump the report at all - just exit mysqlbug.

Another solution for both would be to use 'if' statements to check if the file exists, but this would add extra bloat to the script - mktemp is probably the best way to fix it.

I didn't find any bugs reported in mysqlbug, so I reported this.  Sorry if this has been solved in later releases - I didn't see it in any release notes.
[24 Mar 2004 11:13] Sergei Golubchik
Thank you for your bug report. This issue has been committed to our
source repository of that product and will be incorporated into the
next release.

If necessary, you can access the source repository and build the latest
available version, including the bugfix, yourself. More information 
about accessing the source trees is available at
    http://www.mysql.com/doc/en/Installing_source_tree.html

Additional info:

1) is safe. Directory /tmp/mysqlbug-$$ is created with 0700 permissions.
No attacker will be able to to create a symlink in it.

2) fixed, thank you.
[8 Apr 2004 0:38] Sergei Golubchik
Just to clarify (as this minor issue apparently got a lot of attention :)

The vulnerability was hardly ever exploitable, checking bugs@ archives one can see that we get in average ~60 mysqlbug-generated reports per year. Assuming 4,000,000 installations (one-years old estimation) one can easily see that an average attacker would have to wait for >65,000 years for his sysadmin to call mysqlbug (and then he should make him to abort the procedure and don't send the report :)

Anyway, as said above, the bug was fixed.