Format string vulnerabilities in C programs have been studied
extensively in recent years. The focus has been on the execution of
arbitrary code, although other effects are possible.

For many other programming languages, format string vulnerabilities
are also possible. Given the lack of attention to other languages, it
is highly likely that a large number of applications have these issues
even when they have been audited for other types of vulnerabilities.

For any language that supports format strings, applications that are
written in that language could be subject to format string
vulnerabilities. The impact is specific to the behaviors that are
supported by the format strings, and their interaction with language
internals.

In recent days, Jack Louis of Dyad Security reported on a format
string issue in a Webmin application that is written in Perl
(CVE-2005-3912). He further showed how a problem in the Perl
interpreter itself could allow modification of memory and code
execution in vulnerable apps (CVE-2005-3962).

This paper focuses on format string vulnerabilities at the application
level. It must be emphasized that even if the interpreter problem is
fixed, the impact of format string vulnerabilities will only be
reduced, not completely eliminated.

Excluding problems within the interpreter itself, Perl application
format string vulnerabilities can allow denials of service (primarily
memory or disk consumption), information leaks, and modification of
program variables in ways that may have security implications.

In particular, the sprintf() and printf() functions in Perl can be
abused if an attacker can control the contents of the format string.
Since similar functions are used in C, it is possible that these
functions will be used more frequently by C programmers who are new to
Perl.

It should be noted that Perl's taint checker does not catch some
variants of format string attacks. The behavior differs in Perl 5.004
and 5.6.1 (5.6.1 can identify additional dangerous inputs). However,
modifying the taint checker itself may not be feasible or even
appropriate.

Jean-loup Gailly independently discovered and reported a format string
problem in a Perl application on September 26, 2002 [1]. Arjan de Vet
included format strings and the taint checker in a presentation at
YAPC:Europe in August 2001 [2]. Steve Christey mentioned the
possibility of format strings in PHP applications on April 3, 2003 [3]
and format strings in interpreted languages during a lightning round
talk on vulnerability research gaps at CanSecWest in April 2004 [4].
Jack Louis reported on a format string problem in a Perl application
on November 29, 2005 [5], following it with a description of an
integer wrap within Perl itself that was exploitable via format
strings on December 1, 2005 [6]. The most notable early research on
format strings in C was performed by Tim Newsham in September 2000
[7].

Following are some of the more dangerous specifiers, along with their
implications.

1) Memory or disk consumption

The "%s" specifier, and others that allow field widths to be
defined, can be used to consume a large amount of CPU, memory,
and/or disk, e.g. "%99999s". ("%999999999s" is sufficient to
consume a gigabyte of memory or disk, but it has been reported that
it can also cause the Perl program to crash.)

2) Modification of variables

Using the "%n" specifier, the attacker can modify the values of
certain variables that are provided as arguments to print/sprintf,
possibly altering program behavior in ways that have security
implications. The variable is modified to a number, generally a 0.

The implications of this problem depend on how the program uses the
variables.

If $input is "%10s", then str is formatted with up to 10 spaces
of padding and $a is not modified; but if $input is "%n", then $a
is changed to 0, and the attacker effectively bypasses the check
for authentication.

3) Argument shifting

The "%p" specifier formats a pointer for the next argument to be
processed in the call to *printf. This effectively misdirects or
shifts all remaining arguments to different format specifiers than
the programmer intended. The impact depends on the specific bug.

Argument shifting could also be used to bypass cleansing operations
for other vulnerabilities, by shifting uncleansed values into
variables that contain cleansed values.

4) Altering intended outputs

Any format specifier can alter the intended format of structured
output. This in turn could corrupt files or enable the
exploitation of vulnerabilities in other applications that process
such output. For example, the '%p' specifier, which prints out a
pointer value, could be used to generate integer values that exceed
the expected range of inputs.

But if $index is "%p", the error condition is not detected (since
the string evaluates to 0), and the result would be:

130690 10/01/06 58:42:00

Here, not only does the 'index' value exceed the maximum of 32, but
all the other values are wrong! This is because the %p was used to
format a pointer to the $year+1900 expression. All the other
arguments were then misdirected, and applied to the wrong format
specifier. Thus the month value is formatted as the year, the
seconds value is formatted as the minute, etc.

5) Bypassing cleansing operations

Cleansing operations that remove spaces could be tricked by using
"%2s" or other format specifiers that generate spaces. Programs
may try to remove spaces when passing arguments to commands, or
formatting data.

- IP addresses whose DNS reverse lookup includes format strings
could be returned as the result of gethostbyname().

Log files could be filled easily using "%999s" style strings.

The possibility of CRLF injection was theorized, but a casual
investigation was not successful.

**********************************************************************
4. Some Discussion on Format Strings and the Taint Checker
**********************************************************************

In 5.004:

The taint checker apparently does not flag filenames as tainted
(e.g. as obtained from the readdir() function). Presumably, other
types of "indirect input" may not be tainted. However, it does
identify more direct sources of input such as stdin and environment
variables.

In 5.6.1:

Filenames are tainted, and the taint checker terminates the
program. While the program is safe from exploitation through
dangerous calls, there is still a denial of service, which could be
a problem with critical code that is expected to fully complete its
task, such as a log processing program (although the programmer
should take the possibility of failure into account while running
in taint mode anyway!)

Note that the taint checker does not exit until a *printf-tainted
variable is passed to a dangerous call such as system(). So, if
the program is not tested with specifiers such as '%n' (which
modifies an argument to *printf), then the taint check may not be
discovered.

