分享
 
 
 

一种被忽视的构造和整数溢出重现

王朝厨房·作者佚名  2007-01-04
窄屏简体版  字體: |||超大  

Michael Howard

Secure Windows Initiative

摘要:Michael Howard 研究了一种常常被忽略的代码构造,这种构造可能会导致严重的缓冲区溢出问题,然后介绍了一种在没有溢出副作用的情况下执行算术运算的替代方法。

谈谈构造

很奇怪,有如此之多的安全指导文档提示人们注意危险的函数。在 C 和 C++ 中,很少有危险的函数,不过,有一件事是肯定的,有许多危险的开发人员正在使用 C 和 C++。

因此,您可能会问,“Michael,您究竟要讨论什么?”

我得承认,我听腻了一些文档说的所谓某些函数是危险的,您应该使用更安全的类型来代替它们。例如,“不要使用 strcpy,它是危险的。您应该改用 strncpy,因为它是安全的。”没有什么比这更远离实际情况的了。有可能使用 strcpy 的代码是安全的,而调用 strncpy 的却是不安全的代码。

像 strcpy 这样的函数是有潜在 危险的,因为源数据比目标缓冲区大,并且它来自不受信任的源。如果源数据来自一个受信任的源,并且在复制之前经过了有效性测试,则调用 strcpy 就是安全的:

void func(char *p) {

const int MAX = 10;

char buf[MAX + 1];

memset(buf,0,sizeof(buf));

if (p && strlen(p) <= MAX)

strcpy(buf,p);

}

信不信由您,我正好要在某处用到这个例子。有一种常常被忽略的构造可能会导致缓冲区溢出,它不是函数调用。它是这样的:

while ()

*d++ = *s++;

此处没有函数调用,这是 DCOM 中导致出现 Blaster worm 蠕虫病毒的编码构造。在 Buffer Overrun In RPC Interface Could Allow Code Execution 中,您可以读到更多关于此病毒的修复程序的内容。

该代码如下所示:

HRESULT GetMachineName(WCHAR *pwszPath) {

WCHAR wszMachineName[N + 1])

LPWSTR pwszServerName = wszMachineName;

while (*pwszPath != L’\\’ )

*pwszServerName++ = *pwszPath++;

...

}

这里的问题在于,while 循环是以源字符串中的一些字符为界的。它没有为目标缓冲区的大小所限制。换句话说,如果源数据不受信任,就会出现缓冲区溢出。

我编写了一段简单的 Perl 脚本来搜索 C 和 C++ 代码中这些类型的构造。请注意,这段脚本标记的每个实例并不是一个缺陷,您需要确定是否源数据是受信任的。

use strict;

use File::Find;

my $RECURSE = 1;

###################################################

foreach(@ARGV) {

next if /^-./;

if ($RECURSE) {

finddepth(\&processFile,$_);

} else {

find(\&processFile,$_);

}

}

###################################################

sub processFile {

my $FILE;

my $filename = $_;

if (!$RECURSE && ($File::Find::topdir ne $File::Find::dir)) {

$File::Find::prune = 1;

return;

}

# Only accept C/C++ and header extensions

return if (!(/\.[ch](?:pp|xx)?$/i));

warn "$!\n" unless open FILE, "<" . $filename;

# reset line number

$. = 0;

while () {

chomp;

s/^\s+//;

s/\s+$//;

if (/\*\w+\+\+\s{0,}=\s{0,}\*\w+\+\+) {

print $filename . " " . $_ . "\n";

}

}

注这段脚本只查找 *p++ 构造,而不查找 *++p 构造。

假定您发现了一个缺陷,使代码更安全的一种方法是限制被复制的数据不大于目标缓冲区:

HRESULT GetMachineName(WCHAR *pwszPath) {

WCHAR wszMachineName[N + 1])

LPWSTR pwszServerName = wszMachineName;

size_t cbMachineName = N;

while (*pwszPath != L’\\’ && --cbMachineName)

*pwszServerName++ = *pwszPath++;

...

}

最后,对不为目标缓冲区的大小所限制的任何内存复制函数或构造都应该进行严格检查。

