作业地址: http://csapp.cs.cmu.edu/3e/labs.html
AttackLab共5道题,Phase1~Phase3是缓冲区溢出(Buffer Overflow)攻击,Phase4~Phase5是返回导向(ROP:Return Oriented Programming)攻击。
各题解题思路:
Phase1:
任务: 通过缓冲区溢出来修改函数getbuf的返回地址,使得getbuf返回之后跳转到函数touch1执行。
第一题,说详细一点。
在程序ctarget内部,在函数getbuf内,会通过函数gets来输入一串字符,但当前栈帧并不会检验传入字符串的长度。
在程序实际执行过程中,执行到getbuf对应的指令序列时,输入的字符串对应的二进制数据会被压入栈帧内,由于函数
内部并不会检验输入字符串的长度,字符串的大小就有可能会超出当前栈帧的容量大小,从而导致栈溢出,也就是缓冲
区溢出。超出当前栈帧的那部分数据会覆盖掉栈内存中高位地址上原先的数据。
函数getbuf在程序ctarget内的调用关系是:stable_launch -> launch -> test -> getbuf
函数test的反汇编代码:
函数getbuf的反汇编代码:
注:retq指令相当于popq %rip; jmp %rip。
1)在test内执行指令 callq 0x4017a8 <getbuf>指令相当于 pushq %rip; jmp 0x4017a8;
即将callq 0x4017a8 <getbuf>指令的下一条指令的地址(也就是函数getbuf的返回地址)压入栈内,并跳转到函数getbuf的首地址
开始执行指令。
2)在getbuf内调用Gets函数时,会将输入的字符串数据压入栈内,如果字符串长度过长(超过getbuf栈帧容量的大小0x28,也就是40Bytes),
则会造成缓冲区溢出。Phase1要做的就是通过缓冲区溢出来覆盖getbuf的返回地址,并将这个返回地址改为touch1的首地址。
这样getbuf返回之后就会跳转到touch1执行。
具体操作步骤如下:
1.准备好要往栈内压入的十六进制数据。
比如0x12345678, 则以 12 34 56 78的形式存入文本文件(开头的0x不需要)。
函数touch1首地址:0x00000000004017c0
然后构造文本文件in.txt: 前40个字节的数据随意填充。第41~48字节的数据是以小端形式填入的函数touch1的首地址。
2.使用程序hex2raw将第1步做成的文本文件中的十六进制数据转换成对应的字符,如下
3.将第2步得到的文本文件的字符数据作为ctarget程序的输入,运行ctarget程序。
(由于使用的自学版本,无法连接CMU的用来评分的服务器,所以运行ctarget时,要加上选项-q,即选择不连接服务器)
Phase2:
任务:getbuf函数调用结束后,跳转到touch2执行,同时将Cookie值(Cookie.txt文件内的数据,我这个是0x59b997fa)作为
一个无符号整型(占4字节)参数传入touch2。
思路:将getbuf的返回地址修改为一段自制指令的首地址,这段自制指令结束后跳转到touch2执行;
做法:
touch2首地址:0x00000000004017ec
//getbuf返回地址修改为下面这段指令存放位置的首地址
push 0x4017ec //将touch2地址压入栈内
movq 0x59b997fa, %rdi; //%rdi寄存器用来存放函数的第一个参数
ret; //相当于popq %rip; jmp %rip。此时,$rip = 0x4017ec
使用gcc和objdump 来获取这段汇编指令对应的二进制数据:
1)将上述汇编指令内容写入文件test.s;
2)使用gcc编译test.s文件:
gcc -c test.s 得到可执行文件test.o
3) 使用objdump参看可执行文件test.o对应的二进制指令数据
objdump -d test.o
4)使用gdb查看getbuf函数栈帧的最低地址:0x5561dca0
可将自制指令放在getbuf的栈帧空间内。
最后构造in2.txt内容:
Phase3:
。。。。。。暂时先写到这吧。有时间再续上吧。