Attacks such as resource consumption and data format modification
will still work; however, changing the taint checker to exit as
soon as the printf/sprintf is encountered could break existing
programs.

This is a factor though: "testing" sprintf/printf with normal file
names won't directly trigger the taint checker, unless %n is actually
included in the filename; so, if the programmer tests the Perl code,
but does not include the '%n' option, they won't necessarily find the
taint error. However, a later input with '%n' could cause the program
to halt unexpectedly due to the taint error.

Note: the taint checker doesn't complain when system() is called with
arguments in the following fashion:

system("/bin/echo", $tainted_var1, $tainted_var2);

The following example properly generates an error from the taint
checker, using input from stdin:

In 2002, at least 3 different Perl programs were found vulnerable to
format string attacks:

1) ftplogcheck

2) perl-nocem

3) WASD OpenVMS web server

ftplogcheck
-----------

ftplogcheck is a program used for processing wu-ftpd logs and
generating statistics.

It is not part of the wu-ftp distribution.

One portion of ftplogcheck report lists which files were uploaded to
the server by the "anonymous" user. The code is:

printf REPORT "$time $host $filesize $filename $name\n";

If the wu-ftp server is configured to allow uploads from anonymous
users, then attackers can upload files whose names contain malicious
format strings, which are then fed into the $filename variable.

In this case, the attacker could consume memory or disk space by
causing an extremely large report to be generated (if $filename is
"%999999s") or misrepresent the name of the file that has been
uploaded (if $filename is "word1%1sword2", which would generate the
string "word1 word2").

The value of $nid is obtained from a "notice-id" news article header.
It is not sanity-checked; therefore, malicious format strings can be
inserted into this sprintf() call. The $issuer variable is obtained
from an "issuer" header, but this value must be allowed by the
perl-nocem control file. It may be possible to use a wildcard
character and match any issuer.

The $nr variable contains the total number of articles to be canceled,
and the $diff variable attempts to measure the amount of time required
to cancel the articles, generally 0.01 due to an apparent bug.

According to the developer, the scope of this attack is limited: "the
message is printed only after the nocem notice has been PGP-verified,
so the attacker must be one of the trusted cancellers."

Typical input

Assume that 10 articles are to be canceled ($nr = 10) and $diff is
0.01.

With a $nid (Notice-ID header) of "NID" and a $issuer (Issuer
header) of "ISSUER (at) example (dot) com [email concealed]", the log message output would be:

With a Notice-ID of "%9999999s", a large amount of memory and/or
log file space is consumed:

processed notice

[etc.]

Modification of the $diff variable

With a notice-id of "%n", perl-nocem changes the $diff variable to
17 (the length of the "processed notice " substring), as opposed
to its original value (typically 0.01). This changes the error
message to misrepresent how long it took to cancel the articles:

(notice the double-space in "notice by" where the notice-id would
be).

Note that if perl-nocem had used a format string that began with
the "$nid" variable (e.g. "$nid notice processed" instead of
"processed notice $nid"), then the $diff variable would have been
set to 0, and the "$nr / $diff" expression would have caused the
program to exit with a division-by-zero error.

Other output modifications

With a notice-id of "%p", the resulting log message would be like:

processed notice 130498 by [ISSUER] (10 ids, 0.50000 s, 0.0/s)

where the "130498" is an incorrect notice id.

Developer statement:

[This is] not easily exploitable, the message is printed only after
the nocem notice has been PGP-verified, so the attacker must be one
of the trusted cancellers.

Detection of suspicious code is slightly more difficult than it is for
C code. Constant strings can contain Perl entities such as variables
or references, which are inserted into the string before it is passed
to printf/sprintf.

7. Suggestions for Further Research
************************************************************************

This paper is not an exhaustive work, so further research is needed.

Software developers and vulnerability researchers are encouraged to
actively search for format string issues in all programming languages,
not just C and Perl.

Suggested research topics include:

- for each programming language, identify and publicize all builtin
or common library functions that use format strings.

- extend source and binary code analysis tools to look for improper
use of these functions

- audit individual applications that have been previously deemed free
of obvious vulnerabilities, with a focus on format strings

- study the implications of interactions between a high-level
language and the language it is implemented in. For example, there
may be format string analogues to the problems of the null byte in
Perl and PHP programs and their interaction with the underlying C
code.

- further examination of the taint checker (see below)

Note: in the author's limited experience, format string
vulnerabilities do not appear as frequently in Perl or PHP
applications as they do in C programs. However, more focused efforts
are needed before this suspicion can be confirmed.

# This was gleaned from some real-world code, but the print was
# changed to printf.

# Change what filenames are processed via format strings in
# the filenames, such as a file named "%p%n"
#
# You can "erase" a filename by using '%s', and having this "blank"
# filename could throw off the argument count to system or exec calls,
# which could alter behavior. Consider a backup command like
# exec("/bin/cp", file1, file2) where file1 can be "blanked" out
#
# Similarly, you could "erase" portions of a filename with "%n" or
# "%s". The filename ABC.TXT would be equivalent to ABC%n.%nTXT
#
# You can create very long filenames by using '%999s' (for example).

2) Misuse of format string in log processing, for which many Perl
programs have been written. Could cause larger strings than
expected to be written to files or sent to processes; code that
depends on well-formatted input from the program may be subject to
buffer overflow or other issues.