0%

stack overflow

Buffer Overflow

程序未对buffer做长度检查,造成可以让攻击者输入过长的字串,覆盖其他数据,严重时可以控制程序流程

根据buffer位置分类可分为stack base、data base、heap base

stack base

待补充

data base

  • Vulnerable Function
    • gets
    • scanf
    • strcpy
    • sprintf
    • memcpy
    • strcat
    • …(没有长度检查)

From crash to exploit

Overwrite the return address

Intel 80x86是 little-endian(低在低),使用p32或者反过来填
PowerPC处理器是 big-endian

  • Return to Text
    1. 定位溢出的位置
      • cyclic
        • pwntools中使用 cyclic(num) & cyclic(“str”)
      • gdb pattern_create & crashoff
    2. 控制eip跳到原本程序中的代码
      • objdump查看函数位置
      • IDA
    3. Exploitation
      • Debug exploit
        • attach
  • Return to Shellcode
    • 。c’c’xdata段可执行且位置固定,往data段写shellcode再跳过去

heap base

待补充

Protection

ASLR

地址随机化

每次执行程序时,stack\heap\library 位置都变化

  • 查看是否开启ASLR
    • cat /proc/sys/kernel/randmiize_va_space

DEP (NX)

可写的不可执行,可执行的不可写

PIE(Position Independent Execution)

开启后 data 段和 code 段也会 ASLR

StackGuard (canary)

程序执行时随机生成的数,放进 stack 里,在 function return 时检查该值是否变动,若变动则结束程序

  • 常放在 tls 区段的 tcbhead_t 结构,在 x86/x64 架构下各有一个寄存器指向该结构,程序以寄存器存取该字段
    • x86:gs
    • x64:fs

RELRO

  • Disabled
    • .got/.got.plt 都可写
  • Partial(default)
    • .got 只读
  • Fulled
    • RELRO 保护下,再 load time 时将全部 function resolve 完毕后变成 read only

Lazy binding机制

Dynamic linking 的程序在执行时,有些 library 的函数可能到结束都不会执行到,所以 ELF 采取 Lazy binding 的机制,在第一次 call library 函数时,才会去寻找函数的真正位置进行 binding

  • GOT(Global offset Table)
    • 函数指标阵列,存储其他 library 中 function 的位置,因 lazy binding 机制,并不会一开始把正确的位置填上,而是天上一段 plt 位置的 code,当执行到 library 的 function 时才会真正去寻找 function,最后再把 GOT 中的位置填上真正的 function 位置
    • 分成 .got(保存全局变量引用位置) & .got.plt(保存函数引用位置)
    • .got.plt 前三项
      • address of .dynamic
      • link_map(将引用到的 library 串成的 linked list)
      • dl_runtime_resolve(用来找出函数位置的函数)
    • 找 got 位置
      • objdump -R elf or readelf -r elf
    • 为了实现 lazy binding 机制,got 可写,所以若程序有任意更改位置的漏洞,便可改写 got,改变程序流程

Return to Library

背景

  • 一般程序很少有 system 等,可以直接获得 shell 的 function 而且在 DEP/NX 的保护下无法直接填入 shellcode 去执行代码
  • Dynamic linking 情况下,大部分程序都会载入 libc,libc中有一些 function 可以达成我们的目的
    • system
    • execve
  • 一般情况下 ASLR 会开启,导致每次 libc 载入位置不固定,所以通常需要利用 information leak 的漏洞来获取 libc 的 base address 进而算出 system 等 function 位置,在将程序导过去

获得 libc 的位置

  • got
  • stack 上的残留值
    • function return 后不会将 stack 中的内容清除
  • heap 上的残留值
    • free 完之后在 malloc,也不会将 heap 存的内容清空

获得 function 在 libc 中的 offset

  • objdump -T libc.so.6 | grep function
  • IDA 中搜索

思路

  1. 获取 libc 任意一个函数的地址
  2. 根据该 function 在 libc 中的偏移获取 libc_base_address
    • vmmap、ldd、信息泄漏 等方式获取 libc版本
  3. 利用 system 在 libc 中的偏移和 libc_base_address 获得 system 的地址
    • system 和 sh 之间需加一个数来表示 ret,如
1
2

payload = p32(system_addr) + p32(0xdeadbeef) + p32(sh_addr)