Over a million developers have joined DZone.

use lib '.' Considered Harmful (Exploits Discussed)

DZone's Guide to

use lib '.' Considered Harmful (Exploits Discussed)

A pearl of wisdom about how to protect yourself from a security lapse that is surprisingly common in Perl code.

· Web Dev Zone
Free Resource

Never build auth again! Okta makes it simple to implement authentication, authorization, MFA and more in minutes. Try the free developer API today! 

With the discussion of CVE-2016-1238, a quick-and-easy fix for broken code that has been suggested is to add the following line to the top of broken Perl scripts (Note: this applies to Perl as run anywhere, whether pl/perlU, plain perl, or something else):

 use lib '.'; 

In some corners, this has become the go-to solution for the problem (pun quite deliberate).  It works, gets the job done, and introduces subtle, hidden, and extremely dangerous problems in the process.

For those interested in the concerns specific to PostgreSQL, these will be discussed near the end of this article.

Security and the Garden Path

I am borrowing an idea here from linguistics, the idea of the garden path, as something that I think highlights a lot of subtle security problems. Consider the newspaper headline "Number of Lothian patients made ill by drinking rockets." Starts off simple enough, and then you get to the end, realizing you must have misread it (and you did, probably, since the number of patients increased who were made ill by drinking, not that some people got sick because they drank hydrazine). The obvious reading and the logical reading diverge and this leads to a lot of fun in linguistic circles.

The same basic problem occurs with regard to security problems. Usually, security problems occur because of two problems. Either people do something obviously insecure (plain text authentication for FTP users where it matters) or they do something that looks on the surface like it is secure but behind the scenes does something unexpected.

Perl here has a few surprises here because parsing and running a script is a multi-pass process but we tend to read it as a single pass. Normally these don't cause real problems but in certain cases, there are very subtle dangers lurking. Here, with  use lib '.' , it is possible to inject code into a running program as long as an attacker can get a file placed in the current working directory of the program.

Relative paths, including the current working directory, do have legitimate use cases, but the problems and pitfalls must be understood before selecting this method.

What the Lib Pragma Does

Perl looks for files to require or include based on an array of paths, globally defined, called @INC. Use lib stores a copy of the original lib at first use, and then ensures that the directory specified occurs at the start of the search order. So directories specified with use lib are searched before the default library directories. This becomes important as we look at how Perl programs get executed.

How Perl Runs a Program

Perl runs a program in two passes. First, it creates the parse tree, then it runs the program. This is a recursive process and because of how it works, it is possible for malicious code that gets accidently run in this process to transparently inject code into this (and other portions) of the Perl process.

Keep in mind that this makes Perl a very dynamic language which, on one hand, has serious garden path issues, but on the other ensures that it is an amazingly flexible language.

During the parse stage, Perl systematically works through the file, generating a parse tree, and running any "BEGIN" blocks, "use" statements, and "no" statements. This means that injected code can be run even if later sytnax errors appear to prevent the bulk of the program from running at all or if earlier errors cause run-time exception.

After this process finishes, Perl executes the parse tree that results. This means that Perl code can rewrite the parse tree before your code is ever really written and that code can be inserted into that part of the process.

Transparent Code Injection During 'Use'

Consider a simple Perl script:


use lib '.';
use Cwd;
use 5.010;
use strict;
use warnings;

say getcwd();

Looks straightforward. And, in most cases, it will do exactly what it looks like it does. It loads the standard Cwd module and prints out the current working directory.

However, suppose I run it in a different directory, where I add two additional files:

Cwd.pm contains:

package Cwd;
use Injected;

Hmmmm... that doesn't look good. What does Injected.pm do?

package Injected;
use strict;

sub import {
   local @INC = @INC;
   my ($module) = caller;
   warn $module;
   delete $INC{'Injected.pm'};
   delete $INC{"$module.pm"};
   @INC = grep { $_ ne '.' } @INC;
   eval "require $module";
   warn "Got you!, via $module";

So, when Cwd imports Injected, it deletes itself from the memory of having been included, deletes its caller too, reloads the correct caller (not from the current working directory) and then executes some code (here a harmless warning).

Cwd.pm then returns success.

test.pl runs Cwd->import() which is now the correct one, but we have already run unintended code that could in theory do anything.

Any program capable of being run in arbitrary directories, written in Perl, which has this line in it ( use lib '.' ) is subject to arbitrary code injection attacks using any module in the dependency tree, required or not.

Instead, Do the Opposite (Where You Can)

As a standard part of boilerplate in any secure Perl program, I strongly recommend adding the following line to the top of any script. As long as modules don't add it back in behind your back (would be extremely rare that they would), adding the following line:

 no lib '.'; 

Note that this strips out the current working directory even if it is supplied as a command-line argument. S,o it may not be possible in all cases. So, use common sense and do some testing, and document this as desired behavior. Note one can still invoke with perl -I./. in most cases so it is possible to turn this safety off... Additionally, if you put that at the start of your module, something you include could possibly put it back in.

Safer Alternatives

In a case where you need a path relative to the script being executed, FindBin is the ideal solution. It gives you a fixed path relative to the script being run, which is usually sufficient for most cases of an application being installed on a system as a third party.  So instead you would do:

use FindBin;
use lib $FindBin::Bin;

Then the script's directory will be in the include path.

PL/PerlU Notes:

I always add the explicit rejection of cwd in my plperlu functions. However, if someone has a program that is broken by CVE-2016-1238 related fixes, it is possible that someone would add a  use lib '.'  to a Perl module, which is a bad idea. As discussed in the previous post, careful code review is required to be absolutely safe. Additionally, it is a very good idea to periodically check the PostgreSQL data directory for Perl modules which would indicate a compromised system.

Launch your application faster with Okta’s user management API. Register today for the free forever developer edition!

perl ,security ,hacking

Published at DZone with permission of Chris Travers, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.


Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.


{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}