返回页首

关于整数溢出的更多介绍

在前面的文章 Reviewing Code for Integer Manipulation Vulnerabilities 中,我讨论了与所谓整数溢出 的简单数学运算相关的安全性缺陷。

最近,作为正在进行的可信赖计算工程系列 (Trustworthy Computing Engineering Series) 的一部分,我给 Microsoft 的工程师做了一次关于整数溢出的讲座。在讲座中,我概述了如何发现整数溢出以及如何修复整数溢出。让我感到吃惊的是,我接收到的许多电子邮件都说我的补救方法很好,但是充满危险。请允许我做一些解释。

在该专栏中,我提到过的代码如下所示:

if (A + B > MAX) return -1;

应该改成这样:

if (A + B >= A && A + B < MAX) {

// cool!

}

三年前就有人指出,一些人会看到这段代码,但是不知道它有什么用,从而可能删除 A+B >= A 部分,因为它看起来纯属多余,而现在,整数溢出又重新出现在您面前。不会吧!

作为回应,我写了下面的头文件,它的意图再明白不过了。是的,它看起来像乱码,但这段乱码却是 x86 汇编语言。我之所以使用汇编语言,是因为它可以使我直接访问 jc 操作数,即按进位转移 (jump-on-carry)。换句话说,它检测数学运算是否会导致溢出。

#ifndef _INC_INTOVERFLOW_

#define _INC_INTOVERFLOW_

#ifdef _X86_

inline bool UAdd(size_t a, size_t b, size_t *r) {

__asm {

mov eax,dword ptr [a]

add eax,dword ptr [b]

mov ecx,dword ptr [r]

mov dword ptr [ecx],eax

jc short j1

mov al,1

jmp short j2

j1:

#ifdef _DEBUG

int 3

#endif

xor al,al

j2:

};

}

inline bool UMul(size_t a, size_t b, size_t *r) {

__asm {

mov eax,dword ptr [a]

mul dword ptr [b]

mov ecx,dword ptr [r]

mov dword ptr [ecx],eax

jc short j1

mov al,1

jmp short j2

j1:

#ifdef _DEBUG

int 3

#endif

xor al,al

j2:

};

}

inline bool UMulAdd(size_t mul1, size_t mul2, size_t add, size_t *r) {

size_t t = 0;

if (UMul(mul1,mul2,&t))

return UAdd(t,add,r);

return false;

}

#else

# error "This code compiles only on 32-bit x86

#endif // _X86_

#endif // _INC_INTOVERFLOW_

请查看这个文件,它包括解释这些函数的简单文档。

返回页首

发现安全漏洞

虽然花了一点时间,但是许多人都找到了漏洞。当通过比较字符串来做出安全决策时,这种比较就应该是区域性不变的比较或字节方式的比较。在这个例子中,我编写的代码可能允许访问土耳其语的敏感数据,因为在土耳其语中,字母“I”有四个实例,两个小写字母,两个大写字母。您可以在 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemstringclasscomparetopic5.asp 上阅读这方面的内容。

现在,让我们转到本月的错误。这段代码有什么问题?

void func(char *p) {

char buf[10+1];

memset(buf,0,sizeof(buf));

// limit string to 10 chars

sprintf(buf,"%10s",p);

printf("Hello, %s\n",buf);

}

返回页首

一个小智力游戏

这个智力游戏实际上与安全性毫无关系,但是当我想到人们为整数溢出检测代码所困扰时,我就把它从我记忆的深处拉了出来。这段代码有什么用呢?

int a = 0x42;

int b = 0x69;

a ^= b;

b ^= a;

a ^= b;

这个游戏的规则非常简单,您无法编译或解释这段代码。试着仅仅通过观察来确定它有什么用。

Michael Howard 是 Microsoft Secure Windows Initiative 组的高级安全程序经理,是 Writing Secure Code 的合著者之一,该书的第二版现已发行。他还是 Designing Secure Web-based Applications for Windows 2000 的主要作者。他致力于确保人们所设计、构建、测试和记录的系统符合安全要求。他最喜欢的一句话是“一人之工具,他人之凶器。”

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有