in reply to Re^2: Hide DBI password in scripts
in thread Hide DBI password in scripts

We can eliminate the DBIspy threat by copying in the text of the DBI::connect sub to the caller program:

sub DBI::connect { # code from original DBI::connect }

Yes, sure. And I can read it from the script to be executed and look for functions called from the copied DBI::connect. Most trivially, the next function to attack would be the DBD's connect method. A few lines of code should be sufficient to load and patch the DBD before the script starts, very similar to my DBIspy hack.

This of course would have to be updated manually if a new version of DBI was installed.

So you are creating a maintainance nightmare here, for little or no gain.

And, we can assume that the module is write-protected from all except root.

Only if you use the system perl or a local perl installed by root. It won't be protected if perl is installed by the user running the script.

(We can assume root is not compromised).

Now, that's a very bold statement.

With physical access to the machine, root is compromised within minutes on a standard installation of many Linux distributions. Simply because the boot loader does not prevent me from temporarily adding init=/bin/sh rw to the kernel's command line. After that, I have a root shell without a password prompt and can modify any file on the system. Or, I could reboot and run my own Linux from a CD or a USB stick to modify any file on the system. (So yes, you should prevent physical access, add BIOS and boot loader passwords, and encrypt all disks, if secret data is stored on a machine.)

Without physical access, there are still many ways to get root access. Linux has security problems, like any other system. To make things worse, CPU bugs like Meltdown und Spectre hardware bugs can help gaining root access.

But luckily, I don't need root access.

Also, instead of the inode we can use checksums.

Yes, but they won't help you against LD_PRELOAD. The perl script is unmodified, but I will still get the secret.

Heck, I could even break checksum tests from within perl, with a perl loader script that has the following behaviour:

  1. Create a backup copy of, including a-time and m-time (lstat).
  2. Completely replace the content of with an attack script.
  3. exec("",@ARGV), running the attack script.

The attack script does the following:

  1. Restore content from the backup copy. Note: at this point, perl has completely read the attack script from and no longer cares about the content of
  2. Restore the original a-time and m-time of (utime). Now, looks sane and unmodified again, and it is. It will pass any checksum test. But perl is running my attack code.
  3. Remove the backup copy.
  4. Run any code from required to execute secret-keeper (e.g. set up environment variables, file handles, ...)
  5. Run the unmodified, secret-revealing binary, and print out the secret revealed: print qx(./secret-keeper);

secret-keeper has no chance to detect that attack. My loader script is no longer running. Its last action, exec(""), removed all traces from memory. It will look like was started directly by my shell.'s inode and content seem to be unmodified. This is also true for any module might load. Whatever action the original did before running secret-keeper, my attack script has done the same in the fourth step.


Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)