+ All Categories
Home > Software > The Silence of the Canaries

The Silence of the Canaries

Date post: 15-Apr-2017
Category:
Upload: kernel-tlv
View: 411 times
Download: 0 times
Share this document with a friend
27
The Silence of the Canaries Gili Yankovitch, Nyx Software Security Solutions
Transcript
Page 1: The Silence of the Canaries

The Silence of the CanariesGili Yankovitch, Nyx Software Security Solutions

Page 2: The Silence of the Canaries

Prerequisites

● A functioning brain

● A knowledge in the x86-x64 architectures

● Process loading

● Security attacks

● Operating system basics

Page 3: The Silence of the Canaries

Calling Convention

● foo() has something to tell bar()● Presenting, our stack● And the Assembly for the code

i = 42RetAddr = 0x080483b6

EBP

Locals

Thread Stack

Lower Addr (0x00..)

Higher Addr (0xFF..)

Page 4: The Silence of the Canaries

Buffer Overflow

● Spot the vulnerability

argc, argv...RetAddr

EBP

Locals

Thread Stack

Lower Addr (0x00..)

Higher Addr (0xFF..)

● What happens now?

RetAddrEBP

Locals

“In computer security and programming, a buffer overflow, or buffer overrun, is an anomaly where a program, while writing data to a buffer, overruns the buffer’s boundary and overwrites adjacent memory locations.”

- Wikipedia

Page 5: The Silence of the Canaries

Canaries

● A brief historical context

● Random value

○ Must be random for an attacker won’t be able to guess it.

● Stored before protected data

○ “Before” is relative to direction of overflow.

● Should be changed as much as possible

○ Heavy operation depending on the number of places the canaries are placed at.

Page 6: The Silence of the Canaries

Canaries● gcc implements with -fstack protector

○ -fstack-protector-strong

○ -fstack-protector-all

i = 42RetAddr = 0x080483b6

EBP

Locals

Thread Stack

Lower Addr (0x00..)

Higher Addr (0xFF..)

Canary

Canary == %gs:0x14?

Page 7: The Silence of the Canaries

What is %gs?

● Segment register

○ Once used to partition the memory

○ Memory accesses were SEGMENT:OFFSET

○ i.e. %cs:0x0040 or %ds:0x0040 results different memory regions.

● Now used for special data storage

● %gs segment register used differently across architectures

● Canary values are stored

○ %gs:20 for 32 bit

○ %gs:40 for kernel 64 bit

○ %fs:40 for user 64 bit

Page 8: The Silence of the Canaries

Random

● execve() loads binary

● Transfers Auxiliary Vector to usermode

○ binfmt_elf.c:load_elf_binary() -> create_elf_tables()● “Good” random numbers

Page 9: The Silence of the Canaries

ld.so init

● Every ELF process has an “interpreter”

● Its path is named in the ELF header

● ELF binary interpreter is the dynamic loader

readelf -a <elf_binary>

...

● Initializing internal members at startup

● The described ld.so is GlibC

○ Too much code complexity

○ Very widespread

Page 10: The Silence of the Canaries

Using the random

● During init phase (dl_main), calls security_init

● Initializes TLS (Thread Local Storage)

○ in x86_64 stored in %fs segment register

Offset

0

81624283240

Page 11: The Silence of the Canaries

Check the canaries

● And again, validating the canaries (now x86_64)

Page 12: The Silence of the Canaries

Kernel canaries

● Compiling with CONFIG_CC_STACKPROTECTOR

○ General -> Stack Protector buffer overflow detection

○ Exists for quite some time in Linux

○ Even 2.6.32.68 in kernel.org supports it.

● When rebuilding, needs a clean build

○ Adds snippets for every function prologue and epilogue

● Adds a performance overhead

○ Sorry Linus :(

● Fattens the Kernel image

● Uses gcc -fstack-protector[-strong]

Page 13: The Silence of the Canaries

Kernel canaries

● Let’s say there’s a stack based BOF vulnerability in a system call

● Kernel compiled with CC_STACKPROTECTOR

● However, canary value stored at %gs.

● Malicious program can read value and bypass kernel protection!

Page 14: The Silence of the Canaries

Kernel canaries

● We call a system call● From Intel x86_64 Instruction set

● %gs holds percpu kernel data structures.

○ So we have a different canary for the Kernel.

Page 15: The Silence of the Canaries

arch/x86/include/asm/stackprotector.h

● start_kernel() callsboot_init_stack_canary()

● Canary saved on task_struct

○ Initialization of init processkernel canary● More important, percpu write

Page 16: The Silence of the Canaries

arch/x86/include/asm/percpu.h● Lots of macros...

● Eventually it is something like:

○ movl %1, %%gs:%0

○ Using gcc inline assembly

Page 17: The Silence of the Canaries

Returning to canaries setup

● Let’s focus on the values we write.

64 bit

32 bit

Page 18: The Silence of the Canaries

32 Bit canary placement

● In x86 32 bit, Kernel uses %gs only for canaries. Setup GDT accordingly● Reading stored canary from boot_init_stack_canary● Reading GDT table● Picking the GDT entry for stack canaries● Writing to the specific GDT entry in its wierd encoding● Flushing the GDT to the register

Page 19: The Silence of the Canaries

Kernel canary per process

● Not enough a single canary for kernel

● A kernel canary per user process

○ During fork() in dup_task_struct()

● Randomizes a new canary for Kernel

Page 20: The Silence of the Canaries

You get a canary, and you get a canary, and...

● We want a different kernel canary forevery process

● Need to swap the %gs segmentregister in context switch

● Load per-process kernel canaryexplicitly after task switch

● Kernel canary must be set explicitlyso stack unwinding will succeed aftercontext swapped in __switch_to()

Page 21: The Silence of the Canaries

LAZY_GS

● The top comment at

○ arch/x86/include/asm/stackprotector.h

Page 22: The Silence of the Canaries

LAZY_GS

● Returning to context switch.

○ This is __switch_to in

○ arch/x86/kernel/process_32.c

○ 64 bit isn’t lazy and saves the segment

Page 23: The Silence of the Canaries

32 bit System Call

● When we call 32 bit syscall, save all the registers

Page 24: The Silence of the Canaries

LAZY_GS Macros

● We can see that if %gs is not lazykernel changes the segment registerupon syscall entry.

● But when it’s lazy, it does nothing?● Problem someone?● If this is true, then a hostile usermode

process can overflow canarieswith no apparent problemon x86 32 bit withCONFIG_X86_32_LAZY_GS!

Page 25: The Silence of the Canaries

Can it be?

● Remember this comment at stackprotector.h?

● It seems to be the only place it is done, when kernel is LAZY_GS.

Page 26: The Silence of the Canaries

Look closer

● It seems the kernel holds logic not only in code:● in arch/x86/Kconfig

● So actually we cannot have stack protection and LAZY_GS after all.● (Well, obviously!)

Page 27: The Silence of the Canaries

“Buffer overflows are the poster child of why problems aren't getting better. They were discovered in the 1960s and were first used to attack computers in the 1970s. The Morris worm in 1989 was a very public use of an overflow, which at the time knocked out 10 percent of the Internet--6000 computers. Here we are 40 years later, and buffer overflows are the most common security problem. And that's an easy problem to fix. If you are a software vendor, there is zero excuse for buffer overflows.”

- Bruce Schneier

End to the Overflows

Questions?


Recommended