Ashing's Blog

想学的太多 懂得的太少

0%

Binary安全—Canary机制分析

开启Canary若发生溢出

开启与不开启对比分析

Function Prlogue

  • 多了两条命令
1
2
mov    %fs:0x28,%rax     #从另一个segment的8byte(QWORD)数据拿出来放到rax
mov %rax,-0x8(%rbp) #放到rbp减8的地方,即rbp的栈增长方向上

  • 运行到canary赋值后,第一个byte为’x’\00’(little-endian)

  • 查看Stack情况,rbp-0x8为0,执行下一步再查看栈情况

  • 执行一下指令,rbp-0x8位置已变为canary
1
mov    %rax,-0x8(%rbp)   #放到rbp减8的地方,即rbp的栈增长方向上

输入溢出

  • 查看Stack情况,发现都被覆盖为0x6161….包括canary

Function piloge

  • 多了几条指令
1
2
3
4
5
401264:	48 8b 55 f8          	mov    -0x8(%rbp),%rdx       					# 把放到ebp上面的canary拿出来
401268: 64 48 33 14 25 28 00 xor %fs:0x28,%rdx # 和其他segment的它异或
40126f: 00 00
401271: 74 05 je 401278 <main+0xab> # 若为0,即相同,跳转到main
401273: e8 18 fe ff ff callq 401090 <__stack_chk_fail@plt> # 否则fail

  • 把canary的值拿出来存放与RDX,发现已经被覆盖为0x6161…..

  • 执行xor,发现不一样则不会跳转,然后__stack_chk_fail报错

Canary真实地址

  • fs寄存器是执行当前栈的TLS结构,TLS(Thread Local Storage)的值由security_init初始化,每次重启后不同,同进程不同线程也是不同的,但是fork函数会copy父进程内存因此相同
  • TLS加0x28为canary

  • canary在map出来的一段,在stack前面很多,刚好在load的后面
  • 很难在stack覆盖到canary地方,除非可以任意写地址可以覆盖真实canary

ByPass

  • 劫持__stack_chk_fail 函数

  • 覆盖 TLS(Thread Local Storage) 中储存的 Canary 值:TLS会保存在stack高地址的地方。所以,当我们溢出足够大的字节,就可以控制TLS结构体,进而控制canary,实现ROP。

  • 爆破Canary