发新话题
打印

[讨论]关于不安全函数strncpy();安全缺陷可能性的探讨

[讨论]关于不安全函数strncpy();安全缺陷可能性的探讨

议题提交:Sunwear [E.S.T]
信息来源:邪恶八进制信息安全团队

  你在写程序的时候,有没有刻意的去注意使用的函数是否安全?
你对不安全函数的看法也谈谈。
有人认为strcpy()不安全而使用strncpy()觉得使用他就是非常安全。
strncpy()也不是绝对安全的。
下面来举一个flashsky给出的例子 然后在看看分析。
int
main(int argc, char **argv)
{
char buf1<1024>;
char buf2<256>;

strncpy(buf, argv<1>, 1024);
strncpy(buf2, argv<2>, 256); /* 这里可能导致buf2未中断 */

...

if(somecondition)
print_error(buf2); /* 报错 */

}

void print_error(char *p)
{
char mybuf<263>;

sprintf(mybuf, "error: %s", p);
}

由于main()函数中使用了strncpy(),程序员假设数据在达到print_error()是"干净"的。因此print_error()没有检查就直接调用了sprintf().不幸地是,既然p指向buf2,而buf2又没有正确地被中断,sprintf()就会持续的拷贝数据一直到发现buf1的末尾的NULL为止。

剩下的攻击则主要看对方代码和缓冲区的可控制性方面了,发生溢出也不一定就完全会导致攻击,如例1的:
strncat(name, ".", sizeof name - strlen(name) - 1);虽然会发生溢出但是拷贝多个"."后未知的内容,除非我们能控制在内存中"."后面的内存内容,否则是无法达到攻击目的的。
但是strncat(name, LocalDomain, sizeof name - strlen(name) - 1)中如果我们能控制LocalDomain中的内容和长度,就可以达到攻击目的了。


也感谢岩冰通知的一句话 而展开这个话题

(2005-05-06 23:06:30)  南阳岩冰
没有不安全的函数,只有不会用的人。
(2005-05-06 23:08:10)  sunwear
我觉得strcpy()就是不安全函数,不过,你们说的也有道理呀.以后用 strncpy()
strcpy()函数不检查输入的长度,导致第一个参数在堆栈中分配的大小不足够,导致后面堆栈的地址被覆盖掉,这样修改后面地址代表的变量和堆栈中返回的程序调用地址就可以修改程序流程 。wcscpy()也差不多  
(2005-05-06 23:11:08)  glacier
strncpy()比strcpy()安全,至少可以降低发生安全问题的几率
strcpy()在谁手里都容易导致BUG
如果取消strcpy,保留strncpy,由字符串拷贝带来的安全问题应该能少一多半
还有sprintf()
(2005-05-06 23:13:35)  sunwear
strncpy也不是完全的安全
flashsky曾经不是专门分析过strncpy()的攻击方法吗!posix中也有不安全函数
(2005-05-06 23:14:28)  glacier
嗯,但已经比strcpy安全多了,至少提醒了程序员要考虑字符串的长度
(2005-05-06 23:25:17)  Sidumper
POSIX.1-1996:putc_unlocked() 和 getc_unlocked()就是不安全函数

TOP

栈本身就是不安全的,因为返回地址和局部变量共用同一个栈……怎么可能安全?
如果对方使用的是堆内存,这种攻击方法就没辙了,撑死了可以引发系统崩溃。 [s:37]
对待处女,谁污染,谁治理。 对待内存,谁分配,谁释放。

TOP

无锋小姐说的的确很对,不过跑题了。不用向底层分析。
不过现在有些STOP方法是起一些作用。

TOP

不过现在/GS的功能 可以更改代码,在进入函数时,把返回地址和一个模块加载时随机生成的安全Cookie进行异或运算,并保存运算结果;在退出函数时,通过保存的运算结果和安全Cookie检验返回地址的正确性。如果发现返回地址已被改写,则表明已经发生了缓冲区溢出,这时系统将报告错误,并终止程序的执行。

不过这是基于在编译器上的。但是现在根本的问题好象还没解决。

TOP

……跑题跑得有道理……
根本问题在于硬件设计本身,以及可怜兮兮的向后兼容性。
前者容易解决,而且已经解决了,但后者实在难解决。
对待处女,谁污染,谁治理。 对待内存,谁分配,谁释放。

TOP

引用:
strncpy(buf, argv<1>, 1024);
strncpy(buf2, argv<2>, 256); /* 这里可能导致buf2未中断 */
是不是应该strncpy(buf1, argv<1>, 1024);?

今天才有空看了一下...为了提高论坛的学术交流气氛 我也来参与讨论吧..
PS:嫌我菜者 一律强奸

strncpy确实有不安全的因素 看你怎么用了 不过任何的函数基本都有这种临界状态
而提供strncpy的目的也并不是为了让他比strcpy更安全 而仅仅是为了可以指定n比strcpy更方便而已
方便和安全还是不能划等号的...

