In recent years Linux distributions started treating security more seriously. Out of many security features two are directly affecting C programmers: -fstack-protector and -D_FORTIFY_SOURCE=2. These GCC options are now enabled by default on Ubuntu and Fedora.

What do these options do?

-fstack-protector

Consider the following C function:

void
fun()
{

char
*buf
=
alloca(0x100);

/* Don't allow gcc to optimise away the buf */

asm
volatile(""
::
"m"
(buf));

}

Compiled without the stack protector, with -fno-stack-protector option, GCC produces the following assembly:

<fun>:

push %ebp ; prologue

mov %esp,%ebp

 

sub $0x128,%esp ; reserve 0x128B on the stack

lea 0xf(%esp),%eax ; eax = esp +
0xf

and $0xfffffff0,%eax ; align eax

mov %eax,-0xc(%ebp)
; save eax in the stack frame

 

leave ; epilogue

ret

On the other hand with -fstack-protector option GCC adds protection code to your functions that use alloca or have buffers larger than 8 bytes. Additional code ensures the stack did not overflow. Here's the generated assembly:

<fun>:

push %ebp ; prologue

mov %esp,%ebp

 

sub $0x128,%esp ; reserve 0x128B on the stack

 

mov %gs:0x14,%eax ; load stack canary using gs

mov %eax,-0xc(%ebp)
; save it in the stack frame

xor %eax,%eax ; clear the register

 

lea 0xf(%esp),%eax ; eax = esp +
0xf

and $0xfffffff0,%eax ; align eax

mov %eax,-0x10(%ebp) ; save eax in the stack frame

 

mov -0xc(%ebp),%eax ; load canary

xor %gs:0x14,%eax ; compare against one in gs

<fun+0x2f>

<__stack_chk_fail@plt>

 

leave ; epilogue

ret

After a function prologue a canary is loaded and saved into the stack. Later, just before the epilogue the canary is verified against the original. If the values don't match the program exits with an appropriate message. This can protect against some buffer overflow attacks. It incurs some performance penalty but it seems to be worth the benefit.

When the stack is overwritten and __stack_chk_fail branch is taken the program crashes with a message like this:

***
stack
smashing
detected
***:
./protected
terminated

=======
Backtrace:
=========

/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xf76da0e5]

/lib/i386-linux-gnu/libc.so.6(+0x10409a)[0xf76da09a]

./protected[0x80484de]

./protected[0x80483d7]

/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xf75ef4d3]

./protected[0x8048411]

=======
Memory
map:
========

08048000-08049000
r-xp

00:13

./protected

08049000-0804a000
r--p

00:13

./protected

0804a000-0804b000
rw-p

00:13

./protected

092e5000-09306000
rw-p

00:00

[heap]

f759e000-f75ba000
r-xp

08:01

/lib/i386-linux-gnu/libgcc_s.so.1

f75ba000-f75bb000
r--p
0001b000
08:01

/lib/i386-linux-gnu/libgcc_s.so.1

f75bb000-f75bc000
rw-p
0001c000
08:01

/lib/i386-linux-gnu/libgcc_s.so.1

f75d5000-f75d6000
rw-p

00:00

f75d6000-f7779000
r-xp

08:01

/lib/i386-linux-gnu/libc-2.15.so

f7779000-f777b000
r--p
001a3000
08:01

/lib/i386-linux-gnu/libc-2.15.so

f777b000-f777c000
rw-p
001a5000
08:01

/lib/i386-linux-gnu/libc-2.15.so

f777c000-f777f000
rw-p

00:00

f7796000-f779a000
rw-p

00:00

f779a000-f779b000
r-xp

00:00

[vdso]

f779b000-f77bb000
r-xp

08:01

/lib/i386-linux-gnu/ld-2.15.so

f77bb000-f77bc000
r--p
0001f000
08:01

/lib/i386-linux-gnu/ld-2.15.so

f77bc000-f77bd000
rw-p

08:01

/lib/i386-linux-gnu/ld-2.15.so

ffeb2000-ffed3000
rw-p

00:00

[stack]

Aborted

-D_FORTIFY_SOURCE=2

Sample C code:

void
fun(char
*s)
{

char
buf[0x100];

strcpy(buf,
s);

/* Don't allow gcc to optimise away the buf */

asm
volatile(""
::
"m"
(buf));

}

Compiled without the code fortified, with -U_FORTIFY_SOURCE option:

<fun>:

push %ebp ; prologue

mov %esp,%ebp

 

