【计算机系统】Buflab实验

目录

  • 前言
    • 实验前的准备
    • Level 0:Candle
    • Level 1:Sparkler
    • Level 2:Firecracker
    • Level 3:Dynamite
    • Level 4:Nitroglycerin

前言

内容仅作记录,请谨慎参考。

实验前的准备

首先查看实验文文件:
在这里插入图片描述
可以看到里面一共有三个文件:bufbomb、hex2raw、makecookie
从实验指导书中可以了解到这三个文件的具体作用:
【计算机系统】Buflab实验_第1张图片
bufbomb是我们要攻击的程序
makecookie会根据我们的用户id生成一个“cookie”
hex2raw帮助进行字符串格式之间的转换
接下来使用objdump对bufbomb程序进行反汇编,生成汇编代码
在这里插入图片描述
使用makecookie利用自己的id生成一个“cookie”
在这里插入图片描述
整个实验针对getbuf具有的漏洞展开:
【计算机系统】Buflab实验_第2张图片
getbuf函数从输入流获取一个字符串并将其存储到目的地址中,但是它只是简单地复制字符串,当我们进行非法输入时,它可能会超出所分配的存储空间。输入字符串不超过31个字符时,返回结果为1;输入字符超出的时候就会造成段错误,多出的部分将会导致程序的状态被改写,而我们所利用的就是这个漏洞。
在这里插入图片描述
bufbomb的一些参数设置:
【计算机系统】Buflab实验_第3张图片
-u:不同的用户id使用不同的“cookie”
-h:打印可能的命令行参数
-n:在“Nitro”模式下进行操作,Level 4会被用到
-s:将解决方案提交给服务器打分
文档中给我们提供了几种执行.txt文件的方法:
【计算机系统】Buflab实验_第4张图片
需要注意的点:
【计算机系统】Buflab实验_第5张图片
·getbuf遇到换行就会认为输入停止,换行“\n”对应的ASCII码为0x0a,所以输入的字符串中不能含有0x0a;
·格式转换每次输入的都是两个数字,例如要输入0,就要输入00;
·小端格式输入。

Level 0:Candle

任务:test在执行过程中将会调用getbuf函数,我们的任务是让bufbomb在执行getbuf的返回语句时不返回到test,而是执行smoke的代码。

test源码
【计算机系统】Buflab实验_第6张图片
smoke源码
【计算机系统】Buflab实验_第7张图片
getbuf源码
【计算机系统】Buflab实验_第8张图片
根据最开始文档中对getbuf函数的说明,我们可以利用getbuf函数的漏洞(进行非法输入时,它可能会超出所分配的存储空间),结合栈帧的结构达到相应的目的
getbuf函数的汇编代码:
【计算机系统】Buflab实验_第9张图片
首先push %ebp,然后开辟了0x38大小的栈空间,接着将ebp-0x28的地址传给了,也就是说buf距离返回地址有0x28+4=44个字节,将这44个字节加上smoke的返回地址达到缓冲区溢出,用smoke的返回地址覆盖掉getbuf原本的返回地址而跳转到smoke函数中。
栈帧结构的示意图
【计算机系统】Buflab实验_第10张图片
smoke函数的汇编代码
【计算机系统】Buflab实验_第11张图片
可以看到smoke函数的入口地址为0x08048e0a,据此,可以创建.txt文件,文件内容为44个字符+0x08048e0a,但要注意的是,0x0a对应的是“\n”,根据最开始的文档介绍,输入字符串“\n”,将会认为输入结束,所以将0x08048e0a改为0x08048e0b:
【计算机系统】Buflab实验_第12张图片
[为什么输入0b即可?这是因为我们只需要执行smoke即可,在执行完以后并不需要其返回到哪里继续执行,所以这个push %ebp已经不需要了]
执行验证
在这里插入图片描述

Level 1:Sparkler

任务:与Level 0类似,在我们执行test时,调用完getbuf不返回到test,而是执行fizz函数,同时将我们的“cookie”做为参数传入fizz函数。