下面说说菜鸟冰血封情对此问题的理解 关键应该是在于临界状态
先看原型 这样方面我后面ggyy
char *strcpy(char *destination, const char *source, size_t n);
destination的空间必须要大于等于n就不用说了 这JB都是废话
如果source中包含字符数少于n个 那么拷贝完成后就会在destination的最后加上空字符
但是 如果source拷贝的时候n是大于或者等于destination的空间大小 那么 就不会在destination的末尾加上空字符的
然后最后 返回destination

那么Sunwear给出的flashsky例子的情况 恰恰就是讨论这种临界状态的
但是只是一个需要注意的问题 并非函数本身的问题 没有用好 才会出现长度相等不添加空字符的现象
buf2在前面被声明成256
引用:
char buf2<256>;
但是后面却用argv[2]的前256个拷贝填入buf2 这种问题在我学C的时候 书上专门提出来说了 看来基础是很重要的 我一定要好好学习 追上Sunwear
引用:
strncpy(buf2, argv<2>, 256);
第一 如果argv[2]的前256个字符的最后一个是空字符(或者说包含空字符) 那么自然没有问题
第二 但是如果argv[2]的前256个字符最后一个不是空字符(或者说包含空字符) 那么 由于buf2里本来只有256个空间 已经满了 就无法自动添加空字符了 因为没空间了填个毛呀?strncpy自动添空字符的条件是 有足够的空间 至少最后有那么一个字节
由于 有第二种可能性存在 所以例子中才会说可能 因为不一定
引用:
这里可能导致buf2未中断
那么很容易看见 其实
引用:
strcpy(buf1, argv<1>, 1024);
同样有可能存在这种问题...
完全取决于程序员的操作 当然编译器不会报错 并非语法错误 报根毛? 这就是为什么这个本来没有讨论价值的问题开始有了那么一点点价值 而被善于操作细节的焦点高手提出来专门说了 可见注重细节的优点是很重要的
其实不难发现flashsky的讨论主要集中的不是在错误或者说疏忽使用这个拷贝函数上 而是在不负责的程序员总是假设用户输入的数据是符合他们的想法的 而忽略了恶意用户的存在 没有考虑临界状态 而作为优秀的程序员 你必须考虑到用户输入的所有可能
因此 以前的旧程序里一定有相当部分存在这样类似的安全缺陷 而flashsky大哥的意思也只是抛砖引玉的告诉大家 这个不起眼的安全缺陷 存在可被利用的价值...

SB冰血封情意见如上 高手斧正 谢谢:)

下次讨论利用价值...NND 要迟到了

TOP

丫冰血会的不多 但是见到会的 就往死里说 b4一下
曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

你把我标题改了?汗!我记得我发贴的时候没写这个标题。
sprintf()  wcscpy() 还有 Sidumper兄弟说的
POSIX.1-1996:putc_unlocked() 和 getc_unlocked()就是不安全函数。 当然所谓的“不安全函数”其实还是非常多的。主要还是在于用法
也许讨论目的有些人还不明白?至少冰血封情明白.无疯MM应该不用说都明白。

TOP

我怎么记得C允许在数组后边再留一个空间  比如
strncpy(buf,argv[1],256);  如果拷贝256个字符
那么C会在257处存放\0  C只保证留一个空间

当然 最好的方法是strncpy(buf,argv[1],256-1);
请加47809945   100%通过!每个月总有那么几天,您的网络会受到黑客的攻击--坐立不安,烦躁无力,使用虎虎开发的"月月舒"防火墙,超轻超薄,易于携带,提供由内到外的全方位保护,即使流量再大,也可以冲浪自如,再也不用担心侧漏啦。

TOP

在初始化字符串的时候,字符串最后一个位置存放的是\0,做字符串结束标志
而strncpy和strcpy在copy的时候  strcpy会把\0一起复制  而strncpy在copy以后 之前字符串的\0被舍弃.只在字符船中保留一个\0

TOP

引用:
下面是引用dahubaobao于05-17-2005 21:38发表的:
我怎么记得C允许在数组后边再留一个空间  比如
strncpy(buf,argv[1],256);  如果拷贝256个字符
那么C会在257处存放  C只保证留一个空间

当然 最好的方法是strncpy(buf,argv[1],256-1);
好象没看见有这么一说 但是你强行把buf后紧接的一个空间存入空字符也不是不可以
我学的时候还凑合细 但是没看见有专门说过...
看看无锋怎么说 我找找资料...

TOP

引用:
下面是引用sunwear于05-17-2005 22:57发表的:
在初始化字符串的时候,字符串最后一个位置存放的是,做字符串结束标志
而strncpy和strcpy在copy的时候  strcpy会把一起复制  而strncpy在copy以后 之前字符串的被舍弃.只在字符船中保留一个
对 但是在使用strcpy的时候 如果目标空间不够 那\0也无法写入 后果就和strncpy前面说的错误一样了 系统会默认目前字符串到内存中下一\0才结束 天知道下个空字符在什么地方

TOP

这样的溢出最多是死死进程 没有什么大不了

TOP

发新话题