While taint checking would not have helped with this Webmin bug, the Perl core developers are currently considering changes to Perl's printf family of functions to fail if the format string is tainted. Perl's developers are also working to squash the integer overflow format bug.
Of course, programmers need to be able to untaint data from external sources to make it safe to use, and Perl's powerful, integrated regular expression handling makes this possible. Programmers specify that data must match a certain pattern, and extract only that data that passes this safety check. For common untainting tasks, the CGI::Untaint family of modules makes it a simple function call.
Taint checking is also supported in the de facto standard database module DBI. With taint checking enabled, tainted data cannot be used as SQL statements, as parameters for data to be saved to a database. This taint checking can help ensure that the programmer doesn't inadvertantly open up code to SQL injection attacks. Further, data from a database is marked as tainted upon retrieval.
Insecure dependency in while running with -T switch at ./programname.pl line XX.
With Perl's taint checking enabled, the programmer can't accidentally make this happen. Since $dir comes from an external, untrusted source, it is marked as tainted. "External untrusted source" includes all environment data, data from sockets, and all file input (see the perlsec manual page, at http://perldoc.perl.org/perlsec.html for a complete list). When the Perl interpreter sees that it's asked to execute a command from a tainted string, it refuses:
The intent is that the programmer wants to get a directory name from a web form, and get a list of files in that directory. If an attacker passes the value "; rm -fr /", the actual command executed will be "ls ; rm -fr /", which is two commands: One to list the current directory, and one to delete all the files in the filesystem.
# Now display @files to the user @files = `$cmd`; # Execute shell command and return results $cmd = "ls $dir"; $dir = CGI->param( 'dir' );
Keeping track of which data comes from where can be daunting for the programmer, but Perl has features that make this easier. One of Perl's great unheralded features is variable tainting. Perl considers all data from sources outside of the running program as "tainted." Consider this extremely simplified, extremely dangerous case:
Perl helps prevent errors with untrusted data
The answer to these problems in all cases, especially in the case of Webmin's miniserv.pl program, is to not pass untrusted data into printf format strings.
Please note that miniserv.pl uses Perl's Sys::Syslog module, and that Sys::Syslog uses Perl's internal sprintf function, not the C library. While there is indeed a possibility that an attacker could mount a denial-of-service attack, he should not be able to modify executable code. (However, a recently discovered printf integer overrun discussed at http://www.dyadsecurity.com/adv/perl.adv means that there is indeed a possibility.)
the effects are much less. Perl would allocate a 1,000,000 byte string, which could be a resource drain, or may cause the interpreter to run out of memory, but should not allow executable memory to be modified.
$buffer = sprintf( $untrusted_format, 1 ); $untrusted_format = "%1000000d";
In Perl, while the same sort of bad coding is possible:
The buffer is overrun (unless it is at least 1,000,000 bytes long), potentially smashing executable code and allowing an attacker to inject malicious code bytes to be executed with the permissions of the process.
sprintf( buffer, untrusted_format, 1 ); untrusted_format = "%1000000d";
In C, this can be as simple as:
The problem of using format strings from untrusted sources goes back to C, but doesn't go away with newer dynamic languages like Perl. A printf format string is source code in a mini-language of its own, and should not be brought in from outside sources, regardless of the language being used.
Two articles, "Concerns raised over Perl security flaw" (http://www.networkworld.com/news/2005/113005-perl-flaw.html) and "Danger level rises for Perl app flaws" (http://news.com.com/2100-1002_3-5975954.html), point out an important security hole in the Webmin web administration package. Unfortunately, these articles emphasize that Webmin is written in Perl, as if Perl is the cause of the problem. The problem is not unique to Perl, and Perl actually has a distinctive built-in feature that helps programmers fight this sort of coding error.