【计算机系统】Buflab实验_第13张图片
fizz函数的汇编代码
【计算机系统】Buflab实验_第14张图片
由此我们得到fizz函数的入口地址为:0x08048daf
栈帧结构的示意图
【计算机系统】Buflab实验_第15张图片
结合Level 0的分析,首先利用“44个字符+fizz函数入口地址”实现函数返回后执行fizz函数,因为不是使用call fizz这样的方式来调用fizz函数的,所以我们只是把fizz那里的代码拿来执行,所以不会将返回地址入栈,也就是直接执行push ebp(其实这一步也可以不要),参数在ebp+8的位置,所以需要还“4个字符+参数”,实现最终的任务。
据此,可以创建.txt文件,文件内容为:44个字符+fizz函数入口地址+4个字符+参数
【计算机系统】Buflab实验_第16张图片
执行验证
在这里插入图片描述
另外一种方法
栈帧结构的示意图
【计算机系统】Buflab实验_第17张图片
刚才分析可知,我们只需执行fizz中的代码即可,因此push ebp其实可以不执行,也就是将fizz中的第一行mov %esp %ebp的地址覆盖掉原本的返回地址,而不是用push %ebp的地址。这种方法下,因为没有push %ebp这一步,所以ebp地址会高4个字节,对应的.txt文件内容为:
44个字符+mov %esp %ebp地址+8个字符+参数
【计算机系统】Buflab实验_第18张图片
执行验证
在这里插入图片描述

Level 2:Firecracker

任务:与Level 0和Level 1类似,在我们执行test时,调用完getbuf不返回到test,而是执行bang函数,但函数参数是一个全局变量,在执行bang函数之前需要设计全局变量为我们自己id的“cookie”。

bang函数源码
【计算机系统】Buflab实验_第19张图片
这次任务与上面简单的覆盖不同,我们需要做的是修改全局变量的值,全局变量需要到内存中去修改,但是我们没有一个这样的函数供我们调用,所以我们需要自己来编写一段代码,并执行我们这段代码,从而达到目的。
getbuf函数的汇编代码
【计算机系统】Buflab实验_第20张图片
可以看到lea指令将-0x28(%ebp)赋给了%eax,那么这个地方也就是我们输入的字符串的首地址,我们想要做的就是将这个地址作为一个“入口“,根据之前的分析,需要将其覆盖掉原本的返回地址。
-0x28(%ebp)对应的地址
【计算机系统】Buflab实验_第21张图片
由此,我们可以创建一个.txt文件,文件内容为:
44个字符+0x55683118
这样,getbuf函数在返回时,不会返回到原本test的栈帧,而是去执行0x55683118之后的内容。
栈帧结构的示意图
【计算机系统】Buflab实验_第22张图片
之后需要做的就是构造修改全局变量和执行bang函数的指令码
bang函数的汇编代码
【计算机系统】Buflab实验_第23张图片
查看bang函数的汇编代码,我们可以得到函数的入口地址为0x08048d52,在函数开辟栈空间之后,执行了mov 0x0804d10c,%eax的指令,结合函数源码,0x0804d10c处存放的就是全局变量global_value,因此我们可以按如下方式编写代码:
【计算机系统】Buflab实验_第24张图片
首先将全局变量修改为我们自己的“cookie”的值,之后将bang函数的入口地址入栈,再用ret指令来执行bang函数。
按照实验文档中给出的方法,将其转换为对应的字节码:
在这里插入图片描述
得到对应的机器码
【计算机系统】Buflab实验_第25张图片
据此,结合上述的分析,我们可以创建一个.txt文件,文件内容为:
自己编写程序的机器码+用于填充的字符+0x55683118
【计算机系统】Buflab实验_第26张图片
执行验证
【计算机系统】Buflab实验_第27张图片

Level 3:Dynamite

任务:在每次执行getbuf函数的时候,我们的返回值是1,这次我们需要将返回值设置为我们自己用户id的“cookie”;同时恢复原本%ebp的值,返回到test函数中继续执行。