sub $0x118,%esp ; reserve 0x118B on the stack

mov 0x8(%ebp),%eax ; load parameter `s` to eax

mov %eax,0x4(%esp)
; save parameter for strcpy

lea -0x108(%ebp),%eax ; count `buf`
in eax

mov %eax,(%esp)
; save parameter for strcpy

<strcpy@plt>

 

leave ; epilogue

ret

With -D_FORTIFY_SOURCE=2:

<fun>:

push %ebp ; prologue

mov %esp,%ebp

 

sub $0x118,%esp ; reserve 0x118B on the stack

movl $0x100,0x8(%esp) ; save value 0x100 as parameter

mov 0x8(%ebp),%eax ; load parameter `s` to eax

mov %eax,0x4(%esp) ; save parameter for strcpy

lea -0x108(%ebp),%eax ; count `buf` in eax

mov %eax,(%esp)
; save parameter for strcpy

<__strcpy_chk@plt>

 

leave ; epilogue

ret

You can see GCC generated some additional code. This time instead of calling strcpy(dst, src) GCC automatically calls __strcpy_chk(dst, src, dstlen). With FORTIFY_SOURCE whenever possible GCC tries to uses buffer-length aware replacements for functions like strcpy, memcpy, memset, etc.

Again, this prevents some buffer overflow attacks. Of course you should avoidstrcpy and always use strncpy, but it's worth noting that FORTIFY_SOURCE can also help with strncpy when GCC knows the destination buffer size. For example:

void
fun(char
*s,
int
l)
{

char
buf[0x100];

strncpy(buf,
s,
l);

asm
volatile(""
::
"m"
(buf[0]));

}

Here GCC instead of calling strncpy(dst, src, l) will call__strncpy_chk(dst, src, l, 0x100) as GCC is aware of the size of the destination buffer.

When the buffer is overrun the program fails with a message very similar to the one seen previously. Instead of "stack smashing detected" you'll see "buffer overflow detected" headline:

***
buffer
overflow
detected
***:
./fortified
terminated

=======
Backtrace:
=========

/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xf76d30e5]

/lib/i386-linux-gnu/libc.so.6(+0x102eba)[0xf76d1eba]

/lib/i386-linux-gnu/libc.so.6(+0x1021ed)[0xf76d11ed]

./fortified[0x8048488]

./fortified[0x80483a7]

/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xf75e84d3]

./fortified[0x80483e1]

=======
Memory
map:
========

08048000-08049000
r-xp

00:13

./fortified

08049000-0804a000
r--p

00:13

./fortified

0804a000-0804b000
rw-p

00:13

./fortified

08d6b000-08d8c000
rw-p

00:00

[heap]

f7597000-f75b3000
r-xp

08:01

/lib/i386-linux-gnu/libgcc_s.so.1

f75b3000-f75b4000
r--p
0001b000
08:01

/lib/i386-linux-gnu/libgcc_s.so.1

f75b4000-f75b5000
rw-p
0001c000
08:01

/lib/i386-linux-gnu/libgcc_s.so.1

f75ce000-f75cf000
rw-p

00:00

f75cf000-f7772000
r-xp

08:01

/lib/i386-linux-gnu/libc-2.15.so

f7772000-f7774000
r--p
001a3000
08:01

/lib/i386-linux-gnu/libc-2.15.so

f7774000-f7775000
rw-p
001a5000
08:01

/lib/i386-linux-gnu/libc-2.15.so

f7775000-f7778000
rw-p

00:00

f778f000-f7793000
rw-p

00:00

f7793000-f7794000
r-xp

00:00

[vdso]

f7794000-f77b4000
r-xp

08:01

/lib/i386-linux-gnu/ld-2.15.so

f77b4000-f77b5000
r--p
0001f000
08:01

/lib/i386-linux-gnu/ld-2.15.so

f77b5000-f77b6000
rw-p

08:01

/lib/i386-linux-gnu/ld-2.15.so

fff8d000-fffae000
rw-p

00:00

[stack]

Aborted

 

SRC=https://idea.popcount.org/2013-08-15-fortify_source/

