第一幕 / Chapter 1
烧了些水,决定给兔兔洗个澡. 它们太脏了! 这俩兔孙没一点兔样!
用了半盆温水加,一把清扬洗发水. 洗好了一只,还算挺老实,比较配合.
看着圆圆的小兔,一下水变得给老鼠一个样.
拍了两张,没洗的和洗过的以作比较.
洗完半天不还干. 我直接拿吹风机给它俩吹了吹
这是一种境界. 能陪你生活就好,别管公母与丑美.
第二幕 / Chapter 2
躺下就一直鼻塞,出气不顺,总觉得鼻腔里有点鼻涕什么的,可怎么使劲擤鼻涕都没什么东西出来.
我感冒或扁桃体发炎,想发烧时就总是这样,鼻炎造成的.
前几天同事都一个个感冒了,也该我出症状了. 晚上就感到头蒙,鼻塞,喉咙发毛,还有痰.
鼻子不通,大脑缺氧,头晕. 鼻子不通,失去嗅觉,抽烟都没味.
… … 不知不觉2点多了.
我很想赶快发个烧,可很久都不发烧了. 总是有症状却爆发不出来.
别人说,发烧是自身免疫力对抗病毒和细菌的一次过程,每次发烧机体免疫力将得到提高和修复.
人一年发烧一两次是很正常的.
就像杀毒软件需要更新病毒库,系统需要更新和打补丁一样,身体也需要更新和自我维护.
难怪小孩会经常发烧,因为他的免疫力需要一次次刺激才能成长,变得更强.
我却不发烧,至少很久,好多年没烧过了. 这样说来,显然我的免疫力在下降.
还总是这样,症状都有,可发烧烧不出来,这感觉很是难受.
我给同事发了短信,说我很不舒服,明天可能去不了. 至少现在还没睡,去也可能很晚了.
第三幕 / Chapter 3
继续躺着. 躺着头晕的感觉颇好! 就象喝上了二两.
4点起来泡碗方便米线吃. 特意放了许些姜丝进去,还多加了点醋. 还想加个鸡蛋,可又很懒不想弄.
吃完挺晚了,没去单位. 虽然已告诉过同事,但还是给同事发了短信确认一下,并告知有些工事的话让他帮下忙.
我爸喂了狗,我去喂兔子.
给兔子喂食时发现,其中一只不怎么吃. 一看有一只眼睛似乎感染了.
有些红肿,还有很多眼屎,粘连的几乎张不开眼.
应该怪我. 可能是昨天给它洗澡,洗发水进了眼睛发炎了.
5点多去了超市,发现兜里竟然只有5块钱了? 虽然我对钱概念不大,可量变还是很清楚的.
又去取了钱,买了些日用消耗品. 回来到杜岭街的药店买了一瓶青霉素眼药水,只要0.5元.
除了医院,我买药一般都在那买,因为那的老板同一种病,用的同一种药,他们从不推荐你贵的.
用最少的钱并且达到最好的效果,这才是医德.
还有就是自己买药,尽量买OTC标志的药,就是非处方药,一般不会有不良反应.而且价格都是受国家限制的,很廉价.
回去就给那兔它眼睛擦干净,小心用了药. 它眼睛能挣开了!
第三幕 / Chapter 3
他又说丢钱没你自己都不知道? 我说没丢啊. 因为我都不知道我兜里有多少,只是不想和他吵.
他说:哦,不是你掉的钱都好. 我想:啊!?
他开始讲了,说我出门买东西,他也去买菜了,结果他兜里也就几块钱,又上楼拿钱.
在楼梯上还埋怨自己老了,脑子不够用啥的. 然后发现楼梯上的墙角有钱,还没有人捡.
说拿起来一看20! 然后就没回家直接去买了块肉. 还给我夸他对钱特别敏感,这个月都捡两次了.
要我看见我也敏感! 我很怀疑那钱是我掉的! 所以吃饭时,我就觉得盘里那肉就是我的!
落幕 / End
从晚上讲到晚上.
这要不叫日志,我都没法了!
这就是我的生活,这只是一天.
It’s my life, Just one day!
分类: 未分类
检查代码是否存在整数操作安全漏洞
检查代码是否存在整数操作安全漏洞
发布日期 : 09/02/2004 | 更新日期 : 09/02/2004
Michael Howard
Secure Windows Initiative摘要: Michael Howard 提出关于整数操作安全漏洞的问题,并且阐述可以用来保护自己应用程序的安全性计划。
很多年以前,很少有人听说过整数溢出攻击,但现在好像每隔几天它就会出现一种新的形式。下面的简短列表就是在最近几个月内发现的一些整数溢出的安全性错误:
在本月的专栏中,我将阐述这些错误是如何出现的,如何在代码中搜寻它们以及如何修复它们。
在进入到本文的正题之前,我非常高兴的宣布“Writing Secure Code”接收到了在 2003 年 4 月于 San Francisco 召开的 RSA Security Conference 的“Conference Award for Industry Innovation”。
现在,回到整数攻击问题吧!
我不想解释什么是整数,我假设您知道它们是什么,并且知道有两种类型(有符号和无符号),其中当值是负数时,有符号整数的高位设置为 1,这是对 2 求补算法的结果。您也知道整数大小各有不同,最常见的长度为 64 位、32 位、16 位和 8 位的整数。这就是我所说的关于整数的全部内容,对于本文而言,如果您知道这些知识就足够了。
有三种主要整数操作可以导致安全性漏洞:
上溢和下溢
有符号与无符号的错误
截断
取决于它们自己的情况,这些问题可能不会产生安全性错误。但是,如果您的代码显示有一个或多个这样的问题,并且您的代码会操作内存,那么产生缓冲区溢出错误或应用程序故障的可能性就会增加。让我们仔细查看一下每一项。
上溢和下溢
快速看一下这段代码有什么问题?
bool func(size_t cbSize) { if (cbSize < 1024) { // we never deal with a string trailing null char *buf = new char[cbSize-1]; memset(buf,0,cbSize-1); // do stuff delete [] buf; return true; } else { return false; } }代码是正确的,对吗?它验证 cbSize 不大于 1 KB,并且 new 或 malloc 应该始终正确地分配 1 KB,对吗?让我们忽略以下事实,new 或 malloc 的返回值应该在此时进行检查。同样,cbSize 不能为负数,因为它是 size_t。但是,如果 cbSize 是零,又会如何呢?查看一下分配缓冲区的代码,它从缓冲区大小请求中减去一。从零减去一会产生 size_t 变量,这是一个无符号的整数,其限制为 0xFFFFFFFF(假设为 32 位的值)或者 4 GB。您的应用程序只有结束了,或者更糟!
请看下面相似的问题:
bool func(char *s1, size_t len1, char *s2, size_t len2) { if (1 + len1 + len2 > 64) return false; // accommodate for the trailing null in the addition char *buf = (char*)malloc(len1+len2+1); if (buf) { StringCchCopy(buf,len1+len2,s1); StringCchCat(buf,len1+len2,s2); } // do other stuff with buf if (buf) free(buf); return true; }同样,代码看起来编写得很好;它检查数据大小,验证 malloc 是否成功,并且使用 safe 字符串处理函数 StringCchCopy 和 StringCchCat(您可以从 http://msdn.microsoft.com/library/en-us/dnsecure/html/strsafe.asp 阅读更多关于这些字符串处理函数的内容)。但是,这段代码可能会受到整数上溢的危害。如果 len1 是 64,len2 是 0xFFFFFFFF,又会如何呢?确定缓冲区大小的代码合法地将 1、64 和 0xFFFFFFFF 加在一起,由于加操作的限制,会产生 64。接下来,代码仅分配了 64 个字节,然后代码生成了一个长度为 64 个字节的新字符串,然后将 0xFFFFFFFFF 字节与该字符串相连。同样,应用程序将会结束,在某些情况下,如果利用精心设计的大小进行攻击,代码可能会受到可用缓冲区溢出攻击。
此处的另外一个教训就是,如果缓冲区大小计算不正确,_safe 字符串处理函数就不安全。
JScript 溢出攻击
当使用乘法时也会出现相同类型的上溢错误,这发生在 Microsoft JScript 错误中。该错误仅表明它自己在使用 JScript 稀疏数组支持时会出现:
var arr = new Array(); arr[1] = 1; arr[2] = 2; arr[0x40000001] = 3;在这个示例中,数组具有三个元素,且长度为 0x40000001(十进制为 1073741825)。但是,由于该示例使用稀疏数组,它只占用内存的三个元素的数组。
实现 JScript 自定义排序例程的 C++ 代码在堆上分配临时的缓冲区、将三个元素复制到临时缓冲区中、使用自定义函数排序临时缓冲区,然后将临时缓冲区的内容移动回数组中。下面是分配临时缓冲区的代码:
TemporaryBuffer = (Element *)malloc(ElementCount * sizeof(Element));
Element 是一个 20 字节的数据结构,用于保存数组项。看起来程序将尝试为临时缓冲区分配大约 20 GB。您可能认为由于大多数人的计算机上不会有 20 GB 的内存,分配尝试将会失败。那么,JScript 常规内存不足处理例程将会处理该问题。遗憾的是,并没有发生这样的情况。
当使用 32 位的整数算法时,由于结果 (0x0000000500000014) 太大无法保存在 32 位的值中,我们会受到一个整数上溢攻击:
0x40000001 * 0x00000014 = 0x0000000500000014C++ 会丢弃所有不符合的位,因此我们会得到 0x00000014。这就是分配并未失败的原因 - 分配没有尝试去分配 20 GB,而是仅仅尝试分配了 20 个字节。然后,排序例程会假设缓冲区对于保存稀疏数组中的三个元素来说足够大,因此它将组成这三个元素的 60 个字节复制到了 20 个字节的缓冲区中,这样就溢出缓冲区 40 个字节。实在太冒险了!
有符号与无符号错误
快速查看下面的代码。它类似于第一个示例。看看您是否能够发现错误,如果您发现了错误,请试着确定该错误会产生什么结果。
bool func(char *s1, int len1, char *s2, int len2) { char buf[128]; if (1 + len1 + len2 > 128) return false; if (buf) { strncpy(buf,s1,len1); strncat(buf,s2,len2); } return true; }此处的问题在于字符串的大小存储为有符号的整数,因此只要 len2 是负值,len1 就可以大于 128,从而和就小于 128 个字节。但是,到 strncpy 的调用将会溢出 buf 缓冲区。
截断错误
让我们查看最后一种攻击类型,通过代码示例,您来猜猜看。
bool func(byte *name, DWORD cbBuf) { unsigned short cbCalculatedBufSize = cbBuf; byte *buf = (byte*)malloc(cbCalculatedBufSize); if (buf) { memcpy(buf, name, cbBuf); // do stuff with buf if (buf) free(buf); return true; } return false; }这种攻击,至少这种结果,与前面阐述的 JScript 错误有一点类似。如果 cbBuf 是 0x00010020,又会如何呢?cbCalculatedBufSize 只有 0x20,因为只从 0x00010020 复制了低 16 位。因此,仅分配了 0x20 个字节,并且 0x00010020 字节复制到新分配的目标缓冲区中。请注意,使用 Microsoft Visual C++?/W4 选项编译这段代码会生成:
warning C4244: 'initializing' : conversion from 'DWORD' to 'unsigned short', possible loss of data请注意类似下面的操作不要标记为一个警告:
int len = 16; memcpy(buf, szData, len);memcpy 的最后一个参数是 size_t,而参数 len 是有符号的。不会发出警告是因为 memcpy 始终假设第三个参数是无符号的,转换成无符号不会改变函数的输出。
注意,如果您尝试为 DWORD 分配一个 size_t,您将会收到一个警告,并不是因为在 32 位平台上可能会出现数据丢失,而是因为在 64 位平台上将会出现数据丢失。
warning C4267: '=' : conversion from 'size_t' to 'DWORD', possible loss of data您将收到这个警告,因为所有默认 C++ 项目都使用 -Wp64 选项进行编译,该选项会通知编译器监视 64 位可移植性问题。
托管代码中的整数操作问题
整数操作错误可能会发生在托管语言中,例如 C# 和 Visual Basic?.NET,但是潜在的损害会由于代码不直接访问内存而显著地降低。但是,调用本机代码(假设您的代码被授予调用非托管代码的权限)仍然可能会引起类似于上述的安全性问题。通用语言规范 (CLS) 中的整数是有符号的,一个错误就是当在非托管代码中将变量视为无符号的整数时,在托管代码中验证是否为有符号的整数参数。
这个特定的例子提出了一个更通用的建议:始终检查要传递到未托管代码的内容。托管代码中的很多整数操作错误可能会引起 Visual Basic .NET 中的可靠性错误,因为如果发生上溢或下溢,所有这样的操作都将引发 System.OverflowException。
默认情况下,C# 并不引发这些异常。如果您希望检查这些问题,请使用 checked 关键字:
UInt32 i = 0xFFFFFFF0; UInt32 j = 0x00000100; UInt32 k; checked {k = i + j;}补救措施
谁会想到只是操作整数就会导致安全性问题呢?对于易受攻击的代码的简单的补救措施如下所示:
if (A + B > MAX) return -1;利用无符号整数使用该代码:
if (A + B >= A && A + B < MAX) { // cool! }第一个操作 A + B >= A,检查是否存在包围,第二个操作确保相加后的和小于目标大小。
对于 JScript 中的操作问题,您可以检查元素的数量不超过预定的值,而预定的值要小于您将要分配给内存的最大量。例如,下面的代码会潜在地分配多达 64 MB 的内存:
const size_t MAX = 1024 * 1024 * 64; const size_t ELEM_SIZE = sizeof(ELEMENT); const size_t MAX_ELEMS = MAX / ELEM_SIZE; if (cElems >= MAX_ELEMS) return false;最后,对于数组索引、缓冲区大小以及相似对象,请使用无符号的整数,例如 DWORD 和 size_t。
关键代码检查点
当编译或检查与整数相关的问题的代码时,请记住下列要点:
使用最高的警告级别 /W4 来编译 C 和 C++ 代码。
对于缓冲区大小和元素计数,使用 size_t 或 DWORD。没有任何理由要为这些结构使用有符号的值。
请牢记,size_t 会根据您所使用的平台来表示不同的类型。size_t 是内存地址的大小,因此在 32 位平台上,它是 32 位的值,但在 64 位平台上,它就是 64 位的值。
如果代码执行任意类型的整数操作(加、乘等等),其中结果用于索引到数组或计算缓冲区大小,请确保操作数位于一个小的、容易理解的范围内。
警惕内存分配函数(new、malloc、GlobalAlloc 等等)的有符号参数,因为它们将被视为无符号的整数。
注意产生 C4018、C4389 和 C4244 警告的操作。
注意抛弃 C4018、C4389 和 C4244 警告的转换。
调查禁用 C4018、C4389 和 C4244 警告的 #pragma warning(disable, Cnnnn) 的所有使用。实际上,将它们标记为注释、重新编译,然后检查与整数相关的所有新的警告。
从其他平台或编译器迁移的代码可能会使用不同的数据大小。千万要小心!
如果从托管代码调用非托管代码,请确保它的符号是正确的。Win32 API 的很多参数都是无符号的 int 或 DWORD,而很多托管代码变量则是有符号的。
最后,如果您使用托管代码,请确保在适当的时候使用 catch OverflowExceptions。
发现安全漏洞
很多人检查出了我上个月的问题。它是一个整数上溢攻击。那么这段 C# 代码有什么问题呢?
string Status = "No"; string sqlstring =""; try { SqlConnection sql= new SqlConnection( @"data source=localhost;" + "user id=sa;password=password;"); sql.Open(); sqlstring="SELECT HasShipped" + " FROM detail WHERE ID='" + Id + "'"; SqlCommand cmd = new SqlCommand(sqlstring,sql); if ((int)cmd.ExecuteScalar() != 0) Status = "Yes"; } catch (SqlException se) { Status = sqlstring + " failednr"; foreach (SqlError e in se.Errors) { Status += e.Message + "nr"; } } catch (Exception e) { Status = e.ToString(); }
看奥运首日有感
昨天在家看了奥运开幕的全程直播。感觉不错,有很多炫的地方。体现了张导一贯华丽和盛大的作风。由此可想:这不是一场盈利的奥运会,至少中国没打算以它盈利。所以这真的是一场人文奥运!
据悉场馆建设,配套设施,安保费用,人员支出,再加因之前的奥运筹备和目前的比赛,比如车辆禁行,人员管制,单位放假,直接间接的损失,的确是不小的。但重点是民族荣誉和国家声望,应该这些都是值得的。]]>
万兽之王拥抱昔日主人
即将过去的七月
中! 算你俩狠!
事情是这样的:
最近痕迹
六月天
一个月了,没有一天时间,大家都一直在忙. 差点病倒两个.
忙得成效和结果也不是我们能决定的.
项目组独立核算了,似乎是可以玩命的好理由了.
大家都是为了饭碗,为了前途卖命,别到最后回报不值身体的付出就好.]]>
买了”块”国外的”地”
小熊猫打喷嚏