Tuesday, January 29, 2019

Security Snippet Number 1


Common Weakness Enumerations can be found at https://cwe.mitre.org/data/definitions/699.html

CWE-129: Improper Validation of Array Index

Description

The product uses untrusted input when calculating or using an array index, but the product does not validate or incorrectly validates the index to ensure the index references a valid position within the array.

Demonstrative Examples

Example 1 : Java language

public String getValue(int index) {
  return array[index];
}
This may result in ArrayIndexOutOfBounds Exception being raised if index is outside the range of the array.

Example 2: Java language

private void buildList (int untrustedListSize) {
  if ( 0 > untrustedListSize ) {
    die(“Negative value supplied for list size, die evil hacker!”);
  }
  Widget[] list = new Widget[ untrustedListSize ];
  list[0] = new Widget()’
}
This example attempts to build a list from a user-specified value, and even checks to ensure a non-negative value is supplied. If, however, a 0 value is provided, the code will build an array of size 0 and then try to store a new Widget in the first location, causing an exception to be thrown.

Example 3: C language

int getValueFromArray(int *array, int len, int index) {

int value;

// check that the array index is less than the maximum

// length of the array
if (index < len) {

// get the value at the specified index of the array
value = array[index];
}
// if array index is invalid then output error message

// and return value indicating error
else {
printf("Value is: %d\n", array[index]);
value = -1;
}

return value;
}
This method only verifies that the given array index is less than the maximum length of the array but does not check for the minimum value (CWE-839). This will allow a negative value to be accepted as the input array index, which will result in a out of bounds read (CWE-125) and may allow access to sensitive memory. The input array index should be checked to verify that is within the maximum and minimum range required for the array (CWE-129).

Example 4: C language

int main (int argc, char **argv) {
  char *items[] = {"boat", "car", "truck", "train"};
  int index = GetUntrustedOffset();
  printf("You selected %s\n", items[index-1]);
}
The programmer allows the user to specify which element in the list to select, however an attacker can provide an out-of-bounds offset, resulting in a buffer over-read (CWE-126).

Potential Mitigations using the Ada language

Ada allows the programmer to define numeric types and subtypes with a specified range of valid values. All instances of a specified numeric type must all satisfy the range validity requirements specified for that type.
Example 3 above defines a function returning an int. The function has two parameters, a pointer to an int, which is intended to point to an array of ints, and an int index value which is intended to specify an index in the array.
Within the function a check is made for an invalid index value and the int value -1 is returned if an error is detected. Nowhere in the description of the array or the function is there any restriction on the range of values any of these ints can contain. For instance, it is completely valid for the array to contain negative values, including -1. If -1 is also used to indicate an error then the program can never distinguish between an error and an array value of -1. Much must be changed to fix this fault.

Mitigation 1:

function getIndex(index : Positive) return String with
   Pre => index in String_Array’Range;

function getIndex(index : Positive) return String is
begin
   return String_Array(index);
end getIndex;
The function specification establishes a pre-condition requiring the parameter index to be within the range of index values associated with String_Array. The pre-condition assures that the index value used within the getIndex function is a valid index of String_Array.

Mitigation 2:

generic
   type Element_Type is private;
package List_Handler is
   type List(Size : Positive) is tagged private;
private
   type Element_Array is array (Positive range <>) of Element_Type;
   type List(Size : Positive) is tagged record
      Buffer : Element_Array(1..Size);
   end record;
end List_Handler;
The package specification defines a generic package that can be instantiated with any type, creating a “List” of that type. The type List is defined with a discriminant value named Size which determines the size of the array to be used for a particular instance of List. The discriminant Size is required to be a value of the pre-defined subtype Positive. The minimum valid value for an instance of Positive is 1. This prevents the size of the Buffer element in List from being either negative or 0.

Mitigation 3

type Int_Array is array(Natural range <>) of Integer;
...
function getValueFromArray(Nums : Int_Array; index : Natural) return Integer
   with Pre => index in Nums’Range;

function getValueFromArray(Nums : Int_Array; index : Natural) return Integer is
begin
   return Nums(index);
end getValueFromArray;
The type Int_Array is defined as being indexed by a value of the pre-defined subtype Natural. The minimum value of an instance of Natural is 0. The pre-condition assures that the value of index is within the valid index values for any instance of Int_Array passed to the function. The function getValueFromArray always returns a valid array element when the pre-condition is satisfied. If the pre-condition is not satisfied the call results in an Assertion_Error exception being raised.

Mitigation 3 alternate

This mitigation fixes the indexing problems without the use of pre-conditions.
type Result_Type(Is_Valid : Boolean) is record
   case Is_Valid is
      when True => Value : Integer;
      when False => null;
   end case;
end record;

type Int_Array is array(Natural range <>) of Integer;

function getValueFromArray(Nums : Int_Array; Index : Natural)
                                         return Result_Type is
begin
   if Index in Nums’Range then
      return (Is_Valid => True, Value => Nums(Index));
   else
      return (Is_Valid => False);
   end if;
end getValueFromArray;
The type Result_Type is defined as a variant record. When the discriminant, named Is_Valid, is True the type contains two fields; Is_Valid and Value. When the discriminant Is_Valid is False the type only contains the field Is_Valid.
The conditional expression tests the parameter Index. If Index contains a value within the valid range of index values for the array Nums then the function returns an instance of Result_Type with the field Is_Valid containing True and the field Value containing the integer value that was in Nums(Index), otherwise the function returns an instance of Result_Type only containing the field Is_Valid and that field contains a False value.
This solution clearly separates the concept of an erroneous index value from any value contained in the array to be searched. Use of the variant record allows the function to return two values at the same time. No Value field is returned when the index is invalid because to do so would suggest that a valid value was found. This solution prevents a programmer from erroneously using an invalid return value.

Mitigation 4

with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Integer_IO; use Ada.Integer_IO;

procedure main is
   subtype Item_Index is Integer range 1..4;
   type Item_List is array(Index_Type) of Unbounded_String;
  
   function getOffset return Item_Index is
      Offset : Integer;
   begin
      loop
         Put(“Enter a number in the range of 1 through 4: “);
         Get(Offset);
         exit when Offset in Item_Index;
      end loop;
      return Offset;
   end getOffset;

   Items : Item_List := (To_Unbounded_String(“boat”),
                         To_Unbounded_String(“car”),
                         To_Unbounded_String(“truck”),
                         To_Unbounded_String(“train”));
   index : Item_Index := getOffset;
begin
   Put_Line(“You selected “ & To_String(Item_List(index)));
end main;
The programmer allows the user to specify the element to select and the selection will only access the array after a valid index value has been chosen.
The function getOffset takes no parameters and returns a value of the subtype Item_Index. The simple loop statement continually prompts the user until the user enters a valid value. The function then returns that value. The array of Unbounded_String is only accessed after a valid index value has been obtained from the user.

Conclusion

These examples show that CWE-129 Improper Validation of Array Index is far simpler to avoid using Ada than using C, C++, or Java.

No comments:

Post a Comment

Comparison of three algorithms for summing an array of integers

This article shares a comparison of the time taken to sum an array of integers. This article tests three algorithms for summing the array. •...