FORTIFY_SOURCE的更多相关文章

  1. gcc和g++

    一.GCC GNU编译器套件(GNU Compiler Collection)包括C.C++.Objective-C.Fortran.Java.Ada和Go语言的前端,也包括了这些语言的库(如libs ...

  2. Android 1.5-7.0(持续更新)安全机制一览

    Android 1.5 ProPolice to prevent stack buffer overruns (-fstack-protector),在缓冲区buffer与返回地址之间加入Canary ...

  3. Pwn入坑指南

    栈溢出原理 参考我之前发的一篇 Windows栈溢出原理 还有 brant 师傅的<0day安全笔记> Pwn常用工具 gdb:Linux下程序调试 PEDA:针对gdb的python漏洞 ...

  4. Linux下pwn从入门到放弃

    Linux下pwn从入门到放弃 0x0 简介 pwn,在安全领域中指的是通过二进制/系统调用等方式获得目标主机的shell. 虽然web系统在互联网中占有比较大的分量,但是随着移动端,ioT的逐渐流行 ...

  5. OWASP固件安全性测试指南

    OWASP固件安全性测试指南 固件安全评估,英文名称 firmware security testing methodology 简称 FSTM.该指导方法主要是为了安全研究人员.软件开发人员.顾问. ...

  6. Linux保护机制和绕过方式

    Linux保护机制和绕过方式 CANNARY(栈保护) ​ 栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行.用C ...

  7. PWN二进制漏洞学习指南

    目录 PWN二进制漏洞学习指南 前言 前置技能 PWN概念 概述 发音 术语 PWN环境搭建 PWN知识学习途径 常见漏洞 安全机制 PWN技巧 PWN相关资源博客 Pwn菜鸡小分队 PWN二进制漏洞 ...

  8. 2020ACTF pwn writeup

    为了打2021的ACTF,想着把2020年的pwn题做一做吧,发现2020年的pwn题质量还挺高的.反倒是2021年的题目质量不太高,好像是没有专门的pwn师傅出题,可以理解,毕竟办校赛,说白了就是用 ...

  9. WHUCTF PWN题目

    花了大概两天时间来做WHUCTF的题目,第一次排名这么靠前.首先感谢武汉大学举办这次萌新赛,也感谢fmyy的师傅的耐心指导,让我第一次做出堆的题目来. pwnpwnpwn 这是一道栈题目,32位程序, ...

随机推荐

  1. 开发PL/SQL子程序和包及使用PL/SQL编写触发器、在JDBC中应用Oracle

    1.  子程序的各个部分: 声明部分.可执行部分.异常处理部分(可选) 2.子程序的分类: A.  过程 - 执行某些操作 a.  创建过程的语法: CREATE [OR REPLACE]  PROC ...

  2. 软RAID管理

    软RAID管理 软RAID 软RAID 提供管理界面:mdadm 软RAID为空余磁盘添加冗余,结合了内核中的md(multi devices). RAID 设备可命名为/dev/md0./dev/m ...

  3. PCB CE工具取Genesis JOB与STEP内存地址 方法分享

    今天无意中在硬盘上找到了<CE工具取Genesis JOB与STEP内存地址 >视频, 这是2013年初由郭兄(永明)远程时录制的一段视频,特别感谢郭兄指引与帮助, 想当初要不是你推出全行 ...

  4. [Swift通天遁地]七、数据与安全-(15)使用单元测试进行代码的性能分析

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  5. 【转】深入理解Java多态原理

    之前一直知道多态是什么东西,平时敲代码也经常用到多态,但一直没有真正了解多态底层的运行机制到底是怎么样的,这两天才研究明白点,特地写下来,跟各位同学一起进步,同时也希望各位大神指导和指正. 多态的概念 ...

  6. linux安装/卸载mysql

    其实安装mysql差不多有10次了吧, 但是每次都有坑,各种百度,太麻烦了,所以这次把坑给记录下来,下次直接用. 1. 去官网下载mysql.这里可以使用wget下载.先去官方网站,找到mysql5. ...

  7. JavaScript--如何插入JS

    我们来看看如何写入JS代码?你只需一步操作,使用<script>标签在HTML网页中插入JavaScript代码.注意, <script>标签要成对出现,并把JavaScrip ...

  8. BZOJ 3473

    思路: CF原题 ZYF有题解 O(nlog^2n) //By SiriusRen #include <bits/stdc++.h> using namespace std; ; ]; i ...

  9. Leetcode0143--Reorder List 链表重排

    [转载请注明]https://www.cnblogs.com/igoslly/p/9351564.html 具体的图示可查看 链接 代码一 /** * Definition for singly-li ...

  10. printFinal用法示例

    printFinal是一个基于jQuery的打印插件,支持打印预览,使用很简单,废话不多多说,直接上代码. <!DOCTYPE html PUBLIC "-//W3C//DTD XHT ...