输入验证与表示问题是由元字符、交替编码和数字表示引起的。安全问题源于信任输入。这些问题包括:“Buffer Overflows”、“Cross-Site Scripting”攻击、“SQL Injection”等其他问题。
send
函数及其变体使得程序员可以变通函数上的 Ruby 访问说明符。尤其是,它允许程序员访问私有和受保护的字段和函数,这是通常禁止的行为。paramName
URL 参数的转换或验证的可创建书签的示例视图。
...
<bookmark>
<method>#{paramHandler.handleParams}</method>
<url-parameter>
<name>paramName</name>
<value>#{requestScope.paramName}</value>
</url-parameter>
</bookmark>
...
userClassPath
,来确定在其中搜索要加载的类的目录。
...
productCategory = this.getIntent().getExtras().getString("userClassPath");
DexClassLoader dexClassLoader = new DexClassLoader(productCategory, optimizedDexOutputPath.getAbsolutePath(), null, getClassLoader());
...
userClassPath
的结果修改为指向他们控制的不同路径,以提升的应用程序权限加载库并可能执行任意代码。因为程序不验证从环境读取的值,如果攻击者能够控制 userClassPath
的值,那么他们就可以欺骗应用程序指向他们控制的目录,从而使用与原始应用程序一样的权限加载他们已经定义的类。userOutput
,来确定应将优化的 DEX 文件写入的目录。
...
productCategory = this.getIntent().getExtras().getString("userOutput");
DexClassLoader dexClassLoader = new DexClassLoader(sanitizedPath, productCategory, null, getClassLoader());
...
userOutput
的值更改为他们控制的目录,例如外部存储。一旦达到这一目的,便可以很轻松地将输出的 ODEX 文件替换为恶意 ODEX 文件,并使用与原始应用程序一样的权限加以执行。ModelState.IsValid
检查模型是否通过验证。class.classLoader
,此类属性将允许攻击者覆盖系统属性并可能会执行任意代码。
String prop = request.getParameter('prop');
String value = request.getParameter('value');
HashMap properties = new HashMap();
properties.put(prop, value);
BeanUtils.populate(user, properties);
strncpy()
),使用方式不正确也会引发漏洞。对内存的处理加之有关数据段大小和结构方面所存在种种错误假设,是导致大多数 buffer overflow 漏洞产生的根源。gets()
函数将一个任意大小的数据读取到堆栈缓冲区中。因为没有什么方法可以限制该函数读取数据的量,所以代码的安全性就依赖于用户始终输入比 BUFSIZE
少的字符数量。例 1.b:这一例子表明模仿 C++ 中
...
char buf[BUFSIZE];
gets(buf);
...
gets()
函数的不安全行为是如此的简单,只要通过使用 >>
运算符将输入读取到 char[]
字符串中。例 2:虽然本例中的代码也是依赖于用户输入来控制代码行为,但是它通过使用边界内存复制函数
...
char buf[BUFSIZE];
cin >> (buf);
...
memcpy()
增加了一个间接级。该函数接受一个目标缓冲区、一个起始缓冲区和要复制的字节数。虽然输入缓冲区由 read()
的边界调用填充,但是 memcpy()
复制的字节数需要由用户指定。
...
char buf[64], in[MAX_SIZE];
printf("Enter buffer contents:\n");
read(0, in, MAX_SIZE-1);
printf("Bytes to copy:\n");
scanf("%d", &bytes);
memcpy(buf, in, bytes);
...
lccopy()
的函数将一个字符串作为其变量,然后返回一个堆分配字符串副本,并将该字符串的所有大写字母转化成了小写字母。因为该函数认为 str
总是比 BUFSIZE
小,所以它不会对输入执行任何边界检查。如果攻击者避开对调用 lccopy()
代码的检查,或者如果更改代码,使得程序员对 str
长度的原有假设与实际不符,那么 lccopy()
就会通过无边界调用 strcpy()
溢出 buf
。示例 4:以下代码演示了第三种情况,代码非常复杂,无法轻松预测其行为。该代码来自通用的 libPNG 图像解码器,众多应用程序使用的都是该解码器。
char *lccopy(const char *str) {
char buf[BUFSIZE];
char *p;
strcpy(buf, str);
for (p = buf; *p; p++) {
if (isupper(*p)) {
*p = tolower(*p);
}
}
return strdup(buf);
}
png_crc_read()
复制的数据量。然而,在测试长度前,该代码会立即对 png_ptr->mode
执行检查,如果检查失败,便会发出一个警告,然后会继续进行处理。因为 length
测试在 else if
块中进行,如果针对该代码的首次测试失败,那么就不会再测试 length
,而将其盲目地用于调用 png_crc_read()
,因此很容易引起堆栈 Buffer Overflow。例 5:本例同样演示了第三种情况,程序过于复杂,使其暴露出 buffer overflow 的问题。在这种情况下,问题出现的原因在于其中某个函数的接口不明确,而不是代码结构(同上一个例子中描述的情况一样)。
if (!(png_ptr->mode & PNG_HAVE_PLTE)) {
/* Should be an error, but we can cope with it */
png_warning(png_ptr, "Missing PLTE before tRNS");
}
else if (length > (png_uint_32)png_ptr->num_palette) {
png_warning(png_ptr, "Incorrect tRNS chunk length");
png_crc_finish(png_ptr, length);
return;
}
...
png_crc_read(png_ptr, readbuf, (png_size_t)length);
getUserInfo()
函数采用一个定义为多字节字符串的用户名和一个指向用户信息结构的指针,这一结构由该用户的相关信息填充。因为 Windows authentication 中的用户名使用 Unicode,所以 username
参数首先要从多字节字符串转换成 Unicode 字符串。然后,这个函数便会错误地将 unicodeUser
的长度以字节形式而不是字符形式传递出去。调用 MultiByteToWideChar()
可能会把 (UNLEN+1)*sizeof(WCHAR)
宽字符或者(UNLEN+1)*sizeof(WCHAR)*sizeof(WCHAR)
字节,写到 unicodeUser
数组,该数组仅分配了 (UNLEN+1)*sizeof(WCHAR)
个字节。如果 username
字符串包含了多于 UNLEN
的字符,那么调用 MultiByteToWideChar()
将会溢出 unicodeUser
缓冲区。
void getUserInfo(char *username, struct _USER_INFO_2 info){
WCHAR unicodeUser[UNLEN+1];
MultiByteToWideChar(CP_ACP, 0, username, -1,
unicodeUser, sizeof(unicodeUser));
NetUserGetInfo(NULL, unicodeUser, 2, (LPBYTE *)&info);
}
strncpy()
),使用方式不正确也会引发漏洞。对内存的处理加之有关数据段大小和结构方面所存在种种错误假设,是导致大多数 buffer overflow 漏洞产生的根源。c
,因为 double
类型需要的空间超过分配给 c
的空间。
void formatString(double d) {
char c;
scanf("%d", &c)
}