getbuf源码
【计算机系统】Buflab实验_第28张图片
首先我们需要找到我们输入的buf的首地址,让函数返回值修改为这个地址来执行我们希望执行的内容(这一点与Level 2的思路相同)。
getbuf函数的汇编代码
【计算机系统】Buflab实验_第29张图片
可以看到lea指令将-0x28(%ebp)赋给了%eax,那么这个地方也就是我们输入的字符串的首地址,我们想要做的就是将这个地址作为一个“入口“,根据之前的分析,需要将其覆盖掉原本的返回地址。
-0x28(%ebp)对应的地址
【计算机系统】Buflab实验_第30张图片
栈帧结构的示意图
【计算机系统】Buflab实验_第31张图片
这时我们可以创建一个.txt文件,文件内容为:
44个字符+0x55683118
函数返回值放在寄存器%eax中,要使函数返回值修改为我们的“cookie”值,就需要将我们“cookie”值放到寄存器%eax中
mov $0x37faa4e5,%eax
之后我们要做的是恢复原本%ebp的值,使用gdb查看寄存器%ebp的值
【计算机系统】Buflab实验_第32张图片
mov $0x55683170,%ebp
最后需要能够正常返回到test函数中
test函数的汇编代码
【计算机系统】Buflab实验_第33张图片
可以看到,执行完getbuf函数,下一条指令的地址为0x08048e50,使用push和ret到这个地址处继续执行
push $0x08048e50
ret
得到我们需要执行的代码:
【计算机系统】Buflab实验_第34张图片
按照实验文档中给出的方法,将其转换为对应的字节码:
在这里插入图片描述
据此,根据以上分析,我们可以创建一个.txt文件,文件内容为:
自己编写程序的机器码+用于填充的字符+0x55683118
【计算机系统】Buflab实验_第35张图片
执行验证
【计算机系统】Buflab实验_第36张图片

Level 4:Nitroglycerin

任务:为了运行这个阶段,要使用“-n”指令进入“Nitro”模式,程序没有再调用getbuf,而是调用了另一个函数getbufn,这个函数的缓冲区多达512个字符,在“Nitro”模式下,getbufn函数将被调用5次,每次调用的%ebp值都是不同的,我们要做的是将每次getbufn的返回值都修改为我们用户id的“Cookie”值,并能够正常回到testn函数中继续执行,同时不能破坏testn的堆栈结构。

跳转
根据前面实验的分析,要使我们能够修改返回值,我们可以编写一段代码,我们输入的字符串内容就是这段代码转换后的机器码。要跳转到这里执行我们想要执行的代码就需要找到我们输入字符串的首地址,将这个地址覆盖掉原本函数的返回地址,强制程序去执行这段代码。
【计算机系统】Buflab实验_第37张图片
根据题目所说,getbufn函数将会被调用5次,而且每次的ebp值是不一样的,这也就是说,每次调用的时候,输入字符串的首地址是不相同的。
getbufn函数的汇编代码
【计算机系统】Buflab实验_第38张图片
通过汇编代码我们可以知道,我们输入的字符串的首地址在%ebp-0x208处,使用gdb设置断点,查看5次字符串首地址的值。
【计算机系统】Buflab实验_第39张图片
由调试结果可以看出,这5次的输入字符串的首地址为:
0x55682f38
0x55682ec8
0x55682f48
0x55682ed8
0x55682f58
要保证5次跳转都能执行执行我们要构造的代码,需要将这5个地址中的最大值0x55682f58作为我们要跳转到的地址。
到此,我们可以创建一个.txt文件,文件内容为:
524个字符+0x55682f58
之后我们要编写代码实现:修改返回值为我们用户id的“Cookie”值,恢复原本的ebp值使函数能返回test函数。
我们知道函数返回值存放在寄存器%eax中,因此修改返回值可以写成:
mov $0x37faa4e5,%eax
同时我们要恢复testn的ebp值
testn函数的汇编代码
【计算机系统】Buflab实验_第40张图片
根据testn函数的汇编代码,可以得到其自身以及调用getbufn函数的栈帧结构
函数的堆栈结构
【计算机系统】Buflab实验_第41张图片

根据上图的分析,在我们跳转到“返回地址”处执行我们编写的代码时,虽然getbufn函数的ebp的值在每次调用时是随机的,但testn函数的旧ebp值可以由esp的值减去0x28得到,据此可以编写恢复testn的ebp值得代码:
lea 0x28(%esp),%ebp
另外,我们通过testn函数的汇编代码知道,调用完getbufn的下一行汇编代码的地址为:0x08048ce2,我们要能够在做完所有操作后跳转到这里执行接下来的代码:
push $0x08048ce2
ret
由此我们得到需要执行的代码为:
【计算机系统】Buflab实验_第42张图片
按照实验文档中给出的方法,将其转换为对应的字节码:
在这里插入图片描述
【计算机系统】Buflab实验_第43张图片
据此,根据以上分析,我们可以创建一个.txt文件,文件内容为:
用于填充的字符+自己编写代码对应的机器码+0x55682f58
【计算机系统】Buflab实验_第44张图片
执行验证
【计算机系统】Buflab实验_第45张图片
关于为什么选择字符串首地址中最大的那个
【字不好看】
【计算机系统】Buflab实验_第46张图片

你可能感兴趣的:(计算机系统,经验分享,ubuntu,linux)