代码质量不佳会导致不可预测的行为。对于用户来说,通常表现为可用性差。对于攻击者来说,提供了以意外方式对系统施加压力的机会。
free()
,会引发 buffer overflow。free()
时,会出现 Double free 错误。free()
,会导致 buffer overflow。当程序使用同一参数两次调用 free()
时,程序中的内存管理数据结构会遭到破坏。这种破坏会导致程序崩溃。有时在某些情况下,还会导致两次调用 malloc()
延迟,而返回相同的指针。如果 malloc()
两次都返回同一个值,稍候程序便会允许攻击者控制整个已经写入双倍分配内存的数据,从而使程序更加容易受到 buffer overflow 的攻击。
char* ptr = (char*)malloc (SIZE);
...
if (abrt) {
free(ptr);
}
...
free(ptr);
#include <stdio.h>
int main() {
/* Nothing to see here; newline RLI /*/ return 0 ;
printf("Do we get here?\n");
return 0;
}
Example 1
中,从右到左隔离 (RLI) Unicode 双向控制字符会导致代码如下所示:
#include <stdio.h>
int main() {
/* Nothing to see here; newline; return 0 /*/
printf("Do we get here?\n");
return 0;
}
strncpy()
),使用方式不正确也会引发漏洞。对内存的处理加之有关数据段大小和结构方面所存在种种错误假设,是导致大多数 buffer overflow 漏洞产生的根源。
void wrongNumberArgs(char *s, float f, int d) {
char buf[1024];
sprintf(buf, "Wrong number of %.512s");
}
strncpy()
),使用方式不正确也会引发漏洞。对内存的处理加之有关数据段大小和结构方面所存在种种错误假设,是导致大多数 buffer overflow 漏洞产生的根源。%d
格式说明符将一个浮点转换为 f
。
void ArgTypeMismatch(float f, int d, char *s, wchar *ws) {
char buf[1024];
sprintf(buf, "Wrong type of %d", f);
...
}
Intent
。隐式的内部意图可能会使系统遭受对内部组件的中间人攻击。Intent
使用内部组件定义的自定义操作。隐式意图可以促进从任何给定外部组件调用意图,而无需了解特定组件。将两者结合起来使应用程序能够从所需的应用程序上下文外部访问为特定内部使用指定的意图。Intent
的能力可以实现各种严重程度不等的中间人攻击,从信息泄露、拒绝服务到远程代码执行,具体取决于 Intent
指定的内部操作的能力。Intent
。
...
val imp_internal_intent_action = Intent("INTERNAL_ACTION_HERE")
startActivity(imp_internal_intent_action)
...
PendingIntent
。隐式待定意图可能会导致安全漏洞,例如拒绝服务、私人和系统信息泄漏以及权限提升。Intent
。隐式意图有助于从任何给定的外部组件调用意图,使用通用名称和筛选器来确定执行。Intent
创建为 PendingIntent
,这可能允许将 Intent
发送到在预期时间上下文之外运行的非预期组件,从而使系统容易受到拒绝服务、私人和系统信息泄露以及权限提升等攻击途径。PendingIntent
。
...
val imp_intent = Intent()
val flag_mut = PendingIntent.FLAG_MUTABLE
val pi_flagmutable_impintintent = PendingIntent.getService(
this,
0,
imp_intent,
flag_mut
)
...
PendingIntent
,其标记值设置为 FLAG_MUTABLE
。使用标记值 FLAG_MUTABLE
创建的待定意图很容易在下游设置未指定的 Intent
字段,这样会修改 Intent
的容量并使系统容易受到攻击。PendingIntent
后修改其底层 Intent
可能会使系统容易受到攻击。这主要取决于底层 Intent
的整体功能。在大多数情况下,最佳实践是通过将 PendingIntent
标记设置为 FLAG_IMMUTABLE
来防止发生潜在问题。FLAG_MUTABLE
创建的 PendingIntent
。
...
val intent_flag_mut = Intent(Intent.ACTION_GTALK_SERVICE_DISCONNECTED, Uri.EMPTY, this, DownloadService::class.java)
val flag_mut = PendingIntent.FLAG_MUTABLE
val pi_flagmutable = PendingIntent.getService(
this,
0,
intent_flag_mut,
flag_mut
)
...
read()
后没有返回预期的字节数,以下 C 函数将会泄漏已分配的内存块的信息:
char* getBlock(int fd) {
char* buf = (char*) malloc(BLOCK_SIZE);
if (!buf) {
return NULL;
}
if (read(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) {
return NULL;
}
return buf;
}
CALL "CBL_ALLOC_MEM"
USING mem-pointer
BY VALUE mem-size
BY VALUE flags
RETURNING status-code
END-CALL
IF status-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
SET ADDRESS OF mem TO mem-pointer
END-IF
PERFORM write-data
IF ws-status-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
DISPLAY "Success!"
END-IF
CALL "CBL_FREE_MEM"
USING BY VALUE mem-pointer
RETURNING status-code
END-CALL
GOBACK
.
dealloc()
方法中未能将其释放。init()
方法分配内存,但无法通过 deallocate()
方法将其释放,导致 memory leak:
- (void)init
{
myVar = [NSString alloc] init];
...
}
- (void)dealloc
{
[otherVar release];
}
realloc()
调用无法调整初始分配的大小,以下 C 函数会泄漏一块分配的内存。
char* getBlocks(int fd) {
int amt;
int request = BLOCK_SIZE;
char* buf = (char*) malloc(BLOCK_SIZE + 1);
if (!buf) {
goto ERR;
}
amt = read(fd, buf, request);
while ((amt % BLOCK_SIZE) != 0) {
if (amt < request) {
goto ERR;
}
request = request + BLOCK_SIZE;
buf = realloc(buf, request);
if (!buf) {
goto ERR;
}
amt = read(fd, buf, request);
}
return buf;
ERR:
if (buf) {
free(buf);
}
return NULL;
}
realloc()
无法调整原始分配的大小,则以下 Micro Focus COBOL 程序会泄漏已分配内存块。
CALL "malloc" USING
BY VALUE mem-size
RETURNING mem-pointer
END-CALL
ADD 1000 TO mem-size
CALL "realloc" USING
BY VALUE mem-pointer
BY VALUE mem-size
RETURNING mem-pointer
END-CALL
IF mem-pointer <> null
CALL "free" USING
BY VALUE mem-pointer
END-CALL
END-IF
NullException
。cmd
”的属性。如果攻击者可以控制程序的环境,从而使“cmd
”处于未定义状态,则它就会在尝试调用 Trim()
方法时抛出一个 null 指针异常。
string cmd = null;
...
cmd = Environment.GetEnvironmentVariable("cmd");
cmd = cmd.Trim();
null
的指针是否为 null
之前间接引用该指针,则会发生 check-after-dereference 错误。如果程序明确检查过 null
,并确定该指针为 null
,但仍继续间接引用该指针,则会出现 dereference-after-check 错误。此类错误通常是由于错别字或程序员疏忽造成的。如果程序明确将指针设置为 null
,但稍后却间接引用该指针,则将出现 dereference-after-store 错误。此错误通常是因为程序员在声明变量时将该变量初始化为 null
所致。ptr
不是 NULL
。当程序员间接引用该指针时,这个假设就会清晰的体现出来。当程序员检查 ptr
是否为 NULL
时,就会与该假设发生矛盾。当在 if
语句中检查时,如果 ptr
可以为 NULL
,则在其间接引用时也将为 NULL
,并引起 segmentation fault。示例 2:在下列代码中,程序员会确认变量
ptr->field = val;
...
if (ptr != NULL) {
...
}
ptr
为 NULL
,然后错误地对其进行间接引用。如果在 if
语句中检查 ptr
时其为 NULL
,则会发生 null
dereference,从而导致分段故障。示例 3:在下列代码中,程序员忘记了字符串
if (ptr == null) {
ptr->field = val;
...
}
'\0'
实际上为 0 还是 NULL
,从而间接引用 null 指针并引发分段故障。示例 4:在下列代码中,程序员会将变量
if (ptr == '\0') {
*ptr = val;
...
}
ptr
明确设置为 NULL
。之后,程序员会间接引用 ptr
,而未检查对象是否为 null
值。
*ptr = NULL;
...
ptr->field = val;
...
}
NullPointerException
。cmd
”的属性。如果攻击者可以控制程序的环境,从而使“cmd
”处于未定义状态,则它就会在尝试调用 trim()
方法时抛出一个 null 指针异常。
String val = null;
...
cmd = System.getProperty("cmd");
if (cmd)
val = util.translateCommand(cmd);
...
cmd = val.trim();
SqlClientPermission
对象,它规定了用户如何连接到数据库。在此示例中,程序将 false
作为第二个参数传递给构造函数,以控制是否允许用户使用空密码进行连接。将 false 传递给此参数意味着不允许使用空密码。
...
SCP = new SqlClientPermission(pstate, false);
...
PermissionState
对象代替了任何传递给第二个参数的值,所以这个构造函数允许使用空密码连接到数据库,这与第二个参数相矛盾。要禁止使用空密码,程序应该把 PermissionState.None
传递给构造函数的第一个参数。由于其功能尚不明确,因此不赞成采用 SqlClientPermission
构造函数的“双参数”版本,而建议采用“单参数”版本(与“双参数”版本功能相同但是避免了被误译的风险)。getpw()
来验证明文密码是否与用户加密密码相匹配。如果密码是有效的,则函数将 result
设为 1;如果无效,将其设为 0。
...
getpw(uid, pwdline);
for (i=0; i<3; i++){
cryptpw=strtok(pwdline, ":");
pwdline=0;
}
result = strcmp(crypt(plainpw,cryptpw), cryptpw) == 0;
...
getpw(
) 函数从安全角度来说是有问题的,因为它可以溢出传递给它的第二个参数的缓冲区。因为这个漏洞,getpw()
已由 getpwuid()
替代,它与 getpw()
执行相同的查找,但返回一个指向静态分配结构的指针来降低风险。
...
String name = new String(nameBytes, highByte);
...
nameBytes
表示的字符串进行编码。由于用于编码字符串的字符集的演变,此构造函数已被弃用,取而代之的是接受用于编码字节进行转换的 charset
的名称作为其参数之一的构造函数。Digest::HMAC
stdlib,由于在发布过程中意外参与,因此在文档中明确不鼓励使用。
require 'digest/hmac'
hmac = Digest::HMAC.new("foo", Digest::RMD160)
...
hmac.update(buf)
...
Digest::HMAC
类在由于偶然纳入版本中而介入时立即被弃用。由于代码是试验性的且未经正确测试,导致类存在不按预期工作的可能性,因此绝对禁止使用该类,尤其是考虑到关系 HMAC 与加密功能有关。IsBadXXXPtr()
类的函数有多种原因。这些函数是:IsBadWritePtr()
尝试避免错误的内存写入。
if (IsBadWritePtr(ptr, length))
{
[handle error]
}
public class Totaller {
private int total;
public int total() {
...
}
}
synchronized(this) { }
int un$afe;
r
赋值,并在没有使用所赋数值的情况下,对其加以重写。
int r = getNum();
r = getNewNum(buf);
r
赋值,并在没有使用所赋数值的情况下,对其加以重写。
int r = getNum();
r = getNewNum(buf);
r
赋值,并在没有使用所赋数值的情况下,对其加以重写。
r = getName();
r = getNewBuffer(buf);
r
赋值,并在没有使用所赋数值的情况下,对其加以重写。
r = getName();
r = getNewBuffer(buf);
i
) 使用了两次,而变量 j
却从未使用。
int i,j;
for (i=0; i < outer; i++) {
for (i=0; i < inner; i++) {
...