C++内存越界访问
在C++中可以直接用地址来访问内存,并且不会确保这些位置对被引用的内存缓冲区有效。这可能导致在与其他变量、数据结构或者内部程序的数据相关的内存位置上执行读写操作。因此攻击者能够执行任意代码、预期的控制流、读取敏感消息或者导致系统崩溃。
内存越界的种类:
1.可索引资源的错误访问,范围错误。
2.不检查输入大小的缓冲区复制。
3.越界读取。
4.返回超出预期范围的指针值。
5.在缓冲区之前就开始访问内存。
6.越界写入。
7.缓冲区结束偶访问内存位置。
8.长度不正确的缓冲区访问。
9.不受信任的指针取消引用。
10.使用超出范围的指针偏移。
11.未初始化的指针的访问。
12.过期指针取消引用。
13.输入验证不当。
14.数组索引验证不正确。
15.缓冲区大小计算错误。
16.整数溢出或者环绕。
17.有符号到无符号转换错误。
18.没有检查最小检查的数值范围比较。
19.使用不兼容的类型访问,类型混淆。
20.实数的精度或者准确性不足。
常见的内存错误访问例子
例1.代码如下:
void host_lookup(char *user_supplied_addr){ struct hostent *hp; in_addr_t *addr; char hostname[64]; in_addr_t inet_addr(const char *cp); /*routine that ensures user_supplied_addr is in the right format for conversion */ validate_addr_form(user_supplied_addr); addr = inet_addr(user_supplied_addr); hp = gethostbyaddr( addr, sizeof(struct in_addr), AF_INET); strcpy(hostname, hp->h_name); }
例1中的函数分配一个64字节的缓冲区来存储,但是不能保证主机名不会大于64字节,如果指定的地址是很大很长,则该函数可能会覆盖敏感数据暂时放弃控制流。这个示例还包含一个未经检查的返回值,它可能导致NULL指针。
例2.代码如下:
int main (int argc, char **argv) { char *items[] = {"boat", "car", "truck", "train"}; int index = GetUntrustedOffset(); printf("You selected %s\n", items[index-1]); }
如果程序员允许用户指定要选择列表中那个元素,但是攻击者可以提供越界偏移,从而导致缓冲区过度读取。
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; }
这个例子中仅仅是检查了给定数组索引是否小于数组的最大长度,但是不检查最小值,这将允许接受负值作为数组索引,这也会导致越界读取。并可能访问到敏感内存。有检查输入数组索引以验证其是否在数组所需最大和最小范围内。