Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Perl, unlike most other languages, uses arrays that are not declared with a particular length , and that may grow and shrink in size as is required by subsequent code. In fact, when assigning a value to an element within the array, if the index provided is beyond the end of the array, the array grows to make it valid. Consider the following example:

Code Block
langperl

my @array = (1, 2, 3);   # array contains 3 elements
$array[5] = 0;           # array grows to contain 6 elements
my $value = $array[7];   # array unchanged + uninitialized value warning
$value = $array[-7];     # array unchanged + uninitialized value warning
if (exists $array[9]) {  # false, array unchanged
  print "That's a big array.\n";
}

This automatic growth only occurs if only if the index provided is positive , and the array value is being written, not read, and not passed to a testing function like exists() or defined().

If an attacker is able to substitute a number to be used as an array index , and they provide provides the value 1000000000 (one 1 billion), then Perl will happily try to grow the array to one to 1 billion elements. Depending on the platform's capabilities, this might fail, or hang, or simply cause Perl to consume several gigabytes of memory for the lifetime of the array. As  Because this can cause a denial of sevice, attackers must not be permitted to control array indices.

...

This noncompliant code example takes a set of users via standard input , and adds them to an array, indexed by their UIDs. This program may, for instance, be fed the contents of the /etc/passwd file.

Code Block
bgColor#ffcccc
langperl

my @users;

while (<STDIN>) {
  my ($username, $dummy, $uid) = split( /:/);
  if (not (defined( $uid) and defined( $username))) {next;}
  if (not $uid =~ /^\d*$/) {next;}
  $users[$uid] = $username;
}

# ... Work with @users

...

Code Block
bgColor#ccccff
langperl

my @users;
my $max_uid = 10000;

while (<STDIN>) {
  my ($username, $dummy, $uid) = split( /:/);
  if (not (defined( $uid) and defined( $username))) {next;}
  if (not $uid =~ /^\d*$/) {next;}
  if ($uid > $max_uid) {next;}
  $users[$uid] = $username;
}

# ... Work with @users

...